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