qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

hw/arm/allwinner-h3: add EMAC ethernet device

The Allwinner Sun8i System on Chip family includes an Ethernet MAC (EMAC)
which provides 10M/100M/1000M Ethernet connectivity. This commit
adds support for the Allwinner EMAC from the Sun8i family (H2+, H3, A33, etc),
including emulation for the following functionality:

* DMA transfers
* MII interface
* Transmit CRC calculation

Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Message-id: 20200311221854.30370-10-nieklinnenbank@gmail.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

authored by

Niek Linnenbank and committed by
Peter Maydell
29d08975 82e48382

+1006 -1
+1
hw/arm/Kconfig
··· 300 300 config ALLWINNER_H3 301 301 bool 302 302 select ALLWINNER_A10_PIT 303 + select ALLWINNER_SUN8I_EMAC 303 304 select SERIAL 304 305 select ARM_TIMER 305 306 select ARM_GIC
+15 -1
hw/arm/allwinner-h3.c
··· 54 54 [AW_H3_UART1] = 0x01c28400, 55 55 [AW_H3_UART2] = 0x01c28800, 56 56 [AW_H3_UART3] = 0x01c28c00, 57 + [AW_H3_EMAC] = 0x01c30000, 57 58 [AW_H3_GIC_DIST] = 0x01c81000, 58 59 [AW_H3_GIC_CPU] = 0x01c82000, 59 60 [AW_H3_GIC_HYP] = 0x01c84000, ··· 106 107 { "twi1", 0x01c2b000, 1 * KiB }, 107 108 { "twi2", 0x01c2b400, 1 * KiB }, 108 109 { "scr", 0x01c2c400, 1 * KiB }, 109 - { "emac", 0x01c30000, 64 * KiB }, 110 110 { "gpu", 0x01c40000, 64 * KiB }, 111 111 { "hstmr", 0x01c60000, 4 * KiB }, 112 112 { "dramcom", 0x01c62000, 4 * KiB }, ··· 162 162 AW_H3_GIC_SPI_OHCI2 = 77, 163 163 AW_H3_GIC_SPI_EHCI3 = 78, 164 164 AW_H3_GIC_SPI_OHCI3 = 79, 165 + AW_H3_GIC_SPI_EMAC = 82 165 166 }; 166 167 167 168 /* Allwinner H3 general constants */ ··· 207 208 208 209 sysbus_init_child_obj(obj, "mmc0", &s->mmc0, sizeof(s->mmc0), 209 210 TYPE_AW_SDHOST_SUN5I); 211 + 212 + sysbus_init_child_obj(obj, "emac", &s->emac, sizeof(s->emac), 213 + TYPE_AW_SUN8I_EMAC); 210 214 } 211 215 212 216 static void allwinner_h3_realize(DeviceState *dev, Error **errp) ··· 336 340 337 341 object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->mmc0), 338 342 "sd-bus", &error_abort); 343 + 344 + /* EMAC */ 345 + if (nd_table[0].used) { 346 + qemu_check_nic_model(&nd_table[0], TYPE_AW_SUN8I_EMAC); 347 + qdev_set_nic_properties(DEVICE(&s->emac), &nd_table[0]); 348 + } 349 + qdev_init_nofail(DEVICE(&s->emac)); 350 + sysbus_mmio_map(SYS_BUS_DEVICE(&s->emac), 0, s->memmap[AW_H3_EMAC]); 351 + sysbus_connect_irq(SYS_BUS_DEVICE(&s->emac), 0, 352 + qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_EMAC)); 339 353 340 354 /* Universal Serial Bus */ 341 355 sysbus_create_simple(TYPE_AW_H3_EHCI, s->memmap[AW_H3_EHCI0],
+3
hw/arm/orangepi.c
··· 77 77 warn_report("Security Identifier value does not include H3 prefix"); 78 78 } 79 79 80 + /* Setup EMAC properties */ 81 + object_property_set_int(OBJECT(&h3->emac), 1, "phy-addr", &error_abort); 82 + 80 83 /* Mark H3 object realized */ 81 84 object_property_set_bool(OBJECT(h3), true, "realized", &error_abort); 82 85
+3
hw/net/Kconfig
··· 79 79 config ALLWINNER_EMAC 80 80 bool 81 81 82 + config ALLWINNER_SUN8I_EMAC 83 + bool 84 + 82 85 config IMX_FEC 83 86 bool 84 87
+1
hw/net/Makefile.objs
··· 23 23 common-obj-$(CONFIG_MIPSNET) += mipsnet.o 24 24 common-obj-$(CONFIG_XILINX_AXI) += xilinx_axienet.o 25 25 common-obj-$(CONFIG_ALLWINNER_EMAC) += allwinner_emac.o 26 + common-obj-$(CONFIG_ALLWINNER_SUN8I_EMAC) += allwinner-sun8i-emac.o 26 27 common-obj-$(CONFIG_IMX_FEC) += imx_fec.o 27 28 28 29 common-obj-$(CONFIG_CADENCE) += cadence_gem.o
+871
hw/net/allwinner-sun8i-emac.c
··· 1 + /* 2 + * Allwinner Sun8i Ethernet MAC emulation 3 + * 4 + * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com> 5 + * 6 + * This program is free software: you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation, either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #include "qemu/osdep.h" 21 + #include "qemu/units.h" 22 + #include "hw/sysbus.h" 23 + #include "migration/vmstate.h" 24 + #include "net/net.h" 25 + #include "hw/irq.h" 26 + #include "hw/qdev-properties.h" 27 + #include "qemu/log.h" 28 + #include "trace.h" 29 + #include "net/checksum.h" 30 + #include "qemu/module.h" 31 + #include "exec/cpu-common.h" 32 + #include "hw/net/allwinner-sun8i-emac.h" 33 + 34 + /* EMAC register offsets */ 35 + enum { 36 + REG_BASIC_CTL_0 = 0x0000, /* Basic Control 0 */ 37 + REG_BASIC_CTL_1 = 0x0004, /* Basic Control 1 */ 38 + REG_INT_STA = 0x0008, /* Interrupt Status */ 39 + REG_INT_EN = 0x000C, /* Interrupt Enable */ 40 + REG_TX_CTL_0 = 0x0010, /* Transmit Control 0 */ 41 + REG_TX_CTL_1 = 0x0014, /* Transmit Control 1 */ 42 + REG_TX_FLOW_CTL = 0x001C, /* Transmit Flow Control */ 43 + REG_TX_DMA_DESC_LIST = 0x0020, /* Transmit Descriptor List Address */ 44 + REG_RX_CTL_0 = 0x0024, /* Receive Control 0 */ 45 + REG_RX_CTL_1 = 0x0028, /* Receive Control 1 */ 46 + REG_RX_DMA_DESC_LIST = 0x0034, /* Receive Descriptor List Address */ 47 + REG_FRM_FLT = 0x0038, /* Receive Frame Filter */ 48 + REG_RX_HASH_0 = 0x0040, /* Receive Hash Table 0 */ 49 + REG_RX_HASH_1 = 0x0044, /* Receive Hash Table 1 */ 50 + REG_MII_CMD = 0x0048, /* Management Interface Command */ 51 + REG_MII_DATA = 0x004C, /* Management Interface Data */ 52 + REG_ADDR_HIGH = 0x0050, /* MAC Address High */ 53 + REG_ADDR_LOW = 0x0054, /* MAC Address Low */ 54 + REG_TX_DMA_STA = 0x00B0, /* Transmit DMA Status */ 55 + REG_TX_CUR_DESC = 0x00B4, /* Transmit Current Descriptor */ 56 + REG_TX_CUR_BUF = 0x00B8, /* Transmit Current Buffer */ 57 + REG_RX_DMA_STA = 0x00C0, /* Receive DMA Status */ 58 + REG_RX_CUR_DESC = 0x00C4, /* Receive Current Descriptor */ 59 + REG_RX_CUR_BUF = 0x00C8, /* Receive Current Buffer */ 60 + REG_RGMII_STA = 0x00D0, /* RGMII Status */ 61 + }; 62 + 63 + /* EMAC register flags */ 64 + enum { 65 + BASIC_CTL0_100Mbps = (0b11 << 2), 66 + BASIC_CTL0_FD = (1 << 0), 67 + BASIC_CTL1_SOFTRST = (1 << 0), 68 + }; 69 + 70 + enum { 71 + INT_STA_RGMII_LINK = (1 << 16), 72 + INT_STA_RX_EARLY = (1 << 13), 73 + INT_STA_RX_OVERFLOW = (1 << 12), 74 + INT_STA_RX_TIMEOUT = (1 << 11), 75 + INT_STA_RX_DMA_STOP = (1 << 10), 76 + INT_STA_RX_BUF_UA = (1 << 9), 77 + INT_STA_RX = (1 << 8), 78 + INT_STA_TX_EARLY = (1 << 5), 79 + INT_STA_TX_UNDERFLOW = (1 << 4), 80 + INT_STA_TX_TIMEOUT = (1 << 3), 81 + INT_STA_TX_BUF_UA = (1 << 2), 82 + INT_STA_TX_DMA_STOP = (1 << 1), 83 + INT_STA_TX = (1 << 0), 84 + }; 85 + 86 + enum { 87 + INT_EN_RX_EARLY = (1 << 13), 88 + INT_EN_RX_OVERFLOW = (1 << 12), 89 + INT_EN_RX_TIMEOUT = (1 << 11), 90 + INT_EN_RX_DMA_STOP = (1 << 10), 91 + INT_EN_RX_BUF_UA = (1 << 9), 92 + INT_EN_RX = (1 << 8), 93 + INT_EN_TX_EARLY = (1 << 5), 94 + INT_EN_TX_UNDERFLOW = (1 << 4), 95 + INT_EN_TX_TIMEOUT = (1 << 3), 96 + INT_EN_TX_BUF_UA = (1 << 2), 97 + INT_EN_TX_DMA_STOP = (1 << 1), 98 + INT_EN_TX = (1 << 0), 99 + }; 100 + 101 + enum { 102 + TX_CTL0_TX_EN = (1 << 31), 103 + TX_CTL1_TX_DMA_START = (1 << 31), 104 + TX_CTL1_TX_DMA_EN = (1 << 30), 105 + TX_CTL1_TX_FLUSH = (1 << 0), 106 + }; 107 + 108 + enum { 109 + RX_CTL0_RX_EN = (1 << 31), 110 + RX_CTL0_STRIP_FCS = (1 << 28), 111 + RX_CTL0_CRC_IPV4 = (1 << 27), 112 + }; 113 + 114 + enum { 115 + RX_CTL1_RX_DMA_START = (1 << 31), 116 + RX_CTL1_RX_DMA_EN = (1 << 30), 117 + RX_CTL1_RX_MD = (1 << 1), 118 + }; 119 + 120 + enum { 121 + RX_FRM_FLT_DIS_ADDR = (1 << 31), 122 + }; 123 + 124 + enum { 125 + MII_CMD_PHY_ADDR_SHIFT = (12), 126 + MII_CMD_PHY_ADDR_MASK = (0xf000), 127 + MII_CMD_PHY_REG_SHIFT = (4), 128 + MII_CMD_PHY_REG_MASK = (0xf0), 129 + MII_CMD_PHY_RW = (1 << 1), 130 + MII_CMD_PHY_BUSY = (1 << 0), 131 + }; 132 + 133 + enum { 134 + TX_DMA_STA_STOP = (0b000), 135 + TX_DMA_STA_RUN_FETCH = (0b001), 136 + TX_DMA_STA_WAIT_STA = (0b010), 137 + }; 138 + 139 + enum { 140 + RX_DMA_STA_STOP = (0b000), 141 + RX_DMA_STA_RUN_FETCH = (0b001), 142 + RX_DMA_STA_WAIT_FRM = (0b011), 143 + }; 144 + 145 + /* EMAC register reset values */ 146 + enum { 147 + REG_BASIC_CTL_1_RST = 0x08000000, 148 + }; 149 + 150 + /* EMAC constants */ 151 + enum { 152 + AW_SUN8I_EMAC_MIN_PKT_SZ = 64 153 + }; 154 + 155 + /* Transmit/receive frame descriptor */ 156 + typedef struct FrameDescriptor { 157 + uint32_t status; 158 + uint32_t status2; 159 + uint32_t addr; 160 + uint32_t next; 161 + } FrameDescriptor; 162 + 163 + /* Frame descriptor flags */ 164 + enum { 165 + DESC_STATUS_CTL = (1 << 31), 166 + DESC_STATUS2_BUF_SIZE_MASK = (0x7ff), 167 + }; 168 + 169 + /* Transmit frame descriptor flags */ 170 + enum { 171 + TX_DESC_STATUS_LENGTH_ERR = (1 << 14), 172 + TX_DESC_STATUS2_FIRST_DESC = (1 << 29), 173 + TX_DESC_STATUS2_LAST_DESC = (1 << 30), 174 + TX_DESC_STATUS2_CHECKSUM_MASK = (0x3 << 27), 175 + }; 176 + 177 + /* Receive frame descriptor flags */ 178 + enum { 179 + RX_DESC_STATUS_FIRST_DESC = (1 << 9), 180 + RX_DESC_STATUS_LAST_DESC = (1 << 8), 181 + RX_DESC_STATUS_FRM_LEN_MASK = (0x3fff0000), 182 + RX_DESC_STATUS_FRM_LEN_SHIFT = (16), 183 + RX_DESC_STATUS_NO_BUF = (1 << 14), 184 + RX_DESC_STATUS_HEADER_ERR = (1 << 7), 185 + RX_DESC_STATUS_LENGTH_ERR = (1 << 4), 186 + RX_DESC_STATUS_CRC_ERR = (1 << 1), 187 + RX_DESC_STATUS_PAYLOAD_ERR = (1 << 0), 188 + RX_DESC_STATUS2_RX_INT_CTL = (1 << 31), 189 + }; 190 + 191 + /* MII register offsets */ 192 + enum { 193 + MII_REG_CR = (0x0), /* Control */ 194 + MII_REG_ST = (0x1), /* Status */ 195 + MII_REG_ID_HIGH = (0x2), /* Identifier High */ 196 + MII_REG_ID_LOW = (0x3), /* Identifier Low */ 197 + MII_REG_ADV = (0x4), /* Advertised abilities */ 198 + MII_REG_LPA = (0x5), /* Link partner abilities */ 199 + }; 200 + 201 + /* MII register flags */ 202 + enum { 203 + MII_REG_CR_RESET = (1 << 15), 204 + MII_REG_CR_POWERDOWN = (1 << 11), 205 + MII_REG_CR_10Mbit = (0), 206 + MII_REG_CR_100Mbit = (1 << 13), 207 + MII_REG_CR_1000Mbit = (1 << 6), 208 + MII_REG_CR_AUTO_NEG = (1 << 12), 209 + MII_REG_CR_AUTO_NEG_RESTART = (1 << 9), 210 + MII_REG_CR_FULLDUPLEX = (1 << 8), 211 + }; 212 + 213 + enum { 214 + MII_REG_ST_100BASE_T4 = (1 << 15), 215 + MII_REG_ST_100BASE_X_FD = (1 << 14), 216 + MII_REG_ST_100BASE_X_HD = (1 << 13), 217 + MII_REG_ST_10_FD = (1 << 12), 218 + MII_REG_ST_10_HD = (1 << 11), 219 + MII_REG_ST_100BASE_T2_FD = (1 << 10), 220 + MII_REG_ST_100BASE_T2_HD = (1 << 9), 221 + MII_REG_ST_AUTONEG_COMPLETE = (1 << 5), 222 + MII_REG_ST_AUTONEG_AVAIL = (1 << 3), 223 + MII_REG_ST_LINK_UP = (1 << 2), 224 + }; 225 + 226 + enum { 227 + MII_REG_LPA_10_HD = (1 << 5), 228 + MII_REG_LPA_10_FD = (1 << 6), 229 + MII_REG_LPA_100_HD = (1 << 7), 230 + MII_REG_LPA_100_FD = (1 << 8), 231 + MII_REG_LPA_PAUSE = (1 << 10), 232 + MII_REG_LPA_ASYMPAUSE = (1 << 11), 233 + }; 234 + 235 + /* MII constants */ 236 + enum { 237 + MII_PHY_ID_HIGH = 0x0044, 238 + MII_PHY_ID_LOW = 0x1400, 239 + }; 240 + 241 + static void allwinner_sun8i_emac_mii_set_link(AwSun8iEmacState *s, 242 + bool link_active) 243 + { 244 + if (link_active) { 245 + s->mii_st |= MII_REG_ST_LINK_UP; 246 + } else { 247 + s->mii_st &= ~MII_REG_ST_LINK_UP; 248 + } 249 + } 250 + 251 + static void allwinner_sun8i_emac_mii_reset(AwSun8iEmacState *s, 252 + bool link_active) 253 + { 254 + s->mii_cr = MII_REG_CR_100Mbit | MII_REG_CR_AUTO_NEG | 255 + MII_REG_CR_FULLDUPLEX; 256 + s->mii_st = MII_REG_ST_100BASE_T4 | MII_REG_ST_100BASE_X_FD | 257 + MII_REG_ST_100BASE_X_HD | MII_REG_ST_10_FD | MII_REG_ST_10_HD | 258 + MII_REG_ST_100BASE_T2_FD | MII_REG_ST_100BASE_T2_HD | 259 + MII_REG_ST_AUTONEG_COMPLETE | MII_REG_ST_AUTONEG_AVAIL; 260 + s->mii_adv = 0; 261 + 262 + allwinner_sun8i_emac_mii_set_link(s, link_active); 263 + } 264 + 265 + static void allwinner_sun8i_emac_mii_cmd(AwSun8iEmacState *s) 266 + { 267 + uint8_t addr, reg; 268 + 269 + addr = (s->mii_cmd & MII_CMD_PHY_ADDR_MASK) >> MII_CMD_PHY_ADDR_SHIFT; 270 + reg = (s->mii_cmd & MII_CMD_PHY_REG_MASK) >> MII_CMD_PHY_REG_SHIFT; 271 + 272 + if (addr != s->mii_phy_addr) { 273 + return; 274 + } 275 + 276 + /* Read or write a PHY register? */ 277 + if (s->mii_cmd & MII_CMD_PHY_RW) { 278 + trace_allwinner_sun8i_emac_mii_write_reg(reg, s->mii_data); 279 + 280 + switch (reg) { 281 + case MII_REG_CR: 282 + if (s->mii_data & MII_REG_CR_RESET) { 283 + allwinner_sun8i_emac_mii_reset(s, s->mii_st & 284 + MII_REG_ST_LINK_UP); 285 + } else { 286 + s->mii_cr = s->mii_data & ~(MII_REG_CR_RESET | 287 + MII_REG_CR_AUTO_NEG_RESTART); 288 + } 289 + break; 290 + case MII_REG_ADV: 291 + s->mii_adv = s->mii_data; 292 + break; 293 + case MII_REG_ID_HIGH: 294 + case MII_REG_ID_LOW: 295 + case MII_REG_LPA: 296 + break; 297 + default: 298 + qemu_log_mask(LOG_UNIMP, "allwinner-h3-emac: write access to " 299 + "unknown MII register 0x%x\n", reg); 300 + break; 301 + } 302 + } else { 303 + switch (reg) { 304 + case MII_REG_CR: 305 + s->mii_data = s->mii_cr; 306 + break; 307 + case MII_REG_ST: 308 + s->mii_data = s->mii_st; 309 + break; 310 + case MII_REG_ID_HIGH: 311 + s->mii_data = MII_PHY_ID_HIGH; 312 + break; 313 + case MII_REG_ID_LOW: 314 + s->mii_data = MII_PHY_ID_LOW; 315 + break; 316 + case MII_REG_ADV: 317 + s->mii_data = s->mii_adv; 318 + break; 319 + case MII_REG_LPA: 320 + s->mii_data = MII_REG_LPA_10_HD | MII_REG_LPA_10_FD | 321 + MII_REG_LPA_100_HD | MII_REG_LPA_100_FD | 322 + MII_REG_LPA_PAUSE | MII_REG_LPA_ASYMPAUSE; 323 + break; 324 + default: 325 + qemu_log_mask(LOG_UNIMP, "allwinner-h3-emac: read access to " 326 + "unknown MII register 0x%x\n", reg); 327 + s->mii_data = 0; 328 + break; 329 + } 330 + 331 + trace_allwinner_sun8i_emac_mii_read_reg(reg, s->mii_data); 332 + } 333 + } 334 + 335 + static void allwinner_sun8i_emac_update_irq(AwSun8iEmacState *s) 336 + { 337 + qemu_set_irq(s->irq, (s->int_sta & s->int_en) != 0); 338 + } 339 + 340 + static uint32_t allwinner_sun8i_emac_next_desc(FrameDescriptor *desc, 341 + size_t min_size) 342 + { 343 + uint32_t paddr = desc->next; 344 + 345 + cpu_physical_memory_read(paddr, desc, sizeof(*desc)); 346 + 347 + if ((desc->status & DESC_STATUS_CTL) && 348 + (desc->status2 & DESC_STATUS2_BUF_SIZE_MASK) >= min_size) { 349 + return paddr; 350 + } else { 351 + return 0; 352 + } 353 + } 354 + 355 + static uint32_t allwinner_sun8i_emac_get_desc(FrameDescriptor *desc, 356 + uint32_t start_addr, 357 + size_t min_size) 358 + { 359 + uint32_t desc_addr = start_addr; 360 + 361 + /* Note that the list is a cycle. Last entry points back to the head. */ 362 + while (desc_addr != 0) { 363 + cpu_physical_memory_read(desc_addr, desc, sizeof(*desc)); 364 + 365 + if ((desc->status & DESC_STATUS_CTL) && 366 + (desc->status2 & DESC_STATUS2_BUF_SIZE_MASK) >= min_size) { 367 + return desc_addr; 368 + } else if (desc->next == start_addr) { 369 + break; 370 + } else { 371 + desc_addr = desc->next; 372 + } 373 + } 374 + 375 + return 0; 376 + } 377 + 378 + static uint32_t allwinner_sun8i_emac_rx_desc(AwSun8iEmacState *s, 379 + FrameDescriptor *desc, 380 + size_t min_size) 381 + { 382 + return allwinner_sun8i_emac_get_desc(desc, s->rx_desc_curr, min_size); 383 + } 384 + 385 + static uint32_t allwinner_sun8i_emac_tx_desc(AwSun8iEmacState *s, 386 + FrameDescriptor *desc, 387 + size_t min_size) 388 + { 389 + return allwinner_sun8i_emac_get_desc(desc, s->tx_desc_head, min_size); 390 + } 391 + 392 + static void allwinner_sun8i_emac_flush_desc(FrameDescriptor *desc, 393 + uint32_t phys_addr) 394 + { 395 + cpu_physical_memory_write(phys_addr, desc, sizeof(*desc)); 396 + } 397 + 398 + static int allwinner_sun8i_emac_can_receive(NetClientState *nc) 399 + { 400 + AwSun8iEmacState *s = qemu_get_nic_opaque(nc); 401 + FrameDescriptor desc; 402 + 403 + return (s->rx_ctl0 & RX_CTL0_RX_EN) && 404 + (allwinner_sun8i_emac_rx_desc(s, &desc, 0) != 0); 405 + } 406 + 407 + static ssize_t allwinner_sun8i_emac_receive(NetClientState *nc, 408 + const uint8_t *buf, 409 + size_t size) 410 + { 411 + AwSun8iEmacState *s = qemu_get_nic_opaque(nc); 412 + FrameDescriptor desc; 413 + size_t bytes_left = size; 414 + size_t desc_bytes = 0; 415 + size_t pad_fcs_size = 4; 416 + size_t padding = 0; 417 + 418 + if (!(s->rx_ctl0 & RX_CTL0_RX_EN)) { 419 + return -1; 420 + } 421 + 422 + s->rx_desc_curr = allwinner_sun8i_emac_rx_desc(s, &desc, 423 + AW_SUN8I_EMAC_MIN_PKT_SZ); 424 + if (!s->rx_desc_curr) { 425 + s->int_sta |= INT_STA_RX_BUF_UA; 426 + } 427 + 428 + /* Keep filling RX descriptors until the whole frame is written */ 429 + while (s->rx_desc_curr && bytes_left > 0) { 430 + desc.status &= ~DESC_STATUS_CTL; 431 + desc.status &= ~RX_DESC_STATUS_FRM_LEN_MASK; 432 + 433 + if (bytes_left == size) { 434 + desc.status |= RX_DESC_STATUS_FIRST_DESC; 435 + } 436 + 437 + if ((desc.status2 & DESC_STATUS2_BUF_SIZE_MASK) < 438 + (bytes_left + pad_fcs_size)) { 439 + desc_bytes = desc.status2 & DESC_STATUS2_BUF_SIZE_MASK; 440 + desc.status |= desc_bytes << RX_DESC_STATUS_FRM_LEN_SHIFT; 441 + } else { 442 + padding = pad_fcs_size; 443 + if (bytes_left < AW_SUN8I_EMAC_MIN_PKT_SZ) { 444 + padding += (AW_SUN8I_EMAC_MIN_PKT_SZ - bytes_left); 445 + } 446 + 447 + desc_bytes = (bytes_left); 448 + desc.status |= RX_DESC_STATUS_LAST_DESC; 449 + desc.status |= (bytes_left + padding) 450 + << RX_DESC_STATUS_FRM_LEN_SHIFT; 451 + } 452 + 453 + cpu_physical_memory_write(desc.addr, buf, desc_bytes); 454 + allwinner_sun8i_emac_flush_desc(&desc, s->rx_desc_curr); 455 + trace_allwinner_sun8i_emac_receive(s->rx_desc_curr, desc.addr, 456 + desc_bytes); 457 + 458 + /* Check if frame needs to raise the receive interrupt */ 459 + if (!(desc.status2 & RX_DESC_STATUS2_RX_INT_CTL)) { 460 + s->int_sta |= INT_STA_RX; 461 + } 462 + 463 + /* Increment variables */ 464 + buf += desc_bytes; 465 + bytes_left -= desc_bytes; 466 + 467 + /* Move to the next descriptor */ 468 + s->rx_desc_curr = allwinner_sun8i_emac_next_desc(&desc, 64); 469 + if (!s->rx_desc_curr) { 470 + /* Not enough buffer space available */ 471 + s->int_sta |= INT_STA_RX_BUF_UA; 472 + s->rx_desc_curr = s->rx_desc_head; 473 + break; 474 + } 475 + } 476 + 477 + /* Report receive DMA is finished */ 478 + s->rx_ctl1 &= ~RX_CTL1_RX_DMA_START; 479 + allwinner_sun8i_emac_update_irq(s); 480 + 481 + return size; 482 + } 483 + 484 + static void allwinner_sun8i_emac_transmit(AwSun8iEmacState *s) 485 + { 486 + NetClientState *nc = qemu_get_queue(s->nic); 487 + FrameDescriptor desc; 488 + size_t bytes = 0; 489 + size_t packet_bytes = 0; 490 + size_t transmitted = 0; 491 + static uint8_t packet_buf[2048]; 492 + 493 + s->tx_desc_curr = allwinner_sun8i_emac_tx_desc(s, &desc, 0); 494 + 495 + /* Read all transmit descriptors */ 496 + while (s->tx_desc_curr != 0) { 497 + 498 + /* Read from physical memory into packet buffer */ 499 + bytes = desc.status2 & DESC_STATUS2_BUF_SIZE_MASK; 500 + if (bytes + packet_bytes > sizeof(packet_buf)) { 501 + desc.status |= TX_DESC_STATUS_LENGTH_ERR; 502 + break; 503 + } 504 + cpu_physical_memory_read(desc.addr, packet_buf + packet_bytes, bytes); 505 + packet_bytes += bytes; 506 + desc.status &= ~DESC_STATUS_CTL; 507 + allwinner_sun8i_emac_flush_desc(&desc, s->tx_desc_curr); 508 + 509 + /* After the last descriptor, send the packet */ 510 + if (desc.status2 & TX_DESC_STATUS2_LAST_DESC) { 511 + if (desc.status2 & TX_DESC_STATUS2_CHECKSUM_MASK) { 512 + net_checksum_calculate(packet_buf, packet_bytes); 513 + } 514 + 515 + qemu_send_packet(nc, packet_buf, packet_bytes); 516 + trace_allwinner_sun8i_emac_transmit(s->tx_desc_curr, desc.addr, 517 + bytes); 518 + 519 + packet_bytes = 0; 520 + transmitted++; 521 + } 522 + s->tx_desc_curr = allwinner_sun8i_emac_next_desc(&desc, 0); 523 + } 524 + 525 + /* Raise transmit completed interrupt */ 526 + if (transmitted > 0) { 527 + s->int_sta |= INT_STA_TX; 528 + s->tx_ctl1 &= ~TX_CTL1_TX_DMA_START; 529 + allwinner_sun8i_emac_update_irq(s); 530 + } 531 + } 532 + 533 + static void allwinner_sun8i_emac_reset(DeviceState *dev) 534 + { 535 + AwSun8iEmacState *s = AW_SUN8I_EMAC(dev); 536 + NetClientState *nc = qemu_get_queue(s->nic); 537 + 538 + trace_allwinner_sun8i_emac_reset(); 539 + 540 + s->mii_cmd = 0; 541 + s->mii_data = 0; 542 + s->basic_ctl0 = 0; 543 + s->basic_ctl1 = REG_BASIC_CTL_1_RST; 544 + s->int_en = 0; 545 + s->int_sta = 0; 546 + s->frm_flt = 0; 547 + s->rx_ctl0 = 0; 548 + s->rx_ctl1 = RX_CTL1_RX_MD; 549 + s->rx_desc_head = 0; 550 + s->rx_desc_curr = 0; 551 + s->tx_ctl0 = 0; 552 + s->tx_ctl1 = 0; 553 + s->tx_desc_head = 0; 554 + s->tx_desc_curr = 0; 555 + s->tx_flowctl = 0; 556 + 557 + allwinner_sun8i_emac_mii_reset(s, !nc->link_down); 558 + } 559 + 560 + static uint64_t allwinner_sun8i_emac_read(void *opaque, hwaddr offset, 561 + unsigned size) 562 + { 563 + AwSun8iEmacState *s = AW_SUN8I_EMAC(opaque); 564 + uint64_t value = 0; 565 + FrameDescriptor desc; 566 + 567 + switch (offset) { 568 + case REG_BASIC_CTL_0: /* Basic Control 0 */ 569 + value = s->basic_ctl0; 570 + break; 571 + case REG_BASIC_CTL_1: /* Basic Control 1 */ 572 + value = s->basic_ctl1; 573 + break; 574 + case REG_INT_STA: /* Interrupt Status */ 575 + value = s->int_sta; 576 + break; 577 + case REG_INT_EN: /* Interupt Enable */ 578 + value = s->int_en; 579 + break; 580 + case REG_TX_CTL_0: /* Transmit Control 0 */ 581 + value = s->tx_ctl0; 582 + break; 583 + case REG_TX_CTL_1: /* Transmit Control 1 */ 584 + value = s->tx_ctl1; 585 + break; 586 + case REG_TX_FLOW_CTL: /* Transmit Flow Control */ 587 + value = s->tx_flowctl; 588 + break; 589 + case REG_TX_DMA_DESC_LIST: /* Transmit Descriptor List Address */ 590 + value = s->tx_desc_head; 591 + break; 592 + case REG_RX_CTL_0: /* Receive Control 0 */ 593 + value = s->rx_ctl0; 594 + break; 595 + case REG_RX_CTL_1: /* Receive Control 1 */ 596 + value = s->rx_ctl1; 597 + break; 598 + case REG_RX_DMA_DESC_LIST: /* Receive Descriptor List Address */ 599 + value = s->rx_desc_head; 600 + break; 601 + case REG_FRM_FLT: /* Receive Frame Filter */ 602 + value = s->frm_flt; 603 + break; 604 + case REG_RX_HASH_0: /* Receive Hash Table 0 */ 605 + case REG_RX_HASH_1: /* Receive Hash Table 1 */ 606 + break; 607 + case REG_MII_CMD: /* Management Interface Command */ 608 + value = s->mii_cmd; 609 + break; 610 + case REG_MII_DATA: /* Management Interface Data */ 611 + value = s->mii_data; 612 + break; 613 + case REG_ADDR_HIGH: /* MAC Address High */ 614 + value = *(((uint32_t *) (s->conf.macaddr.a)) + 1); 615 + break; 616 + case REG_ADDR_LOW: /* MAC Address Low */ 617 + value = *(uint32_t *) (s->conf.macaddr.a); 618 + break; 619 + case REG_TX_DMA_STA: /* Transmit DMA Status */ 620 + break; 621 + case REG_TX_CUR_DESC: /* Transmit Current Descriptor */ 622 + value = s->tx_desc_curr; 623 + break; 624 + case REG_TX_CUR_BUF: /* Transmit Current Buffer */ 625 + if (s->tx_desc_curr != 0) { 626 + cpu_physical_memory_read(s->tx_desc_curr, &desc, sizeof(desc)); 627 + value = desc.addr; 628 + } else { 629 + value = 0; 630 + } 631 + break; 632 + case REG_RX_DMA_STA: /* Receive DMA Status */ 633 + break; 634 + case REG_RX_CUR_DESC: /* Receive Current Descriptor */ 635 + value = s->rx_desc_curr; 636 + break; 637 + case REG_RX_CUR_BUF: /* Receive Current Buffer */ 638 + if (s->rx_desc_curr != 0) { 639 + cpu_physical_memory_read(s->rx_desc_curr, &desc, sizeof(desc)); 640 + value = desc.addr; 641 + } else { 642 + value = 0; 643 + } 644 + break; 645 + case REG_RGMII_STA: /* RGMII Status */ 646 + break; 647 + default: 648 + qemu_log_mask(LOG_UNIMP, "allwinner-h3-emac: read access to unknown " 649 + "EMAC register 0x" TARGET_FMT_plx "\n", 650 + offset); 651 + } 652 + 653 + trace_allwinner_sun8i_emac_read(offset, value); 654 + return value; 655 + } 656 + 657 + static void allwinner_sun8i_emac_write(void *opaque, hwaddr offset, 658 + uint64_t value, unsigned size) 659 + { 660 + AwSun8iEmacState *s = AW_SUN8I_EMAC(opaque); 661 + NetClientState *nc = qemu_get_queue(s->nic); 662 + 663 + trace_allwinner_sun8i_emac_write(offset, value); 664 + 665 + switch (offset) { 666 + case REG_BASIC_CTL_0: /* Basic Control 0 */ 667 + s->basic_ctl0 = value; 668 + break; 669 + case REG_BASIC_CTL_1: /* Basic Control 1 */ 670 + if (value & BASIC_CTL1_SOFTRST) { 671 + allwinner_sun8i_emac_reset(DEVICE(s)); 672 + value &= ~BASIC_CTL1_SOFTRST; 673 + } 674 + s->basic_ctl1 = value; 675 + if (allwinner_sun8i_emac_can_receive(nc)) { 676 + qemu_flush_queued_packets(nc); 677 + } 678 + break; 679 + case REG_INT_STA: /* Interrupt Status */ 680 + s->int_sta &= ~value; 681 + allwinner_sun8i_emac_update_irq(s); 682 + break; 683 + case REG_INT_EN: /* Interrupt Enable */ 684 + s->int_en = value; 685 + allwinner_sun8i_emac_update_irq(s); 686 + break; 687 + case REG_TX_CTL_0: /* Transmit Control 0 */ 688 + s->tx_ctl0 = value; 689 + break; 690 + case REG_TX_CTL_1: /* Transmit Control 1 */ 691 + s->tx_ctl1 = value; 692 + if (value & TX_CTL1_TX_DMA_EN) { 693 + allwinner_sun8i_emac_transmit(s); 694 + } 695 + break; 696 + case REG_TX_FLOW_CTL: /* Transmit Flow Control */ 697 + s->tx_flowctl = value; 698 + break; 699 + case REG_TX_DMA_DESC_LIST: /* Transmit Descriptor List Address */ 700 + s->tx_desc_head = value; 701 + s->tx_desc_curr = value; 702 + break; 703 + case REG_RX_CTL_0: /* Receive Control 0 */ 704 + s->rx_ctl0 = value; 705 + break; 706 + case REG_RX_CTL_1: /* Receive Control 1 */ 707 + s->rx_ctl1 = value | RX_CTL1_RX_MD; 708 + if ((value & RX_CTL1_RX_DMA_EN) && 709 + allwinner_sun8i_emac_can_receive(nc)) { 710 + qemu_flush_queued_packets(nc); 711 + } 712 + break; 713 + case REG_RX_DMA_DESC_LIST: /* Receive Descriptor List Address */ 714 + s->rx_desc_head = value; 715 + s->rx_desc_curr = value; 716 + break; 717 + case REG_FRM_FLT: /* Receive Frame Filter */ 718 + s->frm_flt = value; 719 + break; 720 + case REG_RX_HASH_0: /* Receive Hash Table 0 */ 721 + case REG_RX_HASH_1: /* Receive Hash Table 1 */ 722 + break; 723 + case REG_MII_CMD: /* Management Interface Command */ 724 + s->mii_cmd = value & ~MII_CMD_PHY_BUSY; 725 + allwinner_sun8i_emac_mii_cmd(s); 726 + break; 727 + case REG_MII_DATA: /* Management Interface Data */ 728 + s->mii_data = value; 729 + break; 730 + case REG_ADDR_HIGH: /* MAC Address High */ 731 + s->conf.macaddr.a[4] = (value & 0xff); 732 + s->conf.macaddr.a[5] = (value & 0xff00) >> 8; 733 + break; 734 + case REG_ADDR_LOW: /* MAC Address Low */ 735 + s->conf.macaddr.a[0] = (value & 0xff); 736 + s->conf.macaddr.a[1] = (value & 0xff00) >> 8; 737 + s->conf.macaddr.a[2] = (value & 0xff0000) >> 16; 738 + s->conf.macaddr.a[3] = (value & 0xff000000) >> 24; 739 + break; 740 + case REG_TX_DMA_STA: /* Transmit DMA Status */ 741 + case REG_TX_CUR_DESC: /* Transmit Current Descriptor */ 742 + case REG_TX_CUR_BUF: /* Transmit Current Buffer */ 743 + case REG_RX_DMA_STA: /* Receive DMA Status */ 744 + case REG_RX_CUR_DESC: /* Receive Current Descriptor */ 745 + case REG_RX_CUR_BUF: /* Receive Current Buffer */ 746 + case REG_RGMII_STA: /* RGMII Status */ 747 + break; 748 + default: 749 + qemu_log_mask(LOG_UNIMP, "allwinner-h3-emac: write access to unknown " 750 + "EMAC register 0x" TARGET_FMT_plx "\n", 751 + offset); 752 + } 753 + } 754 + 755 + static void allwinner_sun8i_emac_set_link(NetClientState *nc) 756 + { 757 + AwSun8iEmacState *s = qemu_get_nic_opaque(nc); 758 + 759 + trace_allwinner_sun8i_emac_set_link(!nc->link_down); 760 + allwinner_sun8i_emac_mii_set_link(s, !nc->link_down); 761 + } 762 + 763 + static const MemoryRegionOps allwinner_sun8i_emac_mem_ops = { 764 + .read = allwinner_sun8i_emac_read, 765 + .write = allwinner_sun8i_emac_write, 766 + .endianness = DEVICE_NATIVE_ENDIAN, 767 + .valid = { 768 + .min_access_size = 4, 769 + .max_access_size = 4, 770 + }, 771 + .impl.min_access_size = 4, 772 + }; 773 + 774 + static NetClientInfo net_allwinner_sun8i_emac_info = { 775 + .type = NET_CLIENT_DRIVER_NIC, 776 + .size = sizeof(NICState), 777 + .can_receive = allwinner_sun8i_emac_can_receive, 778 + .receive = allwinner_sun8i_emac_receive, 779 + .link_status_changed = allwinner_sun8i_emac_set_link, 780 + }; 781 + 782 + static void allwinner_sun8i_emac_init(Object *obj) 783 + { 784 + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 785 + AwSun8iEmacState *s = AW_SUN8I_EMAC(obj); 786 + 787 + memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_sun8i_emac_mem_ops, 788 + s, TYPE_AW_SUN8I_EMAC, 64 * KiB); 789 + sysbus_init_mmio(sbd, &s->iomem); 790 + sysbus_init_irq(sbd, &s->irq); 791 + } 792 + 793 + static void allwinner_sun8i_emac_realize(DeviceState *dev, Error **errp) 794 + { 795 + AwSun8iEmacState *s = AW_SUN8I_EMAC(dev); 796 + 797 + qemu_macaddr_default_if_unset(&s->conf.macaddr); 798 + s->nic = qemu_new_nic(&net_allwinner_sun8i_emac_info, &s->conf, 799 + object_get_typename(OBJECT(dev)), dev->id, s); 800 + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); 801 + } 802 + 803 + static Property allwinner_sun8i_emac_properties[] = { 804 + DEFINE_NIC_PROPERTIES(AwSun8iEmacState, conf), 805 + DEFINE_PROP_UINT8("phy-addr", AwSun8iEmacState, mii_phy_addr, 0), 806 + DEFINE_PROP_END_OF_LIST(), 807 + }; 808 + 809 + static int allwinner_sun8i_emac_post_load(void *opaque, int version_id) 810 + { 811 + AwSun8iEmacState *s = opaque; 812 + 813 + allwinner_sun8i_emac_set_link(qemu_get_queue(s->nic)); 814 + 815 + return 0; 816 + } 817 + 818 + static const VMStateDescription vmstate_aw_emac = { 819 + .name = "allwinner-sun8i-emac", 820 + .version_id = 1, 821 + .minimum_version_id = 1, 822 + .post_load = allwinner_sun8i_emac_post_load, 823 + .fields = (VMStateField[]) { 824 + VMSTATE_UINT8(mii_phy_addr, AwSun8iEmacState), 825 + VMSTATE_UINT32(mii_cmd, AwSun8iEmacState), 826 + VMSTATE_UINT32(mii_data, AwSun8iEmacState), 827 + VMSTATE_UINT32(mii_cr, AwSun8iEmacState), 828 + VMSTATE_UINT32(mii_st, AwSun8iEmacState), 829 + VMSTATE_UINT32(mii_adv, AwSun8iEmacState), 830 + VMSTATE_UINT32(basic_ctl0, AwSun8iEmacState), 831 + VMSTATE_UINT32(basic_ctl1, AwSun8iEmacState), 832 + VMSTATE_UINT32(int_en, AwSun8iEmacState), 833 + VMSTATE_UINT32(int_sta, AwSun8iEmacState), 834 + VMSTATE_UINT32(frm_flt, AwSun8iEmacState), 835 + VMSTATE_UINT32(rx_ctl0, AwSun8iEmacState), 836 + VMSTATE_UINT32(rx_ctl1, AwSun8iEmacState), 837 + VMSTATE_UINT32(rx_desc_head, AwSun8iEmacState), 838 + VMSTATE_UINT32(rx_desc_curr, AwSun8iEmacState), 839 + VMSTATE_UINT32(tx_ctl0, AwSun8iEmacState), 840 + VMSTATE_UINT32(tx_ctl1, AwSun8iEmacState), 841 + VMSTATE_UINT32(tx_desc_head, AwSun8iEmacState), 842 + VMSTATE_UINT32(tx_desc_curr, AwSun8iEmacState), 843 + VMSTATE_UINT32(tx_flowctl, AwSun8iEmacState), 844 + VMSTATE_END_OF_LIST() 845 + } 846 + }; 847 + 848 + static void allwinner_sun8i_emac_class_init(ObjectClass *klass, void *data) 849 + { 850 + DeviceClass *dc = DEVICE_CLASS(klass); 851 + 852 + dc->realize = allwinner_sun8i_emac_realize; 853 + dc->reset = allwinner_sun8i_emac_reset; 854 + dc->vmsd = &vmstate_aw_emac; 855 + device_class_set_props(dc, allwinner_sun8i_emac_properties); 856 + } 857 + 858 + static const TypeInfo allwinner_sun8i_emac_info = { 859 + .name = TYPE_AW_SUN8I_EMAC, 860 + .parent = TYPE_SYS_BUS_DEVICE, 861 + .instance_size = sizeof(AwSun8iEmacState), 862 + .instance_init = allwinner_sun8i_emac_init, 863 + .class_init = allwinner_sun8i_emac_class_init, 864 + }; 865 + 866 + static void allwinner_sun8i_emac_register_types(void) 867 + { 868 + type_register_static(&allwinner_sun8i_emac_info); 869 + } 870 + 871 + type_init(allwinner_sun8i_emac_register_types)
+10
hw/net/trace-events
··· 1 1 # See docs/devel/tracing.txt for syntax documentation. 2 2 3 + # allwinner-sun8i-emac.c 4 + allwinner_sun8i_emac_mii_write_reg(uint32_t reg, uint32_t value) "MII write: reg=0x%" PRIx32 " value=0x%" PRIx32 5 + allwinner_sun8i_emac_mii_read_reg(uint32_t reg, uint32_t value) "MII read: reg=0x%" PRIx32 " value=0x%" PRIx32 6 + allwinner_sun8i_emac_receive(uint32_t desc, uint32_t paddr, uint32_t bytes) "RX packet: desc=0x%" PRIx32 " paddr=0x%" PRIx32 " bytes=%" PRIu32 7 + allwinner_sun8i_emac_transmit(uint32_t desc, uint32_t paddr, uint32_t bytes) "TX packet: desc=0x%" PRIx32 " paddr=0x%" PRIx32 " bytes=%" PRIu32 8 + allwinner_sun8i_emac_reset(void) "HW reset" 9 + allwinner_sun8i_emac_set_link(bool active) "Set link: active=%u" 10 + allwinner_sun8i_emac_read(uint64_t offset, uint64_t val) "MMIO read: offset=0x%" PRIx64 " value=0x%" PRIx64 11 + allwinner_sun8i_emac_write(uint64_t offset, uint64_t val) "MMIO write: offset=0x%" PRIx64 " value=0x%" PRIx64 12 + 3 13 # etraxfs_eth.c 4 14 mdio_phy_read(int regnum, uint16_t value) "read phy_reg:%d value:0x%04x" 5 15 mdio_phy_write(int regnum, uint16_t value) "write phy_reg:%d value:0x%04x"
+3
include/hw/arm/allwinner-h3.h
··· 44 44 #include "hw/misc/allwinner-h3-sysctrl.h" 45 45 #include "hw/misc/allwinner-sid.h" 46 46 #include "hw/sd/allwinner-sdhost.h" 47 + #include "hw/net/allwinner-sun8i-emac.h" 47 48 #include "target/arm/cpu.h" 48 49 49 50 /** ··· 77 78 AW_H3_UART1, 78 79 AW_H3_UART2, 79 80 AW_H3_UART3, 81 + AW_H3_EMAC, 80 82 AW_H3_GIC_DIST, 81 83 AW_H3_GIC_CPU, 82 84 AW_H3_GIC_HYP, ··· 120 122 AwH3SysCtrlState sysctrl; 121 123 AwSidState sid; 122 124 AwSdHostState mmc0; 125 + AwSun8iEmacState emac; 123 126 GICState gic; 124 127 MemoryRegion sram_a1; 125 128 MemoryRegion sram_a2;
+99
include/hw/net/allwinner-sun8i-emac.h
··· 1 + /* 2 + * Allwinner Sun8i Ethernet MAC emulation 3 + * 4 + * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com> 5 + * 6 + * This program is free software: you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation, either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #ifndef HW_NET_ALLWINNER_SUN8I_EMAC_H 21 + #define HW_NET_ALLWINNER_SUN8I_EMAC_H 22 + 23 + #include "qom/object.h" 24 + #include "net/net.h" 25 + #include "hw/sysbus.h" 26 + 27 + /** 28 + * Object model 29 + * @{ 30 + */ 31 + 32 + #define TYPE_AW_SUN8I_EMAC "allwinner-sun8i-emac" 33 + #define AW_SUN8I_EMAC(obj) \ 34 + OBJECT_CHECK(AwSun8iEmacState, (obj), TYPE_AW_SUN8I_EMAC) 35 + 36 + /** @} */ 37 + 38 + /** 39 + * Allwinner Sun8i EMAC object instance state 40 + */ 41 + typedef struct AwSun8iEmacState { 42 + /*< private >*/ 43 + SysBusDevice parent_obj; 44 + /*< public >*/ 45 + 46 + /** Maps I/O registers in physical memory */ 47 + MemoryRegion iomem; 48 + 49 + /** Interrupt output signal to notify CPU */ 50 + qemu_irq irq; 51 + 52 + /** Generic Network Interface Controller (NIC) for networking API */ 53 + NICState *nic; 54 + 55 + /** Generic Network Interface Controller (NIC) configuration */ 56 + NICConf conf; 57 + 58 + /** 59 + * @name Media Independent Interface (MII) 60 + * @{ 61 + */ 62 + 63 + uint8_t mii_phy_addr; /**< PHY address */ 64 + uint32_t mii_cr; /**< Control */ 65 + uint32_t mii_st; /**< Status */ 66 + uint32_t mii_adv; /**< Advertised Abilities */ 67 + 68 + /** @} */ 69 + 70 + /** 71 + * @name Hardware Registers 72 + * @{ 73 + */ 74 + 75 + uint32_t basic_ctl0; /**< Basic Control 0 */ 76 + uint32_t basic_ctl1; /**< Basic Control 1 */ 77 + uint32_t int_en; /**< Interrupt Enable */ 78 + uint32_t int_sta; /**< Interrupt Status */ 79 + uint32_t frm_flt; /**< Receive Frame Filter */ 80 + 81 + uint32_t rx_ctl0; /**< Receive Control 0 */ 82 + uint32_t rx_ctl1; /**< Receive Control 1 */ 83 + uint32_t rx_desc_head; /**< Receive Descriptor List Address */ 84 + uint32_t rx_desc_curr; /**< Current Receive Descriptor Address */ 85 + 86 + uint32_t tx_ctl0; /**< Transmit Control 0 */ 87 + uint32_t tx_ctl1; /**< Transmit Control 1 */ 88 + uint32_t tx_desc_head; /**< Transmit Descriptor List Address */ 89 + uint32_t tx_desc_curr; /**< Current Transmit Descriptor Address */ 90 + uint32_t tx_flowctl; /**< Transmit Flow Control */ 91 + 92 + uint32_t mii_cmd; /**< Management Interface Command */ 93 + uint32_t mii_data; /**< Management Interface Data */ 94 + 95 + /** @} */ 96 + 97 + } AwSun8iEmacState; 98 + 99 + #endif /* HW_NET_ALLWINNER_SUN8I_H */