aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSathya Perla <sathya.perla@emulex.com>2012-12-17 14:38:51 -0500
committerDavid S. Miller <davem@davemloft.net>2012-12-18 19:18:39 -0500
commitd23e946cb67e5011226bcbd1597a632ac7a48c35 (patch)
tree6c2089b3af7d3d142fb83137b5490628e38a1fd0
parenta323d9bf835e27d5e72eae86b5a41747d98bd9d2 (diff)
be2net: fix wrong frag_idx reported by RX CQ
The RX CQ can report completions with invalid frag_idx when the RXQ that was *previously* using it, was not cleaned up properly. This hits a BUG_ON() in be2net. When completion coalescing is enabled on a CQ, an explicit CQ-notify (with rearm) is needed for each compl, to flush partially coalesced CQ entries that are pending DMA. In be_close(), this fix now notifies CQ for each compl, waits explicitly for the flush compl to arrive and complains if it doesn't arrive. Also renaming be_crit_error() to be_hw_error() as it's the more appropriate name and to convey that we don't wait for the flush compl only when a HW error has occurred. Signed-off-by: Sathya Perla <sathya.perla@emulex.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/emulex/benet/be.h2
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c38
2 files changed, 33 insertions, 7 deletions
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
index abf26c7c1d1..3bc1912afba 100644
--- a/drivers/net/ethernet/emulex/benet/be.h
+++ b/drivers/net/ethernet/emulex/benet/be.h
@@ -616,7 +616,7 @@ static inline bool be_error(struct be_adapter *adapter)
616 return adapter->eeh_error || adapter->hw_error || adapter->fw_timeout; 616 return adapter->eeh_error || adapter->hw_error || adapter->fw_timeout;
617} 617}
618 618
619static inline bool be_crit_error(struct be_adapter *adapter) 619static inline bool be_hw_error(struct be_adapter *adapter)
620{ 620{
621 return adapter->eeh_error || adapter->hw_error; 621 return adapter->eeh_error || adapter->hw_error;
622} 622}
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index bf50e73c1ec..9dca22be812 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -1689,15 +1689,41 @@ static void be_rx_cq_clean(struct be_rx_obj *rxo)
1689 struct be_queue_info *rxq = &rxo->q; 1689 struct be_queue_info *rxq = &rxo->q;
1690 struct be_queue_info *rx_cq = &rxo->cq; 1690 struct be_queue_info *rx_cq = &rxo->cq;
1691 struct be_rx_compl_info *rxcp; 1691 struct be_rx_compl_info *rxcp;
1692 struct be_adapter *adapter = rxo->adapter;
1693 int flush_wait = 0;
1692 u16 tail; 1694 u16 tail;
1693 1695
1694 /* First cleanup pending rx completions */ 1696 /* Consume pending rx completions.
1695 while ((rxcp = be_rx_compl_get(rxo)) != NULL) { 1697 * Wait for the flush completion (identified by zero num_rcvd)
1696 be_rx_compl_discard(rxo, rxcp); 1698 * to arrive. Notify CQ even when there are no more CQ entries
1697 be_cq_notify(rxo->adapter, rx_cq->id, false, 1); 1699 * for HW to flush partially coalesced CQ entries.
1700 * In Lancer, there is no need to wait for flush compl.
1701 */
1702 for (;;) {
1703 rxcp = be_rx_compl_get(rxo);
1704 if (rxcp == NULL) {
1705 if (lancer_chip(adapter))
1706 break;
1707
1708 if (flush_wait++ > 10 || be_hw_error(adapter)) {
1709 dev_warn(&adapter->pdev->dev,
1710 "did not receive flush compl\n");
1711 break;
1712 }
1713 be_cq_notify(adapter, rx_cq->id, true, 0);
1714 mdelay(1);
1715 } else {
1716 be_rx_compl_discard(rxo, rxcp);
1717 be_cq_notify(adapter, rx_cq->id, true, 1);
1718 if (rxcp->num_rcvd == 0)
1719 break;
1720 }
1698 } 1721 }
1699 1722
1700 /* Then free posted rx buffer that were not used */ 1723 /* After cleanup, leave the CQ in unarmed state */
1724 be_cq_notify(adapter, rx_cq->id, false, 0);
1725
1726 /* Then free posted rx buffers that were not used */
1701 tail = (rxq->head + rxq->len - atomic_read(&rxq->used)) % rxq->len; 1727 tail = (rxq->head + rxq->len - atomic_read(&rxq->used)) % rxq->len;
1702 for (; atomic_read(&rxq->used) > 0; index_inc(&tail, rxq->len)) { 1728 for (; atomic_read(&rxq->used) > 0; index_inc(&tail, rxq->len)) {
1703 page_info = get_rx_page_info(rxo, tail); 1729 page_info = get_rx_page_info(rxo, tail);
@@ -2157,7 +2183,7 @@ void be_detect_error(struct be_adapter *adapter)
2157 u32 sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0; 2183 u32 sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0;
2158 u32 i; 2184 u32 i;
2159 2185
2160 if (be_crit_error(adapter)) 2186 if (be_hw_error(adapter))
2161 return; 2187 return;
2162 2188
2163 if (lancer_chip(adapter)) { 2189 if (lancer_chip(adapter)) {