]> Git Repo - qemu.git/blame - hw/net/smc91c111.c
Include migration/vmstate.h less
[qemu.git] / hw / net / smc91c111.c
CommitLineData
5fafdf24 1/*
80337b66
FB
2 * SMSC 91C111 Ethernet interface emulation
3 *
4 * Copyright (c) 2005 CodeSourcery, LLC.
5 * Written by Paul Brook
6 *
8e31bf38 7 * This code is licensed under the GPL
80337b66
FB
8 */
9
e8d40465 10#include "qemu/osdep.h"
83c9f4ca 11#include "hw/sysbus.h"
d6454270 12#include "migration/vmstate.h"
1422e32d 13#include "net/net.h"
64552b6b 14#include "hw/irq.h"
437cc27d 15#include "hw/net/smc91c111.h"
b9992d12 16#include "qemu/log.h"
0b8fa32f 17#include "qemu/module.h"
80337b66
FB
18/* For crc32 */
19#include <zlib.h>
20
21/* Number of 2k memory pages available. */
22#define NUM_PACKETS 4
23
926d152e
AF
24#define TYPE_SMC91C111 "smc91c111"
25#define SMC91C111(obj) OBJECT_CHECK(smc91c111_state, (obj), TYPE_SMC91C111)
26
80337b66 27typedef struct {
926d152e
AF
28 SysBusDevice parent_obj;
29
42a4260f 30 NICState *nic;
50132156 31 NICConf conf;
80337b66
FB
32 uint16_t tcr;
33 uint16_t rcr;
34 uint16_t cr;
35 uint16_t ctr;
36 uint16_t gpr;
37 uint16_t ptr;
38 uint16_t ercv;
d537cf6c 39 qemu_irq irq;
80337b66
FB
40 int bank;
41 int packet_num;
42 int tx_alloc;
43 /* Bitmask of allocated packets. */
44 int allocated;
45 int tx_fifo_len;
46 int tx_fifo[NUM_PACKETS];
47 int rx_fifo_len;
48 int rx_fifo[NUM_PACKETS];
5198cfd9
FB
49 int tx_fifo_done_len;
50 int tx_fifo_done[NUM_PACKETS];
80337b66 51 /* Packet buffer memory. */
5198cfd9 52 uint8_t data[NUM_PACKETS][2048];
80337b66
FB
53 uint8_t int_level;
54 uint8_t int_mask;
5a95b51d 55 MemoryRegion mmio;
80337b66
FB
56} smc91c111_state;
57
3ac59434
PM
58static const VMStateDescription vmstate_smc91c111 = {
59 .name = "smc91c111",
60 .version_id = 1,
61 .minimum_version_id = 1,
8f1e884b 62 .fields = (VMStateField[]) {
3ac59434
PM
63 VMSTATE_UINT16(tcr, smc91c111_state),
64 VMSTATE_UINT16(rcr, smc91c111_state),
65 VMSTATE_UINT16(cr, smc91c111_state),
66 VMSTATE_UINT16(ctr, smc91c111_state),
67 VMSTATE_UINT16(gpr, smc91c111_state),
68 VMSTATE_UINT16(ptr, smc91c111_state),
69 VMSTATE_UINT16(ercv, smc91c111_state),
70 VMSTATE_INT32(bank, smc91c111_state),
71 VMSTATE_INT32(packet_num, smc91c111_state),
72 VMSTATE_INT32(tx_alloc, smc91c111_state),
73 VMSTATE_INT32(allocated, smc91c111_state),
74 VMSTATE_INT32(tx_fifo_len, smc91c111_state),
75 VMSTATE_INT32_ARRAY(tx_fifo, smc91c111_state, NUM_PACKETS),
76 VMSTATE_INT32(rx_fifo_len, smc91c111_state),
77 VMSTATE_INT32_ARRAY(rx_fifo, smc91c111_state, NUM_PACKETS),
78 VMSTATE_INT32(tx_fifo_done_len, smc91c111_state),
79 VMSTATE_INT32_ARRAY(tx_fifo_done, smc91c111_state, NUM_PACKETS),
80 VMSTATE_BUFFER_UNSAFE(data, smc91c111_state, 0, NUM_PACKETS * 2048),
81 VMSTATE_UINT8(int_level, smc91c111_state),
82 VMSTATE_UINT8(int_mask, smc91c111_state),
83 VMSTATE_END_OF_LIST()
84 }
85};
86
80337b66
FB
87#define RCR_SOFT_RST 0x8000
88#define RCR_STRIP_CRC 0x0200
89#define RCR_RXEN 0x0100
90
91#define TCR_EPH_LOOP 0x2000
92#define TCR_NOCRC 0x0100
93#define TCR_PAD_EN 0x0080
94#define TCR_FORCOL 0x0004
95#define TCR_LOOP 0x0002
96#define TCR_TXEN 0x0001
97
98#define INT_MD 0x80
99#define INT_ERCV 0x40
100#define INT_EPH 0x20
101#define INT_RX_OVRN 0x10
102#define INT_ALLOC 0x08
103#define INT_TX_EMPTY 0x04
104#define INT_TX 0x02
105#define INT_RCV 0x01
106
107#define CTR_AUTO_RELEASE 0x0800
108#define CTR_RELOAD 0x0002
109#define CTR_STORE 0x0001
110
111#define RS_ALGNERR 0x8000
112#define RS_BRODCAST 0x4000
113#define RS_BADCRC 0x2000
114#define RS_ODDFRAME 0x1000
115#define RS_TOOLONG 0x0800
116#define RS_TOOSHORT 0x0400
117#define RS_MULTICAST 0x0001
118
119/* Update interrupt status. */
120static void smc91c111_update(smc91c111_state *s)
121{
122 int level;
123
124 if (s->tx_fifo_len == 0)
125 s->int_level |= INT_TX_EMPTY;
5198cfd9
FB
126 if (s->tx_fifo_done_len != 0)
127 s->int_level |= INT_TX;
80337b66 128 level = (s->int_level & s->int_mask) != 0;
d537cf6c 129 qemu_set_irq(s->irq, level);
80337b66
FB
130}
131
8d06b149
PC
132static int smc91c111_can_receive(smc91c111_state *s)
133{
134 if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST)) {
135 return 1;
136 }
e62cb54c
PC
137 if (s->allocated == (1 << NUM_PACKETS) - 1 ||
138 s->rx_fifo_len == NUM_PACKETS) {
8d06b149
PC
139 return 0;
140 }
141 return 1;
142}
143
144static inline void smc91c111_flush_queued_packets(smc91c111_state *s)
145{
146 if (smc91c111_can_receive(s)) {
147 qemu_flush_queued_packets(qemu_get_queue(s->nic));
148 }
149}
150
80337b66
FB
151/* Try to allocate a packet. Returns 0x80 on failure. */
152static int smc91c111_allocate_packet(smc91c111_state *s)
153{
154 int i;
155 if (s->allocated == (1 << NUM_PACKETS) - 1) {
156 return 0x80;
157 }
158
159 for (i = 0; i < NUM_PACKETS; i++) {
160 if ((s->allocated & (1 << i)) == 0)
161 break;
162 }
163 s->allocated |= 1 << i;
164 return i;
165}
166
167
168/* Process a pending TX allocate. */
169static void smc91c111_tx_alloc(smc91c111_state *s)
170{
171 s->tx_alloc = smc91c111_allocate_packet(s);
172 if (s->tx_alloc == 0x80)
173 return;
174 s->int_level |= INT_ALLOC;
175 smc91c111_update(s);
176}
177
178/* Remove and item from the RX FIFO. */
179static void smc91c111_pop_rx_fifo(smc91c111_state *s)
180{
181 int i;
182
183 s->rx_fifo_len--;
184 if (s->rx_fifo_len) {
185 for (i = 0; i < s->rx_fifo_len; i++)
186 s->rx_fifo[i] = s->rx_fifo[i + 1];
187 s->int_level |= INT_RCV;
188 } else {
189 s->int_level &= ~INT_RCV;
190 }
e62cb54c 191 smc91c111_flush_queued_packets(s);
80337b66
FB
192 smc91c111_update(s);
193}
194
5198cfd9
FB
195/* Remove an item from the TX completion FIFO. */
196static void smc91c111_pop_tx_fifo_done(smc91c111_state *s)
197{
198 int i;
199
200 if (s->tx_fifo_done_len == 0)
201 return;
202 s->tx_fifo_done_len--;
203 for (i = 0; i < s->tx_fifo_done_len; i++)
204 s->tx_fifo_done[i] = s->tx_fifo_done[i + 1];
205}
206
80337b66
FB
207/* Release the memory allocated to a packet. */
208static void smc91c111_release_packet(smc91c111_state *s, int packet)
209{
210 s->allocated &= ~(1 << packet);
211 if (s->tx_alloc == 0x80)
212 smc91c111_tx_alloc(s);
8d06b149 213 smc91c111_flush_queued_packets(s);
80337b66
FB
214}
215
216/* Flush the TX FIFO. */
217static void smc91c111_do_tx(smc91c111_state *s)
218{
219 int i;
220 int len;
221 int control;
80337b66
FB
222 int packetnum;
223 uint8_t *p;
224
225 if ((s->tcr & TCR_TXEN) == 0)
226 return;
227 if (s->tx_fifo_len == 0)
228 return;
229 for (i = 0; i < s->tx_fifo_len; i++) {
230 packetnum = s->tx_fifo[i];
231 p = &s->data[packetnum][0];
232 /* Set status word. */
233 *(p++) = 0x01;
234 *(p++) = 0x40;
235 len = *(p++);
236 len |= ((int)*(p++)) << 8;
237 len -= 6;
238 control = p[len + 1];
239 if (control & 0x20)
240 len++;
241 /* ??? This overwrites the data following the buffer.
242 Don't know what real hardware does. */
243 if (len < 64 && (s->tcr & TCR_PAD_EN)) {
244 memset(p + len, 0, 64 - len);
245 len = 64;
246 }
247#if 0
22ed1d34
BS
248 {
249 int add_crc;
250
251 /* The card is supposed to append the CRC to the frame.
252 However none of the other network traffic has the CRC
253 appended. Suspect this is low level ethernet detail we
254 don't need to worry about. */
255 add_crc = (control & 0x10) || (s->tcr & TCR_NOCRC) == 0;
256 if (add_crc) {
257 uint32_t crc;
258
259 crc = crc32(~0, p, len);
260 memcpy(p + len, &crc, 4);
261 len += 4;
262 }
80337b66 263 }
80337b66
FB
264#endif
265 if (s->ctr & CTR_AUTO_RELEASE)
5198cfd9 266 /* Race? */
80337b66 267 smc91c111_release_packet(s, packetnum);
5198cfd9
FB
268 else if (s->tx_fifo_done_len < NUM_PACKETS)
269 s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum;
b356f76d 270 qemu_send_packet(qemu_get_queue(s->nic), p, len);
80337b66
FB
271 }
272 s->tx_fifo_len = 0;
80337b66
FB
273 smc91c111_update(s);
274}
275
276/* Add a packet to the TX FIFO. */
277static void smc91c111_queue_tx(smc91c111_state *s, int packet)
278{
279 if (s->tx_fifo_len == NUM_PACKETS)
280 return;
281 s->tx_fifo[s->tx_fifo_len++] = packet;
282 smc91c111_do_tx(s);
283}
284
1e36f6a5 285static void smc91c111_reset(DeviceState *dev)
80337b66 286{
926d152e
AF
287 smc91c111_state *s = SMC91C111(dev);
288
80337b66
FB
289 s->bank = 0;
290 s->tx_fifo_len = 0;
5198cfd9 291 s->tx_fifo_done_len = 0;
80337b66
FB
292 s->rx_fifo_len = 0;
293 s->allocated = 0;
294 s->packet_num = 0;
295 s->tx_alloc = 0;
296 s->tcr = 0;
297 s->rcr = 0;
298 s->cr = 0xa0b1;
299 s->ctr = 0x1210;
300 s->ptr = 0;
301 s->ercv = 0x1f;
302 s->int_level = INT_TX_EMPTY;
303 s->int_mask = 0;
304 smc91c111_update(s);
305}
306
307#define SET_LOW(name, val) s->name = (s->name & 0xff00) | val
308#define SET_HIGH(name, val) s->name = (s->name & 0xff) | (val << 8)
309
a8170e5e 310static void smc91c111_writeb(void *opaque, hwaddr offset,
80337b66
FB
311 uint32_t value)
312{
313 smc91c111_state *s = (smc91c111_state *)opaque;
314
3b4b86aa 315 offset = offset & 0xf;
80337b66
FB
316 if (offset == 14) {
317 s->bank = value;
318 return;
319 }
320 if (offset == 15)
321 return;
322 switch (s->bank) {
323 case 0:
324 switch (offset) {
325 case 0: /* TCR */
326 SET_LOW(tcr, value);
327 return;
328 case 1:
329 SET_HIGH(tcr, value);
330 return;
331 case 4: /* RCR */
332 SET_LOW(rcr, value);
333 return;
334 case 5:
335 SET_HIGH(rcr, value);
926d152e
AF
336 if (s->rcr & RCR_SOFT_RST) {
337 smc91c111_reset(DEVICE(s));
338 }
271a234a 339 smc91c111_flush_queued_packets(s);
80337b66
FB
340 return;
341 case 10: case 11: /* RPCR */
342 /* Ignored */
343 return;
14da5616
LM
344 case 12: case 13: /* Reserved */
345 return;
80337b66
FB
346 }
347 break;
348
349 case 1:
350 switch (offset) {
351 case 0: /* CONFIG */
352 SET_LOW(cr, value);
353 return;
354 case 1:
355 SET_HIGH(cr,value);
356 return;
357 case 2: case 3: /* BASE */
358 case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
359 /* Not implemented. */
360 return;
361 case 10: /* Genral Purpose */
362 SET_LOW(gpr, value);
363 return;
364 case 11:
365 SET_HIGH(gpr, value);
366 return;
367 case 12: /* Control */
637e5d86
PMD
368 if (value & 1) {
369 qemu_log_mask(LOG_UNIMP,
370 "smc91c111: EEPROM store not implemented\n");
371 }
372 if (value & 2) {
373 qemu_log_mask(LOG_UNIMP,
374 "smc91c111: EEPROM reload not implemented\n");
375 }
80337b66
FB
376 value &= ~3;
377 SET_LOW(ctr, value);
378 return;
379 case 13:
380 SET_HIGH(ctr, value);
381 return;
382 }
383 break;
384
385 case 2:
386 switch (offset) {
387 case 0: /* MMU Command */
388 switch (value >> 5) {
389 case 0: /* no-op */
390 break;
391 case 1: /* Allocate for TX. */
392 s->tx_alloc = 0x80;
393 s->int_level &= ~INT_ALLOC;
394 smc91c111_update(s);
395 smc91c111_tx_alloc(s);
396 break;
397 case 2: /* Reset MMU. */
398 s->allocated = 0;
399 s->tx_fifo_len = 0;
5198cfd9 400 s->tx_fifo_done_len = 0;
80337b66
FB
401 s->rx_fifo_len = 0;
402 s->tx_alloc = 0;
403 break;
404 case 3: /* Remove from RX FIFO. */
405 smc91c111_pop_rx_fifo(s);
406 break;
407 case 4: /* Remove from RX FIFO and release. */
408 if (s->rx_fifo_len > 0) {
409 smc91c111_release_packet(s, s->rx_fifo[0]);
410 }
411 smc91c111_pop_rx_fifo(s);
412 break;
413 case 5: /* Release. */
414 smc91c111_release_packet(s, s->packet_num);
415 break;
416 case 6: /* Add to TX FIFO. */
417 smc91c111_queue_tx(s, s->packet_num);
418 break;
419 case 7: /* Reset TX FIFO. */
420 s->tx_fifo_len = 0;
5198cfd9 421 s->tx_fifo_done_len = 0;
80337b66
FB
422 break;
423 }
424 return;
425 case 1:
426 /* Ignore. */
427 return;
428 case 2: /* Packet Number Register */
429 s->packet_num = value;
430 return;
431 case 3: case 4: case 5:
432 /* Should be readonly, but linux writes to them anyway. Ignore. */
433 return;
434 case 6: /* Pointer */
435 SET_LOW(ptr, value);
436 return;
437 case 7:
438 SET_HIGH(ptr, value);
439 return;
440 case 8: case 9: case 10: case 11: /* Data */
441 {
442 int p;
443 int n;
444
445 if (s->ptr & 0x8000)
446 n = s->rx_fifo[0];
447 else
448 n = s->packet_num;
449 p = s->ptr & 0x07ff;
450 if (s->ptr & 0x4000) {
451 s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x7ff);
452 } else {
453 p += (offset & 3);
454 }
455 s->data[n][p] = value;
456 }
457 return;
458 case 12: /* Interrupt ACK. */
459 s->int_level &= ~(value & 0xd6);
5198cfd9
FB
460 if (value & INT_TX)
461 smc91c111_pop_tx_fifo_done(s);
80337b66
FB
462 smc91c111_update(s);
463 return;
464 case 13: /* Interrupt mask. */
465 s->int_mask = value;
466 smc91c111_update(s);
467 return;
468 }
3a93113a 469 break;
80337b66
FB
470
471 case 3:
472 switch (offset) {
473 case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
474 /* Multicast table. */
475 /* Not implemented. */
476 return;
477 case 8: case 9: /* Management Interface. */
478 /* Not implemented. */
479 return;
480 case 12: /* Early receive. */
481 s->ercv = value & 0x1f;
89556d17 482 return;
80337b66
FB
483 case 13:
484 /* Ignore. */
485 return;
486 }
487 break;
488 }
b9992d12
PMD
489 qemu_log_mask(LOG_GUEST_ERROR, "smc91c111_write(bank:%d) Illegal register"
490 " 0x%" HWADDR_PRIx " = 0x%x\n",
491 s->bank, offset, value);
80337b66
FB
492}
493
a8170e5e 494static uint32_t smc91c111_readb(void *opaque, hwaddr offset)
80337b66
FB
495{
496 smc91c111_state *s = (smc91c111_state *)opaque;
497
3b4b86aa 498 offset = offset & 0xf;
80337b66
FB
499 if (offset == 14) {
500 return s->bank;
501 }
502 if (offset == 15)
503 return 0x33;
504 switch (s->bank) {
505 case 0:
506 switch (offset) {
507 case 0: /* TCR */
508 return s->tcr & 0xff;
509 case 1:
510 return s->tcr >> 8;
511 case 2: /* EPH Status */
512 return 0;
513 case 3:
514 return 0x40;
515 case 4: /* RCR */
516 return s->rcr & 0xff;
517 case 5:
518 return s->rcr >> 8;
519 case 6: /* Counter */
520 case 7:
521 /* Not implemented. */
522 return 0;
687fa640
TS
523 case 8: /* Memory size. */
524 return NUM_PACKETS;
525 case 9: /* Free memory available. */
80337b66
FB
526 {
527 int i;
528 int n;
529 n = 0;
530 for (i = 0; i < NUM_PACKETS; i++) {
531 if (s->allocated & (1 << i))
532 n++;
533 }
534 return n;
535 }
80337b66
FB
536 case 10: case 11: /* RPCR */
537 /* Not implemented. */
538 return 0;
14da5616
LM
539 case 12: case 13: /* Reserved */
540 return 0;
80337b66
FB
541 }
542 break;
543
544 case 1:
545 switch (offset) {
546 case 0: /* CONFIG */
547 return s->cr & 0xff;
548 case 1:
549 return s->cr >> 8;
550 case 2: case 3: /* BASE */
551 /* Not implemented. */
552 return 0;
553 case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
50132156 554 return s->conf.macaddr.a[offset - 4];
80337b66
FB
555 case 10: /* General Purpose */
556 return s->gpr & 0xff;
557 case 11:
558 return s->gpr >> 8;
559 case 12: /* Control */
560 return s->ctr & 0xff;
561 case 13:
562 return s->ctr >> 8;
563 }
564 break;
565
566 case 2:
567 switch (offset) {
568 case 0: case 1: /* MMUCR Busy bit. */
569 return 0;
570 case 2: /* Packet Number. */
571 return s->packet_num;
572 case 3: /* Allocation Result. */
573 return s->tx_alloc;
574 case 4: /* TX FIFO */
5198cfd9 575 if (s->tx_fifo_done_len == 0)
80337b66
FB
576 return 0x80;
577 else
5198cfd9 578 return s->tx_fifo_done[0];
80337b66
FB
579 case 5: /* RX FIFO */
580 if (s->rx_fifo_len == 0)
581 return 0x80;
582 else
583 return s->rx_fifo[0];
584 case 6: /* Pointer */
585 return s->ptr & 0xff;
586 case 7:
587 return (s->ptr >> 8) & 0xf7;
588 case 8: case 9: case 10: case 11: /* Data */
589 {
590 int p;
591 int n;
592
593 if (s->ptr & 0x8000)
594 n = s->rx_fifo[0];
595 else
596 n = s->packet_num;
597 p = s->ptr & 0x07ff;
598 if (s->ptr & 0x4000) {
599 s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x07ff);
600 } else {
601 p += (offset & 3);
602 }
603 return s->data[n][p];
604 }
605 case 12: /* Interrupt status. */
606 return s->int_level;
607 case 13: /* Interrupt mask. */
608 return s->int_mask;
609 }
610 break;
611
612 case 3:
613 switch (offset) {
614 case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
615 /* Multicast table. */
616 /* Not implemented. */
617 return 0;
618 case 8: /* Management Interface. */
619 /* Not implemented. */
620 return 0x30;
621 case 9:
622 return 0x33;
623 case 10: /* Revision. */
624 return 0x91;
625 case 11:
626 return 0x33;
627 case 12:
628 return s->ercv;
629 case 13:
630 return 0;
631 }
632 break;
633 }
b9992d12
PMD
634 qemu_log_mask(LOG_GUEST_ERROR, "smc91c111_read(bank:%d) Illegal register"
635 " 0x%" HWADDR_PRIx "\n",
636 s->bank, offset);
80337b66
FB
637 return 0;
638}
639
50a22d0d 640static uint64_t smc91c111_readfn(void *opaque, hwaddr addr, unsigned size)
80337b66 641{
50a22d0d
PM
642 int i;
643 uint32_t val = 0;
80337b66 644
50a22d0d
PM
645 for (i = 0; i < size; i++) {
646 val |= smc91c111_readb(opaque, addr + i) << (i * 8);
647 }
80337b66
FB
648 return val;
649}
650
50a22d0d
PM
651static void smc91c111_writefn(void *opaque, hwaddr addr,
652 uint64_t value, unsigned size)
80337b66 653{
50a22d0d
PM
654 int i = 0;
655
656 /* 32-bit writes to offset 0xc only actually write to the bank select
657 * register (offset 0xe), so skip the first two bytes we would write.
658 */
659 if (addr == 0xc && size == 4) {
660 i += 2;
661 }
662
663 for (; i < size; i++) {
664 smc91c111_writeb(opaque, addr + i,
665 extract32(value, i * 8, 8));
666 }
80337b66
FB
667}
668
8d06b149 669static int smc91c111_can_receive_nc(NetClientState *nc)
d861b05e 670{
cc1f0f45 671 smc91c111_state *s = qemu_get_nic_opaque(nc);
d861b05e 672
8d06b149 673 return smc91c111_can_receive(s);
d861b05e
PB
674}
675
4e68f7a0 676static ssize_t smc91c111_receive(NetClientState *nc, const uint8_t *buf, size_t size)
80337b66 677{
cc1f0f45 678 smc91c111_state *s = qemu_get_nic_opaque(nc);
80337b66
FB
679 int status;
680 int packetsize;
681 uint32_t crc;
682 int packetnum;
683 uint8_t *p;
684
685 if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
4f1c942b 686 return -1;
9f083493 687 /* Short packets are padded with zeros. Receiving a packet
80337b66
FB
688 < 64 bytes long is considered an error condition. */
689 if (size < 64)
690 packetsize = 64;
691 else
692 packetsize = (size & ~1);
693 packetsize += 6;
694 crc = (s->rcr & RCR_STRIP_CRC) == 0;
695 if (crc)
696 packetsize += 4;
697 /* TODO: Flag overrun and receive errors. */
698 if (packetsize > 2048)
4f1c942b 699 return -1;
80337b66
FB
700 packetnum = smc91c111_allocate_packet(s);
701 if (packetnum == 0x80)
4f1c942b 702 return -1;
80337b66
FB
703 s->rx_fifo[s->rx_fifo_len++] = packetnum;
704
705 p = &s->data[packetnum][0];
706 /* ??? Multicast packets? */
707 status = 0;
708 if (size > 1518)
709 status |= RS_TOOLONG;
710 if (size & 1)
711 status |= RS_ODDFRAME;
712 *(p++) = status & 0xff;
713 *(p++) = status >> 8;
714 *(p++) = packetsize & 0xff;
715 *(p++) = packetsize >> 8;
716 memcpy(p, buf, size & ~1);
717 p += (size & ~1);
718 /* Pad short packets. */
719 if (size < 64) {
720 int pad;
3b46e624 721
80337b66
FB
722 if (size & 1)
723 *(p++) = buf[size - 1];
724 pad = 64 - size;
725 memset(p, 0, pad);
726 p += pad;
727 size = 64;
728 }
729 /* It's not clear if the CRC should go before or after the last byte in
730 odd sized packets. Linux disables the CRC, so that's no help.
731 The pictures in the documentation show the CRC aligned on a 16-bit
732 boundary before the last odd byte, so that's what we do. */
733 if (crc) {
734 crc = crc32(~0, buf, size);
735 *(p++) = crc & 0xff; crc >>= 8;
736 *(p++) = crc & 0xff; crc >>= 8;
737 *(p++) = crc & 0xff; crc >>= 8;
22ed1d34 738 *(p++) = crc & 0xff;
80337b66
FB
739 }
740 if (size & 1) {
741 *(p++) = buf[size - 1];
22ed1d34 742 *p = 0x60;
80337b66
FB
743 } else {
744 *(p++) = 0;
22ed1d34 745 *p = 0x40;
80337b66
FB
746 }
747 /* TODO: Raise early RX interrupt? */
748 s->int_level |= INT_RCV;
749 smc91c111_update(s);
4f1c942b
MM
750
751 return size;
80337b66
FB
752}
753
5a95b51d
PM
754static const MemoryRegionOps smc91c111_mem_ops = {
755 /* The special case for 32 bit writes to 0xc means we can't just
756 * set .impl.min/max_access_size to 1, unfortunately
757 */
50a22d0d
PM
758 .read = smc91c111_readfn,
759 .write = smc91c111_writefn,
760 .valid.min_access_size = 1,
761 .valid.max_access_size = 4,
5a95b51d 762 .endianness = DEVICE_NATIVE_ENDIAN,
80337b66
FB
763};
764
42a4260f 765static NetClientInfo net_smc91c111_info = {
f394b2e2 766 .type = NET_CLIENT_DRIVER_NIC,
42a4260f 767 .size = sizeof(NICState),
8d06b149 768 .can_receive = smc91c111_can_receive_nc,
42a4260f 769 .receive = smc91c111_receive,
42a4260f
MM
770};
771
f5ac82ce 772static void smc91c111_realize(DeviceState *dev, Error **errp)
80337b66 773{
f5ac82ce 774 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
926d152e
AF
775 smc91c111_state *s = SMC91C111(dev);
776
eedfac6f 777 memory_region_init_io(&s->mmio, OBJECT(s), &smc91c111_mem_ops, s,
5a95b51d 778 "smc91c111-mmio", 16);
926d152e
AF
779 sysbus_init_mmio(sbd, &s->mmio);
780 sysbus_init_irq(sbd, &s->irq);
50132156 781 qemu_macaddr_default_if_unset(&s->conf.macaddr);
42a4260f 782 s->nic = qemu_new_nic(&net_smc91c111_info, &s->conf,
926d152e 783 object_get_typename(OBJECT(dev)), dev->id, s);
b356f76d 784 qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
80337b66
FB
785 /* ??? Save/restore. */
786}
418dcf5b 787
999e12bb
AL
788static Property smc91c111_properties[] = {
789 DEFINE_NIC_PROPERTIES(smc91c111_state, conf),
790 DEFINE_PROP_END_OF_LIST(),
791};
792
793static void smc91c111_class_init(ObjectClass *klass, void *data)
794{
39bffca2 795 DeviceClass *dc = DEVICE_CLASS(klass);
999e12bb 796
f5ac82ce 797 dc->realize = smc91c111_realize;
39bffca2
AL
798 dc->reset = smc91c111_reset;
799 dc->vmsd = &vmstate_smc91c111;
800 dc->props = smc91c111_properties;
999e12bb
AL
801}
802
8c43a6f0 803static const TypeInfo smc91c111_info = {
926d152e 804 .name = TYPE_SMC91C111,
39bffca2
AL
805 .parent = TYPE_SYS_BUS_DEVICE,
806 .instance_size = sizeof(smc91c111_state),
807 .class_init = smc91c111_class_init,
50132156
GH
808};
809
83f7d43a 810static void smc91c111_register_types(void)
418dcf5b 811{
39bffca2 812 type_register_static(&smc91c111_info);
418dcf5b
PB
813}
814
815/* Legacy helper function. Should go away when machine config files are
816 implemented. */
817void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq)
818{
819 DeviceState *dev;
820 SysBusDevice *s;
821
822 qemu_check_nic_model(nd, "smc91c111");
926d152e 823 dev = qdev_create(NULL, TYPE_SMC91C111);
50132156 824 qdev_set_nic_properties(dev, nd);
e23a1b33 825 qdev_init_nofail(dev);
1356b98d 826 s = SYS_BUS_DEVICE(dev);
418dcf5b
PB
827 sysbus_mmio_map(s, 0, base);
828 sysbus_connect_irq(s, 0, irq);
829}
830
83f7d43a 831type_init(smc91c111_register_types)
This page took 1.293798 seconds and 4 git commands to generate.