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