aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/enic
diff options
context:
space:
mode:
authorScott Feldman <scofeldm@cisco.com>2009-12-23 08:27:30 -0500
committerDavid S. Miller <davem@davemloft.net>2009-12-24 00:03:39 -0500
commitb3d18d191bb805f3effdfc083c4ce79789470b46 (patch)
tree034a2d4cfda07b9f843942bc33a3e43ea2572489 /drivers/net/enic
parentfe45332ed289d91e57eca11bfd1ca75d6e420ab4 (diff)
enic: Bug fix: use safe queue shutdown in dev->stop
Fix dev->stop shutdown bug where driver was stopping xmit queue and then disabling intrs. Fix is to disable intrs first and then stop the xmit queue, otherwise an interrupt could cause the queue to be rewoken. Also, no need to explicitly do queue servicing because queues are cleaned and reset back to initial state at end of dev->stop. Servicing queues also had the side-effect of also rewakening the xmit queue, which is not what we want. Signed-off-by: Vasanthy Kolluri <vkolluri@cisco.com> Signed-off-by: Scott Feldman <scofeldm@cisco.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/enic')
-rw-r--r--drivers/net/enic/enic.h2
-rw-r--r--drivers/net/enic/enic_main.c62
-rw-r--r--drivers/net/enic/vnic_intr.h1
3 files changed, 27 insertions, 38 deletions
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
index e1c2076228ba..8dd0105a8d9c 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/enic/enic.h
@@ -34,7 +34,7 @@
34 34
35#define DRV_NAME "enic" 35#define DRV_NAME "enic"
36#define DRV_DESCRIPTION "Cisco 10G Ethernet Driver" 36#define DRV_DESCRIPTION "Cisco 10G Ethernet Driver"
37#define DRV_VERSION "1.1.0.100" 37#define DRV_VERSION "1.1.0.241a"
38#define DRV_COPYRIGHT "Copyright 2008-2009 Cisco Systems, Inc" 38#define DRV_COPYRIGHT "Copyright 2008-2009 Cisco Systems, Inc"
39#define PFX DRV_NAME ": " 39#define PFX DRV_NAME ": "
40 40
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index f875751af15e..b4a11befb3b3 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -1084,34 +1084,6 @@ static int enic_rq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc,
1084 return 0; 1084 return 0;
1085} 1085}
1086 1086
1087static void enic_rq_drop_buf(struct vnic_rq *rq,
1088 struct cq_desc *cq_desc, struct vnic_rq_buf *buf,
1089 int skipped, void *opaque)
1090{
1091 struct enic *enic = vnic_dev_priv(rq->vdev);
1092 struct sk_buff *skb = buf->os_buf;
1093
1094 if (skipped)
1095 return;
1096
1097 pci_unmap_single(enic->pdev, buf->dma_addr,
1098 buf->len, PCI_DMA_FROMDEVICE);
1099
1100 dev_kfree_skb_any(skb);
1101}
1102
1103static int enic_rq_service_drop(struct vnic_dev *vdev, struct cq_desc *cq_desc,
1104 u8 type, u16 q_number, u16 completed_index, void *opaque)
1105{
1106 struct enic *enic = vnic_dev_priv(vdev);
1107
1108 vnic_rq_service(&enic->rq[q_number], cq_desc,
1109 completed_index, VNIC_RQ_RETURN_DESC,
1110 enic_rq_drop_buf, opaque);
1111
1112 return 0;
1113}
1114
1115static int enic_poll(struct napi_struct *napi, int budget) 1087static int enic_poll(struct napi_struct *napi, int budget)
1116{ 1088{
1117 struct enic *enic = container_of(napi, struct enic, napi); 1089 struct enic *enic = container_of(napi, struct enic, napi);
@@ -1304,6 +1276,24 @@ static int enic_request_intr(struct enic *enic)
1304 return err; 1276 return err;
1305} 1277}
1306 1278
1279static void enic_synchronize_irqs(struct enic *enic)
1280{
1281 unsigned int i;
1282
1283 switch (vnic_dev_get_intr_mode(enic->vdev)) {
1284 case VNIC_DEV_INTR_MODE_INTX:
1285 case VNIC_DEV_INTR_MODE_MSI:
1286 synchronize_irq(enic->pdev->irq);
1287 break;
1288 case VNIC_DEV_INTR_MODE_MSIX:
1289 for (i = 0; i < enic->intr_count; i++)
1290 synchronize_irq(enic->msix_entry[i].vector);
1291 break;
1292 default:
1293 break;
1294 }
1295}
1296
1307static int enic_notify_set(struct enic *enic) 1297static int enic_notify_set(struct enic *enic)
1308{ 1298{
1309 int err; 1299 int err;
@@ -1409,16 +1399,19 @@ static int enic_stop(struct net_device *netdev)
1409 unsigned int i; 1399 unsigned int i;
1410 int err; 1400 int err;
1411 1401
1402 for (i = 0; i < enic->intr_count; i++)
1403 vnic_intr_mask(&enic->intr[i]);
1404
1405 enic_synchronize_irqs(enic);
1406
1412 del_timer_sync(&enic->notify_timer); 1407 del_timer_sync(&enic->notify_timer);
1413 1408
1414 spin_lock(&enic->devcmd_lock); 1409 spin_lock(&enic->devcmd_lock);
1415 vnic_dev_disable(enic->vdev); 1410 vnic_dev_disable(enic->vdev);
1416 spin_unlock(&enic->devcmd_lock); 1411 spin_unlock(&enic->devcmd_lock);
1417 napi_disable(&enic->napi); 1412 napi_disable(&enic->napi);
1418 netif_stop_queue(netdev); 1413 netif_carrier_off(netdev);
1419 1414 netif_tx_disable(netdev);
1420 for (i = 0; i < enic->intr_count; i++)
1421 vnic_intr_mask(&enic->intr[i]);
1422 1415
1423 for (i = 0; i < enic->wq_count; i++) { 1416 for (i = 0; i < enic->wq_count; i++) {
1424 err = vnic_wq_disable(&enic->wq[i]); 1417 err = vnic_wq_disable(&enic->wq[i]);
@@ -1436,11 +1429,6 @@ static int enic_stop(struct net_device *netdev)
1436 spin_unlock(&enic->devcmd_lock); 1429 spin_unlock(&enic->devcmd_lock);
1437 enic_free_intr(enic); 1430 enic_free_intr(enic);
1438 1431
1439 (void)vnic_cq_service(&enic->cq[ENIC_CQ_RQ],
1440 -1, enic_rq_service_drop, NULL);
1441 (void)vnic_cq_service(&enic->cq[ENIC_CQ_WQ],
1442 -1, enic_wq_service, NULL);
1443
1444 for (i = 0; i < enic->wq_count; i++) 1432 for (i = 0; i < enic->wq_count; i++)
1445 vnic_wq_clean(&enic->wq[i], enic_free_wq_buf); 1433 vnic_wq_clean(&enic->wq[i], enic_free_wq_buf);
1446 for (i = 0; i < enic->rq_count; i++) 1434 for (i = 0; i < enic->rq_count; i++)
diff --git a/drivers/net/enic/vnic_intr.h b/drivers/net/enic/vnic_intr.h
index 9a53604edce6..f79a722b6a03 100644
--- a/drivers/net/enic/vnic_intr.h
+++ b/drivers/net/enic/vnic_intr.h
@@ -61,6 +61,7 @@ static inline void vnic_intr_unmask(struct vnic_intr *intr)
61static inline void vnic_intr_mask(struct vnic_intr *intr) 61static inline void vnic_intr_mask(struct vnic_intr *intr)
62{ 62{
63 iowrite32(1, &intr->ctrl->mask); 63 iowrite32(1, &intr->ctrl->mask);
64 (void)ioread32(&intr->ctrl->mask);
64} 65}
65 66
66static inline void vnic_intr_return_credits(struct vnic_intr *intr, 67static inline void vnic_intr_return_credits(struct vnic_intr *intr,