<p>Frans Hendriks has uploaded this change for <strong>review</strong>.</p><p><a href="https://review.coreboot.org/29419">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">src/soc/intel/braswell/southcluster.c: Correct configuration of interrupts<br><br>The level/edge mode of PIRQ is not configured and i8259 PIC not initialized.<br>Add calls to i8259_configure_irq_trigger(), write_pci_config_irqs() and<br>setup_i8259() to correct the configuration of interrupts.<br><br>BUG=N/A<br>TEST=Intel CherryHill CRB<br><br>Change-Id: I128cb35dd0e348a9cd9fb162651e0aa2b7e4a3ef<br>Signed-off-by: Frans Hendriks <fhendriks@eltan.com><br>---<br>M src/soc/intel/braswell/include/soc/irq.h<br>M src/soc/intel/braswell/southcluster.c<br>2 files changed, 114 insertions(+), 3 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://review.coreboot.org:29418/coreboot refs/changes/19/29419/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/soc/intel/braswell/include/soc/irq.h b/src/soc/intel/braswell/include/soc/irq.h</span><br><span>index 4375c20..9a3c40d 100644</span><br><span>--- a/src/soc/intel/braswell/include/soc/irq.h</span><br><span>+++ b/src/soc/intel/braswell/include/soc/irq.h</span><br><span>@@ -154,6 +154,7 @@</span><br><span> #define PIRQ_PIC_IRQ12                       0xc</span><br><span> #define PIRQ_PIC_IRQ14                   0xe</span><br><span> #define PIRQ_PIC_IRQ15                   0xf</span><br><span style="color: hsl(120, 100%, 40%);">+#define PIRQ_PIC_UNKNOWN_UNUSED 0xff</span><br><span> </span><br><span> /* Overloaded term, but these values determine the per device route. */</span><br><span> #define PIRQA                               0</span><br><span>diff --git a/src/soc/intel/braswell/southcluster.c b/src/soc/intel/braswell/southcluster.c</span><br><span>index ca87d63..537d66d 100644</span><br><span>--- a/src/soc/intel/braswell/southcluster.c</span><br><span>+++ b/src/soc/intel/braswell/southcluster.c</span><br><span>@@ -26,6 +26,7 @@</span><br><span> #include <device/device.h></span><br><span> #include <device/pci.h></span><br><span> #include <device/pci_ids.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <pc80/i8259.h></span><br><span> #include <pc80/mc146818rtc.h></span><br><span> #include <romstage_handoff.h></span><br><span> #include <soc/acpi.h></span><br><span>@@ -78,6 +79,105 @@</span><br><span> #define LPC_DEFAULT_IO_RANGE_LOWER 0</span><br><span> #define LPC_DEFAULT_IO_RANGE_UPPER 0x1000</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Write PCI config space IRQ assignments.  PCI devices have the INT_LINE</span><br><span style="color: hsl(120, 100%, 40%);">+ * (0x3C) and INT_PIN (0x3D) registers which report interrupt routing</span><br><span style="color: hsl(120, 100%, 40%);">+ * information to operating systems and drivers.  The INT_PIN register is</span><br><span style="color: hsl(120, 100%, 40%);">+ * generally read only and reports which interrupt pin A - D it uses.  The</span><br><span style="color: hsl(120, 100%, 40%);">+ * INT_LINE register is configurable and reports which IRQ (generally the</span><br><span style="color: hsl(120, 100%, 40%);">+ * PIC IRQs 1 - 15) it will use.  This needs to take interrupt pin swizzling</span><br><span style="color: hsl(120, 100%, 40%);">+ * on devices that are downstream on a PCI bridge into account.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This function will loop through all enabled PCI devices and program the</span><br><span style="color: hsl(120, 100%, 40%);">+ * INT_LINE register with the correct PIC IRQ number for the INT_PIN that it</span><br><span style="color: hsl(120, 100%, 40%);">+ * uses.  It then configures each interrupt in the pic to be level triggered.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static void write_pci_config_irqs(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      device_t irq_dev;</span><br><span style="color: hsl(120, 100%, 40%);">+     device_t targ_dev;</span><br><span style="color: hsl(120, 100%, 40%);">+    uint8_t int_line = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t original_int_pin = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t new_int_pin = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint16_t current_bdf = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint16_t parent_bdf = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t pirq = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t device_num = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+       const struct soc_irq_route *ir = &global_soc_irq_route;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ir == NULL) {</span><br><span style="color: hsl(120, 100%, 40%);">+             printk(BIOS_WARNING, "Warning: Can't write PCI IRQ assignments because"</span><br><span style="color: hsl(120, 100%, 40%);">+                         " 'global_braswell_irq_route' structure does not exist\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /*</span><br><span style="color: hsl(120, 100%, 40%);">+     * Loop through all enabled devices and program their</span><br><span style="color: hsl(120, 100%, 40%);">+  * INT_LINE, INT_PIN registers from values taken from</span><br><span style="color: hsl(120, 100%, 40%);">+  * the Interrupt Route registers in the ILB</span><br><span style="color: hsl(120, 100%, 40%);">+    */</span><br><span style="color: hsl(120, 100%, 40%);">+   printk(BIOS_DEBUG, "PCI_CFG IRQ: Write PCI config space IRQ assignments\n");</span><br><span style="color: hsl(120, 100%, 40%);">+        for(irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if ((irq_dev->path.type != DEVICE_PATH_PCI) ||</span><br><span style="color: hsl(120, 100%, 40%);">+                     (!irq_dev->enabled))</span><br><span style="color: hsl(120, 100%, 40%);">+                       continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           current_bdf = irq_dev->path.pci.devfn |</span><br><span style="color: hsl(120, 100%, 40%);">+                    irq_dev->bus->secondary << 8;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /*</span><br><span style="color: hsl(120, 100%, 40%);">+             * Step 1: Get the INT_PIN and device structure to look for</span><br><span style="color: hsl(120, 100%, 40%);">+            * in the pirq_data table defined in the mainboard directory.</span><br><span style="color: hsl(120, 100%, 40%);">+          */</span><br><span style="color: hsl(120, 100%, 40%);">+           targ_dev = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+              new_int_pin = get_pci_irq_pins(irq_dev, &targ_dev);</span><br><span style="color: hsl(120, 100%, 40%);">+               if (targ_dev == NULL || new_int_pin < 1)</span><br><span style="color: hsl(120, 100%, 40%);">+                   continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* Get the original INT_PIN for record keeping */</span><br><span style="color: hsl(120, 100%, 40%);">+             original_int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            parent_bdf = targ_dev->path.pci.devfn</span><br><span style="color: hsl(120, 100%, 40%);">+                      | targ_dev->bus->secondary << 8;</span><br><span style="color: hsl(120, 100%, 40%);">+          device_num = PCI_SLOT(parent_bdf);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          if (ir->pcidev[device_num] == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 printk(BIOS_WARNING,</span><br><span style="color: hsl(120, 100%, 40%);">+                          "Warning: PCI Device %d does not have an IRQ entry, skipping it\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                         device_num);</span><br><span style="color: hsl(120, 100%, 40%);">+                  continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* Find the PIRQ that is attached to the INT_PIN this device uses */</span><br><span style="color: hsl(120, 100%, 40%);">+          pirq = (ir->pcidev[device_num] >> ((new_int_pin - 1) * 4)) & 0x7;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              /* Get the INT_LINE this device/function will use */</span><br><span style="color: hsl(120, 100%, 40%);">+          int_line = ir->pic[pirq];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                if (int_line != PIRQ_PIC_IRQDISABLE) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        /* Set this IRQ to level triggered since it is used by a PCI device */</span><br><span style="color: hsl(120, 100%, 40%);">+                        i8259_configure_irq_trigger(int_line, IRQ_LEVEL_TRIGGERED);</span><br><span style="color: hsl(120, 100%, 40%);">+                   /* Set the Interrupt Line register in PCI config space */</span><br><span style="color: hsl(120, 100%, 40%);">+                     pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, int_line);</span><br><span style="color: hsl(120, 100%, 40%);">+             } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      /* Set the Interrupt line register as "unknown or unused" */</span><br><span style="color: hsl(120, 100%, 40%);">+                        pci_write_config8(irq_dev, PCI_INTERRUPT_LINE,</span><br><span style="color: hsl(120, 100%, 40%);">+                                PIRQ_PIC_UNKNOWN_UNUSED);</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           printk(BIOS_SPEW, "\tINT_PIN\t\t: %d (%s)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                       original_int_pin, pin_to_str(original_int_pin));</span><br><span style="color: hsl(120, 100%, 40%);">+              if (parent_bdf != current_bdf)</span><br><span style="color: hsl(120, 100%, 40%);">+                        printk(BIOS_SPEW, "\tSwizzled to\t: %d (%s)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                                     new_int_pin, pin_to_str(new_int_pin));</span><br><span style="color: hsl(120, 100%, 40%);">+                printk(BIOS_SPEW, "\tPIRQ\t\t: %c\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                                                "\tINT_LINE\t: 0x%X (IRQ %d)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                            'A' + pirq, int_line, int_line);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     printk(BIOS_DEBUG, "PCI_CFG IRQ: Finished writing PCI config space IRQ assignments\n");</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static inline int io_range_in_default(int base, int size)</span><br><span> {</span><br><span>     /* Does it start above the range? */</span><br><span>@@ -161,7 +261,6 @@</span><br><span>   const unsigned long pr_base = ILB_BASE_ADDRESS + 0x08;</span><br><span>       const unsigned long ir_base = ILB_BASE_ADDRESS + 0x20;</span><br><span>       void *gen_pmcon1 = (void *)(PMC_BASE_ADDRESS + GEN_PMCON1);</span><br><span style="color: hsl(0, 100%, 40%);">-     void *actl = (void *)(ILB_BASE_ADDRESS + ACTL);</span><br><span>      const struct soc_irq_route *ir = &global_soc_irq_route;</span><br><span>  struct soc_intel_braswell_config *config = dev->chip_info;</span><br><span> </span><br><span>@@ -178,8 +277,14 @@</span><br><span>             write16((void *)(ir_base + i*sizeof(ir->pcidev[i])),</span><br><span>                      ir->pcidev[i]);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  /* Route SCI to IRQ9 */</span><br><span style="color: hsl(0, 100%, 40%);">- write32(actl, (read32(actl) & ~SCIS_MASK) | SCIS_IRQ9);</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Interrupt 9 should be level triggered (SCI) */</span><br><span style="color: hsl(120, 100%, 40%);">+     i8259_configure_irq_trigger(9, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  for (i = 0; i < NUM_PIRQS; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if ( ir->pic[i] ) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        i8259_configure_irq_trigger(ir->pic[i], 1);</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span> </span><br><span>        sc_rtc_init();</span><br><span> </span><br><span>@@ -192,6 +297,11 @@</span><br><span>                    read32(gen_pmcon1) & ~DIS_SLP_X_STRCH_SUS_UP);</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Write IRQ assignments to PCI config space */</span><br><span style="color: hsl(120, 100%, 40%);">+       write_pci_config_irqs();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Initialize i8259 pic */</span><br><span style="color: hsl(120, 100%, 40%);">+    setup_i8259();</span><br><span> }</span><br><span> </span><br><span> /*</span><br><span></span><br></pre><p>To view, visit <a href="https://review.coreboot.org/29419">change 29419</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://review.coreboot.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://review.coreboot.org/29419"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: coreboot </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I128cb35dd0e348a9cd9fb162651e0aa2b7e4a3ef </div>
<div style="display:none"> Gerrit-Change-Number: 29419 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Frans Hendriks <fhendriks@eltan.com> </div>