[coreboot-gerrit] New patch to review for coreboot: d758a87 CIMx: Use the new PCI IRQ functions

Mike Loptien (mike.loptien@se-eng.com) gerrit at coreboot.org
Tue May 27 22:58:04 CEST 2014


Mike Loptien (mike.loptien at se-eng.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/5879

-gerrit

commit d758a87831a22728b3129ba64dda72598186ef72
Author: Mike Loptien <mike.loptien at se-eng.com>
Date:   Fri Feb 7 11:20:33 2014 -0700

    CIMx: Use the new PCI IRQ functions
    
    The PCI IRQ functions in pci_device.c should be used to find
    the IRQ routing information for the PCI devices.  These are
    generic functions that search for the PCI interrupt information
    and returns all of the information needed to correctly program
    the PCI Configuration space registers with the correct IRQ
    values.
    
    Change-Id: I9f44514bbba149f72cfea5aa57f2d10633dd45bf
    Signed-off-by: Mike Loptien <mike.loptien at se-eng.com>
    Reviewed-on: http://gerrit/3293
    Reviewed-by: Marc Jones <marc.jones at se-eng.com>
    Tested-by: Automated Builds <automated.builds at se-eng.com>
---
 src/southbridge/amd/cimx/cimx_util.c | 106 +++++++++++++++++++++++------------
 1 file changed, 69 insertions(+), 37 deletions(-)

diff --git a/src/southbridge/amd/cimx/cimx_util.c b/src/southbridge/amd/cimx/cimx_util.c
index bf8fbfd..8fb7d43 100644
--- a/src/southbridge/amd/cimx/cimx_util.c
+++ b/src/southbridge/amd/cimx/cimx_util.c
@@ -46,6 +46,7 @@ const char * intr_types[] = {
 #endif
 
 const struct pirq_struct * pirq_data_ptr = NULL;
+u32 pirq_data_size = 0;
 const u8 * intr_data_ptr = NULL;
 const u8 * picr_data_ptr = NULL;
 
@@ -114,11 +115,15 @@ void write_pci_int_table (void)
  */
 void write_pci_cfg_irqs(void)
 {
-	device_t dev;
+	device_t dev = NULL;		/* Our current device to route IRQs to */
+	device_t target_dev = NULL;	/* The bridge that a device may be connected to */
 	int int_pin = 0;	/* Value of the INT_PIN register 0x3D */
+	int target_pin = 0;	/* Pin we will search our tables for */
 	int int_line = 0;	/* IRQ number read from PCI_INTR table and programmed to INT_LINE reg 0x3C */
-	int c00_idx = 0;	/* Index into PCI_INTR table, 0xC00/0xC01 */
+	int pci_intr_idx = 0;	/* Index into PCI_INTR table, 0xC00/0xC01 */
+	int bus = 0;		/* A PCI Device Bus number */
 	int devfn = 0;		/* A PCI Device and Function number */
+	int bridged_device = 0;	/* This device is on a PCI bridge */
 	int i = 0;
 
 	if (pirq_data_ptr == NULL) {
@@ -129,65 +134,92 @@ void write_pci_cfg_irqs(void)
 
 	/* Populate the PCI cfg space header with the IRQ assignment */
 	printk(BIOS_DEBUG, "PCI_CFG IRQ: Write PCI config space IRQ assignments\n");
+
 	for (dev = all_devices; dev; dev = dev->next) {
-		devfn = dev->path.pci.devfn;
+		/*
+		 * Step 1: Get the INT_PIN and device structure to look for in the
+		 * PCI_INTR table pirq_data
+		 */
+		target_dev = NULL;
+		target_pin = get_irq_pins(dev, &target_dev);
+		if (target_dev == NULL)
+			continue;
 
-		if (!(dev->enabled))
-			continue;	/* Skip disabled devices */
+		if (target_pin < 1)
+			continue;
 
-		/* Get the INT_PIN that this dev uses */
+		/* Get the original INT_PIN for record keeping */
 		int_pin = pci_read_config8(dev, PCI_INTERRUPT_PIN);
 		if (int_pin < 1 || int_pin > 4)
-			continue;	/* Device has INT_PIN = 0 so we do not need to set up an IRQ for it */
+			continue;	/* Device has invalid INT_PIN so we do not need to set up an IRQ for it */
 
-		printk(BIOS_SPEW, "PCI_CFG IRQ: Found dev %01x:%02xh.%02xh\n",
-				dev->bus->secondary, PCI_SLOT(devfn), PCI_FUNC(devfn));
+		bus   = target_dev->bus->secondary;
+		devfn = target_dev->path.pci.devfn;
 
-		/* Find the index into the PCI_INTR table for this device */
-		i = 0;
-		c00_idx = 0xFF;	/* Will check to make sure it changed */
-		while ((pirq_data_ptr[i].devfn != 0xFF) || (pirq_data_ptr[i].PIN[0] != 0xFF)) {
-			if (pirq_data_ptr[i].devfn != devfn) {
-				i++;
+		/*
+		 * Step 2: Use the INT_PIN and DevFn number to find the PCI_INTR
+		 * register (0xC00) index for this device
+		 */
+		pci_intr_idx = 0xBAD;	/* Will check to make sure it changed */
+		for (i = 0; i <= pirq_data_size - 1; i++) {
+			if (pirq_data_ptr[i].devfn != devfn)
 				continue;
-			}
-			c00_idx = pirq_data_ptr[i].PIN[int_pin - 1];	/* PIN_A is index 0 in pirq_data array but 1 in PCI cfg reg */
-			break;	/* Found our device, stop looping */
+
+			/* PIN_A is index 0 in pirq_data array but 1 in PCI cfg reg */
+			pci_intr_idx = pirq_data_ptr[i].PIN[target_pin - 1];
+			printk(BIOS_SPEW, "\tFound this device in pirq_data table entry %d\n", i);
+			break;
 		}
 
-		/* Make sure we got a valid index */
-		if (c00_idx == 0xFF) {
+		/*
+		 * Step 3: Make sure we got a valid index and use it to get
+		 * the IRQ number from the PCI_INTR register table
+		 */
+		if (pci_intr_idx == 0xBAD) {	/* Not on a bridge or in pirq_data table, skip it */
 			printk(BIOS_SPEW, "PCI Devfn (0x%x) not found in pirq_data table\n", devfn);
 			continue;
-		} else if (c00_idx == 0x1F) {
+		} else if (pci_intr_idx == 0x1F) {	/* Index found is not defined */
 			printk(BIOS_SPEW, "Got index 0x1F (Not Connected), perhaps this device was defined wrong?\n");
 			continue;
+		} else if (pci_intr_idx > FCH_INT_TABLE_SIZE) {	/* Index out of bounds */
+			printk(BIOS_ERR, "%s: got 0xC00/0xC01 table index 0x%x, max is 0x%x\n",
+					__func__, pci_intr_idx, FCH_INT_TABLE_SIZE);
+			continue;
 		}
 
-		/* Program the INT_LINE register (0x3C) in PCI config space */
-		int_line = read_pci_int_idx(c00_idx, 0);	/* Get the IRQ associated with this INT_PIN */
-		if (int_line == IRQ_DIS) {
+		/* Find the value to program into the INT_LINE register from the PCI_INTR registers */
+		int_line = read_pci_int_idx(pci_intr_idx, 0);
+		if (int_line == PIRQ_NC) {	/* The IRQ found is not disabled */
 			printk(BIOS_SPEW, "Got IRQ 0x1F (disabled), perhaps this device was defined wrong?\n");
 			continue;
-		} else if ((1 << int_line) & IRQ_RES) {
+		} else if ((1 << int_line) & IRQ_RES) {	/* Found an IRQ that is reserved */
 			printk(BIOS_WARNING, "WARNING: PCI IRQ %d is reserved, check the mainboard_picr_data table\n"
-					"Skipping write of PCI config space\n", int_line);
+					"Skip writing it to PCI config space to prevent instability\n", int_line);
 			continue;
 		}
-		pci_write_config8(dev, PCI_INTERRUPT_LINE, int_line);	/* Set INT_LINE reg with value from PCI_INTR table */
 
-		/* Set this IRQ to level triggered since it is used by PCI devices */
+		/*
+		 * Step 4: Program the INT_LINE register in this device's
+		 * PCI config space with the IRQ number we found in step 3
+		 * and make it Level Triggered
+		 */
+		pci_write_config8(dev, PCI_INTERRUPT_LINE, int_line);
+
+		/* Set this IRQ to level triggered since it is used by a PCI device */
 		i8259_configure_irq_trigger(int_line, IRQ_LEVEL_TRIGGERED);
 
-		printk(BIOS_SPEW, "\tINT_PIN\t\t: %d (%s)\n", int_pin,
-				(int_pin == 1) ? "PIN A":
-				(int_pin == 2) ? "PIN B":
-				(int_pin == 3) ? "PIN C":
-				(int_pin == 4) ? "PIN D" : "Unknown INT_PIN!");
-		printk(BIOS_SPEW, "\tINT_LINE\t: 0x%x (IRQ %d)\n"
-				"\tPCI_INTR idx\t: 0x%02x (%s)\n",
-				int_line, int_line, c00_idx, intr_types[c00_idx]);
-	}
+		/*
+		 * Step 5: Print out debug info and move on to next device
+		 */
+		printk(BIOS_SPEW, "\tOrig INT_PIN\t: %d (%s)\n",
+						int_pin, pin_to_str(int_pin));
+		if (bridged_device)
+			printk(BIOS_SPEW, "\tSwizzled to\t: %d (%s)\n",
+							target_pin, pin_to_str(target_pin));
+		printk(BIOS_SPEW, "\tPCI_INTR idx\t: 0x%02x (%s)\n"
+						"\tINT_LINE\t: 0x%X (IRQ %d)\n",
+						pci_intr_idx, intr_types[pci_intr_idx], int_line, int_line);
+	}	/* for (dev = all_devices) */
 	printk(BIOS_DEBUG, "PCI_CFG IRQ: Finished writing PCI config space IRQ assignments\n");
 }
 #endif /* __PRE_RAM__ */



More information about the coreboot-gerrit mailing list