From 190af10f0b5a07140ec4ce8e6ef04b7cb238dde1 Mon Sep 17 00:00:00 2001 From: Shrikrishna Khare Date: Thu, 16 Jun 2016 10:51:53 -0700 Subject: [PATCH 1/7] vmxnet3: prepare for version 3 changes vmxnet3 is currently at version 2, but some command definitions from previous vmxnet3 versions are missing. Add those definitions before moving to version 3. Also, introduce utility macros for vmxnet3 version comparison and update Copyright information and Maintained by. Signed-off-by: Shrikrishna Khare Signed-off-by: David S. Miller --- drivers/net/vmxnet3/Makefile | 4 ++-- drivers/net/vmxnet3/upt1_defs.h | 4 ++-- drivers/net/vmxnet3/vmxnet3_defs.h | 9 ++++++--- drivers/net/vmxnet3/vmxnet3_drv.c | 22 +++++++++++++--------- drivers/net/vmxnet3/vmxnet3_ethtool.c | 4 ++-- drivers/net/vmxnet3/vmxnet3_int.h | 13 +++++++++++-- 6 files changed, 36 insertions(+), 20 deletions(-) diff --git a/drivers/net/vmxnet3/Makefile b/drivers/net/vmxnet3/Makefile index 880f5098eac92..8cdbb63d1bb0a 100644 --- a/drivers/net/vmxnet3/Makefile +++ b/drivers/net/vmxnet3/Makefile @@ -2,7 +2,7 @@ # # Linux driver for VMware's vmxnet3 ethernet NIC. # -# Copyright (C) 2007-2009, VMware, Inc. All Rights Reserved. +# Copyright (C) 2007-2016, VMware, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the @@ -21,7 +21,7 @@ # The full GNU General Public License is included in this distribution in # the file called "COPYING". # -# Maintained by: Shreyas Bhatewara +# Maintained by: pv-drivers@vmware.com # # ################################################################################ diff --git a/drivers/net/vmxnet3/upt1_defs.h b/drivers/net/vmxnet3/upt1_defs.h index 969c751ee404f..db9f1fde3aac4 100644 --- a/drivers/net/vmxnet3/upt1_defs.h +++ b/drivers/net/vmxnet3/upt1_defs.h @@ -1,7 +1,7 @@ /* * Linux driver for VMware's vmxnet3 ethernet NIC. * - * Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved. + * Copyright (C) 2008-2016, VMware, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -20,7 +20,7 @@ * The full GNU General Public License is included in this distribution in * the file called "COPYING". * - * Maintained by: Shreyas Bhatewara + * Maintained by: pv-drivers@vmware.com * */ diff --git a/drivers/net/vmxnet3/vmxnet3_defs.h b/drivers/net/vmxnet3/vmxnet3_defs.h index 72ba8ae7f09a6..8345e0c4fec4b 100644 --- a/drivers/net/vmxnet3/vmxnet3_defs.h +++ b/drivers/net/vmxnet3/vmxnet3_defs.h @@ -1,7 +1,7 @@ /* * Linux driver for VMware's vmxnet3 ethernet NIC. * - * Copyright (C) 2008-2015, VMware, Inc. All Rights Reserved. + * Copyright (C) 2008-2016, VMware, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -20,7 +20,7 @@ * The full GNU General Public License is included in this distribution in * the file called "COPYING". * - * Maintained by: Shreyas Bhatewara + * Maintained by: pv-drivers@vmware.com * */ @@ -76,7 +76,9 @@ enum { VMXNET3_CMD_UPDATE_IML, VMXNET3_CMD_UPDATE_PMCFG, VMXNET3_CMD_UPDATE_FEATURE, + VMXNET3_CMD_RESERVED1, VMXNET3_CMD_LOAD_PLUGIN, + VMXNET3_CMD_RESERVED2, VMXNET3_CMD_FIRST_GET = 0xF00D0000, VMXNET3_CMD_GET_QUEUE_STATUS = VMXNET3_CMD_FIRST_GET, @@ -87,7 +89,8 @@ enum { VMXNET3_CMD_GET_DID_LO, VMXNET3_CMD_GET_DID_HI, VMXNET3_CMD_GET_DEV_EXTRA_INFO, - VMXNET3_CMD_GET_CONF_INTR + VMXNET3_CMD_GET_CONF_INTR, + VMXNET3_CMD_GET_RESERVED1, }; /* diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index 08885bc8d6db6..507c53d4e09cf 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -1,7 +1,7 @@ /* * Linux driver for VMware's vmxnet3 ethernet NIC. * - * Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved. + * Copyright (C) 2008-2016, VMware, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -20,7 +20,7 @@ * The full GNU General Public License is included in this distribution in * the file called "COPYING". * - * Maintained by: Shreyas Bhatewara + * Maintained by: pv-drivers@vmware.com * */ @@ -1363,7 +1363,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, rbi->dma_addr = new_dma_addr; rxd->addr = cpu_to_le64(rbi->dma_addr); rxd->len = rbi->len; - if (adapter->version == 2 && + if (VMXNET3_VERSION_GE_2(adapter) && rcd->type == VMXNET3_CDTYPE_RXCOMP_LRO) { struct Vmxnet3_RxCompDescExt *rcdlro; rcdlro = (struct Vmxnet3_RxCompDescExt *)rcd; @@ -3200,12 +3200,16 @@ vmxnet3_probe_device(struct pci_dev *pdev, goto err_alloc_pci; ver = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_VRRS); - if (ver & 2) { - VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_VRRS, 2); - adapter->version = 2; - } else if (ver & 1) { - VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_VRRS, 1); - adapter->version = 1; + if (ver & (1 << VMXNET3_REV_2)) { + VMXNET3_WRITE_BAR1_REG(adapter, + VMXNET3_REG_VRRS, + 1 << VMXNET3_REV_2); + adapter->version = VMXNET3_REV_2 + 1; + } else if (ver & (1 << VMXNET3_REV_1)) { + VMXNET3_WRITE_BAR1_REG(adapter, + VMXNET3_REG_VRRS, + 1 << VMXNET3_REV_1); + adapter->version = VMXNET3_REV_1 + 1; } else { dev_err(&pdev->dev, "Incompatible h/w version (0x%x) for adapter\n", ver); diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c index 9ba11d7377539..163e99c910237 100644 --- a/drivers/net/vmxnet3/vmxnet3_ethtool.c +++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c @@ -1,7 +1,7 @@ /* * Linux driver for VMware's vmxnet3 ethernet NIC. * - * Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved. + * Copyright (C) 2008-2016, VMware, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -20,7 +20,7 @@ * The full GNU General Public License is included in this distribution in * the file called "COPYING". * - * Maintained by: Shreyas Bhatewara + * Maintained by: pv-drivers@vmware.com * */ diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h index 3d2b64e63408d..de068e92cedb6 100644 --- a/drivers/net/vmxnet3/vmxnet3_int.h +++ b/drivers/net/vmxnet3/vmxnet3_int.h @@ -1,7 +1,7 @@ /* * Linux driver for VMware's vmxnet3 ethernet NIC. * - * Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved. + * Copyright (C) 2008-2016, VMware, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -20,7 +20,7 @@ * The full GNU General Public License is included in this distribution in * the file called "COPYING". * - * Maintained by: Shreyas Bhatewara + * Maintained by: pv-drivers@vmware.com * */ @@ -79,6 +79,10 @@ #define VMXNET3_RSS #endif +#define VMXNET3_REV_3 2 /* Vmxnet3 Rev. 3 */ +#define VMXNET3_REV_2 1 /* Vmxnet3 Rev. 2 */ +#define VMXNET3_REV_1 0 /* Vmxnet3 Rev. 1 */ + /* * Capabilities */ @@ -387,6 +391,11 @@ struct vmxnet3_adapter { #define VMXNET3_GET_ADDR_LO(dma) ((u32)(dma)) #define VMXNET3_GET_ADDR_HI(dma) ((u32)(((u64)(dma)) >> 32)) +#define VMXNET3_VERSION_GE_2(adapter) \ + (adapter->version >= VMXNET3_REV_2 + 1) +#define VMXNET3_VERSION_GE_3(adapter) \ + (adapter->version >= VMXNET3_REV_3 + 1) + /* must be a multiple of VMXNET3_RING_SIZE_ALIGN */ #define VMXNET3_DEF_TX_RING_SIZE 512 #define VMXNET3_DEF_RX_RING_SIZE 256 From f35c7480f81b70f9c3030d96a3807e8faba34cf7 Mon Sep 17 00:00:00 2001 From: Shrikrishna Khare Date: Thu, 16 Jun 2016 10:51:54 -0700 Subject: [PATCH 2/7] vmxnet3: introduce generalized command interface to configure the device Shared memory is used to exchange information between the vmxnet3 driver and the emulation. In order to request emulation to perform a task, the driver first populates specific fields in this shared memory and then issues corresponding command by writing to the command register(CMD). The layout of the shared memory was defined by vmxnet3 version 1 and cannot be extended for every new command without breaking backward compatibility. To address this problem, in vmxnet3 version 3, the emulation repurposed a reserved field in the shared memory to represent command information instead. For new commands, the driver first populates the command information field in the shared memory and then issues the command. The emulation interprets the data written to the command information depending on the type of the command. This patch exposes this capability to the driver. Signed-off-by: Guolin Yang Signed-off-by: Shrikrishna Khare Signed-off-by: David S. Miller --- drivers/net/vmxnet3/vmxnet3_defs.h | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/net/vmxnet3/vmxnet3_defs.h b/drivers/net/vmxnet3/vmxnet3_defs.h index 8345e0c4fec4b..a26a69df0e3da 100644 --- a/drivers/net/vmxnet3/vmxnet3_defs.h +++ b/drivers/net/vmxnet3/vmxnet3_defs.h @@ -79,6 +79,7 @@ enum { VMXNET3_CMD_RESERVED1, VMXNET3_CMD_LOAD_PLUGIN, VMXNET3_CMD_RESERVED2, + VMXNET3_CMD_RESERVED3, VMXNET3_CMD_FIRST_GET = 0xF00D0000, VMXNET3_CMD_GET_QUEUE_STATUS = VMXNET3_CMD_FIRST_GET, @@ -612,6 +613,18 @@ struct Vmxnet3_RxQueueDesc { u8 __pad[88]; /* 128 aligned */ }; +struct Vmxnet3_SetPolling { + u8 enablePolling; +}; + +/* If the command data <= 16 bytes, use the shared memory directly. + * otherwise, use variable length configuration descriptor. + */ +union Vmxnet3_CmdInfo { + struct Vmxnet3_VariableLenConfDesc varConf; + struct Vmxnet3_SetPolling setPolling; + __le64 data[2]; +}; struct Vmxnet3_DSDevRead { /* read-only region for device, read by dev in response to a SET cmd */ @@ -630,7 +643,14 @@ struct Vmxnet3_DriverShared { __le32 pad; struct Vmxnet3_DSDevRead devRead; __le32 ecr; - __le32 reserved[5]; + __le32 reserved; + union { + __le32 reserved1[4]; + union Vmxnet3_CmdInfo cmdInfo; /* only valid in the context of + * executing the relevant + * command + */ + } cu; }; From 3c8b3efc061a745d888869dc3462ac4f7dd582d9 Mon Sep 17 00:00:00 2001 From: Shrikrishna Khare Date: Thu, 16 Jun 2016 10:51:55 -0700 Subject: [PATCH 3/7] vmxnet3: allow variable length transmit data ring buffer vmxnet3 driver supports transmit data ring viz. a set of fixed size buffers used by the driver to copy packet headers. Small packets that fit these buffers are copied into these buffers entirely. Currently this buffer size of fixed at 128 bytes. This patch extends transmit data ring implementation to allow variable length transmit data ring buffers. The length of the buffer is read from the emulation during initialization. Signed-off-by: Sriram Rangarajan Signed-off-by: Shrikrishna Khare Signed-off-by: David S. Miller --- drivers/net/vmxnet3/vmxnet3_defs.h | 12 +++++- drivers/net/vmxnet3/vmxnet3_drv.c | 55 ++++++++++++++++++++------- drivers/net/vmxnet3/vmxnet3_ethtool.c | 9 +++-- drivers/net/vmxnet3/vmxnet3_int.h | 7 +++- 4 files changed, 64 insertions(+), 19 deletions(-) diff --git a/drivers/net/vmxnet3/vmxnet3_defs.h b/drivers/net/vmxnet3/vmxnet3_defs.h index a26a69df0e3da..701d98944c58e 100644 --- a/drivers/net/vmxnet3/vmxnet3_defs.h +++ b/drivers/net/vmxnet3/vmxnet3_defs.h @@ -92,6 +92,7 @@ enum { VMXNET3_CMD_GET_DEV_EXTRA_INFO, VMXNET3_CMD_GET_CONF_INTR, VMXNET3_CMD_GET_RESERVED1, + VMXNET3_CMD_GET_TXDATA_DESC_SIZE }; /* @@ -377,6 +378,10 @@ union Vmxnet3_GenericDesc { #define VMXNET3_RING_SIZE_ALIGN 32 #define VMXNET3_RING_SIZE_MASK (VMXNET3_RING_SIZE_ALIGN - 1) +/* Tx Data Ring buffer size must be a multiple of 64 */ +#define VMXNET3_TXDATA_DESC_SIZE_ALIGN 64 +#define VMXNET3_TXDATA_DESC_SIZE_MASK (VMXNET3_TXDATA_DESC_SIZE_ALIGN - 1) + /* Max ring size */ #define VMXNET3_TX_RING_MAX_SIZE 4096 #define VMXNET3_TC_RING_MAX_SIZE 4096 @@ -384,6 +389,9 @@ union Vmxnet3_GenericDesc { #define VMXNET3_RX_RING2_MAX_SIZE 4096 #define VMXNET3_RC_RING_MAX_SIZE 8192 +#define VMXNET3_TXDATA_DESC_MIN_SIZE 128 +#define VMXNET3_TXDATA_DESC_MAX_SIZE 2048 + /* a list of reasons for queue stop */ enum { @@ -470,7 +478,9 @@ struct Vmxnet3_TxQueueConf { __le32 compRingSize; /* # of comp desc */ __le32 ddLen; /* size of driver data */ u8 intrIdx; - u8 _pad[7]; + u8 _pad1[1]; + __le16 txDataRingDescSize; + u8 _pad2[4]; }; diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index 507c53d4e09cf..4e42eb04a1981 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -435,8 +435,8 @@ vmxnet3_tq_destroy(struct vmxnet3_tx_queue *tq, tq->tx_ring.base = NULL; } if (tq->data_ring.base) { - dma_free_coherent(&adapter->pdev->dev, tq->data_ring.size * - sizeof(struct Vmxnet3_TxDataDesc), + dma_free_coherent(&adapter->pdev->dev, + tq->data_ring.size * tq->txdata_desc_size, tq->data_ring.base, tq->data_ring.basePA); tq->data_ring.base = NULL; } @@ -478,8 +478,8 @@ vmxnet3_tq_init(struct vmxnet3_tx_queue *tq, tq->tx_ring.next2fill = tq->tx_ring.next2comp = 0; tq->tx_ring.gen = VMXNET3_INIT_GEN; - memset(tq->data_ring.base, 0, tq->data_ring.size * - sizeof(struct Vmxnet3_TxDataDesc)); + memset(tq->data_ring.base, 0, + tq->data_ring.size * tq->txdata_desc_size); /* reset the tx comp ring contents to 0 and reset comp ring states */ memset(tq->comp_ring.base, 0, tq->comp_ring.size * @@ -514,10 +514,10 @@ vmxnet3_tq_create(struct vmxnet3_tx_queue *tq, } tq->data_ring.base = dma_alloc_coherent(&adapter->pdev->dev, - tq->data_ring.size * sizeof(struct Vmxnet3_TxDataDesc), + tq->data_ring.size * tq->txdata_desc_size, &tq->data_ring.basePA, GFP_KERNEL); if (!tq->data_ring.base) { - netdev_err(adapter->netdev, "failed to allocate data ring\n"); + netdev_err(adapter->netdev, "failed to allocate tx data ring\n"); goto err; } @@ -689,7 +689,7 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx, if (ctx->copy_size) { ctx->sop_txd->txd.addr = cpu_to_le64(tq->data_ring.basePA + tq->tx_ring.next2fill * - sizeof(struct Vmxnet3_TxDataDesc)); + tq->txdata_desc_size); ctx->sop_txd->dword[2] = cpu_to_le32(dw2 | ctx->copy_size); ctx->sop_txd->dword[3] = 0; @@ -873,8 +873,9 @@ vmxnet3_parse_hdr(struct sk_buff *skb, struct vmxnet3_tx_queue *tq, ctx->eth_ip_hdr_size = 0; ctx->l4_hdr_size = 0; /* copy as much as allowed */ - ctx->copy_size = min((unsigned int)VMXNET3_HDR_COPY_SIZE - , skb_headlen(skb)); + ctx->copy_size = min_t(unsigned int, + tq->txdata_desc_size, + skb_headlen(skb)); } if (skb->len <= VMXNET3_HDR_COPY_SIZE) @@ -885,7 +886,7 @@ vmxnet3_parse_hdr(struct sk_buff *skb, struct vmxnet3_tx_queue *tq, goto err; } - if (unlikely(ctx->copy_size > VMXNET3_HDR_COPY_SIZE)) { + if (unlikely(ctx->copy_size > tq->txdata_desc_size)) { tq->stats.oversized_hdr++; ctx->copy_size = 0; return 0; @@ -2336,6 +2337,7 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter) tqc->ddPA = cpu_to_le64(tq->buf_info_pa); tqc->txRingSize = cpu_to_le32(tq->tx_ring.size); tqc->dataRingSize = cpu_to_le32(tq->data_ring.size); + tqc->txDataRingDescSize = cpu_to_le32(tq->txdata_desc_size); tqc->compRingSize = cpu_to_le32(tq->comp_ring.size); tqc->ddLen = cpu_to_le32( sizeof(struct vmxnet3_tx_buf_info) * @@ -2689,7 +2691,8 @@ vmxnet3_adjust_rx_ring_size(struct vmxnet3_adapter *adapter) int vmxnet3_create_queues(struct vmxnet3_adapter *adapter, u32 tx_ring_size, - u32 rx_ring_size, u32 rx_ring2_size) + u32 rx_ring_size, u32 rx_ring2_size, + u16 txdata_desc_size) { int err = 0, i; @@ -2698,6 +2701,7 @@ vmxnet3_create_queues(struct vmxnet3_adapter *adapter, u32 tx_ring_size, tq->tx_ring.size = tx_ring_size; tq->data_ring.size = tx_ring_size; tq->comp_ring.size = tx_ring_size; + tq->txdata_desc_size = txdata_desc_size; tq->shared = &adapter->tqd_start[i].ctrl; tq->stopped = true; tq->adapter = adapter; @@ -2754,9 +2758,34 @@ vmxnet3_open(struct net_device *netdev) for (i = 0; i < adapter->num_tx_queues; i++) spin_lock_init(&adapter->tx_queue[i].tx_lock); - err = vmxnet3_create_queues(adapter, adapter->tx_ring_size, + if (VMXNET3_VERSION_GE_3(adapter)) { + unsigned long flags; + u16 txdata_desc_size; + + spin_lock_irqsave(&adapter->cmd_lock, flags); + VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, + VMXNET3_CMD_GET_TXDATA_DESC_SIZE); + txdata_desc_size = VMXNET3_READ_BAR1_REG(adapter, + VMXNET3_REG_CMD); + spin_unlock_irqrestore(&adapter->cmd_lock, flags); + + if ((txdata_desc_size < VMXNET3_TXDATA_DESC_MIN_SIZE) || + (txdata_desc_size > VMXNET3_TXDATA_DESC_MAX_SIZE) || + (txdata_desc_size & VMXNET3_TXDATA_DESC_SIZE_MASK)) { + adapter->txdata_desc_size = + sizeof(struct Vmxnet3_TxDataDesc); + } else { + adapter->txdata_desc_size = txdata_desc_size; + } + } else { + adapter->txdata_desc_size = sizeof(struct Vmxnet3_TxDataDesc); + } + + err = vmxnet3_create_queues(adapter, + adapter->tx_ring_size, adapter->rx_ring_size, - adapter->rx_ring2_size); + adapter->rx_ring2_size, + adapter->txdata_desc_size); if (err) goto queue_err; diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c index 163e99c910237..3b70cfef97489 100644 --- a/drivers/net/vmxnet3/vmxnet3_ethtool.c +++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c @@ -396,8 +396,7 @@ vmxnet3_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p) buf[j++] = VMXNET3_GET_ADDR_LO(tq->data_ring.basePA); buf[j++] = VMXNET3_GET_ADDR_HI(tq->data_ring.basePA); buf[j++] = tq->data_ring.size; - /* transmit data ring buffer size */ - buf[j++] = VMXNET3_HDR_COPY_SIZE; + buf[j++] = tq->txdata_desc_size; buf[j++] = VMXNET3_GET_ADDR_LO(tq->comp_ring.basePA); buf[j++] = VMXNET3_GET_ADDR_HI(tq->comp_ring.basePA); @@ -591,7 +590,8 @@ vmxnet3_set_ringparam(struct net_device *netdev, vmxnet3_rq_destroy_all(adapter); err = vmxnet3_create_queues(adapter, new_tx_ring_size, - new_rx_ring_size, new_rx_ring2_size); + new_rx_ring_size, new_rx_ring2_size, + adapter->txdata_desc_size); if (err) { /* failed, most likely because of OOM, try default @@ -604,7 +604,8 @@ vmxnet3_set_ringparam(struct net_device *netdev, err = vmxnet3_create_queues(adapter, new_tx_ring_size, new_rx_ring_size, - new_rx_ring2_size); + new_rx_ring2_size, + adapter->txdata_desc_size); if (err) { netdev_err(netdev, "failed to create queues " "with default sizes. Closing it\n"); diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h index de068e92cedb6..94010de67e3de 100644 --- a/drivers/net/vmxnet3/vmxnet3_int.h +++ b/drivers/net/vmxnet3/vmxnet3_int.h @@ -241,6 +241,7 @@ struct vmxnet3_tx_queue { int num_stop; /* # of times the queue is * stopped */ int qid; + u16 txdata_desc_size; } __attribute__((__aligned__(SMP_CACHE_BYTES))); enum vmxnet3_rx_buf_type { @@ -363,6 +364,9 @@ struct vmxnet3_adapter { u32 rx_ring_size; u32 rx_ring2_size; + /* Size of buffer in the data ring */ + u16 txdata_desc_size; + struct work_struct work; unsigned long state; /* VMXNET3_STATE_BIT_xxx */ @@ -427,7 +431,8 @@ vmxnet3_set_features(struct net_device *netdev, netdev_features_t features); int vmxnet3_create_queues(struct vmxnet3_adapter *adapter, - u32 tx_ring_size, u32 rx_ring_size, u32 rx_ring2_size); + u32 tx_ring_size, u32 rx_ring_size, u32 rx_ring2_size, + u16 txdata_desc_size); void vmxnet3_set_ethtool_ops(struct net_device *netdev); From 50a5ce3e7116a70edb7a1d1d209e3bc537752427 Mon Sep 17 00:00:00 2001 From: Shrikrishna Khare Date: Thu, 16 Jun 2016 10:51:56 -0700 Subject: [PATCH 4/7] vmxnet3: add receive data ring support vmxnet3 driver preallocates buffers for receiving packets and posts the buffers to the emulation. In order to deliver a received packet to the guest, the emulation must map buffer(s) and copy the packet into it. To avoid this memory mapping overhead, this patch introduces the receive data ring - a set of small sized buffers that are always mapped by the emulation. If a packet fits into the receive data ring buffer, the emulation delivers the packet via the receive data ring (which must be copied by the guest driver), or else the usual receive path is used. Receive Data Ring buffer length is configurable via ethtool -G ethX rx-mini Signed-off-by: Shrikrishna Khare Signed-off-by: David S. Miller --- drivers/net/vmxnet3/vmxnet3_defs.h | 14 ++- drivers/net/vmxnet3/vmxnet3_drv.c | 153 ++++++++++++++++++++------ drivers/net/vmxnet3/vmxnet3_ethtool.c | 48 ++++++-- drivers/net/vmxnet3/vmxnet3_int.h | 23 +++- 4 files changed, 193 insertions(+), 45 deletions(-) diff --git a/drivers/net/vmxnet3/vmxnet3_defs.h b/drivers/net/vmxnet3/vmxnet3_defs.h index 701d98944c58e..f3b31c2d8abc7 100644 --- a/drivers/net/vmxnet3/vmxnet3_defs.h +++ b/drivers/net/vmxnet3/vmxnet3_defs.h @@ -174,6 +174,8 @@ struct Vmxnet3_TxDataDesc { u8 data[VMXNET3_HDR_COPY_SIZE]; }; +typedef u8 Vmxnet3_RxDataDesc; + #define VMXNET3_TCD_GEN_SHIFT 31 #define VMXNET3_TCD_GEN_SIZE 1 #define VMXNET3_TCD_TXIDX_SHIFT 0 @@ -382,6 +384,10 @@ union Vmxnet3_GenericDesc { #define VMXNET3_TXDATA_DESC_SIZE_ALIGN 64 #define VMXNET3_TXDATA_DESC_SIZE_MASK (VMXNET3_TXDATA_DESC_SIZE_ALIGN - 1) +/* Rx Data Ring buffer size must be a multiple of 64 */ +#define VMXNET3_RXDATA_DESC_SIZE_ALIGN 64 +#define VMXNET3_RXDATA_DESC_SIZE_MASK (VMXNET3_RXDATA_DESC_SIZE_ALIGN - 1) + /* Max ring size */ #define VMXNET3_TX_RING_MAX_SIZE 4096 #define VMXNET3_TC_RING_MAX_SIZE 4096 @@ -392,6 +398,8 @@ union Vmxnet3_GenericDesc { #define VMXNET3_TXDATA_DESC_MIN_SIZE 128 #define VMXNET3_TXDATA_DESC_MAX_SIZE 2048 +#define VMXNET3_RXDATA_DESC_MAX_SIZE 2048 + /* a list of reasons for queue stop */ enum { @@ -488,12 +496,14 @@ struct Vmxnet3_RxQueueConf { __le64 rxRingBasePA[2]; __le64 compRingBasePA; __le64 ddPA; /* driver data */ - __le64 reserved; + __le64 rxDataRingBasePA; __le32 rxRingSize[2]; /* # of rx desc */ __le32 compRingSize; /* # of rx comp desc */ __le32 ddLen; /* size of driver data */ u8 intrIdx; - u8 _pad[7]; + u8 _pad1[1]; + __le16 rxDataRingDescSize; /* size of rx data ring buffer */ + u8 _pad2[4]; }; diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index 4e42eb04a1981..6449d2e6d94f2 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -1284,9 +1284,10 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, */ break; } - BUG_ON(rcd->rqID != rq->qid && rcd->rqID != rq->qid2); + BUG_ON(rcd->rqID != rq->qid && rcd->rqID != rq->qid2 && + rcd->rqID != rq->dataRingQid); idx = rcd->rxdIdx; - ring_idx = rcd->rqID < adapter->num_rx_queues ? 0 : 1; + ring_idx = VMXNET3_GET_RING_IDX(adapter, rcd->rqID); ring = rq->rx_ring + ring_idx; vmxnet3_getRxDesc(rxd, &rq->rx_ring[ring_idx].base[idx].rxd, &rxCmdDesc); @@ -1301,8 +1302,12 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, } if (rcd->sop) { /* first buf of the pkt */ + bool rxDataRingUsed; + u16 len; + BUG_ON(rxd->btype != VMXNET3_RXD_BTYPE_HEAD || - rcd->rqID != rq->qid); + (rcd->rqID != rq->qid && + rcd->rqID != rq->dataRingQid)); BUG_ON(rbi->buf_type != VMXNET3_RX_BUF_SKB); BUG_ON(ctx->skb != NULL || rbi->skb == NULL); @@ -1318,8 +1323,12 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, skip_page_frags = false; ctx->skb = rbi->skb; + + rxDataRingUsed = + VMXNET3_RX_DATA_RING(adapter, rcd->rqID); + len = rxDataRingUsed ? rcd->len : rbi->len; new_skb = netdev_alloc_skb_ip_align(adapter->netdev, - rbi->len); + len); if (new_skb == NULL) { /* Skb allocation failed, do not handover this * skb to stack. Reuse it. Drop the existing pkt @@ -1330,25 +1339,48 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, skip_page_frags = true; goto rcd_done; } - new_dma_addr = dma_map_single(&adapter->pdev->dev, - new_skb->data, rbi->len, - PCI_DMA_FROMDEVICE); - if (dma_mapping_error(&adapter->pdev->dev, - new_dma_addr)) { - dev_kfree_skb(new_skb); - /* Skb allocation failed, do not handover this - * skb to stack. Reuse it. Drop the existing pkt - */ - rq->stats.rx_buf_alloc_failure++; - ctx->skb = NULL; - rq->stats.drop_total++; - skip_page_frags = true; - goto rcd_done; - } - dma_unmap_single(&adapter->pdev->dev, rbi->dma_addr, - rbi->len, - PCI_DMA_FROMDEVICE); + if (rxDataRingUsed) { + size_t sz; + + BUG_ON(rcd->len > rq->data_ring.desc_size); + + ctx->skb = new_skb; + sz = rcd->rxdIdx * rq->data_ring.desc_size; + memcpy(new_skb->data, + &rq->data_ring.base[sz], rcd->len); + } else { + ctx->skb = rbi->skb; + + new_dma_addr = + dma_map_single(&adapter->pdev->dev, + new_skb->data, rbi->len, + PCI_DMA_FROMDEVICE); + if (dma_mapping_error(&adapter->pdev->dev, + new_dma_addr)) { + dev_kfree_skb(new_skb); + /* Skb allocation failed, do not + * handover this skb to stack. Reuse + * it. Drop the existing pkt. + */ + rq->stats.rx_buf_alloc_failure++; + ctx->skb = NULL; + rq->stats.drop_total++; + skip_page_frags = true; + goto rcd_done; + } + + dma_unmap_single(&adapter->pdev->dev, + rbi->dma_addr, + rbi->len, + PCI_DMA_FROMDEVICE); + + /* Immediate refill */ + rbi->skb = new_skb; + rbi->dma_addr = new_dma_addr; + rxd->addr = cpu_to_le64(rbi->dma_addr); + rxd->len = rbi->len; + } #ifdef VMXNET3_RSS if (rcd->rssType != VMXNET3_RCD_RSS_TYPE_NONE && @@ -1359,11 +1391,6 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, #endif skb_put(ctx->skb, rcd->len); - /* Immediate refill */ - rbi->skb = new_skb; - rbi->dma_addr = new_dma_addr; - rxd->addr = cpu_to_le64(rbi->dma_addr); - rxd->len = rbi->len; if (VMXNET3_VERSION_GE_2(adapter) && rcd->type == VMXNET3_CDTYPE_RXCOMP_LRO) { struct Vmxnet3_RxCompDescExt *rcdlro; @@ -1590,6 +1617,13 @@ static void vmxnet3_rq_destroy(struct vmxnet3_rx_queue *rq, rq->buf_info[i] = NULL; } + if (rq->data_ring.base) { + dma_free_coherent(&adapter->pdev->dev, + rq->rx_ring[0].size * rq->data_ring.desc_size, + rq->data_ring.base, rq->data_ring.basePA); + rq->data_ring.base = NULL; + } + if (rq->comp_ring.base) { dma_free_coherent(&adapter->pdev->dev, rq->comp_ring.size * sizeof(struct Vmxnet3_RxCompDesc), @@ -1605,6 +1639,25 @@ static void vmxnet3_rq_destroy(struct vmxnet3_rx_queue *rq, } } +void +vmxnet3_rq_destroy_all_rxdataring(struct vmxnet3_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_rx_queues; i++) { + struct vmxnet3_rx_queue *rq = &adapter->rx_queue[i]; + + if (rq->data_ring.base) { + dma_free_coherent(&adapter->pdev->dev, + (rq->rx_ring[0].size * + rq->data_ring.desc_size), + rq->data_ring.base, + rq->data_ring.basePA); + rq->data_ring.base = NULL; + rq->data_ring.desc_size = 0; + } + } +} static int vmxnet3_rq_init(struct vmxnet3_rx_queue *rq, @@ -1698,6 +1751,22 @@ vmxnet3_rq_create(struct vmxnet3_rx_queue *rq, struct vmxnet3_adapter *adapter) } } + if ((adapter->rxdataring_enabled) && (rq->data_ring.desc_size != 0)) { + sz = rq->rx_ring[0].size * rq->data_ring.desc_size; + rq->data_ring.base = + dma_alloc_coherent(&adapter->pdev->dev, sz, + &rq->data_ring.basePA, + GFP_KERNEL); + if (!rq->data_ring.base) { + netdev_err(adapter->netdev, + "rx data ring will be disabled\n"); + adapter->rxdataring_enabled = false; + } + } else { + rq->data_ring.base = NULL; + rq->data_ring.desc_size = 0; + } + sz = rq->comp_ring.size * sizeof(struct Vmxnet3_RxCompDesc); rq->comp_ring.base = dma_alloc_coherent(&adapter->pdev->dev, sz, &rq->comp_ring.basePA, @@ -1730,6 +1799,8 @@ vmxnet3_rq_create_all(struct vmxnet3_adapter *adapter) { int i, err = 0; + adapter->rxdataring_enabled = VMXNET3_VERSION_GE_3(adapter); + for (i = 0; i < adapter->num_rx_queues; i++) { err = vmxnet3_rq_create(&adapter->rx_queue[i], adapter); if (unlikely(err)) { @@ -1739,6 +1810,10 @@ vmxnet3_rq_create_all(struct vmxnet3_adapter *adapter) goto err_out; } } + + if (!adapter->rxdataring_enabled) + vmxnet3_rq_destroy_all_rxdataring(adapter); + return err; err_out: vmxnet3_rq_destroy_all(adapter); @@ -2046,10 +2121,9 @@ vmxnet3_request_irqs(struct vmxnet3_adapter *adapter) struct vmxnet3_rx_queue *rq = &adapter->rx_queue[i]; rq->qid = i; rq->qid2 = i + adapter->num_rx_queues; + rq->dataRingQid = i + 2 * adapter->num_rx_queues; } - - /* init our intr settings */ for (i = 0; i < intr->num_intrs; i++) intr->mod_levels[i] = UPT1_IML_ADAPTIVE; @@ -2362,6 +2436,12 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter) (rqc->rxRingSize[0] + rqc->rxRingSize[1])); rqc->intrIdx = rq->comp_ring.intr_idx; + if (VMXNET3_VERSION_GE_3(adapter)) { + rqc->rxDataRingBasePA = + cpu_to_le64(rq->data_ring.basePA); + rqc->rxDataRingDescSize = + cpu_to_le16(rq->data_ring.desc_size); + } } #ifdef VMXNET3_RSS @@ -2692,7 +2772,7 @@ vmxnet3_adjust_rx_ring_size(struct vmxnet3_adapter *adapter) int vmxnet3_create_queues(struct vmxnet3_adapter *adapter, u32 tx_ring_size, u32 rx_ring_size, u32 rx_ring2_size, - u16 txdata_desc_size) + u16 txdata_desc_size, u16 rxdata_desc_size) { int err = 0, i; @@ -2718,12 +2798,15 @@ vmxnet3_create_queues(struct vmxnet3_adapter *adapter, u32 tx_ring_size, adapter->rx_queue[0].rx_ring[0].size = rx_ring_size; adapter->rx_queue[0].rx_ring[1].size = rx_ring2_size; vmxnet3_adjust_rx_ring_size(adapter); + + adapter->rxdataring_enabled = VMXNET3_VERSION_GE_3(adapter); for (i = 0; i < adapter->num_rx_queues; i++) { struct vmxnet3_rx_queue *rq = &adapter->rx_queue[i]; /* qid and qid2 for rx queues will be assigned later when num * of rx queues is finalized after allocating intrs */ rq->shared = &adapter->rqd_start[i].ctrl; rq->adapter = adapter; + rq->data_ring.desc_size = rxdata_desc_size; err = vmxnet3_rq_create(rq, adapter); if (err) { if (i == 0) { @@ -2741,6 +2824,10 @@ vmxnet3_create_queues(struct vmxnet3_adapter *adapter, u32 tx_ring_size, } } } + + if (!adapter->rxdataring_enabled) + vmxnet3_rq_destroy_all_rxdataring(adapter); + return err; queue_err: vmxnet3_tq_destroy_all(adapter); @@ -2785,7 +2872,8 @@ vmxnet3_open(struct net_device *netdev) adapter->tx_ring_size, adapter->rx_ring_size, adapter->rx_ring2_size, - adapter->txdata_desc_size); + adapter->txdata_desc_size, + adapter->rxdata_desc_size); if (err) goto queue_err; @@ -3260,6 +3348,9 @@ vmxnet3_probe_device(struct pci_dev *pdev, SET_NETDEV_DEV(netdev, &pdev->dev); vmxnet3_declare_features(adapter, dma64); + adapter->rxdata_desc_size = VMXNET3_VERSION_GE_3(adapter) ? + VMXNET3_DEF_RXDATA_DESC_SIZE : 0; + if (adapter->num_tx_queues == adapter->num_rx_queues) adapter->share_intr = VMXNET3_INTR_BUDDYSHARE; else diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c index 3b70cfef97489..38f7c7975e1f1 100644 --- a/drivers/net/vmxnet3/vmxnet3_ethtool.c +++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c @@ -430,11 +430,10 @@ vmxnet3_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p) buf[j++] = rq->rx_ring[1].next2comp; buf[j++] = rq->rx_ring[1].gen; - /* receive data ring */ - buf[j++] = 0; - buf[j++] = 0; - buf[j++] = 0; - buf[j++] = 0; + buf[j++] = VMXNET3_GET_ADDR_LO(rq->data_ring.basePA); + buf[j++] = VMXNET3_GET_ADDR_HI(rq->data_ring.basePA); + buf[j++] = rq->rx_ring[0].size; + buf[j++] = rq->data_ring.desc_size; buf[j++] = VMXNET3_GET_ADDR_LO(rq->comp_ring.basePA); buf[j++] = VMXNET3_GET_ADDR_HI(rq->comp_ring.basePA); @@ -503,12 +502,14 @@ vmxnet3_get_ringparam(struct net_device *netdev, param->rx_max_pending = VMXNET3_RX_RING_MAX_SIZE; param->tx_max_pending = VMXNET3_TX_RING_MAX_SIZE; - param->rx_mini_max_pending = 0; + param->rx_mini_max_pending = VMXNET3_VERSION_GE_3(adapter) ? + VMXNET3_RXDATA_DESC_MAX_SIZE : 0; param->rx_jumbo_max_pending = VMXNET3_RX_RING2_MAX_SIZE; param->rx_pending = adapter->rx_ring_size; param->tx_pending = adapter->tx_ring_size; - param->rx_mini_pending = 0; + param->rx_mini_pending = VMXNET3_VERSION_GE_3(adapter) ? + adapter->rxdata_desc_size : 0; param->rx_jumbo_pending = adapter->rx_ring2_size; } @@ -519,6 +520,7 @@ vmxnet3_set_ringparam(struct net_device *netdev, { struct vmxnet3_adapter *adapter = netdev_priv(netdev); u32 new_tx_ring_size, new_rx_ring_size, new_rx_ring2_size; + u16 new_rxdata_desc_size; u32 sz; int err = 0; @@ -541,6 +543,15 @@ vmxnet3_set_ringparam(struct net_device *netdev, return -EOPNOTSUPP; } + if (VMXNET3_VERSION_GE_3(adapter)) { + if (param->rx_mini_pending < 0 || + param->rx_mini_pending > VMXNET3_RXDATA_DESC_MAX_SIZE) { + return -EINVAL; + } + } else if (param->rx_mini_pending != 0) { + return -EINVAL; + } + /* round it up to a multiple of VMXNET3_RING_SIZE_ALIGN */ new_tx_ring_size = (param->tx_pending + VMXNET3_RING_SIZE_MASK) & ~VMXNET3_RING_SIZE_MASK; @@ -567,9 +578,19 @@ vmxnet3_set_ringparam(struct net_device *netdev, new_rx_ring2_size = min_t(u32, new_rx_ring2_size, VMXNET3_RX_RING2_MAX_SIZE); + /* rx data ring buffer size has to be a multiple of + * VMXNET3_RXDATA_DESC_SIZE_ALIGN + */ + new_rxdata_desc_size = + (param->rx_mini_pending + VMXNET3_RXDATA_DESC_SIZE_MASK) & + ~VMXNET3_RXDATA_DESC_SIZE_MASK; + new_rxdata_desc_size = min_t(u16, new_rxdata_desc_size, + VMXNET3_RXDATA_DESC_MAX_SIZE); + if (new_tx_ring_size == adapter->tx_ring_size && new_rx_ring_size == adapter->rx_ring_size && - new_rx_ring2_size == adapter->rx_ring2_size) { + new_rx_ring2_size == adapter->rx_ring2_size && + new_rxdata_desc_size == adapter->rxdata_desc_size) { return 0; } @@ -591,8 +612,8 @@ vmxnet3_set_ringparam(struct net_device *netdev, err = vmxnet3_create_queues(adapter, new_tx_ring_size, new_rx_ring_size, new_rx_ring2_size, - adapter->txdata_desc_size); - + adapter->txdata_desc_size, + new_rxdata_desc_size); if (err) { /* failed, most likely because of OOM, try default * size */ @@ -601,11 +622,15 @@ vmxnet3_set_ringparam(struct net_device *netdev, new_rx_ring_size = VMXNET3_DEF_RX_RING_SIZE; new_rx_ring2_size = VMXNET3_DEF_RX_RING2_SIZE; new_tx_ring_size = VMXNET3_DEF_TX_RING_SIZE; + new_rxdata_desc_size = VMXNET3_VERSION_GE_3(adapter) ? + VMXNET3_DEF_RXDATA_DESC_SIZE : 0; + err = vmxnet3_create_queues(adapter, new_tx_ring_size, new_rx_ring_size, new_rx_ring2_size, - adapter->txdata_desc_size); + adapter->txdata_desc_size, + new_rxdata_desc_size); if (err) { netdev_err(netdev, "failed to create queues " "with default sizes. Closing it\n"); @@ -621,6 +646,7 @@ vmxnet3_set_ringparam(struct net_device *netdev, adapter->tx_ring_size = new_tx_ring_size; adapter->rx_ring_size = new_rx_ring_size; adapter->rx_ring2_size = new_rx_ring2_size; + adapter->rxdata_desc_size = new_rxdata_desc_size; out: clear_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state); diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h index 94010de67e3de..c46bf09ade5a5 100644 --- a/drivers/net/vmxnet3/vmxnet3_int.h +++ b/drivers/net/vmxnet3/vmxnet3_int.h @@ -272,15 +272,23 @@ struct vmxnet3_rq_driver_stats { u64 rx_buf_alloc_failure; }; +struct vmxnet3_rx_data_ring { + Vmxnet3_RxDataDesc *base; + dma_addr_t basePA; + u16 desc_size; +}; + struct vmxnet3_rx_queue { char name[IFNAMSIZ + 8]; /* To identify interrupt */ struct vmxnet3_adapter *adapter; struct napi_struct napi; struct vmxnet3_cmd_ring rx_ring[2]; + struct vmxnet3_rx_data_ring data_ring; struct vmxnet3_comp_ring comp_ring; struct vmxnet3_rx_ctx rx_ctx; u32 qid; /* rqID in RCD for buffer from 1st ring */ u32 qid2; /* rqID in RCD for buffer from 2nd ring */ + u32 dataRingQid; /* rqID in RCD for buffer from data ring */ struct vmxnet3_rx_buf_info *buf_info[2]; dma_addr_t buf_info_pa; struct Vmxnet3_RxQueueCtrl *shared; @@ -366,6 +374,9 @@ struct vmxnet3_adapter { /* Size of buffer in the data ring */ u16 txdata_desc_size; + u16 rxdata_desc_size; + + bool rxdataring_enabled; struct work_struct work; @@ -405,9 +416,19 @@ struct vmxnet3_adapter { #define VMXNET3_DEF_RX_RING_SIZE 256 #define VMXNET3_DEF_RX_RING2_SIZE 128 +#define VMXNET3_DEF_RXDATA_DESC_SIZE 128 + #define VMXNET3_MAX_ETH_HDR_SIZE 22 #define VMXNET3_MAX_SKB_BUF_SIZE (3*1024) +#define VMXNET3_GET_RING_IDX(adapter, rqID) \ + ((rqID >= adapter->num_rx_queues && \ + rqID < 2 * adapter->num_rx_queues) ? 1 : 0) \ + +#define VMXNET3_RX_DATA_RING(adapter, rqID) \ + (rqID >= 2 * adapter->num_rx_queues && \ + rqID < 3 * adapter->num_rx_queues) \ + int vmxnet3_quiesce_dev(struct vmxnet3_adapter *adapter); @@ -432,7 +453,7 @@ vmxnet3_set_features(struct net_device *netdev, netdev_features_t features); int vmxnet3_create_queues(struct vmxnet3_adapter *adapter, u32 tx_ring_size, u32 rx_ring_size, u32 rx_ring2_size, - u16 txdata_desc_size); + u16 txdata_desc_size, u16 rxdata_desc_size); void vmxnet3_set_ethtool_ops(struct net_device *netdev); From 4edef40ef5f8d09a0b1ded4d1d9b0e988cd98e97 Mon Sep 17 00:00:00 2001 From: Shrikrishna Khare Date: Thu, 16 Jun 2016 10:51:57 -0700 Subject: [PATCH 5/7] vmxnet3: add support for get_coalesce, set_coalesce ethtool operations The emulation supports a variety of coalescing modes viz. disabled (no coalescing), adaptive, static (number of packets to batch before raising an interrupt), rate based (number of interrupts per second). This patch implements get_coalesce and set_coalesce methods to allow querying and configuring different coalescing modes. Signed-off-by: Keyong Sun Signed-off-by: Manoj Tammali Signed-off-by: Shrikrishna Khare Signed-off-by: David S. Miller --- drivers/net/vmxnet3/vmxnet3_defs.h | 33 +++++- drivers/net/vmxnet3/vmxnet3_drv.c | 54 +++++++++ drivers/net/vmxnet3/vmxnet3_ethtool.c | 158 ++++++++++++++++++++++++++ drivers/net/vmxnet3/vmxnet3_int.h | 9 ++ 4 files changed, 253 insertions(+), 1 deletion(-) diff --git a/drivers/net/vmxnet3/vmxnet3_defs.h b/drivers/net/vmxnet3/vmxnet3_defs.h index f3b31c2d8abc7..274e145ab72af 100644 --- a/drivers/net/vmxnet3/vmxnet3_defs.h +++ b/drivers/net/vmxnet3/vmxnet3_defs.h @@ -80,6 +80,7 @@ enum { VMXNET3_CMD_LOAD_PLUGIN, VMXNET3_CMD_RESERVED2, VMXNET3_CMD_RESERVED3, + VMXNET3_CMD_SET_COALESCE, VMXNET3_CMD_FIRST_GET = 0xF00D0000, VMXNET3_CMD_GET_QUEUE_STATUS = VMXNET3_CMD_FIRST_GET, @@ -92,7 +93,8 @@ enum { VMXNET3_CMD_GET_DEV_EXTRA_INFO, VMXNET3_CMD_GET_CONF_INTR, VMXNET3_CMD_GET_RESERVED1, - VMXNET3_CMD_GET_TXDATA_DESC_SIZE + VMXNET3_CMD_GET_TXDATA_DESC_SIZE, + VMXNET3_CMD_GET_COALESCE, }; /* @@ -637,6 +639,35 @@ struct Vmxnet3_SetPolling { u8 enablePolling; }; +#define VMXNET3_COAL_STATIC_MAX_DEPTH 128 +#define VMXNET3_COAL_RBC_MIN_RATE 100 +#define VMXNET3_COAL_RBC_MAX_RATE 100000 + +enum Vmxnet3_CoalesceMode { + VMXNET3_COALESCE_DISABLED = 0, + VMXNET3_COALESCE_ADAPT = 1, + VMXNET3_COALESCE_STATIC = 2, + VMXNET3_COALESCE_RBC = 3 +}; + +struct Vmxnet3_CoalesceRbc { + u32 rbc_rate; +}; + +struct Vmxnet3_CoalesceStatic { + u32 tx_depth; + u32 tx_comp_depth; + u32 rx_depth; +}; + +struct Vmxnet3_CoalesceScheme { + enum Vmxnet3_CoalesceMode coalMode; + union { + struct Vmxnet3_CoalesceRbc coalRbc; + struct Vmxnet3_CoalesceStatic coalStatic; + } coalPara; +}; + /* If the command data <= 16 bytes, use the shared memory directly. * otherwise, use variable length configuration descriptor. */ diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index 6449d2e6d94f2..d0bcc1d97e80e 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -2491,6 +2491,32 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter) /* the rest are already zeroed */ } +static void +vmxnet3_init_coalesce(struct vmxnet3_adapter *adapter) +{ + struct Vmxnet3_DriverShared *shared = adapter->shared; + union Vmxnet3_CmdInfo *cmdInfo = &shared->cu.cmdInfo; + unsigned long flags; + + if (!VMXNET3_VERSION_GE_3(adapter)) + return; + + spin_lock_irqsave(&adapter->cmd_lock, flags); + cmdInfo->varConf.confVer = 1; + cmdInfo->varConf.confLen = + cpu_to_le32(sizeof(*adapter->coal_conf)); + cmdInfo->varConf.confPA = cpu_to_le64(adapter->coal_conf_pa); + + if (adapter->default_coal_mode) { + VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, + VMXNET3_CMD_GET_COALESCE); + } else { + VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, + VMXNET3_CMD_SET_COALESCE); + } + + spin_unlock_irqrestore(&adapter->cmd_lock, flags); +} int vmxnet3_activate_dev(struct vmxnet3_adapter *adapter) @@ -2540,6 +2566,8 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter) goto activate_err; } + vmxnet3_init_coalesce(adapter); + for (i = 0; i < adapter->num_rx_queues; i++) { VMXNET3_WRITE_BAR0_REG(adapter, VMXNET3_REG_RXPROD + i * VMXNET3_REG_ALIGN, @@ -3345,6 +3373,22 @@ vmxnet3_probe_device(struct pci_dev *pdev, goto err_ver; } + if (VMXNET3_VERSION_GE_3(adapter)) { + adapter->coal_conf = + dma_alloc_coherent(&adapter->pdev->dev, + sizeof(struct Vmxnet3_CoalesceScheme) + , + &adapter->coal_conf_pa, + GFP_KERNEL); + if (!adapter->coal_conf) { + err = -ENOMEM; + goto err_ver; + } + memset(adapter->coal_conf, 0, sizeof(*adapter->coal_conf)); + adapter->coal_conf->coalMode = VMXNET3_COALESCE_DISABLED; + adapter->default_coal_mode = true; + } + SET_NETDEV_DEV(netdev, &pdev->dev); vmxnet3_declare_features(adapter, dma64); @@ -3407,6 +3451,11 @@ vmxnet3_probe_device(struct pci_dev *pdev, return 0; err_register: + if (VMXNET3_VERSION_GE_3(adapter)) { + dma_free_coherent(&adapter->pdev->dev, + sizeof(struct Vmxnet3_CoalesceScheme), + adapter->coal_conf, adapter->coal_conf_pa); + } vmxnet3_free_intr_resources(adapter); err_ver: vmxnet3_free_pci_resources(adapter); @@ -3457,6 +3506,11 @@ vmxnet3_remove_device(struct pci_dev *pdev) vmxnet3_free_intr_resources(adapter); vmxnet3_free_pci_resources(adapter); + if (VMXNET3_VERSION_GE_3(adapter)) { + dma_free_coherent(&adapter->pdev->dev, + sizeof(struct Vmxnet3_CoalesceScheme), + adapter->coal_conf, adapter->coal_conf_pa); + } #ifdef VMXNET3_RSS dma_free_coherent(&adapter->pdev->dev, sizeof(struct UPT1_RSSConf), adapter->rss_conf, adapter->rss_conf_pa); diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c index 38f7c7975e1f1..aabc6ef366b46 100644 --- a/drivers/net/vmxnet3/vmxnet3_ethtool.c +++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c @@ -725,6 +725,162 @@ vmxnet3_set_rss(struct net_device *netdev, const u32 *p, const u8 *key, } #endif +static int +vmxnet3_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec) +{ + struct vmxnet3_adapter *adapter = netdev_priv(netdev); + + if (!VMXNET3_VERSION_GE_3(adapter)) + return -EOPNOTSUPP; + + switch (adapter->coal_conf->coalMode) { + case VMXNET3_COALESCE_DISABLED: + /* struct ethtool_coalesce is already initialized to 0 */ + break; + case VMXNET3_COALESCE_ADAPT: + ec->use_adaptive_rx_coalesce = true; + break; + case VMXNET3_COALESCE_STATIC: + ec->tx_max_coalesced_frames = + adapter->coal_conf->coalPara.coalStatic.tx_comp_depth; + ec->rx_max_coalesced_frames = + adapter->coal_conf->coalPara.coalStatic.rx_depth; + break; + case VMXNET3_COALESCE_RBC: { + u32 rbc_rate; + + rbc_rate = adapter->coal_conf->coalPara.coalRbc.rbc_rate; + ec->rx_coalesce_usecs = VMXNET3_COAL_RBC_USECS(rbc_rate); + } + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int +vmxnet3_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec) +{ + struct vmxnet3_adapter *adapter = netdev_priv(netdev); + struct Vmxnet3_DriverShared *shared = adapter->shared; + union Vmxnet3_CmdInfo *cmdInfo = &shared->cu.cmdInfo; + unsigned long flags; + + if (!VMXNET3_VERSION_GE_3(adapter)) + return -EOPNOTSUPP; + + if (ec->rx_coalesce_usecs_irq || + ec->rx_max_coalesced_frames_irq || + ec->tx_coalesce_usecs || + ec->tx_coalesce_usecs_irq || + ec->tx_max_coalesced_frames_irq || + ec->stats_block_coalesce_usecs || + ec->use_adaptive_tx_coalesce || + ec->pkt_rate_low || + ec->rx_coalesce_usecs_low || + ec->rx_max_coalesced_frames_low || + ec->tx_coalesce_usecs_low || + ec->tx_max_coalesced_frames_low || + ec->pkt_rate_high || + ec->rx_coalesce_usecs_high || + ec->rx_max_coalesced_frames_high || + ec->tx_coalesce_usecs_high || + ec->tx_max_coalesced_frames_high || + ec->rate_sample_interval) { + return -EINVAL; + } + + if ((ec->rx_coalesce_usecs == 0) && + (ec->use_adaptive_rx_coalesce == 0) && + (ec->tx_max_coalesced_frames == 0) && + (ec->rx_max_coalesced_frames == 0)) { + memset(adapter->coal_conf, 0, sizeof(*adapter->coal_conf)); + adapter->coal_conf->coalMode = VMXNET3_COALESCE_DISABLED; + goto done; + } + + if (ec->rx_coalesce_usecs != 0) { + u32 rbc_rate; + + if ((ec->use_adaptive_rx_coalesce != 0) || + (ec->tx_max_coalesced_frames != 0) || + (ec->rx_max_coalesced_frames != 0)) { + return -EINVAL; + } + + rbc_rate = VMXNET3_COAL_RBC_RATE(ec->rx_coalesce_usecs); + if (rbc_rate < VMXNET3_COAL_RBC_MIN_RATE || + rbc_rate > VMXNET3_COAL_RBC_MAX_RATE) { + return -EINVAL; + } + + memset(adapter->coal_conf, 0, sizeof(*adapter->coal_conf)); + adapter->coal_conf->coalMode = VMXNET3_COALESCE_RBC; + adapter->coal_conf->coalPara.coalRbc.rbc_rate = rbc_rate; + goto done; + } + + if (ec->use_adaptive_rx_coalesce != 0) { + if ((ec->rx_coalesce_usecs != 0) || + (ec->tx_max_coalesced_frames != 0) || + (ec->rx_max_coalesced_frames != 0)) { + return -EINVAL; + } + memset(adapter->coal_conf, 0, sizeof(*adapter->coal_conf)); + adapter->coal_conf->coalMode = VMXNET3_COALESCE_ADAPT; + goto done; + } + + if ((ec->tx_max_coalesced_frames != 0) || + (ec->rx_max_coalesced_frames != 0)) { + if ((ec->rx_coalesce_usecs != 0) || + (ec->use_adaptive_rx_coalesce != 0)) { + return -EINVAL; + } + + if ((ec->tx_max_coalesced_frames > + VMXNET3_COAL_STATIC_MAX_DEPTH) || + (ec->rx_max_coalesced_frames > + VMXNET3_COAL_STATIC_MAX_DEPTH)) { + return -EINVAL; + } + + memset(adapter->coal_conf, 0, sizeof(*adapter->coal_conf)); + adapter->coal_conf->coalMode = VMXNET3_COALESCE_STATIC; + + adapter->coal_conf->coalPara.coalStatic.tx_comp_depth = + (ec->tx_max_coalesced_frames ? + ec->tx_max_coalesced_frames : + VMXNET3_COAL_STATIC_DEFAULT_DEPTH); + + adapter->coal_conf->coalPara.coalStatic.rx_depth = + (ec->rx_max_coalesced_frames ? + ec->rx_max_coalesced_frames : + VMXNET3_COAL_STATIC_DEFAULT_DEPTH); + + adapter->coal_conf->coalPara.coalStatic.tx_depth = + VMXNET3_COAL_STATIC_DEFAULT_DEPTH; + goto done; + } + +done: + adapter->default_coal_mode = false; + if (netif_running(netdev)) { + spin_lock_irqsave(&adapter->cmd_lock, flags); + cmdInfo->varConf.confVer = 1; + cmdInfo->varConf.confLen = + cpu_to_le32(sizeof(*adapter->coal_conf)); + cmdInfo->varConf.confPA = cpu_to_le64(adapter->coal_conf_pa); + VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, + VMXNET3_CMD_SET_COALESCE); + spin_unlock_irqrestore(&adapter->cmd_lock, flags); + } + + return 0; +} + static const struct ethtool_ops vmxnet3_ethtool_ops = { .get_settings = vmxnet3_get_settings, .get_drvinfo = vmxnet3_get_drvinfo, @@ -733,6 +889,8 @@ static const struct ethtool_ops vmxnet3_ethtool_ops = { .get_wol = vmxnet3_get_wol, .set_wol = vmxnet3_set_wol, .get_link = ethtool_op_get_link, + .get_coalesce = vmxnet3_get_coalesce, + .set_coalesce = vmxnet3_set_coalesce, .get_strings = vmxnet3_get_strings, .get_sset_count = vmxnet3_get_sset_count, .get_ethtool_stats = vmxnet3_get_ethtool_stats, diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h index c46bf09ade5a5..63df4f2a743d9 100644 --- a/drivers/net/vmxnet3/vmxnet3_int.h +++ b/drivers/net/vmxnet3/vmxnet3_int.h @@ -358,6 +358,7 @@ struct vmxnet3_adapter { int rx_buf_per_pkt; /* only apply to the 1st ring */ dma_addr_t shared_pa; dma_addr_t queue_desc_pa; + dma_addr_t coal_conf_pa; /* Wake-on-LAN */ u32 wol; @@ -384,6 +385,9 @@ struct vmxnet3_adapter { int share_intr; + struct Vmxnet3_CoalesceScheme *coal_conf; + bool default_coal_mode; + dma_addr_t adapter_pa; dma_addr_t pm_conf_pa; dma_addr_t rss_conf_pa; @@ -429,6 +433,11 @@ struct vmxnet3_adapter { (rqID >= 2 * adapter->num_rx_queues && \ rqID < 3 * adapter->num_rx_queues) \ +#define VMXNET3_COAL_STATIC_DEFAULT_DEPTH 64 + +#define VMXNET3_COAL_RBC_RATE(usecs) (1000000 / usecs) +#define VMXNET3_COAL_RBC_USECS(rbc_rate) (1000000 / rbc_rate) + int vmxnet3_quiesce_dev(struct vmxnet3_adapter *adapter); From 474432229f9482f0f4a2732f2e130dc48247f1d7 Mon Sep 17 00:00:00 2001 From: Shrikrishna Khare Date: Thu, 16 Jun 2016 10:51:58 -0700 Subject: [PATCH 6/7] vmxnet3: introduce command to register memory region In vmxnet3 version 3, the emulation added support for the vmxnet3 driver to communicate information about the memory regions the driver will use for rx/tx buffers. The driver can also indicate which rx/tx queue the memory region is applicable for. If this information is communicated to the emulation, the emulation will always keep these memory regions mapped, thereby avoiding the mapping/unmapping overhead for every packet. Currently, Linux vmxnet3 driver does not leverage this capability. The feasibility of using this approach for the Linux vmxnet3 driver will be investigated independently and if possible, will be part of a different patch. This patch only exposes the emulation capability to the driver (vmxnet3_defs.h is identical between the driver and the emulation). Signed-off-by: Guolin Yang Signed-off-by: Shrikrishna Khare Signed-off-by: David S. Miller --- drivers/net/vmxnet3/vmxnet3_defs.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/net/vmxnet3/vmxnet3_defs.h b/drivers/net/vmxnet3/vmxnet3_defs.h index 274e145ab72af..c3a31646189f9 100644 --- a/drivers/net/vmxnet3/vmxnet3_defs.h +++ b/drivers/net/vmxnet3/vmxnet3_defs.h @@ -81,6 +81,7 @@ enum { VMXNET3_CMD_RESERVED2, VMXNET3_CMD_RESERVED3, VMXNET3_CMD_SET_COALESCE, + VMXNET3_CMD_REGISTER_MEMREGS, VMXNET3_CMD_FIRST_GET = 0xF00D0000, VMXNET3_CMD_GET_QUEUE_STATUS = VMXNET3_CMD_FIRST_GET, @@ -668,6 +669,22 @@ struct Vmxnet3_CoalesceScheme { } coalPara; }; +struct Vmxnet3_MemoryRegion { + __le64 startPA; + __le32 length; + __le16 txQueueBits; + __le16 rxQueueBits; +}; + +#define MAX_MEMORY_REGION_PER_QUEUE 16 +#define MAX_MEMORY_REGION_PER_DEVICE 256 + +struct Vmxnet3_MemRegs { + __le16 numRegs; + __le16 pad[3]; + struct Vmxnet3_MemoryRegion memRegs[1]; +}; + /* If the command data <= 16 bytes, use the shared memory directly. * otherwise, use variable length configuration descriptor. */ From 6af9d787459e3ea32da446fe0aa76cff65fd2f8c Mon Sep 17 00:00:00 2001 From: Shrikrishna Khare Date: Thu, 16 Jun 2016 10:51:59 -0700 Subject: [PATCH 7/7] vmxnet3: update to version 3 With all vmxnet3 version 3 changes incorporated in the vmxnet3 driver, the driver can configure emulation to run at vmxnet3 version 3, provided the emulation advertises support for version 3. Signed-off-by: Shrikrishna Khare Signed-off-by: David S. Miller --- drivers/net/vmxnet3/vmxnet3_drv.c | 7 ++++++- drivers/net/vmxnet3/vmxnet3_int.h | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index d0bcc1d97e80e..c68fe495d3f9b 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -3345,7 +3345,12 @@ vmxnet3_probe_device(struct pci_dev *pdev, goto err_alloc_pci; ver = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_VRRS); - if (ver & (1 << VMXNET3_REV_2)) { + if (ver & (1 << VMXNET3_REV_3)) { + VMXNET3_WRITE_BAR1_REG(adapter, + VMXNET3_REG_VRRS, + 1 << VMXNET3_REV_3); + adapter->version = VMXNET3_REV_3 + 1; + } else if (ver & (1 << VMXNET3_REV_2)) { VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_VRRS, 1 << VMXNET3_REV_2); diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h index 63df4f2a743d9..74fc03072b878 100644 --- a/drivers/net/vmxnet3/vmxnet3_int.h +++ b/drivers/net/vmxnet3/vmxnet3_int.h @@ -69,10 +69,10 @@ /* * Version numbers */ -#define VMXNET3_DRIVER_VERSION_STRING "1.4.8.0-k" +#define VMXNET3_DRIVER_VERSION_STRING "1.4.9.0-k" /* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */ -#define VMXNET3_DRIVER_VERSION_NUM 0x01040800 +#define VMXNET3_DRIVER_VERSION_NUM 0x01040900 #if defined(CONFIG_PCI_MSI) /* RSS only makes sense if MSI-X is supported. */