root / hw / net / xgmac.c @ 49ab747f
History | View | Annotate | Download (14.5 kB)
1 |
/*
|
---|---|
2 |
* QEMU model of XGMAC Ethernet.
|
3 |
*
|
4 |
* derived from the Xilinx AXI-Ethernet by Edgar E. Iglesias.
|
5 |
*
|
6 |
* Copyright (c) 2011 Calxeda, Inc.
|
7 |
*
|
8 |
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
9 |
* of this software and associated documentation files (the "Software"), to deal
|
10 |
* in the Software without restriction, including without limitation the rights
|
11 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
12 |
* copies of the Software, and to permit persons to whom the Software is
|
13 |
* furnished to do so, subject to the following conditions:
|
14 |
*
|
15 |
* The above copyright notice and this permission notice shall be included in
|
16 |
* all copies or substantial portions of the Software.
|
17 |
*
|
18 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
19 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
20 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
21 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
22 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
23 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
24 |
* THE SOFTWARE.
|
25 |
*/
|
26 |
|
27 |
#include "hw/sysbus.h" |
28 |
#include "char/char.h" |
29 |
#include "qemu/log.h" |
30 |
#include "net/net.h" |
31 |
#include "net/checksum.h" |
32 |
|
33 |
#ifdef DEBUG_XGMAC
|
34 |
#define DEBUGF_BRK(message, args...) do { \ |
35 |
fprintf(stderr, (message), ## args); \ |
36 |
} while (0) |
37 |
#else
|
38 |
#define DEBUGF_BRK(message, args...) do { } while (0) |
39 |
#endif
|
40 |
|
41 |
#define XGMAC_CONTROL 0x00000000 /* MAC Configuration */ |
42 |
#define XGMAC_FRAME_FILTER 0x00000001 /* MAC Frame Filter */ |
43 |
#define XGMAC_FLOW_CTRL 0x00000006 /* MAC Flow Control */ |
44 |
#define XGMAC_VLAN_TAG 0x00000007 /* VLAN Tags */ |
45 |
#define XGMAC_VERSION 0x00000008 /* Version */ |
46 |
/* VLAN tag for insertion or replacement into tx frames */
|
47 |
#define XGMAC_VLAN_INCL 0x00000009 |
48 |
#define XGMAC_LPI_CTRL 0x0000000a /* LPI Control and Status */ |
49 |
#define XGMAC_LPI_TIMER 0x0000000b /* LPI Timers Control */ |
50 |
#define XGMAC_TX_PACE 0x0000000c /* Transmit Pace and Stretch */ |
51 |
#define XGMAC_VLAN_HASH 0x0000000d /* VLAN Hash Table */ |
52 |
#define XGMAC_DEBUG 0x0000000e /* Debug */ |
53 |
#define XGMAC_INT_STATUS 0x0000000f /* Interrupt and Control */ |
54 |
/* HASH table registers */
|
55 |
#define XGMAC_HASH(n) ((0x00000300/4) + (n)) |
56 |
#define XGMAC_NUM_HASH 16 |
57 |
/* Operation Mode */
|
58 |
#define XGMAC_OPMODE (0x00000400/4) |
59 |
/* Remote Wake-Up Frame Filter */
|
60 |
#define XGMAC_REMOTE_WAKE (0x00000700/4) |
61 |
/* PMT Control and Status */
|
62 |
#define XGMAC_PMT (0x00000704/4) |
63 |
|
64 |
#define XGMAC_ADDR_HIGH(reg) (0x00000010+((reg) * 2)) |
65 |
#define XGMAC_ADDR_LOW(reg) (0x00000011+((reg) * 2)) |
66 |
|
67 |
#define DMA_BUS_MODE 0x000003c0 /* Bus Mode */ |
68 |
#define DMA_XMT_POLL_DEMAND 0x000003c1 /* Transmit Poll Demand */ |
69 |
#define DMA_RCV_POLL_DEMAND 0x000003c2 /* Received Poll Demand */ |
70 |
#define DMA_RCV_BASE_ADDR 0x000003c3 /* Receive List Base */ |
71 |
#define DMA_TX_BASE_ADDR 0x000003c4 /* Transmit List Base */ |
72 |
#define DMA_STATUS 0x000003c5 /* Status Register */ |
73 |
#define DMA_CONTROL 0x000003c6 /* Ctrl (Operational Mode) */ |
74 |
#define DMA_INTR_ENA 0x000003c7 /* Interrupt Enable */ |
75 |
#define DMA_MISSED_FRAME_CTR 0x000003c8 /* Missed Frame Counter */ |
76 |
/* Receive Interrupt Watchdog Timer */
|
77 |
#define DMA_RI_WATCHDOG_TIMER 0x000003c9 |
78 |
#define DMA_AXI_BUS 0x000003ca /* AXI Bus Mode */ |
79 |
#define DMA_AXI_STATUS 0x000003cb /* AXI Status */ |
80 |
#define DMA_CUR_TX_DESC_ADDR 0x000003d2 /* Current Host Tx Descriptor */ |
81 |
#define DMA_CUR_RX_DESC_ADDR 0x000003d3 /* Current Host Rx Descriptor */ |
82 |
#define DMA_CUR_TX_BUF_ADDR 0x000003d4 /* Current Host Tx Buffer */ |
83 |
#define DMA_CUR_RX_BUF_ADDR 0x000003d5 /* Current Host Rx Buffer */ |
84 |
#define DMA_HW_FEATURE 0x000003d6 /* Enabled Hardware Features */ |
85 |
|
86 |
/* DMA Status register defines */
|
87 |
#define DMA_STATUS_GMI 0x08000000 /* MMC interrupt */ |
88 |
#define DMA_STATUS_GLI 0x04000000 /* GMAC Line interface int */ |
89 |
#define DMA_STATUS_EB_MASK 0x00380000 /* Error Bits Mask */ |
90 |
#define DMA_STATUS_EB_TX_ABORT 0x00080000 /* Error Bits - TX Abort */ |
91 |
#define DMA_STATUS_EB_RX_ABORT 0x00100000 /* Error Bits - RX Abort */ |
92 |
#define DMA_STATUS_TS_MASK 0x00700000 /* Transmit Process State */ |
93 |
#define DMA_STATUS_TS_SHIFT 20 |
94 |
#define DMA_STATUS_RS_MASK 0x000e0000 /* Receive Process State */ |
95 |
#define DMA_STATUS_RS_SHIFT 17 |
96 |
#define DMA_STATUS_NIS 0x00010000 /* Normal Interrupt Summary */ |
97 |
#define DMA_STATUS_AIS 0x00008000 /* Abnormal Interrupt Summary */ |
98 |
#define DMA_STATUS_ERI 0x00004000 /* Early Receive Interrupt */ |
99 |
#define DMA_STATUS_FBI 0x00002000 /* Fatal Bus Error Interrupt */ |
100 |
#define DMA_STATUS_ETI 0x00000400 /* Early Transmit Interrupt */ |
101 |
#define DMA_STATUS_RWT 0x00000200 /* Receive Watchdog Timeout */ |
102 |
#define DMA_STATUS_RPS 0x00000100 /* Receive Process Stopped */ |
103 |
#define DMA_STATUS_RU 0x00000080 /* Receive Buffer Unavailable */ |
104 |
#define DMA_STATUS_RI 0x00000040 /* Receive Interrupt */ |
105 |
#define DMA_STATUS_UNF 0x00000020 /* Transmit Underflow */ |
106 |
#define DMA_STATUS_OVF 0x00000010 /* Receive Overflow */ |
107 |
#define DMA_STATUS_TJT 0x00000008 /* Transmit Jabber Timeout */ |
108 |
#define DMA_STATUS_TU 0x00000004 /* Transmit Buffer Unavailable */ |
109 |
#define DMA_STATUS_TPS 0x00000002 /* Transmit Process Stopped */ |
110 |
#define DMA_STATUS_TI 0x00000001 /* Transmit Interrupt */ |
111 |
|
112 |
/* DMA Control register defines */
|
113 |
#define DMA_CONTROL_ST 0x00002000 /* Start/Stop Transmission */ |
114 |
#define DMA_CONTROL_SR 0x00000002 /* Start/Stop Receive */ |
115 |
#define DMA_CONTROL_DFF 0x01000000 /* Disable flush of rx frames */ |
116 |
|
117 |
struct desc {
|
118 |
uint32_t ctl_stat; |
119 |
uint16_t buffer1_size; |
120 |
uint16_t buffer2_size; |
121 |
uint32_t buffer1_addr; |
122 |
uint32_t buffer2_addr; |
123 |
uint32_t ext_stat; |
124 |
uint32_t res[3];
|
125 |
}; |
126 |
|
127 |
#define R_MAX 0x400 |
128 |
|
129 |
typedef struct RxTxStats { |
130 |
uint64_t rx_bytes; |
131 |
uint64_t tx_bytes; |
132 |
|
133 |
uint64_t rx; |
134 |
uint64_t rx_bcast; |
135 |
uint64_t rx_mcast; |
136 |
} RxTxStats; |
137 |
|
138 |
typedef struct XgmacState { |
139 |
SysBusDevice busdev; |
140 |
MemoryRegion iomem; |
141 |
qemu_irq sbd_irq; |
142 |
qemu_irq pmt_irq; |
143 |
qemu_irq mci_irq; |
144 |
NICState *nic; |
145 |
NICConf conf; |
146 |
|
147 |
struct RxTxStats stats;
|
148 |
uint32_t regs[R_MAX]; |
149 |
} XgmacState; |
150 |
|
151 |
const VMStateDescription vmstate_rxtx_stats = {
|
152 |
.name = "xgmac_stats",
|
153 |
.version_id = 1,
|
154 |
.minimum_version_id = 1,
|
155 |
.fields = (VMStateField[]) { |
156 |
VMSTATE_UINT64(rx_bytes, RxTxStats), |
157 |
VMSTATE_UINT64(tx_bytes, RxTxStats), |
158 |
VMSTATE_UINT64(rx, RxTxStats), |
159 |
VMSTATE_UINT64(rx_bcast, RxTxStats), |
160 |
VMSTATE_UINT64(rx_mcast, RxTxStats), |
161 |
VMSTATE_END_OF_LIST() |
162 |
} |
163 |
}; |
164 |
|
165 |
static const VMStateDescription vmstate_xgmac = { |
166 |
.name = "xgmac",
|
167 |
.version_id = 1,
|
168 |
.minimum_version_id = 1,
|
169 |
.fields = (VMStateField[]) { |
170 |
VMSTATE_STRUCT(stats, XgmacState, 0, vmstate_rxtx_stats, RxTxStats),
|
171 |
VMSTATE_UINT32_ARRAY(regs, XgmacState, R_MAX), |
172 |
VMSTATE_END_OF_LIST() |
173 |
} |
174 |
}; |
175 |
|
176 |
static void xgmac_read_desc(struct XgmacState *s, struct desc *d, int rx) |
177 |
{ |
178 |
uint32_t addr = rx ? s->regs[DMA_CUR_RX_DESC_ADDR] : |
179 |
s->regs[DMA_CUR_TX_DESC_ADDR]; |
180 |
cpu_physical_memory_read(addr, d, sizeof(*d));
|
181 |
} |
182 |
|
183 |
static void xgmac_write_desc(struct XgmacState *s, struct desc *d, int rx) |
184 |
{ |
185 |
int reg = rx ? DMA_CUR_RX_DESC_ADDR : DMA_CUR_TX_DESC_ADDR;
|
186 |
uint32_t addr = s->regs[reg]; |
187 |
|
188 |
if (!rx && (d->ctl_stat & 0x00200000)) { |
189 |
s->regs[reg] = s->regs[DMA_TX_BASE_ADDR]; |
190 |
} else if (rx && (d->buffer1_size & 0x8000)) { |
191 |
s->regs[reg] = s->regs[DMA_RCV_BASE_ADDR]; |
192 |
} else {
|
193 |
s->regs[reg] += sizeof(*d);
|
194 |
} |
195 |
cpu_physical_memory_write(addr, d, sizeof(*d));
|
196 |
} |
197 |
|
198 |
static void xgmac_enet_send(struct XgmacState *s) |
199 |
{ |
200 |
struct desc bd;
|
201 |
int frame_size;
|
202 |
int len;
|
203 |
uint8_t frame[8192];
|
204 |
uint8_t *ptr; |
205 |
|
206 |
ptr = frame; |
207 |
frame_size = 0;
|
208 |
while (1) { |
209 |
xgmac_read_desc(s, &bd, 0);
|
210 |
if ((bd.ctl_stat & 0x80000000) == 0) { |
211 |
/* Run out of descriptors to transmit. */
|
212 |
break;
|
213 |
} |
214 |
len = (bd.buffer1_size & 0xfff) + (bd.buffer2_size & 0xfff); |
215 |
|
216 |
if ((bd.buffer1_size & 0xfff) > 2048) { |
217 |
DEBUGF_BRK("qemu:%s:ERROR...ERROR...ERROR... -- "
|
218 |
"xgmac buffer 1 len on send > 2048 (0x%x)\n",
|
219 |
__func__, bd.buffer1_size & 0xfff);
|
220 |
} |
221 |
if ((bd.buffer2_size & 0xfff) != 0) { |
222 |
DEBUGF_BRK("qemu:%s:ERROR...ERROR...ERROR... -- "
|
223 |
"xgmac buffer 2 len on send != 0 (0x%x)\n",
|
224 |
__func__, bd.buffer2_size & 0xfff);
|
225 |
} |
226 |
if (len >= sizeof(frame)) { |
227 |
DEBUGF_BRK("qemu:%s: buffer overflow %d read into %zu "
|
228 |
"buffer\n" , __func__, len, sizeof(frame)); |
229 |
DEBUGF_BRK("qemu:%s: buffer1.size=%d; buffer2.size=%d\n",
|
230 |
__func__, bd.buffer1_size, bd.buffer2_size); |
231 |
} |
232 |
|
233 |
cpu_physical_memory_read(bd.buffer1_addr, ptr, len); |
234 |
ptr += len; |
235 |
frame_size += len; |
236 |
if (bd.ctl_stat & 0x20000000) { |
237 |
/* Last buffer in frame. */
|
238 |
qemu_send_packet(qemu_get_queue(s->nic), frame, len); |
239 |
ptr = frame; |
240 |
frame_size = 0;
|
241 |
s->regs[DMA_STATUS] |= DMA_STATUS_TI | DMA_STATUS_NIS; |
242 |
} |
243 |
bd.ctl_stat &= ~0x80000000;
|
244 |
/* Write back the modified descriptor. */
|
245 |
xgmac_write_desc(s, &bd, 0);
|
246 |
} |
247 |
} |
248 |
|
249 |
static void enet_update_irq(struct XgmacState *s) |
250 |
{ |
251 |
int stat = s->regs[DMA_STATUS] & s->regs[DMA_INTR_ENA];
|
252 |
qemu_set_irq(s->sbd_irq, !!stat); |
253 |
} |
254 |
|
255 |
static uint64_t enet_read(void *opaque, hwaddr addr, unsigned size) |
256 |
{ |
257 |
struct XgmacState *s = opaque;
|
258 |
uint64_t r = 0;
|
259 |
addr >>= 2;
|
260 |
|
261 |
switch (addr) {
|
262 |
case XGMAC_VERSION:
|
263 |
r = 0x1012;
|
264 |
break;
|
265 |
default:
|
266 |
if (addr < ARRAY_SIZE(s->regs)) {
|
267 |
r = s->regs[addr]; |
268 |
} |
269 |
break;
|
270 |
} |
271 |
return r;
|
272 |
} |
273 |
|
274 |
static void enet_write(void *opaque, hwaddr addr, |
275 |
uint64_t value, unsigned size)
|
276 |
{ |
277 |
struct XgmacState *s = opaque;
|
278 |
|
279 |
addr >>= 2;
|
280 |
switch (addr) {
|
281 |
case DMA_BUS_MODE:
|
282 |
s->regs[DMA_BUS_MODE] = value & ~0x1;
|
283 |
break;
|
284 |
case DMA_XMT_POLL_DEMAND:
|
285 |
xgmac_enet_send(s); |
286 |
break;
|
287 |
case DMA_STATUS:
|
288 |
s->regs[DMA_STATUS] = s->regs[DMA_STATUS] & ~value; |
289 |
break;
|
290 |
case DMA_RCV_BASE_ADDR:
|
291 |
s->regs[DMA_RCV_BASE_ADDR] = s->regs[DMA_CUR_RX_DESC_ADDR] = value; |
292 |
break;
|
293 |
case DMA_TX_BASE_ADDR:
|
294 |
s->regs[DMA_TX_BASE_ADDR] = s->regs[DMA_CUR_TX_DESC_ADDR] = value; |
295 |
break;
|
296 |
default:
|
297 |
if (addr < ARRAY_SIZE(s->regs)) {
|
298 |
s->regs[addr] = value; |
299 |
} |
300 |
break;
|
301 |
} |
302 |
enet_update_irq(s); |
303 |
} |
304 |
|
305 |
static const MemoryRegionOps enet_mem_ops = { |
306 |
.read = enet_read, |
307 |
.write = enet_write, |
308 |
.endianness = DEVICE_LITTLE_ENDIAN, |
309 |
}; |
310 |
|
311 |
static int eth_can_rx(NetClientState *nc) |
312 |
{ |
313 |
struct XgmacState *s = qemu_get_nic_opaque(nc);
|
314 |
|
315 |
/* RX enabled? */
|
316 |
return s->regs[DMA_CONTROL] & DMA_CONTROL_SR;
|
317 |
} |
318 |
|
319 |
static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size) |
320 |
{ |
321 |
struct XgmacState *s = qemu_get_nic_opaque(nc);
|
322 |
static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, |
323 |
0xff, 0xff, 0xff}; |
324 |
int unicast, broadcast, multicast;
|
325 |
struct desc bd;
|
326 |
ssize_t ret; |
327 |
|
328 |
unicast = ~buf[0] & 0x1; |
329 |
broadcast = memcmp(buf, sa_bcast, 6) == 0; |
330 |
multicast = !unicast && !broadcast; |
331 |
if (size < 12) { |
332 |
s->regs[DMA_STATUS] |= DMA_STATUS_RI | DMA_STATUS_NIS; |
333 |
ret = -1;
|
334 |
goto out;
|
335 |
} |
336 |
|
337 |
xgmac_read_desc(s, &bd, 1);
|
338 |
if ((bd.ctl_stat & 0x80000000) == 0) { |
339 |
s->regs[DMA_STATUS] |= DMA_STATUS_RU | DMA_STATUS_AIS; |
340 |
ret = size; |
341 |
goto out;
|
342 |
} |
343 |
|
344 |
cpu_physical_memory_write(bd.buffer1_addr, buf, size); |
345 |
|
346 |
/* Add in the 4 bytes for crc (the real hw returns length incl crc) */
|
347 |
size += 4;
|
348 |
bd.ctl_stat = (size << 16) | 0x300; |
349 |
xgmac_write_desc(s, &bd, 1);
|
350 |
|
351 |
s->stats.rx_bytes += size; |
352 |
s->stats.rx++; |
353 |
if (multicast) {
|
354 |
s->stats.rx_mcast++; |
355 |
} else if (broadcast) { |
356 |
s->stats.rx_bcast++; |
357 |
} |
358 |
|
359 |
s->regs[DMA_STATUS] |= DMA_STATUS_RI | DMA_STATUS_NIS; |
360 |
ret = size; |
361 |
|
362 |
out:
|
363 |
enet_update_irq(s); |
364 |
return ret;
|
365 |
} |
366 |
|
367 |
static void eth_cleanup(NetClientState *nc) |
368 |
{ |
369 |
struct XgmacState *s = qemu_get_nic_opaque(nc);
|
370 |
s->nic = NULL;
|
371 |
} |
372 |
|
373 |
static NetClientInfo net_xgmac_enet_info = {
|
374 |
.type = NET_CLIENT_OPTIONS_KIND_NIC, |
375 |
.size = sizeof(NICState),
|
376 |
.can_receive = eth_can_rx, |
377 |
.receive = eth_rx, |
378 |
.cleanup = eth_cleanup, |
379 |
}; |
380 |
|
381 |
static int xgmac_enet_init(SysBusDevice *dev) |
382 |
{ |
383 |
struct XgmacState *s = FROM_SYSBUS(typeof(*s), dev);
|
384 |
|
385 |
memory_region_init_io(&s->iomem, &enet_mem_ops, s, "xgmac", 0x1000); |
386 |
sysbus_init_mmio(dev, &s->iomem); |
387 |
sysbus_init_irq(dev, &s->sbd_irq); |
388 |
sysbus_init_irq(dev, &s->pmt_irq); |
389 |
sysbus_init_irq(dev, &s->mci_irq); |
390 |
|
391 |
qemu_macaddr_default_if_unset(&s->conf.macaddr); |
392 |
s->nic = qemu_new_nic(&net_xgmac_enet_info, &s->conf, |
393 |
object_get_typename(OBJECT(dev)), dev->qdev.id, s); |
394 |
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); |
395 |
|
396 |
s->regs[XGMAC_ADDR_HIGH(0)] = (s->conf.macaddr.a[5] << 8) | |
397 |
s->conf.macaddr.a[4];
|
398 |
s->regs[XGMAC_ADDR_LOW(0)] = (s->conf.macaddr.a[3] << 24) | |
399 |
(s->conf.macaddr.a[2] << 16) | |
400 |
(s->conf.macaddr.a[1] << 8) | |
401 |
s->conf.macaddr.a[0];
|
402 |
|
403 |
return 0; |
404 |
} |
405 |
|
406 |
static Property xgmac_properties[] = {
|
407 |
DEFINE_NIC_PROPERTIES(struct XgmacState, conf),
|
408 |
DEFINE_PROP_END_OF_LIST(), |
409 |
}; |
410 |
|
411 |
static void xgmac_enet_class_init(ObjectClass *klass, void *data) |
412 |
{ |
413 |
SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); |
414 |
DeviceClass *dc = DEVICE_CLASS(klass); |
415 |
|
416 |
sbc->init = xgmac_enet_init; |
417 |
dc->vmsd = &vmstate_xgmac; |
418 |
dc->props = xgmac_properties; |
419 |
} |
420 |
|
421 |
static const TypeInfo xgmac_enet_info = { |
422 |
.name = "xgmac",
|
423 |
.parent = TYPE_SYS_BUS_DEVICE, |
424 |
.instance_size = sizeof(struct XgmacState), |
425 |
.class_init = xgmac_enet_class_init, |
426 |
}; |
427 |
|
428 |
static void xgmac_enet_register_types(void) |
429 |
{ |
430 |
type_register_static(&xgmac_enet_info); |
431 |
} |
432 |
|
433 |
type_init(xgmac_enet_register_types) |