cxgb3: disable high freq non-data interrupts
[safe/jmp/linux-2.6] / drivers / net / cxgb3 / cxgb3_main.c
index 9e8727c..9ff0452 100644 (file)
@@ -90,6 +90,7 @@ static const struct pci_device_id cxgb3_pci_tbl[] = {
        CH_DEVICE(0x30, 2),     /* T3B10 */
        CH_DEVICE(0x31, 3),     /* T3B20 */
        CH_DEVICE(0x32, 1),     /* T3B02 */
+       CH_DEVICE(0x35, 6),     /* T3C20-derived T3C10 */
        {0,}
 };
 
@@ -338,7 +339,7 @@ static void free_irq_resources(struct adapter *adapter)
 
                free_irq(adapter->msix_info[0].vec, adapter);
                for_each_port(adapter, i)
-                   n += adap2pinfo(adapter, i)->nqsets;
+                       n += adap2pinfo(adapter, i)->nqsets;
 
                for (i = 0; i < n; ++i)
                        free_irq(adapter->msix_info[i + 1].vec,
@@ -508,19 +509,9 @@ static void set_qset_lro(struct net_device *dev, int qset_idx, int val)
 {
        struct port_info *pi = netdev_priv(dev);
        struct adapter *adapter = pi->adapter;
-       int i, lro_on = 1;
 
        adapter->params.sge.qset[qset_idx].lro = !!val;
        adapter->sge.qs[qset_idx].lro_enabled = !!val;
-
-       /* let ethtool report LRO on only if all queues are LRO enabled */
-       for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; ++i)
-               lro_on &= adapter->params.sge.qset[i].lro;
-
-       if (lro_on)
-               dev->features |= NETIF_F_LRO;
-       else
-               dev->features &= ~NETIF_F_LRO;
 }
 
 /**
@@ -546,7 +537,7 @@ static int setup_sge_qsets(struct adapter *adap)
                pi->qs = &adap->sge.qs[pi->first_qset];
                for (j = pi->first_qset; j < pi->first_qset + pi->nqsets;
                     ++j, ++qset_idx) {
-                       set_qset_lro(dev, qset_idx, pi->rx_csum_offload);
+                       set_qset_lro(dev, qset_idx, pi->rx_offload & T3_LRO);
                        err = t3_sge_alloc_qset(adap, qset_idx, 1,
                                (adap->flags & USING_MSIX) ? qset_idx + 1 :
                                                             irq_idx,
@@ -958,21 +949,22 @@ release_tpsram:
 static int cxgb_up(struct adapter *adap)
 {
        int err;
-       int must_load;
 
        if (!(adap->flags & FULL_INIT_DONE)) {
-               err = t3_check_fw_version(adap, &must_load);
+               err = t3_check_fw_version(adap);
                if (err == -EINVAL) {
                        err = upgrade_fw(adap);
-                       if (err && must_load)
-                               goto out;
+                       CH_WARN(adap, "FW upgrade to %d.%d.%d %s\n",
+                               FW_VERSION_MAJOR, FW_VERSION_MINOR,
+                               FW_VERSION_MICRO, err ? "failed" : "succeeded");
                }
 
-               err = t3_check_tpsram_version(adap, &must_load);
+               err = t3_check_tpsram_version(adap);
                if (err == -EINVAL) {
                        err = update_tpsram(adap);
-                       if (err && must_load)
-                               goto out;
+                       CH_WARN(adap, "TP upgrade to %d.%d.%d %s\n",
+                               TP_VERSION_MAJOR, TP_VERSION_MINOR,
+                               TP_VERSION_MICRO, err ? "failed" : "succeeded");
                }
 
                /*
@@ -1432,9 +1424,9 @@ static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
        *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANINS);
        *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TX_CSUM);
        *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_RX_CSUM_GOOD);
-       *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_LRO_AGGR);
-       *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_LRO_FLUSHED);
-       *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_LRO_NO_DESC);
+       *data++ = 0;
+       *data++ = 0;
+       *data++ = 0;
        *data++ = s->rx_cong_drops;
 
        *data++ = s->num_toggled;
@@ -1574,7 +1566,6 @@ static int speed_duplex_to_caps(int speed, int duplex)
 
 static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-       int cap;
        struct port_info *p = netdev_priv(dev);
        struct link_config *lc = &p->link_config;
 
@@ -1584,7 +1575,7 @@ static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                 * being requested.
                 */
                if (cmd->autoneg == AUTONEG_DISABLE) {
-                       cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
+                       int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
                        if (lc->supported & cap)
                                return 0;
                }
