]> Pileus Git - ~andy/linux/blobdiff - drivers/net/ixgbe/ixgbe_main.c
ixgbe: Fixup the watchdog interrupt scheduling on 82599
[~andy/linux] / drivers / net / ixgbe / ixgbe_main.c
index 76fd5c6db02b4a7852137f4b4babdebed5316e41..0956be7c74889c22322486477bf020dbb4e2dc95 100644 (file)
@@ -251,6 +251,8 @@ static void ixgbe_tx_timeout(struct net_device *netdev);
  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
  * @adapter: board private structure
  * @tx_ring: tx ring to clean
+ *
+ * returns true if transmit work is done
  **/
 static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter,
                                struct ixgbe_ring *tx_ring)
@@ -266,7 +268,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter,
        eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
 
        while ((eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)) &&
-              (count < tx_ring->count)) {
+              (count < tx_ring->work_limit)) {
                bool cleaned = false;
                for ( ; !cleaned; count++) {
                        struct sk_buff *skb;
@@ -328,8 +330,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter,
        }
 
        /* re-arm the interrupt */
-       if ((total_packets >= tx_ring->work_limit) ||
-           (count == tx_ring->count))
+       if (count >= tx_ring->work_limit)
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, tx_ring->v_idx);
 
        tx_ring->total_bytes += total_bytes;
@@ -338,7 +339,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter,
        tx_ring->stats.bytes += total_bytes;
        adapter->net_stats.tx_bytes += total_bytes;
        adapter->net_stats.tx_packets += total_packets;
-       return (total_packets ? true : false);
+       return (count < tx_ring->work_limit);
 }
 
 #ifdef CONFIG_IXGBE_DCA
@@ -778,7 +779,8 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
 
        q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
 
-       /* Populate the IVAR table and set the ITR values to the
+       /*
+        * Populate the IVAR table and set the ITR values to the
         * corresponding register.
         */
        for (v_idx = 0; v_idx < q_vectors; v_idx++) {
@@ -813,7 +815,7 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
                        q_vector->eitr = adapter->eitr_param;
 
                /*
-                * since ths is initial set up don't need to call
+                * since this is initial set up don't need to call
                 * ixgbe_write_eitr helper
                 */
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(v_idx),
@@ -1431,27 +1433,6 @@ static void ixgbe_set_itr(struct ixgbe_adapter *adapter)
        return;
 }
 
-/**
- * ixgbe_irq_disable - Mask off interrupt generation on the NIC
- * @adapter: board private structure
- **/
-static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter)
-{
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0);
-       if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
-               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), ~0);
-               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(2), ~0);
-       }
-       IXGBE_WRITE_FLUSH(&adapter->hw);
-       if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
-               int i;
-               for (i = 0; i < adapter->num_msix_vectors; i++)
-                       synchronize_irq(adapter->msix_entries[i].vector);
-       } else {
-               synchronize_irq(adapter->pdev->irq);
-       }
-}
-
 /**
  * ixgbe_irq_enable - Enable default interrupt generation settings
  * @adapter: board private structure
@@ -1463,6 +1444,7 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter)
        if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE)
                mask |= IXGBE_EIMS_GPI_SDP1;
        if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
+               mask |= IXGBE_EIMS_ECC;
                mask |= IXGBE_EIMS_GPI_SDP1;
                mask |= IXGBE_EIMS_GPI_SDP2;
        }
@@ -1593,6 +1575,39 @@ static void ixgbe_free_irq(struct ixgbe_adapter *adapter)
        }
 }
 
+/**
+ * ixgbe_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ **/
+static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter)
+{
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0);
+       if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), ~0);
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(2), ~0);
+       }
+       IXGBE_WRITE_FLUSH(&adapter->hw);
+       if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
+               int i;
+               for (i = 0; i < adapter->num_msix_vectors; i++)
+                       synchronize_irq(adapter->msix_entries[i].vector);
+       } else {
+               synchronize_irq(adapter->pdev->irq);
+       }
+}
+
+static inline void ixgbe_irq_enable_queues(struct ixgbe_adapter *adapter)
+{
+       u32 mask = IXGBE_EIMS_RTX_QUEUE;
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask);
+       if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(1), mask << 16);
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(2),
+                               (mask << 16 | mask));
+       }
+       /* skip the flush */
+}
+
 /**
  * ixgbe_configure_msi_and_legacy - Initialize PIN (INTA...) and MSI interrupts
  *
@@ -1794,12 +1809,9 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
                 * effects of setting this bit are only that SRRCTL must be
                 * fully programmed [0..15]
                 */
