ixgbe: Remove the multicast spinlock
[dragonfly.git] / sys / dev / netif / ixgbe / ixgbe.c
index 91edb57..2361af6 100644 (file)
@@ -30,7 +30,7 @@
   POSSIBILITY OF SUCH DAMAGE.
 
 ******************************************************************************/
-/*$FreeBSD: src/sys/dev/ixgbe/ixgbe.c,v 1.69 2012/06/07 22:57:26 emax Exp $*/
+/*$FreeBSD: src/sys/dev/ixgbe/ixgbe.c,v 1.70 2012/07/05 20:51:44 jfv Exp $*/
 
 #include "opt_inet.h"
 #include "opt_inet6.h"
@@ -45,7 +45,7 @@ int             ixgbe_display_debug_stats = 0;
 /*********************************************************************
  *  Driver version
  *********************************************************************/
-char ixgbe_driver_version[] = "2.4.5";
+char ixgbe_driver_version[] = "2.4.8";
 
 /*********************************************************************
  *  PCI Device ID Table
@@ -78,8 +78,10 @@ static ixgbe_vendor_info_t ixgbe_vendor_info_array[] =
        {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_T3_LOM, 0, 0, 0},
        {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_COMBO_BACKPLANE, 0, 0, 0},
        {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_BACKPLANE_FCOE, 0, 0, 0},
+       {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_SF2, 0, 0, 0},
        {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_FCOE, 0, 0, 0},
        {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599EN_SFP, 0, 0, 0},
+       {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540T1, 0, 0, 0},
        {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540T, 0, 0, 0},
        /* required last entry */
        {0, 0, 0, 0, 0}
@@ -246,10 +248,6 @@ TUNABLE_INT("hw.ixgbe.max_interrupt_rate", &ixgbe_max_interrupt_rate);
 static int ixgbe_rx_process_limit = 128;
 TUNABLE_INT("hw.ixgbe.rx_process_limit", &ixgbe_rx_process_limit);
 
-/* Flow control setting, default to full */
-static int ixgbe_flow_control = ixgbe_fc_full;
-TUNABLE_INT("hw.ixgbe.flow_control", &ixgbe_flow_control);
-
 /*
 ** Smart speed setting, default to on
 ** this only works as a compile option
@@ -259,6 +257,9 @@ TUNABLE_INT("hw.ixgbe.flow_control", &ixgbe_flow_control);
 */
 static int ixgbe_smart_speed = ixgbe_smart_speed_on;
 
+static int ixgbe_msi_enable = 1;
+TUNABLE_INT("hw.ixgbe.msi.enable", &ixgbe_msi_enable);
+
 /*
  * MSIX should be the default for best performance,
  * but this allows it to be forced off for testing.
@@ -417,7 +418,6 @@ ixgbe_attach(device_t dev)
 
        /* Core Lock Init*/
        IXGBE_CORE_LOCK_INIT(adapter, device_get_nameunit(dev));
-       spin_init(&adapter->mcast_spin);
 
        /* SYSCTL APIs */
 
@@ -455,8 +455,6 @@ ixgbe_attach(device_t dev)
                        0, ixgbe_set_thermal_test, "I", "Thermal Test");
 
        /* Set up the timer callout */
-       /* XXX: shouldn't this be a spin lock ? */
-       lockinit(&adapter->core_lock, "ixgbe core lock", 0, LK_CANRECURSE);
        callout_init(&adapter->timer);
 
        /* Determine hardware revision */
@@ -541,28 +539,25 @@ ixgbe_attach(device_t dev)
                goto err_late;
        }
 
-       /* Get Hardware Flow Control setting */
-       hw->fc.requested_mode = ixgbe_fc_full;
-       adapter->fc = hw->fc.requested_mode;
-       hw->fc.pause_time = IXGBE_FC_PAUSE;
-       hw->fc.low_water = IXGBE_FC_LO;
-       hw->fc.high_water[0] = IXGBE_FC_HI;
-       hw->fc.send_xon = TRUE;
-
        error = ixgbe_init_hw(hw);
-       if (error == IXGBE_ERR_EEPROM_VERSION) {
+       switch (error) {
+       case IXGBE_ERR_EEPROM_VERSION:
                device_printf(dev, "This device is a pre-production adapter/"
                    "LOM.  Please be aware there may be issues associated "
                    "with your hardware.\n If you are experiencing problems "
                    "please contact your Intel or hardware representative "
                    "who provided you with this hardware.\n");
-       } else if (error == IXGBE_ERR_SFP_NOT_SUPPORTED)
+               break;
+       case IXGBE_ERR_SFP_NOT_SUPPORTED:
                device_printf(dev,"Unsupported SFP+ Module\n");
-
-       if (error) {
                error = EIO;
                device_printf(dev,"Hardware Initialization Failure\n");
                goto err_late;
+       case IXGBE_ERR_SFP_NOT_PRESENT:
+               device_printf(dev,"No SFP+ Module found\n");
+               /* falls thru */
+       default:
+               break;
        }
 
        /* Detect and set physical type */
@@ -713,7 +708,6 @@ ixgbe_detach(device_t dev)
        kfree(adapter->mta, M_DEVBUF);
        sysctl_ctx_free(&adapter->sysctl_ctx);
        
-       spin_uninit(&adapter->mcast_spin);
        IXGBE_CORE_LOCK_DESTROY(adapter);
        return (0);
 }
