2 * Emulation of Allwinner EMAC Fast Ethernet controller and
3 * Realtek RTL8201CP PHY
5 * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
7 * This model is based on reverse-engineering of Linux kernel driver.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
19 #include "hw/sysbus.h"
21 #include "qemu/fifo8.h"
22 #include "hw/net/allwinner_emac.h"
25 static uint8_t padding
[60];
27 static void mii_set_link(RTL8201CPState
*mii
, bool link_ok
)
30 mii
->bmsr
|= MII_BMSR_LINK_ST
| MII_BMSR_AN_COMP
;
31 mii
->anlpar
|= MII_ANAR_TXFD
| MII_ANAR_10FD
| MII_ANAR_10
|
34 mii
->bmsr
&= ~(MII_BMSR_LINK_ST
| MII_BMSR_AN_COMP
);
35 mii
->anlpar
= MII_ANAR_TX
;
39 static void mii_reset(RTL8201CPState
*mii
, bool link_ok
)
41 mii
->bmcr
= MII_BMCR_FD
| MII_BMCR_AUTOEN
| MII_BMCR_SPEED
;
42 mii
->bmsr
= MII_BMSR_100TX_FD
| MII_BMSR_100TX_HD
| MII_BMSR_10T_FD
|
43 MII_BMSR_10T_HD
| MII_BMSR_MFPS
| MII_BMSR_AUTONEG
;
44 mii
->anar
= MII_ANAR_TXFD
| MII_ANAR_TX
| MII_ANAR_10FD
| MII_ANAR_10
|
46 mii
->anlpar
= MII_ANAR_TX
;
48 mii_set_link(mii
, link_ok
);
51 static uint16_t RTL8201CP_mdio_read(AwEmacState
*s
, uint8_t addr
, uint8_t reg
)
53 RTL8201CPState
*mii
= &s
->mii
;
54 uint16_t ret
= 0xffff;
56 if (addr
== s
->phy_addr
) {
63 return RTL8201CP_PHYID1
;
65 return RTL8201CP_PHYID2
;
76 qemu_log_mask(LOG_UNIMP
,
77 "allwinner_emac: read from unimpl. mii reg 0x%x\n",
81 qemu_log_mask(LOG_GUEST_ERROR
,
82 "allwinner_emac: read from invalid mii reg 0x%x\n",
90 static void RTL8201CP_mdio_write(AwEmacState
*s
, uint8_t addr
, uint8_t reg
,
93 RTL8201CPState
*mii
= &s
->mii
;
96 if (addr
== s
->phy_addr
) {
99 if (value
& MII_BMCR_RESET
) {
100 nc
= qemu_get_queue(s
->nic
);
101 mii_reset(mii
, !nc
->link_down
);
114 qemu_log_mask(LOG_GUEST_ERROR
,
115 "allwinner_emac: write to read-only mii reg 0x%x\n",
123 qemu_log_mask(LOG_UNIMP
,
124 "allwinner_emac: write to unimpl. mii reg 0x%x\n",
128 qemu_log_mask(LOG_GUEST_ERROR
,
129 "allwinner_emac: write to invalid mii reg 0x%x\n",
135 static void aw_emac_update_irq(AwEmacState
*s
)
137 qemu_set_irq(s
->irq
, (s
->int_sta
& s
->int_ctl
) != 0);
140 static void aw_emac_tx_reset(AwEmacState
*s
, int chan
)
142 fifo8_reset(&s
->tx_fifo
[chan
]);
143 s
->tx_length
[chan
] = 0;
146 static void aw_emac_rx_reset(AwEmacState
*s
)
148 fifo8_reset(&s
->rx_fifo
);
149 s
->rx_num_packets
= 0;
150 s
->rx_packet_size
= 0;
151 s
->rx_packet_pos
= 0;
154 static void fifo8_push_word(Fifo8
*fifo
, uint32_t val
)
156 fifo8_push(fifo
, val
);
157 fifo8_push(fifo
, val
>> 8);
158 fifo8_push(fifo
, val
>> 16);
159 fifo8_push(fifo
, val
>> 24);
162 static uint32_t fifo8_pop_word(Fifo8
*fifo
)
166 ret
= fifo8_pop(fifo
);
167 ret
|= fifo8_pop(fifo
) << 8;
168 ret
|= fifo8_pop(fifo
) << 16;
169 ret
|= fifo8_pop(fifo
) << 24;
174 static int aw_emac_can_receive(NetClientState
*nc
)
176 AwEmacState
*s
= qemu_get_nic_opaque(nc
);
179 * To avoid packet drops, allow reception only when there is space
180 * for a full frame: 1522 + 8 (rx headers) + 2 (padding).
182 return (s
->ctl
& EMAC_CTL_RX_EN
) && (fifo8_num_free(&s
->rx_fifo
) >= 1532);
185 static ssize_t
aw_emac_receive(NetClientState
*nc
, const uint8_t *buf
,
188 AwEmacState
*s
= qemu_get_nic_opaque(nc
);
189 Fifo8
*fifo
= &s
->rx_fifo
;
190 size_t padded_size
, total_size
;
193 padded_size
= size
> 60 ? size
: 60;
194 total_size
= QEMU_ALIGN_UP(RX_HDR_SIZE
+ padded_size
+ CRC_SIZE
, 4);
196 if (!(s
->ctl
& EMAC_CTL_RX_EN
) || (fifo8_num_free(fifo
) < total_size
)) {
200 fifo8_push_word(fifo
, EMAC_UNDOCUMENTED_MAGIC
);
201 fifo8_push_word(fifo
, EMAC_RX_HEADER(padded_size
+ CRC_SIZE
,
202 EMAC_RX_IO_DATA_STATUS_OK
));
203 fifo8_push_all(fifo
, buf
, size
);
204 crc
= crc32(~0, buf
, size
);
206 if (padded_size
!= size
) {
207 fifo8_push_all(fifo
, padding
, padded_size
- size
);
208 crc
= crc32(crc
, padding
, padded_size
- size
);
211 fifo8_push_word(fifo
, crc
);
212 fifo8_push_all(fifo
, padding
, QEMU_ALIGN_UP(padded_size
, 4) - padded_size
);
215 s
->int_sta
|= EMAC_INT_RX
;
216 aw_emac_update_irq(s
);
221 static void aw_emac_cleanup(NetClientState
*nc
)
223 AwEmacState
*s
= qemu_get_nic_opaque(nc
);
228 static void aw_emac_reset(DeviceState
*dev
)
230 AwEmacState
*s
= AW_EMAC(dev
);
231 NetClientState
*nc
= qemu_get_queue(s
->nic
);
240 aw_emac_tx_reset(s
, 0);
241 aw_emac_tx_reset(s
, 1);
244 mii_reset(&s
->mii
, !nc
->link_down
);
247 static uint64_t aw_emac_read(void *opaque
, hwaddr offset
, unsigned size
)
249 AwEmacState
*s
= opaque
;
250 Fifo8
*fifo
= &s
->rx_fifo
;
257 case EMAC_TX_MODE_REG
:
259 case EMAC_TX_INS_REG
:
260 return s
->tx_channel
;
261 case EMAC_RX_CTL_REG
:
263 case EMAC_RX_IO_DATA_REG
:
264 if (!s
->rx_num_packets
) {
265 qemu_log_mask(LOG_GUEST_ERROR
,
266 "Read IO data register when no packet available");
270 ret
= fifo8_pop_word(fifo
);
272 switch (s
->rx_packet_pos
) {
273 case 0: /* Word is magic header */
274 s
->rx_packet_pos
+= 4;
276 case 4: /* Word is rx info header */
277 s
->rx_packet_pos
+= 4;
278 s
->rx_packet_size
= QEMU_ALIGN_UP(extract32(ret
, 0, 16), 4);
280 default: /* Word is packet data */
281 s
->rx_packet_pos
+= 4;
282 s
->rx_packet_size
-= 4;
284 if (!s
->rx_packet_size
) {
285 s
->rx_packet_pos
= 0;
287 nc
= qemu_get_queue(s
->nic
);
288 if (aw_emac_can_receive(nc
)) {
289 qemu_flush_queued_packets(nc
);
294 case EMAC_RX_FBC_REG
:
295 return s
->rx_num_packets
;
296 case EMAC_INT_CTL_REG
:
298 case EMAC_INT_STA_REG
:
300 case EMAC_MAC_MRDD_REG
:
301 return RTL8201CP_mdio_read(s
,
302 extract32(s
->phy_target
, PHY_ADDR_SHIFT
, 8),
303 extract32(s
->phy_target
, PHY_REG_SHIFT
, 8));
305 qemu_log_mask(LOG_UNIMP
,
306 "allwinner_emac: read access to unknown register 0x"
307 TARGET_FMT_plx
"\n", offset
);
314 static void aw_emac_write(void *opaque
, hwaddr offset
, uint64_t value
,
317 AwEmacState
*s
= opaque
;
319 NetClientState
*nc
= qemu_get_queue(s
->nic
);
324 if (value
& EMAC_CTL_RESET
) {
325 aw_emac_reset(DEVICE(s
));
326 value
&= ~EMAC_CTL_RESET
;
329 if (aw_emac_can_receive(nc
)) {
330 qemu_flush_queued_packets(nc
);
333 case EMAC_TX_MODE_REG
:
336 case EMAC_TX_CTL0_REG
:
337 case EMAC_TX_CTL1_REG
:
338 chan
= (offset
== EMAC_TX_CTL0_REG
? 0 : 1);
339 if ((value
& 1) && (s
->ctl
& EMAC_CTL_TX_EN
)) {
343 fifo
= &s
->tx_fifo
[chan
];
344 len
= s
->tx_length
[chan
];
346 if (len
> fifo8_num_used(fifo
)) {
347 len
= fifo8_num_used(fifo
);
348 qemu_log_mask(LOG_GUEST_ERROR
,
349 "allwinner_emac: TX length > fifo data length\n");
352 data
= fifo8_pop_buf(fifo
, len
, &ret
);
353 qemu_send_packet(nc
, data
, ret
);
354 aw_emac_tx_reset(s
, chan
);
355 /* Raise TX interrupt */
356 s
->int_sta
|= EMAC_INT_TX_CHAN(chan
);
357 aw_emac_update_irq(s
);
361 case EMAC_TX_INS_REG
:
362 s
->tx_channel
= value
< NUM_TX_FIFOS
? value
: 0;
364 case EMAC_TX_PL0_REG
:
365 case EMAC_TX_PL1_REG
:
366 chan
= (offset
== EMAC_TX_PL0_REG
? 0 : 1);
367 if (value
> TX_FIFO_SIZE
) {
368 qemu_log_mask(LOG_GUEST_ERROR
,
369 "allwinner_emac: invalid TX frame length %d\n",
371 value
= TX_FIFO_SIZE
;
373 s
->tx_length
[chan
] = value
;
375 case EMAC_TX_IO_DATA_REG
:
376 fifo
= &s
->tx_fifo
[s
->tx_channel
];
377 if (fifo8_num_free(fifo
) < 4) {
378 qemu_log_mask(LOG_GUEST_ERROR
,
379 "allwinner_emac: TX data overruns fifo\n");
382 fifo8_push_word(fifo
, value
);
384 case EMAC_RX_CTL_REG
:
387 case EMAC_RX_FBC_REG
:
392 case EMAC_INT_CTL_REG
:
394 aw_emac_update_irq(s
);
396 case EMAC_INT_STA_REG
:
397 s
->int_sta
&= ~value
;
398 aw_emac_update_irq(s
);
400 case EMAC_MAC_MADR_REG
:
401 s
->phy_target
= value
;
403 case EMAC_MAC_MWTD_REG
:
404 RTL8201CP_mdio_write(s
, extract32(s
->phy_target
, PHY_ADDR_SHIFT
, 8),
405 extract32(s
->phy_target
, PHY_REG_SHIFT
, 8), value
);
408 qemu_log_mask(LOG_UNIMP
,
409 "allwinner_emac: write access to unknown register 0x"
410 TARGET_FMT_plx
"\n", offset
);
414 static void aw_emac_set_link(NetClientState
*nc
)
416 AwEmacState
*s
= qemu_get_nic_opaque(nc
);
418 mii_set_link(&s
->mii
, !nc
->link_down
);
421 static const MemoryRegionOps aw_emac_mem_ops
= {
422 .read
= aw_emac_read
,
423 .write
= aw_emac_write
,
424 .endianness
= DEVICE_NATIVE_ENDIAN
,
426 .min_access_size
= 4,
427 .max_access_size
= 4,
431 static NetClientInfo net_aw_emac_info
= {
432 .type
= NET_CLIENT_OPTIONS_KIND_NIC
,
433 .size
= sizeof(NICState
),
434 .can_receive
= aw_emac_can_receive
,
435 .receive
= aw_emac_receive
,
436 .cleanup
= aw_emac_cleanup
,
437 .link_status_changed
= aw_emac_set_link
,
440 static void aw_emac_init(Object
*obj
)
442 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
443 AwEmacState
*s
= AW_EMAC(obj
);
445 memory_region_init_io(&s
->iomem
, OBJECT(s
), &aw_emac_mem_ops
, s
,
447 sysbus_init_mmio(sbd
, &s
->iomem
);
448 sysbus_init_irq(sbd
, &s
->irq
);
451 static void aw_emac_realize(DeviceState
*dev
, Error
**errp
)
453 AwEmacState
*s
= AW_EMAC(dev
);
455 qemu_macaddr_default_if_unset(&s
->conf
.macaddr
);
456 s
->nic
= qemu_new_nic(&net_aw_emac_info
, &s
->conf
,
457 object_get_typename(OBJECT(dev
)), dev
->id
, s
);
458 qemu_format_nic_info_str(qemu_get_queue(s
->nic
), s
->conf
.macaddr
.a
);
460 fifo8_create(&s
->rx_fifo
, RX_FIFO_SIZE
);
461 fifo8_create(&s
->tx_fifo
[0], TX_FIFO_SIZE
);
462 fifo8_create(&s
->tx_fifo
[1], TX_FIFO_SIZE
);
465 static Property aw_emac_properties
[] = {
466 DEFINE_NIC_PROPERTIES(AwEmacState
, conf
),
467 DEFINE_PROP_UINT8("phy-addr", AwEmacState
, phy_addr
, 0),
468 DEFINE_PROP_END_OF_LIST(),
471 static const VMStateDescription vmstate_mii
= {
474 .minimum_version_id
= 1,
475 .fields
= (VMStateField
[]) {
476 VMSTATE_UINT16(bmcr
, RTL8201CPState
),
477 VMSTATE_UINT16(bmsr
, RTL8201CPState
),
478 VMSTATE_UINT16(anar
, RTL8201CPState
),
479 VMSTATE_UINT16(anlpar
, RTL8201CPState
),
480 VMSTATE_END_OF_LIST()
484 static int aw_emac_post_load(void *opaque
, int version_id
)
486 AwEmacState
*s
= opaque
;
488 aw_emac_set_link(qemu_get_queue(s
->nic
));
493 static const VMStateDescription vmstate_aw_emac
= {
494 .name
= "allwinner_emac",
496 .minimum_version_id
= 1,
497 .post_load
= aw_emac_post_load
,
498 .fields
= (VMStateField
[]) {
499 VMSTATE_STRUCT(mii
, AwEmacState
, 1, vmstate_mii
, RTL8201CPState
),
500 VMSTATE_UINT32(ctl
, AwEmacState
),
501 VMSTATE_UINT32(tx_mode
, AwEmacState
),
502 VMSTATE_UINT32(rx_ctl
, AwEmacState
),
503 VMSTATE_UINT32(int_ctl
, AwEmacState
),
504 VMSTATE_UINT32(int_sta
, AwEmacState
),
505 VMSTATE_UINT32(phy_target
, AwEmacState
),
506 VMSTATE_FIFO8(rx_fifo
, AwEmacState
),
507 VMSTATE_UINT32(rx_num_packets
, AwEmacState
),
508 VMSTATE_UINT32(rx_packet_size
, AwEmacState
),
509 VMSTATE_UINT32(rx_packet_pos
, AwEmacState
),
510 VMSTATE_STRUCT_ARRAY(tx_fifo
, AwEmacState
, NUM_TX_FIFOS
, 1,
511 vmstate_fifo8
, Fifo8
),
512 VMSTATE_UINT32_ARRAY(tx_length
, AwEmacState
, NUM_TX_FIFOS
),
513 VMSTATE_UINT32(tx_channel
, AwEmacState
),
514 VMSTATE_END_OF_LIST()
518 static void aw_emac_class_init(ObjectClass
*klass
, void *data
)
520 DeviceClass
*dc
= DEVICE_CLASS(klass
);
522 dc
->realize
= aw_emac_realize
;
523 dc
->props
= aw_emac_properties
;
524 dc
->reset
= aw_emac_reset
;
525 dc
->vmsd
= &vmstate_aw_emac
;
528 static const TypeInfo aw_emac_info
= {
529 .name
= TYPE_AW_EMAC
,
530 .parent
= TYPE_SYS_BUS_DEVICE
,
531 .instance_size
= sizeof(AwEmacState
),
532 .instance_init
= aw_emac_init
,
533 .class_init
= aw_emac_class_init
,
536 static void aw_emac_register_types(void)
538 type_register_static(&aw_emac_info
);
541 type_init(aw_emac_register_types
)