Mike Loptien (mike.loptien@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@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@se-eng.com Reviewed-on: http://gerrit/3293 Reviewed-by: Marc Jones marc.jones@se-eng.com Tested-by: Automated Builds automated.builds@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__ */