/* * Set up the grant operations for this fragment. If it's a flipping * interface, we also set up the unmap request from here. */ static void xenvif_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb, struct netrx_pending_operations *npo, struct page *page, unsigned long size, unsigned long offset, int *head, struct xenvif *foreign_vif, grant_ref_t foreign_gref) { struct gnttab_copy *copy_gop; struct xenvif_rx_meta *meta; unsigned long bytes; int gso_type = XEN_NETIF_GSO_TYPE_NONE; /* Data must not cross a page boundary. */ BUG_ON(size + offset > PAGE_SIZE<<compound_order(page)); meta = npo->meta + npo->meta_prod - 1; /* Skip unused frames from start of page */ page += offset >> PAGE_SHIFT; offset &= ~PAGE_MASK; while (size > 0) { BUG_ON(offset >= PAGE_SIZE); BUG_ON(npo->copy_off > MAX_BUFFER_OFFSET); bytes = PAGE_SIZE - offset; if (bytes > size) bytes = size; if (start_new_rx_buffer(npo->copy_off, bytes, *head)) { /* * Netfront requires there to be some data in the head * buffer. */ BUG_ON(*head); meta = get_next_rx_buffer(vif, npo); } if (npo->copy_off + bytes > MAX_BUFFER_OFFSET) bytes = MAX_BUFFER_OFFSET - npo->copy_off; copy_gop = npo->copy + npo->copy_prod++; copy_gop->flags = GNTCOPY_dest_gref; copy_gop->len = bytes; if (foreign_vif) { copy_gop->source.domid = foreign_vif->domid; copy_gop->source.u.ref = foreign_gref; copy_gop->flags |= GNTCOPY_source_gref; } else { copy_gop->source.domid = DOMID_SELF; copy_gop->source.u.gmfn = virt_to_mfn(page_address(page)); } copy_gop->source.offset = offset; copy_gop->dest.domid = vif->domid; copy_gop->dest.offset = npo->copy_off; copy_gop->dest.u.ref = npo->copy_gref; npo->copy_off += bytes; meta->size += bytes; offset += bytes; size -= bytes; /* Next frame */ if (offset == PAGE_SIZE && size) { BUG_ON(!PageCompound(page)); page++; offset = 0; } /* Leave a gap for the GSO descriptor. */ if (skb_is_gso(skb)) { if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) gso_type = XEN_NETIF_GSO_TYPE_TCPV4; else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) gso_type = XEN_NETIF_GSO_TYPE_TCPV6; } if (*head && ((1 << gso_type) & vif->gso_mask)) vif->rx.req_cons++; *head = 0; /* There must be something in this buffer now. */ } }
/* * Set up the grant operations for this fragment. If it's a flipping * interface, we also set up the unmap request from here. */ static void netbk_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb, struct netrx_pending_operations *npo, struct page *page, unsigned long size, unsigned long offset, int *head) { struct gnttab_copy *copy_gop; struct netbk_rx_meta *meta; /* * These variables are used iff get_page_ext returns true, * in which case they are guaranteed to be initialized. */ unsigned int uninitialized_var(group), uninitialized_var(idx); int foreign = get_page_ext(page, &group, &idx); unsigned long bytes; /* Data must not cross a page boundary. */ BUG_ON(size + offset > PAGE_SIZE<<compound_order(page)); meta = npo->meta + npo->meta_prod - 1; /* Skip unused frames from start of page */ page += offset >> PAGE_SHIFT; offset &= ~PAGE_MASK; while (size > 0) { BUG_ON(offset >= PAGE_SIZE); BUG_ON(npo->copy_off > MAX_BUFFER_OFFSET); bytes = PAGE_SIZE - offset; if (bytes > size) bytes = size; if (start_new_rx_buffer(npo->copy_off, bytes, *head)) { /* * Netfront requires there to be some data in the head * buffer. */ BUG_ON(*head); meta = get_next_rx_buffer(vif, npo); } if (npo->copy_off + bytes > MAX_BUFFER_OFFSET) bytes = MAX_BUFFER_OFFSET - npo->copy_off; copy_gop = npo->copy + npo->copy_prod++; copy_gop->flags = GNTCOPY_dest_gref; if (foreign) { struct xen_netbk *netbk = &xen_netbk[group]; struct pending_tx_info *src_pend; src_pend = &netbk->pending_tx_info[idx]; copy_gop->source.domid = src_pend->vif->domid; copy_gop->source.u.ref = src_pend->req.gref; copy_gop->flags |= GNTCOPY_source_gref; } else { void *vaddr = page_address(page); copy_gop->source.domid = DOMID_SELF; copy_gop->source.u.gmfn = virt_to_mfn(vaddr); } copy_gop->source.offset = offset; copy_gop->dest.domid = vif->domid; copy_gop->dest.offset = npo->copy_off; copy_gop->dest.u.ref = npo->copy_gref; copy_gop->len = bytes; npo->copy_off += bytes; meta->size += bytes; offset += bytes; size -= bytes; /* Next frame */ if (offset == PAGE_SIZE && size) { BUG_ON(!PageCompound(page)); page++; offset = 0; } /* Leave a gap for the GSO descriptor. */ if (*head && skb_shinfo(skb)->gso_size && !vif->gso_prefix) vif->rx.req_cons++; *head = 0; /* There must be something in this buffer now. */ } }
static void netbk_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb, struct netrx_pending_operations *npo, struct page *page, unsigned long size, unsigned long offset, int *head) { struct gnttab_copy *copy_gop; struct netbk_rx_meta *meta; /* */ unsigned int uninitialized_var(group), uninitialized_var(idx); int foreign = get_page_ext(page, &group, &idx); unsigned long bytes; /* */ BUG_ON(size + offset > PAGE_SIZE); meta = npo->meta + npo->meta_prod - 1; while (size > 0) { BUG_ON(npo->copy_off > MAX_BUFFER_OFFSET); if (start_new_rx_buffer(npo->copy_off, size, *head)) { /* */ BUG_ON(*head); meta = get_next_rx_buffer(vif, npo); } bytes = size; if (npo->copy_off + bytes > MAX_BUFFER_OFFSET) bytes = MAX_BUFFER_OFFSET - npo->copy_off; copy_gop = npo->copy + npo->copy_prod++; copy_gop->flags = GNTCOPY_dest_gref; if (foreign) { struct xen_netbk *netbk = &xen_netbk[group]; struct pending_tx_info *src_pend; src_pend = &netbk->pending_tx_info[idx]; copy_gop->source.domid = src_pend->vif->domid; copy_gop->source.u.ref = src_pend->req.gref; copy_gop->flags |= GNTCOPY_source_gref; } else { void *vaddr = page_address(page); copy_gop->source.domid = DOMID_SELF; copy_gop->source.u.gmfn = virt_to_mfn(vaddr); } copy_gop->source.offset = offset; copy_gop->dest.domid = vif->domid; copy_gop->dest.offset = npo->copy_off; copy_gop->dest.u.ref = npo->copy_gref; copy_gop->len = bytes; npo->copy_off += bytes; meta->size += bytes; offset += bytes; size -= bytes; /* */ if (*head && skb_shinfo(skb)->gso_size && !vif->gso_prefix) vif->rx.req_cons++; *head = 0; /* */ } }