16d81f488SPhilippe Mathieu-Daudé /* SPDX-License-Identifier: GPL-2.0-or-later */ 26d81f488SPhilippe Mathieu-Daudé /* 36d81f488SPhilippe Mathieu-Daudé * Marvell MV88W8618 / Freecom MusicPal emulation. 46d81f488SPhilippe Mathieu-Daudé * 56d81f488SPhilippe Mathieu-Daudé * Copyright (c) 2008 Jan Kiszka 66d81f488SPhilippe Mathieu-Daudé */ 76d81f488SPhilippe Mathieu-Daudé 86d81f488SPhilippe Mathieu-Daudé #include "qemu/osdep.h" 96d81f488SPhilippe Mathieu-Daudé #include "qapi/error.h" 106d81f488SPhilippe Mathieu-Daudé #include "hw/qdev-properties.h" 116d81f488SPhilippe Mathieu-Daudé #include "hw/sysbus.h" 126d81f488SPhilippe Mathieu-Daudé #include "hw/irq.h" 136d81f488SPhilippe Mathieu-Daudé #include "hw/net/mv88w8618_eth.h" 146d81f488SPhilippe Mathieu-Daudé #include "migration/vmstate.h" 156d81f488SPhilippe Mathieu-Daudé #include "sysemu/dma.h" 166d81f488SPhilippe Mathieu-Daudé #include "net/net.h" 176d81f488SPhilippe Mathieu-Daudé 186d81f488SPhilippe Mathieu-Daudé #define MP_ETH_SIZE 0x00001000 196d81f488SPhilippe Mathieu-Daudé 206d81f488SPhilippe Mathieu-Daudé /* Ethernet register offsets */ 216d81f488SPhilippe Mathieu-Daudé #define MP_ETH_SMIR 0x010 226d81f488SPhilippe Mathieu-Daudé #define MP_ETH_PCXR 0x408 236d81f488SPhilippe Mathieu-Daudé #define MP_ETH_SDCMR 0x448 246d81f488SPhilippe Mathieu-Daudé #define MP_ETH_ICR 0x450 256d81f488SPhilippe Mathieu-Daudé #define MP_ETH_IMR 0x458 266d81f488SPhilippe Mathieu-Daudé #define MP_ETH_FRDP0 0x480 276d81f488SPhilippe Mathieu-Daudé #define MP_ETH_FRDP1 0x484 286d81f488SPhilippe Mathieu-Daudé #define MP_ETH_FRDP2 0x488 296d81f488SPhilippe Mathieu-Daudé #define MP_ETH_FRDP3 0x48C 306d81f488SPhilippe Mathieu-Daudé #define MP_ETH_CRDP0 0x4A0 316d81f488SPhilippe Mathieu-Daudé #define MP_ETH_CRDP1 0x4A4 326d81f488SPhilippe Mathieu-Daudé #define MP_ETH_CRDP2 0x4A8 336d81f488SPhilippe Mathieu-Daudé #define MP_ETH_CRDP3 0x4AC 346d81f488SPhilippe Mathieu-Daudé #define MP_ETH_CTDP0 0x4E0 356d81f488SPhilippe Mathieu-Daudé #define MP_ETH_CTDP1 0x4E4 366d81f488SPhilippe Mathieu-Daudé 376d81f488SPhilippe Mathieu-Daudé /* MII PHY access */ 386d81f488SPhilippe Mathieu-Daudé #define MP_ETH_SMIR_DATA 0x0000FFFF 396d81f488SPhilippe Mathieu-Daudé #define MP_ETH_SMIR_ADDR 0x03FF0000 406d81f488SPhilippe Mathieu-Daudé #define MP_ETH_SMIR_OPCODE (1 << 26) /* Read value */ 416d81f488SPhilippe Mathieu-Daudé #define MP_ETH_SMIR_RDVALID (1 << 27) 426d81f488SPhilippe Mathieu-Daudé 436d81f488SPhilippe Mathieu-Daudé /* PHY registers */ 446d81f488SPhilippe Mathieu-Daudé #define MP_ETH_PHY1_BMSR 0x00210000 456d81f488SPhilippe Mathieu-Daudé #define MP_ETH_PHY1_PHYSID1 0x00410000 466d81f488SPhilippe Mathieu-Daudé #define MP_ETH_PHY1_PHYSID2 0x00610000 476d81f488SPhilippe Mathieu-Daudé 486d81f488SPhilippe Mathieu-Daudé #define MP_PHY_BMSR_LINK 0x0004 496d81f488SPhilippe Mathieu-Daudé #define MP_PHY_BMSR_AUTONEG 0x0008 506d81f488SPhilippe Mathieu-Daudé 516d81f488SPhilippe Mathieu-Daudé #define MP_PHY_88E3015 0x01410E20 526d81f488SPhilippe Mathieu-Daudé 536d81f488SPhilippe Mathieu-Daudé /* TX descriptor status */ 546d81f488SPhilippe Mathieu-Daudé #define MP_ETH_TX_OWN (1U << 31) 556d81f488SPhilippe Mathieu-Daudé 566d81f488SPhilippe Mathieu-Daudé /* RX descriptor status */ 576d81f488SPhilippe Mathieu-Daudé #define MP_ETH_RX_OWN (1U << 31) 586d81f488SPhilippe Mathieu-Daudé 596d81f488SPhilippe Mathieu-Daudé /* Interrupt cause/mask bits */ 606d81f488SPhilippe Mathieu-Daudé #define MP_ETH_IRQ_RX_BIT 0 616d81f488SPhilippe Mathieu-Daudé #define MP_ETH_IRQ_RX (1 << MP_ETH_IRQ_RX_BIT) 626d81f488SPhilippe Mathieu-Daudé #define MP_ETH_IRQ_TXHI_BIT 2 636d81f488SPhilippe Mathieu-Daudé #define MP_ETH_IRQ_TXLO_BIT 3 646d81f488SPhilippe Mathieu-Daudé 656d81f488SPhilippe Mathieu-Daudé /* Port config bits */ 666d81f488SPhilippe Mathieu-Daudé #define MP_ETH_PCXR_2BSM_BIT 28 /* 2-byte incoming suffix */ 676d81f488SPhilippe Mathieu-Daudé 686d81f488SPhilippe Mathieu-Daudé /* SDMA command bits */ 696d81f488SPhilippe Mathieu-Daudé #define MP_ETH_CMD_TXHI (1 << 23) 706d81f488SPhilippe Mathieu-Daudé #define MP_ETH_CMD_TXLO (1 << 22) 716d81f488SPhilippe Mathieu-Daudé 726d81f488SPhilippe Mathieu-Daudé typedef struct mv88w8618_tx_desc { 736d81f488SPhilippe Mathieu-Daudé uint32_t cmdstat; 746d81f488SPhilippe Mathieu-Daudé uint16_t res; 756d81f488SPhilippe Mathieu-Daudé uint16_t bytes; 766d81f488SPhilippe Mathieu-Daudé uint32_t buffer; 776d81f488SPhilippe Mathieu-Daudé uint32_t next; 786d81f488SPhilippe Mathieu-Daudé } mv88w8618_tx_desc; 796d81f488SPhilippe Mathieu-Daudé 806d81f488SPhilippe Mathieu-Daudé typedef struct mv88w8618_rx_desc { 816d81f488SPhilippe Mathieu-Daudé uint32_t cmdstat; 826d81f488SPhilippe Mathieu-Daudé uint16_t bytes; 836d81f488SPhilippe Mathieu-Daudé uint16_t buffer_size; 846d81f488SPhilippe Mathieu-Daudé uint32_t buffer; 856d81f488SPhilippe Mathieu-Daudé uint32_t next; 866d81f488SPhilippe Mathieu-Daudé } mv88w8618_rx_desc; 876d81f488SPhilippe Mathieu-Daudé 886d81f488SPhilippe Mathieu-Daudé OBJECT_DECLARE_SIMPLE_TYPE(mv88w8618_eth_state, MV88W8618_ETH) 896d81f488SPhilippe Mathieu-Daudé 906d81f488SPhilippe Mathieu-Daudé struct mv88w8618_eth_state { 916d81f488SPhilippe Mathieu-Daudé /*< private >*/ 926d81f488SPhilippe Mathieu-Daudé SysBusDevice parent_obj; 936d81f488SPhilippe Mathieu-Daudé /*< public >*/ 946d81f488SPhilippe Mathieu-Daudé 956d81f488SPhilippe Mathieu-Daudé MemoryRegion iomem; 966d81f488SPhilippe Mathieu-Daudé qemu_irq irq; 976d81f488SPhilippe Mathieu-Daudé MemoryRegion *dma_mr; 986d81f488SPhilippe Mathieu-Daudé AddressSpace dma_as; 996d81f488SPhilippe Mathieu-Daudé uint32_t smir; 1006d81f488SPhilippe Mathieu-Daudé uint32_t icr; 1016d81f488SPhilippe Mathieu-Daudé uint32_t imr; 1026d81f488SPhilippe Mathieu-Daudé int mmio_index; 1036d81f488SPhilippe Mathieu-Daudé uint32_t vlan_header; 1046d81f488SPhilippe Mathieu-Daudé uint32_t tx_queue[2]; 1056d81f488SPhilippe Mathieu-Daudé uint32_t rx_queue[4]; 1066d81f488SPhilippe Mathieu-Daudé uint32_t frx_queue[4]; 1076d81f488SPhilippe Mathieu-Daudé uint32_t cur_rx[4]; 1086d81f488SPhilippe Mathieu-Daudé NICState *nic; 1096d81f488SPhilippe Mathieu-Daudé NICConf conf; 1106d81f488SPhilippe Mathieu-Daudé }; 1116d81f488SPhilippe Mathieu-Daudé 1126d81f488SPhilippe Mathieu-Daudé static void eth_rx_desc_put(AddressSpace *dma_as, uint32_t addr, 1136d81f488SPhilippe Mathieu-Daudé mv88w8618_rx_desc *desc) 1146d81f488SPhilippe Mathieu-Daudé { 1156d81f488SPhilippe Mathieu-Daudé cpu_to_le32s(&desc->cmdstat); 1166d81f488SPhilippe Mathieu-Daudé cpu_to_le16s(&desc->bytes); 1176d81f488SPhilippe Mathieu-Daudé cpu_to_le16s(&desc->buffer_size); 1186d81f488SPhilippe Mathieu-Daudé cpu_to_le32s(&desc->buffer); 1196d81f488SPhilippe Mathieu-Daudé cpu_to_le32s(&desc->next); 1206d81f488SPhilippe Mathieu-Daudé dma_memory_write(dma_as, addr, desc, sizeof(*desc), MEMTXATTRS_UNSPECIFIED); 1216d81f488SPhilippe Mathieu-Daudé } 1226d81f488SPhilippe Mathieu-Daudé 1236d81f488SPhilippe Mathieu-Daudé static void eth_rx_desc_get(AddressSpace *dma_as, uint32_t addr, 1246d81f488SPhilippe Mathieu-Daudé mv88w8618_rx_desc *desc) 1256d81f488SPhilippe Mathieu-Daudé { 1266d81f488SPhilippe Mathieu-Daudé dma_memory_read(dma_as, addr, desc, sizeof(*desc), MEMTXATTRS_UNSPECIFIED); 1276d81f488SPhilippe Mathieu-Daudé le32_to_cpus(&desc->cmdstat); 1286d81f488SPhilippe Mathieu-Daudé le16_to_cpus(&desc->bytes); 1296d81f488SPhilippe Mathieu-Daudé le16_to_cpus(&desc->buffer_size); 1306d81f488SPhilippe Mathieu-Daudé le32_to_cpus(&desc->buffer); 1316d81f488SPhilippe Mathieu-Daudé le32_to_cpus(&desc->next); 1326d81f488SPhilippe Mathieu-Daudé } 1336d81f488SPhilippe Mathieu-Daudé 1346d81f488SPhilippe Mathieu-Daudé static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size) 1356d81f488SPhilippe Mathieu-Daudé { 1366d81f488SPhilippe Mathieu-Daudé mv88w8618_eth_state *s = qemu_get_nic_opaque(nc); 1376d81f488SPhilippe Mathieu-Daudé uint32_t desc_addr; 1386d81f488SPhilippe Mathieu-Daudé mv88w8618_rx_desc desc; 1396d81f488SPhilippe Mathieu-Daudé int i; 1406d81f488SPhilippe Mathieu-Daudé 1416d81f488SPhilippe Mathieu-Daudé for (i = 0; i < 4; i++) { 1426d81f488SPhilippe Mathieu-Daudé desc_addr = s->cur_rx[i]; 1436d81f488SPhilippe Mathieu-Daudé if (!desc_addr) { 1446d81f488SPhilippe Mathieu-Daudé continue; 1456d81f488SPhilippe Mathieu-Daudé } 1466d81f488SPhilippe Mathieu-Daudé do { 1476d81f488SPhilippe Mathieu-Daudé eth_rx_desc_get(&s->dma_as, desc_addr, &desc); 1486d81f488SPhilippe Mathieu-Daudé if ((desc.cmdstat & MP_ETH_RX_OWN) && desc.buffer_size >= size) { 1496d81f488SPhilippe Mathieu-Daudé dma_memory_write(&s->dma_as, desc.buffer + s->vlan_header, 1506d81f488SPhilippe Mathieu-Daudé buf, size, MEMTXATTRS_UNSPECIFIED); 1516d81f488SPhilippe Mathieu-Daudé desc.bytes = size + s->vlan_header; 1526d81f488SPhilippe Mathieu-Daudé desc.cmdstat &= ~MP_ETH_RX_OWN; 1536d81f488SPhilippe Mathieu-Daudé s->cur_rx[i] = desc.next; 1546d81f488SPhilippe Mathieu-Daudé 1556d81f488SPhilippe Mathieu-Daudé s->icr |= MP_ETH_IRQ_RX; 1566d81f488SPhilippe Mathieu-Daudé if (s->icr & s->imr) { 1576d81f488SPhilippe Mathieu-Daudé qemu_irq_raise(s->irq); 1586d81f488SPhilippe Mathieu-Daudé } 1596d81f488SPhilippe Mathieu-Daudé eth_rx_desc_put(&s->dma_as, desc_addr, &desc); 1606d81f488SPhilippe Mathieu-Daudé return size; 1616d81f488SPhilippe Mathieu-Daudé } 1626d81f488SPhilippe Mathieu-Daudé desc_addr = desc.next; 1636d81f488SPhilippe Mathieu-Daudé } while (desc_addr != s->rx_queue[i]); 1646d81f488SPhilippe Mathieu-Daudé } 1656d81f488SPhilippe Mathieu-Daudé return size; 1666d81f488SPhilippe Mathieu-Daudé } 1676d81f488SPhilippe Mathieu-Daudé 1686d81f488SPhilippe Mathieu-Daudé static void eth_tx_desc_put(AddressSpace *dma_as, uint32_t addr, 1696d81f488SPhilippe Mathieu-Daudé mv88w8618_tx_desc *desc) 1706d81f488SPhilippe Mathieu-Daudé { 1716d81f488SPhilippe Mathieu-Daudé cpu_to_le32s(&desc->cmdstat); 1726d81f488SPhilippe Mathieu-Daudé cpu_to_le16s(&desc->res); 1736d81f488SPhilippe Mathieu-Daudé cpu_to_le16s(&desc->bytes); 1746d81f488SPhilippe Mathieu-Daudé cpu_to_le32s(&desc->buffer); 1756d81f488SPhilippe Mathieu-Daudé cpu_to_le32s(&desc->next); 1766d81f488SPhilippe Mathieu-Daudé dma_memory_write(dma_as, addr, desc, sizeof(*desc), MEMTXATTRS_UNSPECIFIED); 1776d81f488SPhilippe Mathieu-Daudé } 1786d81f488SPhilippe Mathieu-Daudé 1796d81f488SPhilippe Mathieu-Daudé static void eth_tx_desc_get(AddressSpace *dma_as, uint32_t addr, 1806d81f488SPhilippe Mathieu-Daudé mv88w8618_tx_desc *desc) 1816d81f488SPhilippe Mathieu-Daudé { 1826d81f488SPhilippe Mathieu-Daudé dma_memory_read(dma_as, addr, desc, sizeof(*desc), MEMTXATTRS_UNSPECIFIED); 1836d81f488SPhilippe Mathieu-Daudé le32_to_cpus(&desc->cmdstat); 1846d81f488SPhilippe Mathieu-Daudé le16_to_cpus(&desc->res); 1856d81f488SPhilippe Mathieu-Daudé le16_to_cpus(&desc->bytes); 1866d81f488SPhilippe Mathieu-Daudé le32_to_cpus(&desc->buffer); 1876d81f488SPhilippe Mathieu-Daudé le32_to_cpus(&desc->next); 1886d81f488SPhilippe Mathieu-Daudé } 1896d81f488SPhilippe Mathieu-Daudé 1906d81f488SPhilippe Mathieu-Daudé static void eth_send(mv88w8618_eth_state *s, int queue_index) 1916d81f488SPhilippe Mathieu-Daudé { 1926d81f488SPhilippe Mathieu-Daudé uint32_t desc_addr = s->tx_queue[queue_index]; 1936d81f488SPhilippe Mathieu-Daudé mv88w8618_tx_desc desc; 1946d81f488SPhilippe Mathieu-Daudé uint32_t next_desc; 1956d81f488SPhilippe Mathieu-Daudé uint8_t buf[2048]; 1966d81f488SPhilippe Mathieu-Daudé int len; 1976d81f488SPhilippe Mathieu-Daudé 1986d81f488SPhilippe Mathieu-Daudé do { 1996d81f488SPhilippe Mathieu-Daudé eth_tx_desc_get(&s->dma_as, desc_addr, &desc); 2006d81f488SPhilippe Mathieu-Daudé next_desc = desc.next; 2016d81f488SPhilippe Mathieu-Daudé if (desc.cmdstat & MP_ETH_TX_OWN) { 2026d81f488SPhilippe Mathieu-Daudé len = desc.bytes; 2036d81f488SPhilippe Mathieu-Daudé if (len < 2048) { 2046d81f488SPhilippe Mathieu-Daudé dma_memory_read(&s->dma_as, desc.buffer, buf, len, 2056d81f488SPhilippe Mathieu-Daudé MEMTXATTRS_UNSPECIFIED); 2066d81f488SPhilippe Mathieu-Daudé qemu_send_packet(qemu_get_queue(s->nic), buf, len); 2076d81f488SPhilippe Mathieu-Daudé } 2086d81f488SPhilippe Mathieu-Daudé desc.cmdstat &= ~MP_ETH_TX_OWN; 2096d81f488SPhilippe Mathieu-Daudé s->icr |= 1 << (MP_ETH_IRQ_TXLO_BIT - queue_index); 2106d81f488SPhilippe Mathieu-Daudé eth_tx_desc_put(&s->dma_as, desc_addr, &desc); 2116d81f488SPhilippe Mathieu-Daudé } 2126d81f488SPhilippe Mathieu-Daudé desc_addr = next_desc; 2136d81f488SPhilippe Mathieu-Daudé } while (desc_addr != s->tx_queue[queue_index]); 2146d81f488SPhilippe Mathieu-Daudé } 2156d81f488SPhilippe Mathieu-Daudé 2166d81f488SPhilippe Mathieu-Daudé static uint64_t mv88w8618_eth_read(void *opaque, hwaddr offset, 2176d81f488SPhilippe Mathieu-Daudé unsigned size) 2186d81f488SPhilippe Mathieu-Daudé { 2196d81f488SPhilippe Mathieu-Daudé mv88w8618_eth_state *s = opaque; 2206d81f488SPhilippe Mathieu-Daudé 2216d81f488SPhilippe Mathieu-Daudé switch (offset) { 2226d81f488SPhilippe Mathieu-Daudé case MP_ETH_SMIR: 2236d81f488SPhilippe Mathieu-Daudé if (s->smir & MP_ETH_SMIR_OPCODE) { 2246d81f488SPhilippe Mathieu-Daudé switch (s->smir & MP_ETH_SMIR_ADDR) { 2256d81f488SPhilippe Mathieu-Daudé case MP_ETH_PHY1_BMSR: 2266d81f488SPhilippe Mathieu-Daudé return MP_PHY_BMSR_LINK | MP_PHY_BMSR_AUTONEG | 2276d81f488SPhilippe Mathieu-Daudé MP_ETH_SMIR_RDVALID; 2286d81f488SPhilippe Mathieu-Daudé case MP_ETH_PHY1_PHYSID1: 2296d81f488SPhilippe Mathieu-Daudé return (MP_PHY_88E3015 >> 16) | MP_ETH_SMIR_RDVALID; 2306d81f488SPhilippe Mathieu-Daudé case MP_ETH_PHY1_PHYSID2: 2316d81f488SPhilippe Mathieu-Daudé return (MP_PHY_88E3015 & 0xFFFF) | MP_ETH_SMIR_RDVALID; 2326d81f488SPhilippe Mathieu-Daudé default: 2336d81f488SPhilippe Mathieu-Daudé return MP_ETH_SMIR_RDVALID; 2346d81f488SPhilippe Mathieu-Daudé } 2356d81f488SPhilippe Mathieu-Daudé } 2366d81f488SPhilippe Mathieu-Daudé return 0; 2376d81f488SPhilippe Mathieu-Daudé 2386d81f488SPhilippe Mathieu-Daudé case MP_ETH_ICR: 2396d81f488SPhilippe Mathieu-Daudé return s->icr; 2406d81f488SPhilippe Mathieu-Daudé 2416d81f488SPhilippe Mathieu-Daudé case MP_ETH_IMR: 2426d81f488SPhilippe Mathieu-Daudé return s->imr; 2436d81f488SPhilippe Mathieu-Daudé 2446d81f488SPhilippe Mathieu-Daudé case MP_ETH_FRDP0 ... MP_ETH_FRDP3: 2456d81f488SPhilippe Mathieu-Daudé return s->frx_queue[(offset - MP_ETH_FRDP0) / 4]; 2466d81f488SPhilippe Mathieu-Daudé 2476d81f488SPhilippe Mathieu-Daudé case MP_ETH_CRDP0 ... MP_ETH_CRDP3: 2486d81f488SPhilippe Mathieu-Daudé return s->rx_queue[(offset - MP_ETH_CRDP0) / 4]; 2496d81f488SPhilippe Mathieu-Daudé 2506d81f488SPhilippe Mathieu-Daudé case MP_ETH_CTDP0 ... MP_ETH_CTDP1: 2516d81f488SPhilippe Mathieu-Daudé return s->tx_queue[(offset - MP_ETH_CTDP0) / 4]; 2526d81f488SPhilippe Mathieu-Daudé 2536d81f488SPhilippe Mathieu-Daudé default: 2546d81f488SPhilippe Mathieu-Daudé return 0; 2556d81f488SPhilippe Mathieu-Daudé } 2566d81f488SPhilippe Mathieu-Daudé } 2576d81f488SPhilippe Mathieu-Daudé 2586d81f488SPhilippe Mathieu-Daudé static void mv88w8618_eth_write(void *opaque, hwaddr offset, 2596d81f488SPhilippe Mathieu-Daudé uint64_t value, unsigned size) 2606d81f488SPhilippe Mathieu-Daudé { 2616d81f488SPhilippe Mathieu-Daudé mv88w8618_eth_state *s = opaque; 2626d81f488SPhilippe Mathieu-Daudé 2636d81f488SPhilippe Mathieu-Daudé switch (offset) { 2646d81f488SPhilippe Mathieu-Daudé case MP_ETH_SMIR: 2656d81f488SPhilippe Mathieu-Daudé s->smir = value; 2666d81f488SPhilippe Mathieu-Daudé break; 2676d81f488SPhilippe Mathieu-Daudé 2686d81f488SPhilippe Mathieu-Daudé case MP_ETH_PCXR: 2696d81f488SPhilippe Mathieu-Daudé s->vlan_header = ((value >> MP_ETH_PCXR_2BSM_BIT) & 1) * 2; 2706d81f488SPhilippe Mathieu-Daudé break; 2716d81f488SPhilippe Mathieu-Daudé 2726d81f488SPhilippe Mathieu-Daudé case MP_ETH_SDCMR: 2736d81f488SPhilippe Mathieu-Daudé if (value & MP_ETH_CMD_TXHI) { 2746d81f488SPhilippe Mathieu-Daudé eth_send(s, 1); 2756d81f488SPhilippe Mathieu-Daudé } 2766d81f488SPhilippe Mathieu-Daudé if (value & MP_ETH_CMD_TXLO) { 2776d81f488SPhilippe Mathieu-Daudé eth_send(s, 0); 2786d81f488SPhilippe Mathieu-Daudé } 2796d81f488SPhilippe Mathieu-Daudé if (value & (MP_ETH_CMD_TXHI | MP_ETH_CMD_TXLO) && s->icr & s->imr) { 2806d81f488SPhilippe Mathieu-Daudé qemu_irq_raise(s->irq); 2816d81f488SPhilippe Mathieu-Daudé } 2826d81f488SPhilippe Mathieu-Daudé break; 2836d81f488SPhilippe Mathieu-Daudé 2846d81f488SPhilippe Mathieu-Daudé case MP_ETH_ICR: 2856d81f488SPhilippe Mathieu-Daudé s->icr &= value; 2866d81f488SPhilippe Mathieu-Daudé break; 2876d81f488SPhilippe Mathieu-Daudé 2886d81f488SPhilippe Mathieu-Daudé case MP_ETH_IMR: 2896d81f488SPhilippe Mathieu-Daudé s->imr = value; 2906d81f488SPhilippe Mathieu-Daudé if (s->icr & s->imr) { 2916d81f488SPhilippe Mathieu-Daudé qemu_irq_raise(s->irq); 2926d81f488SPhilippe Mathieu-Daudé } 2936d81f488SPhilippe Mathieu-Daudé break; 2946d81f488SPhilippe Mathieu-Daudé 2956d81f488SPhilippe Mathieu-Daudé case MP_ETH_FRDP0 ... MP_ETH_FRDP3: 2966d81f488SPhilippe Mathieu-Daudé s->frx_queue[(offset - MP_ETH_FRDP0) / 4] = value; 2976d81f488SPhilippe Mathieu-Daudé break; 2986d81f488SPhilippe Mathieu-Daudé 2996d81f488SPhilippe Mathieu-Daudé case MP_ETH_CRDP0 ... MP_ETH_CRDP3: 3006d81f488SPhilippe Mathieu-Daudé s->rx_queue[(offset - MP_ETH_CRDP0) / 4] = 3016d81f488SPhilippe Mathieu-Daudé s->cur_rx[(offset - MP_ETH_CRDP0) / 4] = value; 3026d81f488SPhilippe Mathieu-Daudé break; 3036d81f488SPhilippe Mathieu-Daudé 3046d81f488SPhilippe Mathieu-Daudé case MP_ETH_CTDP0 ... MP_ETH_CTDP1: 3056d81f488SPhilippe Mathieu-Daudé s->tx_queue[(offset - MP_ETH_CTDP0) / 4] = value; 3066d81f488SPhilippe Mathieu-Daudé break; 3076d81f488SPhilippe Mathieu-Daudé } 3086d81f488SPhilippe Mathieu-Daudé } 3096d81f488SPhilippe Mathieu-Daudé 3106d81f488SPhilippe Mathieu-Daudé static const MemoryRegionOps mv88w8618_eth_ops = { 3116d81f488SPhilippe Mathieu-Daudé .read = mv88w8618_eth_read, 3126d81f488SPhilippe Mathieu-Daudé .write = mv88w8618_eth_write, 3136d81f488SPhilippe Mathieu-Daudé .endianness = DEVICE_NATIVE_ENDIAN, 3146d81f488SPhilippe Mathieu-Daudé }; 3156d81f488SPhilippe Mathieu-Daudé 3166d81f488SPhilippe Mathieu-Daudé static void eth_cleanup(NetClientState *nc) 3176d81f488SPhilippe Mathieu-Daudé { 3186d81f488SPhilippe Mathieu-Daudé mv88w8618_eth_state *s = qemu_get_nic_opaque(nc); 3196d81f488SPhilippe Mathieu-Daudé 3206d81f488SPhilippe Mathieu-Daudé s->nic = NULL; 3216d81f488SPhilippe Mathieu-Daudé } 3226d81f488SPhilippe Mathieu-Daudé 3236d81f488SPhilippe Mathieu-Daudé static NetClientInfo net_mv88w8618_info = { 3246d81f488SPhilippe Mathieu-Daudé .type = NET_CLIENT_DRIVER_NIC, 3256d81f488SPhilippe Mathieu-Daudé .size = sizeof(NICState), 3266d81f488SPhilippe Mathieu-Daudé .receive = eth_receive, 3276d81f488SPhilippe Mathieu-Daudé .cleanup = eth_cleanup, 3286d81f488SPhilippe Mathieu-Daudé }; 3296d81f488SPhilippe Mathieu-Daudé 3306d81f488SPhilippe Mathieu-Daudé static void mv88w8618_eth_init(Object *obj) 3316d81f488SPhilippe Mathieu-Daudé { 3326d81f488SPhilippe Mathieu-Daudé SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 3336d81f488SPhilippe Mathieu-Daudé DeviceState *dev = DEVICE(sbd); 3346d81f488SPhilippe Mathieu-Daudé mv88w8618_eth_state *s = MV88W8618_ETH(dev); 3356d81f488SPhilippe Mathieu-Daudé 3366d81f488SPhilippe Mathieu-Daudé sysbus_init_irq(sbd, &s->irq); 3376d81f488SPhilippe Mathieu-Daudé memory_region_init_io(&s->iomem, obj, &mv88w8618_eth_ops, s, 3386d81f488SPhilippe Mathieu-Daudé "mv88w8618-eth", MP_ETH_SIZE); 3396d81f488SPhilippe Mathieu-Daudé sysbus_init_mmio(sbd, &s->iomem); 3406d81f488SPhilippe Mathieu-Daudé } 3416d81f488SPhilippe Mathieu-Daudé 3426d81f488SPhilippe Mathieu-Daudé static void mv88w8618_eth_realize(DeviceState *dev, Error **errp) 3436d81f488SPhilippe Mathieu-Daudé { 3446d81f488SPhilippe Mathieu-Daudé mv88w8618_eth_state *s = MV88W8618_ETH(dev); 3456d81f488SPhilippe Mathieu-Daudé 3466d81f488SPhilippe Mathieu-Daudé if (!s->dma_mr) { 3476d81f488SPhilippe Mathieu-Daudé error_setg(errp, TYPE_MV88W8618_ETH " 'dma-memory' link not set"); 3486d81f488SPhilippe Mathieu-Daudé return; 3496d81f488SPhilippe Mathieu-Daudé } 3506d81f488SPhilippe Mathieu-Daudé 3516d81f488SPhilippe Mathieu-Daudé address_space_init(&s->dma_as, s->dma_mr, "emac-dma"); 3526d81f488SPhilippe Mathieu-Daudé s->nic = qemu_new_nic(&net_mv88w8618_info, &s->conf, 353*7d0fefdfSAkihiko Odaki object_get_typename(OBJECT(dev)), dev->id, 354*7d0fefdfSAkihiko Odaki &dev->mem_reentrancy_guard, s); 3556d81f488SPhilippe Mathieu-Daudé } 3566d81f488SPhilippe Mathieu-Daudé 3576d81f488SPhilippe Mathieu-Daudé static const VMStateDescription mv88w8618_eth_vmsd = { 3586d81f488SPhilippe Mathieu-Daudé .name = "mv88w8618_eth", 3596d81f488SPhilippe Mathieu-Daudé .version_id = 1, 3606d81f488SPhilippe Mathieu-Daudé .minimum_version_id = 1, 3616d81f488SPhilippe Mathieu-Daudé .fields = (VMStateField[]) { 3626d81f488SPhilippe Mathieu-Daudé VMSTATE_UINT32(smir, mv88w8618_eth_state), 3636d81f488SPhilippe Mathieu-Daudé VMSTATE_UINT32(icr, mv88w8618_eth_state), 3646d81f488SPhilippe Mathieu-Daudé VMSTATE_UINT32(imr, mv88w8618_eth_state), 3656d81f488SPhilippe Mathieu-Daudé VMSTATE_UINT32(vlan_header, mv88w8618_eth_state), 3666d81f488SPhilippe Mathieu-Daudé VMSTATE_UINT32_ARRAY(tx_queue, mv88w8618_eth_state, 2), 3676d81f488SPhilippe Mathieu-Daudé VMSTATE_UINT32_ARRAY(rx_queue, mv88w8618_eth_state, 4), 3686d81f488SPhilippe Mathieu-Daudé VMSTATE_UINT32_ARRAY(frx_queue, mv88w8618_eth_state, 4), 3696d81f488SPhilippe Mathieu-Daudé VMSTATE_UINT32_ARRAY(cur_rx, mv88w8618_eth_state, 4), 3706d81f488SPhilippe Mathieu-Daudé VMSTATE_END_OF_LIST() 3716d81f488SPhilippe Mathieu-Daudé } 3726d81f488SPhilippe Mathieu-Daudé }; 3736d81f488SPhilippe Mathieu-Daudé 3746d81f488SPhilippe Mathieu-Daudé static Property mv88w8618_eth_properties[] = { 3756d81f488SPhilippe Mathieu-Daudé DEFINE_NIC_PROPERTIES(mv88w8618_eth_state, conf), 3766d81f488SPhilippe Mathieu-Daudé DEFINE_PROP_LINK("dma-memory", mv88w8618_eth_state, dma_mr, 3776d81f488SPhilippe Mathieu-Daudé TYPE_MEMORY_REGION, MemoryRegion *), 3786d81f488SPhilippe Mathieu-Daudé DEFINE_PROP_END_OF_LIST(), 3796d81f488SPhilippe Mathieu-Daudé }; 3806d81f488SPhilippe Mathieu-Daudé 3816d81f488SPhilippe Mathieu-Daudé static void mv88w8618_eth_class_init(ObjectClass *klass, void *data) 3826d81f488SPhilippe Mathieu-Daudé { 3836d81f488SPhilippe Mathieu-Daudé DeviceClass *dc = DEVICE_CLASS(klass); 3846d81f488SPhilippe Mathieu-Daudé 3856d81f488SPhilippe Mathieu-Daudé dc->vmsd = &mv88w8618_eth_vmsd; 3866d81f488SPhilippe Mathieu-Daudé device_class_set_props(dc, mv88w8618_eth_properties); 3876d81f488SPhilippe Mathieu-Daudé dc->realize = mv88w8618_eth_realize; 3886d81f488SPhilippe Mathieu-Daudé } 3896d81f488SPhilippe Mathieu-Daudé 3906d81f488SPhilippe Mathieu-Daudé static const TypeInfo mv88w8618_eth_info = { 3916d81f488SPhilippe Mathieu-Daudé .name = TYPE_MV88W8618_ETH, 3926d81f488SPhilippe Mathieu-Daudé .parent = TYPE_SYS_BUS_DEVICE, 3936d81f488SPhilippe Mathieu-Daudé .instance_size = sizeof(mv88w8618_eth_state), 3946d81f488SPhilippe Mathieu-Daudé .instance_init = mv88w8618_eth_init, 3956d81f488SPhilippe Mathieu-Daudé .class_init = mv88w8618_eth_class_init, 3966d81f488SPhilippe Mathieu-Daudé }; 3976d81f488SPhilippe Mathieu-Daudé 3986d81f488SPhilippe Mathieu-Daudé static void musicpal_register_types(void) 3996d81f488SPhilippe Mathieu-Daudé { 4006d81f488SPhilippe Mathieu-Daudé type_register_static(&mv88w8618_eth_info); 4016d81f488SPhilippe Mathieu-Daudé } 4026d81f488SPhilippe Mathieu-Daudé 4036d81f488SPhilippe Mathieu-Daudé type_init(musicpal_register_types) 4046d81f488SPhilippe Mathieu-Daudé 405