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