|
|
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"
1.1.1.3 ! root 34: #include "dma.h"
1.1 root 35:
36: #include "pcnet.h"
37:
38: //#define PCNET_DEBUG
39: //#define PCNET_DEBUG_IO
40: //#define PCNET_DEBUG_BCR
41: //#define PCNET_DEBUG_CSR
42: //#define PCNET_DEBUG_RMD
43: //#define PCNET_DEBUG_TMD
44: //#define PCNET_DEBUG_MATCH
45:
46:
47: typedef struct {
48: PCIDevice pci_dev;
49: PCNetState state;
1.1.1.3 ! root 50: MemoryRegion io_bar;
1.1 root 51: } PCIPCNetState;
52:
53: static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val)
54: {
55: PCNetState *s = opaque;
56: #ifdef PCNET_DEBUG
57: printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val);
58: #endif
1.1.1.3 ! root 59: if (BCR_APROMWE(s)) {
1.1 root 60: s->prom[addr & 15] = val;
1.1.1.3 ! root 61: }
1.1 root 62: }
63:
64: static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr)
65: {
66: PCNetState *s = opaque;
67: uint32_t val = s->prom[addr & 15];
68: #ifdef PCNET_DEBUG
69: printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val);
70: #endif
71: return val;
72: }
73:
1.1.1.3 ! root 74: static uint64_t pcnet_ioport_read(void *opaque, target_phys_addr_t addr,
! 75: unsigned size)
1.1 root 76: {
1.1.1.3 ! root 77: PCNetState *d = opaque;
1.1 root 78:
1.1.1.3 ! root 79: if (addr < 0x10) {
! 80: if (!BCR_DWIO(d) && size == 1) {
! 81: return pcnet_aprom_readb(d, addr);
! 82: } else if (!BCR_DWIO(d) && (addr & 1) == 0 && size == 2) {
! 83: return pcnet_aprom_readb(d, addr) |
! 84: (pcnet_aprom_readb(d, addr + 1) << 8);
! 85: } else if (BCR_DWIO(d) && (addr & 3) == 0 && size == 4) {
! 86: return pcnet_aprom_readb(d, addr) |
! 87: (pcnet_aprom_readb(d, addr + 1) << 8) |
! 88: (pcnet_aprom_readb(d, addr + 2) << 16) |
! 89: (pcnet_aprom_readb(d, addr + 3) << 24);
! 90: }
! 91: } else {
! 92: if (size == 2) {
! 93: return pcnet_ioport_readw(d, addr);
! 94: } else if (size == 4) {
! 95: return pcnet_ioport_readl(d, addr);
! 96: }
! 97: }
! 98: return ((uint64_t)1 << (size * 8)) - 1;
! 99: }
1.1 root 100:
1.1.1.3 ! root 101: static void pcnet_ioport_write(void *opaque, target_phys_addr_t addr,
! 102: uint64_t data, unsigned size)
! 103: {
! 104: PCNetState *d = opaque;
1.1 root 105:
1.1.1.3 ! root 106: if (addr < 0x10) {
! 107: if (!BCR_DWIO(d) && size == 1) {
! 108: pcnet_aprom_writeb(d, addr, data);
! 109: } else if (!BCR_DWIO(d) && (addr & 1) == 0 && size == 2) {
! 110: pcnet_aprom_writeb(d, addr, data & 0xff);
! 111: pcnet_aprom_writeb(d, addr + 1, data >> 8);
! 112: } else if (BCR_DWIO(d) && (addr & 3) == 0 && size == 4) {
! 113: pcnet_aprom_writeb(d, addr, data & 0xff);
! 114: pcnet_aprom_writeb(d, addr + 1, (data >> 8) & 0xff);
! 115: pcnet_aprom_writeb(d, addr + 2, (data >> 16) & 0xff);
! 116: pcnet_aprom_writeb(d, addr + 3, data >> 24);
! 117: }
! 118: } else {
! 119: if (size == 2) {
! 120: pcnet_ioport_writew(d, addr, data);
! 121: } else if (size == 4) {
! 122: pcnet_ioport_writel(d, addr, data);
! 123: }
! 124: }
1.1 root 125: }
126:
1.1.1.3 ! root 127: static const MemoryRegionOps pcnet_io_ops = {
! 128: .read = pcnet_ioport_read,
! 129: .write = pcnet_ioport_write,
! 130: .endianness = DEVICE_NATIVE_ENDIAN,
! 131: };
! 132:
1.1 root 133: static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
134: {
135: PCNetState *d = opaque;
136: #ifdef PCNET_DEBUG_IO
137: printf("pcnet_mmio_writeb addr=0x" TARGET_FMT_plx" val=0x%02x\n", addr,
138: val);
139: #endif
140: if (!(addr & 0x10))
141: pcnet_aprom_writeb(d, addr & 0x0f, val);
142: }
143:
144: static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr)
145: {
146: PCNetState *d = opaque;
147: uint32_t val = -1;
148: if (!(addr & 0x10))
149: val = pcnet_aprom_readb(d, addr & 0x0f);
150: #ifdef PCNET_DEBUG_IO
151: printf("pcnet_mmio_readb addr=0x" TARGET_FMT_plx " val=0x%02x\n", addr,
152: val & 0xff);
153: #endif
154: return val;
155: }
156:
157: static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
158: {
159: PCNetState *d = opaque;
160: #ifdef PCNET_DEBUG_IO
161: printf("pcnet_mmio_writew addr=0x" TARGET_FMT_plx " val=0x%04x\n", addr,
162: val);
163: #endif
164: if (addr & 0x10)
165: pcnet_ioport_writew(d, addr & 0x0f, val);
166: else {
167: addr &= 0x0f;
168: pcnet_aprom_writeb(d, addr, val & 0xff);
169: pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
170: }
171: }
172:
173: static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr)
174: {
175: PCNetState *d = opaque;
176: uint32_t val = -1;
177: if (addr & 0x10)
178: val = pcnet_ioport_readw(d, addr & 0x0f);
179: else {
180: addr &= 0x0f;
181: val = pcnet_aprom_readb(d, addr+1);
182: val <<= 8;
183: val |= pcnet_aprom_readb(d, addr);
184: }
185: #ifdef PCNET_DEBUG_IO
186: printf("pcnet_mmio_readw addr=0x" TARGET_FMT_plx" val = 0x%04x\n", addr,
187: val & 0xffff);
188: #endif
189: return val;
190: }
191:
192: static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
193: {
194: PCNetState *d = opaque;
195: #ifdef PCNET_DEBUG_IO
196: printf("pcnet_mmio_writel addr=0x" TARGET_FMT_plx" val=0x%08x\n", addr,
197: val);
198: #endif
199: if (addr & 0x10)
200: pcnet_ioport_writel(d, addr & 0x0f, val);
201: else {
202: addr &= 0x0f;
203: pcnet_aprom_writeb(d, addr, val & 0xff);
204: pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
205: pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16);
206: pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24);
207: }
208: }
209:
210: static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr)
211: {
212: PCNetState *d = opaque;
213: uint32_t val;
214: if (addr & 0x10)
215: val = pcnet_ioport_readl(d, addr & 0x0f);
216: else {
217: addr &= 0x0f;
218: val = pcnet_aprom_readb(d, addr+3);
219: val <<= 8;
220: val |= pcnet_aprom_readb(d, addr+2);
221: val <<= 8;
222: val |= pcnet_aprom_readb(d, addr+1);
223: val <<= 8;
224: val |= pcnet_aprom_readb(d, addr);
225: }
226: #ifdef PCNET_DEBUG_IO
227: printf("pcnet_mmio_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr,
228: val);
229: #endif
230: return val;
231: }
232:
233: static const VMStateDescription vmstate_pci_pcnet = {
234: .name = "pcnet",
235: .version_id = 3,
236: .minimum_version_id = 2,
237: .minimum_version_id_old = 2,
238: .fields = (VMStateField []) {
239: VMSTATE_PCI_DEVICE(pci_dev, PCIPCNetState),
240: VMSTATE_STRUCT(state, PCIPCNetState, 0, vmstate_pcnet, PCNetState),
241: VMSTATE_END_OF_LIST()
242: }
243: };
244:
245: /* PCI interface */
246:
1.1.1.3 ! root 247: static const MemoryRegionOps pcnet_mmio_ops = {
! 248: .old_mmio = {
! 249: .read = { pcnet_mmio_readb, pcnet_mmio_readw, pcnet_mmio_readl },
! 250: .write = { pcnet_mmio_writeb, pcnet_mmio_writew, pcnet_mmio_writel },
! 251: },
! 252: .endianness = DEVICE_NATIVE_ENDIAN,
1.1 root 253: };
254:
255: static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr,
256: uint8_t *buf, int len, int do_bswap)
257: {
1.1.1.3 ! root 258: pci_dma_write(dma_opaque, addr, buf, len);
1.1 root 259: }
260:
261: static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr,
262: uint8_t *buf, int len, int do_bswap)
263: {
1.1.1.3 ! root 264: pci_dma_read(dma_opaque, addr, buf, len);
1.1 root 265: }
266:
267: static void pci_pcnet_cleanup(VLANClientState *nc)
268: {
269: PCNetState *d = DO_UPCAST(NICState, nc, nc)->opaque;
270:
271: pcnet_common_cleanup(d);
272: }
273:
274: static int pci_pcnet_uninit(PCIDevice *dev)
275: {
276: PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, dev);
277:
1.1.1.3 ! root 278: memory_region_destroy(&d->state.mmio);
! 279: memory_region_destroy(&d->io_bar);
1.1 root 280: qemu_del_timer(d->state.poll_timer);
281: qemu_free_timer(d->state.poll_timer);
282: qemu_del_vlan_client(&d->state.nic->nc);
283: return 0;
284: }
285:
286: static NetClientInfo net_pci_pcnet_info = {
287: .type = NET_CLIENT_TYPE_NIC,
288: .size = sizeof(NICState),
289: .can_receive = pcnet_can_receive,
290: .receive = pcnet_receive,
1.1.1.3 ! root 291: .link_status_changed = pcnet_set_link_status,
1.1 root 292: .cleanup = pci_pcnet_cleanup,
293: };
294:
295: static int pci_pcnet_init(PCIDevice *pci_dev)
296: {
297: PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
298: PCNetState *s = &d->state;
299: uint8_t *pci_conf;
300:
301: #if 0
302: printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n",
303: sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD));
304: #endif
305:
306: pci_conf = pci_dev->config;
307:
308: pci_set_word(pci_conf + PCI_STATUS,
309: PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
310:
311: pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x0);
312: pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0);
313:
1.1.1.3 ! root 314: pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
1.1 root 315: pci_conf[PCI_MIN_GNT] = 0x06;
316: pci_conf[PCI_MAX_LAT] = 0xff;
317:
318: /* Handler for memory-mapped I/O */
1.1.1.3 ! root 319: memory_region_init_io(&d->state.mmio, &pcnet_mmio_ops, s, "pcnet-mmio",
! 320: PCNET_PNPMMIO_SIZE);
1.1 root 321:
1.1.1.3 ! root 322: memory_region_init_io(&d->io_bar, &pcnet_io_ops, s, "pcnet-io",
! 323: PCNET_IOPORT_SIZE);
! 324: pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->io_bar);
1.1 root 325:
1.1.1.3 ! root 326: pci_register_bar(pci_dev, 1, 0, &s->mmio);
1.1 root 327:
328: s->irq = pci_dev->irq[0];
329: s->phys_mem_read = pci_physical_memory_read;
330: s->phys_mem_write = pci_physical_memory_write;
1.1.1.3 ! root 331: s->dma_opaque = pci_dev;
1.1 root 332:
333: if (!pci_dev->qdev.hotplugged) {
334: static int loaded = 0;
335: if (!loaded) {
1.1.1.2 root 336: rom_add_option("pxe-pcnet.rom", -1);
1.1 root 337: loaded = 1;
338: }
339: }
340:
341: return pcnet_common_init(&pci_dev->qdev, s, &net_pci_pcnet_info);
342: }
343:
344: static void pci_reset(DeviceState *dev)
345: {
346: PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev.qdev, dev);
347:
348: pcnet_h_reset(&d->state);
349: }
350:
351: static PCIDeviceInfo pcnet_info = {
352: .qdev.name = "pcnet",
353: .qdev.size = sizeof(PCIPCNetState),
354: .qdev.reset = pci_reset,
355: .qdev.vmsd = &vmstate_pci_pcnet,
356: .init = pci_pcnet_init,
357: .exit = pci_pcnet_uninit,
1.1.1.2 root 358: .vendor_id = PCI_VENDOR_ID_AMD,
359: .device_id = PCI_DEVICE_ID_AMD_LANCE,
360: .revision = 0x10,
361: .class_id = PCI_CLASS_NETWORK_ETHERNET,
1.1 root 362: .qdev.props = (Property[]) {
363: DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf),
364: DEFINE_PROP_END_OF_LIST(),
365: }
366: };
367:
368: static void pci_pcnet_register_devices(void)
369: {
370: pci_qdev_register(&pcnet_info);
371: }
372:
373: 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.