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