ixgbe: Add optional DCA infrastructure
authorJeb Cramer <cramerj@intel.com>
Mon, 3 Mar 2008 23:04:02 +0000 (15:04 -0800)
committerJeff Garzik <jeff@garzik.org>
Mon, 17 Mar 2008 11:49:28 +0000 (07:49 -0400)
82598 cards and up support DCA, which enables the chipset to warm
up the caches for upcoming payload data. This code makes the
driver plug into the CONFIG_DCA infrastructure that was merged
earlier.

Signed-off-by: Jeb Cramer <cramerj@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
drivers/net/ixgbe/ixgbe.h
drivers/net/ixgbe/ixgbe_main.c

index 79f5519e2aa974337f19f1f8bf9be67e1c985fa7..d98113472a89ff1dcde99095a1b0e48450442b42 100644 (file)
@@ -36,6 +36,9 @@
 #include "ixgbe_type.h"
 #include "ixgbe_common.h"
 
+#ifdef CONFIG_DCA
+#include <linux/dca.h>
+#endif
 
 #define IXGBE_ERR(args...) printk(KERN_ERR "ixgbe: " args)
 
@@ -142,6 +145,11 @@ struct ixgbe_ring {
        u16 reg_idx; /* holds the special value that gets the hardware register
                      * offset associated with this ring, which is different
                      * for DCE and RSS modes */
+
+#ifdef CONFIG_DCA
+       /* cpu for tx queue */
+       int cpu;
+#endif
        struct ixgbe_queue_stats stats;
        u8 v_idx; /* maps directly to the index for this ring in the hardware
                   * vector array, can also be used for finding the bit in EICR
@@ -261,6 +269,7 @@ struct ixgbe_adapter {
 #define IXGBE_FLAG_IMIR_ENABLED                 (u32)(1 << 5)
 #define IXGBE_FLAG_RSS_ENABLED                  (u32)(1 << 6)
 #define IXGBE_FLAG_VMDQ_ENABLED                 (u32)(1 << 7)
+#define IXGBE_FLAG_DCA_ENABLED                  (u32)(1 << 8)
 
        /* OS defined structs */
        struct net_device *netdev;
index e1f11e686f476dd013d652f91f760048c97ebf98..da8becf9a501240ab2b9913e506d97faa518e55c 100644 (file)
@@ -80,6 +80,16 @@ static struct pci_device_id ixgbe_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, ixgbe_pci_tbl);
 
+#ifdef CONFIG_DCA
+static int ixgbe_notify_dca(struct notifier_block *, unsigned long event,
+                           void *p);
+static struct notifier_block dca_notifier = {
+       .notifier_call = ixgbe_notify_dca,
+       .next          = NULL,
+       .priority      = 0
+};
+#endif
+
 MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
 MODULE_DESCRIPTION("Intel(R) 10 Gigabit PCI Express Network Driver");
 MODULE_LICENSE("GPL");
@@ -290,6 +300,91 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter,
        return cleaned;
 }
 
