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 <rangarajans@vmware.com> Signed-off-by: Shrikrishna Khare <skhare@vmware.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
f35c7480f8
Коммит
3c8b3efc06
|
@ -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];
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче