X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=hw%2Fsmc91c111.c;h=3a8a85c1f194dcd8891ff834544681be2aa8876b;hb=8e31bf388e56e5babd9600b110a94381d1be07b1;hp=a08bdb0a594fd3c2537ec1fa14c0ad448d456027;hpb=81a322d4a1b68d47908a6630bf22897a289722aa;p=qemu.git diff --git a/hw/smc91c111.c b/hw/smc91c111.c index a08bdb0a5..3a8a85c1f 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -4,7 +4,7 @@ * Copyright (c) 2005 CodeSourcery, LLC. * Written by Paul Brook * - * This code is licenced under the GPL + * This code is licensed under the GPL */ #include "sysbus.h" @@ -18,7 +18,8 @@ typedef struct { SysBusDevice busdev; - VLANClientState *vc; + NICState *nic; + NICConf conf; uint16_t tcr; uint16_t rcr; uint16_t cr; @@ -42,10 +43,38 @@ typedef struct { uint8_t data[NUM_PACKETS][2048]; uint8_t int_level; uint8_t int_mask; - uint8_t macaddr[6]; int mmio_index; } smc91c111_state; +static const VMStateDescription vmstate_smc91c111 = { + .name = "smc91c111", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField []) { + VMSTATE_UINT16(tcr, smc91c111_state), + VMSTATE_UINT16(rcr, smc91c111_state), + VMSTATE_UINT16(cr, smc91c111_state), + VMSTATE_UINT16(ctr, smc91c111_state), + VMSTATE_UINT16(gpr, smc91c111_state), + VMSTATE_UINT16(ptr, smc91c111_state), + VMSTATE_UINT16(ercv, smc91c111_state), + VMSTATE_INT32(bank, smc91c111_state), + VMSTATE_INT32(packet_num, smc91c111_state), + VMSTATE_INT32(tx_alloc, smc91c111_state), + VMSTATE_INT32(allocated, smc91c111_state), + VMSTATE_INT32(tx_fifo_len, smc91c111_state), + VMSTATE_INT32_ARRAY(tx_fifo, smc91c111_state, NUM_PACKETS), + VMSTATE_INT32(rx_fifo_len, smc91c111_state), + VMSTATE_INT32_ARRAY(rx_fifo, smc91c111_state, NUM_PACKETS), + VMSTATE_INT32(tx_fifo_done_len, smc91c111_state), + VMSTATE_INT32_ARRAY(tx_fifo_done, smc91c111_state, NUM_PACKETS), + VMSTATE_BUFFER_UNSAFE(data, smc91c111_state, 0, NUM_PACKETS * 2048), + VMSTATE_UINT8(int_level, smc91c111_state), + VMSTATE_UINT8(int_mask, smc91c111_state), + VMSTATE_END_OF_LIST() + } +}; + #define RCR_SOFT_RST 0x8000 #define RCR_STRIP_CRC 0x0200 #define RCR_RXEN 0x0100 @@ -160,7 +189,6 @@ static void smc91c111_do_tx(smc91c111_state *s) int i; int len; int control; - int add_crc; int packetnum; uint8_t *p; @@ -187,27 +215,29 @@ static void smc91c111_do_tx(smc91c111_state *s) len = 64; } #if 0 - /* The card is supposed to append the CRC to the frame. However - none of the other network traffic has the CRC appended. - Suspect this is low level ethernet detail we don't need to worry - about. */ - add_crc = (control & 0x10) || (s->tcr & TCR_NOCRC) == 0; - if (add_crc) { - uint32_t crc; - - crc = crc32(~0, p, len); - memcpy(p + len, &crc, 4); - len += 4; + { + int add_crc; + + /* The card is supposed to append the CRC to the frame. + However none of the other network traffic has the CRC + appended. Suspect this is low level ethernet detail we + don't need to worry about. */ + add_crc = (control & 0x10) || (s->tcr & TCR_NOCRC) == 0; + if (add_crc) { + uint32_t crc; + + crc = crc32(~0, p, len); + memcpy(p + len, &crc, 4); + len += 4; + } } -#else - add_crc = 0; #endif if (s->ctr & CTR_AUTO_RELEASE) /* Race? */ smc91c111_release_packet(s, packetnum); else if (s->tx_fifo_done_len < NUM_PACKETS) s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum; - qemu_send_packet(s->vc, p, len); + qemu_send_packet(&s->nic->nc, p, len); } s->tx_fifo_len = 0; smc91c111_update(s); @@ -222,8 +252,9 @@ static void smc91c111_queue_tx(smc91c111_state *s, int packet) smc91c111_do_tx(s); } -static void smc91c111_reset(smc91c111_state *s) +static void smc91c111_reset(DeviceState *dev) { + smc91c111_state *s = FROM_SYSBUS(smc91c111_state, sysbus_from_qdev(dev)); s->bank = 0; s->tx_fifo_len = 0; s->tx_fifo_done_len = 0; @@ -250,6 +281,7 @@ static void smc91c111_writeb(void *opaque, target_phys_addr_t offset, { smc91c111_state *s = (smc91c111_state *)opaque; + offset = offset & 0xf; if (offset == 14) { s->bank = value; return; @@ -271,11 +303,13 @@ static void smc91c111_writeb(void *opaque, target_phys_addr_t offset, case 5: SET_HIGH(rcr, value); if (s->rcr & RCR_SOFT_RST) - smc91c111_reset(s); + smc91c111_reset(&s->busdev.qdev); return; case 10: case 11: /* RPCR */ /* Ignored */ return; + case 12: case 13: /* Reserved */ + return; } break; @@ -421,6 +455,7 @@ static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset) { smc91c111_state *s = (smc91c111_state *)opaque; + offset = offset & 0xf; if (offset == 14) { return s->bank; } @@ -461,6 +496,8 @@ static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset) case 10: case 11: /* RPCR */ /* Not implemented. */ return 0; + case 12: case 13: /* Reserved */ + return 0; } break; @@ -474,7 +511,7 @@ static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset) /* Not implemented. */ return 0; case 4: case 5: case 6: case 7: case 8: case 9: /* IA */ - return s->macaddr[offset - 4]; + return s->conf.macaddr.a[offset - 4]; case 10: /* General Purpose */ return s->gpr & 0xff; case 11: @@ -591,9 +628,9 @@ static uint32_t smc91c111_readl(void *opaque, target_phys_addr_t offset) return val; } -static int smc91c111_can_receive(VLANClientState *vc) +static int smc91c111_can_receive(VLANClientState *nc) { - smc91c111_state *s = vc->opaque; + smc91c111_state *s = DO_UPCAST(NICState, nc, nc)->opaque; if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST)) return 1; @@ -602,9 +639,9 @@ static int smc91c111_can_receive(VLANClientState *vc) return 1; } -static ssize_t smc91c111_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t smc91c111_receive(VLANClientState *nc, const uint8_t *buf, size_t size) { - smc91c111_state *s = vc->opaque; + smc91c111_state *s = DO_UPCAST(NICState, nc, nc)->opaque; int status; int packetsize; uint32_t crc; @@ -664,14 +701,14 @@ static ssize_t smc91c111_receive(VLANClientState *vc, const uint8_t *buf, size_t *(p++) = crc & 0xff; crc >>= 8; *(p++) = crc & 0xff; crc >>= 8; *(p++) = crc & 0xff; crc >>= 8; - *(p++) = crc & 0xff; crc >>= 8; + *(p++) = crc & 0xff; } if (size & 1) { *(p++) = buf[size - 1]; - *(p++) = 0x60; + *p = 0x60; } else { *(p++) = 0; - *(p++) = 0x40; + *p = 0x40; } /* TODO: Raise early RX interrupt? */ s->int_level |= INT_RCV; @@ -692,37 +729,53 @@ static CPUWriteMemoryFunc * const smc91c111_writefn[] = { smc91c111_writel }; -static void smc91c111_cleanup(VLANClientState *vc) +static void smc91c111_cleanup(VLANClientState *nc) { - smc91c111_state *s = vc->opaque; + smc91c111_state *s = DO_UPCAST(NICState, nc, nc)->opaque; - cpu_unregister_io_memory(s->mmio_index); - qemu_free(s); + s->nic = NULL; } +static NetClientInfo net_smc91c111_info = { + .type = NET_CLIENT_TYPE_NIC, + .size = sizeof(NICState), + .can_receive = smc91c111_can_receive, + .receive = smc91c111_receive, + .cleanup = smc91c111_cleanup, +}; + static int smc91c111_init1(SysBusDevice *dev) { smc91c111_state *s = FROM_SYSBUS(smc91c111_state, dev); s->mmio_index = cpu_register_io_memory(smc91c111_readfn, - smc91c111_writefn, s); + smc91c111_writefn, s, + DEVICE_NATIVE_ENDIAN); sysbus_init_mmio(dev, 16, s->mmio_index); sysbus_init_irq(dev, &s->irq); - qdev_get_macaddr(&dev->qdev, s->macaddr); - - smc91c111_reset(s); - - s->vc = qdev_get_vlan_client(&dev->qdev, - smc91c111_can_receive, smc91c111_receive, NULL, - smc91c111_cleanup, s); - qemu_format_nic_info_str(s->vc, s->macaddr); + qemu_macaddr_default_if_unset(&s->conf.macaddr); + s->nic = qemu_new_nic(&net_smc91c111_info, &s->conf, + dev->qdev.info->name, dev->qdev.id, s); + qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); /* ??? Save/restore. */ return 0; } +static SysBusDeviceInfo smc91c111_info = { + .init = smc91c111_init1, + .qdev.name = "smc91c111", + .qdev.size = sizeof(smc91c111_state), + .qdev.vmsd = &vmstate_smc91c111, + .qdev.reset = smc91c111_reset, + .qdev.props = (Property[]) { + DEFINE_NIC_PROPERTIES(smc91c111_state, conf), + DEFINE_PROP_END_OF_LIST(), + } +}; + static void smc91c111_register_devices(void) { - sysbus_register_dev("smc91c111", sizeof(smc91c111_state), smc91c111_init1); + sysbus_register_withprop(&smc91c111_info); } /* Legacy helper function. Should go away when machine config files are @@ -734,8 +787,8 @@ void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq) qemu_check_nic_model(nd, "smc91c111"); dev = qdev_create(NULL, "smc91c111"); - dev->nd = nd; - qdev_init(dev); + qdev_set_nic_properties(dev, nd); + qdev_init_nofail(dev); s = sysbus_from_qdev(dev); sysbus_mmio_map(s, 0, base); sysbus_connect_irq(s, 0, irq);