-               if (adapter->flags &
-                   (IXGBE_FLAG_RSS_ENABLED | IXGBE_FLAG_VMDQ_ENABLED)) {
-                       rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
-                       rdrxctl |= IXGBE_RDRXCTL_MVMEN;
-                       IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl);
-               }
+               rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
+               rdrxctl |= IXGBE_RDRXCTL_MVMEN;
+               IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl);
        }
 
        /* Program MRQC for the distribution of queues */
@@ -1836,16 +1848,17 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
                for (i = 0; i < 10; i++)
                        IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), seed[i]);
 
-               mrqc = IXGBE_MRQC_RSSEN
+               if (hw->mac.type == ixgbe_mac_82598EB)
+                       mrqc |= IXGBE_MRQC_RSSEN;
                    /* Perform hash on these packet types */
-                      | IXGBE_MRQC_RSS_FIELD_IPV4
-                      | IXGBE_MRQC_RSS_FIELD_IPV4_TCP
-                      | IXGBE_MRQC_RSS_FIELD_IPV4_UDP
-                      | IXGBE_MRQC_RSS_FIELD_IPV6
-                      | IXGBE_MRQC_RSS_FIELD_IPV6_TCP
-                      | IXGBE_MRQC_RSS_FIELD_IPV6_UDP;
-               IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
+               mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4
+                     | IXGBE_MRQC_RSS_FIELD_IPV4_TCP
+                     | IXGBE_MRQC_RSS_FIELD_IPV4_UDP
+                     | IXGBE_MRQC_RSS_FIELD_IPV6
+                     | IXGBE_MRQC_RSS_FIELD_IPV6_TCP
+                     | IXGBE_MRQC_RSS_FIELD_IPV6_UDP;
        }
+       IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
 
        rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
 
@@ -2339,8 +2352,6 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
        else
                ixgbe_configure_msi_and_legacy(adapter);
 
-       ixgbe_napi_add_all(adapter);
-
        clear_bit(__IXGBE_DOWN, &adapter->state);
        ixgbe_napi_enable_all(adapter);
 
@@ -2397,6 +2408,8 @@ int ixgbe_up(struct ixgbe_adapter *adapter)
        /* hardware has been reset, we need to reload some things */
        ixgbe_configure(adapter);
 
+       ixgbe_napi_add_all(adapter);
+
        return ixgbe_up_complete(adapter);
 }
 
@@ -2458,8 +2471,10 @@ static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter,
        rx_ring->next_to_clean = 0;
        rx_ring->next_to_use = 0;
 
-       writel(0, adapter->hw.hw_addr + rx_ring->head);
-       writel(0, adapter->hw.hw_addr + rx_ring->tail);
+       if (rx_ring->head)
+               writel(0, adapter->hw.hw_addr + rx_ring->head);
+       if (rx_ring->tail)
+               writel(0, adapter->hw.hw_addr + rx_ring->tail);
 }
 
 /**
@@ -2490,8 +2505,10 @@ static void ixgbe_clean_tx_ring(struct ixgbe_adapter *adapter,
        tx_ring->next_to_use = 0;
        tx_ring->next_to_clean = 0;
 
-       writel(0, adapter->hw.hw_addr + tx_ring->head);
-       writel(0, adapter->hw.hw_addr + tx_ring->tail);
+       if (tx_ring->head)
+               writel(0, adapter->hw.hw_addr + tx_ring->head);
+       if (tx_ring->tail)
+               writel(0, adapter->hw.hw_addr + tx_ring->tail);
 }
 
 /**
@@ -2554,6 +2571,11 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
                IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j),
                                (txdctl & ~IXGBE_TXDCTL_ENABLE));
        }
+       /* Disable the Tx DMA engine on 82599 */
+       if (hw->mac.type == ixgbe_mac_82599EB)
+               IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL,
+                               (IXGBE_READ_REG(hw, IXGBE_DMATXCTL) &
+                                ~IXGBE_DMATXCTL_TE));
 
        netif_carrier_off(netdev);
 
