emx: Use MSI, if device supports it
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Tue, 27 Dec 2011 05:43:09 +0000 (13:43 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Tue, 27 Dec 2011 05:44:43 +0000 (13:44 +0800)
sys/dev/netif/emx/if_emx.c
sys/dev/netif/emx/if_emx.h

index fe8e03c..83e7bbb 100644 (file)
@@ -276,12 +276,13 @@ DRIVER_MODULE(if_emx, pci, emx_driver, emx_devclass, NULL, NULL);
 static int     emx_int_throttle_ceil = EMX_DEFAULT_ITR;
 static int     emx_rxd = EMX_DEFAULT_RXD;
 static int     emx_txd = EMX_DEFAULT_TXD;
-static int     emx_smart_pwr_down = FALSE;
+static int     emx_smart_pwr_down = 0;
 
 /* Controls whether promiscuous also shows bad packets */
 static int     emx_debug_sbp = FALSE;
 
-static int     emx_82573_workaround = TRUE;
+static int     emx_82573_workaround = 1;
+static int     emx_msi_enable = 1;
 
 TUNABLE_INT("hw.emx.int_throttle_ceil", &emx_int_throttle_ceil);
 TUNABLE_INT("hw.emx.rxd", &emx_rxd);
@@ -289,6 +290,7 @@ TUNABLE_INT("hw.emx.txd", &emx_txd);
 TUNABLE_INT("hw.emx.smart_pwr_down", &emx_smart_pwr_down);
 TUNABLE_INT("hw.emx.sbp", &emx_debug_sbp);
 TUNABLE_INT("hw.emx.82573_workaround", &emx_82573_workaround);
+TUNABLE_INT("hw.emx.msi.enable", &emx_msi_enable);
 
 /* Global used in WOL setup with multiport cards */
 static int     emx_global_quad_port_a = 0;
@@ -398,8 +400,10 @@ emx_attach(device_t dev)
 {
        struct emx_softc *sc = device_get_softc(dev);
        struct ifnet *ifp = &sc->arpcom.ac_if;
-       int error = 0, i;
+       int error = 0, i, msi_enable;
+       u_int intr_flags;
        uint16_t eeprom_data, device_id, apme_mask;
+       char env[64];
 
        lwkt_serialize_init(&sc->main_serialize);
        lwkt_serialize_init(&sc->tx_serialize);
@@ -452,12 +456,37 @@ emx_attach(device_t dev)
        /*
         * Allocate interrupt
         */
+       msi_enable = emx_msi_enable;
+       ksnprintf(env, sizeof(env), "hw.%s.msi.enable",
+           device_get_nameunit(dev));
+       kgetenv_int(env, &msi_enable);
+
        sc->intr_rid = 0;
+       sc->intr_type = EMX_INTR_TYPE_LEGACY;
+       intr_flags = RF_SHAREABLE | RF_ACTIVE;
+
+       if (msi_enable) {
+               int cpu = -1;
+
+               ksnprintf(env, sizeof(env), "hw.%s.msi.cpu",
+                   device_get_nameunit(dev));
+               kgetenv_int(env, &cpu);
+               if (cpu >= ncpus)
+                       cpu = ncpus - 1;
+
+               if (pci_alloc_msi(dev, &sc->intr_rid, 1, cpu) == 0) {
+                       intr_flags &= ~RF_SHAREABLE;
+                       sc->intr_type = EMX_INTR_TYPE_MSI;
+               }
+       }
+
        sc->intr_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->intr_rid,
-                                             RF_SHAREABLE | RF_ACTIVE);
+           intr_flags);
        if (sc->intr_res == NULL) {
                device_printf(dev, "Unable to allocate bus resource: "
                    "interrupt\n");
+               if (sc->intr_rid != 0)
+                       pci_release_msi(dev);
                error = ENXIO;
                goto fail;
        }
@@ -686,7 +715,7 @@ emx_attach(device_t dev)
                goto fail;
        }
 
-       ifp->if_cpuid = ithread_cpuid(rman_get_start(sc->intr_res));
+       ifp->if_cpuid = rman_get_cpuid(sc->intr_res);
        KKASSERT(ifp->if_cpuid >= 0 && ifp->if_cpuid < ncpus);
        return (0);
 fail:
@@ -732,6 +761,9 @@ emx_detach(device_t dev)
                                     sc->intr_res);
        }
 
+       if (sc->intr_type == EMX_INTR_TYPE_MSI)
+               pci_release_msi(dev);
+
        if (sc->memory != NULL) {
                bus_release_resource(dev, SYS_RES_MEMORY, sc->memory_rid,
                                     sc->memory);
index af52c83..37639f9 100644 (file)
@@ -252,6 +252,7 @@ struct emx_softc {
        struct resource         *intr_res;
        void                    *intr_tag;
        int                     intr_rid;
+       int                     intr_type;
 
        struct ifmedia          media;
        struct callout          timer;
@@ -376,6 +377,9 @@ struct emx_softc {
        struct e1000_hw_stats   stats;
 };
 
+#define EMX_INTR_TYPE_LEGACY   0
+#define EMX_INTR_TYPE_MSI      1
+
 struct emx_txbuf {
        struct mbuf     *m_head;
        bus_dmamap_t    map;