xref: /openbmc/qemu/hw/net/npcm7xx_emc.c (revision a53b931645183bd0c15dd19ae0708fc3c81ecf1d)
101c966b5SDoug Evans /*
201c966b5SDoug Evans  * Nuvoton NPCM7xx EMC Module
301c966b5SDoug Evans  *
401c966b5SDoug Evans  * Copyright 2020 Google LLC
501c966b5SDoug Evans  *
601c966b5SDoug Evans  * This program is free software; you can redistribute it and/or modify it
701c966b5SDoug Evans  * under the terms of the GNU General Public License as published by the
801c966b5SDoug Evans  * Free Software Foundation; either version 2 of the License, or
901c966b5SDoug Evans  * (at your option) any later version.
1001c966b5SDoug Evans  *
1101c966b5SDoug Evans  * This program is distributed in the hope that it will be useful, but WITHOUT
1201c966b5SDoug Evans  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1301c966b5SDoug Evans  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1401c966b5SDoug Evans  * for more details.
1501c966b5SDoug Evans  *
1601c966b5SDoug Evans  * Unsupported/unimplemented features:
1701c966b5SDoug Evans  * - MCMDR.FDUP (full duplex) is ignored, half duplex is not supported
1801c966b5SDoug Evans  * - Only CAM0 is supported, CAM[1-15] are not
1901c966b5SDoug Evans  *   - writes to CAMEN.[1-15] are ignored, these bits always read as zeroes
2001c966b5SDoug Evans  * - MII is not implemented, MIIDA.BUSY and MIID always return zero
2101c966b5SDoug Evans  * - MCMDR.LBK is not implemented
2201c966b5SDoug Evans  * - MCMDR.{OPMOD,ENSQE,AEP,ARP} are not supported
2301c966b5SDoug Evans  * - H/W FIFOs are not supported, MCMDR.FFTCR is ignored
2401c966b5SDoug Evans  * - MGSTA.SQE is not supported
2501c966b5SDoug Evans  * - pause and control frames are not implemented
2601c966b5SDoug Evans  * - MGSTA.CCNT is not supported
2701c966b5SDoug Evans  * - MPCNT, DMARFS are not implemented
2801c966b5SDoug Evans  */
2901c966b5SDoug Evans 
3001c966b5SDoug Evans #include "qemu/osdep.h"
3101c966b5SDoug Evans 
32*5691f477SMichael Tokarev #include <zlib.h> /* for crc32 */
3301c966b5SDoug Evans 
3401c966b5SDoug Evans #include "hw/irq.h"
3501c966b5SDoug Evans #include "hw/qdev-clock.h"
3601c966b5SDoug Evans #include "hw/qdev-properties.h"
3701c966b5SDoug Evans #include "hw/net/npcm7xx_emc.h"
3801c966b5SDoug Evans #include "net/eth.h"
3901c966b5SDoug Evans #include "migration/vmstate.h"
4001c966b5SDoug Evans #include "qemu/bitops.h"
4101c966b5SDoug Evans #include "qemu/error-report.h"
4201c966b5SDoug Evans #include "qemu/log.h"
4301c966b5SDoug Evans #include "qemu/module.h"
4401c966b5SDoug Evans #include "qemu/units.h"
4501c966b5SDoug Evans #include "sysemu/dma.h"
4601c966b5SDoug Evans #include "trace.h"
4701c966b5SDoug Evans 
4801c966b5SDoug Evans #define CRC_LENGTH 4
4901c966b5SDoug Evans 
5001c966b5SDoug Evans /*
5101c966b5SDoug Evans  * The maximum size of a (layer 2) ethernet frame as defined by 802.3.
5201c966b5SDoug Evans  * 1518 = 6(dest macaddr) + 6(src macaddr) + 2(proto) + 4(crc) + 1500(payload)
5301c966b5SDoug Evans  * This does not include an additional 4 for the vlan field (802.1q).
5401c966b5SDoug Evans  */
5501c966b5SDoug Evans #define MAX_ETH_FRAME_SIZE 1518
5601c966b5SDoug Evans 
emc_reg_name(int regno)5701c966b5SDoug Evans static const char *emc_reg_name(int regno)
5801c966b5SDoug Evans {
5901c966b5SDoug Evans #define REG(name) case REG_ ## name: return #name;
6001c966b5SDoug Evans     switch (regno) {
6101c966b5SDoug Evans     REG(CAMCMR)
6201c966b5SDoug Evans     REG(CAMEN)
6301c966b5SDoug Evans     REG(TXDLSA)
6401c966b5SDoug Evans     REG(RXDLSA)
6501c966b5SDoug Evans     REG(MCMDR)
6601c966b5SDoug Evans     REG(MIID)
6701c966b5SDoug Evans     REG(MIIDA)
6801c966b5SDoug Evans     REG(FFTCR)
6901c966b5SDoug Evans     REG(TSDR)
7001c966b5SDoug Evans     REG(RSDR)
7101c966b5SDoug Evans     REG(DMARFC)
7201c966b5SDoug Evans     REG(MIEN)
7301c966b5SDoug Evans     REG(MISTA)
7401c966b5SDoug Evans     REG(MGSTA)
7501c966b5SDoug Evans     REG(MPCNT)
7601c966b5SDoug Evans     REG(MRPC)
7701c966b5SDoug Evans     REG(MRPCC)
7801c966b5SDoug Evans     REG(MREPC)
7901c966b5SDoug Evans     REG(DMARFS)
8001c966b5SDoug Evans     REG(CTXDSA)
8101c966b5SDoug Evans     REG(CTXBSA)
8201c966b5SDoug Evans     REG(CRXDSA)
8301c966b5SDoug Evans     REG(CRXBSA)
8401c966b5SDoug Evans     case REG_CAMM_BASE + 0: return "CAM0M";
8501c966b5SDoug Evans     case REG_CAML_BASE + 0: return "CAM0L";
8601c966b5SDoug Evans     case REG_CAMM_BASE + 2 ... REG_CAMML_LAST:
8701c966b5SDoug Evans         /* Only CAM0 is supported, fold the others into something simple. */
8801c966b5SDoug Evans         if (regno & 1) {
8901c966b5SDoug Evans             return "CAM<n>L";
9001c966b5SDoug Evans         } else {
9101c966b5SDoug Evans             return "CAM<n>M";
9201c966b5SDoug Evans         }
9301c966b5SDoug Evans     default: return "UNKNOWN";
9401c966b5SDoug Evans     }
9501c966b5SDoug Evans #undef REG
9601c966b5SDoug Evans }
9701c966b5SDoug Evans 
emc_reset(NPCM7xxEMCState * emc)9801c966b5SDoug Evans static void emc_reset(NPCM7xxEMCState *emc)
9901c966b5SDoug Evans {
10047189638SPatrick Venture     uint32_t value;
10147189638SPatrick Venture 
10201c966b5SDoug Evans     trace_npcm7xx_emc_reset(emc->emc_num);
10301c966b5SDoug Evans 
10401c966b5SDoug Evans     memset(&emc->regs[0], 0, sizeof(emc->regs));
10501c966b5SDoug Evans 
10601c966b5SDoug Evans     /* These regs have non-zero reset values. */
10701c966b5SDoug Evans     emc->regs[REG_TXDLSA] = 0xfffffffc;
10801c966b5SDoug Evans     emc->regs[REG_RXDLSA] = 0xfffffffc;
10901c966b5SDoug Evans     emc->regs[REG_MIIDA] = 0x00900000;
11001c966b5SDoug Evans     emc->regs[REG_FFTCR] = 0x0101;
11101c966b5SDoug Evans     emc->regs[REG_DMARFC] = 0x0800;
11201c966b5SDoug Evans     emc->regs[REG_MPCNT] = 0x7fff;
11301c966b5SDoug Evans 
11401c966b5SDoug Evans     emc->tx_active = false;
11501c966b5SDoug Evans     emc->rx_active = false;
11647189638SPatrick Venture 
11747189638SPatrick Venture     /* Set the MAC address in the register space. */
11847189638SPatrick Venture     value = (emc->conf.macaddr.a[0] << 24) |
11947189638SPatrick Venture         (emc->conf.macaddr.a[1] << 16) |
12047189638SPatrick Venture         (emc->conf.macaddr.a[2] << 8) |
12147189638SPatrick Venture         emc->conf.macaddr.a[3];
12247189638SPatrick Venture     emc->regs[REG_CAMM_BASE] = value;
12347189638SPatrick Venture 
12447189638SPatrick Venture     value = (emc->conf.macaddr.a[4] << 24) | (emc->conf.macaddr.a[5] << 16);
12547189638SPatrick Venture     emc->regs[REG_CAML_BASE] = value;
12601c966b5SDoug Evans }
12701c966b5SDoug Evans 
npcm7xx_emc_reset(DeviceState * dev)12801c966b5SDoug Evans static void npcm7xx_emc_reset(DeviceState *dev)
12901c966b5SDoug Evans {
13001c966b5SDoug Evans     NPCM7xxEMCState *emc = NPCM7XX_EMC(dev);
13101c966b5SDoug Evans     emc_reset(emc);
13201c966b5SDoug Evans }
13301c966b5SDoug Evans 
emc_soft_reset(NPCM7xxEMCState * emc)13401c966b5SDoug Evans static void emc_soft_reset(NPCM7xxEMCState *emc)
13501c966b5SDoug Evans {
13601c966b5SDoug Evans     /*
13701c966b5SDoug Evans      * The docs say at least MCMDR.{LBK,OPMOD} bits are not changed during a
13801c966b5SDoug Evans      * soft reset, but does not go into further detail. For now, KISS.
13901c966b5SDoug Evans      */
14001c966b5SDoug Evans     uint32_t mcmdr = emc->regs[REG_MCMDR];
14101c966b5SDoug Evans     emc_reset(emc);
14201c966b5SDoug Evans     emc->regs[REG_MCMDR] = mcmdr & (REG_MCMDR_LBK | REG_MCMDR_OPMOD);
14301c966b5SDoug Evans 
14401c966b5SDoug Evans     qemu_set_irq(emc->tx_irq, 0);
14501c966b5SDoug Evans     qemu_set_irq(emc->rx_irq, 0);
14601c966b5SDoug Evans }
14701c966b5SDoug Evans 
emc_set_link(NetClientState * nc)14801c966b5SDoug Evans static void emc_set_link(NetClientState *nc)
14901c966b5SDoug Evans {
15001c966b5SDoug Evans     /* Nothing to do yet. */
15101c966b5SDoug Evans }
15201c966b5SDoug Evans 
15301c966b5SDoug Evans /* MISTA.TXINTR is the union of the individual bits with their enables. */
emc_update_mista_txintr(NPCM7xxEMCState * emc)15401c966b5SDoug Evans static void emc_update_mista_txintr(NPCM7xxEMCState *emc)
15501c966b5SDoug Evans {
15601c966b5SDoug Evans     /* Only look at the bits we support. */
15701c966b5SDoug Evans     uint32_t mask = (REG_MISTA_TXBERR |
15801c966b5SDoug Evans                      REG_MISTA_TDU |
15901c966b5SDoug Evans                      REG_MISTA_TXCP);
16001c966b5SDoug Evans     if (emc->regs[REG_MISTA] & emc->regs[REG_MIEN] & mask) {
16101c966b5SDoug Evans         emc->regs[REG_MISTA] |= REG_MISTA_TXINTR;
16201c966b5SDoug Evans     } else {
16301c966b5SDoug Evans         emc->regs[REG_MISTA] &= ~REG_MISTA_TXINTR;
16401c966b5SDoug Evans     }
16501c966b5SDoug Evans }
16601c966b5SDoug Evans 
16701c966b5SDoug Evans /* MISTA.RXINTR is the union of the individual bits with their enables. */
emc_update_mista_rxintr(NPCM7xxEMCState * emc)16801c966b5SDoug Evans static void emc_update_mista_rxintr(NPCM7xxEMCState *emc)
16901c966b5SDoug Evans {
17001c966b5SDoug Evans     /* Only look at the bits we support. */
17101c966b5SDoug Evans     uint32_t mask = (REG_MISTA_RXBERR |
17201c966b5SDoug Evans                      REG_MISTA_RDU |
17301c966b5SDoug Evans                      REG_MISTA_RXGD);
17401c966b5SDoug Evans     if (emc->regs[REG_MISTA] & emc->regs[REG_MIEN] & mask) {
17501c966b5SDoug Evans         emc->regs[REG_MISTA] |= REG_MISTA_RXINTR;
17601c966b5SDoug Evans     } else {
17701c966b5SDoug Evans         emc->regs[REG_MISTA] &= ~REG_MISTA_RXINTR;
17801c966b5SDoug Evans     }
17901c966b5SDoug Evans }
18001c966b5SDoug Evans 
18101c966b5SDoug Evans /* N.B. emc_update_mista_txintr must have already been called. */
emc_update_tx_irq(NPCM7xxEMCState * emc)18201c966b5SDoug Evans static void emc_update_tx_irq(NPCM7xxEMCState *emc)
18301c966b5SDoug Evans {
18401c966b5SDoug Evans     int level = !!(emc->regs[REG_MISTA] &
18501c966b5SDoug Evans                    emc->regs[REG_MIEN] &
18601c966b5SDoug Evans                    REG_MISTA_TXINTR);
18701c966b5SDoug Evans     trace_npcm7xx_emc_update_tx_irq(level);
18801c966b5SDoug Evans     qemu_set_irq(emc->tx_irq, level);
18901c966b5SDoug Evans }
19001c966b5SDoug Evans 
19101c966b5SDoug Evans /* N.B. emc_update_mista_rxintr must have already been called. */
emc_update_rx_irq(NPCM7xxEMCState * emc)19201c966b5SDoug Evans static void emc_update_rx_irq(NPCM7xxEMCState *emc)
19301c966b5SDoug Evans {
19401c966b5SDoug Evans     int level = !!(emc->regs[REG_MISTA] &
19501c966b5SDoug Evans                    emc->regs[REG_MIEN] &
19601c966b5SDoug Evans                    REG_MISTA_RXINTR);
19701c966b5SDoug Evans     trace_npcm7xx_emc_update_rx_irq(level);
19801c966b5SDoug Evans     qemu_set_irq(emc->rx_irq, level);
19901c966b5SDoug Evans }
20001c966b5SDoug Evans 
20101c966b5SDoug Evans /* Update IRQ states due to changes in MIEN,MISTA. */
emc_update_irq_from_reg_change(NPCM7xxEMCState * emc)20201c966b5SDoug Evans static void emc_update_irq_from_reg_change(NPCM7xxEMCState *emc)
20301c966b5SDoug Evans {
20401c966b5SDoug Evans     emc_update_mista_txintr(emc);
20501c966b5SDoug Evans     emc_update_tx_irq(emc);
20601c966b5SDoug Evans 
20701c966b5SDoug Evans     emc_update_mista_rxintr(emc);
20801c966b5SDoug Evans     emc_update_rx_irq(emc);
20901c966b5SDoug Evans }
21001c966b5SDoug Evans 
emc_read_tx_desc(dma_addr_t addr,NPCM7xxEMCTxDesc * desc)21101c966b5SDoug Evans static int emc_read_tx_desc(dma_addr_t addr, NPCM7xxEMCTxDesc *desc)
21201c966b5SDoug Evans {
213ba06fe8aSPhilippe Mathieu-Daudé     if (dma_memory_read(&address_space_memory, addr, desc,
214ba06fe8aSPhilippe Mathieu-Daudé                         sizeof(*desc), MEMTXATTRS_UNSPECIFIED)) {
21501c966b5SDoug Evans         qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to read descriptor @ 0x%"
21601c966b5SDoug Evans                       HWADDR_PRIx "\n", __func__, addr);
21701c966b5SDoug Evans         return -1;
21801c966b5SDoug Evans     }
21901c966b5SDoug Evans     desc->flags = le32_to_cpu(desc->flags);
22001c966b5SDoug Evans     desc->txbsa = le32_to_cpu(desc->txbsa);
22101c966b5SDoug Evans     desc->status_and_length = le32_to_cpu(desc->status_and_length);
22201c966b5SDoug Evans     desc->ntxdsa = le32_to_cpu(desc->ntxdsa);
22301c966b5SDoug Evans     return 0;
22401c966b5SDoug Evans }
22501c966b5SDoug Evans 
emc_write_tx_desc(const NPCM7xxEMCTxDesc * desc,dma_addr_t addr)22601c966b5SDoug Evans static int emc_write_tx_desc(const NPCM7xxEMCTxDesc *desc, dma_addr_t addr)
22701c966b5SDoug Evans {
22801c966b5SDoug Evans     NPCM7xxEMCTxDesc le_desc;
22901c966b5SDoug Evans 
23001c966b5SDoug Evans     le_desc.flags = cpu_to_le32(desc->flags);
23101c966b5SDoug Evans     le_desc.txbsa = cpu_to_le32(desc->txbsa);
23201c966b5SDoug Evans     le_desc.status_and_length = cpu_to_le32(desc->status_and_length);
23301c966b5SDoug Evans     le_desc.ntxdsa = cpu_to_le32(desc->ntxdsa);
23401c966b5SDoug Evans     if (dma_memory_write(&address_space_memory, addr, &le_desc,
235ba06fe8aSPhilippe Mathieu-Daudé                          sizeof(le_desc), MEMTXATTRS_UNSPECIFIED)) {
23601c966b5SDoug Evans         qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to write descriptor @ 0x%"
23701c966b5SDoug Evans                       HWADDR_PRIx "\n", __func__, addr);
23801c966b5SDoug Evans         return -1;
23901c966b5SDoug Evans     }
24001c966b5SDoug Evans     return 0;
24101c966b5SDoug Evans }
24201c966b5SDoug Evans 
emc_read_rx_desc(dma_addr_t addr,NPCM7xxEMCRxDesc * desc)24301c966b5SDoug Evans static int emc_read_rx_desc(dma_addr_t addr, NPCM7xxEMCRxDesc *desc)
24401c966b5SDoug Evans {
245ba06fe8aSPhilippe Mathieu-Daudé     if (dma_memory_read(&address_space_memory, addr, desc,
246ba06fe8aSPhilippe Mathieu-Daudé                         sizeof(*desc), MEMTXATTRS_UNSPECIFIED)) {
24701c966b5SDoug Evans         qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to read descriptor @ 0x%"
24801c966b5SDoug Evans                       HWADDR_PRIx "\n", __func__, addr);
24901c966b5SDoug Evans         return -1;
25001c966b5SDoug Evans     }
25101c966b5SDoug Evans     desc->status_and_length = le32_to_cpu(desc->status_and_length);
25201c966b5SDoug Evans     desc->rxbsa = le32_to_cpu(desc->rxbsa);
25301c966b5SDoug Evans     desc->reserved = le32_to_cpu(desc->reserved);
25401c966b5SDoug Evans     desc->nrxdsa = le32_to_cpu(desc->nrxdsa);
25501c966b5SDoug Evans     return 0;
25601c966b5SDoug Evans }
25701c966b5SDoug Evans 
emc_write_rx_desc(const NPCM7xxEMCRxDesc * desc,dma_addr_t addr)25801c966b5SDoug Evans static int emc_write_rx_desc(const NPCM7xxEMCRxDesc *desc, dma_addr_t addr)
25901c966b5SDoug Evans {
26001c966b5SDoug Evans     NPCM7xxEMCRxDesc le_desc;
26101c966b5SDoug Evans 
26201c966b5SDoug Evans     le_desc.status_and_length = cpu_to_le32(desc->status_and_length);
26301c966b5SDoug Evans     le_desc.rxbsa = cpu_to_le32(desc->rxbsa);
26401c966b5SDoug Evans     le_desc.reserved = cpu_to_le32(desc->reserved);
26501c966b5SDoug Evans     le_desc.nrxdsa = cpu_to_le32(desc->nrxdsa);
26601c966b5SDoug Evans     if (dma_memory_write(&address_space_memory, addr, &le_desc,
267ba06fe8aSPhilippe Mathieu-Daudé                          sizeof(le_desc), MEMTXATTRS_UNSPECIFIED)) {
26801c966b5SDoug Evans         qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to write descriptor @ 0x%"
26901c966b5SDoug Evans                       HWADDR_PRIx "\n", __func__, addr);
27001c966b5SDoug Evans         return -1;
27101c966b5SDoug Evans     }
27201c966b5SDoug Evans     return 0;
27301c966b5SDoug Evans }
27401c966b5SDoug Evans 
emc_set_mista(NPCM7xxEMCState * emc,uint32_t flags)27501c966b5SDoug Evans static void emc_set_mista(NPCM7xxEMCState *emc, uint32_t flags)
27601c966b5SDoug Evans {
27701c966b5SDoug Evans     trace_npcm7xx_emc_set_mista(flags);
27801c966b5SDoug Evans     emc->regs[REG_MISTA] |= flags;
27901c966b5SDoug Evans     if (extract32(flags, 16, 16)) {
28001c966b5SDoug Evans         emc_update_mista_txintr(emc);
28101c966b5SDoug Evans     }
28201c966b5SDoug Evans     if (extract32(flags, 0, 16)) {
28301c966b5SDoug Evans         emc_update_mista_rxintr(emc);
28401c966b5SDoug Evans     }
28501c966b5SDoug Evans }
28601c966b5SDoug Evans 
emc_halt_tx(NPCM7xxEMCState * emc,uint32_t mista_flag)28701c966b5SDoug Evans static void emc_halt_tx(NPCM7xxEMCState *emc, uint32_t mista_flag)
28801c966b5SDoug Evans {
28901c966b5SDoug Evans     emc->tx_active = false;
29001c966b5SDoug Evans     emc_set_mista(emc, mista_flag);
29101c966b5SDoug Evans }
29201c966b5SDoug Evans 
emc_halt_rx(NPCM7xxEMCState * emc,uint32_t mista_flag)29301c966b5SDoug Evans static void emc_halt_rx(NPCM7xxEMCState *emc, uint32_t mista_flag)
29401c966b5SDoug Evans {
29501c966b5SDoug Evans     emc->rx_active = false;
29601c966b5SDoug Evans     emc_set_mista(emc, mista_flag);
29701c966b5SDoug Evans }
29801c966b5SDoug Evans 
emc_enable_rx_and_flush(NPCM7xxEMCState * emc)299530cd6c2SPatrick Venture static void emc_enable_rx_and_flush(NPCM7xxEMCState *emc)
300530cd6c2SPatrick Venture {
301530cd6c2SPatrick Venture     emc->rx_active = true;
302530cd6c2SPatrick Venture     qemu_flush_queued_packets(qemu_get_queue(emc->nic));
303530cd6c2SPatrick Venture }
304530cd6c2SPatrick Venture 
emc_set_next_tx_descriptor(NPCM7xxEMCState * emc,const NPCM7xxEMCTxDesc * tx_desc,uint32_t desc_addr)30501c966b5SDoug Evans static void emc_set_next_tx_descriptor(NPCM7xxEMCState *emc,
30601c966b5SDoug Evans                                        const NPCM7xxEMCTxDesc *tx_desc,
30701c966b5SDoug Evans                                        uint32_t desc_addr)
30801c966b5SDoug Evans {
30901c966b5SDoug Evans     /* Update the current descriptor, if only to reset the owner flag. */
31001c966b5SDoug Evans     if (emc_write_tx_desc(tx_desc, desc_addr)) {
31101c966b5SDoug Evans         /*
31201c966b5SDoug Evans          * We just read it so this shouldn't generally happen.
31301c966b5SDoug Evans          * Error already reported.
31401c966b5SDoug Evans          */
31501c966b5SDoug Evans         emc_set_mista(emc, REG_MISTA_TXBERR);
31601c966b5SDoug Evans     }
31701c966b5SDoug Evans     emc->regs[REG_CTXDSA] = TX_DESC_NTXDSA(tx_desc->ntxdsa);
31801c966b5SDoug Evans }
31901c966b5SDoug Evans 
emc_set_next_rx_descriptor(NPCM7xxEMCState * emc,const NPCM7xxEMCRxDesc * rx_desc,uint32_t desc_addr)32001c966b5SDoug Evans static void emc_set_next_rx_descriptor(NPCM7xxEMCState *emc,
32101c966b5SDoug Evans                                        const NPCM7xxEMCRxDesc *rx_desc,
32201c966b5SDoug Evans                                        uint32_t desc_addr)
32301c966b5SDoug Evans {
32401c966b5SDoug Evans     /* Update the current descriptor, if only to reset the owner flag. */
32501c966b5SDoug Evans     if (emc_write_rx_desc(rx_desc, desc_addr)) {
32601c966b5SDoug Evans         /*
32701c966b5SDoug Evans          * We just read it so this shouldn't generally happen.
32801c966b5SDoug Evans          * Error already reported.
32901c966b5SDoug Evans          */
33001c966b5SDoug Evans         emc_set_mista(emc, REG_MISTA_RXBERR);
33101c966b5SDoug Evans     }
33201c966b5SDoug Evans     emc->regs[REG_CRXDSA] = RX_DESC_NRXDSA(rx_desc->nrxdsa);
33301c966b5SDoug Evans }
33401c966b5SDoug Evans 
emc_try_send_next_packet(NPCM7xxEMCState * emc)33501c966b5SDoug Evans static void emc_try_send_next_packet(NPCM7xxEMCState *emc)
33601c966b5SDoug Evans {
33701c966b5SDoug Evans     /* Working buffer for sending out packets. Most packets fit in this. */
33801c966b5SDoug Evans #define TX_BUFFER_SIZE 2048
33901c966b5SDoug Evans     uint8_t tx_send_buffer[TX_BUFFER_SIZE];
34001c966b5SDoug Evans     uint32_t desc_addr = TX_DESC_NTXDSA(emc->regs[REG_CTXDSA]);
34101c966b5SDoug Evans     NPCM7xxEMCTxDesc tx_desc;
34201c966b5SDoug Evans     uint32_t next_buf_addr, length;
34301c966b5SDoug Evans     uint8_t *buf;
34401c966b5SDoug Evans     g_autofree uint8_t *malloced_buf = NULL;
34501c966b5SDoug Evans 
34601c966b5SDoug Evans     if (emc_read_tx_desc(desc_addr, &tx_desc)) {
34701c966b5SDoug Evans         /* Error reading descriptor, already reported. */
34801c966b5SDoug Evans         emc_halt_tx(emc, REG_MISTA_TXBERR);
34901c966b5SDoug Evans         emc_update_tx_irq(emc);
35001c966b5SDoug Evans         return;
35101c966b5SDoug Evans     }
35201c966b5SDoug Evans 
35301c966b5SDoug Evans     /* Nothing we can do if we don't own the descriptor. */
35401c966b5SDoug Evans     if (!(tx_desc.flags & TX_DESC_FLAG_OWNER_MASK)) {
35501c966b5SDoug Evans         trace_npcm7xx_emc_cpu_owned_desc(desc_addr);
35601c966b5SDoug Evans         emc_halt_tx(emc, REG_MISTA_TDU);
35701c966b5SDoug Evans         emc_update_tx_irq(emc);
35801c966b5SDoug Evans         return;
35901c966b5SDoug Evans      }
36001c966b5SDoug Evans 
36101c966b5SDoug Evans     /* Give the descriptor back regardless of what happens. */
36201c966b5SDoug Evans     tx_desc.flags &= ~TX_DESC_FLAG_OWNER_MASK;
36301c966b5SDoug Evans     tx_desc.status_and_length &= 0xffff;
36401c966b5SDoug Evans 
36501c966b5SDoug Evans     /*
36601c966b5SDoug Evans      * Despite the h/w documentation saying the tx buffer is word aligned,
36701c966b5SDoug Evans      * the linux driver does not word align the buffer. There is value in not
36801c966b5SDoug Evans      * aligning the buffer: See the description of NET_IP_ALIGN in linux
36901c966b5SDoug Evans      * kernel sources.
37001c966b5SDoug Evans      */
37101c966b5SDoug Evans     next_buf_addr = tx_desc.txbsa;
37201c966b5SDoug Evans     emc->regs[REG_CTXBSA] = next_buf_addr;
37301c966b5SDoug Evans     length = TX_DESC_PKT_LEN(tx_desc.status_and_length);
37401c966b5SDoug Evans     buf = &tx_send_buffer[0];
37501c966b5SDoug Evans 
37601c966b5SDoug Evans     if (length > sizeof(tx_send_buffer)) {
37701c966b5SDoug Evans         malloced_buf = g_malloc(length);
37801c966b5SDoug Evans         buf = malloced_buf;
37901c966b5SDoug Evans     }
38001c966b5SDoug Evans 
381ba06fe8aSPhilippe Mathieu-Daudé     if (dma_memory_read(&address_space_memory, next_buf_addr, buf,
382ba06fe8aSPhilippe Mathieu-Daudé                         length, MEMTXATTRS_UNSPECIFIED)) {
38301c966b5SDoug Evans         qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to read packet @ 0x%x\n",
38401c966b5SDoug Evans                       __func__, next_buf_addr);
38501c966b5SDoug Evans         emc_set_mista(emc, REG_MISTA_TXBERR);
38601c966b5SDoug Evans         emc_set_next_tx_descriptor(emc, &tx_desc, desc_addr);
38701c966b5SDoug Evans         emc_update_tx_irq(emc);
38801c966b5SDoug Evans         trace_npcm7xx_emc_tx_done(emc->regs[REG_CTXDSA]);
38901c966b5SDoug Evans         return;
39001c966b5SDoug Evans     }
39101c966b5SDoug Evans 
39201c966b5SDoug Evans     if ((tx_desc.flags & TX_DESC_FLAG_PADEN) && (length < MIN_PACKET_LENGTH)) {
39301c966b5SDoug Evans         memset(buf + length, 0, MIN_PACKET_LENGTH - length);
39401c966b5SDoug Evans         length = MIN_PACKET_LENGTH;
39501c966b5SDoug Evans     }
39601c966b5SDoug Evans 
39701c966b5SDoug Evans     /* N.B. emc_receive can get called here. */
39801c966b5SDoug Evans     qemu_send_packet(qemu_get_queue(emc->nic), buf, length);
39901c966b5SDoug Evans     trace_npcm7xx_emc_sent_packet(length);
40001c966b5SDoug Evans 
40101c966b5SDoug Evans     tx_desc.status_and_length |= TX_DESC_STATUS_TXCP;
40201c966b5SDoug Evans     if (tx_desc.flags & TX_DESC_FLAG_INTEN) {
40301c966b5SDoug Evans         emc_set_mista(emc, REG_MISTA_TXCP);
40401c966b5SDoug Evans     }
40501c966b5SDoug Evans     if (emc->regs[REG_MISTA] & emc->regs[REG_MIEN] & REG_MISTA_TXINTR) {
40601c966b5SDoug Evans         tx_desc.status_and_length |= TX_DESC_STATUS_TXINTR;
40701c966b5SDoug Evans     }
40801c966b5SDoug Evans 
40901c966b5SDoug Evans     emc_set_next_tx_descriptor(emc, &tx_desc, desc_addr);
41001c966b5SDoug Evans     emc_update_tx_irq(emc);
41101c966b5SDoug Evans     trace_npcm7xx_emc_tx_done(emc->regs[REG_CTXDSA]);
41201c966b5SDoug Evans }
41301c966b5SDoug Evans 
emc_can_receive(NetClientState * nc)41401c966b5SDoug Evans static bool emc_can_receive(NetClientState *nc)
41501c966b5SDoug Evans {
41601c966b5SDoug Evans     NPCM7xxEMCState *emc = NPCM7XX_EMC(qemu_get_nic_opaque(nc));
41701c966b5SDoug Evans 
41801c966b5SDoug Evans     bool can_receive = emc->rx_active;
41901c966b5SDoug Evans     trace_npcm7xx_emc_can_receive(can_receive);
42001c966b5SDoug Evans     return can_receive;
42101c966b5SDoug Evans }
42201c966b5SDoug Evans 
42301c966b5SDoug Evans /* If result is false then *fail_reason contains the reason. */
emc_receive_filter1(NPCM7xxEMCState * emc,const uint8_t * buf,size_t len,const char ** fail_reason)42401c966b5SDoug Evans static bool emc_receive_filter1(NPCM7xxEMCState *emc, const uint8_t *buf,
42501c966b5SDoug Evans                                 size_t len, const char **fail_reason)
42601c966b5SDoug Evans {
42701c966b5SDoug Evans     eth_pkt_types_e pkt_type = get_eth_packet_type(PKT_GET_ETH_HDR(buf));
42801c966b5SDoug Evans 
42901c966b5SDoug Evans     switch (pkt_type) {
43001c966b5SDoug Evans     case ETH_PKT_BCAST:
43101c966b5SDoug Evans         if (emc->regs[REG_CAMCMR] & REG_CAMCMR_CCAM) {
43201c966b5SDoug Evans             return true;
43301c966b5SDoug Evans         } else {
43401c966b5SDoug Evans             *fail_reason = "Broadcast packet disabled";
43501c966b5SDoug Evans             return !!(emc->regs[REG_CAMCMR] & REG_CAMCMR_ABP);
43601c966b5SDoug Evans         }
43701c966b5SDoug Evans     case ETH_PKT_MCAST:
43801c966b5SDoug Evans         if (emc->regs[REG_CAMCMR] & REG_CAMCMR_CCAM) {
43901c966b5SDoug Evans             return true;
44001c966b5SDoug Evans         } else {
44101c966b5SDoug Evans             *fail_reason = "Multicast packet disabled";
44201c966b5SDoug Evans             return !!(emc->regs[REG_CAMCMR] & REG_CAMCMR_AMP);
44301c966b5SDoug Evans         }
44401c966b5SDoug Evans     case ETH_PKT_UCAST: {
44501c966b5SDoug Evans         bool matches;
44647189638SPatrick Venture         uint32_t value;
44747189638SPatrick Venture         struct MACAddr mac;
44801c966b5SDoug Evans         if (emc->regs[REG_CAMCMR] & REG_CAMCMR_AUP) {
44901c966b5SDoug Evans             return true;
45001c966b5SDoug Evans         }
45147189638SPatrick Venture 
45247189638SPatrick Venture         value = emc->regs[REG_CAMM_BASE];
45347189638SPatrick Venture         mac.a[0] = value >> 24;
45447189638SPatrick Venture         mac.a[1] = value >> 16;
45547189638SPatrick Venture         mac.a[2] = value >> 8;
45647189638SPatrick Venture         mac.a[3] = value >> 0;
45747189638SPatrick Venture         value = emc->regs[REG_CAML_BASE];
45847189638SPatrick Venture         mac.a[4] = value >> 24;
45947189638SPatrick Venture         mac.a[5] = value >> 16;
46047189638SPatrick Venture 
46101c966b5SDoug Evans         matches = ((emc->regs[REG_CAMCMR] & REG_CAMCMR_ECMP) &&
46201c966b5SDoug Evans                    /* We only support one CAM register, CAM0. */
46301c966b5SDoug Evans                    (emc->regs[REG_CAMEN] & (1 << 0)) &&
46447189638SPatrick Venture                    memcmp(buf, mac.a, ETH_ALEN) == 0);
46501c966b5SDoug Evans         if (emc->regs[REG_CAMCMR] & REG_CAMCMR_CCAM) {
46601c966b5SDoug Evans             *fail_reason = "MACADDR matched, comparison complemented";
46701c966b5SDoug Evans             return !matches;
46801c966b5SDoug Evans         } else {
46901c966b5SDoug Evans             *fail_reason = "MACADDR didn't match";
47001c966b5SDoug Evans             return matches;
47101c966b5SDoug Evans         }
47201c966b5SDoug Evans     }
47301c966b5SDoug Evans     default:
47401c966b5SDoug Evans         g_assert_not_reached();
47501c966b5SDoug Evans     }
47601c966b5SDoug Evans }
47701c966b5SDoug Evans 
emc_receive_filter(NPCM7xxEMCState * emc,const uint8_t * buf,size_t len)47801c966b5SDoug Evans static bool emc_receive_filter(NPCM7xxEMCState *emc, const uint8_t *buf,
47901c966b5SDoug Evans                                size_t len)
48001c966b5SDoug Evans {
48101c966b5SDoug Evans     const char *fail_reason = NULL;
48201c966b5SDoug Evans     bool ok = emc_receive_filter1(emc, buf, len, &fail_reason);
48301c966b5SDoug Evans     if (!ok) {
48401c966b5SDoug Evans         trace_npcm7xx_emc_packet_filtered_out(fail_reason);
48501c966b5SDoug Evans     }
48601c966b5SDoug Evans     return ok;
48701c966b5SDoug Evans }
48801c966b5SDoug Evans 
emc_receive(NetClientState * nc,const uint8_t * buf,size_t len1)48901c966b5SDoug Evans static ssize_t emc_receive(NetClientState *nc, const uint8_t *buf, size_t len1)
49001c966b5SDoug Evans {
49101c966b5SDoug Evans     NPCM7xxEMCState *emc = NPCM7XX_EMC(qemu_get_nic_opaque(nc));
49201c966b5SDoug Evans     const uint32_t len = len1;
49301c966b5SDoug Evans     size_t max_frame_len;
49401c966b5SDoug Evans     bool long_frame;
49501c966b5SDoug Evans     uint32_t desc_addr;
49601c966b5SDoug Evans     NPCM7xxEMCRxDesc rx_desc;
49701c966b5SDoug Evans     uint32_t crc;
49801c966b5SDoug Evans     uint8_t *crc_ptr;
49901c966b5SDoug Evans     uint32_t buf_addr;
50001c966b5SDoug Evans 
50101c966b5SDoug Evans     trace_npcm7xx_emc_receiving_packet(len);
50201c966b5SDoug Evans 
50301c966b5SDoug Evans     if (!emc_can_receive(nc)) {
50401c966b5SDoug Evans         qemu_log_mask(LOG_GUEST_ERROR, "%s: Unexpected packet\n", __func__);
50501c966b5SDoug Evans         return -1;
50601c966b5SDoug Evans     }
50701c966b5SDoug Evans 
50801c966b5SDoug Evans     if (len < ETH_HLEN ||
50901c966b5SDoug Evans         /* Defensive programming: drop unsupportable large packets. */
51001c966b5SDoug Evans         len > 0xffff - CRC_LENGTH) {
51101c966b5SDoug Evans         qemu_log_mask(LOG_GUEST_ERROR, "%s: Dropped frame of %u bytes\n",
51201c966b5SDoug Evans                       __func__, len);
51301c966b5SDoug Evans         return len;
51401c966b5SDoug Evans     }
51501c966b5SDoug Evans 
51601c966b5SDoug Evans     /*
51701c966b5SDoug Evans      * DENI is set if EMC received the Length/Type field of the incoming
51801c966b5SDoug Evans      * packet, so it will be set regardless of what happens next.
51901c966b5SDoug Evans      */
52001c966b5SDoug Evans     emc_set_mista(emc, REG_MISTA_DENI);
52101c966b5SDoug Evans 
52201c966b5SDoug Evans     if (!emc_receive_filter(emc, buf, len)) {
52301c966b5SDoug Evans         emc_update_rx_irq(emc);
52401c966b5SDoug Evans         return len;
52501c966b5SDoug Evans     }
52601c966b5SDoug Evans 
52701c966b5SDoug Evans     /* Huge frames (> DMARFC) are dropped. */
52801c966b5SDoug Evans     max_frame_len = REG_DMARFC_RXMS(emc->regs[REG_DMARFC]);
52901c966b5SDoug Evans     if (len + CRC_LENGTH > max_frame_len) {
53001c966b5SDoug Evans         trace_npcm7xx_emc_packet_dropped(len);
53101c966b5SDoug Evans         emc_set_mista(emc, REG_MISTA_DFOI);
53201c966b5SDoug Evans         emc_update_rx_irq(emc);
53301c966b5SDoug Evans         return len;
53401c966b5SDoug Evans     }
53501c966b5SDoug Evans 
53601c966b5SDoug Evans     /*
53701c966b5SDoug Evans      * Long Frames (> MAX_ETH_FRAME_SIZE) are also dropped, unless MCMDR.ALP
53801c966b5SDoug Evans      * is set.
53901c966b5SDoug Evans      */
54001c966b5SDoug Evans     long_frame = false;
54101c966b5SDoug Evans     if (len + CRC_LENGTH > MAX_ETH_FRAME_SIZE) {
54201c966b5SDoug Evans         if (emc->regs[REG_MCMDR] & REG_MCMDR_ALP) {
54301c966b5SDoug Evans             long_frame = true;
54401c966b5SDoug Evans         } else {
54501c966b5SDoug Evans             trace_npcm7xx_emc_packet_dropped(len);
54601c966b5SDoug Evans             emc_set_mista(emc, REG_MISTA_PTLE);
54701c966b5SDoug Evans             emc_update_rx_irq(emc);
54801c966b5SDoug Evans             return len;
54901c966b5SDoug Evans         }
55001c966b5SDoug Evans     }
55101c966b5SDoug Evans 
55201c966b5SDoug Evans     desc_addr = RX_DESC_NRXDSA(emc->regs[REG_CRXDSA]);
55301c966b5SDoug Evans     if (emc_read_rx_desc(desc_addr, &rx_desc)) {
55401c966b5SDoug Evans         /* Error reading descriptor, already reported. */
55501c966b5SDoug Evans         emc_halt_rx(emc, REG_MISTA_RXBERR);
55601c966b5SDoug Evans         emc_update_rx_irq(emc);
55701c966b5SDoug Evans         return len;
55801c966b5SDoug Evans     }
55901c966b5SDoug Evans 
56001c966b5SDoug Evans     /* Nothing we can do if we don't own the descriptor. */
56101c966b5SDoug Evans     if (!(rx_desc.status_and_length & RX_DESC_STATUS_OWNER_MASK)) {
56201c966b5SDoug Evans         trace_npcm7xx_emc_cpu_owned_desc(desc_addr);
56301c966b5SDoug Evans         emc_halt_rx(emc, REG_MISTA_RDU);
56401c966b5SDoug Evans         emc_update_rx_irq(emc);
56501c966b5SDoug Evans         return len;
56601c966b5SDoug Evans     }
56701c966b5SDoug Evans 
56801c966b5SDoug Evans     crc = 0;
56901c966b5SDoug Evans     crc_ptr = (uint8_t *) &crc;
57001c966b5SDoug Evans     if (!(emc->regs[REG_MCMDR] & REG_MCMDR_SPCRC)) {
57101c966b5SDoug Evans         crc = cpu_to_be32(crc32(~0, buf, len));
57201c966b5SDoug Evans     }
57301c966b5SDoug Evans 
57401c966b5SDoug Evans     /* Give the descriptor back regardless of what happens. */
57501c966b5SDoug Evans     rx_desc.status_and_length &= ~RX_DESC_STATUS_OWNER_MASK;
57601c966b5SDoug Evans 
57701c966b5SDoug Evans     buf_addr = rx_desc.rxbsa;
57801c966b5SDoug Evans     emc->regs[REG_CRXBSA] = buf_addr;
579ba06fe8aSPhilippe Mathieu-Daudé     if (dma_memory_write(&address_space_memory, buf_addr, buf,
580ba06fe8aSPhilippe Mathieu-Daudé                          len, MEMTXATTRS_UNSPECIFIED) ||
58101c966b5SDoug Evans         (!(emc->regs[REG_MCMDR] & REG_MCMDR_SPCRC) &&
582ba06fe8aSPhilippe Mathieu-Daudé          dma_memory_write(&address_space_memory, buf_addr + len,
583ba06fe8aSPhilippe Mathieu-Daudé                           crc_ptr, 4, MEMTXATTRS_UNSPECIFIED))) {
58401c966b5SDoug Evans         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bus error writing packet\n",
58501c966b5SDoug Evans                       __func__);
58601c966b5SDoug Evans         emc_set_mista(emc, REG_MISTA_RXBERR);
58701c966b5SDoug Evans         emc_set_next_rx_descriptor(emc, &rx_desc, desc_addr);
58801c966b5SDoug Evans         emc_update_rx_irq(emc);
58901c966b5SDoug Evans         trace_npcm7xx_emc_rx_done(emc->regs[REG_CRXDSA]);
59001c966b5SDoug Evans         return len;
59101c966b5SDoug Evans     }
59201c966b5SDoug Evans 
59301c966b5SDoug Evans     trace_npcm7xx_emc_received_packet(len);
59401c966b5SDoug Evans 
59501c966b5SDoug Evans     /* Note: We've already verified len+4 <= 0xffff. */
59601c966b5SDoug Evans     rx_desc.status_and_length = len;
59701c966b5SDoug Evans     if (!(emc->regs[REG_MCMDR] & REG_MCMDR_SPCRC)) {
59801c966b5SDoug Evans         rx_desc.status_and_length += 4;
59901c966b5SDoug Evans     }
60001c966b5SDoug Evans     rx_desc.status_and_length |= RX_DESC_STATUS_RXGD;
60101c966b5SDoug Evans     emc_set_mista(emc, REG_MISTA_RXGD);
60201c966b5SDoug Evans 
60301c966b5SDoug Evans     if (emc->regs[REG_MISTA] & emc->regs[REG_MIEN] & REG_MISTA_RXINTR) {
60401c966b5SDoug Evans         rx_desc.status_and_length |= RX_DESC_STATUS_RXINTR;
60501c966b5SDoug Evans     }
60601c966b5SDoug Evans     if (long_frame) {
60701c966b5SDoug Evans         rx_desc.status_and_length |= RX_DESC_STATUS_PTLE;
60801c966b5SDoug Evans     }
60901c966b5SDoug Evans 
61001c966b5SDoug Evans     emc_set_next_rx_descriptor(emc, &rx_desc, desc_addr);
61101c966b5SDoug Evans     emc_update_rx_irq(emc);
61201c966b5SDoug Evans     trace_npcm7xx_emc_rx_done(emc->regs[REG_CRXDSA]);
61301c966b5SDoug Evans     return len;
61401c966b5SDoug Evans }
61501c966b5SDoug Evans 
npcm7xx_emc_read(void * opaque,hwaddr offset,unsigned size)61601c966b5SDoug Evans static uint64_t npcm7xx_emc_read(void *opaque, hwaddr offset, unsigned size)
61701c966b5SDoug Evans {
61801c966b5SDoug Evans     NPCM7xxEMCState *emc = opaque;
61901c966b5SDoug Evans     uint32_t reg = offset / sizeof(uint32_t);
62001c966b5SDoug Evans     uint32_t result;
62101c966b5SDoug Evans 
62201c966b5SDoug Evans     if (reg >= NPCM7XX_NUM_EMC_REGS) {
62301c966b5SDoug Evans         qemu_log_mask(LOG_GUEST_ERROR,
62401c966b5SDoug Evans                       "%s: Invalid offset 0x%04" HWADDR_PRIx "\n",
62501c966b5SDoug Evans                       __func__, offset);
62601c966b5SDoug Evans         return 0;
62701c966b5SDoug Evans     }
62801c966b5SDoug Evans 
62901c966b5SDoug Evans     switch (reg) {
63001c966b5SDoug Evans     case REG_MIID:
63101c966b5SDoug Evans         /*
63201c966b5SDoug Evans          * We don't implement MII. For determinism, always return zero as
63301c966b5SDoug Evans          * writes record the last value written for debugging purposes.
63401c966b5SDoug Evans          */
63501c966b5SDoug Evans         qemu_log_mask(LOG_UNIMP, "%s: Read of MIID, returning 0\n", __func__);
63601c966b5SDoug Evans         result = 0;
63701c966b5SDoug Evans         break;
63801c966b5SDoug Evans     case REG_TSDR:
63901c966b5SDoug Evans     case REG_RSDR:
64001c966b5SDoug Evans         qemu_log_mask(LOG_GUEST_ERROR,
64101c966b5SDoug Evans                       "%s: Read of write-only reg, %s/%d\n",
64201c966b5SDoug Evans                       __func__, emc_reg_name(reg), reg);
64301c966b5SDoug Evans         return 0;
64401c966b5SDoug Evans     default:
64501c966b5SDoug Evans         result = emc->regs[reg];
64601c966b5SDoug Evans         break;
64701c966b5SDoug Evans     }
64801c966b5SDoug Evans 
64901c966b5SDoug Evans     trace_npcm7xx_emc_reg_read(emc->emc_num, result, emc_reg_name(reg), reg);
65001c966b5SDoug Evans     return result;
65101c966b5SDoug Evans }
65201c966b5SDoug Evans 
npcm7xx_emc_write(void * opaque,hwaddr offset,uint64_t v,unsigned size)65301c966b5SDoug Evans static void npcm7xx_emc_write(void *opaque, hwaddr offset,
65401c966b5SDoug Evans                               uint64_t v, unsigned size)
65501c966b5SDoug Evans {
65601c966b5SDoug Evans     NPCM7xxEMCState *emc = opaque;
65701c966b5SDoug Evans     uint32_t reg = offset / sizeof(uint32_t);
65801c966b5SDoug Evans     uint32_t value = v;
65901c966b5SDoug Evans 
66001c966b5SDoug Evans     g_assert(size == sizeof(uint32_t));
66101c966b5SDoug Evans 
66201c966b5SDoug Evans     if (reg >= NPCM7XX_NUM_EMC_REGS) {
66301c966b5SDoug Evans         qemu_log_mask(LOG_GUEST_ERROR,
66401c966b5SDoug Evans                       "%s: Invalid offset 0x%04" HWADDR_PRIx "\n",
66501c966b5SDoug Evans                       __func__, offset);
66601c966b5SDoug Evans         return;
66701c966b5SDoug Evans     }
66801c966b5SDoug Evans 
66901c966b5SDoug Evans     trace_npcm7xx_emc_reg_write(emc->emc_num, emc_reg_name(reg), reg, value);
67001c966b5SDoug Evans 
67101c966b5SDoug Evans     switch (reg) {
67201c966b5SDoug Evans     case REG_CAMCMR:
67301c966b5SDoug Evans         emc->regs[reg] = value;
67401c966b5SDoug Evans         break;
67501c966b5SDoug Evans     case REG_CAMEN:
67601c966b5SDoug Evans         /* Only CAM0 is supported, don't pretend otherwise. */
67701c966b5SDoug Evans         if (value & ~1) {
67801c966b5SDoug Evans             qemu_log_mask(LOG_GUEST_ERROR,
67901c966b5SDoug Evans                           "%s: Only CAM0 is supported, cannot enable others"
68001c966b5SDoug Evans                           ": 0x%x\n",
68101c966b5SDoug Evans                           __func__, value);
68201c966b5SDoug Evans         }
68301c966b5SDoug Evans         emc->regs[reg] = value & 1;
68401c966b5SDoug Evans         break;
68501c966b5SDoug Evans     case REG_CAMM_BASE + 0:
68601c966b5SDoug Evans         emc->regs[reg] = value;
68701c966b5SDoug Evans         break;
68801c966b5SDoug Evans     case REG_CAML_BASE + 0:
68901c966b5SDoug Evans         emc->regs[reg] = value;
69001c966b5SDoug Evans         break;
69101c966b5SDoug Evans     case REG_MCMDR: {
69201c966b5SDoug Evans         uint32_t prev;
69301c966b5SDoug Evans         if (value & REG_MCMDR_SWR) {
69401c966b5SDoug Evans             emc_soft_reset(emc);
69501c966b5SDoug Evans             /* On h/w the reset happens over multiple cycles. For now KISS. */
69601c966b5SDoug Evans             break;
69701c966b5SDoug Evans         }
69801c966b5SDoug Evans         prev = emc->regs[reg];
69901c966b5SDoug Evans         emc->regs[reg] = value;
70001c966b5SDoug Evans         /* Update tx state. */
70101c966b5SDoug Evans         if (!(prev & REG_MCMDR_TXON) &&
70201c966b5SDoug Evans             (value & REG_MCMDR_TXON)) {
70301c966b5SDoug Evans             emc->regs[REG_CTXDSA] = emc->regs[REG_TXDLSA];
70401c966b5SDoug Evans             /*
70501c966b5SDoug Evans              * Linux kernel turns TX on with CPU still holding descriptor,
70601c966b5SDoug Evans              * which suggests we should wait for a write to TSDR before trying
70701c966b5SDoug Evans              * to send a packet: so we don't send one here.
70801c966b5SDoug Evans              */
70901c966b5SDoug Evans         } else if ((prev & REG_MCMDR_TXON) &&
71001c966b5SDoug Evans                    !(value & REG_MCMDR_TXON)) {
71101c966b5SDoug Evans             emc->regs[REG_MGSTA] |= REG_MGSTA_TXHA;
71201c966b5SDoug Evans         }
71301c966b5SDoug Evans         if (!(value & REG_MCMDR_TXON)) {
71401c966b5SDoug Evans             emc_halt_tx(emc, 0);
71501c966b5SDoug Evans         }
71601c966b5SDoug Evans         /* Update rx state. */
71701c966b5SDoug Evans         if (!(prev & REG_MCMDR_RXON) &&
71801c966b5SDoug Evans             (value & REG_MCMDR_RXON)) {
71901c966b5SDoug Evans             emc->regs[REG_CRXDSA] = emc->regs[REG_RXDLSA];
72001c966b5SDoug Evans         } else if ((prev & REG_MCMDR_RXON) &&
72101c966b5SDoug Evans                    !(value & REG_MCMDR_RXON)) {
72201c966b5SDoug Evans             emc->regs[REG_MGSTA] |= REG_MGSTA_RXHA;
72301c966b5SDoug Evans         }
724a62ee00aSDoug Evans         if (value & REG_MCMDR_RXON) {
725530cd6c2SPatrick Venture             emc_enable_rx_and_flush(emc);
726a62ee00aSDoug Evans         } else {
72701c966b5SDoug Evans             emc_halt_rx(emc, 0);
72801c966b5SDoug Evans         }
72901c966b5SDoug Evans         break;
73001c966b5SDoug Evans     }
73101c966b5SDoug Evans     case REG_TXDLSA:
73201c966b5SDoug Evans     case REG_RXDLSA:
73301c966b5SDoug Evans     case REG_DMARFC:
73401c966b5SDoug Evans     case REG_MIID:
73501c966b5SDoug Evans         emc->regs[reg] = value;
73601c966b5SDoug Evans         break;
73701c966b5SDoug Evans     case REG_MIEN:
73801c966b5SDoug Evans         emc->regs[reg] = value;
73901c966b5SDoug Evans         emc_update_irq_from_reg_change(emc);
74001c966b5SDoug Evans         break;
74101c966b5SDoug Evans     case REG_MISTA:
74201c966b5SDoug Evans         /* Clear the bits that have 1 in "value". */
74301c966b5SDoug Evans         emc->regs[reg] &= ~value;
74401c966b5SDoug Evans         emc_update_irq_from_reg_change(emc);
74501c966b5SDoug Evans         break;
74601c966b5SDoug Evans     case REG_MGSTA:
74701c966b5SDoug Evans         /* Clear the bits that have 1 in "value". */
74801c966b5SDoug Evans         emc->regs[reg] &= ~value;
74901c966b5SDoug Evans         break;
75001c966b5SDoug Evans     case REG_TSDR:
75101c966b5SDoug Evans         if (emc->regs[REG_MCMDR] & REG_MCMDR_TXON) {
75201c966b5SDoug Evans             emc->tx_active = true;
75301c966b5SDoug Evans             /* Keep trying to send packets until we run out. */
75401c966b5SDoug Evans             while (emc->tx_active) {
75501c966b5SDoug Evans                 emc_try_send_next_packet(emc);
75601c966b5SDoug Evans             }
75701c966b5SDoug Evans         }
75801c966b5SDoug Evans         break;
75901c966b5SDoug Evans     case REG_RSDR:
76001c966b5SDoug Evans         if (emc->regs[REG_MCMDR] & REG_MCMDR_RXON) {
761530cd6c2SPatrick Venture             emc_enable_rx_and_flush(emc);
76201c966b5SDoug Evans         }
76301c966b5SDoug Evans         break;
76401c966b5SDoug Evans     case REG_MIIDA:
76501c966b5SDoug Evans         emc->regs[reg] = value & ~REG_MIIDA_BUSY;
76601c966b5SDoug Evans         break;
76701c966b5SDoug Evans     case REG_MRPC:
76801c966b5SDoug Evans     case REG_MRPCC:
76901c966b5SDoug Evans     case REG_MREPC:
77001c966b5SDoug Evans     case REG_CTXDSA:
77101c966b5SDoug Evans     case REG_CTXBSA:
77201c966b5SDoug Evans     case REG_CRXDSA:
77301c966b5SDoug Evans     case REG_CRXBSA:
77401c966b5SDoug Evans         qemu_log_mask(LOG_GUEST_ERROR,
77501c966b5SDoug Evans                       "%s: Write to read-only reg %s/%d\n",
77601c966b5SDoug Evans                       __func__, emc_reg_name(reg), reg);
77701c966b5SDoug Evans         break;
77801c966b5SDoug Evans     default:
77901c966b5SDoug Evans         qemu_log_mask(LOG_UNIMP, "%s: Write to unimplemented reg %s/%d\n",
78001c966b5SDoug Evans                       __func__, emc_reg_name(reg), reg);
78101c966b5SDoug Evans         break;
78201c966b5SDoug Evans     }
78301c966b5SDoug Evans }
78401c966b5SDoug Evans 
78501c966b5SDoug Evans static const struct MemoryRegionOps npcm7xx_emc_ops = {
78601c966b5SDoug Evans     .read = npcm7xx_emc_read,
78701c966b5SDoug Evans     .write = npcm7xx_emc_write,
78801c966b5SDoug Evans     .endianness = DEVICE_LITTLE_ENDIAN,
78901c966b5SDoug Evans     .valid = {
79001c966b5SDoug Evans         .min_access_size = 4,
79101c966b5SDoug Evans         .max_access_size = 4,
79201c966b5SDoug Evans         .unaligned = false,
79301c966b5SDoug Evans     },
79401c966b5SDoug Evans };
79501c966b5SDoug Evans 
emc_cleanup(NetClientState * nc)79601c966b5SDoug Evans static void emc_cleanup(NetClientState *nc)
79701c966b5SDoug Evans {
79801c966b5SDoug Evans     /* Nothing to do yet. */
79901c966b5SDoug Evans }
80001c966b5SDoug Evans 
80101c966b5SDoug Evans static NetClientInfo net_npcm7xx_emc_info = {
80201c966b5SDoug Evans     .type = NET_CLIENT_DRIVER_NIC,
80301c966b5SDoug Evans     .size = sizeof(NICState),
80401c966b5SDoug Evans     .can_receive = emc_can_receive,
80501c966b5SDoug Evans     .receive = emc_receive,
80601c966b5SDoug Evans     .cleanup = emc_cleanup,
80701c966b5SDoug Evans     .link_status_changed = emc_set_link,
80801c966b5SDoug Evans };
80901c966b5SDoug Evans 
npcm7xx_emc_realize(DeviceState * dev,Error ** errp)81001c966b5SDoug Evans static void npcm7xx_emc_realize(DeviceState *dev, Error **errp)
81101c966b5SDoug Evans {
81201c966b5SDoug Evans     NPCM7xxEMCState *emc = NPCM7XX_EMC(dev);
81301c966b5SDoug Evans     SysBusDevice *sbd = SYS_BUS_DEVICE(emc);
81401c966b5SDoug Evans 
81501c966b5SDoug Evans     memory_region_init_io(&emc->iomem, OBJECT(emc), &npcm7xx_emc_ops, emc,
81601c966b5SDoug Evans                           TYPE_NPCM7XX_EMC, 4 * KiB);
81701c966b5SDoug Evans     sysbus_init_mmio(sbd, &emc->iomem);
81801c966b5SDoug Evans     sysbus_init_irq(sbd, &emc->tx_irq);
81901c966b5SDoug Evans     sysbus_init_irq(sbd, &emc->rx_irq);
82001c966b5SDoug Evans 
82101c966b5SDoug Evans     qemu_macaddr_default_if_unset(&emc->conf.macaddr);
82201c966b5SDoug Evans     emc->nic = qemu_new_nic(&net_npcm7xx_emc_info, &emc->conf,
8237d0fefdfSAkihiko Odaki                             object_get_typename(OBJECT(dev)), dev->id,
8247d0fefdfSAkihiko Odaki                             &dev->mem_reentrancy_guard, emc);
82501c966b5SDoug Evans     qemu_format_nic_info_str(qemu_get_queue(emc->nic), emc->conf.macaddr.a);
82601c966b5SDoug Evans }
82701c966b5SDoug Evans 
npcm7xx_emc_unrealize(DeviceState * dev)82801c966b5SDoug Evans static void npcm7xx_emc_unrealize(DeviceState *dev)
82901c966b5SDoug Evans {
83001c966b5SDoug Evans     NPCM7xxEMCState *emc = NPCM7XX_EMC(dev);
83101c966b5SDoug Evans 
83201c966b5SDoug Evans     qemu_del_nic(emc->nic);
83301c966b5SDoug Evans }
83401c966b5SDoug Evans 
83501c966b5SDoug Evans static const VMStateDescription vmstate_npcm7xx_emc = {
83601c966b5SDoug Evans     .name = TYPE_NPCM7XX_EMC,
83701c966b5SDoug Evans     .version_id = 0,
83801c966b5SDoug Evans     .minimum_version_id = 0,
8391de81b42SRichard Henderson     .fields = (const VMStateField[]) {
84001c966b5SDoug Evans         VMSTATE_UINT8(emc_num, NPCM7xxEMCState),
84101c966b5SDoug Evans         VMSTATE_UINT32_ARRAY(regs, NPCM7xxEMCState, NPCM7XX_NUM_EMC_REGS),
84201c966b5SDoug Evans         VMSTATE_BOOL(tx_active, NPCM7xxEMCState),
84301c966b5SDoug Evans         VMSTATE_BOOL(rx_active, NPCM7xxEMCState),
84401c966b5SDoug Evans         VMSTATE_END_OF_LIST(),
84501c966b5SDoug Evans     },
84601c966b5SDoug Evans };
84701c966b5SDoug Evans 
84801c966b5SDoug Evans static Property npcm7xx_emc_properties[] = {
84901c966b5SDoug Evans     DEFINE_NIC_PROPERTIES(NPCM7xxEMCState, conf),
85001c966b5SDoug Evans     DEFINE_PROP_END_OF_LIST(),
85101c966b5SDoug Evans };
85201c966b5SDoug Evans 
npcm7xx_emc_class_init(ObjectClass * klass,void * data)85301c966b5SDoug Evans static void npcm7xx_emc_class_init(ObjectClass *klass, void *data)
85401c966b5SDoug Evans {
85501c966b5SDoug Evans     DeviceClass *dc = DEVICE_CLASS(klass);
85601c966b5SDoug Evans 
85701c966b5SDoug Evans     set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
85801c966b5SDoug Evans     dc->desc = "NPCM7xx EMC Controller";
85901c966b5SDoug Evans     dc->realize = npcm7xx_emc_realize;
86001c966b5SDoug Evans     dc->unrealize = npcm7xx_emc_unrealize;
861e3d08143SPeter Maydell     device_class_set_legacy_reset(dc, npcm7xx_emc_reset);
86201c966b5SDoug Evans     dc->vmsd = &vmstate_npcm7xx_emc;
86301c966b5SDoug Evans     device_class_set_props(dc, npcm7xx_emc_properties);
86401c966b5SDoug Evans }
86501c966b5SDoug Evans 
86601c966b5SDoug Evans static const TypeInfo npcm7xx_emc_info = {
86701c966b5SDoug Evans     .name = TYPE_NPCM7XX_EMC,
86801c966b5SDoug Evans     .parent = TYPE_SYS_BUS_DEVICE,
86901c966b5SDoug Evans     .instance_size = sizeof(NPCM7xxEMCState),
87001c966b5SDoug Evans     .class_init = npcm7xx_emc_class_init,
87101c966b5SDoug Evans };
87201c966b5SDoug Evans 
npcm7xx_emc_register_type(void)87301c966b5SDoug Evans static void npcm7xx_emc_register_type(void)
87401c966b5SDoug Evans {
87501c966b5SDoug Evans     type_register_static(&npcm7xx_emc_info);
87601c966b5SDoug Evans }
87701c966b5SDoug Evans 
87801c966b5SDoug Evans type_init(npcm7xx_emc_register_type)
879