@@ -1269,7 +1263,7 @@ ixgbe_init_locked(struct adapter *adapter)
 #ifdef IXGBE_FDIR
        /* Init Flow director */
        if (hw->mac.type != ixgbe_mac_82598EB) {
-               u32 hdrm = 64 << fdir_pballoc;
+               u32 hdrm = 32 << fdir_pballoc;
 
                hw->mac.ops.setup_rxpba(hw, 0, hdrm, PBA_STRATEGY_EQUAL);
                ixgbe_init_fdir_signature_82599(&adapter->hw, fdir_pballoc);
@@ -1295,6 +1289,35 @@ ixgbe_init_locked(struct adapter *adapter)
        /* Config/Enable Link */
        ixgbe_config_link(adapter);
 
+       /* Hardware Packet Buffer & Flow Control setup */
+       {
+               u32 rxpb, frame, size, tmp;
+
+               frame = adapter->max_frame_size;
+
+               /* Calculate High Water */
+               if (hw->mac.type == ixgbe_mac_X540)
+                       tmp = IXGBE_DV_X540(frame, frame);
+               else
+                       tmp = IXGBE_DV(frame, frame);
+               size = IXGBE_BT2KB(tmp);
+               rxpb = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) >> 10;
+               hw->fc.high_water[0] = rxpb - size;
+
+               /* Now calculate Low Water */
+               if (hw->mac.type == ixgbe_mac_X540)
+                       tmp = IXGBE_LOW_DV_X540(frame);
+               else
+                       tmp = IXGBE_LOW_DV(frame);
+               hw->fc.low_water[0] = IXGBE_BT2KB(tmp);
+               
+               adapter->fc = hw->fc.requested_mode = ixgbe_fc_full;
+               hw->fc.pause_time = IXGBE_FC_PAUSE;
+               hw->fc.send_xon = TRUE;
+       }
+       /* Initialize the FC settings */
+       ixgbe_start_hw(hw);
+
        /* And now turn on interrupts */
        ixgbe_enable_intr(adapter);
 
@@ -1587,10 +1610,8 @@ ixgbe_msix_link(void *arg)
                        /* This is probably overkill :) */
                        if (!atomic_cmpset_int(&adapter->fdir_reinit, 0, 1))
                                return;
-                       /* Clear the interrupt */
-                       IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_FLOW_DIR);
-                       /* Turn off the interface */
-                       adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+                       /* Disable the interrupt */
+                       IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EICR_FLOW_DIR);
                        taskqueue_enqueue(adapter->tq, &adapter->fdir_task);
                } else
 #endif
@@ -1953,7 +1974,6 @@ ixgbe_set_multi(struct adapter *adapter)
        
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, fctrl);
 
-       spin_lock(&adapter->mcast_spin);
        TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
                if (ifma->ifma_addr->sa_family != AF_LINK)
                        continue;
@@ -1962,7 +1982,6 @@ ixgbe_set_multi(struct adapter *adapter)
                    IXGBE_ETH_LENGTH_OF_ADDRESS);
                mcnt++;
        }
-       spin_unlock(&adapter->mcast_spin);
 
        update_ptr = mta;
        ixgbe_update_mc_addr_list(&adapter->hw,
@@ -2007,8 +2026,7 @@ ixgbe_local_timer(void *arg)
        struct tx_ring  *txr = adapter->tx_rings;
        int             hung, busy, paused;
 
-       lockmgr(&adapter->core_lock, LK_EXCLUSIVE);
-       KKASSERT(lockstatus(&adapter->core_lock, curthread) != 0);
+       IXGBE_CORE_LOCK(adapter);
        hung = busy = paused = 0;
 
        /* Check for pluggable optics */
@@ -2053,7 +2071,7 @@ ixgbe_local_timer(void *arg)
 out:
        ixgbe_rearm_queues(adapter, adapter->que_mask);
        callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter);
-       lockmgr(&adapter->core_lock, LK_RELEASE);
+       IXGBE_CORE_UNLOCK(adapter);
        return;
 
 watchdog:
@@ -2068,7 +2086,7 @@ watchdog:
        adapter->watchdog_events++;
        ixgbe_init_locked(adapter);
 
