]> git.proxmox.com Git - mirror_qemu.git/blame - hw/net/smc91c111.c
hw/net/e1000e_core: Let e1000e_can_receive() return a boolean
[mirror_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"
a27bd6c7 16#include "hw/qdev-properties.h"
b9992d12 17#include "qemu/log.h"
0b8fa32f 18#include "qemu/module.h"
80337b66
FB
19/* For crc32 */
20#include <zlib.h>
21
22/* Number of 2k memory pages available. */
23#define NUM_PACKETS 4
24
926d152e
AF
25#define TYPE_SMC91C111 "smc91c111"
26#define SMC91C111(obj) OBJECT_CHECK(smc91c111_state, (obj), TYPE_SMC91C111)
27
80337b66 28typedef struct {
926d152e
AF
29 SysBusDevice parent_obj;
30
42a4260f 31 NICState *nic;
50132156 32 NICConf conf;
80337b66
FB
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;
d537cf6c 40 qemu_irq irq;
80337b66
FB
41 int bank;
42 int packet_num;
43 int tx_alloc;
44 /* Bitmask of allocated packets. */
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];
5198cfd9
FB
50 int tx_fifo_done_len;
51 int tx_fifo_done[NUM_PACKETS];
80337b66 52 /* Packet buffer memory. */
5198cfd9 53 uint8_t data[NUM_PACKETS][2048];
80337b66
FB
54 uint8_t int_level;
55 uint8_t int_mask;
5a95b51d 56 MemoryRegion mmio;
80337b66
FB
57} smc91c111_state;
58
3ac59434
PM
59static const VMStateDescription vmstate_smc91c111 = {
60 .name = "smc91c111",
61 .version_id = 1,
62 .minimum_version_id = 1,
8f1e884b 63 .fields = (VMStateField[]) {
3ac59434
PM
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
80337b66
FB
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/* Update interrupt status. */
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;
5198cfd9
FB
127 if (s->tx_fifo_done_len != 0)
128 s->int_level |= INT_TX;
80337b66 129 level = (s->int_level & s->int_mask) != 0;
d537cf6c 130 qemu_set_irq(s->irq, level);
80337b66
FB
131}
132
8d06b149
PC
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 }
e62cb54c
PC
138 if (s->allocated == (1 << NUM_PACKETS) - 1 ||
139 s->rx_fifo_len == NUM_PACKETS) {
8d06b149
PC
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
80337b66
FB
152/* Try to allocate a packet. Returns 0x80 on failure. */
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/* Process a pending TX allocate. */
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/* Remove and item from the RX FIFO. */
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 }
e62cb54c 192 smc91c111_flush_queued_packets(s);
80337b66
FB
193 smc91c111_update(s);
194}
195
5198cfd9
FB
196/* Remove an item from the TX completion FIFO. */
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
80337b66
FB
208/* Release the memory allocated to a packet. */
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);
8d06b149 214 smc91c111_flush_queued_packets(s);
80337b66
FB
215}
216
217/* Flush the TX FIFO. */
218static void smc91c111_do_tx(smc91c111_state *s)
219{
220 int i;
221 int len;
222 int control;
80337b66
FB
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 /* Set status word. */
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 /* ??? This overwrites the data following the buffer.
243 Don't know what real hardware does. */
244 if (len < 64 && (s->tcr & TCR_PAD_EN)) {
245 memset(p + len, 0, 64 - len);
246 len = 64;
247 }
248#if 0
22ed1d34
BS
249 {
250 int add_crc;
251
252 /* The card is supposed to append the CRC to the frame.
253 However none of the other network traffic has the CRC
254 appended. Suspect this is low level ethernet detail we
255 don't need to worry about. */
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 }
80337b66 264 }
80337b66
FB
265#endif
266 if (s->ctr & CTR_AUTO_RELEASE)
5198cfd9 267 /* Race? */
80337b66 268 smc91c111_release_packet(s, packetnum);
5198cfd9
FB
269 else if (s->tx_fifo_done_len < NUM_PACKETS)
270 s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum;
b356f76d 271 qemu_send_packet(qemu_get_queue(s->nic), p, len);
80337b66
FB
272 }
273 s->tx_fifo_len = 0;
80337b66
FB
274 smc91c111_update(s);
275}
276
277/* Add a packet to the TX FIFO. */
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
1e36f6a5 286static void smc91c111_reset(DeviceState *dev)
80337b66 287{
926d152e
AF
288 smc91c111_state *s = SMC91C111(dev);
289
80337b66
FB
290 s->bank = 0;
291 s->tx_fifo_len = 0;
5198cfd9 292 s->tx_fifo_done_len = 0;
80337b66
FB
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
a8170e5e 311static void smc91c111_writeb(void *opaque, hwaddr offset,
80337b66
FB
312 uint32_t value)
313{
314 smc91c111_state *s = (smc91c111_state *)opaque;
315
3b4b86aa 316 offset = offset & 0xf;
80337b66
FB
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: /* TCR */
327 SET_LOW(tcr, value);
328 return;
329 case 1:
330 SET_HIGH(tcr, value);
331 return;
332 case 4: /* RCR */
333 SET_LOW(rcr, value);
334 return;
335 case 5:
336 SET_HIGH(rcr, value);
926d152e
AF
337 if (s->rcr & RCR_SOFT_RST) {
338 smc91c111_reset(DEVICE(s));
339 }
271a234a 340 smc91c111_flush_queued_packets(s);
80337b66
FB
341 return;
342 case 10: case 11: /* RPCR */
343 /* Ignored */
344 return;
14da5616
LM
345 case 12: case 13: /* Reserved */
346 return;
80337b66
FB
347 }
348 break;
349
350 case 1:
351 switch (offset) {
352 case 0: /* CONFIG */
353 SET_LOW(cr, value);
354 return;
355 case 1:
356 SET_HIGH(cr,value);
357 return;
358 case 2: case 3: /* BASE */
359 case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
360 /* Not implemented. */
361 return;
362 case 10: /* Genral Purpose */
363 SET_LOW(gpr, value);
364 return;
365 case 11:
366 SET_HIGH(gpr, value);
367 return;
368 case 12: /* Control */
637e5d86
PMD
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 }
80337b66
FB
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: /* MMU Command */
389 switch (value >> 5) {
390 case 0: /* no-op */
391 break;
392 case 1: /* Allocate for TX. */
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: /* Reset MMU. */
399 s->allocated = 0;
400 s->tx_fifo_len = 0;
5198cfd9 401 s->tx_fifo_done_len = 0;
80337b66
FB
402 s->rx_fifo_len = 0;
403 s->tx_alloc = 0;
404 break;
405 case 3: /* Remove from RX FIFO. */
406 smc91c111_pop_rx_fifo(s);
407 break;
408 case 4: /* Remove from RX FIFO and release. */
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: /* Release. */
415 smc91c111_release_packet(s, s->packet_num);
416 break;
417 case 6: /* Add to TX FIFO. */
418 smc91c111_queue_tx(s, s->packet_num);
419 break;
420 case 7: /* Reset TX FIFO. */
421 s->tx_fifo_len = 0;
5198cfd9 422 s->tx_fifo_done_len = 0;
80337b66
FB
423 break;
424 }
425 return;
426 case 1:
427 /* Ignore. */
428 return;
429 case 2: /* Packet Number Register */
430 s->packet_num = value;
431 return;
432 case 3: case 4: case 5:
433 /* Should be readonly, but linux writes to them anyway. Ignore. */
434 return;
435 case 6: /* Pointer */
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: /* Data */
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: /* Interrupt ACK. */
460 s->int_level &= ~(value & 0xd6);
5198cfd9
FB
461 if (value & INT_TX)
462 smc91c111_pop_tx_fifo_done(s);
80337b66
FB
463 smc91c111_update(s);
464 return;
465 case 13: /* Interrupt mask. */
466 s->int_mask = value;
467 smc91c111_update(s);
468 return;
469 }
3a93113a 470 break;
80337b66
FB
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 /* Multicast table. */
476 /* Not implemented. */
477 return;
478 case 8: case 9: /* Management Interface. */
479 /* Not implemented. */
480 return;
481 case 12: /* Early receive. */
482 s->ercv = value & 0x1f;
89556d17 483 return;
80337b66
FB
484 case 13:
485 /* Ignore. */
486 return;
487 }
488 break;
489 }
b9992d12
PMD
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);
80337b66
FB
493}
494
a8170e5e 495static uint32_t smc91c111_readb(void *opaque, hwaddr offset)
80337b66
FB
496{
497 smc91c111_state *s = (smc91c111_state *)opaque;
498
3b4b86aa 499 offset = offset & 0xf;
80337b66
FB
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: /* TCR */
509 return s->tcr & 0xff;
510 case 1:
511 return s->tcr >> 8;
512 case 2: /* EPH Status */
513 return 0;
514 case 3:
515 return 0x40;
516 case 4: /* RCR */
517 return s->rcr & 0xff;
518 case 5:
519 return s->rcr >> 8;
520 case 6: /* Counter */
521 case 7:
522 /* Not implemented. */
523 return 0;
687fa640
TS
524 case 8: /* Memory size. */
525 return NUM_PACKETS;
526 case 9: /* Free memory available. */
80337b66
FB
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 }
80337b66
FB
537 case 10: case 11: /* RPCR */
538 /* Not implemented. */
539 return 0;
14da5616
LM
540 case 12: case 13: /* Reserved */
541 return 0;
80337b66
FB
542 }
543 break;
544
545 case 1:
546 switch (offset) {
547 case 0: /* CONFIG */
548 return s->cr & 0xff;
549 case 1:
550 return s->cr >> 8;
551 case 2: case 3: /* BASE */
552 /* Not implemented. */
553 return 0;
554 case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
50132156 555 return s->conf.macaddr.a[offset - 4];
80337b66
FB
556 case 10: /* General Purpose */
557 return s->gpr & 0xff;
558 case 11:
559 return s->gpr >> 8;
560 case 12: /* Control */
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: /* MMUCR Busy bit. */
570 return 0;
571 case 2: /* Packet Number. */
572 return s->packet_num;
573 case 3: /* Allocation Result. */
574 return s->tx_alloc;
575 case 4: /* TX FIFO */
5198cfd9 576 if (s->tx_fifo_done_len == 0)
80337b66
FB
577 return 0x80;
578 else
5198cfd9 579 return s->tx_fifo_done[0];
80337b66
FB
580 case 5: /* RX FIFO */
581 if (s->rx_fifo_len == 0)
582 return 0x80;
583 else
584 return s->rx_fifo[0];
585 case 6: /* Pointer */
586 return s->ptr & 0xff;
587 case 7:
588 return (s->ptr >> 8) & 0xf7;
589 case 8: case 9: case 10: case 11: /* Data */
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: /* Interrupt status. */
607 return s->int_level;
608 case 13: /* Interrupt mask. */
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 /* Multicast table. */
617 /* Not implemented. */
618 return 0;
619 case 8: /* Management Interface. */
620 /* Not implemented. */
621 return 0x30;
622 case 9:
623 return 0x33;
624 case 10: /* Revision. */
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 }
b9992d12
PMD
635 qemu_log_mask(LOG_GUEST_ERROR, "smc91c111_read(bank:%d) Illegal register"
636 " 0x%" HWADDR_PRIx "\n",
637 s->bank, offset);
80337b66
FB
638 return 0;
639}
640
50a22d0d 641static uint64_t smc91c111_readfn(void *opaque, hwaddr addr, unsigned size)
80337b66 642{
50a22d0d
PM
643 int i;
644 uint32_t val = 0;
80337b66 645
50a22d0d
PM
646 for (i = 0; i < size; i++) {
647 val |= smc91c111_readb(opaque, addr + i) << (i * 8);
648 }
80337b66
FB
649 return val;
650}
651
50a22d0d
PM
652static void smc91c111_writefn(void *opaque, hwaddr addr,
653 uint64_t value, unsigned size)
80337b66 654{
50a22d0d
PM
655 int i = 0;
656
657 /* 32-bit writes to offset 0xc only actually write to the bank select
658 * register (offset 0xe), so skip the first two bytes we would write.
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 }
80337b66
FB
668}
669
8d06b149 670static int smc91c111_can_receive_nc(NetClientState *nc)
d861b05e 671{
cc1f0f45 672 smc91c111_state *s = qemu_get_nic_opaque(nc);
d861b05e 673
8d06b149 674 return smc91c111_can_receive(s);
d861b05e
PB
675}
676
4e68f7a0 677static ssize_t smc91c111_receive(NetClientState *nc, const uint8_t *buf, size_t size)
80337b66 678{
cc1f0f45 679 smc91c111_state *s = qemu_get_nic_opaque(nc);
80337b66
FB
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))
4f1c942b 687 return -1;
9f083493 688 /* Short packets are padded with zeros. Receiving a packet
80337b66
FB
689 < 64 bytes long is considered an error condition. */
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 /* TODO: Flag overrun and receive errors. */
699 if (packetsize > 2048)
4f1c942b 700 return -1;
80337b66
FB
701 packetnum = smc91c111_allocate_packet(s);
702 if (packetnum == 0x80)
4f1c942b 703 return -1;
80337b66
FB
704 s->rx_fifo[s->rx_fifo_len++] = packetnum;
705
706 p = &s->data[packetnum][0];
707 /* ??? Multicast packets? */
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 /* Pad short packets. */
720 if (size < 64) {
721 int pad;
3b46e624 722
80337b66
FB
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 /* It's not clear if the CRC should go before or after the last byte in
731 odd sized packets. Linux disables the CRC, so that's no help.
732 The pictures in the documentation show the CRC aligned on a 16-bit
733 boundary before the last odd byte, so that's what we do. */
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;
22ed1d34 739 *(p++) = crc & 0xff;
80337b66
FB
740 }
741 if (size & 1) {
742 *(p++) = buf[size - 1];
22ed1d34 743 *p = 0x60;
80337b66
FB
744 } else {
745 *(p++) = 0;
22ed1d34 746 *p = 0x40;
80337b66
FB
747 }
748 /* TODO: Raise early RX interrupt? */
749 s->int_level |= INT_RCV;
750 smc91c111_update(s);
4f1c942b
MM
751
752 return size;
80337b66
FB
753}
754
5a95b51d
PM
755static const MemoryRegionOps smc91c111_mem_ops = {
756 /* The special case for 32 bit writes to 0xc means we can't just
757 * set .impl.min/max_access_size to 1, unfortunately
758 */
50a22d0d
PM
759 .read = smc91c111_readfn,
760 .write = smc91c111_writefn,
761 .valid.min_access_size = 1,
762 .valid.max_access_size = 4,
5a95b51d 763 .endianness = DEVICE_NATIVE_ENDIAN,
80337b66
FB
764};
765
42a4260f 766static NetClientInfo net_smc91c111_info = {
f394b2e2 767 .type = NET_CLIENT_DRIVER_NIC,
42a4260f 768 .size = sizeof(NICState),
8d06b149 769 .can_receive = smc91c111_can_receive_nc,
42a4260f 770 .receive = smc91c111_receive,
42a4260f
MM
771};
772
f5ac82ce 773static void smc91c111_realize(DeviceState *dev, Error **errp)
80337b66 774{
f5ac82ce 775 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
926d152e
AF
776 smc91c111_state *s = SMC91C111(dev);
777
eedfac6f 778 memory_region_init_io(&s->mmio, OBJECT(s), &smc91c111_mem_ops, s,
5a95b51d 779 "smc91c111-mmio", 16);
926d152e
AF
780 sysbus_init_mmio(sbd, &s->mmio);
781 sysbus_init_irq(sbd, &s->irq);
50132156 782 qemu_macaddr_default_if_unset(&s->conf.macaddr);
42a4260f 783 s->nic = qemu_new_nic(&net_smc91c111_info, &s->conf,
926d152e 784 object_get_typename(OBJECT(dev)), dev->id, s);
b356f76d 785 qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
80337b66
FB
786 /* ??? Save/restore. */
787}
418dcf5b 788
999e12bb
AL
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{
39bffca2 796 DeviceClass *dc = DEVICE_CLASS(klass);
999e12bb 797
f5ac82ce 798 dc->realize = smc91c111_realize;
39bffca2
AL
799 dc->reset = smc91c111_reset;
800 dc->vmsd = &vmstate_smc91c111;
4f67d30b 801 device_class_set_props(dc, smc91c111_properties);
999e12bb
AL
802}
803
8c43a6f0 804static const TypeInfo smc91c111_info = {
926d152e 805 .name = TYPE_SMC91C111,
39bffca2
AL
806 .parent = TYPE_SYS_BUS_DEVICE,
807 .instance_size = sizeof(smc91c111_state),
808 .class_init = smc91c111_class_init,
50132156
GH
809};
810
83f7d43a 811static void smc91c111_register_types(void)
418dcf5b 812{
39bffca2 813 type_register_static(&smc91c111_info);
418dcf5b
PB
814}
815
816/* Legacy helper function. Should go away when machine config files are
817 implemented. */
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");
926d152e 824 dev = qdev_create(NULL, TYPE_SMC91C111);
50132156 825 qdev_set_nic_properties(dev, nd);
e23a1b33 826 qdev_init_nofail(dev);
1356b98d 827 s = SYS_BUS_DEVICE(dev);
418dcf5b
PB
828 sysbus_mmio_map(s, 0, base);
829 sysbus_connect_irq(s, 0, irq);
830}
831
83f7d43a 832type_init(smc91c111_register_types)