patch-2.2.17 linux/arch/ppc/kernel/prep_pci.c

Next file: linux/arch/ppc/kernel/prep_setup.c
Previous file: linux/arch/ppc/kernel/ppc_ksyms.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.16/arch/ppc/kernel/prep_pci.c linux/arch/ppc/kernel/prep_pci.c
@@ -8,6 +8,7 @@
  */
 
 #include <linux/types.h>
+#include <linux/string.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -36,7 +37,7 @@
 unsigned char *Motherboard_routes;
 void (*Motherboard_non0)(struct pci_dev *);
 
-void Mesquite_Map_Non0(struct pci_dev *);
+void Powerplus_Map_Non0(struct pci_dev *);
 
 /* Used for Motorola to store system config register */
 static unsigned long	*ProcInfo;
@@ -508,6 +509,51 @@
         13      /* Line 4 */
 };
 
+/* Motorola PowerPlus architecture PCI IRQ tables */
+/* Interrupt line values for INTA-D on primary/secondary MPIC inputs */
+
+struct powerplus_irq_list
+{
+	unsigned char primary[4];	/* INT A-D */
+	unsigned char secondary[4];	/* INT A-D */
+};
+
+/*
+ * For standard PowerPlus boards, bus 0 PCI INTs A-D are routed to
+ * OpenPIC inputs 9-12.  PCI INTs A-D from the on board P2P bridge
+ * are routed to OpenPIC inputs 5-8.  These values are offset by 
+ * 16 in the table to reflect the Linux kernel interrupt value.
+ */
+struct powerplus_irq_list Powerplus_pci_IRQ_list =
+{
+	{25, 26, 27, 28},
+	{21, 22, 23, 24}
+};
+
+/* 
+ * For the MCP750 (system slot board), bus 0 PCI INTs A-D are routed
+ * to OpenPIC inputs 8-11.  PCI INTs A-D from the on board P2P bridge
+ * are routed to OpenPIC inputs 12-15.  These values are offset by 16
+ * in the table to reflect the Linux kernel interrupt value.
+ */
+struct powerplus_irq_list Mesquite_pci_IRQ_list =
+{
+	{24, 25, 26, 27},
+	{28, 29, 30, 31}
+};
+
+/*
+ * This table represents the standard PCI swizzle defined in the
+ * PCI bus specification.
+ */ 
+static unsigned char prep_pci_intpins[4][4] =
+{
+        { 1, 2, 3, 4},  /* Buses 0, 4, 8, ... */
+        { 2, 3, 4, 1},  /* Buses 1, 5, 9, ... */
+        { 3, 4, 1, 2},  /* Buses 2, 6, 10 ... */
+        { 4, 1, 2, 3},  /* Buses 3, 7, 11 ... */
+};
+
 /* We have to turn on LEVEL mode for changed IRQ's */
 /* All PCI IRQ's need to be level mode, so this should be something
  * other than hard-coded as well... IRQ's are individually mappable
@@ -685,8 +731,7 @@
 #define MOT_RAVEN_PRESENT	0x1
 #define MOT_HAWK_PRESENT	0x2
 
-/* Keyboard present flag */
-int prep_kbd_present = 1;   /* Keyboard present by default */
+int mot_entry = -1;
 
 int MotMPIC = 0;
 int mot_multi = 0;
@@ -751,13 +796,17 @@
 		mot_multi = 1;
 	}
 
-	/* This is a hack.  If this is a 2300 or 2400 mot board then there is
-	 * no keyboard controller and we have to indicate that.
+	/*
+	 * If a Motorola MVME2300, 2400, or MCPN750 board is detected
+	 * disable keyboard controller initialization to avoid system
+	 * hangs.
 	 */
 	base_mod = inb(MOTOROLA_BASETYPE_REG);
 	if ((MotMPIC == MOT_HAWK_PRESENT) || (base_mod == 0xF9) ||
-	    (base_mod == 0xFA) || (base_mod == 0xE1))
-		prep_kbd_present = 0;
+	    (base_mod == 0xFA) || (base_mod == 0xE1)) {
+		ppc_md.kbd_leds	= NULL; 
+		ppc_md.kbd_init_hw = NULL; 
+	}
 
 	return 1;
 }
@@ -771,33 +820,35 @@
 	unsigned char	*map;
 	unsigned char	*routes;
 	void		(*map_non0_bus)(struct pci_dev *);	/* For boards with more than bus 0 devices. */
