aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/vxge
diff options
context:
space:
mode:
authorBenjamin LaHaise <ben.lahaise@neterion.com>2009-08-04 06:21:03 -0400
committerDavid S. Miller <davem@davemloft.net>2009-08-05 16:10:43 -0400
commitff67df55f6bde9de5e508bf1f09509c843accd54 (patch)
treef859b2b598762fd914bc3a79e38cf306fadd1894 /drivers/net/vxge
parent4403b371888d5947ed08200ee6351441a188a5c7 (diff)
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')
-rw-r--r--drivers/net/vxge/vxge-config.h7
-rw-r--r--drivers/net/vxge/vxge-main.c53
-rw-r--r--drivers/net/vxge/vxge-main.h3
-rw-r--r--drivers/net/vxge/vxge-traffic.c7
-rw-r--r--drivers/net/vxge/vxge-traffic.h2
5 files changed, 40 insertions, 32 deletions
diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h
index 224acea771ed..62779a520ca1 100644
--- a/drivers/net/vxge/vxge-config.h
+++ b/drivers/net/vxge/vxge-config.h
@@ -978,7 +978,9 @@ struct __vxge_hw_fifo {
978 void *txdlh, 978 void *txdlh,
979 enum vxge_hw_fifo_tcode t_code, 979 enum vxge_hw_fifo_tcode t_code,
980 void *userdata, 980 void *userdata,
981 void **skb_ptr); 981 struct sk_buff ***skb_ptr,
982 int nr_skb,
983 int *more);
982 984
983 void (*txdl_term)( 985 void (*txdl_term)(
984 void *txdlh, 986 void *txdlh,
@@ -1779,7 +1781,8 @@ struct vxge_hw_fifo_attr {
1779 void *txdlh, 1781 void *txdlh,
1780 enum vxge_hw_fifo_tcode t_code, 1782 enum vxge_hw_fifo_tcode t_code,
1781 void *userdata, 1783 void *userdata,
1782 void **skb_ptr); 1784 struct sk_buff ***skb_ptr,
1785 int nr_skb, int *more);
1783 1786
1784 void (*txdl_term)( 1787 void (*txdl_term)(
1785 void *txdlh, 1788 void *txdlh,
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)
87static inline void VXGE_COMPLETE_VPATH_TX(struct vxge_fifo *fifo) 87static inline void VXGE_COMPLETE_VPATH_TX(struct vxge_fifo *fifo)
88{ 88{
89 unsigned long flags = 0; 89 unsigned long flags = 0;
90 struct sk_buff *skb_ptr = NULL; 90 struct sk_buff **skb_ptr = NULL;
91 struct sk_buff **temp, *head, *skb; 91 struct sk_buff **temp;
92 92#define NR_SKB_COMPLETED 128
93 if (spin_trylock_irqsave(&fifo->tx_lock, flags)) { 93 struct sk_buff *completed[NR_SKB_COMPLETED];
94 vxge_hw_vpath_poll_tx(fifo->handle, (void **)&skb_ptr); 94 int more;
95 spin_unlock_irqrestore(&fifo->tx_lock, flags); 95
96 } 96 do {
97 /* free SKBs */ 97 more = 0;
98 head = skb_ptr; 98 skb_ptr = completed;
99 while (head) { 99
100 skb = head; 100 if (spin_trylock_irqsave(&fifo->tx_lock, flags)) {
101 temp = (struct sk_buff **)&skb->cb; 101 vxge_hw_vpath_poll_tx(fifo->handle, &skb_ptr,
102 head = *temp; 102 NR_SKB_COMPLETED, &more);
103 *temp = NULL; 103 spin_unlock_irqrestore(&fifo->tx_lock, flags);
104 dev_kfree_skb_irq(skb); 104 }
105 } 105 /* free SKBs */
106 for (temp = completed; temp != skb_ptr; temp++)
107 dev_kfree_skb_irq(*temp);
108 } while (more) ;
106} 109}
107 110
108static inline void VXGE_COMPLETE_ALL_TX(struct vxgedev *vdev) 111static inline void VXGE_COMPLETE_ALL_TX(struct vxgedev *vdev)
@@ -600,11 +603,10 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
600enum vxge_hw_status 603enum vxge_hw_status
601vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr, 604vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr,
602 enum vxge_hw_fifo_tcode t_code, void *userdata, 605 enum vxge_hw_fifo_tcode t_code, void *userdata,
603 void **skb_ptr) 606 struct sk_buff ***skb_ptr, int nr_skb, int *more)
604{ 607{
605 struct vxge_fifo *fifo = (struct vxge_fifo *)userdata; 608 struct vxge_fifo *fifo = (struct vxge_fifo *)userdata;
606 struct sk_buff *skb, *head = NULL; 609 struct sk_buff *skb, **done_skb = *skb_ptr;
607 struct sk_buff **temp;
608 int pkt_cnt = 0; 610 int pkt_cnt = 0;
609 611
610 vxge_debug_entryexit(VXGE_TRACE, 612 vxge_debug_entryexit(VXGE_TRACE,
@@ -657,9 +659,12 @@ vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr,
657 fifo->stats.tx_frms++; 659 fifo->stats.tx_frms++;
658 fifo->stats.tx_bytes += skb->len; 660 fifo->stats.tx_bytes += skb->len;
659 661
660 temp = (struct sk_buff **)&skb->cb; 662 *done_skb++ = skb;
661 *temp = head; 663
662 head = skb; 664 if (--nr_skb <= 0) {
665 *more = 1;
666 break;
667 }
663 668
664 pkt_cnt++; 669 pkt_cnt++;
665 if (pkt_cnt > fifo->indicate_max_pkts) 670 if (pkt_cnt > fifo->indicate_max_pkts)
@@ -668,11 +673,9 @@ vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr,
668 } while (vxge_hw_fifo_txdl_next_completed(fifo_hw, 673 } while (vxge_hw_fifo_txdl_next_completed(fifo_hw,
669 &dtr, &t_code) == VXGE_HW_OK); 674 &dtr, &t_code) == VXGE_HW_OK);
670 675
676 *skb_ptr = done_skb;
671 vxge_wake_tx_queue(fifo, skb); 677 vxge_wake_tx_queue(fifo, skb);
672 678
673 if (skb_ptr)
674 *skb_ptr = (void *) head;
675
676 vxge_debug_entryexit(VXGE_TRACE, 679 vxge_debug_entryexit(VXGE_TRACE,
677 "%s: %s:%d Exiting...", 680 "%s: %s:%d Exiting...",
678 fifo->ndev->name, __func__, __LINE__); 681 fifo->ndev->name, __func__, __LINE__);
diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h
index 18d824c3ab93..8b3989bc707f 100644
--- a/drivers/net/vxge/vxge-main.h
+++ b/drivers/net/vxge/vxge-main.h
@@ -428,7 +428,8 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
428 428
429enum vxge_hw_status 429enum vxge_hw_status
430vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr, 430vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr,
431 enum vxge_hw_fifo_tcode t_code, void *userdata, void **skb_ptr); 431 enum vxge_hw_fifo_tcode t_code, void *userdata,
432 struct sk_buff ***skb_ptr, int nr_skbs, int *more);
432 433
433int vxge_close(struct net_device *dev); 434int vxge_close(struct net_device *dev);
434 435
diff --git a/drivers/net/vxge/vxge-traffic.c b/drivers/net/vxge/vxge-traffic.c
index 370f55cbbad7..c249cd25a5d0 100644
--- a/drivers/net/vxge/vxge-traffic.c
+++ b/drivers/net/vxge/vxge-traffic.c
@@ -2508,7 +2508,8 @@ enum vxge_hw_status vxge_hw_vpath_poll_rx(struct __vxge_hw_ring *ring)
2508 * See also: vxge_hw_vpath_poll_tx(). 2508 * See also: vxge_hw_vpath_poll_tx().
2509 */ 2509 */
2510enum vxge_hw_status vxge_hw_vpath_poll_tx(struct __vxge_hw_fifo *fifo, 2510enum vxge_hw_status vxge_hw_vpath_poll_tx(struct __vxge_hw_fifo *fifo,
2511 void **skb_ptr) 2511 struct sk_buff ***skb_ptr, int nr_skb,
2512 int *more)
2512{ 2513{
2513 enum vxge_hw_fifo_tcode t_code; 2514 enum vxge_hw_fifo_tcode t_code;
2514 void *first_txdlh; 2515 void *first_txdlh;
@@ -2520,8 +2521,8 @@ enum vxge_hw_status vxge_hw_vpath_poll_tx(struct __vxge_hw_fifo *fifo,
2520 status = vxge_hw_fifo_txdl_next_completed(fifo, 2521 status = vxge_hw_fifo_txdl_next_completed(fifo,
2521 &first_txdlh, &t_code); 2522 &first_txdlh, &t_code);
2522 if (status == VXGE_HW_OK) 2523 if (status == VXGE_HW_OK)
2523 if (fifo->callback(fifo, first_txdlh, 2524 if (fifo->callback(fifo, first_txdlh, t_code,
2524 t_code, channel->userdata, skb_ptr) != VXGE_HW_OK) 2525 channel->userdata, skb_ptr, nr_skb, more) != VXGE_HW_OK)
2525 status = VXGE_HW_COMPLETIONS_REMAIN; 2526 status = VXGE_HW_COMPLETIONS_REMAIN;
2526 2527
2527 return status; 2528 return status;
diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h
index 8260b91fd795..461742b4442b 100644
--- a/drivers/net/vxge/vxge-traffic.h
+++ b/drivers/net/vxge/vxge-traffic.h
@@ -2326,7 +2326,7 @@ enum vxge_hw_status vxge_hw_vpath_poll_rx(
2326 2326
2327enum vxge_hw_status vxge_hw_vpath_poll_tx( 2327enum vxge_hw_status vxge_hw_vpath_poll_tx(
2328 struct __vxge_hw_fifo *fifoh, 2328 struct __vxge_hw_fifo *fifoh,
2329 void **skb_ptr); 2329 struct sk_buff ***skb_ptr, int nr_skb, int *more);
2330 2330
2331enum vxge_hw_status vxge_hw_vpath_alarm_process( 2331enum vxge_hw_status vxge_hw_vpath_alarm_process(
2332 struct __vxge_hw_vpath_handle *vpath_handle, 2332 struct __vxge_hw_vpath_handle *vpath_handle,