1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * Marvell MV88W8618 / Freecom MusicPal emulation. 4 * 5 * Copyright (c) 2008 Jan Kiszka 6 */ 7 8 #include "qemu/osdep.h" 9 #include "qapi/error.h" 10 #include "hw/qdev-properties.h" 11 #include "hw/sysbus.h" 12 #include "hw/irq.h" 13 #include "hw/net/mv88w8618_eth.h" 14 #include "migration/vmstate.h" 15 #include "sysemu/dma.h" 16 #include "net/net.h" 17 18 #define MP_ETH_SIZE 0x00001000 19 20 /* Ethernet register offsets */ 21 #define MP_ETH_SMIR 0x010 22 #define MP_ETH_PCXR 0x408 23 #define MP_ETH_SDCMR 0x448 24 #define MP_ETH_ICR 0x450 25 #define MP_ETH_IMR 0x458 26 #define MP_ETH_FRDP0 0x480 27 #define MP_ETH_FRDP1 0x484 28 #define MP_ETH_FRDP2 0x488 29 #define MP_ETH_FRDP3 0x48C 30 #define MP_ETH_CRDP0 0x4A0 31 #define MP_ETH_CRDP1 0x4A4 32 #define MP_ETH_CRDP2 0x4A8 33 #define MP_ETH_CRDP3 0x4AC 34 #define MP_ETH_CTDP0 0x4E0 35 #define MP_ETH_CTDP1 0x4E4 36 37 /* MII PHY access */ 38 #define MP_ETH_SMIR_DATA 0x0000FFFF 39 #define MP_ETH_SMIR_ADDR 0x03FF0000 40 #define MP_ETH_SMIR_OPCODE (1 << 26) /* Read value */ 41 #define MP_ETH_SMIR_RDVALID (1 << 27) 42 43 /* PHY registers */ 44 #define MP_ETH_PHY1_BMSR 0x00210000 45 #define MP_ETH_PHY1_PHYSID1 0x00410000 46 #define MP_ETH_PHY1_PHYSID2 0x00610000 47 48 #define MP_PHY_BMSR_LINK 0x0004 49 #define MP_PHY_BMSR_AUTONEG 0x0008 50 51 #define MP_PHY_88E3015 0x01410E20 52 53 /* TX descriptor status */ 54 #define MP_ETH_TX_OWN (1U << 31) 55 56 /* RX descriptor status */ 57 #define MP_ETH_RX_OWN (1U << 31) 58 59 /* Interrupt cause/mask bits */ 60 #define MP_ETH_IRQ_RX_BIT 0 61 #define MP_ETH_IRQ_RX (1 << MP_ETH_IRQ_RX_BIT) 62 #define MP_ETH_IRQ_TXHI_BIT 2 63 #define MP_ETH_IRQ_TXLO_BIT 3 64 65 /* Port config bits */ 66 #define MP_ETH_PCXR_2BSM_BIT 28 /* 2-byte incoming suffix */ 67 68 /* SDMA command bits */ 69 #define MP_ETH_CMD_TXHI (1 << 23) 70 #define MP_ETH_CMD_TXLO (1 << 22) 71 72 typedef struct mv88w8618_tx_desc { 73 uint32_t cmdstat; 74 uint16_t res; 75 uint16_t bytes; 76 uint32_t buffer; 77 uint32_t next; 78 } mv88w8618_tx_desc; 79 80 typedef struct mv88w8618_rx_desc { 81 uint32_t cmdstat; 82 uint16_t bytes; 83 uint16_t buffer_size; 84 uint32_t buffer; 85 uint32_t next; 86 } mv88w8618_rx_desc; 87 88 OBJECT_DECLARE_SIMPLE_TYPE(mv88w8618_eth_state, MV88W8618_ETH) 89 90 struct mv88w8618_eth_state { 91 /*< private >*/ 92 SysBusDevice parent_obj; 93 /*< public >*/ 94 95 MemoryRegion iomem; 96 qemu_irq irq; 97 MemoryRegion *dma_mr; 98 AddressSpace dma_as; 99 uint32_t smir; 100 uint32_t icr; 101 uint32_t imr; 102 int mmio_index; 103 uint32_t vlan_header; 104 uint32_t tx_queue[2]; 105 uint32_t rx_queue[4]; 106 uint32_t frx_queue[4]; 107 uint32_t cur_rx[4]; 108 NICState *nic; 109 NICConf conf; 110 }; 111 112 static void eth_rx_desc_put(AddressSpace *dma_as, uint32_t addr, 113 mv88w8618_rx_desc *desc) 114 { 115 cpu_to_le32s(&desc->cmdstat); 116 cpu_to_le16s(&desc->bytes); 117 cpu_to_le16s(&desc->buffer_size); 118 cpu_to_le32s(&desc->buffer); 119 cpu_to_le32s(&desc->next); 120 dma_memory_write(dma_as, addr, desc, sizeof(*desc), MEMTXATTRS_UNSPECIFIED); 121 } 122 123 static void eth_rx_desc_get(AddressSpace *dma_as, uint32_t addr, 124 mv88w8618_rx_desc *desc) 125 { 126 dma_memory_read(dma_as, addr, desc, sizeof(*desc), MEMTXATTRS_UNSPECIFIED); 127 le32_to_cpus(&desc->cmdstat); 128 le16_to_cpus(&desc->bytes); 129 le16_to_cpus(&desc->buffer_size); 130 le32_to_cpus(&desc->buffer); 131 le32_to_cpus(&desc->next); 132 } 133 134 static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size) 135 { 136 mv88w8618_eth_state *s = qemu_get_nic_opaque(nc); 137 uint32_t desc_addr; 138 mv88w8618_rx_desc desc; 139 int i; 140 141 for (i = 0; i < 4; i++) { 142 desc_addr = s->cur_rx[i]; 143 if (!desc_addr) { 144 continue; 145 } 146 do { 147 eth_rx_desc_get(&s->dma_as, desc_addr, &desc); 148 if ((desc.cmdstat & MP_ETH_RX_OWN) && desc.buffer_size >= size) { 149 dma_memory_write(&s->dma_as, desc.buffer + s->vlan_header, 150 buf, size, MEMTXATTRS_UNSPECIFIED); 151 desc.bytes = size + s->vlan_header; 152 desc.cmdstat &= ~MP_ETH_RX_OWN; 153 s->cur_rx[i] = desc.next; 154 155 s->icr |= MP_ETH_IRQ_RX; 156 if (s->icr & s->imr) { 157 qemu_irq_raise(s->irq); 158 } 159 eth_rx_desc_put(&s->dma_as, desc_addr, &desc); 160 return size; 161 } 162 desc_addr = desc.next; 163 } while (desc_addr != s->rx_queue[i]); 164 } 165 return size; 166 } 167 168 static void eth_tx_desc_put(AddressSpace *dma_as, uint32_t addr, 169 mv88w8618_tx_desc *desc) 170 { 171 cpu_to_le32s(&desc->cmdstat); 172 cpu_to_le16s(&desc->res); 173 cpu_to_le16s(&desc->bytes); 174 cpu_to_le32s(&desc->buffer); 175 cpu_to_le32s(&desc->next); 176 dma_memory_write(dma_as, addr, desc, sizeof(*desc), MEMTXATTRS_UNSPECIFIED); 177 } 178 179 static void eth_tx_desc_get(AddressSpace *dma_as, uint32_t addr, 180 mv88w8618_tx_desc *desc) 181 { 182 dma_memory_read(dma_as, addr, desc, sizeof(*desc), MEMTXATTRS_UNSPECIFIED); 183 le32_to_cpus(&desc->cmdstat); 184 le16_to_cpus(&desc->res); 185 le16_to_cpus(&desc->bytes); 186 le32_to_cpus(&desc->buffer); 187 le32_to_cpus(&desc->next); 188 } 189 190 static void eth_send(mv88w8618_eth_state *s, int queue_index) 191 { 192 uint32_t desc_addr = s->tx_queue[queue_index]; 193 mv88w8618_tx_desc desc; 194 uint32_t next_desc; 195 uint8_t buf[2048]; 196 int len; 197 198 do { 199 eth_tx_desc_get(&s->dma_as, desc_addr, &desc); 200 next_desc = desc.next; 201 if (desc.cmdstat & MP_ETH_TX_OWN) { 202 len = desc.bytes; 203 if (len < 2048) { 204 dma_memory_read(&s->dma_as, desc.buffer, buf, len, 205 MEMTXATTRS_UNSPECIFIED); 206 qemu_send_packet(qemu_get_queue(s->nic), buf, len); 207 } 208 desc.cmdstat &= ~MP_ETH_TX_OWN; 209 s->icr |= 1 << (MP_ETH_IRQ_TXLO_BIT - queue_index); 210 eth_tx_desc_put(&s->dma_as, desc_addr, &desc); 211 } 212 desc_addr = next_desc; 213 } while (desc_addr != s->tx_queue[queue_index]); 214 } 215 216 static uint64_t mv88w8618_eth_read(void *opaque, hwaddr offset, 217 unsigned size) 218 { 219 mv88w8618_eth_state *s = opaque; 220 221 switch (offset) { 222 case MP_ETH_SMIR: 223 if (s->smir & MP_ETH_SMIR_OPCODE) { 224 switch (s->smir & MP_ETH_SMIR_ADDR) { 225 case MP_ETH_PHY1_BMSR: 226 return MP_PHY_BMSR_LINK | MP_PHY_BMSR_AUTONEG | 227 MP_ETH_SMIR_RDVALID; 228 case MP_ETH_PHY1_PHYSID1: 229 return (MP_PHY_88E3015 >> 16) | MP_ETH_SMIR_RDVALID; 230 case MP_ETH_PHY1_PHYSID2: 231 return (MP_PHY_88E3015 & 0xFFFF) | MP_ETH_SMIR_RDVALID; 232 default: 233 return MP_ETH_SMIR_RDVALID; 234 } 235 } 236 return 0; 237 238 case MP_ETH_ICR: 239 return s->icr; 240 241 case MP_ETH_IMR: 242 return s->imr; 243 244 case MP_ETH_FRDP0 ... MP_ETH_FRDP3: 245 return s->frx_queue[(offset - MP_ETH_FRDP0) / 4]; 246 247 case MP_ETH_CRDP0 ... MP_ETH_CRDP3: 248 return s->rx_queue[(offset - MP_ETH_CRDP0) / 4]; 249 250 case MP_ETH_CTDP0 ... MP_ETH_CTDP1: 251 return s->tx_queue[(offset - MP_ETH_CTDP0) / 4]; 252 253 default: 254 return 0; 255 } 256 } 257 258 static void mv88w8618_eth_write(void *opaque, hwaddr offset, 259 uint64_t value, unsigned size) 260 { 261 mv88w8618_eth_state *s = opaque; 262 263 switch (offset) { 264 case MP_ETH_SMIR: 265 s->smir = value; 266 break; 267 268 case MP_ETH_PCXR: 269 s->vlan_header = ((value >> MP_ETH_PCXR_2BSM_BIT) & 1) * 2; 270 break; 271 272 case MP_ETH_SDCMR: 273 if (value & MP_ETH_CMD_TXHI) { 274 eth_send(s, 1); 275 } 276 if (value & MP_ETH_CMD_TXLO) { 277 eth_send(s, 0); 278 } 279 if (value & (MP_ETH_CMD_TXHI | MP_ETH_CMD_TXLO) && s->icr & s->imr) { 280 qemu_irq_raise(s->irq); 281 } 282 break; 283 284 case MP_ETH_ICR: 285 s->icr &= value; 286 break; 287 288 case MP_ETH_IMR: 289 s->imr = value; 290 if (s->icr & s->imr) { 291 qemu_irq_raise(s->irq); 292 } 293 break; 294 295 case MP_ETH_FRDP0 ... MP_ETH_FRDP3: 296 s->frx_queue[(offset - MP_ETH_FRDP0) / 4] = value; 297 break; 298 299 case MP_ETH_CRDP0 ... MP_ETH_CRDP3: 300 s->rx_queue[(offset - MP_ETH_CRDP0) / 4] = 301 s->cur_rx[(offset - MP_ETH_CRDP0) / 4] = value; 302 break; 303 304 case MP_ETH_CTDP0 ... MP_ETH_CTDP1: 305 s->tx_queue[(offset - MP_ETH_CTDP0) / 4] = value; 306 break; 307 } 308 } 309 310 static const MemoryRegionOps mv88w8618_eth_ops = { 311 .read = mv88w8618_eth_read, 312 .write = mv88w8618_eth_write, 313 .endianness = DEVICE_NATIVE_ENDIAN, 314 }; 315 316 static void eth_cleanup(NetClientState *nc) 317 { 318 mv88w8618_eth_state *s = qemu_get_nic_opaque(nc); 319 320 s->nic = NULL; 321 } 322 323 static NetClientInfo net_mv88w8618_info = { 324 .type = NET_CLIENT_DRIVER_NIC, 325 .size = sizeof(NICState), 326 .receive = eth_receive, 327 .cleanup = eth_cleanup, 328 }; 329 330 static void mv88w8618_eth_init(Object *obj) 331 { 332 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 333 DeviceState *dev = DEVICE(sbd); 334 mv88w8618_eth_state *s = MV88W8618_ETH(dev); 335 336 sysbus_init_irq(sbd, &s->irq); 337 memory_region_init_io(&s->iomem, obj, &mv88w8618_eth_ops, s, 338 "mv88w8618-eth", MP_ETH_SIZE); 339 sysbus_init_mmio(sbd, &s->iomem); 340 } 341 342 static void mv88w8618_eth_realize(DeviceState *dev, Error **errp) 343 { 344 mv88w8618_eth_state *s = MV88W8618_ETH(dev); 345 346 if (!s->dma_mr) { 347 error_setg(errp, TYPE_MV88W8618_ETH " 'dma-memory' link not set"); 348 return; 349 } 350 351 address_space_init(&s->dma_as, s->dma_mr, "emac-dma"); 352 s->nic = qemu_new_nic(&net_mv88w8618_info, &s->conf, 353 object_get_typename(OBJECT(dev)), dev->id, 354 &dev->mem_reentrancy_guard, s); 355 } 356 357 static const VMStateDescription mv88w8618_eth_vmsd = { 358 .name = "mv88w8618_eth", 359 .version_id = 1, 360 .minimum_version_id = 1, 361 .fields = (VMStateField[]) { 362 VMSTATE_UINT32(smir, mv88w8618_eth_state), 363 VMSTATE_UINT32(icr, mv88w8618_eth_state), 364 VMSTATE_UINT32(imr, mv88w8618_eth_state), 365 VMSTATE_UINT32(vlan_header, mv88w8618_eth_state), 366 VMSTATE_UINT32_ARRAY(tx_queue, mv88w8618_eth_state, 2), 367 VMSTATE_UINT32_ARRAY(rx_queue, mv88w8618_eth_state, 4), 368 VMSTATE_UINT32_ARRAY(frx_queue, mv88w8618_eth_state, 4), 369 VMSTATE_UINT32_ARRAY(cur_rx, mv88w8618_eth_state, 4), 370 VMSTATE_END_OF_LIST() 371 } 372 }; 373 374 static Property mv88w8618_eth_properties[] = { 375 DEFINE_NIC_PROPERTIES(mv88w8618_eth_state, conf), 376 DEFINE_PROP_LINK("dma-memory", mv88w8618_eth_state, dma_mr, 377 TYPE_MEMORY_REGION, MemoryRegion *), 378 DEFINE_PROP_END_OF_LIST(), 379 }; 380 381 static void mv88w8618_eth_class_init(ObjectClass *klass, void *data) 382 { 383 DeviceClass *dc = DEVICE_CLASS(klass); 384 385 dc->vmsd = &mv88w8618_eth_vmsd; 386 device_class_set_props(dc, mv88w8618_eth_properties); 387 dc->realize = mv88w8618_eth_realize; 388 } 389 390 static const TypeInfo mv88w8618_eth_info = { 391 .name = TYPE_MV88W8618_ETH, 392 .parent = TYPE_SYS_BUS_DEVICE, 393 .instance_size = sizeof(mv88w8618_eth_state), 394 .instance_init = mv88w8618_eth_init, 395 .class_init = mv88w8618_eth_class_init, 396 }; 397 398 static void musicpal_register_types(void) 399 { 400 type_register_static(&mv88w8618_eth_info); 401 } 402 403 type_init(musicpal_register_types) 404 405