diff options
Diffstat (limited to 'hw/net')
| -rw-r--r-- | hw/net/allwinner-sun8i-emac.c | 2 | ||||
| -rw-r--r-- | hw/net/allwinner_emac.c | 2 | ||||
| -rw-r--r-- | hw/net/cadence_gem.c | 26 | ||||
| -rw-r--r-- | hw/net/fsl_etsec/etsec.c | 4 | ||||
| -rw-r--r-- | hw/net/meson.build | 1 | ||||
| -rw-r--r-- | hw/net/npcm_pcs.c | 410 | ||||
| -rw-r--r-- | hw/net/rocker/rocker-hmp-cmds.c | 2 | ||||
| -rw-r--r-- | hw/net/smc91c111.c | 9 | ||||
| -rw-r--r-- | hw/net/trace-events | 4 | ||||
| -rw-r--r-- | hw/net/virtio-net.c | 2 | ||||
| -rw-r--r-- | hw/net/xen_nic.c | 2 | ||||
| -rw-r--r-- | hw/net/xilinx_ethlite.c | 29 |
12 files changed, 472 insertions, 21 deletions
diff --git a/hw/net/allwinner-sun8i-emac.c b/hw/net/allwinner-sun8i-emac.c index ff44554e95..5adb41dc46 100644 --- a/hw/net/allwinner-sun8i-emac.c +++ b/hw/net/allwinner-sun8i-emac.c @@ -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, diff --git a/hw/net/allwinner_emac.c b/hw/net/allwinner_emac.c index 3eb9e09dc5..47f1e7f086 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, diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index f744054a6d..80fbbacc1e 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -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; diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c index 781b900395..3ce4fa2662 100644 --- a/hw/net/fsl_etsec/etsec.c +++ b/hw/net/fsl_etsec/etsec.c @@ -425,14 +425,12 @@ static void etsec_class_init(ObjectClass *klass, void *data) dc->realize = etsec_realize; device_class_set_legacy_reset(dc, etsec_reset); device_class_set_props(dc, etsec_properties); - /* Supported by ppce500 machine */ - dc->user_creatable = true; } static const TypeInfo etsec_types[] = { { .name = TYPE_ETSEC_COMMON, - .parent = TYPE_SYS_BUS_DEVICE, + .parent = TYPE_DYNAMIC_SYS_BUS_DEVICE, .instance_size = sizeof(eTSEC), .class_init = etsec_class_init, .instance_init = etsec_instance_init, diff --git a/hw/net/meson.build b/hw/net/meson.build index 3bb5d749a8..e6759e26ca 100644 --- a/hw/net/meson.build +++ b/hw/net/meson.build @@ -40,6 +40,7 @@ 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_COLDFIRE', if_true: files('mcf_fec.c')) specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_llan.c')) diff --git a/hw/net/npcm_pcs.c b/hw/net/npcm_pcs.c new file mode 100644 index 0000000000..ce5034e234 --- /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, 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/rocker/rocker-hmp-cmds.c b/hw/net/rocker/rocker-hmp-cmds.c index 197c6e28dc..df40991f6d 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/smc91c111.c b/hw/net/smc91c111.c index b18d5c23c3..0e13dfa18b 100644 --- a/hw/net/smc91c111.c +++ b/hw/net/smc91c111.c @@ -182,6 +182,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++) diff --git a/hw/net/trace-events b/hw/net/trace-events index c35bfb2eb8..72b69c4a8b 100644 --- a/hw/net/trace-events +++ b/hw/net/trace-events @@ -483,8 +483,8 @@ npcm_gmac_packet_tx_desc_data(const char* name, uint32_t tdes0, uint32_t tdes1) 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" diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index d64941bf8e..de87cfadff 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" diff --git a/hw/net/xen_nic.c b/hw/net/xen_nic.c index 5410039490..c48691207d 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> diff --git a/hw/net/xilinx_ethlite.c b/hw/net/xilinx_ethlite.c index 14bf2b2e17..15d9b95aa8 100644 --- a/hw/net/xilinx_ethlite.c +++ b/hw/net/xilinx_ethlite.c @@ -34,6 +34,7 @@ #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" @@ -85,6 +86,7 @@ struct XlnxXpsEthLite { SysBusDevice parent_obj; + EndianMode model_endianness; MemoryRegion container; qemu_irq irq; NICState *nic; @@ -183,10 +185,10 @@ static void port_tx_write(void *opaque, hwaddr addr, uint64_t value, } } -static const MemoryRegionOps eth_porttx_ops = { +static const MemoryRegionOps eth_porttx_ops[2] = { + [0 ... 1] = { .read = port_tx_read, .write = port_tx_write, - .endianness = DEVICE_NATIVE_ENDIAN, .impl = { .min_access_size = 4, .max_access_size = 4, @@ -195,6 +197,9 @@ static const MemoryRegionOps eth_porttx_ops = { .min_access_size = 4, .max_access_size = 4, }, + }, + [0].endianness = DEVICE_LITTLE_ENDIAN, + [1].endianness = DEVICE_BIG_ENDIAN, }; static uint64_t port_rx_read(void *opaque, hwaddr addr, unsigned int size) @@ -232,10 +237,10 @@ static void port_rx_write(void *opaque, hwaddr addr, uint64_t value, } } -static const MemoryRegionOps eth_portrx_ops = { +static const MemoryRegionOps eth_portrx_ops[2] = { + [0 ... 1] = { .read = port_rx_read, .write = port_rx_write, - .endianness = DEVICE_NATIVE_ENDIAN, .impl = { .min_access_size = 4, .max_access_size = 4, @@ -244,6 +249,9 @@ static const MemoryRegionOps eth_portrx_ops = { .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) @@ -300,6 +308,14 @@ static NetClientInfo net_xilinx_ethlite_info = { static void xilinx_ethlite_realize(DeviceState *dev, Error **errp) { 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); @@ -328,7 +344,7 @@ static void xilinx_ethlite_realize(DeviceState *dev, Error **errp) 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, s, + ð_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, @@ -340,7 +356,7 @@ static void xilinx_ethlite_realize(DeviceState *dev, Error **errp) 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, s, + ð_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, @@ -363,6 +379,7 @@ static void xilinx_ethlite_init(Object *obj) } 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), |