cxgb4vf: add call to Firmware to reset VF State.
[linux-2.6.git] / drivers / net / cxgb4vf / cxgb4vf_main.c
index bd73ff5..c3449bb 100644 (file)
@@ -423,12 +423,13 @@ static int fwevtq_handler(struct sge_rspq *rspq, const __be64 *rsp,
 
        case CPL_SGE_EGR_UPDATE: {
                /*
-                * We've received an Egress Queue status update message.
-                * We get these, as the SGE is currently configured, when
-                * the firmware passes certain points in processing our
-                * TX Ethernet Queue.  We use these updates to determine
-                * when we may need to restart a TX Ethernet Queue which
-                * was stopped for lack of free slots ...
+                * We've received an Egress Queue Status Update message.  We
+                * get these, if the SGE is configured to send these when the
+                * firmware passes certain points in processing our TX
+                * Ethernet Queue or if we make an explicit request for one.
+                * We use these updates to determine when we may need to
+                * restart a TX Ethernet Queue which was stopped for lack of
+                * free TX Queue Descriptors ...
                 */
                const struct cpl_sge_egr_update *p = (void *)cpl;
                unsigned int qid = EGR_QID(be32_to_cpu(p->opcode_qid));
@@ -436,7 +437,6 @@ static int fwevtq_handler(struct sge_rspq *rspq, const __be64 *rsp,
                struct sge_txq *tq;
                struct sge_eth_txq *txq;
                unsigned int eq_idx;
-               int hw_cidx, reclaimable, in_use;
 
                /*
                 * Perform sanity checking on the Queue ID to make sure it
@@ -466,24 +466,6 @@ static int fwevtq_handler(struct sge_rspq *rspq, const __be64 *rsp,
                }
 
                /*
-                * Skip TX Queues which aren't stopped.
-                */
-               if (likely(!netif_tx_queue_stopped(txq->txq)))
-                       break;
-
-               /*
-                * Skip stopped TX Queues which have more than half of their
-                * DMA rings occupied with unacknowledged writes.
-                */
-               hw_cidx = be16_to_cpu(txq->q.stat->cidx);
-               reclaimable = hw_cidx - txq->q.cidx;
-               if (reclaimable < 0)
-                       reclaimable += txq->q.size;
-               in_use = txq->q.in_use - reclaimable;
-               if (in_use >= txq->q.size/2)
-                       break;
-
-               /*
                 * Restart a stopped TX Queue which has less than half of its
                 * TX ring in use ...
                 */
@@ -551,10 +533,9 @@ static int setup_sge_queues(struct adapter *adapter)
                struct port_info *pi = netdev_priv(dev);
                struct sge_eth_rxq *rxq = &s->ethrxq[pi->first_qset];
                struct sge_eth_txq *txq = &s->ethtxq[pi->first_qset];
-               int nqsets = (adapter->flags & USING_MSIX) ? pi->nqsets : 1;
                int qs;
 
-               for (qs = 0; qs < nqsets; qs++, rxq++, txq++) {
+               for (qs = 0; qs < pi->nqsets; qs++, rxq++, txq++) {
                        err = t4vf_sge_alloc_rxq(adapter, &rxq->rspq, false,
                                                 dev, msix++,
                                                 &rxq->fl, t4vf_ethrx_handler);
@@ -583,10 +564,9 @@ static int setup_sge_queues(struct adapter *adapter)
                struct port_info *pi = netdev_priv(dev);
                struct sge_eth_rxq *rxq = &s->ethrxq[pi->first_qset];
                struct sge_eth_txq *txq = &s->ethtxq[pi->first_qset];
-               int nqsets = (adapter->flags & USING_MSIX) ? pi->nqsets : 1;
                int qs;
 
-               for (qs = 0; qs < nqsets; qs++, rxq++, txq++) {
+               for (qs = 0; qs < pi->nqsets; qs++, rxq++, txq++) {
                        IQ_MAP(s, rxq->rspq.abs_id) = &rxq->rspq;
                        EQ_MAP(s, txq->q.abs_id) = &txq->q;
 
@@ -768,9 +748,14 @@ static int cxgb4vf_open(struct net_device *dev)
        /*
         * Note that this interface is up and start everything up ...
         */
-       dev->real_num_tx_queues = pi->nqsets;
+       netif_set_real_num_tx_queues(dev, pi->nqsets);
+       err = netif_set_real_num_rx_queues(dev, pi->nqsets);
+       if (err)
+               return err;
        set_bit(pi->port_id, &adapter->open_device_map);
-       link_start(dev);
+       err = link_start(dev);
+       if (err)
+               return err;
        netif_tx_start_all_queues(dev);
        return 0;
 }
@@ -1120,18 +1105,6 @@ static int cxgb4vf_set_mac_addr(struct net_device *dev, void *_addr)
        return 0;
 }
 
-/*
- * Return a TX Queue on which to send the specified skb.
- */
-static u16 cxgb4vf_select_queue(struct net_device *dev, struct sk_buff *skb)
-{
-       /*
-        * XXX For now just use the default hash but we probably want to
-        * XXX look at other possibilities ...
-        */
-       return skb_tx_hash(dev, skb);
-}
-
 #ifdef CONFIG_NET_POLL_CONTROLLER
 /*
  * Poll all of our receive queues.  This is called outside of normal interrupt
@@ -1790,7 +1763,7 @@ static int sge_qstats_show(struct seq_file *seq, void *v)
                  (rxq[qs].rspq.netdev
                   ? rxq[qs].rspq.netdev->name
                   : "N/A"));
-               R3("u", "RspQNullInts", rspq.unhandled_irqs);
+               R3("u", "RspQNullInts:", rspq.unhandled_irqs);
                R("RxPackets:", stats.pkts);
                R("RxCSO:", stats.rx_cso);
                R("VLANxtract:", stats.vlan_ex);
@@ -1814,14 +1787,16 @@ static int sge_qstats_show(struct seq_file *seq, void *v)
                const struct sge_rspq *evtq = &adapter->sge.fw_evtq;
 
                seq_printf(seq, "%-8s %16s\n", "QType:", "FW event queue");
-               /* no real response queue statistics available to display */
+               seq_printf(seq, "%-16s %8u\n", "RspQNullInts:",
+                          evtq->unhandled_irqs);
                seq_printf(seq, "%-16s %8u\n", "RspQ CIdx:", evtq->cidx);
                seq_printf(seq, "%-16s %8u\n", "RspQ Gen:", evtq->gen);
        } else if (r == 1) {
                const struct sge_rspq *intrq = &adapter->sge.intrq;
 
                seq_printf(seq, "%-8s %16s\n", "QType:", "Interrupt Queue");
-               /* no real response queue statistics available to display */
+               seq_printf(seq, "%-16s %8u\n", "RspQNullInts:",
+                          intrq->unhandled_irqs);
                seq_printf(seq, "%-16s %8u\n", "RspQ CIdx:", intrq->cidx);
                seq_printf(seq, "%-16s %8u\n", "RspQ Gen:", intrq->gen);
        }
@@ -2090,6 +2065,22 @@ static int adap_init0(struct adapter *adapter)
        }
 
        /*
+        * Some environments do not properly handle PCIE FLRs -- e.g. in Linux
+        * 2.6.31 and later we can't call pci_reset_function() in order to
+        * issue an FLR because of a self- deadlock on the device semaphore.
+        * Meanwhile, the OS infrastructure doesn't issue FLRs in all the
+        * cases where they're needed -- for instance, some versions of KVM
+        * fail to reset "Assigned Devices" when the VM reboots.  Therefore we
+        * use the firmware based reset in order to reset any per function
+        * state.
+        */
+       err = t4vf_fw_reset(adapter);
+       if (err < 0) {
+               dev_err(adapter->pdev_dev, "FW reset failed: err=%d\n", err);
+               return err;
+       }
+
+       /*
         * Grab basic operational parameters.  These will predominantly have
         * been set up by the Physical Function Driver or will be hard coded
         * into the adapter.  We just have to live with them ...  Note that
@@ -2432,7 +2423,6 @@ static const struct net_device_ops cxgb4vf_netdev_ops     = {
        .ndo_get_stats          = cxgb4vf_get_stats,
        .ndo_set_rx_mode        = cxgb4vf_set_rxmode,
        .ndo_set_mac_address    = cxgb4vf_set_mac_addr,
-       .ndo_select_queue       = cxgb4vf_select_queue,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_do_ioctl           = cxgb4vf_do_ioctl,
        .ndo_change_mtu         = cxgb4vf_change_mtu,
@@ -2480,23 +2470,24 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
                version_printed = 1;
        }
 
+
        /*
-        * Reserve PCI resources for the device.  If we can't get them some
-        * other driver may have already claimed the device ...
+        * Initialize generic PCI device state.
         */
-       err = pci_request_regions(pdev, KBUILD_MODNAME);
+       err = pci_enable_device(pdev);
        if (err) {
-               dev_err(&pdev->dev, "cannot obtain PCI resources\n");
+               dev_err(&pdev->dev, "cannot enable PCI device\n");
                return err;
        }
 
        /*
-        * Initialize generic PCI device state.
+        * Reserve PCI resources for the device.  If we can't get them some
+        * other driver may have already claimed the device ...
         */
-       err = pci_enable_device(pdev);
+       err = pci_request_regions(pdev, KBUILD_MODNAME);
        if (err) {
-               dev_err(&pdev->dev, "cannot enable PCI device\n");
-               goto err_release_regions;
+               dev_err(&pdev->dev, "cannot obtain PCI resources\n");
+               goto err_disable_device;
        }
 
        /*
@@ -2509,14 +2500,14 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
                if (err) {
                        dev_err(&pdev->dev, "unable to obtain 64-bit DMA for"
                                " coherent allocations\n");
-                       goto err_disable_device;
+                       goto err_release_regions;
                }
                pci_using_dac = 1;
        } else {
                err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
                if (err != 0) {
                        dev_err(&pdev->dev, "no usable DMA configuration\n");
-                       goto err_disable_device;
+                       goto err_release_regions;
                }
                pci_using_dac = 0;
        }
@@ -2532,7 +2523,7 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
        adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
        if (!adapter) {
                err = -ENOMEM;
-               goto err_disable_device;
+               goto err_release_regions;
        }
        pci_set_drvdata(pdev, adapter);
        adapter->pdev = pdev;
@@ -2614,7 +2605,6 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
                pi->xact_addr_filt = -1;
                pi->rx_offload = RX_CSO;
                netif_carrier_off(netdev);
-               netif_tx_stop_all_queues(netdev);
                netdev->irq = pdev->irq;
 
                netdev->features = (NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
@@ -2639,7 +2629,6 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
                netdev->do_ioctl = cxgb4vf_do_ioctl;
                netdev->change_mtu = cxgb4vf_change_mtu;
                netdev->set_mac_address = cxgb4vf_set_mac_addr;
-               netdev->select_queue = cxgb4vf_select_queue;
 #ifdef CONFIG_NET_POLL_CONTROLLER
                netdev->poll_controller = cxgb4vf_poll_controller;
 #endif
@@ -2768,13 +2757,13 @@ err_free_adapter:
        kfree(adapter);
        pci_set_drvdata(pdev, NULL);
 
-err_disable_device:
-       pci_disable_device(pdev);
-       pci_clear_master(pdev);
-
 err_release_regions:
        pci_release_regions(pdev);
        pci_set_drvdata(pdev, NULL);
+       pci_clear_master(pdev);
+
+err_disable_device:
+       pci_disable_device(pdev);
 
 err_out:
        return err;
@@ -2858,6 +2847,14 @@ static struct pci_device_id cxgb4vf_pci_tbl[] = {
        CH_DEVICE(0x4800, 0),   /* T440-dbg */
        CH_DEVICE(0x4801, 0),   /* T420-cr */
        CH_DEVICE(0x4802, 0),   /* T422-cr */
+       CH_DEVICE(0x4803, 0),   /* T440-cr */
+       CH_DEVICE(0x4804, 0),   /* T420-bch */
+       CH_DEVICE(0x4805, 0),   /* T440-bch */
+       CH_DEVICE(0x4806, 0),   /* T460-ch */
+       CH_DEVICE(0x4807, 0),   /* T420-so */
+       CH_DEVICE(0x4808, 0),   /* T420-cx */
+       CH_DEVICE(0x4809, 0),   /* T420-bt */
+       CH_DEVICE(0x480a, 0),   /* T404-bt */
        { 0, }
 };