qemu

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

xilinx_ethlite.c (8288B)


      1 /*
      2  * QEMU model of the Xilinx Ethernet Lite MAC.
      3  *
      4  * Copyright (c) 2009 Edgar E. Iglesias.
      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 #include "qemu/osdep.h"
     26 #include "qemu/module.h"
     27 #include "qom/object.h"
     28 #include "cpu.h" /* FIXME should not use tswap* */
     29 #include "hw/sysbus.h"
     30 #include "hw/irq.h"
     31 #include "hw/qdev-properties.h"
     32 #include "net/net.h"
     33 
     34 #define D(x)
     35 #define R_TX_BUF0     0
     36 #define R_TX_LEN0     (0x07f4 / 4)
     37 #define R_TX_GIE0     (0x07f8 / 4)
     38 #define R_TX_CTRL0    (0x07fc / 4)
     39 #define R_TX_BUF1     (0x0800 / 4)
     40 #define R_TX_LEN1     (0x0ff4 / 4)
     41 #define R_TX_CTRL1    (0x0ffc / 4)
     42 
     43 #define R_RX_BUF0     (0x1000 / 4)
     44 #define R_RX_CTRL0    (0x17fc / 4)
     45 #define R_RX_BUF1     (0x1800 / 4)
     46 #define R_RX_CTRL1    (0x1ffc / 4)
     47 #define R_MAX         (0x2000 / 4)
     48 
     49 #define GIE_GIE    0x80000000
     50 
     51 #define CTRL_I     0x8
     52 #define CTRL_P     0x2
     53 #define CTRL_S     0x1
     54 
     55 #define TYPE_XILINX_ETHLITE "xlnx.xps-ethernetlite"
     56 DECLARE_INSTANCE_CHECKER(struct xlx_ethlite, XILINX_ETHLITE,
     57                          TYPE_XILINX_ETHLITE)
     58 
     59 struct xlx_ethlite
     60 {
     61     SysBusDevice parent_obj;
     62 
     63     MemoryRegion mmio;
     64     qemu_irq irq;
     65     NICState *nic;
     66     NICConf conf;
     67 
     68     uint32_t c_tx_pingpong;
     69     uint32_t c_rx_pingpong;
     70     unsigned int txbuf;
     71     unsigned int rxbuf;
     72 
     73     uint32_t regs[R_MAX];
     74 };
     75 
     76 static inline void eth_pulse_irq(struct xlx_ethlite *s)
     77 {
     78     /* Only the first gie reg is active.  */
     79     if (s->regs[R_TX_GIE0] & GIE_GIE) {
     80         qemu_irq_pulse(s->irq);
     81     }
     82 }
     83 
     84 static uint64_t
     85 eth_read(void *opaque, hwaddr addr, unsigned int size)
     86 {
     87     struct xlx_ethlite *s = opaque;
     88     uint32_t r = 0;
     89 
     90     addr >>= 2;
     91 
     92     switch (addr)
     93     {
     94         case R_TX_GIE0:
     95         case R_TX_LEN0:
     96         case R_TX_LEN1:
     97         case R_TX_CTRL1:
     98         case R_TX_CTRL0:
     99         case R_RX_CTRL1:
    100         case R_RX_CTRL0:
    101             r = s->regs[addr];
    102             D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr * 4, r));
    103             break;
    104 
    105         default:
    106             r = tswap32(s->regs[addr]);
    107             break;
    108     }
    109     return r;
    110 }
    111 
    112 static void
    113 eth_write(void *opaque, hwaddr addr,
    114           uint64_t val64, unsigned int size)
    115 {
    116     struct xlx_ethlite *s = opaque;
    117     unsigned int base = 0;
    118     uint32_t value = val64;
    119 
    120     addr >>= 2;
    121     switch (addr) 
    122     {
    123         case R_TX_CTRL0:
    124         case R_TX_CTRL1:
    125             if (addr == R_TX_CTRL1)
    126                 base = 0x800 / 4;
    127 
    128             D(qemu_log("%s addr=" TARGET_FMT_plx " val=%x\n",
    129                        __func__, addr * 4, value));
    130             if ((value & (CTRL_P | CTRL_S)) == CTRL_S) {
    131                 qemu_send_packet(qemu_get_queue(s->nic),
    132                                  (void *) &s->regs[base],
    133                                  s->regs[base + R_TX_LEN0]);
    134                 D(qemu_log("eth_tx %d\n", s->regs[base + R_TX_LEN0]));
    135                 if (s->regs[base + R_TX_CTRL0] & CTRL_I)
    136                     eth_pulse_irq(s);
    137             } else if ((value & (CTRL_P | CTRL_S)) == (CTRL_P | CTRL_S)) {
    138                 memcpy(&s->conf.macaddr.a[0], &s->regs[base], 6);
    139                 if (s->regs[base + R_TX_CTRL0] & CTRL_I)
    140                     eth_pulse_irq(s);
    141             }
    142 
    143             /* We are fast and get ready pretty much immediately so
    144                we actually never flip the S nor P bits to one.  */
    145             s->regs[addr] = value & ~(CTRL_P | CTRL_S);
    146             break;
    147 
    148         /* Keep these native.  */
    149         case R_RX_CTRL0:
    150         case R_RX_CTRL1:
    151             if (!(value & CTRL_S)) {
    152                 qemu_flush_queued_packets(qemu_get_queue(s->nic));
    153             }
    154             /* fall through */
    155         case R_TX_LEN0:
    156         case R_TX_LEN1:
    157         case R_TX_GIE0:
    158             D(qemu_log("%s addr=" TARGET_FMT_plx " val=%x\n",
    159                        __func__, addr * 4, value));
    160             s->regs[addr] = value;
    161             break;
    162 
    163         default:
    164             s->regs[addr] = tswap32(value);
    165             break;
    166     }
    167 }
    168 
    169 static const MemoryRegionOps eth_ops = {
    170     .read = eth_read,
    171     .write = eth_write,
    172     .endianness = DEVICE_NATIVE_ENDIAN,
    173     .valid = {
    174         .min_access_size = 4,
    175         .max_access_size = 4
    176     }
    177 };
    178 
    179 static bool eth_can_rx(NetClientState *nc)
    180 {
    181     struct xlx_ethlite *s = qemu_get_nic_opaque(nc);
    182     unsigned int rxbase = s->rxbuf * (0x800 / 4);
    183 
    184     return !(s->regs[rxbase + R_RX_CTRL0] & CTRL_S);
    185 }
    186 
    187 static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
    188 {
    189     struct xlx_ethlite *s = qemu_get_nic_opaque(nc);
    190     unsigned int rxbase = s->rxbuf * (0x800 / 4);
    191 
    192     /* DA filter.  */
    193     if (!(buf[0] & 0x80) && memcmp(&s->conf.macaddr.a[0], buf, 6))
    194         return size;
    195 
    196     if (s->regs[rxbase + R_RX_CTRL0] & CTRL_S) {
    197         D(qemu_log("ethlite lost packet %x\n", s->regs[R_RX_CTRL0]));
    198         return -1;
    199     }
    200 
    201     D(qemu_log("%s %zd rxbase=%x\n", __func__, size, rxbase));
    202     if (size > (R_MAX - R_RX_BUF0 - rxbase) * 4) {
    203         D(qemu_log("ethlite packet is too big, size=%x\n", size));
    204         return -1;
    205     }
    206     memcpy(&s->regs[rxbase + R_RX_BUF0], buf, size);
    207 
    208     s->regs[rxbase + R_RX_CTRL0] |= CTRL_S;
    209     if (s->regs[R_RX_CTRL0] & CTRL_I) {
    210         eth_pulse_irq(s);
    211     }
    212 
    213     /* If c_rx_pingpong was set flip buffers.  */
    214     s->rxbuf ^= s->c_rx_pingpong;
    215     return size;
    216 }
    217 
    218 static void xilinx_ethlite_reset(DeviceState *dev)
    219 {
    220     struct xlx_ethlite *s = XILINX_ETHLITE(dev);
    221 
    222     s->rxbuf = 0;
    223 }
    224 
    225 static NetClientInfo net_xilinx_ethlite_info = {
    226     .type = NET_CLIENT_DRIVER_NIC,
    227     .size = sizeof(NICState),
    228     .can_receive = eth_can_rx,
    229     .receive = eth_rx,
    230 };
    231 
    232 static void xilinx_ethlite_realize(DeviceState *dev, Error **errp)
    233 {
    234     struct xlx_ethlite *s = XILINX_ETHLITE(dev);
    235 
    236     qemu_macaddr_default_if_unset(&s->conf.macaddr);
    237     s->nic = qemu_new_nic(&net_xilinx_ethlite_info, &s->conf,
    238                           object_get_typename(OBJECT(dev)), dev->id, s);
    239     qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
    240 }
    241 
    242 static void xilinx_ethlite_init(Object *obj)
    243 {
    244     struct xlx_ethlite *s = XILINX_ETHLITE(obj);
    245 
    246     sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
    247 
    248     memory_region_init_io(&s->mmio, obj, &eth_ops, s,
    249                           "xlnx.xps-ethernetlite", R_MAX * 4);
    250     sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
    251 }
    252 
    253 static Property xilinx_ethlite_properties[] = {
    254     DEFINE_PROP_UINT32("tx-ping-pong", struct xlx_ethlite, c_tx_pingpong, 1),
    255     DEFINE_PROP_UINT32("rx-ping-pong", struct xlx_ethlite, c_rx_pingpong, 1),
    256     DEFINE_NIC_PROPERTIES(struct xlx_ethlite, conf),
    257     DEFINE_PROP_END_OF_LIST(),
    258 };
    259 
    260 static void xilinx_ethlite_class_init(ObjectClass *klass, void *data)
    261 {
    262     DeviceClass *dc = DEVICE_CLASS(klass);
    263 
    264     dc->realize = xilinx_ethlite_realize;
    265     dc->reset = xilinx_ethlite_reset;
    266     device_class_set_props(dc, xilinx_ethlite_properties);
    267 }
    268 
    269 static const TypeInfo xilinx_ethlite_info = {
    270     .name          = TYPE_XILINX_ETHLITE,
    271     .parent        = TYPE_SYS_BUS_DEVICE,
    272     .instance_size = sizeof(struct xlx_ethlite),
    273     .instance_init = xilinx_ethlite_init,
    274     .class_init    = xilinx_ethlite_class_init,
    275 };
    276 
    277 static void xilinx_ethlite_register_types(void)
    278 {
    279     type_register_static(&xilinx_ethlite_info);
    280 }
    281 
    282 type_init(xilinx_ethlite_register_types)