<p>Arthur Heymans has uploaded this change for <strong>review</strong>.</p><p><a href="https://review.coreboot.org/c/coreboot/+/30320">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">sb/intel/i82801gx: Implement PCIe coalescing<br><br>The implementation is a simplified version of the haswell/broadwell code.<br>This also adds a chip option to enable coalescing from the devicetree.<br><br>Untested.<br><br>Change-Id: I6d7ddef96e4f45e163f7017175398a0938a18273<br>Signed-off-by: Arthur Heymans <arthur@aheymans.xyz><br>---<br>M src/southbridge/intel/i82801gx/chip.h<br>M src/southbridge/intel/i82801gx/pcie.c<br>2 files changed, 157 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://review.coreboot.org:29418/coreboot refs/changes/20/30320/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/southbridge/intel/i82801gx/chip.h b/src/southbridge/intel/i82801gx/chip.h</span><br><span>index 3a20ab1..db27ef7 100644</span><br><span>--- a/src/southbridge/intel/i82801gx/chip.h</span><br><span>+++ b/src/southbridge/intel/i82801gx/chip.h</span><br><span>@@ -68,6 +68,9 @@</span><br><span>        uint32_t sata_ahci;</span><br><span>  uint32_t sata_ports_implemented;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+  /* Enable linear PCIe Root Port function numbers starting at zero */</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t pcie_port_coalesce;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>        int c4onc3_enable:1;</span><br><span>         int docking_supported:1;</span><br><span>     int p_cnt_throttling_supported:1;</span><br><span>diff --git a/src/southbridge/intel/i82801gx/pcie.c b/src/southbridge/intel/i82801gx/pcie.c</span><br><span>index 7de9890..6059499 100644</span><br><span>--- a/src/southbridge/intel/i82801gx/pcie.c</span><br><span>+++ b/src/southbridge/intel/i82801gx/pcie.c</span><br><span>@@ -18,6 +18,37 @@</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 "i82801gx.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Low Power variant has 6 root ports. */</span><br><span style="color: hsl(120, 100%, 40%);">+#define NUM_ROOT_PORTS 6</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct root_port_config {</span><br><span style="color: hsl(120, 100%, 40%);">+        /* RPFN is a write-once register so keep a copy until it is written */</span><br><span style="color: hsl(120, 100%, 40%);">+        u32 orig_rpfn;</span><br><span style="color: hsl(120, 100%, 40%);">+        u32 new_rpfn;</span><br><span style="color: hsl(120, 100%, 40%);">+ int coalesce;</span><br><span style="color: hsl(120, 100%, 40%);">+ int num_ports;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct device *ports[NUM_ROOT_PORTS];</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%);">+static struct root_port_config rpc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static inline int root_port_is_first(struct device *dev)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       return PCI_FUNC(dev->path.pci.devfn) == 0;</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%);">+static inline int root_port_is_last(struct device *dev)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        return PCI_FUNC(dev->path.pci.devfn) == (rpc.num_ports - 1);</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%);">+/* Root ports are numbered 1..N in the documentation. */</span><br><span style="color: hsl(120, 100%, 40%);">+static inline int root_port_number(struct device *dev)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     return PCI_FUNC(dev->path.pci.devfn) + 1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> </span><br><span> static void pci_init(struct device *dev)</span><br><span> {</span><br><span>@@ -89,6 +120,128 @@</span><br><span>  pci_write_config16(dev, 0x1e, reg16);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void root_port_init_config(struct device *dev)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      int rp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (root_port_is_first(dev)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                rpc.orig_rpfn = RCBA32(RPFN);</span><br><span style="color: hsl(120, 100%, 40%);">+         rpc.new_rpfn = rpc.orig_rpfn;</span><br><span style="color: hsl(120, 100%, 40%);">+         rpc.num_ports = NUM_ROOT_PORTS;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             if (dev->chip_info != NULL) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      struct southbridge_intel_i82801gx_config *config</span><br><span style="color: hsl(120, 100%, 40%);">+                              = dev->chip_info;</span><br><span style="color: hsl(120, 100%, 40%);">+                  rpc.coalesce = config->pcie_port_coalesce;</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%);">+   rp = root_port_number(dev);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rp > rpc.num_ports) {</span><br><span style="color: hsl(120, 100%, 40%);">+          printk(BIOS_ERR, "Found Root Port %d, expecting %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     rp, rpc.num_ports);</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%);">+   /* Cache pci device. */</span><br><span style="color: hsl(120, 100%, 40%);">+       rpc.ports[rp - 1] = dev;</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%);">+/* Update devicetree with new Root Port function number assignment */</span><br><span style="color: hsl(120, 100%, 40%);">+static void ich_pcie_device_set_func(int index, int pci_func)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct device *dev;</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int new_devfn;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     dev = rpc.ports[index];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Set the new PCI function field for this Root Port. */</span><br><span style="color: hsl(120, 100%, 40%);">+      rpc.new_rpfn &= ~RPFN_FNMASK(index);</span><br><span style="color: hsl(120, 100%, 40%);">+      rpc.new_rpfn |= RPFN_FNSET(index, pci_func);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Determine the new devfn for this port */</span><br><span style="color: hsl(120, 100%, 40%);">+   new_devfn = PCI_DEVFN(ICH_PCIE_DEV_SLOT, pci_func);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (dev->path.pci.devfn != new_devfn) {</span><br><span style="color: hsl(120, 100%, 40%);">+            printk(BIOS_DEBUG,</span><br><span style="color: hsl(120, 100%, 40%);">+                   "ICH: PCIe map %02x.%1x -> %02x.%1x\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                  PCI_SLOT(dev->path.pci.devfn),</span><br><span style="color: hsl(120, 100%, 40%);">+                     PCI_FUNC(dev->path.pci.devfn),</span><br><span style="color: hsl(120, 100%, 40%);">+                     PCI_SLOT(new_devfn), PCI_FUNC(new_devfn));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           dev->path.pci.devfn = new_devfn;</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%);">+static void root_port_commit_config(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* If the first root port is disabled the coalesce ports. */</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!rpc.ports[0]->enabled)</span><br><span style="color: hsl(120, 100%, 40%);">+                rpc.coalesce = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   for (i = 0; i < rpc.num_ports; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+              struct device *dev;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         dev = rpc.ports[i];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         if (dev == NULL) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    printk(BIOS_ERR, "Root Port %d device is NULL?\n", i+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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (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%);">+           printk(BIOS_DEBUG, "%s: Disabling device\n",  dev_path(dev));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             /* Disable this device if possible */</span><br><span style="color: hsl(120, 100%, 40%);">+         i82801gx_enable(dev);</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%);">+   if (rpc.coalesce) {</span><br><span style="color: hsl(120, 100%, 40%);">+           int current_func;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* For all Root Ports N enabled ports get assigned the lower</span><br><span style="color: hsl(120, 100%, 40%);">+           * PCI function number. The disabled ones get upper PCI</span><br><span style="color: hsl(120, 100%, 40%);">+                * function numbers. */</span><br><span style="color: hsl(120, 100%, 40%);">+               current_func = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             for (i = 0; i < rpc.num_ports; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (!rpc.ports[i]->enabled)</span><br><span style="color: hsl(120, 100%, 40%);">+                                continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                     ich_pcie_device_set_func(i, current_func);</span><br><span style="color: hsl(120, 100%, 40%);">+                    current_func++;</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%);">+           /* Allocate the disabled devices' PCI function number. */</span><br><span style="color: hsl(120, 100%, 40%);">+         for (i = 0; i < rpc.num_ports; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (rpc.ports[i]->enabled)</span><br><span style="color: hsl(120, 100%, 40%);">+                         continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                     ich_pcie_device_set_func(i, current_func);</span><br><span style="color: hsl(120, 100%, 40%);">+                    current_func++;</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%);">+   printk(BIOS_SPEW, "ICH: RPFN 0x%08x -> 0x%08x\n",</span><br><span style="color: hsl(120, 100%, 40%);">+               rpc.orig_rpfn, rpc.new_rpfn);</span><br><span style="color: hsl(120, 100%, 40%);">+  RCBA32(RPFN) = rpc.new_rpfn;</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%);">+static void ich_pcie_enable(struct device *dev)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Add this device to the root port config structure. */</span><br><span style="color: hsl(120, 100%, 40%);">+      root_port_init_config(dev);</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%);">+     * When processing the last PCIe root port we can now</span><br><span style="color: hsl(120, 100%, 40%);">+  * update the Root Port Function Number and Hide register.</span><br><span style="color: hsl(120, 100%, 40%);">+     */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (root_port_is_last(dev))</span><br><span style="color: hsl(120, 100%, 40%);">+           root_port_commit_config();</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> static void pcie_set_subsystem(struct device *dev, unsigned int vendor,</span><br><span>                                unsigned int device)</span><br><span> {</span><br><span>@@ -111,6 +264,7 @@</span><br><span>       .set_resources          = pci_dev_set_resources,</span><br><span>     .enable_resources       = pci_bus_enable_resources,</span><br><span>  .init                   = pci_init,</span><br><span style="color: hsl(120, 100%, 40%);">+   .enable                 = ich_pcie_enable,</span><br><span>   .scan_bus               = pci_scan_bridge,</span><br><span>   .ops_pci                = &pci_ops,</span><br><span> };</span><br><span></span><br></pre><p>To view, visit <a href="https://review.coreboot.org/c/coreboot/+/30320">change 30320</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/c/coreboot/+/30320"/><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-Change-Id: I6d7ddef96e4f45e163f7017175398a0938a18273 </div>
<div style="display:none"> Gerrit-Change-Number: 30320 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Arthur Heymans <arthur@aheymans.xyz> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>