From 8a9474122e8956f836ac6863fd4ac5bdb2989159 Mon Sep 17 00:00:00 2001 From: yongari Date: Fri, 29 Dec 2006 03:33:33 +0000 Subject: Fix MSI support. Now it correctly allocates SYS_RES_IRQ resources on Yukon II which reports it can handle two messages. Submitted by: jhb Tested by: bms --- sys/dev/msk/if_msk.c | 76 +++++++++++++++++++++++++++++++++---------------- sys/dev/msk/if_mskreg.h | 6 ++-- 2 files changed, 55 insertions(+), 27 deletions(-) (limited to 'sys/dev') diff --git a/sys/dev/msk/if_msk.c b/sys/dev/msk/if_msk.c index 2b2fe6d..c7fb1f6 100644 --- a/sys/dev/msk/if_msk.c +++ b/sys/dev/msk/if_msk.c @@ -339,16 +339,25 @@ DRIVER_MODULE(miibus, msk, miibus_driver, miibus_devclass, 0, 0); static struct resource_spec msk_res_spec_io[] = { { SYS_RES_IOPORT, PCIR_BAR(1), RF_ACTIVE }, - { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE }, { -1, 0, 0 } }; static struct resource_spec msk_res_spec_mem[] = { { SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE }, + { -1, 0, 0 } +}; + +static struct resource_spec msk_irq_spec_legacy[] = { { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE }, { -1, 0, 0 } }; +static struct resource_spec msk_irq_spec_msi[] = { + { SYS_RES_IRQ, 1, RF_ACTIVE }, + { SYS_RES_IRQ, 2, RF_ACTIVE }, + { -1, 0, 0 } +}; + static int msk_miibus_readreg(device_t dev, int phy, int reg) { @@ -1546,25 +1555,7 @@ mskc_attach(device_t dev) */ pci_enable_busmaster(dev); - /* Allocate resources */ - sc->msk_msi = 0; - msic = pci_msi_count(dev); - if (bootverbose) - device_printf(dev, "MSI count : %d\n", msic); - /* - * Due to a unknown reason Yukon II reports it can handle two - * messages even if it can handle just one message. Forcing - * to allocate 1 message seems to work but reloading kernel - * module after unloading the driver fails. Only use MSI when - * it reports 1 message until we have better understanding - * for the hardware. - */ - if (msic == 1 && msi_disable == 0 && pci_alloc_msi(dev, &msic) == 0) { - sc->msk_msi = 1; - /* Set rid to 1 for SYS_RES_IRQ to use MSI. */ - msk_res_spec_io[1].rid = 1; - msk_res_spec_mem[1].rid = 1; - } + /* Allocate I/O resource */ #ifdef MSK_USEIOSPACE sc->msk_res_spec = msk_res_spec_io; #else @@ -1710,6 +1701,36 @@ mskc_attach(device_t dev) sc->msk_hw_feature = 0; } + /* Allocate IRQ resources. */ + msic = pci_msi_count(dev); + if (bootverbose) + device_printf(dev, "MSI count : %d\n", msic); + /* + * The Yukon II reports it can handle two messages, one for each + * possible port. We go ahead and allocate two messages and only + * setup a handler for both if we have a dual port card. + * + * XXX: I haven't untangled the interrupt handler to handle dual + * port cards with separate MSI messages, so for now I disable MSI + * on dual port cards. + */ + if (msic == 2 && msi_disable == 0 && sc->msk_num_port == 1 && + pci_alloc_msi(dev, &msic) == 0) { + if (msic == 2) { + sc->msk_msi = 1; + sc->msk_irq_spec = msk_irq_spec_msi; + } else { + pci_release_msi(dev); + sc->msk_irq_spec = msk_irq_spec_legacy; + } + } + + error = bus_alloc_resources(dev, sc->msk_irq_spec, sc->msk_irq); + if (error) { + device_printf(dev, "couldn't allocate IRQ resources\n"); + goto fail; + } + if ((error = msk_status_dma_alloc(sc)) != 0) goto fail; @@ -1770,8 +1791,8 @@ mskc_attach(device_t dev) taskqueue_start_threads(&sc->msk_tq, 1, PI_NET, "%s taskq", device_get_nameunit(sc->msk_dev)); /* Hook interrupt last to avoid having to lock softc. */ - error = bus_setup_intr(dev, sc->msk_res[1], INTR_TYPE_NET | - INTR_MPSAFE | INTR_FAST, msk_intr, sc, &sc->msk_intrhand); + error = bus_setup_intr(dev, sc->msk_irq[0], INTR_TYPE_NET | + INTR_MPSAFE | INTR_FAST, msk_intr, sc, &sc->msk_intrhand[0]); if (error != 0) { device_printf(dev, "couldn't set up interrupt handler\n"); @@ -1884,10 +1905,15 @@ mskc_detach(device_t dev) taskqueue_free(sc->msk_tq); sc->msk_tq = NULL; } - if (sc->msk_intrhand) { - bus_teardown_intr(dev, sc->msk_res[1], sc->msk_intrhand); - sc->msk_intrhand = NULL; + if (sc->msk_intrhand[0]) { + bus_teardown_intr(dev, sc->msk_irq[0], sc->msk_intrhand[0]); + sc->msk_intrhand[0] = NULL; + } + if (sc->msk_intrhand[1]) { + bus_teardown_intr(dev, sc->msk_irq[0], sc->msk_intrhand[0]); + sc->msk_intrhand[1] = NULL; } + bus_release_resources(dev, sc->msk_irq_spec, sc->msk_irq); if (sc->msk_msi) pci_release_msi(dev); bus_release_resources(dev, sc->msk_res_spec, sc->msk_res); diff --git a/sys/dev/msk/if_mskreg.h b/sys/dev/msk/if_mskreg.h index e9208e5..dd061d7 100644 --- a/sys/dev/msk/if_mskreg.h +++ b/sys/dev/msk/if_mskreg.h @@ -2314,9 +2314,11 @@ struct msk_if_softc; /* Softc for the Marvell Yukon II controller. */ struct msk_softc { - struct resource *msk_res[2]; /* I/O and IRQ resources */ + struct resource *msk_res[1]; /* I/O resource */ struct resource_spec *msk_res_spec; - void *msk_intrhand; /* irq handler handle */ + struct resource *msk_irq[2]; /* IRQ resources */ + struct resource_spec *msk_irq_spec; + void *msk_intrhand[2]; /* irq handler handle */ device_t msk_dev; uint8_t msk_hw_id; uint8_t msk_hw_rev; -- cgit v1.1