@@ -2590,10 +2612,10 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
  **/
 static int ixgbe_poll(struct napi_struct *napi, int budget)
 {
-       struct ixgbe_q_vector *q_vector = container_of(napi,
-                                                 struct ixgbe_q_vector, napi);
+       struct ixgbe_q_vector *q_vector =
+                               container_of(napi, struct ixgbe_q_vector, napi);
        struct ixgbe_adapter *adapter = q_vector->adapter;
-       int tx_cleaned, work_done = 0;
+       int tx_clean_complete, work_done = 0;
 
 #ifdef CONFIG_IXGBE_DCA
        if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) {
@@ -2602,10 +2624,10 @@ static int ixgbe_poll(struct napi_struct *napi, int budget)
        }
 #endif
 
-       tx_cleaned = ixgbe_clean_tx_irq(adapter, adapter->tx_ring);
+       tx_clean_complete = ixgbe_clean_tx_irq(adapter, adapter->tx_ring);
        ixgbe_clean_rx_irq(q_vector, adapter->rx_ring, &work_done, budget);
 
-       if (tx_cleaned)
+       if (!tx_clean_complete)
                work_done = budget;
 
        /* If budget not fully consumed, exit the polling mode */
@@ -2614,7 +2636,7 @@ static int ixgbe_poll(struct napi_struct *napi, int budget)
                if (adapter->itr_setting & 1)
                        ixgbe_set_itr(adapter);
                if (!test_bit(__IXGBE_DOWN, &adapter->state))
-                       ixgbe_irq_enable(adapter);
+                       ixgbe_irq_enable_queues(adapter);
        }
        return work_done;
 }
@@ -2666,6 +2688,14 @@ static inline bool ixgbe_set_dcb_queues(struct ixgbe_adapter *adapter)
 }
 #endif
 
+/**
+ * ixgbe_set_rss_queues: Allocate queues for RSS
+ * @adapter: board private structure to initialize
+ *
+ * This is our "base" multiqueue mode.  RSS (Receive Side Scaling) will try
+ * to allocate one Rx queue per CPU, and if available, one Tx queue per CPU.
+ *
+ **/
 static inline bool ixgbe_set_rss_queues(struct ixgbe_adapter *adapter)
 {
        bool ret = false;
@@ -2684,6 +2714,17 @@ static inline bool ixgbe_set_rss_queues(struct ixgbe_adapter *adapter)
        return ret;
 }
 
