aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulien Grall <julien.grall@citrix.com>2015-05-05 08:15:29 -0400
committerDavid Vrabel <david.vrabel@citrix.com>2015-10-23 09:20:41 -0400
commitd0089e8a0e4c9723d85b01713671358e3d6960df (patch)
treea183a66197f3400504934c8e29c6b04a5c240622
parent30c5d7f0da82f55c86c0a09bf21c0623474bb17f (diff)
net/xen-netback: Make it running on 64KB page granularity
The PV network protocol is using 4KB page granularity. The goal of this patch is to allow a Linux using 64KB page granularity working as a network backend on a non-modified Xen. It's only necessary to adapt the ring size and break skb data in small chunk of 4KB. The rest of the code is relying on the grant table code. Signed-off-by: Julien Grall <julien.grall@citrix.com> Reviewed-by: Wei Liu <wei.liu2@citrix.com> Signed-off-by: David Vrabel <david.vrabel@citrix.com>
-rw-r--r--drivers/net/xen-netback/common.h16
-rw-r--r--drivers/net/xen-netback/netback.c157
2 files changed, 111 insertions, 62 deletions
diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
index a7bf74727116..0333ab0fd926 100644
--- a/drivers/net/xen-netback/common.h
+++ b/drivers/net/xen-netback/common.h
@@ -44,6 +44,7 @@
44#include <xen/interface/grant_table.h> 44#include <xen/interface/grant_table.h>
45#include <xen/grant_table.h> 45#include <xen/grant_table.h>
46#include <xen/xenbus.h> 46#include <xen/xenbus.h>
47#include <xen/page.h>
47#include <linux/debugfs.h> 48#include <linux/debugfs.h>
48 49
49typedef unsigned int pending_ring_idx_t; 50typedef unsigned int pending_ring_idx_t;
@@ -64,8 +65,8 @@ struct pending_tx_info {
64 struct ubuf_info callback_struct; 65 struct ubuf_info callback_struct;
65}; 66};
66 67
67#define XEN_NETIF_TX_RING_SIZE __CONST_RING_SIZE(xen_netif_tx, PAGE_SIZE) 68#define XEN_NETIF_TX_RING_SIZE __CONST_RING_SIZE(xen_netif_tx, XEN_PAGE_SIZE)
68#define XEN_NETIF_RX_RING_SIZE __CONST_RING_SIZE(xen_netif_rx, PAGE_SIZE) 69#define XEN_NETIF_RX_RING_SIZE __CONST_RING_SIZE(xen_netif_rx, XEN_PAGE_SIZE)
69 70
70struct xenvif_rx_meta { 71struct xenvif_rx_meta {
71 int id; 72 int id;
@@ -80,16 +81,21 @@ struct xenvif_rx_meta {
80/* Discriminate from any valid pending_idx value. */ 81/* Discriminate from any valid pending_idx value. */
81#define INVALID_PENDING_IDX 0xFFFF 82#define INVALID_PENDING_IDX 0xFFFF
82 83
83#define MAX_BUFFER_OFFSET PAGE_SIZE 84#define MAX_BUFFER_OFFSET XEN_PAGE_SIZE
84 85
85#define MAX_PENDING_REQS XEN_NETIF_TX_RING_SIZE 86#define MAX_PENDING_REQS XEN_NETIF_TX_RING_SIZE
86 87
88/* The maximum number of frags is derived from the size of a grant (same
89 * as a Xen page size for now).
90 */
91#define MAX_XEN_SKB_FRAGS (65536 / XEN_PAGE_SIZE + 1)
92
87/* It's possible for an skb to have a maximal number of frags 93/* It's possible for an skb to have a maximal number of frags
88 * but still be less than MAX_BUFFER_OFFSET in size. Thus the 94 * but still be less than MAX_BUFFER_OFFSET in size. Thus the
89 * worst-case number of copy operations is MAX_SKB_FRAGS per 95 * worst-case number of copy operations is MAX_XEN_SKB_FRAGS per
90 * ring slot. 96 * ring slot.
91 */ 97 */
92#define MAX_GRANT_COPY_OPS (MAX_SKB_FRAGS * XEN_NETIF_RX_RING_SIZE) 98#define MAX_GRANT_COPY_OPS (MAX_XEN_SKB_FRAGS * XEN_NETIF_RX_RING_SIZE)
93 99
94#define NETBACK_INVALID_HANDLE -1 100#define NETBACK_INVALID_HANDLE -1
95 101
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index c4e6c025d64d..e481f3710bd3 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -152,9 +152,9 @@ static inline pending_ring_idx_t pending_index(unsigned i)
152static int xenvif_rx_ring_slots_needed(struct xenvif *vif) 152static int xenvif_rx_ring_slots_needed(struct xenvif *vif)
153{ 153{
154 if (vif->gso_mask) 154 if (vif->gso_mask)
155 return DIV_ROUND_UP(vif->dev->gso_max_size, PAGE_SIZE) + 1; 155 return DIV_ROUND_UP(vif->dev->gso_max_size, XEN_PAGE_SIZE) + 1;
156 else 156 else
157 return DIV_ROUND_UP(vif->dev->mtu, PAGE_SIZE); 157 return DIV_ROUND_UP(vif->dev->mtu, XEN_PAGE_SIZE);
158} 158}
159 159
160static bool xenvif_rx_ring_slots_available(struct xenvif_queue *queue) 160static bool xenvif_rx_ring_slots_available(struct xenvif_queue *queue)
@@ -274,6 +274,80 @@ static struct xenvif_rx_meta *get_next_rx_buffer(struct xenvif_queue *queue,
274 return meta; 274 return meta;
275} 275}
276 276
277struct gop_frag_copy {
278 struct xenvif_queue *queue;
279 struct netrx_pending_operations *npo;
280 struct xenvif_rx_meta *meta;
281 int head;
282 int gso_type;
283
284 struct page *page;
285};
286
287static void xenvif_setup_copy_gop(unsigned long gfn,
288 unsigned int offset,
289 unsigned int *len,
290 struct gop_frag_copy *info)
291{
292 struct gnttab_copy *copy_gop;
293 struct xen_page_foreign *foreign;
294 /* Convenient aliases */
295 struct xenvif_queue *queue = info->queue;
296 struct netrx_pending_operations *npo = info->npo;
297 struct page *page = info->page;
298
299 BUG_ON(npo->copy_off > MAX_BUFFER_OFFSET);
300
301 if (npo->copy_off == MAX_BUFFER_OFFSET)
302 info->meta = get_next_rx_buffer(queue, npo);
303
304 if (npo->copy_off + *len > MAX_BUFFER_OFFSET)
305 *len = MAX_BUFFER_OFFSET - npo->copy_off;
306
307 copy_gop = npo->copy + npo->copy_prod++;
308 copy_gop->flags = GNTCOPY_dest_gref;
309 copy_gop->len = *len;
310
311 foreign = xen_page_foreign(page);
312 if (foreign) {
313 copy_gop->source.domid = foreign->domid;
314 copy_gop->source.u.ref = foreign->gref;
315 copy_gop->flags |= GNTCOPY_source_gref;
316 } else {
317 copy_gop->source.domid = DOMID_SELF;
318 copy_gop->source.u.gmfn = gfn;
319 }
320 copy_gop->source.offset = offset;
321
322 copy_gop->dest.domid = queue->vif->domid;
323 copy_gop->dest.offset = npo->copy_off;
324 copy_gop->dest.u.ref = npo->copy_gref;
325
326 npo->copy_off += *len;
327 info->meta->size += *len;
328
329 /* Leave a gap for the GSO descriptor. */
330 if (info->head && ((1 << info->gso_type) & queue->vif->gso_mask))
331 queue->rx.req_cons++;
332
333 info->head = 0; /* There must be something in this buffer now */
334}
335
336static void xenvif_gop_frag_copy_grant(unsigned long gfn,
337 unsigned offset,
338 unsigned int len,
339 void *data)
340{
341 unsigned int bytes;
342
343 while (len) {
344 bytes = len;
345 xenvif_setup_copy_gop(gfn, offset, &bytes, data);
346 offset += bytes;
347 len -= bytes;
348 }
349}
350
277/* 351/*
278 * Set up the grant operations for this fragment. If it's a flipping 352 * Set up the grant operations for this fragment. If it's a flipping
279 * interface, we also set up the unmap request from here. 353 * interface, we also set up the unmap request from here.
@@ -283,83 +357,52 @@ static void xenvif_gop_frag_copy(struct xenvif_queue *queue, struct sk_buff *skb
283 struct page *page, unsigned long size, 357 struct page *page, unsigned long size,
284 unsigned long offset, int *head) 358 unsigned long offset, int *head)
285{ 359{
286 struct gnttab_copy *copy_gop; 360 struct gop_frag_copy info = {
287 struct xenvif_rx_meta *meta; 361 .queue = queue,
362 .npo = npo,
363 .head = *head,
364 .gso_type = XEN_NETIF_GSO_TYPE_NONE,
365 };
288 unsigned long bytes; 366 unsigned long bytes;
289 int gso_type = XEN_NETIF_GSO_TYPE_NONE;
290 367
291 if (skb_is_gso(skb)) { 368 if (skb_is_gso(skb)) {
292 if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) 369 if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
293 gso_type = XEN_NETIF_GSO_TYPE_TCPV4; 370 info.gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
294 else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) 371 else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
295 gso_type = XEN_NETIF_GSO_TYPE_TCPV6; 372 info.gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
296 } 373 }
297 374
298 /* Data must not cross a page boundary. */ 375 /* Data must not cross a page boundary. */
299 BUG_ON(size + offset > PAGE_SIZE<<compound_order(page)); 376 BUG_ON(size + offset > PAGE_SIZE<<compound_order(page));
300 377
301 meta = npo->meta + npo->meta_prod - 1; 378 info.meta = npo->meta + npo->meta_prod - 1;
302 379
303 /* Skip unused frames from start of page */ 380 /* Skip unused frames from start of page */
304 page += offset >> PAGE_SHIFT; 381 page += offset >> PAGE_SHIFT;
305 offset &= ~PAGE_MASK; 382 offset &= ~PAGE_MASK;
306 383
307 while (size > 0) { 384 while (size > 0) {
308 struct xen_page_foreign *foreign;
309
310 BUG_ON(offset >= PAGE_SIZE); 385 BUG_ON(offset >= PAGE_SIZE);
311 BUG_ON(npo->copy_off > MAX_BUFFER_OFFSET);
312
313 if (npo->copy_off == MAX_BUFFER_OFFSET)
314 meta = get_next_rx_buffer(queue, npo);
315 386
316 bytes = PAGE_SIZE - offset; 387 bytes = PAGE_SIZE - offset;
317 if (bytes > size) 388 if (bytes > size)
318 bytes = size; 389 bytes = size;
319 390
320 if (npo->copy_off + bytes > MAX_BUFFER_OFFSET) 391 info.page = page;
321 bytes = MAX_BUFFER_OFFSET - npo->copy_off; 392 gnttab_foreach_grant_in_range(page, offset, bytes,
322 393 xenvif_gop_frag_copy_grant,
323 copy_gop = npo->copy + npo->copy_prod++; 394 &info);
324 copy_gop->flags = GNTCOPY_dest_gref;
325 copy_gop->len = bytes;
326
327 foreign = xen_page_foreign(page);
328 if (foreign) {
329 copy_gop->source.domid = foreign->domid;
330 copy_gop->source.u.ref = foreign->gref;
331 copy_gop->flags |= GNTCOPY_source_gref;
332 } else {
333 copy_gop->source.domid = DOMID_SELF;
334 copy_gop->source.u.gmfn =
335 virt_to_gfn(page_address(page));
336 }
337 copy_gop->source.offset = offset;
338
339 copy_gop->dest.domid = queue->vif->domid;
340 copy_gop->dest.offset = npo->copy_off;
341 copy_gop->dest.u.ref = npo->copy_gref;
342
343 npo->copy_off += bytes;
344 meta->size += bytes;
345
346 offset += bytes;
347 size -= bytes; 395 size -= bytes;
396 offset = 0;
348 397
349 /* Next frame */ 398 /* Next page */
350 if (offset == PAGE_SIZE && size) { 399 if (size) {
351 BUG_ON(!PageCompound(page)); 400 BUG_ON(!PageCompound(page));
352 page++; 401 page++;
353 offset = 0;
354 } 402 }
355
356 /* Leave a gap for the GSO descriptor. */
357 if (*head && ((1 << gso_type) & queue->vif->gso_mask))
358 queue->rx.req_cons++;
359
360 *head = 0; /* There must be something in this buffer now. */
361
362 } 403 }
404
405 *head = info.head;
363} 406}
364 407
365/* 408/*
@@ -758,7 +801,7 @@ static int xenvif_count_requests(struct xenvif_queue *queue,
758 first->size -= txp->size; 801 first->size -= txp->size;
759 slots++; 802 slots++;
760 803
761 if (unlikely((txp->offset + txp->size) > PAGE_SIZE)) { 804 if (unlikely((txp->offset + txp->size) > XEN_PAGE_SIZE)) {
762 netdev_err(queue->vif->dev, "Cross page boundary, txp->offset: %u, size: %u\n", 805 netdev_err(queue->vif->dev, "Cross page boundary, txp->offset: %u, size: %u\n",
763 txp->offset, txp->size); 806 txp->offset, txp->size);
764 xenvif_fatal_tx_err(queue->vif); 807 xenvif_fatal_tx_err(queue->vif);
@@ -1339,11 +1382,11 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
1339 } 1382 }
1340 1383
1341 /* No crossing a page as the payload mustn't fragment. */ 1384 /* No crossing a page as the payload mustn't fragment. */
1342 if (unlikely((txreq.offset + txreq.size) > PAGE_SIZE)) { 1385 if (unlikely((txreq.offset + txreq.size) > XEN_PAGE_SIZE)) {
1343 netdev_err(queue->vif->dev, 1386 netdev_err(queue->vif->dev,
1344 "txreq.offset: %u, size: %u, end: %lu\n", 1387 "txreq.offset: %u, size: %u, end: %lu\n",
1345 txreq.offset, txreq.size, 1388 txreq.offset, txreq.size,
1346 (unsigned long)(txreq.offset&~PAGE_MASK) + txreq.size); 1389 (unsigned long)(txreq.offset&~XEN_PAGE_MASK) + txreq.size);
1347 xenvif_fatal_tx_err(queue->vif); 1390 xenvif_fatal_tx_err(queue->vif);
1348 break; 1391 break;
1349 } 1392 }
@@ -1409,7 +1452,7 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
1409 virt_to_gfn(skb->data); 1452 virt_to_gfn(skb->data);
1410 queue->tx_copy_ops[*copy_ops].dest.domid = DOMID_SELF; 1453 queue->tx_copy_ops[*copy_ops].dest.domid = DOMID_SELF;
1411 queue->tx_copy_ops[*copy_ops].dest.offset = 1454 queue->tx_copy_ops[*copy_ops].dest.offset =
1412 offset_in_page(skb->data); 1455 offset_in_page(skb->data) & ~XEN_PAGE_MASK;
1413 1456
1414 queue->tx_copy_ops[*copy_ops].len = data_len; 1457 queue->tx_copy_ops[*copy_ops].len = data_len;
1415 queue->tx_copy_ops[*copy_ops].flags = GNTCOPY_source_gref; 1458 queue->tx_copy_ops[*copy_ops].flags = GNTCOPY_source_gref;
@@ -1894,7 +1937,7 @@ int xenvif_map_frontend_rings(struct xenvif_queue *queue,
1894 goto err; 1937 goto err;
1895 1938
1896 txs = (struct xen_netif_tx_sring *)addr; 1939 txs = (struct xen_netif_tx_sring *)addr;
1897 BACK_RING_INIT(&queue->tx, txs, PAGE_SIZE); 1940 BACK_RING_INIT(&queue->tx, txs, XEN_PAGE_SIZE);
1898 1941
1899 err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(queue->vif), 1942 err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(queue->vif),
1900 &rx_ring_ref, 1, &addr); 1943 &rx_ring_ref, 1, &addr);
@@ -1902,7 +1945,7 @@ int xenvif_map_frontend_rings(struct xenvif_queue *queue,
1902 goto err; 1945 goto err;
1903 1946
1904 rxs = (struct xen_netif_rx_sring *)addr; 1947 rxs = (struct xen_netif_rx_sring *)addr;
1905 BACK_RING_INIT(&queue->rx, rxs, PAGE_SIZE); 1948 BACK_RING_INIT(&queue->rx, rxs, XEN_PAGE_SIZE);
1906 1949
1907 return 0; 1950 return 0;
1908 1951