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