qemu/hw/net/lasi_i82596.c
<<
>>
Prefs
   1/*
   2 * QEMU LASI NIC i82596 emulation
   3 *
   4 * Copyright (c) 2019 Helge Deller <deller@gmx.de>
   5 * This work is licensed under the GNU GPL license version 2 or later.
   6 *
   7 *
   8 * On PA-RISC, this is the Network part of LASI chip.
   9 * See:
  10 * https://parisc.wiki.kernel.org/images-parisc/7/79/Lasi_ers.pdf
  11 */
  12
  13#include "qemu/osdep.h"
  14#include "qapi/error.h"
  15#include "qemu/timer.h"
  16#include "hw/sysbus.h"
  17#include "net/eth.h"
  18#include "hw/net/lasi_82596.h"
  19#include "hw/net/i82596.h"
  20#include "trace.h"
  21#include "hw/qdev-properties.h"
  22#include "migration/vmstate.h"
  23
  24#define PA_I82596_RESET         0       /* Offsets relative to LASI-LAN-Addr.*/
  25#define PA_CPU_PORT_L_ACCESS    4
  26#define PA_CHANNEL_ATTENTION    8
  27#define PA_GET_MACADDR          12
  28
  29#define SWAP32(x)   (((uint32_t)(x) << 16) | ((((uint32_t)(x))) >> 16))
  30
  31static void lasi_82596_mem_write(void *opaque, hwaddr addr,
  32                            uint64_t val, unsigned size)
  33{
  34    SysBusI82596State *d = opaque;
  35
  36    trace_lasi_82596_mem_writew(addr, val);
  37    switch (addr) {
  38    case PA_I82596_RESET:
  39        i82596_h_reset(&d->state);
  40        break;
  41    case PA_CPU_PORT_L_ACCESS:
  42        d->val_index++;
  43        if (d->val_index == 0) {
  44            uint32_t v = d->last_val | (val << 16);
  45            v = v & ~0xff;
  46            i82596_ioport_writew(&d->state, d->last_val & 0xff, v);
  47        }
  48        d->last_val = val;
  49        break;
  50    case PA_CHANNEL_ATTENTION:
  51        i82596_ioport_writew(&d->state, PORT_CA, val);
  52        break;
  53    case PA_GET_MACADDR:
  54        /*
  55         * Provided for SeaBIOS only. Write MAC of Network card to addr @val.
  56         * Needed for the PDC_LAN_STATION_ID_READ PDC call.
  57         */
  58        address_space_write(&address_space_memory, val,
  59                            MEMTXATTRS_UNSPECIFIED, d->state.conf.macaddr.a,
  60                            ETH_ALEN);
  61        break;
  62    }
  63}
  64
  65static uint64_t lasi_82596_mem_read(void *opaque, hwaddr addr,
  66                               unsigned size)
  67{
  68    SysBusI82596State *d = opaque;
  69    uint32_t val;
  70
  71    if (addr == PA_GET_MACADDR) {
  72        val = 0xBEEFBABE;
  73    } else {
  74        val = i82596_ioport_readw(&d->state, addr);
  75    }
  76    trace_lasi_82596_mem_readw(addr, val);
  77    return val;
  78}
  79
  80static const MemoryRegionOps lasi_82596_mem_ops = {
  81    .read = lasi_82596_mem_read,
  82    .write = lasi_82596_mem_write,
  83    .endianness = DEVICE_BIG_ENDIAN,
  84    .valid = {
  85        .min_access_size = 4,
  86        .max_access_size = 4,
  87    },
  88};
  89
  90static NetClientInfo net_lasi_82596_info = {
  91    .type = NET_CLIENT_DRIVER_NIC,
  92    .size = sizeof(NICState),
  93    .can_receive = i82596_can_receive,
  94    .receive = i82596_receive,
  95    .link_status_changed = i82596_set_link_status,
  96};
  97
  98static const VMStateDescription vmstate_lasi_82596 = {
  99    .name = "i82596",
 100    .version_id = 1,
 101    .minimum_version_id = 1,
 102    .fields = (VMStateField[]) {
 103        VMSTATE_STRUCT(state, SysBusI82596State, 0, vmstate_i82596,
 104                I82596State),
 105        VMSTATE_END_OF_LIST()
 106    }
 107};
 108
 109static void lasi_82596_realize(DeviceState *dev, Error **errp)
 110{
 111    SysBusI82596State *d = SYSBUS_I82596(dev);
 112    I82596State *s = &d->state;
 113
 114    memory_region_init_io(&s->mmio, OBJECT(d), &lasi_82596_mem_ops, d,
 115                "lasi_82596-mmio", PA_GET_MACADDR + 4);
 116
 117    i82596_common_init(dev, s, &net_lasi_82596_info);
 118}
 119
 120SysBusI82596State *lasi_82596_init(MemoryRegion *addr_space,
 121                  hwaddr hpa, qemu_irq lan_irq)
 122{
 123    DeviceState *dev;
 124    SysBusI82596State *s;
 125    static const MACAddr HP_MAC = {
 126        .a = { 0x08, 0x00, 0x09, 0xef, 0x34, 0xf6 } };
 127
 128    qemu_check_nic_model(&nd_table[0], TYPE_LASI_82596);
 129    dev = qdev_new(TYPE_LASI_82596);
 130    s = SYSBUS_I82596(dev);
 131    s->state.irq = lan_irq;
 132    qdev_set_nic_properties(dev, &nd_table[0]);
 133    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
 134    s->state.conf.macaddr = HP_MAC; /* set HP MAC prefix */
 135
 136    /* LASI 82596 ports in main memory. */
 137    memory_region_add_subregion(addr_space, hpa, &s->state.mmio);
 138    return s;
 139}
 140
 141static void lasi_82596_reset(DeviceState *dev)
 142{
 143    SysBusI82596State *d = SYSBUS_I82596(dev);
 144
 145    i82596_h_reset(&d->state);
 146}
 147
 148static void lasi_82596_instance_init(Object *obj)
 149{
 150    SysBusI82596State *d = SYSBUS_I82596(obj);
 151    I82596State *s = &d->state;
 152
 153    device_add_bootindex_property(obj, &s->conf.bootindex,
 154                                  "bootindex", "/ethernet-phy@0",
 155                                  DEVICE(obj));
 156}
 157
 158static Property lasi_82596_properties[] = {
 159    DEFINE_NIC_PROPERTIES(SysBusI82596State, state.conf),
 160    DEFINE_PROP_END_OF_LIST(),
 161};
 162
 163static void lasi_82596_class_init(ObjectClass *klass, void *data)
 164{
 165    DeviceClass *dc = DEVICE_CLASS(klass);
 166
 167    dc->realize = lasi_82596_realize;
 168    set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
 169    dc->fw_name = "ethernet";
 170    dc->reset = lasi_82596_reset;
 171    dc->vmsd = &vmstate_lasi_82596;
 172    dc->user_creatable = false;
 173    device_class_set_props(dc, lasi_82596_properties);
 174}
 175
 176static const TypeInfo lasi_82596_info = {
 177    .name          = TYPE_LASI_82596,
 178    .parent        = TYPE_SYS_BUS_DEVICE,
 179    .instance_size = sizeof(SysBusI82596State),
 180    .class_init    = lasi_82596_class_init,
 181    .instance_init = lasi_82596_instance_init,
 182};
 183
 184static void lasi_82596_register_types(void)
 185{
 186    type_register_static(&lasi_82596_info);
 187}
 188
 189type_init(lasi_82596_register_types)
 190