aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@vyatta.com>2010-05-04 12:58:56 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-05-11 14:36:10 -0400
commitb220f5f925b8938747bfe4a61e362d132bdd9544 (patch)
treea2611046dbe3b5de730e843a1fb2694d38aaf7a5
parent6048718d719f460abba8eaff1c0122247b2c3d91 (diff)
Staging: hv: add transmit flow control
Keep track of the number of pages sent over transmit and stop before going over. Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Acked-by: Hank Janssen <hjanssen@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/staging/hv/netvsc_drv.c72
1 files changed, 27 insertions, 45 deletions
diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/staging/hv/netvsc_drv.c
index 4124979835a..a6ca01025e4 100644
--- a/drivers/staging/hv/netvsc_drv.c
+++ b/drivers/staging/hv/netvsc_drv.c
@@ -43,6 +43,7 @@
43struct net_device_context { 43struct net_device_context {
44 /* point back to our device context */ 44 /* point back to our device context */
45 struct vm_device *device_ctx; 45 struct vm_device *device_ctx;
46 unsigned long avail;
46}; 47};
47 48
48struct netvsc_driver_context { 49struct netvsc_driver_context {
@@ -52,8 +53,10 @@ struct netvsc_driver_context {
52 struct netvsc_driver drv_obj; 53 struct netvsc_driver drv_obj;
53}; 54};
54 55
55/* Need at least MAX_SKB_FRAGS (18) + 1 56#define PACKET_PAGES_LOWATER 8
56 to handle worst case fragmented packet */ 57/* Need this many pages to handle worst case fragmented packet */
58#define PACKET_PAGES_HIWATER (MAX_SKB_FRAGS + 2)
59
57static int ring_size = roundup_pow_of_two(2*MAX_SKB_FRAGS+1); 60static int ring_size = roundup_pow_of_two(2*MAX_SKB_FRAGS+1);
58module_param(ring_size, int, S_IRUGO); 61module_param(ring_size, int, S_IRUGO);
59MODULE_PARM_DESC(ring_size, "Ring buffer size (# of pages)"); 62MODULE_PARM_DESC(ring_size, "Ring buffer size (# of pages)");
@@ -122,14 +125,13 @@ static void netvsc_xmit_completion(void *context)
122 125
123 if (skb) { 126 if (skb) {
124 struct net_device *net = skb->dev; 127 struct net_device *net = skb->dev;
125 dev_kfree_skb_any(skb); 128 struct net_device_context *net_device_ctx = netdev_priv(net);
129 unsigned int num_pages = skb_shinfo(skb)->nr_frags + 2;
126 130
127 if (netif_queue_stopped(net)) { 131 dev_kfree_skb_any(skb);
128 DPRINT_INFO(NETVSC_DRV, "net device (%p) waking up...",
129 net);
130 132
131 netif_wake_queue(net); 133 if ((net_device_ctx->avail += num_pages) >= PACKET_PAGES_HIWATER)
132 } 134 netif_wake_queue(net);
133 } 135 }
134 136
135 DPRINT_EXIT(NETVSC_DRV); 137 DPRINT_EXIT(NETVSC_DRV);
@@ -146,7 +148,6 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
146 struct hv_netvsc_packet *packet; 148 struct hv_netvsc_packet *packet;
147 int ret; 149 int ret;
148 unsigned int i, num_pages; 150 unsigned int i, num_pages;
149 int retries = 0;
150 151
151 DPRINT_ENTER(NETVSC_DRV); 152 DPRINT_ENTER(NETVSC_DRV);
152 153
@@ -155,14 +156,20 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
155 156
156 /* Add 1 for skb->data and additional one for RNDIS */ 157 /* Add 1 for skb->data and additional one for RNDIS */
157 num_pages = skb_shinfo(skb)->nr_frags + 1 + 1; 158 num_pages = skb_shinfo(skb)->nr_frags + 1 + 1;
159 if (num_pages > net_device_ctx->avail)
160 return NETDEV_TX_BUSY;
158 161
159 /* Allocate a netvsc packet based on # of frags. */ 162 /* Allocate a netvsc packet based on # of frags. */
160 packet = kzalloc(sizeof(struct hv_netvsc_packet) + 163 packet = kzalloc(sizeof(struct hv_netvsc_packet) +
161 (num_pages * sizeof(struct hv_page_buffer)) + 164 (num_pages * sizeof(struct hv_page_buffer)) +
162 net_drv_obj->RequestExtSize, GFP_ATOMIC); 165 net_drv_obj->RequestExtSize, GFP_ATOMIC);
163 if (!packet) { 166 if (!packet) {
167 /* out of memory, silently drop packet */
164 DPRINT_ERR(NETVSC_DRV, "unable to allocate hv_netvsc_packet"); 168 DPRINT_ERR(NETVSC_DRV, "unable to allocate hv_netvsc_packet");
165 return -1; 169
170 dev_kfree_skb(skb);
171 net->stats.tx_dropped++;
172 return NETDEV_TX_OK;
166 } 173 }
167 174
168 packet->Extension = (void *)(unsigned long)packet + 175 packet->Extension = (void *)(unsigned long)packet +
@@ -198,52 +205,26 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
198 packet->Completion.Send.SendCompletionContext = packet; 205 packet->Completion.Send.SendCompletionContext = packet;
199 packet->Completion.Send.SendCompletionTid = (unsigned long)skb; 206 packet->Completion.Send.SendCompletionTid = (unsigned long)skb;
200 207
201retry_send:
202 ret = net_drv_obj->OnSend(&net_device_ctx->device_ctx->device_obj, 208 ret = net_drv_obj->OnSend(&net_device_ctx->device_ctx->device_obj,
203 packet); 209 packet);
204
205 if (ret == 0) { 210 if (ret == 0) {
206 ret = NETDEV_TX_OK;
207 net->stats.tx_bytes += skb->len; 211 net->stats.tx_bytes += skb->len;
208 net->stats.tx_packets++; 212 net->stats.tx_packets++;
209 } else {
210 retries++;
211 if (retries < 4) {
212 DPRINT_ERR(NETVSC_DRV, "unable to send..."
213 "retrying %d...", retries);
214 udelay(100);
215 goto retry_send;
216 }
217 213
218 /* no more room or we are shutting down */ 214 DPRINT_DBG(NETVSC_DRV, "# of xmits %lu total size %lu",
219 DPRINT_ERR(NETVSC_DRV, "unable to send (%d)..." 215 net->stats.tx_packets,
220 "marking net device (%p) busy", ret, net); 216 net->stats.tx_bytes);
221 DPRINT_INFO(NETVSC_DRV, "net device (%p) stopping", net);
222 217
223 ret = NETDEV_TX_BUSY; 218 if ((net_device_ctx->avail -= num_pages) < PACKET_PAGES_LOWATER)
219 netif_stop_queue(net);
220 } else {
221 /* we are shutting down or bus overloaded, just drop packet */
224 net->stats.tx_dropped++; 222 net->stats.tx_dropped++;
225 223 netvsc_xmit_completion(packet);
226 netif_stop_queue(net);
227
228 /*
229 * Null it since the caller will free it instead of the
230 * completion routine
231 */
232 packet->Completion.Send.SendCompletionTid = 0;
233
234 /*
235 * Release the resources since we will not get any send
236 * completion
237 */
238 netvsc_xmit_completion((void *)packet);
239 } 224 }
240 225
241 DPRINT_DBG(NETVSC_DRV, "# of xmits %lu total size %lu",
242 net->stats.tx_packets,
243 net->stats.tx_bytes);
244
245 DPRINT_EXIT(NETVSC_DRV); 226 DPRINT_EXIT(NETVSC_DRV);
246 return ret; 227 return NETDEV_TX_OK;
247} 228}
248 229
249/* 230/*
@@ -382,6 +363,7 @@ static int netvsc_probe(struct device *device)
382 363
383 net_device_ctx = netdev_priv(net); 364 net_device_ctx = netdev_priv(net);
384 net_device_ctx->device_ctx = device_ctx; 365 net_device_ctx->device_ctx = device_ctx;
366 net_device_ctx->avail = ring_size;
385 dev_set_drvdata(device, net); 367 dev_set_drvdata(device, net);
386 368
387 /* Notify the netvsc driver of the new device */ 369 /* Notify the netvsc driver of the new device */