108f787a3SHao Wu /* 208f787a3SHao Wu * Nuvoton NPCM7xx/8xx GMAC Module 308f787a3SHao Wu * 408f787a3SHao Wu * Copyright 2024 Google LLC 508f787a3SHao Wu * Authors: 608f787a3SHao Wu * Hao Wu <wuhaotsh@google.com> 708f787a3SHao Wu * Nabih Estefan <nabihestefan@google.com> 808f787a3SHao Wu * 908f787a3SHao Wu * This program is free software; you can redistribute it and/or modify it 1008f787a3SHao Wu * under the terms of the GNU General Public License as published by the 1108f787a3SHao Wu * Free Software Foundation; either version 2 of the License, or 1208f787a3SHao Wu * (at your option) any later version. 1308f787a3SHao Wu * 1408f787a3SHao Wu * This program is distributed in the hope that it will be useful, but WITHOUT 1508f787a3SHao Wu * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1608f787a3SHao Wu * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1708f787a3SHao Wu * for more details. 1808f787a3SHao Wu * 1908f787a3SHao Wu * Unsupported/unimplemented features: 2008f787a3SHao Wu * - MII is not implemented, MII_ADDR.BUSY and MII_DATA always return zero 2108f787a3SHao Wu * - Precision timestamp (PTP) is not implemented. 2208f787a3SHao Wu */ 2308f787a3SHao Wu 2408f787a3SHao Wu #include "qemu/osdep.h" 2508f787a3SHao Wu 2608f787a3SHao Wu #include "hw/registerfields.h" 2708f787a3SHao Wu #include "hw/net/mii.h" 2808f787a3SHao Wu #include "hw/net/npcm_gmac.h" 2908f787a3SHao Wu #include "migration/vmstate.h" 30*a4dd7a1dSNabih Estefan Diaz #include "net/checksum.h" 31*a4dd7a1dSNabih Estefan Diaz #include "net/eth.h" 32*a4dd7a1dSNabih Estefan Diaz #include "net/net.h" 33*a4dd7a1dSNabih Estefan Diaz #include "qemu/cutils.h" 3408f787a3SHao Wu #include "qemu/log.h" 3508f787a3SHao Wu #include "qemu/units.h" 3608f787a3SHao Wu #include "sysemu/dma.h" 3708f787a3SHao Wu #include "trace.h" 3808f787a3SHao Wu 3908f787a3SHao Wu REG32(NPCM_DMA_BUS_MODE, 0x1000) 4008f787a3SHao Wu REG32(NPCM_DMA_XMT_POLL_DEMAND, 0x1004) 4108f787a3SHao Wu REG32(NPCM_DMA_RCV_POLL_DEMAND, 0x1008) 4208f787a3SHao Wu REG32(NPCM_DMA_RX_BASE_ADDR, 0x100c) 4308f787a3SHao Wu REG32(NPCM_DMA_TX_BASE_ADDR, 0x1010) 4408f787a3SHao Wu REG32(NPCM_DMA_STATUS, 0x1014) 4508f787a3SHao Wu REG32(NPCM_DMA_CONTROL, 0x1018) 4608f787a3SHao Wu REG32(NPCM_DMA_INTR_ENA, 0x101c) 4708f787a3SHao Wu REG32(NPCM_DMA_MISSED_FRAME_CTR, 0x1020) 4808f787a3SHao Wu REG32(NPCM_DMA_HOST_TX_DESC, 0x1048) 4908f787a3SHao Wu REG32(NPCM_DMA_HOST_RX_DESC, 0x104c) 5008f787a3SHao Wu REG32(NPCM_DMA_CUR_TX_BUF_ADDR, 0x1050) 5108f787a3SHao Wu REG32(NPCM_DMA_CUR_RX_BUF_ADDR, 0x1054) 5208f787a3SHao Wu REG32(NPCM_DMA_HW_FEATURE, 0x1058) 5308f787a3SHao Wu 5408f787a3SHao Wu REG32(NPCM_GMAC_MAC_CONFIG, 0x0) 5508f787a3SHao Wu REG32(NPCM_GMAC_FRAME_FILTER, 0x4) 5608f787a3SHao Wu REG32(NPCM_GMAC_HASH_HIGH, 0x8) 5708f787a3SHao Wu REG32(NPCM_GMAC_HASH_LOW, 0xc) 5808f787a3SHao Wu REG32(NPCM_GMAC_MII_ADDR, 0x10) 5908f787a3SHao Wu REG32(NPCM_GMAC_MII_DATA, 0x14) 6008f787a3SHao Wu REG32(NPCM_GMAC_FLOW_CTRL, 0x18) 6108f787a3SHao Wu REG32(NPCM_GMAC_VLAN_FLAG, 0x1c) 6208f787a3SHao Wu REG32(NPCM_GMAC_VERSION, 0x20) 6308f787a3SHao Wu REG32(NPCM_GMAC_WAKEUP_FILTER, 0x28) 6408f787a3SHao Wu REG32(NPCM_GMAC_PMT, 0x2c) 6508f787a3SHao Wu REG32(NPCM_GMAC_LPI_CTRL, 0x30) 6608f787a3SHao Wu REG32(NPCM_GMAC_TIMER_CTRL, 0x34) 6708f787a3SHao Wu REG32(NPCM_GMAC_INT_STATUS, 0x38) 6808f787a3SHao Wu REG32(NPCM_GMAC_INT_MASK, 0x3c) 6908f787a3SHao Wu REG32(NPCM_GMAC_MAC0_ADDR_HI, 0x40) 7008f787a3SHao Wu REG32(NPCM_GMAC_MAC0_ADDR_LO, 0x44) 7108f787a3SHao Wu REG32(NPCM_GMAC_MAC1_ADDR_HI, 0x48) 7208f787a3SHao Wu REG32(NPCM_GMAC_MAC1_ADDR_LO, 0x4c) 7308f787a3SHao Wu REG32(NPCM_GMAC_MAC2_ADDR_HI, 0x50) 7408f787a3SHao Wu REG32(NPCM_GMAC_MAC2_ADDR_LO, 0x54) 7508f787a3SHao Wu REG32(NPCM_GMAC_MAC3_ADDR_HI, 0x58) 7608f787a3SHao Wu REG32(NPCM_GMAC_MAC3_ADDR_LO, 0x5c) 7708f787a3SHao Wu REG32(NPCM_GMAC_RGMII_STATUS, 0xd8) 7808f787a3SHao Wu REG32(NPCM_GMAC_WATCHDOG, 0xdc) 7908f787a3SHao Wu REG32(NPCM_GMAC_PTP_TCR, 0x700) 8008f787a3SHao Wu REG32(NPCM_GMAC_PTP_SSIR, 0x704) 8108f787a3SHao Wu REG32(NPCM_GMAC_PTP_STSR, 0x708) 8208f787a3SHao Wu REG32(NPCM_GMAC_PTP_STNSR, 0x70c) 8308f787a3SHao Wu REG32(NPCM_GMAC_PTP_STSUR, 0x710) 8408f787a3SHao Wu REG32(NPCM_GMAC_PTP_STNSUR, 0x714) 8508f787a3SHao Wu REG32(NPCM_GMAC_PTP_TAR, 0x718) 8608f787a3SHao Wu REG32(NPCM_GMAC_PTP_TTSR, 0x71c) 8708f787a3SHao Wu 8808f787a3SHao Wu /* Register Fields */ 8908f787a3SHao Wu #define NPCM_GMAC_MII_ADDR_BUSY BIT(0) 9008f787a3SHao Wu #define NPCM_GMAC_MII_ADDR_WRITE BIT(1) 9108f787a3SHao Wu #define NPCM_GMAC_MII_ADDR_GR(rv) extract16((rv), 6, 5) 9208f787a3SHao Wu #define NPCM_GMAC_MII_ADDR_PA(rv) extract16((rv), 11, 5) 9308f787a3SHao Wu 9408f787a3SHao Wu #define NPCM_GMAC_INT_MASK_LPIIM BIT(10) 9508f787a3SHao Wu #define NPCM_GMAC_INT_MASK_PMTM BIT(3) 9608f787a3SHao Wu #define NPCM_GMAC_INT_MASK_RGIM BIT(0) 9708f787a3SHao Wu 9808f787a3SHao Wu #define NPCM_DMA_BUS_MODE_SWR BIT(0) 9908f787a3SHao Wu 10008f787a3SHao Wu static const uint32_t npcm_gmac_cold_reset_values[NPCM_GMAC_NR_REGS] = { 10108f787a3SHao Wu /* Reduce version to 3.2 so that the kernel can enable interrupt. */ 10208f787a3SHao Wu [R_NPCM_GMAC_VERSION] = 0x00001032, 10308f787a3SHao Wu [R_NPCM_GMAC_TIMER_CTRL] = 0x03e80000, 10408f787a3SHao Wu [R_NPCM_GMAC_MAC0_ADDR_HI] = 0x8000ffff, 10508f787a3SHao Wu [R_NPCM_GMAC_MAC0_ADDR_LO] = 0xffffffff, 10608f787a3SHao Wu [R_NPCM_GMAC_MAC1_ADDR_HI] = 0x0000ffff, 10708f787a3SHao Wu [R_NPCM_GMAC_MAC1_ADDR_LO] = 0xffffffff, 10808f787a3SHao Wu [R_NPCM_GMAC_MAC2_ADDR_HI] = 0x0000ffff, 10908f787a3SHao Wu [R_NPCM_GMAC_MAC2_ADDR_LO] = 0xffffffff, 11008f787a3SHao Wu [R_NPCM_GMAC_MAC3_ADDR_HI] = 0x0000ffff, 11108f787a3SHao Wu [R_NPCM_GMAC_MAC3_ADDR_LO] = 0xffffffff, 11208f787a3SHao Wu [R_NPCM_GMAC_PTP_TCR] = 0x00002000, 11308f787a3SHao Wu [R_NPCM_DMA_BUS_MODE] = 0x00020101, 11408f787a3SHao Wu [R_NPCM_DMA_HW_FEATURE] = 0x100d4f37, 11508f787a3SHao Wu }; 11608f787a3SHao Wu 11708f787a3SHao Wu static const uint16_t phy_reg_init[] = { 11808f787a3SHao Wu [MII_BMCR] = MII_BMCR_AUTOEN | MII_BMCR_FD | MII_BMCR_SPEED1000, 11908f787a3SHao Wu [MII_BMSR] = MII_BMSR_100TX_FD | MII_BMSR_100TX_HD | MII_BMSR_10T_FD | 12008f787a3SHao Wu MII_BMSR_10T_HD | MII_BMSR_EXTSTAT | MII_BMSR_AUTONEG | 12108f787a3SHao Wu MII_BMSR_LINK_ST | MII_BMSR_EXTCAP, 12208f787a3SHao Wu [MII_PHYID1] = 0x0362, 12308f787a3SHao Wu [MII_PHYID2] = 0x5e6a, 12408f787a3SHao Wu [MII_ANAR] = MII_ANAR_TXFD | MII_ANAR_TX | MII_ANAR_10FD | 12508f787a3SHao Wu MII_ANAR_10 | MII_ANAR_CSMACD, 12608f787a3SHao Wu [MII_ANLPAR] = MII_ANLPAR_ACK | MII_ANLPAR_PAUSE | 12708f787a3SHao Wu MII_ANLPAR_TXFD | MII_ANLPAR_TX | MII_ANLPAR_10FD | 12808f787a3SHao Wu MII_ANLPAR_10 | MII_ANLPAR_CSMACD, 12908f787a3SHao Wu [MII_ANER] = 0x64 | MII_ANER_NWAY, 13008f787a3SHao Wu [MII_ANNP] = 0x2001, 13108f787a3SHao Wu [MII_CTRL1000] = MII_CTRL1000_FULL, 13208f787a3SHao Wu [MII_STAT1000] = MII_STAT1000_FULL, 13308f787a3SHao Wu [MII_EXTSTAT] = 0x3000, /* 1000BASTE_T full-duplex capable */ 13408f787a3SHao Wu }; 13508f787a3SHao Wu 13608f787a3SHao Wu static void npcm_gmac_soft_reset(NPCMGMACState *gmac) 13708f787a3SHao Wu { 13808f787a3SHao Wu memcpy(gmac->regs, npcm_gmac_cold_reset_values, 13908f787a3SHao Wu NPCM_GMAC_NR_REGS * sizeof(uint32_t)); 14008f787a3SHao Wu /* Clear reset bits */ 14108f787a3SHao Wu gmac->regs[R_NPCM_DMA_BUS_MODE] &= ~NPCM_DMA_BUS_MODE_SWR; 14208f787a3SHao Wu } 14308f787a3SHao Wu 14408f787a3SHao Wu static void gmac_phy_set_link(NPCMGMACState *gmac, bool active) 14508f787a3SHao Wu { 14608f787a3SHao Wu /* Autonegotiation status mirrors link status. */ 14708f787a3SHao Wu if (active) { 14808f787a3SHao Wu gmac->phy_regs[0][MII_BMSR] |= (MII_BMSR_LINK_ST | MII_BMSR_AN_COMP); 14908f787a3SHao Wu } else { 15008f787a3SHao Wu gmac->phy_regs[0][MII_BMSR] &= ~(MII_BMSR_LINK_ST | MII_BMSR_AN_COMP); 15108f787a3SHao Wu } 15208f787a3SHao Wu } 15308f787a3SHao Wu 15408f787a3SHao Wu static bool gmac_can_receive(NetClientState *nc) 15508f787a3SHao Wu { 156*a4dd7a1dSNabih Estefan Diaz NPCMGMACState *gmac = NPCM_GMAC(qemu_get_nic_opaque(nc)); 157*a4dd7a1dSNabih Estefan Diaz 158*a4dd7a1dSNabih Estefan Diaz /* If GMAC receive is disabled. */ 159*a4dd7a1dSNabih Estefan Diaz if (!(gmac->regs[R_NPCM_GMAC_MAC_CONFIG] & NPCM_GMAC_MAC_CONFIG_RX_EN)) { 160*a4dd7a1dSNabih Estefan Diaz return false; 161*a4dd7a1dSNabih Estefan Diaz } 162*a4dd7a1dSNabih Estefan Diaz 163*a4dd7a1dSNabih Estefan Diaz /* If GMAC DMA RX is stopped. */ 164*a4dd7a1dSNabih Estefan Diaz if (!(gmac->regs[R_NPCM_DMA_CONTROL] & NPCM_DMA_CONTROL_START_STOP_RX)) { 165*a4dd7a1dSNabih Estefan Diaz return false; 166*a4dd7a1dSNabih Estefan Diaz } 16708f787a3SHao Wu return true; 16808f787a3SHao Wu } 16908f787a3SHao Wu 17008f787a3SHao Wu /* 17108f787a3SHao Wu * Function that updates the GMAC IRQ 17208f787a3SHao Wu * It find the logical OR of the enabled bits for NIS (if enabled) 17308f787a3SHao Wu * It find the logical OR of the enabled bits for AIS (if enabled) 17408f787a3SHao Wu */ 17508f787a3SHao Wu static void gmac_update_irq(NPCMGMACState *gmac) 17608f787a3SHao Wu { 17708f787a3SHao Wu /* 17808f787a3SHao Wu * Check if the normal interrupts summary is enabled 17908f787a3SHao Wu * if so, add the bits for the summary that are enabled 18008f787a3SHao Wu */ 18108f787a3SHao Wu if (gmac->regs[R_NPCM_DMA_INTR_ENA] & gmac->regs[R_NPCM_DMA_STATUS] & 18208f787a3SHao Wu (NPCM_DMA_INTR_ENAB_NIE_BITS)) { 18308f787a3SHao Wu gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_NIS; 18408f787a3SHao Wu } 18508f787a3SHao Wu /* 18608f787a3SHao Wu * Check if the abnormal interrupts summary is enabled 18708f787a3SHao Wu * if so, add the bits for the summary that are enabled 18808f787a3SHao Wu */ 18908f787a3SHao Wu if (gmac->regs[R_NPCM_DMA_INTR_ENA] & gmac->regs[R_NPCM_DMA_STATUS] & 19008f787a3SHao Wu (NPCM_DMA_INTR_ENAB_AIE_BITS)) { 19108f787a3SHao Wu gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_AIS; 19208f787a3SHao Wu } 19308f787a3SHao Wu 19408f787a3SHao Wu /* Get the logical OR of both normal and abnormal interrupts */ 19508f787a3SHao Wu int level = !!((gmac->regs[R_NPCM_DMA_STATUS] & 19608f787a3SHao Wu gmac->regs[R_NPCM_DMA_INTR_ENA] & 19708f787a3SHao Wu NPCM_DMA_STATUS_NIS) | 19808f787a3SHao Wu (gmac->regs[R_NPCM_DMA_STATUS] & 19908f787a3SHao Wu gmac->regs[R_NPCM_DMA_INTR_ENA] & 20008f787a3SHao Wu NPCM_DMA_STATUS_AIS)); 20108f787a3SHao Wu 20208f787a3SHao Wu /* Set the IRQ */ 20308f787a3SHao Wu trace_npcm_gmac_update_irq(DEVICE(gmac)->canonical_path, 20408f787a3SHao Wu gmac->regs[R_NPCM_DMA_STATUS], 20508f787a3SHao Wu gmac->regs[R_NPCM_DMA_INTR_ENA], 20608f787a3SHao Wu level); 20708f787a3SHao Wu qemu_set_irq(gmac->irq, level); 20808f787a3SHao Wu } 20908f787a3SHao Wu 210*a4dd7a1dSNabih Estefan Diaz static int gmac_read_rx_desc(dma_addr_t addr, struct NPCMGMACRxDesc *desc) 211*a4dd7a1dSNabih Estefan Diaz { 212*a4dd7a1dSNabih Estefan Diaz if (dma_memory_read(&address_space_memory, addr, desc, 213*a4dd7a1dSNabih Estefan Diaz sizeof(*desc), MEMTXATTRS_UNSPECIFIED)) { 214*a4dd7a1dSNabih Estefan Diaz qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to read descriptor @ 0x%" 215*a4dd7a1dSNabih Estefan Diaz HWADDR_PRIx "\n", __func__, addr); 216*a4dd7a1dSNabih Estefan Diaz return -1; 217*a4dd7a1dSNabih Estefan Diaz } 218*a4dd7a1dSNabih Estefan Diaz desc->rdes0 = le32_to_cpu(desc->rdes0); 219*a4dd7a1dSNabih Estefan Diaz desc->rdes1 = le32_to_cpu(desc->rdes1); 220*a4dd7a1dSNabih Estefan Diaz desc->rdes2 = le32_to_cpu(desc->rdes2); 221*a4dd7a1dSNabih Estefan Diaz desc->rdes3 = le32_to_cpu(desc->rdes3); 222*a4dd7a1dSNabih Estefan Diaz return 0; 223*a4dd7a1dSNabih Estefan Diaz } 224*a4dd7a1dSNabih Estefan Diaz 225*a4dd7a1dSNabih Estefan Diaz static int gmac_write_rx_desc(dma_addr_t addr, struct NPCMGMACRxDesc *desc) 226*a4dd7a1dSNabih Estefan Diaz { 227*a4dd7a1dSNabih Estefan Diaz struct NPCMGMACRxDesc le_desc; 228*a4dd7a1dSNabih Estefan Diaz le_desc.rdes0 = cpu_to_le32(desc->rdes0); 229*a4dd7a1dSNabih Estefan Diaz le_desc.rdes1 = cpu_to_le32(desc->rdes1); 230*a4dd7a1dSNabih Estefan Diaz le_desc.rdes2 = cpu_to_le32(desc->rdes2); 231*a4dd7a1dSNabih Estefan Diaz le_desc.rdes3 = cpu_to_le32(desc->rdes3); 232*a4dd7a1dSNabih Estefan Diaz if (dma_memory_write(&address_space_memory, addr, &le_desc, 233*a4dd7a1dSNabih Estefan Diaz sizeof(le_desc), MEMTXATTRS_UNSPECIFIED)) { 234*a4dd7a1dSNabih Estefan Diaz qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to write descriptor @ 0x%" 235*a4dd7a1dSNabih Estefan Diaz HWADDR_PRIx "\n", __func__, addr); 236*a4dd7a1dSNabih Estefan Diaz return -1; 237*a4dd7a1dSNabih Estefan Diaz } 238*a4dd7a1dSNabih Estefan Diaz return 0; 239*a4dd7a1dSNabih Estefan Diaz } 240*a4dd7a1dSNabih Estefan Diaz 241*a4dd7a1dSNabih Estefan Diaz static int gmac_rx_transfer_frame_to_buffer(uint32_t rx_buf_len, 242*a4dd7a1dSNabih Estefan Diaz uint32_t *left_frame, 243*a4dd7a1dSNabih Estefan Diaz uint32_t rx_buf_addr, 244*a4dd7a1dSNabih Estefan Diaz bool *eof_transferred, 245*a4dd7a1dSNabih Estefan Diaz const uint8_t **frame_ptr, 246*a4dd7a1dSNabih Estefan Diaz uint16_t *transferred) 247*a4dd7a1dSNabih Estefan Diaz { 248*a4dd7a1dSNabih Estefan Diaz uint32_t to_transfer; 249*a4dd7a1dSNabih Estefan Diaz /* 250*a4dd7a1dSNabih Estefan Diaz * Check that buffer is bigger than the frame being transfered 251*a4dd7a1dSNabih Estefan Diaz * If bigger then transfer only whats left of frame 252*a4dd7a1dSNabih Estefan Diaz * Else, fill frame with all the content possible 253*a4dd7a1dSNabih Estefan Diaz */ 254*a4dd7a1dSNabih Estefan Diaz if (rx_buf_len >= *left_frame) { 255*a4dd7a1dSNabih Estefan Diaz to_transfer = *left_frame; 256*a4dd7a1dSNabih Estefan Diaz *eof_transferred = true; 257*a4dd7a1dSNabih Estefan Diaz } else { 258*a4dd7a1dSNabih Estefan Diaz to_transfer = rx_buf_len; 259*a4dd7a1dSNabih Estefan Diaz } 260*a4dd7a1dSNabih Estefan Diaz 261*a4dd7a1dSNabih Estefan Diaz /* write frame part to memory */ 262*a4dd7a1dSNabih Estefan Diaz if (dma_memory_write(&address_space_memory, (uint64_t) rx_buf_addr, 263*a4dd7a1dSNabih Estefan Diaz *frame_ptr, to_transfer, MEMTXATTRS_UNSPECIFIED)) { 264*a4dd7a1dSNabih Estefan Diaz return -1; 265*a4dd7a1dSNabih Estefan Diaz } 266*a4dd7a1dSNabih Estefan Diaz 267*a4dd7a1dSNabih Estefan Diaz /* update frame pointer and size of whats left of frame */ 268*a4dd7a1dSNabih Estefan Diaz *frame_ptr += to_transfer; 269*a4dd7a1dSNabih Estefan Diaz *left_frame -= to_transfer; 270*a4dd7a1dSNabih Estefan Diaz *transferred += to_transfer; 271*a4dd7a1dSNabih Estefan Diaz 272*a4dd7a1dSNabih Estefan Diaz return 0; 273*a4dd7a1dSNabih Estefan Diaz } 274*a4dd7a1dSNabih Estefan Diaz 275*a4dd7a1dSNabih Estefan Diaz static void gmac_dma_set_state(NPCMGMACState *gmac, int shift, uint32_t state) 276*a4dd7a1dSNabih Estefan Diaz { 277*a4dd7a1dSNabih Estefan Diaz gmac->regs[R_NPCM_DMA_STATUS] = deposit32(gmac->regs[R_NPCM_DMA_STATUS], 278*a4dd7a1dSNabih Estefan Diaz shift, 3, state); 279*a4dd7a1dSNabih Estefan Diaz } 280*a4dd7a1dSNabih Estefan Diaz 28108f787a3SHao Wu static ssize_t gmac_receive(NetClientState *nc, const uint8_t *buf, size_t len) 28208f787a3SHao Wu { 283*a4dd7a1dSNabih Estefan Diaz /* 284*a4dd7a1dSNabih Estefan Diaz * Comments have steps that relate to the 285*a4dd7a1dSNabih Estefan Diaz * receiving process steps in pg 386 286*a4dd7a1dSNabih Estefan Diaz */ 287*a4dd7a1dSNabih Estefan Diaz NPCMGMACState *gmac = NPCM_GMAC(qemu_get_nic_opaque(nc)); 288*a4dd7a1dSNabih Estefan Diaz uint32_t left_frame = len; 289*a4dd7a1dSNabih Estefan Diaz const uint8_t *frame_ptr = buf; 290*a4dd7a1dSNabih Estefan Diaz uint32_t desc_addr; 291*a4dd7a1dSNabih Estefan Diaz uint32_t rx_buf_len, rx_buf_addr; 292*a4dd7a1dSNabih Estefan Diaz struct NPCMGMACRxDesc rx_desc; 293*a4dd7a1dSNabih Estefan Diaz uint16_t transferred = 0; 294*a4dd7a1dSNabih Estefan Diaz bool eof_transferred = false; 295*a4dd7a1dSNabih Estefan Diaz 296*a4dd7a1dSNabih Estefan Diaz trace_npcm_gmac_packet_receive(DEVICE(gmac)->canonical_path, len); 297*a4dd7a1dSNabih Estefan Diaz if (!gmac_can_receive(nc)) { 298*a4dd7a1dSNabih Estefan Diaz qemu_log_mask(LOG_GUEST_ERROR, "GMAC Currently is not able for Rx"); 299*a4dd7a1dSNabih Estefan Diaz return -1; 300*a4dd7a1dSNabih Estefan Diaz } 301*a4dd7a1dSNabih Estefan Diaz if (!gmac->regs[R_NPCM_DMA_HOST_RX_DESC]) { 302*a4dd7a1dSNabih Estefan Diaz gmac->regs[R_NPCM_DMA_HOST_RX_DESC] = 303*a4dd7a1dSNabih Estefan Diaz NPCM_DMA_HOST_RX_DESC_MASK(gmac->regs[R_NPCM_DMA_RX_BASE_ADDR]); 304*a4dd7a1dSNabih Estefan Diaz } 305*a4dd7a1dSNabih Estefan Diaz desc_addr = NPCM_DMA_HOST_RX_DESC_MASK(gmac->regs[R_NPCM_DMA_HOST_RX_DESC]); 306*a4dd7a1dSNabih Estefan Diaz 307*a4dd7a1dSNabih Estefan Diaz /* step 1 */ 308*a4dd7a1dSNabih Estefan Diaz gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT, 309*a4dd7a1dSNabih Estefan Diaz NPCM_DMA_STATUS_RX_RUNNING_FETCHING_STATE); 310*a4dd7a1dSNabih Estefan Diaz trace_npcm_gmac_packet_desc_read(DEVICE(gmac)->canonical_path, desc_addr); 311*a4dd7a1dSNabih Estefan Diaz if (gmac_read_rx_desc(desc_addr, &rx_desc)) { 312*a4dd7a1dSNabih Estefan Diaz qemu_log_mask(LOG_GUEST_ERROR, "RX Descriptor @ 0x%x cant be read\n", 313*a4dd7a1dSNabih Estefan Diaz desc_addr); 314*a4dd7a1dSNabih Estefan Diaz gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT, 315*a4dd7a1dSNabih Estefan Diaz NPCM_DMA_STATUS_RX_SUSPENDED_STATE); 316*a4dd7a1dSNabih Estefan Diaz return -1; 317*a4dd7a1dSNabih Estefan Diaz } 318*a4dd7a1dSNabih Estefan Diaz 319*a4dd7a1dSNabih Estefan Diaz /* step 2 */ 320*a4dd7a1dSNabih Estefan Diaz if (!(rx_desc.rdes0 & RX_DESC_RDES0_OWN)) { 321*a4dd7a1dSNabih Estefan Diaz qemu_log_mask(LOG_GUEST_ERROR, 322*a4dd7a1dSNabih Estefan Diaz "RX Descriptor @ 0x%x is owned by software\n", 323*a4dd7a1dSNabih Estefan Diaz desc_addr); 324*a4dd7a1dSNabih Estefan Diaz gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_RU; 325*a4dd7a1dSNabih Estefan Diaz gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_RI; 326*a4dd7a1dSNabih Estefan Diaz gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT, 327*a4dd7a1dSNabih Estefan Diaz NPCM_DMA_STATUS_RX_SUSPENDED_STATE); 328*a4dd7a1dSNabih Estefan Diaz gmac_update_irq(gmac); 329*a4dd7a1dSNabih Estefan Diaz return len; 330*a4dd7a1dSNabih Estefan Diaz } 331*a4dd7a1dSNabih Estefan Diaz /* step 3 */ 332*a4dd7a1dSNabih Estefan Diaz /* 333*a4dd7a1dSNabih Estefan Diaz * TODO -- 334*a4dd7a1dSNabih Estefan Diaz * Implement all frame filtering and processing (with its own interrupts) 335*a4dd7a1dSNabih Estefan Diaz */ 336*a4dd7a1dSNabih Estefan Diaz trace_npcm_gmac_debug_desc_data(DEVICE(gmac)->canonical_path, &rx_desc, 337*a4dd7a1dSNabih Estefan Diaz rx_desc.rdes0, rx_desc.rdes1, rx_desc.rdes2, 338*a4dd7a1dSNabih Estefan Diaz rx_desc.rdes3); 339*a4dd7a1dSNabih Estefan Diaz /* Clear rdes0 for the incoming descriptor and set FS in first descriptor.*/ 340*a4dd7a1dSNabih Estefan Diaz rx_desc.rdes0 = RX_DESC_RDES0_FIRST_DESC_MASK; 341*a4dd7a1dSNabih Estefan Diaz 342*a4dd7a1dSNabih Estefan Diaz gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT, 343*a4dd7a1dSNabih Estefan Diaz NPCM_DMA_STATUS_RX_RUNNING_TRANSFERRING_STATE); 344*a4dd7a1dSNabih Estefan Diaz 345*a4dd7a1dSNabih Estefan Diaz /* Pad the frame with FCS as the kernel driver will strip it away. */ 346*a4dd7a1dSNabih Estefan Diaz left_frame += ETH_FCS_LEN; 347*a4dd7a1dSNabih Estefan Diaz 348*a4dd7a1dSNabih Estefan Diaz /* repeat while we still have frame to transfer to memory */ 349*a4dd7a1dSNabih Estefan Diaz while (!eof_transferred) { 350*a4dd7a1dSNabih Estefan Diaz /* Return descriptor no matter what happens */ 351*a4dd7a1dSNabih Estefan Diaz rx_desc.rdes0 &= ~RX_DESC_RDES0_OWN; 352*a4dd7a1dSNabih Estefan Diaz /* Set the frame to be an IPv4/IPv6 frame. */ 353*a4dd7a1dSNabih Estefan Diaz rx_desc.rdes0 |= RX_DESC_RDES0_FRM_TYPE_MASK; 354*a4dd7a1dSNabih Estefan Diaz 355*a4dd7a1dSNabih Estefan Diaz /* step 4 */ 356*a4dd7a1dSNabih Estefan Diaz rx_buf_len = RX_DESC_RDES1_BFFR1_SZ_MASK(rx_desc.rdes1); 357*a4dd7a1dSNabih Estefan Diaz rx_buf_addr = rx_desc.rdes2; 358*a4dd7a1dSNabih Estefan Diaz gmac->regs[R_NPCM_DMA_CUR_RX_BUF_ADDR] = rx_buf_addr; 359*a4dd7a1dSNabih Estefan Diaz gmac_rx_transfer_frame_to_buffer(rx_buf_len, &left_frame, rx_buf_addr, 360*a4dd7a1dSNabih Estefan Diaz &eof_transferred, &frame_ptr, 361*a4dd7a1dSNabih Estefan Diaz &transferred); 362*a4dd7a1dSNabih Estefan Diaz 363*a4dd7a1dSNabih Estefan Diaz trace_npcm_gmac_packet_receiving_buffer(DEVICE(gmac)->canonical_path, 364*a4dd7a1dSNabih Estefan Diaz rx_buf_len, rx_buf_addr); 365*a4dd7a1dSNabih Estefan Diaz /* if we still have frame left and the second buffer is not chained */ 366*a4dd7a1dSNabih Estefan Diaz if (!(rx_desc.rdes1 & RX_DESC_RDES1_SEC_ADDR_CHND_MASK) && \ 367*a4dd7a1dSNabih Estefan Diaz !eof_transferred) { 368*a4dd7a1dSNabih Estefan Diaz /* repeat process from above on buffer 2 */ 369*a4dd7a1dSNabih Estefan Diaz rx_buf_len = RX_DESC_RDES1_BFFR2_SZ_MASK(rx_desc.rdes1); 370*a4dd7a1dSNabih Estefan Diaz rx_buf_addr = rx_desc.rdes3; 371*a4dd7a1dSNabih Estefan Diaz gmac->regs[R_NPCM_DMA_CUR_RX_BUF_ADDR] = rx_buf_addr; 372*a4dd7a1dSNabih Estefan Diaz gmac_rx_transfer_frame_to_buffer(rx_buf_len, &left_frame, 373*a4dd7a1dSNabih Estefan Diaz rx_buf_addr, &eof_transferred, 374*a4dd7a1dSNabih Estefan Diaz &frame_ptr, &transferred); 375*a4dd7a1dSNabih Estefan Diaz trace_npcm_gmac_packet_receiving_buffer( \ 376*a4dd7a1dSNabih Estefan Diaz DEVICE(gmac)->canonical_path, 377*a4dd7a1dSNabih Estefan Diaz rx_buf_len, rx_buf_addr); 378*a4dd7a1dSNabih Estefan Diaz } 379*a4dd7a1dSNabih Estefan Diaz /* update address for descriptor */ 380*a4dd7a1dSNabih Estefan Diaz gmac->regs[R_NPCM_DMA_HOST_RX_DESC] = rx_buf_addr; 381*a4dd7a1dSNabih Estefan Diaz /* Return descriptor */ 382*a4dd7a1dSNabih Estefan Diaz rx_desc.rdes0 &= ~RX_DESC_RDES0_OWN; 383*a4dd7a1dSNabih Estefan Diaz /* Update frame length transferred */ 384*a4dd7a1dSNabih Estefan Diaz rx_desc.rdes0 |= ((uint32_t)transferred) 385*a4dd7a1dSNabih Estefan Diaz << RX_DESC_RDES0_FRAME_LEN_SHIFT; 386*a4dd7a1dSNabih Estefan Diaz trace_npcm_gmac_debug_desc_data(DEVICE(gmac)->canonical_path, &rx_desc, 387*a4dd7a1dSNabih Estefan Diaz rx_desc.rdes0, rx_desc.rdes1, 388*a4dd7a1dSNabih Estefan Diaz rx_desc.rdes2, rx_desc.rdes3); 389*a4dd7a1dSNabih Estefan Diaz 390*a4dd7a1dSNabih Estefan Diaz /* step 5 */ 391*a4dd7a1dSNabih Estefan Diaz gmac_write_rx_desc(desc_addr, &rx_desc); 392*a4dd7a1dSNabih Estefan Diaz trace_npcm_gmac_debug_desc_data(DEVICE(gmac)->canonical_path, 393*a4dd7a1dSNabih Estefan Diaz &rx_desc, rx_desc.rdes0, 394*a4dd7a1dSNabih Estefan Diaz rx_desc.rdes1, rx_desc.rdes2, 395*a4dd7a1dSNabih Estefan Diaz rx_desc.rdes3); 396*a4dd7a1dSNabih Estefan Diaz /* read new descriptor into rx_desc if needed*/ 397*a4dd7a1dSNabih Estefan Diaz if (!eof_transferred) { 398*a4dd7a1dSNabih Estefan Diaz /* Get next descriptor address (chained or sequential) */ 399*a4dd7a1dSNabih Estefan Diaz if (rx_desc.rdes1 & RX_DESC_RDES1_RC_END_RING_MASK) { 400*a4dd7a1dSNabih Estefan Diaz desc_addr = gmac->regs[R_NPCM_DMA_RX_BASE_ADDR]; 401*a4dd7a1dSNabih Estefan Diaz } else if (rx_desc.rdes1 & RX_DESC_RDES1_SEC_ADDR_CHND_MASK) { 402*a4dd7a1dSNabih Estefan Diaz desc_addr = rx_desc.rdes3; 403*a4dd7a1dSNabih Estefan Diaz } else { 404*a4dd7a1dSNabih Estefan Diaz desc_addr += sizeof(rx_desc); 405*a4dd7a1dSNabih Estefan Diaz } 406*a4dd7a1dSNabih Estefan Diaz trace_npcm_gmac_packet_desc_read(DEVICE(gmac)->canonical_path, 407*a4dd7a1dSNabih Estefan Diaz desc_addr); 408*a4dd7a1dSNabih Estefan Diaz if (gmac_read_rx_desc(desc_addr, &rx_desc)) { 409*a4dd7a1dSNabih Estefan Diaz qemu_log_mask(LOG_GUEST_ERROR, 410*a4dd7a1dSNabih Estefan Diaz "RX Descriptor @ 0x%x cant be read\n", 411*a4dd7a1dSNabih Estefan Diaz desc_addr); 412*a4dd7a1dSNabih Estefan Diaz gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_RU; 413*a4dd7a1dSNabih Estefan Diaz gmac_update_irq(gmac); 414*a4dd7a1dSNabih Estefan Diaz return len; 415*a4dd7a1dSNabih Estefan Diaz } 416*a4dd7a1dSNabih Estefan Diaz 417*a4dd7a1dSNabih Estefan Diaz /* step 6 */ 418*a4dd7a1dSNabih Estefan Diaz if (!(rx_desc.rdes0 & RX_DESC_RDES0_OWN)) { 419*a4dd7a1dSNabih Estefan Diaz if (!(gmac->regs[R_NPCM_DMA_CONTROL] & \ 420*a4dd7a1dSNabih Estefan Diaz NPCM_DMA_CONTROL_FLUSH_MASK)) { 421*a4dd7a1dSNabih Estefan Diaz rx_desc.rdes0 |= RX_DESC_RDES0_DESC_ERR_MASK; 422*a4dd7a1dSNabih Estefan Diaz } 423*a4dd7a1dSNabih Estefan Diaz eof_transferred = true; 424*a4dd7a1dSNabih Estefan Diaz } 425*a4dd7a1dSNabih Estefan Diaz /* Clear rdes0 for the incoming descriptor */ 426*a4dd7a1dSNabih Estefan Diaz rx_desc.rdes0 = 0; 427*a4dd7a1dSNabih Estefan Diaz } 428*a4dd7a1dSNabih Estefan Diaz } 429*a4dd7a1dSNabih Estefan Diaz gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT, 430*a4dd7a1dSNabih Estefan Diaz NPCM_DMA_STATUS_RX_RUNNING_CLOSING_STATE); 431*a4dd7a1dSNabih Estefan Diaz 432*a4dd7a1dSNabih Estefan Diaz rx_desc.rdes0 |= RX_DESC_RDES0_LAST_DESC_MASK; 433*a4dd7a1dSNabih Estefan Diaz if (!(rx_desc.rdes1 & RX_DESC_RDES1_DIS_INTR_COMP_MASK)) { 434*a4dd7a1dSNabih Estefan Diaz gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_RI; 435*a4dd7a1dSNabih Estefan Diaz gmac_update_irq(gmac); 436*a4dd7a1dSNabih Estefan Diaz } 437*a4dd7a1dSNabih Estefan Diaz trace_npcm_gmac_debug_desc_data(DEVICE(gmac)->canonical_path, &rx_desc, 438*a4dd7a1dSNabih Estefan Diaz rx_desc.rdes0, rx_desc.rdes1, rx_desc.rdes2, 439*a4dd7a1dSNabih Estefan Diaz rx_desc.rdes3); 440*a4dd7a1dSNabih Estefan Diaz 441*a4dd7a1dSNabih Estefan Diaz /* step 8 */ 442*a4dd7a1dSNabih Estefan Diaz gmac->regs[R_NPCM_DMA_CONTROL] |= NPCM_DMA_CONTROL_FLUSH_MASK; 443*a4dd7a1dSNabih Estefan Diaz 444*a4dd7a1dSNabih Estefan Diaz /* step 9 */ 445*a4dd7a1dSNabih Estefan Diaz trace_npcm_gmac_packet_received(DEVICE(gmac)->canonical_path, left_frame); 446*a4dd7a1dSNabih Estefan Diaz gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT, 447*a4dd7a1dSNabih Estefan Diaz NPCM_DMA_STATUS_RX_RUNNING_WAITING_STATE); 448*a4dd7a1dSNabih Estefan Diaz gmac_write_rx_desc(desc_addr, &rx_desc); 449*a4dd7a1dSNabih Estefan Diaz 450*a4dd7a1dSNabih Estefan Diaz /* Get next descriptor address (chained or sequential) */ 451*a4dd7a1dSNabih Estefan Diaz if (rx_desc.rdes1 & RX_DESC_RDES1_RC_END_RING_MASK) { 452*a4dd7a1dSNabih Estefan Diaz desc_addr = gmac->regs[R_NPCM_DMA_RX_BASE_ADDR]; 453*a4dd7a1dSNabih Estefan Diaz } else if (rx_desc.rdes1 & RX_DESC_RDES1_SEC_ADDR_CHND_MASK) { 454*a4dd7a1dSNabih Estefan Diaz desc_addr = rx_desc.rdes3; 455*a4dd7a1dSNabih Estefan Diaz } else { 456*a4dd7a1dSNabih Estefan Diaz desc_addr += sizeof(rx_desc); 457*a4dd7a1dSNabih Estefan Diaz } 458*a4dd7a1dSNabih Estefan Diaz gmac->regs[R_NPCM_DMA_HOST_RX_DESC] = desc_addr; 459*a4dd7a1dSNabih Estefan Diaz return len; 46008f787a3SHao Wu } 46108f787a3SHao Wu 46208f787a3SHao Wu static void gmac_cleanup(NetClientState *nc) 46308f787a3SHao Wu { 46408f787a3SHao Wu /* Nothing to do yet. */ 46508f787a3SHao Wu } 46608f787a3SHao Wu 46708f787a3SHao Wu static void gmac_set_link(NetClientState *nc) 46808f787a3SHao Wu { 46908f787a3SHao Wu NPCMGMACState *gmac = qemu_get_nic_opaque(nc); 47008f787a3SHao Wu 47108f787a3SHao Wu trace_npcm_gmac_set_link(!nc->link_down); 47208f787a3SHao Wu gmac_phy_set_link(gmac, !nc->link_down); 47308f787a3SHao Wu } 47408f787a3SHao Wu 47508f787a3SHao Wu static void npcm_gmac_mdio_access(NPCMGMACState *gmac, uint16_t v) 47608f787a3SHao Wu { 47708f787a3SHao Wu bool busy = v & NPCM_GMAC_MII_ADDR_BUSY; 47808f787a3SHao Wu uint8_t is_write; 47908f787a3SHao Wu uint8_t pa, gr; 48008f787a3SHao Wu uint16_t data; 48108f787a3SHao Wu 48208f787a3SHao Wu if (busy) { 48308f787a3SHao Wu is_write = v & NPCM_GMAC_MII_ADDR_WRITE; 48408f787a3SHao Wu pa = NPCM_GMAC_MII_ADDR_PA(v); 48508f787a3SHao Wu gr = NPCM_GMAC_MII_ADDR_GR(v); 48608f787a3SHao Wu /* Both pa and gr are 5 bits, so they are less than 32. */ 48708f787a3SHao Wu g_assert(pa < NPCM_GMAC_MAX_PHYS); 48808f787a3SHao Wu g_assert(gr < NPCM_GMAC_MAX_PHY_REGS); 48908f787a3SHao Wu 49008f787a3SHao Wu 49108f787a3SHao Wu if (v & NPCM_GMAC_MII_ADDR_WRITE) { 49208f787a3SHao Wu data = gmac->regs[R_NPCM_GMAC_MII_DATA]; 49308f787a3SHao Wu /* Clear reset bit for BMCR register */ 49408f787a3SHao Wu switch (gr) { 49508f787a3SHao Wu case MII_BMCR: 49608f787a3SHao Wu data &= ~MII_BMCR_RESET; 49708f787a3SHao Wu /* Autonegotiation is a W1C bit*/ 49808f787a3SHao Wu if (data & MII_BMCR_ANRESTART) { 49908f787a3SHao Wu /* Tells autonegotiation to not restart again */ 50008f787a3SHao Wu data &= ~MII_BMCR_ANRESTART; 50108f787a3SHao Wu } 50208f787a3SHao Wu if ((data & MII_BMCR_AUTOEN) && 50308f787a3SHao Wu !(gmac->phy_regs[pa][MII_BMSR] & MII_BMSR_AN_COMP)) { 50408f787a3SHao Wu /* sets autonegotiation as complete */ 50508f787a3SHao Wu gmac->phy_regs[pa][MII_BMSR] |= MII_BMSR_AN_COMP; 50608f787a3SHao Wu /* Resolve AN automatically->need to set this */ 50708f787a3SHao Wu gmac->phy_regs[0][MII_ANLPAR] = 0x0000; 50808f787a3SHao Wu } 50908f787a3SHao Wu } 51008f787a3SHao Wu gmac->phy_regs[pa][gr] = data; 51108f787a3SHao Wu } else { 51208f787a3SHao Wu data = gmac->phy_regs[pa][gr]; 51308f787a3SHao Wu gmac->regs[R_NPCM_GMAC_MII_DATA] = data; 51408f787a3SHao Wu } 51508f787a3SHao Wu trace_npcm_gmac_mdio_access(DEVICE(gmac)->canonical_path, is_write, pa, 51608f787a3SHao Wu gr, data); 51708f787a3SHao Wu } 51808f787a3SHao Wu gmac->regs[R_NPCM_GMAC_MII_ADDR] = v & ~NPCM_GMAC_MII_ADDR_BUSY; 51908f787a3SHao Wu } 52008f787a3SHao Wu 52108f787a3SHao Wu static uint64_t npcm_gmac_read(void *opaque, hwaddr offset, unsigned size) 52208f787a3SHao Wu { 52308f787a3SHao Wu NPCMGMACState *gmac = opaque; 52408f787a3SHao Wu uint32_t v = 0; 52508f787a3SHao Wu 52608f787a3SHao Wu switch (offset) { 52708f787a3SHao Wu /* Write only registers */ 52808f787a3SHao Wu case A_NPCM_DMA_XMT_POLL_DEMAND: 52908f787a3SHao Wu case A_NPCM_DMA_RCV_POLL_DEMAND: 53008f787a3SHao Wu qemu_log_mask(LOG_GUEST_ERROR, 53108f787a3SHao Wu "%s: Read of write-only reg: offset: 0x%04" HWADDR_PRIx 53208f787a3SHao Wu "\n", DEVICE(gmac)->canonical_path, offset); 53308f787a3SHao Wu break; 53408f787a3SHao Wu 53508f787a3SHao Wu default: 53608f787a3SHao Wu v = gmac->regs[offset / sizeof(uint32_t)]; 53708f787a3SHao Wu } 53808f787a3SHao Wu 53908f787a3SHao Wu trace_npcm_gmac_reg_read(DEVICE(gmac)->canonical_path, offset, v); 54008f787a3SHao Wu return v; 54108f787a3SHao Wu } 54208f787a3SHao Wu 54308f787a3SHao Wu static void npcm_gmac_write(void *opaque, hwaddr offset, 54408f787a3SHao Wu uint64_t v, unsigned size) 54508f787a3SHao Wu { 54608f787a3SHao Wu NPCMGMACState *gmac = opaque; 54708f787a3SHao Wu 54808f787a3SHao Wu trace_npcm_gmac_reg_write(DEVICE(gmac)->canonical_path, offset, v); 54908f787a3SHao Wu 55008f787a3SHao Wu switch (offset) { 55108f787a3SHao Wu /* Read only registers */ 55208f787a3SHao Wu case A_NPCM_GMAC_VERSION: 55308f787a3SHao Wu case A_NPCM_GMAC_INT_STATUS: 55408f787a3SHao Wu case A_NPCM_GMAC_RGMII_STATUS: 55508f787a3SHao Wu case A_NPCM_GMAC_PTP_STSR: 55608f787a3SHao Wu case A_NPCM_GMAC_PTP_STNSR: 55708f787a3SHao Wu case A_NPCM_DMA_MISSED_FRAME_CTR: 55808f787a3SHao Wu case A_NPCM_DMA_HOST_TX_DESC: 55908f787a3SHao Wu case A_NPCM_DMA_HOST_RX_DESC: 56008f787a3SHao Wu case A_NPCM_DMA_CUR_TX_BUF_ADDR: 56108f787a3SHao Wu case A_NPCM_DMA_CUR_RX_BUF_ADDR: 56208f787a3SHao Wu case A_NPCM_DMA_HW_FEATURE: 56308f787a3SHao Wu qemu_log_mask(LOG_GUEST_ERROR, 56408f787a3SHao Wu "%s: Write of read-only reg: offset: 0x%04" HWADDR_PRIx 56508f787a3SHao Wu ", value: 0x%04" PRIx64 "\n", 56608f787a3SHao Wu DEVICE(gmac)->canonical_path, offset, v); 56708f787a3SHao Wu break; 56808f787a3SHao Wu 56908f787a3SHao Wu case A_NPCM_GMAC_MAC_CONFIG: 570*a4dd7a1dSNabih Estefan Diaz gmac->regs[offset / sizeof(uint32_t)] = v; 57108f787a3SHao Wu break; 57208f787a3SHao Wu 57308f787a3SHao Wu case A_NPCM_GMAC_MII_ADDR: 57408f787a3SHao Wu npcm_gmac_mdio_access(gmac, v); 57508f787a3SHao Wu break; 57608f787a3SHao Wu 57708f787a3SHao Wu case A_NPCM_GMAC_MAC0_ADDR_HI: 57808f787a3SHao Wu gmac->regs[offset / sizeof(uint32_t)] = v; 57908f787a3SHao Wu gmac->conf.macaddr.a[0] = v >> 8; 58008f787a3SHao Wu gmac->conf.macaddr.a[1] = v >> 0; 58108f787a3SHao Wu break; 58208f787a3SHao Wu 58308f787a3SHao Wu case A_NPCM_GMAC_MAC0_ADDR_LO: 58408f787a3SHao Wu gmac->regs[offset / sizeof(uint32_t)] = v; 58508f787a3SHao Wu gmac->conf.macaddr.a[2] = v >> 24; 58608f787a3SHao Wu gmac->conf.macaddr.a[3] = v >> 16; 58708f787a3SHao Wu gmac->conf.macaddr.a[4] = v >> 8; 58808f787a3SHao Wu gmac->conf.macaddr.a[5] = v >> 0; 58908f787a3SHao Wu break; 59008f787a3SHao Wu 59108f787a3SHao Wu case A_NPCM_GMAC_MAC1_ADDR_HI: 59208f787a3SHao Wu case A_NPCM_GMAC_MAC1_ADDR_LO: 59308f787a3SHao Wu case A_NPCM_GMAC_MAC2_ADDR_HI: 59408f787a3SHao Wu case A_NPCM_GMAC_MAC2_ADDR_LO: 59508f787a3SHao Wu case A_NPCM_GMAC_MAC3_ADDR_HI: 59608f787a3SHao Wu case A_NPCM_GMAC_MAC3_ADDR_LO: 59708f787a3SHao Wu gmac->regs[offset / sizeof(uint32_t)] = v; 59808f787a3SHao Wu qemu_log_mask(LOG_UNIMP, 59908f787a3SHao Wu "%s: Only MAC Address 0 is supported. This request " 60008f787a3SHao Wu "is ignored.\n", DEVICE(gmac)->canonical_path); 60108f787a3SHao Wu break; 60208f787a3SHao Wu 60308f787a3SHao Wu case A_NPCM_DMA_BUS_MODE: 60408f787a3SHao Wu gmac->regs[offset / sizeof(uint32_t)] = v; 60508f787a3SHao Wu if (v & NPCM_DMA_BUS_MODE_SWR) { 60608f787a3SHao Wu npcm_gmac_soft_reset(gmac); 60708f787a3SHao Wu } 60808f787a3SHao Wu break; 60908f787a3SHao Wu 61008f787a3SHao Wu case A_NPCM_DMA_RCV_POLL_DEMAND: 61108f787a3SHao Wu /* We dont actually care about the value */ 612*a4dd7a1dSNabih Estefan Diaz gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT, 613*a4dd7a1dSNabih Estefan Diaz NPCM_DMA_STATUS_RX_RUNNING_WAITING_STATE); 61408f787a3SHao Wu break; 61508f787a3SHao Wu 61608f787a3SHao Wu case A_NPCM_DMA_STATUS: 61708f787a3SHao Wu /* Check that RO bits are not written to */ 61808f787a3SHao Wu if (NPCM_DMA_STATUS_RO_MASK(v)) { 61908f787a3SHao Wu qemu_log_mask(LOG_GUEST_ERROR, 62008f787a3SHao Wu "%s: Write of read-only bits of reg: offset: 0x%04" 62108f787a3SHao Wu HWADDR_PRIx ", value: 0x%04" PRIx64 "\n", 62208f787a3SHao Wu DEVICE(gmac)->canonical_path, offset, v); 62308f787a3SHao Wu } 624*a4dd7a1dSNabih Estefan Diaz /* for W1C bits, implement W1C */ 625*a4dd7a1dSNabih Estefan Diaz gmac->regs[offset / sizeof(uint32_t)] &= ~NPCM_DMA_STATUS_W1C_MASK(v); 626*a4dd7a1dSNabih Estefan Diaz if (v & NPCM_DMA_STATUS_RU) { 627*a4dd7a1dSNabih Estefan Diaz /* Clearing RU bit indicates descriptor is owned by DMA again. */ 628*a4dd7a1dSNabih Estefan Diaz gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT, 629*a4dd7a1dSNabih Estefan Diaz NPCM_DMA_STATUS_RX_RUNNING_WAITING_STATE); 630*a4dd7a1dSNabih Estefan Diaz qemu_flush_queued_packets(qemu_get_queue(gmac->nic)); 631*a4dd7a1dSNabih Estefan Diaz } 63208f787a3SHao Wu break; 63308f787a3SHao Wu 63408f787a3SHao Wu default: 63508f787a3SHao Wu gmac->regs[offset / sizeof(uint32_t)] = v; 63608f787a3SHao Wu break; 63708f787a3SHao Wu } 63808f787a3SHao Wu 63908f787a3SHao Wu gmac_update_irq(gmac); 64008f787a3SHao Wu } 64108f787a3SHao Wu 64208f787a3SHao Wu static void npcm_gmac_reset(DeviceState *dev) 64308f787a3SHao Wu { 64408f787a3SHao Wu NPCMGMACState *gmac = NPCM_GMAC(dev); 64508f787a3SHao Wu 64608f787a3SHao Wu npcm_gmac_soft_reset(gmac); 64708f787a3SHao Wu memcpy(gmac->phy_regs[0], phy_reg_init, sizeof(phy_reg_init)); 64808f787a3SHao Wu 64908f787a3SHao Wu trace_npcm_gmac_reset(DEVICE(gmac)->canonical_path, 65008f787a3SHao Wu gmac->phy_regs[0][MII_BMSR]); 65108f787a3SHao Wu } 65208f787a3SHao Wu 65308f787a3SHao Wu static NetClientInfo net_npcm_gmac_info = { 65408f787a3SHao Wu .type = NET_CLIENT_DRIVER_NIC, 65508f787a3SHao Wu .size = sizeof(NICState), 65608f787a3SHao Wu .can_receive = gmac_can_receive, 65708f787a3SHao Wu .receive = gmac_receive, 65808f787a3SHao Wu .cleanup = gmac_cleanup, 65908f787a3SHao Wu .link_status_changed = gmac_set_link, 66008f787a3SHao Wu }; 66108f787a3SHao Wu 66208f787a3SHao Wu static const struct MemoryRegionOps npcm_gmac_ops = { 66308f787a3SHao Wu .read = npcm_gmac_read, 66408f787a3SHao Wu .write = npcm_gmac_write, 66508f787a3SHao Wu .endianness = DEVICE_LITTLE_ENDIAN, 66608f787a3SHao Wu .valid = { 66708f787a3SHao Wu .min_access_size = 4, 66808f787a3SHao Wu .max_access_size = 4, 66908f787a3SHao Wu .unaligned = false, 67008f787a3SHao Wu }, 67108f787a3SHao Wu }; 67208f787a3SHao Wu 67308f787a3SHao Wu static void npcm_gmac_realize(DeviceState *dev, Error **errp) 67408f787a3SHao Wu { 67508f787a3SHao Wu NPCMGMACState *gmac = NPCM_GMAC(dev); 67608f787a3SHao Wu SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 67708f787a3SHao Wu 67808f787a3SHao Wu memory_region_init_io(&gmac->iomem, OBJECT(gmac), &npcm_gmac_ops, gmac, 67908f787a3SHao Wu TYPE_NPCM_GMAC, 8 * KiB); 68008f787a3SHao Wu sysbus_init_mmio(sbd, &gmac->iomem); 68108f787a3SHao Wu sysbus_init_irq(sbd, &gmac->irq); 68208f787a3SHao Wu 68308f787a3SHao Wu qemu_macaddr_default_if_unset(&gmac->conf.macaddr); 68408f787a3SHao Wu 68508f787a3SHao Wu gmac->nic = qemu_new_nic(&net_npcm_gmac_info, &gmac->conf, TYPE_NPCM_GMAC, 68608f787a3SHao Wu dev->id, &dev->mem_reentrancy_guard, gmac); 68708f787a3SHao Wu qemu_format_nic_info_str(qemu_get_queue(gmac->nic), gmac->conf.macaddr.a); 68808f787a3SHao Wu gmac->regs[R_NPCM_GMAC_MAC0_ADDR_HI] = (gmac->conf.macaddr.a[0] << 8) + \ 68908f787a3SHao Wu gmac->conf.macaddr.a[1]; 69008f787a3SHao Wu gmac->regs[R_NPCM_GMAC_MAC0_ADDR_LO] = (gmac->conf.macaddr.a[2] << 24) + \ 69108f787a3SHao Wu (gmac->conf.macaddr.a[3] << 16) + \ 69208f787a3SHao Wu (gmac->conf.macaddr.a[4] << 8) + \ 69308f787a3SHao Wu gmac->conf.macaddr.a[5]; 69408f787a3SHao Wu } 69508f787a3SHao Wu 69608f787a3SHao Wu static void npcm_gmac_unrealize(DeviceState *dev) 69708f787a3SHao Wu { 69808f787a3SHao Wu NPCMGMACState *gmac = NPCM_GMAC(dev); 69908f787a3SHao Wu 70008f787a3SHao Wu qemu_del_nic(gmac->nic); 70108f787a3SHao Wu } 70208f787a3SHao Wu 70308f787a3SHao Wu static const VMStateDescription vmstate_npcm_gmac = { 70408f787a3SHao Wu .name = TYPE_NPCM_GMAC, 70508f787a3SHao Wu .version_id = 0, 70608f787a3SHao Wu .minimum_version_id = 0, 70708f787a3SHao Wu .fields = (VMStateField[]) { 70808f787a3SHao Wu VMSTATE_UINT32_ARRAY(regs, NPCMGMACState, NPCM_GMAC_NR_REGS), 70908f787a3SHao Wu VMSTATE_END_OF_LIST(), 71008f787a3SHao Wu }, 71108f787a3SHao Wu }; 71208f787a3SHao Wu 71308f787a3SHao Wu static Property npcm_gmac_properties[] = { 71408f787a3SHao Wu DEFINE_NIC_PROPERTIES(NPCMGMACState, conf), 71508f787a3SHao Wu DEFINE_PROP_END_OF_LIST(), 71608f787a3SHao Wu }; 71708f787a3SHao Wu 71808f787a3SHao Wu static void npcm_gmac_class_init(ObjectClass *klass, void *data) 71908f787a3SHao Wu { 72008f787a3SHao Wu DeviceClass *dc = DEVICE_CLASS(klass); 72108f787a3SHao Wu 72208f787a3SHao Wu set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); 72308f787a3SHao Wu dc->desc = "NPCM GMAC Controller"; 72408f787a3SHao Wu dc->realize = npcm_gmac_realize; 72508f787a3SHao Wu dc->unrealize = npcm_gmac_unrealize; 72608f787a3SHao Wu dc->reset = npcm_gmac_reset; 72708f787a3SHao Wu dc->vmsd = &vmstate_npcm_gmac; 72808f787a3SHao Wu device_class_set_props(dc, npcm_gmac_properties); 72908f787a3SHao Wu } 73008f787a3SHao Wu 73108f787a3SHao Wu static const TypeInfo npcm_gmac_types[] = { 73208f787a3SHao Wu { 73308f787a3SHao Wu .name = TYPE_NPCM_GMAC, 73408f787a3SHao Wu .parent = TYPE_SYS_BUS_DEVICE, 73508f787a3SHao Wu .instance_size = sizeof(NPCMGMACState), 73608f787a3SHao Wu .class_init = npcm_gmac_class_init, 73708f787a3SHao Wu }, 73808f787a3SHao Wu }; 73908f787a3SHao Wu DEFINE_TYPES(npcm_gmac_types) 740