diff options
-rw-r--r-- | drivers/net/ethernet/marvell/skge.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/realtek/8139cp.c | 2 | ||||
-rw-r--r-- | include/linux/netdevice.h | 15 | ||||
-rw-r--r-- | net/core/dev.c | 38 |
4 files changed, 42 insertions, 15 deletions
diff --git a/drivers/net/ethernet/marvell/skge.c b/drivers/net/ethernet/marvell/skge.c index 3f7dab46626b..9b9c2ac5c4c2 100644 --- a/drivers/net/ethernet/marvell/skge.c +++ b/drivers/net/ethernet/marvell/skge.c | |||
@@ -3189,7 +3189,7 @@ static int skge_poll(struct napi_struct *napi, int to_do) | |||
3189 | if (work_done < to_do) { | 3189 | if (work_done < to_do) { |
3190 | unsigned long flags; | 3190 | unsigned long flags; |
3191 | 3191 | ||
3192 | napi_gro_flush(napi); | 3192 | napi_gro_flush(napi, false); |
3193 | spin_lock_irqsave(&hw->hw_lock, flags); | 3193 | spin_lock_irqsave(&hw->hw_lock, flags); |
3194 | __napi_complete(napi); | 3194 | __napi_complete(napi); |
3195 | hw->intr_mask |= napimask[skge->port]; | 3195 | hw->intr_mask |= napimask[skge->port]; |
diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c index 995d0cfc4c06..1c818254b7be 100644 --- a/drivers/net/ethernet/realtek/8139cp.c +++ b/drivers/net/ethernet/realtek/8139cp.c | |||
@@ -563,7 +563,7 @@ rx_next: | |||
563 | if (cpr16(IntrStatus) & cp_rx_intr_mask) | 563 | if (cpr16(IntrStatus) & cp_rx_intr_mask) |
564 | goto rx_status_loop; | 564 | goto rx_status_loop; |
565 | 565 | ||
566 | napi_gro_flush(napi); | 566 | napi_gro_flush(napi, false); |
567 | spin_lock_irqsave(&cp->lock, flags); | 567 | spin_lock_irqsave(&cp->lock, flags); |
568 | __napi_complete(napi); | 568 | __napi_complete(napi); |
569 | cpw16_f(IntrMask, cp_intr_mask); | 569 | cpw16_f(IntrMask, cp_intr_mask); |
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index a659fd0ba965..0a36fff75bd5 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -1497,19 +1497,22 @@ struct napi_gro_cb { | |||
1497 | /* This indicates where we are processing relative to skb->data. */ | 1497 | /* This indicates where we are processing relative to skb->data. */ |
1498 | int data_offset; | 1498 | int data_offset; |
1499 | 1499 | ||
1500 | /* This is non-zero if the packet may be of the same flow. */ | ||
1501 | int same_flow; | ||
1502 | |||
1503 | /* This is non-zero if the packet cannot be merged with the new skb. */ | 1500 | /* This is non-zero if the packet cannot be merged with the new skb. */ |
1504 | int flush; | 1501 | int flush; |
1505 | 1502 | ||
1506 | /* Number of segments aggregated. */ | 1503 | /* Number of segments aggregated. */ |
1507 | int count; | 1504 | u16 count; |
1505 | |||
1506 | /* This is non-zero if the packet may be of the same flow. */ | ||
1507 | u8 same_flow; | ||
1508 | 1508 | ||
1509 | /* Free the skb? */ | 1509 | /* Free the skb? */ |
1510 | int free; | 1510 | u8 free; |
1511 | #define NAPI_GRO_FREE 1 | 1511 | #define NAPI_GRO_FREE 1 |
1512 | #define NAPI_GRO_FREE_STOLEN_HEAD 2 | 1512 | #define NAPI_GRO_FREE_STOLEN_HEAD 2 |
1513 | |||
1514 | /* jiffies when first packet was created/queued */ | ||
1515 | unsigned long age; | ||
1513 | }; | 1516 | }; |
1514 | 1517 | ||
1515 | #define NAPI_GRO_CB(skb) ((struct napi_gro_cb *)(skb)->cb) | 1518 | #define NAPI_GRO_CB(skb) ((struct napi_gro_cb *)(skb)->cb) |
@@ -2156,7 +2159,7 @@ extern gro_result_t dev_gro_receive(struct napi_struct *napi, | |||
2156 | extern gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb); | 2159 | extern gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb); |
2157 | extern gro_result_t napi_gro_receive(struct napi_struct *napi, | 2160 | extern gro_result_t napi_gro_receive(struct napi_struct *napi, |
2158 | struct sk_buff *skb); | 2161 | struct sk_buff *skb); |
2159 | extern void napi_gro_flush(struct napi_struct *napi); | 2162 | extern void napi_gro_flush(struct napi_struct *napi, bool flush_old); |
2160 | extern struct sk_buff * napi_get_frags(struct napi_struct *napi); | 2163 | extern struct sk_buff * napi_get_frags(struct napi_struct *napi); |
2161 | extern gro_result_t napi_frags_finish(struct napi_struct *napi, | 2164 | extern gro_result_t napi_frags_finish(struct napi_struct *napi, |
2162 | struct sk_buff *skb, | 2165 | struct sk_buff *skb, |
diff --git a/net/core/dev.c b/net/core/dev.c index de2bad717d56..d44668f63c88 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -3471,17 +3471,31 @@ out: | |||
3471 | return netif_receive_skb(skb); | 3471 | return netif_receive_skb(skb); |
3472 | } | 3472 | } |
3473 | 3473 | ||
3474 | inline void napi_gro_flush(struct napi_struct *napi) | 3474 | /* napi->gro_list contains packets ordered by age. |
3475 | * youngest packets at the head of it. | ||
3476 | * Complete skbs in reverse order to reduce latencies. | ||
3477 | */ | ||
3478 | void napi_gro_flush(struct napi_struct *napi, bool flush_old) | ||
3475 | { | 3479 | { |
3476 | struct sk_buff *skb, *next; | 3480 | struct sk_buff *skb, *prev = NULL; |
3477 | 3481 | ||
3478 | for (skb = napi->gro_list; skb; skb = next) { | 3482 | /* scan list and build reverse chain */ |
3479 | next = skb->next; | 3483 | for (skb = napi->gro_list; skb != NULL; skb = skb->next) { |
3484 | skb->prev = prev; | ||
3485 | prev = skb; | ||
3486 | } | ||
3487 | |||
3488 | for (skb = prev; skb; skb = prev) { | ||
3480 | skb->next = NULL; | 3489 | skb->next = NULL; |
3490 | |||
3491 | if (flush_old && NAPI_GRO_CB(skb)->age == jiffies) | ||
3492 | return; | ||
3493 | |||
3494 | prev = skb->prev; | ||
3481 | napi_gro_complete(skb); | 3495 | napi_gro_complete(skb); |
3496 | napi->gro_count--; | ||
3482 | } | 3497 | } |
3483 | 3498 | ||
3484 | napi->gro_count = 0; | ||
3485 | napi->gro_list = NULL; | 3499 | napi->gro_list = NULL; |
3486 | } | 3500 | } |
3487 | EXPORT_SYMBOL(napi_gro_flush); | 3501 | EXPORT_SYMBOL(napi_gro_flush); |
@@ -3542,6 +3556,7 @@ enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) | |||
3542 | 3556 | ||
3543 | napi->gro_count++; | 3557 | napi->gro_count++; |
3544 | NAPI_GRO_CB(skb)->count = 1; | 3558 | NAPI_GRO_CB(skb)->count = 1; |
3559 | NAPI_GRO_CB(skb)->age = jiffies; | ||
3545 | skb_shinfo(skb)->gso_size = skb_gro_len(skb); | 3560 | skb_shinfo(skb)->gso_size = skb_gro_len(skb); |
3546 | skb->next = napi->gro_list; | 3561 | skb->next = napi->gro_list; |
3547 | napi->gro_list = skb; | 3562 | napi->gro_list = skb; |
@@ -3878,7 +3893,7 @@ void napi_complete(struct napi_struct *n) | |||
3878 | if (unlikely(test_bit(NAPI_STATE_NPSVC, &n->state))) | 3893 | if (unlikely(test_bit(NAPI_STATE_NPSVC, &n->state))) |
3879 | return; | 3894 | return; |
3880 | 3895 | ||
3881 | napi_gro_flush(n); | 3896 | napi_gro_flush(n, false); |
3882 | local_irq_save(flags); | 3897 | local_irq_save(flags); |
3883 | __napi_complete(n); | 3898 | __napi_complete(n); |
3884 | local_irq_restore(flags); | 3899 | local_irq_restore(flags); |
@@ -3983,8 +3998,17 @@ static void net_rx_action(struct softirq_action *h) | |||
3983 | local_irq_enable(); | 3998 | local_irq_enable(); |
3984 | napi_complete(n); | 3999 | napi_complete(n); |
3985 | local_irq_disable(); | 4000 | local_irq_disable(); |
3986 | } else | 4001 | } else { |
4002 | if (n->gro_list) { | ||
4003 | /* flush too old packets | ||
4004 | * If HZ < 1000, flush all packets. | ||
4005 | */ | ||
4006 | local_irq_enable(); | ||
4007 | napi_gro_flush(n, HZ >= 1000); | ||
4008 | local_irq_disable(); | ||
4009 | } | ||
3987 | list_move_tail(&n->poll_list, &sd->poll_list); | 4010 | list_move_tail(&n->poll_list, &sd->poll_list); |
4011 | } | ||
3988 | } | 4012 | } |
3989 | 4013 | ||
3990 | netpoll_poll_unlock(have); | 4014 | netpoll_poll_unlock(have); |