1376b8519SHelge Deller /* 2376b8519SHelge Deller * QEMU LASI NIC i82596 emulation 3376b8519SHelge Deller * 4376b8519SHelge Deller * Copyright (c) 2019 Helge Deller <deller@gmx.de> 5376b8519SHelge Deller * This work is licensed under the GNU GPL license version 2 or later. 6376b8519SHelge Deller * 7376b8519SHelge Deller * 8376b8519SHelge Deller * On PA-RISC, this is the Network part of LASI chip. 9376b8519SHelge Deller * See: 10376b8519SHelge Deller * https://parisc.wiki.kernel.org/images-parisc/7/79/Lasi_ers.pdf 11376b8519SHelge Deller */ 12376b8519SHelge Deller 13376b8519SHelge Deller #include "qemu/osdep.h" 14376b8519SHelge Deller #include "qemu/timer.h" 15376b8519SHelge Deller #include "hw/sysbus.h" 16376b8519SHelge Deller #include "net/eth.h" 17376b8519SHelge Deller #include "hw/net/lasi_82596.h" 18376b8519SHelge Deller #include "hw/net/i82596.h" 19376b8519SHelge Deller #include "trace.h" 20376b8519SHelge Deller #include "sysemu/sysemu.h" 21376b8519SHelge Deller #include "hw/qdev-properties.h" 22376b8519SHelge Deller #include "migration/vmstate.h" 23376b8519SHelge Deller 24376b8519SHelge Deller #define PA_I82596_RESET 0 /* Offsets relative to LASI-LAN-Addr.*/ 25376b8519SHelge Deller #define PA_CPU_PORT_L_ACCESS 4 26376b8519SHelge Deller #define PA_CHANNEL_ATTENTION 8 27376b8519SHelge Deller #define PA_GET_MACADDR 12 28376b8519SHelge Deller 29376b8519SHelge Deller #define SWAP32(x) (((uint32_t)(x) << 16) | ((((uint32_t)(x))) >> 16)) 30376b8519SHelge Deller 31376b8519SHelge Deller static void lasi_82596_mem_write(void *opaque, hwaddr addr, 32376b8519SHelge Deller uint64_t val, unsigned size) 33376b8519SHelge Deller { 34376b8519SHelge Deller SysBusI82596State *d = opaque; 35376b8519SHelge Deller 36376b8519SHelge Deller trace_lasi_82596_mem_writew(addr, val); 37376b8519SHelge Deller switch (addr) { 38376b8519SHelge Deller case PA_I82596_RESET: 39376b8519SHelge Deller i82596_h_reset(&d->state); 40376b8519SHelge Deller break; 41376b8519SHelge Deller case PA_CPU_PORT_L_ACCESS: 42376b8519SHelge Deller d->val_index++; 43376b8519SHelge Deller if (d->val_index == 0) { 44376b8519SHelge Deller uint32_t v = d->last_val | (val << 16); 45376b8519SHelge Deller v = v & ~0xff; 46376b8519SHelge Deller i82596_ioport_writew(&d->state, d->last_val & 0xff, v); 47376b8519SHelge Deller } 48376b8519SHelge Deller d->last_val = val; 49376b8519SHelge Deller break; 50376b8519SHelge Deller case PA_CHANNEL_ATTENTION: 51376b8519SHelge Deller i82596_ioport_writew(&d->state, PORT_CA, val); 52376b8519SHelge Deller break; 53376b8519SHelge Deller case PA_GET_MACADDR: 54376b8519SHelge Deller /* 55376b8519SHelge Deller * Provided for SeaBIOS only. Write MAC of Network card to addr @val. 56376b8519SHelge Deller * Needed for the PDC_LAN_STATION_ID_READ PDC call. 57376b8519SHelge Deller */ 5819f70347SPeter Maydell address_space_write(&address_space_memory, val, 5919f70347SPeter Maydell MEMTXATTRS_UNSPECIFIED, d->state.conf.macaddr.a, 6019f70347SPeter Maydell ETH_ALEN); 61376b8519SHelge Deller break; 62376b8519SHelge Deller } 63376b8519SHelge Deller } 64376b8519SHelge Deller 65376b8519SHelge Deller static uint64_t lasi_82596_mem_read(void *opaque, hwaddr addr, 66376b8519SHelge Deller unsigned size) 67376b8519SHelge Deller { 68376b8519SHelge Deller SysBusI82596State *d = opaque; 69376b8519SHelge Deller uint32_t val; 70376b8519SHelge Deller 71376b8519SHelge Deller if (addr == PA_GET_MACADDR) { 72376b8519SHelge Deller val = 0xBEEFBABE; 73376b8519SHelge Deller } else { 74376b8519SHelge Deller val = i82596_ioport_readw(&d->state, addr); 75376b8519SHelge Deller } 76376b8519SHelge Deller trace_lasi_82596_mem_readw(addr, val); 77376b8519SHelge Deller return val; 78376b8519SHelge Deller } 79376b8519SHelge Deller 80376b8519SHelge Deller static const MemoryRegionOps lasi_82596_mem_ops = { 81376b8519SHelge Deller .read = lasi_82596_mem_read, 82376b8519SHelge Deller .write = lasi_82596_mem_write, 83376b8519SHelge Deller .endianness = DEVICE_BIG_ENDIAN, 84376b8519SHelge Deller .valid = { 85376b8519SHelge Deller .min_access_size = 4, 86376b8519SHelge Deller .max_access_size = 4, 87376b8519SHelge Deller }, 88376b8519SHelge Deller }; 89376b8519SHelge Deller 90376b8519SHelge Deller static NetClientInfo net_lasi_82596_info = { 91376b8519SHelge Deller .type = NET_CLIENT_DRIVER_NIC, 92376b8519SHelge Deller .size = sizeof(NICState), 93376b8519SHelge Deller .can_receive = i82596_can_receive, 94376b8519SHelge Deller .receive = i82596_receive, 95376b8519SHelge Deller .link_status_changed = i82596_set_link_status, 96376b8519SHelge Deller }; 97376b8519SHelge Deller 98376b8519SHelge Deller static const VMStateDescription vmstate_lasi_82596 = { 99376b8519SHelge Deller .name = "i82596", 100376b8519SHelge Deller .version_id = 1, 101376b8519SHelge Deller .minimum_version_id = 1, 102376b8519SHelge Deller .fields = (VMStateField[]) { 103376b8519SHelge Deller VMSTATE_STRUCT(state, SysBusI82596State, 0, vmstate_i82596, 104376b8519SHelge Deller I82596State), 105376b8519SHelge Deller VMSTATE_END_OF_LIST() 106376b8519SHelge Deller } 107376b8519SHelge Deller }; 108376b8519SHelge Deller 109376b8519SHelge Deller static void lasi_82596_realize(DeviceState *dev, Error **errp) 110376b8519SHelge Deller { 111376b8519SHelge Deller SysBusI82596State *d = SYSBUS_I82596(dev); 112376b8519SHelge Deller I82596State *s = &d->state; 113376b8519SHelge Deller 114376b8519SHelge Deller memory_region_init_io(&s->mmio, OBJECT(d), &lasi_82596_mem_ops, d, 115376b8519SHelge Deller "lasi_82596-mmio", PA_GET_MACADDR + 4); 116376b8519SHelge Deller 117376b8519SHelge Deller i82596_common_init(dev, s, &net_lasi_82596_info); 118376b8519SHelge Deller } 119376b8519SHelge Deller 120376b8519SHelge Deller SysBusI82596State *lasi_82596_init(MemoryRegion *addr_space, 121376b8519SHelge Deller hwaddr hpa, qemu_irq lan_irq) 122376b8519SHelge Deller { 123376b8519SHelge Deller DeviceState *dev; 124376b8519SHelge Deller SysBusI82596State *s; 125376b8519SHelge Deller static const MACAddr HP_MAC = { 126376b8519SHelge Deller .a = { 0x08, 0x00, 0x09, 0xef, 0x34, 0xf6 } }; 127376b8519SHelge Deller 128376b8519SHelge Deller qemu_check_nic_model(&nd_table[0], TYPE_LASI_82596); 129376b8519SHelge Deller dev = qdev_create(NULL, TYPE_LASI_82596); 130376b8519SHelge Deller s = SYSBUS_I82596(dev); 131376b8519SHelge Deller s->state.irq = lan_irq; 132376b8519SHelge Deller qdev_set_nic_properties(dev, &nd_table[0]); 133376b8519SHelge Deller qdev_init_nofail(dev); 134376b8519SHelge Deller s->state.conf.macaddr = HP_MAC; /* set HP MAC prefix */ 135376b8519SHelge Deller 136376b8519SHelge Deller /* LASI 82596 ports in main memory. */ 137376b8519SHelge Deller memory_region_add_subregion(addr_space, hpa, &s->state.mmio); 138376b8519SHelge Deller return s; 139376b8519SHelge Deller } 140376b8519SHelge Deller 141376b8519SHelge Deller static void lasi_82596_reset(DeviceState *dev) 142376b8519SHelge Deller { 143376b8519SHelge Deller SysBusI82596State *d = SYSBUS_I82596(dev); 144376b8519SHelge Deller 145376b8519SHelge Deller i82596_h_reset(&d->state); 146376b8519SHelge Deller } 147376b8519SHelge Deller 148376b8519SHelge Deller static void lasi_82596_instance_init(Object *obj) 149376b8519SHelge Deller { 150376b8519SHelge Deller SysBusI82596State *d = SYSBUS_I82596(obj); 151376b8519SHelge Deller I82596State *s = &d->state; 152376b8519SHelge Deller 153376b8519SHelge Deller device_add_bootindex_property(obj, &s->conf.bootindex, 154376b8519SHelge Deller "bootindex", "/ethernet-phy@0", 155*40c2281cSMarkus Armbruster DEVICE(obj)); 156376b8519SHelge Deller } 157376b8519SHelge Deller 158376b8519SHelge Deller static Property lasi_82596_properties[] = { 159376b8519SHelge Deller DEFINE_NIC_PROPERTIES(SysBusI82596State, state.conf), 160376b8519SHelge Deller DEFINE_PROP_END_OF_LIST(), 161376b8519SHelge Deller }; 162376b8519SHelge Deller 163376b8519SHelge Deller static void lasi_82596_class_init(ObjectClass *klass, void *data) 164376b8519SHelge Deller { 165376b8519SHelge Deller DeviceClass *dc = DEVICE_CLASS(klass); 166376b8519SHelge Deller 167376b8519SHelge Deller dc->realize = lasi_82596_realize; 168376b8519SHelge Deller set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); 169376b8519SHelge Deller dc->fw_name = "ethernet"; 170376b8519SHelge Deller dc->reset = lasi_82596_reset; 171376b8519SHelge Deller dc->vmsd = &vmstate_lasi_82596; 172376b8519SHelge Deller dc->user_creatable = false; 173376b8519SHelge Deller device_class_set_props(dc, lasi_82596_properties); 174376b8519SHelge Deller } 175376b8519SHelge Deller 176376b8519SHelge Deller static const TypeInfo lasi_82596_info = { 177376b8519SHelge Deller .name = TYPE_LASI_82596, 178376b8519SHelge Deller .parent = TYPE_SYS_BUS_DEVICE, 179376b8519SHelge Deller .instance_size = sizeof(SysBusI82596State), 180376b8519SHelge Deller .class_init = lasi_82596_class_init, 181376b8519SHelge Deller .instance_init = lasi_82596_instance_init, 182376b8519SHelge Deller }; 183376b8519SHelge Deller 184376b8519SHelge Deller static void lasi_82596_register_types(void) 185376b8519SHelge Deller { 186376b8519SHelge Deller type_register_static(&lasi_82596_info); 187376b8519SHelge Deller } 188376b8519SHelge Deller 189376b8519SHelge Deller type_init(lasi_82596_register_types) 190