cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

allwinner-sun8i-emac.c (29962B)


      1/*
      2 * Allwinner Sun8i Ethernet MAC emulation
      3 *
      4 * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
      5 *
      6 * This program is free software: you can redistribute it and/or modify
      7 * it under the terms of the GNU General Public License as published by
      8 * the Free Software Foundation, either version 2 of the License, or
      9 * (at your option) any later version.
     10 *
     11 * This program is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 * GNU General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU General Public License
     17 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     18 */
     19
     20#include "qemu/osdep.h"
     21#include "qemu/units.h"
     22#include "qapi/error.h"
     23#include "hw/sysbus.h"
     24#include "migration/vmstate.h"
     25#include "net/net.h"
     26#include "hw/irq.h"
     27#include "hw/qdev-properties.h"
     28#include "qemu/log.h"
     29#include "trace.h"
     30#include "net/checksum.h"
     31#include "qemu/module.h"
     32#include "exec/cpu-common.h"
     33#include "sysemu/dma.h"
     34#include "hw/net/allwinner-sun8i-emac.h"
     35
     36/* EMAC register offsets */
     37enum {
     38    REG_BASIC_CTL_0        = 0x0000, /* Basic Control 0 */
     39    REG_BASIC_CTL_1        = 0x0004, /* Basic Control 1 */
     40    REG_INT_STA            = 0x0008, /* Interrupt Status */
     41    REG_INT_EN             = 0x000C, /* Interrupt Enable */
     42    REG_TX_CTL_0           = 0x0010, /* Transmit Control 0 */
     43    REG_TX_CTL_1           = 0x0014, /* Transmit Control 1 */
     44    REG_TX_FLOW_CTL        = 0x001C, /* Transmit Flow Control */
     45    REG_TX_DMA_DESC_LIST   = 0x0020, /* Transmit Descriptor List Address */
     46    REG_RX_CTL_0           = 0x0024, /* Receive Control 0 */
     47    REG_RX_CTL_1           = 0x0028, /* Receive Control 1 */
     48    REG_RX_DMA_DESC_LIST   = 0x0034, /* Receive Descriptor List Address */
     49    REG_FRM_FLT            = 0x0038, /* Receive Frame Filter */
     50    REG_RX_HASH_0          = 0x0040, /* Receive Hash Table 0 */
     51    REG_RX_HASH_1          = 0x0044, /* Receive Hash Table 1 */
     52    REG_MII_CMD            = 0x0048, /* Management Interface Command */
     53    REG_MII_DATA           = 0x004C, /* Management Interface Data */
     54    REG_ADDR_HIGH          = 0x0050, /* MAC Address High */
     55    REG_ADDR_LOW           = 0x0054, /* MAC Address Low */
     56    REG_TX_DMA_STA         = 0x00B0, /* Transmit DMA Status */
     57    REG_TX_CUR_DESC        = 0x00B4, /* Transmit Current Descriptor */
     58    REG_TX_CUR_BUF         = 0x00B8, /* Transmit Current Buffer */
     59    REG_RX_DMA_STA         = 0x00C0, /* Receive DMA Status */
     60    REG_RX_CUR_DESC        = 0x00C4, /* Receive Current Descriptor */
     61    REG_RX_CUR_BUF         = 0x00C8, /* Receive Current Buffer */
     62    REG_RGMII_STA          = 0x00D0, /* RGMII Status */
     63};
     64
     65/* EMAC register flags */
     66enum {
     67    BASIC_CTL0_100Mbps     = (0b11 << 2),
     68    BASIC_CTL0_FD          = (1 << 0),
     69    BASIC_CTL1_SOFTRST     = (1 << 0),
     70};
     71
     72enum {
     73    INT_STA_RGMII_LINK     = (1 << 16),
     74    INT_STA_RX_EARLY       = (1 << 13),
     75    INT_STA_RX_OVERFLOW    = (1 << 12),
     76    INT_STA_RX_TIMEOUT     = (1 << 11),
     77    INT_STA_RX_DMA_STOP    = (1 << 10),
     78    INT_STA_RX_BUF_UA      = (1 << 9),
     79    INT_STA_RX             = (1 << 8),
     80    INT_STA_TX_EARLY       = (1 << 5),
     81    INT_STA_TX_UNDERFLOW   = (1 << 4),
     82    INT_STA_TX_TIMEOUT     = (1 << 3),
     83    INT_STA_TX_BUF_UA      = (1 << 2),
     84    INT_STA_TX_DMA_STOP    = (1 << 1),
     85    INT_STA_TX             = (1 << 0),
     86};
     87
     88enum {
     89    INT_EN_RX_EARLY        = (1 << 13),
     90    INT_EN_RX_OVERFLOW     = (1 << 12),
     91    INT_EN_RX_TIMEOUT      = (1 << 11),
     92    INT_EN_RX_DMA_STOP     = (1 << 10),
     93    INT_EN_RX_BUF_UA       = (1 << 9),
     94    INT_EN_RX              = (1 << 8),
     95    INT_EN_TX_EARLY        = (1 << 5),
     96    INT_EN_TX_UNDERFLOW    = (1 << 4),
     97    INT_EN_TX_TIMEOUT      = (1 << 3),
     98    INT_EN_TX_BUF_UA       = (1 << 2),
     99    INT_EN_TX_DMA_STOP     = (1 << 1),
    100    INT_EN_TX              = (1 << 0),
    101};
    102
    103enum {
    104    TX_CTL0_TX_EN          = (1 << 31),
    105    TX_CTL1_TX_DMA_START   = (1 << 31),
    106    TX_CTL1_TX_DMA_EN      = (1 << 30),
    107    TX_CTL1_TX_FLUSH       = (1 << 0),
    108};
    109
    110enum {
    111    RX_CTL0_RX_EN          = (1 << 31),
    112    RX_CTL0_STRIP_FCS      = (1 << 28),
    113    RX_CTL0_CRC_IPV4       = (1 << 27),
    114};
    115
    116enum {
    117    RX_CTL1_RX_DMA_START   = (1 << 31),
    118    RX_CTL1_RX_DMA_EN      = (1 << 30),
    119    RX_CTL1_RX_MD          = (1 << 1),
    120};
    121
    122enum {
    123    RX_FRM_FLT_DIS_ADDR    = (1 << 31),
    124};
    125
    126enum {
    127    MII_CMD_PHY_ADDR_SHIFT = (12),
    128    MII_CMD_PHY_ADDR_MASK  = (0xf000),
    129    MII_CMD_PHY_REG_SHIFT  = (4),
    130    MII_CMD_PHY_REG_MASK   = (0xf0),
    131    MII_CMD_PHY_RW         = (1 << 1),
    132    MII_CMD_PHY_BUSY       = (1 << 0),
    133};
    134
    135enum {
    136    TX_DMA_STA_STOP        = (0b000),
    137    TX_DMA_STA_RUN_FETCH   = (0b001),
    138    TX_DMA_STA_WAIT_STA    = (0b010),
    139};
    140
    141enum {
    142    RX_DMA_STA_STOP        = (0b000),
    143    RX_DMA_STA_RUN_FETCH   = (0b001),
    144    RX_DMA_STA_WAIT_FRM    = (0b011),
    145};
    146
    147/* EMAC register reset values */
    148enum {
    149    REG_BASIC_CTL_1_RST    = 0x08000000,
    150};
    151
    152/* EMAC constants */
    153enum {
    154    AW_SUN8I_EMAC_MIN_PKT_SZ  = 64
    155};
    156
    157/* Transmit/receive frame descriptor */
    158typedef struct FrameDescriptor {
    159    uint32_t status;
    160    uint32_t status2;
    161    uint32_t addr;
    162    uint32_t next;
    163} FrameDescriptor;
    164
    165/* Frame descriptor flags */
    166enum {
    167    DESC_STATUS_CTL                 = (1 << 31),
    168    DESC_STATUS2_BUF_SIZE_MASK      = (0x7ff),
    169};
    170
    171/* Transmit frame descriptor flags */
    172enum {
    173    TX_DESC_STATUS_LENGTH_ERR       = (1 << 14),
    174    TX_DESC_STATUS2_FIRST_DESC      = (1 << 29),
    175    TX_DESC_STATUS2_LAST_DESC       = (1 << 30),
    176    TX_DESC_STATUS2_CHECKSUM_MASK   = (0x3 << 27),
    177};
    178
    179/* Receive frame descriptor flags */
    180enum {
    181    RX_DESC_STATUS_FIRST_DESC       = (1 << 9),
    182    RX_DESC_STATUS_LAST_DESC        = (1 << 8),
    183    RX_DESC_STATUS_FRM_LEN_MASK     = (0x3fff0000),
    184    RX_DESC_STATUS_FRM_LEN_SHIFT    = (16),
    185    RX_DESC_STATUS_NO_BUF           = (1 << 14),
    186    RX_DESC_STATUS_HEADER_ERR       = (1 << 7),
    187    RX_DESC_STATUS_LENGTH_ERR       = (1 << 4),
    188    RX_DESC_STATUS_CRC_ERR          = (1 << 1),
    189    RX_DESC_STATUS_PAYLOAD_ERR      = (1 << 0),
    190    RX_DESC_STATUS2_RX_INT_CTL      = (1 << 31),
    191};
    192
    193/* MII register offsets */
    194enum {
    195    MII_REG_CR                      = (0x0), /* Control */
    196    MII_REG_ST                      = (0x1), /* Status */
    197    MII_REG_ID_HIGH                 = (0x2), /* Identifier High */
    198    MII_REG_ID_LOW                  = (0x3), /* Identifier Low */
    199    MII_REG_ADV                     = (0x4), /* Advertised abilities */
    200    MII_REG_LPA                     = (0x5), /* Link partner abilities */
    201};
    202
    203/* MII register flags */
    204enum {
    205    MII_REG_CR_RESET                = (1 << 15),
    206    MII_REG_CR_POWERDOWN            = (1 << 11),
    207    MII_REG_CR_10Mbit               = (0),
    208    MII_REG_CR_100Mbit              = (1 << 13),
    209    MII_REG_CR_1000Mbit             = (1 << 6),
    210    MII_REG_CR_AUTO_NEG             = (1 << 12),
    211    MII_REG_CR_AUTO_NEG_RESTART     = (1 << 9),
    212    MII_REG_CR_FULLDUPLEX           = (1 << 8),
    213};
    214
    215enum {
    216    MII_REG_ST_100BASE_T4           = (1 << 15),
    217    MII_REG_ST_100BASE_X_FD         = (1 << 14),
    218    MII_REG_ST_100BASE_X_HD         = (1 << 13),
    219    MII_REG_ST_10_FD                = (1 << 12),
    220    MII_REG_ST_10_HD                = (1 << 11),
    221    MII_REG_ST_100BASE_T2_FD        = (1 << 10),
    222    MII_REG_ST_100BASE_T2_HD        = (1 << 9),
    223    MII_REG_ST_AUTONEG_COMPLETE     = (1 << 5),
    224    MII_REG_ST_AUTONEG_AVAIL        = (1 << 3),
    225    MII_REG_ST_LINK_UP              = (1 << 2),
    226};
    227
    228enum {
    229    MII_REG_LPA_10_HD               = (1 << 5),
    230    MII_REG_LPA_10_FD               = (1 << 6),
    231    MII_REG_LPA_100_HD              = (1 << 7),
    232    MII_REG_LPA_100_FD              = (1 << 8),
    233    MII_REG_LPA_PAUSE               = (1 << 10),
    234    MII_REG_LPA_ASYMPAUSE           = (1 << 11),
    235};
    236
    237/* MII constants */
    238enum {
    239    MII_PHY_ID_HIGH                 = 0x0044,
    240    MII_PHY_ID_LOW                  = 0x1400,
    241};
    242
    243static void allwinner_sun8i_emac_mii_set_link(AwSun8iEmacState *s,
    244                                              bool link_active)
    245{
    246    if (link_active) {
    247        s->mii_st |= MII_REG_ST_LINK_UP;
    248    } else {
    249        s->mii_st &= ~MII_REG_ST_LINK_UP;
    250    }
    251}
    252
    253static void allwinner_sun8i_emac_mii_reset(AwSun8iEmacState *s,
    254                                           bool link_active)
    255{
    256    s->mii_cr = MII_REG_CR_100Mbit | MII_REG_CR_AUTO_NEG |
    257                MII_REG_CR_FULLDUPLEX;
    258    s->mii_st = MII_REG_ST_100BASE_T4 | MII_REG_ST_100BASE_X_FD |
    259                MII_REG_ST_100BASE_X_HD | MII_REG_ST_10_FD | MII_REG_ST_10_HD |
    260                MII_REG_ST_100BASE_T2_FD | MII_REG_ST_100BASE_T2_HD |
    261                MII_REG_ST_AUTONEG_COMPLETE | MII_REG_ST_AUTONEG_AVAIL;
    262    s->mii_adv = 0;
    263
    264    allwinner_sun8i_emac_mii_set_link(s, link_active);
    265}
    266
    267static void allwinner_sun8i_emac_mii_cmd(AwSun8iEmacState *s)
    268{
    269    uint8_t addr, reg;
    270
    271    addr = (s->mii_cmd & MII_CMD_PHY_ADDR_MASK) >> MII_CMD_PHY_ADDR_SHIFT;
    272    reg = (s->mii_cmd & MII_CMD_PHY_REG_MASK) >> MII_CMD_PHY_REG_SHIFT;
    273
    274    if (addr != s->mii_phy_addr) {
    275        return;
    276    }
    277
    278    /* Read or write a PHY register? */
    279    if (s->mii_cmd & MII_CMD_PHY_RW) {
    280        trace_allwinner_sun8i_emac_mii_write_reg(reg, s->mii_data);
    281
    282        switch (reg) {
    283        case MII_REG_CR:
    284            if (s->mii_data & MII_REG_CR_RESET) {
    285                allwinner_sun8i_emac_mii_reset(s, s->mii_st &
    286                                                  MII_REG_ST_LINK_UP);
    287            } else {
    288                s->mii_cr = s->mii_data & ~(MII_REG_CR_RESET |
    289                                            MII_REG_CR_AUTO_NEG_RESTART);
    290            }
    291            break;
    292        case MII_REG_ADV:
    293            s->mii_adv = s->mii_data;
    294            break;
    295        case MII_REG_ID_HIGH:
    296        case MII_REG_ID_LOW:
    297        case MII_REG_LPA:
    298            break;
    299        default:
    300            qemu_log_mask(LOG_UNIMP, "allwinner-h3-emac: write access to "
    301                                     "unknown MII register 0x%x\n", reg);
    302            break;
    303        }
    304    } else {
    305        switch (reg) {
    306        case MII_REG_CR:
    307            s->mii_data = s->mii_cr;
    308            break;
    309        case MII_REG_ST:
    310            s->mii_data = s->mii_st;
    311            break;
    312        case MII_REG_ID_HIGH:
    313            s->mii_data = MII_PHY_ID_HIGH;
    314            break;
    315        case MII_REG_ID_LOW:
    316            s->mii_data = MII_PHY_ID_LOW;
    317            break;
    318        case MII_REG_ADV:
    319            s->mii_data = s->mii_adv;
    320            break;
    321        case MII_REG_LPA:
    322            s->mii_data = MII_REG_LPA_10_HD | MII_REG_LPA_10_FD |
    323                          MII_REG_LPA_100_HD | MII_REG_LPA_100_FD |
    324                          MII_REG_LPA_PAUSE | MII_REG_LPA_ASYMPAUSE;
    325            break;
    326        default:
    327            qemu_log_mask(LOG_UNIMP, "allwinner-h3-emac: read access to "
    328                                     "unknown MII register 0x%x\n", reg);
    329            s->mii_data = 0;
    330            break;
    331        }
    332
    333        trace_allwinner_sun8i_emac_mii_read_reg(reg, s->mii_data);
    334    }
    335}
    336
    337static void allwinner_sun8i_emac_update_irq(AwSun8iEmacState *s)
    338{
    339    qemu_set_irq(s->irq, (s->int_sta & s->int_en) != 0);
    340}
    341
    342static bool allwinner_sun8i_emac_desc_owned(FrameDescriptor *desc,
    343                                            size_t min_buf_size)
    344{
    345    return (desc->status & DESC_STATUS_CTL) && (min_buf_size == 0 ||
    346           (desc->status2 & DESC_STATUS2_BUF_SIZE_MASK) >= min_buf_size);
    347}
    348
    349static void allwinner_sun8i_emac_get_desc(AwSun8iEmacState *s,
    350                                          FrameDescriptor *desc,
    351                                          uint32_t phys_addr)
    352{
    353    dma_memory_read(&s->dma_as, phys_addr, desc, sizeof(*desc));
    354}
    355
    356static uint32_t allwinner_sun8i_emac_next_desc(AwSun8iEmacState *s,
    357                                               FrameDescriptor *desc)
    358{
    359    const uint32_t nxt = desc->next;
    360    allwinner_sun8i_emac_get_desc(s, desc, nxt);
    361    return nxt;
    362}
    363
    364static uint32_t allwinner_sun8i_emac_find_desc(AwSun8iEmacState *s,
    365                                               FrameDescriptor *desc,
    366                                               uint32_t start_addr,
    367                                               size_t min_size)
    368{
    369    uint32_t desc_addr = start_addr;
    370
    371    /* Note that the list is a cycle. Last entry points back to the head. */
    372    while (desc_addr != 0) {
    373        allwinner_sun8i_emac_get_desc(s, desc, desc_addr);
    374
    375        if (allwinner_sun8i_emac_desc_owned(desc, min_size)) {
    376            return desc_addr;
    377        } else if (desc->next == start_addr) {
    378            break;
    379        } else {
    380            desc_addr = desc->next;
    381        }
    382    }
    383
    384    return 0;
    385}
    386
    387static uint32_t allwinner_sun8i_emac_rx_desc(AwSun8iEmacState *s,
    388                                             FrameDescriptor *desc,
    389                                             size_t min_size)
    390{
    391    return allwinner_sun8i_emac_find_desc(s, desc, s->rx_desc_curr, min_size);
    392}
    393
    394static uint32_t allwinner_sun8i_emac_tx_desc(AwSun8iEmacState *s,
    395                                             FrameDescriptor *desc)
    396{
    397    allwinner_sun8i_emac_get_desc(s, desc, s->tx_desc_curr);
    398    return s->tx_desc_curr;
    399}
    400
    401static void allwinner_sun8i_emac_flush_desc(AwSun8iEmacState *s,
    402                                            FrameDescriptor *desc,
    403                                            uint32_t phys_addr)
    404{
    405    dma_memory_write(&s->dma_as, phys_addr, desc, sizeof(*desc));
    406}
    407
    408static bool allwinner_sun8i_emac_can_receive(NetClientState *nc)
    409{
    410    AwSun8iEmacState *s = qemu_get_nic_opaque(nc);
    411    FrameDescriptor desc;
    412
    413    return (s->rx_ctl0 & RX_CTL0_RX_EN) &&
    414           (allwinner_sun8i_emac_rx_desc(s, &desc, 0) != 0);
    415}
    416
    417static ssize_t allwinner_sun8i_emac_receive(NetClientState *nc,
    418                                            const uint8_t *buf,
    419                                            size_t size)
    420{
    421    AwSun8iEmacState *s = qemu_get_nic_opaque(nc);
    422    FrameDescriptor desc;
    423    size_t bytes_left = size;
    424    size_t desc_bytes = 0;
    425    size_t pad_fcs_size = 4;
    426    size_t padding = 0;
    427
    428    if (!(s->rx_ctl0 & RX_CTL0_RX_EN)) {
    429        return -1;
    430    }
    431
    432    s->rx_desc_curr = allwinner_sun8i_emac_rx_desc(s, &desc,
    433                                                   AW_SUN8I_EMAC_MIN_PKT_SZ);
    434    if (!s->rx_desc_curr) {
    435        s->int_sta |= INT_STA_RX_BUF_UA;
    436    }
    437
    438    /* Keep filling RX descriptors until the whole frame is written */
    439    while (s->rx_desc_curr && bytes_left > 0) {
    440        desc.status &= ~DESC_STATUS_CTL;
    441        desc.status &= ~RX_DESC_STATUS_FRM_LEN_MASK;
    442
    443        if (bytes_left == size) {
    444            desc.status |= RX_DESC_STATUS_FIRST_DESC;
    445        }
    446
    447        if ((desc.status2 & DESC_STATUS2_BUF_SIZE_MASK) <
    448            (bytes_left + pad_fcs_size)) {
    449            desc_bytes = desc.status2 & DESC_STATUS2_BUF_SIZE_MASK;
    450            desc.status |= desc_bytes << RX_DESC_STATUS_FRM_LEN_SHIFT;
    451        } else {
    452            padding = pad_fcs_size;
    453            if (bytes_left < AW_SUN8I_EMAC_MIN_PKT_SZ) {
    454                padding += (AW_SUN8I_EMAC_MIN_PKT_SZ - bytes_left);
    455            }
    456
    457            desc_bytes = (bytes_left);
    458            desc.status |= RX_DESC_STATUS_LAST_DESC;
    459            desc.status |= (bytes_left + padding)
    460                            << RX_DESC_STATUS_FRM_LEN_SHIFT;
    461        }
    462
    463        dma_memory_write(&s->dma_as, desc.addr, buf, desc_bytes);
    464        allwinner_sun8i_emac_flush_desc(s, &desc, s->rx_desc_curr);
    465        trace_allwinner_sun8i_emac_receive(s->rx_desc_curr, desc.addr,
    466                                           desc_bytes);
    467
    468        /* Check if frame needs to raise the receive interrupt */
    469        if (!(desc.status2 & RX_DESC_STATUS2_RX_INT_CTL)) {
    470            s->int_sta |= INT_STA_RX;
    471        }
    472
    473        /* Increment variables */
    474        buf += desc_bytes;
    475        bytes_left -= desc_bytes;
    476
    477        /* Move to the next descriptor */
    478        s->rx_desc_curr = allwinner_sun8i_emac_find_desc(s, &desc, desc.next,
    479                                                         AW_SUN8I_EMAC_MIN_PKT_SZ);
    480        if (!s->rx_desc_curr) {
    481            /* Not enough buffer space available */
    482            s->int_sta |= INT_STA_RX_BUF_UA;
    483            s->rx_desc_curr = s->rx_desc_head;
    484            break;
    485        }
    486    }
    487
    488    /* Report receive DMA is finished */
    489    s->rx_ctl1 &= ~RX_CTL1_RX_DMA_START;
    490    allwinner_sun8i_emac_update_irq(s);
    491
    492    return size;
    493}
    494
    495static void allwinner_sun8i_emac_transmit(AwSun8iEmacState *s)
    496{
    497    NetClientState *nc = qemu_get_queue(s->nic);
    498    FrameDescriptor desc;
    499    size_t bytes = 0;
    500    size_t packet_bytes = 0;
    501    size_t transmitted = 0;
    502    static uint8_t packet_buf[2048];
    503
    504    s->tx_desc_curr = allwinner_sun8i_emac_tx_desc(s, &desc);
    505
    506    /* Read all transmit descriptors */
    507    while (allwinner_sun8i_emac_desc_owned(&desc, 0)) {
    508
    509        /* Read from physical memory into packet buffer */
    510        bytes = desc.status2 & DESC_STATUS2_BUF_SIZE_MASK;
    511        if (bytes + packet_bytes > sizeof(packet_buf)) {
    512            desc.status |= TX_DESC_STATUS_LENGTH_ERR;
    513            break;
    514        }
    515        dma_memory_read(&s->dma_as, desc.addr, packet_buf + packet_bytes, bytes);
    516        packet_bytes += bytes;
    517        desc.status &= ~DESC_STATUS_CTL;
    518        allwinner_sun8i_emac_flush_desc(s, &desc, s->tx_desc_curr);
    519
    520        /* After the last descriptor, send the packet */
    521        if (desc.status2 & TX_DESC_STATUS2_LAST_DESC) {
    522            if (desc.status2 & TX_DESC_STATUS2_CHECKSUM_MASK) {
    523                net_checksum_calculate(packet_buf, packet_bytes, CSUM_ALL);
    524            }
    525
    526            qemu_send_packet(nc, packet_buf, packet_bytes);
    527            trace_allwinner_sun8i_emac_transmit(s->tx_desc_curr, desc.addr,
    528                                                bytes);
    529
    530            packet_bytes = 0;
    531            transmitted++;
    532        }
    533        s->tx_desc_curr = allwinner_sun8i_emac_next_desc(s, &desc);
    534    }
    535
    536    /* Raise transmit completed interrupt */
    537    if (transmitted > 0) {
    538        s->int_sta |= INT_STA_TX;
    539        s->tx_ctl1 &= ~TX_CTL1_TX_DMA_START;
    540        allwinner_sun8i_emac_update_irq(s);
    541    }
    542}
    543
    544static void allwinner_sun8i_emac_reset(DeviceState *dev)
    545{
    546    AwSun8iEmacState *s = AW_SUN8I_EMAC(dev);
    547    NetClientState *nc = qemu_get_queue(s->nic);
    548
    549    trace_allwinner_sun8i_emac_reset();
    550
    551    s->mii_cmd = 0;
    552    s->mii_data = 0;
    553    s->basic_ctl0 = 0;
    554    s->basic_ctl1 = REG_BASIC_CTL_1_RST;
    555    s->int_en = 0;
    556    s->int_sta = 0;
    557    s->frm_flt = 0;
    558    s->rx_ctl0 = 0;
    559    s->rx_ctl1 = RX_CTL1_RX_MD;
    560    s->rx_desc_head = 0;
    561    s->rx_desc_curr = 0;
    562    s->tx_ctl0 = 0;
    563    s->tx_ctl1 = 0;
    564    s->tx_desc_head = 0;
    565    s->tx_desc_curr = 0;
    566    s->tx_flowctl = 0;
    567
    568    allwinner_sun8i_emac_mii_reset(s, !nc->link_down);
    569}
    570
    571static uint64_t allwinner_sun8i_emac_read(void *opaque, hwaddr offset,
    572                                          unsigned size)
    573{
    574    AwSun8iEmacState *s = AW_SUN8I_EMAC(opaque);
    575    uint64_t value = 0;
    576    FrameDescriptor desc;
    577
    578    switch (offset) {
    579    case REG_BASIC_CTL_0:       /* Basic Control 0 */
    580        value = s->basic_ctl0;
    581        break;
    582    case REG_BASIC_CTL_1:       /* Basic Control 1 */
    583        value = s->basic_ctl1;
    584        break;
    585    case REG_INT_STA:           /* Interrupt Status */
    586        value = s->int_sta;
    587        break;
    588    case REG_INT_EN:            /* Interrupt Enable */
    589        value = s->int_en;
    590        break;
    591    case REG_TX_CTL_0:          /* Transmit Control 0 */
    592        value = s->tx_ctl0;
    593        break;
    594    case REG_TX_CTL_1:          /* Transmit Control 1 */
    595        value = s->tx_ctl1;
    596        break;
    597    case REG_TX_FLOW_CTL:       /* Transmit Flow Control */
    598        value = s->tx_flowctl;
    599        break;
    600    case REG_TX_DMA_DESC_LIST:  /* Transmit Descriptor List Address */
    601        value = s->tx_desc_head;
    602        break;
    603    case REG_RX_CTL_0:          /* Receive Control 0 */
    604        value = s->rx_ctl0;
    605        break;
    606    case REG_RX_CTL_1:          /* Receive Control 1 */
    607        value = s->rx_ctl1;
    608        break;
    609    case REG_RX_DMA_DESC_LIST:  /* Receive Descriptor List Address */
    610        value = s->rx_desc_head;
    611        break;
    612    case REG_FRM_FLT:           /* Receive Frame Filter */
    613        value = s->frm_flt;
    614        break;
    615    case REG_RX_HASH_0:         /* Receive Hash Table 0 */
    616    case REG_RX_HASH_1:         /* Receive Hash Table 1 */
    617        break;
    618    case REG_MII_CMD:           /* Management Interface Command */
    619        value = s->mii_cmd;
    620        break;
    621    case REG_MII_DATA:          /* Management Interface Data */
    622        value = s->mii_data;
    623        break;
    624    case REG_ADDR_HIGH:         /* MAC Address High */
    625        value = lduw_le_p(s->conf.macaddr.a + 4);
    626        break;
    627    case REG_ADDR_LOW:          /* MAC Address Low */
    628        value = ldl_le_p(s->conf.macaddr.a);
    629        break;
    630    case REG_TX_DMA_STA:        /* Transmit DMA Status */
    631        break;
    632    case REG_TX_CUR_DESC:       /* Transmit Current Descriptor */
    633        value = s->tx_desc_curr;
    634        break;
    635    case REG_TX_CUR_BUF:        /* Transmit Current Buffer */
    636        if (s->tx_desc_curr != 0) {
    637            dma_memory_read(&s->dma_as, s->tx_desc_curr, &desc, sizeof(desc));
    638            value = desc.addr;
    639        } else {
    640            value = 0;
    641        }
    642        break;
    643    case REG_RX_DMA_STA:        /* Receive DMA Status */
    644        break;
    645    case REG_RX_CUR_DESC:       /* Receive Current Descriptor */
    646        value = s->rx_desc_curr;
    647        break;
    648    case REG_RX_CUR_BUF:        /* Receive Current Buffer */
    649        if (s->rx_desc_curr != 0) {
    650            dma_memory_read(&s->dma_as, s->rx_desc_curr, &desc, sizeof(desc));
    651            value = desc.addr;
    652        } else {
    653            value = 0;
    654        }
    655        break;
    656    case REG_RGMII_STA:         /* RGMII Status */
    657        break;
    658    default:
    659        qemu_log_mask(LOG_UNIMP, "allwinner-h3-emac: read access to unknown "
    660                                 "EMAC register 0x" TARGET_FMT_plx "\n",
    661                                  offset);
    662    }
    663
    664    trace_allwinner_sun8i_emac_read(offset, value);
    665    return value;
    666}
    667
    668static void allwinner_sun8i_emac_write(void *opaque, hwaddr offset,
    669                                       uint64_t value, unsigned size)
    670{
    671    AwSun8iEmacState *s = AW_SUN8I_EMAC(opaque);
    672    NetClientState *nc = qemu_get_queue(s->nic);
    673
    674    trace_allwinner_sun8i_emac_write(offset, value);
    675
    676    switch (offset) {
    677    case REG_BASIC_CTL_0:       /* Basic Control 0 */
    678        s->basic_ctl0 = value;
    679        break;
    680    case REG_BASIC_CTL_1:       /* Basic Control 1 */
    681        if (value & BASIC_CTL1_SOFTRST) {
    682            allwinner_sun8i_emac_reset(DEVICE(s));
    683            value &= ~BASIC_CTL1_SOFTRST;
    684        }
    685        s->basic_ctl1 = value;
    686        if (allwinner_sun8i_emac_can_receive(nc)) {
    687            qemu_flush_queued_packets(nc);
    688        }
    689        break;
    690    case REG_INT_STA:           /* Interrupt Status */
    691        s->int_sta &= ~value;
    692        allwinner_sun8i_emac_update_irq(s);
    693        break;
    694    case REG_INT_EN:            /* Interrupt Enable */
    695        s->int_en = value;
    696        allwinner_sun8i_emac_update_irq(s);
    697        break;
    698    case REG_TX_CTL_0:          /* Transmit Control 0 */
    699        s->tx_ctl0 = value;
    700        break;
    701    case REG_TX_CTL_1:          /* Transmit Control 1 */
    702        s->tx_ctl1 = value;
    703        if (value & TX_CTL1_TX_DMA_EN) {
    704            allwinner_sun8i_emac_transmit(s);
    705        }
    706        break;
    707    case REG_TX_FLOW_CTL:       /* Transmit Flow Control */
    708        s->tx_flowctl = value;
    709        break;
    710    case REG_TX_DMA_DESC_LIST:  /* Transmit Descriptor List Address */
    711        s->tx_desc_head = value;
    712        s->tx_desc_curr = value;
    713        break;
    714    case REG_RX_CTL_0:          /* Receive Control 0 */
    715        s->rx_ctl0 = value;
    716        break;
    717    case REG_RX_CTL_1:          /* Receive Control 1 */
    718        s->rx_ctl1 = value | RX_CTL1_RX_MD;
    719        if ((value & RX_CTL1_RX_DMA_EN) &&
    720             allwinner_sun8i_emac_can_receive(nc)) {
    721            qemu_flush_queued_packets(nc);
    722        }
    723        break;
    724    case REG_RX_DMA_DESC_LIST:  /* Receive Descriptor List Address */
    725        s->rx_desc_head = value;
    726        s->rx_desc_curr = value;
    727        break;
    728    case REG_FRM_FLT:           /* Receive Frame Filter */
    729        s->frm_flt = value;
    730        break;
    731    case REG_RX_HASH_0:         /* Receive Hash Table 0 */
    732    case REG_RX_HASH_1:         /* Receive Hash Table 1 */
    733        break;
    734    case REG_MII_CMD:           /* Management Interface Command */
    735        s->mii_cmd = value & ~MII_CMD_PHY_BUSY;
    736        allwinner_sun8i_emac_mii_cmd(s);
    737        break;
    738    case REG_MII_DATA:          /* Management Interface Data */
    739        s->mii_data = value;
    740        break;
    741    case REG_ADDR_HIGH:         /* MAC Address High */
    742        stw_le_p(s->conf.macaddr.a + 4, value);
    743        break;
    744    case REG_ADDR_LOW:          /* MAC Address Low */
    745        stl_le_p(s->conf.macaddr.a, value);
    746        break;
    747    case REG_TX_DMA_STA:        /* Transmit DMA Status */
    748    case REG_TX_CUR_DESC:       /* Transmit Current Descriptor */
    749    case REG_TX_CUR_BUF:        /* Transmit Current Buffer */
    750    case REG_RX_DMA_STA:        /* Receive DMA Status */
    751    case REG_RX_CUR_DESC:       /* Receive Current Descriptor */
    752    case REG_RX_CUR_BUF:        /* Receive Current Buffer */
    753    case REG_RGMII_STA:         /* RGMII Status */
    754        break;
    755    default:
    756        qemu_log_mask(LOG_UNIMP, "allwinner-h3-emac: write access to unknown "
    757                                 "EMAC register 0x" TARGET_FMT_plx "\n",
    758                                  offset);
    759    }
    760}
    761
    762static void allwinner_sun8i_emac_set_link(NetClientState *nc)
    763{
    764    AwSun8iEmacState *s = qemu_get_nic_opaque(nc);
    765
    766    trace_allwinner_sun8i_emac_set_link(!nc->link_down);
    767    allwinner_sun8i_emac_mii_set_link(s, !nc->link_down);
    768}
    769
    770static const MemoryRegionOps allwinner_sun8i_emac_mem_ops = {
    771    .read = allwinner_sun8i_emac_read,
    772    .write = allwinner_sun8i_emac_write,
    773    .endianness = DEVICE_NATIVE_ENDIAN,
    774    .valid = {
    775        .min_access_size = 4,
    776        .max_access_size = 4,
    777    },
    778    .impl.min_access_size = 4,
    779};
    780
    781static NetClientInfo net_allwinner_sun8i_emac_info = {
    782    .type = NET_CLIENT_DRIVER_NIC,
    783    .size = sizeof(NICState),
    784    .can_receive = allwinner_sun8i_emac_can_receive,
    785    .receive = allwinner_sun8i_emac_receive,
    786    .link_status_changed = allwinner_sun8i_emac_set_link,
    787};
    788
    789static void allwinner_sun8i_emac_init(Object *obj)
    790{
    791    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    792    AwSun8iEmacState *s = AW_SUN8I_EMAC(obj);
    793
    794    memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_sun8i_emac_mem_ops,
    795                           s, TYPE_AW_SUN8I_EMAC, 64 * KiB);
    796    sysbus_init_mmio(sbd, &s->iomem);
    797    sysbus_init_irq(sbd, &s->irq);
    798}
    799
    800static void allwinner_sun8i_emac_realize(DeviceState *dev, Error **errp)
    801{
    802    AwSun8iEmacState *s = AW_SUN8I_EMAC(dev);
    803
    804    if (!s->dma_mr) {
    805        error_setg(errp, TYPE_AW_SUN8I_EMAC " 'dma-memory' link not set");
    806        return;
    807    }
    808
    809    address_space_init(&s->dma_as, s->dma_mr, "emac-dma");
    810
    811    qemu_macaddr_default_if_unset(&s->conf.macaddr);
    812    s->nic = qemu_new_nic(&net_allwinner_sun8i_emac_info, &s->conf,
    813                           object_get_typename(OBJECT(dev)), dev->id, s);
    814    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
    815}
    816
    817static Property allwinner_sun8i_emac_properties[] = {
    818    DEFINE_NIC_PROPERTIES(AwSun8iEmacState, conf),
    819    DEFINE_PROP_UINT8("phy-addr", AwSun8iEmacState, mii_phy_addr, 0),
    820    DEFINE_PROP_LINK("dma-memory", AwSun8iEmacState, dma_mr,
    821                     TYPE_MEMORY_REGION, MemoryRegion *),
    822    DEFINE_PROP_END_OF_LIST(),
    823};
    824
    825static int allwinner_sun8i_emac_post_load(void *opaque, int version_id)
    826{
    827    AwSun8iEmacState *s = opaque;
    828
    829    allwinner_sun8i_emac_set_link(qemu_get_queue(s->nic));
    830
    831    return 0;
    832}
    833
    834static const VMStateDescription vmstate_aw_emac = {
    835    .name = "allwinner-sun8i-emac",
    836    .version_id = 1,
    837    .minimum_version_id = 1,
    838    .post_load = allwinner_sun8i_emac_post_load,
    839    .fields = (VMStateField[]) {
    840        VMSTATE_UINT8(mii_phy_addr, AwSun8iEmacState),
    841        VMSTATE_UINT32(mii_cmd, AwSun8iEmacState),
    842        VMSTATE_UINT32(mii_data, AwSun8iEmacState),
    843        VMSTATE_UINT32(mii_cr, AwSun8iEmacState),
    844        VMSTATE_UINT32(mii_st, AwSun8iEmacState),
    845        VMSTATE_UINT32(mii_adv, AwSun8iEmacState),
    846        VMSTATE_UINT32(basic_ctl0, AwSun8iEmacState),
    847        VMSTATE_UINT32(basic_ctl1, AwSun8iEmacState),
    848        VMSTATE_UINT32(int_en, AwSun8iEmacState),
    849        VMSTATE_UINT32(int_sta, AwSun8iEmacState),
    850        VMSTATE_UINT32(frm_flt, AwSun8iEmacState),
    851        VMSTATE_UINT32(rx_ctl0, AwSun8iEmacState),
    852        VMSTATE_UINT32(rx_ctl1, AwSun8iEmacState),
    853        VMSTATE_UINT32(rx_desc_head, AwSun8iEmacState),
    854        VMSTATE_UINT32(rx_desc_curr, AwSun8iEmacState),
    855        VMSTATE_UINT32(tx_ctl0, AwSun8iEmacState),
    856        VMSTATE_UINT32(tx_ctl1, AwSun8iEmacState),
    857        VMSTATE_UINT32(tx_desc_head, AwSun8iEmacState),
    858        VMSTATE_UINT32(tx_desc_curr, AwSun8iEmacState),
    859        VMSTATE_UINT32(tx_flowctl, AwSun8iEmacState),
    860        VMSTATE_END_OF_LIST()
    861    }
    862};
    863
    864static void allwinner_sun8i_emac_class_init(ObjectClass *klass, void *data)
    865{
    866    DeviceClass *dc = DEVICE_CLASS(klass);
    867
    868    dc->realize = allwinner_sun8i_emac_realize;
    869    dc->reset = allwinner_sun8i_emac_reset;
    870    dc->vmsd = &vmstate_aw_emac;
    871    device_class_set_props(dc, allwinner_sun8i_emac_properties);
    872}
    873
    874static const TypeInfo allwinner_sun8i_emac_info = {
    875    .name           = TYPE_AW_SUN8I_EMAC,
    876    .parent         = TYPE_SYS_BUS_DEVICE,
    877    .instance_size  = sizeof(AwSun8iEmacState),
    878    .instance_init  = allwinner_sun8i_emac_init,
    879    .class_init     = allwinner_sun8i_emac_class_init,
    880};
    881
    882static void allwinner_sun8i_emac_register_types(void)
    883{
    884    type_register_static(&allwinner_sun8i_emac_info);
    885}
    886
    887type_init(allwinner_sun8i_emac_register_types)