Commit 292ef18a authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/jasowang/tags/net-pull-request' into staging



# gpg: Signature made Thu 18 Jun 2020 14:16:22 BST
# gpg:                using RSA key EF04965B398D6211
# gpg: Good signature from "Jason Wang (Jason Wang on RedHat) <jasowang@redhat.com>" [marginal]
# gpg: WARNING: This key is not certified with sufficiently trusted signatures!
# gpg:          It is not certain that the signature belongs to the owner.
# Primary key fingerprint: 215D 46F4 8246 689E C77F  3562 EF04 965B 398D 6211

* remotes/jasowang/tags/net-pull-request: (33 commits)
  net: Drop the NetLegacy structure, always use Netdev instead
  net: Drop the legacy "name" parameter from the -net option
  hw/net/e1000e: Do not abort() on invalid PSRCTL register value
  colo-compare: Fix memory leak in packet_enqueue()
  net/colo-compare.c: Correct ordering in complete and finalize
  net/colo-compare.c: Check that colo-compare is active
  net/colo-compare.c: Only hexdump packets if tracing is enabled
  net/colo-compare.c: Fix deadlock in compare_chr_send
  chardev/char.c: Use qemu_co_sleep_ns if in coroutine
  net/colo-compare.c: Create event_bh with the right AioContext
  net: use peer when purging queue in qemu_flush_or_purge_queue_packets()
  net: cadence_gem: Fix RX address filtering
  net: cadence_gem: TX_LAST bit should be set by guest
  net: cadence_gem: Update the reset value for interrupt mask register
  net: cadnece_gem: Update irq_read_clear field of designcfg_debug1 reg
  net: cadence_gem: Add support for jumbo frames
  net: cadence_gem: Fix up code style
  net: cadence_gem: Move tx/rx packet buffert to CadenceGEMState
  net: cadence_gem: Set ISR according to queue in use
  net: cadence_gem: Define access permission for interrupt registers
  ...

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents eefe34ea 71830d84
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@
#include "qemu/module.h"
#include "qemu/option.h"
#include "qemu/id.h"
#include "qemu/coroutine.h"

#include "chardev/char-mux.h"

@@ -119,7 +120,11 @@ static int qemu_chr_write_buffer(Chardev *s,
    retry:
        res = cc->chr_write(s, buf + *offset, len - *offset);
        if (res < 0 && errno == EAGAIN && write_all) {
            if (qemu_in_coroutine()) {
                qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000);
            } else {
                g_usleep(100);
            }
            goto retry;
        }

+9 −6
Original line number Diff line number Diff line
@@ -47,12 +47,6 @@ The 'file' driver for drives is no longer appropriate for character or host
devices and will only accept regular files (S_IFREG). The correct driver
for these file types is 'host_cdrom' or 'host_device' as appropriate.

``-net ...,name=``\ *name* (since 3.1)
''''''''''''''''''''''''''''''''''''''

The ``name`` parameter of the ``-net`` option is a synonym
for the ``id`` parameter, which should now be used instead.

