diff options
Diffstat (limited to 'hw/net')
71 files changed, 1910 insertions, 1819 deletions
diff --git a/hw/net/Kconfig b/hw/net/Kconfig index 7fcc0d7..7f80218 100644 --- a/hw/net/Kconfig +++ b/hw/net/Kconfig @@ -62,8 +62,12 @@ config VMXNET3_PCI config SMC91C111 bool +config LAN9118_PHY + bool + config LAN9118 bool + select LAN9118_PHY select PTIMER config NE2000_ISA @@ -89,6 +93,7 @@ config ALLWINNER_SUN8I_EMAC config IMX_FEC bool + select LAN9118_PHY config CADENCE bool diff --git a/hw/net/allwinner-sun8i-emac.c b/hw/net/allwinner-sun8i-emac.c index 108ae9c..30a8157 100644 --- a/hw/net/allwinner-sun8i-emac.c +++ b/hw/net/allwinner-sun8i-emac.c @@ -30,7 +30,7 @@ #include "net/checksum.h" #include "qemu/module.h" #include "exec/cpu-common.h" -#include "sysemu/dma.h" +#include "system/dma.h" #include "hw/net/allwinner-sun8i-emac.h" /* EMAC register offsets */ @@ -784,7 +784,7 @@ static void allwinner_sun8i_emac_set_link(NetClientState *nc) static const MemoryRegionOps allwinner_sun8i_emac_mem_ops = { .read = allwinner_sun8i_emac_read, .write = allwinner_sun8i_emac_write, - .endianness = DEVICE_NATIVE_ENDIAN, + .endianness = DEVICE_LITTLE_ENDIAN, .valid = { .min_access_size = 4, .max_access_size = 4, @@ -829,12 +829,11 @@ static void allwinner_sun8i_emac_realize(DeviceState *dev, Error **errp) qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); } -static Property allwinner_sun8i_emac_properties[] = { +static const Property allwinner_sun8i_emac_properties[] = { DEFINE_NIC_PROPERTIES(AwSun8iEmacState, conf), DEFINE_PROP_UINT8("phy-addr", AwSun8iEmacState, mii_phy_addr, 0), DEFINE_PROP_LINK("dma-memory", AwSun8iEmacState, dma_mr, TYPE_MEMORY_REGION, MemoryRegion *), - DEFINE_PROP_END_OF_LIST(), }; static int allwinner_sun8i_emac_post_load(void *opaque, int version_id) @@ -876,12 +875,13 @@ static const VMStateDescription vmstate_aw_emac = { } }; -static void allwinner_sun8i_emac_class_init(ObjectClass *klass, void *data) +static void allwinner_sun8i_emac_class_init(ObjectClass *klass, + const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = allwinner_sun8i_emac_realize; - dc->reset = allwinner_sun8i_emac_reset; + device_class_set_legacy_reset(dc, allwinner_sun8i_emac_reset); dc->vmsd = &vmstate_aw_emac; device_class_set_props(dc, allwinner_sun8i_emac_properties); } diff --git a/hw/net/allwinner_emac.c b/hw/net/allwinner_emac.c index d40ff37..77d089d 100644 --- a/hw/net/allwinner_emac.c +++ b/hw/net/allwinner_emac.c @@ -421,7 +421,7 @@ static void aw_emac_set_link(NetClientState *nc) static const MemoryRegionOps aw_emac_mem_ops = { .read = aw_emac_read, .write = aw_emac_write, - .endianness = DEVICE_NATIVE_ENDIAN, + .endianness = DEVICE_LITTLE_ENDIAN, .valid = { .min_access_size = 4, .max_access_size = 4, @@ -462,10 +462,9 @@ static void aw_emac_realize(DeviceState *dev, Error **errp) fifo8_create(&s->tx_fifo[1], TX_FIFO_SIZE); } -static Property aw_emac_properties[] = { +static const Property aw_emac_properties[] = { DEFINE_NIC_PROPERTIES(AwEmacState, conf), DEFINE_PROP_UINT8("phy-addr", AwEmacState, phy_addr, 0), - DEFINE_PROP_END_OF_LIST(), }; static const VMStateDescription vmstate_mii = { @@ -515,13 +514,13 @@ static const VMStateDescription vmstate_aw_emac = { } }; -static void aw_emac_class_init(ObjectClass *klass, void *data) +static void aw_emac_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = aw_emac_realize; device_class_set_props(dc, aw_emac_properties); - dc->reset = aw_emac_reset; + device_class_set_legacy_reset(dc, aw_emac_reset); dc->vmsd = &vmstate_aw_emac; } diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index ec7bf56..50025d5 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -23,7 +23,7 @@ */ #include "qemu/osdep.h" -#include <zlib.h> /* For crc32 */ +#include <zlib.h> /* for crc32 */ #include "hw/irq.h" #include "hw/net/cadence_gem.h" @@ -33,7 +33,7 @@ #include "qapi/error.h" #include "qemu/log.h" #include "qemu/module.h" -#include "sysemu/dma.h" +#include "system/dma.h" #include "net/checksum.h" #include "net/eth.h" @@ -909,8 +909,8 @@ static int get_queue_from_screen(CadenceGEMState *s, uint8_t *rxbuf_ptr, /* Compare A, B, C */ for (j = 0; j < 3; j++) { - uint32_t cr0, cr1, mask, compare; - uint16_t rx_cmp; + uint32_t cr0, cr1, mask, compare, disable_mask; + uint32_t rx_cmp; int offset; int cr_idx = extract32(reg, R_SCREENING_TYPE2_REG0_COMPARE_A_SHIFT + j * 6, R_SCREENING_TYPE2_REG0_COMPARE_A_LENGTH); @@ -946,9 +946,25 @@ static int get_queue_from_screen(CadenceGEMState *s, uint8_t *rxbuf_ptr, break; } - rx_cmp = rxbuf_ptr[offset] << 8 | rxbuf_ptr[offset]; - mask = FIELD_EX32(cr0, TYPE2_COMPARE_0_WORD_0, MASK_VALUE); - compare = FIELD_EX32(cr0, TYPE2_COMPARE_0_WORD_0, COMPARE_VALUE); + disable_mask = + FIELD_EX32(cr1, TYPE2_COMPARE_0_WORD_1, DISABLE_MASK); + if (disable_mask) { + /* + * If disable_mask is set, mask_value is used as an + * additional 2 byte Compare Value; that is equivalent + * to using the whole cr0 register as the comparison value. + * Load 32 bits of data from rx_buf, and set mask to + * all-ones so we compare all 32 bits. + */ + rx_cmp = ldl_le_p(rxbuf_ptr + offset); + mask = 0xFFFFFFFF; + compare = cr0; + } else { + rx_cmp = lduw_le_p(rxbuf_ptr + offset); + mask = FIELD_EX32(cr0, TYPE2_COMPARE_0_WORD_0, MASK_VALUE); + compare = + FIELD_EX32(cr0, TYPE2_COMPARE_0_WORD_0, COMPARE_VALUE); + } if ((rx_cmp & mask) == (compare & mask)) { matched = true; @@ -1784,7 +1800,7 @@ static const VMStateDescription vmstate_cadence_gem = { } }; -static Property gem_properties[] = { +static const Property gem_properties[] = { DEFINE_NIC_PROPERTIES(CadenceGEMState, conf), DEFINE_PROP_UINT32("revision", CadenceGEMState, revision, GEM_MODID_VALUE), @@ -1799,17 +1815,16 @@ static Property gem_properties[] = { jumbo_max_len, 10240), DEFINE_PROP_LINK("dma", CadenceGEMState, dma_mr, TYPE_MEMORY_REGION, MemoryRegion *), - DEFINE_PROP_END_OF_LIST(), }; -static void gem_class_init(ObjectClass *klass, void *data) +static void gem_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = gem_realize; device_class_set_props(dc, gem_properties); dc->vmsd = &vmstate_cadence_gem; - dc->reset = gem_reset; + device_class_set_legacy_reset(dc, gem_reset); } static const TypeInfo gem_info = { diff --git a/hw/net/can/can_kvaser_pci.c b/hw/net/can/can_kvaser_pci.c index bf41e6b..be16769 100644 --- a/hw/net/can/can_kvaser_pci.c +++ b/hw/net/can/can_kvaser_pci.c @@ -30,12 +30,8 @@ */ #include "qemu/osdep.h" -#include "qemu/event_notifier.h" #include "qemu/module.h" -#include "qemu/thread.h" -#include "qemu/sockets.h" #include "qapi/error.h" -#include "chardev/char.h" #include "hw/irq.h" #include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" @@ -286,7 +282,7 @@ static void kvaser_pci_instance_init(Object *obj) 0); } -static void kvaser_pci_class_init(ObjectClass *klass, void *data) +static void kvaser_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -299,7 +295,7 @@ static void kvaser_pci_class_init(ObjectClass *klass, void *data) k->class_id = 0x00ff00; dc->desc = "Kvaser PCICANx"; dc->vmsd = &vmstate_kvaser_pci; - dc->reset = kvaser_pci_reset; + device_class_set_legacy_reset(dc, kvaser_pci_reset); set_bit(DEVICE_CATEGORY_MISC, dc->categories); } @@ -309,7 +305,7 @@ static const TypeInfo kvaser_pci_info = { .instance_size = sizeof(KvaserPCIState), .class_init = kvaser_pci_class_init, .instance_init = kvaser_pci_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/net/can/can_mioe3680_pci.c b/hw/net/can/can_mioe3680_pci.c index 308b17e..44f3ba3 100644 --- a/hw/net/can/can_mioe3680_pci.c +++ b/hw/net/can/can_mioe3680_pci.c @@ -26,12 +26,8 @@ */ #include "qemu/osdep.h" -#include "qemu/event_notifier.h" #include "qemu/module.h" -#include "qemu/thread.h" -#include "qemu/sockets.h" #include "qapi/error.h" -#include "chardev/char.h" #include "hw/irq.h" #include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" @@ -227,7 +223,7 @@ static void mioe3680_pci_instance_init(Object *obj) 0); } -static void mioe3680_pci_class_init(ObjectClass *klass, void *data) +static void mioe3680_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -243,7 +239,7 @@ static void mioe3680_pci_class_init(ObjectClass *klass, void *data) dc->desc = "Mioe3680 PCICANx"; dc->vmsd = &vmstate_mioe3680_pci; set_bit(DEVICE_CATEGORY_MISC, dc->categories); - dc->reset = mioe3680_pci_reset; + device_class_set_legacy_reset(dc, mioe3680_pci_reset); } static const TypeInfo mioe3680_pci_info = { @@ -252,7 +248,7 @@ static const TypeInfo mioe3680_pci_info = { .instance_size = sizeof(Mioe3680PCIState), .class_init = mioe3680_pci_class_init, .instance_init = mioe3680_pci_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/net/can/can_pcm3680_pci.c b/hw/net/can/can_pcm3680_pci.c index e4c8d93..7296d63 100644 --- a/hw/net/can/can_pcm3680_pci.c +++ b/hw/net/can/can_pcm3680_pci.c @@ -26,12 +26,8 @@ */ #include "qemu/osdep.h" -#include "qemu/event_notifier.h" #include "qemu/module.h" -#include "qemu/thread.h" -#include "qemu/sockets.h" #include "qapi/error.h" -#include "chardev/char.h" #include "hw/irq.h" #include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" @@ -228,7 +224,7 @@ static void pcm3680i_pci_instance_init(Object *obj) 0); } -static void pcm3680i_pci_class_init(ObjectClass *klass, void *data) +static void pcm3680i_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -244,7 +240,7 @@ static void pcm3680i_pci_class_init(ObjectClass *klass, void *data) dc->desc = "Pcm3680i PCICANx"; dc->vmsd = &vmstate_pcm3680i_pci; set_bit(DEVICE_CATEGORY_MISC, dc->categories); - dc->reset = pcm3680i_pci_reset; + device_class_set_legacy_reset(dc, pcm3680i_pci_reset); } static const TypeInfo pcm3680i_pci_info = { @@ -253,7 +249,7 @@ static const TypeInfo pcm3680i_pci_info = { .instance_size = sizeof(Pcm3680iPCIState), .class_init = pcm3680i_pci_class_init, .instance_init = pcm3680i_pci_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/net/can/can_sja1000.c b/hw/net/can/can_sja1000.c index 6694d7b..5b6ba9d 100644 --- a/hw/net/can/can_sja1000.c +++ b/hw/net/can/can_sja1000.c @@ -27,7 +27,7 @@ #include "qemu/osdep.h" #include "qemu/log.h" -#include "chardev/char.h" +#include "qemu/bitops.h" #include "hw/irq.h" #include "migration/vmstate.h" #include "net/can_emu.h" diff --git a/hw/net/can/ctucan_core.c b/hw/net/can/ctucan_core.c index 812b83e..17131a4 100644 --- a/hw/net/can/ctucan_core.c +++ b/hw/net/can/ctucan_core.c @@ -28,7 +28,8 @@ #include "qemu/osdep.h" #include "qemu/log.h" -#include "chardev/char.h" +#include "qemu/bswap.h" +#include "qemu/bitops.h" #include "hw/irq.h" #include "migration/vmstate.h" #include "net/can_emu.h" @@ -399,8 +400,6 @@ void ctucan_mem_write(CtuCanCoreState *s, hwaddr addr, uint64_t val, ctucan_update_irq(s); } - - return; } uint64_t ctucan_mem_read(CtuCanCoreState *s, hwaddr addr, unsigned size) diff --git a/hw/net/can/ctucan_pci.c b/hw/net/can/ctucan_pci.c index d8f7344d..bed6785 100644 --- a/hw/net/can/ctucan_pci.c +++ b/hw/net/can/ctucan_pci.c @@ -27,12 +27,8 @@ */ #include "qemu/osdep.h" -#include "qemu/event_notifier.h" #include "qemu/module.h" -#include "qemu/thread.h" -#include "qemu/sockets.h" #include "qapi/error.h" -#include "chardev/char.h" #include "hw/irq.h" #include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" @@ -241,7 +237,7 @@ static void ctucan_pci_instance_init(Object *obj) #endif } -static void ctucan_pci_class_init(ObjectClass *klass, void *data) +static void ctucan_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -257,7 +253,7 @@ static void ctucan_pci_class_init(ObjectClass *klass, void *data) dc->desc = "CTU CAN PCI"; dc->vmsd = &vmstate_ctucan_pci; set_bit(DEVICE_CATEGORY_MISC, dc->categories); - dc->reset = ctucan_pci_reset; + device_class_set_legacy_reset(dc, ctucan_pci_reset); } static const TypeInfo ctucan_pci_info = { @@ -266,7 +262,7 @@ static const TypeInfo ctucan_pci_info = { .instance_size = sizeof(CtuCanPCIState), .class_init = ctucan_pci_class_init, .instance_init = ctucan_pci_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/net/can/xlnx-versal-canfd.c b/hw/net/can/xlnx-versal-canfd.c index 5f083c2..3eb1119 100644 --- a/hw/net/can/xlnx-versal-canfd.c +++ b/hw/net/can/xlnx-versal-canfd.c @@ -678,12 +678,10 @@ REG32(RB_DW15_REGISTER_1, 0x4144) FIELD(RB_DW15_REGISTER_1, DATA_BYTES62, 8, 8) FIELD(RB_DW15_REGISTER_1, DATA_BYTES63, 0, 8) -static uint8_t canfd_dlc_array[8] = {8, 12, 16, 20, 24, 32, 48, 64}; - static void canfd_update_irq(XlnxVersalCANFDState *s) { - unsigned int irq = s->regs[R_INTERRUPT_STATUS_REGISTER] & - s->regs[R_INTERRUPT_ENABLE_REGISTER]; + const bool irq = (s->regs[R_INTERRUPT_STATUS_REGISTER] & + s->regs[R_INTERRUPT_ENABLE_REGISTER]) != 0; g_autofree char *path = object_get_canonical_path(OBJECT(s)); /* RX watermark interrupts. */ @@ -869,6 +867,10 @@ static void regs2frame(XlnxVersalCANFDState *s, qemu_can_frame *frame, uint32_t val = 0; uint32_t dlc_reg_val = 0; uint32_t dlc_value = 0; + uint32_t id_reg_val = 0; + bool is_rtr = false; + + frame->flags = 0; /* Check that reg_num should be within TX register space. */ assert(reg_num <= R_TB_ID_REGISTER + (NUM_REGS_PER_MSG_SPACE * @@ -877,56 +879,37 @@ static void regs2frame(XlnxVersalCANFDState *s, qemu_can_frame *frame, dlc_reg_val = s->regs[reg_num + 1]; dlc_value = FIELD_EX32(dlc_reg_val, TB0_DLC_REGISTER, DLC); - frame->can_id = s->regs[reg_num]; + id_reg_val = s->regs[reg_num]; + if (FIELD_EX32(id_reg_val, TB_ID_REGISTER, IDE)) { + frame->can_id = (FIELD_EX32(id_reg_val, TB_ID_REGISTER, ID) << 18) | + (FIELD_EX32(id_reg_val, TB_ID_REGISTER, ID_EXT)) | + QEMU_CAN_EFF_FLAG; + if (FIELD_EX32(id_reg_val, TB_ID_REGISTER, RTR_RRS)) { + is_rtr = true; + } + } else { + frame->can_id = FIELD_EX32(id_reg_val, TB_ID_REGISTER, ID); + if (FIELD_EX32(id_reg_val, TB_ID_REGISTER, SRR_RTR_RRS)) { + is_rtr = true; + } + } if (FIELD_EX32(dlc_reg_val, TB0_DLC_REGISTER, FDF)) { - /* - * CANFD frame. - * Converting dlc(0 to 15) 4 Byte data to plain length(i.e. 0 to 64) - * 1 Byte data. This is done to make it work with SocketCAN. - * On actual CANFD frame, this value can't be more than 0xF. - * Conversion table for DLC to plain length: - * - * DLC Plain Length - * 0 - 8 0 - 8 - * 9 9 - 12 - * 10 13 - 16 - * 11 17 - 20 - * 12 21 - 24 - * 13 25 - 32 - * 14 33 - 48 - * 15 49 - 64 - */ - - frame->flags = QEMU_CAN_FRMF_TYPE_FD; + frame->flags |= QEMU_CAN_FRMF_TYPE_FD; - if (dlc_value < 8) { - frame->can_dlc = dlc_value; - } else { - assert((dlc_value - 8) < ARRAY_SIZE(canfd_dlc_array)); - frame->can_dlc = canfd_dlc_array[dlc_value - 8]; + if (FIELD_EX32(dlc_reg_val, TB0_DLC_REGISTER, BRS)) { + frame->flags |= QEMU_CAN_FRMF_BRS; } } else { - /* - * FD Format bit not set that means it is a CAN Frame. - * Conversion table for classic CAN: - * - * DLC Plain Length - * 0 - 7 0 - 7 - * 8 - 15 8 - */ - - if (dlc_value > 8) { - frame->can_dlc = 8; - qemu_log_mask(LOG_GUEST_ERROR, "Maximum DLC value for Classic CAN" - " frame is 8. Only 8 byte data will be sent.\n"); - } else { - frame->can_dlc = dlc_value; + if (is_rtr) { + frame->can_id |= QEMU_CAN_RTR_FLAG; } } + frame->can_dlc = can_dlc2len(dlc_value); + for (j = 0; j < frame->can_dlc; j++) { - val = 8 * i; + val = 8 * (3 - i); frame->data[j] = extract32(s->regs[reg_num + 2 + (j / 4)], val, 8); i++; @@ -948,6 +931,33 @@ static void process_cancellation_requests(XlnxVersalCANFDState *s) canfd_update_irq(s); } +static uint32_t frame_to_reg_id(const qemu_can_frame *frame) +{ + uint32_t id_reg_val = 0; + const bool is_canfd_frame = frame->flags & QEMU_CAN_FRMF_TYPE_FD; + const bool is_rtr = !is_canfd_frame && (frame->can_id & QEMU_CAN_RTR_FLAG); + + if (frame->can_id & QEMU_CAN_EFF_FLAG) { + id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, ID, + (frame->can_id & QEMU_CAN_EFF_MASK) >> 18); + id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, ID_EXT, + frame->can_id & QEMU_CAN_EFF_MASK); + id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, IDE, 1); + id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, SRR_RTR_RRS, 1); + if (is_rtr) { + id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, RTR_RRS, 1); + } + } else { + id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, ID, + frame->can_id & QEMU_CAN_SFF_MASK); + if (is_rtr) { + id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, SRR_RTR_RRS, 1); + } + } + + return id_reg_val; +} + static void store_rx_sequential(XlnxVersalCANFDState *s, const qemu_can_frame *frame, uint32_t fill_level, uint32_t read_index, @@ -955,7 +965,6 @@ static void store_rx_sequential(XlnxVersalCANFDState *s, bool rx_fifo_id, uint8_t filter_index) { int i; - bool is_canfd_frame; uint8_t dlc = frame->can_dlc; uint8_t rx_reg_num = 0; uint32_t dlc_reg_val = 0; @@ -999,30 +1008,21 @@ static void store_rx_sequential(XlnxVersalCANFDState *s, NUM_REGS_PER_MSG_SPACE)); } - s->regs[store_location] = frame->can_id; + s->regs[store_location] = frame_to_reg_id(frame); - dlc = frame->can_dlc; + dlc_reg_val = FIELD_DP32(0, RB_DLC_REGISTER, DLC, can_len2dlc(dlc)); - if (frame->flags == QEMU_CAN_FRMF_TYPE_FD) { - is_canfd_frame = true; + if (frame->flags & QEMU_CAN_FRMF_TYPE_FD) { + dlc_reg_val |= FIELD_DP32(0, RB_DLC_REGISTER, FDF, 1); - /* Store dlc value in Xilinx specific format. */ - for (i = 0; i < ARRAY_SIZE(canfd_dlc_array); i++) { - if (canfd_dlc_array[i] == frame->can_dlc) { - dlc_reg_val = FIELD_DP32(0, RB_DLC_REGISTER, DLC, 8 + i); - } + if (frame->flags & QEMU_CAN_FRMF_BRS) { + dlc_reg_val |= FIELD_DP32(0, RB_DLC_REGISTER, BRS, 1); } - } else { - is_canfd_frame = false; - - if (frame->can_dlc > 8) { - dlc = 8; + if (frame->flags & QEMU_CAN_FRMF_ESI) { + dlc_reg_val |= FIELD_DP32(0, RB_DLC_REGISTER, ESI, 1); } - - dlc_reg_val = FIELD_DP32(0, RB_DLC_REGISTER, DLC, dlc); } - dlc_reg_val |= FIELD_DP32(0, RB_DLC_REGISTER, FDF, is_canfd_frame); dlc_reg_val |= FIELD_DP32(0, RB_DLC_REGISTER, TIMESTAMP, rx_timestamp); dlc_reg_val |= FIELD_DP32(0, RB_DLC_REGISTER, MATCHED_FILTER_INDEX, filter_index); @@ -1034,19 +1034,19 @@ static void store_rx_sequential(XlnxVersalCANFDState *s, case 0: rx_reg_num = i / 4; - data_reg_val = FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES3, + data_reg_val = FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES0, frame->data[i]); break; case 1: - data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES2, + data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES1, frame->data[i]); break; case 2: - data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES1, + data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES2, frame->data[i]); break; case 3: - data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES0, + data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES3, frame->data[i]); /* * Last Bytes data which means we have all 4 bytes ready to @@ -1090,11 +1090,12 @@ static void update_rx_sequential(XlnxVersalCANFDState *s, if (s->regs[R_ACCEPTANCE_FILTER_CONTROL_REGISTER]) { uint32_t acceptance_filter_status = s->regs[R_ACCEPTANCE_FILTER_CONTROL_REGISTER]; + const uint32_t reg_id = frame_to_reg_id(frame); for (i = 0; i < 32; i++) { if (acceptance_filter_status & 0x1) { uint32_t msg_id_masked = s->regs[R_AFMR_REGISTER + 2 * i] & - frame->can_id; + reg_id; uint32_t afir_id_masked = s->regs[R_AFIR_REGISTER + 2 * i] & s->regs[R_AFMR_REGISTER + 2 * i]; uint16_t std_msg_id_masked = FIELD_EX32(msg_id_masked, @@ -1143,18 +1144,8 @@ static void update_rx_sequential(XlnxVersalCANFDState *s, read_index = ARRAY_FIELD_EX32(s->regs, RX_FIFO_STATUS_REGISTER, RI); store_index = read_index + fill_level; - if (read_index == s->cfg.rx0_fifo - 1) { - /* - * When ri is s->cfg.rx0_fifo - 1 i.e. max, it goes cyclic that - * means we reset the ri to 0x0. - */ - read_index = 0; - ARRAY_FIELD_DP32(s->regs, RX_FIFO_STATUS_REGISTER, RI, - read_index); - } - if (store_index > s->cfg.rx0_fifo - 1) { - store_index -= s->cfg.rx0_fifo - 1; + store_index -= s->cfg.rx0_fifo; } store_location = R_RB_ID_REGISTER + @@ -1171,18 +1162,8 @@ static void update_rx_sequential(XlnxVersalCANFDState *s, RI_1); store_index = read_index + fill_level; - if (read_index == s->cfg.rx1_fifo - 1) { - /* - * When ri is s->cfg.rx1_fifo - 1 i.e. max, it goes cyclic that - * means we reset the ri to 0x0. - */ - read_index = 0; - ARRAY_FIELD_DP32(s->regs, RX_FIFO_STATUS_REGISTER, RI_1, - read_index); - } - if (store_index > s->cfg.rx1_fifo - 1) { - store_index -= s->cfg.rx1_fifo - 1; + store_index -= s->cfg.rx1_fifo; } store_location = R_RB_ID_REGISTER_1 + @@ -1264,18 +1245,8 @@ static void tx_fifo_stamp(XlnxVersalCANFDState *s, uint32_t tb0_regid) " Discarding the message\n"); ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, TXEOFLW, 1); } else { - if (read_index == s->cfg.tx_fifo - 1) { - /* - * When ri is s->cfg.tx_fifo - 1 i.e. max, it goes cyclic that - * means we reset the ri to 0x0. - */ - read_index = 0; - ARRAY_FIELD_DP32(s->regs, TX_EVENT_FIFO_STATUS_REGISTER, TXE_RI, - read_index); - } - if (store_index > s->cfg.tx_fifo - 1) { - store_index -= s->cfg.tx_fifo - 1; + store_index -= s->cfg.tx_fifo; } assert(store_index < s->cfg.tx_fifo); @@ -1307,7 +1278,7 @@ static void tx_fifo_stamp(XlnxVersalCANFDState *s, uint32_t tb0_regid) } } -static gint g_cmp_ids(gconstpointer data1, gconstpointer data2) +static gint g_cmp_ids(gconstpointer data1, gconstpointer data2, gpointer d) { tx_ready_reg_info *tx_reg_1 = (tx_ready_reg_info *) data1; tx_ready_reg_info *tx_reg_2 = (tx_ready_reg_info *) data2; @@ -1327,8 +1298,6 @@ static void free_list(GSList *list) } g_slist_free(list); - - return; } static GSList *prepare_tx_data(XlnxVersalCANFDState *s) @@ -1347,7 +1316,7 @@ static GSList *prepare_tx_data(XlnxVersalCANFDState *s) temp->can_id = s->regs[reg_num]; temp->reg_num = reg_num; list = g_slist_prepend(list, temp); - list = g_slist_sort(list, g_cmp_ids); + list = g_slist_sort_with_data(list, g_cmp_ids, NULL); } reg_ready >>= 1; @@ -2071,7 +2040,7 @@ static const VMStateDescription vmstate_canfd = { } }; -static Property canfd_core_properties[] = { +static const Property canfd_core_properties[] = { DEFINE_PROP_UINT8("rx-fifo0", XlnxVersalCANFDState, cfg.rx0_fifo, 0x40), DEFINE_PROP_UINT8("rx-fifo1", XlnxVersalCANFDState, cfg.rx1_fifo, 0x40), DEFINE_PROP_UINT8("tx-fifo", XlnxVersalCANFDState, cfg.tx_fifo, 0x20), @@ -2081,14 +2050,13 @@ static Property canfd_core_properties[] = { CANFD_DEFAULT_CLOCK), DEFINE_PROP_LINK("canfdbus", XlnxVersalCANFDState, canfdbus, TYPE_CAN_BUS, CanBusState *), - DEFINE_PROP_END_OF_LIST(), }; -static void canfd_class_init(ObjectClass *klass, void *data) +static void canfd_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - dc->reset = canfd_reset; + device_class_set_legacy_reset(dc, canfd_reset); dc->realize = canfd_realize; device_class_set_props(dc, canfd_core_properties); dc->vmsd = &vmstate_canfd; diff --git a/hw/net/can/xlnx-zynqmp-can.c b/hw/net/can/xlnx-zynqmp-can.c index 58f1432..ca9edd4 100644 --- a/hw/net/can/xlnx-zynqmp-can.c +++ b/hw/net/can/xlnx-zynqmp-can.c @@ -1169,15 +1169,14 @@ static const VMStateDescription vmstate_can = { } }; -static Property xlnx_zynqmp_can_properties[] = { +static const Property xlnx_zynqmp_can_properties[] = { DEFINE_PROP_UINT32("ext_clk_freq", XlnxZynqMPCANState, cfg.ext_clk_freq, CAN_DEFAULT_CLOCK), DEFINE_PROP_LINK("canbus", XlnxZynqMPCANState, canbus, TYPE_CAN_BUS, CanBusState *), - DEFINE_PROP_END_OF_LIST(), }; -static void xlnx_zynqmp_can_class_init(ObjectClass *klass, void *data) +static void xlnx_zynqmp_can_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c index bf0652d..d490320 100644 --- a/hw/net/dp8393x.c +++ b/hw/net/dp8393x.c @@ -27,7 +27,7 @@ #include "qapi/error.h" #include "qemu/module.h" #include "qemu/timer.h" -#include <zlib.h> +#include <zlib.h> /* for crc32 */ #include "qom/object.h" #include "trace.h" @@ -931,22 +931,21 @@ static const VMStateDescription vmstate_dp8393x = { } }; -static Property dp8393x_properties[] = { +static const Property dp8393x_properties[] = { DEFINE_NIC_PROPERTIES(dp8393xState, conf), DEFINE_PROP_LINK("dma_mr", dp8393xState, dma_mr, TYPE_MEMORY_REGION, MemoryRegion *), DEFINE_PROP_UINT8("it_shift", dp8393xState, it_shift, 0), DEFINE_PROP_BOOL("big_endian", dp8393xState, big_endian, false), - DEFINE_PROP_END_OF_LIST(), }; -static void dp8393x_class_init(ObjectClass *klass, void *data) +static void dp8393x_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->realize = dp8393x_realize; - dc->reset = dp8393x_reset; + device_class_set_legacy_reset(dc, dp8393x_reset); dc->vmsd = &vmstate_dp8393x; device_class_set_props(dc, dp8393x_properties); } diff --git a/hw/net/e1000.c b/hw/net/e1000.c index 5012b96..a80a7b0 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c @@ -33,8 +33,8 @@ #include "net/eth.h" #include "net/net.h" #include "net/checksum.h" -#include "sysemu/sysemu.h" -#include "sysemu/dma.h" +#include "system/system.h" +#include "system/dma.h" #include "qemu/iov.h" #include "qemu/module.h" #include "qemu/range.h" @@ -127,10 +127,8 @@ struct E1000State_st { QEMUTimer *flush_queue_timer; /* Compatibility flags for migration to/from qemu 1.3.0 and older */ -#define E1000_FLAG_MAC_BIT 2 #define E1000_FLAG_TSO_BIT 3 #define E1000_FLAG_VET_BIT 4 -#define E1000_FLAG_MAC (1 << E1000_FLAG_MAC_BIT) #define E1000_FLAG_TSO (1 << E1000_FLAG_TSO_BIT) #define E1000_FLAG_VET (1 << E1000_FLAG_VET_BIT) @@ -1212,52 +1210,51 @@ enum { NWRITEOPS = ARRAY_SIZE(macreg_writeops) }; enum { MAC_ACCESS_PARTIAL = 1, MAC_ACCESS_FLAG_NEEDED = 2 }; -#define markflag(x) ((E1000_FLAG_##x << 2) | MAC_ACCESS_FLAG_NEEDED) /* In the array below the meaning of the bits is: [f|f|f|f|f|f|n|p] * f - flag bits (up to 6 possible flags) * n - flag needed - * p - partially implenented */ + * p - partially implemented */ static const uint8_t mac_reg_access[0x8000] = { - [IPAV] = markflag(MAC), [WUC] = markflag(MAC), - [IP6AT] = markflag(MAC), [IP4AT] = markflag(MAC), - [FFVT] = markflag(MAC), [WUPM] = markflag(MAC), - [ECOL] = markflag(MAC), [MCC] = markflag(MAC), - [DC] = markflag(MAC), [TNCRS] = markflag(MAC), - [RLEC] = markflag(MAC), [XONRXC] = markflag(MAC), - [XOFFTXC] = markflag(MAC), [RFC] = markflag(MAC), - [TSCTFC] = markflag(MAC), [MGTPRC] = markflag(MAC), - [WUS] = markflag(MAC), [AIT] = markflag(MAC), - [FFLT] = markflag(MAC), [FFMT] = markflag(MAC), - [SCC] = markflag(MAC), [FCRUC] = markflag(MAC), - [LATECOL] = markflag(MAC), [COLC] = markflag(MAC), - [SEQEC] = markflag(MAC), [CEXTERR] = markflag(MAC), - [XONTXC] = markflag(MAC), [XOFFRXC] = markflag(MAC), - [RJC] = markflag(MAC), [RNBC] = markflag(MAC), - [MGTPDC] = markflag(MAC), [MGTPTC] = markflag(MAC), - [RUC] = markflag(MAC), [ROC] = markflag(MAC), - [GORCL] = markflag(MAC), [GORCH] = markflag(MAC), - [GOTCL] = markflag(MAC), [GOTCH] = markflag(MAC), - [BPRC] = markflag(MAC), [MPRC] = markflag(MAC), - [TSCTC] = markflag(MAC), [PRC64] = markflag(MAC), - [PRC127] = markflag(MAC), [PRC255] = markflag(MAC), - [PRC511] = markflag(MAC), [PRC1023] = markflag(MAC), - [PRC1522] = markflag(MAC), [PTC64] = markflag(MAC), - [PTC127] = markflag(MAC), [PTC255] = markflag(MAC), - [PTC511] = markflag(MAC), [PTC1023] = markflag(MAC), - [PTC1522] = markflag(MAC), [MPTC] = markflag(MAC), - [BPTC] = markflag(MAC), - - [TDFH] = markflag(MAC) | MAC_ACCESS_PARTIAL, - [TDFT] = markflag(MAC) | MAC_ACCESS_PARTIAL, - [TDFHS] = markflag(MAC) | MAC_ACCESS_PARTIAL, - [TDFTS] = markflag(MAC) | MAC_ACCESS_PARTIAL, - [TDFPC] = markflag(MAC) | MAC_ACCESS_PARTIAL, - [RDFH] = markflag(MAC) | MAC_ACCESS_PARTIAL, - [RDFT] = markflag(MAC) | MAC_ACCESS_PARTIAL, - [RDFHS] = markflag(MAC) | MAC_ACCESS_PARTIAL, - [RDFTS] = markflag(MAC) | MAC_ACCESS_PARTIAL, - [RDFPC] = markflag(MAC) | MAC_ACCESS_PARTIAL, - [PBM] = markflag(MAC) | MAC_ACCESS_PARTIAL, + [IPAV] = MAC_ACCESS_FLAG_NEEDED, [WUC] = MAC_ACCESS_FLAG_NEEDED, + [IP6AT] = MAC_ACCESS_FLAG_NEEDED, [IP4AT] = MAC_ACCESS_FLAG_NEEDED, + [FFVT] = MAC_ACCESS_FLAG_NEEDED, [WUPM] = MAC_ACCESS_FLAG_NEEDED, + [ECOL] = MAC_ACCESS_FLAG_NEEDED, [MCC] = MAC_ACCESS_FLAG_NEEDED, + [DC] = MAC_ACCESS_FLAG_NEEDED, [TNCRS] = MAC_ACCESS_FLAG_NEEDED, + [RLEC] = MAC_ACCESS_FLAG_NEEDED, [XONRXC] = MAC_ACCESS_FLAG_NEEDED, + [XOFFTXC] = MAC_ACCESS_FLAG_NEEDED, [RFC] = MAC_ACCESS_FLAG_NEEDED, + [TSCTFC] = MAC_ACCESS_FLAG_NEEDED, [MGTPRC] = MAC_ACCESS_FLAG_NEEDED, + [WUS] = MAC_ACCESS_FLAG_NEEDED, [AIT] = MAC_ACCESS_FLAG_NEEDED, + [FFLT] = MAC_ACCESS_FLAG_NEEDED, [FFMT] = MAC_ACCESS_FLAG_NEEDED, + [SCC] = MAC_ACCESS_FLAG_NEEDED, [FCRUC] = MAC_ACCESS_FLAG_NEEDED, + [LATECOL] = MAC_ACCESS_FLAG_NEEDED, [COLC] = MAC_ACCESS_FLAG_NEEDED, + [SEQEC] = MAC_ACCESS_FLAG_NEEDED, [CEXTERR] = MAC_ACCESS_FLAG_NEEDED, + [XONTXC] = MAC_ACCESS_FLAG_NEEDED, [XOFFRXC] = MAC_ACCESS_FLAG_NEEDED, + [RJC] = MAC_ACCESS_FLAG_NEEDED, [RNBC] = MAC_ACCESS_FLAG_NEEDED, + [MGTPDC] = MAC_ACCESS_FLAG_NEEDED, [MGTPTC] = MAC_ACCESS_FLAG_NEEDED, + [RUC] = MAC_ACCESS_FLAG_NEEDED, [ROC] = MAC_ACCESS_FLAG_NEEDED, + [GORCL] = MAC_ACCESS_FLAG_NEEDED, [GORCH] = MAC_ACCESS_FLAG_NEEDED, + [GOTCL] = MAC_ACCESS_FLAG_NEEDED, [GOTCH] = MAC_ACCESS_FLAG_NEEDED, + [BPRC] = MAC_ACCESS_FLAG_NEEDED, [MPRC] = MAC_ACCESS_FLAG_NEEDED, + [TSCTC] = MAC_ACCESS_FLAG_NEEDED, [PRC64] = MAC_ACCESS_FLAG_NEEDED, + [PRC127] = MAC_ACCESS_FLAG_NEEDED, [PRC255] = MAC_ACCESS_FLAG_NEEDED, + [PRC511] = MAC_ACCESS_FLAG_NEEDED, [PRC1023] = MAC_ACCESS_FLAG_NEEDED, + [PRC1522] = MAC_ACCESS_FLAG_NEEDED, [PTC64] = MAC_ACCESS_FLAG_NEEDED, + [PTC127] = MAC_ACCESS_FLAG_NEEDED, [PTC255] = MAC_ACCESS_FLAG_NEEDED, + [PTC511] = MAC_ACCESS_FLAG_NEEDED, [PTC1023] = MAC_ACCESS_FLAG_NEEDED, + [PTC1522] = MAC_ACCESS_FLAG_NEEDED, [MPTC] = MAC_ACCESS_FLAG_NEEDED, + [BPTC] = MAC_ACCESS_FLAG_NEEDED, + + [TDFH] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL, + [TDFT] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL, + [TDFHS] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL, + [TDFTS] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL, + [TDFPC] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL, + [RDFH] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL, + [RDFT] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL, + [RDFHS] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL, + [RDFTS] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL, + [RDFPC] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL, + [PBM] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL, }; static void @@ -1419,13 +1416,6 @@ static int e1000_tx_tso_post_load(void *opaque, int version_id) return 0; } -static bool e1000_full_mac_needed(void *opaque) -{ - E1000State *s = opaque; - - return chkflag(MAC); -} - static bool e1000_tso_state_needed(void *opaque) { E1000State *s = opaque; @@ -1451,7 +1441,6 @@ static const VMStateDescription vmstate_e1000_full_mac_state = { .name = "e1000/full_mac_state", .version_id = 1, .minimum_version_id = 1, - .needed = e1000_full_mac_needed, .fields = (const VMStateField[]) { VMSTATE_UINT32_ARRAY(mac_reg, E1000State, 0x8000), VMSTATE_END_OF_LIST() @@ -1677,15 +1666,12 @@ static void pci_e1000_realize(PCIDevice *pci_dev, Error **errp) e1000_flush_queue_timer, d); } -static Property e1000_properties[] = { +static const Property e1000_properties[] = { DEFINE_NIC_PROPERTIES(E1000State, conf), - DEFINE_PROP_BIT("extra_mac_registers", E1000State, - compat_flags, E1000_FLAG_MAC_BIT, true), DEFINE_PROP_BIT("migrate_tso_props", E1000State, compat_flags, E1000_FLAG_TSO_BIT, true), DEFINE_PROP_BIT("init-vet", E1000State, compat_flags, E1000_FLAG_VET_BIT, true), - DEFINE_PROP_END_OF_LIST(), }; typedef struct E1000Info { @@ -1695,7 +1681,7 @@ typedef struct E1000Info { uint16_t phy_id2; } E1000Info; -static void e1000_class_init(ObjectClass *klass, void *data) +static void e1000_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); @@ -1733,7 +1719,7 @@ static const TypeInfo e1000_base_info = { .instance_init = e1000_instance_init, .class_size = sizeof(E1000BaseClass), .abstract = true, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, @@ -1771,10 +1757,10 @@ static void e1000_register_types(void) type_info.name = info->name; type_info.parent = TYPE_E1000_BASE; - type_info.class_data = (void *)info; + type_info.class_data = info; type_info.class_init = e1000_class_init; - type_register(&type_info); + type_register_static(&type_info); } } diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c index 843892c..89e6d52 100644 --- a/hw/net/e1000e.c +++ b/hw/net/e1000e.c @@ -40,7 +40,7 @@ #include "net/tap.h" #include "qemu/module.h" #include "qemu/range.h" -#include "sysemu/sysemu.h" +#include "system/system.h" #include "hw/hw.h" #include "hw/net/mii.h" #include "hw/pci/msi.h" @@ -372,8 +372,7 @@ static int e1000e_add_pm_capability(PCIDevice *pdev, uint8_t offset, uint16_t pmc) { Error *local_err = NULL; - int ret = pci_add_capability(pdev, PCI_CAP_ID_PM, offset, - PCI_PM_SIZEOF, &local_err); + int ret = pci_pm_init(pdev, offset, &local_err); if (local_err) { error_report_err(local_err); @@ -661,7 +660,7 @@ static PropertyInfo e1000e_prop_disable_vnet, e1000e_prop_subsys_ven, e1000e_prop_subsys; -static Property e1000e_properties[] = { +static const Property e1000e_properties[] = { DEFINE_NIC_PROPERTIES(E1000EState, conf), DEFINE_PROP_SIGNED("disable_vnet_hdr", E1000EState, disable_vnet, false, e1000e_prop_disable_vnet, bool), @@ -672,10 +671,9 @@ static Property e1000e_properties[] = { e1000e_prop_subsys, uint16_t), DEFINE_PROP_BOOL("init-vet", E1000EState, init_vet, true), DEFINE_PROP_BOOL("migrate-timadj", E1000EState, timadj, true), - DEFINE_PROP_END_OF_LIST(), }; -static void e1000e_class_init(ObjectClass *class, void *data) +static void e1000e_class_init(ObjectClass *class, const void *data) { DeviceClass *dc = DEVICE_CLASS(class); ResettableClass *rc = RESETTABLE_CLASS(class); @@ -723,7 +721,7 @@ static const TypeInfo e1000e_info = { .instance_size = sizeof(E1000EState), .class_init = e1000e_class_init, .instance_init = e1000e_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_PCIE_DEVICE }, { } }, diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c index 3ae2a18..2413858 100644 --- a/hw/net/e1000e_core.c +++ b/hw/net/e1000e_core.c @@ -40,7 +40,7 @@ #include "hw/net/mii.h" #include "hw/pci/msi.h" #include "hw/pci/msix.h" -#include "sysemu/runstate.h" +#include "system/runstate.h" #include "net_tx_pkt.h" #include "net_rx_pkt.h" @@ -561,8 +561,7 @@ e1000e_rss_calc_hash(E1000ECore *core, type = NetPktRssIpV6Ex; break; default: - assert(false); - return 0; + g_assert_not_reached(); } return net_rx_pkt_calc_rss_hash(pkt, type, (uint8_t *) &core->mac[RSSRK]); @@ -841,7 +840,6 @@ e1000e_ring_free_descr_num(E1000ECore *core, const E1000ERingInfo *r) } g_assert_not_reached(); - return 0; } static inline bool diff --git a/hw/net/e1000x_regs.h b/hw/net/e1000x_regs.h index cd896fc..e9a74de 100644 --- a/hw/net/e1000x_regs.h +++ b/hw/net/e1000x_regs.h @@ -900,7 +900,7 @@ struct e1000_context_desc { uint16_t tucse; /* TCP checksum end */ } tcp_fields; } upper_setup; - uint32_t cmd_and_length; /* */ + uint32_t cmd_and_length; union { uint32_t data; struct { diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c index d9a70c4..d47df5a 100644 --- a/hw/net/eepro100.c +++ b/hw/net/eepro100.c @@ -6,10 +6,12 @@ * Portions of the code are copies from grub / etherboot eepro100.c * and linux e100.c. * + * SPDX-License-Identifier: GPL-2.0-or-later + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or - * (at your option) version 3 or any later version. + * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -48,9 +50,9 @@ #include "net/net.h" #include "net/eth.h" #include "hw/nvram/eeprom93xx.h" -#include "sysemu/sysemu.h" -#include "sysemu/dma.h" -#include "sysemu/reset.h" +#include "system/system.h" +#include "system/dma.h" +#include "system/reset.h" #include "qemu/bitops.h" #include "qemu/module.h" #include "qapi/error.h" @@ -549,9 +551,7 @@ static void e100_pci_reset(EEPRO100State *s, Error **errp) if (info->power_management) { /* Power Management Capabilities */ int cfg_offset = 0xdc; - int r = pci_add_capability(&s->dev, PCI_CAP_ID_PM, - cfg_offset, PCI_PM_SIZEOF, - errp); + int r = pci_pm_init(&s->dev, cfg_offset, errp); if (r < 0) { return; } @@ -2056,12 +2056,11 @@ static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s) return eepro100_get_class_by_name(object_get_typename(OBJECT(s))); } -static Property e100_properties[] = { +static const Property e100_properties[] = { DEFINE_NIC_PROPERTIES(EEPRO100State, conf), - DEFINE_PROP_END_OF_LIST(), }; -static void eepro100_class_init(ObjectClass *klass, void *data) +static void eepro100_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -2095,12 +2094,12 @@ static void eepro100_register_types(void) type_info.class_init = eepro100_class_init; type_info.instance_size = sizeof(EEPRO100State); type_info.instance_init = eepro100_instance_init; - type_info.interfaces = (InterfaceInfo[]) { + type_info.interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }; - type_register(&type_info); + type_register_static(&type_info); } } diff --git a/hw/net/etraxfs_eth.c b/hw/net/etraxfs_eth.c deleted file mode 100644 index 5faf20c..0000000 --- a/hw/net/etraxfs_eth.c +++ /dev/null @@ -1,688 +0,0 @@ -/* - * QEMU ETRAX Ethernet Controller. - * - * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/sysbus.h" -#include "net/net.h" -#include "hw/cris/etraxfs.h" -#include "qemu/error-report.h" -#include "qemu/module.h" -#include "trace.h" -#include "qom/object.h" - -#define D(x) - -/* Advertisement control register. */ -#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ -#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */ -#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ -#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ - -/* - * The MDIO extensions in the TDK PHY model were reversed engineered from the - * linux driver (PHYID and Diagnostics reg). - * TODO: Add friendly names for the register nums. - */ -struct qemu_phy -{ - uint32_t regs[32]; - - int link; - - unsigned int (*read)(struct qemu_phy *phy, unsigned int req); - void (*write)(struct qemu_phy *phy, unsigned int req, unsigned int data); -}; - -static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req) -{ - int regnum; - unsigned r = 0; - - regnum = req & 0x1f; - - switch (regnum) { - case 1: - if (!phy->link) { - break; - } - /* MR1. */ - /* Speeds and modes. */ - r |= (1 << 13) | (1 << 14); - r |= (1 << 11) | (1 << 12); - r |= (1 << 5); /* Autoneg complete. */ - r |= (1 << 3); /* Autoneg able. */ - r |= (1 << 2); /* link. */ - break; - case 5: - /* Link partner ability. - We are kind; always agree with whatever best mode - the guest advertises. */ - r = 1 << 14; /* Success. */ - /* Copy advertised modes. */ - r |= phy->regs[4] & (15 << 5); - /* Autoneg support. */ - r |= 1; - break; - case 18: - { - /* Diagnostics reg. */ - int duplex = 0; - int speed_100 = 0; - - if (!phy->link) { - break; - } - - /* Are we advertising 100 half or 100 duplex ? */ - speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF); - speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL); - - /* Are we advertising 10 duplex or 100 duplex ? */ - duplex = !!(phy->regs[4] & ADVERTISE_100FULL); - duplex |= !!(phy->regs[4] & ADVERTISE_10FULL); - r = (speed_100 << 10) | (duplex << 11); - } - break; - - default: - r = phy->regs[regnum]; - break; - } - trace_mdio_phy_read(regnum, r); - return r; -} - -static void -tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data) -{ - int regnum; - - regnum = req & 0x1f; - trace_mdio_phy_write(regnum, data); - switch (regnum) { - default: - phy->regs[regnum] = data; - break; - } -} - -static void -tdk_reset(struct qemu_phy *phy) -{ - phy->regs[0] = 0x3100; - /* PHY Id. */ - phy->regs[2] = 0x0300; - phy->regs[3] = 0xe400; - /* Autonegotiation advertisement reg. */ - phy->regs[4] = 0x01E1; - phy->link = 1; -} - -struct qemu_mdio -{ - /* bus. */ - int mdc; - int mdio; - - /* decoder. */ - enum { - PREAMBLE, - SOF, - OPC, - ADDR, - REQ, - TURNAROUND, - DATA - } state; - unsigned int drive; - - unsigned int cnt; - unsigned int addr; - unsigned int opc; - unsigned int req; - unsigned int data; - - struct qemu_phy *devs[32]; -}; - -static void -mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr) -{ - bus->devs[addr & 0x1f] = phy; -} - -#ifdef USE_THIS_DEAD_CODE -static void -mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr) -{ - bus->devs[addr & 0x1f] = NULL; -} -#endif - -static void mdio_read_req(struct qemu_mdio *bus) -{ - struct qemu_phy *phy; - - phy = bus->devs[bus->addr]; - if (phy && phy->read) { - bus->data = phy->read(phy, bus->req); - } else { - bus->data = 0xffff; - } -} - -static void mdio_write_req(struct qemu_mdio *bus) -{ - struct qemu_phy *phy; - - phy = bus->devs[bus->addr]; - if (phy && phy->write) { - phy->write(phy, bus->req, bus->data); - } -} - -static void mdio_cycle(struct qemu_mdio *bus) -{ - bus->cnt++; - - trace_mdio_bitbang(bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive); -#if 0 - if (bus->mdc) { - printf("%d", bus->mdio); - } -#endif - switch (bus->state) { - case PREAMBLE: - if (bus->mdc) { - if (bus->cnt >= (32 * 2) && !bus->mdio) { - bus->cnt = 0; - bus->state = SOF; - bus->data = 0; - } - } - break; - case SOF: - if (bus->mdc) { - if (bus->mdio != 1) { - printf("WARNING: no SOF\n"); - } - if (bus->cnt == 1*2) { - bus->cnt = 0; - bus->opc = 0; - bus->state = OPC; - } - } - break; - case OPC: - if (bus->mdc) { - bus->opc <<= 1; - bus->opc |= bus->mdio & 1; - if (bus->cnt == 2*2) { - bus->cnt = 0; - bus->addr = 0; - bus->state = ADDR; - } - } - break; - case ADDR: - if (bus->mdc) { - bus->addr <<= 1; - bus->addr |= bus->mdio & 1; - - if (bus->cnt == 5*2) { - bus->cnt = 0; - bus->req = 0; - bus->state = REQ; - } - } - break; - case REQ: - if (bus->mdc) { - bus->req <<= 1; - bus->req |= bus->mdio & 1; - if (bus->cnt == 5*2) { - bus->cnt = 0; - bus->state = TURNAROUND; - } - } - break; - case TURNAROUND: - if (bus->mdc && bus->cnt == 2*2) { - bus->mdio = 0; - bus->cnt = 0; - - if (bus->opc == 2) { - bus->drive = 1; - mdio_read_req(bus); - bus->mdio = bus->data & 1; - } - bus->state = DATA; - } - break; - case DATA: - if (!bus->mdc) { - if (bus->drive) { - bus->mdio = !!(bus->data & (1 << 15)); - bus->data <<= 1; - } - } else { - if (!bus->drive) { - bus->data <<= 1; - bus->data |= bus->mdio; - } - if (bus->cnt == 16 * 2) { - bus->cnt = 0; - bus->state = PREAMBLE; - if (!bus->drive) { - mdio_write_req(bus); - } - bus->drive = 0; - } - } - break; - default: - break; - } -} - -/* ETRAX-FS Ethernet MAC block starts here. */ - -#define RW_MA0_LO 0x00 -#define RW_MA0_HI 0x01 -#define RW_MA1_LO 0x02 -#define RW_MA1_HI 0x03 -#define RW_GA_LO 0x04 -#define RW_GA_HI 0x05 -#define RW_GEN_CTRL 0x06 -#define RW_REC_CTRL 0x07 -#define RW_TR_CTRL 0x08 -#define RW_CLR_ERR 0x09 -#define RW_MGM_CTRL 0x0a -#define R_STAT 0x0b -#define FS_ETH_MAX_REGS 0x17 - -#define TYPE_ETRAX_FS_ETH "etraxfs-eth" -OBJECT_DECLARE_SIMPLE_TYPE(ETRAXFSEthState, ETRAX_FS_ETH) - -struct ETRAXFSEthState { - SysBusDevice parent_obj; - - MemoryRegion mmio; - NICState *nic; - NICConf conf; - - /* Two addrs in the filter. */ - uint8_t macaddr[2][6]; - uint32_t regs[FS_ETH_MAX_REGS]; - - struct etraxfs_dma_client *dma_out; - struct etraxfs_dma_client *dma_in; - - /* MDIO bus. */ - struct qemu_mdio mdio_bus; - unsigned int phyaddr; - int duplex_mismatch; - - /* PHY. */ - struct qemu_phy phy; -}; - -static void eth_validate_duplex(ETRAXFSEthState *eth) -{ - struct qemu_phy *phy; - unsigned int phy_duplex; - unsigned int mac_duplex; - int new_mm = 0; - - phy = eth->mdio_bus.devs[eth->phyaddr]; - phy_duplex = !!(phy->read(phy, 18) & (1 << 11)); - mac_duplex = !!(eth->regs[RW_REC_CTRL] & 128); - - if (mac_duplex != phy_duplex) { - new_mm = 1; - } - - if (eth->regs[RW_GEN_CTRL] & 1) { - if (new_mm != eth->duplex_mismatch) { - if (new_mm) { - printf("HW: WARNING ETH duplex mismatch MAC=%d PHY=%d\n", - mac_duplex, phy_duplex); - } else { - printf("HW: ETH duplex ok.\n"); - } - } - eth->duplex_mismatch = new_mm; - } -} - -static uint64_t -eth_read(void *opaque, hwaddr addr, unsigned int size) -{ - ETRAXFSEthState *eth = opaque; - uint32_t r = 0; - - addr >>= 2; - - switch (addr) { - case R_STAT: - r = eth->mdio_bus.mdio & 1; - break; - default: - r = eth->regs[addr]; - D(printf("%s %x\n", __func__, addr * 4)); - break; - } - return r; -} - -static void eth_update_ma(ETRAXFSEthState *eth, int ma) -{ - int reg; - int i = 0; - - ma &= 1; - - reg = RW_MA0_LO; - if (ma) { - reg = RW_MA1_LO; - } - - eth->macaddr[ma][i++] = eth->regs[reg]; - eth->macaddr[ma][i++] = eth->regs[reg] >> 8; - eth->macaddr[ma][i++] = eth->regs[reg] >> 16; - eth->macaddr[ma][i++] = eth->regs[reg] >> 24; - eth->macaddr[ma][i++] = eth->regs[reg + 1]; - eth->macaddr[ma][i] = eth->regs[reg + 1] >> 8; - - D(printf("set mac%d=%x.%x.%x.%x.%x.%x\n", ma, - eth->macaddr[ma][0], eth->macaddr[ma][1], - eth->macaddr[ma][2], eth->macaddr[ma][3], - eth->macaddr[ma][4], eth->macaddr[ma][5])); -} - -static void -eth_write(void *opaque, hwaddr addr, - uint64_t val64, unsigned int size) -{ - ETRAXFSEthState *eth = opaque; - uint32_t value = val64; - - addr >>= 2; - switch (addr) { - case RW_MA0_LO: - case RW_MA0_HI: - eth->regs[addr] = value; - eth_update_ma(eth, 0); - break; - case RW_MA1_LO: - case RW_MA1_HI: - eth->regs[addr] = value; - eth_update_ma(eth, 1); - break; - - case RW_MGM_CTRL: - /* Attach an MDIO/PHY abstraction. */ - if (value & 2) { - eth->mdio_bus.mdio = value & 1; - } - if (eth->mdio_bus.mdc != (value & 4)) { - mdio_cycle(ð->mdio_bus); - eth_validate_duplex(eth); - } - eth->mdio_bus.mdc = !!(value & 4); - eth->regs[addr] = value; - break; - - case RW_REC_CTRL: - eth->regs[addr] = value; - eth_validate_duplex(eth); - break; - - default: - eth->regs[addr] = value; - D(printf("%s %x %x\n", __func__, addr, value)); - break; - } -} - -/* The ETRAX FS has a groupt address table (GAT) which works like a k=1 bloom - filter dropping group addresses we have not joined. The filter has 64 - bits (m). The has function is a simple nible xor of the group addr. */ -static int eth_match_groupaddr(ETRAXFSEthState *eth, const unsigned char *sa) -{ - unsigned int hsh; - int m_individual = eth->regs[RW_REC_CTRL] & 4; - int match; - - /* First bit on the wire of a MAC address signals multicast or - physical address. */ - if (!m_individual && !(sa[0] & 1)) { - return 0; - } - - /* Calculate the hash index for the GA registers. */ - hsh = 0; - hsh ^= (*sa) & 0x3f; - hsh ^= ((*sa) >> 6) & 0x03; - ++sa; - hsh ^= ((*sa) << 2) & 0x03c; - hsh ^= ((*sa) >> 4) & 0xf; - ++sa; - hsh ^= ((*sa) << 4) & 0x30; - hsh ^= ((*sa) >> 2) & 0x3f; - ++sa; - hsh ^= (*sa) & 0x3f; - hsh ^= ((*sa) >> 6) & 0x03; - ++sa; - hsh ^= ((*sa) << 2) & 0x03c; - hsh ^= ((*sa) >> 4) & 0xf; - ++sa; - hsh ^= ((*sa) << 4) & 0x30; - hsh ^= ((*sa) >> 2) & 0x3f; - - hsh &= 63; - if (hsh > 31) { - match = eth->regs[RW_GA_HI] & (1 << (hsh - 32)); - } else { - match = eth->regs[RW_GA_LO] & (1 << hsh); - } - D(printf("hsh=%x ga=%x.%x mtch=%d\n", hsh, - eth->regs[RW_GA_HI], eth->regs[RW_GA_LO], match)); - return match; -} - -static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size) -{ - unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - ETRAXFSEthState *eth = qemu_get_nic_opaque(nc); - int use_ma0 = eth->regs[RW_REC_CTRL] & 1; - int use_ma1 = eth->regs[RW_REC_CTRL] & 2; - int r_bcast = eth->regs[RW_REC_CTRL] & 8; - - if (size < 12) { - return -1; - } - - D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n", - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], - use_ma0, use_ma1, r_bcast)); - - /* Does the frame get through the address filters? */ - if ((!use_ma0 || memcmp(buf, eth->macaddr[0], 6)) - && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6)) - && (!r_bcast || memcmp(buf, sa_bcast, 6)) - && !eth_match_groupaddr(eth, buf)) { - return size; - } - - /* FIXME: Find another way to pass on the fake csum. */ - etraxfs_dmac_input(eth->dma_in, (void *)buf, size + 4, 1); - - return size; -} - -static int eth_tx_push(void *opaque, unsigned char *buf, int len, bool eop) -{ - ETRAXFSEthState *eth = opaque; - - D(printf("%s buf=%p len=%d\n", __func__, buf, len)); - qemu_send_packet(qemu_get_queue(eth->nic), buf, len); - return len; -} - -static void eth_set_link(NetClientState *nc) -{ - ETRAXFSEthState *eth = qemu_get_nic_opaque(nc); - D(printf("%s %d\n", __func__, nc->link_down)); - eth->phy.link = !nc->link_down; -} - -static const MemoryRegionOps eth_ops = { - .read = eth_read, - .write = eth_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4 - } -}; - -static NetClientInfo net_etraxfs_info = { - .type = NET_CLIENT_DRIVER_NIC, - .size = sizeof(NICState), - .receive = eth_receive, - .link_status_changed = eth_set_link, -}; - -static void etraxfs_eth_reset(DeviceState *dev) -{ - ETRAXFSEthState *s = ETRAX_FS_ETH(dev); - - memset(s->regs, 0, sizeof(s->regs)); - memset(s->macaddr, 0, sizeof(s->macaddr)); - s->duplex_mismatch = 0; - - s->mdio_bus.mdc = 0; - s->mdio_bus.mdio = 0; - s->mdio_bus.state = 0; - s->mdio_bus.drive = 0; - s->mdio_bus.cnt = 0; - s->mdio_bus.addr = 0; - s->mdio_bus.opc = 0; - s->mdio_bus.req = 0; - s->mdio_bus.data = 0; - - tdk_reset(&s->phy); -} - -static void etraxfs_eth_realize(DeviceState *dev, Error **errp) -{ - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - ETRAXFSEthState *s = ETRAX_FS_ETH(dev); - - if (!s->dma_out || !s->dma_in) { - error_setg(errp, "Unconnected ETRAX-FS Ethernet MAC"); - return; - } - - s->dma_out->client.push = eth_tx_push; - s->dma_out->client.opaque = s; - s->dma_in->client.opaque = s; - s->dma_in->client.pull = NULL; - - memory_region_init_io(&s->mmio, OBJECT(dev), ð_ops, s, - "etraxfs-eth", 0x5c); - sysbus_init_mmio(sbd, &s->mmio); - - qemu_macaddr_default_if_unset(&s->conf.macaddr); - s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf, - object_get_typename(OBJECT(s)), dev->id, - &dev->mem_reentrancy_guard, s); - qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); - - s->phy.read = tdk_read; - s->phy.write = tdk_write; - mdio_attach(&s->mdio_bus, &s->phy, s->phyaddr); -} - -static Property etraxfs_eth_properties[] = { - DEFINE_PROP_UINT32("phyaddr", ETRAXFSEthState, phyaddr, 1), - DEFINE_NIC_PROPERTIES(ETRAXFSEthState, conf), - DEFINE_PROP_END_OF_LIST(), -}; - -static void etraxfs_eth_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = etraxfs_eth_realize; - dc->reset = etraxfs_eth_reset; - device_class_set_props(dc, etraxfs_eth_properties); - /* Reason: dma_out, dma_in are not user settable */ - dc->user_creatable = false; -} - - -/* Instantiate an ETRAXFS Ethernet MAC. */ -DeviceState * -etraxfs_eth_init(hwaddr base, int phyaddr, - struct etraxfs_dma_client *dma_out, - struct etraxfs_dma_client *dma_in) -{ - DeviceState *dev; - - dev = qdev_new("etraxfs-eth"); - qemu_configure_nic_device(dev, true, "fseth"); - qdev_prop_set_uint32(dev, "phyaddr", phyaddr); - - /* - * TODO: QOM design, define a QOM interface for "I am an etraxfs - * DMA client" (which replaces the current 'struct - * etraxfs_dma_client' ad-hoc interface), implement it on the - * ethernet device, and then have QOM link properties on the DMA - * controller device so that you can pass the interface - * implementations to it. - */ - ETRAX_FS_ETH(dev)->dma_out = dma_out; - ETRAX_FS_ETH(dev)->dma_in = dma_in; - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - - return dev; -} - -static const TypeInfo etraxfs_eth_info = { - .name = TYPE_ETRAX_FS_ETH, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(ETRAXFSEthState), - .class_init = etraxfs_eth_class_init, -}; - -static void etraxfs_eth_register_types(void) -{ - type_register_static(&etraxfs_eth_info); -} - -type_init(etraxfs_eth_register_types) diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c index 00315f3..846f6cb 100644 --- a/hw/net/fsl_etsec/etsec.c +++ b/hw/net/fsl_etsec/etsec.c @@ -36,7 +36,6 @@ #include "registers.h" #include "qapi/error.h" #include "qemu/log.h" -#include "qemu/module.h" /* #define HEX_DUMP */ /* #define DEBUG_REGISTER */ @@ -390,6 +389,7 @@ static void etsec_realize(DeviceState *dev, Error **errp) { eTSEC *etsec = ETSEC_COMMON(dev); + qemu_macaddr_default_if_unset(&etsec->conf.macaddr); etsec->nic = qemu_new_nic(&net_etsec_info, &etsec->conf, object_get_typename(OBJECT(dev)), dev->id, &dev->mem_reentrancy_guard, etsec); @@ -415,33 +415,29 @@ static void etsec_instance_init(Object *obj) sysbus_init_irq(sbd, &etsec->err_irq); } -static Property etsec_properties[] = { +static const Property etsec_properties[] = { DEFINE_NIC_PROPERTIES(eTSEC, conf), - DEFINE_PROP_END_OF_LIST(), }; -static void etsec_class_init(ObjectClass *klass, void *data) +static void etsec_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = etsec_realize; - dc->reset = etsec_reset; + dc->desc = "Freescale Enhanced Three-Speed Ethernet Controller"; + device_class_set_legacy_reset(dc, etsec_reset); device_class_set_props(dc, etsec_properties); - /* Supported by ppce500 machine */ - dc->user_creatable = true; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); } -static const TypeInfo etsec_info = { - .name = TYPE_ETSEC_COMMON, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(eTSEC), - .class_init = etsec_class_init, - .instance_init = etsec_instance_init, +static const TypeInfo etsec_types[] = { + { + .name = TYPE_ETSEC_COMMON, + .parent = TYPE_DYNAMIC_SYS_BUS_DEVICE, + .instance_size = sizeof(eTSEC), + .class_init = etsec_class_init, + .instance_init = etsec_instance_init, + }, }; -static void etsec_register_types(void) -{ - type_register_static(&etsec_info); -} - -type_init(etsec_register_types) +DEFINE_TYPES(etsec_types) diff --git a/hw/net/fsl_etsec/miim.c b/hw/net/fsl_etsec/miim.c index b48d2cb..4e91699 100644 --- a/hw/net/fsl_etsec/miim.c +++ b/hw/net/fsl_etsec/miim.c @@ -29,13 +29,6 @@ /* #define DEBUG_MIIM */ -#define MIIM_CONTROL 0 -#define MIIM_STATUS 1 -#define MIIM_PHY_ID_1 2 -#define MIIM_PHY_ID_2 3 -#define MIIM_T2_STATUS 10 -#define MIIM_EXT_STATUS 15 - static void miim_read_cycle(eTSEC *etsec) { uint8_t phy; @@ -47,14 +40,14 @@ static void miim_read_cycle(eTSEC *etsec) addr = etsec->regs[MIIMADD].value & 0x1F; switch (addr) { - case MIIM_CONTROL: + case MII_BMCR: value = etsec->phy_control; break; - case MIIM_STATUS: + case MII_BMSR: value = etsec->phy_status; break; - case MIIM_T2_STATUS: - value = 0x1800; /* Local and remote receivers OK */ + case MII_STAT1000: + value = MII_STAT1000_LOK | MII_STAT1000_ROK; break; default: value = 0x0; @@ -84,8 +77,8 @@ static void miim_write_cycle(eTSEC *etsec) #endif switch (addr) { - case MIIM_CONTROL: - etsec->phy_control = value & ~(0x8100); + case MII_BMCR: + etsec->phy_control = value & ~(MII_BMCR_RESET | MII_BMCR_FD); break; default: break; diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c index 80f9cd5..c41ce88 100644 --- a/hw/net/ftgmac100.c +++ b/hw/net/ftgmac100.c @@ -14,7 +14,7 @@ #include "qemu/osdep.h" #include "hw/irq.h" #include "hw/net/ftgmac100.h" -#include "sysemu/dma.h" +#include "system/dma.h" #include "qapi/error.h" #include "qemu/log.h" #include "qemu/module.h" @@ -24,8 +24,7 @@ #include "hw/qdev-properties.h" #include "migration/vmstate.h" -/* For crc32 */ -#include <zlib.h> +#include <zlib.h> /* for crc32 */ /* * FTGMAC100 registers @@ -1255,19 +1254,18 @@ static const VMStateDescription vmstate_ftgmac100 = { } }; -static Property ftgmac100_properties[] = { +static const Property ftgmac100_properties[] = { DEFINE_PROP_BOOL("aspeed", FTGMAC100State, aspeed, false), DEFINE_NIC_PROPERTIES(FTGMAC100State, conf), DEFINE_PROP_BOOL("dma64", FTGMAC100State, dma64, false), - DEFINE_PROP_END_OF_LIST(), }; -static void ftgmac100_class_init(ObjectClass *klass, void *data) +static void ftgmac100_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->vmsd = &vmstate_ftgmac100; - dc->reset = ftgmac100_reset; + device_class_set_legacy_reset(dc, ftgmac100_reset); device_class_set_props(dc, ftgmac100_properties); set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->realize = ftgmac100_realize; @@ -1416,18 +1414,17 @@ static const VMStateDescription vmstate_aspeed_mii = { } }; -static Property aspeed_mii_properties[] = { +static const Property aspeed_mii_properties[] = { DEFINE_PROP_LINK("nic", AspeedMiiState, nic, TYPE_FTGMAC100, FTGMAC100State *), - DEFINE_PROP_END_OF_LIST(), }; -static void aspeed_mii_class_init(ObjectClass *klass, void *data) +static void aspeed_mii_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->vmsd = &vmstate_aspeed_mii; - dc->reset = aspeed_mii_reset; + device_class_set_legacy_reset(dc, aspeed_mii_reset); dc->realize = aspeed_mii_realize; dc->desc = "Aspeed MII controller"; device_class_set_props(dc, aspeed_mii_properties); diff --git a/hw/net/i82596.c b/hw/net/i82596.c index 6cc8292..c1ff3e6 100644 --- a/hw/net/i82596.c +++ b/hw/net/i82596.c @@ -5,7 +5,7 @@ * This work is licensed under the GNU GPL license version 2 or later. * * This software was written to be compatible with the specification: - * https://www.intel.com/assets/pdf/general/82596ca.pdf + * https://parisc.docs.kernel.org/en/latest/_downloads/96672be0650d9fc046bbcea40b92482f/82596CA.pdf */ #include "qemu/osdep.h" @@ -15,11 +15,11 @@ #include "hw/irq.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "qemu/module.h" #include "trace.h" #include "i82596.h" -#include <zlib.h> /* For crc32 */ +#include <zlib.h> /* for crc32 */ #if defined(ENABLE_DEBUG) #define DBG(x) x @@ -177,6 +177,26 @@ static void set_individual_address(I82596State *s, uint32_t addr) trace_i82596_new_mac(nc->info_str); } +static void i82596_configure(I82596State *s, uint32_t addr) +{ + uint8_t byte_cnt; + byte_cnt = get_byte(addr + 8) & 0x0f; + + byte_cnt = MAX(byte_cnt, 4); + byte_cnt = MIN(byte_cnt, sizeof(s->config)); + /* copy byte_cnt max. */ + address_space_read(&address_space_memory, addr + 8, + MEMTXATTRS_UNSPECIFIED, s->config, byte_cnt); + /* config byte according to page 35ff */ + s->config[2] &= 0x82; /* mask valid bits */ + s->config[2] |= 0x40; + s->config[7] &= 0xf7; /* clear zero bit */ + assert(I596_NOCRC_INS == 0); /* do CRC insertion */ + s->config[10] = MAX(s->config[10], 5); /* min frame length */ + s->config[12] &= 0x40; /* only full duplex field valid */ + s->config[13] |= 0x3f; /* set ones in byte 13 */ +} + static void set_multicast_list(I82596State *s, uint32_t addr) { uint16_t mc_count, i; @@ -234,7 +254,6 @@ static void command_loop(I82596State *s) { uint16_t cmd; uint16_t status; - uint8_t byte_cnt; DBG(printf("STARTING COMMAND LOOP cmd_p=%08x\n", s->cmd_p)); @@ -254,20 +273,7 @@ static void command_loop(I82596State *s) set_individual_address(s, s->cmd_p); break; case CmdConfigure: - byte_cnt = get_byte(s->cmd_p + 8) & 0x0f; - byte_cnt = MAX(byte_cnt, 4); - byte_cnt = MIN(byte_cnt, sizeof(s->config)); - /* copy byte_cnt max. */ - address_space_read(&address_space_memory, s->cmd_p + 8, - MEMTXATTRS_UNSPECIFIED, s->config, byte_cnt); - /* config byte according to page 35ff */ - s->config[2] &= 0x82; /* mask valid bits */ - s->config[2] |= 0x40; - s->config[7] &= 0xf7; /* clear zero bit */ - assert(I596_NOCRC_INS == 0); /* do CRC insertion */ - s->config[10] = MAX(s->config[10], 5); /* min frame length */ - s->config[12] &= 0x40; /* only full duplex field valid */ - s->config[13] |= 0x3f; /* set ones in byte 13 */ + i82596_configure(s, s->cmd_p); break; case CmdTDR: /* get signal LINK */ @@ -282,7 +288,7 @@ static void command_loop(I82596State *s) case CmdDump: case CmdDiagnose: printf("FIXME Command %d !!\n", cmd & 7); - assert(0); + g_assert_not_reached(); } /* update status */ diff --git a/hw/net/i82596.h b/hw/net/i82596.h index f0bbe81..dc1fa1a 100644 --- a/hw/net/i82596.h +++ b/hw/net/i82596.h @@ -3,8 +3,8 @@ #define I82596_IOPORT_SIZE 0x20 -#include "exec/memory.h" -#include "exec/address-spaces.h" +#include "system/memory.h" +#include "system/address-spaces.h" #define PORT_RESET 0x00 /* reset 82596 */ #define PORT_SELFTEST 0x01 /* selftest */ diff --git a/hw/net/igb.c b/hw/net/igb.c index b92bba4..e4c0236 100644 --- a/hw/net/igb.c +++ b/hw/net/igb.c @@ -44,7 +44,7 @@ #include "net/tap.h" #include "qemu/module.h" #include "qemu/range.h" -#include "sysemu/sysemu.h" +#include "system/system.h" #include "hw/hw.h" #include "hw/net/mii.h" #include "hw/pci/pci.h" @@ -356,8 +356,7 @@ static int igb_add_pm_capability(PCIDevice *pdev, uint8_t offset, uint16_t pmc) { Error *local_err = NULL; - int ret = pci_add_capability(pdev, PCI_CAP_ID_PM, offset, - PCI_PM_SIZEOF, &local_err); + int ret = pci_pm_init(pdev, offset, &local_err); if (local_err) { error_report_err(local_err); @@ -446,9 +445,13 @@ static void igb_pci_realize(PCIDevice *pci_dev, Error **errp) pcie_ari_init(pci_dev, 0x150); - pcie_sriov_pf_init(pci_dev, IGB_CAP_SRIOV_OFFSET, TYPE_IGBVF, - IGB_82576_VF_DEV_ID, IGB_MAX_VF_FUNCTIONS, IGB_MAX_VF_FUNCTIONS, - IGB_VF_OFFSET, IGB_VF_STRIDE); + if (!pcie_sriov_pf_init(pci_dev, IGB_CAP_SRIOV_OFFSET, TYPE_IGBVF, + IGB_82576_VF_DEV_ID, IGB_MAX_VF_FUNCTIONS, + IGB_MAX_VF_FUNCTIONS, IGB_VF_OFFSET, IGB_VF_STRIDE, + errp)) { + igb_cleanup_msix(s); + return; + } pcie_sriov_pf_init_vf_bar(pci_dev, IGBVF_MMIO_BAR_IDX, PCI_BASE_ADDRESS_MEM_TYPE_64 | PCI_BASE_ADDRESS_MEM_PREFETCH, @@ -591,13 +594,12 @@ static const VMStateDescription igb_vmstate = { } }; -static Property igb_properties[] = { +static const Property igb_properties[] = { DEFINE_NIC_PROPERTIES(IGBState, conf), DEFINE_PROP_BOOL("x-pcie-flr-init", IGBState, has_flr, true), - DEFINE_PROP_END_OF_LIST(), }; -static void igb_class_init(ObjectClass *class, void *data) +static void igb_class_init(ObjectClass *class, const void *data) { DeviceClass *dc = DEVICE_CLASS(class); ResettableClass *rc = RESETTABLE_CLASS(class); @@ -633,7 +635,7 @@ static const TypeInfo igb_info = { .instance_size = sizeof(IGBState), .class_init = igb_class_init, .instance_init = igb_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_PCIE_DEVICE }, { } }, diff --git a/hw/net/igb_core.c b/hw/net/igb_core.c index bcd5f6c..39e3ce1 100644 --- a/hw/net/igb_core.c +++ b/hw/net/igb_core.c @@ -44,7 +44,7 @@ #include "hw/net/mii.h" #include "hw/pci/msi.h" #include "hw/pci/msix.h" -#include "sysemu/runstate.h" +#include "system/runstate.h" #include "net_tx_pkt.h" #include "net_rx_pkt.h" @@ -397,8 +397,7 @@ igb_rss_calc_hash(IGBCore *core, struct NetRxPkt *pkt, E1000E_RSSInfo *info) type = NetPktRssIpV6Udp; break; default: - assert(false); - return 0; + g_assert_not_reached(); } return net_rx_pkt_calc_rss_hash(pkt, type, (uint8_t *) &core->mac[RSSRK]); @@ -747,7 +746,6 @@ igb_ring_free_descr_num(IGBCore *core, const E1000ERingInfo *r) } g_assert_not_reached(); - return 0; } static inline bool diff --git a/hw/net/igb_regs.h b/hw/net/igb_regs.h index e5a47ea..4dc4c31 100644 --- a/hw/net/igb_regs.h +++ b/hw/net/igb_regs.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * This is copied + edited from kernel header files in * drivers/net/ethernet/intel/igb diff --git a/hw/net/igbvf.c b/hw/net/igbvf.c index 21a97d4..31d72c4 100644 --- a/hw/net/igbvf.c +++ b/hw/net/igbvf.c @@ -299,7 +299,7 @@ static void igbvf_pci_uninit(PCIDevice *dev) msix_uninit(dev, &s->msix, &s->msix); } -static void igbvf_class_init(ObjectClass *class, void *data) +static void igbvf_class_init(ObjectClass *class, const void *data) { DeviceClass *dc = DEVICE_CLASS(class); PCIDeviceClass *c = PCI_DEVICE_CLASS(class); @@ -325,7 +325,7 @@ static const TypeInfo igbvf_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(IgbVfState), .class_init = igbvf_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_PCIE_DEVICE }, { } }, diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 8c91d20..e5e34dd 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -26,15 +26,14 @@ #include "hw/net/imx_fec.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" -#include "sysemu/dma.h" +#include "system/dma.h" #include "qemu/log.h" #include "qemu/module.h" #include "net/checksum.h" #include "net/eth.h" #include "trace.h" -/* For crc32 */ -#include <zlib.h> +#include <zlib.h> /* for crc32 */ #define IMX_MAX_DESC 1024 @@ -204,17 +203,12 @@ static const VMStateDescription vmstate_imx_eth_txdescs = { static const VMStateDescription vmstate_imx_eth = { .name = TYPE_IMX_FEC, - .version_id = 2, - .minimum_version_id = 2, + .version_id = 3, + .minimum_version_id = 3, .fields = (const VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, IMXFECState, ENET_MAX), VMSTATE_UINT32(rx_descriptor, IMXFECState), VMSTATE_UINT32(tx_descriptor[0], IMXFECState), - VMSTATE_UINT32(phy_status, IMXFECState), - VMSTATE_UINT32(phy_control, IMXFECState), - VMSTATE_UINT32(phy_advertise, IMXFECState), - VMSTATE_UINT32(phy_int, IMXFECState), - VMSTATE_UINT32(phy_int_mask, IMXFECState), VMSTATE_END_OF_LIST() }, .subsections = (const VMStateDescription * const []) { @@ -223,14 +217,6 @@ static const VMStateDescription vmstate_imx_eth = { }, }; -#define PHY_INT_ENERGYON (1 << 7) -#define PHY_INT_AUTONEG_COMPLETE (1 << 6) -#define PHY_INT_FAULT (1 << 5) -#define PHY_INT_DOWN (1 << 4) -#define PHY_INT_AUTONEG_LP (1 << 3) -#define PHY_INT_PARFAULT (1 << 2) -#define PHY_INT_AUTONEG_PAGE (1 << 1) - static void imx_eth_update(IMXFECState *s); /* @@ -239,47 +225,19 @@ static void imx_eth_update(IMXFECState *s); * For now we don't handle any GPIO/interrupt line, so the OS will * have to poll for the PHY status. */ -static void imx_phy_update_irq(IMXFECState *s) -{ - imx_eth_update(s); -} - -static void imx_phy_update_link(IMXFECState *s) +static void imx_phy_update_irq(void *opaque, int n, int level) { - /* Autonegotiation status mirrors link status. */ - if (qemu_get_queue(s->nic)->link_down) { - trace_imx_phy_update_link("down"); - s->phy_status &= ~0x0024; - s->phy_int |= PHY_INT_DOWN; - } else { - trace_imx_phy_update_link("up"); - s->phy_status |= 0x0024; - s->phy_int |= PHY_INT_ENERGYON; - s->phy_int |= PHY_INT_AUTONEG_COMPLETE; - } - imx_phy_update_irq(s); + imx_eth_update(opaque); } static void imx_eth_set_link(NetClientState *nc) { - imx_phy_update_link(IMX_FEC(qemu_get_nic_opaque(nc))); -} - -static void imx_phy_reset(IMXFECState *s) -{ - trace_imx_phy_reset(); - - s->phy_status = 0x7809; - s->phy_control = 0x3000; - s->phy_advertise = 0x01e1; - s->phy_int_mask = 0; - s->phy_int = 0; - imx_phy_update_link(s); + lan9118_phy_update_link(&IMX_FEC(qemu_get_nic_opaque(nc))->mii, + nc->link_down); } static uint32_t imx_phy_read(IMXFECState *s, int reg) { - uint32_t val; uint32_t phy = reg / 32; if (!s->phy_connected) { @@ -297,54 +255,7 @@ static uint32_t imx_phy_read(IMXFECState *s, int reg) reg %= 32; - switch (reg) { - case 0: /* Basic Control */ - val = s->phy_control; - break; - case 1: /* Basic Status */ - val = s->phy_status; - break; - case 2: /* ID1 */ - val = 0x0007; - break; - case 3: /* ID2 */ - val = 0xc0d1; - break; - case 4: /* Auto-neg advertisement */ - val = s->phy_advertise; - break; - case 5: /* Auto-neg Link Partner Ability */ - val = 0x0f71; - break; - case 6: /* Auto-neg Expansion */ - val = 1; - break; - case 29: /* Interrupt source. */ - val = s->phy_int; - s->phy_int = 0; - imx_phy_update_irq(s); - break; - case 30: /* Interrupt mask */ - val = s->phy_int_mask; - break; - case 17: - case 18: - case 27: - case 31: - qemu_log_mask(LOG_UNIMP, "[%s.phy]%s: reg %d not implemented\n", - TYPE_IMX_FEC, __func__, reg); - val = 0; - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad address at offset %d\n", - TYPE_IMX_FEC, __func__, reg); - val = 0; - break; - } - - trace_imx_phy_read(val, phy, reg); - - return val; + return lan9118_phy_read(&s->mii, reg); } static void imx_phy_write(IMXFECState *s, int reg, uint32_t val) @@ -366,39 +277,7 @@ static void imx_phy_write(IMXFECState *s, int reg, uint32_t val) reg %= 32; - trace_imx_phy_write(val, phy, reg); - - switch (reg) { - case 0: /* Basic Control */ - if (val & 0x8000) { - imx_phy_reset(s); - } else { - s->phy_control = val & 0x7980; - /* Complete autonegotiation immediately. */ - if (val & 0x1000) { - s->phy_status |= 0x0020; - } - } - break; - case 4: /* Auto-neg advertisement */ - s->phy_advertise = (val & 0x2d7f) | 0x80; - break; - case 30: /* Interrupt mask */ - s->phy_int_mask = val & 0xff; - imx_phy_update_irq(s); - break; - case 17: - case 18: - case 27: - case 31: - qemu_log_mask(LOG_UNIMP, "[%s.phy)%s: reg %d not implemented\n", - TYPE_IMX_FEC, __func__, reg); - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad address at offset %d\n", - TYPE_IMX_FEC, __func__, reg); - break; - } + lan9118_phy_write(&s->mii, reg, val); } static void imx_fec_read_bd(IMXFECBufDesc *bd, dma_addr_t addr) @@ -683,9 +562,6 @@ static void imx_eth_reset(DeviceState *d) s->rx_descriptor = 0; memset(s->tx_descriptor, 0, sizeof(s->tx_descriptor)); - - /* We also reset the PHY */ - imx_phy_reset(s); } static uint32_t imx_default_read(IMXFECState *s, uint32_t index) @@ -792,7 +668,6 @@ static void imx_default_write(IMXFECState *s, uint32_t index, uint32_t value) { qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" PRIx32 "\n", TYPE_IMX_FEC, __func__, index * 4); - return; } static void imx_fec_write(IMXFECState *s, uint32_t index, uint32_t value) @@ -1330,6 +1205,13 @@ static void imx_eth_realize(DeviceState *dev, Error **errp) sysbus_init_irq(sbd, &s->irq[0]); sysbus_init_irq(sbd, &s->irq[1]); + qemu_init_irq(&s->mii_irq, imx_phy_update_irq, s, 0); + object_initialize_child(OBJECT(s), "mii", &s->mii, TYPE_LAN9118_PHY); + if (!sysbus_realize_and_unref(SYS_BUS_DEVICE(&s->mii), errp)) { + return; + } + qdev_connect_gpio_out(DEVICE(&s->mii), 0, &s->mii_irq); + qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&imx_eth_net_info, &s->conf, @@ -1339,22 +1221,21 @@ static void imx_eth_realize(DeviceState *dev, Error **errp) qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); } -static Property imx_eth_properties[] = { +static const Property imx_eth_properties[] = { DEFINE_NIC_PROPERTIES(IMXFECState, conf), DEFINE_PROP_UINT32("tx-ring-num", IMXFECState, tx_ring_num, 1), DEFINE_PROP_UINT32("phy-num", IMXFECState, phy_num, 0), DEFINE_PROP_BOOL("phy-connected", IMXFECState, phy_connected, true), DEFINE_PROP_LINK("phy-consumer", IMXFECState, phy_consumer, TYPE_IMX_FEC, IMXFECState *), - DEFINE_PROP_END_OF_LIST(), }; -static void imx_eth_class_init(ObjectClass *klass, void *data) +static void imx_eth_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->vmsd = &vmstate_imx_eth; - dc->reset = imx_eth_reset; + device_class_set_legacy_reset(dc, imx_eth_reset); device_class_set_props(dc, imx_eth_properties); dc->realize = imx_eth_realize; dc->desc = "i.MX FEC/ENET Ethernet Controller"; diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c index 91d81b4..6dda1e5 100644 --- a/hw/net/lan9118.c +++ b/hw/net/lan9118.c @@ -16,14 +16,14 @@ #include "net/net.h" #include "net/eth.h" #include "hw/irq.h" +#include "hw/net/lan9118_phy.h" #include "hw/net/lan9118.h" #include "hw/ptimer.h" #include "hw/qdev-properties.h" #include "qapi/error.h" #include "qemu/log.h" #include "qemu/module.h" -/* For crc32 */ -#include <zlib.h> +#include <zlib.h> /* for crc32 */ #include "qom/object.h" //#define DEBUG_LAN9118 @@ -140,14 +140,6 @@ do { printf("lan9118: " fmt , ## __VA_ARGS__); } while (0) #define MAC_CR_RXEN 0x00000004 #define MAC_CR_RESERVED 0x7f404213 -#define PHY_INT_ENERGYON 0x80 -#define PHY_INT_AUTONEG_COMPLETE 0x40 -#define PHY_INT_FAULT 0x20 -#define PHY_INT_DOWN 0x10 -#define PHY_INT_AUTONEG_LP 0x08 -#define PHY_INT_PARFAULT 0x04 -#define PHY_INT_AUTONEG_PAGE 0x02 - #define GPT_TIMER_EN 0x20000000 /* @@ -229,11 +221,8 @@ struct lan9118_state { uint32_t mac_mii_data; uint32_t mac_flow; - uint32_t phy_status; - uint32_t phy_control; - uint32_t phy_advertise; - uint32_t phy_int; - uint32_t phy_int_mask; + Lan9118PhyState mii; + IRQState mii_irq; int32_t eeprom_writable; uint8_t eeprom[128]; @@ -275,8 +264,8 @@ struct lan9118_state { static const VMStateDescription vmstate_lan9118 = { .name = "lan9118", - .version_id = 2, - .minimum_version_id = 1, + .version_id = 3, + .minimum_version_id = 3, .fields = (const VMStateField[]) { VMSTATE_PTIMER(timer, lan9118_state), VMSTATE_UINT32(irq_cfg, lan9118_state), @@ -302,11 +291,6 @@ static const VMStateDescription vmstate_lan9118 = { VMSTATE_UINT32(mac_mii_acc, lan9118_state), VMSTATE_UINT32(mac_mii_data, lan9118_state), VMSTATE_UINT32(mac_flow, lan9118_state), - VMSTATE_UINT32(phy_status, lan9118_state), - VMSTATE_UINT32(phy_control, lan9118_state), - VMSTATE_UINT32(phy_advertise, lan9118_state), - VMSTATE_UINT32(phy_int, lan9118_state), - VMSTATE_UINT32(phy_int_mask, lan9118_state), VMSTATE_INT32(eeprom_writable, lan9118_state), VMSTATE_UINT8_ARRAY(eeprom, lan9118_state, 128), VMSTATE_INT32(tx_fifo_size, lan9118_state), @@ -386,9 +370,11 @@ static void lan9118_reload_eeprom(lan9118_state *s) lan9118_mac_changed(s); } -static void phy_update_irq(lan9118_state *s) +static void lan9118_update_irq(void *opaque, int n, int level) { - if (s->phy_int & s->phy_int_mask) { + lan9118_state *s = opaque; + + if (level) { s->int_sts |= PHY_INT; } else { s->int_sts &= ~PHY_INT; @@ -396,33 +382,10 @@ static void phy_update_irq(lan9118_state *s) lan9118_update(s); } -static void phy_update_link(lan9118_state *s) -{ - /* Autonegotiation status mirrors link status. */ - if (qemu_get_queue(s->nic)->link_down) { - s->phy_status &= ~0x0024; - s->phy_int |= PHY_INT_DOWN; - } else { - s->phy_status |= 0x0024; - s->phy_int |= PHY_INT_ENERGYON; - s->phy_int |= PHY_INT_AUTONEG_COMPLETE; - } - phy_update_irq(s); -} - static void lan9118_set_link(NetClientState *nc) { - phy_update_link(qemu_get_nic_opaque(nc)); -} - -static void phy_reset(lan9118_state *s) -{ - s->phy_status = 0x7809; - s->phy_control = 0x3000; - s->phy_advertise = 0x01e1; - s->phy_int_mask = 0; - s->phy_int = 0; - phy_update_link(s); + lan9118_phy_update_link(&LAN9118(qemu_get_nic_opaque(nc))->mii, + nc->link_down); } static void lan9118_reset(DeviceState *d) @@ -479,8 +442,6 @@ static void lan9118_reset(DeviceState *d) s->read_word_n = 0; s->write_word_n = 0; - phy_reset(s); - s->eeprom_writable = 0; lan9118_reload_eeprom(s); } @@ -679,7 +640,7 @@ static void do_tx_packet(lan9118_state *s) uint32_t status; /* FIXME: Honor TX disable, and allow queueing of packets. */ - if (s->phy_control & 0x4000) { + if (s->mii.control & 0x4000) { /* This assumes the receive routine doesn't touch the VLANClient. */ qemu_receive_packet(qemu_get_queue(s->nic), s->txp->data, s->txp->len); } else { @@ -835,68 +796,6 @@ static void tx_fifo_push(lan9118_state *s, uint32_t val) } } -static uint32_t do_phy_read(lan9118_state *s, int reg) -{ - uint32_t val; - - switch (reg) { - case 0: /* Basic Control */ - return s->phy_control; - case 1: /* Basic Status */ - return s->phy_status; - case 2: /* ID1 */ - return 0x0007; - case 3: /* ID2 */ - return 0xc0d1; - case 4: /* Auto-neg advertisement */ - return s->phy_advertise; - case 5: /* Auto-neg Link Partner Ability */ - return 0x0f71; - case 6: /* Auto-neg Expansion */ - return 1; - /* TODO 17, 18, 27, 29, 30, 31 */ - case 29: /* Interrupt source. */ - val = s->phy_int; - s->phy_int = 0; - phy_update_irq(s); - return val; - case 30: /* Interrupt mask */ - return s->phy_int_mask; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "do_phy_read: PHY read reg %d\n", reg); - return 0; - } -} - -static void do_phy_write(lan9118_state *s, int reg, uint32_t val) -{ - switch (reg) { - case 0: /* Basic Control */ - if (val & 0x8000) { - phy_reset(s); - break; - } - s->phy_control = val & 0x7980; - /* Complete autonegotiation immediately. */ - if (val & 0x1000) { - s->phy_status |= 0x0020; - } - break; - case 4: /* Auto-neg advertisement */ - s->phy_advertise = (val & 0x2d7f) | 0x80; - break; - /* TODO 17, 18, 27, 31 */ - case 30: /* Interrupt mask */ - s->phy_int_mask = val & 0xff; - phy_update_irq(s); - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "do_phy_write: PHY write reg %d = 0x%04x\n", reg, val); - } -} - static void do_mac_write(lan9118_state *s, int reg, uint32_t val) { switch (reg) { @@ -930,9 +829,9 @@ static void do_mac_write(lan9118_state *s, int reg, uint32_t val) if (val & 2) { DPRINTF("PHY write %d = 0x%04x\n", (val >> 6) & 0x1f, s->mac_mii_data); - do_phy_write(s, (val >> 6) & 0x1f, s->mac_mii_data); + lan9118_phy_write(&s->mii, (val >> 6) & 0x1f, s->mac_mii_data); } else { - s->mac_mii_data = do_phy_read(s, (val >> 6) & 0x1f); + s->mac_mii_data = lan9118_phy_read(&s->mii, (val >> 6) & 0x1f); DPRINTF("PHY read %d = 0x%04x\n", (val >> 6) & 0x1f, s->mac_mii_data); } @@ -1127,7 +1026,7 @@ static void lan9118_writel(void *opaque, hwaddr offset, break; case CSR_PMT_CTRL: if (val & 0x400) { - phy_reset(s); + lan9118_phy_reset(&s->mii); } s->pmt_ctrl &= ~0x34e; s->pmt_ctrl |= (val & 0x34e); @@ -1374,6 +1273,13 @@ static void lan9118_realize(DeviceState *dev, Error **errp) const MemoryRegionOps *mem_ops = s->mode_16bit ? &lan9118_16bit_mem_ops : &lan9118_mem_ops; + qemu_init_irq(&s->mii_irq, lan9118_update_irq, s, 0); + object_initialize_child(OBJECT(s), "mii", &s->mii, TYPE_LAN9118_PHY); + if (!sysbus_realize_and_unref(SYS_BUS_DEVICE(&s->mii), errp)) { + return; + } + qdev_connect_gpio_out(DEVICE(&s->mii), 0, &s->mii_irq); + memory_region_init_io(&s->mmio, OBJECT(dev), mem_ops, s, "lan9118-mmio", 0x100); sysbus_init_mmio(sbd, &s->mmio); @@ -1398,17 +1304,16 @@ static void lan9118_realize(DeviceState *dev, Error **errp) ptimer_transaction_commit(s->timer); } -static Property lan9118_properties[] = { +static const Property lan9118_properties[] = { DEFINE_NIC_PROPERTIES(lan9118_state, conf), DEFINE_PROP_UINT32("mode_16bit", lan9118_state, mode_16bit, 0), - DEFINE_PROP_END_OF_LIST(), }; -static void lan9118_class_init(ObjectClass *klass, void *data) +static void lan9118_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - dc->reset = lan9118_reset; + device_class_set_legacy_reset(dc, lan9118_reset); device_class_set_props(dc, lan9118_properties); dc->vmsd = &vmstate_lan9118; dc->realize = lan9118_realize; diff --git a/hw/net/lan9118_phy.c b/hw/net/lan9118_phy.c new file mode 100644 index 0000000..4c4e03d --- /dev/null +++ b/hw/net/lan9118_phy.c @@ -0,0 +1,222 @@ +/* + * SMSC LAN9118 PHY emulation + * + * Copyright (c) 2009 CodeSourcery, LLC. + * Written by Paul Brook + * + * Copyright (c) 2013 Jean-Christophe Dubois. <jcd@tribudubois.net> + * + * This code is licensed under the GNU GPL v2 + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "hw/net/lan9118_phy.h" +#include "hw/net/mii.h" +#include "hw/irq.h" +#include "hw/resettable.h" +#include "migration/vmstate.h" +#include "qemu/log.h" +#include "trace.h" + +#define PHY_INT_ENERGYON (1 << 7) +#define PHY_INT_AUTONEG_COMPLETE (1 << 6) +#define PHY_INT_FAULT (1 << 5) +#define PHY_INT_DOWN (1 << 4) +#define PHY_INT_AUTONEG_LP (1 << 3) +#define PHY_INT_PARFAULT (1 << 2) +#define PHY_INT_AUTONEG_PAGE (1 << 1) + +static void lan9118_phy_update_irq(Lan9118PhyState *s) +{ + qemu_set_irq(s->irq, !!(s->ints & s->int_mask)); +} + +uint16_t lan9118_phy_read(Lan9118PhyState *s, int reg) +{ + uint16_t val; + + switch (reg) { + case MII_BMCR: + val = s->control; + break; + case MII_BMSR: + val = s->status; + break; + case MII_PHYID1: + val = SMSCLAN9118_PHYID1; + break; + case MII_PHYID2: + val = SMSCLAN9118_PHYID2; + break; + case MII_ANAR: + val = s->advertise; + break; + case MII_ANLPAR: + val = MII_ANLPAR_PAUSEASY | MII_ANLPAR_PAUSE | MII_ANLPAR_T4 | + MII_ANLPAR_TXFD | MII_ANLPAR_TX | MII_ANLPAR_10FD | + MII_ANLPAR_10 | MII_ANLPAR_CSMACD; + break; + case MII_ANER: + val = MII_ANER_NWAY; + break; + case 29: /* Interrupt source. */ + val = s->ints; + s->ints = 0; + lan9118_phy_update_irq(s); + break; + case 30: /* Interrupt mask */ + val = s->int_mask; + break; + case 17: + case 18: + case 27: + case 31: + qemu_log_mask(LOG_UNIMP, "%s: reg %d not implemented\n", + __func__, reg); + val = 0; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address at offset %d\n", + __func__, reg); + val = 0; + break; + } + + trace_lan9118_phy_read(val, reg); + + return val; +} + +void lan9118_phy_write(Lan9118PhyState *s, int reg, uint16_t val) +{ + trace_lan9118_phy_write(val, reg); + + switch (reg) { + case MII_BMCR: + if (val & MII_BMCR_RESET) { + lan9118_phy_reset(s); + } else { + s->control = val & (MII_BMCR_LOOPBACK | MII_BMCR_SPEED100 | + MII_BMCR_AUTOEN | MII_BMCR_PDOWN | MII_BMCR_FD | + MII_BMCR_CTST); + /* Complete autonegotiation immediately. */ + if (val & MII_BMCR_AUTOEN) { + s->status |= MII_BMSR_AN_COMP; + } + } + break; + case MII_ANAR: + s->advertise = (val & (MII_ANAR_RFAULT | MII_ANAR_PAUSE_ASYM | + MII_ANAR_PAUSE | MII_ANAR_TXFD | MII_ANAR_10FD | + MII_ANAR_10 | MII_ANAR_SELECT)) + | MII_ANAR_TX; + break; + case 30: /* Interrupt mask */ + s->int_mask = val & 0xff; + lan9118_phy_update_irq(s); + break; + case 17: + case 18: + case 27: + case 31: + qemu_log_mask(LOG_UNIMP, "%s: reg %d not implemented\n", + __func__, reg); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address at offset %d\n", + __func__, reg); + break; + } +} + +void lan9118_phy_update_link(Lan9118PhyState *s, bool link_down) +{ + s->link_down = link_down; + + /* Autonegotiation status mirrors link status. */ + if (link_down) { + trace_lan9118_phy_update_link("down"); + s->status &= ~(MII_BMSR_AN_COMP | MII_BMSR_LINK_ST); + s->ints |= PHY_INT_DOWN; + } else { + trace_lan9118_phy_update_link("up"); + s->status |= MII_BMSR_AN_COMP | MII_BMSR_LINK_ST; + s->ints |= PHY_INT_ENERGYON; + s->ints |= PHY_INT_AUTONEG_COMPLETE; + } + lan9118_phy_update_irq(s); +} + +void lan9118_phy_reset(Lan9118PhyState *s) +{ + trace_lan9118_phy_reset(); + + s->control = MII_BMCR_AUTOEN | MII_BMCR_SPEED100; + s->status = MII_BMSR_100TX_FD + | MII_BMSR_100TX_HD + | MII_BMSR_10T_FD + | MII_BMSR_10T_HD + | MII_BMSR_AUTONEG + | MII_BMSR_EXTCAP; + s->advertise = MII_ANAR_TXFD + | MII_ANAR_TX + | MII_ANAR_10FD + | MII_ANAR_10 + | MII_ANAR_CSMACD; + s->int_mask = 0; + s->ints = 0; + lan9118_phy_update_link(s, s->link_down); +} + +static void lan9118_phy_reset_hold(Object *obj, ResetType type) +{ + Lan9118PhyState *s = LAN9118_PHY(obj); + + lan9118_phy_reset(s); +} + +static void lan9118_phy_init(Object *obj) +{ + Lan9118PhyState *s = LAN9118_PHY(obj); + + qdev_init_gpio_out(DEVICE(s), &s->irq, 1); +} + +static const VMStateDescription vmstate_lan9118_phy = { + .name = "lan9118-phy", + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]) { + VMSTATE_UINT16(status, Lan9118PhyState), + VMSTATE_UINT16(control, Lan9118PhyState), + VMSTATE_UINT16(advertise, Lan9118PhyState), + VMSTATE_UINT16(ints, Lan9118PhyState), + VMSTATE_UINT16(int_mask, Lan9118PhyState), + VMSTATE_BOOL(link_down, Lan9118PhyState), + VMSTATE_END_OF_LIST() + } +}; + +static void lan9118_phy_class_init(ObjectClass *klass, const void *data) +{ + ResettableClass *rc = RESETTABLE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + rc->phases.hold = lan9118_phy_reset_hold; + dc->vmsd = &vmstate_lan9118_phy; +} + +static const TypeInfo types[] = { + { + .name = TYPE_LAN9118_PHY, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Lan9118PhyState), + .instance_init = lan9118_phy_init, + .class_init = lan9118_phy_class_init, + } +}; + +DEFINE_TYPES(types) diff --git a/hw/net/lance.c b/hw/net/lance.c index e1ed24c..dfb855c 100644 --- a/hw/net/lance.c +++ b/hw/net/lance.c @@ -43,7 +43,7 @@ #include "hw/net/lance.h" #include "hw/qdev-properties.h" #include "trace.h" -#include "sysemu/sysemu.h" +#include "system/system.h" static void parent_lance_reset(void *opaque, int irq, int level) @@ -137,21 +137,20 @@ static void lance_instance_init(Object *obj) DEVICE(obj)); } -static Property lance_properties[] = { +static const Property lance_properties[] = { DEFINE_PROP_LINK("dma", SysBusPCNetState, state.dma_opaque, TYPE_DEVICE, DeviceState *), DEFINE_NIC_PROPERTIES(SysBusPCNetState, state.conf), - DEFINE_PROP_END_OF_LIST(), }; -static void lance_class_init(ObjectClass *klass, void *data) +static void lance_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = lance_realize; set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->fw_name = "ethernet"; - dc->reset = lance_reset; + device_class_set_legacy_reset(dc, lance_reset); dc->vmsd = &vmstate_lance; device_class_set_props(dc, lance_properties); } diff --git a/hw/net/lasi_i82596.c b/hw/net/lasi_i82596.c index fcf7fae..9e1dd21 100644 --- a/hw/net/lasi_i82596.c +++ b/hw/net/lasi_i82596.c @@ -14,7 +14,7 @@ #include "qapi/error.h" #include "qemu/timer.h" #include "hw/sysbus.h" -#include "sysemu/sysemu.h" +#include "system/system.h" #include "net/eth.h" #include "hw/net/lasi_82596.h" #include "hw/net/i82596.h" @@ -158,19 +158,18 @@ static void lasi_82596_instance_init(Object *obj) DEVICE(obj)); } -static Property lasi_82596_properties[] = { +static const Property lasi_82596_properties[] = { DEFINE_NIC_PROPERTIES(SysBusI82596State, state.conf), - DEFINE_PROP_END_OF_LIST(), }; -static void lasi_82596_class_init(ObjectClass *klass, void *data) +static void lasi_82596_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = lasi_82596_realize; set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->fw_name = "ethernet"; - dc->reset = lasi_82596_reset; + device_class_set_legacy_reset(dc, lasi_82596_reset); dc->vmsd = &vmstate_lasi_82596; dc->user_creatable = false; device_class_set_props(dc, lasi_82596_properties); diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c index e690271..ae128fa 100644 --- a/hw/net/mcf_fec.c +++ b/hw/net/mcf_fec.c @@ -16,8 +16,7 @@ #include "hw/net/mii.h" #include "hw/qdev-properties.h" #include "hw/sysbus.h" -/* For crc32 */ -#include <zlib.h> +#include <zlib.h> /* for crc32 */ //#define DEBUG_FEC 1 @@ -661,19 +660,18 @@ static void mcf_fec_instance_init(Object *obj) } } -static Property mcf_fec_properties[] = { +static const Property mcf_fec_properties[] = { DEFINE_NIC_PROPERTIES(mcf_fec_state, conf), - DEFINE_PROP_END_OF_LIST(), }; -static void mcf_fec_class_init(ObjectClass *oc, void *data) +static void mcf_fec_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->realize = mcf_fec_realize; dc->desc = "MCF Fast Ethernet Controller network device"; - dc->reset = mcf_fec_reset; + device_class_set_legacy_reset(dc, mcf_fec_reset); device_class_set_props(dc, mcf_fec_properties); } diff --git a/hw/net/meson.build b/hw/net/meson.build index b742687..e6759e2 100644 --- a/hw/net/meson.build +++ b/hw/net/meson.build @@ -19,6 +19,7 @@ system_ss.add(when: 'CONFIG_VMXNET3_PCI', if_true: files('vmxnet3.c')) system_ss.add(when: 'CONFIG_SMC91C111', if_true: files('smc91c111.c')) system_ss.add(when: 'CONFIG_LAN9118', if_true: files('lan9118.c')) +system_ss.add(when: 'CONFIG_LAN9118_PHY', if_true: files('lan9118_phy.c')) system_ss.add(when: 'CONFIG_NE2000_ISA', if_true: files('ne2000-isa.c')) system_ss.add(when: 'CONFIG_OPENCORES_ETH', if_true: files('opencores_eth.c')) system_ss.add(when: 'CONFIG_XGMAC', if_true: files('xgmac.c')) @@ -39,8 +40,8 @@ system_ss.add(when: 'CONFIG_SUNHME', if_true: files('sunhme.c')) system_ss.add(when: 'CONFIG_FTGMAC100', if_true: files('ftgmac100.c')) system_ss.add(when: 'CONFIG_SUNGEM', if_true: files('sungem.c')) system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_emc.c', 'npcm_gmac.c')) +system_ss.add(when: 'CONFIG_NPCM8XX', if_true: files('npcm_pcs.c')) -system_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_eth.c')) system_ss.add(when: 'CONFIG_COLDFIRE', if_true: files('mcf_fec.c')) specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_llan.c')) system_ss.add(when: 'CONFIG_XILINX_ETHLITE', if_true: files('xilinx_ethlite.c')) diff --git a/hw/net/mipsnet.c b/hw/net/mipsnet.c index df5101a..583aa1c 100644 --- a/hw/net/mipsnet.c +++ b/hw/net/mipsnet.c @@ -266,19 +266,18 @@ static void mipsnet_sysbus_reset(DeviceState *dev) mipsnet_reset(s); } -static Property mipsnet_properties[] = { +static const Property mipsnet_properties[] = { DEFINE_NIC_PROPERTIES(MIPSnetState, conf), - DEFINE_PROP_END_OF_LIST(), }; -static void mipsnet_class_init(ObjectClass *klass, void *data) +static void mipsnet_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = mipsnet_realize; set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->desc = "MIPS Simulator network device"; - dc->reset = mipsnet_sysbus_reset; + device_class_set_legacy_reset(dc, mipsnet_sysbus_reset); dc->vmsd = &vmstate_mipsnet; device_class_set_props(dc, mipsnet_properties); } diff --git a/hw/net/msf2-emac.c b/hw/net/msf2-emac.c index c1fc10d..5904597 100644 --- a/hw/net/msf2-emac.c +++ b/hw/net/msf2-emac.c @@ -546,11 +546,10 @@ static void msf2_emac_init(Object *obj) sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); } -static Property msf2_emac_properties[] = { +static const Property msf2_emac_properties[] = { DEFINE_PROP_LINK("ahb-bus", MSF2EmacState, dma_mr, TYPE_MEMORY_REGION, MemoryRegion *), DEFINE_NIC_PROPERTIES(MSF2EmacState, conf), - DEFINE_PROP_END_OF_LIST(), }; static const VMStateDescription vmstate_msf2_emac = { @@ -566,12 +565,12 @@ static const VMStateDescription vmstate_msf2_emac = { } }; -static void msf2_emac_class_init(ObjectClass *klass, void *data) +static void msf2_emac_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = msf2_emac_realize; - dc->reset = msf2_emac_reset; + device_class_set_legacy_reset(dc, msf2_emac_reset); dc->vmsd = &vmstate_msf2_emac; device_class_set_props(dc, msf2_emac_properties); } diff --git a/hw/net/mv88w8618_eth.c b/hw/net/mv88w8618_eth.c index 96c65f4..6f08846 100644 --- a/hw/net/mv88w8618_eth.c +++ b/hw/net/mv88w8618_eth.c @@ -12,7 +12,7 @@ #include "hw/irq.h" #include "hw/net/mv88w8618_eth.h" #include "migration/vmstate.h" -#include "sysemu/dma.h" +#include "system/dma.h" #include "net/net.h" #define MP_ETH_SIZE 0x00001000 @@ -371,14 +371,13 @@ static const VMStateDescription mv88w8618_eth_vmsd = { } }; -static Property mv88w8618_eth_properties[] = { +static const Property mv88w8618_eth_properties[] = { DEFINE_NIC_PROPERTIES(mv88w8618_eth_state, conf), DEFINE_PROP_LINK("dma-memory", mv88w8618_eth_state, dma_mr, TYPE_MEMORY_REGION, MemoryRegion *), - DEFINE_PROP_END_OF_LIST(), }; -static void mv88w8618_eth_class_init(ObjectClass *klass, void *data) +static void mv88w8618_eth_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/net/ne2000-isa.c b/hw/net/ne2000-isa.c index 26980e0..673c785 100644 --- a/hw/net/ne2000-isa.c +++ b/hw/net/ne2000-isa.c @@ -27,7 +27,7 @@ #include "hw/net/ne2000-isa.h" #include "migration/vmstate.h" #include "ne2000.h" -#include "sysemu/sysemu.h" +#include "system/system.h" #include "qapi/error.h" #include "qapi/visitor.h" #include "qemu/module.h" @@ -79,14 +79,13 @@ static void isa_ne2000_realizefn(DeviceState *dev, Error **errp) qemu_format_nic_info_str(qemu_get_queue(s->nic), s->c.macaddr.a); } -static Property ne2000_isa_properties[] = { +static const Property ne2000_isa_properties[] = { DEFINE_PROP_UINT32("iobase", ISANE2000State, iobase, 0x300), DEFINE_PROP_UINT32("irq", ISANE2000State, isairq, 9), DEFINE_NIC_PROPERTIES(ISANE2000State, ne2000.c), - DEFINE_PROP_END_OF_LIST(), }; -static void isa_ne2000_class_initfn(ObjectClass *klass, void *data) +static void isa_ne2000_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/net/ne2000-pci.c b/hw/net/ne2000-pci.c index 7477306..ce937e1 100644 --- a/hw/net/ne2000-pci.c +++ b/hw/net/ne2000-pci.c @@ -28,7 +28,7 @@ #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "ne2000.h" -#include "sysemu/sysemu.h" +#include "system/system.h" typedef struct PCINE2000State { PCIDevice dev; @@ -96,12 +96,11 @@ static void ne2000_instance_init(Object *obj) &pci_dev->qdev); } -static Property ne2000_properties[] = { +static const Property ne2000_properties[] = { DEFINE_NIC_PROPERTIES(PCINE2000State, ne2000.c), - DEFINE_PROP_END_OF_LIST(), }; -static void ne2000_class_init(ObjectClass *klass, void *data) +static void ne2000_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -123,7 +122,7 @@ static const TypeInfo ne2000_info = { .instance_size = sizeof(PCINE2000State), .class_init = ne2000_class_init, .instance_init = ne2000_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c index b482c5f..b1923c8 100644 --- a/hw/net/ne2000.c +++ b/hw/net/ne2000.c @@ -25,7 +25,7 @@ #include "qemu/osdep.h" #include "net/eth.h" #include "qemu/module.h" -#include "exec/memory.h" +#include "system/memory.h" #include "hw/irq.h" #include "migration/vmstate.h" #include "ne2000.h" diff --git a/hw/net/net_rx_pkt.c b/hw/net/net_rx_pkt.c index 32e5f3f..f87b6f0 100644 --- a/hw/net/net_rx_pkt.c +++ b/hw/net/net_rx_pkt.c @@ -209,12 +209,6 @@ void net_rx_pkt_get_protocols(struct NetRxPkt *pkt, *l4hdr_proto = pkt->l4hdr_info.proto; } -size_t net_rx_pkt_get_l3_hdr_offset(struct NetRxPkt *pkt) -{ - assert(pkt); - return pkt->l3hdr_off; -} - size_t net_rx_pkt_get_l4_hdr_offset(struct NetRxPkt *pkt) { assert(pkt); @@ -375,8 +369,7 @@ net_rx_pkt_calc_rss_hash(struct NetRxPkt *pkt, _net_rx_rss_prepare_udp(&rss_input[0], pkt, &rss_length); break; default: - assert(false); - break; + g_assert_not_reached(); } net_toeplitz_key_init(&key_data, key); @@ -427,13 +420,6 @@ struct iovec *net_rx_pkt_get_iovec(struct NetRxPkt *pkt) return pkt->vec; } -uint16_t net_rx_pkt_get_iovec_len(struct NetRxPkt *pkt) -{ - assert(pkt); - - return pkt->vec_len; -} - void net_rx_pkt_set_vhdr(struct NetRxPkt *pkt, struct virtio_net_hdr *vhdr) { diff --git a/hw/net/net_rx_pkt.h b/hw/net/net_rx_pkt.h index 55ec67a..ea077f5 100644 --- a/hw/net/net_rx_pkt.h +++ b/hw/net/net_rx_pkt.h @@ -78,14 +78,6 @@ void net_rx_pkt_get_protocols(struct NetRxPkt *pkt, EthL4HdrProto *l4hdr_proto); /** -* fetches L3 header offset -* -* @pkt: packet -* -*/ -size_t net_rx_pkt_get_l3_hdr_offset(struct NetRxPkt *pkt); - -/** * fetches L4 header offset * * @pkt: packet @@ -268,15 +260,6 @@ net_rx_pkt_attach_data(struct NetRxPkt *pkt, const void *data, struct iovec *net_rx_pkt_get_iovec(struct NetRxPkt *pkt); /** -* returns io vector length that holds the attached data -* -* @pkt: packet -* @ret: IOVec length -* -*/ -uint16_t net_rx_pkt_get_iovec_len(struct NetRxPkt *pkt); - -/** * prints rx packet data if debug is enabled * * @pkt: packet diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c index 1f79b82..903238d 100644 --- a/hw/net/net_tx_pkt.c +++ b/hw/net/net_tx_pkt.c @@ -141,10 +141,6 @@ bool net_tx_pkt_update_sctp_checksum(struct NetTxPkt *pkt) uint32_t csum = 0; struct iovec *pl_start_frag = pkt->vec + NET_TX_PKT_PL_START_FRAG; - if (iov_size(pl_start_frag, pkt->payload_frags) < 8 + sizeof(csum)) { - return false; - } - if (iov_from_buf(pl_start_frag, pkt->payload_frags, 8, &csum, sizeof(csum)) < sizeof(csum)) { return false; } diff --git a/hw/net/npcm7xx_emc.c b/hw/net/npcm7xx_emc.c index d1583b6..9ba35e2 100644 --- a/hw/net/npcm7xx_emc.c +++ b/hw/net/npcm7xx_emc.c @@ -29,8 +29,7 @@ #include "qemu/osdep.h" -/* For crc32 */ -#include <zlib.h> +#include <zlib.h> /* for crc32 */ #include "hw/irq.h" #include "hw/qdev-clock.h" @@ -43,7 +42,7 @@ #include "qemu/log.h" #include "qemu/module.h" #include "qemu/units.h" -#include "sysemu/dma.h" +#include "system/dma.h" #include "trace.h" #define CRC_LENGTH 4 @@ -846,12 +845,11 @@ static const VMStateDescription vmstate_npcm7xx_emc = { }, }; -static Property npcm7xx_emc_properties[] = { +static const Property npcm7xx_emc_properties[] = { DEFINE_NIC_PROPERTIES(NPCM7xxEMCState, conf), - DEFINE_PROP_END_OF_LIST(), }; -static void npcm7xx_emc_class_init(ObjectClass *klass, void *data) +static void npcm7xx_emc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -859,7 +857,7 @@ static void npcm7xx_emc_class_init(ObjectClass *klass, void *data) dc->desc = "NPCM7xx EMC Controller"; dc->realize = npcm7xx_emc_realize; dc->unrealize = npcm7xx_emc_unrealize; - dc->reset = npcm7xx_emc_reset; + device_class_set_legacy_reset(dc, npcm7xx_emc_reset); dc->vmsd = &vmstate_npcm7xx_emc; device_class_set_props(dc, npcm7xx_emc_properties); } diff --git a/hw/net/npcm_gmac.c b/hw/net/npcm_gmac.c index 1b71e25..a434112 100644 --- a/hw/net/npcm_gmac.c +++ b/hw/net/npcm_gmac.c @@ -33,7 +33,7 @@ #include "qemu/cutils.h" #include "qemu/log.h" #include "qemu/units.h" -#include "sysemu/dma.h" +#include "system/dma.h" #include "trace.h" REG32(NPCM_DMA_BUS_MODE, 0x1000) @@ -546,9 +546,8 @@ static void gmac_try_send_next_packet(NPCMGMACState *gmac) /* 1 = DMA Owned, 0 = Software Owned */ if (!(tx_desc.tdes0 & TX_DESC_TDES0_OWN)) { - qemu_log_mask(LOG_GUEST_ERROR, - "TX Descriptor @ 0x%x is owned by software\n", - desc_addr); + trace_npcm_gmac_tx_desc_owner(DEVICE(gmac)->canonical_path, + desc_addr); gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_TU; gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT, NPCM_DMA_STATUS_TX_SUSPENDED_STATE); @@ -913,12 +912,11 @@ static const VMStateDescription vmstate_npcm_gmac = { }, }; -static Property npcm_gmac_properties[] = { +static const Property npcm_gmac_properties[] = { DEFINE_NIC_PROPERTIES(NPCMGMACState, conf), - DEFINE_PROP_END_OF_LIST(), }; -static void npcm_gmac_class_init(ObjectClass *klass, void *data) +static void npcm_gmac_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -926,7 +924,7 @@ static void npcm_gmac_class_init(ObjectClass *klass, void *data) dc->desc = "NPCM GMAC Controller"; dc->realize = npcm_gmac_realize; dc->unrealize = npcm_gmac_unrealize; - dc->reset = npcm_gmac_reset; + device_class_set_legacy_reset(dc, npcm_gmac_reset); dc->vmsd = &vmstate_npcm_gmac; device_class_set_props(dc, npcm_gmac_properties); } diff --git a/hw/net/npcm_pcs.c b/hw/net/npcm_pcs.c new file mode 100644 index 0000000..6aec105 --- /dev/null +++ b/hw/net/npcm_pcs.c @@ -0,0 +1,410 @@ +/* + * Nuvoton NPCM8xx PCS Module + * + * Copyright 2022 Google LLC + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/* + * Disclaimer: + * Currently we only implemented the default values of the registers and + * the soft reset feature. These are required to boot up the GMAC module + * in Linux kernel for NPCM845 boards. Other functionalities are not modeled. + */ + +#include "qemu/osdep.h" + +#include "exec/hwaddr.h" +#include "hw/registerfields.h" +#include "hw/net/npcm_pcs.h" +#include "migration/vmstate.h" +#include "qemu/log.h" +#include "qemu/units.h" +#include "trace.h" + +#define NPCM_PCS_IND_AC_BA 0x1fe +#define NPCM_PCS_IND_SR_CTL 0x1e00 +#define NPCM_PCS_IND_SR_MII 0x1f00 +#define NPCM_PCS_IND_SR_TIM 0x1f07 +#define NPCM_PCS_IND_VR_MII 0x1f80 + +REG16(NPCM_PCS_SR_CTL_ID1, 0x08) +REG16(NPCM_PCS_SR_CTL_ID2, 0x0a) +REG16(NPCM_PCS_SR_CTL_STS, 0x10) + +REG16(NPCM_PCS_SR_MII_CTRL, 0x00) +REG16(NPCM_PCS_SR_MII_STS, 0x02) +REG16(NPCM_PCS_SR_MII_DEV_ID1, 0x04) +REG16(NPCM_PCS_SR_MII_DEV_ID2, 0x06) +REG16(NPCM_PCS_SR_MII_AN_ADV, 0x08) +REG16(NPCM_PCS_SR_MII_LP_BABL, 0x0a) +REG16(NPCM_PCS_SR_MII_AN_EXPN, 0x0c) +REG16(NPCM_PCS_SR_MII_EXT_STS, 0x1e) + +REG16(NPCM_PCS_SR_TIM_SYNC_ABL, 0x10) +REG16(NPCM_PCS_SR_TIM_SYNC_TX_MAX_DLY_LWR, 0x12) +REG16(NPCM_PCS_SR_TIM_SYNC_TX_MAX_DLY_UPR, 0x14) +REG16(NPCM_PCS_SR_TIM_SYNC_TX_MIN_DLY_LWR, 0x16) +REG16(NPCM_PCS_SR_TIM_SYNC_TX_MIN_DLY_UPR, 0x18) +REG16(NPCM_PCS_SR_TIM_SYNC_RX_MAX_DLY_LWR, 0x1a) +REG16(NPCM_PCS_SR_TIM_SYNC_RX_MAX_DLY_UPR, 0x1c) +REG16(NPCM_PCS_SR_TIM_SYNC_RX_MIN_DLY_LWR, 0x1e) +REG16(NPCM_PCS_SR_TIM_SYNC_RX_MIN_DLY_UPR, 0x20) + +REG16(NPCM_PCS_VR_MII_MMD_DIG_CTRL1, 0x000) +REG16(NPCM_PCS_VR_MII_AN_CTRL, 0x002) +REG16(NPCM_PCS_VR_MII_AN_INTR_STS, 0x004) +REG16(NPCM_PCS_VR_MII_TC, 0x006) +REG16(NPCM_PCS_VR_MII_DBG_CTRL, 0x00a) +REG16(NPCM_PCS_VR_MII_EEE_MCTRL0, 0x00c) +REG16(NPCM_PCS_VR_MII_EEE_TXTIMER, 0x010) +REG16(NPCM_PCS_VR_MII_EEE_RXTIMER, 0x012) +REG16(NPCM_PCS_VR_MII_LINK_TIMER_CTRL, 0x014) +REG16(NPCM_PCS_VR_MII_EEE_MCTRL1, 0x016) +REG16(NPCM_PCS_VR_MII_DIG_STS, 0x020) +REG16(NPCM_PCS_VR_MII_ICG_ERRCNT1, 0x022) +REG16(NPCM_PCS_VR_MII_MISC_STS, 0x030) +REG16(NPCM_PCS_VR_MII_RX_LSTS, 0x040) +REG16(NPCM_PCS_VR_MII_MP_TX_BSTCTRL0, 0x070) +REG16(NPCM_PCS_VR_MII_MP_TX_LVLCTRL0, 0x074) +REG16(NPCM_PCS_VR_MII_MP_TX_GENCTRL0, 0x07a) +REG16(NPCM_PCS_VR_MII_MP_TX_GENCTRL1, 0x07c) +REG16(NPCM_PCS_VR_MII_MP_TX_STS, 0x090) +REG16(NPCM_PCS_VR_MII_MP_RX_GENCTRL0, 0x0b0) +REG16(NPCM_PCS_VR_MII_MP_RX_GENCTRL1, 0x0b2) +REG16(NPCM_PCS_VR_MII_MP_RX_LOS_CTRL0, 0x0ba) +REG16(NPCM_PCS_VR_MII_MP_MPLL_CTRL0, 0x0f0) +REG16(NPCM_PCS_VR_MII_MP_MPLL_CTRL1, 0x0f2) +REG16(NPCM_PCS_VR_MII_MP_MPLL_STS, 0x110) +REG16(NPCM_PCS_VR_MII_MP_MISC_CTRL2, 0x126) +REG16(NPCM_PCS_VR_MII_MP_LVL_CTRL, 0x130) +REG16(NPCM_PCS_VR_MII_MP_MISC_CTRL0, 0x132) +REG16(NPCM_PCS_VR_MII_MP_MISC_CTRL1, 0x134) +REG16(NPCM_PCS_VR_MII_DIG_CTRL2, 0x1c2) +REG16(NPCM_PCS_VR_MII_DIG_ERRCNT_SEL, 0x1c4) + +/* Register Fields */ +#define NPCM_PCS_SR_MII_CTRL_RST BIT(15) + +static const uint16_t npcm_pcs_sr_ctl_cold_reset_values[NPCM_PCS_NR_SR_CTLS] = { + [R_NPCM_PCS_SR_CTL_ID1] = 0x699e, + [R_NPCM_PCS_SR_CTL_STS] = 0x8000, +}; + +static const uint16_t npcm_pcs_sr_mii_cold_reset_values[NPCM_PCS_NR_SR_MIIS] = { + [R_NPCM_PCS_SR_MII_CTRL] = 0x1140, + [R_NPCM_PCS_SR_MII_STS] = 0x0109, + [R_NPCM_PCS_SR_MII_DEV_ID1] = 0x699e, + [R_NPCM_PCS_SR_MII_DEV_ID2] = 0xced0, + [R_NPCM_PCS_SR_MII_AN_ADV] = 0x0020, + [R_NPCM_PCS_SR_MII_EXT_STS] = 0xc000, +}; + +static const uint16_t npcm_pcs_sr_tim_cold_reset_values[NPCM_PCS_NR_SR_TIMS] = { + [R_NPCM_PCS_SR_TIM_SYNC_ABL] = 0x0003, + [R_NPCM_PCS_SR_TIM_SYNC_TX_MAX_DLY_LWR] = 0x0038, + [R_NPCM_PCS_SR_TIM_SYNC_TX_MIN_DLY_LWR] = 0x0038, + [R_NPCM_PCS_SR_TIM_SYNC_RX_MAX_DLY_LWR] = 0x0058, + [R_NPCM_PCS_SR_TIM_SYNC_RX_MIN_DLY_LWR] = 0x0048, +}; + +static const uint16_t npcm_pcs_vr_mii_cold_reset_values[NPCM_PCS_NR_VR_MIIS] = { + [R_NPCM_PCS_VR_MII_MMD_DIG_CTRL1] = 0x2400, + [R_NPCM_PCS_VR_MII_AN_INTR_STS] = 0x000a, + [R_NPCM_PCS_VR_MII_EEE_MCTRL0] = 0x899c, + [R_NPCM_PCS_VR_MII_DIG_STS] = 0x0010, + [R_NPCM_PCS_VR_MII_MP_TX_BSTCTRL0] = 0x000a, + [R_NPCM_PCS_VR_MII_MP_TX_LVLCTRL0] = 0x007f, + [R_NPCM_PCS_VR_MII_MP_TX_GENCTRL0] = 0x0001, + [R_NPCM_PCS_VR_MII_MP_RX_GENCTRL0] = 0x0100, + [R_NPCM_PCS_VR_MII_MP_RX_GENCTRL1] = 0x1100, + [R_NPCM_PCS_VR_MII_MP_RX_LOS_CTRL0] = 0x000e, + [R_NPCM_PCS_VR_MII_MP_MPLL_CTRL0] = 0x0100, + [R_NPCM_PCS_VR_MII_MP_MPLL_CTRL1] = 0x0032, + [R_NPCM_PCS_VR_MII_MP_MPLL_STS] = 0x0001, + [R_NPCM_PCS_VR_MII_MP_LVL_CTRL] = 0x0019, +}; + +static void npcm_pcs_soft_reset(NPCMPCSState *s) +{ + memcpy(s->sr_ctl, npcm_pcs_sr_ctl_cold_reset_values, + NPCM_PCS_NR_SR_CTLS * sizeof(uint16_t)); + memcpy(s->sr_mii, npcm_pcs_sr_mii_cold_reset_values, + NPCM_PCS_NR_SR_MIIS * sizeof(uint16_t)); + memcpy(s->sr_tim, npcm_pcs_sr_tim_cold_reset_values, + NPCM_PCS_NR_SR_TIMS * sizeof(uint16_t)); + memcpy(s->vr_mii, npcm_pcs_vr_mii_cold_reset_values, + NPCM_PCS_NR_VR_MIIS * sizeof(uint16_t)); +} + +static uint16_t npcm_pcs_read_sr_ctl(NPCMPCSState *s, hwaddr offset) +{ + hwaddr regno = offset / sizeof(uint16_t); + + if (regno >= NPCM_PCS_NR_SR_CTLS) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: SR_CTL read offset 0x%04" HWADDR_PRIx + " is out of range.\n", + DEVICE(s)->canonical_path, offset); + return 0; + } + + return s->sr_ctl[regno]; +} + +static uint16_t npcm_pcs_read_sr_mii(NPCMPCSState *s, hwaddr offset) +{ + hwaddr regno = offset / sizeof(uint16_t); + + if (regno >= NPCM_PCS_NR_SR_MIIS) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: SR_MII read offset 0x%04" HWADDR_PRIx + " is out of range.\n", + DEVICE(s)->canonical_path, offset); + return 0; + } + + return s->sr_mii[regno]; +} + +static uint16_t npcm_pcs_read_sr_tim(NPCMPCSState *s, hwaddr offset) +{ + hwaddr regno = offset / sizeof(uint16_t); + + if (regno >= NPCM_PCS_NR_SR_TIMS) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: SR_TIM read offset 0x%04" HWADDR_PRIx + " is out of range.\n", + DEVICE(s)->canonical_path, offset); + return 0; + } + + return s->sr_tim[regno]; +} + +static uint16_t npcm_pcs_read_vr_mii(NPCMPCSState *s, hwaddr offset) +{ + hwaddr regno = offset / sizeof(uint16_t); + + if (regno >= NPCM_PCS_NR_VR_MIIS) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: VR_MII read offset 0x%04" HWADDR_PRIx + " is out of range.\n", + DEVICE(s)->canonical_path, offset); + return 0; + } + + return s->vr_mii[regno]; +} + +static void npcm_pcs_write_sr_ctl(NPCMPCSState *s, hwaddr offset, uint16_t v) +{ + hwaddr regno = offset / sizeof(uint16_t); + + if (regno >= NPCM_PCS_NR_SR_CTLS) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: SR_CTL write offset 0x%04" HWADDR_PRIx + " is out of range.\n", + DEVICE(s)->canonical_path, offset); + return; + } + + s->sr_ctl[regno] = v; +} + +static void npcm_pcs_write_sr_mii(NPCMPCSState *s, hwaddr offset, uint16_t v) +{ + hwaddr regno = offset / sizeof(uint16_t); + + if (regno >= NPCM_PCS_NR_SR_MIIS) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: SR_MII write offset 0x%04" HWADDR_PRIx + " is out of range.\n", + DEVICE(s)->canonical_path, offset); + return; + } + + s->sr_mii[regno] = v; + + if ((offset == A_NPCM_PCS_SR_MII_CTRL) && (v & NPCM_PCS_SR_MII_CTRL_RST)) { + /* Trigger a soft reset */ + npcm_pcs_soft_reset(s); + } +} + +static void npcm_pcs_write_sr_tim(NPCMPCSState *s, hwaddr offset, uint16_t v) +{ + hwaddr regno = offset / sizeof(uint16_t); + + if (regno >= NPCM_PCS_NR_SR_TIMS) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: SR_TIM write offset 0x%04" HWADDR_PRIx + " is out of range.\n", + DEVICE(s)->canonical_path, offset); + return; + } + + s->sr_tim[regno] = v; +} + +static void npcm_pcs_write_vr_mii(NPCMPCSState *s, hwaddr offset, uint16_t v) +{ + hwaddr regno = offset / sizeof(uint16_t); + + if (regno >= NPCM_PCS_NR_VR_MIIS) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: VR_MII write offset 0x%04" HWADDR_PRIx + " is out of range.\n", + DEVICE(s)->canonical_path, offset); + return; + } + + s->vr_mii[regno] = v; +} + +static uint64_t npcm_pcs_read(void *opaque, hwaddr offset, unsigned size) +{ + NPCMPCSState *s = opaque; + uint16_t v = 0; + + if (offset == NPCM_PCS_IND_AC_BA) { + v = s->indirect_access_base; + } else { + switch (s->indirect_access_base) { + case NPCM_PCS_IND_SR_CTL: + v = npcm_pcs_read_sr_ctl(s, offset); + break; + + case NPCM_PCS_IND_SR_MII: + v = npcm_pcs_read_sr_mii(s, offset); + break; + + case NPCM_PCS_IND_SR_TIM: + v = npcm_pcs_read_sr_tim(s, offset); + break; + + case NPCM_PCS_IND_VR_MII: + v = npcm_pcs_read_vr_mii(s, offset); + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Read with invalid indirect address base: 0x%" + PRIx16 "\n", DEVICE(s)->canonical_path, + s->indirect_access_base); + } + } + + trace_npcm_pcs_reg_read(DEVICE(s)->canonical_path, s->indirect_access_base, + offset, v); + return v; +} + +static void npcm_pcs_write(void *opaque, hwaddr offset, + uint64_t v, unsigned size) +{ + NPCMPCSState *s = opaque; + + trace_npcm_pcs_reg_write(DEVICE(s)->canonical_path, s->indirect_access_base, + offset, v); + if (offset == NPCM_PCS_IND_AC_BA) { + s->indirect_access_base = v; + } else { + switch (s->indirect_access_base) { + case NPCM_PCS_IND_SR_CTL: + npcm_pcs_write_sr_ctl(s, offset, v); + break; + + case NPCM_PCS_IND_SR_MII: + npcm_pcs_write_sr_mii(s, offset, v); + break; + + case NPCM_PCS_IND_SR_TIM: + npcm_pcs_write_sr_tim(s, offset, v); + break; + + case NPCM_PCS_IND_VR_MII: + npcm_pcs_write_vr_mii(s, offset, v); + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Write with invalid indirect address base: 0x%02" + PRIx16 "\n", DEVICE(s)->canonical_path, + s->indirect_access_base); + } + } +} + +static void npcm_pcs_enter_reset(Object *obj, ResetType type) +{ + NPCMPCSState *s = NPCM_PCS(obj); + + npcm_pcs_soft_reset(s); +} + +static const struct MemoryRegionOps npcm_pcs_ops = { + .read = npcm_pcs_read, + .write = npcm_pcs_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 2, + .max_access_size = 2, + .unaligned = false, + }, +}; + +static void npcm_pcs_realize(DeviceState *dev, Error **errp) +{ + NPCMPCSState *pcs = NPCM_PCS(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + + memory_region_init_io(&pcs->iomem, OBJECT(pcs), &npcm_pcs_ops, pcs, + TYPE_NPCM_PCS, 8 * KiB); + sysbus_init_mmio(sbd, &pcs->iomem); +} + +static const VMStateDescription vmstate_npcm_pcs = { + .name = TYPE_NPCM_PCS, + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT16(indirect_access_base, NPCMPCSState), + VMSTATE_UINT16_ARRAY(sr_ctl, NPCMPCSState, NPCM_PCS_NR_SR_CTLS), + VMSTATE_UINT16_ARRAY(sr_mii, NPCMPCSState, NPCM_PCS_NR_SR_MIIS), + VMSTATE_UINT16_ARRAY(sr_tim, NPCMPCSState, NPCM_PCS_NR_SR_TIMS), + VMSTATE_UINT16_ARRAY(vr_mii, NPCMPCSState, NPCM_PCS_NR_VR_MIIS), + VMSTATE_END_OF_LIST(), + }, +}; + +static void npcm_pcs_class_init(ObjectClass *klass, const void *data) +{ + ResettableClass *rc = RESETTABLE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + dc->desc = "NPCM PCS Controller"; + dc->realize = npcm_pcs_realize; + dc->vmsd = &vmstate_npcm_pcs; + rc->phases.enter = npcm_pcs_enter_reset; +} + +static const TypeInfo npcm_pcs_types[] = { + { + .name = TYPE_NPCM_PCS, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(NPCMPCSState), + .class_init = npcm_pcs_class_init, + }, +}; +DEFINE_TYPES(npcm_pcs_types) diff --git a/hw/net/opencores_eth.c b/hw/net/opencores_eth.c index f96d6ea..7e955c0 100644 --- a/hw/net/opencores_eth.c +++ b/hw/net/opencores_eth.c @@ -743,19 +743,18 @@ static void qdev_open_eth_reset(DeviceState *dev) open_eth_reset(d); } -static Property open_eth_properties[] = { +static const Property open_eth_properties[] = { DEFINE_NIC_PROPERTIES(OpenEthState, conf), - DEFINE_PROP_END_OF_LIST(), }; -static void open_eth_class_init(ObjectClass *klass, void *data) +static void open_eth_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = sysbus_open_eth_realize; set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->desc = "Opencores 10/100 Mbit Ethernet"; - dc->reset = qdev_open_eth_reset; + device_class_set_legacy_reset(dc, qdev_open_eth_reset); device_class_set_props(dc, open_eth_properties); } diff --git a/hw/net/pcnet-pci.c b/hw/net/pcnet-pci.c index fe1a845..0ca5bc2 100644 --- a/hw/net/pcnet-pci.c +++ b/hw/net/pcnet-pci.c @@ -35,8 +35,8 @@ #include "net/net.h" #include "qemu/module.h" #include "qemu/timer.h" -#include "sysemu/dma.h" -#include "sysemu/sysemu.h" +#include "system/dma.h" +#include "system/system.h" #include "trace.h" #include "pcnet.h" @@ -252,12 +252,11 @@ static void pcnet_instance_init(Object *obj) DEVICE(obj)); } -static Property pcnet_properties[] = { +static const Property pcnet_properties[] = { DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf), - DEFINE_PROP_END_OF_LIST(), }; -static void pcnet_class_init(ObjectClass *klass, void *data) +static void pcnet_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -269,7 +268,7 @@ static void pcnet_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_AMD_LANCE; k->revision = 0x10; k->class_id = PCI_CLASS_NETWORK_ETHERNET; - dc->reset = pci_reset; + device_class_set_legacy_reset(dc, pci_reset); dc->vmsd = &vmstate_pci_pcnet; device_class_set_props(dc, pcnet_properties); set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); @@ -281,7 +280,7 @@ static const TypeInfo pcnet_info = { .instance_size = sizeof(PCIPCNetState), .class_init = pcnet_class_init, .instance_init = pcnet_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/net/pcnet.h b/hw/net/pcnet.h index eb7f46a..a94356e 100644 --- a/hw/net/pcnet.h +++ b/hw/net/pcnet.h @@ -7,7 +7,7 @@ #define PCNET_LOOPTEST_CRC 1 #define PCNET_LOOPTEST_NOCRC 2 -#include "exec/memory.h" +#include "system/memory.h" #include "hw/irq.h" /* BUS CONFIGURATION REGISTERS */ diff --git a/hw/net/rocker/rocker-hmp-cmds.c b/hw/net/rocker/rocker-hmp-cmds.c index 197c6e2..df40991 100644 --- a/hw/net/rocker/rocker-hmp-cmds.c +++ b/hw/net/rocker/rocker-hmp-cmds.c @@ -18,7 +18,7 @@ #include "monitor/monitor.h" #include "net/eth.h" #include "qapi/qapi-commands-rocker.h" -#include "qapi/qmp/qdict.h" +#include "qobject/qdict.h" void hmp_rocker(Monitor *mon, const QDict *qdict) { diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c index 7ea8eb6..cc49701 100644 --- a/hw/net/rocker/rocker.c +++ b/hw/net/rocker/rocker.c @@ -134,11 +134,6 @@ RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp) return list; } -uint32_t rocker_fp_ports(Rocker *r) -{ - return r->fp_ports; -} - static uint32_t rocker_get_pport_by_tx_ring(Rocker *r, DescRing *ring) { @@ -1464,7 +1459,7 @@ static void rocker_reset(DeviceState *dev) DPRINTF("Reset done\n"); } -static Property rocker_properties[] = { +static const Property rocker_properties[] = { DEFINE_PROP_STRING("name", Rocker, name), DEFINE_PROP_STRING("world", Rocker, world_name), DEFINE_PROP_MACADDR("fp_start_macaddr", Rocker, @@ -1473,7 +1468,6 @@ static Property rocker_properties[] = { switch_id, 0), DEFINE_PROP_ARRAY("ports", Rocker, fp_ports, fp_ports_peers, qdev_prop_netdev, NICPeers), - DEFINE_PROP_END_OF_LIST(), }; static const VMStateDescription rocker_vmsd = { @@ -1481,7 +1475,7 @@ static const VMStateDescription rocker_vmsd = { .unmigratable = 1, }; -static void rocker_class_init(ObjectClass *klass, void *data) +static void rocker_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -1494,7 +1488,7 @@ static void rocker_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_NETWORK_OTHER; set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->desc = "Rocker Switch"; - dc->reset = rocker_reset; + device_class_set_legacy_reset(dc, rocker_reset); device_class_set_props(dc, rocker_properties); dc->vmsd = &rocker_vmsd; } @@ -1504,7 +1498,7 @@ static const TypeInfo rocker_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(Rocker), .class_init = rocker_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/net/rocker/rocker.h b/hw/net/rocker/rocker.h index f85354d..ae06c1c 100644 --- a/hw/net/rocker/rocker.h +++ b/hw/net/rocker/rocker.h @@ -36,15 +36,7 @@ static inline G_GNUC_PRINTF(1, 2) int DPRINTF(const char *fmt, ...) } #endif -#define __le16 uint16_t -#define __le32 uint32_t -#define __le64 uint64_t - -#define __be16 uint16_t -#define __be32 uint32_t -#define __be64 uint64_t - -static inline bool ipv4_addr_is_multicast(__be32 addr) +static inline bool ipv4_addr_is_multicast(uint32_t addr) { return (addr & htonl(0xf0000000)) == htonl(0xe0000000); } @@ -52,8 +44,8 @@ static inline bool ipv4_addr_is_multicast(__be32 addr) typedef struct ipv6_addr { union { uint8_t addr8[16]; - __be16 addr16[8]; - __be32 addr32[4]; + uint16_t addr16[8]; + uint32_t addr32[4]; }; } Ipv6Addr; @@ -72,7 +64,6 @@ DECLARE_INSTANCE_CHECKER(Rocker, ROCKER, TYPE_ROCKER) Rocker *rocker_find(const char *name); -uint32_t rocker_fp_ports(Rocker *r); int rocker_event_link_changed(Rocker *r, uint32_t pport, bool link_up); int rocker_event_mac_vlan_seen(Rocker *r, uint32_t pport, uint8_t *addr, uint16_t vlan_id); diff --git a/hw/net/rocker/rocker_hw.h b/hw/net/rocker/rocker_hw.h index 1786323..7ec6bfb 100644 --- a/hw/net/rocker/rocker_hw.h +++ b/hw/net/rocker/rocker_hw.h @@ -9,10 +9,6 @@ #ifndef ROCKER_HW_H #define ROCKER_HW_H -#define __le16 uint16_t -#define __le32 uint32_t -#define __le64 uint64_t - /* * Return codes */ @@ -124,12 +120,12 @@ enum { */ typedef struct rocker_desc { - __le64 buf_addr; + uint64_t buf_addr; uint64_t cookie; - __le16 buf_size; - __le16 tlv_size; - __le16 rsvd[5]; /* pad to 32 bytes */ - __le16 comp_err; + uint16_t buf_size; + uint16_t tlv_size; + uint16_t rsvd[5]; /* pad to 32 bytes */ + uint16_t comp_err; } __attribute__((packed, aligned(8))) RockerDesc; /* @@ -137,9 +133,9 @@ typedef struct rocker_desc { */ typedef struct rocker_tlv { - __le32 type; - __le16 len; - __le16 rsvd; + uint32_t type; + uint16_t len; + uint16_t rsvd; } __attribute__((packed, aligned(8))) RockerTlv; /* cmd msg */ diff --git a/hw/net/rocker/rocker_of_dpa.c b/hw/net/rocker/rocker_of_dpa.c index 5e16056..4aed178 100644 --- a/hw/net/rocker/rocker_of_dpa.c +++ b/hw/net/rocker/rocker_of_dpa.c @@ -52,10 +52,10 @@ typedef struct of_dpa_flow_key { uint32_t tunnel_id; /* overlay tunnel id */ uint32_t tbl_id; /* table id */ struct { - __be16 vlan_id; /* 0 if no VLAN */ + uint16_t vlan_id; /* 0 if no VLAN */ MACAddr src; /* ethernet source address */ MACAddr dst; /* ethernet destination address */ - __be16 type; /* ethernet frame type */ + uint16_t type; /* ethernet frame type */ } eth; struct { uint8_t proto; /* IP protocol or ARP opcode */ @@ -66,14 +66,14 @@ typedef struct of_dpa_flow_key { union { struct { struct { - __be32 src; /* IP source address */ - __be32 dst; /* IP destination address */ + uint32_t src; /* IP source address */ + uint32_t dst; /* IP destination address */ } addr; union { struct { - __be16 src; /* TCP/UDP/SCTP source port */ - __be16 dst; /* TCP/UDP/SCTP destination port */ - __be16 flags; /* TCP flags */ + uint16_t src; /* TCP/UDP/SCTP source port */ + uint16_t dst; /* TCP/UDP/SCTP destination port */ + uint16_t flags; /* TCP flags */ } tp; struct { MACAddr sha; /* ARP source hardware address */ @@ -86,11 +86,11 @@ typedef struct of_dpa_flow_key { Ipv6Addr src; /* IPv6 source address */ Ipv6Addr dst; /* IPv6 destination address */ } addr; - __be32 label; /* IPv6 flow label */ + uint32_t label; /* IPv6 flow label */ struct { - __be16 src; /* TCP/UDP/SCTP source port */ - __be16 dst; /* TCP/UDP/SCTP destination port */ - __be16 flags; /* TCP flags */ + uint16_t src; /* TCP/UDP/SCTP source port */ + uint16_t dst; /* TCP/UDP/SCTP destination port */ + uint16_t flags; /* TCP flags */ } tp; struct { Ipv6Addr target; /* ND target address */ @@ -112,13 +112,13 @@ typedef struct of_dpa_flow_action { struct { uint32_t group_id; uint32_t tun_log_lport; - __be16 vlan_id; + uint16_t vlan_id; } write; struct { - __be16 new_vlan_id; + uint16_t new_vlan_id; uint32_t out_pport; uint8_t copy_to_cpu; - __be16 vlan_id; + uint16_t vlan_id; } apply; } OfDpaFlowAction; @@ -143,7 +143,7 @@ typedef struct of_dpa_flow { typedef struct of_dpa_flow_pkt_fields { uint32_t tunnel_id; struct eth_header *ethhdr; - __be16 *h_proto; + uint16_t *h_proto; struct vlan_header *vlanhdr; struct ip_header *ipv4hdr; struct ip6_header *ipv6hdr; @@ -180,7 +180,7 @@ typedef struct of_dpa_group { uint32_t group_id; MACAddr src_mac; MACAddr dst_mac; - __be16 vlan_id; + uint16_t vlan_id; } l2_rewrite; struct { uint16_t group_count; @@ -190,13 +190,13 @@ typedef struct of_dpa_group { uint32_t group_id; MACAddr src_mac; MACAddr dst_mac; - __be16 vlan_id; + uint16_t vlan_id; uint8_t ttl_check; } l3_unicast; }; } OfDpaGroup; -static int of_dpa_mask2prefix(__be32 mask) +static int of_dpa_mask2prefix(uint32_t mask) { int i; int count = 32; @@ -451,7 +451,7 @@ static void of_dpa_flow_pkt_parse(OfDpaFlowContext *fc, fc->iovcnt = iovcnt + 2; } -static void of_dpa_flow_pkt_insert_vlan(OfDpaFlowContext *fc, __be16 vlan_id) +static void of_dpa_flow_pkt_insert_vlan(OfDpaFlowContext *fc, uint16_t vlan_id) { OfDpaFlowPktFields *fields = &fc->fields; uint16_t h_proto = fields->ethhdr->h_proto; @@ -486,7 +486,7 @@ static void of_dpa_flow_pkt_strip_vlan(OfDpaFlowContext *fc) static void of_dpa_flow_pkt_hdr_rewrite(OfDpaFlowContext *fc, uint8_t *src_mac, uint8_t *dst_mac, - __be16 vlan_id) + uint16_t vlan_id) { OfDpaFlowPktFields *fields = &fc->fields; @@ -1635,8 +1635,8 @@ static int of_dpa_cmd_add_multicast_routing(OfDpaFlow *flow, return ROCKER_OK; } -static int of_dpa_cmd_add_acl_ip(OfDpaFlowKey *key, OfDpaFlowKey *mask, - RockerTlv **flow_tlvs) +static void of_dpa_cmd_add_acl_ip(OfDpaFlowKey *key, OfDpaFlowKey *mask, + RockerTlv **flow_tlvs) { key->width = FLOW_KEY_WIDTH(ip.tos); @@ -1669,8 +1669,6 @@ static int of_dpa_cmd_add_acl_ip(OfDpaFlowKey *key, OfDpaFlowKey *mask, mask->ip.tos |= rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_IP_ECN_MASK]) << 6; } - - return ROCKER_OK; } static int of_dpa_cmd_add_acl(OfDpaFlow *flow, RockerTlv **flow_tlvs) @@ -1689,7 +1687,6 @@ static int of_dpa_cmd_add_acl(OfDpaFlow *flow, RockerTlv **flow_tlvs) ACL_MODE_ANY_VLAN, ACL_MODE_ANY_TENANT, } mode = ACL_MODE_UNKNOWN; - int err = ROCKER_OK; if (!flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT] || !flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE]) { @@ -1776,14 +1773,10 @@ static int of_dpa_cmd_add_acl(OfDpaFlow *flow, RockerTlv **flow_tlvs) switch (ntohs(key->eth.type)) { case 0x0800: case 0x86dd: - err = of_dpa_cmd_add_acl_ip(key, mask, flow_tlvs); + of_dpa_cmd_add_acl_ip(key, mask, flow_tlvs); break; } - if (err) { - return err; - } - if (flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]) { action->write.group_id = rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]); diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c index 03a204e..654a087 100644 --- a/hw/net/rtl8139.c +++ b/hw/net/rtl8139.c @@ -48,20 +48,18 @@ * 2011-Mar-22 Benjamin Poirier: Implemented VLAN offloading */ -/* For crc32 */ - #include "qemu/osdep.h" -#include <zlib.h> +#include <zlib.h> /* for crc32 */ #include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" -#include "sysemu/dma.h" +#include "system/dma.h" #include "qemu/module.h" #include "qemu/timer.h" #include "net/net.h" #include "net/eth.h" -#include "sysemu/sysemu.h" +#include "system/system.h" #include "qom/object.h" /* debug RTL8139 card */ @@ -1818,7 +1816,7 @@ static int rtl8139_transmit_one(RTL8139State *s, int descriptor) PCIDevice *d = PCI_DEVICE(s); int txsize = s->TxStatus[descriptor] & 0x1fff; - uint8_t txbuffer[0x2000]; + QEMU_UNINITIALIZED uint8_t txbuffer[0x2000]; DPRINTF("+++ transmit reading %d bytes from host memory at 0x%08x\n", txsize, s->TxAddr[descriptor]); @@ -3412,12 +3410,11 @@ static void rtl8139_instance_init(Object *obj) DEVICE(obj)); } -static Property rtl8139_properties[] = { +static const Property rtl8139_properties[] = { DEFINE_NIC_PROPERTIES(RTL8139State, conf), - DEFINE_PROP_END_OF_LIST(), }; -static void rtl8139_class_init(ObjectClass *klass, void *data) +static void rtl8139_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -3429,7 +3426,7 @@ static void rtl8139_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_REALTEK_8139; k->revision = RTL8139_PCI_REVID; /* >=0x20 is for 8139C+ */ k->class_id = PCI_CLASS_NETWORK_ETHERNET; - dc->reset = rtl8139_reset; + device_class_set_legacy_reset(dc, rtl8139_reset); dc->vmsd = &vmstate_rtl8139; device_class_set_props(dc, rtl8139_properties); set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); @@ -3441,7 +3438,7 @@ static const TypeInfo rtl8139_info = { .instance_size = sizeof(RTL8139State), .class_init = rtl8139_class_init, .instance_init = rtl8139_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/net/smc91c111.c b/hw/net/smc91c111.c index 702d0e8..5cd78e3 100644 --- a/hw/net/smc91c111.c +++ b/hw/net/smc91c111.c @@ -13,16 +13,23 @@ #include "net/net.h" #include "hw/irq.h" #include "hw/net/smc91c111.h" +#include "hw/registerfields.h" #include "hw/qdev-properties.h" #include "qapi/error.h" #include "qemu/log.h" #include "qemu/module.h" -/* For crc32 */ -#include <zlib.h> +#include <zlib.h> /* for crc32 */ #include "qom/object.h" /* Number of 2k memory pages available. */ #define NUM_PACKETS 4 +/* + * Maximum size of a data frame, including the leading status word + * and byte count fields and the trailing CRC, last data byte + * and control byte (per figure 8-1 in the Microchip Technology + * LAN91C111 datasheet). + */ +#define MAX_PACKET_SIZE 2048 #define TYPE_SMC91C111 "smc91c111" OBJECT_DECLARE_SIMPLE_TYPE(smc91c111_state, SMC91C111) @@ -52,7 +59,7 @@ struct smc91c111_state { int tx_fifo_done_len; int tx_fifo_done[NUM_PACKETS]; /* Packet buffer memory. */ - uint8_t data[NUM_PACKETS][2048]; + uint8_t data[NUM_PACKETS][MAX_PACKET_SIZE]; uint8_t int_level; uint8_t int_mask; MemoryRegion mmio; @@ -80,7 +87,8 @@ static const VMStateDescription vmstate_smc91c111 = { VMSTATE_INT32_ARRAY(rx_fifo, smc91c111_state, NUM_PACKETS), VMSTATE_INT32(tx_fifo_done_len, smc91c111_state), VMSTATE_INT32_ARRAY(tx_fifo_done, smc91c111_state, NUM_PACKETS), - VMSTATE_BUFFER_UNSAFE(data, smc91c111_state, 0, NUM_PACKETS * 2048), + VMSTATE_BUFFER_UNSAFE(data, smc91c111_state, 0, + NUM_PACKETS * MAX_PACKET_SIZE), VMSTATE_UINT8(int_level, smc91c111_state), VMSTATE_UINT8(int_mask, smc91c111_state), VMSTATE_END_OF_LIST() @@ -119,6 +127,18 @@ static const VMStateDescription vmstate_smc91c111 = { #define RS_TOOSHORT 0x0400 #define RS_MULTICAST 0x0001 +FIELD(PTR, PTR, 0, 11) +FIELD(PTR, NOT_EMPTY, 11, 1) +FIELD(PTR, RESERVED, 12, 1) +FIELD(PTR, READ, 13, 1) +FIELD(PTR, AUTOINCR, 14, 1) +FIELD(PTR, RCV, 15, 1) + +static inline bool packetnum_valid(int packet_num) +{ + return packet_num >= 0 && packet_num < NUM_PACKETS; +} + /* Update interrupt status. */ static void smc91c111_update(smc91c111_state *s) { @@ -183,6 +203,15 @@ static void smc91c111_pop_rx_fifo(smc91c111_state *s) { int i; + if (s->rx_fifo_len == 0) { + /* + * The datasheet doesn't document what the behaviour is if the + * guest tries to pop an empty RX FIFO, and there's no obvious + * error status register to report it. Just ignore the attempt. + */ + return; + } + s->rx_fifo_len--; if (s->rx_fifo_len) { for (i = 0; i < s->rx_fifo_len; i++) @@ -210,12 +239,33 @@ static void smc91c111_pop_tx_fifo_done(smc91c111_state *s) /* Release the memory allocated to a packet. */ static void smc91c111_release_packet(smc91c111_state *s, int packet) { + if (!packetnum_valid(packet)) { + /* + * Data sheet doesn't document behaviour in this guest error + * case, and there is no error status register to report it. + * Log and ignore the attempt. + */ + qemu_log_mask(LOG_GUEST_ERROR, + "smc91c111: attempt to release invalid packet %d\n", + packet); + return; + } s->allocated &= ~(1 << packet); if (s->tx_alloc == 0x80) smc91c111_tx_alloc(s); smc91c111_flush_queued_packets(s); } +static void smc91c111_complete_tx_packet(smc91c111_state *s, int packetnum) +{ + if (s->ctr & CTR_AUTO_RELEASE) { + /* Race? */ + smc91c111_release_packet(s, packetnum); + } else if (s->tx_fifo_done_len < NUM_PACKETS) { + s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum; + } +} + /* Flush the TX FIFO. */ static void smc91c111_do_tx(smc91c111_state *s) { @@ -231,12 +281,25 @@ static void smc91c111_do_tx(smc91c111_state *s) return; for (i = 0; i < s->tx_fifo_len; i++) { packetnum = s->tx_fifo[i]; + /* queue_tx checked the packet number was valid */ + assert(packetnum_valid(packetnum)); p = &s->data[packetnum][0]; /* Set status word. */ *(p++) = 0x01; *(p++) = 0x40; len = *(p++); len |= ((int)*(p++)) << 8; + if (len > MAX_PACKET_SIZE) { + /* + * Datasheet doesn't say what to do here, and there is no + * relevant tx error condition listed. Log, and drop the packet. + */ + qemu_log_mask(LOG_GUEST_ERROR, + "smc91c111: tx packet with bad length %d, dropping\n", + len); + smc91c111_complete_tx_packet(s, packetnum); + continue; + } len -= 6; control = p[len + 1]; if (control & 0x20) @@ -265,11 +328,7 @@ static void smc91c111_do_tx(smc91c111_state *s) } } #endif - if (s->ctr & CTR_AUTO_RELEASE) - /* Race? */ - smc91c111_release_packet(s, packetnum); - else if (s->tx_fifo_done_len < NUM_PACKETS) - s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum; + smc91c111_complete_tx_packet(s, packetnum); qemu_send_packet(qemu_get_queue(s->nic), p, len); } s->tx_fifo_len = 0; @@ -279,6 +338,17 @@ static void smc91c111_do_tx(smc91c111_state *s) /* Add a packet to the TX FIFO. */ static void smc91c111_queue_tx(smc91c111_state *s, int packet) { + if (!packetnum_valid(packet)) { + /* + * Datasheet doesn't document behaviour in this error case, and + * there's no error status register we could report it in. + * Log and ignore. + */ + qemu_log_mask(LOG_GUEST_ERROR, + "smc91c111: attempt to queue invalid packet %d\n", + packet); + return; + } if (s->tx_fifo_len == NUM_PACKETS) return; s->tx_fifo[s->tx_fifo_len++] = packet; @@ -310,6 +380,49 @@ static void smc91c111_reset(DeviceState *dev) #define SET_LOW(name, val) s->name = (s->name & 0xff00) | val #define SET_HIGH(name, val) s->name = (s->name & 0xff) | (val << 8) +/* + * The pointer register's pointer is an 11 bit value (so it exactly + * indexes a 2048-byte data frame). Add the specified offset to it, + * wrapping around at the 2048 byte mark, and return the resulting + * wrapped value. There are flag bits in the top part of the register, + * but we can ignore them here as the mask will mask them out. + */ +static int ptr_reg_add(smc91c111_state *s, int offset) +{ + return (s->ptr + offset) & R_PTR_PTR_MASK; +} + +/* + * For an access to the Data Register at @offset, return the + * required offset into the packet's data frame. This will + * perform the pointer register autoincrement if required, and + * guarantees to return an in-bounds offset. + */ +static int data_reg_ptr(smc91c111_state *s, int offset) +{ + int p; + + if (s->ptr & R_PTR_AUTOINCR_MASK) { + /* + * Autoincrement: use the current pointer value, and + * increment the pointer register's pointer field. + */ + p = FIELD_EX32(s->ptr, PTR, PTR); + s->ptr = FIELD_DP32(s->ptr, PTR, PTR, ptr_reg_add(s, 1)); + } else { + /* + * No autoincrement: register offset determines which + * byte we're addressing. Setting the pointer to the top + * of the data buffer and then using the pointer wrapping + * to read the bottom byte of the buffer is not something + * sensible guest software will do, but the datasheet + * doesn't say what the behaviour is, so we don't forbid it. + */ + p = ptr_reg_add(s, offset & 3); + } + return p; +} + static void smc91c111_writeb(void *opaque, hwaddr offset, uint32_t value) { @@ -449,12 +562,14 @@ static void smc91c111_writeb(void *opaque, hwaddr offset, n = s->rx_fifo[0]; else n = s->packet_num; - p = s->ptr & 0x07ff; - if (s->ptr & 0x4000) { - s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x7ff); - } else { - p += (offset & 3); + if (!packetnum_valid(n)) { + /* Datasheet doesn't document what to do here */ + qemu_log_mask(LOG_GUEST_ERROR, + "smc91c111: attempt to write data to invalid packet %d\n", + n); + return; } + p = data_reg_ptr(s, offset); s->data[n][p] = value; } return; @@ -597,12 +712,14 @@ static uint32_t smc91c111_readb(void *opaque, hwaddr offset) n = s->rx_fifo[0]; else n = s->packet_num; - p = s->ptr & 0x07ff; - if (s->ptr & 0x4000) { - s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x07ff); - } else { - p += (offset & 3); + if (!packetnum_valid(n)) { + /* Datasheet doesn't document what to do here */ + qemu_log_mask(LOG_GUEST_ERROR, + "smc91c111: attempt to read data from invalid packet %d\n", + n); + return 0; } + p = data_reg_ptr(s, offset); return s->data[n][p]; } case 12: /* Interrupt status. */ @@ -698,13 +815,16 @@ static ssize_t smc91c111_receive(NetClientState *nc, const uint8_t *buf, size_t if (crc) packetsize += 4; /* TODO: Flag overrun and receive errors. */ - if (packetsize > 2048) + if (packetsize > MAX_PACKET_SIZE) { return -1; + } packetnum = smc91c111_allocate_packet(s); if (packetnum == 0x80) return -1; s->rx_fifo[s->rx_fifo_len++] = packetnum; + /* allocate_packet() will not hand us back an invalid packet number */ + assert(packetnum_valid(packetnum)); p = &s->data[packetnum][0]; /* ??? Multicast packets? */ status = 0; @@ -789,17 +909,16 @@ static void smc91c111_realize(DeviceState *dev, Error **errp) /* ??? Save/restore. */ } -static Property smc91c111_properties[] = { +static const Property smc91c111_properties[] = { DEFINE_NIC_PROPERTIES(smc91c111_state, conf), - DEFINE_PROP_END_OF_LIST(), }; -static void smc91c111_class_init(ObjectClass *klass, void *data) +static void smc91c111_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = smc91c111_realize; - dc->reset = smc91c111_reset; + device_class_set_legacy_reset(dc, smc91c111_reset); dc->vmsd = &vmstate_smc91c111; device_class_set_props(dc, smc91c111_properties); } diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c index 8af33d9..f6f217d 100644 --- a/hw/net/spapr_llan.c +++ b/hw/net/spapr_llan.c @@ -33,7 +33,7 @@ #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" #include "hw/qdev-properties.h" -#include "sysemu/sysemu.h" +#include "system/system.h" #include "trace.h" #include <libfdt.h> @@ -786,12 +786,11 @@ static target_ulong h_change_logical_lan_mac(PowerPCCPU *cpu, return H_SUCCESS; } -static Property spapr_vlan_properties[] = { +static const Property spapr_vlan_properties[] = { DEFINE_SPAPR_PROPERTIES(SpaprVioVlan, sdev), DEFINE_NIC_PROPERTIES(SpaprVioVlan, nicconf), DEFINE_PROP_BIT("use-rx-buffer-pools", SpaprVioVlan, compat_flags, SPAPRVLAN_FLAG_RX_BUF_POOLS_BIT, true), - DEFINE_PROP_END_OF_LIST(), }; static bool spapr_vlan_rx_buffer_pools_needed(void *opaque) @@ -849,7 +848,7 @@ static const VMStateDescription vmstate_spapr_llan = { } }; -static void spapr_vlan_class_init(ObjectClass *klass, void *data) +static void spapr_vlan_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass); diff --git a/hw/net/stellaris_enet.c b/hw/net/stellaris_enet.c index db95766..2fc51e1 100644 --- a/hw/net/stellaris_enet.c +++ b/hw/net/stellaris_enet.c @@ -15,7 +15,7 @@ #include "net/net.h" #include "qemu/log.h" #include "qemu/module.h" -#include <zlib.h> +#include <zlib.h> /* for crc32 */ #include "qom/object.h" //#define DEBUG_STELLARIS_ENET 1 @@ -497,17 +497,16 @@ static void stellaris_enet_realize(DeviceState *dev, Error **errp) qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); } -static Property stellaris_enet_properties[] = { +static const Property stellaris_enet_properties[] = { DEFINE_NIC_PROPERTIES(stellaris_enet_state, conf), - DEFINE_PROP_END_OF_LIST(), }; -static void stellaris_enet_class_init(ObjectClass *klass, void *data) +static void stellaris_enet_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = stellaris_enet_realize; - dc->reset = stellaris_enet_reset; + device_class_set_legacy_reset(dc, stellaris_enet_reset); device_class_set_props(dc, stellaris_enet_properties); dc->vmsd = &vmstate_stellaris_enet; } diff --git a/hw/net/sungem.c b/hw/net/sungem.c index dd1b4a1..b405eb8 100644 --- a/hw/net/sungem.c +++ b/hw/net/sungem.c @@ -17,7 +17,7 @@ #include "net/eth.h" #include "net/checksum.h" #include "hw/net/mii.h" -#include "sysemu/sysemu.h" +#include "system/system.h" #include "trace.h" #include "qom/object.h" @@ -1420,14 +1420,13 @@ static void sungem_instance_init(Object *obj) DEVICE(obj)); } -static Property sungem_properties[] = { +static const Property sungem_properties[] = { DEFINE_NIC_PROPERTIES(SunGEMState, conf), /* Phy address should be 0 for most Apple machines except * for K2 in which case it's 1. Will be set by a machine * override. */ DEFINE_PROP_UINT32("phy_addr", SunGEMState, phy_addr, 0), - DEFINE_PROP_END_OF_LIST(), }; static const VMStateDescription vmstate_sungem = { @@ -1455,7 +1454,7 @@ static const VMStateDescription vmstate_sungem = { } }; -static void sungem_class_init(ObjectClass *klass, void *data) +static void sungem_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -1467,7 +1466,7 @@ static void sungem_class_init(ObjectClass *klass, void *data) k->revision = 0x01; k->class_id = PCI_CLASS_NETWORK_ETHERNET; dc->vmsd = &vmstate_sungem; - dc->reset = sungem_reset; + device_class_set_legacy_reset(dc, sungem_reset); device_class_set_props(dc, sungem_properties); set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); } @@ -1478,7 +1477,7 @@ static const TypeInfo sungem_info = { .instance_size = sizeof(SunGEMState), .class_init = sungem_class_init, .instance_init = sungem_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { } } diff --git a/hw/net/sunhme.c b/hw/net/sunhme.c index ae8452e..c2f7a84 100644 --- a/hw/net/sunhme.c +++ b/hw/net/sunhme.c @@ -31,7 +31,7 @@ #include "qemu/module.h" #include "net/checksum.h" #include "net/eth.h" -#include "sysemu/sysemu.h" +#include "system/system.h" #include "trace.h" #include "qom/object.h" @@ -177,9 +177,8 @@ struct SunHMEState { uint16_t miiregs[HME_MII_REGS_SIZE]; }; -static Property sunhme_properties[] = { +static const Property sunhme_properties[] = { DEFINE_NIC_PROPERTIES(SunHMEState, conf), - DEFINE_PROP_END_OF_LIST(), }; static void sunhme_reset_tx(SunHMEState *s) @@ -938,7 +937,7 @@ static const VMStateDescription vmstate_hme = { } }; -static void sunhme_class_init(ObjectClass *klass, void *data) +static void sunhme_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -948,7 +947,7 @@ static void sunhme_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_SUN_HME; k->class_id = PCI_CLASS_NETWORK_ETHERNET; dc->vmsd = &vmstate_hme; - dc->reset = sunhme_reset; + device_class_set_legacy_reset(dc, sunhme_reset); device_class_set_props(dc, sunhme_properties); set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); } @@ -959,7 +958,7 @@ static const TypeInfo sunhme_info = { .class_init = sunhme_class_init, .instance_size = sizeof(SunHMEState), .instance_init = sunhme_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { } } diff --git a/hw/net/trace-events b/hw/net/trace-events index 78efa2e..72b69c4 100644 --- a/hw/net/trace-events +++ b/hw/net/trace-events @@ -10,10 +10,11 @@ allwinner_sun8i_emac_set_link(bool active) "Set link: active=%u" allwinner_sun8i_emac_read(uint64_t offset, uint64_t val) "MMIO read: offset=0x%" PRIx64 " value=0x%" PRIx64 allwinner_sun8i_emac_write(uint64_t offset, uint64_t val) "MMIO write: offset=0x%" PRIx64 " value=0x%" PRIx64 -# etraxfs_eth.c -mdio_phy_read(int regnum, uint16_t value) "read phy_reg:%d value:0x%04x" -mdio_phy_write(int regnum, uint16_t value) "write phy_reg:%d value:0x%04x" -mdio_bitbang(bool mdc, bool mdio, int state, uint16_t cnt, unsigned int drive) "bitbang mdc=%u mdio=%u state=%d cnt=%u drv=%d" +# lan9118_phy.c +lan9118_phy_read(uint16_t val, int reg) "[0x%02x] -> 0x%04" PRIx16 +lan9118_phy_write(uint16_t val, int reg) "[0x%02x] <- 0x%04" PRIx16 +lan9118_phy_update_link(const char *s) "%s" +lan9118_phy_reset(void) "" # lance.c lance_mem_readw(uint64_t addr, uint32_t ret) "addr=0x%"PRIx64"val=0x%04x" @@ -399,9 +400,11 @@ virtio_net_announce_notify(void) "" virtio_net_announce_timer(int round) "%d" virtio_net_handle_announce(int round) "%d" virtio_net_post_load_device(void) -virtio_net_rss_disable(void) -virtio_net_rss_error(const char *msg, uint32_t value) "%s, value 0x%08x" -virtio_net_rss_enable(uint32_t p1, uint16_t p2, uint8_t p3) "hashes 0x%x, table of %d, key of %d" +virtio_net_rss_load(void *nic, size_t nfds, void *fds) "nic=%p nfds=%zu fds=%p" +virtio_net_rss_attach_ebpf(void *nic, int prog_fd) "nic=%p prog-fd=%d" +virtio_net_rss_disable(void *nic) "nic=%p" +virtio_net_rss_error(void *nic, const char *msg, uint32_t value) "nic=%p msg=%s, value 0x%08x" +virtio_net_rss_enable(void *nic, uint32_t p1, uint16_t p2, uint8_t p3) "nic=%p hashes 0x%x, table of %d, key of %d" # tulip.c tulip_reg_write(uint64_t addr, const char *name, int size, uint64_t val) "addr 0x%02"PRIx64" (%s) size %d value 0x%08"PRIx64 @@ -431,12 +434,8 @@ i82596_set_multicast(uint16_t count) "Added %d multicast entries" i82596_channel_attention(void *s) "%p: Received CHANNEL ATTENTION" # imx_fec.c -imx_phy_read(uint32_t val, int phy, int reg) "0x%04"PRIx32" <= phy[%d].reg[%d]" imx_phy_read_num(int phy, int configured) "read request from unconfigured phy %d (configured %d)" -imx_phy_write(uint32_t val, int phy, int reg) "0x%04"PRIx32" => phy[%d].reg[%d]" imx_phy_write_num(int phy, int configured) "write request to unconfigured phy %d (configured %d)" -imx_phy_update_link(const char *s) "%s" -imx_phy_reset(void) "" imx_fec_read_bd(uint64_t addr, int flags, int len, int data) "tx_bd 0x%"PRIx64" flags 0x%04x len %d data 0x%08x" imx_enet_read_bd(uint64_t addr, int flags, int len, int data, int options, int status) "tx_bd 0x%"PRIx64" flags 0x%04x len %d data 0x%08x option 0x%04x status 0x%04x" imx_eth_tx_bd_busy(void) "tx_bd ran out of descriptors to transmit" @@ -481,10 +480,11 @@ npcm_gmac_packet_received(const char* name, uint32_t len) "%s: Reception finishe npcm_gmac_packet_sent(const char* name, uint16_t len) "%s: TX packet sent!, length: 0x%04" PRIX16 npcm_gmac_debug_desc_data(const char* name, void* addr, uint32_t des0, uint32_t des1, uint32_t des2, uint32_t des3)"%s: Address: %p Descriptor 0: 0x%04" PRIX32 " Descriptor 1: 0x%04" PRIX32 "Descriptor 2: 0x%04" PRIX32 " Descriptor 3: 0x%04" PRIX32 npcm_gmac_packet_tx_desc_data(const char* name, uint32_t tdes0, uint32_t tdes1) "%s: Tdes0: 0x%04" PRIX32 " Tdes1: 0x%04" PRIX32 +npcm_gmac_tx_desc_owner(const char* name, uint32_t desc_addr) "%s: TX Descriptor @0x%04" PRIX32 " is owned by software" # npcm_pcs.c -npcm_pcs_reg_read(const char *name, uint16_t indirect_access_baes, uint64_t offset, uint16_t value) "%s: IND: 0x%02" PRIx16 " offset: 0x%04" PRIx64 " value: 0x%04" PRIx16 -npcm_pcs_reg_write(const char *name, uint16_t indirect_access_baes, uint64_t offset, uint16_t value) "%s: IND: 0x%02" PRIx16 " offset: 0x%04" PRIx64 " value: 0x%04" PRIx16 +npcm_pcs_reg_read(const char *name, uint16_t indirect_access_base, uint64_t offset, uint16_t value) "%s: IND: 0x%02" PRIx16 " offset: 0x%04" PRIx64 " value: 0x%04" PRIx16 +npcm_pcs_reg_write(const char *name, uint16_t indirect_access_base, uint64_t offset, uint16_t value) "%s: IND: 0x%02" PRIx16 " offset: 0x%04" PRIx64 " value: 0x%04" PRIx16 # dp8398x.c dp8393x_raise_irq(int isr) "raise irq, isr is 0x%04x" @@ -513,3 +513,7 @@ xen_netdev_connect(int dev, unsigned int tx, unsigned int rx, int port) "vif%u t xen_netdev_frontend_changed(const char *dev, int state) "vif%s state %d" xen_netdev_tx(int dev, int ref, int off, int len, unsigned int flags, const char *c, const char *d, const char *m, const char *e) "vif%u ref %u off %u len %u flags 0x%x%s%s%s%s" xen_netdev_rx(int dev, int idx, int status, int flags) "vif%u idx %d status %d flags 0x%x" + +# xilinx_ethlite.c +ethlite_pkt_lost(uint32_t rx_ctrl) "rx_ctrl:0x%" PRIx32 +ethlite_pkt_size_too_big(uint64_t size) "size:0x%" PRIx64 diff --git a/hw/net/tulip.c b/hw/net/tulip.c index 1f2ef20..319af90 100644 --- a/hw/net/tulip.c +++ b/hw/net/tulip.c @@ -13,7 +13,7 @@ #include "hw/qdev-properties.h" #include "hw/nvram/eeprom93xx.h" #include "migration/vmstate.h" -#include "sysemu/sysemu.h" +#include "system/system.h" #include "tulip.h" #include "trace.h" #include "net/eth.h" @@ -629,7 +629,7 @@ static void tulip_setup_filter_addr(TULIPState *s, uint8_t *buf, int n) static void tulip_setup_frame(TULIPState *s, struct tulip_descriptor *desc) { - uint8_t buf[4096]; + QEMU_UNINITIALIZED uint8_t buf[4096]; int len = (desc->control >> TDES1_BUF1_SIZE_SHIFT) & TDES1_BUF1_SIZE_MASK; int i; @@ -1007,12 +1007,11 @@ static void tulip_instance_init(Object *obj) &pci_dev->qdev); } -static Property tulip_properties[] = { +static const Property tulip_properties[] = { DEFINE_NIC_PROPERTIES(TULIPState, c), - DEFINE_PROP_END_OF_LIST(), }; -static void tulip_class_init(ObjectClass *klass, void *data) +static void tulip_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -1026,7 +1025,7 @@ static void tulip_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_NETWORK_ETHERNET; dc->vmsd = &vmstate_pci_tulip; device_class_set_props(dc, tulip_properties); - dc->reset = tulip_qdev_reset; + device_class_set_legacy_reset(dc, tulip_qdev_reset); set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); } @@ -1036,7 +1035,7 @@ static const TypeInfo tulip_info = { .instance_size = sizeof(TULIPState), .class_init = tulip_class_init, .instance_init = tulip_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index dedf9ad..891f235 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -162,6 +162,148 @@ void vhost_net_save_acked_features(NetClientState *nc) #endif } +static void vhost_net_disable_notifiers_nvhosts(VirtIODevice *dev, + NetClientState *ncs, int data_queue_pairs, int nvhosts) +{ + VirtIONet *n = VIRTIO_NET(dev); + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev))); + struct vhost_net *net; + struct vhost_dev *hdev; + int r, i, j; + NetClientState *peer; + + /* + * Batch all the host notifiers in a single transaction to avoid + * quadratic time complexity in address_space_update_ioeventfds(). + */ + memory_region_transaction_begin(); + + for (i = 0; i < nvhosts; i++) { + if (i < data_queue_pairs) { + peer = qemu_get_peer(ncs, i); + } else { + peer = qemu_get_peer(ncs, n->max_queue_pairs); + } + + net = get_vhost_net(peer); + hdev = &net->dev; + for (j = 0; j < hdev->nvqs; j++) { + r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), + hdev->vq_index + j, + false); + if (r < 0) { + error_report("vhost %d VQ %d notifier cleanup failed: %d", + i, j, -r); + } + assert(r >= 0); + } + } + /* + * The transaction expects the ioeventfds to be open when it + * commits. Do it now, before the cleanup loop. + */ + memory_region_transaction_commit(); + + for (i = 0; i < nvhosts; i++) { + if (i < data_queue_pairs) { + peer = qemu_get_peer(ncs, i); + } else { + peer = qemu_get_peer(ncs, n->max_queue_pairs); + } + + net = get_vhost_net(peer); + hdev = &net->dev; + for (j = 0; j < hdev->nvqs; j++) { + virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), + hdev->vq_index + j); + } + virtio_device_release_ioeventfd(dev); + } +} + +static int vhost_net_enable_notifiers(VirtIODevice *dev, + NetClientState *ncs, int data_queue_pairs, int cvq) +{ + VirtIONet *n = VIRTIO_NET(dev); + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev))); + int nvhosts = data_queue_pairs + cvq; + struct vhost_net *net; + struct vhost_dev *hdev; + int r, i, j, k; + NetClientState *peer; + + /* + * We will pass the notifiers to the kernel, make sure that QEMU + * doesn't interfere. + */ + for (i = 0; i < nvhosts; i++) { + r = virtio_device_grab_ioeventfd(dev); + if (r < 0) { + error_report("vhost %d binding does not support host notifiers", i); + for (k = 0; k < i; k++) { + virtio_device_release_ioeventfd(dev); + } + return r; + } + } + + /* + * Batch all the host notifiers in a single transaction to avoid + * quadratic time complexity in address_space_update_ioeventfds(). + */ + memory_region_transaction_begin(); + + for (i = 0; i < nvhosts; i++) { + if (i < data_queue_pairs) { + peer = qemu_get_peer(ncs, i); + } else { + peer = qemu_get_peer(ncs, n->max_queue_pairs); + } + + net = get_vhost_net(peer); + hdev = &net->dev; + + for (j = 0; j < hdev->nvqs; j++) { + r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), + hdev->vq_index + j, + true); + if (r < 0) { + error_report("vhost %d VQ %d notifier binding failed: %d", + i, j, -r); + memory_region_transaction_commit(); + vhost_dev_disable_notifiers_nvqs(hdev, dev, j); + goto fail_nvhosts; + } + } + } + + memory_region_transaction_commit(); + + return 0; +fail_nvhosts: + vhost_net_disable_notifiers_nvhosts(dev, ncs, data_queue_pairs, i); + /* + * This for loop starts from i+1, not i, because the i-th ioeventfd + * has already been released in vhost_dev_disable_notifiers_nvqs(). + */ + for (k = i + 1; k < nvhosts; k++) { + virtio_device_release_ioeventfd(dev); + } + + return r; +} + +/* + * Stop processing guest IO notifications in qemu. + * Start processing them in vhost in kernel. + */ +static void vhost_net_disable_notifiers(VirtIODevice *dev, + NetClientState *ncs, int data_queue_pairs, int cvq) +{ + vhost_net_disable_notifiers_nvhosts(dev, ncs, data_queue_pairs, + data_queue_pairs + cvq); +} + static int vhost_net_get_fd(NetClientState *backend) { switch (backend->info->type) { @@ -272,11 +414,6 @@ static int vhost_net_start_one(struct vhost_net *net, } } - r = vhost_dev_enable_notifiers(&net->dev, dev); - if (r < 0) { - goto fail_notifiers; - } - r = vhost_dev_start(&net->dev, dev, false); if (r < 0) { goto fail_start; @@ -328,8 +465,6 @@ fail: } vhost_dev_stop(&net->dev, dev, false); fail_start: - vhost_dev_disable_notifiers(&net->dev, dev); -fail_notifiers: return r; } @@ -351,7 +486,6 @@ static void vhost_net_stop_one(struct vhost_net *net, if (net->nc->info->stop) { net->nc->info->stop(net->nc); } - vhost_dev_disable_notifiers(&net->dev, dev); } int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, @@ -396,10 +530,16 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, } } + r = vhost_net_enable_notifiers(dev, ncs, data_queue_pairs, cvq); + if (r < 0) { + error_report("Error enabling host notifiers: %d", -r); + goto err; + } + r = k->set_guest_notifiers(qbus->parent, total_notifiers, true); if (r < 0) { error_report("Error binding guest notifier: %d", -r); - goto err; + goto err_host_notifiers; } for (i = 0; i < nvhosts; i++) { @@ -414,19 +554,19 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, r = vhost_set_vring_enable(peer, peer->vring_enable); if (r < 0) { - goto err_start; + goto err_guest_notifiers; } } r = vhost_net_start_one(get_vhost_net(peer), dev); if (r < 0) { - goto err_start; + goto err_guest_notifiers; } } return 0; -err_start: +err_guest_notifiers: while (--i >= 0) { peer = qemu_get_peer(ncs, i < data_queue_pairs ? i : n->max_queue_pairs); @@ -437,6 +577,8 @@ err_start: fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", e); fflush(stderr); } +err_host_notifiers: + vhost_net_disable_notifiers(dev, ncs, data_queue_pairs, cvq); err: return r; } @@ -468,6 +610,8 @@ void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs, fflush(stderr); } assert(r >= 0); + + vhost_net_disable_notifiers(dev, ncs, data_queue_pairs, cvq); } void vhost_net_cleanup(struct vhost_net *net) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index ed33a32..eb93607 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -26,7 +26,7 @@ #include "qemu/option.h" #include "qemu/option_int.h" #include "qemu/config-file.h" -#include "qapi/qmp/qdict.h" +#include "qobject/qdict.h" #include "hw/virtio/virtio-net.h" #include "net/vhost_net.h" #include "net/announce.h" @@ -39,15 +39,15 @@ #include "hw/virtio/virtio-access.h" #include "migration/misc.h" #include "standard-headers/linux/ethtool.h" -#include "sysemu/sysemu.h" -#include "sysemu/replay.h" +#include "system/system.h" +#include "system/replay.h" #include "trace.h" #include "monitor/qdev.h" #include "monitor/monitor.h" #include "hw/pci/pci_device.h" #include "net_rx_pkt.h" #include "hw/virtio/vhost.h" -#include "sysemu/qtest.h" +#include "system/qtest.h" #define VIRTIO_NET_VM_VERSION 11 @@ -382,7 +382,7 @@ static void virtio_net_drop_tx_queue_data(VirtIODevice *vdev, VirtQueue *vq) } } -static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status) +static int virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status) { VirtIONet *n = VIRTIO_NET(vdev); VirtIONetQueue *q; @@ -437,6 +437,7 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status) } } } + return 0; } static void virtio_net_set_link_status(NetClientState *nc) @@ -1241,6 +1242,7 @@ static bool virtio_net_attach_ebpf_to_backend(NICState *nic, int prog_fd) return false; } + trace_virtio_net_rss_attach_ebpf(nic, prog_fd); return nc->info->set_steering_ebpf(nc, prog_fd); } @@ -1254,7 +1256,7 @@ static void rss_data_to_rss_config(struct VirtioNetRssData *data, config->default_queue = data->default_queue; } -static bool virtio_net_attach_epbf_rss(VirtIONet *n) +static bool virtio_net_attach_ebpf_rss(VirtIONet *n) { struct EBPFRSSConfig config = {}; @@ -1265,7 +1267,8 @@ static bool virtio_net_attach_epbf_rss(VirtIONet *n) rss_data_to_rss_config(&n->rss_data, &config); if (!ebpf_rss_set_all(&n->ebpf_rss, &config, - n->rss_data.indirections_table, n->rss_data.key)) { + n->rss_data.indirections_table, n->rss_data.key, + NULL)) { return false; } @@ -1276,7 +1279,7 @@ static bool virtio_net_attach_epbf_rss(VirtIONet *n) return true; } -static void virtio_net_detach_epbf_rss(VirtIONet *n) +static void virtio_net_detach_ebpf_rss(VirtIONet *n) { virtio_net_attach_ebpf_to_backend(n->nic, -1); } @@ -1286,8 +1289,8 @@ static void virtio_net_commit_rss_config(VirtIONet *n) if (n->rss_data.enabled) { n->rss_data.enabled_software_rss = n->rss_data.populate_hash; if (n->rss_data.populate_hash) { - virtio_net_detach_epbf_rss(n); - } else if (!virtio_net_attach_epbf_rss(n)) { + virtio_net_detach_ebpf_rss(n); + } else if (!virtio_net_attach_ebpf_rss(n)) { if (get_vhost_net(qemu_get_queue(n->nic)->peer)) { warn_report("Can't load eBPF RSS for vhost"); } else { @@ -1296,12 +1299,13 @@ static void virtio_net_commit_rss_config(VirtIONet *n) } } - trace_virtio_net_rss_enable(n->rss_data.hash_types, + trace_virtio_net_rss_enable(n, + n->rss_data.hash_types, n->rss_data.indirections_len, sizeof(n->rss_data.key)); } else { - virtio_net_detach_epbf_rss(n); - trace_virtio_net_rss_disable(); + virtio_net_detach_ebpf_rss(n); + trace_virtio_net_rss_disable(n); } } @@ -1315,28 +1319,27 @@ static void virtio_net_disable_rss(VirtIONet *n) virtio_net_commit_rss_config(n); } -static bool virtio_net_load_ebpf_fds(VirtIONet *n) +static bool virtio_net_load_ebpf_fds(VirtIONet *n, Error **errp) { int fds[EBPF_RSS_MAX_FDS] = { [0 ... EBPF_RSS_MAX_FDS - 1] = -1}; int ret = true; int i = 0; if (n->nr_ebpf_rss_fds != EBPF_RSS_MAX_FDS) { - warn_report("Expected %d file descriptors but got %d", - EBPF_RSS_MAX_FDS, n->nr_ebpf_rss_fds); - return false; - } + error_setg(errp, "Expected %d file descriptors but got %d", + EBPF_RSS_MAX_FDS, n->nr_ebpf_rss_fds); + return false; + } for (i = 0; i < n->nr_ebpf_rss_fds; i++) { - fds[i] = monitor_fd_param(monitor_cur(), n->ebpf_rss_fds[i], - &error_warn); + fds[i] = monitor_fd_param(monitor_cur(), n->ebpf_rss_fds[i], errp); if (fds[i] < 0) { ret = false; goto exit; } } - ret = ebpf_rss_load_fds(&n->ebpf_rss, fds[0], fds[1], fds[2], fds[3]); + ret = ebpf_rss_load_fds(&n->ebpf_rss, fds[0], fds[1], fds[2], fds[3], errp); exit: if (!ret) { @@ -1348,17 +1351,27 @@ exit: return ret; } -static bool virtio_net_load_ebpf(VirtIONet *n) +static bool virtio_net_load_ebpf(VirtIONet *n, Error **errp) { - bool ret = false; + if (!virtio_net_attach_ebpf_to_backend(n->nic, -1)) { + return true; + } - if (virtio_net_attach_ebpf_to_backend(n->nic, -1)) { - if (!(n->ebpf_rss_fds && virtio_net_load_ebpf_fds(n))) { - ret = ebpf_rss_load(&n->ebpf_rss); - } + trace_virtio_net_rss_load(n, n->nr_ebpf_rss_fds, n->ebpf_rss_fds); + + /* + * If user explicitly gave QEMU RSS FDs to use, then + * failing to use them must be considered a fatal + * error. If no RSS FDs were provided, QEMU is trying + * eBPF on a "best effort" basis only, so report a + * warning and allow fallback to software RSS. + */ + if (n->ebpf_rss_fds) { + return virtio_net_load_ebpf_fds(n, errp); } - return ret; + ebpf_rss_load(&n->ebpf_rss, &error_warn); + return true; } static void virtio_net_unload_ebpf(VirtIONet *n) @@ -1401,17 +1414,17 @@ static uint16_t virtio_net_handle_rss(VirtIONet *n, n->rss_data.hash_types = virtio_ldl_p(vdev, &cfg.hash_types); n->rss_data.indirections_len = virtio_lduw_p(vdev, &cfg.indirection_table_mask); - n->rss_data.indirections_len++; if (!do_rss) { - n->rss_data.indirections_len = 1; + n->rss_data.indirections_len = 0; } - if (!is_power_of_2(n->rss_data.indirections_len)) { - err_msg = "Invalid size of indirection table"; + if (n->rss_data.indirections_len >= VIRTIO_NET_RSS_MAX_TABLE_LEN) { + err_msg = "Too large indirection table"; err_value = n->rss_data.indirections_len; goto error; } - if (n->rss_data.indirections_len > VIRTIO_NET_RSS_MAX_TABLE_LEN) { - err_msg = "Too large indirection table"; + n->rss_data.indirections_len++; + if (!is_power_of_2(n->rss_data.indirections_len)) { + err_msg = "Invalid size of indirection table"; err_value = n->rss_data.indirections_len; goto error; } @@ -1482,7 +1495,7 @@ static uint16_t virtio_net_handle_rss(VirtIONet *n, virtio_net_commit_rss_config(n); return queue_pairs; error: - trace_virtio_net_rss_error(err_msg, err_value); + trace_virtio_net_rss_error(n, err_msg, err_value); virtio_net_disable_rss(n); return 0; } @@ -1692,8 +1705,11 @@ static void virtio_net_hdr_swap(VirtIODevice *vdev, struct virtio_net_hdr *hdr) static void work_around_broken_dhclient(struct virtio_net_hdr *hdr, uint8_t *buf, size_t size) { + size_t csum_size = ETH_HLEN + sizeof(struct ip_header) + + sizeof(struct udp_header); + if ((hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && /* missing csum */ - (size > 27 && size < 1500) && /* normal sized MTU */ + (size >= csum_size && size < 1500) && /* normal sized MTU */ (buf[12] == 0x08 && buf[13] == 0x00) && /* ethertype == IPv4 */ (buf[23] == 17) && /* ip.protocol == UDP */ (buf[34] == 0 && buf[35] == 67)) { /* udp.srcport == bootps */ @@ -1890,32 +1906,34 @@ static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf, } static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, - size_t size, bool no_rss) + size_t size) { VirtIONet *n = qemu_get_nic_opaque(nc); - VirtIONetQueue *q = virtio_net_get_subqueue(nc); + VirtIONetQueue *q; VirtIODevice *vdev = VIRTIO_DEVICE(n); - VirtQueueElement *elems[VIRTQUEUE_MAX_SIZE]; - size_t lens[VIRTQUEUE_MAX_SIZE]; - struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE]; + QEMU_UNINITIALIZED VirtQueueElement *elems[VIRTQUEUE_MAX_SIZE]; + QEMU_UNINITIALIZED size_t lens[VIRTQUEUE_MAX_SIZE]; + QEMU_UNINITIALIZED struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE]; struct virtio_net_hdr_v1_hash extra_hdr; unsigned mhdr_cnt = 0; size_t offset, i, guest_offset, j; ssize_t err; - if (!virtio_net_can_receive(nc)) { - return -1; - } + memset(&extra_hdr, 0, sizeof(extra_hdr)); - if (!no_rss && n->rss_data.enabled && n->rss_data.enabled_software_rss) { + if (n->rss_data.enabled && n->rss_data.enabled_software_rss) { int index = virtio_net_process_rss(nc, buf, size, &extra_hdr); if (index >= 0) { - NetClientState *nc2 = - qemu_get_subqueue(n->nic, index % n->curr_queue_pairs); - return virtio_net_receive_rcu(nc2, buf, size, true); + nc = qemu_get_subqueue(n->nic, index % n->curr_queue_pairs); } } + if (!virtio_net_can_receive(nc)) { + return -1; + } + + q = virtio_net_get_subqueue(nc); + /* hdr_len refers to the header we supply to the guest */ if (!virtio_net_has_buffers(q, size + n->guest_hdr_len - n->host_hdr_len)) { return 0; @@ -1971,6 +1989,8 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, sg, elem->in_num, offsetof(typeof(extra_hdr), hdr.num_buffers), sizeof(extra_hdr.hdr.num_buffers)); + } else { + extra_hdr.hdr.num_buffers = cpu_to_le16(1); } receive_header(n, sg, elem->in_num, buf, size); @@ -2041,7 +2061,22 @@ static ssize_t virtio_net_do_receive(NetClientState *nc, const uint8_t *buf, { RCU_READ_LOCK_GUARD(); - return virtio_net_receive_rcu(nc, buf, size, false); + return virtio_net_receive_rcu(nc, buf, size); +} + +/* + * Accessors to read and write the IP packet data length field. This + * is a potentially unaligned network-byte-order 16 bit unsigned integer + * pointed to by unit->ip_len. + */ +static uint16_t read_unit_ip_len(VirtioNetRscUnit *unit) +{ + return lduw_be_p(unit->ip_plen); +} + +static void write_unit_ip_len(VirtioNetRscUnit *unit, uint16_t l) +{ + stw_be_p(unit->ip_plen, l); } static void virtio_net_rsc_extract_unit4(VirtioNetRscChain *chain, @@ -2058,7 +2093,7 @@ static void virtio_net_rsc_extract_unit4(VirtioNetRscChain *chain, unit->ip_plen = &ip->ip_len; unit->tcp = (struct tcp_header *)(((uint8_t *)unit->ip) + ip_hdrlen); unit->tcp_hdrlen = (htons(unit->tcp->th_offset_flags) & 0xF000) >> 10; - unit->payload = htons(*unit->ip_plen) - ip_hdrlen - unit->tcp_hdrlen; + unit->payload = read_unit_ip_len(unit) - ip_hdrlen - unit->tcp_hdrlen; } static void virtio_net_rsc_extract_unit6(VirtioNetRscChain *chain, @@ -2077,7 +2112,7 @@ static void virtio_net_rsc_extract_unit6(VirtioNetRscChain *chain, /* There is a difference between payload length in ipv4 and v6, ip header is excluded in ipv6 */ - unit->payload = htons(*unit->ip_plen) - unit->tcp_hdrlen; + unit->payload = read_unit_ip_len(unit) - unit->tcp_hdrlen; } static size_t virtio_net_rsc_drain_seg(VirtioNetRscChain *chain, @@ -2226,7 +2261,7 @@ static int32_t virtio_net_rsc_coalesce_data(VirtioNetRscChain *chain, VirtioNetRscUnit *o_unit; o_unit = &seg->unit; - o_ip_len = htons(*o_unit->ip_plen); + o_ip_len = read_unit_ip_len(o_unit); nseq = htonl(n_unit->tcp->th_seq); oseq = htonl(o_unit->tcp->th_seq); @@ -2262,7 +2297,7 @@ coalesce: o_unit->payload += n_unit->payload; /* update new data len */ /* update field in ip header */ - *o_unit->ip_plen = htons(o_ip_len + n_unit->payload); + write_unit_ip_len(o_unit, o_ip_len + n_unit->payload); /* Bring 'PUSH' big, the whql test guide says 'PUSH' can be coalesced for windows guest, while this may change the behavior for linux @@ -3032,6 +3067,15 @@ static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue) virtio_net_set_queue_pairs(n); } +static int virtio_net_pre_load_queues(VirtIODevice *vdev) +{ + virtio_net_set_multiqueue(VIRTIO_NET(vdev), + virtio_has_feature(vdev->guest_features, VIRTIO_NET_F_RSS) || + virtio_has_feature(vdev->guest_features, VIRTIO_NET_F_MQ)); + + return 0; +} + static int virtio_net_post_load_device(void *opaque, int version_id) { VirtIONet *n = opaque; @@ -3296,6 +3340,117 @@ static const VMStateDescription vmstate_virtio_net_rss = { }, }; +static struct vhost_dev *virtio_net_get_vhost(VirtIODevice *vdev) +{ + VirtIONet *n = VIRTIO_NET(vdev); + NetClientState *nc; + struct vhost_net *net; + + if (!n->nic) { + return NULL; + } + + nc = qemu_get_queue(n->nic); + if (!nc) { + return NULL; + } + + net = get_vhost_net(nc->peer); + if (!net) { + return NULL; + } + + return &net->dev; +} + +static int vhost_user_net_save_state(QEMUFile *f, void *pv, size_t size, + const VMStateField *field, + JSONWriter *vmdesc) +{ + VirtIONet *n = pv; + VirtIODevice *vdev = VIRTIO_DEVICE(n); + struct vhost_dev *vhdev; + Error *local_error = NULL; + int ret; + + vhdev = virtio_net_get_vhost(vdev); + if (vhdev == NULL) { + error_reportf_err(local_error, + "Error getting vhost back-end of %s device %s: ", + vdev->name, vdev->parent_obj.canonical_path); + return -1; + } + + ret = vhost_save_backend_state(vhdev, f, &local_error); + if (ret < 0) { + error_reportf_err(local_error, + "Error saving back-end state of %s device %s: ", + vdev->name, vdev->parent_obj.canonical_path); + return ret; + } + + return 0; +} + +static int vhost_user_net_load_state(QEMUFile *f, void *pv, size_t size, + const VMStateField *field) +{ + VirtIONet *n = pv; + VirtIODevice *vdev = VIRTIO_DEVICE(n); + struct vhost_dev *vhdev; + Error *local_error = NULL; + int ret; + + vhdev = virtio_net_get_vhost(vdev); + if (vhdev == NULL) { + error_reportf_err(local_error, + "Error getting vhost back-end of %s device %s: ", + vdev->name, vdev->parent_obj.canonical_path); + return -1; + } + + ret = vhost_load_backend_state(vhdev, f, &local_error); + if (ret < 0) { + error_reportf_err(local_error, + "Error loading back-end state of %s device %s: ", + vdev->name, vdev->parent_obj.canonical_path); + return ret; + } + + return 0; +} + +static bool vhost_user_net_is_internal_migration(void *opaque) +{ + VirtIONet *n = opaque; + VirtIODevice *vdev = VIRTIO_DEVICE(n); + struct vhost_dev *vhdev; + + vhdev = virtio_net_get_vhost(vdev); + if (vhdev == NULL) { + return false; + } + + return vhost_supports_device_state(vhdev); +} + +static const VMStateDescription vhost_user_net_backend_state = { + .name = "virtio-net-device/backend", + .version_id = 0, + .needed = vhost_user_net_is_internal_migration, + .fields = (const VMStateField[]) { + { + .name = "backend", + .info = &(const VMStateInfo) { + .name = "virtio-net vhost-user backend state", + .get = vhost_user_net_load_state, + .put = vhost_user_net_save_state, + }, + }, + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_virtio_net_device = { .name = "virtio-net-device", .version_id = VIRTIO_NET_VM_VERSION, @@ -3348,6 +3503,7 @@ static const VMStateDescription vmstate_virtio_net_device = { }, .subsections = (const VMStateDescription * const []) { &vmstate_virtio_net_rss, + &vhost_user_net_backend_state, NULL } }; @@ -3760,7 +3916,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) net_rx_pkt_init(&n->rx_pkt); if (virtio_has_feature(n->host_features, VIRTIO_NET_F_RSS)) { - virtio_net_load_ebpf(n); + virtio_net_load_ebpf(n, errp); } } @@ -3893,14 +4049,6 @@ static bool dev_unplug_pending(void *opaque) return vdc->primary_unplug_pending(dev); } -static struct vhost_dev *virtio_net_get_vhost(VirtIODevice *vdev) -{ - VirtIONet *n = VIRTIO_NET(vdev); - NetClientState *nc = qemu_get_queue(n->nic); - struct vhost_net *net = get_vhost_net(nc->peer); - return &net->dev; -} - static const VMStateDescription vmstate_virtio_net = { .name = "virtio-net", .minimum_version_id = VIRTIO_NET_VM_VERSION, @@ -3913,7 +4061,7 @@ static const VMStateDescription vmstate_virtio_net = { .dev_unplug_pending = dev_unplug_pending, }; -static Property virtio_net_properties[] = { +static const Property virtio_net_properties[] = { DEFINE_PROP_BIT64("csum", VirtIONet, host_features, VIRTIO_NET_F_CSUM, true), DEFINE_PROP_BIT64("guest_csum", VirtIONet, host_features, @@ -3985,10 +4133,9 @@ static Property virtio_net_properties[] = { VIRTIO_NET_F_GUEST_USO6, true), DEFINE_PROP_BIT64("host_uso", VirtIONet, host_features, VIRTIO_NET_F_HOST_USO, true), - DEFINE_PROP_END_OF_LIST(), }; -static void virtio_net_class_init(ObjectClass *klass, void *data) +static void virtio_net_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); @@ -4010,6 +4157,7 @@ static void virtio_net_class_init(ObjectClass *klass, void *data) vdc->guest_notifier_mask = virtio_net_guest_notifier_mask; vdc->guest_notifier_pending = virtio_net_guest_notifier_pending; vdc->legacy_features |= (0x1 << VIRTIO_NET_F_GSO); + vdc->pre_load_queues = virtio_net_pre_load_queues; vdc->post_load = virtio_net_post_load_virtio; vdc->vmsd = &vmstate_virtio_net_device; vdc->primary_unplug_pending = primary_unplug_pending; diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index 63a9187..7c0ca56 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -21,7 +21,7 @@ #include "hw/qdev-properties.h" #include "net/tap.h" #include "net/checksum.h" -#include "sysemu/sysemu.h" +#include "system/system.h" #include "qemu/bswap.h" #include "qemu/log.h" #include "qemu/module.h" @@ -41,19 +41,9 @@ #define PCI_DEVICE_ID_VMWARE_VMXNET3_REVISION 0x1 #define VMXNET3_MSIX_BAR_SIZE 0x2000 -/* Compatibility flags for migration */ -#define VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS_BIT 0 -#define VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS \ - (1 << VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS_BIT) -#define VMXNET3_COMPAT_FLAG_DISABLE_PCIE_BIT 1 -#define VMXNET3_COMPAT_FLAG_DISABLE_PCIE \ - (1 << VMXNET3_COMPAT_FLAG_DISABLE_PCIE_BIT) - #define VMXNET3_EXP_EP_OFFSET (0x48) -#define VMXNET3_MSI_OFFSET(s) \ - ((s)->compat_flags & VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS ? 0x50 : 0x84) -#define VMXNET3_MSIX_OFFSET(s) \ - ((s)->compat_flags & VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS ? 0 : 0x9c) +#define VMXNET3_MSI_OFFSET (0x84) +#define VMXNET3_MSIX_OFFSET (0x9c) #define VMXNET3_DSN_OFFSET (0x100) #define VMXNET3_BAR0_IDX (0) @@ -61,8 +51,7 @@ #define VMXNET3_MSIX_BAR_IDX (2) #define VMXNET3_OFF_MSIX_TABLE (0x000) -#define VMXNET3_OFF_MSIX_PBA(s) \ - ((s)->compat_flags & VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS ? 0x800 : 0x1000) +#define VMXNET3_OFF_MSIX_PBA (0x1000) /* Link speed in Mbps should be shifted by 16 */ #define VMXNET3_LINK_SPEED (1000 << 16) @@ -456,7 +445,6 @@ vmxnet3_setup_tx_offloads(VMXNET3State *s) default: g_assert_not_reached(); - return false; } return true; @@ -933,7 +921,6 @@ static void vmxnet3_rx_update_descr(struct NetRxPkt *pkt, nocsum: rxcd->cnc = 1; - return; } static void @@ -2124,8 +2111,8 @@ vmxnet3_init_msix(VMXNET3State *s) &s->msix_bar, VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_TABLE, &s->msix_bar, - VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_PBA(s), - VMXNET3_MSIX_OFFSET(s), NULL); + VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_PBA, + VMXNET3_MSIX_OFFSET, NULL); if (0 > res) { VMW_WRPRN("Failed to initialize MSI-X, error %d", res); @@ -2223,7 +2210,7 @@ static void vmxnet3_pci_realize(PCIDevice *pci_dev, Error **errp) /* Interrupt pin A */ pci_dev->config[PCI_INTERRUPT_PIN] = 0x01; - ret = msi_init(pci_dev, VMXNET3_MSI_OFFSET(s), VMXNET3_MAX_NMSIX_INTRS, + ret = msi_init(pci_dev, VMXNET3_MSI_OFFSET, VMXNET3_MAX_NMSIX_INTRS, VMXNET3_USE_64BIT, VMXNET3_PER_VECTOR_MASK, NULL); /* Any error other than -ENOTSUP(board's MSI support is broken) * is a programming error. Fall back to INTx silently on -ENOTSUP */ @@ -2251,6 +2238,7 @@ static void vmxnet3_instance_init(Object *obj) device_add_bootindex_property(obj, &s->conf.bootindex, "bootindex", "/ethernet-phy@0", DEVICE(obj)); + PCI_DEVICE(obj)->cap_present |= QEMU_PCI_CAP_EXPRESS; } static void vmxnet3_pci_uninit(PCIDevice *pci_dev) @@ -2472,33 +2460,14 @@ static const VMStateDescription vmstate_vmxnet3 = { } }; -static Property vmxnet3_properties[] = { +static const Property vmxnet3_properties[] = { DEFINE_NIC_PROPERTIES(VMXNET3State, conf), - DEFINE_PROP_BIT("x-old-msi-offsets", VMXNET3State, compat_flags, - VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS_BIT, false), - DEFINE_PROP_BIT("x-disable-pcie", VMXNET3State, compat_flags, - VMXNET3_COMPAT_FLAG_DISABLE_PCIE_BIT, false), - DEFINE_PROP_END_OF_LIST(), }; -static void vmxnet3_realize(DeviceState *qdev, Error **errp) -{ - VMXNET3Class *vc = VMXNET3_DEVICE_GET_CLASS(qdev); - PCIDevice *pci_dev = PCI_DEVICE(qdev); - VMXNET3State *s = VMXNET3(qdev); - - if (!(s->compat_flags & VMXNET3_COMPAT_FLAG_DISABLE_PCIE)) { - pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS; - } - - vc->parent_dc_realize(qdev, errp); -} - -static void vmxnet3_class_init(ObjectClass *class, void *data) +static void vmxnet3_class_init(ObjectClass *class, const void *data) { DeviceClass *dc = DEVICE_CLASS(class); PCIDeviceClass *c = PCI_DEVICE_CLASS(class); - VMXNET3Class *vc = VMXNET3_DEVICE_CLASS(class); c->realize = vmxnet3_pci_realize; c->exit = vmxnet3_pci_uninit; @@ -2509,10 +2478,8 @@ static void vmxnet3_class_init(ObjectClass *class, void *data) c->class_id = PCI_CLASS_NETWORK_ETHERNET; c->subsystem_vendor_id = PCI_VENDOR_ID_VMWARE; c->subsystem_id = PCI_DEVICE_ID_VMWARE_VMXNET3; - device_class_set_parent_realize(dc, vmxnet3_realize, - &vc->parent_dc_realize); dc->desc = "VMWare Paravirtualized Ethernet v3"; - dc->reset = vmxnet3_qdev_reset; + device_class_set_legacy_reset(dc, vmxnet3_qdev_reset); dc->vmsd = &vmstate_vmxnet3; device_class_set_props(dc, vmxnet3_properties); set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); @@ -2525,7 +2492,7 @@ static const TypeInfo vmxnet3_info = { .instance_size = sizeof(VMXNET3State), .class_init = vmxnet3_class_init, .instance_init = vmxnet3_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_PCIE_DEVICE }, { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { } diff --git a/hw/net/vmxnet3.h b/hw/net/vmxnet3.h index f9283f9..dbc69d5 100644 --- a/hw/net/vmxnet3.h +++ b/hw/net/vmxnet3.h @@ -63,8 +63,8 @@ * details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * along with this program; if not, see + * <https://www.gnu.org/licenses/>. * * The full GNU General Public License is included in this distribution in * the file called "COPYING". diff --git a/hw/net/xen_nic.c b/hw/net/xen_nic.c index 89487b4..34c6a1d 100644 --- a/hw/net/xen_nic.c +++ b/hw/net/xen_nic.c @@ -24,7 +24,7 @@ #include "qemu/cutils.h" #include "qemu/log.h" #include "qemu/qemu-print.h" -#include "qapi/qmp/qdict.h" +#include "qobject/qdict.h" #include "qapi/error.h" #include <sys/socket.h> @@ -510,23 +510,22 @@ static char *xen_netdev_get_name(XenDevice *xendev, Error **errp) if (netdev->dev == -1) { XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); - char fe_path[XENSTORE_ABS_PATH_MAX + 1]; int idx = (xen_mode == XEN_EMULATE) ? 0 : 1; + Error *local_err = NULL; char *value; /* Theoretically we could go up to INT_MAX here but that's overkill */ while (idx < 100) { - snprintf(fe_path, sizeof(fe_path), - "/local/domain/%u/device/vif/%u", - xendev->frontend_id, idx); - value = qemu_xen_xs_read(xenbus->xsh, XBT_NULL, fe_path, NULL); + value = xs_node_read(xenbus->xsh, XBT_NULL, NULL, &local_err, + "/local/domain/%u/device/vif/%u", + xendev->frontend_id, idx); if (!value) { if (errno == ENOENT) { netdev->dev = idx; + error_free(local_err); goto found; } - error_setg(errp, "cannot read %s: %s", fe_path, - strerror(errno)); + error_propagate(errp, local_err); return NULL; } free(value); @@ -555,13 +554,12 @@ static void xen_netdev_unrealize(XenDevice *xendev) /* ------------------------------------------------------------- */ -static Property xen_netdev_properties[] = { +static const Property xen_netdev_properties[] = { DEFINE_NIC_PROPERTIES(XenNetDev, conf), DEFINE_PROP_INT32("idx", XenNetDev, dev, -1), - DEFINE_PROP_END_OF_LIST(), }; -static void xen_netdev_class_init(ObjectClass *class, void *data) +static void xen_netdev_class_init(ObjectClass *class, const void *data) { DeviceClass *dev_class = DEVICE_CLASS(class); XenDeviceClass *xendev_class = XEN_DEVICE_CLASS(class); diff --git a/hw/net/xgmac.c b/hw/net/xgmac.c index ffe3fc8..d45f872 100644 --- a/hw/net/xgmac.c +++ b/hw/net/xgmac.c @@ -207,7 +207,7 @@ static void xgmac_enet_send(XgmacState *s) struct desc bd; int frame_size; int len; - uint8_t frame[8192]; + QEMU_UNINITIALIZED uint8_t frame[8192]; uint8_t *ptr; ptr = frame; @@ -414,12 +414,11 @@ static void xgmac_enet_realize(DeviceState *dev, Error **errp) s->conf.macaddr.a[0]; } -static Property xgmac_properties[] = { +static const Property xgmac_properties[] = { DEFINE_NIC_PROPERTIES(XgmacState, conf), - DEFINE_PROP_END_OF_LIST(), }; -static void xgmac_enet_class_init(ObjectClass *klass, void *data) +static void xgmac_enet_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c index 05d41bd..1f5c748 100644 --- a/hw/net/xilinx_axienet.c +++ b/hw/net/xilinx_axienet.c @@ -996,7 +996,7 @@ static void xilinx_enet_init(Object *obj) sysbus_init_mmio(sbd, &s->iomem); } -static Property xilinx_enet_properties[] = { +static const Property xilinx_enet_properties[] = { DEFINE_PROP_UINT32("phyaddr", XilinxAXIEnet, c_phyaddr, 7), DEFINE_PROP_UINT32("rxmem", XilinxAXIEnet, c_rxmem, 0x1000), DEFINE_PROP_UINT32("txmem", XilinxAXIEnet, c_txmem, 0x1000), @@ -1005,27 +1005,27 @@ static Property xilinx_enet_properties[] = { tx_data_dev, TYPE_STREAM_SINK, StreamSink *), DEFINE_PROP_LINK("axistream-control-connected", XilinxAXIEnet, tx_control_dev, TYPE_STREAM_SINK, StreamSink *), - DEFINE_PROP_END_OF_LIST(), }; -static void xilinx_enet_class_init(ObjectClass *klass, void *data) +static void xilinx_enet_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = xilinx_enet_realize; device_class_set_props(dc, xilinx_enet_properties); - dc->reset = xilinx_axienet_reset; + device_class_set_legacy_reset(dc, xilinx_axienet_reset); } static void xilinx_enet_control_stream_class_init(ObjectClass *klass, - void *data) + const void *data) { StreamSinkClass *ssc = STREAM_SINK_CLASS(klass); ssc->push = xilinx_axienet_control_stream_push; } -static void xilinx_enet_data_stream_class_init(ObjectClass *klass, void *data) +static void xilinx_enet_data_stream_class_init(ObjectClass *klass, + const void *data) { StreamSinkClass *ssc = STREAM_SINK_CLASS(klass); @@ -1045,7 +1045,7 @@ static const TypeInfo xilinx_enet_data_stream_info = { .parent = TYPE_OBJECT, .instance_size = sizeof(XilinxAXIEnetStreamSink), .class_init = xilinx_enet_data_stream_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_STREAM_SINK }, { } } @@ -1056,7 +1056,7 @@ static const TypeInfo xilinx_enet_control_stream_info = { .parent = TYPE_OBJECT, .instance_size = sizeof(XilinxAXIEnetStreamSink), .class_init = xilinx_enet_control_stream_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_STREAM_SINK }, { } } diff --git a/hw/net/xilinx_ethlite.c b/hw/net/xilinx_ethlite.c index 989afaf..42b19d0 100644 --- a/hw/net/xilinx_ethlite.c +++ b/hw/net/xilinx_ethlite.c @@ -2,6 +2,10 @@ * QEMU model of the Xilinx Ethernet Lite MAC. * * Copyright (c) 2009 Edgar E. Iglesias. + * Copyright (c) 2024 Linaro, Ltd + * + * DS580: https://docs.amd.com/v/u/en-US/xps_ethernetlite + * LogiCORE IP XPS Ethernet Lite Media Access Controller * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,27 +28,35 @@ #include "qemu/osdep.h" #include "qemu/module.h" +#include "qemu/bitops.h" #include "qom/object.h" -#include "exec/tswap.h" +#include "qapi/error.h" #include "hw/sysbus.h" #include "hw/irq.h" #include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "hw/misc/unimp.h" #include "net/net.h" +#include "trace.h" + +#define BUFSZ_MAX 0x07e4 +#define A_MDIO_BASE 0x07e4 +#define A_TX_BASE0 0x07f4 +#define A_TX_BASE1 0x0ff4 +#define A_RX_BASE0 0x17fc +#define A_RX_BASE1 0x1ffc + +enum { + TX_LEN = 0, + TX_GIE = 1, + TX_CTRL = 2, + TX_MAX +}; -#define D(x) -#define R_TX_BUF0 0 -#define R_TX_LEN0 (0x07f4 / 4) -#define R_TX_GIE0 (0x07f8 / 4) -#define R_TX_CTRL0 (0x07fc / 4) -#define R_TX_BUF1 (0x0800 / 4) -#define R_TX_LEN1 (0x0ff4 / 4) -#define R_TX_CTRL1 (0x0ffc / 4) - -#define R_RX_BUF0 (0x1000 / 4) -#define R_RX_CTRL0 (0x17fc / 4) -#define R_RX_BUF1 (0x1800 / 4) -#define R_RX_CTRL1 (0x1ffc / 4) -#define R_MAX (0x2000 / 4) +enum { + RX_CTRL = 0, + RX_MAX +}; #define GIE_GIE 0x80000000 @@ -52,174 +64,238 @@ #define CTRL_P 0x2 #define CTRL_S 0x1 +typedef struct XlnxXpsEthLitePort { + MemoryRegion txio; + MemoryRegion rxio; + MemoryRegion txbuf; + MemoryRegion rxbuf; + + struct { + uint32_t tx_len; + uint32_t tx_gie; + uint32_t tx_ctrl; + + uint32_t rx_ctrl; + } reg; +} XlnxXpsEthLitePort; + #define TYPE_XILINX_ETHLITE "xlnx.xps-ethernetlite" -DECLARE_INSTANCE_CHECKER(struct xlx_ethlite, XILINX_ETHLITE, - TYPE_XILINX_ETHLITE) +OBJECT_DECLARE_SIMPLE_TYPE(XlnxXpsEthLite, XILINX_ETHLITE) -struct xlx_ethlite +struct XlnxXpsEthLite { SysBusDevice parent_obj; - MemoryRegion mmio; + EndianMode model_endianness; + MemoryRegion container; qemu_irq irq; NICState *nic; NICConf conf; uint32_t c_tx_pingpong; uint32_t c_rx_pingpong; - unsigned int txbuf; - unsigned int rxbuf; + unsigned int port_index; /* dual port RAM index */ - uint32_t regs[R_MAX]; + UnimplementedDeviceState rsvd; + UnimplementedDeviceState mdio; + XlnxXpsEthLitePort port[2]; }; -static inline void eth_pulse_irq(struct xlx_ethlite *s) +static inline void eth_pulse_irq(XlnxXpsEthLite *s) { /* Only the first gie reg is active. */ - if (s->regs[R_TX_GIE0] & GIE_GIE) { + if (s->port[0].reg.tx_gie & GIE_GIE) { qemu_irq_pulse(s->irq); } } -static uint64_t -eth_read(void *opaque, hwaddr addr, unsigned int size) +static unsigned addr_to_port_index(hwaddr addr) { - struct xlx_ethlite *s = opaque; - uint32_t r = 0; + return extract64(addr, 11, 1); +} - addr >>= 2; +static void *txbuf_ptr(XlnxXpsEthLite *s, unsigned port_index) +{ + return memory_region_get_ram_ptr(&s->port[port_index].txbuf); +} - switch (addr) - { - case R_TX_GIE0: - case R_TX_LEN0: - case R_TX_LEN1: - case R_TX_CTRL1: - case R_TX_CTRL0: - case R_RX_CTRL1: - case R_RX_CTRL0: - r = s->regs[addr]; - D(qemu_log("%s " HWADDR_FMT_plx "=%x\n", __func__, addr * 4, r)); - break; - - default: - r = tswap32(s->regs[addr]); - break; +static void *rxbuf_ptr(XlnxXpsEthLite *s, unsigned port_index) +{ + return memory_region_get_ram_ptr(&s->port[port_index].rxbuf); +} + +static uint64_t port_tx_read(void *opaque, hwaddr addr, unsigned int size) +{ + XlnxXpsEthLite *s = opaque; + unsigned port_index = addr_to_port_index(addr); + uint32_t r = 0; + + switch (addr >> 2) { + case TX_LEN: + r = s->port[port_index].reg.tx_len; + break; + case TX_GIE: + r = s->port[port_index].reg.tx_gie; + break; + case TX_CTRL: + r = s->port[port_index].reg.tx_ctrl; + break; + default: + g_assert_not_reached(); } + return r; } -static void -eth_write(void *opaque, hwaddr addr, - uint64_t val64, unsigned int size) +static void port_tx_write(void *opaque, hwaddr addr, uint64_t value, + unsigned int size) { - struct xlx_ethlite *s = opaque; - unsigned int base = 0; - uint32_t value = val64; - - addr >>= 2; - switch (addr) - { - case R_TX_CTRL0: - case R_TX_CTRL1: - if (addr == R_TX_CTRL1) - base = 0x800 / 4; - - D(qemu_log("%s addr=" HWADDR_FMT_plx " val=%x\n", - __func__, addr * 4, value)); - if ((value & (CTRL_P | CTRL_S)) == CTRL_S) { - qemu_send_packet(qemu_get_queue(s->nic), - (void *) &s->regs[base], - s->regs[base + R_TX_LEN0]); - D(qemu_log("eth_tx %d\n", s->regs[base + R_TX_LEN0])); - if (s->regs[base + R_TX_CTRL0] & CTRL_I) - eth_pulse_irq(s); - } else if ((value & (CTRL_P | CTRL_S)) == (CTRL_P | CTRL_S)) { - memcpy(&s->conf.macaddr.a[0], &s->regs[base], 6); - if (s->regs[base + R_TX_CTRL0] & CTRL_I) - eth_pulse_irq(s); + XlnxXpsEthLite *s = opaque; + unsigned port_index = addr_to_port_index(addr); + + switch (addr >> 2) { + case TX_LEN: + s->port[port_index].reg.tx_len = value; + break; + case TX_GIE: + s->port[port_index].reg.tx_gie = value; + break; + case TX_CTRL: + if ((value & (CTRL_P | CTRL_S)) == CTRL_S) { + qemu_send_packet(qemu_get_queue(s->nic), + txbuf_ptr(s, port_index), + s->port[port_index].reg.tx_len); + if (s->port[port_index].reg.tx_ctrl & CTRL_I) { + eth_pulse_irq(s); + } + } else if ((value & (CTRL_P | CTRL_S)) == (CTRL_P | CTRL_S)) { + memcpy(&s->conf.macaddr.a[0], txbuf_ptr(s, port_index), 6); + if (s->port[port_index].reg.tx_ctrl & CTRL_I) { + eth_pulse_irq(s); } + } + /* + * We are fast and get ready pretty much immediately + * so we actually never flip the S nor P bits to one. + */ + s->port[port_index].reg.tx_ctrl = value & ~(CTRL_P | CTRL_S); + break; + default: + g_assert_not_reached(); + } +} - /* We are fast and get ready pretty much immediately so - we actually never flip the S nor P bits to one. */ - s->regs[addr] = value & ~(CTRL_P | CTRL_S); - break; +static const MemoryRegionOps eth_porttx_ops[2] = { + [0 ... 1] = { + .read = port_tx_read, + .write = port_tx_write, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, + }, + [0].endianness = DEVICE_LITTLE_ENDIAN, + [1].endianness = DEVICE_BIG_ENDIAN, +}; - /* Keep these native. */ - case R_RX_CTRL0: - case R_RX_CTRL1: - if (!(value & CTRL_S)) { - qemu_flush_queued_packets(qemu_get_queue(s->nic)); - } - /* fall through */ - case R_TX_LEN0: - case R_TX_LEN1: - case R_TX_GIE0: - D(qemu_log("%s addr=" HWADDR_FMT_plx " val=%x\n", - __func__, addr * 4, value)); - s->regs[addr] = value; - break; - - default: - s->regs[addr] = tswap32(value); - break; +static uint64_t port_rx_read(void *opaque, hwaddr addr, unsigned int size) +{ + XlnxXpsEthLite *s = opaque; + unsigned port_index = addr_to_port_index(addr); + uint32_t r = 0; + + switch (addr >> 2) { + case RX_CTRL: + r = s->port[port_index].reg.rx_ctrl; + break; + default: + g_assert_not_reached(); } + + return r; } -static const MemoryRegionOps eth_ops = { - .read = eth_read, - .write = eth_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4 +static void port_rx_write(void *opaque, hwaddr addr, uint64_t value, + unsigned int size) +{ + XlnxXpsEthLite *s = opaque; + unsigned port_index = addr_to_port_index(addr); + + switch (addr >> 2) { + case RX_CTRL: + if (!(value & CTRL_S)) { + qemu_flush_queued_packets(qemu_get_queue(s->nic)); + } + s->port[port_index].reg.rx_ctrl = value; + break; + default: + g_assert_not_reached(); } +} + +static const MemoryRegionOps eth_portrx_ops[2] = { + [0 ... 1] = { + .read = port_rx_read, + .write = port_rx_write, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, + }, + [0].endianness = DEVICE_LITTLE_ENDIAN, + [1].endianness = DEVICE_BIG_ENDIAN, }; static bool eth_can_rx(NetClientState *nc) { - struct xlx_ethlite *s = qemu_get_nic_opaque(nc); - unsigned int rxbase = s->rxbuf * (0x800 / 4); + XlnxXpsEthLite *s = qemu_get_nic_opaque(nc); - return !(s->regs[rxbase + R_RX_CTRL0] & CTRL_S); + return !(s->port[s->port_index].reg.rx_ctrl & CTRL_S); } static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size) { - struct xlx_ethlite *s = qemu_get_nic_opaque(nc); - unsigned int rxbase = s->rxbuf * (0x800 / 4); + XlnxXpsEthLite *s = qemu_get_nic_opaque(nc); + unsigned int port_index = s->port_index; /* DA filter. */ if (!(buf[0] & 0x80) && memcmp(&s->conf.macaddr.a[0], buf, 6)) return size; - if (s->regs[rxbase + R_RX_CTRL0] & CTRL_S) { - D(qemu_log("ethlite lost packet %x\n", s->regs[R_RX_CTRL0])); + if (s->port[port_index].reg.rx_ctrl & CTRL_S) { + trace_ethlite_pkt_lost(s->port[port_index].reg.rx_ctrl); return -1; } - D(qemu_log("%s %zd rxbase=%x\n", __func__, size, rxbase)); - if (size > (R_MAX - R_RX_BUF0 - rxbase) * 4) { - D(qemu_log("ethlite packet is too big, size=%x\n", size)); + if (size >= BUFSZ_MAX) { + trace_ethlite_pkt_size_too_big(size); return -1; } - memcpy(&s->regs[rxbase + R_RX_BUF0], buf, size); + memcpy(rxbuf_ptr(s, port_index), buf, size); - s->regs[rxbase + R_RX_CTRL0] |= CTRL_S; - if (s->regs[R_RX_CTRL0] & CTRL_I) { + s->port[port_index].reg.rx_ctrl |= CTRL_S; + if (s->port[port_index].reg.rx_ctrl & CTRL_I) { eth_pulse_irq(s); } /* If c_rx_pingpong was set flip buffers. */ - s->rxbuf ^= s->c_rx_pingpong; + s->port_index ^= s->c_rx_pingpong; return size; } static void xilinx_ethlite_reset(DeviceState *dev) { - struct xlx_ethlite *s = XILINX_ETHLITE(dev); + XlnxXpsEthLite *s = XILINX_ETHLITE(dev); - s->rxbuf = 0; + s->port_index = 0; } static NetClientInfo net_xilinx_ethlite_info = { @@ -231,7 +307,61 @@ static NetClientInfo net_xilinx_ethlite_info = { static void xilinx_ethlite_realize(DeviceState *dev, Error **errp) { - struct xlx_ethlite *s = XILINX_ETHLITE(dev); + XlnxXpsEthLite *s = XILINX_ETHLITE(dev); + unsigned ops_index; + + if (s->model_endianness == ENDIAN_MODE_UNSPECIFIED) { + error_setg(errp, TYPE_XILINX_ETHLITE " property 'endianness'" + " must be set to 'big' or 'little'"); + return; + } + ops_index = s->model_endianness == ENDIAN_MODE_BIG ? 1 : 0; + + memory_region_init(&s->container, OBJECT(dev), + "xlnx.xps-ethernetlite", 0x2000); + + object_initialize_child(OBJECT(dev), "ethlite.reserved", &s->rsvd, + TYPE_UNIMPLEMENTED_DEVICE); + qdev_prop_set_string(DEVICE(&s->rsvd), "name", "ethlite.reserved"); + qdev_prop_set_uint64(DEVICE(&s->rsvd), "size", + memory_region_size(&s->container)); + sysbus_realize(SYS_BUS_DEVICE(&s->rsvd), &error_fatal); + memory_region_add_subregion_overlap(&s->container, 0, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->rsvd), 0), + -1); + + object_initialize_child(OBJECT(dev), "ethlite.mdio", &s->mdio, + TYPE_UNIMPLEMENTED_DEVICE); + qdev_prop_set_string(DEVICE(&s->mdio), "name", "ethlite.mdio"); + qdev_prop_set_uint64(DEVICE(&s->mdio), "size", 4 * 4); + sysbus_realize(SYS_BUS_DEVICE(&s->mdio), &error_fatal); + memory_region_add_subregion(&s->container, A_MDIO_BASE, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mdio), 0)); + + for (unsigned i = 0; i < 2; i++) { + memory_region_init_ram(&s->port[i].txbuf, OBJECT(dev), + i ? "ethlite.tx[1]buf" : "ethlite.tx[0]buf", + BUFSZ_MAX, &error_abort); + memory_region_add_subregion(&s->container, 0x0800 * i, &s->port[i].txbuf); + memory_region_init_io(&s->port[i].txio, OBJECT(dev), + ð_porttx_ops[ops_index], s, + i ? "ethlite.tx[1]io" : "ethlite.tx[0]io", + 4 * TX_MAX); + memory_region_add_subregion(&s->container, i ? A_TX_BASE1 : A_TX_BASE0, + &s->port[i].txio); + + memory_region_init_ram(&s->port[i].rxbuf, OBJECT(dev), + i ? "ethlite.rx[1]buf" : "ethlite.rx[0]buf", + BUFSZ_MAX, &error_abort); + memory_region_add_subregion(&s->container, 0x1000 + 0x0800 * i, + &s->port[i].rxbuf); + memory_region_init_io(&s->port[i].rxio, OBJECT(dev), + ð_portrx_ops[ops_index], s, + i ? "ethlite.rx[1]io" : "ethlite.rx[0]io", + 4 * RX_MAX); + memory_region_add_subregion(&s->container, i ? A_RX_BASE1 : A_RX_BASE0, + &s->port[i].rxio); + } qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_xilinx_ethlite_info, &s->conf, @@ -242,42 +372,36 @@ static void xilinx_ethlite_realize(DeviceState *dev, Error **errp) static void xilinx_ethlite_init(Object *obj) { - struct xlx_ethlite *s = XILINX_ETHLITE(obj); + XlnxXpsEthLite *s = XILINX_ETHLITE(obj); sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); - - memory_region_init_io(&s->mmio, obj, ð_ops, s, - "xlnx.xps-ethernetlite", R_MAX * 4); - sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->container); } -static Property xilinx_ethlite_properties[] = { - DEFINE_PROP_UINT32("tx-ping-pong", struct xlx_ethlite, c_tx_pingpong, 1), - DEFINE_PROP_UINT32("rx-ping-pong", struct xlx_ethlite, c_rx_pingpong, 1), - DEFINE_NIC_PROPERTIES(struct xlx_ethlite, conf), - DEFINE_PROP_END_OF_LIST(), +static const Property xilinx_ethlite_properties[] = { + DEFINE_PROP_ENDIAN_NODEFAULT("endianness", XlnxXpsEthLite, model_endianness), + DEFINE_PROP_UINT32("tx-ping-pong", XlnxXpsEthLite, c_tx_pingpong, 1), + DEFINE_PROP_UINT32("rx-ping-pong", XlnxXpsEthLite, c_rx_pingpong, 1), + DEFINE_NIC_PROPERTIES(XlnxXpsEthLite, conf), }; -static void xilinx_ethlite_class_init(ObjectClass *klass, void *data) +static void xilinx_ethlite_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = xilinx_ethlite_realize; - dc->reset = xilinx_ethlite_reset; + device_class_set_legacy_reset(dc, xilinx_ethlite_reset); device_class_set_props(dc, xilinx_ethlite_properties); } -static const TypeInfo xilinx_ethlite_info = { - .name = TYPE_XILINX_ETHLITE, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(struct xlx_ethlite), - .instance_init = xilinx_ethlite_init, - .class_init = xilinx_ethlite_class_init, +static const TypeInfo xilinx_ethlite_types[] = { + { + .name = TYPE_XILINX_ETHLITE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(XlnxXpsEthLite), + .instance_init = xilinx_ethlite_init, + .class_init = xilinx_ethlite_class_init, + }, }; -static void xilinx_ethlite_register_types(void) -{ - type_register_static(&xilinx_ethlite_info); -} - -type_init(xilinx_ethlite_register_types) +DEFINE_TYPES(xilinx_ethlite_types) |