svn commit: r212285 - head/sys/mips/rmi
Jayachandran C.
jchandra at FreeBSD.org
Tue Sep 7 07:31:58 UTC 2010
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);
More information about the svn-src-head
mailing list