summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/broadcom/bcmsysport.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/broadcom/bcmsysport.c')
-rw-r--r--drivers/net/ethernet/broadcom/bcmsysport.c50
1 files changed, 45 insertions, 5 deletions
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c
index 3a6778a667f4..5b308a4a4d0e 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.c
+++ b/drivers/net/ethernet/broadcom/bcmsysport.c
@@ -274,6 +274,9 @@ static const struct bcm_sysport_stats bcm_sysport_gstrings_stats[] = {
/* RBUF misc statistics */
STAT_RBUF("rbuf_ovflow_cnt", mib.rbuf_ovflow_cnt, RBUF_OVFL_DISC_CNTR),
STAT_RBUF("rbuf_err_cnt", mib.rbuf_err_cnt, RBUF_ERR_PKT_CNTR),
+ STAT_MIB_RX("alloc_rx_buff_failed", mib.alloc_rx_buff_failed),
+ STAT_MIB_RX("rx_dma_failed", mib.rx_dma_failed),
+ STAT_MIB_TX("tx_dma_failed", mib.tx_dma_failed),
};
#define BCM_SYSPORT_STATS_LEN ARRAY_SIZE(bcm_sysport_gstrings_stats)
@@ -477,6 +480,7 @@ static int bcm_sysport_rx_refill(struct bcm_sysport_priv *priv,
RX_BUF_LENGTH, DMA_FROM_DEVICE);
ret = dma_mapping_error(kdev, mapping);
if (ret) {
+ priv->mib.rx_dma_failed++;
bcm_sysport_free_cb(cb);
netif_err(priv, rx_err, ndev, "DMA mapping failure\n");
return ret;
@@ -526,6 +530,7 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv,
unsigned int p_index;
u16 len, status;
struct bcm_rsb *rsb;
+ int ret;
/* Determine how much we should process since last call */
p_index = rdma_readl(priv, RDMA_PROD_INDEX);
@@ -620,7 +625,9 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv,
napi_gro_receive(&priv->napi, skb);
refill:
- bcm_sysport_rx_refill(priv, cb);
+ ret = bcm_sysport_rx_refill(priv, cb);
+ if (ret)
+ priv->mib.alloc_rx_buff_failed++;
}
return processed;
@@ -731,9 +738,11 @@ static int bcm_sysport_tx_poll(struct napi_struct *napi, int budget)
napi_complete(napi);
/* re-enable TX interrupt */
intrl2_1_mask_clear(ring->priv, BIT(ring->index));
+
+ return 0;
}
- return 0;
+ return budget;
}
static void bcm_sysport_tx_reclaim_all(struct bcm_sysport_priv *priv)
@@ -971,6 +980,7 @@ static netdev_tx_t bcm_sysport_xmit(struct sk_buff *skb,
mapping = dma_map_single(kdev, skb->data, skb_len, DMA_TO_DEVICE);
if (dma_mapping_error(kdev, mapping)) {
+ priv->mib.tx_dma_failed++;
netif_err(priv, tx_err, dev, "DMA map failed at %p (len=%d)\n",
skb->data, skb_len);
ret = NETDEV_TX_OK;
@@ -1110,7 +1120,8 @@ static int bcm_sysport_init_tx_ring(struct bcm_sysport_priv *priv,
/* We just need one DMA descriptor which is DMA-able, since writing to
* the port will allocate a new descriptor in its internal linked-list
*/
- p = dma_zalloc_coherent(kdev, 1, &ring->desc_dma, GFP_KERNEL);
+ p = dma_zalloc_coherent(kdev, sizeof(struct dma_desc), &ring->desc_dma,
+ GFP_KERNEL);
if (!p) {
netif_err(priv, hw, priv->netdev, "DMA alloc failed\n");
return -ENOMEM;
@@ -1174,6 +1185,13 @@ static void bcm_sysport_fini_tx_ring(struct bcm_sysport_priv *priv,
if (!(reg & TDMA_DISABLED))
netdev_warn(priv->netdev, "TDMA not stopped!\n");
+ /* ring->cbs is the last part in bcm_sysport_init_tx_ring which could
+ * fail, so by checking this pointer we know whether the TX ring was
+ * fully initialized or not.
+ */
+ if (!ring->cbs)
+ return;
+
napi_disable(&ring->napi);
netif_napi_del(&ring->napi);
@@ -1183,7 +1201,8 @@ static void bcm_sysport_fini_tx_ring(struct bcm_sysport_priv *priv,
ring->cbs = NULL;
if (ring->desc_dma) {
- dma_free_coherent(kdev, 1, ring->desc_cpu, ring->desc_dma);
+ dma_free_coherent(kdev, sizeof(struct dma_desc),
+ ring->desc_cpu, ring->desc_dma);
ring->desc_dma = 0;
}
ring->size = 0;
@@ -1390,6 +1409,27 @@ static void topctrl_flush(struct bcm_sysport_priv *priv)
topctrl_writel(priv, 0, TX_FLUSH_CNTL);
}
+static int bcm_sysport_change_mac(struct net_device *dev, void *p)
+{
+ struct bcm_sysport_priv *priv = netdev_priv(dev);
+ struct sockaddr *addr = p;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EINVAL;
+
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+ /* interface is disabled, changes to MAC will be reflected on next
+ * open call
+ */
+ if (!netif_running(dev))
+ return 0;
+
+ umac_set_hw_addr(priv, dev->dev_addr);
+
+ return 0;
+}
+
static void bcm_sysport_netif_start(struct net_device *dev)
{
struct bcm_sysport_priv *priv = netdev_priv(dev);
@@ -1609,6 +1649,7 @@ static const struct net_device_ops bcm_sysport_netdev_ops = {
.ndo_stop = bcm_sysport_stop,
.ndo_set_features = bcm_sysport_set_features,
.ndo_set_rx_mode = bcm_sysport_set_rx_mode,
+ .ndo_set_mac_address = bcm_sysport_change_mac,
};
#define REV_FMT "v%2x.%02x"
@@ -1953,7 +1994,6 @@ static struct platform_driver bcm_sysport_driver = {
.remove = bcm_sysport_remove,
.driver = {
.name = "brcm-systemport",
- .owner = THIS_MODULE,
.of_match_table = bcm_sysport_of_match,
.pm = &bcm_sysport_pm_ops,
},