@@ -1656,17 +1647,19 @@ static u32 get_rx_csum(struct net_device *dev)
 {
        struct port_info *p = netdev_priv(dev);
 
-       return p->rx_csum_offload;
+       return p->rx_offload & T3_RX_CSUM;
 }
 
 static int set_rx_csum(struct net_device *dev, u32 data)
 {
        struct port_info *p = netdev_priv(dev);
 
-       p->rx_csum_offload = data;
-       if (!data) {
+       if (data) {
+               p->rx_offload |= T3_RX_CSUM;
+       } else {
                int i;
 
+               p->rx_offload &= ~(T3_RX_CSUM | T3_LRO);
                for (i = p->first_qset; i < p->first_qset + p->nqsets; i++)
                        set_qset_lro(dev, i, 0);
        }
@@ -1823,25 +1816,6 @@ static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        memset(&wol->sopass, 0, sizeof(wol->sopass));
 }
 
-static int cxgb3_set_flags(struct net_device *dev, u32 data)
-{
-       struct port_info *pi = netdev_priv(dev);
-       int i;
-
-       if (data & ETH_FLAG_LRO) {
-               if (!pi->rx_csum_offload)
-                       return -EINVAL;
-
-               for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; i++)
-                       set_qset_lro(dev, i, 1);
-
-       } else
-               for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; i++)
-                       set_qset_lro(dev, i, 0);
-
-       return 0;
-}
-
 static const struct ethtool_ops cxgb_ethtool_ops = {
        .get_settings = get_settings,
        .set_settings = set_settings,
@@ -1871,8 +1845,6 @@ static const struct ethtool_ops cxgb_ethtool_ops = {
        .get_regs = get_regs,
        .get_wol = get_wol,
        .set_tso = ethtool_op_set_tso,
-       .get_flags = ethtool_op_get_flags,
-       .set_flags = cxgb3_set_flags,
 };
 
 static int in_range(int val, int lo, int hi)
@@ -1925,7 +1897,7 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
                                pi = adap2pinfo(adapter, i);
                                if (t.qset_idx >= pi->first_qset &&
                                    t.qset_idx < pi->first_qset + pi->nqsets &&
-                                   !pi->rx_csum_offload)
+                                   !(pi->rx_offload & T3_RX_CSUM))
                                        return -EINVAL;
                        }
 
@@ -2499,6 +2471,8 @@ static void t3_adap_check_task(struct work_struct *work)
        struct adapter *adapter = container_of(work, struct adapter,
                                               adap_check_task.work);
        const struct adapter_params *p = &adapter->params;
+       int port;
+       unsigned int v, status, reset;
 
        adapter->check_task_cnt++;
 
@@ -2517,6 +2491,54 @@ static void t3_adap_check_task(struct work_struct *work)
        if (p->rev == T3_REV_B2)
                check_t3b2_mac(adapter);
 
+       /*
+        * Scan the XGMAC's to check for various conditions which we want to
+        * monitor in a periodic polling manner rather than via an interrupt
+        * condition.  This is used for conditions which would otherwise flood
+        * the system with interrupts and we only really need to know that the
+        * conditions are "happening" ...  For each condition we count the
+        * detection of the condition and reset it for the next polling loop.
+        */
+       for_each_port(adapter, port) {
+               struct cmac *mac =  &adap2pinfo(adapter, port)->mac;
+               u32 cause;
+
+               cause = t3_read_reg(adapter, A_XGM_INT_CAUSE + mac->offset);
+               reset = 0;
+               if (cause & F_RXFIFO_OVERFLOW) {
+                       mac->stats.rx_fifo_ovfl++;
+                       reset |= F_RXFIFO_OVERFLOW;
+               }
+
+               t3_write_reg(adapter, A_XGM_INT_CAUSE + mac->offset, reset);
+       }
+
+       /*
+        * We do the same as above for FL_EMPTY interrupts.
+        */
+       status = t3_read_reg(adapter, A_SG_INT_CAUSE);
+       reset = 0;
+
+       if (status & F_FLEMPTY) {
+               struct sge_qset *qs = &adapter->sge.qs[0];
+               int i = 0;
+
+               reset |= F_FLEMPTY;
+
+               v = (t3_read_reg(adapter, A_SG_RSPQ_FL_STATUS) >> S_FL0EMPTY) &
+                   0xffff;
+
+               while (v) {
+                       qs->fl[i].empty += (v & 1);
+                       if (i)
+                               qs++;
+                       i ^= 1;
+                       v >>= 1;
+               }
+       }
+
+       t3_write_reg(adapter, A_SG_INT_CAUSE, reset);
+
        /* Schedule the next check update if any port is active. */
        spin_lock_irq(&adapter->work_lock);
        if (adapter->open_device_map & PORT_MASK)
