e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt, const E1000E_RxRing *rxr, const E1000E_RSSInfo *rss_info) { PCIDevice *d = core->owner; dma_addr_t base; uint8_t desc[E1000_MAX_RX_DESC_LEN]; size_t desc_size; size_t desc_offset = 0; size_t iov_ofs = 0; struct iovec *iov = net_rx_pkt_get_iovec(pkt); size_t size = net_rx_pkt_get_total_len(pkt); size_t total_size = size + e1000x_fcs_len(core->mac); const E1000E_RingInfo *rxi; size_t ps_hdr_len = 0; bool do_ps = e1000e_do_ps(core, pkt, &ps_hdr_len); rxi = rxr->i; do { hwaddr ba[MAX_PS_BUFFERS]; e1000e_ba_state bastate = { { 0 } }; bool is_last = false; bool is_first = true; desc_size = total_size - desc_offset; if (desc_size > core->rx_desc_buf_size) { desc_size = core->rx_desc_buf_size; } base = e1000e_ring_head_descr(core, rxi); pci_dma_read(d, base, &desc, core->rx_desc_len); trace_e1000e_rx_descr(rxi->idx, base, core->rx_desc_len); e1000e_read_rx_descr(core, desc, &ba); if (ba[0]) { if (desc_offset < size) { static const uint32_t fcs_pad; size_t iov_copy; size_t copy_size = size - desc_offset; if (copy_size > core->rx_desc_buf_size) { copy_size = core->rx_desc_buf_size; } /* For PS mode copy the packet header first */ if (do_ps) { if (is_first) { size_t ps_hdr_copied = 0; do { iov_copy = MIN(ps_hdr_len - ps_hdr_copied, iov->iov_len - iov_ofs); e1000e_write_hdr_to_rx_buffers(core, &ba, &bastate, iov->iov_base, iov_copy); copy_size -= iov_copy; ps_hdr_copied += iov_copy; iov_ofs += iov_copy; if (iov_ofs == iov->iov_len) { iov++; iov_ofs = 0; } } while (ps_hdr_copied < ps_hdr_len); is_first = false; } else { /* Leave buffer 0 of each descriptor except first */ /* empty as per spec 7.1.5.1 */ e1000e_write_hdr_to_rx_buffers(core, &ba, &bastate, NULL, 0); } } /* Copy packet payload */ while (copy_size) { iov_copy = MIN(copy_size, iov->iov_len - iov_ofs); e1000e_write_to_rx_buffers(core, &ba, &bastate, iov->iov_base + iov_ofs, iov_copy); copy_size -= iov_copy; iov_ofs += iov_copy; if (iov_ofs == iov->iov_len) { iov++; iov_ofs = 0; } } if (desc_offset + desc_size >= total_size) { /* Simulate FCS checksum presence in the last descriptor */ e1000e_write_to_rx_buffers(core, &ba, &bastate, (const char *) &fcs_pad, e1000x_fcs_len(core->mac)); } } desc_offset += desc_size; if (desc_offset >= total_size) { is_last = true; } } else { /* as per intel docs; skip descriptors with null buf addr */ trace_e1000e_rx_null_descriptor(); } e1000e_write_rx_descr(core, desc, is_last ? core->rx_pkt : NULL, rss_info, do_ps ? ps_hdr_len : 0, &bastate.written); pci_dma_write(d, base, &desc, core->rx_desc_len); e1000e_ring_advance(core, rxi, core->rx_desc_len / E1000_MIN_RX_DESC_LEN); } while (desc_offset < total_size); e1000e_update_rx_stats(core, size, total_size); }