summaryrefslogtreecommitdiff
path: root/drivers/net/vxge/vxge-main.c
diff options
context:
space:
mode:
authorBenjamin LaHaise <ben.lahaise@neterion.com>2009-08-04 10:21:03 +0000
committerDavid S. Miller <davem@davemloft.net>2009-08-05 13:10:43 -0700
commitff67df55f6bde9de5e508bf1f09509c843accd54 (patch)
treef859b2b598762fd914bc3a79e38cf306fadd1894 /drivers/net/vxge/vxge-main.c
parent4403b371888d5947ed08200ee6351441a188a5c7 (diff)
downloadlwn-ff67df55f6bde9de5e508bf1f09509c843accd54.tar.gz
lwn-ff67df55f6bde9de5e508bf1f09509c843accd54.zip
vxge: fix pktgen hangs (don't abuse skb->cb[])
This patch fixes a case in the transmit completion code which was resulting in pktgen hanging at the end of a run. The cause is due to the fact that the ->cb[] area of an skb cannot be used in a network driver's transmit path, as that area belongs to the network protocol. Pktgen hangs, as it sends out the same packet multiple times, and vxge's use of this area of the skb for a temporary list can only add the packet to the temporary list once (while it may be on the queue many times). The fix is to remove this abuse of skb->cb[]. Instead, skb pointers are placed into a temporary stack array, and then free outside of the tx lock. This retains the smp optimization of doing dev_kfree_skb() outside of the tx lock. Signed-off-by: Benjamin LaHaise <ben.lahaise@neterion.com> Signed-off-by: Sreenivasa Honnur <sreenivasa.honnur@neterion.com> Signed-off-by: Ramkrishna Vepa <ram.vepa@neterion.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/vxge/vxge-main.c')
-rw-r--r--drivers/net/vxge/vxge-main.c53
1 files changed, 28 insertions, 25 deletions
diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c
index beee4ab2ed30..4b22513bed40 100644
--- a/drivers/net/vxge/vxge-main.c
+++ b/drivers/net/vxge/vxge-main.c
@@ -87,22 +87,25 @@ static inline int is_vxge_card_up(struct vxgedev *vdev)
static inline void VXGE_COMPLETE_VPATH_TX(struct vxge_fifo *fifo)
{
unsigned long flags = 0;
- struct sk_buff *skb_ptr = NULL;
- struct sk_buff **temp, *head, *skb;
-
- if (spin_trylock_irqsave(&fifo->tx_lock, flags)) {
- vxge_hw_vpath_poll_tx(fifo->handle, (void **)&skb_ptr);
- spin_unlock_irqrestore(&fifo->tx_lock, flags);
- }
- /* free SKBs */
- head = skb_ptr;
- while (head) {
- skb = head;
- temp = (struct sk_buff **)&skb->cb;
- head = *temp;
- *temp = NULL;
- dev_kfree_skb_irq(skb);
- }
+ struct sk_buff **skb_ptr = NULL;
+ struct sk_buff **temp;
+#define NR_SKB_COMPLETED 128
+ struct sk_buff *completed[NR_SKB_COMPLETED];
+ int more;
+
+ do {
+ more = 0;
+ skb_ptr = completed;
+
+ if (spin_trylock_irqsave(&fifo->tx_lock, flags)) {
+ vxge_hw_vpath_poll_tx(fifo->handle, &skb_ptr,
+ NR_SKB_COMPLETED, &more);
+ spin_unlock_irqrestore(&fifo->tx_lock, flags);
+ }
+ /* free SKBs */
+ for (temp = completed; temp != skb_ptr; temp++)
+ dev_kfree_skb_irq(*temp);
+ } while (more) ;
}
static inline void VXGE_COMPLETE_ALL_TX(struct vxgedev *vdev)
@@ -600,11 +603,10 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
enum vxge_hw_status
vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr,
enum vxge_hw_fifo_tcode t_code, void *userdata,
- void **skb_ptr)
+ struct sk_buff ***skb_ptr, int nr_skb, int *more)
{
struct vxge_fifo *fifo = (struct vxge_fifo *)userdata;
- struct sk_buff *skb, *head = NULL;
- struct sk_buff **temp;
+ struct sk_buff *skb, **done_skb = *skb_ptr;
int pkt_cnt = 0;
vxge_debug_entryexit(VXGE_TRACE,
@@ -657,9 +659,12 @@ vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr,
fifo->stats.tx_frms++;
fifo->stats.tx_bytes += skb->len;
- temp = (struct sk_buff **)&skb->cb;
- *temp = head;
- head = skb;
+ *done_skb++ = skb;
+
+ if (--nr_skb <= 0) {
+ *more = 1;
+ break;
+ }
pkt_cnt++;
if (pkt_cnt > fifo->indicate_max_pkts)
@@ -668,11 +673,9 @@ vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr,
} while (vxge_hw_fifo_txdl_next_completed(fifo_hw,
&dtr, &t_code) == VXGE_HW_OK);
+ *skb_ptr = done_skb;
vxge_wake_tx_queue(fifo, skb);
- if (skb_ptr)
- *skb_ptr = (void *) head;
-
vxge_debug_entryexit(VXGE_TRACE,
"%s: %s:%d Exiting...",
fifo->ndev->name, __func__, __LINE__);