Author: jchandra
Date: Tue Sep  7 07:31:58 2010
New Revision: 212285
URL: http://svn.freebsd.org/changeset/base/212285

Log:
  PCIe updates for XLS.
  
  Fix interrupt routing so that the irq returned is correct for XLR and
  XLS. This also updates the MSI hack we had earlier - we still don't
  really support MSI, but we support some drivers that use MSI, by providing
  support for allocating one MSI per pci link - this MSI is directly
  mapped to the link IRQ.

Modified:
  head/sys/mips/rmi/xlr_pci.c

Modified: head/sys/mips/rmi/xlr_pci.c
==============================================================================
--- head/sys/mips/rmi/xlr_pci.c Tue Sep  7 06:02:43 2010        (r212284)
+++ head/sys/mips/rmi/xlr_pci.c Tue Sep  7 07:31:58 2010        (r212285)
@@ -326,51 +326,77 @@ xlr_pcib_identify(driver_t * driver, dev
        BUS_ADD_CHILD(parent, 0, "pcib", 0);
 }
 
+/*
+ * XLS PCIe can have upto 4 links, and each link has its on IRQ
+ * Find the link on which the device is on 
+ */
 static int
-xlr_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs)
+xls_pcie_link(device_t pcib, device_t dev)
 {
-       int pciirq;
-       int i;
        device_t parent, tmp;
 
        /* find the lane on which the slot is connected to */
+       printf("xls_pcie_link : bus %s dev %s\n", device_get_nameunit(pcib),
+               device_get_nameunit(dev));
        tmp = dev;
        while (1) {
                parent = device_get_parent(tmp);
                if (parent == NULL || parent == pcib) {
                        device_printf(dev, "Cannot find parent bus\n");
-                       return (ENXIO);
+                       return (-1);
                }
                if (strcmp(device_get_nameunit(parent), "pci0") == 0)
                        break;
                tmp = parent;
        }
+       return (pci_get_slot(tmp));
+}
+
+/*
+ * Find the IRQ for the link, each link has a different interrupt 
+ * at the XLS pic
+ */
+static int
+xls_pcie_link_irq(int link)
+{
 
-       switch (pci_get_slot(tmp)) {
+       switch (link) {
        case 0:
-               pciirq = PIC_PCIE_LINK0_IRQ;
-               break;
+               return (PIC_PCIE_LINK0_IRQ);
        case 1:
-               pciirq = PIC_PCIE_LINK1_IRQ;
-               break;
+               return (PIC_PCIE_LINK1_IRQ);
        case 2:
-               pciirq = PIC_PCIE_LINK2_IRQ;
-               break;
+               return (PIC_PCIE_LINK2_IRQ);
        case 3:
-               pciirq = PIC_PCIE_LINK3_IRQ;
-               break;
-       default:
-               return (ENXIO);
+               return (PIC_PCIE_LINK3_IRQ);
        }
+       return (-1);
+}
+
+static int
+xlr_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs)
+{
+       int i, link;
 
-       irqs[0] = pciirq;
        /*
-        * For now put in some fixed values for the other requested MSI,
-        * TODO handle multiple messages
+        * Each link has 32 MSIs that can be allocated, but for now
+        * we only support one device per link.
+        * msi_alloc() equivalent is needed when we start supporting 
+        * bridges on the PCIe link.
         */
-       for (i = 1; i < count; i++)
-               irqs[i] = pciirq + 64 * i;
+       link = xls_pcie_link(pcib, dev);
+       if (link == -1)
+               return (ENXIO);
+
+       /*
+        * encode the irq so that we know it is a MSI interrupt when we
+        * setup interrupts
+        */
+       for (i = 0; i < count; i++)
+               irqs[i] = 64 + link * 32 + i;
 
+       device_printf(dev, "Alloc MSI count %d maxcount %d irq %d link %d\n",
+                       count, maxcount, i, link);
        return (0);
 }
 
@@ -383,20 +409,18 @@ xlr_release_msi(device_t pcib, device_t 
 }
 
 static int