-       lockmgr(&adapter->core_lock, LK_RELEASE);
+       IXGBE_CORE_UNLOCK(adapter);
 }
 
 /*
@@ -2091,6 +2109,8 @@ ixgbe_update_link_status(struct adapter *adapter)
                                    ((adapter->link_speed == 128)? 10:1),
                                    "Full Duplex");
                        adapter->link_active = TRUE;
+                       /* Update any Flow Control changes */
+                       ixgbe_fc_enable(&adapter->hw);
                        ifp->if_link_state = LINK_STATE_UP;
                        if_link_state_change(ifp);
                }
@@ -2244,14 +2264,19 @@ ixgbe_allocate_legacy(struct adapter *adapter)
        device_t dev = adapter->dev;
        struct          ix_queue *que = adapter->queues;
        int error, rid = 0;
+       unsigned int intr_flags;
 
        /* MSI RID at 1 */
        if (adapter->msix == 1)
                rid = 1;
 
+       /* Try allocating a MSI interrupt first */
+       adapter->intr_type = pci_alloc_1intr(dev, ixgbe_msi_enable,
+               &rid, &intr_flags);
+
        /* We allocate a single interrupt resource */
        adapter->res = bus_alloc_resource_any(dev,
-            SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE);
+            SYS_RES_IRQ, &rid, intr_flags);
        if (adapter->res == NULL) {
                device_printf(dev, "Unable to allocate bus resource: "
                    "interrupt\n");
@@ -2546,6 +2571,8 @@ ixgbe_free_pci_resources(struct adapter * adapter)
        }
        if (adapter->res != NULL)
                bus_release_resource(dev, SYS_RES_IRQ, rid, adapter->res);
+       if (adapter->intr_type == PCI_INTR_TYPE_MSI)
+               pci_release_msi(adapter->dev);
 
 mem:
        if (adapter->msix)
@@ -3106,7 +3133,7 @@ ixgbe_initialize_transmit_units(struct adapter *adapter)
                        txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(i));
                        break;
                 }
-               txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
+               txctrl &= ~IXGBE_DCA_TXCTRL_DESC_WRO_EN;
                switch (hw->mac.type) {
                case ixgbe_mac_82598EB:
                        IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(i), txctrl);
@@ -5172,6 +5199,8 @@ ixgbe_reinit_fdir(void *context, int pending)
                return;
        ixgbe_reinit_fdir_tables_82599(&adapter->hw);
        adapter->fdir_reinit = 0;
+       /* re-enable flow director interrupts */
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_FLOW_DIR);
        /* Restart the interface */
        ifp->if_drv_flags |= IFF_DRV_RUNNING;
        return;
@@ -5732,8 +5761,9 @@ ixgbe_set_flowcntl(SYSCTL_HANDLER_ARGS)
                default:
                        adapter->hw.fc.requested_mode = ixgbe_fc_none;
        }
-
-       ixgbe_fc_enable(&adapter->hw, 0);
+       /* Don't autoneg if forcing a value */
+       adapter->hw.fc.disable_fc_autoneg = TRUE;
+       ixgbe_fc_enable(&adapter->hw);
        return error;
 }
 
@@ -5749,9 +5779,9 @@ ixgbe_add_rx_process_limit(struct adapter *adapter, const char *name,
 
 /*
 ** Control link advertise speed:
-**     0 - normal
 **     1 - advertise only 1G
 **     2 - advertise 100Mb
+**     3 - advertise normal
 */
 static int
 ixgbe_set_advertise(SYSCTL_HANDLER_ARGS)
@@ -5765,13 +5795,15 @@ ixgbe_set_advertise(SYSCTL_HANDLER_ARGS)
        adapter = (struct adapter *) arg1;
        dev = adapter->dev;
        hw = &adapter->hw;
-       last = hw->phy.autoneg_advertised;
+       last = adapter->advertise;
 
        error = sysctl_handle_int(oidp, &adapter->advertise, 0, req);
-
        if ((error) || (adapter->advertise == -1))
                return (error);
 
+       if (adapter->advertise == last) /* no change */
+               return (0);
+
        if (!((hw->phy.media_type == ixgbe_media_type_copper) ||
             (hw->phy.multispeed_fiber)))
                return (error);
@@ -5785,11 +5817,10 @@ ixgbe_set_advertise(SYSCTL_HANDLER_ARGS)
                 speed = IXGBE_LINK_SPEED_1GB_FULL;
        else if (adapter->advertise == 2)
                 speed = IXGBE_LINK_SPEED_100_FULL;
-       else
+       else if (adapter->advertise == 3)
                 speed = IXGBE_LINK_SPEED_1GB_FULL |
                        IXGBE_LINK_SPEED_10GB_FULL;
-
-       if (speed == last) /* no change */
+       else /* bogus value */
                return (error);
 
        hw->mac.autotry_restart = TRUE;