static int xenvif_read_io_ring(struct seq_file *m, void *v) { struct xenvif_queue *queue = m->private; struct xen_netif_tx_back_ring *tx_ring = &queue->tx; struct xen_netif_rx_back_ring *rx_ring = &queue->rx; struct netdev_queue *dev_queue; if (tx_ring->sring) { struct xen_netif_tx_sring *sring = tx_ring->sring; seq_printf(m, "Queue %d\nTX: nr_ents %u\n", queue->id, tx_ring->nr_ents); seq_printf(m, "req prod %u (%d) cons %u (%d) event %u (%d)\n", sring->req_prod, sring->req_prod - sring->rsp_prod, tx_ring->req_cons, tx_ring->req_cons - sring->rsp_prod, sring->req_event, sring->req_event - sring->rsp_prod); seq_printf(m, "rsp prod %u (base) pvt %u (%d) event %u (%d)\n", sring->rsp_prod, tx_ring->rsp_prod_pvt, tx_ring->rsp_prod_pvt - sring->rsp_prod, sring->rsp_event, sring->rsp_event - sring->rsp_prod); seq_printf(m, "pending prod %u pending cons %u nr_pending_reqs %u\n", queue->pending_prod, queue->pending_cons, nr_pending_reqs(queue)); seq_printf(m, "dealloc prod %u dealloc cons %u dealloc_queue %u\n\n", queue->dealloc_prod, queue->dealloc_cons, queue->dealloc_prod - queue->dealloc_cons); } if (rx_ring->sring) { struct xen_netif_rx_sring *sring = rx_ring->sring; seq_printf(m, "RX: nr_ents %u\n", rx_ring->nr_ents); seq_printf(m, "req prod %u (%d) cons %u (%d) event %u (%d)\n", sring->req_prod, sring->req_prod - sring->rsp_prod, rx_ring->req_cons, rx_ring->req_cons - sring->rsp_prod, sring->req_event, sring->req_event - sring->rsp_prod); seq_printf(m, "rsp prod %u (base) pvt %u (%d) event %u (%d)\n\n", sring->rsp_prod, rx_ring->rsp_prod_pvt, rx_ring->rsp_prod_pvt - sring->rsp_prod, sring->rsp_event, sring->rsp_event - sring->rsp_prod); } seq_printf(m, "NAPI state: %lx NAPI weight: %d TX queue len %u\n" "Credit timer_pending: %d, credit: %lu, usec: %lu\n" "remaining: %lu, expires: %lu, now: %lu\n", queue->napi.state, queue->napi.weight, skb_queue_len(&queue->tx_queue), timer_pending(&queue->credit_timeout), queue->credit_bytes, queue->credit_usec, queue->remaining_credit, queue->credit_timeout.expires, jiffies); dev_queue = netdev_get_tx_queue(queue->vif->dev, queue->id); seq_printf(m, "\nRx internal queue: len %u max %u pkts %u %s\n", queue->rx_queue_len, queue->rx_queue_max, skb_queue_len(&queue->rx_queue), netif_tx_queue_stopped(dev_queue) ? "stopped" : "running"); return 0; }
static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget) { struct gnttab_copy *gop = vif->tx_copy_ops, *request_gop; struct sk_buff *skb; int ret; while ((nr_pending_reqs(vif) + XEN_NETBK_LEGACY_SLOTS_MAX < MAX_PENDING_REQS) && (skb_queue_len(&vif->tx_queue) < budget)) { struct xen_netif_tx_request txreq; struct xen_netif_tx_request txfrags[XEN_NETBK_LEGACY_SLOTS_MAX]; struct page *page; struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1]; u16 pending_idx; RING_IDX idx; int work_to_do; unsigned int data_len; pending_ring_idx_t index; if (vif->tx.sring->req_prod - vif->tx.req_cons > XEN_NETIF_TX_RING_SIZE) { netdev_err(vif->dev, "Impossible number of requests. " "req_prod %d, req_cons %d, size %ld\n", vif->tx.sring->req_prod, vif->tx.req_cons, XEN_NETIF_TX_RING_SIZE); xenvif_fatal_tx_err(vif); continue; } work_to_do = RING_HAS_UNCONSUMED_REQUESTS(&vif->tx); if (!work_to_do) break; idx = vif->tx.req_cons; rmb(); /* Ensure that we see the request before we copy it. */ memcpy(&txreq, RING_GET_REQUEST(&vif->tx, idx), sizeof(txreq)); /* Credit-based scheduling. */ if (txreq.size > vif->remaining_credit && tx_credit_exceeded(vif, txreq.size)) break; vif->remaining_credit -= txreq.size; work_to_do--; vif->tx.req_cons = ++idx; memset(extras, 0, sizeof(extras)); if (txreq.flags & XEN_NETTXF_extra_info) { work_to_do = xenvif_get_extras(vif, extras, work_to_do); idx = vif->tx.req_cons; if (unlikely(work_to_do < 0)) break; } ret = xenvif_count_requests(vif, &txreq, txfrags, work_to_do); if (unlikely(ret < 0)) break; idx += ret; if (unlikely(txreq.size < ETH_HLEN)) { netdev_dbg(vif->dev, "Bad packet size: %d\n", txreq.size); xenvif_tx_err(vif, &txreq, idx); break; } /* No crossing a page as the payload mustn't fragment. */ if (unlikely((txreq.offset + txreq.size) > PAGE_SIZE)) { netdev_err(vif->dev, "txreq.offset: %x, size: %u, end: %lu\n", txreq.offset, txreq.size, (txreq.offset&~PAGE_MASK) + txreq.size); xenvif_fatal_tx_err(vif); break; } index = pending_index(vif->pending_cons); pending_idx = vif->pending_ring[index]; data_len = (txreq.size > PKT_PROT_LEN && ret < XEN_NETBK_LEGACY_SLOTS_MAX) ? PKT_PROT_LEN : txreq.size; skb = alloc_skb(data_len + NET_SKB_PAD + NET_IP_ALIGN, GFP_ATOMIC | __GFP_NOWARN); if (unlikely(skb == NULL)) { netdev_dbg(vif->dev, "Can't allocate a skb in start_xmit.\n"); xenvif_tx_err(vif, &txreq, idx); break; } /* Packets passed to netif_rx() must have some headroom. */ skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) { struct xen_netif_extra_info *gso; gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1]; if (xenvif_set_skb_gso(vif, skb, gso)) { /* Failure in xenvif_set_skb_gso is fatal. */ kfree_skb(skb); break; } } /* XXX could copy straight to head */ page = xenvif_alloc_page(vif, pending_idx); if (!page) { kfree_skb(skb); xenvif_tx_err(vif, &txreq, idx); break; } gop->source.u.ref = txreq.gref; gop->source.domid = vif->domid; gop->source.offset = txreq.offset; gop->dest.u.gmfn = virt_to_mfn(page_address(page)); gop->dest.domid = DOMID_SELF; gop->dest.offset = txreq.offset; gop->len = txreq.size; gop->flags = GNTCOPY_source_gref; gop++; memcpy(&vif->pending_tx_info[pending_idx].req, &txreq, sizeof(txreq)); vif->pending_tx_info[pending_idx].head = index; *((u16 *)skb->data) = pending_idx; __skb_put(skb, data_len); skb_shinfo(skb)->nr_frags = ret; if (data_len < txreq.size) { skb_shinfo(skb)->nr_frags++; frag_set_pending_idx(&skb_shinfo(skb)->frags[0], pending_idx); } else { frag_set_pending_idx(&skb_shinfo(skb)->frags[0], INVALID_PENDING_IDX); } vif->pending_cons++; request_gop = xenvif_get_requests(vif, skb, txfrags, gop); if (request_gop == NULL) { kfree_skb(skb); xenvif_tx_err(vif, &txreq, idx); break; } gop = request_gop; __skb_queue_tail(&vif->tx_queue, skb); vif->tx.req_cons = idx; if ((gop-vif->tx_copy_ops) >= ARRAY_SIZE(vif->tx_copy_ops)) break; } return gop - vif->tx_copy_ops; }