diff options
author | Anthony Liguori <anthony@codemonkey.ws> | 2013-09-23 11:53:11 -0500 |
---|---|---|
committer | Anthony Liguori <anthony@codemonkey.ws> | 2013-09-23 11:53:11 -0500 |
commit | feb678c6f7234d5227610939aff0510878590e83 (patch) | |
tree | 10458241ef441f904f9bc062c2c1dac621b493a9 /hw | |
parent | 16121fa39e1ec17308162af4de5c5f6c01c1cce1 (diff) | |
parent | 97410dde60fdb66a65268fd9d7b14092efac7614 (diff) | |
download | qemu-feb678c6f7234d5227610939aff0510878590e83.tar.gz qemu-feb678c6f7234d5227610939aff0510878590e83.tar.bz2 qemu-feb678c6f7234d5227610939aff0510878590e83.zip |
Merge remote-tracking branch 'stefanha/net' into staging
# By Aurelien Jarno (1) and Vincenzo Maffione (1)
# Via Stefan Hajnoczi
* stefanha/net:
e1000: NetClientInfo.receive_iov implemented
pcnet-pci: mark I/O and MMIO as LITTLE_ENDIAN
Message-id: 1379699613-5338-1-git-send-email-stefanha@redhat.com
Diffstat (limited to 'hw')
-rw-r--r-- | hw/net/e1000.c | 70 | ||||
-rw-r--r-- | hw/net/pcnet-pci.c | 4 |
2 files changed, 60 insertions, 14 deletions
diff --git a/hw/net/e1000.c b/hw/net/e1000.c index d3f274cc28..151d25e0b7 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c @@ -32,6 +32,7 @@ #include "hw/loader.h" #include "sysemu/sysemu.h" #include "sysemu/dma.h" +#include "qemu/iov.h" #include "e1000_regs.h" @@ -64,6 +65,8 @@ static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL); /* this is the size past which hardware will drop packets when setting LPE=1 */ #define MAXIMUM_ETHERNET_LPE_SIZE 16384 +#define MAXIMUM_ETHERNET_HDR_LEN (14+4) + /* * HW models: * E1000_DEV_ID_82540EM works with Windows and Linux @@ -899,7 +902,7 @@ static uint64_t rx_desc_base(E1000State *s) } static ssize_t -e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) +e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt) { E1000State *s = qemu_get_nic_opaque(nc); PCIDevice *d = PCI_DEVICE(s); @@ -908,8 +911,12 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) unsigned int n, rdt; uint32_t rdh_start; uint16_t vlan_special = 0; - uint8_t vlan_status = 0, vlan_offset = 0; + uint8_t vlan_status = 0; uint8_t min_buf[MIN_BUF_SIZE]; + struct iovec min_iov; + uint8_t *filter_buf = iov->iov_base; + size_t size = iov_size(iov, iovcnt); + size_t iov_ofs = 0; size_t desc_offset; size_t desc_size; size_t total_size; @@ -924,10 +931,16 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) /* Pad to minimum Ethernet frame length */ if (size < sizeof(min_buf)) { - memcpy(min_buf, buf, size); + iov_to_buf(iov, iovcnt, 0, min_buf, size); memset(&min_buf[size], 0, sizeof(min_buf) - size); - buf = min_buf; - size = sizeof(min_buf); + min_iov.iov_base = filter_buf = min_buf; + min_iov.iov_len = size = sizeof(min_buf); + iovcnt = 1; + iov = &min_iov; + } else if (iov->iov_len < MAXIMUM_ETHERNET_HDR_LEN) { + /* This is very unlikely, but may happen. */ + iov_to_buf(iov, iovcnt, 0, min_buf, MAXIMUM_ETHERNET_HDR_LEN); + filter_buf = min_buf; } /* Discard oversized packets if !LPE and !SBP. */ @@ -938,14 +951,24 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) return size; } - if (!receive_filter(s, buf, size)) + if (!receive_filter(s, filter_buf, size)) { return size; + } - if (vlan_enabled(s) && is_vlan_packet(s, buf)) { - vlan_special = cpu_to_le16(be16_to_cpup((uint16_t *)(buf + 14))); - memmove((uint8_t *)buf + 4, buf, 12); + if (vlan_enabled(s) && is_vlan_packet(s, filter_buf)) { + vlan_special = cpu_to_le16(be16_to_cpup((uint16_t *)(filter_buf + + 14))); + iov_ofs = 4; + if (filter_buf == iov->iov_base) { + memmove(filter_buf + 4, filter_buf, 12); + } else { + iov_from_buf(iov, iovcnt, 4, filter_buf, 12); + while (iov->iov_len <= iov_ofs) { + iov_ofs -= iov->iov_len; + iov++; + } + } vlan_status = E1000_RXD_STAT_VP; - vlan_offset = 4; size -= 4; } @@ -967,12 +990,23 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) desc.status |= (vlan_status | E1000_RXD_STAT_DD); if (desc.buffer_addr) { if (desc_offset < size) { + size_t iov_copy; + hwaddr ba = le64_to_cpu(desc.buffer_addr); size_t copy_size = size - desc_offset; if (copy_size > s->rxbuf_size) { copy_size = s->rxbuf_size; } - pci_dma_write(d, le64_to_cpu(desc.buffer_addr), - buf + desc_offset + vlan_offset, copy_size); + do { + iov_copy = MIN(copy_size, iov->iov_len - iov_ofs); + pci_dma_write(d, ba, iov->iov_base + iov_ofs, iov_copy); + copy_size -= iov_copy; + ba += iov_copy; + iov_ofs += iov_copy; + if (iov_ofs == iov->iov_len) { + iov++; + iov_ofs = 0; + } + } while (copy_size); } desc_offset += desc_size; desc.length = cpu_to_le16(desc_size); @@ -1022,6 +1056,17 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) return size; } +static ssize_t +e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) +{ + const struct iovec iov = { + .iov_base = (uint8_t *)buf, + .iov_len = size + }; + + return e1000_receive_iov(nc, &iov, 1); +} + static uint32_t mac_readreg(E1000State *s, int index) { @@ -1448,6 +1493,7 @@ static NetClientInfo net_e1000_info = { .size = sizeof(NICState), .can_receive = e1000_can_receive, .receive = e1000_receive, + .receive_iov = e1000_receive_iov, .cleanup = e1000_cleanup, .link_status_changed = e1000_set_link_status, }; diff --git a/hw/net/pcnet-pci.c b/hw/net/pcnet-pci.c index a8931652b3..865f2f0c59 100644 --- a/hw/net/pcnet-pci.c +++ b/hw/net/pcnet-pci.c @@ -134,7 +134,7 @@ static void pcnet_ioport_write(void *opaque, hwaddr addr, static const MemoryRegionOps pcnet_io_ops = { .read = pcnet_ioport_read, .write = pcnet_ioport_write, - .endianness = DEVICE_NATIVE_ENDIAN, + .endianness = DEVICE_LITTLE_ENDIAN, }; static void pcnet_mmio_writeb(void *opaque, hwaddr addr, uint32_t val) @@ -256,7 +256,7 @@ static const MemoryRegionOps pcnet_mmio_ops = { .read = { pcnet_mmio_readb, pcnet_mmio_readw, pcnet_mmio_readl }, .write = { pcnet_mmio_writeb, pcnet_mmio_writew, pcnet_mmio_writel }, }, - .endianness = DEVICE_NATIVE_ENDIAN, + .endianness = DEVICE_LITTLE_ENDIAN, }; static void pci_physical_memory_write(void *dma_opaque, hwaddr addr, |