+	struct powerplus_irq_list *pci_irq_list; /* List of PCI MPIC inputs */
+	unsigned char	secondary_bridge_devfn;	/* devfn of secondary bus transparent bridge */
 } mot_info[] = {
-	{0x300, 0x00, 0x00, "MVME 2400",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x010, 0x00, 0x00, "Genesis",				Genesis_pci_IRQ_map,	Genesis_pci_IRQ_routes, NULL},
-	{0x020, 0x00, 0x00, "Powerstack (Series E)",		Comet_pci_IRQ_map,	Comet_pci_IRQ_routes,	NULL},
-	{0x040, 0x00, 0x00, "Blackhawk (Powerstack)",		Blackhawk_pci_IRQ_map,	Blackhawk_pci_IRQ_routes, NULL},
-	{0x050, 0x00, 0x00, "Omaha (PowerStack II Pro3000)",	Omaha_pci_IRQ_map,	Omaha_pci_IRQ_routes,	NULL},
-	{0x060, 0x00, 0x00, "Utah (Powerstack II Pro4000)",	Utah_pci_IRQ_map,	Utah_pci_IRQ_routes,	NULL},
-	{0x0A0, 0x00, 0x00, "Powerstack (Series EX)",		Comet2_pci_IRQ_map,	Comet2_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)",		Mesquite_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)",		Sitka_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC",	Mesquite_pci_IRQ_map,	Raven_pci_IRQ_routes,	Mesquite_Map_Non0},
-	{0x1E0, 0xF6, 0x80, "MTX Plus",				MTXplus_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xF6, 0x81, "Dual MTX Plus",			MTXplus_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port",		MTX_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port",	MTX_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port",		MTX_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port",	MTX_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xF9, 0x00, "MVME 2300",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xFA, 0x00, "MVME 2300SC/2600",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761",	Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xFF, 0x00, "MVME 1600-001 or 1600-011",	Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x000, 0x00, 0x00, "",					NULL,			NULL,	NULL}
+	{0x300, 0x00, 0x00, "MVME 2400",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x010, 0x00, 0x00, "Genesis",				Genesis_pci_IRQ_map,	Genesis_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x020, 0x00, 0x00, "Powerstack (Series E)",		Comet_pci_IRQ_map,	Comet_pci_IRQ_routes,	NULL, NULL, 0x00},
+	{0x040, 0x00, 0x00, "Blackhawk (Powerstack)",		Blackhawk_pci_IRQ_map,	Blackhawk_pci_IRQ_routes, NULL, NULL, 0x00},
+	{0x050, 0x00, 0x00, "Omaha (PowerStack II Pro3000)",	Omaha_pci_IRQ_map,	Omaha_pci_IRQ_routes,	NULL, NULL, 0x00},
+	{0x060, 0x00, 0x00, "Utah (Powerstack II Pro4000)",	Utah_pci_IRQ_map,	Utah_pci_IRQ_routes,	NULL, NULL, 0x00},
+	{0x0A0, 0x00, 0x00, "Powerstack (Series EX)",		Comet2_pci_IRQ_map,	Comet2_pci_IRQ_routes,	NULL, NULL, 0x00},
+	{0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)",		Mesquite_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Mesquite_pci_IRQ_list, 0x00},
+	{0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)",		Sitka_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC",	Mesquite_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Mesquite_pci_IRQ_list, 0xC0},
+	{0x1E0, 0xF6, 0x80, "MTX Plus",				MTXplus_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xA0},
+	{0x1E0, 0xF6, 0x81, "Dual MTX Plus",			MTXplus_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xA0},
+	{0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port",		MTX_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port",	MTX_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port",		MTX_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port",	MTX_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xF9, 0x00, "MVME 2300",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xFA, 0x00, "MVME 2300SC/2600",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761",	Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xFF, 0x00, "MVME 1600-001 or 1600-011",	Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL, NULL, 0x00},
+	{0x000, 0x00, 0x00, "",					NULL,			NULL,	NULL, 0x00}
 };
 
 __initfunc(unsigned long prep_route_pci_interrupts(void))
@@ -812,7 +863,6 @@
 		unsigned char  cpu_type;
 		unsigned char  base_mod;
 		int	       entry;
-		int	       mot_entry = -1;
 
 		cpu_type = inb(MOTOROLA_CPUTYPE_REG) & 0xF0;
 		base_mod = inb(MOTOROLA_BASETYPE_REG);
@@ -989,91 +1039,91 @@
 	return 0;
 }
 
