qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

allwinner_emac.c (15700B)


      1 /*
      2  * Emulation of Allwinner EMAC Fast Ethernet controller and
      3  * Realtek RTL8201CP PHY
      4  *
      5  * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
      6  *
      7  * This model is based on reverse-engineering of Linux kernel driver.
      8  *
      9  * This program is free software; you can redistribute it and/or modify
     10  * it under the terms of the GNU General Public License version 2 as
     11  * published by the Free Software Foundation.
     12  *
     13  * This program is distributed in the hope that it will be useful,
     14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     16  * GNU General Public License for more details.
     17  *
     18  */
     19 
     20 #include "qemu/osdep.h"
     21 #include "hw/sysbus.h"
     22 #include "migration/vmstate.h"
     23 #include "net/net.h"
     24 #include "qemu/fifo8.h"
     25 #include "hw/irq.h"
     26 #include "hw/net/allwinner_emac.h"
     27 #include "hw/qdev-properties.h"
     28 #include "qemu/log.h"
     29 #include "qemu/module.h"
     30 #include <zlib.h>
     31 
     32 static uint8_t padding[60];
     33 
     34 static void mii_set_link(RTL8201CPState *mii, bool link_ok)
     35 {
     36     if (link_ok) {
     37         mii->bmsr |= MII_BMSR_LINK_ST | MII_BMSR_AN_COMP;
     38         mii->anlpar |= MII_ANAR_TXFD | MII_ANAR_10FD | MII_ANAR_10 |
     39                        MII_ANAR_CSMACD;
     40     } else {
     41         mii->bmsr &= ~(MII_BMSR_LINK_ST | MII_BMSR_AN_COMP);
     42         mii->anlpar = MII_ANAR_TX;
     43     }
     44 }
     45 
     46 static void mii_reset(RTL8201CPState *mii, bool link_ok)
     47 {
     48     mii->bmcr = MII_BMCR_FD | MII_BMCR_AUTOEN | MII_BMCR_SPEED;
     49     mii->bmsr = MII_BMSR_100TX_FD | MII_BMSR_100TX_HD | MII_BMSR_10T_FD |
     50                 MII_BMSR_10T_HD | MII_BMSR_MFPS | MII_BMSR_AUTONEG;
     51     mii->anar = MII_ANAR_TXFD | MII_ANAR_TX | MII_ANAR_10FD | MII_ANAR_10 |
     52                 MII_ANAR_CSMACD;
     53     mii->anlpar = MII_ANAR_TX;
     54 
     55     mii_set_link(mii, link_ok);
     56 }
     57 
     58 static uint16_t RTL8201CP_mdio_read(AwEmacState *s, uint8_t addr, uint8_t reg)
     59 {
     60     RTL8201CPState *mii = &s->mii;
     61     uint16_t ret = 0xffff;
     62 
     63     if (addr == s->phy_addr) {
     64         switch (reg) {
     65         case MII_BMCR:
     66             return mii->bmcr;
     67         case MII_BMSR:
     68             return mii->bmsr;
     69         case MII_PHYID1:
     70             return RTL8201CP_PHYID1;
     71         case MII_PHYID2:
     72             return RTL8201CP_PHYID2;
     73         case MII_ANAR:
     74             return mii->anar;
     75         case MII_ANLPAR:
     76             return mii->anlpar;
     77         case MII_ANER:
     78         case MII_NSR:
     79         case MII_LBREMR:
     80         case MII_REC:
     81         case MII_SNRDR:
     82         case MII_TEST:
     83             qemu_log_mask(LOG_UNIMP,
     84                           "allwinner_emac: read from unimpl. mii reg 0x%x\n",
     85                           reg);
     86             return 0;
     87         default:
     88             qemu_log_mask(LOG_GUEST_ERROR,
     89                           "allwinner_emac: read from invalid mii reg 0x%x\n",
     90                           reg);
     91             return 0;
     92         }
     93     }
     94     return ret;
     95 }
     96 
     97 static void RTL8201CP_mdio_write(AwEmacState *s, uint8_t addr, uint8_t reg,
     98                                  uint16_t value)
     99 {
    100     RTL8201CPState *mii = &s->mii;
    101     NetClientState *nc;
    102 
    103     if (addr == s->phy_addr) {
    104         switch (reg) {
    105         case MII_BMCR:
    106             if (value & MII_BMCR_RESET) {
    107                 nc = qemu_get_queue(s->nic);
    108                 mii_reset(mii, !nc->link_down);
    109             } else {
    110                 mii->bmcr = value;
    111             }
    112             break;
    113         case MII_ANAR:
    114             mii->anar = value;
    115             break;
    116         case MII_BMSR:
    117         case MII_PHYID1:
    118         case MII_PHYID2:
    119         case MII_ANLPAR:
    120         case MII_ANER:
    121             qemu_log_mask(LOG_GUEST_ERROR,
    122                           "allwinner_emac: write to read-only mii reg 0x%x\n",
    123                           reg);
    124             break;
    125         case MII_NSR:
    126         case MII_LBREMR:
    127         case MII_REC:
    128         case MII_SNRDR:
    129         case MII_TEST:
    130             qemu_log_mask(LOG_UNIMP,
    131                           "allwinner_emac: write to unimpl. mii reg 0x%x\n",
    132                           reg);
    133             break;
    134         default:
    135             qemu_log_mask(LOG_GUEST_ERROR,
    136                           "allwinner_emac: write to invalid mii reg 0x%x\n",
    137                           reg);
    138         }
    139     }
    140 }
    141 
    142 static void aw_emac_update_irq(AwEmacState *s)
    143 {
    144     qemu_set_irq(s->irq, (s->int_sta & s->int_ctl) != 0);
    145 }
    146 
    147 static void aw_emac_tx_reset(AwEmacState *s, int chan)
    148 {
    149     fifo8_reset(&s->tx_fifo[chan]);
    150     s->tx_length[chan] = 0;
    151 }
    152 
    153 static void aw_emac_rx_reset(AwEmacState *s)
    154 {
    155     fifo8_reset(&s->rx_fifo);
    156     s->rx_num_packets = 0;
    157     s->rx_packet_size = 0;
    158     s->rx_packet_pos = 0;
    159 }
    160 
    161 static void fifo8_push_word(Fifo8 *fifo, uint32_t val)
    162 {
    163     fifo8_push(fifo, val);
    164     fifo8_push(fifo, val >> 8);
    165     fifo8_push(fifo, val >> 16);
    166     fifo8_push(fifo, val >> 24);
    167 }
    168 
    169 static uint32_t fifo8_pop_word(Fifo8 *fifo)
    170 {
    171     uint32_t ret;
    172 
    173     ret = fifo8_pop(fifo);
    174     ret |= fifo8_pop(fifo) << 8;
    175     ret |= fifo8_pop(fifo) << 16;
    176     ret |= fifo8_pop(fifo) << 24;
    177 
    178     return ret;
    179 }
    180 
    181 static bool aw_emac_can_receive(NetClientState *nc)
    182 {
    183     AwEmacState *s = qemu_get_nic_opaque(nc);
    184 
    185     /*
    186      * To avoid packet drops, allow reception only when there is space
    187      * for a full frame: 1522 + 8 (rx headers) + 2 (padding).
    188      */
    189     return (s->ctl & EMAC_CTL_RX_EN) && (fifo8_num_free(&s->rx_fifo) >= 1532);
    190 }
    191 
    192 static ssize_t aw_emac_receive(NetClientState *nc, const uint8_t *buf,
    193                                size_t size)
    194 {
    195     AwEmacState *s = qemu_get_nic_opaque(nc);
    196     Fifo8 *fifo = &s->rx_fifo;
    197     size_t padded_size, total_size;
    198     uint32_t crc;
    199 
    200     padded_size = size > 60 ? size : 60;
    201     total_size = QEMU_ALIGN_UP(RX_HDR_SIZE + padded_size + CRC_SIZE, 4);
    202 
    203     if (!(s->ctl & EMAC_CTL_RX_EN) || (fifo8_num_free(fifo) < total_size)) {
    204         return -1;
    205     }
    206 
    207     fifo8_push_word(fifo, EMAC_UNDOCUMENTED_MAGIC);
    208     fifo8_push_word(fifo, EMAC_RX_HEADER(padded_size + CRC_SIZE,
    209                                          EMAC_RX_IO_DATA_STATUS_OK));
    210     fifo8_push_all(fifo, buf, size);
    211     crc = crc32(~0, buf, size);
    212 
    213     if (padded_size != size) {
    214         fifo8_push_all(fifo, padding, padded_size - size);
    215         crc = crc32(crc, padding, padded_size - size);
    216     }
    217 
    218     fifo8_push_word(fifo, crc);
    219     fifo8_push_all(fifo, padding, QEMU_ALIGN_UP(padded_size, 4) - padded_size);
    220     s->rx_num_packets++;
    221 
    222     s->int_sta |= EMAC_INT_RX;
    223     aw_emac_update_irq(s);
    224 
    225     return size;
    226 }
    227 
    228 static void aw_emac_reset(DeviceState *dev)
    229 {
    230     AwEmacState *s = AW_EMAC(dev);
    231     NetClientState *nc = qemu_get_queue(s->nic);
    232 
    233     s->ctl = 0;
    234     s->tx_mode = 0;
    235     s->int_ctl = 0;
    236     s->int_sta = 0;
    237     s->tx_channel = 0;
    238     s->phy_target = 0;
    239 
    240     aw_emac_tx_reset(s, 0);
    241     aw_emac_tx_reset(s, 1);
    242     aw_emac_rx_reset(s);
    243 
    244     mii_reset(&s->mii, !nc->link_down);
    245 }
    246 
    247 static uint64_t aw_emac_read(void *opaque, hwaddr offset, unsigned size)
    248 {
    249     AwEmacState *s = opaque;
    250     Fifo8 *fifo = &s->rx_fifo;
    251     NetClientState *nc;
    252     uint64_t ret;
    253 
    254     switch (offset) {
    255     case EMAC_CTL_REG:
    256         return s->ctl;
    257     case EMAC_TX_MODE_REG:
    258         return s->tx_mode;
    259     case EMAC_TX_INS_REG:
    260         return s->tx_channel;
    261     case EMAC_RX_CTL_REG:
    262         return s->rx_ctl;
    263     case EMAC_RX_IO_DATA_REG:
    264         if (!s->rx_num_packets) {
    265             qemu_log_mask(LOG_GUEST_ERROR,
    266                           "Read IO data register when no packet available");
    267             return 0;
    268         }
    269 
    270         ret = fifo8_pop_word(fifo);
    271 
    272         switch (s->rx_packet_pos) {
    273         case 0:     /* Word is magic header */
    274             s->rx_packet_pos += 4;
    275             break;
    276         case 4:     /* Word is rx info header */
    277             s->rx_packet_pos += 4;
    278             s->rx_packet_size = QEMU_ALIGN_UP(extract32(ret, 0, 16), 4);
    279             break;
    280         default:    /* Word is packet data */
    281             s->rx_packet_pos += 4;
    282             s->rx_packet_size -= 4;
    283 
    284             if (!s->rx_packet_size) {
    285                 s->rx_packet_pos = 0;
    286                 s->rx_num_packets--;
    287                 nc = qemu_get_queue(s->nic);
    288                 if (aw_emac_can_receive(nc)) {
    289                     qemu_flush_queued_packets(nc);
    290                 }
    291             }
    292         }
    293         return ret;
    294     case EMAC_RX_FBC_REG:
    295         return s->rx_num_packets;
    296     case EMAC_INT_CTL_REG:
    297         return s->int_ctl;
    298     case EMAC_INT_STA_REG:
    299         return s->int_sta;
    300     case EMAC_MAC_MRDD_REG:
    301         return RTL8201CP_mdio_read(s,
    302                                    extract32(s->phy_target, PHY_ADDR_SHIFT, 8),
    303                                    extract32(s->phy_target, PHY_REG_SHIFT, 8));
    304     default:
    305         qemu_log_mask(LOG_UNIMP,
    306                       "allwinner_emac: read access to unknown register 0x"
    307                       TARGET_FMT_plx "\n", offset);
    308         ret = 0;
    309     }
    310 
    311     return ret;
    312 }
    313 
    314 static void aw_emac_write(void *opaque, hwaddr offset, uint64_t value,
    315                           unsigned size)
    316 {
    317     AwEmacState *s = opaque;
    318     Fifo8 *fifo;
    319     NetClientState *nc = qemu_get_queue(s->nic);
    320     int chan;
    321 
    322     switch (offset) {
    323     case EMAC_CTL_REG:
    324         if (value & EMAC_CTL_RESET) {
    325             aw_emac_reset(DEVICE(s));
    326             value &= ~EMAC_CTL_RESET;
    327         }
    328         s->ctl = value;
    329         if (aw_emac_can_receive(nc)) {
    330             qemu_flush_queued_packets(nc);
    331         }
    332         break;
    333     case EMAC_TX_MODE_REG:
    334         s->tx_mode = value;
    335         break;
    336     case EMAC_TX_CTL0_REG:
    337     case EMAC_TX_CTL1_REG:
    338         chan = (offset == EMAC_TX_CTL0_REG ? 0 : 1);
    339         if ((value & 1) && (s->ctl & EMAC_CTL_TX_EN)) {
    340             uint32_t len, ret;
    341             const uint8_t *data;
    342 
    343             fifo = &s->tx_fifo[chan];
    344             len = s->tx_length[chan];
    345 
    346             if (len > fifo8_num_used(fifo)) {
    347                 len = fifo8_num_used(fifo);
    348                 qemu_log_mask(LOG_GUEST_ERROR,
    349                               "allwinner_emac: TX length > fifo data length\n");
    350             }
    351             if (len > 0) {
    352                 data = fifo8_pop_buf(fifo, len, &ret);
    353                 qemu_send_packet(nc, data, ret);
    354                 aw_emac_tx_reset(s, chan);
    355                 /* Raise TX interrupt */
    356                 s->int_sta |= EMAC_INT_TX_CHAN(chan);
    357                 aw_emac_update_irq(s);
    358             }
    359         }
    360         break;
    361     case EMAC_TX_INS_REG:
    362         s->tx_channel = value < NUM_TX_FIFOS ? value : 0;
    363         break;
    364     case EMAC_TX_PL0_REG:
    365     case EMAC_TX_PL1_REG:
    366         chan = (offset == EMAC_TX_PL0_REG ? 0 : 1);
    367         if (value > TX_FIFO_SIZE) {
    368             qemu_log_mask(LOG_GUEST_ERROR,
    369                           "allwinner_emac: invalid TX frame length %d\n",
    370                           (int)value);
    371             value = TX_FIFO_SIZE;
    372         }
    373         s->tx_length[chan] = value;
    374         break;
    375     case EMAC_TX_IO_DATA_REG:
    376         fifo = &s->tx_fifo[s->tx_channel];
    377         if (fifo8_num_free(fifo) < 4) {
    378             qemu_log_mask(LOG_GUEST_ERROR,
    379                           "allwinner_emac: TX data overruns fifo\n");
    380             break;
    381         }
    382         fifo8_push_word(fifo, value);
    383         break;
    384     case EMAC_RX_CTL_REG:
    385         s->rx_ctl = value;
    386         break;
    387     case EMAC_RX_FBC_REG:
    388         if (value == 0) {
    389             aw_emac_rx_reset(s);
    390         }
    391         break;
    392     case EMAC_INT_CTL_REG:
    393         s->int_ctl = value;
    394         aw_emac_update_irq(s);
    395         break;
    396     case EMAC_INT_STA_REG:
    397         s->int_sta &= ~value;
    398         aw_emac_update_irq(s);
    399         break;
    400     case EMAC_MAC_MADR_REG:
    401         s->phy_target = value;
    402         break;
    403     case EMAC_MAC_MWTD_REG:
    404         RTL8201CP_mdio_write(s, extract32(s->phy_target, PHY_ADDR_SHIFT, 8),
    405                              extract32(s->phy_target, PHY_REG_SHIFT, 8), value);
    406         break;
    407     default:
    408         qemu_log_mask(LOG_UNIMP,
    409                       "allwinner_emac: write access to unknown register 0x"
    410                       TARGET_FMT_plx "\n", offset);
    411     }
    412 }
    413 
    414 static void aw_emac_set_link(NetClientState *nc)
    415 {
    416     AwEmacState *s = qemu_get_nic_opaque(nc);
    417 
    418     mii_set_link(&s->mii, !nc->link_down);
    419 }
    420 
    421 static const MemoryRegionOps aw_emac_mem_ops = {
    422     .read = aw_emac_read,
    423     .write = aw_emac_write,
    424     .endianness = DEVICE_NATIVE_ENDIAN,
    425     .valid = {
    426         .min_access_size = 4,
    427         .max_access_size = 4,
    428     },
    429 };
    430 
    431 static NetClientInfo net_aw_emac_info = {
    432     .type = NET_CLIENT_DRIVER_NIC,
    433     .size = sizeof(NICState),
    434     .can_receive = aw_emac_can_receive,
    435     .receive = aw_emac_receive,
    436     .link_status_changed = aw_emac_set_link,
    437 };
    438 
    439 static void aw_emac_init(Object *obj)
    440 {
    441     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    442     AwEmacState *s = AW_EMAC(obj);
    443 
    444     memory_region_init_io(&s->iomem, OBJECT(s), &aw_emac_mem_ops, s,
    445                           "aw_emac", 0x1000);
    446     sysbus_init_mmio(sbd, &s->iomem);
    447     sysbus_init_irq(sbd, &s->irq);
    448 }
    449 
    450 static void aw_emac_realize(DeviceState *dev, Error **errp)
    451 {
    452     AwEmacState *s = AW_EMAC(dev);
    453 
    454     qemu_macaddr_default_if_unset(&s->conf.macaddr);
    455     s->nic = qemu_new_nic(&net_aw_emac_info, &s->conf,
    456                           object_get_typename(OBJECT(dev)), dev->id, s);
    457     qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
    458 
    459     fifo8_create(&s->rx_fifo, RX_FIFO_SIZE);
    460     fifo8_create(&s->tx_fifo[0], TX_FIFO_SIZE);
    461     fifo8_create(&s->tx_fifo[1], TX_FIFO_SIZE);
    462 }
    463 
    464 static Property aw_emac_properties[] = {
    465     DEFINE_NIC_PROPERTIES(AwEmacState, conf),
    466     DEFINE_PROP_UINT8("phy-addr", AwEmacState, phy_addr, 0),
    467     DEFINE_PROP_END_OF_LIST(),
    468 };
    469 
    470 static const VMStateDescription vmstate_mii = {
    471     .name = "rtl8201cp",
    472     .version_id = 1,
    473     .minimum_version_id = 1,
    474     .fields = (VMStateField[]) {
    475         VMSTATE_UINT16(bmcr, RTL8201CPState),
    476         VMSTATE_UINT16(bmsr, RTL8201CPState),
    477         VMSTATE_UINT16(anar, RTL8201CPState),
    478         VMSTATE_UINT16(anlpar, RTL8201CPState),
    479         VMSTATE_END_OF_LIST()
    480     }
    481 };
    482 
    483 static int aw_emac_post_load(void *opaque, int version_id)
    484 {
    485     AwEmacState *s = opaque;
    486 
    487     aw_emac_set_link(qemu_get_queue(s->nic));
    488 
    489     return 0;
    490 }
    491 
    492 static const VMStateDescription vmstate_aw_emac = {
    493     .name = "allwinner_emac",
    494     .version_id = 1,
    495     .minimum_version_id = 1,
    496     .post_load = aw_emac_post_load,
    497     .fields = (VMStateField[]) {
    498         VMSTATE_STRUCT(mii, AwEmacState, 1, vmstate_mii, RTL8201CPState),
    499         VMSTATE_UINT32(ctl, AwEmacState),
    500         VMSTATE_UINT32(tx_mode, AwEmacState),
    501         VMSTATE_UINT32(rx_ctl, AwEmacState),
    502         VMSTATE_UINT32(int_ctl, AwEmacState),
    503         VMSTATE_UINT32(int_sta, AwEmacState),
    504         VMSTATE_UINT32(phy_target, AwEmacState),
    505         VMSTATE_FIFO8(rx_fifo, AwEmacState),
    506         VMSTATE_UINT32(rx_num_packets, AwEmacState),
    507         VMSTATE_UINT32(rx_packet_size, AwEmacState),
    508         VMSTATE_UINT32(rx_packet_pos, AwEmacState),
    509         VMSTATE_STRUCT_ARRAY(tx_fifo, AwEmacState, NUM_TX_FIFOS, 1,
    510                              vmstate_fifo8, Fifo8),
    511         VMSTATE_UINT32_ARRAY(tx_length, AwEmacState, NUM_TX_FIFOS),
    512         VMSTATE_UINT32(tx_channel, AwEmacState),
    513         VMSTATE_END_OF_LIST()
    514     }
    515 };
    516 
    517 static void aw_emac_class_init(ObjectClass *klass, void *data)
    518 {
    519     DeviceClass *dc = DEVICE_CLASS(klass);
    520 
    521     dc->realize = aw_emac_realize;
    522     device_class_set_props(dc, aw_emac_properties);
    523     dc->reset = aw_emac_reset;
    524     dc->vmsd = &vmstate_aw_emac;
    525 }
    526 
    527 static const TypeInfo aw_emac_info = {
    528     .name           = TYPE_AW_EMAC,
    529     .parent         = TYPE_SYS_BUS_DEVICE,
    530     .instance_size  = sizeof(AwEmacState),
    531     .instance_init   = aw_emac_init,
    532     .class_init     = aw_emac_class_init,
    533 };
    534 
    535 static void aw_emac_register_types(void)
    536 {
    537     type_register_static(&aw_emac_info);
    538 }
    539 
    540 type_init(aw_emac_register_types)