# HG changeset patch # User sos22@xxxxxxxxxxxxxxxxxxxx # Date 1153175686 -3600 # Node ID 7053592c928b488b0c653fb25ce6f73bc6deeb05 # Parent 4726fd416506a34da96888bac0e7c9772c5037e8 Copying netback. diff -r 4726fd416506 -r 7053592c928b linux-2.6-xen-sparse/drivers/xen/netback/common.h --- a/linux-2.6-xen-sparse/drivers/xen/netback/common.h Mon Jul 17 22:55:34 2006 +0100 +++ b/linux-2.6-xen-sparse/drivers/xen/netback/common.h Mon Jul 17 23:34:46 2006 +0100 @@ -59,6 +59,8 @@ typedef struct netif_st { /* Unique identifier for this interface. */ domid_t domid; unsigned int handle; + unsigned int rx_flags; + unsigned int copy_delivery_offset; u8 fe_dev_addr[6]; diff -r 4726fd416506 -r 7053592c928b linux-2.6-xen-sparse/drivers/xen/netback/netback.c --- a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c Mon Jul 17 22:55:34 2006 +0100 +++ b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c Mon Jul 17 23:34:46 2006 +0100 @@ -63,13 +63,17 @@ static struct timer_list net_timer; #define MAX_PENDING_REQS 256 static struct sk_buff_head rx_queue; -static multicall_entry_t rx_mcl[NET_RX_RING_SIZE+1]; +static multicall_entry_t rx_mcl[NET_RX_RING_SIZE+3]; static mmu_update_t rx_mmu[NET_RX_RING_SIZE]; -static gnttab_transfer_t grant_rx_op[NET_RX_RING_SIZE]; +static gnttab_transfer_t grant_rx_trans_op[NET_RX_RING_SIZE]; +static gnttab_map_grant_ref_t grant_rx_map_op[NET_RX_RING_SIZE]; +static gnttab_unmap_grant_ref_t grant_rx_unmap_op[NET_RX_RING_SIZE]; static unsigned char rx_notify[NR_IRQS]; static unsigned long mmap_vstart; #define MMAP_VADDR(_req) (mmap_vstart + ((_req) * PAGE_SIZE)) + +static void *rx_mmap_area; #define PKT_PROT_LEN 64 @@ -96,13 +100,12 @@ static struct list_head net_schedule_lis static struct list_head net_schedule_list; static spinlock_t net_schedule_list_lock; +static unsigned long alloc_mfn(void) +{ #define MAX_MFN_ALLOC 64 -static unsigned long mfn_list[MAX_MFN_ALLOC]; -static unsigned int alloc_index = 0; -static DEFINE_SPINLOCK(mfn_lock); - -static unsigned long alloc_mfn(void) -{ + static unsigned long mfn_list[MAX_MFN_ALLOC]; + static unsigned int alloc_index = 0; + static DEFINE_SPINLOCK(mfn_lock); unsigned long mfn = 0, flags; struct xen_memory_reservation reservation = { .nr_extents = MAX_MFN_ALLOC, @@ -218,73 +221,122 @@ static void net_rx_action(unsigned long u16 size, id, irq, flags; multicall_entry_t *mcl; mmu_update_t *mmu; - gnttab_transfer_t *gop; + gnttab_transfer_t *flip_gop; + gnttab_map_grant_ref_t *map_gop; + gnttab_unmap_grant_ref_t *unmap_gop; unsigned long vdata, old_mfn, new_mfn; - struct sk_buff_head rxq; + struct sk_buff_head flip_rxq, copy_rxq; struct sk_buff *skb; u16 notify_list[NET_RX_RING_SIZE]; int notify_nr = 0; int ret; - - skb_queue_head_init(&rxq); + void *rx_mmap_ptr; + netif_rx_request_t *rx_req_p; + void *remote_data; + + skb_queue_head_init(&flip_rxq); + skb_queue_head_init(©_rxq); mcl = rx_mcl; mmu = rx_mmu; - gop = grant_rx_op; - + flip_gop = grant_rx_trans_op; + map_gop = grant_rx_map_op; + rx_mmap_ptr = rx_mmap_area; + + /* Split the incoming skbs according to whether they need to + be page flipped or copied, and build up the first set of + hypercall arguments. */ while ((skb = skb_dequeue(&rx_queue)) != NULL) { netif = netdev_priv(skb->dev); - vdata = (unsigned long)skb->data; - old_mfn = virt_to_mfn(vdata); - - if (!xen_feature(XENFEAT_auto_translated_physmap)) { - /* Memory squeeze? Back off for an arbitrary while. */ - if ((new_mfn = alloc_mfn()) == 0) { - if ( net_ratelimit() ) - WPRINTK("Memory squeeze in netback " - "driver.\n"); - mod_timer(&net_timer, jiffies + HZ); - skb_queue_head(&rx_queue, skb); + size = skb->tail - skb->data; + rx_req_p = RING_GET_REQUEST(&netif->rx, + netif->rx.req_cons); + + if (netif->rx_flags && + (rx_req_p->flags & NETIF_RXRF_copy_packet)) { + if (map_gop - grant_rx_map_op == + ARRAY_SIZE(grant_rx_map_op)) break; + if (size > PAGE_SIZE - netif->copy_delivery_offset) { + if (net_ratelimit()) { + printk("Discarding jumbogram to copying interface\n"); + } + netif_put(netif); + dev_kfree_skb(skb); + continue; } - /* - * Set the new P2M table entry before reassigning - * the old data page. Heed the comment in - * pgtable-2level.h:pte_page(). :-) - */ - set_phys_to_machine( - __pa(skb->data) >> PAGE_SHIFT, - new_mfn); - - MULTI_update_va_mapping(mcl, vdata, - pfn_pte_ma(new_mfn, - PAGE_KERNEL), 0); - mcl++; - - mmu->ptr = ((maddr_t)new_mfn << PAGE_SHIFT) | - MMU_MACHPHYS_UPDATE; - mmu->val = __pa(vdata) >> PAGE_SHIFT; - mmu++; - } - - gop->mfn = old_mfn; - gop->domid = netif->domid; - gop->ref = RING_GET_REQUEST( - &netif->rx, netif->rx.req_cons)->gref; - netif->rx.req_cons++; - gop++; - - __skb_queue_tail(&rxq, skb); - - /* Filled the batch queue? */ - if ((gop - grant_rx_op) == ARRAY_SIZE(grant_rx_op)) - break; - } - - if (!xen_feature(XENFEAT_auto_translated_physmap)) { - if (mcl == rx_mcl) - return; - + map_gop->host_addr = (unsigned long)rx_mmap_ptr; + map_gop->dom = netif->domid; + map_gop->ref = rx_req_p->gref; + map_gop->flags = GNTMAP_host_map; + map_gop++; + rx_mmap_ptr += PAGE_SIZE; + + memcpy(skb->cb, rx_req_p, sizeof(*rx_req_p)); + + netif->rx.req_cons++; + __skb_queue_tail(©_rxq, skb); + } else { + /* Filled the batch queue? */ + if ((flip_gop - grant_rx_trans_op) == + ARRAY_SIZE(grant_rx_trans_op)) + break; + + vdata = (unsigned long)skb->data; + old_mfn = virt_to_mfn(vdata); + + if (!xen_feature(XENFEAT_auto_translated_physmap)) { + /* Memory squeeze? Back off for an + * arbitrary while. */ + if ((new_mfn = alloc_mfn()) == 0) { + if ( net_ratelimit() ) + WPRINTK("Memory squeeze in netback " + "driver.\n"); + mod_timer(&net_timer, jiffies + HZ); + skb_queue_head(&rx_queue, skb); + break; + } + /* + * Set the new P2M table entry before + * reassigning the old data page. Heed + * the comment in + * pgtable-2level.h:pte_page(). :-) + */ + set_phys_to_machine( + __pa(skb->data) >> PAGE_SHIFT, + new_mfn); + + MULTI_update_va_mapping(mcl, vdata, + pfn_pte_ma(new_mfn, + PAGE_KERNEL), 0); + mcl++; + + mmu->ptr = ((maddr_t)new_mfn << PAGE_SHIFT) | + MMU_MACHPHYS_UPDATE; + mmu->val = __pa(vdata) >> PAGE_SHIFT; + mmu++; + } + + flip_gop->mfn = old_mfn; + flip_gop->domid = netif->domid; + flip_gop->ref = rx_req_p->gref; + flip_gop++; + + netif->rx.req_cons++; + __skb_queue_tail(&flip_rxq, skb); + } + + netif->stats.tx_bytes += size; + netif->stats.tx_packets++; + } + + if (flip_gop == grant_rx_trans_op && map_gop == grant_rx_map_op) { + /* Nothing to do */ + return; + } + + if (mcl != rx_mcl) { + /* Did some unmaps -> need a TLB flush */ mcl[-1].args[MULTI_UVMFLAGS_INDEX] = UVMF_TLB_FLUSH|UVMF_ALL; if (mmu - rx_mmu) { @@ -296,26 +348,32 @@ static void net_rx_action(unsigned long mcl++; } - ret = HYPERVISOR_multicall(rx_mcl, mcl - rx_mcl); - BUG_ON(ret != 0); - } - - ret = HYPERVISOR_grant_table_op(GNTTABOP_transfer, grant_rx_op, - gop - grant_rx_op); + BUG_ON(flip_gop == grant_rx_trans_op); + MULTI_grant_table_op(mcl, GNTTABOP_transfer, + grant_rx_trans_op, + flip_gop - grant_rx_trans_op); + mcl++; + } + if (map_gop != grant_rx_map_op) { + MULTI_grant_table_op(mcl, GNTTABOP_map_grant_ref, + grant_rx_map_op, + map_gop - grant_rx_map_op); + mcl++; + } + + ret = HYPERVISOR_multicall(rx_mcl, mcl - rx_mcl); BUG_ON(ret != 0); + /* Now do all of the page flips */ mcl = rx_mcl; - gop = grant_rx_op; - while ((skb = __skb_dequeue(&rxq)) != NULL) { + flip_gop = grant_rx_trans_op; + while ((skb = __skb_dequeue(&flip_rxq)) != NULL) { netif = netdev_priv(skb->dev); size = skb->tail - skb->data; atomic_set(&(skb_shinfo(skb)->dataref), 1); skb_shinfo(skb)->nr_frags = 0; skb_shinfo(skb)->frag_list = NULL; - - netif->stats.tx_bytes += size; - netif->stats.tx_packets++; if (!xen_feature(XENFEAT_auto_translated_physmap)) { /* The update_va_mapping() must not fail. */ @@ -325,14 +383,14 @@ static void net_rx_action(unsigned long /* Check the reassignment error code. */ status = NETIF_RSP_OKAY; - if (gop->status != 0) { + if (flip_gop->status != 0) { DPRINTK("Bad status %d from grant transfer to DOM%u\n", - gop->status, netif->domid); + flip_gop->status, netif->domid); /* * Page no longer belongs to us unless GNTST_bad_page, * but that should be a fatal error anyway. */ - BUG_ON(gop->status == GNTST_bad_page); + BUG_ON(flip_gop->status == GNTST_bad_page); status = NETIF_RSP_ERROR; } irq = netif->irq; @@ -352,7 +410,72 @@ static void net_rx_action(unsigned long netif_put(netif); dev_kfree_skb(skb); - gop++; + flip_gop++; + } + + /* Now do all of the copies */ + map_gop = grant_rx_map_op; + unmap_gop = grant_rx_unmap_op; + skb = ((struct sk_buff *)©_rxq)->next; + while (skb != (struct sk_buff *)©_rxq) { + netif = netdev_priv(skb->dev); + size = skb->tail - skb->data; + + rx_req_p = (netif_rx_request_t *)skb->cb; + + if (map_gop->status == 0) { + remote_data = + (void *)(unsigned long)map_gop->host_addr; + memcpy(remote_data + 16, + skb->data, + size); + unmap_gop->host_addr = map_gop->host_addr; + unmap_gop->dev_bus_addr = 0; + unmap_gop->handle = map_gop->handle; + unmap_gop++; + } + + map_gop++; + skb = skb->next; + } + + /* Unmap the packets we just copied into */ + if (unmap_gop != grant_rx_unmap_op) { + ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, + grant_rx_unmap_op, + unmap_gop - grant_rx_unmap_op); + BUG_ON(ret); + map_gop = grant_rx_map_op; + /* And notify the other side. */ + while ((skb = __skb_dequeue(©_rxq)) != NULL) { + netif = netdev_priv(skb->dev); + rx_req_p = (netif_rx_request_t *)skb->cb; + + flags = 0; + if (skb->ip_summed == CHECKSUM_HW) + flags |= (NETRXF_csum_blank | + NETRXF_data_validated); + else if (skb->proto_data_valid) + flags |= NETRXF_data_validated; + + if (map_gop->status) + status = NETIF_RSP_ERROR; + else + status = NETIF_RSP_OKAY; + + irq = netif->irq; + if (make_rx_response(netif, rx_req_p->id, status, + netif->copy_delivery_offset, size, + flags) && + rx_notify[irq] == 0) { + rx_notify[irq] = 1; + notify_list[notify_nr++] = irq; + } + + netif_put(netif); + dev_kfree_skb(skb); + map_gop++; + } } while (notify_nr != 0) { @@ -966,6 +1089,12 @@ static void netif_page_release(struct pa set_page_count(page, 1); netif_idx_release(pending_idx); +} + +static void netif_rx_page_release(struct page *page) +{ + /* Ready for next use. */ + set_page_count(page, 1); } irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs) @@ -1093,6 +1222,16 @@ static int __init netback_init(void) SetPageForeign(page, netif_page_release); } + page = balloon_alloc_empty_page_range(NET_RX_RING_SIZE); + BUG_ON(page == NULL); + rx_mmap_area = pfn_to_kaddr(page_to_pfn(page)); + + for (i = 0; i < NET_RX_RING_SIZE; i++) { + page = virt_to_page(rx_mmap_area + (i * PAGE_SIZE)); + set_page_count(page, 1); + SetPageForeign(page, netif_rx_page_release); + } + pending_cons = 0; pending_prod = MAX_PENDING_REQS; for (i = 0; i < MAX_PENDING_REQS; i++) diff -r 4726fd416506 -r 7053592c928b linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c --- a/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c Mon Jul 17 22:55:34 2006 +0100 +++ b/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c Mon Jul 17 23:34:46 2006 +0100 @@ -110,6 +110,18 @@ static int netback_probe(struct xenbus_d } #endif + err = xenbus_printf(xbt, dev->nodename, "feature-rx-copy", "%d", 1); + if (err) { + message = "writing feature-copying"; + goto abort_transaction; + } + + err = xenbus_printf(xbt, dev->nodename, "feature-rx-flags", "%d", 1); + if (err) { + message = "writing feature-rx-flags"; + goto abort_transaction; + } + err = xenbus_transaction_end(xbt, 0); } while (err == -EAGAIN); @@ -363,6 +375,30 @@ static int connect_rings(struct backend_ if (err) { xenbus_dev_fatal(dev, err, "reading %s/ring-ref and event-channel", + dev->otherend); + return err; + } + + err = xenbus_scanf(XBT_NIL, dev->otherend, + "use-rx-flags", "%u", + &be->netif->rx_flags); + if (err == -ENOENT) { + be->netif->rx_flags = 0; + } else if (err < 0) { + xenbus_dev_fatal(dev, err, + "reading %s/use-rx-flags", + dev->otherend); + return err; + } + + err = xenbus_scanf(XBT_NIL, dev->otherend, + "copy-delivery-offset", "%u", + &be->netif->copy_delivery_offset); + if (err == -ENOENT) { + be->netif->copy_delivery_offset = 0; + } else if (err < 0) { + xenbus_dev_fatal(dev, err, + "reading %s/copy_delivery_offset", dev->otherend); return err; } diff -r 4726fd416506 -r 7053592c928b linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypervisor.h --- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypervisor.h Mon Jul 17 22:55:34 2006 +0100 +++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypervisor.h Mon Jul 17 23:34:46 2006 +0100 @@ -200,6 +200,16 @@ MULTI_update_va_mapping( } static inline void +MULTI_grant_table_op(multicall_entry_t *mcl, unsigned int cmd, + void *uop, unsigned int count) +{ + mcl->op = __HYPERVISOR_grant_table_op; + mcl->args[0] = cmd; + mcl->args[1] = (unsigned long)uop; + mcl->args[2] = count; +} + +static inline void MULTI_update_va_mapping_otherdomain( multicall_entry_t *mcl, unsigned long va, pte_t new_val, unsigned long flags, domid_t domid) diff -r 4726fd416506 -r 7053592c928b xen/include/public/io/netif.h --- a/xen/include/public/io/netif.h Mon Jul 17 22:55:34 2006 +0100 +++ b/xen/include/public/io/netif.h Mon Jul 17 23:34:46 2006 +0100 @@ -109,8 +109,12 @@ struct netif_tx_response { }; typedef struct netif_tx_response netif_tx_response_t; +#define _NETIF_RXRF_copy_packet (0) +#define NETIF_RXRF_copy_packet (1U<<_NETIF_RXRF_copy_packet) + struct netif_rx_request { uint16_t id; /* Echoed in response message. */ + uint16_t flags; /* NETRXRF_* */ grant_ref_t gref; /* Reference to incoming granted frame */ }; typedef struct netif_rx_request netif_rx_request_t;