+#ifdef CONFIG_DCA
+static void ixgbe_update_rx_dca(struct ixgbe_adapter *adapter,
+                               struct ixgbe_ring *rxr)
+{
+       u32 rxctrl;
+       int cpu = get_cpu();
+       int q = rxr - adapter->rx_ring;
+
+       if (rxr->cpu != cpu) {
+               rxctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_DCA_RXCTRL(q));
+               rxctrl &= ~IXGBE_DCA_RXCTRL_CPUID_MASK;
+               rxctrl |= dca_get_tag(cpu);
+               rxctrl |= IXGBE_DCA_RXCTRL_DESC_DCA_EN;
+               rxctrl |= IXGBE_DCA_RXCTRL_HEAD_DCA_EN;
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_RXCTRL(q), rxctrl);
+               rxr->cpu = cpu;
+       }
+       put_cpu();
+}
+
+static void ixgbe_update_tx_dca(struct ixgbe_adapter *adapter,
+                               struct ixgbe_ring *txr)
+{
+       u32 txctrl;
+       int cpu = get_cpu();
+       int q = txr - adapter->tx_ring;
+
+       if (txr->cpu != cpu) {
+               txctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_DCA_TXCTRL(q));
+               txctrl &= ~IXGBE_DCA_TXCTRL_CPUID_MASK;
+               txctrl |= dca_get_tag(cpu);
+               txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN;
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_TXCTRL(q), txctrl);
+               txr->cpu = cpu;
+       }
+       put_cpu();
+}
+
+static void ixgbe_setup_dca(struct ixgbe_adapter *adapter)
+{
+       int i;
+
+       if (!(adapter->flags & IXGBE_FLAG_DCA_ENABLED))
+               return;
+
+       for (i = 0; i < adapter->num_tx_queues; i++) {
+               adapter->tx_ring[i].cpu = -1;
+               ixgbe_update_tx_dca(adapter, &adapter->tx_ring[i]);
+       }
+       for (i = 0; i < adapter->num_rx_queues; i++) {
+               adapter->rx_ring[i].cpu = -1;
+               ixgbe_update_rx_dca(adapter, &adapter->rx_ring[i]);
+       }
+}
+
+static int __ixgbe_notify_dca(struct device *dev, void *data)
+{
+       struct net_device *netdev = dev_get_drvdata(dev);
+       struct ixgbe_adapter *adapter = netdev_priv(netdev);
+       unsigned long event = *(unsigned long *)data;
+
+       switch (event) {
+       case DCA_PROVIDER_ADD:
+               adapter->flags |= IXGBE_FLAG_DCA_ENABLED;
+               /* Always use CB2 mode, difference is masked
+                * in the CB driver. */
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_CTRL, 2);
+               if (dca_add_requester(dev) == IXGBE_SUCCESS) {
+                       ixgbe_setup_dca(adapter);
+                       break;
+               }
+               /* Fall Through since DCA is disabled. */
+       case DCA_PROVIDER_REMOVE:
+               if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) {
+                       dca_remove_requester(dev);
+                       adapter->flags &= ~IXGBE_FLAG_DCA_ENABLED;
+                       IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_CTRL, 1);
+               }
+               break;
+       }
+
+       return IXGBE_SUCCESS;
+}
+
+#endif /* CONFIG_DCA */
 /**
  * ixgbe_receive_skb - Send a completed packet up the stack
  * @adapter: board private structure
@@ -811,6 +906,10 @@ static irqreturn_t ixgbe_msix_clean_tx(int irq, void *data)
        r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues);
        for (i = 0; i < q_vector->txr_count; i++) {
                txr = &(adapter->tx_ring[r_idx]);
+#ifdef CONFIG_DCA
+               if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
+                       ixgbe_update_tx_dca(adapter, txr);
+#endif
                txr->total_bytes = 0;
                txr->total_packets = 0;
                ixgbe_clean_tx_irq(adapter, txr);
@@ -872,6 +971,10 @@ static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget)
 
        r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
        rxr = &(adapter->rx_ring[r_idx]);
+#ifdef CONFIG_DCA
+       if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
+               ixgbe_update_rx_dca(adapter, rxr);
+#endif
 
        ixgbe_clean_rx_irq(adapter, rxr, &work_done, budget);
 
@@ -1924,6 +2027,13 @@ static int ixgbe_poll(struct napi_struct *napi, int budget)
        struct ixgbe_adapter *adapter = q_vector->adapter;
        int tx_cleaned = 0, work_done = 0;
 
+#ifdef CONFIG_DCA
+       if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) {
+               ixgbe_update_tx_dca(adapter, adapter->tx_ring);
+               ixgbe_update_rx_dca(adapter, adapter->rx_ring);
+       }
+#endif
+
        tx_cleaned = ixgbe_clean_tx_irq(adapter, adapter->tx_ring);
        ixgbe_clean_rx_irq(adapter, adapter->rx_ring, &work_done, budget);
 
@@ -3494,6 +3604,15 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
        if (err)
                goto err_register;
 
+#ifdef CONFIG_DCA
+       if (dca_add_requester(&pdev->dev) == IXGBE_SUCCESS) {
+               adapter->flags |= IXGBE_FLAG_DCA_ENABLED;
+               /* always use CB2 mode, difference is masked
+                * in the CB driver */
+               IXGBE_WRITE_REG(hw, IXGBE_DCA_CTRL, 2);
+               ixgbe_setup_dca(adapter);
+       }
+#endif
 
        dev_info(&pdev->dev, "Intel(R) 10 Gigabit Network Connection\n");
        cards_found++;
@@ -3535,6 +3654,14 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
 
        flush_scheduled_work();
 
+#ifdef CONFIG_DCA
+       if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) {
+               adapter->flags &= ~IXGBE_FLAG_DCA_ENABLED;
+               dca_remove_requester(&pdev->dev);
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_CTRL, 1);
+       }
+
+#endif
        unregister_netdev(netdev);
 
        ixgbe_reset_interrupt_capability(adapter);
@@ -3659,6 +3786,10 @@ static int __init ixgbe_init_module(void)
 
        printk(KERN_INFO "%s: %s\n", ixgbe_driver_name, ixgbe_copyright);
 
+#ifdef CONFIG_DCA
+       dca_register_notify(&dca_notifier);
+
+#endif
        ret = pci_register_driver(&ixgbe_driver);
        return ret;
 }
@@ -3672,8 +3803,25 @@ module_init(ixgbe_init_module);
  **/
 static void __exit ixgbe_exit_module(void)
 {
+#ifdef CONFIG_DCA
+       dca_unregister_notify(&dca_notifier);
+#endif
        pci_unregister_driver(&ixgbe_driver);
 }
+
+#ifdef CONFIG_DCA
+static int ixgbe_notify_dca(struct notifier_block *nb, unsigned long event,
+                           void *p)
+{
+       int ret_val;
+
+       ret_val = driver_for_each_device(&ixgbe_driver.driver, NULL, &event,
+                                        __ixgbe_notify_dca);
+
+       return ret_val ? NOTIFY_BAD : NOTIFY_DONE;
+}
+#endif /* CONFIG_DCA */
+
 module_exit(ixgbe_exit_module);
 
 /* ixgbe_main.c */