1
2
3
4
5
6
7
8
9
10#include "qemu/osdep.h"
11#include "hw/sysbus.h"
12#include "migration/vmstate.h"
13#include "net/net.h"
14#include "hw/irq.h"
15#include "hw/net/smc91c111.h"
16#include "hw/qdev-properties.h"
17#include "qemu/log.h"
18#include "qemu/module.h"
19
20#include <zlib.h>
21
22
23#define NUM_PACKETS 4
24
25#define TYPE_SMC91C111 "smc91c111"
26#define SMC91C111(obj) OBJECT_CHECK(smc91c111_state, (obj), TYPE_SMC91C111)
27
28typedef struct {
29 SysBusDevice parent_obj;
30
31 NICState *nic;
32 NICConf conf;
33 uint16_t tcr;
34 uint16_t rcr;
35 uint16_t cr;
36 uint16_t ctr;
37 uint16_t gpr;
38 uint16_t ptr;
39 uint16_t ercv;
40 qemu_irq irq;
41 int bank;
42 int packet_num;
43 int tx_alloc;
44
45 int allocated;
46 int tx_fifo_len;
47 int tx_fifo[NUM_PACKETS];
48 int rx_fifo_len;
49 int rx_fifo[NUM_PACKETS];
50 int tx_fifo_done_len;
51 int tx_fifo_done[NUM_PACKETS];
52
53 uint8_t data[NUM_PACKETS][2048];
54 uint8_t int_level;
55 uint8_t int_mask;
56 MemoryRegion mmio;
57} smc91c111_state;
58
59static const VMStateDescription vmstate_smc91c111 = {
60 .name = "smc91c111",
61 .version_id = 1,
62 .minimum_version_id = 1,
63 .fields = (VMStateField[]) {
64 VMSTATE_UINT16(tcr, smc91c111_state),
65 VMSTATE_UINT16(rcr, smc91c111_state),
66 VMSTATE_UINT16(cr, smc91c111_state),
67 VMSTATE_UINT16(ctr, smc91c111_state),
68 VMSTATE_UINT16(gpr, smc91c111_state),
69 VMSTATE_UINT16(ptr, smc91c111_state),
70 VMSTATE_UINT16(ercv, smc91c111_state),
71 VMSTATE_INT32(bank, smc91c111_state),
72 VMSTATE_INT32(packet_num, smc91c111_state),
73 VMSTATE_INT32(tx_alloc, smc91c111_state),
74 VMSTATE_INT32(allocated, smc91c111_state),
75 VMSTATE_INT32(tx_fifo_len, smc91c111_state),
76 VMSTATE_INT32_ARRAY(tx_fifo, smc91c111_state, NUM_PACKETS),
77 VMSTATE_INT32(rx_fifo_len, smc91c111_state),
78 VMSTATE_INT32_ARRAY(rx_fifo, smc91c111_state, NUM_PACKETS),
79 VMSTATE_INT32(tx_fifo_done_len, smc91c111_state),
80 VMSTATE_INT32_ARRAY(tx_fifo_done, smc91c111_state, NUM_PACKETS),
81 VMSTATE_BUFFER_UNSAFE(data, smc91c111_state, 0, NUM_PACKETS * 2048),
82 VMSTATE_UINT8(int_level, smc91c111_state),
83 VMSTATE_UINT8(int_mask, smc91c111_state),
84 VMSTATE_END_OF_LIST()
85 }
86};
87
88#define RCR_SOFT_RST 0x8000
89#define RCR_STRIP_CRC 0x0200
90#define RCR_RXEN 0x0100
91
92#define TCR_EPH_LOOP 0x2000
93#define TCR_NOCRC 0x0100
94#define TCR_PAD_EN 0x0080
95#define TCR_FORCOL 0x0004
96#define TCR_LOOP 0x0002
97#define TCR_TXEN 0x0001
98
99#define INT_MD 0x80
100#define INT_ERCV 0x40
101#define INT_EPH 0x20
102#define INT_RX_OVRN 0x10
103#define INT_ALLOC 0x08
104#define INT_TX_EMPTY 0x04
105#define INT_TX 0x02
106#define INT_RCV 0x01
107
108#define CTR_AUTO_RELEASE 0x0800
109#define CTR_RELOAD 0x0002
110#define CTR_STORE 0x0001
111
112#define RS_ALGNERR 0x8000
113#define RS_BRODCAST 0x4000
114#define RS_BADCRC 0x2000
115#define RS_ODDFRAME 0x1000
116#define RS_TOOLONG 0x0800
117#define RS_TOOSHORT 0x0400
118#define RS_MULTICAST 0x0001
119
120
121static void smc91c111_update(smc91c111_state *s)
122{
123 int level;
124
125 if (s->tx_fifo_len == 0)
126 s->int_level |= INT_TX_EMPTY;
127 if (s->tx_fifo_done_len != 0)
128 s->int_level |= INT_TX;
129 level = (s->int_level & s->int_mask) != 0;
130 qemu_set_irq(s->irq, level);
131}
132
133static int smc91c111_can_receive(smc91c111_state *s)
134{
135 if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST)) {
136 return 1;
137 }
138 if (s->allocated == (1 << NUM_PACKETS) - 1 ||
139 s->rx_fifo_len == NUM_PACKETS) {
140 return 0;
141 }
142 return 1;
143}
144
145static inline void smc91c111_flush_queued_packets(smc91c111_state *s)
146{
147 if (smc91c111_can_receive(s)) {
148 qemu_flush_queued_packets(qemu_get_queue(s->nic));
149 }
150}
151
152
153static int smc91c111_allocate_packet(smc91c111_state *s)
154{
155 int i;
156 if (s->allocated == (1 << NUM_PACKETS) - 1) {
157 return 0x80;
158 }
159
160 for (i = 0; i < NUM_PACKETS; i++) {
161 if ((s->allocated & (1 << i)) == 0)
162 break;
163 }
164 s->allocated |= 1 << i;
165 return i;
166}
167
168
169
170static void smc91c111_tx_alloc(smc91c111_state *s)
171{
172 s->tx_alloc = smc91c111_allocate_packet(s);
173 if (s->tx_alloc == 0x80)
174 return;
175 s->int_level |= INT_ALLOC;
176 smc91c111_update(s);
177}
178
179
180static void smc91c111_pop_rx_fifo(smc91c111_state *s)
181{
182 int i;
183
184 s->rx_fifo_len--;
185 if (s->rx_fifo_len) {
186 for (i = 0; i < s->rx_fifo_len; i++)
187 s->rx_fifo[i] = s->rx_fifo[i + 1];
188 s->int_level |= INT_RCV;
189 } else {
190 s->int_level &= ~INT_RCV;
191 }
192 smc91c111_flush_queued_packets(s);
193 smc91c111_update(s);
194}
195
196
197static void smc91c111_pop_tx_fifo_done(smc91c111_state *s)
198{
199 int i;
200
201 if (s->tx_fifo_done_len == 0)
202 return;
203 s->tx_fifo_done_len--;
204 for (i = 0; i < s->tx_fifo_done_len; i++)
205 s->tx_fifo_done[i] = s->tx_fifo_done[i + 1];
206}
207
208
209static void smc91c111_release_packet(smc91c111_state *s, int packet)
210{
211 s->allocated &= ~(1 << packet);
212 if (s->tx_alloc == 0x80)
213 smc91c111_tx_alloc(s);
214 smc91c111_flush_queued_packets(s);
215}
216
217
218static void smc91c111_do_tx(smc91c111_state *s)
219{
220 int i;
221 int len;
222 int control;
223 int packetnum;
224 uint8_t *p;
225
226 if ((s->tcr & TCR_TXEN) == 0)
227 return;
228 if (s->tx_fifo_len == 0)
229 return;
230 for (i = 0; i < s->tx_fifo_len; i++) {
231 packetnum = s->tx_fifo[i];
232 p = &s->data[packetnum][0];
233
234 *(p++) = 0x01;
235 *(p++) = 0x40;
236 len = *(p++);
237 len |= ((int)*(p++)) << 8;
238 len -= 6;
239 control = p[len + 1];
240 if (control & 0x20)
241 len++;
242
243
244 if (len < 64 && (s->tcr & TCR_PAD_EN)) {
245 memset(p + len, 0, 64 - len);
246 len = 64;
247 }
248#if 0
249 {
250 int add_crc;
251
252
253
254
255
256 add_crc = (control & 0x10) || (s->tcr & TCR_NOCRC) == 0;
257 if (add_crc) {
258 uint32_t crc;
259
260 crc = crc32(~0, p, len);
261 memcpy(p + len, &crc, 4);
262 len += 4;
263 }
264 }
265#endif
266 if (s->ctr & CTR_AUTO_RELEASE)
267
268 smc91c111_release_packet(s, packetnum);
269 else if (s->tx_fifo_done_len < NUM_PACKETS)
270 s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum;
271 qemu_send_packet(qemu_get_queue(s->nic), p, len);
272 }
273 s->tx_fifo_len = 0;
274 smc91c111_update(s);
275}
276
277
278static void smc91c111_queue_tx(smc91c111_state *s, int packet)
279{
280 if (s->tx_fifo_len == NUM_PACKETS)
281 return;
282 s->tx_fifo[s->tx_fifo_len++] = packet;
283 smc91c111_do_tx(s);
284}
285
286static void smc91c111_reset(DeviceState *dev)
287{
288 smc91c111_state *s = SMC91C111(dev);
289
290 s->bank = 0;
291 s->tx_fifo_len = 0;
292 s->tx_fifo_done_len = 0;
293 s->rx_fifo_len = 0;
294 s->allocated = 0;
295 s->packet_num = 0;
296 s->tx_alloc = 0;
297 s->tcr = 0;
298 s->rcr = 0;
299 s->cr = 0xa0b1;
300 s->ctr = 0x1210;
301 s->ptr = 0;
302 s->ercv = 0x1f;
303 s->int_level = INT_TX_EMPTY;
304 s->int_mask = 0;
305 smc91c111_update(s);
306}
307
308#define SET_LOW(name, val) s->name = (s->name & 0xff00) | val
309#define SET_HIGH(name, val) s->name = (s->name & 0xff) | (val << 8)
310
311static void smc91c111_writeb(void *opaque, hwaddr offset,
312 uint32_t value)
313{
314 smc91c111_state *s = (smc91c111_state *)opaque;
315
316 offset = offset & 0xf;
317 if (offset == 14) {
318 s->bank = value;
319 return;
320 }
321 if (offset == 15)
322 return;
323 switch (s->bank) {
324 case 0:
325 switch (offset) {
326 case 0:
327 SET_LOW(tcr, value);
328 return;
329 case 1:
330 SET_HIGH(tcr, value);
331 return;
332 case 4:
333 SET_LOW(rcr, value);
334 return;
335 case 5:
336 SET_HIGH(rcr, value);
337 if (s->rcr & RCR_SOFT_RST) {
338 smc91c111_reset(DEVICE(s));
339 }
340 smc91c111_flush_queued_packets(s);
341 return;
342 case 10: case 11:
343
344 return;
345 case 12: case 13:
346 return;
347 }
348 break;
349
350 case 1:
351 switch (offset) {
352 case 0:
353 SET_LOW(cr, value);
354 return;
355 case 1:
356 SET_HIGH(cr,value);
357 return;
358 case 2: case 3:
359 case 4: case 5: case 6: case 7: case 8: case 9:
360
361 return;
362 case 10:
363 SET_LOW(gpr, value);
364 return;
365 case 11:
366 SET_HIGH(gpr, value);
367 return;
368 case 12:
369 if (value & 1) {
370 qemu_log_mask(LOG_UNIMP,
371 "smc91c111: EEPROM store not implemented\n");
372 }
373 if (value & 2) {
374 qemu_log_mask(LOG_UNIMP,
375 "smc91c111: EEPROM reload not implemented\n");
376 }
377 value &= ~3;
378 SET_LOW(ctr, value);
379 return;
380 case 13:
381 SET_HIGH(ctr, value);
382 return;
383 }
384 break;
385
386 case 2:
387 switch (offset) {
388 case 0:
389 switch (value >> 5) {
390 case 0:
391 break;
392 case 1:
393 s->tx_alloc = 0x80;
394 s->int_level &= ~INT_ALLOC;
395 smc91c111_update(s);
396 smc91c111_tx_alloc(s);
397 break;
398 case 2:
399 s->allocated = 0;
400 s->tx_fifo_len = 0;
401 s->tx_fifo_done_len = 0;
402 s->rx_fifo_len = 0;
403 s->tx_alloc = 0;
404 break;
405 case 3:
406 smc91c111_pop_rx_fifo(s);
407 break;
408 case 4:
409 if (s->rx_fifo_len > 0) {
410 smc91c111_release_packet(s, s->rx_fifo[0]);
411 }
412 smc91c111_pop_rx_fifo(s);
413 break;
414 case 5:
415 smc91c111_release_packet(s, s->packet_num);
416 break;
417 case 6:
418 smc91c111_queue_tx(s, s->packet_num);
419 break;
420 case 7:
421 s->tx_fifo_len = 0;
422 s->tx_fifo_done_len = 0;
423 break;
424 }
425 return;
426 case 1:
427
428 return;
429 case 2:
430 s->packet_num = value;
431 return;
432 case 3: case 4: case 5:
433
434 return;
435 case 6:
436 SET_LOW(ptr, value);
437 return;
438 case 7:
439 SET_HIGH(ptr, value);
440 return;
441 case 8: case 9: case 10: case 11:
442 {
443 int p;
444 int n;
445
446 if (s->ptr & 0x8000)
447 n = s->rx_fifo[0];
448 else
449 n = s->packet_num;
450 p = s->ptr & 0x07ff;
451 if (s->ptr & 0x4000) {
452 s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x7ff);
453 } else {
454 p += (offset & 3);
455 }
456 s->data[n][p] = value;
457 }
458 return;
459 case 12:
460 s->int_level &= ~(value & 0xd6);
461 if (value & INT_TX)
462 smc91c111_pop_tx_fifo_done(s);
463 smc91c111_update(s);
464 return;
465 case 13:
466 s->int_mask = value;
467 smc91c111_update(s);
468 return;
469 }
470 break;
471
472 case 3:
473 switch (offset) {
474 case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
475
476
477 return;
478 case 8: case 9:
479
480 return;
481 case 12:
482 s->ercv = value & 0x1f;
483 return;
484 case 13:
485
486 return;
487 }
488 break;
489 }
490 qemu_log_mask(LOG_GUEST_ERROR, "smc91c111_write(bank:%d) Illegal register"
491 " 0x%" HWADDR_PRIx " = 0x%x\n",
492 s->bank, offset, value);
493}
494
495static uint32_t smc91c111_readb(void *opaque, hwaddr offset)
496{
497 smc91c111_state *s = (smc91c111_state *)opaque;
498
499 offset = offset & 0xf;
500 if (offset == 14) {
501 return s->bank;
502 }
503 if (offset == 15)
504 return 0x33;
505 switch (s->bank) {
506 case 0:
507 switch (offset) {
508 case 0:
509 return s->tcr & 0xff;
510 case 1:
511 return s->tcr >> 8;
512 case 2:
513 return 0;
514 case 3:
515 return 0x40;
516 case 4:
517 return s->rcr & 0xff;
518 case 5:
519 return s->rcr >> 8;
520 case 6:
521 case 7:
522
523 return 0;
524 case 8:
525 return NUM_PACKETS;
526 case 9:
527 {
528 int i;
529 int n;
530 n = 0;
531 for (i = 0; i < NUM_PACKETS; i++) {
532 if (s->allocated & (1 << i))
533 n++;
534 }
535 return n;
536 }
537 case 10: case 11:
538
539 return 0;
540 case 12: case 13:
541 return 0;
542 }
543 break;
544
545 case 1:
546 switch (offset) {
547 case 0:
548 return s->cr & 0xff;
549 case 1:
550 return s->cr >> 8;
551 case 2: case 3:
552
553 return 0;
554 case 4: case 5: case 6: case 7: case 8: case 9:
555 return s->conf.macaddr.a[offset - 4];
556 case 10:
557 return s->gpr & 0xff;
558 case 11:
559 return s->gpr >> 8;
560 case 12:
561 return s->ctr & 0xff;
562 case 13:
563 return s->ctr >> 8;
564 }
565 break;
566
567 case 2:
568 switch (offset) {
569 case 0: case 1:
570 return 0;
571 case 2:
572 return s->packet_num;
573 case 3:
574 return s->tx_alloc;
575 case 4:
576 if (s->tx_fifo_done_len == 0)
577 return 0x80;
578 else
579 return s->tx_fifo_done[0];
580 case 5:
581 if (s->rx_fifo_len == 0)
582 return 0x80;
583 else
584 return s->rx_fifo[0];
585 case 6:
586 return s->ptr & 0xff;
587 case 7:
588 return (s->ptr >> 8) & 0xf7;
589 case 8: case 9: case 10: case 11:
590 {
591 int p;
592 int n;
593
594 if (s->ptr & 0x8000)
595 n = s->rx_fifo[0];
596 else
597 n = s->packet_num;
598 p = s->ptr & 0x07ff;
599 if (s->ptr & 0x4000) {
600 s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x07ff);
601 } else {
602 p += (offset & 3);
603 }
604 return s->data[n][p];
605 }
606 case 12:
607 return s->int_level;
608 case 13:
609 return s->int_mask;
610 }
611 break;
612
613 case 3:
614 switch (offset) {
615 case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
616
617
618 return 0;
619 case 8:
620
621 return 0x30;
622 case 9:
623 return 0x33;
624 case 10:
625 return 0x91;
626 case 11:
627 return 0x33;
628 case 12:
629 return s->ercv;
630 case 13:
631 return 0;
632 }
633 break;
634 }
635 qemu_log_mask(LOG_GUEST_ERROR, "smc91c111_read(bank:%d) Illegal register"
636 " 0x%" HWADDR_PRIx "\n",
637 s->bank, offset);
638 return 0;
639}
640
641static uint64_t smc91c111_readfn(void *opaque, hwaddr addr, unsigned size)
642{
643 int i;
644 uint32_t val = 0;
645
646 for (i = 0; i < size; i++) {
647 val |= smc91c111_readb(opaque, addr + i) << (i * 8);
648 }
649 return val;
650}
651
652static void smc91c111_writefn(void *opaque, hwaddr addr,
653 uint64_t value, unsigned size)
654{
655 int i = 0;
656
657
658
659
660 if (addr == 0xc && size == 4) {
661 i += 2;
662 }
663
664 for (; i < size; i++) {
665 smc91c111_writeb(opaque, addr + i,
666 extract32(value, i * 8, 8));
667 }
668}
669
670static int smc91c111_can_receive_nc(NetClientState *nc)
671{
672 smc91c111_state *s = qemu_get_nic_opaque(nc);
673
674 return smc91c111_can_receive(s);
675}
676
677static ssize_t smc91c111_receive(NetClientState *nc, const uint8_t *buf, size_t size)
678{
679 smc91c111_state *s = qemu_get_nic_opaque(nc);
680 int status;
681 int packetsize;
682 uint32_t crc;
683 int packetnum;
684 uint8_t *p;
685
686 if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
687 return -1;
688
689
690 if (size < 64)
691 packetsize = 64;
692 else
693 packetsize = (size & ~1);
694 packetsize += 6;
695 crc = (s->rcr & RCR_STRIP_CRC) == 0;
696 if (crc)
697 packetsize += 4;
698
699 if (packetsize > 2048)
700 return -1;
701 packetnum = smc91c111_allocate_packet(s);
702 if (packetnum == 0x80)
703 return -1;
704 s->rx_fifo[s->rx_fifo_len++] = packetnum;
705
706 p = &s->data[packetnum][0];
707
708 status = 0;
709 if (size > 1518)
710 status |= RS_TOOLONG;
711 if (size & 1)
712 status |= RS_ODDFRAME;
713 *(p++) = status & 0xff;
714 *(p++) = status >> 8;
715 *(p++) = packetsize & 0xff;
716 *(p++) = packetsize >> 8;
717 memcpy(p, buf, size & ~1);
718 p += (size & ~1);
719
720 if (size < 64) {
721 int pad;
722
723 if (size & 1)
724 *(p++) = buf[size - 1];
725 pad = 64 - size;
726 memset(p, 0, pad);
727 p += pad;
728 size = 64;
729 }
730
731
732
733
734 if (crc) {
735 crc = crc32(~0, buf, size);
736 *(p++) = crc & 0xff; crc >>= 8;
737 *(p++) = crc & 0xff; crc >>= 8;
738 *(p++) = crc & 0xff; crc >>= 8;
739 *(p++) = crc & 0xff;
740 }
741 if (size & 1) {
742 *(p++) = buf[size - 1];
743 *p = 0x60;
744 } else {
745 *(p++) = 0;
746 *p = 0x40;
747 }
748
749 s->int_level |= INT_RCV;
750 smc91c111_update(s);
751
752 return size;
753}
754
755static const MemoryRegionOps smc91c111_mem_ops = {
756
757
758
759 .read = smc91c111_readfn,
760 .write = smc91c111_writefn,
761 .valid.min_access_size = 1,
762 .valid.max_access_size = 4,
763 .endianness = DEVICE_NATIVE_ENDIAN,
764};
765
766static NetClientInfo net_smc91c111_info = {
767 .type = NET_CLIENT_DRIVER_NIC,
768 .size = sizeof(NICState),
769 .can_receive = smc91c111_can_receive_nc,
770 .receive = smc91c111_receive,
771};
772
773static void smc91c111_realize(DeviceState *dev, Error **errp)
774{
775 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
776 smc91c111_state *s = SMC91C111(dev);
777
778 memory_region_init_io(&s->mmio, OBJECT(s), &smc91c111_mem_ops, s,
779 "smc91c111-mmio", 16);
780 sysbus_init_mmio(sbd, &s->mmio);
781 sysbus_init_irq(sbd, &s->irq);
782 qemu_macaddr_default_if_unset(&s->conf.macaddr);
783 s->nic = qemu_new_nic(&net_smc91c111_info, &s->conf,
784 object_get_typename(OBJECT(dev)), dev->id, s);
785 qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
786
787}
788
789static Property smc91c111_properties[] = {
790 DEFINE_NIC_PROPERTIES(smc91c111_state, conf),
791 DEFINE_PROP_END_OF_LIST(),
792};
793
794static void smc91c111_class_init(ObjectClass *klass, void *data)
795{
796 DeviceClass *dc = DEVICE_CLASS(klass);
797
798 dc->realize = smc91c111_realize;
799 dc->reset = smc91c111_reset;
800 dc->vmsd = &vmstate_smc91c111;
801 dc->props = smc91c111_properties;
802}
803
804static const TypeInfo smc91c111_info = {
805 .name = TYPE_SMC91C111,
806 .parent = TYPE_SYS_BUS_DEVICE,
807 .instance_size = sizeof(smc91c111_state),
808 .class_init = smc91c111_class_init,
809};
810
811static void smc91c111_register_types(void)
812{
813 type_register_static(&smc91c111_info);
814}
815
816
817
818void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq)
819{
820 DeviceState *dev;
821 SysBusDevice *s;
822
823 qemu_check_nic_model(nd, "smc91c111");
824 dev = qdev_create(NULL, TYPE_SMC91C111);
825 qdev_set_nic_properties(dev, nd);
826 qdev_init_nofail(dev);
827 s = SYS_BUS_DEVICE(dev);
828 sysbus_mmio_map(s, 0, base);
829 sysbus_connect_irq(s, 0, irq);
830}
831
832type_init(smc91c111_register_types)
833