diff options
author | Sathya Perla <sathyap@serverengines.com> | 2010-03-02 06:56:39 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-03-02 06:56:39 -0500 |
commit | f31e50a802baae939c49819b8acd8f077019d398 (patch) | |
tree | f9bb9e3950933db922a4ce814d7ac281569778f1 /drivers/net/benet/be_main.c | |
parent | b88aafd365bc6a2222e2d03ff320adea3a37f628 (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/be_main.c')
-rw-r--r-- | drivers/net/benet/be_main.c | 47 |
1 files changed, 23 insertions, 24 deletions
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); |
587 | done: | 587 | done: |
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 | ||
1472 | void 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 | */ | ||
1475 | static 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 | */ | ||
1506 | static 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 | } |