+/*
+ * ixgbe_set_num_queues: Allocate queues for device, feature dependant
+ * @adapter: board private structure to initialize
+ *
+ * This is the top level queue allocation routine.  The order here is very
+ * important, starting with the "most" number of features turned on at once,
+ * and ending with the smallest set of features.  This way large combinations
+ * can be allocated if they're turned on, and smaller combinations are the
+ * fallthrough conditions.
+ *
+ **/
 static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter)
 {
        /* Start with base case */
@@ -2847,7 +2888,8 @@ static void ixgbe_cache_ring_register(struct ixgbe_adapter *adapter)
  * @adapter: board private structure to initialize
  *
  * We allocate one ring per queue at run-time since we don't know the
- * number of queues at compile-time.
+ * number of queues at compile-time.  The polling_netdev array is
+ * intended for Multiqueue, but should work fine with a single queue.
  **/
 static int ixgbe_alloc_queues(struct ixgbe_adapter *adapter)
 {
@@ -3026,7 +3068,8 @@ static void ixgbe_sfp_timer(unsigned long data)
 {
        struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data;
 
-       /* Do the sfp_timer outside of interrupt context due to the
+       /*
+        * Do the sfp_timer outside of interrupt context due to the
         * delays that sfp+ detection requires
         */
        schedule_work(&adapter->sfp_task);
@@ -3327,7 +3370,8 @@ static void ixgbe_free_all_tx_resources(struct ixgbe_adapter *adapter)
        int i;
 
        for (i = 0; i < adapter->num_tx_queues; i++)
-               ixgbe_free_tx_resources(adapter, &adapter->tx_ring[i]);
+               if (adapter->tx_ring[i].desc)
+                       ixgbe_free_tx_resources(adapter, &adapter->tx_ring[i]);
 }
 
 /**
@@ -3363,7 +3407,8 @@ static void ixgbe_free_all_rx_resources(struct ixgbe_adapter *adapter)
        int i;
 
        for (i = 0; i < adapter->num_rx_queues; i++)
-               ixgbe_free_rx_resources(adapter, &adapter->rx_ring[i]);
+               if (adapter->rx_ring[i].desc)
+                       ixgbe_free_rx_resources(adapter, &adapter->rx_ring[i]);
 }
 
 /**
@@ -3426,6 +3471,8 @@ static int ixgbe_open(struct net_device *netdev)
 
        ixgbe_configure(adapter);
 
+       ixgbe_napi_add_all(adapter);
+
        err = ixgbe_request_irq(adapter);
        if (err)
                goto err_req_irq;
@@ -3480,6 +3527,7 @@ static int ixgbe_close(struct net_device *netdev)
 /**
  * ixgbe_napi_add_all - prep napi structs for use
  * @adapter: private struct
+ *
  * helper function to napi_add each possible q_vector->napi
  */
 void ixgbe_napi_add_all(struct ixgbe_adapter *adapter)
@@ -3552,7 +3600,6 @@ static int ixgbe_resume(struct pci_dev *pdev)
                return err;
        }
 
-       ixgbe_napi_add_all(adapter);
        ixgbe_reset(adapter);
 
        if (netif_running(netdev)) {
@@ -3596,6 +3643,7 @@ static int ixgbe_suspend(struct pci_dev *pdev, pm_message_t state)
        retval = pci_save_state(pdev);
        if (retval)
                return retval;
+
 #endif
        if (wufc) {
                ixgbe_set_rx_mode(netdev);
@@ -3770,17 +3818,54 @@ static void ixgbe_watchdog(unsigned long data)
        /* Do the watchdog outside of interrupt context due to the lovely
         * delays that some of the newer hardware requires */
        if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
+               u64 eics = 0;
+               int i;
+
+               for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++)
+                       eics |= (1 << i);
+
                /* Cause software interrupt to ensure rx rings are cleaned */
-               if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
-                       u32 eics =
-                        (1 << (adapter->num_msix_vectors - NON_Q_VECTORS)) - 1;
-                       IXGBE_WRITE_REG(hw, IXGBE_EICS, eics);
-               } else {
-                       /* For legacy and MSI interrupts don't set any bits that
-                        * are enabled for EIAM, because this operation would
-                        * set *both* EIMS and EICS for any bit in EIAM */
-                       IXGBE_WRITE_REG(hw, IXGBE_EICS,
-                                    (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER));
+               switch (hw->mac.type) {
+               case ixgbe_mac_82598EB:
+                       if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
+                               IXGBE_WRITE_REG(hw, IXGBE_EICS, (u32)eics);
+                       } else {
+                               /*
+                                * for legacy and MSI interrupts don't set any
+                                * bits that are enabled for EIAM, because this
+                                * operation would set *both* EIMS and EICS for
+                                * any bit in EIAM
+                                */
+                               IXGBE_WRITE_REG(hw, IXGBE_EICS,
+                                    (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER));
+                       }
+                       break;
+               case ixgbe_mac_82599EB:
+                       if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
+                               /*
+                                * EICS(0..15) first 0-15 q vectors
+                                * EICS[1] (16..31) q vectors 16-31
+                                * EICS[2] (0..31) q vectors 32-63
+                                */
+                               IXGBE_WRITE_REG(hw, IXGBE_EICS,
+                                               (u32)(eics & 0xFFFF));
+                               IXGBE_WRITE_REG(hw, IXGBE_EICS_EX(1),
+                                               (u32)(eics & 0xFFFF0000));
+                               IXGBE_WRITE_REG(hw, IXGBE_EICS_EX(2),
+                                               (u32)(eics >> 32));
+                       } else {
+                               /*
+                                * for legacy and MSI interrupts don't set any
+                                * bits that are enabled for EIAM, because this
+                                * operation would set *both* EIMS and EICS for
+                                * any bit in EIAM
+                                */
+                               IXGBE_WRITE_REG(hw, IXGBE_EICS,
+                                    (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER));
+                       }
+                       break;
+               default:
+                       break;
                }
                /* Reset the timer */
                mod_timer(&adapter->watchdog_timer,
@@ -4366,6 +4451,7 @@ static const struct net_device_ops ixgbe_netdev_ops = {
        .ndo_stop               = ixgbe_close,
        .ndo_start_xmit         = ixgbe_xmit_frame,
        .ndo_get_stats          = ixgbe_get_stats,
+       .ndo_set_rx_mode        = ixgbe_set_rx_mode,
        .ndo_set_multicast_list = ixgbe_set_rx_mode,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_mac_address    = ixgbe_set_mac,
@@ -4786,7 +4872,7 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev)
                pci_enable_wake(pdev, PCI_D3cold, 0);
 
                ixgbe_reset(adapter);
-
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_WUS, ~0);
                result = PCI_ERS_RESULT_RECOVERED;
        }