]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * QEMU TULIP Emulation | |
3 | * | |
4 | * Copyright (c) 2019 Sven Schnelle <svens@stackframe.org> | |
5 | * | |
6 | * This work is licensed under the GNU GPL license version 2 or later. | |
7 | */ | |
8 | ||
9 | #include "qemu/osdep.h" | |
10 | #include "qemu/log.h" | |
11 | #include "hw/irq.h" | |
12 | #include "hw/pci/pci_device.h" | |
13 | #include "hw/qdev-properties.h" | |
14 | #include "hw/nvram/eeprom93xx.h" | |
15 | #include "migration/vmstate.h" | |
16 | #include "sysemu/sysemu.h" | |
17 | #include "tulip.h" | |
18 | #include "trace.h" | |
19 | #include "net/eth.h" | |
20 | ||
21 | struct TULIPState { | |
22 | PCIDevice dev; | |
23 | MemoryRegion io; | |
24 | MemoryRegion memory; | |
25 | NICConf c; | |
26 | qemu_irq irq; | |
27 | NICState *nic; | |
28 | eeprom_t *eeprom; | |
29 | uint32_t csr[16]; | |
30 | ||
31 | /* state for MII */ | |
32 | uint32_t old_csr9; | |
33 | uint32_t mii_word; | |
34 | uint32_t mii_bitcnt; | |
35 | ||
36 | hwaddr current_rx_desc; | |
37 | hwaddr current_tx_desc; | |
38 | ||
39 | uint8_t rx_frame[2048]; | |
40 | uint8_t tx_frame[2048]; | |
41 | uint16_t tx_frame_len; | |
42 | uint16_t rx_frame_len; | |
43 | uint16_t rx_frame_size; | |
44 | ||
45 | uint32_t rx_status; | |
46 | uint8_t filter[16][6]; | |
47 | }; | |
48 | ||
49 | static const VMStateDescription vmstate_pci_tulip = { | |
50 | .name = "tulip", | |
51 | .fields = (VMStateField[]) { | |
52 | VMSTATE_PCI_DEVICE(dev, TULIPState), | |
53 | VMSTATE_UINT32_ARRAY(csr, TULIPState, 16), | |
54 | VMSTATE_UINT32(old_csr9, TULIPState), | |
55 | VMSTATE_UINT32(mii_word, TULIPState), | |
56 | VMSTATE_UINT32(mii_bitcnt, TULIPState), | |
57 | VMSTATE_UINT64(current_rx_desc, TULIPState), | |
58 | VMSTATE_UINT64(current_tx_desc, TULIPState), | |
59 | VMSTATE_BUFFER(rx_frame, TULIPState), | |
60 | VMSTATE_BUFFER(tx_frame, TULIPState), | |
61 | VMSTATE_UINT16(rx_frame_len, TULIPState), | |
62 | VMSTATE_UINT16(tx_frame_len, TULIPState), | |
63 | VMSTATE_UINT16(rx_frame_size, TULIPState), | |
64 | VMSTATE_UINT32(rx_status, TULIPState), | |
65 | VMSTATE_UINT8_2DARRAY(filter, TULIPState, 16, 6), | |
66 | VMSTATE_END_OF_LIST() | |
67 | } | |
68 | }; | |
69 | ||
70 | static void tulip_desc_read(TULIPState *s, hwaddr p, | |
71 | struct tulip_descriptor *desc) | |
72 | { | |
73 | const MemTxAttrs attrs = { .memory = true }; | |
74 | ||
75 | if (s->csr[0] & CSR0_DBO) { | |
76 | ldl_be_pci_dma(&s->dev, p, &desc->status, attrs); | |
77 | ldl_be_pci_dma(&s->dev, p + 4, &desc->control, attrs); | |
78 | ldl_be_pci_dma(&s->dev, p + 8, &desc->buf_addr1, attrs); | |
79 | ldl_be_pci_dma(&s->dev, p + 12, &desc->buf_addr2, attrs); | |
80 | } else { | |
81 | ldl_le_pci_dma(&s->dev, p, &desc->status, attrs); | |
82 | ldl_le_pci_dma(&s->dev, p + 4, &desc->control, attrs); | |
83 | ldl_le_pci_dma(&s->dev, p + 8, &desc->buf_addr1, attrs); | |
84 | ldl_le_pci_dma(&s->dev, p + 12, &desc->buf_addr2, attrs); | |
85 | } | |
86 | } | |
87 | ||
88 | static void tulip_desc_write(TULIPState *s, hwaddr p, | |
89 | struct tulip_descriptor *desc) | |
90 | { | |
91 | const MemTxAttrs attrs = { .memory = true }; | |
92 | ||
93 | if (s->csr[0] & CSR0_DBO) { | |
94 | stl_be_pci_dma(&s->dev, p, desc->status, attrs); | |
95 | stl_be_pci_dma(&s->dev, p + 4, desc->control, attrs); | |
96 | stl_be_pci_dma(&s->dev, p + 8, desc->buf_addr1, attrs); | |
97 | stl_be_pci_dma(&s->dev, p + 12, desc->buf_addr2, attrs); | |
98 | } else { | |
99 | stl_le_pci_dma(&s->dev, p, desc->status, attrs); | |
100 | stl_le_pci_dma(&s->dev, p + 4, desc->control, attrs); | |
101 | stl_le_pci_dma(&s->dev, p + 8, desc->buf_addr1, attrs); | |
102 | stl_le_pci_dma(&s->dev, p + 12, desc->buf_addr2, attrs); | |
103 | } | |
104 | } | |
105 | ||
106 | static void tulip_update_int(TULIPState *s) | |
107 | { | |
108 | uint32_t ie = s->csr[5] & s->csr[7]; | |
109 | bool assert = false; | |
110 | ||
111 | s->csr[5] &= ~(CSR5_AIS | CSR5_NIS); | |
112 | ||
113 | if (ie & (CSR5_TI | CSR5_TU | CSR5_RI | CSR5_GTE | CSR5_ERI)) { | |
114 | s->csr[5] |= CSR5_NIS; | |
115 | } | |
116 | ||
117 | if (ie & (CSR5_LC | CSR5_GPI | CSR5_FBE | CSR5_LNF | CSR5_ETI | CSR5_RWT | | |
118 | CSR5_RPS | CSR5_RU | CSR5_UNF | CSR5_LNP_ANC | CSR5_TJT | | |
119 | CSR5_TPS)) { | |
120 | s->csr[5] |= CSR5_AIS; | |
121 | } | |
122 | ||
123 | assert = s->csr[5] & s->csr[7] & (CSR5_AIS | CSR5_NIS); | |
124 | trace_tulip_irq(s->csr[5], s->csr[7], assert ? "assert" : "deassert"); | |
125 | qemu_set_irq(s->irq, assert); | |
126 | } | |
127 | ||
128 | static bool tulip_rx_stopped(TULIPState *s) | |
129 | { | |
130 | return ((s->csr[5] >> CSR5_RS_SHIFT) & CSR5_RS_MASK) == CSR5_RS_STOPPED; | |
131 | } | |
132 | ||
133 | static void tulip_dump_tx_descriptor(TULIPState *s, | |
134 | struct tulip_descriptor *desc) | |
135 | { | |
136 | trace_tulip_descriptor("TX ", s->current_tx_desc, | |
137 | desc->status, desc->control >> 22, | |
138 | desc->control & 0x7ff, (desc->control >> 11) & 0x7ff, | |
139 | desc->buf_addr1, desc->buf_addr2); | |
140 | } | |
141 | ||
142 | static void tulip_dump_rx_descriptor(TULIPState *s, | |
143 | struct tulip_descriptor *desc) | |
144 | { | |
145 | trace_tulip_descriptor("RX ", s->current_rx_desc, | |
146 | desc->status, desc->control >> 22, | |
147 | desc->control & 0x7ff, (desc->control >> 11) & 0x7ff, | |
148 | desc->buf_addr1, desc->buf_addr2); | |
149 | } | |
150 | ||
151 | static void tulip_next_rx_descriptor(TULIPState *s, | |
152 | struct tulip_descriptor *desc) | |
153 | { | |
154 | if (desc->control & RDES1_RER) { | |
155 | s->current_rx_desc = s->csr[3]; | |
156 | } else if (desc->control & RDES1_RCH) { | |
157 | s->current_rx_desc = desc->buf_addr2; | |
158 | } else { | |
159 | s->current_rx_desc += sizeof(struct tulip_descriptor) + | |
160 | (((s->csr[0] >> CSR0_DSL_SHIFT) & CSR0_DSL_MASK) << 2); | |
161 | } | |
162 | s->current_rx_desc &= ~3ULL; | |
163 | } | |
164 | ||
165 | static void tulip_copy_rx_bytes(TULIPState *s, struct tulip_descriptor *desc) | |
166 | { | |
167 | int len1 = (desc->control >> RDES1_BUF1_SIZE_SHIFT) & RDES1_BUF1_SIZE_MASK; | |
168 | int len2 = (desc->control >> RDES1_BUF2_SIZE_SHIFT) & RDES1_BUF2_SIZE_MASK; | |
169 | int len; | |
170 | ||
171 | if (s->rx_frame_len && len1) { | |
172 | if (s->rx_frame_len > len1) { | |
173 | len = len1; | |
174 | } else { | |
175 | len = s->rx_frame_len; | |
176 | } | |
177 | ||
178 | pci_dma_write(&s->dev, desc->buf_addr1, s->rx_frame + | |
179 | (s->rx_frame_size - s->rx_frame_len), len); | |
180 | s->rx_frame_len -= len; | |
181 | } | |
182 | ||
183 | if (s->rx_frame_len && len2) { | |
184 | if (s->rx_frame_len > len2) { | |
185 | len = len2; | |
186 | } else { | |
187 | len = s->rx_frame_len; | |
188 | } | |
189 | ||
190 | pci_dma_write(&s->dev, desc->buf_addr2, s->rx_frame + | |
191 | (s->rx_frame_size - s->rx_frame_len), len); | |
192 | s->rx_frame_len -= len; | |
193 | } | |
194 | } | |
195 | ||
196 | static bool tulip_filter_address(TULIPState *s, const uint8_t *addr) | |
197 | { | |
198 | static const char broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | |
199 | bool ret = false; | |
200 | int i; | |
201 | ||
202 | for (i = 0; i < 16 && ret == false; i++) { | |
203 | if (!memcmp(&s->filter[i], addr, ETH_ALEN)) { | |
204 | ret = true; | |
205 | } | |
206 | } | |
207 | ||
208 | if (!memcmp(addr, broadcast, ETH_ALEN)) { | |
209 | return true; | |
210 | } | |
211 | ||
212 | if (s->csr[6] & (CSR6_PR | CSR6_RA)) { | |
213 | /* Promiscuous mode enabled */ | |
214 | s->rx_status |= RDES0_FF; | |
215 | return true; | |
216 | } | |
217 | ||
218 | if ((s->csr[6] & CSR6_PM) && (addr[0] & 1)) { | |
219 | /* Pass all Multicast enabled */ | |
220 | s->rx_status |= RDES0_MF; | |
221 | return true; | |
222 | } | |
223 | ||
224 | if (s->csr[6] & CSR6_IF) { | |
225 | ret ^= true; | |
226 | } | |
227 | return ret; | |
228 | } | |
229 | ||
230 | static ssize_t tulip_receive(TULIPState *s, const uint8_t *buf, size_t size) | |
231 | { | |
232 | struct tulip_descriptor desc; | |
233 | ||
234 | trace_tulip_receive(buf, size); | |
235 | ||
236 | if (size < 14 || size > sizeof(s->rx_frame) - 4 | |
237 | || s->rx_frame_len || tulip_rx_stopped(s)) { | |
238 | return 0; | |
239 | } | |
240 | ||
241 | if (!tulip_filter_address(s, buf)) { | |
242 | return size; | |
243 | } | |
244 | ||
245 | do { | |
246 | tulip_desc_read(s, s->current_rx_desc, &desc); | |
247 | tulip_dump_rx_descriptor(s, &desc); | |
248 | ||
249 | if (!(desc.status & RDES0_OWN)) { | |
250 | s->csr[5] |= CSR5_RU; | |
251 | tulip_update_int(s); | |
252 | return s->rx_frame_size - s->rx_frame_len; | |
253 | } | |
254 | desc.status = 0; | |
255 | ||
256 | if (!s->rx_frame_len) { | |
257 | s->rx_frame_size = size + 4; | |
258 | s->rx_status = RDES0_LS | | |
259 | ((s->rx_frame_size & RDES0_FL_MASK) << RDES0_FL_SHIFT); | |
260 | desc.status |= RDES0_FS; | |
261 | memcpy(s->rx_frame, buf, size); | |
262 | s->rx_frame_len = s->rx_frame_size; | |
263 | } | |
264 | ||
265 | tulip_copy_rx_bytes(s, &desc); | |
266 | ||
267 | if (!s->rx_frame_len) { | |
268 | desc.status |= s->rx_status; | |
269 | s->csr[5] |= CSR5_RI; | |
270 | tulip_update_int(s); | |
271 | } | |
272 | tulip_dump_rx_descriptor(s, &desc); | |
273 | tulip_desc_write(s, s->current_rx_desc, &desc); | |
274 | tulip_next_rx_descriptor(s, &desc); | |
275 | } while (s->rx_frame_len); | |
276 | return size; | |
277 | } | |
278 | ||
279 | static ssize_t tulip_receive_nc(NetClientState *nc, | |
280 | const uint8_t *buf, size_t size) | |
281 | { | |
282 | return tulip_receive(qemu_get_nic_opaque(nc), buf, size); | |
283 | } | |
284 | ||
285 | static NetClientInfo net_tulip_info = { | |
286 | .type = NET_CLIENT_DRIVER_NIC, | |
287 | .size = sizeof(NICState), | |
288 | .receive = tulip_receive_nc, | |
289 | }; | |
290 | ||
291 | static const char *tulip_reg_name(const hwaddr addr) | |
292 | { | |
293 | switch (addr) { | |
294 | case CSR(0): | |
295 | return "CSR0"; | |
296 | ||
297 | case CSR(1): | |
298 | return "CSR1"; | |
299 | ||
300 | case CSR(2): | |
301 | return "CSR2"; | |
302 | ||
303 | case CSR(3): | |
304 | return "CSR3"; | |
305 | ||
306 | case CSR(4): | |
307 | return "CSR4"; | |
308 | ||
309 | case CSR(5): | |
310 | return "CSR5"; | |
311 | ||
312 | case CSR(6): | |
313 | return "CSR6"; | |
314 | ||
315 | case CSR(7): | |
316 | return "CSR7"; | |
317 | ||
318 | case CSR(8): | |
319 | return "CSR8"; | |
320 | ||
321 | case CSR(9): | |
322 | return "CSR9"; | |
323 | ||
324 | case CSR(10): | |
325 | return "CSR10"; | |
326 | ||
327 | case CSR(11): | |
328 | return "CSR11"; | |
329 | ||
330 | case CSR(12): | |
331 | return "CSR12"; | |
332 | ||
333 | case CSR(13): | |
334 | return "CSR13"; | |
335 | ||
336 | case CSR(14): | |
337 | return "CSR14"; | |
338 | ||
339 | case CSR(15): | |
340 | return "CSR15"; | |
341 | ||
342 | default: | |
343 | break; | |
344 | } | |
345 | return ""; | |
346 | } | |
347 | ||
348 | static const char *tulip_rx_state_name(int state) | |
349 | { | |
350 | switch (state) { | |
351 | case CSR5_RS_STOPPED: | |
352 | return "STOPPED"; | |
353 | ||
354 | case CSR5_RS_RUNNING_FETCH: | |
355 | return "RUNNING/FETCH"; | |
356 | ||
357 | case CSR5_RS_RUNNING_CHECK_EOR: | |
358 | return "RUNNING/CHECK EOR"; | |
359 | ||
360 | case CSR5_RS_RUNNING_WAIT_RECEIVE: | |
361 | return "WAIT RECEIVE"; | |
362 | ||
363 | case CSR5_RS_SUSPENDED: | |
364 | return "SUSPENDED"; | |
365 | ||
366 | case CSR5_RS_RUNNING_CLOSE: | |
367 | return "RUNNING/CLOSE"; | |
368 | ||
369 | case CSR5_RS_RUNNING_FLUSH: | |
370 | return "RUNNING/FLUSH"; | |
371 | ||
372 | case CSR5_RS_RUNNING_QUEUE: | |
373 | return "RUNNING/QUEUE"; | |
374 | ||
375 | default: | |
376 | break; | |
377 | } | |
378 | return ""; | |
379 | } | |
380 | ||
381 | static const char *tulip_tx_state_name(int state) | |
382 | { | |
383 | switch (state) { | |
384 | case CSR5_TS_STOPPED: | |
385 | return "STOPPED"; | |
386 | ||
387 | case CSR5_TS_RUNNING_FETCH: | |
388 | return "RUNNING/FETCH"; | |
389 | ||
390 | case CSR5_TS_RUNNING_WAIT_EOT: | |
391 | return "RUNNING/WAIT EOT"; | |
392 | ||
393 | case CSR5_TS_RUNNING_READ_BUF: | |
394 | return "RUNNING/READ BUF"; | |
395 | ||
396 | case CSR5_TS_RUNNING_SETUP: | |
397 | return "RUNNING/SETUP"; | |
398 | ||
399 | case CSR5_TS_SUSPENDED: | |
400 | return "SUSPENDED"; | |
401 | ||
402 | case CSR5_TS_RUNNING_CLOSE: | |
403 | return "RUNNING/CLOSE"; | |
404 | ||
405 | default: | |
406 | break; | |
407 | } | |
408 | return ""; | |
409 | } | |
410 | ||
411 | static void tulip_update_rs(TULIPState *s, int state) | |
412 | { | |
413 | s->csr[5] &= ~(CSR5_RS_MASK << CSR5_RS_SHIFT); | |
414 | s->csr[5] |= (state & CSR5_RS_MASK) << CSR5_RS_SHIFT; | |
415 | trace_tulip_rx_state(tulip_rx_state_name(state)); | |
416 | } | |
417 | ||
418 | static uint16_t tulip_mdi_default[] = { | |
419 | /* MDI Registers 0 - 6, 7 */ | |
420 | 0x3100, 0xf02c, 0x7810, 0x0000, 0x0501, 0x4181, 0x0000, 0x0000, | |
421 | /* MDI Registers 8 - 15 */ | |
422 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | |
423 | /* MDI Registers 16 - 31 */ | |
424 | 0x0003, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | |
425 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | |
426 | }; | |
427 | ||
428 | /* Readonly mask for MDI (PHY) registers */ | |
429 | static const uint16_t tulip_mdi_mask[] = { | |
430 | 0x0000, 0xffff, 0xffff, 0xffff, 0xc01f, 0xffff, 0xffff, 0x0000, | |
431 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | |
432 | 0x0fff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, | |
433 | 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | |
434 | }; | |
435 | ||
436 | static uint16_t tulip_mii_read(TULIPState *s, int phy, int reg) | |
437 | { | |
438 | uint16_t ret = 0; | |
439 | if (phy == 1) { | |
440 | ret = tulip_mdi_default[reg]; | |
441 | } | |
442 | trace_tulip_mii_read(phy, reg, ret); | |
443 | return ret; | |
444 | } | |
445 | ||
446 | static void tulip_mii_write(TULIPState *s, int phy, int reg, uint16_t data) | |
447 | { | |
448 | trace_tulip_mii_write(phy, reg, data); | |
449 | ||
450 | if (phy != 1) { | |
451 | return; | |
452 | } | |
453 | ||
454 | tulip_mdi_default[reg] &= ~tulip_mdi_mask[reg]; | |
455 | tulip_mdi_default[reg] |= (data & tulip_mdi_mask[reg]); | |
456 | } | |
457 | ||
458 | static void tulip_mii(TULIPState *s) | |
459 | { | |
460 | uint32_t changed = s->old_csr9 ^ s->csr[9]; | |
461 | uint16_t data; | |
462 | int op, phy, reg; | |
463 | ||
464 | if (!(changed & CSR9_MDC)) { | |
465 | return; | |
466 | } | |
467 | ||
468 | if (!(s->csr[9] & CSR9_MDC)) { | |
469 | return; | |
470 | } | |
471 | ||
472 | s->mii_bitcnt++; | |
473 | s->mii_word <<= 1; | |
474 | ||
475 | if (s->csr[9] & CSR9_MDO && (s->mii_bitcnt < 16 || | |
476 | !(s->csr[9] & CSR9_MII))) { | |
477 | /* write op or address bits */ | |
478 | s->mii_word |= 1; | |
479 | } | |
480 | ||
481 | if (s->mii_bitcnt >= 16 && (s->csr[9] & CSR9_MII)) { | |
482 | if (s->mii_word & 0x8000) { | |
483 | s->csr[9] |= CSR9_MDI; | |
484 | } else { | |
485 | s->csr[9] &= ~CSR9_MDI; | |
486 | } | |
487 | } | |
488 | ||
489 | if (s->mii_word == 0xffffffff) { | |
490 | s->mii_bitcnt = 0; | |
491 | } else if (s->mii_bitcnt == 16) { | |
492 | op = (s->mii_word >> 12) & 0x0f; | |
493 | phy = (s->mii_word >> 7) & 0x1f; | |
494 | reg = (s->mii_word >> 2) & 0x1f; | |
495 | ||
496 | if (op == 6) { | |
497 | s->mii_word = tulip_mii_read(s, phy, reg); | |
498 | } | |
499 | } else if (s->mii_bitcnt == 32) { | |
500 | op = (s->mii_word >> 28) & 0x0f; | |
501 | phy = (s->mii_word >> 23) & 0x1f; | |
502 | reg = (s->mii_word >> 18) & 0x1f; | |
503 | data = s->mii_word & 0xffff; | |
504 | ||
505 | if (op == 5) { | |
506 | tulip_mii_write(s, phy, reg, data); | |
507 | } | |
508 | } | |
509 | } | |
510 | ||
511 | static uint32_t tulip_csr9_read(TULIPState *s) | |
512 | { | |
513 | if (s->csr[9] & CSR9_SR) { | |
514 | if (eeprom93xx_read(s->eeprom)) { | |
515 | s->csr[9] |= CSR9_SR_DO; | |
516 | } else { | |
517 | s->csr[9] &= ~CSR9_SR_DO; | |
518 | } | |
519 | } | |
520 | ||
521 | tulip_mii(s); | |
522 | return s->csr[9]; | |
523 | } | |
524 | ||
525 | static void tulip_update_ts(TULIPState *s, int state) | |
526 | { | |
527 | s->csr[5] &= ~(CSR5_TS_MASK << CSR5_TS_SHIFT); | |
528 | s->csr[5] |= (state & CSR5_TS_MASK) << CSR5_TS_SHIFT; | |
529 | trace_tulip_tx_state(tulip_tx_state_name(state)); | |
530 | } | |
531 | ||
532 | static uint64_t tulip_read(void *opaque, hwaddr addr, | |
533 | unsigned size) | |
534 | { | |
535 | TULIPState *s = opaque; | |
536 | uint64_t data = 0; | |
537 | ||
538 | switch (addr) { | |
539 | case CSR(9): | |
540 | data = tulip_csr9_read(s); | |
541 | break; | |
542 | ||
543 | case CSR(12): | |
544 | /* Fake autocompletion complete until we have PHY emulation */ | |
545 | data = 5 << CSR12_ANS_SHIFT; | |
546 | break; | |
547 | ||
548 | default: | |
549 | if (addr & 7) { | |
550 | qemu_log_mask(LOG_GUEST_ERROR, "%s: read access at unknown address" | |
551 | " 0x%"PRIx64"\n", __func__, addr); | |
552 | } else { | |
553 | data = s->csr[addr >> 3]; | |
554 | } | |
555 | break; | |
556 | } | |
557 | trace_tulip_reg_read(addr, tulip_reg_name(addr), size, data); | |
558 | return data; | |
559 | } | |
560 | ||
561 | static void tulip_tx(TULIPState *s, struct tulip_descriptor *desc) | |
562 | { | |
563 | if (s->tx_frame_len) { | |
564 | if ((s->csr[6] >> CSR6_OM_SHIFT) & CSR6_OM_MASK) { | |
565 | /* Internal or external Loopback */ | |
566 | tulip_receive(s, s->tx_frame, s->tx_frame_len); | |
567 | } else if (s->tx_frame_len <= sizeof(s->tx_frame)) { | |
568 | qemu_send_packet(qemu_get_queue(s->nic), | |
569 | s->tx_frame, s->tx_frame_len); | |
570 | } | |
571 | } | |
572 | ||
573 | if (desc->control & TDES1_IC) { | |
574 | s->csr[5] |= CSR5_TI; | |
575 | tulip_update_int(s); | |
576 | } | |
577 | } | |
578 | ||
579 | static int tulip_copy_tx_buffers(TULIPState *s, struct tulip_descriptor *desc) | |
580 | { | |
581 | int len1 = (desc->control >> TDES1_BUF1_SIZE_SHIFT) & TDES1_BUF1_SIZE_MASK; | |
582 | int len2 = (desc->control >> TDES1_BUF2_SIZE_SHIFT) & TDES1_BUF2_SIZE_MASK; | |
583 | ||
584 | if (s->tx_frame_len + len1 > sizeof(s->tx_frame)) { | |
585 | qemu_log_mask(LOG_GUEST_ERROR, | |
586 | "%s: descriptor overflow (ofs: %u, len:%d, size:%zu)\n", | |
587 | __func__, s->tx_frame_len, len1, sizeof(s->tx_frame)); | |
588 | return -1; | |
589 | } | |
590 | if (len1) { | |
591 | pci_dma_read(&s->dev, desc->buf_addr1, | |
592 | s->tx_frame + s->tx_frame_len, len1); | |
593 | s->tx_frame_len += len1; | |
594 | } | |
595 | ||
596 | if (s->tx_frame_len + len2 > sizeof(s->tx_frame)) { | |
597 | qemu_log_mask(LOG_GUEST_ERROR, | |
598 | "%s: descriptor overflow (ofs: %u, len:%d, size:%zu)\n", | |
599 | __func__, s->tx_frame_len, len2, sizeof(s->tx_frame)); | |
600 | return -1; | |
601 | } | |
602 | if (len2) { | |
603 | pci_dma_read(&s->dev, desc->buf_addr2, | |
604 | s->tx_frame + s->tx_frame_len, len2); | |
605 | s->tx_frame_len += len2; | |
606 | } | |
607 | desc->status = (len1 + len2) ? 0 : 0x7fffffff; | |
608 | ||
609 | return 0; | |
610 | } | |
611 | ||
612 | static void tulip_setup_filter_addr(TULIPState *s, uint8_t *buf, int n) | |
613 | { | |
614 | int offset = n * 12; | |
615 | ||
616 | s->filter[n][0] = buf[offset]; | |
617 | s->filter[n][1] = buf[offset + 1]; | |
618 | ||
619 | s->filter[n][2] = buf[offset + 4]; | |
620 | s->filter[n][3] = buf[offset + 5]; | |
621 | ||
622 | s->filter[n][4] = buf[offset + 8]; | |
623 | s->filter[n][5] = buf[offset + 9]; | |
624 | ||
625 | trace_tulip_setup_filter(n, s->filter[n][5], s->filter[n][4], | |
626 | s->filter[n][3], s->filter[n][2], s->filter[n][1], s->filter[n][0]); | |
627 | } | |
628 | ||
629 | static void tulip_setup_frame(TULIPState *s, | |
630 | struct tulip_descriptor *desc) | |
631 | { | |
632 | uint8_t buf[4096]; | |
633 | int len = (desc->control >> TDES1_BUF1_SIZE_SHIFT) & TDES1_BUF1_SIZE_MASK; | |
634 | int i; | |
635 | ||
636 | trace_tulip_setup_frame(); | |
637 | ||
638 | if (len == 192) { | |
639 | pci_dma_read(&s->dev, desc->buf_addr1, buf, len); | |
640 | for (i = 0; i < 16; i++) { | |
641 | tulip_setup_filter_addr(s, buf, i); | |
642 | } | |
643 | } | |
644 | ||
645 | desc->status = 0x7fffffff; | |
646 | ||
647 | if (desc->control & TDES1_IC) { | |
648 | s->csr[5] |= CSR5_TI; | |
649 | tulip_update_int(s); | |
650 | } | |
651 | } | |
652 | ||
653 | static void tulip_next_tx_descriptor(TULIPState *s, | |
654 | struct tulip_descriptor *desc) | |
655 | { | |
656 | if (desc->control & TDES1_TER) { | |
657 | s->current_tx_desc = s->csr[4]; | |
658 | } else if (desc->control & TDES1_TCH) { | |
659 | s->current_tx_desc = desc->buf_addr2; | |
660 | } else { | |
661 | s->current_tx_desc += sizeof(struct tulip_descriptor) + | |
662 | (((s->csr[0] >> CSR0_DSL_SHIFT) & CSR0_DSL_MASK) << 2); | |
663 | } | |
664 | s->current_tx_desc &= ~3ULL; | |
665 | } | |
666 | ||
667 | static uint32_t tulip_ts(TULIPState *s) | |
668 | { | |
669 | return (s->csr[5] >> CSR5_TS_SHIFT) & CSR5_TS_MASK; | |
670 | } | |
671 | ||
672 | static void tulip_xmit_list_update(TULIPState *s) | |
673 | { | |
674 | #define TULIP_DESC_MAX 128 | |
675 | uint8_t i = 0; | |
676 | struct tulip_descriptor desc; | |
677 | ||
678 | if (tulip_ts(s) != CSR5_TS_SUSPENDED) { | |
679 | return; | |
680 | } | |
681 | ||
682 | for (i = 0; i < TULIP_DESC_MAX; i++) { | |
683 | tulip_desc_read(s, s->current_tx_desc, &desc); | |
684 | tulip_dump_tx_descriptor(s, &desc); | |
685 | ||
686 | if (!(desc.status & TDES0_OWN)) { | |
687 | tulip_update_ts(s, CSR5_TS_SUSPENDED); | |
688 | s->csr[5] |= CSR5_TU; | |
689 | tulip_update_int(s); | |
690 | return; | |
691 | } | |
692 | ||
693 | if (desc.control & TDES1_SET) { | |
694 | tulip_setup_frame(s, &desc); | |
695 | } else { | |
696 | if (desc.control & TDES1_FS) { | |
697 | s->tx_frame_len = 0; | |
698 | } | |
699 | ||
700 | if (!tulip_copy_tx_buffers(s, &desc)) { | |
701 | if (desc.control & TDES1_LS) { | |
702 | tulip_tx(s, &desc); | |
703 | } | |
704 | } | |
705 | } | |
706 | tulip_desc_write(s, s->current_tx_desc, &desc); | |
707 | tulip_next_tx_descriptor(s, &desc); | |
708 | } | |
709 | } | |
710 | ||
711 | static void tulip_csr9_write(TULIPState *s, uint32_t old_val, | |
712 | uint32_t new_val) | |
713 | { | |
714 | if (new_val & CSR9_SR) { | |
715 | eeprom93xx_write(s->eeprom, | |
716 | !!(new_val & CSR9_SR_CS), | |
717 | !!(new_val & CSR9_SR_SK), | |
718 | !!(new_val & CSR9_SR_DI)); | |
719 | } | |
720 | } | |
721 | ||
722 | static void tulip_reset(TULIPState *s) | |
723 | { | |
724 | trace_tulip_reset(); | |
725 | ||
726 | s->csr[0] = 0xfe000000; | |
727 | s->csr[1] = 0xffffffff; | |
728 | s->csr[2] = 0xffffffff; | |
729 | s->csr[5] = 0xf0000000; | |
730 | s->csr[6] = 0x32000040; | |
731 | s->csr[7] = 0xf3fe0000; | |
732 | s->csr[8] = 0xe0000000; | |
733 | s->csr[9] = 0xfff483ff; | |
734 | s->csr[11] = 0xfffe0000; | |
735 | s->csr[12] = 0x000000c6; | |
736 | s->csr[13] = 0xffff0000; | |
737 | s->csr[14] = 0xffffffff; | |
738 | s->csr[15] = 0x8ff00000; | |
739 | } | |
740 | ||
741 | static void tulip_qdev_reset(DeviceState *dev) | |
742 | { | |
743 | PCIDevice *d = PCI_DEVICE(dev); | |
744 | TULIPState *s = TULIP(d); | |
745 | ||
746 | tulip_reset(s); | |
747 | } | |
748 | ||
749 | static void tulip_write(void *opaque, hwaddr addr, | |
750 | uint64_t data, unsigned size) | |
751 | { | |
752 | TULIPState *s = opaque; | |
753 | trace_tulip_reg_write(addr, tulip_reg_name(addr), size, data); | |
754 | ||
755 | switch (addr) { | |
756 | case CSR(0): | |
757 | s->csr[0] = data; | |
758 | if (data & CSR0_SWR) { | |
759 | tulip_reset(s); | |
760 | tulip_update_int(s); | |
761 | } | |
762 | break; | |
763 | ||
764 | case CSR(1): | |
765 | tulip_xmit_list_update(s); | |
766 | break; | |
767 | ||
768 | case CSR(2): | |
769 | qemu_flush_queued_packets(qemu_get_queue(s->nic)); | |
770 | break; | |
771 | ||
772 | case CSR(3): | |
773 | s->csr[3] = data & ~3ULL; | |
774 | s->current_rx_desc = s->csr[3]; | |
775 | qemu_flush_queued_packets(qemu_get_queue(s->nic)); | |
776 | break; | |
777 | ||
778 | case CSR(4): | |
779 | s->csr[4] = data & ~3ULL; | |
780 | s->current_tx_desc = s->csr[4]; | |
781 | tulip_xmit_list_update(s); | |
782 | break; | |
783 | ||
784 | case CSR(5): | |
785 | /* Status register, write clears bit */ | |
786 | s->csr[5] &= ~(data & (CSR5_TI | CSR5_TPS | CSR5_TU | CSR5_TJT | | |
787 | CSR5_LNP_ANC | CSR5_UNF | CSR5_RI | CSR5_RU | | |
788 | CSR5_RPS | CSR5_RWT | CSR5_ETI | CSR5_GTE | | |
789 | CSR5_LNF | CSR5_FBE | CSR5_ERI | CSR5_AIS | | |
790 | CSR5_NIS | CSR5_GPI | CSR5_LC)); | |
791 | tulip_update_int(s); | |
792 | break; | |
793 | ||
794 | case CSR(6): | |
795 | s->csr[6] = data; | |
796 | if (s->csr[6] & CSR6_SR) { | |
797 | tulip_update_rs(s, CSR5_RS_RUNNING_WAIT_RECEIVE); | |
798 | qemu_flush_queued_packets(qemu_get_queue(s->nic)); | |
799 | } else { | |
800 | tulip_update_rs(s, CSR5_RS_STOPPED); | |
801 | } | |
802 | ||
803 | if (s->csr[6] & CSR6_ST) { | |
804 | tulip_update_ts(s, CSR5_TS_SUSPENDED); | |
805 | tulip_xmit_list_update(s); | |
806 | } else { | |
807 | tulip_update_ts(s, CSR5_TS_STOPPED); | |
808 | } | |
809 | break; | |
810 | ||
811 | case CSR(7): | |
812 | s->csr[7] = data; | |
813 | tulip_update_int(s); | |
814 | break; | |
815 | ||
816 | case CSR(8): | |
817 | s->csr[9] = data; | |
818 | break; | |
819 | ||
820 | case CSR(9): | |
821 | tulip_csr9_write(s, s->csr[9], data); | |
822 | /* don't clear MII read data */ | |
823 | s->csr[9] &= CSR9_MDI; | |
824 | s->csr[9] |= (data & ~CSR9_MDI); | |
825 | tulip_mii(s); | |
826 | s->old_csr9 = s->csr[9]; | |
827 | break; | |
828 | ||
829 | case CSR(10): | |
830 | s->csr[10] = data; | |
831 | break; | |
832 | ||
833 | case CSR(11): | |
834 | s->csr[11] = data; | |
835 | break; | |
836 | ||
837 | case CSR(12): | |
838 | /* SIA Status register, some bits are cleared by writing 1 */ | |
839 | s->csr[12] &= ~(data & (CSR12_MRA | CSR12_TRA | CSR12_ARA)); | |
840 | break; | |
841 | ||
842 | case CSR(13): | |
843 | s->csr[13] = data; | |
844 | break; | |
845 | ||
846 | case CSR(14): | |
847 | s->csr[14] = data; | |
848 | break; | |
849 | ||
850 | case CSR(15): | |
851 | s->csr[15] = data; | |
852 | break; | |
853 | ||
854 | default: | |
855 | qemu_log_mask(LOG_GUEST_ERROR, "%s: write to CSR at unknown address " | |
856 | "0x%"PRIx64"\n", __func__, addr); | |
857 | break; | |
858 | } | |
859 | } | |
860 | ||
861 | static const MemoryRegionOps tulip_ops = { | |
862 | .read = tulip_read, | |
863 | .write = tulip_write, | |
864 | .endianness = DEVICE_LITTLE_ENDIAN, | |
865 | .impl = { | |
866 | .min_access_size = 4, | |
867 | .max_access_size = 4, | |
868 | }, | |
869 | }; | |
870 | ||
871 | static void tulip_idblock_crc(TULIPState *s, uint16_t *srom) | |
872 | { | |
873 | int word; | |
874 | int bit; | |
875 | unsigned char bitval, crc; | |
876 | const int len = 9; | |
877 | crc = -1; | |
878 | ||
879 | for (word = 0; word < len; word++) { | |
880 | for (bit = 15; bit >= 0; bit--) { | |
881 | if ((word == (len - 1)) && (bit == 7)) { | |
882 | /* | |
883 | * Insert the correct CRC result into input data stream | |
884 | * in place. | |
885 | */ | |
886 | srom[len - 1] = (srom[len - 1] & 0xff00) | (unsigned short)crc; | |
887 | break; | |
888 | } | |
889 | bitval = ((srom[word] >> bit) & 1) ^ ((crc >> 7) & 1); | |
890 | crc = crc << 1; | |
891 | if (bitval == 1) { | |
892 | crc ^= 6; | |
893 | crc |= 0x01; | |
894 | } | |
895 | } | |
896 | } | |
897 | } | |
898 | ||
899 | static uint16_t tulip_srom_crc(TULIPState *s, uint8_t *eeprom, size_t len) | |
900 | { | |
901 | unsigned long crc = 0xffffffff; | |
902 | unsigned long flippedcrc = 0; | |
903 | unsigned char currentbyte; | |
904 | unsigned int msb, bit, i; | |
905 | ||
906 | for (i = 0; i < len; i++) { | |
907 | currentbyte = eeprom[i]; | |
908 | for (bit = 0; bit < 8; bit++) { | |
909 | msb = (crc >> 31) & 1; | |
910 | crc <<= 1; | |
911 | if (msb ^ (currentbyte & 1)) { | |
912 | crc ^= 0x04c11db6; | |
913 | crc |= 0x00000001; | |
914 | } | |
915 | currentbyte >>= 1; | |
916 | } | |
917 | } | |
918 | ||
919 | for (i = 0; i < 32; i++) { | |
920 | flippedcrc <<= 1; | |
921 | bit = crc & 1; | |
922 | crc >>= 1; | |
923 | flippedcrc += bit; | |
924 | } | |
925 | return (flippedcrc ^ 0xffffffff) & 0xffff; | |
926 | } | |
927 | ||
928 | static const uint8_t eeprom_default[128] = { | |
929 | 0x3c, 0x10, 0x4f, 0x10, 0x00, 0x00, 0x00, 0x00, | |
930 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
931 | 0x56, 0x08, 0x04, 0x01, 0x00, 0x80, 0x48, 0xb3, | |
932 | 0x0e, 0xa7, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x08, | |
933 | 0x01, 0x8d, 0x03, 0x00, 0x00, 0x00, 0x00, 0x78, | |
934 | 0xe0, 0x01, 0x00, 0x50, 0x00, 0x18, 0x00, 0x00, | |
935 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
936 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
937 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
938 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
939 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
940 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x6b, | |
941 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, | |
942 | 0x48, 0xb3, 0x0e, 0xa7, 0x40, 0x00, 0x00, 0x00, | |
943 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
944 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
945 | }; | |
946 | ||
947 | static void tulip_fill_eeprom(TULIPState *s) | |
948 | { | |
949 | uint16_t *eeprom = eeprom93xx_data(s->eeprom); | |
950 | memcpy(eeprom, eeprom_default, 128); | |
951 | ||
952 | /* patch in our mac address */ | |
953 | eeprom[10] = cpu_to_le16(s->c.macaddr.a[0] | (s->c.macaddr.a[1] << 8)); | |
954 | eeprom[11] = cpu_to_le16(s->c.macaddr.a[2] | (s->c.macaddr.a[3] << 8)); | |
955 | eeprom[12] = cpu_to_le16(s->c.macaddr.a[4] | (s->c.macaddr.a[5] << 8)); | |
956 | tulip_idblock_crc(s, eeprom); | |
957 | eeprom[63] = cpu_to_le16(tulip_srom_crc(s, (uint8_t *)eeprom, 126)); | |
958 | } | |
959 | ||
960 | static void pci_tulip_realize(PCIDevice *pci_dev, Error **errp) | |
961 | { | |
962 | TULIPState *s = DO_UPCAST(TULIPState, dev, pci_dev); | |
963 | uint8_t *pci_conf; | |
964 | ||
965 | pci_conf = s->dev.config; | |
966 | pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */ | |
967 | ||
968 | qemu_macaddr_default_if_unset(&s->c.macaddr); | |
969 | ||
970 | s->eeprom = eeprom93xx_new(&pci_dev->qdev, 64); | |
971 | tulip_fill_eeprom(s); | |
972 | ||
973 | memory_region_init_io(&s->io, OBJECT(&s->dev), &tulip_ops, s, | |
974 | "tulip-io", 128); | |
975 | ||
976 | memory_region_init_io(&s->memory, OBJECT(&s->dev), &tulip_ops, s, | |
977 | "tulip-mem", 128); | |
978 | ||
979 | pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io); | |
980 | pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->memory); | |
981 | ||
982 | s->irq = pci_allocate_irq(&s->dev); | |
983 | ||
984 | s->nic = qemu_new_nic(&net_tulip_info, &s->c, | |
985 | object_get_typename(OBJECT(pci_dev)), | |
986 | pci_dev->qdev.id, s); | |
987 | qemu_format_nic_info_str(qemu_get_queue(s->nic), s->c.macaddr.a); | |
988 | } | |
989 | ||
990 | static void pci_tulip_exit(PCIDevice *pci_dev) | |
991 | { | |
992 | TULIPState *s = DO_UPCAST(TULIPState, dev, pci_dev); | |
993 | ||
994 | qemu_del_nic(s->nic); | |
995 | qemu_free_irq(s->irq); | |
996 | eeprom93xx_free(&pci_dev->qdev, s->eeprom); | |
997 | } | |
998 | ||
999 | static void tulip_instance_init(Object *obj) | |
1000 | { | |
1001 | PCIDevice *pci_dev = PCI_DEVICE(obj); | |
1002 | TULIPState *d = DO_UPCAST(TULIPState, dev, pci_dev); | |
1003 | ||
1004 | device_add_bootindex_property(obj, &d->c.bootindex, | |
1005 | "bootindex", "/ethernet-phy@0", | |
1006 | &pci_dev->qdev); | |
1007 | } | |
1008 | ||
1009 | static Property tulip_properties[] = { | |
1010 | DEFINE_NIC_PROPERTIES(TULIPState, c), | |
1011 | DEFINE_PROP_END_OF_LIST(), | |
1012 | }; | |
1013 | ||
1014 | static void tulip_class_init(ObjectClass *klass, void *data) | |
1015 | { | |
1016 | DeviceClass *dc = DEVICE_CLASS(klass); | |
1017 | PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); | |
1018 | ||
1019 | k->realize = pci_tulip_realize; | |
1020 | k->exit = pci_tulip_exit; | |
1021 | k->vendor_id = PCI_VENDOR_ID_DEC; | |
1022 | k->device_id = PCI_DEVICE_ID_DEC_21143; | |
1023 | k->subsystem_vendor_id = PCI_VENDOR_ID_HP; | |
1024 | k->subsystem_id = 0x104f; | |
1025 | k->class_id = PCI_CLASS_NETWORK_ETHERNET; | |
1026 | dc->vmsd = &vmstate_pci_tulip; | |
1027 | device_class_set_props(dc, tulip_properties); | |
1028 | dc->reset = tulip_qdev_reset; | |
1029 | set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); | |
1030 | } | |
1031 | ||
1032 | static const TypeInfo tulip_info = { | |
1033 | .name = TYPE_TULIP, | |
1034 | .parent = TYPE_PCI_DEVICE, | |
1035 | .instance_size = sizeof(TULIPState), | |
1036 | .class_init = tulip_class_init, | |
1037 | .instance_init = tulip_instance_init, | |
1038 | .interfaces = (InterfaceInfo[]) { | |
1039 | { INTERFACE_CONVENTIONAL_PCI_DEVICE }, | |
1040 | { }, | |
1041 | }, | |
1042 | }; | |
1043 | ||
1044 | static void tulip_register_types(void) | |
1045 | { | |
1046 | type_register_static(&tulip_info); | |
1047 | } | |
1048 | ||
1049 | type_init(tulip_register_types) |