2 * SMSC 91C111 Ethernet interface emulation
4 * Copyright (c) 2005 CodeSourcery, LLC.
5 * Written by Paul Brook
7 * This code is licensed under the GPL
10 #include "qemu/osdep.h"
11 #include "hw/sysbus.h"
13 #include "hw/net/smc91c111.h"
15 #include "qemu/module.h"
19 /* Number of 2k memory pages available. */
22 #define TYPE_SMC91C111 "smc91c111"
23 #define SMC91C111(obj) OBJECT_CHECK(smc91c111_state, (obj), TYPE_SMC91C111)
26 SysBusDevice parent_obj
;
41 /* Bitmask of allocated packets. */
44 int tx_fifo
[NUM_PACKETS
];
46 int rx_fifo
[NUM_PACKETS
];
48 int tx_fifo_done
[NUM_PACKETS
];
49 /* Packet buffer memory. */
50 uint8_t data
[NUM_PACKETS
][2048];
56 static const VMStateDescription vmstate_smc91c111
= {
59 .minimum_version_id
= 1,
60 .fields
= (VMStateField
[]) {
61 VMSTATE_UINT16(tcr
, smc91c111_state
),
62 VMSTATE_UINT16(rcr
, smc91c111_state
),
63 VMSTATE_UINT16(cr
, smc91c111_state
),
64 VMSTATE_UINT16(ctr
, smc91c111_state
),
65 VMSTATE_UINT16(gpr
, smc91c111_state
),
66 VMSTATE_UINT16(ptr
, smc91c111_state
),
67 VMSTATE_UINT16(ercv
, smc91c111_state
),
68 VMSTATE_INT32(bank
, smc91c111_state
),
69 VMSTATE_INT32(packet_num
, smc91c111_state
),
70 VMSTATE_INT32(tx_alloc
, smc91c111_state
),
71 VMSTATE_INT32(allocated
, smc91c111_state
),
72 VMSTATE_INT32(tx_fifo_len
, smc91c111_state
),
73 VMSTATE_INT32_ARRAY(tx_fifo
, smc91c111_state
, NUM_PACKETS
),
74 VMSTATE_INT32(rx_fifo_len
, smc91c111_state
),
75 VMSTATE_INT32_ARRAY(rx_fifo
, smc91c111_state
, NUM_PACKETS
),
76 VMSTATE_INT32(tx_fifo_done_len
, smc91c111_state
),
77 VMSTATE_INT32_ARRAY(tx_fifo_done
, smc91c111_state
, NUM_PACKETS
),
78 VMSTATE_BUFFER_UNSAFE(data
, smc91c111_state
, 0, NUM_PACKETS
* 2048),
79 VMSTATE_UINT8(int_level
, smc91c111_state
),
80 VMSTATE_UINT8(int_mask
, smc91c111_state
),
85 #define RCR_SOFT_RST 0x8000
86 #define RCR_STRIP_CRC 0x0200
87 #define RCR_RXEN 0x0100
89 #define TCR_EPH_LOOP 0x2000
90 #define TCR_NOCRC 0x0100
91 #define TCR_PAD_EN 0x0080
92 #define TCR_FORCOL 0x0004
93 #define TCR_LOOP 0x0002
94 #define TCR_TXEN 0x0001
99 #define INT_RX_OVRN 0x10
100 #define INT_ALLOC 0x08
101 #define INT_TX_EMPTY 0x04
105 #define CTR_AUTO_RELEASE 0x0800
106 #define CTR_RELOAD 0x0002
107 #define CTR_STORE 0x0001
109 #define RS_ALGNERR 0x8000
110 #define RS_BRODCAST 0x4000
111 #define RS_BADCRC 0x2000
112 #define RS_ODDFRAME 0x1000
113 #define RS_TOOLONG 0x0800
114 #define RS_TOOSHORT 0x0400
115 #define RS_MULTICAST 0x0001
117 /* Update interrupt status. */
118 static void smc91c111_update(smc91c111_state
*s
)
122 if (s
->tx_fifo_len
== 0)
123 s
->int_level
|= INT_TX_EMPTY
;
124 if (s
->tx_fifo_done_len
!= 0)
125 s
->int_level
|= INT_TX
;
126 level
= (s
->int_level
& s
->int_mask
) != 0;
127 qemu_set_irq(s
->irq
, level
);
130 static int smc91c111_can_receive(smc91c111_state
*s
)
132 if ((s
->rcr
& RCR_RXEN
) == 0 || (s
->rcr
& RCR_SOFT_RST
)) {
135 if (s
->allocated
== (1 << NUM_PACKETS
) - 1 ||
136 s
->rx_fifo_len
== NUM_PACKETS
) {
142 static inline void smc91c111_flush_queued_packets(smc91c111_state
*s
)
144 if (smc91c111_can_receive(s
)) {
145 qemu_flush_queued_packets(qemu_get_queue(s
->nic
));
149 /* Try to allocate a packet. Returns 0x80 on failure. */
150 static int smc91c111_allocate_packet(smc91c111_state
*s
)
153 if (s
->allocated
== (1 << NUM_PACKETS
) - 1) {
157 for (i
= 0; i
< NUM_PACKETS
; i
++) {
158 if ((s
->allocated
& (1 << i
)) == 0)
161 s
->allocated
|= 1 << i
;
166 /* Process a pending TX allocate. */
167 static void smc91c111_tx_alloc(smc91c111_state
*s
)
169 s
->tx_alloc
= smc91c111_allocate_packet(s
);
170 if (s
->tx_alloc
== 0x80)
172 s
->int_level
|= INT_ALLOC
;
176 /* Remove and item from the RX FIFO. */
177 static void smc91c111_pop_rx_fifo(smc91c111_state
*s
)
182 if (s
->rx_fifo_len
) {
183 for (i
= 0; i
< s
->rx_fifo_len
; i
++)
184 s
->rx_fifo
[i
] = s
->rx_fifo
[i
+ 1];
185 s
->int_level
|= INT_RCV
;
187 s
->int_level
&= ~INT_RCV
;
189 smc91c111_flush_queued_packets(s
);
193 /* Remove an item from the TX completion FIFO. */
194 static void smc91c111_pop_tx_fifo_done(smc91c111_state
*s
)
198 if (s
->tx_fifo_done_len
== 0)
200 s
->tx_fifo_done_len
--;
201 for (i
= 0; i
< s
->tx_fifo_done_len
; i
++)
202 s
->tx_fifo_done
[i
] = s
->tx_fifo_done
[i
+ 1];
205 /* Release the memory allocated to a packet. */
206 static void smc91c111_release_packet(smc91c111_state
*s
, int packet
)
208 s
->allocated
&= ~(1 << packet
);
209 if (s
->tx_alloc
== 0x80)
210 smc91c111_tx_alloc(s
);
211 smc91c111_flush_queued_packets(s
);
214 /* Flush the TX FIFO. */
215 static void smc91c111_do_tx(smc91c111_state
*s
)
223 if ((s
->tcr
& TCR_TXEN
) == 0)
225 if (s
->tx_fifo_len
== 0)
227 for (i
= 0; i
< s
->tx_fifo_len
; i
++) {
228 packetnum
= s
->tx_fifo
[i
];
229 p
= &s
->data
[packetnum
][0];
230 /* Set status word. */
234 len
|= ((int)*(p
++)) << 8;
236 control
= p
[len
+ 1];
239 /* ??? This overwrites the data following the buffer.
240 Don't know what real hardware does. */
241 if (len
< 64 && (s
->tcr
& TCR_PAD_EN
)) {
242 memset(p
+ len
, 0, 64 - len
);
249 /* The card is supposed to append the CRC to the frame.
250 However none of the other network traffic has the CRC
251 appended. Suspect this is low level ethernet detail we
252 don't need to worry about. */
253 add_crc
= (control
& 0x10) || (s
->tcr
& TCR_NOCRC
) == 0;
257 crc
= crc32(~0, p
, len
);
258 memcpy(p
+ len
, &crc
, 4);
263 if (s
->ctr
& CTR_AUTO_RELEASE
)
265 smc91c111_release_packet(s
, packetnum
);
266 else if (s
->tx_fifo_done_len
< NUM_PACKETS
)
267 s
->tx_fifo_done
[s
->tx_fifo_done_len
++] = packetnum
;
268 qemu_send_packet(qemu_get_queue(s
->nic
), p
, len
);
274 /* Add a packet to the TX FIFO. */
275 static void smc91c111_queue_tx(smc91c111_state
*s
, int packet
)
277 if (s
->tx_fifo_len
== NUM_PACKETS
)
279 s
->tx_fifo
[s
->tx_fifo_len
++] = packet
;
283 static void smc91c111_reset(DeviceState
*dev
)
285 smc91c111_state
*s
= SMC91C111(dev
);
289 s
->tx_fifo_done_len
= 0;
300 s
->int_level
= INT_TX_EMPTY
;
305 #define SET_LOW(name, val) s->name = (s->name & 0xff00) | val
306 #define SET_HIGH(name, val) s->name = (s->name & 0xff) | (val << 8)
308 static void smc91c111_writeb(void *opaque
, hwaddr offset
,
311 smc91c111_state
*s
= (smc91c111_state
*)opaque
;
313 offset
= offset
& 0xf;
327 SET_HIGH(tcr
, value
);
333 SET_HIGH(rcr
, value
);
334 if (s
->rcr
& RCR_SOFT_RST
) {
335 smc91c111_reset(DEVICE(s
));
337 smc91c111_flush_queued_packets(s
);
339 case 10: case 11: /* RPCR */
342 case 12: case 13: /* Reserved */
355 case 2: case 3: /* BASE */
356 case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
357 /* Not implemented. */
359 case 10: /* Genral Purpose */
363 SET_HIGH(gpr
, value
);
365 case 12: /* Control */
367 qemu_log_mask(LOG_UNIMP
,
368 "smc91c111: EEPROM store not implemented\n");
371 qemu_log_mask(LOG_UNIMP
,
372 "smc91c111: EEPROM reload not implemented\n");
378 SET_HIGH(ctr
, value
);
385 case 0: /* MMU Command */
386 switch (value
>> 5) {
389 case 1: /* Allocate for TX. */
391 s
->int_level
&= ~INT_ALLOC
;
393 smc91c111_tx_alloc(s
);
395 case 2: /* Reset MMU. */
398 s
->tx_fifo_done_len
= 0;
402 case 3: /* Remove from RX FIFO. */
403 smc91c111_pop_rx_fifo(s
);
405 case 4: /* Remove from RX FIFO and release. */
406 if (s
->rx_fifo_len
> 0) {
407 smc91c111_release_packet(s
, s
->rx_fifo
[0]);
409 smc91c111_pop_rx_fifo(s
);
411 case 5: /* Release. */
412 smc91c111_release_packet(s
, s
->packet_num
);
414 case 6: /* Add to TX FIFO. */
415 smc91c111_queue_tx(s
, s
->packet_num
);
417 case 7: /* Reset TX FIFO. */
419 s
->tx_fifo_done_len
= 0;
426 case 2: /* Packet Number Register */
427 s
->packet_num
= value
;
429 case 3: case 4: case 5:
430 /* Should be readonly, but linux writes to them anyway. Ignore. */
432 case 6: /* Pointer */
436 SET_HIGH(ptr
, value
);
438 case 8: case 9: case 10: case 11: /* Data */
448 if (s
->ptr
& 0x4000) {
449 s
->ptr
= (s
->ptr
& 0xf800) | ((s
->ptr
+ 1) & 0x7ff);
453 s
->data
[n
][p
] = value
;
456 case 12: /* Interrupt ACK. */
457 s
->int_level
&= ~(value
& 0xd6);
459 smc91c111_pop_tx_fifo_done(s
);
462 case 13: /* Interrupt mask. */
471 case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
472 /* Multicast table. */
473 /* Not implemented. */
475 case 8: case 9: /* Management Interface. */
476 /* Not implemented. */
478 case 12: /* Early receive. */
479 s
->ercv
= value
& 0x1f;
487 qemu_log_mask(LOG_GUEST_ERROR
, "smc91c111_write(bank:%d) Illegal register"
488 " 0x%" HWADDR_PRIx
" = 0x%x\n",
489 s
->bank
, offset
, value
);
492 static uint32_t smc91c111_readb(void *opaque
, hwaddr offset
)
494 smc91c111_state
*s
= (smc91c111_state
*)opaque
;
496 offset
= offset
& 0xf;
506 return s
->tcr
& 0xff;
509 case 2: /* EPH Status */
514 return s
->rcr
& 0xff;
517 case 6: /* Counter */
519 /* Not implemented. */
521 case 8: /* Memory size. */
523 case 9: /* Free memory available. */
528 for (i
= 0; i
< NUM_PACKETS
; i
++) {
529 if (s
->allocated
& (1 << i
))
534 case 10: case 11: /* RPCR */
535 /* Not implemented. */
537 case 12: case 13: /* Reserved */
548 case 2: case 3: /* BASE */
549 /* Not implemented. */
551 case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
552 return s
->conf
.macaddr
.a
[offset
- 4];
553 case 10: /* General Purpose */
554 return s
->gpr
& 0xff;
557 case 12: /* Control */
558 return s
->ctr
& 0xff;
566 case 0: case 1: /* MMUCR Busy bit. */
568 case 2: /* Packet Number. */
569 return s
->packet_num
;
570 case 3: /* Allocation Result. */
572 case 4: /* TX FIFO */
573 if (s
->tx_fifo_done_len
== 0)
576 return s
->tx_fifo_done
[0];
577 case 5: /* RX FIFO */
578 if (s
->rx_fifo_len
== 0)
581 return s
->rx_fifo
[0];
582 case 6: /* Pointer */
583 return s
->ptr
& 0xff;
585 return (s
->ptr
>> 8) & 0xf7;
586 case 8: case 9: case 10: case 11: /* Data */
596 if (s
->ptr
& 0x4000) {
597 s
->ptr
= (s
->ptr
& 0xf800) | ((s
->ptr
+ 1) & 0x07ff);
601 return s
->data
[n
][p
];
603 case 12: /* Interrupt status. */
605 case 13: /* Interrupt mask. */
612 case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
613 /* Multicast table. */
614 /* Not implemented. */
616 case 8: /* Management Interface. */
617 /* Not implemented. */
621 case 10: /* Revision. */
632 qemu_log_mask(LOG_GUEST_ERROR
, "smc91c111_read(bank:%d) Illegal register"
633 " 0x%" HWADDR_PRIx
"\n",
638 static uint64_t smc91c111_readfn(void *opaque
, hwaddr addr
, unsigned size
)
643 for (i
= 0; i
< size
; i
++) {
644 val
|= smc91c111_readb(opaque
, addr
+ i
) << (i
* 8);
649 static void smc91c111_writefn(void *opaque
, hwaddr addr
,
650 uint64_t value
, unsigned size
)
654 /* 32-bit writes to offset 0xc only actually write to the bank select
655 * register (offset 0xe), so skip the first two bytes we would write.
657 if (addr
== 0xc && size
== 4) {
661 for (; i
< size
; i
++) {
662 smc91c111_writeb(opaque
, addr
+ i
,
663 extract32(value
, i
* 8, 8));
667 static int smc91c111_can_receive_nc(NetClientState
*nc
)
669 smc91c111_state
*s
= qemu_get_nic_opaque(nc
);
671 return smc91c111_can_receive(s
);
674 static ssize_t
smc91c111_receive(NetClientState
*nc
, const uint8_t *buf
, size_t size
)
676 smc91c111_state
*s
= qemu_get_nic_opaque(nc
);
683 if ((s
->rcr
& RCR_RXEN
) == 0 || (s
->rcr
& RCR_SOFT_RST
))
685 /* Short packets are padded with zeros. Receiving a packet
686 < 64 bytes long is considered an error condition. */
690 packetsize
= (size
& ~1);
692 crc
= (s
->rcr
& RCR_STRIP_CRC
) == 0;
695 /* TODO: Flag overrun and receive errors. */
696 if (packetsize
> 2048)
698 packetnum
= smc91c111_allocate_packet(s
);
699 if (packetnum
== 0x80)
701 s
->rx_fifo
[s
->rx_fifo_len
++] = packetnum
;
703 p
= &s
->data
[packetnum
][0];
704 /* ??? Multicast packets? */
707 status
|= RS_TOOLONG
;
709 status
|= RS_ODDFRAME
;
710 *(p
++) = status
& 0xff;
711 *(p
++) = status
>> 8;
712 *(p
++) = packetsize
& 0xff;
713 *(p
++) = packetsize
>> 8;
714 memcpy(p
, buf
, size
& ~1);
716 /* Pad short packets. */
721 *(p
++) = buf
[size
- 1];
727 /* It's not clear if the CRC should go before or after the last byte in
728 odd sized packets. Linux disables the CRC, so that's no help.
729 The pictures in the documentation show the CRC aligned on a 16-bit
730 boundary before the last odd byte, so that's what we do. */
732 crc
= crc32(~0, buf
, size
);
733 *(p
++) = crc
& 0xff; crc
>>= 8;
734 *(p
++) = crc
& 0xff; crc
>>= 8;
735 *(p
++) = crc
& 0xff; crc
>>= 8;
739 *(p
++) = buf
[size
- 1];
745 /* TODO: Raise early RX interrupt? */
746 s
->int_level
|= INT_RCV
;
752 static const MemoryRegionOps smc91c111_mem_ops
= {
753 /* The special case for 32 bit writes to 0xc means we can't just
754 * set .impl.min/max_access_size to 1, unfortunately
756 .read
= smc91c111_readfn
,
757 .write
= smc91c111_writefn
,
758 .valid
.min_access_size
= 1,
759 .valid
.max_access_size
= 4,
760 .endianness
= DEVICE_NATIVE_ENDIAN
,
763 static NetClientInfo net_smc91c111_info
= {
764 .type
= NET_CLIENT_DRIVER_NIC
,
765 .size
= sizeof(NICState
),
766 .can_receive
= smc91c111_can_receive_nc
,
767 .receive
= smc91c111_receive
,
770 static void smc91c111_realize(DeviceState
*dev
, Error
**errp
)
772 SysBusDevice
*sbd
= SYS_BUS_DEVICE(dev
);
773 smc91c111_state
*s
= SMC91C111(dev
);
775 memory_region_init_io(&s
->mmio
, OBJECT(s
), &smc91c111_mem_ops
, s
,
776 "smc91c111-mmio", 16);
777 sysbus_init_mmio(sbd
, &s
->mmio
);
778 sysbus_init_irq(sbd
, &s
->irq
);
779 qemu_macaddr_default_if_unset(&s
->conf
.macaddr
);
780 s
->nic
= qemu_new_nic(&net_smc91c111_info
, &s
->conf
,
781 object_get_typename(OBJECT(dev
)), dev
->id
, s
);
782 qemu_format_nic_info_str(qemu_get_queue(s
->nic
), s
->conf
.macaddr
.a
);
783 /* ??? Save/restore. */
786 static Property smc91c111_properties
[] = {
787 DEFINE_NIC_PROPERTIES(smc91c111_state
, conf
),
788 DEFINE_PROP_END_OF_LIST(),
791 static void smc91c111_class_init(ObjectClass
*klass
, void *data
)
793 DeviceClass
*dc
= DEVICE_CLASS(klass
);
795 dc
->realize
= smc91c111_realize
;
796 dc
->reset
= smc91c111_reset
;
797 dc
->vmsd
= &vmstate_smc91c111
;
798 dc
->props
= smc91c111_properties
;
801 static const TypeInfo smc91c111_info
= {
802 .name
= TYPE_SMC91C111
,
803 .parent
= TYPE_SYS_BUS_DEVICE
,
804 .instance_size
= sizeof(smc91c111_state
),
805 .class_init
= smc91c111_class_init
,
808 static void smc91c111_register_types(void)
810 type_register_static(&smc91c111_info
);
813 /* Legacy helper function. Should go away when machine config files are
815 void smc91c111_init(NICInfo
*nd
, uint32_t base
, qemu_irq irq
)
820 qemu_check_nic_model(nd
, "smc91c111");
821 dev
= qdev_create(NULL
, TYPE_SMC91C111
);
822 qdev_set_nic_properties(dev
, nd
);
823 qdev_init_nofail(dev
);
824 s
= SYS_BUS_DEVICE(dev
);
825 sysbus_mmio_map(s
, 0, base
);
826 sysbus_connect_irq(s
, 0, irq
);
829 type_init(smc91c111_register_types
)