aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/benet
diff options
context:
space:
mode:
authorSathya Perla <sathyap@serverengines.com>2010-03-02 06:56:39 -0500
committerDavid S. Miller <davem@davemloft.net>2010-03-02 06:56:39 -0500
commitf31e50a802baae939c49819b8acd8f077019d398 (patch)
treef9bb9e3950933db922a4ce814d7ac281569778f1 /drivers/net/benet
parentb88aafd365bc6a2222e2d03ff320adea3a37f628 (diff)
be2net: fix tx completion polling
In tx/mcc polling, napi_complete() is being incorrectly called before reaping tx completions. This can cause tx compl processing to be scheduled on another cpu concurrently which can result in a panic. This if fixed by calling napi complete() after tx/mcc compl processing but before re-enabling interrupts (via a cq notify). Signed-off-by: Sathya Perla <sathyap@serverengines.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/benet')
-rw-r--r--drivers/net/benet/be_cmds.c26
-rw-r--r--drivers/net/benet/be_cmds.h2
-rw-r--r--drivers/net/benet/be_main.c47
3 files changed, 37 insertions, 38 deletions
diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c
index c8a2bacb1d13..4b1f80519ca4 100644
--- a/drivers/net/benet/be_cmds.c
+++ b/drivers/net/benet/be_cmds.c
@@ -119,10 +119,10 @@ void be_async_mcc_disable(struct be_adapter *adapter)
119 adapter->mcc_obj.rearm_cq = false; 119 adapter->mcc_obj.rearm_cq = false;
120} 120}
121 121
122int be_process_mcc(struct be_adapter *adapter) 122int be_process_mcc(struct be_adapter *adapter, int *status)
123{ 123{
124 struct be_mcc_compl *compl; 124 struct be_mcc_compl *compl;
125 int num = 0, status = 0; 125 int num = 0;
126 struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; 126 struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
127 127
128 spin_lock_bh(&adapter->mcc_cq_lock); 128 spin_lock_bh(&adapter->mcc_cq_lock);
@@ -135,31 +135,31 @@ int be_process_mcc(struct be_adapter *adapter)
135 be_async_link_state_process(adapter, 135 be_async_link_state_process(adapter,
136 (struct be_async_event_link_state *) compl); 136 (struct be_async_event_link_state *) compl);
137 } else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) { 137 } else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) {
138 status = be_mcc_compl_process(adapter, compl); 138 *status = be_mcc_compl_process(adapter, compl);
139 atomic_dec(&mcc_obj->q.used); 139 atomic_dec(&mcc_obj->q.used);
140 } 140 }
141 be_mcc_compl_use(compl); 141 be_mcc_compl_use(compl);
142 num++; 142 num++;
143 } 143 }
144 144
145 if (num)
146 be_cq_notify(adapter, mcc_obj->cq.id, mcc_obj->rearm_cq, num);
147
148 spin_unlock_bh(&adapter->mcc_cq_lock); 145 spin_unlock_bh(&adapter->mcc_cq_lock);
149 return status; 146 return num;
150} 147}
151 148
152/* Wait till no more pending mcc requests are present */ 149/* Wait till no more pending mcc requests are present */
153static int be_mcc_wait_compl(struct be_adapter *adapter) 150static int be_mcc_wait_compl(struct be_adapter *adapter)
154{ 151{
155#define mcc_timeout 120000 /* 12s timeout */ 152#define mcc_timeout 120000 /* 12s timeout */
156 int i, status; 153 int i, num, status = 0;
154 struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
155
157 for (i = 0; i < mcc_timeout; i++) { 156 for (i = 0; i < mcc_timeout; i++) {
158 status = be_process_mcc(adapter); 157 num = be_process_mcc(adapter, &status);
159 if (status) 158 if (num)
160 return status; 159 be_cq_notify(adapter, mcc_obj->cq.id,
160 mcc_obj->rearm_cq, num);
161 161
162 if (atomic_read(&adapter->mcc_obj.q.used) == 0) 162 if (atomic_read(&mcc_obj->q.used) == 0)
163 break; 163 break;
164 udelay(100); 164 udelay(100);
165 } 165 }
@@ -167,7 +167,7 @@ static int be_mcc_wait_compl(struct be_adapter *adapter)
167 dev_err(&adapter->pdev->dev, "mccq poll timed out\n"); 167 dev_err(&adapter->pdev->dev, "mccq poll timed out\n");
168 return -1; 168 return -1;
169 } 169 }
170 return 0; 170 return status;
171} 171}
172 172
173/* Notify MCC requests and wait for completion */ 173/* Notify MCC requests and wait for completion */
diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h
index 728b0d736929..cce61f9a3714 100644
--- a/drivers/net/benet/be_cmds.h
+++ b/drivers/net/benet/be_cmds.h
@@ -920,7 +920,7 @@ extern int be_cmd_get_flow_control(struct be_adapter *adapter,
920extern int be_cmd_query_fw_cfg(struct be_adapter *adapter, 920extern int be_cmd_query_fw_cfg(struct be_adapter *adapter,
921 u32 *port_num, u32 *cap); 921 u32 *port_num, u32 *cap);
922extern int be_cmd_reset_function(struct be_adapter *adapter); 922extern int be_cmd_reset_function(struct be_adapter *adapter);
923extern int be_process_mcc(struct be_adapter *adapter); 923extern int be_process_mcc(struct be_adapter *adapter, int *status);
924extern int be_cmd_set_beacon_state(struct be_adapter *adapter, 924extern int be_cmd_set_beacon_state(struct be_adapter *adapter,
925 u8 port_num, u8 beacon, u8 status, u8 state); 925 u8 port_num, u8 beacon, u8 status, u8 state);
926extern int be_cmd_get_beacon_state(struct be_adapter *adapter, 926extern int be_cmd_get_beacon_state(struct be_adapter *adapter,
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index 27ccdd80257b..a703ed8e24fe 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -583,7 +583,7 @@ static void be_set_multicast_list(struct net_device *netdev)
583 } 583 }
584 584
585 be_cmd_multicast_set(adapter, adapter->if_handle, netdev, 585 be_cmd_multicast_set(adapter, adapter->if_handle, netdev,
586 &adapter->mc_cmd_mem); 586 &adapter->mc_cmd_mem);
587done: 587done:
588 return; 588 return;
589} 589}
@@ -1469,23 +1469,38 @@ int be_poll_rx(struct napi_struct *napi, int budget)
1469 return work_done; 1469 return work_done;
1470} 1470}
1471 1471
1472void be_process_tx(struct be_adapter *adapter) 1472/* As TX and MCC share the same EQ check for both TX and MCC completions.
1473 * For TX/MCC we don't honour budget; consume everything
1474 */
1475static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
1473{ 1476{
1477 struct be_eq_obj *tx_eq = container_of(napi, struct be_eq_obj, napi);
1478 struct be_adapter *adapter =
1479 container_of(tx_eq, struct be_adapter, tx_eq);
1474 struct be_queue_info *txq = &adapter->tx_obj.q; 1480 struct be_queue_info *txq = &adapter->tx_obj.q;
1475 struct be_queue_info *tx_cq = &adapter->tx_obj.cq; 1481 struct be_queue_info *tx_cq = &adapter->tx_obj.cq;
1476 struct be_eth_tx_compl *txcp; 1482 struct be_eth_tx_compl *txcp;
1477 u32 num_cmpl = 0; 1483 int tx_compl = 0, mcc_compl, status = 0;
1478 u16 end_idx; 1484 u16 end_idx;
1479 1485
1480 while ((txcp = be_tx_compl_get(tx_cq))) { 1486 while ((txcp = be_tx_compl_get(tx_cq))) {
1481 end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl, 1487 end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl,
1482 wrb_index, txcp); 1488 wrb_index, txcp);
1483 be_tx_compl_process(adapter, end_idx); 1489 be_tx_compl_process(adapter, end_idx);
1484 num_cmpl++; 1490 tx_compl++;
1485 } 1491 }
1486 1492
1487 if (num_cmpl) { 1493 mcc_compl = be_process_mcc(adapter, &status);
1488 be_cq_notify(adapter, tx_cq->id, true, num_cmpl); 1494
1495 napi_complete(napi);
1496
1497 if (mcc_compl) {
1498 struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
1499 be_cq_notify(adapter, mcc_obj->cq.id, true, mcc_compl);
1500 }
1501
1502 if (tx_compl) {
1503 be_cq_notify(adapter, adapter->tx_obj.cq.id, true, tx_compl);
1489 1504
1490 /* As Tx wrbs have been freed up, wake up netdev queue if 1505 /* As Tx wrbs have been freed up, wake up netdev queue if
1491 * it was stopped due to lack of tx wrbs. 1506 * it was stopped due to lack of tx wrbs.
@@ -1496,24 +1511,8 @@ void be_process_tx(struct be_adapter *adapter)
1496 } 1511 }
1497 1512
1498 drvr_stats(adapter)->be_tx_events++; 1513 drvr_stats(adapter)->be_tx_events++;
1499 drvr_stats(adapter)->be_tx_compl += num_cmpl; 1514 drvr_stats(adapter)->be_tx_compl += tx_compl;
1500 } 1515 }
1501}
1502
1503/* As TX and MCC share the same EQ check for both TX and MCC completions.
1504 * For TX/MCC we don't honour budget; consume everything
1505 */
1506static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
1507{
1508 struct be_eq_obj *tx_eq = container_of(napi, struct be_eq_obj, napi);
1509 struct be_adapter *adapter =
1510 container_of(tx_eq, struct be_adapter, tx_eq);
1511
1512 napi_complete(napi);
1513
1514 be_process_tx(adapter);
1515
1516 be_process_mcc(adapter);
1517 1516
1518 return 1; 1517 return 1;
1519} 1518}