@@ -2570,6 +2592,12 @@ static int t3_adapter_error(struct adapter *adapter, int reset)
 {
        int i, ret = 0;
 
+       if (is_offload(adapter) &&
+           test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) {
+               cxgb3_err_notify(&adapter->tdev, OFFLOAD_STATUS_DOWN, 0);
+               offload_close(&adapter->tdev);
+       }
+
        /* Stop all ports */
        for_each_port(adapter, i) {
                struct net_device *netdev = adapter->port[i];
@@ -2578,10 +2606,6 @@ static int t3_adapter_error(struct adapter *adapter, int reset)
                        cxgb_close(netdev);
        }
 
-       if (is_offload(adapter) &&
-           test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
-               offload_close(&adapter->tdev);
-
        /* Stop SGE timers */
        t3_stop_sge_timers(adapter);
 
@@ -2633,6 +2657,9 @@ static void t3_resume_ports(struct adapter *adapter)
                        }
                }
        }
+
+       if (is_offload(adapter) && !ofld_disable)
+               cxgb3_err_notify(&adapter->tdev, OFFLOAD_STATUS_UP, 0);
 }
 
 /*
@@ -2746,7 +2773,7 @@ static void set_nqsets(struct adapter *adap)
        int i, j = 0;
        int num_cpus = num_online_cpus();
        int hwports = adap->params.nports;
-       int nqsets = SGE_QSETS;
+       int nqsets = adap->msix_nvectors - 1;
 
        if (adap->params.rev > 0 && adap->flags & USING_MSIX) {
                if (hwports == 2 &&
@@ -2775,18 +2802,25 @@ static void set_nqsets(struct adapter *adap)
 static int __devinit cxgb_enable_msix(struct adapter *adap)
 {
        struct msix_entry entries[SGE_QSETS + 1];
+       int vectors;
        int i, err;
 
-       for (i = 0; i < ARRAY_SIZE(entries); ++i)
+       vectors = ARRAY_SIZE(entries);
+       for (i = 0; i < vectors; ++i)
                entries[i].entry = i;
 
-       err = pci_enable_msix(adap->pdev, entries, ARRAY_SIZE(entries));
+       while ((err = pci_enable_msix(adap->pdev, entries, vectors)) > 0)
+               vectors = err;
+
+       if (!err && vectors < (adap->params.nports + 1))
+               err = -1;
+
        if (!err) {
-               for (i = 0; i < ARRAY_SIZE(entries); ++i)
+               for (i = 0; i < vectors; ++i)
                        adap->msix_info[i].vec = entries[i].vector;
-       } else if (err > 0)
-               dev_info(&adap->pdev->dev,
-                      "only %d MSI-X vectors left, not using MSI-X\n", err);
+               adap->msix_nvectors = vectors;
+       }
+
        return err;
 }
 
@@ -2945,7 +2979,7 @@ static int __devinit init_one(struct pci_dev *pdev,
                adapter->port[i] = netdev;
                pi = netdev_priv(netdev);
                pi->adapter = adapter;
-               pi->rx_csum_offload = 1;
+               pi->rx_offload = T3_RX_CSUM | T3_LRO;
                pi->port_id = i;
                netif_carrier_off(netdev);
                netif_tx_stop_all_queues(netdev);
@@ -2954,6 +2988,7 @@ static int __devinit init_one(struct pci_dev *pdev,
                netdev->mem_end = mmio_start + mmio_len - 1;
                netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
                netdev->features |= NETIF_F_LLTX;
+               netdev->features |= NETIF_F_GRO;
                if (pci_using_dac)
                        netdev->features |= NETIF_F_HIGHDMA;