|
|
1.1 ! root 1: /* ! 2: * QEMU AMD PC-Net II (Am79C970A) PCI emulation ! 3: * ! 4: * Copyright (c) 2004 Antony T Curtis ! 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: /* This software was written to be compatible with the specification: ! 26: * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet ! 27: * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000 ! 28: */ ! 29: ! 30: #include "pci.h" ! 31: #include "net.h" ! 32: #include "loader.h" ! 33: #include "qemu-timer.h" ! 34: ! 35: #include "pcnet.h" ! 36: ! 37: //#define PCNET_DEBUG ! 38: //#define PCNET_DEBUG_IO ! 39: //#define PCNET_DEBUG_BCR ! 40: //#define PCNET_DEBUG_CSR ! 41: //#define PCNET_DEBUG_RMD ! 42: //#define PCNET_DEBUG_TMD ! 43: //#define PCNET_DEBUG_MATCH ! 44: ! 45: ! 46: typedef struct { ! 47: PCIDevice pci_dev; ! 48: PCNetState state; ! 49: } PCIPCNetState; ! 50: ! 51: static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val) ! 52: { ! 53: PCNetState *s = opaque; ! 54: #ifdef PCNET_DEBUG ! 55: printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val); ! 56: #endif ! 57: /* Check APROMWE bit to enable write access */ ! 58: if (pcnet_bcr_readw(s,2) & 0x100) ! 59: s->prom[addr & 15] = val; ! 60: } ! 61: ! 62: static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr) ! 63: { ! 64: PCNetState *s = opaque; ! 65: uint32_t val = s->prom[addr & 15]; ! 66: #ifdef PCNET_DEBUG ! 67: printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val); ! 68: #endif ! 69: return val; ! 70: } ! 71: ! 72: static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num, ! 73: pcibus_t addr, pcibus_t size, int type) ! 74: { ! 75: PCNetState *d = &DO_UPCAST(PCIPCNetState, pci_dev, pci_dev)->state; ! 76: ! 77: #ifdef PCNET_DEBUG_IO ! 78: printf("pcnet_ioport_map addr=0x%04"FMT_PCIBUS" size=0x%04"FMT_PCIBUS"\n", ! 79: addr, size); ! 80: #endif ! 81: ! 82: register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d); ! 83: register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d); ! 84: ! 85: register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d); ! 86: register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d); ! 87: register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d); ! 88: register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d); ! 89: } ! 90: ! 91: static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) ! 92: { ! 93: PCNetState *d = opaque; ! 94: #ifdef PCNET_DEBUG_IO ! 95: printf("pcnet_mmio_writeb addr=0x" TARGET_FMT_plx" val=0x%02x\n", addr, ! 96: val); ! 97: #endif ! 98: if (!(addr & 0x10)) ! 99: pcnet_aprom_writeb(d, addr & 0x0f, val); ! 100: } ! 101: ! 102: static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr) ! 103: { ! 104: PCNetState *d = opaque; ! 105: uint32_t val = -1; ! 106: if (!(addr & 0x10)) ! 107: val = pcnet_aprom_readb(d, addr & 0x0f); ! 108: #ifdef PCNET_DEBUG_IO ! 109: printf("pcnet_mmio_readb addr=0x" TARGET_FMT_plx " val=0x%02x\n", addr, ! 110: val & 0xff); ! 111: #endif ! 112: return val; ! 113: } ! 114: ! 115: static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) ! 116: { ! 117: PCNetState *d = opaque; ! 118: #ifdef PCNET_DEBUG_IO ! 119: printf("pcnet_mmio_writew addr=0x" TARGET_FMT_plx " val=0x%04x\n", addr, ! 120: val); ! 121: #endif ! 122: if (addr & 0x10) ! 123: pcnet_ioport_writew(d, addr & 0x0f, val); ! 124: else { ! 125: addr &= 0x0f; ! 126: pcnet_aprom_writeb(d, addr, val & 0xff); ! 127: pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8); ! 128: } ! 129: } ! 130: ! 131: static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr) ! 132: { ! 133: PCNetState *d = opaque; ! 134: uint32_t val = -1; ! 135: if (addr & 0x10) ! 136: val = pcnet_ioport_readw(d, addr & 0x0f); ! 137: else { ! 138: addr &= 0x0f; ! 139: val = pcnet_aprom_readb(d, addr+1); ! 140: val <<= 8; ! 141: val |= pcnet_aprom_readb(d, addr); ! 142: } ! 143: #ifdef PCNET_DEBUG_IO ! 144: printf("pcnet_mmio_readw addr=0x" TARGET_FMT_plx" val = 0x%04x\n", addr, ! 145: val & 0xffff); ! 146: #endif ! 147: return val; ! 148: } ! 149: ! 150: static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) ! 151: { ! 152: PCNetState *d = opaque; ! 153: #ifdef PCNET_DEBUG_IO ! 154: printf("pcnet_mmio_writel addr=0x" TARGET_FMT_plx" val=0x%08x\n", addr, ! 155: val); ! 156: #endif ! 157: if (addr & 0x10) ! 158: pcnet_ioport_writel(d, addr & 0x0f, val); ! 159: else { ! 160: addr &= 0x0f; ! 161: pcnet_aprom_writeb(d, addr, val & 0xff); ! 162: pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8); ! 163: pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16); ! 164: pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24); ! 165: } ! 166: } ! 167: ! 168: static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr) ! 169: { ! 170: PCNetState *d = opaque; ! 171: uint32_t val; ! 172: if (addr & 0x10) ! 173: val = pcnet_ioport_readl(d, addr & 0x0f); ! 174: else { ! 175: addr &= 0x0f; ! 176: val = pcnet_aprom_readb(d, addr+3); ! 177: val <<= 8; ! 178: val |= pcnet_aprom_readb(d, addr+2); ! 179: val <<= 8; ! 180: val |= pcnet_aprom_readb(d, addr+1); ! 181: val <<= 8; ! 182: val |= pcnet_aprom_readb(d, addr); ! 183: } ! 184: #ifdef PCNET_DEBUG_IO ! 185: printf("pcnet_mmio_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, ! 186: val); ! 187: #endif ! 188: return val; ! 189: } ! 190: ! 191: static const VMStateDescription vmstate_pci_pcnet = { ! 192: .name = "pcnet", ! 193: .version_id = 3, ! 194: .minimum_version_id = 2, ! 195: .minimum_version_id_old = 2, ! 196: .fields = (VMStateField []) { ! 197: VMSTATE_PCI_DEVICE(pci_dev, PCIPCNetState), ! 198: VMSTATE_STRUCT(state, PCIPCNetState, 0, vmstate_pcnet, PCNetState), ! 199: VMSTATE_END_OF_LIST() ! 200: } ! 201: }; ! 202: ! 203: /* PCI interface */ ! 204: ! 205: static CPUWriteMemoryFunc * const pcnet_mmio_write[] = { ! 206: &pcnet_mmio_writeb, ! 207: &pcnet_mmio_writew, ! 208: &pcnet_mmio_writel ! 209: }; ! 210: ! 211: static CPUReadMemoryFunc * const pcnet_mmio_read[] = { ! 212: &pcnet_mmio_readb, ! 213: &pcnet_mmio_readw, ! 214: &pcnet_mmio_readl ! 215: }; ! 216: ! 217: static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num, ! 218: pcibus_t addr, pcibus_t size, int type) ! 219: { ! 220: PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev); ! 221: ! 222: #ifdef PCNET_DEBUG_IO ! 223: printf("pcnet_mmio_map addr=0x%08"FMT_PCIBUS" 0x%08"FMT_PCIBUS"\n", ! 224: addr, size); ! 225: #endif ! 226: ! 227: cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->state.mmio_index); ! 228: } ! 229: ! 230: static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr, ! 231: uint8_t *buf, int len, int do_bswap) ! 232: { ! 233: cpu_physical_memory_write(addr, buf, len); ! 234: } ! 235: ! 236: static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr, ! 237: uint8_t *buf, int len, int do_bswap) ! 238: { ! 239: cpu_physical_memory_read(addr, buf, len); ! 240: } ! 241: ! 242: static void pci_pcnet_cleanup(VLANClientState *nc) ! 243: { ! 244: PCNetState *d = DO_UPCAST(NICState, nc, nc)->opaque; ! 245: ! 246: pcnet_common_cleanup(d); ! 247: } ! 248: ! 249: static int pci_pcnet_uninit(PCIDevice *dev) ! 250: { ! 251: PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, dev); ! 252: ! 253: cpu_unregister_io_memory(d->state.mmio_index); ! 254: qemu_del_timer(d->state.poll_timer); ! 255: qemu_free_timer(d->state.poll_timer); ! 256: qemu_del_vlan_client(&d->state.nic->nc); ! 257: return 0; ! 258: } ! 259: ! 260: static NetClientInfo net_pci_pcnet_info = { ! 261: .type = NET_CLIENT_TYPE_NIC, ! 262: .size = sizeof(NICState), ! 263: .can_receive = pcnet_can_receive, ! 264: .receive = pcnet_receive, ! 265: .cleanup = pci_pcnet_cleanup, ! 266: }; ! 267: ! 268: static int pci_pcnet_init(PCIDevice *pci_dev) ! 269: { ! 270: PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev); ! 271: PCNetState *s = &d->state; ! 272: uint8_t *pci_conf; ! 273: ! 274: #if 0 ! 275: printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n", ! 276: sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD)); ! 277: #endif ! 278: ! 279: pci_conf = pci_dev->config; ! 280: ! 281: pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_AMD); ! 282: pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_AMD_LANCE); ! 283: pci_set_word(pci_conf + PCI_STATUS, ! 284: PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM); ! 285: pci_conf[PCI_REVISION_ID] = 0x10; ! 286: pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET); ! 287: ! 288: pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x0); ! 289: pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0); ! 290: ! 291: pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0 ! 292: pci_conf[PCI_MIN_GNT] = 0x06; ! 293: pci_conf[PCI_MAX_LAT] = 0xff; ! 294: ! 295: /* Handler for memory-mapped I/O */ ! 296: s->mmio_index = ! 297: cpu_register_io_memory(pcnet_mmio_read, pcnet_mmio_write, &d->state, ! 298: DEVICE_NATIVE_ENDIAN); ! 299: ! 300: pci_register_bar(pci_dev, 0, PCNET_IOPORT_SIZE, ! 301: PCI_BASE_ADDRESS_SPACE_IO, pcnet_ioport_map); ! 302: ! 303: pci_register_bar(pci_dev, 1, PCNET_PNPMMIO_SIZE, ! 304: PCI_BASE_ADDRESS_SPACE_MEMORY, pcnet_mmio_map); ! 305: ! 306: s->irq = pci_dev->irq[0]; ! 307: s->phys_mem_read = pci_physical_memory_read; ! 308: s->phys_mem_write = pci_physical_memory_write; ! 309: ! 310: if (!pci_dev->qdev.hotplugged) { ! 311: static int loaded = 0; ! 312: if (!loaded) { ! 313: rom_add_option("pxe-pcnet.bin", -1); ! 314: loaded = 1; ! 315: } ! 316: } ! 317: ! 318: return pcnet_common_init(&pci_dev->qdev, s, &net_pci_pcnet_info); ! 319: } ! 320: ! 321: static void pci_reset(DeviceState *dev) ! 322: { ! 323: PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev.qdev, dev); ! 324: ! 325: pcnet_h_reset(&d->state); ! 326: } ! 327: ! 328: static PCIDeviceInfo pcnet_info = { ! 329: .qdev.name = "pcnet", ! 330: .qdev.size = sizeof(PCIPCNetState), ! 331: .qdev.reset = pci_reset, ! 332: .qdev.vmsd = &vmstate_pci_pcnet, ! 333: .init = pci_pcnet_init, ! 334: .exit = pci_pcnet_uninit, ! 335: .qdev.props = (Property[]) { ! 336: DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf), ! 337: DEFINE_PROP_END_OF_LIST(), ! 338: } ! 339: }; ! 340: ! 341: static void pci_pcnet_register_devices(void) ! 342: { ! 343: pci_qdev_register(&pcnet_info); ! 344: } ! 345: ! 346: device_init(pci_pcnet_register_devices)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.