qemu

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

etsec.c (12407B)


      1 /*
      2  * QEMU Freescale eTSEC Emulator
      3  *
      4  * Copyright (c) 2011-2013 AdaCore
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a copy
      7  * of this software and associated documentation files (the "Software"), to deal
      8  * in the Software without restriction, including without limitation the rights
      9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10  * copies of the Software, and to permit persons to whom the Software is
     11  * furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22  * THE SOFTWARE.
     23  */
     24 
     25 /*
     26  * This implementation doesn't include ring priority, TCP/IP Off-Load, QoS.
     27  */
     28 
     29 #include "qemu/osdep.h"
     30 #include "hw/sysbus.h"
     31 #include "hw/irq.h"
     32 #include "hw/ptimer.h"
     33 #include "hw/qdev-properties.h"
     34 #include "etsec.h"
     35 #include "registers.h"
     36 #include "qapi/error.h"
     37 #include "qemu/log.h"
     38 #include "qemu/module.h"
     39 
     40 /* #define HEX_DUMP */
     41 /* #define DEBUG_REGISTER */
     42 
     43 #ifdef DEBUG_REGISTER
     44 static const int debug_etsec = 1;
     45 #else
     46 static const int debug_etsec;
     47 #endif
     48 
     49 #define DPRINTF(fmt, ...) do {                 \
     50     if (debug_etsec) {                         \
     51         qemu_log(fmt , ## __VA_ARGS__);        \
     52     }                                          \
     53     } while (0)
     54 
     55 /* call after any change to IEVENT or IMASK */
     56 void etsec_update_irq(eTSEC *etsec)
     57 {
     58     uint32_t ievent = etsec->regs[IEVENT].value;
     59     uint32_t imask  = etsec->regs[IMASK].value;
     60     uint32_t active = ievent & imask;
     61 
     62     int tx  = !!(active & IEVENT_TX_MASK);
     63     int rx  = !!(active & IEVENT_RX_MASK);
     64     int err = !!(active & IEVENT_ERR_MASK);
     65 
     66     DPRINTF("%s IRQ ievent=%"PRIx32" imask=%"PRIx32" %c%c%c",
     67             __func__, ievent, imask,
     68             tx  ? 'T' : '_',
     69             rx  ? 'R' : '_',
     70             err ? 'E' : '_');
     71 
     72     qemu_set_irq(etsec->tx_irq, tx);
     73     qemu_set_irq(etsec->rx_irq, rx);
     74     qemu_set_irq(etsec->err_irq, err);
     75 }
     76 
     77 static uint64_t etsec_read(void *opaque, hwaddr addr, unsigned size)
     78 {
     79     eTSEC          *etsec     = opaque;
     80     uint32_t        reg_index = addr / 4;
     81     eTSEC_Register *reg       = NULL;
     82     uint32_t        ret       = 0x0;
     83 
     84     assert(reg_index < ETSEC_REG_NUMBER);
     85 
     86     reg = &etsec->regs[reg_index];
     87 
     88 
     89     switch (reg->access) {
     90     case ACC_WO:
     91         ret = 0x00000000;
     92         break;
     93 
     94     case ACC_RW:
     95     case ACC_W1C:
     96     case ACC_RO:
     97     default:
     98         ret = reg->value;
     99         break;
    100     }
    101 
    102     DPRINTF("Read  0x%08x @ 0x" TARGET_FMT_plx
    103             "                            : %s (%s)\n",
    104             ret, addr, reg->name, reg->desc);
    105 
    106     return ret;
    107 }
    108 
    109 static void write_tstat(eTSEC          *etsec,
    110                         eTSEC_Register *reg,
    111                         uint32_t        reg_index,
    112                         uint32_t        value)
    113 {
    114     int i = 0;
    115 
    116     for (i = 0; i < 8; i++) {
    117         /* Check THLTi flag in TSTAT */
    118         if (value & (1 << (31 - i))) {
    119             etsec_walk_tx_ring(etsec, i);
    120         }
    121     }
    122 
    123     /* Write 1 to clear */
    124     reg->value &= ~value;
    125 }
    126 
    127 static void write_rstat(eTSEC          *etsec,
    128                         eTSEC_Register *reg,
    129                         uint32_t        reg_index,
    130                         uint32_t        value)
    131 {
    132     int i = 0;
    133 
    134     for (i = 0; i < 8; i++) {
    135         /* Check QHLTi flag in RSTAT */
    136         if (value & (1 << (23 - i)) && !(reg->value & (1 << (23 - i)))) {
    137             etsec_walk_rx_ring(etsec, i);
    138         }
    139     }
    140 
    141     /* Write 1 to clear */
    142     reg->value &= ~value;
    143 }
    144 
    145 static void write_tbasex(eTSEC          *etsec,
    146                          eTSEC_Register *reg,
    147                          uint32_t        reg_index,
    148                          uint32_t        value)
    149 {
    150     reg->value = value & ~0x7;
    151 
    152     /* Copy this value in the ring's TxBD pointer */
    153     etsec->regs[TBPTR0 + (reg_index - TBASE0)].value = value & ~0x7;
    154 }
    155 
    156 static void write_rbasex(eTSEC          *etsec,
    157                          eTSEC_Register *reg,
    158                          uint32_t        reg_index,
    159                          uint32_t        value)
    160 {
    161     reg->value = value & ~0x7;
    162 
    163     /* Copy this value in the ring's RxBD pointer */
    164     etsec->regs[RBPTR0 + (reg_index - RBASE0)].value = value & ~0x7;
    165 }
    166 
    167 static void write_dmactrl(eTSEC          *etsec,
    168                           eTSEC_Register *reg,
    169                           uint32_t        reg_index,
    170                           uint32_t        value)
    171 {
    172     reg->value = value;
    173 
    174     if (value & DMACTRL_GRS) {
    175 
    176         if (etsec->rx_buffer_len != 0) {
    177             /* Graceful receive stop delayed until end of frame */
    178         } else {
    179             /* Graceful receive stop now */
    180             etsec->regs[IEVENT].value |= IEVENT_GRSC;
    181             etsec_update_irq(etsec);
    182         }
    183     }
    184 
    185     if (value & DMACTRL_GTS) {
    186 
    187         if (etsec->tx_buffer_len != 0) {
    188             /* Graceful transmit stop delayed until end of frame */
    189         } else {
    190             /* Graceful transmit stop now */
    191             etsec->regs[IEVENT].value |= IEVENT_GTSC;
    192             etsec_update_irq(etsec);
    193         }
    194     }
    195 
    196     if (!(value & DMACTRL_WOP)) {
    197         /* Start polling */
    198         ptimer_transaction_begin(etsec->ptimer);
    199         ptimer_stop(etsec->ptimer);
    200         ptimer_set_count(etsec->ptimer, 1);
    201         ptimer_run(etsec->ptimer, 1);
    202         ptimer_transaction_commit(etsec->ptimer);
    203     }
    204 }
    205 
    206 static void etsec_write(void     *opaque,
    207                         hwaddr    addr,
    208                         uint64_t  value,
    209                         unsigned  size)
    210 {
    211     eTSEC          *etsec     = opaque;
    212     uint32_t        reg_index = addr / 4;
    213     eTSEC_Register *reg       = NULL;
    214     uint32_t        before    = 0x0;
    215 
    216     assert(reg_index < ETSEC_REG_NUMBER);
    217 
    218     reg = &etsec->regs[reg_index];
    219     before = reg->value;
    220 
    221     switch (reg_index) {
    222     case IEVENT:
    223         /* Write 1 to clear */
    224         reg->value &= ~value;
    225 
    226         etsec_update_irq(etsec);
    227         break;
    228 
    229     case IMASK:
    230         reg->value = value;
    231 
    232         etsec_update_irq(etsec);
    233         break;
    234 
    235     case DMACTRL:
    236         write_dmactrl(etsec, reg, reg_index, value);
    237         break;
    238 
    239     case TSTAT:
    240         write_tstat(etsec, reg, reg_index, value);
    241         break;
    242 
    243     case RSTAT:
    244         write_rstat(etsec, reg, reg_index, value);
    245         break;
    246 
    247     case TBASE0 ... TBASE7:
    248         write_tbasex(etsec, reg, reg_index, value);
    249         break;
    250 
    251     case RBASE0 ... RBASE7:
    252         write_rbasex(etsec, reg, reg_index, value);
    253         break;
    254 
    255     case MIIMCFG ... MIIMIND:
    256         etsec_write_miim(etsec, reg, reg_index, value);
    257         break;
    258 
    259     default:
    260         /* Default handling */
    261         switch (reg->access) {
    262 
    263         case ACC_RW:
    264         case ACC_WO:
    265             reg->value = value;
    266             break;
    267 
    268         case ACC_W1C:
    269             reg->value &= ~value;
    270             break;
    271 
    272         case ACC_RO:
    273         default:
    274             /* Read Only or Unknown register */
    275             break;
    276         }
    277     }
    278 
    279     DPRINTF("Write 0x%08x @ 0x" TARGET_FMT_plx
    280             " val:0x%08x->0x%08x : %s (%s)\n",
    281             (unsigned int)value, addr, before, reg->value,
    282             reg->name, reg->desc);
    283 }
    284 
    285 static const MemoryRegionOps etsec_ops = {
    286     .read = etsec_read,
    287     .write = etsec_write,
    288     .endianness = DEVICE_NATIVE_ENDIAN,
    289     .impl = {
    290         .min_access_size = 4,
    291         .max_access_size = 4,
    292     },
    293 };
    294 
    295 static void etsec_timer_hit(void *opaque)
    296 {
    297     eTSEC *etsec = opaque;
    298 
    299     ptimer_stop(etsec->ptimer);
    300 
    301     if (!(etsec->regs[DMACTRL].value & DMACTRL_WOP)) {
    302 
    303         if (!(etsec->regs[DMACTRL].value & DMACTRL_GTS)) {
    304             etsec_walk_tx_ring(etsec, 0);
    305         }
    306         ptimer_set_count(etsec->ptimer, 1);
    307         ptimer_run(etsec->ptimer, 1);
    308     }
    309 }
    310 
    311 static void etsec_reset(DeviceState *d)
    312 {
    313     eTSEC *etsec = ETSEC_COMMON(d);
    314     int i = 0;
    315     int reg_index = 0;
    316 
    317     /* Default value for all registers */
    318     for (i = 0; i < ETSEC_REG_NUMBER; i++) {
    319         etsec->regs[i].name   = "Reserved";
    320         etsec->regs[i].desc   = "";
    321         etsec->regs[i].access = ACC_UNKNOWN;
    322         etsec->regs[i].value  = 0x00000000;
    323     }
    324 
    325     /* Set-up known registers */
    326     for (i = 0; eTSEC_registers_def[i].name != NULL; i++) {
    327 
    328         reg_index = eTSEC_registers_def[i].offset / 4;
    329 
    330         etsec->regs[reg_index].name   = eTSEC_registers_def[i].name;
    331         etsec->regs[reg_index].desc   = eTSEC_registers_def[i].desc;
    332         etsec->regs[reg_index].access = eTSEC_registers_def[i].access;
    333         etsec->regs[reg_index].value  = eTSEC_registers_def[i].reset;
    334     }
    335 
    336     etsec->tx_buffer     = NULL;
    337     etsec->tx_buffer_len = 0;
    338     etsec->rx_buffer     = NULL;
    339     etsec->rx_buffer_len = 0;
    340 
    341     etsec->phy_status =
    342         MII_SR_EXTENDED_CAPS    | MII_SR_LINK_STATUS   | MII_SR_AUTONEG_CAPS  |
    343         MII_SR_AUTONEG_COMPLETE | MII_SR_PREAMBLE_SUPPRESS |
    344         MII_SR_EXTENDED_STATUS  | MII_SR_100T2_HD_CAPS | MII_SR_100T2_FD_CAPS |
    345         MII_SR_10T_HD_CAPS      | MII_SR_10T_FD_CAPS   | MII_SR_100X_HD_CAPS  |
    346         MII_SR_100X_FD_CAPS     | MII_SR_100T4_CAPS;
    347 
    348     etsec_update_irq(etsec);
    349 }
    350 
    351 static ssize_t etsec_receive(NetClientState *nc,
    352                              const uint8_t  *buf,
    353                              size_t          size)
    354 {
    355     ssize_t ret;
    356     eTSEC *etsec = qemu_get_nic_opaque(nc);
    357 
    358 #if defined(HEX_DUMP)
    359     fprintf(stderr, "%s receive size:%zd\n", nc->name, size);
    360     qemu_hexdump(stderr, "", buf, size);
    361 #endif
    362     /* Flush is unnecessary as are already in receiving path */
    363     etsec->need_flush = false;
    364     ret = etsec_rx_ring_write(etsec, buf, size);
    365     if (ret == 0) {
    366         /* The packet will be queued, let's flush it when buffer is available
    367          * again. */
    368         etsec->need_flush = true;
    369     }
    370     return ret;
    371 }
    372 
    373 
    374 static void etsec_set_link_status(NetClientState *nc)
    375 {
    376     eTSEC *etsec = qemu_get_nic_opaque(nc);
    377 
    378     etsec_miim_link_status(etsec, nc);
    379 }
    380 
    381 static NetClientInfo net_etsec_info = {
    382     .type = NET_CLIENT_DRIVER_NIC,
    383     .size = sizeof(NICState),
    384     .receive = etsec_receive,
    385     .link_status_changed = etsec_set_link_status,
    386 };
    387 
    388 static void etsec_realize(DeviceState *dev, Error **errp)
    389 {
    390     eTSEC        *etsec = ETSEC_COMMON(dev);
    391 
    392     etsec->nic = qemu_new_nic(&net_etsec_info, &etsec->conf,
    393                               object_get_typename(OBJECT(dev)), dev->id, etsec);
    394     qemu_format_nic_info_str(qemu_get_queue(etsec->nic), etsec->conf.macaddr.a);
    395 
    396     etsec->ptimer = ptimer_init(etsec_timer_hit, etsec, PTIMER_POLICY_LEGACY);
    397     ptimer_transaction_begin(etsec->ptimer);
    398     ptimer_set_freq(etsec->ptimer, 100);
    399     ptimer_transaction_commit(etsec->ptimer);
    400 }
    401 
    402 static void etsec_instance_init(Object *obj)
    403 {
    404     eTSEC        *etsec = ETSEC_COMMON(obj);
    405     SysBusDevice *sbd   = SYS_BUS_DEVICE(obj);
    406 
    407     memory_region_init_io(&etsec->io_area, OBJECT(etsec), &etsec_ops, etsec,
    408                           "eTSEC", 0x1000);
    409     sysbus_init_mmio(sbd, &etsec->io_area);
    410 
    411     sysbus_init_irq(sbd, &etsec->tx_irq);
    412     sysbus_init_irq(sbd, &etsec->rx_irq);
    413     sysbus_init_irq(sbd, &etsec->err_irq);
    414 }
    415 
    416 static Property etsec_properties[] = {
    417     DEFINE_NIC_PROPERTIES(eTSEC, conf),
    418     DEFINE_PROP_END_OF_LIST(),
    419 };
    420 
    421 static void etsec_class_init(ObjectClass *klass, void *data)
    422 {
    423     DeviceClass *dc = DEVICE_CLASS(klass);
    424 
    425     dc->realize = etsec_realize;
    426     dc->reset = etsec_reset;
    427     device_class_set_props(dc, etsec_properties);
    428     /* Supported by ppce500 machine */
    429     dc->user_creatable = true;
    430 }
    431 
    432 static const TypeInfo etsec_info = {
    433     .name                  = TYPE_ETSEC_COMMON,
    434     .parent                = TYPE_SYS_BUS_DEVICE,
    435     .instance_size         = sizeof(eTSEC),
    436     .class_init            = etsec_class_init,
    437     .instance_init         = etsec_instance_init,
    438 };
    439 
    440 static void etsec_register_types(void)
    441 {
    442     type_register_static(&etsec_info);
    443 }
    444 
    445 type_init(etsec_register_types)