[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH 1/2] hw/net: Add support for Intel pch_gbe ether
From: |
Philippe Mathieu-Daudé |
Subject: |
Re: [Qemu-devel] [PATCH 1/2] hw/net: Add support for Intel pch_gbe ethernet |
Date: |
Mon, 2 Jul 2018 20:36:57 -0300 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.8.0 |
Cc'ing Jason, the "Network devices" maintainer.
On 02/17/2018 04:22 PM, Paul Burton wrote:
> This patch introduces support for emulating the ethernet controller
> found in the Intel EG20T Platform Controller Hub, referred to as pch_gbe
> for consistency with both Linux & U-Boot.
>
> Documentation for the hardware can be found here:
>
>
> https://www.intel.com/content/www/us/en/intelligent-systems/queens-bay/platform-controller-hub-eg20t-datasheet.html
>
> The device is used on MIPS Boston development boards as well as the
> Intel Crown Bay platform including devices such as the Minnowboard V1.
>
> Enough functionality is implemented for Linux to make use of the device,
> and has been tested using Linux v4.16-rc1.
>
> Signed-off-by: Paul Burton <address@hidden>
> Cc: Aurelien Jarno <address@hidden>
> Cc: Yongbok Kim <address@hidden>
> ---
>
> hw/net/Makefile.objs | 1 +
> hw/net/pch_gbe.c | 766
> +++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 767 insertions(+)
> create mode 100644 hw/net/pch_gbe.c
>
> diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs
> index ab22968641..08706d9a96 100644
> --- a/hw/net/Makefile.objs
> +++ b/hw/net/Makefile.objs
> @@ -12,6 +12,7 @@ common-obj-$(CONFIG_E1000E_PCI) += e1000e.o e1000e_core.o
> e1000x_common.o
> common-obj-$(CONFIG_RTL8139_PCI) += rtl8139.o
> common-obj-$(CONFIG_VMXNET3_PCI) += net_tx_pkt.o net_rx_pkt.o
> common-obj-$(CONFIG_VMXNET3_PCI) += vmxnet3.o
> +common-obj-$(CONFIG_PCH_GBE_PCI) += pch_gbe.o
>
> common-obj-$(CONFIG_SMC91C111) += smc91c111.o
> common-obj-$(CONFIG_LAN9118) += lan9118.o
> diff --git a/hw/net/pch_gbe.c b/hw/net/pch_gbe.c
> new file mode 100644
> index 0000000000..be9a9f5916
> --- /dev/null
> +++ b/hw/net/pch_gbe.c
> @@ -0,0 +1,766 @@
> +#include "qemu/osdep.h"
> +#include "hw/hw.h"
> +#include "hw/net/mii.h"
> +#include "hw/pci/pci.h"
> +#include "net/checksum.h"
> +#include "net/eth.h"
> +#include "net/net.h"
> +#include "qemu/bitops.h"
> +#include "qemu/log.h"
> +
> +#define TYPE_PCH_GBE "pch_gbe"
> +#define PCH_GBE(obj) OBJECT_CHECK(PCHGBEState, (obj), TYPE_PCH_GBE)
> +
> +#define PCH_GBE_INTR_RX_DMA_CMPLT BIT(0)
> +#define PCH_GBE_INTR_RX_VALID BIT(1)
> +#define PCH_GBE_INTR_RX_FRAME_ERR BIT(2)
> +#define PCH_GBE_INTR_RX_FIFO_ERR BIT(3)
> +#define PCH_GBE_INTR_RX_DMA_ERR BIT(4)
> +#define PCH_GBE_INTR_RX_DSC_EMP BIT(5)
> +#define PCH_GBE_INTR_TX_CMPLT BIT(8)
> +#define PCH_GBE_INTR_TX_DMA_CMPLT BIT(9)
> +#define PCH_GBE_INTR_TX_FIFO_ERR BIT(10)
> +#define PCH_GBE_INTR_TX_DMA_ERR BIT(11)
> +#define PCH_GBE_INTR_PAUSE_CMPLT BIT(12)
> +#define PCH_GBE_INTR_MIIM_CMPLT BIT(16)
> +#define PCH_GBE_INTR_PHY_INT BIT(20)
> +#define PCH_GBE_INTR_WOL_DET BIT(24)
> +#define PCH_GBE_INTR_TCPIP_ERR BIT(28)
> +#define PCH_GBE_INTR_ALL ( \
> + PCH_GBE_INTR_RX_DMA_CMPLT | \
> + PCH_GBE_INTR_RX_VALID | \
> + PCH_GBE_INTR_RX_FRAME_ERR | \
> + PCH_GBE_INTR_RX_FIFO_ERR | \
> + PCH_GBE_INTR_RX_DMA_ERR | \
> + PCH_GBE_INTR_RX_DSC_EMP | \
> + PCH_GBE_INTR_TX_CMPLT | \
> + PCH_GBE_INTR_TX_DMA_CMPLT | \
> + PCH_GBE_INTR_TX_FIFO_ERR | \
> + PCH_GBE_INTR_TX_DMA_ERR | \
> + PCH_GBE_INTR_PAUSE_CMPLT | \
> + PCH_GBE_INTR_MIIM_CMPLT | \
> + PCH_GBE_INTR_PHY_INT | \
> + PCH_GBE_INTR_WOL_DET | \
> + PCH_GBE_INTR_TCPIP_ERR)
> +
> +struct pch_gbe_tx_desc {
> + uint32_t addr;
> +
> + uint32_t len;
> +#define PCH_GBE_TX_LENGTH 0xffff
> +
> + uint32_t control;
> +#define PCH_GBE_TX_CONTROL_EOB 0x3
> +#define PCH_GBE_TX_CONTROL_WORDS 0xfffc
> +#define PCH_GBE_TX_CONTROL_APAD BIT(16)
> +#define PCH_GBE_TX_CONTROL_ICRC BIT(17)
> +#define PCH_GBE_TX_CONTROL_ITAG BIT(18)
> +#define PCH_GBE_TX_CONTROL_ACCOFF BIT(19)
> +
> + uint32_t status;
> +#define PCH_GBE_TX_STATUS_TSHRT BIT(22)
> +#define PCH_GBE_TX_STATUS_TLNG BIT(23)
> +#define PCH_GBE_TX_STATUS_ABT BIT(28)
> +#define PCH_GBE_TX_STATUS_CMPLT BIT(29)
> +};
> +
> +struct pch_gbe_rx_desc {
> + uint32_t addr;
> +
> + uint32_t acc_status;
> +
> + uint32_t mac_status;
> +#define PCH_GBE_RX_MAC_STATUS_EOB 0x3
> +#define PCH_GBE_RX_MAC_STATUS_WORDS 0xfffc
> +#define PCH_GBE_RX_MAC_STATUS_LENGTH 0xffff
> +#define PCH_GBE_RX_MAC_STATUS_TSHRT BIT(19)
> +#define PCH_GBE_RX_MAC_STATUS_TLNG BIT(20)
> +
> + uint32_t dma_status;
> +};
> +
> +typedef struct {
> + /*< private >*/
> + PCIDevice parent_obj;
> + /*< public >*/
> +
> + NICState *nic;
> + NICConf conf;
> +
> + bool reset;
> + bool phy_reset;
> +
> + bool link;
> +
> + uint32_t intr_status;
> + uint32_t intr_status_hold;
> + uint32_t intr_enable;
> +
> + uint16_t addr_mask;
> +
> + bool rx_enable;
> + bool rx_dma_enable;
> + bool rx_acc_enable;
> + bool rx_acc_csum_off;
> + uint32_t rx_desc_base;
> + uint32_t rx_desc_size;
> + uint32_t rx_desc_hard_ptr;
> + uint32_t rx_desc_hard_ptr_hold;
> + uint32_t rx_desc_soft_ptr;
> +
> + bool tx_dma_enable;
> + bool tx_acc_enable;
> + uint32_t tx_desc_base;
> + uint32_t tx_desc_size;
> + uint32_t tx_desc_hard_ptr;
> + uint32_t tx_desc_hard_ptr_hold;
> + uint32_t tx_desc_soft_ptr;
> +
> + uint8_t miim_phy_addr;
> + uint8_t miim_reg_addr;
> + uint16_t miim_data;
> +
> + MemoryRegion bar_mem;
> + MemoryRegion bar_io;
> + uint16_t io_index;
> +
> + uint8_t *pkt_buf;
> +} PCHGBEState;
> +
> +static void pch_gbe_update_irq(PCHGBEState *s)
> +{
> + PCIDevice *d = PCI_DEVICE(s);
> +
> + pci_set_irq(d, !!(s->intr_status & s->intr_enable));
> +}
> +
> +static void pch_gbe_set_intr(PCHGBEState *s, uint32_t intr)
> +{
> + s->intr_status |= intr;
> + pch_gbe_update_irq(s);
> +}
> +
> +static void pch_gbe_tx(PCHGBEState *s)
> +{
> + struct pch_gbe_tx_desc desc;
> + dma_addr_t addr, len, pad;
> + uint32_t ctl, sts;
> +
> + if (!s->tx_dma_enable) {
> + return;
> + }
> +
> + while (s->tx_desc_hard_ptr != s->tx_desc_soft_ptr) {
> + if ((s->tx_desc_hard_ptr & 0xf) ||
> + (s->tx_desc_hard_ptr < s->tx_desc_base) ||
> + (s->tx_desc_hard_ptr >= (s->tx_desc_base + s->tx_desc_size))) {
> + pch_gbe_set_intr(s, PCH_GBE_INTR_TX_DMA_ERR);
> + break;
> + }
> +
> + pci_dma_read(PCI_DEVICE(s), s->tx_desc_hard_ptr, &desc,
> sizeof(desc));
> +
> + ctl = le32_to_cpu(desc.control);
> + addr = le32_to_cpu(desc.addr);
> + len = le32_to_cpu(desc.len) & PCH_GBE_TX_LENGTH;
> + pad = s->tx_acc_enable ? 2 : 0;
> +
> + pci_dma_read(PCI_DEVICE(s), addr, s->pkt_buf, len + pad);
> +
> + if (pad && (len >= 14)) {
> + memcpy(s->pkt_buf + 14, s->pkt_buf + 16, len - 14);
> + }
> +
> + if ((ctl & PCH_GBE_TX_CONTROL_APAD) && (len < 64)) {
> + memset(s->pkt_buf + len, 0, 64 - len);
> + len = 64;
> + }
> +
> + if (s->tx_acc_enable &&
> + !(ctl & (PCH_GBE_TX_CONTROL_ICRC | PCH_GBE_TX_CONTROL_ACCOFF))) {
> + net_checksum_calculate(s->pkt_buf, len);
> + }
> +
> + qemu_send_packet(qemu_get_queue(s->nic), s->pkt_buf, len);
> + pch_gbe_set_intr(s, PCH_GBE_INTR_TX_DMA_CMPLT);
> +
> + sts = PCH_GBE_TX_STATUS_CMPLT;
> + desc.status = cpu_to_le32(sts);
> + pci_dma_write(PCI_DEVICE(s), s->tx_desc_hard_ptr, &desc,
> sizeof(desc));
> + pch_gbe_set_intr(s, PCH_GBE_INTR_TX_CMPLT);
> +
> + s->tx_desc_hard_ptr += sizeof(desc);
> + if (s->tx_desc_hard_ptr >= (s->tx_desc_base + s->tx_desc_size)) {
> + s->tx_desc_hard_ptr = s->tx_desc_base;
> + }
> + }
> +}
> +
> +static ssize_t pch_gbe_receive(NetClientState *nc,
> + const uint8_t *buf, size_t len)
> +{
> + PCHGBEState *s = qemu_get_nic_opaque(nc);
> + struct pch_gbe_rx_desc desc;
> + uint32_t mac_status;
> + dma_addr_t addr;
> +
> + if (s->reset || !s->link || !s->rx_enable || !s->rx_dma_enable) {
> + return -1;
> + }
> +
> + if (s->rx_desc_hard_ptr == s->rx_desc_soft_ptr) {
> + pch_gbe_set_intr(s, PCH_GBE_INTR_RX_DSC_EMP);
> + return -1;
> + }
> +
> + pci_dma_read(PCI_DEVICE(s), s->rx_desc_hard_ptr, &desc, sizeof(desc));
> + addr = le32_to_cpu(desc.addr);
> +
> + if (len < 1519) {
> + memcpy(s->pkt_buf, buf, len);
> +
> + /* Add an empty FCS */
> + memset(&s->pkt_buf[len], 0, 4);
> + len += 4;
> +
> + pci_dma_write(PCI_DEVICE(s), addr, s->pkt_buf, len);
> +
> + mac_status = (len + 3) & PCH_GBE_RX_MAC_STATUS_EOB;
> + mac_status |= (len + 3) & PCH_GBE_RX_MAC_STATUS_WORDS;
> +
> + /*
> + * Unsure why this is required, but the Linux driver subtracts 4 from
> + * the length if bit 1 of rx_eob is set. We add 4 here to compensate.
> + */
> + if (mac_status & BIT(1)) {
> + mac_status = (mac_status + 4) & PCH_GBE_RX_MAC_STATUS_LENGTH;
> + }
> +
> + pch_gbe_set_intr(s, PCH_GBE_INTR_RX_DMA_CMPLT);
> + pch_gbe_set_intr(s, PCH_GBE_INTR_RX_VALID);
> + } else {
> + mac_status = PCH_GBE_RX_MAC_STATUS_TLNG;
> + pch_gbe_set_intr(s, PCH_GBE_INTR_RX_FRAME_ERR);
> + }
> +
> + desc.acc_status = 0;
> + desc.mac_status = cpu_to_le32(mac_status);
> + desc.dma_status = 0;
> + pci_dma_write(PCI_DEVICE(s), s->rx_desc_hard_ptr, &desc, sizeof(desc));
> +
> + s->rx_desc_hard_ptr += sizeof(desc);
> + if (s->rx_desc_hard_ptr >= (s->rx_desc_base + s->rx_desc_size)) {
> + s->rx_desc_hard_ptr = s->rx_desc_base;
> + }
> +
> + return len;
> +}
> +
> +static int pch_gbe_can_receive(NetClientState *nc)
> +{
> + PCHGBEState *s = qemu_get_nic_opaque(nc);
> +
> + return s->rx_desc_hard_ptr != s->rx_desc_soft_ptr;
> +}
> +
> +static void pch_gbe_set_link_status(NetClientState *nc)
> +{
> + PCHGBEState *s = qemu_get_nic_opaque(nc);
> +
> + s->link = !nc->link_down;
> +}
> +
> +static NetClientInfo pch_gbe_net_client_info = {
> + .type = NET_CLIENT_DRIVER_NIC,
> + .size = sizeof(NICState),
> + .can_receive = pch_gbe_can_receive,
> + .receive = pch_gbe_receive,
> + .link_status_changed = pch_gbe_set_link_status,
> +};
> +
> +static void pch_gbe_reset(DeviceState *d)
> +{
> + PCHGBEState *s = PCH_GBE(d);
> +
> + s->io_index = 0;
> +
> + s->intr_status = 0;
> + s->intr_status_hold = 0;
> + s->intr_enable = 0;
> + pch_gbe_update_irq(s);
> +
> + pch_gbe_set_link_status(qemu_get_queue(s->nic));
> +}
> +
> +/*
> + * PHY registers
> + */
> +
> +static void pch_gbe_phy_write(PCHGBEState *s, uint8_t addr, uint16_t val)
> +{
> + switch (addr) {
> + default:
> + qemu_log_mask(LOG_UNIMP, "pch_gbe: Unhandled PHY write 0x%x =
> 0x%x\n",
> + addr, val);
> + }
> +}
> +
> +static uint16_t pch_gbe_phy_read(PCHGBEState *s, uint8_t addr)
> +{
> + switch (addr) {
> + case MII_BMCR:
> + return MII_BMCR_SPEED1000 | MII_BMCR_FD;
> +
> + case MII_BMSR:
> + return MII_BMSR_100TX_FD | MII_BMSR_AN_COMP |
> + (s->link ? MII_BMSR_LINK_ST : 0);
> +
> + default:
> + qemu_log_mask(LOG_UNIMP, "pch_gbe: Unhandled PHY read 0x%x\n", addr);
> + }
> + return 0;
> +}
> +
> +/*
> + * PCI Memory Mapped I/O Space
> + */
> +
> +enum pch_gbe_mem_regs {
> + PCH_GBE_MEM_INTR = 0x000,
> + PCH_GBE_MEM_INTR_EN = 0x004,
> + PCH_GBE_MEM_INTR_HOLD = 0x018,
> +
> + PCH_GBE_MEM_RESET = 0x00c,
> +#define PCH_GBE_MEM_RESET_ALL BIT(31)
> +#define PCH_GBE_MEM_RESET_TX BIT(15)
> +#define PCH_GBE_MEM_RESET_RX BIT(14)
> +
> + PCH_GBE_MEM_TCPIPACC = 0x010,
> +#define PCH_GBE_MEM_TCPIPACC_RXEN BIT(0)
> +#define PCH_GBE_MEM_TCPIPACC_TXEN BIT(1)
> +#define PCH_GBE_MEM_TCPIPACC_RXSUMOFF BIT(2)
> +
> + PCH_GBE_MEM_MAX_RXEN = 0x020,
> +#define PCH_GBE_MEM_MAX_RXEN_EN BIT(0)
> +
> + PCH_GBE_MEM_MAC_ADDR_1A = 0x060,
> + PCH_GBE_MEM_MAC_ADDR_1B = 0x064,
> +
> + PCH_GBE_MEM_ADDR_MASK = 0x0e0,
> +#define PCH_GBE_MEM_ADDR_MASK_MAC0 BIT(0)
> +#define PCH_GBE_MEM_ADDR_MASK_BUSY BIT(31)
> +
> + PCH_GBE_MEM_MIIM = 0x0e4,
> +#define PCH_GBE_MEM_MIIM_READY BIT(26)
> +#define PCH_GBE_MEM_MIIM_WRITE BIT(26)
> +#define PCH_GBE_MEM_MIIM_PHY_ADDR_SHF 21
> +#define PCH_GBE_MEM_MIIM_PHY_ADDR_MSK (0x1f << 21)
> +#define PCH_GBE_MEM_MIIM_REG_ADDR_SHF 16
> +#define PCH_GBE_MEM_MIIM_REG_ADDR_MSK (0x1f << 16)
> +#define PCH_GBE_MEM_MIIM_DATA 0xffff
> +
> + PCH_GBE_MEM_RGMII_STATUS = 0x0ec,
> +#define PCH_GBE_MEM_RGMII_STATUS_FDPLX BIT(0)
> +#define PCH_GBE_MEM_RGMII_STATUS_UP BIT(3)
> +
> + PCH_GBE_MEM_DMA_CONTROL = 0x100,
> +#define PCH_GBE_MEM_DMA_CONTROL_TX_EN BIT(0)
> +#define PCH_GBE_MEM_DMA_CONTROL_RX_EN BIT(1)
> +
> + PCH_GBE_MEM_RX_DESC_BASE = 0x110,
> +
> + PCH_GBE_MEM_RX_DESC_SIZE = 0x114,
> +#define PCH_GBE_MEM_RX_DESC_SIZE_SIZE 0xfff0
> +
> + PCH_GBE_MEM_RX_DESC_HARD_PTR = 0x118,
> + PCH_GBE_MEM_RX_DESC_HARD_PTR_HOLD = 0x11c,
> + PCH_GBE_MEM_RX_DESC_SOFT_PTR = 0x120,
> +
> + PCH_GBE_MEM_TX_DESC_BASE = 0x130,
> +
> + PCH_GBE_MEM_TX_DESC_SIZE = 0x134,
> +#define PCH_GBE_MEM_TX_DESC_SIZE_SIZE 0xfff0
> +
> + PCH_GBE_MEM_TX_DESC_HARD_PTR = 0x138,
> + PCH_GBE_MEM_TX_DESC_HARD_PTR_HOLD = 0x13c,
> + PCH_GBE_MEM_TX_DESC_SOFT_PTR = 0x140,
> +
> + PCH_GBE_MEM_SRST = 0x1fc,
> +#define PCH_GBE_MEM_SRST_SRST BIT(0)
> +};
> +
> +static void pch_gbe_mem_write(void *opaque, hwaddr addr,
> + uint64_t val, unsigned size)
> +{
> + PCHGBEState *s = PCH_GBE(opaque);
> +
> + switch (addr) {
> + case PCH_GBE_MEM_INTR:
> + case PCH_GBE_MEM_INTR_HOLD:
> + case PCH_GBE_MEM_RX_DESC_HARD_PTR_HOLD:
> + case PCH_GBE_MEM_TX_DESC_HARD_PTR_HOLD:
> + /* read-only */
> + break;
> +
> + case PCH_GBE_MEM_INTR_EN:
> + s->intr_enable = val & PCH_GBE_INTR_ALL;
> + pch_gbe_update_irq(s);
> + break;
> +
> + case PCH_GBE_MEM_RESET:
> + s->reset = !!(val & PCH_GBE_MEM_RESET_ALL);
> + if (s->reset) {
> + pch_gbe_reset(DEVICE(s));
> + s->reset = false;
> + break;
> + }
> + if (val & PCH_GBE_MEM_RESET_TX) {
> + qemu_log_mask(LOG_UNIMP,
> + "pch_gbe: Partial (TX) reset unimplemented\n");
> + }
> + if (val & PCH_GBE_MEM_RESET_RX) {
> + qemu_log_mask(LOG_UNIMP,
> + "pch_gbe: Partial (RX) reset unimplemented\n");
> + }
> + break;
> +
> + case PCH_GBE_MEM_TCPIPACC:
> + s->rx_acc_enable = !!(val & PCH_GBE_MEM_TCPIPACC_RXEN);
> + s->tx_acc_enable = !!(val & PCH_GBE_MEM_TCPIPACC_TXEN);
> + s->rx_acc_csum_off = !!(val & PCH_GBE_MEM_TCPIPACC_RXSUMOFF);
> + if (s->rx_acc_enable) {
> + qemu_log_mask(LOG_UNIMP,
> + "pch_gbe: RX acceleration unimplemented\n");
> + }
> + break;
> +
> + case PCH_GBE_MEM_MAX_RXEN:
> + s->rx_enable = !!(val & PCH_GBE_MEM_MAX_RXEN_EN);
> + break;
> +
> + case PCH_GBE_MEM_MAC_ADDR_1A:
> + s->conf.macaddr.a[0] = (val >> 0);
> + s->conf.macaddr.a[1] = (val >> 8);
> + s->conf.macaddr.a[2] = (val >> 16);
> + s->conf.macaddr.a[3] = (val >> 24);
> + break;
> +
> + case PCH_GBE_MEM_MAC_ADDR_1B:
> + s->conf.macaddr.a[4] = (val >> 0);
> + s->conf.macaddr.a[5] = (val >> 8);
> + break;
> +
> + case PCH_GBE_MEM_ADDR_MASK:
> + s->addr_mask = val & PCH_GBE_MEM_ADDR_MASK_MAC0;
> + break;
> +
> + case PCH_GBE_MEM_MIIM:
> + s->miim_phy_addr = (val & PCH_GBE_MEM_MIIM_PHY_ADDR_MSK)
> + >> PCH_GBE_MEM_MIIM_PHY_ADDR_SHF;
> + s->miim_reg_addr = (val & PCH_GBE_MEM_MIIM_REG_ADDR_MSK)
> + >> PCH_GBE_MEM_MIIM_REG_ADDR_SHF;
> + s->miim_data = val & PCH_GBE_MEM_MIIM_DATA;
> + if (s->miim_phy_addr == 1) {
> + if (val & PCH_GBE_MEM_MIIM_WRITE) {
> + pch_gbe_phy_write(s, s->miim_reg_addr, s->miim_data);
> + } else {
> + s->miim_data = pch_gbe_phy_read(s, s->miim_reg_addr);
> + }
> + } else if (!(val & PCH_GBE_MEM_MIIM_WRITE)) {
> + s->miim_data = PCH_GBE_MEM_MIIM_DATA;
> + }
> + pch_gbe_set_intr(s, PCH_GBE_INTR_MIIM_CMPLT);
> + break;
> +
> + case PCH_GBE_MEM_DMA_CONTROL:
> + s->rx_dma_enable = !!(val & PCH_GBE_MEM_DMA_CONTROL_RX_EN);
> + s->tx_dma_enable = !!(val & PCH_GBE_MEM_DMA_CONTROL_TX_EN);
> + break;
> +
> + case PCH_GBE_MEM_RX_DESC_BASE:
> + s->rx_desc_base = val;
> + s->rx_desc_hard_ptr = s->rx_desc_base;
> + break;
> +
> + case PCH_GBE_MEM_RX_DESC_SIZE:
> + s->rx_desc_size = (val & PCH_GBE_MEM_RX_DESC_SIZE_SIZE) + 0x10;
> + break;
> +
> + case PCH_GBE_MEM_RX_DESC_HARD_PTR:
> + s->rx_desc_hard_ptr = val;
> + break;
> +
> + case PCH_GBE_MEM_RX_DESC_SOFT_PTR:
> + s->rx_desc_soft_ptr = val;
> + break;
> +
> + case PCH_GBE_MEM_TX_DESC_BASE:
> + s->tx_desc_base = val;
> + s->tx_desc_hard_ptr = s->tx_desc_base;
> + pch_gbe_tx(s);
> + break;
> +
> + case PCH_GBE_MEM_TX_DESC_SIZE:
> + s->tx_desc_size = (val & PCH_GBE_MEM_TX_DESC_SIZE_SIZE) + 0x10;
> + pch_gbe_tx(s);
> + break;
> +
> + case PCH_GBE_MEM_TX_DESC_HARD_PTR:
> + s->tx_desc_hard_ptr = val;
> + pch_gbe_tx(s);
> + break;
> +
> + case PCH_GBE_MEM_TX_DESC_SOFT_PTR:
> + s->tx_desc_soft_ptr = val;
> + pch_gbe_tx(s);
> + break;
> +
> + case PCH_GBE_MEM_SRST:
> + s->reset = val & PCH_GBE_MEM_SRST_SRST;
> + if (s->reset) {
> + pch_gbe_reset(DEVICE(s));
> + }
> + break;
> +
> + default:
> + qemu_log_mask(LOG_UNIMP, "pch_gbe: Unhandled PCI mem write 0x%"
> + HWADDR_PRIx " = 0x%" PRIx64 "\n", addr, val);
> + }
> +}
> +
> +static uint64_t pch_gbe_mem_read(void *opaque, hwaddr addr, unsigned size)
> +{
> + PCHGBEState *s = PCH_GBE(opaque);
> +
> + switch (addr) {
> + case PCH_GBE_MEM_INTR:
> + s->rx_desc_hard_ptr_hold = s->rx_desc_hard_ptr;
> + s->tx_desc_hard_ptr_hold = s->tx_desc_hard_ptr;
> + s->intr_status_hold = s->intr_status;
> + s->intr_status = 0;
> + pch_gbe_update_irq(s);
> + case PCH_GBE_MEM_INTR_HOLD:
> + return s->intr_status_hold;
> +
> + case PCH_GBE_MEM_INTR_EN:
> + return s->intr_enable;
> +
> + case PCH_GBE_MEM_RESET:
> + return 0;
> +
> + case PCH_GBE_MEM_TCPIPACC:
> + return (s->rx_acc_enable ? PCH_GBE_MEM_TCPIPACC_RXEN : 0) |
> + (s->tx_acc_enable ? PCH_GBE_MEM_TCPIPACC_TXEN : 0) |
> + (s->rx_acc_csum_off ? PCH_GBE_MEM_TCPIPACC_RXSUMOFF : 0);
> +
> + case PCH_GBE_MEM_MAX_RXEN:
> + return s->rx_enable ? PCH_GBE_MEM_MAX_RXEN_EN : 0;
> +
> + case PCH_GBE_MEM_MAC_ADDR_1A:
> + return s->conf.macaddr.a[0] << 0 |
> + s->conf.macaddr.a[1] << 8 |
> + s->conf.macaddr.a[2] << 16 |
> + s->conf.macaddr.a[3] << 24;
> +
> + case PCH_GBE_MEM_MAC_ADDR_1B:
> + return s->conf.macaddr.a[4] << 0 |
> + s->conf.macaddr.a[5] << 8;
> +
> + case PCH_GBE_MEM_ADDR_MASK:
> + return s->addr_mask;
> +
> + case PCH_GBE_MEM_MIIM:
> + return PCH_GBE_MEM_MIIM_READY |
> + (s->miim_phy_addr << PCH_GBE_MEM_MIIM_PHY_ADDR_SHF) |
> + (s->miim_reg_addr << PCH_GBE_MEM_MIIM_REG_ADDR_SHF) |
> + s->miim_data;
> +
> + case PCH_GBE_MEM_SRST:
> + return s->reset ? PCH_GBE_MEM_SRST_SRST : 0;
> +
> + case PCH_GBE_MEM_RGMII_STATUS:
> + return (s->link ? PCH_GBE_MEM_RGMII_STATUS_UP : 0) |
> + PCH_GBE_MEM_RGMII_STATUS_FDPLX;
> +
> + case PCH_GBE_MEM_DMA_CONTROL:
> + return (s->rx_dma_enable ? PCH_GBE_MEM_DMA_CONTROL_RX_EN : 0) |
> + (s->tx_dma_enable ? PCH_GBE_MEM_DMA_CONTROL_TX_EN : 0);
> +
> + case PCH_GBE_MEM_RX_DESC_BASE:
> + return s->rx_desc_base;
> +
> + case PCH_GBE_MEM_RX_DESC_SIZE:
> + return (s->rx_desc_size - 0x10) & PCH_GBE_MEM_RX_DESC_SIZE_SIZE;
> +
> + case PCH_GBE_MEM_RX_DESC_HARD_PTR:
> + return s->rx_desc_hard_ptr;
> +
> + case PCH_GBE_MEM_RX_DESC_HARD_PTR_HOLD:
> + return s->rx_desc_hard_ptr_hold;
> +
> + case PCH_GBE_MEM_RX_DESC_SOFT_PTR:
> + return s->rx_desc_soft_ptr;
> +
> + case PCH_GBE_MEM_TX_DESC_BASE:
> + return s->tx_desc_base;
> +
> + case PCH_GBE_MEM_TX_DESC_SIZE:
> + return (s->tx_desc_size - 0x10) & PCH_GBE_MEM_TX_DESC_SIZE_SIZE;
> +
> + case PCH_GBE_MEM_TX_DESC_HARD_PTR:
> + return s->tx_desc_hard_ptr;
> +
> + case PCH_GBE_MEM_TX_DESC_HARD_PTR_HOLD:
> + return s->tx_desc_hard_ptr_hold;
> +
> + case PCH_GBE_MEM_TX_DESC_SOFT_PTR:
> + return s->tx_desc_soft_ptr;
> +
> + default:
> + qemu_log_mask(LOG_UNIMP, "pch_gbe: Unhandled PCI mem read 0x%"
> + HWADDR_PRIx "\n", addr);
> + return -1;
> + }
> +}
> +
> +static const MemoryRegionOps pch_gbe_mem_ops = {
> + .read = pch_gbe_mem_read,
> + .write = pch_gbe_mem_write,
> + .impl = {
> + .min_access_size = 1,
> + .max_access_size = 4,
> + },
> + .endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +/*
> + * PCI I/O Space
> + */
> +
> +enum pch_gbe_io_regs {
> + PCH_GBE_IO_INDEX = 0x0,
> +#define PCH_GBE_IO_INDEX_INDEX 0x1ff
> +
> + PCH_GBE_IO_DATA = 0x4,
> +};
> +
> +static void pch_gbe_io_write(void *opaque, hwaddr addr,
> + uint64_t val, unsigned size)
> +{
> + PCHGBEState *s = PCH_GBE(opaque);
> +
> + switch (addr) {
> + case PCH_GBE_IO_INDEX:
> + s->io_index = val & PCH_GBE_IO_INDEX_INDEX;
> + break;
> +
> + case PCH_GBE_IO_DATA:
> + pch_gbe_mem_write(opaque, s->io_index, val, size);
> + break;
> +
> + default:
> + qemu_log_mask(LOG_UNIMP, "pch_gbe: Unhandled PCI I/O write 0x%"
> + HWADDR_PRIx " = 0x%" PRIx64 "\n", addr, val);
> + }
> +}
> +
> +static uint64_t pch_gbe_io_read(void *opaque, hwaddr addr, unsigned size)
> +{
> + PCHGBEState *s = PCH_GBE(opaque);
> +
> + switch (addr) {
> + case PCH_GBE_IO_INDEX:
> + return s->io_index;
> +
> + case PCH_GBE_IO_DATA:
> + return pch_gbe_mem_read(opaque, s->io_index, size);
> +
> + default:
> + qemu_log_mask(LOG_UNIMP, "pch_gbe: Unhandled PCI I/O read 0x%"
> + HWADDR_PRIx "\n", addr);
> + return -1;
> + }
> +}
> +
> +static const MemoryRegionOps pch_gbe_io_ops = {
> + .read = pch_gbe_io_read,
> + .write = pch_gbe_io_write,
> + .impl = {
> + .min_access_size = 1,
> + .max_access_size = 4,
> + },
> + .endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +static void pch_gbe_realize(PCIDevice *dev, Error **errp)
> +{
> + PCHGBEState *s = PCH_GBE(dev);
> +
> + pci_config_set_interrupt_pin(dev->config, 1);
> +
> + memory_region_init_io(&s->bar_io, OBJECT(s), &pch_gbe_io_ops, s,
> + "pch_gbe-io", 0x20);
> + memory_region_init_io(&s->bar_mem, OBJECT(s), &pch_gbe_mem_ops, s,
> + "pch_gbe-mem", 0x200);
> +
> + pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->bar_io);
> + pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar_mem);
> +
> + qemu_macaddr_default_if_unset(&s->conf.macaddr);
> +
> + s->pkt_buf = g_malloc(64 * 1024);
> +
> + s->nic = qemu_new_nic(&pch_gbe_net_client_info, &s->conf,
> + object_get_typename(OBJECT(dev)), DEVICE(dev)->id,
> s);
> + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
> +}
> +
> +static void pch_gbe_uninit(PCIDevice *dev)
> +{
> + PCHGBEState *s = PCH_GBE(dev);
> +
> + g_free(s->pkt_buf);
> +}
> +
> +static void pch_gbe_instance_init(Object *obj)
> +{
> +}
> +
> +static Property pch_gbe_properties[] = {
> + DEFINE_NIC_PROPERTIES(PCHGBEState, conf),
> + DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void pch_gbe_class_init(ObjectClass *klass, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
> +
> + k->realize = pch_gbe_realize;
> + k->exit = pch_gbe_uninit;
> + k->vendor_id = PCI_VENDOR_ID_INTEL;
> + k->device_id = 0x8802;
> + k->revision = 0x2;
> + k->class_id = PCI_CLASS_NETWORK_ETHERNET;
> + dc->reset = pch_gbe_reset;
> + dc->props = pch_gbe_properties;
> + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
> +}
> +
> +static const TypeInfo pch_gbe_info = {
> + .name = TYPE_PCH_GBE,
> + .parent = TYPE_PCI_DEVICE,
> + .instance_size = sizeof(PCHGBEState),
> + .class_init = pch_gbe_class_init,
> + .instance_init = pch_gbe_instance_init,
> + .interfaces = (InterfaceInfo[]) {
> + { INTERFACE_PCIE_DEVICE },
> + { },
> + },
> +};
> +
> +static void pch_gbe_register_types(void)
> +{
> + type_register_static(&pch_gbe_info);
> +}
> +type_init(pch_gbe_register_types)
>
- Re: [Qemu-devel] [PATCH 1/2] hw/net: Add support for Intel pch_gbe ethernet,
Philippe Mathieu-Daudé <=