``-smp`` (invalid topologies) (since 3.1)
'''''''''''''''''''''''''''''''''''''''''

@@ -441,6 +435,15 @@ What follows is a record of recently removed, formerly deprecated
features that serves as a record for users who have encountered
trouble after a recent upgrade.

System emulator command line arguments
--------------------------------------

``-net ...,name=``\ *name* (removed in 5.1)
'''''''''''''''''''''''''''''''''''''''''''

The ``name`` parameter of the ``-net`` option was a synonym
for the ``id`` parameter, which should now be used instead.

QEMU Machine Protocol (QMP) commands
------------------------------------

+1 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ obj-$(CONFIG_MILKYMIST) += milkymist-minimac2.o
obj-$(CONFIG_PSERIES) += spapr_llan.o
obj-$(CONFIG_XILINX_ETHLITE) += xilinx_ethlite.o

common-obj-$(CONFIG_VIRTIO_NET) += net_rx_pkt.o
obj-$(CONFIG_VIRTIO_NET) += virtio-net.o
common-obj-$(call land,$(CONFIG_VIRTIO_NET),$(CONFIG_VHOST_NET)) += vhost_net.o
common-obj-$(call lnot,$(call land,$(CONFIG_VIRTIO_NET),$(CONFIG_VHOST_NET))) += vhost_net-stub.o
+259 −199
Original line number Diff line number Diff line
@@ -34,15 +34,15 @@
#include "qemu/module.h"
#include "sysemu/dma.h"
#include "net/checksum.h"
#include "net/eth.h"

#ifdef CADENCE_GEM_ERR_DEBUG
#define CADENCE_GEM_ERR_DEBUG 0
#define DB_PRINT(...) do {\
    fprintf(stderr,  ": %s: ", __func__); \
    fprintf(stderr, ## __VA_ARGS__); \
    if (CADENCE_GEM_ERR_DEBUG) {   \
        qemu_log(": %s: ", __func__); \
        qemu_log(__VA_ARGS__); \
    } \
} while (0)
#else
    #define DB_PRINT(...)
#endif

#define GEM_NWCTRL        (0x00000000 / 4) /* Network Control reg */
#define GEM_NWCFG         (0x00000004 / 4) /* Network Config reg */
@@ -62,6 +62,7 @@
#define GEM_TXPAUSE       (0x0000003C / 4) /* TX Pause Time reg */
#define GEM_TXPARTIALSF   (0x00000040 / 4) /* TX Partial Store and Forward */
#define GEM_RXPARTIALSF   (0x00000044 / 4) /* RX Partial Store and Forward */
#define GEM_JUMBO_MAX_LEN (0x00000048 / 4) /* Max Jumbo Frame Size */
#define GEM_HASHLO        (0x00000080 / 4) /* Hash Low address reg */
#define GEM_HASHHI        (0x00000084 / 4) /* Hash High address reg */
#define GEM_SPADDR1LO     (0x00000088 / 4) /* Specific addr 1 low reg */
@@ -122,7 +123,7 @@
#define GEM_RXALIGNERRCNT (0x0000019C / 4) /* Alignment Error Counter */
#define GEM_RXRSCERRCNT   (0x000001A0 / 4) /* Receive Resource Error Counter */
#define GEM_RXORUNCNT     (0x000001A4 / 4) /* Receive Overrun Counter */
#define GEM_RXIPCSERRCNT  (0x000001A8/4) /* IP header Checksum Error Counter */
#define GEM_RXIPCSERRCNT  (0x000001A8 / 4) /* IP header Checksum Err Counter */
#define GEM_RXTCPCCNT     (0x000001AC / 4) /* TCP Checksum Error Counter */
#define GEM_RXUDPCCNT     (0x000001B0 / 4) /* UDP Checksum Error Counter */

@@ -131,7 +132,9 @@
#define GEM_1588ADJ       (0x000001D8 / 4) /* 1588 Timer Adjust */
#define GEM_1588INC       (0x000001DC / 4) /* 1588 Timer Increment */
#define GEM_PTPETXS       (0x000001E0 / 4) /* PTP Event Frame Transmitted (s) */
#define GEM_PTPETXNS      (0x000001E4/4) /* PTP Event Frame Transmitted (ns) */
#define GEM_PTPETXNS      (0x000001E4 / 4) /*
                                            * PTP Event Frame Transmitted (ns)
                                            */
#define GEM_PTPERXS       (0x000001E8 / 4) /* PTP Event Frame Received (s) */
#define GEM_PTPERXNS      (0x000001EC / 4) /* PTP Event Frame Received (ns) */
#define GEM_PTPPTXS       (0x000001E0 / 4) /* PTP Peer Frame Transmitted (s) */
@@ -211,10 +214,12 @@
#define GEM_NWCFG_LERR_DISC    0x00010000 /* Discard RX frames with len err */
#define GEM_NWCFG_BUFF_OFST_M  0x0000C000 /* Receive buffer offset mask */
#define GEM_NWCFG_BUFF_OFST_S  14         /* Receive buffer offset shift */
#define GEM_NWCFG_RCV_1538     0x00000100 /* Receive 1538 bytes frame */
#define GEM_NWCFG_UCAST_HASH   0x00000080 /* accept unicast if hash match */
#define GEM_NWCFG_MCAST_HASH   0x00000040 /* accept multicast if hash match */
#define GEM_NWCFG_BCAST_REJ    0x00000020 /* Reject broadcast packets */
#define GEM_NWCFG_PROMISC      0x00000010 /* Accept all packets */
#define GEM_NWCFG_JUMBO_FRAME  0x00000008 /* Jumbo Frames enable */

#define GEM_DMACFG_ADDR_64B    (1U << 30)
#define GEM_DMACFG_TX_BD_EXT   (1U << 29)
@@ -232,6 +237,7 @@

/* GEM_ISR GEM_IER GEM_IDR GEM_IMR */
#define GEM_INT_TXCMPL        0x00000080 /* Transmit Complete */
#define GEM_INT_AMBA_ERR      0x00000040
#define GEM_INT_TXUSED         0x00000008
#define GEM_INT_RXUSED         0x00000004
#define GEM_INT_RXCMPL        0x00000002
@@ -345,11 +351,6 @@ static inline unsigned tx_desc_get_last(uint32_t *desc)
    return (desc[1] & DESC_1_TX_LAST) ? 1 : 0;
}

static inline void tx_desc_set_last(uint32_t *desc)
{
    desc[1] |= DESC_1_TX_LAST;
}

static inline unsigned tx_desc_get_length(uint32_t *desc)
{
    return desc[1] & DESC_1_LENGTH;
@@ -452,6 +453,34 @@ static inline void rx_desc_set_sar(uint32_t *desc, int sar_idx)
/* The broadcast MAC address: 0xFFFFFFFFFFFF */
static const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };

static uint32_t gem_get_max_buf_len(CadenceGEMState *s, bool tx)
{
    uint32_t size;
    if (s->regs[GEM_NWCFG] & GEM_NWCFG_JUMBO_FRAME) {
        size = s->regs[GEM_JUMBO_MAX_LEN];
        if (size > s->jumbo_max_len) {
            size = s->jumbo_max_len;
            qemu_log_mask(LOG_GUEST_ERROR, "GEM_JUMBO_MAX_LEN reg cannot be"
                " greater than 0x%" PRIx32 "\n", s->jumbo_max_len);
        }
    } else if (tx) {
        size = 1518;
    } else {
        size = s->regs[GEM_NWCFG] & GEM_NWCFG_RCV_1538 ? 1538 : 1518;
    }
    return size;
}

static void gem_set_isr(CadenceGEMState *s, int q, uint32_t flag)
{
    if (q == 0) {
        s->regs[GEM_ISR] |= flag & ~(s->regs[GEM_IMR]);
    } else {
        s->regs[GEM_INT_Q1_STATUS + q - 1] |= flag &
                                      ~(s->regs[GEM_INT_Q1_MASK + q - 1]);
    }
}

/*
 * gem_init_register_masks:
 * One time initialization.
@@ -459,6 +488,7 @@ static const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
 */
static void gem_init_register_masks(CadenceGEMState *s)
{
    unsigned int i;
    /* Mask of register bits which are read only */
    memset(&s->regs_ro[0], 0, sizeof(s->regs_ro));
    s->regs_ro[GEM_NWCTRL]   = 0xFFF80000;
@@ -471,10 +501,19 @@ static void gem_init_register_masks(CadenceGEMState *s)
    s->regs_ro[GEM_ISR]      = 0xFFFFFFFF;
    s->regs_ro[GEM_IMR]      = 0xFFFFFFFF;
    s->regs_ro[GEM_MODID]    = 0xFFFFFFFF;
    for (i = 0; i < s->num_priority_queues; i++) {
        s->regs_ro[GEM_INT_Q1_STATUS + i] = 0xFFFFFFFF;
        s->regs_ro[GEM_INT_Q1_ENABLE + i] = 0xFFFFF319;
        s->regs_ro[GEM_INT_Q1_DISABLE + i] = 0xFFFFF319;
        s->regs_ro[GEM_INT_Q1_MASK + i] = 0xFFFFFFFF;
    }

    /* Mask of register bits which are clear on read */
    memset(&s->regs_rtc[0], 0, sizeof(s->regs_rtc));
    s->regs_rtc[GEM_ISR]      = 0xFFFFFFFF;
    for (i = 0; i < s->num_priority_queues; i++) {
        s->regs_rtc[GEM_INT_Q1_STATUS + i] = 0x00000CE6;
    }

    /* Mask of register bits which are write 1 to clear */
    memset(&s->regs_w1c[0], 0, sizeof(s->regs_w1c));
@@ -486,6 +525,10 @@ static void gem_init_register_masks(CadenceGEMState *s)
    s->regs_wo[GEM_NWCTRL]   = 0x00073E60;
    s->regs_wo[GEM_IER]      = 0x07FFFFFF;
    s->regs_wo[GEM_IDR]      = 0x07FFFFFF;
    for (i = 0; i < s->num_priority_queues; i++) {
        s->regs_wo[GEM_INT_Q1_ENABLE + i] = 0x00000CE6;
        s->regs_wo[GEM_INT_Q1_DISABLE + i] = 0x00000CE6;
    }
}

/*
@@ -555,29 +598,10 @@ static void gem_update_int_status(CadenceGEMState *s)
{
    int i;

    if (!s->regs[GEM_ISR]) {
        /* ISR isn't set, clear all the interrupts */
        for (i = 0; i < s->num_priority_queues; ++i) {
            qemu_set_irq(s->irq[i], 0);
        }
        return;
    }

    /* If we get here we know s->regs[GEM_ISR] is set, so we don't need to
     * check it again.
     */
    if (s->num_priority_queues == 1) {
        /* No priority queues, just trigger the interrupt */
        DB_PRINT("asserting int.\n");
        qemu_set_irq(s->irq[0], 1);
        return;
    }
    qemu_set_irq(s->irq[0], !!s->regs[GEM_ISR]);

    for (i = 0; i < s->num_priority_queues; ++i) {
        if (s->regs[GEM_INT_Q1_STATUS + i]) {
            DB_PRINT("asserting int. (q=%d)\n", i);
            qemu_set_irq(s->irq[i], 1);
        }
    for (i = 1; i < s->num_priority_queues; ++i) {
        qemu_set_irq(s->irq[i], !!s->regs[GEM_INT_Q1_STATUS + i - 1]);
    }
}

@@ -679,7 +703,7 @@ static unsigned calc_mac_hash(const uint8_t *mac)
static int gem_mac_address_filter(CadenceGEMState *s, const uint8_t *packet)
{
    uint8_t *gem_spaddr;
    int i;
    int i, is_mc;

    /* Promiscuous mode? */
    if (s->regs[GEM_NWCFG] & GEM_NWCFG_PROMISC) {
@@ -695,22 +719,17 @@ static int gem_mac_address_filter(CadenceGEMState *s, const uint8_t *packet)
    }

    /* Accept packets -w- hash match? */
    if ((packet[0] == 0x01 && (s->regs[GEM_NWCFG] & GEM_NWCFG_MCAST_HASH)) ||
        (packet[0] != 0x01 && (s->regs[GEM_NWCFG] & GEM_NWCFG_UCAST_HASH))) {
    is_mc = is_multicast_ether_addr(packet);
    if ((is_mc && (s->regs[GEM_NWCFG] & GEM_NWCFG_MCAST_HASH)) ||
        (!is_mc && (s->regs[GEM_NWCFG] & GEM_NWCFG_UCAST_HASH))) {
        uint64_t buckets;
        unsigned hash_index;

        hash_index = calc_mac_hash(packet);
        if (hash_index < 32) {
            if (s->regs[GEM_HASHLO] & (1<<hash_index)) {
                return packet[0] == 0x01 ? GEM_RX_MULTICAST_HASH_ACCEPT :
                                           GEM_RX_UNICAST_HASH_ACCEPT;
            }
        } else {
            hash_index -= 32;
            if (s->regs[GEM_HASHHI] & (1<<hash_index)) {
                return packet[0] == 0x01 ? GEM_RX_MULTICAST_HASH_ACCEPT :
                                           GEM_RX_UNICAST_HASH_ACCEPT;
            }
        buckets = ((uint64_t)s->regs[GEM_HASHHI] << 32) | s->regs[GEM_HASHLO];
        if ((buckets >> hash_index) & 1) {
            return is_mc ? GEM_RX_MULTICAST_HASH_ACCEPT
                         : GEM_RX_UNICAST_HASH_ACCEPT;
        }
    }

@@ -846,6 +865,35 @@ static int get_queue_from_screen(CadenceGEMState *s, uint8_t *rxbuf_ptr,
    return 0;
}

static uint32_t gem_get_queue_base_addr(CadenceGEMState *s, bool tx, int q)
{
    uint32_t base_addr = 0;

    switch (q) {
    case 0:
        base_addr = s->regs[tx ? GEM_TXQBASE : GEM_RXQBASE];
        break;
    case 1 ... (MAX_PRIORITY_QUEUES - 1):
        base_addr = s->regs[(tx ? GEM_TRANSMIT_Q1_PTR :
                                 GEM_RECEIVE_Q1_PTR) + q - 1];
        break;
    default:
        g_assert_not_reached();
    };

    return base_addr;
}

static inline uint32_t gem_get_tx_queue_base_addr(CadenceGEMState *s, int q)
{
    return gem_get_queue_base_addr(s, true, q);
}

static inline uint32_t gem_get_rx_queue_base_addr(CadenceGEMState *s, int q)
{
    return gem_get_queue_base_addr(s, false, q);
}

static hwaddr gem_get_desc_addr(CadenceGEMState *s, bool tx, int q)
{
    hwaddr desc_addr = 0;
@@ -883,7 +931,7 @@ static void gem_get_rx_desc(CadenceGEMState *s, int q)
    if (rx_desc_get_ownership(s->rx_desc[q]) == 1) {
        DB_PRINT("descriptor 0x%" HWADDR_PRIx " owned by sw.\n", desc_addr);
        s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_NOBUF;
        s->regs[GEM_ISR] |= GEM_INT_RXUSED & ~(s->regs[GEM_IMR]);
        gem_set_isr(s, q, GEM_INT_RXUSED);
        /* Handle interrupt consequences */
        gem_update_int_status(s);
    }
@@ -895,21 +943,18 @@ static void gem_get_rx_desc(CadenceGEMState *s, int q)
 */
static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
{
    CadenceGEMState *s;
    CadenceGEMState *s = qemu_get_nic_opaque(nc);
    unsigned   rxbufsize, bytes_to_copy;
    unsigned   rxbuf_offset;
    uint8_t    rxbuf[2048];
    uint8_t   *rxbuf_ptr;
    bool first_desc = true;
    int maf;
    int q = 0;

    s = qemu_get_nic_opaque(nc);

    /* Is this destination MAC address "for us" ? */
    maf = gem_mac_address_filter(s, buf);
    if (maf == GEM_RX_REJECT) {
        return -1;
        return size;  /* no, drop siliently b/c it's not an error */
    }

    /* Discard packets with receive length error enabled ? */
@@ -961,29 +1006,35 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
    } else {
        unsigned crc_val;

        if (size > sizeof(rxbuf) - sizeof(crc_val)) {
            size = sizeof(rxbuf) - sizeof(crc_val);
        if (size > MAX_FRAME_SIZE - sizeof(crc_val)) {
            size = MAX_FRAME_SIZE - sizeof(crc_val);
        }
        bytes_to_copy = size;
        /* The application wants the FCS field, which QEMU does not provide.
         * We must try and calculate one.
         */

        memcpy(rxbuf, buf, size);
        memset(rxbuf + size, 0, sizeof(rxbuf) - size);
        rxbuf_ptr = rxbuf;
        crc_val = cpu_to_le32(crc32(0, rxbuf, MAX(size, 60)));
        memcpy(rxbuf + size, &crc_val, sizeof(crc_val));
        memcpy(s->rx_packet, buf, size);
        memset(s->rx_packet + size, 0, MAX_FRAME_SIZE - size);
        rxbuf_ptr = s->rx_packet;
        crc_val = cpu_to_le32(crc32(0, s->rx_packet, MAX(size, 60)));
        memcpy(s->rx_packet + size, &crc_val, sizeof(crc_val));

        bytes_to_copy += 4;
        size += 4;
    }

    DB_PRINT("config bufsize: %d packet size: %ld\n", rxbufsize, size);
    DB_PRINT("config bufsize: %u packet size: %zd\n", rxbufsize, size);

    /* Find which queue we are targeting */
    q = get_queue_from_screen(s, rxbuf_ptr, rxbufsize);

    if (size > gem_get_max_buf_len(s, false)) {
        qemu_log_mask(LOG_GUEST_ERROR, "rx frame too long\n");
        gem_set_isr(s, q, GEM_INT_AMBA_ERR);
        return -1;
    }

    while (bytes_to_copy) {
        hwaddr desc_addr;

@@ -992,7 +1043,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
            return -1;
        }

        DB_PRINT("copy %u bytes to 0x%" PRIx64 "\n",
        DB_PRINT("copy %" PRIu32 " bytes to 0x%" PRIx64 "\n",
                MIN(bytes_to_copy, rxbufsize),
                rx_desc_get_buffer(s, s->rx_desc[q]));

@@ -1044,7 +1095,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
        /* Next descriptor */
        if (rx_desc_get_wrap(s->rx_desc[q])) {
            DB_PRINT("wrapping RX descriptor list\n");
            s->rx_desc_addr[q] = s->regs[GEM_RXQBASE];
            s->rx_desc_addr[q] = gem_get_rx_queue_base_addr(s, q);
        } else {
            DB_PRINT("incrementing RX descriptor list\n");
            s->rx_desc_addr[q] += 4 * gem_get_desc_len(s, true);
@@ -1057,7 +1108,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
    gem_receive_updatestats(s, buf, size);

    s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_FRMRCVD;
    s->regs[GEM_ISR] |= GEM_INT_RXCMPL & ~(s->regs[GEM_IMR]);
    gem_set_isr(s, q, GEM_INT_RXCMPL);

    /* Handle interrupt consequences */
    gem_update_int_status(s);
@@ -1119,7 +1170,6 @@ static void gem_transmit(CadenceGEMState *s)
{
    uint32_t desc[DESC_MAX_NUM_WORDS];
    hwaddr packet_desc_addr;
    uint8_t     tx_packet[2048];
    uint8_t     *p;
    unsigned    total_bytes;
    int q = 0;
@@ -1135,7 +1185,7 @@ static void gem_transmit(CadenceGEMState *s)
     * Packets scattered across multiple descriptors are gathered to this
     * one contiguous buffer first.
     */
    p = tx_packet;
    p = s->tx_packet;
    total_bytes = 0;

    for (q = s->num_priority_queues - 1; q >= 0; q--) {
@@ -1160,17 +1210,18 @@ static void gem_transmit(CadenceGEMState *s)
             */
            if ((tx_desc_get_buffer(s, desc) == 0) ||
                (tx_desc_get_length(desc) == 0)) {
                DB_PRINT("Invalid TX descriptor @ 0x%x\n",
                         (unsigned)packet_desc_addr);
                DB_PRINT("Invalid TX descriptor @ 0x%" HWADDR_PRIx "\n",
                         packet_desc_addr);
                break;
            }

            if (tx_desc_get_length(desc) > sizeof(tx_packet) -
                                               (p - tx_packet)) {
                DB_PRINT("TX descriptor @ 0x%" HWADDR_PRIx \
                         " too large: size 0x%x space 0x%zx\n",
            if (tx_desc_get_length(desc) > gem_get_max_buf_len(s, true) -
                                               (p - s->tx_packet)) {
                qemu_log_mask(LOG_GUEST_ERROR, "TX descriptor @ 0x%" \
                         HWADDR_PRIx " too large: size 0x%x space 0x%zx\n",
                         packet_desc_addr, tx_desc_get_length(desc),
                         sizeof(tx_packet) - (p - tx_packet));
                         gem_get_max_buf_len(s, true) - (p - s->tx_packet));
                gem_set_isr(s, q, GEM_INT_AMBA_ERR);
                break;
            }

@@ -1200,7 +1251,7 @@ static void gem_transmit(CadenceGEMState *s)
                                    sizeof(desc_first));
                /* Advance the hardware current descriptor past this packet */
                if (tx_desc_get_wrap(desc)) {
                    s->tx_desc_addr[q] = s->regs[GEM_TXQBASE];
                    s->tx_desc_addr[q] = gem_get_tx_queue_base_addr(s, q);
                } else {
                    s->tx_desc_addr[q] = packet_desc_addr +
                                         4 * gem_get_desc_len(s, false);
@@ -1208,43 +1259,36 @@ static void gem_transmit(CadenceGEMState *s)
                DB_PRINT("TX descriptor next: 0x%08x\n", s->tx_desc_addr[q]);

                s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_TXCMPL;
                s->regs[GEM_ISR] |= GEM_INT_TXCMPL & ~(s->regs[GEM_IMR]);

                /* Update queue interrupt status */
                if (s->num_priority_queues > 1) {
                    s->regs[GEM_INT_Q1_STATUS + q] |=
                            GEM_INT_TXCMPL & ~(s->regs[GEM_INT_Q1_MASK + q]);
                }
                gem_set_isr(s, q, GEM_INT_TXCMPL);

                /* Handle interrupt consequences */
                gem_update_int_status(s);

                /* Is checksum offload enabled? */
                if (s->regs[GEM_DMACFG] & GEM_DMACFG_TXCSUM_OFFL) {
                    net_checksum_calculate(tx_packet, total_bytes);
                    net_checksum_calculate(s->tx_packet, total_bytes);
                }

                /* Update MAC statistics */
                gem_transmit_updatestats(s, tx_packet, total_bytes);
                gem_transmit_updatestats(s, s->tx_packet, total_bytes);

                /* Send the packet somewhere */
                if (s->phy_loop || (s->regs[GEM_NWCTRL] &
                                    GEM_NWCTRL_LOCALLOOP)) {
                    gem_receive(qemu_get_queue(s->nic), tx_packet,
                    gem_receive(qemu_get_queue(s->nic), s->tx_packet,
                                total_bytes);
                } else {
                    qemu_send_packet(qemu_get_queue(s->nic), tx_packet,
                    qemu_send_packet(qemu_get_queue(s->nic), s->tx_packet,
                                     total_bytes);
                }

                /* Prepare for next packet */
                p = tx_packet;
                p = s->tx_packet;
                total_bytes = 0;
            }

            /* read next descriptor */
            if (tx_desc_get_wrap(desc)) {
                tx_desc_set_last(desc);

                if (s->regs[GEM_DMACFG] & GEM_DMACFG_ADDR_64B) {
                    packet_desc_addr = s->regs[GEM_TBQPH];
@@ -1252,7 +1296,7 @@ static void gem_transmit(CadenceGEMState *s)
                } else {
                    packet_desc_addr = 0;
                }
                packet_desc_addr |= s->regs[GEM_TXQBASE];
                packet_desc_addr |= gem_get_tx_queue_base_addr(s, q);
            } else {
                packet_desc_addr += 4 * gem_get_desc_len(s, false);
            }
@@ -1264,7 +1308,10 @@ static void gem_transmit(CadenceGEMState *s)

        if (tx_desc_get_used(desc)) {
            s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_USED;
            s->regs[GEM_ISR] |= GEM_INT_TXUSED & ~(s->regs[GEM_IMR]);
            /* IRQ TXUSED is defined only for queue 0 */
            if (q == 0) {
                gem_set_isr(s, 0, GEM_INT_TXUSED);
            }
            gem_update_int_status(s);
        }
    }
@@ -1314,10 +1361,12 @@ static void gem_reset(DeviceState *d)
    s->regs[GEM_TXPARTIALSF] = 0x000003ff;
    s->regs[GEM_RXPARTIALSF] = 0x000003ff;
    s->regs[GEM_MODID] = s->revision;
    s->regs[GEM_DESCONF] = 0x02500111;
    s->regs[GEM_DESCONF2] = 0x2ab13fff;
    s->regs[GEM_DESCONF] = 0x02D00111;
    s->regs[GEM_DESCONF2] = 0x2ab10000 | s->jumbo_max_len;
    s->regs[GEM_DESCONF5] = 0x002f2045;
    s->regs[GEM_DESCONF6] = GEM_DESCONF6_64B_MASK;
    s->regs[GEM_INT_Q1_MASK] = 0x00000CE6;
    s->regs[GEM_JUMBO_MAX_LEN] = s->jumbo_max_len;

    if (s->num_priority_queues > 1) {
        queues_mask = MAKE_64BIT_MASK(1, s->num_priority_queues - 1);
@@ -1458,7 +1507,7 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val,
        if (!(val & GEM_NWCTRL_TXENA)) {
            /* Reset to start of Q when transmit disabled. */
            for (i = 0; i < s->num_priority_queues; i++) {
                s->tx_desc_addr[i] = s->regs[GEM_TXQBASE];
                s->tx_desc_addr[i] = gem_get_tx_queue_base_addr(s, i);
            }
        }
        if (gem_can_receive(qemu_get_queue(s->nic))) {
@@ -1488,6 +1537,9 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val,
        s->regs[GEM_IMR] &= ~val;
        gem_update_int_status(s);
        break;
    case GEM_JUMBO_MAX_LEN:
        s->regs[GEM_JUMBO_MAX_LEN] = val & MAX_JUMBO_FRAME_SIZE_MASK;
        break;
    case GEM_INT_Q1_ENABLE ... GEM_INT_Q7_ENABLE:
        s->regs[GEM_INT_Q1_MASK + offset - GEM_INT_Q1_ENABLE] &= ~val;
        gem_update_int_status(s);
@@ -1582,6 +1634,12 @@ static void gem_realize(DeviceState *dev, Error **errp)

    s->nic = qemu_new_nic(&net_gem_info, &s->conf,
                          object_get_typename(OBJECT(dev)), dev->id, s);

    if (s->jumbo_max_len > MAX_FRAME_SIZE) {
        error_setg(errp, "jumbo-max-len is greater than %d",
                  MAX_FRAME_SIZE);
        return;
    }
}

static void gem_init(Object *obj)
@@ -1630,6 +1688,8 @@ static Property gem_properties[] = {
                      num_type1_screeners, 4),
    DEFINE_PROP_UINT8("num-type2-screeners", CadenceGEMState,
                      num_type2_screeners, 4),
    DEFINE_PROP_UINT16("jumbo-max-len", CadenceGEMState,
                       jumbo_max_len, 10240),
    DEFINE_PROP_END_OF_LIST(),
};

+7 −3
Original line number Diff line number Diff line
@@ -34,9 +34,9 @@
*/

#include "qemu/osdep.h"
#include "qemu/log.h"
#include "net/net.h"
#include "net/tap.h"
#include "hw/hw.h"
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
#include "sysemu/runstate.h"
@@ -2816,11 +2816,15 @@ e1000e_set_psrctl(E1000ECore *core, int index, uint32_t val)
    if (core->mac[RCTL] & E1000_RCTL_DTYP_MASK) {

        if ((val & E1000_PSRCTL_BSIZE0_MASK) == 0) {
            hw_error("e1000e: PSRCTL.BSIZE0 cannot be zero");
            qemu_log_mask(LOG_GUEST_ERROR,
                          "e1000e: PSRCTL.BSIZE0 cannot be zero");
            return;
        }

        if ((val & E1000_PSRCTL_BSIZE1_MASK) == 0) {
            hw_error("e1000e: PSRCTL.BSIZE1 cannot be zero");
            qemu_log_mask(LOG_GUEST_ERROR,
                          "e1000e: PSRCTL.BSIZE1 cannot be zero");
            return;
        }
    }

Loading