|
|
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 pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr,
218: uint8_t *buf, int len, int do_bswap)
219: {
220: cpu_physical_memory_write(addr, buf, len);
221: }
222:
223: static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr,
224: uint8_t *buf, int len, int do_bswap)
225: {
226: cpu_physical_memory_read(addr, buf, len);
227: }
228:
229: static void pci_pcnet_cleanup(VLANClientState *nc)
230: {
231: PCNetState *d = DO_UPCAST(NICState, nc, nc)->opaque;
232:
233: pcnet_common_cleanup(d);
234: }
235:
236: static int pci_pcnet_uninit(PCIDevice *dev)
237: {
238: PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, dev);
239:
240: cpu_unregister_io_memory(d->state.mmio_index);
241: qemu_del_timer(d->state.poll_timer);
242: qemu_free_timer(d->state.poll_timer);
243: qemu_del_vlan_client(&d->state.nic->nc);
244: return 0;
245: }
246:
247: static NetClientInfo net_pci_pcnet_info = {
248: .type = NET_CLIENT_TYPE_NIC,
249: .size = sizeof(NICState),
250: .can_receive = pcnet_can_receive,
251: .receive = pcnet_receive,
252: .cleanup = pci_pcnet_cleanup,
253: };
254:
255: static int pci_pcnet_init(PCIDevice *pci_dev)
256: {
257: PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
258: PCNetState *s = &d->state;
259: uint8_t *pci_conf;
260:
261: #if 0
262: printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n",
263: sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD));
264: #endif
265:
266: pci_conf = pci_dev->config;
267:
268: pci_set_word(pci_conf + PCI_STATUS,
269: PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
270:
271: pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x0);
272: pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0);
273:
274: pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0
275: pci_conf[PCI_MIN_GNT] = 0x06;
276: pci_conf[PCI_MAX_LAT] = 0xff;
277:
278: /* Handler for memory-mapped I/O */
279: s->mmio_index =
280: cpu_register_io_memory(pcnet_mmio_read, pcnet_mmio_write, &d->state,
281: DEVICE_NATIVE_ENDIAN);
282:
283: pci_register_bar(pci_dev, 0, PCNET_IOPORT_SIZE,
284: PCI_BASE_ADDRESS_SPACE_IO, pcnet_ioport_map);
285:
1.1.1.2 ! root 286: pci_register_bar_simple(pci_dev, 1, PCNET_PNPMMIO_SIZE, 0, s->mmio_index);
1.1 root 287:
288: s->irq = pci_dev->irq[0];
289: s->phys_mem_read = pci_physical_memory_read;
290: s->phys_mem_write = pci_physical_memory_write;
291:
292: if (!pci_dev->qdev.hotplugged) {
293: static int loaded = 0;
294: if (!loaded) {
1.1.1.2 ! root 295: rom_add_option("pxe-pcnet.rom", -1);
1.1 root 296: loaded = 1;
297: }
298: }
299:
300: return pcnet_common_init(&pci_dev->qdev, s, &net_pci_pcnet_info);
301: }
302:
303: static void pci_reset(DeviceState *dev)
304: {
305: PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev.qdev, dev);
306:
307: pcnet_h_reset(&d->state);
308: }
309:
310: static PCIDeviceInfo pcnet_info = {
311: .qdev.name = "pcnet",
312: .qdev.size = sizeof(PCIPCNetState),
313: .qdev.reset = pci_reset,
314: .qdev.vmsd = &vmstate_pci_pcnet,
315: .init = pci_pcnet_init,
316: .exit = pci_pcnet_uninit,
1.1.1.2 ! root 317: .vendor_id = PCI_VENDOR_ID_AMD,
! 318: .device_id = PCI_DEVICE_ID_AMD_LANCE,
! 319: .revision = 0x10,
! 320: .class_id = PCI_CLASS_NETWORK_ETHERNET,
1.1 root 321: .qdev.props = (Property[]) {
322: DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf),
323: DEFINE_PROP_END_OF_LIST(),
324: }
325: };
326:
327: static void pci_pcnet_register_devices(void)
328: {
329: pci_qdev_register(&pcnet_info);
330: }
331:
332: 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.