-static unsigned int pci_localpirqs[4] =
-{
-	24,
-	25,
-	26,
-	27
-};
-
-static unsigned int pci_remotepirqs[4] =
-{
-	28,
-	29,
-	30,
-	31
-};
-
-static unsigned int pci_remotedev = 0xc0;
-
+/*
+ * Remove a device from the kernel PCI device list based on its 
+ * devfn identifier.
+ */
+__initfunc(
 void
-Mesquite_Map_Non0(struct pci_dev *pdev)
+prep_exclude_pci_device(unsigned char devfn)
+)
 {
-	struct pci_bus  *pbus;          /* Parent Bus Structure Pointer */
-	unsigned int    devnum;         /* Accumulated Device Number */
-	unsigned int    irq;            /* IRQ Value */
-
-	/*
-	**    Device Interrupt Line register initialization.
-	**    The IRQ line number will be generated after
-	**    taking into account all the PCI-2-PCI bridge
-	**    devices between the device and the Host Bridge.
-	*/
-	devnum = PCI_SLOT(pdev->devfn);
-	pbus = pdev->bus;
+	struct pci_dev *dev, *pdev = NULL;
 
-	while ((pbus->parent)->primary != (pbus->parent)->secondary)
-	{
-	    devnum += PCI_SLOT((pbus->self)->devfn);
+	/* Walk the pci device list */
+	for(dev=pci_devices; dev; dev=dev->next) {
+		if (dev->devfn == devfn)
+		{
+			/*
+			 * If we find a matching device, adjust
+			 * the list to remove the device.
+			 */
+			if (pdev != NULL)
+				pdev->next = dev->next;
+			else
+				pci_devices = dev->next;
 
-	    pbus = pbus->parent;
+			break;
+		}
+		pdev = dev;
 	}
+}
 
-	devnum &= 0x03;
-
-	/*
-	**    By default, get the PCI local domain IRQ value.
-	*/
-	irq = pci_localpirqs[devnum];
-
-	/*
-	**    Determine if the device is located in the
-	**    remote domain or not. We must find the
-	**    domain's bridge device located on bus 0.
-	*/
-	pbus = pdev->bus;
+void
+Powerplus_Map_Non0(struct pci_dev *dev)
+{
+	struct pci_bus  *pbus;          /* Parent bus structure pointer */
+	struct pci_dev	*tdev;		/* Temporary device structure */
+        unsigned int    devnum;         /* Accumulated device number */
+        unsigned char   intline;        /* Linux interrupt value */
+	unsigned char	intpin;		/* PCI interrupt pin */
+ 
+	/* Check for valid PCI dev pointer */
+	if (dev == NULL) return;
+
+	/* Fill our temporary device, and get the device number */
+	*tdev = *dev;
+	devnum = PCI_SLOT(tdev->devfn);
+
+	/* Read the interrupt pin of the device and adjust for indexing */
+	pcibios_read_config_byte(tdev->bus->number, tdev->devfn,
+				PCI_INTERRUPT_PIN, &intpin);
 
-	while (pbus->primary != 0)
-	    pbus = pbus->parent;
+	/* If device doesn't request an interrupt, return */
+	if ( (intpin < 1) || (intpin > 4) )
+		return;
 
-	/*
-	**    Check the device/function of domain's bridge
-	**    device against the remote device/function.
-	**    If the same, then the device is located in
-	**    the remote domain. Thus, get the PCI remote
-	**    domain IRQ value.
-	*/
-	if ((pbus->self)->devfn == pci_remotedev)
-        irq = pci_remotepirqs[devnum];
+	intpin--;
 
-	/*
-	**    Validate the IRQ number.
-	*/
-	if (irq <= 255)
+	/* Walk up to bus 0, adjusting the interrupt pin for the standard
+	   PCI bus swizzle. */
+	do {
+		intpin = (prep_pci_intpins[devnum % 4][intpin]) - 1;
+		pbus = tdev->bus;        /* up one level */
+		tdev = pbus->self;
+		devnum = PCI_SLOT(tdev->devfn);
+	} while(tdev->bus->number);
+
+	/* Use the primary interrupt inputs by default */
+	intline = mot_info[mot_entry].pci_irq_list->primary[intpin];
+
+	/* If the board has secondary interrupt inputs, walk the bus and
+	   note the devfn of the bridge from bus 0.  If it is the same as
+	   the devfn of the bus bridge with secondary inputs, use those. */
+	if (mot_info[mot_entry].secondary_bridge_devfn)
 	{
-	    /*
-	    **    Set the device's Interrupt Line register
-	    **    to the IRQ number and save it in the
-	    **    device's structure.
-	    */
-
-	    pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, (u8)irq);
-
-	    pdev->irq = irq;
-
+		pbus = dev->bus;
+ 
+		while (pbus->primary != 0)
+			pbus = pbus->parent;
+ 
+		if ((pbus->self)->devfn == mot_info[mot_entry].secondary_bridge_devfn)
+			intline = mot_info[mot_entry].pci_irq_list->secondary[intpin];
 	}
-	return;
+	
+	/* Write calculated interrupt value to header and device list */
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, (u8)intline);
+	dev->irq = intline;
 }
 
 int motopenpic_to_irq(int n)
@@ -1137,6 +1187,15 @@
 
 	prep_route_pci_interrupts();
 
+	/*
+	 * If MTX+, exclude the SL82C105 IDE controller so the driver
+	 * doesn't hang.
+	 */
+	if ( _prep_type == _PREP_Motorola )
+		if ( strstr(mot_info[mot_entry].name, "MTX Plus") )
+			/* On MTX+, SL82C105 is at IDSEL 0xb function 0x1 */
+			prep_exclude_pci_device(PCI_DEVFN(0xb, 0x1));
+
 	prep_pib_init();
 
 	printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name);
@@ -1150,7 +1209,7 @@
 		       motopenpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]);
 
 		    pcibios_write_config_byte(dev->bus->number, dev->devfn, 
-					      PCI_INTERRUPT_PIN, dev->irq);
+					      PCI_INTERRUPT_LINE, dev->irq);
 		} else {
 			if (Motherboard_non0 != NULL)
 				Motherboard_non0(dev);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)