-xlr_map_msi(device_t pcib, device_t dev, int irq, uint64_t * addr,
-    uint32_t * data)
+xlr_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr,
+    uint32_t *data)
 {
+       int msi;
 
-       switch (irq) {
-       case PIC_PCIE_LINK0_IRQ:
-       case PIC_PCIE_LINK1_IRQ:
-       case PIC_PCIE_LINK2_IRQ:
-       case PIC_PCIE_LINK3_IRQ:
+       device_printf(dev, "MAP MSI irq %d\n", irq);
+       if (irq >= 64) {
+               msi = irq - 64;
                *addr = MIPS_MSI_ADDR(0);
-               *data = MIPS_MSI_DATA(irq);
+               *data = MIPS_MSI_DATA(msi);
                return (0);
-
-       default:
+       } else {
                device_printf(dev, "%s: map_msi for irq %d  - ignored", 
                    device_get_nameunit(pcib), irq);
                return (ENXIO);
@@ -437,10 +461,8 @@ bridge_pcie_ack(int irq)
 
 static int
 mips_platform_pci_setup_intr(device_t dev, device_t child,
-    struct resource *irq, int flags,
-    driver_filter_t * filt,
-    driver_intr_t * intr, void *arg,
-    void **cookiep)
+    struct resource *irq, int flags, driver_filter_t *filt,
+    driver_intr_t *intr, void *arg, void **cookiep)
 {
        int error = 0;
        int xlrirq;
@@ -454,6 +476,8 @@ mips_platform_pci_setup_intr(device_t de
                return (EINVAL);
        }
        xlrirq = rman_get_start(irq);
+       device_printf(dev, "%s: setup intr %d\n", device_get_nameunit(child),
+                       xlrirq);
 
        if (strcmp(device_get_name(dev), "pcib") != 0)
                return (0);
@@ -463,6 +487,18 @@ mips_platform_pci_setup_intr(device_t de
                    intr, arg, PIC_PCIX_IRQ, flags, cookiep, bridge_pcix_ack);
                pic_setup_intr(PIC_IRT_PCIX_INDEX, PIC_PCIX_IRQ, 0x1, 1);
        } else {
+               /* 
+                * temporary hack for MSI, we support just one device per
+                * link, and assign the link interrupt to the device interrupt
+                */
+               if (xlrirq >= 64) {
+                       xlrirq -= 64;
+                       if (xlrirq % 32 != 0)
+                               return (0);
+                       xlrirq = xls_pcie_link_irq(xlrirq / 32);
+                       if (xlrirq == -1)
+                               return (EINVAL);
+               }
                xlr_establish_intr(device_get_name(child), filt,
                    intr, arg, xlrirq, flags, cookiep, bridge_pcie_ack);
                pic_setup_intr(xlrirq - PIC_IRQ_BASE, xlrirq, 0x1, 1);
@@ -492,6 +528,9 @@ xlr_pci_alloc_resource(device_t bus, dev
        vm_offset_t va;
        int needactivate = flags & RF_ACTIVE;
 
+       device_printf(child, "Alloc res type %d, rid %d, start %lx, end %lx, 
count %lx flags %u\n",
+                       type, *rid, start, end, count, flags);
+
        switch (type) {
        case SYS_RES_IRQ:
                rm = &irq_rman;
@@ -559,28 +598,24 @@ xlr_pci_deactivate_resource(device_t bus
 static int
 mips_pci_route_interrupt(device_t bus, device_t dev, int pin)
 {
+       int irq, link;
 
        /*
         * Validate requested pin number.
         */
+       device_printf(dev, "route intr pin %d (bus %d, slot %d)\n",
+           pin, pci_get_bus(dev), pci_get_slot(dev));
        if ((pin < 1) || (pin > 4))
                return (255);
 
        if (xlr_board_info.is_xls) {
-               switch (pin) {
-               case 1:
-                       return (PIC_PCIE_LINK0_IRQ);
-               case 2:
-                       return (PIC_PCIE_LINK1_IRQ);
-               case 3:
-                       return (PIC_PCIE_LINK2_IRQ);
-               case 4:
-                       return (PIC_PCIE_LINK3_IRQ);
-               }
+               link = xls_pcie_link(bus, dev);
+               irq = xls_pcie_link_irq(link);
+               if (irq != -1)
+                       return (irq);
        } else {
-               if (pin == 1) {
-                       return (16);
-               }
+               if (pin == 1)
+                       return (PIC_PCIX_IRQ);
        }
 
        return (255);
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to