X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/c3ab4c9cf24ec9efb9c6d82b6027c0587d3081fa..b6af097528caba5b23b79db3f1f1fd08fa4fa11e:/hw/net/rtl8139.c diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c index a00ff581dc..2040618afa 100644 --- a/hw/net/rtl8139.c +++ b/hw/net/rtl8139.c @@ -43,7 +43,7 @@ * Added rx/tx buffer reset when enabling rx/tx operation * * 2010-Feb-04 Frediano Ziglio: Rewrote timer support using QEMU timer only - * when strictly needed (required for for + * when strictly needed (required for * Darwin) * 2011-Mar-22 Benjamin Poirier: Implemented VLAN offloading */ @@ -56,6 +56,7 @@ #include "sysemu/dma.h" #include "qemu/timer.h" #include "net/net.h" +#include "net/eth.h" #include "hw/loader.h" #include "sysemu/sysemu.h" #include "qemu/iov.h" @@ -72,11 +73,8 @@ #define MOD2(input, size) \ ( ( input ) & ( size - 1 ) ) -#define ETHER_ADDR_LEN 6 #define ETHER_TYPE_LEN 2 -#define ETH_HLEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN) -#define ETH_P_IP 0x0800 /* Internet Protocol packet */ -#define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */ +#define ETH_HLEN (ETH_ALEN * 2 + ETHER_TYPE_LEN) #define ETH_MTU 1500 #define VLAN_TCI_LEN 2 @@ -92,6 +90,11 @@ static inline GCC_FMT_ATTR(1, 2) int DPRINTF(const char *fmt, ...) } #endif +#define TYPE_RTL8139 "rtl8139" + +#define RTL8139(obj) \ + OBJECT_CHECK(RTL8139State, (obj), TYPE_RTL8139) + /* Symbolic offsets to registers. */ enum RTL8139_registers { MAC0 = 0, /* Ethernet hardware address. */ @@ -428,7 +431,10 @@ typedef struct RTL8139TallyCounters static void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters); typedef struct RTL8139State { - PCIDevice dev; + /*< private >*/ + PCIDevice parent_obj; + /*< public >*/ + uint8_t phys[8]; /* mac address */ uint8_t mult[8]; /* multicast mask array */ @@ -500,7 +506,6 @@ typedef struct RTL8139State { /* PCI interrupt timer */ QEMUTimer *timer; - int64_t TimerExpire; MemoryRegion bar_io; MemoryRegion bar_mem; @@ -512,7 +517,7 @@ typedef struct RTL8139State { /* Writes tally counters to memory via DMA */ static void RTL8139TallyCounters_dma_write(RTL8139State *s, dma_addr_t tc_addr); -static void rtl8139_set_next_tctr_time(RTL8139State *s, int64_t current_time); +static void rtl8139_set_next_tctr_time(RTL8139State *s); static void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command) { @@ -701,13 +706,14 @@ static void prom9346_set_wire(RTL8139State *s, int eecs, int eesk, int eedi) static void rtl8139_update_irq(RTL8139State *s) { + PCIDevice *d = PCI_DEVICE(s); int isr; isr = (s->IntrStatus & s->IntrMask) & 0xffff; DPRINTF("Set IRQ to %d (%04x %04x)\n", isr ? 1 : 0, s->IntrStatus, s->IntrMask); - qemu_set_irq(s->dev.irq[0], (isr != 0)); + pci_set_irq(d, (isr != 0)); } static int rtl8139_RxWrap(RTL8139State *s) @@ -738,6 +744,8 @@ static int rtl8139_cp_transmitter_enabled(RTL8139State *s) static void rtl8139_write_buffer(RTL8139State *s, const void *buf, int size) { + PCIDevice *d = PCI_DEVICE(s); + if (s->RxBufAddr + size > s->RxBufferSize) { int wrapped = MOD2(s->RxBufAddr + size, s->RxBufferSize); @@ -749,14 +757,14 @@ static void rtl8139_write_buffer(RTL8139State *s, const void *buf, int size) if (size > wrapped) { - pci_dma_write(&s->dev, s->RxBuf + s->RxBufAddr, + pci_dma_write(d, s->RxBuf + s->RxBufAddr, buf, size-wrapped); } /* reset buffer pointer */ s->RxBufAddr = 0; - pci_dma_write(&s->dev, s->RxBuf + s->RxBufAddr, + pci_dma_write(d, s->RxBuf + s->RxBufAddr, buf + (size-wrapped), wrapped); s->RxBufAddr = wrapped; @@ -766,7 +774,7 @@ static void rtl8139_write_buffer(RTL8139State *s, const void *buf, int size) } /* non-wrapping path or overwrapping enabled */ - pci_dma_write(&s->dev, s->RxBuf + s->RxBufAddr, buf, size); + pci_dma_write(d, s->RxBuf + s->RxBufAddr, buf, size); s->RxBufAddr += size; } @@ -809,6 +817,7 @@ static int rtl8139_can_receive(NetClientState *nc) static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t size_, int do_interrupt) { RTL8139State *s = qemu_get_nic_opaque(nc); + PCIDevice *d = PCI_DEVICE(s); /* size is the length of the buffer passed to the driver */ int size = size_; const uint8_t *dot1q_buf = NULL; @@ -973,13 +982,13 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t uint32_t val, rxdw0,rxdw1,rxbufLO,rxbufHI; - pci_dma_read(&s->dev, cplus_rx_ring_desc, &val, 4); + pci_dma_read(d, cplus_rx_ring_desc, &val, 4); rxdw0 = le32_to_cpu(val); - pci_dma_read(&s->dev, cplus_rx_ring_desc+4, &val, 4); + pci_dma_read(d, cplus_rx_ring_desc+4, &val, 4); rxdw1 = le32_to_cpu(val); - pci_dma_read(&s->dev, cplus_rx_ring_desc+8, &val, 4); + pci_dma_read(d, cplus_rx_ring_desc+8, &val, 4); rxbufLO = le32_to_cpu(val); - pci_dma_read(&s->dev, cplus_rx_ring_desc+12, &val, 4); + pci_dma_read(d, cplus_rx_ring_desc+12, &val, 4); rxbufHI = le32_to_cpu(val); DPRINTF("+++ C+ mode RX descriptor %d %08x %08x %08x %08x\n", @@ -1005,8 +1014,8 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t /* write VLAN info to descriptor variables. */ if (s->CpCmd & CPlusRxVLAN && be16_to_cpup((uint16_t *) - &buf[ETHER_ADDR_LEN * 2]) == ETH_P_8021Q) { - dot1q_buf = &buf[ETHER_ADDR_LEN * 2]; + &buf[ETH_ALEN * 2]) == ETH_P_VLAN) { + dot1q_buf = &buf[ETH_ALEN * 2]; size -= VLAN_HLEN; /* if too small buffer, use the tailroom added duing expansion */ if (size < MIN_BUF_SIZE) { @@ -1047,12 +1056,12 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t /* receive/copy to target memory */ if (dot1q_buf) { - pci_dma_write(&s->dev, rx_addr, buf, 2 * ETHER_ADDR_LEN); - pci_dma_write(&s->dev, rx_addr + 2 * ETHER_ADDR_LEN, - buf + 2 * ETHER_ADDR_LEN + VLAN_HLEN, - size - 2 * ETHER_ADDR_LEN); + pci_dma_write(d, rx_addr, buf, 2 * ETH_ALEN); + pci_dma_write(d, rx_addr + 2 * ETH_ALEN, + buf + 2 * ETH_ALEN + VLAN_HLEN, + size - 2 * ETH_ALEN); } else { - pci_dma_write(&s->dev, rx_addr, buf, size); + pci_dma_write(d, rx_addr, buf, size); } if (s->CpCmd & CPlusRxChkSum) @@ -1062,7 +1071,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t /* write checksum */ val = cpu_to_le32(crc32(0, buf, size_)); - pci_dma_write(&s->dev, rx_addr+size, (uint8_t *)&val, 4); + pci_dma_write(d, rx_addr+size, (uint8_t *)&val, 4); /* first segment of received packet flag */ #define CP_RX_STATUS_FS (1<<29) @@ -1108,9 +1117,9 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t /* update ring data */ val = cpu_to_le32(rxdw0); - pci_dma_write(&s->dev, cplus_rx_ring_desc, (uint8_t *)&val, 4); + pci_dma_write(d, cplus_rx_ring_desc, (uint8_t *)&val, 4); val = cpu_to_le32(rxdw1); - pci_dma_write(&s->dev, cplus_rx_ring_desc+4, (uint8_t *)&val, 4); + pci_dma_write(d, cplus_rx_ring_desc+4, (uint8_t *)&val, 4); /* update tally counter */ ++s->tally_counters.RxOk; @@ -1137,7 +1146,9 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t /* if receiver buffer is empty then avail == 0 */ - if (avail != 0 && size + 8 >= avail) +#define RX_ALIGN(x) (((x) + 3) & ~0x3) + + if (avail != 0 && RX_ALIGN(size + 8) >= avail) { DPRINTF("rx overflow: rx buffer length %d head 0x%04x " "read 0x%04x === available 0x%04x need 0x%04x\n", @@ -1146,7 +1157,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t s->IntrStatus |= RxOverflow; ++s->RxMissed; rtl8139_update_irq(s); - return size_; + return 0; } packet_header |= RxStatusOK; @@ -1165,7 +1176,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t rtl8139_write_buffer(s, (uint8_t *)&val, 4); /* correct buffer write pointer */ - s->RxBufAddr = MOD2((s->RxBufAddr + 3) & ~0x3, s->RxBufferSize); + s->RxBufAddr = MOD2(RX_ALIGN(s->RxBufAddr), s->RxBufferSize); /* now we can signal we have received something */ @@ -1197,11 +1208,12 @@ static void rtl8139_reset_rxring(RTL8139State *s, uint32_t bufferSize) static void rtl8139_reset(DeviceState *d) { - RTL8139State *s = container_of(d, RTL8139State, dev.qdev); + RTL8139State *s = RTL8139(d); int i; /* restore MAC address */ memcpy(s->phys, s->conf.macaddr.a, 6); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->phys); /* reset interrupt mask */ s->IntrStatus = 0; @@ -1269,6 +1281,7 @@ static void rtl8139_reset(DeviceState *d) s->TCTR = 0; s->TimerInt = 0; s->TCTR_base = 0; + rtl8139_set_next_tctr_time(s); /* reset tally counters */ RTL8139TallyCounters_clear(&s->tally_counters); @@ -1293,49 +1306,50 @@ static void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters) static void RTL8139TallyCounters_dma_write(RTL8139State *s, dma_addr_t tc_addr) { + PCIDevice *d = PCI_DEVICE(s); RTL8139TallyCounters *tally_counters = &s->tally_counters; uint16_t val16; uint32_t val32; uint64_t val64; val64 = cpu_to_le64(tally_counters->TxOk); - pci_dma_write(&s->dev, tc_addr + 0, (uint8_t *)&val64, 8); + pci_dma_write(d, tc_addr + 0, (uint8_t *)&val64, 8); val64 = cpu_to_le64(tally_counters->RxOk); - pci_dma_write(&s->dev, tc_addr + 8, (uint8_t *)&val64, 8); + pci_dma_write(d, tc_addr + 8, (uint8_t *)&val64, 8); val64 = cpu_to_le64(tally_counters->TxERR); - pci_dma_write(&s->dev, tc_addr + 16, (uint8_t *)&val64, 8); + pci_dma_write(d, tc_addr + 16, (uint8_t *)&val64, 8); val32 = cpu_to_le32(tally_counters->RxERR); - pci_dma_write(&s->dev, tc_addr + 24, (uint8_t *)&val32, 4); + pci_dma_write(d, tc_addr + 24, (uint8_t *)&val32, 4); val16 = cpu_to_le16(tally_counters->MissPkt); - pci_dma_write(&s->dev, tc_addr + 28, (uint8_t *)&val16, 2); + pci_dma_write(d, tc_addr + 28, (uint8_t *)&val16, 2); val16 = cpu_to_le16(tally_counters->FAE); - pci_dma_write(&s->dev, tc_addr + 30, (uint8_t *)&val16, 2); + pci_dma_write(d, tc_addr + 30, (uint8_t *)&val16, 2); val32 = cpu_to_le32(tally_counters->Tx1Col); - pci_dma_write(&s->dev, tc_addr + 32, (uint8_t *)&val32, 4); + pci_dma_write(d, tc_addr + 32, (uint8_t *)&val32, 4); val32 = cpu_to_le32(tally_counters->TxMCol); - pci_dma_write(&s->dev, tc_addr + 36, (uint8_t *)&val32, 4); + pci_dma_write(d, tc_addr + 36, (uint8_t *)&val32, 4); val64 = cpu_to_le64(tally_counters->RxOkPhy); - pci_dma_write(&s->dev, tc_addr + 40, (uint8_t *)&val64, 8); + pci_dma_write(d, tc_addr + 40, (uint8_t *)&val64, 8); val64 = cpu_to_le64(tally_counters->RxOkBrd); - pci_dma_write(&s->dev, tc_addr + 48, (uint8_t *)&val64, 8); + pci_dma_write(d, tc_addr + 48, (uint8_t *)&val64, 8); val32 = cpu_to_le32(tally_counters->RxOkMul); - pci_dma_write(&s->dev, tc_addr + 56, (uint8_t *)&val32, 4); + pci_dma_write(d, tc_addr + 56, (uint8_t *)&val32, 4); val16 = cpu_to_le16(tally_counters->TxAbt); - pci_dma_write(&s->dev, tc_addr + 60, (uint8_t *)&val16, 2); + pci_dma_write(d, tc_addr + 60, (uint8_t *)&val16, 2); val16 = cpu_to_le16(tally_counters->TxUndrn); - pci_dma_write(&s->dev, tc_addr + 62, (uint8_t *)&val16, 2); + pci_dma_write(d, tc_addr + 62, (uint8_t *)&val16, 2); } /* Loads values of tally counters from VM state file */ @@ -1344,8 +1358,7 @@ static const VMStateDescription vmstate_tally_counters = { .name = "tally_counters", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT64(TxOk, RTL8139TallyCounters), VMSTATE_UINT64(RxOk, RTL8139TallyCounters), VMSTATE_UINT64(TxERR, RTL8139TallyCounters), @@ -1364,6 +1377,8 @@ static const VMStateDescription vmstate_tally_counters = { static void rtl8139_ChipCmd_write(RTL8139State *s, uint32_t val) { + DeviceState *d = DEVICE(s); + val &= 0xff; DPRINTF("ChipCmd write val=0x%08x\n", val); @@ -1371,7 +1386,7 @@ static void rtl8139_ChipCmd_write(RTL8139State *s, uint32_t val) if (val & CmdReset) { DPRINTF("ChipCmd reset\n"); - rtl8139_reset(&s->dev.qdev); + rtl8139_reset(d); } if (val & CmdRxEnb) { @@ -1525,6 +1540,8 @@ static uint32_t rtl8139_BasicModeStatus_read(RTL8139State *s) static void rtl8139_Cfg9346_write(RTL8139State *s, uint32_t val) { + DeviceState *d = DEVICE(s); + val &= 0xff; DPRINTF("Cfg9346 write val=0x%02x\n", val); @@ -1544,7 +1561,7 @@ static void rtl8139_Cfg9346_write(RTL8139State *s, uint32_t val) } else if (opmode == 0x40) { /* Reset. */ val = 0; - rtl8139_reset(&s->dev.qdev); + rtl8139_reset(d); } s->Cfg9346 = val; @@ -1758,6 +1775,7 @@ static void rtl8139_transfer_frame(RTL8139State *s, uint8_t *buf, int size, int do_interrupt, const uint8_t *dot1q_buf) { struct iovec *iov = NULL; + struct iovec vlan_iov[3]; if (!size) { @@ -1765,13 +1783,16 @@ static void rtl8139_transfer_frame(RTL8139State *s, uint8_t *buf, int size, return; } - if (dot1q_buf && size >= ETHER_ADDR_LEN * 2) { + if (dot1q_buf && size >= ETH_ALEN * 2) { iov = (struct iovec[3]) { - { .iov_base = buf, .iov_len = ETHER_ADDR_LEN * 2 }, + { .iov_base = buf, .iov_len = ETH_ALEN * 2 }, { .iov_base = (void *) dot1q_buf, .iov_len = VLAN_HLEN }, - { .iov_base = buf + ETHER_ADDR_LEN * 2, - .iov_len = size - ETHER_ADDR_LEN * 2 }, + { .iov_base = buf + ETH_ALEN * 2, + .iov_len = size - ETH_ALEN * 2 }, }; + + memcpy(vlan_iov, iov, sizeof(vlan_iov)); + iov = vlan_iov; } if (TxLoopBack == (s->TxConfig & TxLoopBack)) @@ -1821,13 +1842,14 @@ static int rtl8139_transmit_one(RTL8139State *s, int descriptor) DPRINTF("+++ transmitting from descriptor %d\n", descriptor); + PCIDevice *d = PCI_DEVICE(s); int txsize = s->TxStatus[descriptor] & 0x1fff; uint8_t txbuffer[0x2000]; DPRINTF("+++ transmit reading %d bytes from host memory at 0x%08x\n", txsize, s->TxAddr[descriptor]); - pci_dma_read(&s->dev, s->TxAddr[descriptor], txbuffer, txsize); + pci_dma_read(d, s->TxAddr[descriptor], txbuffer, txsize); /* Mark descriptor as transferred */ s->TxStatus[descriptor] |= TxHostOwns; @@ -1846,64 +1868,12 @@ static int rtl8139_transmit_one(RTL8139State *s, int descriptor) } /* structures and macros for task offloading */ -typedef struct ip_header -{ - uint8_t ip_ver_len; /* version and header length */ - uint8_t ip_tos; /* type of service */ - uint16_t ip_len; /* total length */ - uint16_t ip_id; /* identification */ - uint16_t ip_off; /* fragment offset field */ - uint8_t ip_ttl; /* time to live */ - uint8_t ip_p; /* protocol */ - uint16_t ip_sum; /* checksum */ - uint32_t ip_src,ip_dst; /* source and dest address */ -} ip_header; - -#define IP_HEADER_VERSION_4 4 -#define IP_HEADER_VERSION(ip) ((ip->ip_ver_len >> 4)&0xf) -#define IP_HEADER_LENGTH(ip) (((ip->ip_ver_len)&0xf) << 2) - -typedef struct tcp_header -{ - uint16_t th_sport; /* source port */ - uint16_t th_dport; /* destination port */ - uint32_t th_seq; /* sequence number */ - uint32_t th_ack; /* acknowledgement number */ - uint16_t th_offset_flags; /* data offset, reserved 6 bits, TCP protocol flags */ - uint16_t th_win; /* window */ - uint16_t th_sum; /* checksum */ - uint16_t th_urp; /* urgent pointer */ -} tcp_header; - -typedef struct udp_header -{ - uint16_t uh_sport; /* source port */ - uint16_t uh_dport; /* destination port */ - uint16_t uh_ulen; /* udp length */ - uint16_t uh_sum; /* udp checksum */ -} udp_header; - -typedef struct ip_pseudo_header -{ - uint32_t ip_src; - uint32_t ip_dst; - uint8_t zeros; - uint8_t ip_proto; - uint16_t ip_payload; -} ip_pseudo_header; - -#define IP_PROTO_TCP 6 -#define IP_PROTO_UDP 17 - #define TCP_HEADER_DATA_OFFSET(tcp) (((be16_to_cpu(tcp->th_offset_flags) >> 12)&0xf) << 2) #define TCP_FLAGS_ONLY(flags) ((flags)&0x3f) #define TCP_HEADER_FLAGS(tcp) TCP_FLAGS_ONLY(be16_to_cpu(tcp->th_offset_flags)) #define TCP_HEADER_CLEAR_FLAGS(tcp, off) ((tcp)->th_offset_flags &= cpu_to_be16(~TCP_FLAGS_ONLY(off))) -#define TCP_FLAG_FIN 0x01 -#define TCP_FLAG_PUSH 0x08 - /* produces ones' complement sum of data */ static uint16_t ones_complement_sum(uint8_t *data, size_t len) { @@ -1946,6 +1916,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) return 0 ; } + PCIDevice *d = PCI_DEVICE(s); int descriptor = s->currCPlusTxDesc; dma_addr_t cplus_tx_ring_desc = rtl8139_addr64(s->TxAddr[0], s->TxAddr[1]); @@ -1959,13 +1930,13 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) uint32_t val, txdw0,txdw1,txbufLO,txbufHI; - pci_dma_read(&s->dev, cplus_tx_ring_desc, (uint8_t *)&val, 4); + pci_dma_read(d, cplus_tx_ring_desc, (uint8_t *)&val, 4); txdw0 = le32_to_cpu(val); - pci_dma_read(&s->dev, cplus_tx_ring_desc+4, (uint8_t *)&val, 4); + pci_dma_read(d, cplus_tx_ring_desc+4, (uint8_t *)&val, 4); txdw1 = le32_to_cpu(val); - pci_dma_read(&s->dev, cplus_tx_ring_desc+8, (uint8_t *)&val, 4); + pci_dma_read(d, cplus_tx_ring_desc+8, (uint8_t *)&val, 4); txbufLO = le32_to_cpu(val); - pci_dma_read(&s->dev, cplus_tx_ring_desc+12, (uint8_t *)&val, 4); + pci_dma_read(d, cplus_tx_ring_desc+12, (uint8_t *)&val, 4); txbufHI = le32_to_cpu(val); DPRINTF("+++ C+ mode TX descriptor %d %08x %08x %08x %08x\n", descriptor, @@ -2052,27 +2023,13 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) "length to %d\n", txsize); } - if (!s->cplus_txbuffer) - { - /* out of memory */ - - DPRINTF("+++ C+ mode transmiter failed to reallocate %d bytes\n", - s->cplus_txbuffer_len); - - /* update tally counter */ - ++s->tally_counters.TxERR; - ++s->tally_counters.TxAbt; - - return 0; - } - /* append more data to the packet */ DPRINTF("+++ C+ mode transmit reading %d bytes from host memory at " DMA_ADDR_FMT" to offset %d\n", txsize, tx_addr, s->cplus_txbuffer_offset); - pci_dma_read(&s->dev, tx_addr, + pci_dma_read(d, tx_addr, s->cplus_txbuffer + s->cplus_txbuffer_offset, txsize); s->cplus_txbuffer_offset += txsize; @@ -2100,7 +2057,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) /* update ring data */ val = cpu_to_le32(txdw0); - pci_dma_write(&s->dev, cplus_tx_ring_desc, (uint8_t *)&val, 4); + pci_dma_write(d, cplus_tx_ring_desc, (uint8_t *)&val, 4); /* Now decide if descriptor being processed is holding the last segment of packet */ if (txdw0 & CP_TX_LS) @@ -2125,7 +2082,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) bswap16(txdw1 & CP_TX_VLAN_TAG_MASK)); dot1q_buffer = (uint16_t *) dot1q_buffer_space; - dot1q_buffer[0] = cpu_to_be16(ETH_P_8021Q); + dot1q_buffer[0] = cpu_to_be16(ETH_P_VLAN); /* BE + le_to_cpu() + ~cpu_to_le()~ = BE */ dot1q_buffer[1] = cpu_to_le16(txdw1 & CP_TX_VLAN_TAG_MASK); } else { @@ -2141,8 +2098,13 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) { DPRINTF("+++ C+ mode offloaded task checksum\n"); + /* Large enough for Ethernet and IP headers? */ + if (saved_size < ETH_HLEN + sizeof(struct ip_header)) { + goto skip_offload; + } + /* ip packet header */ - ip_header *ip = NULL; + struct ip_header *ip = NULL; int hlen = 0; uint8_t ip_protocol = 0; uint16_t ip_data_len = 0; @@ -2151,223 +2113,240 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) size_t eth_payload_len = 0; int proto = be16_to_cpu(*(uint16_t *)(saved_buffer + 12)); - if (proto == ETH_P_IP) + if (proto != ETH_P_IP) { - DPRINTF("+++ C+ mode has IP packet\n"); - - /* not aligned */ - eth_payload_data = saved_buffer + ETH_HLEN; - eth_payload_len = saved_size - ETH_HLEN; - - ip = (ip_header*)eth_payload_data; - - if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) { - DPRINTF("+++ C+ mode packet has bad IP version %d " - "expected %d\n", IP_HEADER_VERSION(ip), - IP_HEADER_VERSION_4); - ip = NULL; - } else { - hlen = IP_HEADER_LENGTH(ip); - ip_protocol = ip->ip_p; - ip_data_len = be16_to_cpu(ip->ip_len) - hlen; - } + goto skip_offload; } - if (ip) + DPRINTF("+++ C+ mode has IP packet\n"); + + /* Note on memory alignment: eth_payload_data is 16-bit aligned + * since saved_buffer is allocated with g_malloc() and ETH_HLEN is + * even. 32-bit accesses must use ldl/stl wrappers to avoid + * unaligned accesses. + */ + eth_payload_data = saved_buffer + ETH_HLEN; + eth_payload_len = saved_size - ETH_HLEN; + + ip = (struct ip_header*)eth_payload_data; + + if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) { + DPRINTF("+++ C+ mode packet has bad IP version %d " + "expected %d\n", IP_HEADER_VERSION(ip), + IP_HEADER_VERSION_4); + goto skip_offload; + } + + hlen = IP_HDR_GET_LEN(ip); + if (hlen < sizeof(struct ip_header) || hlen > eth_payload_len) { + goto skip_offload; + } + + ip_protocol = ip->ip_p; + + ip_data_len = be16_to_cpu(ip->ip_len); + if (ip_data_len < hlen || ip_data_len > eth_payload_len) { + goto skip_offload; + } + ip_data_len -= hlen; + + if (txdw0 & CP_TX_IPCS) { - if (txdw0 & CP_TX_IPCS) - { - DPRINTF("+++ C+ mode need IP checksum\n"); + DPRINTF("+++ C+ mode need IP checksum\n"); - if (hleneth_payload_len) {/* min header length */ - /* bad packet header len */ - /* or packet too short */ - } - else - { - ip->ip_sum = 0; - ip->ip_sum = ip_checksum(ip, hlen); - DPRINTF("+++ C+ mode IP header len=%d checksum=%04x\n", - hlen, ip->ip_sum); - } + ip->ip_sum = 0; + ip->ip_sum = ip_checksum(ip, hlen); + DPRINTF("+++ C+ mode IP header len=%d checksum=%04x\n", + hlen, ip->ip_sum); + } + + if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP) + { + /* Large enough for the TCP header? */ + if (ip_data_len < sizeof(tcp_header)) { + goto skip_offload; } - if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP) - { - int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK; + int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK; - DPRINTF("+++ C+ mode offloaded task TSO MTU=%d IP data %d " - "frame data %d specified MSS=%d\n", ETH_MTU, - ip_data_len, saved_size - ETH_HLEN, large_send_mss); + DPRINTF("+++ C+ mode offloaded task TSO MTU=%d IP data %d " + "frame data %d specified MSS=%d\n", ETH_MTU, + ip_data_len, saved_size - ETH_HLEN, large_send_mss); - int tcp_send_offset = 0; - int send_count = 0; + int tcp_send_offset = 0; + int send_count = 0; - /* maximum IP header length is 60 bytes */ - uint8_t saved_ip_header[60]; + /* maximum IP header length is 60 bytes */ + uint8_t saved_ip_header[60]; - /* save IP header template; data area is used in tcp checksum calculation */ - memcpy(saved_ip_header, eth_payload_data, hlen); + /* save IP header template; data area is used in tcp checksum calculation */ + memcpy(saved_ip_header, eth_payload_data, hlen); - /* a placeholder for checksum calculation routine in tcp case */ - uint8_t *data_to_checksum = eth_payload_data + hlen - 12; - // size_t data_to_checksum_len = eth_payload_len - hlen + 12; + /* a placeholder for checksum calculation routine in tcp case */ + uint8_t *data_to_checksum = eth_payload_data + hlen - 12; + // size_t data_to_checksum_len = eth_payload_len - hlen + 12; - /* pointer to TCP header */ - tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen); + /* pointer to TCP header */ + tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen); - int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr); + int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr); - /* ETH_MTU = ip header len + tcp header len + payload */ - int tcp_data_len = ip_data_len - tcp_hlen; - int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen; + /* Invalid TCP data offset? */ + if (tcp_hlen < sizeof(tcp_header) || tcp_hlen > ip_data_len) { + goto skip_offload; + } - DPRINTF("+++ C+ mode TSO IP data len %d TCP hlen %d TCP " - "data len %d TCP chunk size %d\n", ip_data_len, - tcp_hlen, tcp_data_len, tcp_chunk_size); + /* ETH_MTU = ip header len + tcp header len + payload */ + int tcp_data_len = ip_data_len - tcp_hlen; + int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen; - /* note the cycle below overwrites IP header data, - but restores it from saved_ip_header before sending packet */ + DPRINTF("+++ C+ mode TSO IP data len %d TCP hlen %d TCP " + "data len %d TCP chunk size %d\n", ip_data_len, + tcp_hlen, tcp_data_len, tcp_chunk_size); - int is_last_frame = 0; + /* note the cycle below overwrites IP header data, + but restores it from saved_ip_header before sending packet */ - for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size) - { - uint16_t chunk_size = tcp_chunk_size; - - /* check if this is the last frame */ - if (tcp_send_offset + tcp_chunk_size >= tcp_data_len) - { - is_last_frame = 1; - chunk_size = tcp_data_len - tcp_send_offset; - } - - DPRINTF("+++ C+ mode TSO TCP seqno %08x\n", - be32_to_cpu(p_tcp_hdr->th_seq)); - - /* add 4 TCP pseudoheader fields */ - /* copy IP source and destination fields */ - memcpy(data_to_checksum, saved_ip_header + 12, 8); - - DPRINTF("+++ C+ mode TSO calculating TCP checksum for " - "packet with %d bytes data\n", tcp_hlen + - chunk_size); - - if (tcp_send_offset) - { - memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size); - } - - /* keep PUSH and FIN flags only for the last frame */ - if (!is_last_frame) - { - TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_PUSH|TCP_FLAG_FIN); - } - - /* recalculate TCP checksum */ - ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum; - p_tcpip_hdr->zeros = 0; - p_tcpip_hdr->ip_proto = IP_PROTO_TCP; - p_tcpip_hdr->ip_payload = cpu_to_be16(tcp_hlen + chunk_size); - - p_tcp_hdr->th_sum = 0; - - int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12); - DPRINTF("+++ C+ mode TSO TCP checksum %04x\n", - tcp_checksum); - - p_tcp_hdr->th_sum = tcp_checksum; - - /* restore IP header */ - memcpy(eth_payload_data, saved_ip_header, hlen); - - /* set IP data length and recalculate IP checksum */ - ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size); - - /* increment IP id for subsequent frames */ - ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id)); - - ip->ip_sum = 0; - ip->ip_sum = ip_checksum(eth_payload_data, hlen); - DPRINTF("+++ C+ mode TSO IP header len=%d " - "checksum=%04x\n", hlen, ip->ip_sum); - - int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size; - DPRINTF("+++ C+ mode TSO transferring packet size " - "%d\n", tso_send_size); - rtl8139_transfer_frame(s, saved_buffer, tso_send_size, - 0, (uint8_t *) dot1q_buffer); - - /* add transferred count to TCP sequence number */ - p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + be32_to_cpu(p_tcp_hdr->th_seq)); - ++send_count; - } + int is_last_frame = 0; - /* Stop sending this frame */ - saved_size = 0; - } - else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS)) + for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size) { - DPRINTF("+++ C+ mode need TCP or UDP checksum\n"); + uint16_t chunk_size = tcp_chunk_size; - /* maximum IP header length is 60 bytes */ - uint8_t saved_ip_header[60]; - memcpy(saved_ip_header, eth_payload_data, hlen); + /* check if this is the last frame */ + if (tcp_send_offset + tcp_chunk_size >= tcp_data_len) + { + is_last_frame = 1; + chunk_size = tcp_data_len - tcp_send_offset; + } - uint8_t *data_to_checksum = eth_payload_data + hlen - 12; - // size_t data_to_checksum_len = eth_payload_len - hlen + 12; + DPRINTF("+++ C+ mode TSO TCP seqno %08x\n", + ldl_be_p(&p_tcp_hdr->th_seq)); /* add 4 TCP pseudoheader fields */ /* copy IP source and destination fields */ memcpy(data_to_checksum, saved_ip_header + 12, 8); - if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP) + DPRINTF("+++ C+ mode TSO calculating TCP checksum for " + "packet with %d bytes data\n", tcp_hlen + + chunk_size); + + if (tcp_send_offset) { - DPRINTF("+++ C+ mode calculating TCP checksum for " - "packet with %d bytes data\n", ip_data_len); + memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size); + } - ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum; - p_tcpip_hdr->zeros = 0; - p_tcpip_hdr->ip_proto = IP_PROTO_TCP; - p_tcpip_hdr->ip_payload = cpu_to_be16(ip_data_len); + /* keep PUSH and FIN flags only for the last frame */ + if (!is_last_frame) + { + TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TH_PUSH | TH_FIN); + } - tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12); + /* recalculate TCP checksum */ + ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum; + p_tcpip_hdr->zeros = 0; + p_tcpip_hdr->ip_proto = IP_PROTO_TCP; + p_tcpip_hdr->ip_payload = cpu_to_be16(tcp_hlen + chunk_size); - p_tcp_hdr->th_sum = 0; + p_tcp_hdr->th_sum = 0; - int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); - DPRINTF("+++ C+ mode TCP checksum %04x\n", - tcp_checksum); + int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12); + DPRINTF("+++ C+ mode TSO TCP checksum %04x\n", + tcp_checksum); - p_tcp_hdr->th_sum = tcp_checksum; - } - else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP) - { - DPRINTF("+++ C+ mode calculating UDP checksum for " - "packet with %d bytes data\n", ip_data_len); + p_tcp_hdr->th_sum = tcp_checksum; - ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum; - p_udpip_hdr->zeros = 0; - p_udpip_hdr->ip_proto = IP_PROTO_UDP; - p_udpip_hdr->ip_payload = cpu_to_be16(ip_data_len); + /* restore IP header */ + memcpy(eth_payload_data, saved_ip_header, hlen); - udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12); + /* set IP data length and recalculate IP checksum */ + ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size); - p_udp_hdr->uh_sum = 0; + /* increment IP id for subsequent frames */ + ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id)); - int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); - DPRINTF("+++ C+ mode UDP checksum %04x\n", - udp_checksum); + ip->ip_sum = 0; + ip->ip_sum = ip_checksum(eth_payload_data, hlen); + DPRINTF("+++ C+ mode TSO IP header len=%d " + "checksum=%04x\n", hlen, ip->ip_sum); - p_udp_hdr->uh_sum = udp_checksum; - } + int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size; + DPRINTF("+++ C+ mode TSO transferring packet size " + "%d\n", tso_send_size); + rtl8139_transfer_frame(s, saved_buffer, tso_send_size, + 0, (uint8_t *) dot1q_buffer); - /* restore IP header */ - memcpy(eth_payload_data, saved_ip_header, hlen); + /* add transferred count to TCP sequence number */ + stl_be_p(&p_tcp_hdr->th_seq, + chunk_size + ldl_be_p(&p_tcp_hdr->th_seq)); + ++send_count; } + + /* Stop sending this frame */ + saved_size = 0; + } + else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS)) + { + DPRINTF("+++ C+ mode need TCP or UDP checksum\n"); + + /* maximum IP header length is 60 bytes */ + uint8_t saved_ip_header[60]; + memcpy(saved_ip_header, eth_payload_data, hlen); + + uint8_t *data_to_checksum = eth_payload_data + hlen - 12; + // size_t data_to_checksum_len = eth_payload_len - hlen + 12; + + /* add 4 TCP pseudoheader fields */ + /* copy IP source and destination fields */ + memcpy(data_to_checksum, saved_ip_header + 12, 8); + + if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP) + { + DPRINTF("+++ C+ mode calculating TCP checksum for " + "packet with %d bytes data\n", ip_data_len); + + ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum; + p_tcpip_hdr->zeros = 0; + p_tcpip_hdr->ip_proto = IP_PROTO_TCP; + p_tcpip_hdr->ip_payload = cpu_to_be16(ip_data_len); + + tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12); + + p_tcp_hdr->th_sum = 0; + + int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); + DPRINTF("+++ C+ mode TCP checksum %04x\n", + tcp_checksum); + + p_tcp_hdr->th_sum = tcp_checksum; + } + else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP) + { + DPRINTF("+++ C+ mode calculating UDP checksum for " + "packet with %d bytes data\n", ip_data_len); + + ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum; + p_udpip_hdr->zeros = 0; + p_udpip_hdr->ip_proto = IP_PROTO_UDP; + p_udpip_hdr->ip_payload = cpu_to_be16(ip_data_len); + + udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12); + + p_udp_hdr->uh_sum = 0; + + int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); + DPRINTF("+++ C+ mode UDP checksum %04x\n", + udp_checksum); + + p_udp_hdr->uh_sum = udp_checksum; + } + + /* restore IP header */ + memcpy(eth_payload_data, saved_ip_header, hlen); } } +skip_offload: /* update tally counter */ ++s->tally_counters.TxOk; @@ -2629,7 +2608,6 @@ static void rtl8139_IntrMask_write(RTL8139State *s, uint32_t val) s->IntrMask = val; - rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock)); rtl8139_update_irq(s); } @@ -2664,13 +2642,7 @@ static void rtl8139_IntrStatus_write(RTL8139State *s, uint32_t val) rtl8139_update_irq(s); s->IntrStatus = newStatus; - /* - * Computing if we miss an interrupt here is not that correct but - * considered that we should have had already an interrupt - * and probably emulated is slower is better to assume this resetting was - * done before testing on previous rtl8139_update_irq lead to IRQ losing - */ - rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock)); + rtl8139_set_next_tctr_time(s); rtl8139_update_irq(s); #endif @@ -2678,8 +2650,6 @@ static void rtl8139_IntrStatus_write(RTL8139State *s, uint32_t val) static uint32_t rtl8139_IntrStatus_read(RTL8139State *s) { - rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock)); - uint32_t ret = s->IntrStatus; DPRINTF("IntrStatus read(w) val=0x%04x\n", ret); @@ -2721,9 +2691,13 @@ static void rtl8139_io_writeb(void *opaque, uint8_t addr, uint32_t val) switch (addr) { - case MAC0 ... MAC0+5: + case MAC0 ... MAC0+4: s->phys[addr - MAC0] = val; break; + case MAC0+5: + s->phys[addr - MAC0] = val; + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->phys); + break; case MAC0+6 ... MAC0+7: /* reserved */ break; @@ -2858,43 +2832,32 @@ static void rtl8139_io_writew(void *opaque, uint8_t addr, uint32_t val) } } -static void rtl8139_set_next_tctr_time(RTL8139State *s, int64_t current_time) +static void rtl8139_set_next_tctr_time(RTL8139State *s) { - int64_t pci_time, next_time; - uint32_t low_pci; + const uint64_t ns_per_period = + muldiv64(0x100000000LL, get_ticks_per_sec(), PCI_FREQUENCY); DPRINTF("entered rtl8139_set_next_tctr_time\n"); - if (s->TimerExpire && current_time >= s->TimerExpire) { - s->IntrStatus |= PCSTimeout; - rtl8139_update_irq(s); - } - - /* Set QEMU timer only if needed that is - * - TimerInt <> 0 (we have a timer) - * - mask = 1 (we want an interrupt timer) - * - irq = 0 (irq is not already active) - * If any of above change we need to compute timer again - * Also we must check if timer is passed without QEMU timer + /* This function is called at least once per period, so it is a good + * place to update the timer base. + * + * After one iteration of this loop the value in the Timer register does + * not change, but the device model is counting up by 2^32 ticks (approx. + * 130 seconds). */ - s->TimerExpire = 0; - if (!s->TimerInt) { - return; - } - - pci_time = muldiv64(current_time - s->TCTR_base, PCI_FREQUENCY, - get_ticks_per_sec()); - low_pci = pci_time & 0xffffffff; - pci_time = pci_time - low_pci + s->TimerInt; - if (low_pci >= s->TimerInt) { - pci_time += 0x100000000LL; + while (s->TCTR_base + ns_per_period <= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) { + s->TCTR_base += ns_per_period; } - next_time = s->TCTR_base + muldiv64(pci_time, get_ticks_per_sec(), - PCI_FREQUENCY); - s->TimerExpire = next_time; - if ((s->IntrMask & PCSTimeout) != 0 && (s->IntrStatus & PCSTimeout) == 0) { - qemu_mod_timer(s->timer, next_time); + if (!s->TimerInt) { + timer_del(s->timer); + } else { + uint64_t delta = muldiv64(s->TimerInt, get_ticks_per_sec(), PCI_FREQUENCY); + if (s->TCTR_base + delta <= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) { + delta += ns_per_period; + } + timer_mod(s->timer, s->TCTR_base + delta); } } @@ -2941,15 +2904,15 @@ static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val) case Timer: DPRINTF("TCTR Timer reset on write\n"); - s->TCTR_base = qemu_get_clock_ns(vm_clock); - rtl8139_set_next_tctr_time(s, s->TCTR_base); + s->TCTR_base = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + rtl8139_set_next_tctr_time(s); break; case FlashReg: DPRINTF("FlashReg TimerInt write val=0x%08x\n", val); if (s->TimerInt != val) { s->TimerInt = val; - rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock)); + rtl8139_set_next_tctr_time(s); } break; @@ -3164,7 +3127,7 @@ static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr) break; case Timer: - ret = muldiv64(qemu_get_clock_ns(vm_clock) - s->TCTR_base, + ret = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->TCTR_base, PCI_FREQUENCY, get_ticks_per_sec()); DPRINTF("TCTR Timer read val=0x%08x\n", ret); break; @@ -3226,7 +3189,7 @@ static uint32_t rtl8139_mmio_readl(void *opaque, hwaddr addr) static int rtl8139_post_load(void *opaque, int version_id) { RTL8139State* s = opaque; - rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock)); + rtl8139_set_next_tctr_time(s); if (version_id < 4) { s->cplus_enabled = s->CpCmd != 0; } @@ -3247,8 +3210,8 @@ static const VMStateDescription vmstate_rtl8139_hotplug_ready ={ .name = "rtl8139/hotplug_ready", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .needed = rtl8139_hotplug_ready_needed, + .fields = (VMStateField[]) { VMSTATE_END_OF_LIST() } }; @@ -3256,10 +3219,9 @@ static const VMStateDescription vmstate_rtl8139_hotplug_ready ={ static void rtl8139_pre_save(void *opaque) { RTL8139State* s = opaque; - int64_t current_time = qemu_get_clock_ns(vm_clock); + int64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - /* set IntrStatus correctly */ - rtl8139_set_next_tctr_time(s, current_time); + /* for migration to older versions */ s->TCTR = muldiv64(current_time - s->TCTR_base, PCI_FREQUENCY, get_ticks_per_sec()); s->rtl8139_mmio_io_addr_dummy = 0; @@ -3269,11 +3231,10 @@ static const VMStateDescription vmstate_rtl8139 = { .name = "rtl8139", .version_id = 4, .minimum_version_id = 3, - .minimum_version_id_old = 3, .post_load = rtl8139_post_load, .pre_save = rtl8139_pre_save, - .fields = (VMStateField []) { - VMSTATE_PCI_DEVICE(dev, RTL8139State), + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(parent_obj, RTL8139State), VMSTATE_PARTIAL_BUFFER(phys, RTL8139State, 6), VMSTATE_BUFFER(mult, RTL8139State), VMSTATE_UINT32_ARRAY(TxStatus, RTL8139State, 4), @@ -3345,13 +3306,9 @@ static const VMStateDescription vmstate_rtl8139 = { VMSTATE_UINT32_V(cplus_enabled, RTL8139State, 4), VMSTATE_END_OF_LIST() }, - .subsections = (VMStateSubsection []) { - { - .vmsd = &vmstate_rtl8139_hotplug_ready, - .needed = rtl8139_hotplug_ready_needed, - }, { - /* empty */ - } + .subsections = (const VMStateDescription*[]) { + &vmstate_rtl8139_hotplug_ready, + NULL } }; @@ -3427,28 +3384,19 @@ static void rtl8139_timer(void *opaque) s->IntrStatus |= PCSTimeout; rtl8139_update_irq(s); - rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock)); -} - -static void rtl8139_cleanup(NetClientState *nc) -{ - RTL8139State *s = qemu_get_nic_opaque(nc); - - s->nic = NULL; + rtl8139_set_next_tctr_time(s); } static void pci_rtl8139_uninit(PCIDevice *dev) { - RTL8139State *s = DO_UPCAST(RTL8139State, dev, dev); + RTL8139State *s = RTL8139(dev); - memory_region_destroy(&s->bar_io); - memory_region_destroy(&s->bar_mem); if (s->cplus_txbuffer) { g_free(s->cplus_txbuffer); s->cplus_txbuffer = NULL; } - qemu_del_timer(s->timer); - qemu_free_timer(s->timer); + timer_del(s->timer); + timer_free(s->timer); qemu_del_nic(s->nic); } @@ -3471,16 +3419,16 @@ static NetClientInfo net_rtl8139_info = { .size = sizeof(NICState), .can_receive = rtl8139_can_receive, .receive = rtl8139_receive, - .cleanup = rtl8139_cleanup, .link_status_changed = rtl8139_set_link_status, }; -static int pci_rtl8139_init(PCIDevice *dev) +static void pci_rtl8139_realize(PCIDevice *dev, Error **errp) { - RTL8139State * s = DO_UPCAST(RTL8139State, dev, dev); + RTL8139State *s = RTL8139(dev); + DeviceState *d = DEVICE(dev); uint8_t *pci_conf; - pci_conf = s->dev.config; + pci_conf = dev->config; pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */ /* TODO: start of capability list, but no capability * list bit in status register, and offset 0xdc seems unused. */ @@ -3490,8 +3438,8 @@ static int pci_rtl8139_init(PCIDevice *dev) "rtl8139", 0x100); memory_region_init_io(&s->bar_mem, OBJECT(s), &rtl8139_mmio_ops, s, "rtl8139", 0x100); - pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->bar_io); - pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar_mem); + pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->bar_io); + pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar_mem); qemu_macaddr_default_if_unset(&s->conf.macaddr); @@ -3507,20 +3455,23 @@ static int pci_rtl8139_init(PCIDevice *dev) s->eeprom.contents[9] = s->conf.macaddr.a[4] | s->conf.macaddr.a[5] << 8; s->nic = qemu_new_nic(&net_rtl8139_info, &s->conf, - object_get_typename(OBJECT(dev)), dev->qdev.id, s); + object_get_typename(OBJECT(dev)), d->id, s); qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); s->cplus_txbuffer = NULL; s->cplus_txbuffer_len = 0; s->cplus_txbuffer_offset = 0; - s->TimerExpire = 0; - s->timer = qemu_new_timer_ns(vm_clock, rtl8139_timer, s); - rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock)); + s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, rtl8139_timer, s); +} - add_boot_device_path(s->conf.bootindex, &dev->qdev, "/ethernet-phy@0"); +static void rtl8139_instance_init(Object *obj) +{ + RTL8139State *s = RTL8139(obj); - return 0; + device_add_bootindex_property(obj, &s->conf.bootindex, + "bootindex", "/ethernet-phy@0", + DEVICE(obj), NULL); } static Property rtl8139_properties[] = { @@ -3533,7 +3484,7 @@ static void rtl8139_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - k->init = pci_rtl8139_init; + k->realize = pci_rtl8139_realize; k->exit = pci_rtl8139_uninit; k->romfile = "efi-rtl8139.rom"; k->vendor_id = PCI_VENDOR_ID_REALTEK; @@ -3543,13 +3494,15 @@ static void rtl8139_class_init(ObjectClass *klass, void *data) dc->reset = rtl8139_reset; dc->vmsd = &vmstate_rtl8139; dc->props = rtl8139_properties; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); } static const TypeInfo rtl8139_info = { - .name = "rtl8139", + .name = TYPE_RTL8139, .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(RTL8139State), .class_init = rtl8139_class_init, + .instance_init = rtl8139_instance_init, }; static void rtl8139_register_types(void)