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