summaryrefslogtreecommitdiff
path: root/drivers/net/vmxnet3
diff options
context:
space:
mode:
authorAndré Fabian Silva Delgado <emulatorman@parabola.nu>2016-01-20 14:01:31 -0300
committerAndré Fabian Silva Delgado <emulatorman@parabola.nu>2016-01-20 14:01:31 -0300
commitb4b7ff4b08e691656c9d77c758fc355833128ac0 (patch)
tree82fcb00e6b918026dc9f2d1f05ed8eee83874cc0 /drivers/net/vmxnet3
parent35acfa0fc609f2a2cd95cef4a6a9c3a5c38f1778 (diff)
Linux-libre 4.4-gnupck-4.4-gnu
Diffstat (limited to 'drivers/net/vmxnet3')
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c78
-rw-r--r--drivers/net/vmxnet3/vmxnet3_ethtool.c122
-rw-r--r--drivers/net/vmxnet3/vmxnet3_int.h4
3 files changed, 156 insertions, 48 deletions
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index 46f4caddc..0cbf520ce 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -587,6 +587,12 @@ vmxnet3_rq_alloc_rx_buf(struct vmxnet3_rx_queue *rq, u32 ring_idx,
&adapter->pdev->dev,
rbi->skb->data, rbi->len,
PCI_DMA_FROMDEVICE);
+ if (dma_mapping_error(&adapter->pdev->dev,
+ rbi->dma_addr)) {
+ dev_kfree_skb_any(rbi->skb);
+ rq->stats.rx_buf_alloc_failure++;
+ break;
+ }
} else {
/* rx buffer skipped by the device */
}
@@ -605,13 +611,18 @@ vmxnet3_rq_alloc_rx_buf(struct vmxnet3_rx_queue *rq, u32 ring_idx,
&adapter->pdev->dev,
rbi->page, 0, PAGE_SIZE,
PCI_DMA_FROMDEVICE);
+ if (dma_mapping_error(&adapter->pdev->dev,
+ rbi->dma_addr)) {
+ put_page(rbi->page);
+ rq->stats.rx_buf_alloc_failure++;
+ break;
+ }
} else {
/* rx buffers skipped by the device */
}
val = VMXNET3_RXD_BTYPE_BODY << VMXNET3_RXD_BTYPE_SHIFT;
}
- BUG_ON(rbi->dma_addr == 0);
gd->rxd.addr = cpu_to_le64(rbi->dma_addr);
gd->dword[2] = cpu_to_le32((!ring->gen << VMXNET3_RXD_GEN_SHIFT)
| val | rbi->len);
@@ -655,7 +666,7 @@ vmxnet3_append_frag(struct sk_buff *skb, struct Vmxnet3_RxCompDesc *rcd,
}
-static void
+static int
vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
struct vmxnet3_tx_queue *tq, struct pci_dev *pdev,
struct vmxnet3_adapter *adapter)
@@ -715,6 +726,8 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
tbi->dma_addr = dma_map_single(&adapter->pdev->dev,
skb->data + buf_offset, buf_size,
PCI_DMA_TODEVICE);
+ if (dma_mapping_error(&adapter->pdev->dev, tbi->dma_addr))
+ return -EFAULT;
tbi->len = buf_size;
@@ -755,6 +768,8 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
tbi->dma_addr = skb_frag_dma_map(&adapter->pdev->dev, frag,
buf_offset, buf_size,
DMA_TO_DEVICE);
+ if (dma_mapping_error(&adapter->pdev->dev, tbi->dma_addr))
+ return -EFAULT;
tbi->len = buf_size;
@@ -782,6 +797,8 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
/* set the last buf_info for the pkt */
tbi->skb = skb;
tbi->sop_idx = ctx->sop_txd - tq->tx_ring.base;
+
+ return 0;
}
@@ -1020,7 +1037,8 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
}
/* fill tx descs related to addr & len */
- vmxnet3_map_pkt(skb, &ctx, tq, adapter->pdev, adapter);
+ if (vmxnet3_map_pkt(skb, &ctx, tq, adapter->pdev, adapter))
+ goto unlock_drop_pkt;
/* setup the EOP desc */
ctx.eop_txd->dword[3] = cpu_to_le32(VMXNET3_TXD_CQ | VMXNET3_TXD_EOP);
@@ -1231,6 +1249,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
struct vmxnet3_rx_buf_info *rbi;
struct sk_buff *skb, *new_skb = NULL;
struct page *new_page = NULL;
+ dma_addr_t new_dma_addr;
int num_to_alloc;
struct Vmxnet3_RxDesc *rxd;
u32 idx, ring_idx;
@@ -1287,6 +1306,21 @@ 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,
@@ -1303,9 +1337,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
/* Immediate refill */
rbi->skb = new_skb;
- rbi->dma_addr = dma_map_single(&adapter->pdev->dev,
- rbi->skb->data, rbi->len,
- PCI_DMA_FROMDEVICE);
+ rbi->dma_addr = new_dma_addr;
rxd->addr = cpu_to_le64(rbi->dma_addr);
rxd->len = rbi->len;
if (adapter->version == 2 &&
@@ -1348,6 +1380,19 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
skip_page_frags = true;
goto rcd_done;
}
+ new_dma_addr = dma_map_page(&adapter->pdev->dev,
+ new_page,
+ 0, PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
+ if (dma_mapping_error(&adapter->pdev->dev,
+ new_dma_addr)) {
+ put_page(new_page);
+ rq->stats.rx_buf_alloc_failure++;
+ dev_kfree_skb(ctx->skb);
+ ctx->skb = NULL;
+ skip_page_frags = true;
+ goto rcd_done;
+ }
dma_unmap_page(&adapter->pdev->dev,
rbi->dma_addr, rbi->len,
@@ -1357,10 +1402,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
/* Immediate refill */
rbi->page = new_page;
- rbi->dma_addr = dma_map_page(&adapter->pdev->dev
- , rbi->page,
- 0, PAGE_SIZE,
- PCI_DMA_FROMDEVICE);
+ rbi->dma_addr = new_dma_addr;
rxd->addr = cpu_to_le64(rbi->dma_addr);
rxd->len = rbi->len;
}
@@ -2157,16 +2199,18 @@ vmxnet3_set_mc(struct net_device *netdev)
if (!netdev_mc_empty(netdev)) {
new_table = vmxnet3_copy_mc(netdev);
if (new_table) {
- rxConf->mfTableLen = cpu_to_le16(
- netdev_mc_count(netdev) * ETH_ALEN);
+ size_t sz = netdev_mc_count(netdev) * ETH_ALEN;
+
+ rxConf->mfTableLen = cpu_to_le16(sz);
new_table_pa = dma_map_single(
&adapter->pdev->dev,
new_table,
- rxConf->mfTableLen,
+ sz,
PCI_DMA_TODEVICE);
}
- if (new_table_pa) {
+ if (!dma_mapping_error(&adapter->pdev->dev,
+ new_table_pa)) {
new_mode |= VMXNET3_RXM_MCAST;
rxConf->mfTablePA = cpu_to_le64(new_table_pa);
} else {
@@ -3074,6 +3118,11 @@ vmxnet3_probe_device(struct pci_dev *pdev,
adapter->adapter_pa = dma_map_single(&adapter->pdev->dev, adapter,
sizeof(struct vmxnet3_adapter),
PCI_DMA_TODEVICE);
+ if (dma_mapping_error(&adapter->pdev->dev, adapter->adapter_pa)) {
+ dev_err(&pdev->dev, "Failed to map dma\n");
+ err = -EFAULT;
+ goto err_dma_map;
+ }
adapter->shared = dma_alloc_coherent(
&adapter->pdev->dev,
sizeof(struct Vmxnet3_DriverShared),
@@ -3232,6 +3281,7 @@ err_alloc_queue_desc:
err_alloc_shared:
dma_unmap_single(&adapter->pdev->dev, adapter->adapter_pa,
sizeof(struct vmxnet3_adapter), PCI_DMA_TODEVICE);
+err_dma_map:
free_netdev(netdev);
return err;
}
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c
index c1d0e7a9d..9ba11d737 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethtool.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c
@@ -183,16 +183,22 @@ vmxnet3_get_sset_count(struct net_device *netdev, int sset)
}
-/* Should be multiple of 4 */
-#define NUM_TX_REGS 8
-#define NUM_RX_REGS 12
-
+/* This is a version 2 of the vmxnet3 ethtool_regs which goes hand in hand with
+ * the version 2 of the vmxnet3 support for ethtool(8) --register-dump.
+ * Therefore, if any registers are added, removed or modified, then a version
+ * bump and a corresponding change in the vmxnet3 support for ethtool(8)
+ * --register-dump would be required.
+ */
static int
vmxnet3_get_regs_len(struct net_device *netdev)
{
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
- return (adapter->num_tx_queues * NUM_TX_REGS * sizeof(u32) +
- adapter->num_rx_queues * NUM_RX_REGS * sizeof(u32));
+
+ return ((9 /* BAR1 registers */ +
+ (1 + adapter->intr.num_intrs) +
+ (1 + adapter->num_tx_queues * 17 /* Tx queue registers */) +
+ (1 + adapter->num_rx_queues * 23 /* Rx queue registers */)) *
+ sizeof(u32));
}
@@ -208,10 +214,6 @@ vmxnet3_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
sizeof(drvinfo->bus_info));
- drvinfo->n_stats = vmxnet3_get_sset_count(netdev, ETH_SS_STATS);
- drvinfo->testinfo_len = 0;
- drvinfo->eedump_len = 0;
- drvinfo->regdump_len = vmxnet3_get_regs_len(netdev);
}
@@ -342,6 +344,12 @@ vmxnet3_get_ethtool_stats(struct net_device *netdev,
}
+/* This is a version 2 of the vmxnet3 ethtool_regs which goes hand in hand with
+ * the version 2 of the vmxnet3 support for ethtool(8) --register-dump.
+ * Therefore, if any registers are added, removed or modified, then a version
+ * bump and a corresponding change in the vmxnet3 support for ethtool(8)
+ * --register-dump would be required.
+ */
static void
vmxnet3_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
{
@@ -351,40 +359,90 @@ vmxnet3_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
memset(p, 0, vmxnet3_get_regs_len(netdev));
- regs->version = 1;
+ regs->version = 2;
/* Update vmxnet3_get_regs_len if we want to dump more registers */
- /* make each ring use multiple of 16 bytes */
- for (i = 0; i < adapter->num_tx_queues; i++) {
- buf[j++] = adapter->tx_queue[i].tx_ring.next2fill;
- buf[j++] = adapter->tx_queue[i].tx_ring.next2comp;
- buf[j++] = adapter->tx_queue[i].tx_ring.gen;
- buf[j++] = 0;
+ buf[j++] = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_VRRS);
+ buf[j++] = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_UVRS);
+ buf[j++] = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_DSAL);
+ buf[j++] = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_DSAH);
+ buf[j++] = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
+ buf[j++] = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_MACL);
+ buf[j++] = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_MACH);
+ buf[j++] = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_ICR);
+ buf[j++] = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_ECR);
+
+ buf[j++] = adapter->intr.num_intrs;
+ for (i = 0; i < adapter->intr.num_intrs; i++) {
+ buf[j++] = VMXNET3_READ_BAR0_REG(adapter, VMXNET3_REG_IMR
+ + i * VMXNET3_REG_ALIGN);
+ }
- buf[j++] = adapter->tx_queue[i].comp_ring.next2proc;
- buf[j++] = adapter->tx_queue[i].comp_ring.gen;
- buf[j++] = adapter->tx_queue[i].stopped;
- buf[j++] = 0;
+ buf[j++] = adapter->num_tx_queues;
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ struct vmxnet3_tx_queue *tq = &adapter->tx_queue[i];
+
+ buf[j++] = VMXNET3_READ_BAR0_REG(adapter, VMXNET3_REG_TXPROD +
+ i * VMXNET3_REG_ALIGN);
+
+ buf[j++] = VMXNET3_GET_ADDR_LO(tq->tx_ring.basePA);
+ buf[j++] = VMXNET3_GET_ADDR_HI(tq->tx_ring.basePA);
+ buf[j++] = tq->tx_ring.size;
+ buf[j++] = tq->tx_ring.next2fill;
+ buf[j++] = tq->tx_ring.next2comp;
+ buf[j++] = tq->tx_ring.gen;
+
+ 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++] = VMXNET3_GET_ADDR_LO(tq->comp_ring.basePA);
+ buf[j++] = VMXNET3_GET_ADDR_HI(tq->comp_ring.basePA);
+ buf[j++] = tq->comp_ring.size;
+ buf[j++] = tq->comp_ring.next2proc;
+ buf[j++] = tq->comp_ring.gen;
+
+ buf[j++] = tq->stopped;
}
+ buf[j++] = adapter->num_rx_queues;
for (i = 0; i < adapter->num_rx_queues; i++) {
- buf[j++] = adapter->rx_queue[i].rx_ring[0].next2fill;
- buf[j++] = adapter->rx_queue[i].rx_ring[0].next2comp;
- buf[j++] = adapter->rx_queue[i].rx_ring[0].gen;
+ struct vmxnet3_rx_queue *rq = &adapter->rx_queue[i];
+
+ buf[j++] = VMXNET3_READ_BAR0_REG(adapter, VMXNET3_REG_RXPROD +
+ i * VMXNET3_REG_ALIGN);
+ buf[j++] = VMXNET3_READ_BAR0_REG(adapter, VMXNET3_REG_RXPROD2 +
+ i * VMXNET3_REG_ALIGN);
+
+ buf[j++] = VMXNET3_GET_ADDR_LO(rq->rx_ring[0].basePA);
+ buf[j++] = VMXNET3_GET_ADDR_HI(rq->rx_ring[0].basePA);
+ buf[j++] = rq->rx_ring[0].size;
+ buf[j++] = rq->rx_ring[0].next2fill;
+ buf[j++] = rq->rx_ring[0].next2comp;
+ buf[j++] = rq->rx_ring[0].gen;
+
+ buf[j++] = VMXNET3_GET_ADDR_LO(rq->rx_ring[1].basePA);
+ buf[j++] = VMXNET3_GET_ADDR_HI(rq->rx_ring[1].basePA);
+ buf[j++] = rq->rx_ring[1].size;
+ buf[j++] = rq->rx_ring[1].next2fill;
+ buf[j++] = rq->rx_ring[1].next2comp;
+ buf[j++] = rq->rx_ring[1].gen;
+
+ /* receive data ring */
buf[j++] = 0;
-
- buf[j++] = adapter->rx_queue[i].rx_ring[1].next2fill;
- buf[j++] = adapter->rx_queue[i].rx_ring[1].next2comp;
- buf[j++] = adapter->rx_queue[i].rx_ring[1].gen;
buf[j++] = 0;
-
- buf[j++] = adapter->rx_queue[i].comp_ring.next2proc;
- buf[j++] = adapter->rx_queue[i].comp_ring.gen;
buf[j++] = 0;
buf[j++] = 0;
- }
+ buf[j++] = VMXNET3_GET_ADDR_LO(rq->comp_ring.basePA);
+ buf[j++] = VMXNET3_GET_ADDR_HI(rq->comp_ring.basePA);
+ buf[j++] = rq->comp_ring.size;
+ buf[j++] = rq->comp_ring.next2proc;
+ buf[j++] = rq->comp_ring.gen;
+ }
}
diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h
index 265224563..bdb8a6c0f 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.2.0-k"
+#define VMXNET3_DRIVER_VERSION_STRING "1.4.5.0-k"
/* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
-#define VMXNET3_DRIVER_VERSION_NUM 0x01040200
+#define VMXNET3_DRIVER_VERSION_NUM 0x01040500
#if defined(CONFIG_PCI_MSI)
/* RSS only makes sense if MSI-X is supported. */