aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/broadcom
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/broadcom')
-rw-r--r--drivers/net/ethernet/broadcom/Kconfig8
-rw-r--r--drivers/net/ethernet/broadcom/bcmsysport.c532
-rw-r--r--drivers/net/ethernet/broadcom/bcmsysport.h14
-rw-r--r--drivers/net/ethernet/broadcom/bnx2.c9
-rw-r--r--drivers/net/ethernet/broadcom/bnx2.h5
-rw-r--r--drivers/net/ethernet/broadcom/bnx2_fw.h3
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x.h10
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c67
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c4
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c45
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c11
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c264
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h35
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c78
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h23
-rw-r--r--drivers/net/ethernet/broadcom/cnic.c10
-rw-r--r--drivers/net/ethernet/broadcom/cnic.h3
-rw-r--r--drivers/net/ethernet/broadcom/cnic_defs.h3
-rw-r--r--drivers/net/ethernet/broadcom/cnic_if.h3
-rw-r--r--drivers/net/ethernet/broadcom/genet/Makefile2
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.c623
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.h32
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c206
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmmii.c54
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c28
25 files changed, 1543 insertions, 529 deletions
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index 3e488094b073..7dcfb19a31c8 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -72,23 +72,23 @@ config BCMGENET
Broadcom BCM7xxx Set Top Box family chipset.
config BNX2
- tristate "Broadcom NetXtremeII support"
+ tristate "QLogic NetXtremeII support"
depends on PCI
select CRC32
select FW_LOADER
---help---
- This driver supports Broadcom NetXtremeII gigabit Ethernet cards.
+ This driver supports QLogic NetXtremeII gigabit Ethernet cards.
To compile this driver as a module, choose M here: the module
will be called bnx2. This is recommended.
config CNIC
- tristate "Broadcom CNIC support"
+ tristate "QLogic CNIC support"
depends on PCI
select BNX2
select UIO
---help---
- This driver supports offload features of Broadcom NetXtremeII
+ This driver supports offload features of QLogic NetXtremeII
gigabit Ethernet cards.
To compile this driver as a module, choose M here: the module
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c
index 141160ef249a..6f4e18644bd4 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.c
+++ b/drivers/net/ethernet/broadcom/bcmsysport.c
@@ -81,14 +81,14 @@ static inline void dma_desc_set_addr(struct bcm_sysport_priv *priv,
{
#ifdef CONFIG_PHYS_ADDR_T_64BIT
__raw_writel(upper_32_bits(addr) & DESC_ADDR_HI_MASK,
- d + DESC_ADDR_HI_STATUS_LEN);
+ d + DESC_ADDR_HI_STATUS_LEN);
#endif
__raw_writel(lower_32_bits(addr), d + DESC_ADDR_LO);
}
static inline void tdma_port_write_desc_addr(struct bcm_sysport_priv *priv,
- struct dma_desc *desc,
- unsigned int port)
+ struct dma_desc *desc,
+ unsigned int port)
{
/* Ports are latched, so write upper address first */
tdma_writel(priv, desc->addr_status_len, TDMA_WRITE_PORT_HI(port));
@@ -108,7 +108,7 @@ static int bcm_sysport_set_settings(struct net_device *dev,
}
static int bcm_sysport_get_settings(struct net_device *dev,
- struct ethtool_cmd *cmd)
+ struct ethtool_cmd *cmd)
{
struct bcm_sysport_priv *priv = netdev_priv(dev);
@@ -119,14 +119,14 @@ static int bcm_sysport_get_settings(struct net_device *dev,
}
static int bcm_sysport_set_rx_csum(struct net_device *dev,
- netdev_features_t wanted)
+ netdev_features_t wanted)
{
struct bcm_sysport_priv *priv = netdev_priv(dev);
u32 reg;
- priv->rx_csum_en = !!(wanted & NETIF_F_RXCSUM);
+ priv->rx_chk_en = !!(wanted & NETIF_F_RXCSUM);
reg = rxchk_readl(priv, RXCHK_CONTROL);
- if (priv->rx_csum_en)
+ if (priv->rx_chk_en)
reg |= RXCHK_EN;
else
reg &= ~RXCHK_EN;
@@ -134,7 +134,7 @@ static int bcm_sysport_set_rx_csum(struct net_device *dev,
/* If UniMAC forwards CRC, we need to skip over it to get
* a valid CHK bit to be set in the per-packet status word
*/
- if (priv->rx_csum_en && priv->crc_fwd)
+ if (priv->rx_chk_en && priv->crc_fwd)
reg |= RXCHK_SKIP_FCS;
else
reg &= ~RXCHK_SKIP_FCS;
@@ -145,7 +145,7 @@ static int bcm_sysport_set_rx_csum(struct net_device *dev,
}
static int bcm_sysport_set_tx_csum(struct net_device *dev,
- netdev_features_t wanted)
+ netdev_features_t wanted)
{
struct bcm_sysport_priv *priv = netdev_priv(dev);
u32 reg;
@@ -165,7 +165,7 @@ static int bcm_sysport_set_tx_csum(struct net_device *dev,
}
static int bcm_sysport_set_features(struct net_device *dev,
- netdev_features_t features)
+ netdev_features_t features)
{
netdev_features_t changed = features ^ dev->features;
netdev_features_t wanted = dev->wanted_features;
@@ -261,7 +261,7 @@ static const struct bcm_sysport_stats bcm_sysport_gstrings_stats[] = {
/* RXCHK misc statistics */
STAT_RXCHK("rxchk_bad_csum", mib.rxchk_bad_csum, RXCHK_BAD_CSUM_CNTR),
STAT_RXCHK("rxchk_other_pkt_disc", mib.rxchk_other_pkt_disc,
- RXCHK_OTHER_DISC_CNTR),
+ RXCHK_OTHER_DISC_CNTR),
/* 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),
@@ -270,7 +270,7 @@ static const struct bcm_sysport_stats bcm_sysport_gstrings_stats[] = {
#define BCM_SYSPORT_STATS_LEN ARRAY_SIZE(bcm_sysport_gstrings_stats)
static void bcm_sysport_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
+ struct ethtool_drvinfo *info)
{
strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
strlcpy(info->version, "0.1", sizeof(info->version));
@@ -303,7 +303,7 @@ static int bcm_sysport_get_sset_count(struct net_device *dev, int string_set)
}
static void bcm_sysport_get_strings(struct net_device *dev,
- u32 stringset, u8 *data)
+ u32 stringset, u8 *data)
{
int i;
@@ -311,8 +311,8 @@ static void bcm_sysport_get_strings(struct net_device *dev,
case ETH_SS_STATS:
for (i = 0; i < BCM_SYSPORT_STATS_LEN; i++) {
memcpy(data + i * ETH_GSTRING_LEN,
- bcm_sysport_gstrings_stats[i].stat_string,
- ETH_GSTRING_LEN);
+ bcm_sysport_gstrings_stats[i].stat_string,
+ ETH_GSTRING_LEN);
}
break;
default:
@@ -362,7 +362,7 @@ static void bcm_sysport_update_mib_counters(struct bcm_sysport_priv *priv)
}
static void bcm_sysport_get_stats(struct net_device *dev,
- struct ethtool_stats *stats, u64 *data)
+ struct ethtool_stats *stats, u64 *data)
{
struct bcm_sysport_priv *priv = netdev_priv(dev);
int i;
@@ -384,6 +384,64 @@ static void bcm_sysport_get_stats(struct net_device *dev,
}
}
+static void bcm_sysport_get_wol(struct net_device *dev,
+ struct ethtool_wolinfo *wol)
+{
+ struct bcm_sysport_priv *priv = netdev_priv(dev);
+ u32 reg;
+
+ wol->supported = WAKE_MAGIC | WAKE_MAGICSECURE;
+ wol->wolopts = priv->wolopts;
+
+ if (!(priv->wolopts & WAKE_MAGICSECURE))
+ return;
+
+ /* Return the programmed SecureOn password */
+ reg = umac_readl(priv, UMAC_PSW_MS);
+ put_unaligned_be16(reg, &wol->sopass[0]);
+ reg = umac_readl(priv, UMAC_PSW_LS);
+ put_unaligned_be32(reg, &wol->sopass[2]);
+}
+
+static int bcm_sysport_set_wol(struct net_device *dev,
+ struct ethtool_wolinfo *wol)
+{
+ struct bcm_sysport_priv *priv = netdev_priv(dev);
+ struct device *kdev = &priv->pdev->dev;
+ u32 supported = WAKE_MAGIC | WAKE_MAGICSECURE;
+
+ if (!device_can_wakeup(kdev))
+ return -ENOTSUPP;
+
+ if (wol->wolopts & ~supported)
+ return -EINVAL;
+
+ /* Program the SecureOn password */
+ if (wol->wolopts & WAKE_MAGICSECURE) {
+ umac_writel(priv, get_unaligned_be16(&wol->sopass[0]),
+ UMAC_PSW_MS);
+ umac_writel(priv, get_unaligned_be32(&wol->sopass[2]),
+ UMAC_PSW_LS);
+ }
+
+ /* Flag the device and relevant IRQ as wakeup capable */
+ if (wol->wolopts) {
+ device_set_wakeup_enable(kdev, 1);
+ enable_irq_wake(priv->wol_irq);
+ priv->wol_irq_disabled = 0;
+ } else {
+ device_set_wakeup_enable(kdev, 0);
+ /* Avoid unbalanced disable_irq_wake calls */
+ if (!priv->wol_irq_disabled)
+ disable_irq_wake(priv->wol_irq);
+ priv->wol_irq_disabled = 1;
+ }
+
+ priv->wolopts = wol->wolopts;
+
+ return 0;
+}
+
static void bcm_sysport_free_cb(struct bcm_sysport_cb *cb)
{
dev_kfree_skb_any(cb->skb);
@@ -406,7 +464,7 @@ static int bcm_sysport_rx_refill(struct bcm_sysport_priv *priv,
}
mapping = dma_map_single(kdev, cb->skb->data,
- RX_BUF_LENGTH, DMA_FROM_DEVICE);
+ RX_BUF_LENGTH, DMA_FROM_DEVICE);
ret = dma_mapping_error(kdev, mapping);
if (ret) {
bcm_sysport_free_cb(cb);
@@ -470,22 +528,20 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv,
to_process = p_index - priv->rx_c_index;
netif_dbg(priv, rx_status, ndev,
- "p_index=%d rx_c_index=%d to_process=%d\n",
- p_index, priv->rx_c_index, to_process);
-
- while ((processed < to_process) &&
- (processed < budget)) {
+ "p_index=%d rx_c_index=%d to_process=%d\n",
+ p_index, priv->rx_c_index, to_process);
+ while ((processed < to_process) && (processed < budget)) {
cb = &priv->rx_cbs[priv->rx_read_ptr];
skb = cb->skb;
dma_unmap_single(kdev, dma_unmap_addr(cb, dma_addr),
- RX_BUF_LENGTH, DMA_FROM_DEVICE);
+ RX_BUF_LENGTH, DMA_FROM_DEVICE);
/* Extract the Receive Status Block prepended */
rsb = (struct bcm_rsb *)skb->data;
len = (rsb->rx_status_len >> DESC_LEN_SHIFT) & DESC_LEN_MASK;
status = (rsb->rx_status_len >> DESC_STATUS_SHIFT) &
- DESC_STATUS_MASK;
+ DESC_STATUS_MASK;
processed++;
priv->rx_read_ptr++;
@@ -493,9 +549,9 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv,
priv->rx_read_ptr = 0;
netif_dbg(priv, rx_status, ndev,
- "p=%d, c=%d, rd_ptr=%d, len=%d, flag=0x%04x\n",
- p_index, priv->rx_c_index, priv->rx_read_ptr,
- len, status);
+ "p=%d, c=%d, rd_ptr=%d, len=%d, flag=0x%04x\n",
+ p_index, priv->rx_c_index, priv->rx_read_ptr,
+ len, status);
if (unlikely(!skb)) {
netif_err(priv, rx_err, ndev, "out of memory!\n");
@@ -554,9 +610,9 @@ refill:
}
static void bcm_sysport_tx_reclaim_one(struct bcm_sysport_priv *priv,
- struct bcm_sysport_cb *cb,
- unsigned int *bytes_compl,
- unsigned int *pkts_compl)
+ struct bcm_sysport_cb *cb,
+ unsigned int *bytes_compl,
+ unsigned int *pkts_compl)
{
struct device *kdev = &priv->pdev->dev;
struct net_device *ndev = priv->netdev;
@@ -565,8 +621,8 @@ static void bcm_sysport_tx_reclaim_one(struct bcm_sysport_priv *priv,
ndev->stats.tx_bytes += cb->skb->len;
*bytes_compl += cb->skb->len;
dma_unmap_single(kdev, dma_unmap_addr(cb, dma_addr),
- dma_unmap_len(cb, dma_len),
- DMA_TO_DEVICE);
+ dma_unmap_len(cb, dma_len),
+ DMA_TO_DEVICE);
ndev->stats.tx_packets++;
(*pkts_compl)++;
bcm_sysport_free_cb(cb);
@@ -574,7 +630,7 @@ static void bcm_sysport_tx_reclaim_one(struct bcm_sysport_priv *priv,
} else if (dma_unmap_addr(cb, dma_addr)) {
ndev->stats.tx_bytes += dma_unmap_len(cb, dma_len);
dma_unmap_page(kdev, dma_unmap_addr(cb, dma_addr),
- dma_unmap_len(cb, dma_len), DMA_TO_DEVICE);
+ dma_unmap_len(cb, dma_len), DMA_TO_DEVICE);
dma_unmap_addr_set(cb, dma_addr, 0);
}
}
@@ -608,8 +664,8 @@ static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv,
last_tx_cn = num_tx_cbs - last_c_index + c_index;
netif_dbg(priv, tx_done, ndev,
- "ring=%d c_index=%d last_tx_cn=%d last_c_index=%d\n",
- ring->index, c_index, last_tx_cn, last_c_index);
+ "ring=%d c_index=%d last_tx_cn=%d last_c_index=%d\n",
+ ring->index, c_index, last_tx_cn, last_c_index);
while (last_tx_cn-- > 0) {
cb = ring->cbs + last_c_index;
@@ -626,8 +682,8 @@ static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv,
netif_tx_wake_queue(txq);
netif_dbg(priv, tx_done, ndev,
- "ring=%d c_index=%d pkts_compl=%d, bytes_compl=%d\n",
- ring->index, ring->c_index, pkts_compl, bytes_compl);
+ "ring=%d c_index=%d pkts_compl=%d, bytes_compl=%d\n",
+ ring->index, ring->c_index, pkts_compl, bytes_compl);
return pkts_compl;
}
@@ -654,13 +710,13 @@ static int bcm_sysport_tx_poll(struct napi_struct *napi, int budget)
work_done = bcm_sysport_tx_reclaim(ring->priv, ring);
- if (work_done < budget) {
+ if (work_done == 0) {
napi_complete(napi);
/* re-enable TX interrupt */
intrl2_1_mask_clear(ring->priv, BIT(ring->index));
}
- return work_done;
+ return 0;
}
static void bcm_sysport_tx_reclaim_all(struct bcm_sysport_priv *priv)
@@ -692,6 +748,20 @@ static int bcm_sysport_poll(struct napi_struct *napi, int budget)
return work_done;
}
+static void bcm_sysport_resume_from_wol(struct bcm_sysport_priv *priv)
+{
+ u32 reg;
+
+ /* Stop monitoring MPD interrupt */
+ intrl2_0_mask_set(priv, INTRL2_0_MPD);
+
+ /* Clear the MagicPacket detection logic */
+ reg = umac_readl(priv, UMAC_MPD_CTRL);
+ reg &= ~MPD_EN;
+ umac_writel(priv, reg, UMAC_MPD_CTRL);
+
+ netif_dbg(priv, wol, priv->netdev, "resumed from WOL\n");
+}
/* RX and misc interrupt routine */
static irqreturn_t bcm_sysport_rx_isr(int irq, void *dev_id)
@@ -722,6 +792,11 @@ static irqreturn_t bcm_sysport_rx_isr(int irq, void *dev_id)
if (priv->irq0_stat & INTRL2_0_TX_RING_FULL)
bcm_sysport_tx_reclaim_all(priv);
+ if (priv->irq0_stat & INTRL2_0_MPD) {
+ netdev_info(priv->netdev, "Wake-on-LAN interrupt!\n");
+ bcm_sysport_resume_from_wol(priv);
+ }
+
return IRQ_HANDLED;
}
@@ -757,6 +832,15 @@ static irqreturn_t bcm_sysport_tx_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static irqreturn_t bcm_sysport_wol_isr(int irq, void *dev_id)
+{
+ struct bcm_sysport_priv *priv = dev_id;
+
+ pm_wakeup_event(&priv->pdev->dev, 0);
+
+ return IRQ_HANDLED;
+}
+
static int bcm_sysport_insert_tsb(struct sk_buff *skb, struct net_device *dev)
{
struct sk_buff *nskb;
@@ -804,8 +888,9 @@ static int bcm_sysport_insert_tsb(struct sk_buff *skb, struct net_device *dev)
csum_info |= L4_LENGTH_VALID;
if (ip_proto == IPPROTO_UDP && ip_ver == ETH_P_IP)
csum_info |= L4_UDP;
- } else
+ } else {
csum_info = 0;
+ }
tsb->l4_ptr_dest_map = csum_info;
}
@@ -869,7 +954,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)) {
netif_err(priv, tx_err, dev, "DMA map failed at %p (len=%d)\n",
- skb->data, skb_len);
+ skb->data, skb_len);
ret = NETDEV_TX_OK;
goto out;
}
@@ -887,7 +972,7 @@ static netdev_tx_t bcm_sysport_xmit(struct sk_buff *skb,
len_status = upper_32_bits(mapping) & DESC_ADDR_HI_MASK;
len_status |= (skb_len << DESC_LEN_SHIFT);
len_status |= (DESC_SOP | DESC_EOP | TX_STATUS_APP_CRC) <<
- DESC_STATUS_SHIFT;
+ DESC_STATUS_SHIFT;
if (skb->ip_summed == CHECKSUM_PARTIAL)
len_status |= (DESC_L4_CSUM << DESC_STATUS_SHIFT);
@@ -912,7 +997,7 @@ static netdev_tx_t bcm_sysport_xmit(struct sk_buff *skb,
netif_tx_stop_queue(txq);
netif_dbg(priv, tx_queued, dev, "ring=%d desc_count=%d, curr_desc=%d\n",
- ring->index, ring->desc_count, ring->curr_desc);
+ ring->index, ring->desc_count, ring->curr_desc);
ret = NETDEV_TX_OK;
out:
@@ -1010,7 +1095,7 @@ static int bcm_sysport_init_tx_ring(struct bcm_sysport_priv *priv,
return -ENOMEM;
}
- ring->cbs = kzalloc(sizeof(struct bcm_sysport_cb) * size, GFP_KERNEL);
+ ring->cbs = kcalloc(size, sizeof(struct bcm_sysport_cb), GFP_KERNEL);
if (!ring->cbs) {
netif_err(priv, hw, priv->netdev, "CB allocation failed\n");
return -ENOMEM;
@@ -1050,14 +1135,14 @@ static int bcm_sysport_init_tx_ring(struct bcm_sysport_priv *priv,
napi_enable(&ring->napi);
netif_dbg(priv, hw, priv->netdev,
- "TDMA cfg, size=%d, desc_cpu=%p\n",
- ring->size, ring->desc_cpu);
+ "TDMA cfg, size=%d, desc_cpu=%p\n",
+ ring->size, ring->desc_cpu);
return 0;
}
static void bcm_sysport_fini_tx_ring(struct bcm_sysport_priv *priv,
- unsigned int index)
+ unsigned int index)
{
struct bcm_sysport_tx_ring *ring = &priv->tx_rings[index];
struct device *kdev = &priv->pdev->dev;
@@ -1088,7 +1173,7 @@ static void bcm_sysport_fini_tx_ring(struct bcm_sysport_priv *priv,
/* RDMA helper */
static inline int rdma_enable_set(struct bcm_sysport_priv *priv,
- unsigned int enable)
+ unsigned int enable)
{
unsigned int timeout = 1000;
u32 reg;
@@ -1115,7 +1200,7 @@ static inline int rdma_enable_set(struct bcm_sysport_priv *priv,
/* TDMA helper */
static inline int tdma_enable_set(struct bcm_sysport_priv *priv,
- unsigned int enable)
+ unsigned int enable)
{
unsigned int timeout = 1000;
u32 reg;
@@ -1153,8 +1238,8 @@ static int bcm_sysport_init_rx_ring(struct bcm_sysport_priv *priv)
priv->rx_bd_assign_index = 0;
priv->rx_c_index = 0;
priv->rx_read_ptr = 0;
- priv->rx_cbs = kzalloc(priv->num_rx_bds *
- sizeof(struct bcm_sysport_cb), GFP_KERNEL);
+ priv->rx_cbs = kcalloc(priv->num_rx_bds, sizeof(struct bcm_sysport_cb),
+ GFP_KERNEL);
if (!priv->rx_cbs) {
netif_err(priv, hw, priv->netdev, "CB allocation failed\n");
return -ENOMEM;
@@ -1186,8 +1271,8 @@ static int bcm_sysport_init_rx_ring(struct bcm_sysport_priv *priv)
rdma_writel(priv, 1, RDMA_MBDONE_INTR);
netif_dbg(priv, hw, priv->netdev,
- "RDMA cfg, num_rx_bds=%d, rx_bds=%p\n",
- priv->num_rx_bds, priv->rx_bds);
+ "RDMA cfg, num_rx_bds=%d, rx_bds=%p\n",
+ priv->num_rx_bds, priv->rx_bds);
return 0;
}
@@ -1207,8 +1292,8 @@ static void bcm_sysport_fini_rx_ring(struct bcm_sysport_priv *priv)
cb = &priv->rx_cbs[i];
if (dma_unmap_addr(cb, dma_addr))
dma_unmap_single(&priv->pdev->dev,
- dma_unmap_addr(cb, dma_addr),
- RX_BUF_LENGTH, DMA_FROM_DEVICE);
+ dma_unmap_addr(cb, dma_addr),
+ RX_BUF_LENGTH, DMA_FROM_DEVICE);
bcm_sysport_free_cb(cb);
}
@@ -1236,15 +1321,15 @@ static void bcm_sysport_set_rx_mode(struct net_device *dev)
}
static inline void umac_enable_set(struct bcm_sysport_priv *priv,
- unsigned int enable)
+ u32 mask, unsigned int enable)
{
u32 reg;
reg = umac_readl(priv, UMAC_CMD);
if (enable)
- reg |= CMD_RX_EN | CMD_TX_EN;
+ reg |= mask;
else
- reg &= ~(CMD_RX_EN | CMD_TX_EN);
+ reg &= ~mask;
umac_writel(priv, reg, UMAC_CMD);
/* UniMAC stops on a packet boundary, wait for a full-sized packet
@@ -1254,32 +1339,21 @@ static inline void umac_enable_set(struct bcm_sysport_priv *priv,
usleep_range(1000, 2000);
}
-static inline int umac_reset(struct bcm_sysport_priv *priv)
+static inline void umac_reset(struct bcm_sysport_priv *priv)
{
- unsigned int timeout = 0;
u32 reg;
- int ret = 0;
- umac_writel(priv, 0, UMAC_CMD);
- while (timeout++ < 1000) {
- reg = umac_readl(priv, UMAC_CMD);
- if (!(reg & CMD_SW_RESET))
- break;
-
- udelay(1);
- }
-
- if (timeout == 1000) {
- dev_err(&priv->pdev->dev,
- "timeout waiting for MAC to come out of reset\n");
- ret = -ETIMEDOUT;
- }
-
- return ret;
+ reg = umac_readl(priv, UMAC_CMD);
+ reg |= CMD_SW_RESET;
+ umac_writel(priv, reg, UMAC_CMD);
+ udelay(10);
+ reg = umac_readl(priv, UMAC_CMD);
+ reg &= ~CMD_SW_RESET;
+ umac_writel(priv, reg, UMAC_CMD);
}
static void umac_set_hw_addr(struct bcm_sysport_priv *priv,
- unsigned char *addr)
+ unsigned char *addr)
{
umac_writel(priv, (addr[0] << 24) | (addr[1] << 16) |
(addr[2] << 8) | addr[3], UMAC_MAC0);
@@ -1295,30 +1369,48 @@ static void topctrl_flush(struct bcm_sysport_priv *priv)
topctrl_writel(priv, 0, TX_FLUSH_CNTL);
}
+static void bcm_sysport_netif_start(struct net_device *dev)
+{
+ struct bcm_sysport_priv *priv = netdev_priv(dev);
+
+ /* Enable NAPI */
+ napi_enable(&priv->napi);
+
+ phy_start(priv->phydev);
+
+ /* Enable TX interrupts for the 32 TXQs */
+ intrl2_1_mask_clear(priv, 0xffffffff);
+
+ /* Last call before we start the real business */
+ netif_tx_start_all_queues(dev);
+}
+
+static void rbuf_init(struct bcm_sysport_priv *priv)
+{
+ u32 reg;
+
+ reg = rbuf_readl(priv, RBUF_CONTROL);
+ reg |= RBUF_4B_ALGN | RBUF_RSB_EN;
+ rbuf_writel(priv, reg, RBUF_CONTROL);
+}
+
static int bcm_sysport_open(struct net_device *dev)
{
struct bcm_sysport_priv *priv = netdev_priv(dev);
unsigned int i;
- u32 reg;
int ret;
/* Reset UniMAC */
- ret = umac_reset(priv);
- if (ret) {
- netdev_err(dev, "UniMAC reset failed\n");
- return ret;
- }
+ umac_reset(priv);
/* Flush TX and RX FIFOs at TOPCTRL level */
topctrl_flush(priv);
/* Disable the UniMAC RX/TX */
- umac_enable_set(priv, 0);
+ umac_enable_set(priv, CMD_RX_EN | CMD_TX_EN, 0);
/* Enable RBUF 2bytes alignment and Receive Status Block */
- reg = rbuf_readl(priv, RBUF_CONTROL);
- reg |= RBUF_4B_ALGN | RBUF_RSB_EN;
- rbuf_writel(priv, reg, RBUF_CONTROL);
+ rbuf_init(priv);
/* Set maximum frame length */
umac_writel(priv, UMAC_MAX_MTU_SIZE, UMAC_MAX_FRAME_LEN);
@@ -1366,7 +1458,7 @@ static int bcm_sysport_open(struct net_device *dev)
ret = bcm_sysport_init_tx_ring(priv, i);
if (ret) {
netdev_err(dev, "failed to initialize TX ring %d\n",
- i);
+ i);
goto out_free_tx_ring;
}
}
@@ -1394,19 +1486,10 @@ static int bcm_sysport_open(struct net_device *dev)
if (ret)
goto out_clear_rx_int;
- /* Enable NAPI */
- napi_enable(&priv->napi);
-
/* Turn on UniMAC TX/RX */
- umac_enable_set(priv, 1);
-
- phy_start(priv->phydev);
+ umac_enable_set(priv, CMD_RX_EN | CMD_TX_EN, 1);
- /* Enable TX interrupts for the 32 TXQs */
- intrl2_1_mask_clear(priv, 0xffffffff);
-
- /* Last call before we start the real business */
- netif_tx_start_all_queues(dev);
+ bcm_sysport_netif_start(dev);
return 0;
@@ -1425,12 +1508,9 @@ out_phy_disconnect:
return ret;
}
-static int bcm_sysport_stop(struct net_device *dev)
+static void bcm_sysport_netif_stop(struct net_device *dev)
{
struct bcm_sysport_priv *priv = netdev_priv(dev);
- unsigned int i;
- u32 reg;
- int ret;
/* stop all software from updating hardware */
netif_tx_stop_all_queues(dev);
@@ -1442,11 +1522,18 @@ static int bcm_sysport_stop(struct net_device *dev)
intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
intrl2_1_mask_set(priv, 0xffffffff);
intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
+}
+
+static int bcm_sysport_stop(struct net_device *dev)
+{
+ struct bcm_sysport_priv *priv = netdev_priv(dev);
+ unsigned int i;
+ int ret;
+
+ bcm_sysport_netif_stop(dev);
/* Disable UniMAC RX */
- reg = umac_readl(priv, UMAC_CMD);
- reg &= ~CMD_RX_EN;
- umac_writel(priv, reg, UMAC_CMD);
+ umac_enable_set(priv, CMD_RX_EN, 0);
ret = tdma_enable_set(priv, 0);
if (ret) {
@@ -1464,9 +1551,7 @@ static int bcm_sysport_stop(struct net_device *dev)
}
/* Disable UniMAC TX */
- reg = umac_readl(priv, UMAC_CMD);
- reg &= ~CMD_TX_EN;
- umac_writel(priv, reg, UMAC_CMD);
+ umac_enable_set(priv, CMD_TX_EN, 0);
/* Free RX/TX rings SW structures */
for (i = 0; i < dev->num_tx_queues; i++)
@@ -1492,6 +1577,8 @@ static struct ethtool_ops bcm_sysport_ethtool_ops = {
.get_strings = bcm_sysport_get_strings,
.get_ethtool_stats = bcm_sysport_get_stats,
.get_sset_count = bcm_sysport_get_sset_count,
+ .get_wol = bcm_sysport_get_wol,
+ .set_wol = bcm_sysport_set_wol,
};
static const struct net_device_ops bcm_sysport_netdev_ops = {
@@ -1533,6 +1620,7 @@ static int bcm_sysport_probe(struct platform_device *pdev)
priv->irq0 = platform_get_irq(pdev, 0);
priv->irq1 = platform_get_irq(pdev, 1);
+ priv->wol_irq = platform_get_irq(pdev, 2);
if (priv->irq0 <= 0 || priv->irq1 <= 0) {
dev_err(&pdev->dev, "invalid interrupts\n");
ret = -EINVAL;
@@ -1585,16 +1673,17 @@ static int bcm_sysport_probe(struct platform_device *pdev)
dev->hw_features |= NETIF_F_RXCSUM | NETIF_F_HIGHDMA |
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+ /* Request the WOL interrupt and advertise suspend if available */
+ priv->wol_irq_disabled = 1;
+ ret = devm_request_irq(&pdev->dev, priv->wol_irq,
+ bcm_sysport_wol_isr, 0, dev->name, priv);
+ if (!ret)
+ device_set_wakeup_capable(&pdev->dev, 1);
+
/* Set the needed headroom once and for all */
BUILD_BUG_ON(sizeof(struct bcm_tsb) != 8);
dev->needed_headroom += sizeof(struct bcm_tsb);
- /* We are interfaced to a switch which handles the multicast
- * filtering for us, so we do not support programming any
- * multicast hash table in this Ethernet MAC.
- */
- dev->flags &= ~IFF_MULTICAST;
-
/* libphy will adjust the link state accordingly */
netif_carrier_off(dev);
@@ -1606,10 +1695,10 @@ static int bcm_sysport_probe(struct platform_device *pdev)
priv->rev = topctrl_readl(priv, REV_CNTL) & REV_MASK;
dev_info(&pdev->dev,
- "Broadcom SYSTEMPORT" REV_FMT
- " at 0x%p (irqs: %d, %d, TXQs: %d, RXQs: %d)\n",
- (priv->rev >> 8) & 0xff, priv->rev & 0xff,
- priv->base, priv->irq0, priv->irq1, txq, rxq);
+ "Broadcom SYSTEMPORT" REV_FMT
+ " at 0x%p (irqs: %d, %d, TXQs: %d, RXQs: %d)\n",
+ (priv->rev >> 8) & 0xff, priv->rev & 0xff,
+ priv->base, priv->irq0, priv->irq1, txq, rxq);
return 0;
err:
@@ -1631,6 +1720,208 @@ static int bcm_sysport_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int bcm_sysport_suspend_to_wol(struct bcm_sysport_priv *priv)
+{
+ struct net_device *ndev = priv->netdev;
+ unsigned int timeout = 1000;
+ u32 reg;
+
+ /* Password has already been programmed */
+ reg = umac_readl(priv, UMAC_MPD_CTRL);
+ reg |= MPD_EN;
+ reg &= ~PSW_EN;
+ if (priv->wolopts & WAKE_MAGICSECURE)
+ reg |= PSW_EN;
+ umac_writel(priv, reg, UMAC_MPD_CTRL);
+
+ /* Make sure RBUF entered WoL mode as result */
+ do {
+ reg = rbuf_readl(priv, RBUF_STATUS);
+ if (reg & RBUF_WOL_MODE)
+ break;
+
+ udelay(10);
+ } while (timeout-- > 0);
+
+ /* Do not leave the UniMAC RBUF matching only MPD packets */
+ if (!timeout) {
+ reg = umac_readl(priv, UMAC_MPD_CTRL);
+ reg &= ~MPD_EN;
+ umac_writel(priv, reg, UMAC_MPD_CTRL);
+ netif_err(priv, wol, ndev, "failed to enter WOL mode\n");
+ return -ETIMEDOUT;
+ }
+
+ /* UniMAC receive needs to be turned on */
+ umac_enable_set(priv, CMD_RX_EN, 1);
+
+ /* Enable the interrupt wake-up source */
+ intrl2_0_mask_clear(priv, INTRL2_0_MPD);
+
+ netif_dbg(priv, wol, ndev, "entered WOL mode\n");
+
+ return 0;
+}
+
+static int bcm_sysport_suspend(struct device *d)
+{
+ struct net_device *dev = dev_get_drvdata(d);
+ struct bcm_sysport_priv *priv = netdev_priv(dev);
+ unsigned int i;
+ int ret = 0;
+ u32 reg;
+
+ if (!netif_running(dev))
+ return 0;
+
+ bcm_sysport_netif_stop(dev);
+
+ phy_suspend(priv->phydev);
+
+ netif_device_detach(dev);
+
+ /* Disable UniMAC RX */
+ umac_enable_set(priv, CMD_RX_EN, 0);
+
+ ret = rdma_enable_set(priv, 0);
+ if (ret) {
+ netdev_err(dev, "RDMA timeout!\n");
+ return ret;
+ }
+
+ /* Disable RXCHK if enabled */
+ if (priv->rx_chk_en) {
+ reg = rxchk_readl(priv, RXCHK_CONTROL);
+ reg &= ~RXCHK_EN;
+ rxchk_writel(priv, reg, RXCHK_CONTROL);
+ }
+
+ /* Flush RX pipe */
+ if (!priv->wolopts)
+ topctrl_writel(priv, RX_FLUSH, RX_FLUSH_CNTL);
+
+ ret = tdma_enable_set(priv, 0);
+ if (ret) {
+ netdev_err(dev, "TDMA timeout!\n");
+ return ret;
+ }
+
+ /* Wait for a packet boundary */
+ usleep_range(2000, 3000);
+
+ umac_enable_set(priv, CMD_TX_EN, 0);
+
+ topctrl_writel(priv, TX_FLUSH, TX_FLUSH_CNTL);
+
+ /* Free RX/TX rings SW structures */
+ for (i = 0; i < dev->num_tx_queues; i++)
+ bcm_sysport_fini_tx_ring(priv, i);
+ bcm_sysport_fini_rx_ring(priv);
+
+ /* Get prepared for Wake-on-LAN */
+ if (device_may_wakeup(d) && priv->wolopts)
+ ret = bcm_sysport_suspend_to_wol(priv);
+
+ return ret;
+}
+
+static int bcm_sysport_resume(struct device *d)
+{
+ struct net_device *dev = dev_get_drvdata(d);
+ struct bcm_sysport_priv *priv = netdev_priv(dev);
+ unsigned int i;
+ u32 reg;
+ int ret;
+
+ if (!netif_running(dev))
+ return 0;
+
+ /* We may have been suspended and never received a WOL event that
+ * would turn off MPD detection, take care of that now
+ */
+ bcm_sysport_resume_from_wol(priv);
+
+ /* Initialize both hardware and software ring */
+ for (i = 0; i < dev->num_tx_queues; i++) {
+ ret = bcm_sysport_init_tx_ring(priv, i);
+ if (ret) {
+ netdev_err(dev, "failed to initialize TX ring %d\n",
+ i);
+ goto out_free_tx_rings;
+ }
+ }
+
+ /* Initialize linked-list */
+ tdma_writel(priv, TDMA_LL_RAM_INIT_BUSY, TDMA_STATUS);
+
+ /* Initialize RX ring */
+ ret = bcm_sysport_init_rx_ring(priv);
+ if (ret) {
+ netdev_err(dev, "failed to initialize RX ring\n");
+ goto out_free_rx_ring;
+ }
+
+ netif_device_attach(dev);
+
+ /* Enable RX interrupt and TX ring full interrupt */
+ intrl2_0_mask_clear(priv, INTRL2_0_RDMA_MBDONE | INTRL2_0_TX_RING_FULL);
+
+ /* RX pipe enable */
+ topctrl_writel(priv, 0, RX_FLUSH_CNTL);
+
+ ret = rdma_enable_set(priv, 1);
+ if (ret) {
+ netdev_err(dev, "failed to enable RDMA\n");
+ goto out_free_rx_ring;
+ }
+
+ /* Enable rxhck */
+ if (priv->rx_chk_en) {
+ reg = rxchk_readl(priv, RXCHK_CONTROL);
+ reg |= RXCHK_EN;
+ rxchk_writel(priv, reg, RXCHK_CONTROL);
+ }
+
+ rbuf_init(priv);
+
+ /* Set maximum frame length */
+ umac_writel(priv, UMAC_MAX_MTU_SIZE, UMAC_MAX_FRAME_LEN);
+
+ /* Set MAC address */
+ umac_set_hw_addr(priv, dev->dev_addr);
+
+ umac_enable_set(priv, CMD_RX_EN, 1);
+
+ /* TX pipe enable */
+ topctrl_writel(priv, 0, TX_FLUSH_CNTL);
+
+ umac_enable_set(priv, CMD_TX_EN, 1);
+
+ ret = tdma_enable_set(priv, 1);
+ if (ret) {
+ netdev_err(dev, "TDMA timeout!\n");
+ goto out_free_rx_ring;
+ }
+
+ phy_resume(priv->phydev);
+
+ bcm_sysport_netif_start(dev);
+
+ return 0;
+
+out_free_rx_ring:
+ bcm_sysport_fini_rx_ring(priv);
+out_free_tx_rings:
+ for (i = 0; i < dev->num_tx_queues; i++)
+ bcm_sysport_fini_tx_ring(priv, i);
+ return ret;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(bcm_sysport_pm_ops,
+ bcm_sysport_suspend, bcm_sysport_resume);
+
static const struct of_device_id bcm_sysport_of_match[] = {
{ .compatible = "brcm,systemport-v1.00" },
{ .compatible = "brcm,systemport" },
@@ -1644,6 +1935,7 @@ static struct platform_driver bcm_sysport_driver = {
.name = "brcm-systemport",
.owner = THIS_MODULE,
.of_match_table = bcm_sysport_of_match,
+ .pm = &bcm_sysport_pm_ops,
},
};
module_platform_driver(bcm_sysport_driver);
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.h b/drivers/net/ethernet/broadcom/bcmsysport.h
index 281c08246037..b08dab828101 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.h
+++ b/drivers/net/ethernet/broadcom/bcmsysport.h
@@ -246,6 +246,15 @@ struct bcm_rsb {
#define MIB_RX_CNT_RST (1 << 0)
#define MIB_RUNT_CNT_RST (1 << 1)
#define MIB_TX_CNT_RST (1 << 2)
+
+#define UMAC_MPD_CTRL 0x620
+#define MPD_EN (1 << 0)
+#define MSEQ_LEN_SHIFT 16
+#define MSEQ_LEN_MASK 0xff
+#define PSW_EN (1 << 27)
+
+#define UMAC_PSW_MS 0x624
+#define UMAC_PSW_LS 0x628
#define UMAC_MDF_CTRL 0x650
#define UMAC_MDF_ADDR 0x654
@@ -642,6 +651,7 @@ struct bcm_sysport_priv {
struct platform_device *pdev;
int irq0;
int irq1;
+ int wol_irq;
/* Transmit rings */
struct bcm_sysport_tx_ring tx_rings[TDMA_NUM_RINGS];
@@ -664,10 +674,12 @@ struct bcm_sysport_priv {
int old_duplex;
/* Misc fields */
- unsigned int rx_csum_en:1;
+ unsigned int rx_chk_en:1;
unsigned int tsb_en:1;
unsigned int crc_fwd:1;
u16 rev;
+ u32 wolopts;
+ unsigned int wol_irq_disabled:1;
/* MIB related fields */
struct bcm_sysport_mib mib;
diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c
index 67d2b0047371..e64c963fe775 100644
--- a/drivers/net/ethernet/broadcom/bnx2.c
+++ b/drivers/net/ethernet/broadcom/bnx2.c
@@ -1,6 +1,7 @@
-/* bnx2.c: Broadcom NX2 network driver.
+/* bnx2.c: QLogic NX2 network driver.
*
- * Copyright (c) 2004-2013 Broadcom Corporation
+ * Copyright (c) 2004-2014 Broadcom Corporation
+ * Copyright (c) 2014 QLogic Corporation
*
* 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
@@ -71,10 +72,10 @@
#define TX_TIMEOUT (5*HZ)
static char version[] =
- "Broadcom NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+ "QLogic NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
MODULE_AUTHOR("Michael Chan <mchan@broadcom.com>");
-MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709/5716 Driver");
+MODULE_DESCRIPTION("QLogic NetXtreme II BCM5706/5708/5709/5716 Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_MODULE_VERSION);
MODULE_FIRMWARE(FW_MIPS_FILE_06);
diff --git a/drivers/net/ethernet/broadcom/bnx2.h b/drivers/net/ethernet/broadcom/bnx2.h
index e341bc366fa5..28df35d35893 100644
--- a/drivers/net/ethernet/broadcom/bnx2.h
+++ b/drivers/net/ethernet/broadcom/bnx2.h
@@ -1,6 +1,7 @@
-/* bnx2.h: Broadcom NX2 network driver.
+/* bnx2.h: QLogic NX2 network driver.
*
- * Copyright (c) 2004-2013 Broadcom Corporation
+ * Copyright (c) 2004-2014 Broadcom Corporation
+ * Copyright (c) 2014 QLogic Corporation
*
* 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
diff --git a/drivers/net/ethernet/broadcom/bnx2_fw.h b/drivers/net/ethernet/broadcom/bnx2_fw.h
index 940eb91f209d..7db79c28b5ff 100644
--- a/drivers/net/ethernet/broadcom/bnx2_fw.h
+++ b/drivers/net/ethernet/broadcom/bnx2_fw.h
@@ -1,6 +1,7 @@
-/* bnx2_fw.h: Broadcom NX2 network driver.
+/* bnx2_fw.h: QLogic NX2 network driver.
*
* Copyright (c) 2004, 2005, 2006, 2007 Broadcom Corporation
+ * Copyright (c) 2014 QLogic Corporation
*
* 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
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
index 4cab09d3f807..d777fae86988 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
@@ -346,6 +346,7 @@ struct sw_tx_bd {
u8 flags;
/* Set on the first BD descriptor when there is a split BD */
#define BNX2X_TSO_SPLIT_BD (1<<0)
+#define BNX2X_HAS_SECOND_PBD (1<<1)
};
struct sw_rx_page {
@@ -1482,6 +1483,7 @@ struct bnx2x {
union pf_vf_bulletin *pf2vf_bulletin;
dma_addr_t pf2vf_bulletin_mapping;
+ union pf_vf_bulletin shadow_bulletin;
struct pf_vf_bulletin_content old_bulletin;
u16 requested_nr_virtfn;
@@ -1507,8 +1509,10 @@ struct bnx2x {
/* TCP with Timestamp Option (32) + IPv6 (40) */
#define ETH_MAX_TPA_HEADER_SIZE 72
- /* Max supported alignment is 256 (8 shift) */
-#define BNX2X_RX_ALIGN_SHIFT min(8, L1_CACHE_SHIFT)
+ /* Max supported alignment is 256 (8 shift)
+ * minimal alignment shift 6 is optimal for 57xxx HW performance
+ */
+#define BNX2X_RX_ALIGN_SHIFT max(6, min(8, L1_CACHE_SHIFT))
/* FW uses 2 Cache lines Alignment for start packet and size
*
@@ -1928,6 +1932,8 @@ struct bnx2x {
struct semaphore stats_sema;
u8 phys_port_id[ETH_ALEN];
+
+ struct bnx2x_link_report_data vf_link_vars;
};
/* Tx queues may be less or equal to Rx queues */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index 47c5814114e1..4e6c82e20224 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -227,6 +227,12 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata,
--nbd;
bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
+ if (tx_buf->flags & BNX2X_HAS_SECOND_PBD) {
+ /* Skip second parse bd... */
+ --nbd;
+ bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
+ }
+
/* TSO headers+data bds share a common mapping. See bnx2x_tx_split() */
if (tx_buf->flags & BNX2X_TSO_SPLIT_BD) {
tx_data_bd = &txdata->tx_desc_ring[bd_idx].reg_bd;
@@ -797,7 +803,8 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
return;
}
- bnx2x_frag_free(fp, new_data);
+ if (new_data)
+ bnx2x_frag_free(fp, new_data);
drop:
/* drop the packet and keep the buffer in the bin */
DP(NETIF_MSG_RX_STATUS,
@@ -1185,29 +1192,38 @@ u16 bnx2x_get_mf_speed(struct bnx2x *bp)
static void bnx2x_fill_report_data(struct bnx2x *bp,
struct bnx2x_link_report_data *data)
{
- u16 line_speed = bnx2x_get_mf_speed(bp);
-
memset(data, 0, sizeof(*data));
- /* Fill the report data: effective line speed */
- data->line_speed = line_speed;
-
- /* Link is down */
- if (!bp->link_vars.link_up || (bp->flags & MF_FUNC_DIS))
- __set_bit(BNX2X_LINK_REPORT_LINK_DOWN,
- &data->link_report_flags);
-
- /* Full DUPLEX */
- if (bp->link_vars.duplex == DUPLEX_FULL)
- __set_bit(BNX2X_LINK_REPORT_FD, &data->link_report_flags);
-
- /* Rx Flow Control is ON */
- if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX)
- __set_bit(BNX2X_LINK_REPORT_RX_FC_ON, &data->link_report_flags);
-
- /* Tx Flow Control is ON */
- if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX)
- __set_bit(BNX2X_LINK_REPORT_TX_FC_ON, &data->link_report_flags);
+ if (IS_PF(bp)) {
+ /* Fill the report data: effective line speed */
+ data->line_speed = bnx2x_get_mf_speed(bp);
+
+ /* Link is down */
+ if (!bp->link_vars.link_up || (bp->flags & MF_FUNC_DIS))
+ __set_bit(BNX2X_LINK_REPORT_LINK_DOWN,
+ &data->link_report_flags);
+
+ if (!BNX2X_NUM_ETH_QUEUES(bp))
+ __set_bit(BNX2X_LINK_REPORT_LINK_DOWN,
+ &data->link_report_flags);
+
+ /* Full DUPLEX */
+ if (bp->link_vars.duplex == DUPLEX_FULL)
+ __set_bit(BNX2X_LINK_REPORT_FD,
+ &data->link_report_flags);
+
+ /* Rx Flow Control is ON */
+ if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX)
+ __set_bit(BNX2X_LINK_REPORT_RX_FC_ON,
+ &data->link_report_flags);
+
+ /* Tx Flow Control is ON */
+ if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX)
+ __set_bit(BNX2X_LINK_REPORT_TX_FC_ON,
+ &data->link_report_flags);
+ } else { /* VF */
+ *data = bp->vf_link_vars;
+ }
}
/**
@@ -1261,6 +1277,10 @@ void __bnx2x_link_report(struct bnx2x *bp)
*/
memcpy(&bp->last_reported_link, &cur_data, sizeof(cur_data));
+ /* propagate status to VFs */
+ if (IS_PF(bp))
+ bnx2x_iov_link_update(bp);
+
if (test_bit(BNX2X_LINK_REPORT_LINK_DOWN,
&cur_data.link_report_flags)) {
netif_carrier_off(bp->dev);
@@ -3888,6 +3908,9 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* set encapsulation flag in start BD */
SET_FLAG(tx_start_bd->general_data,
ETH_TX_START_BD_TUNNEL_EXIST, 1);
+
+ tx_buf->flags |= BNX2X_HAS_SECOND_PBD;
+
nbd++;
} else if (xmit_type & XMIT_CSUM) {
/* Set PBD in checksum offload case w/o encapsulation */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
index 51a952c51cb1..fb26bc4c42a1 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
@@ -2303,8 +2303,8 @@ static int bnx2x_set_admin_app_up(struct bnx2x *bp, u8 idtype, u16 idval, u8 up)
return 0;
}
-static u8 bnx2x_dcbnl_set_app_up(struct net_device *netdev, u8 idtype,
- u16 idval, u8 up)
+static int bnx2x_dcbnl_set_app_up(struct net_device *netdev, u8 idtype,
+ u16 idval, u8 up)
{
struct bnx2x *bp = netdev_priv(netdev);
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
index bd0600cf7266..92fee842f954 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
@@ -216,6 +216,43 @@ static int bnx2x_get_port_type(struct bnx2x *bp)
return port_type;
}
+static int bnx2x_get_vf_settings(struct net_device *dev,
+ struct ethtool_cmd *cmd)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+
+ if (bp->state == BNX2X_STATE_OPEN) {
+ if (test_bit(BNX2X_LINK_REPORT_FD,
+ &bp->vf_link_vars.link_report_flags))
+ cmd->duplex = DUPLEX_FULL;
+ else
+ cmd->duplex = DUPLEX_HALF;
+
+ ethtool_cmd_speed_set(cmd, bp->vf_link_vars.line_speed);
+ } else {
+ cmd->duplex = DUPLEX_UNKNOWN;
+ ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN);
+ }
+
+ cmd->port = PORT_OTHER;
+ cmd->phy_address = 0;
+ cmd->transceiver = XCVR_INTERNAL;
+ cmd->autoneg = AUTONEG_DISABLE;
+ cmd->maxtxpkt = 0;
+ cmd->maxrxpkt = 0;
+
+ DP(BNX2X_MSG_ETHTOOL, "ethtool_cmd: cmd %d\n"
+ " supported 0x%x advertising 0x%x speed %u\n"
+ " duplex %d port %d phy_address %d transceiver %d\n"
+ " autoneg %d maxtxpkt %d maxrxpkt %d\n",
+ cmd->cmd, cmd->supported, cmd->advertising,
+ ethtool_cmd_speed(cmd),
+ cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver,
+ cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt);
+
+ return 0;
+}
+
static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct bnx2x *bp = netdev_priv(dev);
@@ -379,6 +416,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
break;
case PORT_FIBRE:
case PORT_DA:
+ case PORT_NONE:
if (!(bp->port.supported[0] & SUPPORTED_FIBRE ||
bp->port.supported[1] & SUPPORTED_FIBRE)) {
DP(BNX2X_MSG_ETHTOOL,
@@ -1110,6 +1148,10 @@ static u32 bnx2x_get_link(struct net_device *dev)
if (bp->flags & MF_FUNC_DIS || (bp->state != BNX2X_STATE_OPEN))
return 0;
+ if (IS_VF(bp))
+ return !test_bit(BNX2X_LINK_REPORT_LINK_DOWN,
+ &bp->vf_link_vars.link_report_flags);
+
return bp->link_vars.link_up;
}
@@ -3484,8 +3526,7 @@ static const struct ethtool_ops bnx2x_ethtool_ops = {
};
static const struct ethtool_ops bnx2x_vf_ethtool_ops = {
- .get_settings = bnx2x_get_settings,
- .set_settings = bnx2x_set_settings,
+ .get_settings = bnx2x_get_vf_settings,
.get_drvinfo = bnx2x_get_drvinfo,
.get_msglevel = bnx2x_get_msglevel,
.set_msglevel = bnx2x_set_msglevel,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index 2887034523e0..3871ec49cc4d 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -2698,6 +2698,14 @@ void bnx2x__link_status_update(struct bnx2x *bp)
bp->link_vars.duplex = DUPLEX_FULL;
bp->link_vars.flow_ctrl = BNX2X_FLOW_CTRL_NONE;
__bnx2x_link_report(bp);
+
+ bnx2x_sample_bulletin(bp);
+
+ /* if bulletin board did not have an update for link status
+ * __bnx2x_link_report will report current status
+ * but it will NOT duplicate report in case of already reported
+ * during sampling bulletin board.
+ */
bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
}
}
@@ -12424,6 +12432,7 @@ static const struct net_device_ops bnx2x_netdev_ops = {
.ndo_busy_poll = bnx2x_low_latency_recv,
#endif
.ndo_get_phys_port_id = bnx2x_get_phys_port_id,
+ .ndo_set_vf_link_state = bnx2x_set_vf_link_state,
};
static int bnx2x_set_coherency_mask(struct bnx2x *bp)
@@ -12937,7 +12946,7 @@ static int bnx2x_get_num_non_def_sbs(struct pci_dev *pdev, int cnic_cnt)
* without the default SB.
* For VFs there is no default SB, then we return (index+1).
*/
- pci_read_config_word(pdev, pdev->msix_cap + PCI_MSI_FLAGS, &control);
+ pci_read_config_word(pdev, pdev->msix_cap + PCI_MSIX_FLAGS, &control);
index = control & PCI_MSIX_FLAGS_QSIZE;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
index eda8583f6fc0..662310c5f4e9 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
@@ -24,6 +24,11 @@
#include <linux/crc32.h>
#include <linux/if_vlan.h>
+static int bnx2x_vf_op_prep(struct bnx2x *bp, int vfidx,
+ struct bnx2x_virtf **vf,
+ struct pf_vf_bulletin_content **bulletin,
+ bool test_queue);
+
/* General service functions */
static void storm_memset_vf_to_pf(struct bnx2x *bp, u16 abs_fid,
u16 pf_id)
@@ -597,8 +602,7 @@ int bnx2x_vf_mcast(struct bnx2x *bp, struct bnx2x_virtf *vf,
rc = bnx2x_config_mcast(bp, &mcast, BNX2X_MCAST_CMD_DEL);
if (rc) {
BNX2X_ERR("Failed to remove multicasts\n");
- if (mc)
- kfree(mc);
+ kfree(mc);
return rc;
}
@@ -1328,6 +1332,8 @@ int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param,
/* Prepare the VFs event synchronization mechanism */
mutex_init(&bp->vfdb->event_mutex);
+ mutex_init(&bp->vfdb->bulletin_mutex);
+
return 0;
failed:
DP(BNX2X_MSG_IOV, "Failed err=%d\n", err);
@@ -1473,6 +1479,107 @@ static void bnx2x_vfq_init(struct bnx2x *bp, struct bnx2x_virtf *vf,
vf->abs_vfid, q->sp_obj.func_id, q->cid);
}
+static int bnx2x_max_speed_cap(struct bnx2x *bp)
+{
+ u32 supported = bp->port.supported[bnx2x_get_link_cfg_idx(bp)];
+
+ if (supported &
+ (SUPPORTED_20000baseMLD2_Full | SUPPORTED_20000baseKR2_Full))
+ return 20000;
+
+ return 10000; /* assume lowest supported speed is 10G */
+}
+
+int bnx2x_iov_link_update_vf(struct bnx2x *bp, int idx)
+{
+ struct bnx2x_link_report_data *state = &bp->last_reported_link;
+ struct pf_vf_bulletin_content *bulletin;
+ struct bnx2x_virtf *vf;
+ bool update = true;
+ int rc = 0;
+
+ /* sanity and init */
+ rc = bnx2x_vf_op_prep(bp, idx, &vf, &bulletin, false);
+ if (rc)
+ return rc;
+
+ mutex_lock(&bp->vfdb->bulletin_mutex);
+
+ if (vf->link_cfg == IFLA_VF_LINK_STATE_AUTO) {
+ bulletin->valid_bitmap |= 1 << LINK_VALID;
+
+ bulletin->link_speed = state->line_speed;
+ bulletin->link_flags = 0;
+ if (test_bit(BNX2X_LINK_REPORT_LINK_DOWN,
+ &state->link_report_flags))
+ bulletin->link_flags |= VFPF_LINK_REPORT_LINK_DOWN;
+ if (test_bit(BNX2X_LINK_REPORT_FD,
+ &state->link_report_flags))
+ bulletin->link_flags |= VFPF_LINK_REPORT_FULL_DUPLEX;
+ if (test_bit(BNX2X_LINK_REPORT_RX_FC_ON,
+ &state->link_report_flags))
+ bulletin->link_flags |= VFPF_LINK_REPORT_RX_FC_ON;
+ if (test_bit(BNX2X_LINK_REPORT_TX_FC_ON,
+ &state->link_report_flags))
+ bulletin->link_flags |= VFPF_LINK_REPORT_TX_FC_ON;
+ } else if (vf->link_cfg == IFLA_VF_LINK_STATE_DISABLE &&
+ !(bulletin->link_flags & VFPF_LINK_REPORT_LINK_DOWN)) {
+ bulletin->valid_bitmap |= 1 << LINK_VALID;
+ bulletin->link_flags |= VFPF_LINK_REPORT_LINK_DOWN;
+ } else if (vf->link_cfg == IFLA_VF_LINK_STATE_ENABLE &&
+ (bulletin->link_flags & VFPF_LINK_REPORT_LINK_DOWN)) {
+ bulletin->valid_bitmap |= 1 << LINK_VALID;
+ bulletin->link_speed = bnx2x_max_speed_cap(bp);
+ bulletin->link_flags &= ~VFPF_LINK_REPORT_LINK_DOWN;
+ } else {
+ update = false;
+ }
+
+ if (update) {
+ DP(NETIF_MSG_LINK | BNX2X_MSG_IOV,
+ "vf %d mode %u speed %d flags %x\n", idx,
+ vf->link_cfg, bulletin->link_speed, bulletin->link_flags);
+
+ /* Post update on VF's bulletin board */
+ rc = bnx2x_post_vf_bulletin(bp, idx);
+ if (rc) {
+ BNX2X_ERR("failed to update VF[%d] bulletin\n", idx);
+ goto out;
+ }
+ }
+
+out:
+ mutex_unlock(&bp->vfdb->bulletin_mutex);
+ return rc;
+}
+
+int bnx2x_set_vf_link_state(struct net_device *dev, int idx, int link_state)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ struct bnx2x_virtf *vf = BP_VF(bp, idx);
+
+ if (!vf)
+ return -EINVAL;
+
+ if (vf->link_cfg == link_state)
+ return 0; /* nothing todo */
+
+ vf->link_cfg = link_state;
+
+ return bnx2x_iov_link_update_vf(bp, idx);
+}
+
+void bnx2x_iov_link_update(struct bnx2x *bp)
+{
+ int vfid;
+
+ if (!IS_SRIOV(bp))
+ return;
+
+ for_each_vf(bp, vfid)
+ bnx2x_iov_link_update_vf(bp, vfid);
+}
+
/* called by bnx2x_nic_load */
int bnx2x_iov_nic_init(struct bnx2x *bp)
{
@@ -2510,22 +2617,23 @@ void bnx2x_disable_sriov(struct bnx2x *bp)
pci_disable_sriov(bp->pdev);
}
-static int bnx2x_vf_ndo_prep(struct bnx2x *bp, int vfidx,
- struct bnx2x_virtf **vf,
- struct pf_vf_bulletin_content **bulletin)
+static int bnx2x_vf_op_prep(struct bnx2x *bp, int vfidx,
+ struct bnx2x_virtf **vf,
+ struct pf_vf_bulletin_content **bulletin,
+ bool test_queue)
{
if (bp->state != BNX2X_STATE_OPEN) {
- BNX2X_ERR("vf ndo called though PF is down\n");
+ BNX2X_ERR("PF is down - can't utilize iov-related functionality\n");
return -EINVAL;
}
if (!IS_SRIOV(bp)) {
- BNX2X_ERR("vf ndo called though sriov is disabled\n");
+ BNX2X_ERR("sriov is disabled - can't utilize iov-realted functionality\n");
return -EINVAL;
}
if (vfidx >= BNX2X_NR_VIRTFN(bp)) {
- BNX2X_ERR("vf ndo called for uninitialized VF. vfidx was %d BNX2X_NR_VIRTFN was %d\n",
+ BNX2X_ERR("VF is uninitialized - can't utilize iov-related functionality. vfidx was %d BNX2X_NR_VIRTFN was %d\n",
vfidx, BNX2X_NR_VIRTFN(bp));
return -EINVAL;
}
@@ -2535,19 +2643,18 @@ static int bnx2x_vf_ndo_prep(struct bnx2x *bp, int vfidx,
*bulletin = BP_VF_BULLETIN(bp, vfidx);
if (!*vf) {
- BNX2X_ERR("vf ndo called but vf struct is null. vfidx was %d\n",
- vfidx);
+ BNX2X_ERR("Unable to get VF structure for vfidx %d\n", vfidx);
return -EINVAL;
}
- if (!(*vf)->vfqs) {
- BNX2X_ERR("vf ndo called but vfqs struct is null. Was ndo invoked before dynamically enabling SR-IOV? vfidx was %d\n",
+ if (test_queue && !(*vf)->vfqs) {
+ BNX2X_ERR("vfqs struct is null. Was this invoked before dynamically enabling SR-IOV? vfidx was %d\n",
vfidx);
return -EINVAL;
}
if (!*bulletin) {
- BNX2X_ERR("vf ndo called but Bulletin Board struct is null. vfidx was %d\n",
+ BNX2X_ERR("Bulletin Board struct is null for vfidx %d\n",
vfidx);
return -EINVAL;
}
@@ -2566,9 +2673,10 @@ int bnx2x_get_vf_config(struct net_device *dev, int vfidx,
int rc;
/* sanity and init */
- rc = bnx2x_vf_ndo_prep(bp, vfidx, &vf, &bulletin);
+ rc = bnx2x_vf_op_prep(bp, vfidx, &vf, &bulletin, true);
if (rc)
return rc;
+
mac_obj = &bnx2x_leading_vfq(vf, mac_obj);
vlan_obj = &bnx2x_leading_vfq(vf, vlan_obj);
if (!mac_obj || !vlan_obj) {
@@ -2591,6 +2699,7 @@ int bnx2x_get_vf_config(struct net_device *dev, int vfidx,
VLAN_HLEN);
}
} else {
+ mutex_lock(&bp->vfdb->bulletin_mutex);
/* mac */
if (bulletin->valid_bitmap & (1 << MAC_ADDR_VALID))
/* mac configured by ndo so its in bulletin board */
@@ -2606,6 +2715,8 @@ int bnx2x_get_vf_config(struct net_device *dev, int vfidx,
else
/* function has not been loaded yet. Show vlans as 0s */
memset(&ivi->vlan, 0, VLAN_HLEN);
+
+ mutex_unlock(&bp->vfdb->bulletin_mutex);
}
return 0;
@@ -2635,15 +2746,18 @@ int bnx2x_set_vf_mac(struct net_device *dev, int vfidx, u8 *mac)
struct bnx2x_virtf *vf = NULL;
struct pf_vf_bulletin_content *bulletin = NULL;
- /* sanity and init */
- rc = bnx2x_vf_ndo_prep(bp, vfidx, &vf, &bulletin);
- if (rc)
- return rc;
if (!is_valid_ether_addr(mac)) {
BNX2X_ERR("mac address invalid\n");
return -EINVAL;
}
+ /* sanity and init */
+ rc = bnx2x_vf_op_prep(bp, vfidx, &vf, &bulletin, true);
+ if (rc)
+ return rc;
+
+ mutex_lock(&bp->vfdb->bulletin_mutex);
+
/* update PF's copy of the VF's bulletin. Will no longer accept mac
* configuration requests from vf unless match this mac
*/
@@ -2652,6 +2766,10 @@ int bnx2x_set_vf_mac(struct net_device *dev, int vfidx, u8 *mac)
/* Post update on VF's bulletin board */
rc = bnx2x_post_vf_bulletin(bp, vfidx);
+
+ /* release lock before checking return code */
+ mutex_unlock(&bp->vfdb->bulletin_mutex);
+
if (rc) {
BNX2X_ERR("failed to update VF[%d] bulletin\n", vfidx);
return rc;
@@ -2716,11 +2834,6 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos)
unsigned long accept_flags;
int rc;
- /* sanity and init */
- rc = bnx2x_vf_ndo_prep(bp, vfidx, &vf, &bulletin);
- if (rc)
- return rc;
-
if (vlan > 4095) {
BNX2X_ERR("illegal vlan value %d\n", vlan);
return -EINVAL;
@@ -2729,18 +2842,27 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos)
DP(BNX2X_MSG_IOV, "configuring VF %d with VLAN %d qos %d\n",
vfidx, vlan, 0);
+ /* sanity and init */
+ rc = bnx2x_vf_op_prep(bp, vfidx, &vf, &bulletin, true);
+ if (rc)
+ return rc;
+
/* update PF's copy of the VF's bulletin. No point in posting the vlan
* to the VF since it doesn't have anything to do with it. But it useful
* to store it here in case the VF is not up yet and we can only
* configure the vlan later when it does. Treat vlan id 0 as remove the
* Host tag.
*/
+ mutex_lock(&bp->vfdb->bulletin_mutex);
+
if (vlan > 0)
bulletin->valid_bitmap |= 1 << VLAN_VALID;
else
bulletin->valid_bitmap &= ~(1 << VLAN_VALID);
bulletin->vlan = vlan;
+ mutex_unlock(&bp->vfdb->bulletin_mutex);
+
/* is vf initialized and queue set up? */
if (vf->state != VF_ENABLED ||
bnx2x_get_q_logical_state(bp, &bnx2x_leading_vfq(vf, sp_obj)) !=
@@ -2850,10 +2972,9 @@ out:
* entire bulletin board excluding the crc field itself. Use the length field
* as the Bulletin Board was posted by a PF with possibly a different version
* from the vf which will sample it. Therefore, the length is computed by the
- * PF and the used blindly by the VF.
+ * PF and then used blindly by the VF.
*/
-u32 bnx2x_crc_vf_bulletin(struct bnx2x *bp,
- struct pf_vf_bulletin_content *bulletin)
+u32 bnx2x_crc_vf_bulletin(struct pf_vf_bulletin_content *bulletin)
{
return crc32(BULLETIN_CRC_SEED,
((u8 *)bulletin) + sizeof(bulletin->crc),
@@ -2863,47 +2984,74 @@ u32 bnx2x_crc_vf_bulletin(struct bnx2x *bp,
/* Check for new posts on the bulletin board */
enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp)
{
- struct pf_vf_bulletin_content bulletin = bp->pf2vf_bulletin->content;
+ struct pf_vf_bulletin_content *bulletin;
int attempts;
- /* bulletin board hasn't changed since last sample */
- if (bp->old_bulletin.version == bulletin.version)
- return PFVF_BULLETIN_UNCHANGED;
+ /* sampling structure in mid post may result with corrupted data
+ * validate crc to ensure coherency.
+ */
+ for (attempts = 0; attempts < BULLETIN_ATTEMPTS; attempts++) {
+ u32 crc;
- /* validate crc of new bulletin board */
- if (bp->old_bulletin.version != bp->pf2vf_bulletin->content.version) {
- /* sampling structure in mid post may result with corrupted data
- * validate crc to ensure coherency.
- */
- for (attempts = 0; attempts < BULLETIN_ATTEMPTS; attempts++) {
- bulletin = bp->pf2vf_bulletin->content;
- if (bulletin.crc == bnx2x_crc_vf_bulletin(bp,
- &bulletin))
- break;
- BNX2X_ERR("bad crc on bulletin board. Contained %x computed %x\n",
- bulletin.crc,
- bnx2x_crc_vf_bulletin(bp, &bulletin));
- }
- if (attempts >= BULLETIN_ATTEMPTS) {
- BNX2X_ERR("pf to vf bulletin board crc was wrong %d consecutive times. Aborting\n",
- attempts);
- return PFVF_BULLETIN_CRC_ERR;
- }
+ /* sample the bulletin board */
+ memcpy(&bp->shadow_bulletin, bp->pf2vf_bulletin,
+ sizeof(union pf_vf_bulletin));
+
+ crc = bnx2x_crc_vf_bulletin(&bp->shadow_bulletin.content);
+
+ if (bp->shadow_bulletin.content.crc == crc)
+ break;
+
+ BNX2X_ERR("bad crc on bulletin board. Contained %x computed %x\n",
+ bp->shadow_bulletin.content.crc, crc);
+ }
+
+ if (attempts >= BULLETIN_ATTEMPTS) {
+ BNX2X_ERR("pf to vf bulletin board crc was wrong %d consecutive times. Aborting\n",
+ attempts);
+ return PFVF_BULLETIN_CRC_ERR;
}
+ bulletin = &bp->shadow_bulletin.content;
+
+ /* bulletin board hasn't changed since last sample */
+ if (bp->old_bulletin.version == bulletin->version)
+ return PFVF_BULLETIN_UNCHANGED;
/* the mac address in bulletin board is valid and is new */
- if (bulletin.valid_bitmap & 1 << MAC_ADDR_VALID &&
- !ether_addr_equal(bulletin.mac, bp->old_bulletin.mac)) {
+ if (bulletin->valid_bitmap & 1 << MAC_ADDR_VALID &&
+ !ether_addr_equal(bulletin->mac, bp->old_bulletin.mac)) {
/* update new mac to net device */
- memcpy(bp->dev->dev_addr, bulletin.mac, ETH_ALEN);
+ memcpy(bp->dev->dev_addr, bulletin->mac, ETH_ALEN);
+ }
+
+ if (bulletin->valid_bitmap & (1 << LINK_VALID)) {
+ DP(BNX2X_MSG_IOV, "link update speed %d flags %x\n",
+ bulletin->link_speed, bulletin->link_flags);
+
+ bp->vf_link_vars.line_speed = bulletin->link_speed;
+ bp->vf_link_vars.link_report_flags = 0;
+ /* Link is down */
+ if (bulletin->link_flags & VFPF_LINK_REPORT_LINK_DOWN)
+ __set_bit(BNX2X_LINK_REPORT_LINK_DOWN,
+ &bp->vf_link_vars.link_report_flags);
+ /* Full DUPLEX */
+ if (bulletin->link_flags & VFPF_LINK_REPORT_FULL_DUPLEX)
+ __set_bit(BNX2X_LINK_REPORT_FD,
+ &bp->vf_link_vars.link_report_flags);
+ /* Rx Flow Control is ON */
+ if (bulletin->link_flags & VFPF_LINK_REPORT_RX_FC_ON)
+ __set_bit(BNX2X_LINK_REPORT_RX_FC_ON,
+ &bp->vf_link_vars.link_report_flags);
+ /* Tx Flow Control is ON */
+ if (bulletin->link_flags & VFPF_LINK_REPORT_TX_FC_ON)
+ __set_bit(BNX2X_LINK_REPORT_TX_FC_ON,
+ &bp->vf_link_vars.link_report_flags);
+ __bnx2x_link_report(bp);
}
- /* the vlan in bulletin board is valid and is new */
- if (bulletin.valid_bitmap & 1 << VLAN_VALID)
- memcpy(&bulletin.vlan, &bp->old_bulletin.vlan, VLAN_HLEN);
-
/* copy new bulletin board to bp */
- bp->old_bulletin = bulletin;
+ memcpy(&bp->old_bulletin, bulletin,
+ sizeof(struct pf_vf_bulletin_content));
return PFVF_BULLETIN_UPDATED;
}
@@ -2948,6 +3096,8 @@ int bnx2x_vf_pci_alloc(struct bnx2x *bp)
if (!bp->pf2vf_bulletin)
goto alloc_mem_err;
+ bnx2x_vf_bulletin_finalize(&bp->pf2vf_bulletin->content, true);
+
return 0;
alloc_mem_err:
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
index 96c575e147a5..ca1055f3d8af 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
@@ -126,7 +126,11 @@ struct bnx2x_virtf {
#define VF_CACHE_LINE 0x0010
#define VF_CFG_VLAN 0x0020
#define VF_CFG_STATS_COALESCE 0x0040
-
+#define VF_CFG_EXT_BULLETIN 0x0080
+ u8 link_cfg; /* IFLA_VF_LINK_STATE_AUTO
+ * IFLA_VF_LINK_STATE_ENABLE
+ * IFLA_VF_LINK_STATE_DISABLE
+ */
u8 state;
#define VF_FREE 0 /* VF ready to be acquired holds no resc */
#define VF_ACQUIRED 1 /* VF acquired, but not initialized */
@@ -295,22 +299,22 @@ struct bnx2x_vfdb {
#define BP_VFDB(bp) ((bp)->vfdb)
/* vf array */
struct bnx2x_virtf *vfs;
-#define BP_VF(bp, idx) (&((bp)->vfdb->vfs[(idx)]))
-#define bnx2x_vf(bp, idx, var) ((bp)->vfdb->vfs[(idx)].var)
+#define BP_VF(bp, idx) (&((bp)->vfdb->vfs[idx]))
+#define bnx2x_vf(bp, idx, var) ((bp)->vfdb->vfs[idx].var)
/* queue array - for all vfs */
struct bnx2x_vf_queue *vfqs;
/* vf HW contexts */
struct hw_dma context[BNX2X_VF_CIDS/ILT_PAGE_CIDS];
-#define BP_VF_CXT_PAGE(bp, i) (&(bp)->vfdb->context[(i)])
+#define BP_VF_CXT_PAGE(bp, i) (&(bp)->vfdb->context[i])
/* SR-IOV information */
struct bnx2x_sriov sriov;
struct hw_dma mbx_dma;
#define BP_VF_MBX_DMA(bp) (&((bp)->vfdb->mbx_dma))
struct bnx2x_vf_mbx mbxs[BNX2X_MAX_NUM_OF_VFS];
-#define BP_VF_MBX(bp, vfid) (&((bp)->vfdb->mbxs[(vfid)]))
+#define BP_VF_MBX(bp, vfid) (&((bp)->vfdb->mbxs[vfid]))
struct hw_dma bulletin_dma;
#define BP_VF_BULLETIN_DMA(bp) (&((bp)->vfdb->bulletin_dma))
@@ -336,6 +340,9 @@ struct bnx2x_vfdb {
/* sp_rtnl synchronization */
struct mutex event_mutex;
u64 event_occur;
+
+ /* bulletin board update synchronization */
+ struct mutex bulletin_mutex;
};
/* queue access */
@@ -467,9 +474,10 @@ void bnx2x_vf_handle_flr_event(struct bnx2x *bp);
bool bnx2x_tlv_supported(u16 tlvtype);
-u32 bnx2x_crc_vf_bulletin(struct bnx2x *bp,
- struct pf_vf_bulletin_content *bulletin);
+u32 bnx2x_crc_vf_bulletin(struct pf_vf_bulletin_content *bulletin);
int bnx2x_post_vf_bulletin(struct bnx2x *bp, int vf);
+void bnx2x_vf_bulletin_finalize(struct pf_vf_bulletin_content *bulletin,
+ bool support_long);
enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp);
@@ -520,6 +528,11 @@ void bnx2x_iov_task(struct work_struct *work);
void bnx2x_schedule_iov_task(struct bnx2x *bp, enum bnx2x_iov_flag flag);
+void bnx2x_iov_link_update(struct bnx2x *bp);
+int bnx2x_iov_link_update_vf(struct bnx2x *bp, int idx);
+
+int bnx2x_set_vf_link_state(struct net_device *dev, int vf, int link_state);
+
#else /* CONFIG_BNX2X_SRIOV */
static inline void bnx2x_iov_set_queue_sp_obj(struct bnx2x *bp, int vf_cid,
@@ -579,6 +592,14 @@ static inline void bnx2x_iov_channel_down(struct bnx2x *bp) {}
static inline void bnx2x_iov_task(struct work_struct *work) {}
static inline void bnx2x_schedule_iov_task(struct bnx2x *bp, enum bnx2x_iov_flag flag) {}
+static inline void bnx2x_iov_link_update(struct bnx2x *bp) {}
+static inline int bnx2x_iov_link_update_vf(struct bnx2x *bp, int idx) {return 0; }
+
+static inline int bnx2x_set_vf_link_state(struct net_device *dev, int vf,
+ int link_state) {return 0; }
+struct pf_vf_bulletin_content;
+static inline void bnx2x_vf_bulletin_finalize(struct pf_vf_bulletin_content *bulletin,
+ bool support_long) {}
#endif /* CONFIG_BNX2X_SRIOV */
#endif /* bnx2x_sriov.h */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
index d712d0ddd719..54e0427a9ee6 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
@@ -251,6 +251,9 @@ int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count)
bnx2x_add_tlv(bp, req, req->first_tlv.tl.length,
CHANNEL_TLV_PHYS_PORT_ID, sizeof(struct channel_tlv));
+ /* Bulletin support for bulletin board with length > legacy length */
+ req->vfdev_info.caps |= VF_CAP_SUPPORT_EXT_BULLETIN;
+
/* add list termination tlv */
bnx2x_add_tlv(bp, req,
req->first_tlv.tl.length + sizeof(struct channel_tlv),
@@ -1232,6 +1235,41 @@ static void bnx2x_vf_mbx_acquire_resp(struct bnx2x *bp, struct bnx2x_virtf *vf,
bnx2x_vf_mbx_resp_send_msg(bp, vf, vfop_status);
}
+static bool bnx2x_vf_mbx_is_windows_vm(struct bnx2x *bp,
+ struct vfpf_acquire_tlv *acquire)
+{
+ /* Windows driver does one of three things:
+ * 1. Old driver doesn't have bulletin board address set.
+ * 2. 'Middle' driver sends mc_num == 32.
+ * 3. New driver sets the OS field.
+ */
+ if (!acquire->bulletin_addr ||
+ acquire->resc_request.num_mc_filters == 32 ||
+ ((acquire->vfdev_info.vf_os & VF_OS_MASK) ==
+ VF_OS_WINDOWS))
+ return true;
+
+ return false;
+}
+
+static int bnx2x_vf_mbx_acquire_chk_dorq(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vf_mbx *mbx)
+{
+ /* Linux drivers which correctly set the doorbell size also
+ * send a physical port request
+ */
+ if (bnx2x_search_tlv_list(bp, &mbx->msg->req,
+ CHANNEL_TLV_PHYS_PORT_ID))
+ return 0;
+
+ /* Issue does not exist in windows VMs */
+ if (bnx2x_vf_mbx_is_windows_vm(bp, &mbx->msg->req.acquire))
+ return 0;
+
+ return -EOPNOTSUPP;
+}
+
static void bnx2x_vf_mbx_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf,
struct bnx2x_vf_mbx *mbx)
{
@@ -1247,12 +1285,32 @@ static void bnx2x_vf_mbx_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf,
acquire->resc_request.num_vlan_filters,
acquire->resc_request.num_mc_filters);
+ /* Prevent VFs with old drivers from loading, since they calculate
+ * CIDs incorrectly requiring a VF-flr [VM reboot] in order to recover
+ * while being upgraded.
+ */
+ rc = bnx2x_vf_mbx_acquire_chk_dorq(bp, vf, mbx);
+ if (rc) {
+ DP(BNX2X_MSG_IOV,
+ "VF [%d] - Can't support acquire request due to doorbell mismatch. Please update VM driver\n",
+ vf->abs_vfid);
+ goto out;
+ }
+
/* acquire the resources */
rc = bnx2x_vf_acquire(bp, vf, &acquire->resc_request);
/* store address of vf's bulletin board */
vf->bulletin_map = acquire->bulletin_addr;
+ if (acquire->vfdev_info.caps & VF_CAP_SUPPORT_EXT_BULLETIN) {
+ DP(BNX2X_MSG_IOV, "VF[%d] supports long bulletin boards\n",
+ vf->abs_vfid);
+ vf->cfg_flags |= VF_CFG_EXT_BULLETIN;
+ } else {
+ vf->cfg_flags &= ~VF_CFG_EXT_BULLETIN;
+ }
+out:
/* response */
bnx2x_vf_mbx_acquire_resp(bp, vf, mbx, rc);
}
@@ -1273,6 +1331,10 @@ static void bnx2x_vf_mbx_init_vf(struct bnx2x *bp, struct bnx2x_virtf *vf,
if (init->flags & VFPF_INIT_FLG_STATS_COALESCE)
vf->cfg_flags |= VF_CFG_STATS_COALESCE;
+ /* Update VF's view of link state */
+ if (vf->cfg_flags & VF_CFG_EXT_BULLETIN)
+ bnx2x_iov_link_update_vf(bp, vf->index);
+
/* response */
bnx2x_vf_mbx_resp(bp, vf, rc);
}
@@ -2007,6 +2069,17 @@ void bnx2x_vf_mbx(struct bnx2x *bp)
}
}
+void bnx2x_vf_bulletin_finalize(struct pf_vf_bulletin_content *bulletin,
+ bool support_long)
+{
+ /* Older VFs contain a bug where they can't check CRC for bulletin
+ * boards of length greater than legacy size.
+ */
+ bulletin->length = support_long ? BULLETIN_CONTENT_SIZE :
+ BULLETIN_CONTENT_LEGACY_SIZE;
+ bulletin->crc = bnx2x_crc_vf_bulletin(bulletin);
+}
+
/* propagate local bulletin board to vf */
int bnx2x_post_vf_bulletin(struct bnx2x *bp, int vf)
{
@@ -2023,8 +2096,9 @@ int bnx2x_post_vf_bulletin(struct bnx2x *bp, int vf)
/* increment bulletin board version and compute crc */
bulletin->version++;
- bulletin->length = BULLETIN_CONTENT_SIZE;
- bulletin->crc = bnx2x_crc_vf_bulletin(bp, bulletin);
+ bnx2x_vf_bulletin_finalize(bulletin,
+ (bnx2x_vf(bp, vf, cfg_flags) &
+ VF_CFG_EXT_BULLETIN) ? true : false);
/* propagate bulletin board via dmae to vm memory */
rc = bnx2x_copy32_vf_dmae(bp, false, pf_addr,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h
index e21e706762c9..15670c499a20 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h
@@ -65,6 +65,7 @@ struct hw_sb_info {
#define VFPF_RX_MASK_ACCEPT_ALL_MULTICAST 0x00000008
#define VFPF_RX_MASK_ACCEPT_BROADCAST 0x00000010
#define BULLETIN_CONTENT_SIZE (sizeof(struct pf_vf_bulletin_content))
+#define BULLETIN_CONTENT_LEGACY_SIZE (32)
#define BULLETIN_ATTEMPTS 5 /* crc failures before throwing towel */
#define BULLETIN_CRC_SEED 0
@@ -117,7 +118,15 @@ struct vfpf_acquire_tlv {
/* the following fields are for debug purposes */
u8 vf_id; /* ME register value */
u8 vf_os; /* e.g. Linux, W2K8 */
- u8 padding[2];
+#define VF_OS_SUBVERSION_MASK (0x1f)
+#define VF_OS_MASK (0xe0)
+#define VF_OS_SHIFT (5)
+#define VF_OS_UNDEFINED (0 << VF_OS_SHIFT)
+#define VF_OS_WINDOWS (1 << VF_OS_SHIFT)
+
+ u8 padding;
+ u8 caps;
+#define VF_CAP_SUPPORT_EXT_BULLETIN (1 << 0)
} vfdev_info;
struct vf_pf_resc_request resc_request;
@@ -393,11 +402,23 @@ struct pf_vf_bulletin_content {
* to attempt to send messages on the
* channel after this bit is set
*/
+#define LINK_VALID 3 /* alert the VF thet a new link status
+ * update is available for it
+ */
u8 mac[ETH_ALEN];
u8 mac_padding[2];
u16 vlan;
u8 vlan_padding[6];
+
+ u16 link_speed; /* Effective line speed */
+ u8 link_speed_padding[6];
+ u32 link_flags; /* VFPF_LINK_REPORT_XXX flags */
+#define VFPF_LINK_REPORT_LINK_DOWN (1 << 0)
+#define VFPF_LINK_REPORT_FULL_DUPLEX (1 << 1)
+#define VFPF_LINK_REPORT_RX_FC_ON (1 << 2)
+#define VFPF_LINK_REPORT_TX_FC_ON (1 << 3)
+ u8 link_flags_padding[4];
};
union pf_vf_bulletin {
diff --git a/drivers/net/ethernet/broadcom/cnic.c b/drivers/net/ethernet/broadcom/cnic.c
index 8244e2b14bb4..27861a6c7ca5 100644
--- a/drivers/net/ethernet/broadcom/cnic.c
+++ b/drivers/net/ethernet/broadcom/cnic.c
@@ -1,13 +1,15 @@
-/* cnic.c: Broadcom CNIC core network driver.
+/* cnic.c: QLogic CNIC core network driver.
*
* Copyright (c) 2006-2014 Broadcom Corporation
+ * Copyright (c) 2014 QLogic Corporation
*
* 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 Free Software Foundation.
*
* Original skeleton written by: John(Zongxi) Chen (zongxi@broadcom.com)
- * Modified and maintained by: Michael Chan <mchan@broadcom.com>
+ * Previously modified and maintained by: Michael Chan <mchan@broadcom.com>
+ * Maintained By: Dept-HSGLinuxNICDev@qlogic.com
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -56,11 +58,11 @@
#define CNIC_MODULE_NAME "cnic"
static char version[] =
- "Broadcom NetXtreme II CNIC Driver " CNIC_MODULE_NAME " v" CNIC_MODULE_VERSION " (" CNIC_MODULE_RELDATE ")\n";
+ "QLogic NetXtreme II CNIC Driver " CNIC_MODULE_NAME " v" CNIC_MODULE_VERSION " (" CNIC_MODULE_RELDATE ")\n";
MODULE_AUTHOR("Michael Chan <mchan@broadcom.com> and John(Zongxi) "
"Chen (zongxi@broadcom.com");
-MODULE_DESCRIPTION("Broadcom NetXtreme II CNIC Driver");
+MODULE_DESCRIPTION("QLogic NetXtreme II CNIC Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(CNIC_MODULE_VERSION);
diff --git a/drivers/net/ethernet/broadcom/cnic.h b/drivers/net/ethernet/broadcom/cnic.h
index d535ae4228b4..4baea81bae7a 100644
--- a/drivers/net/ethernet/broadcom/cnic.h
+++ b/drivers/net/ethernet/broadcom/cnic.h
@@ -1,6 +1,7 @@
-/* cnic.h: Broadcom CNIC core network driver.
+/* cnic.h: QLogic CNIC core network driver.
*
* Copyright (c) 2006-2014 Broadcom Corporation
+ * Copyright (c) 2014 QLogic Corporation
*
* 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
diff --git a/drivers/net/ethernet/broadcom/cnic_defs.h b/drivers/net/ethernet/broadcom/cnic_defs.h
index dcbca6997e8f..b38499774071 100644
--- a/drivers/net/ethernet/broadcom/cnic_defs.h
+++ b/drivers/net/ethernet/broadcom/cnic_defs.h
@@ -1,7 +1,8 @@
-/* cnic.c: Broadcom CNIC core network driver.
+/* cnic.c: QLogic CNIC core network driver.
*
* Copyright (c) 2006-2014 Broadcom Corporation
+ * Copyright (c) 2014 QLogic Corporation
*
* 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
diff --git a/drivers/net/ethernet/broadcom/cnic_if.h b/drivers/net/ethernet/broadcom/cnic_if.h
index 5f4d5573a73d..8bb36c1c4d68 100644
--- a/drivers/net/ethernet/broadcom/cnic_if.h
+++ b/drivers/net/ethernet/broadcom/cnic_if.h
@@ -1,6 +1,7 @@
-/* cnic_if.h: Broadcom CNIC core network driver.
+/* cnic_if.h: QLogic CNIC core network driver.
*
* Copyright (c) 2006-2014 Broadcom Corporation
+ * Copyright (c) 2014 QLogic Corporation
*
* 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
diff --git a/drivers/net/ethernet/broadcom/genet/Makefile b/drivers/net/ethernet/broadcom/genet/Makefile
index 31f55a90a197..9b6885efa9e7 100644
--- a/drivers/net/ethernet/broadcom/genet/Makefile
+++ b/drivers/net/ethernet/broadcom/genet/Makefile
@@ -1,2 +1,2 @@
obj-$(CONFIG_BCMGENET) += genet.o
-genet-objs := bcmgenet.o bcmmii.o
+genet-objs := bcmgenet.o bcmmii.o bcmgenet_wol.o
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 5ba1cfbd60da..3f9d4de8173c 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -6,15 +6,6 @@
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#define pr_fmt(fmt) "bcmgenet: " fmt
@@ -79,13 +70,13 @@
TOTAL_DESC * DMA_DESC_SIZE)
static inline void dmadesc_set_length_status(struct bcmgenet_priv *priv,
- void __iomem *d, u32 value)
+ void __iomem *d, u32 value)
{
__raw_writel(value, d + DMA_DESC_LENGTH_STATUS);
}
static inline u32 dmadesc_get_length_status(struct bcmgenet_priv *priv,
- void __iomem *d)
+ void __iomem *d)
{
return __raw_readl(d + DMA_DESC_LENGTH_STATUS);
}
@@ -98,7 +89,7 @@ static inline void dmadesc_set_addr(struct bcmgenet_priv *priv,
/* Register writes to GISB bus can take couple hundred nanoseconds
* and are done for each packet, save these expensive writes unless
- * the platform is explicitely configured for 64-bits/LPAE.
+ * the platform is explicitly configured for 64-bits/LPAE.
*/
#ifdef CONFIG_PHYS_ADDR_T_64BIT
if (priv->hw_params->flags & GENET_HAS_40BITS)
@@ -108,7 +99,7 @@ static inline void dmadesc_set_addr(struct bcmgenet_priv *priv,
/* Combined address + length/status setter */
static inline void dmadesc_set(struct bcmgenet_priv *priv,
- void __iomem *d, dma_addr_t addr, u32 val)
+ void __iomem *d, dma_addr_t addr, u32 val)
{
dmadesc_set_length_status(priv, d, val);
dmadesc_set_addr(priv, d, addr);
@@ -123,7 +114,7 @@ static inline dma_addr_t dmadesc_get_addr(struct bcmgenet_priv *priv,
/* Register writes to GISB bus can take couple hundred nanoseconds
* and are done for each packet, save these expensive writes unless
- * the platform is explicitely configured for 64-bits/LPAE.
+ * the platform is explicitly configured for 64-bits/LPAE.
*/
#ifdef CONFIG_PHYS_ADDR_T_64BIT
if (priv->hw_params->flags & GENET_HAS_40BITS)
@@ -242,7 +233,7 @@ static inline struct bcmgenet_priv *dev_to_priv(struct device *dev)
}
static inline u32 bcmgenet_tdma_readl(struct bcmgenet_priv *priv,
- enum dma_reg r)
+ enum dma_reg r)
{
return __raw_readl(priv->base + GENET_TDMA_REG_OFF +
DMA_RINGS_SIZE + bcmgenet_dma_regs[r]);
@@ -256,7 +247,7 @@ static inline void bcmgenet_tdma_writel(struct bcmgenet_priv *priv,
}
static inline u32 bcmgenet_rdma_readl(struct bcmgenet_priv *priv,
- enum dma_reg r)
+ enum dma_reg r)
{
return __raw_readl(priv->base + GENET_RDMA_REG_OFF +
DMA_RINGS_SIZE + bcmgenet_dma_regs[r]);
@@ -333,8 +324,8 @@ static const u8 genet_dma_ring_regs_v123[] = {
static const u8 *genet_dma_ring_regs;
static inline u32 bcmgenet_tdma_ring_readl(struct bcmgenet_priv *priv,
- unsigned int ring,
- enum dma_ring_reg r)
+ unsigned int ring,
+ enum dma_ring_reg r)
{
return __raw_readl(priv->base + GENET_TDMA_REG_OFF +
(DMA_RING_SIZE * ring) +
@@ -342,9 +333,8 @@ static inline u32 bcmgenet_tdma_ring_readl(struct bcmgenet_priv *priv,
}
static inline void bcmgenet_tdma_ring_writel(struct bcmgenet_priv *priv,
- unsigned int ring,
- u32 val,
- enum dma_ring_reg r)
+ unsigned int ring, u32 val,
+ enum dma_ring_reg r)
{
__raw_writel(val, priv->base + GENET_TDMA_REG_OFF +
(DMA_RING_SIZE * ring) +
@@ -352,8 +342,8 @@ static inline void bcmgenet_tdma_ring_writel(struct bcmgenet_priv *priv,
}
static inline u32 bcmgenet_rdma_ring_readl(struct bcmgenet_priv *priv,
- unsigned int ring,
- enum dma_ring_reg r)
+ unsigned int ring,
+ enum dma_ring_reg r)
{
return __raw_readl(priv->base + GENET_RDMA_REG_OFF +
(DMA_RING_SIZE * ring) +
@@ -361,9 +351,8 @@ static inline u32 bcmgenet_rdma_ring_readl(struct bcmgenet_priv *priv,
}
static inline void bcmgenet_rdma_ring_writel(struct bcmgenet_priv *priv,
- unsigned int ring,
- u32 val,
- enum dma_ring_reg r)
+ unsigned int ring, u32 val,
+ enum dma_ring_reg r)
{
__raw_writel(val, priv->base + GENET_RDMA_REG_OFF +
(DMA_RING_SIZE * ring) +
@@ -371,7 +360,7 @@ static inline void bcmgenet_rdma_ring_writel(struct bcmgenet_priv *priv,
}
static int bcmgenet_get_settings(struct net_device *dev,
- struct ethtool_cmd *cmd)
+ struct ethtool_cmd *cmd)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
@@ -385,7 +374,7 @@ static int bcmgenet_get_settings(struct net_device *dev,
}
static int bcmgenet_set_settings(struct net_device *dev,
- struct ethtool_cmd *cmd)
+ struct ethtool_cmd *cmd)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
@@ -458,7 +447,7 @@ static int bcmgenet_set_tx_csum(struct net_device *dev,
}
static int bcmgenet_set_features(struct net_device *dev,
- netdev_features_t features)
+ netdev_features_t features)
{
netdev_features_t changed = features ^ dev->features;
netdev_features_t wanted = dev->wanted_features;
@@ -625,12 +614,11 @@ static const struct bcmgenet_stats bcmgenet_gstrings_stats[] = {
#define BCMGENET_STATS_LEN ARRAY_SIZE(bcmgenet_gstrings_stats)
static void bcmgenet_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
+ struct ethtool_drvinfo *info)
{
strlcpy(info->driver, "bcmgenet", sizeof(info->driver));
strlcpy(info->version, "v2.0", sizeof(info->version));
info->n_stats = BCMGENET_STATS_LEN;
-
}
static int bcmgenet_get_sset_count(struct net_device *dev, int string_set)
@@ -643,8 +631,8 @@ static int bcmgenet_get_sset_count(struct net_device *dev, int string_set)
}
}
-static void bcmgenet_get_strings(struct net_device *dev,
- u32 stringset, u8 *data)
+static void bcmgenet_get_strings(struct net_device *dev, u32 stringset,
+ u8 *data)
{
int i;
@@ -652,8 +640,8 @@ static void bcmgenet_get_strings(struct net_device *dev,
case ETH_SS_STATS:
for (i = 0; i < BCMGENET_STATS_LEN; i++) {
memcpy(data + i * ETH_GSTRING_LEN,
- bcmgenet_gstrings_stats[i].stat_string,
- ETH_GSTRING_LEN);
+ bcmgenet_gstrings_stats[i].stat_string,
+ ETH_GSTRING_LEN);
}
break;
}
@@ -678,8 +666,8 @@ static void bcmgenet_update_mib_counters(struct bcmgenet_priv *priv)
case BCMGENET_STAT_RUNT:
if (s->type != BCMGENET_STAT_MIB_RX)
offset = BCMGENET_STAT_OFFSET;
- val = bcmgenet_umac_readl(priv, UMAC_MIB_START +
- j + offset);
+ val = bcmgenet_umac_readl(priv,
+ UMAC_MIB_START + j + offset);
break;
case BCMGENET_STAT_MISC:
val = bcmgenet_umac_readl(priv, s->reg_offset);
@@ -696,8 +684,8 @@ static void bcmgenet_update_mib_counters(struct bcmgenet_priv *priv)
}
static void bcmgenet_get_ethtool_stats(struct net_device *dev,
- struct ethtool_stats *stats,
- u64 *data)
+ struct ethtool_stats *stats,
+ u64 *data)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
int i;
@@ -730,6 +718,8 @@ static struct ethtool_ops bcmgenet_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_msglevel = bcmgenet_get_msglevel,
.set_msglevel = bcmgenet_set_msglevel,
+ .get_wol = bcmgenet_get_wol,
+ .set_wol = bcmgenet_set_wol,
};
/* Power down the unimac, based on mode. */
@@ -743,9 +733,12 @@ static void bcmgenet_power_down(struct bcmgenet_priv *priv,
phy_detach(priv->phydev);
break;
+ case GENET_POWER_WOL_MAGIC:
+ bcmgenet_wol_power_down_cfg(priv, mode);
+ break;
+
case GENET_POWER_PASSIVE:
/* Power down LED */
- bcmgenet_mii_reset(priv->dev);
if (priv->hw_params->flags & GENET_HAS_EXT) {
reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
reg |= (EXT_PWR_DOWN_PHY |
@@ -759,7 +752,7 @@ static void bcmgenet_power_down(struct bcmgenet_priv *priv,
}
static void bcmgenet_power_up(struct bcmgenet_priv *priv,
- enum bcmgenet_power_mode mode)
+ enum bcmgenet_power_mode mode)
{
u32 reg;
@@ -777,12 +770,17 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv,
/* enable APD */
reg |= EXT_PWR_DN_EN_LD;
break;
+ case GENET_POWER_WOL_MAGIC:
+ bcmgenet_wol_power_up_cfg(priv, mode);
+ return;
default:
break;
}
bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
- bcmgenet_mii_reset(priv->dev);
+
+ if (mode == GENET_POWER_PASSIVE)
+ bcmgenet_mii_reset(priv->dev);
}
/* ioctl handle special commands that are not present in ethtool. */
@@ -841,37 +839,37 @@ static inline void bcmgenet_tx_ring16_int_disable(struct bcmgenet_priv *priv,
struct bcmgenet_tx_ring *ring)
{
bcmgenet_intrl2_0_writel(priv,
- UMAC_IRQ_TXDMA_BDONE | UMAC_IRQ_TXDMA_PDONE,
- INTRL2_CPU_MASK_SET);
+ UMAC_IRQ_TXDMA_BDONE | UMAC_IRQ_TXDMA_PDONE,
+ INTRL2_CPU_MASK_SET);
}
static inline void bcmgenet_tx_ring16_int_enable(struct bcmgenet_priv *priv,
struct bcmgenet_tx_ring *ring)
{
bcmgenet_intrl2_0_writel(priv,
- UMAC_IRQ_TXDMA_BDONE | UMAC_IRQ_TXDMA_PDONE,
- INTRL2_CPU_MASK_CLEAR);
+ UMAC_IRQ_TXDMA_BDONE | UMAC_IRQ_TXDMA_PDONE,
+ INTRL2_CPU_MASK_CLEAR);
}
static inline void bcmgenet_tx_ring_int_enable(struct bcmgenet_priv *priv,
- struct bcmgenet_tx_ring *ring)
+ struct bcmgenet_tx_ring *ring)
{
- bcmgenet_intrl2_1_writel(priv,
- (1 << ring->index), INTRL2_CPU_MASK_CLEAR);
+ bcmgenet_intrl2_1_writel(priv, (1 << ring->index),
+ INTRL2_CPU_MASK_CLEAR);
priv->int1_mask &= ~(1 << ring->index);
}
static inline void bcmgenet_tx_ring_int_disable(struct bcmgenet_priv *priv,
struct bcmgenet_tx_ring *ring)
{
- bcmgenet_intrl2_1_writel(priv,
- (1 << ring->index), INTRL2_CPU_MASK_SET);
+ bcmgenet_intrl2_1_writel(priv, (1 << ring->index),
+ INTRL2_CPU_MASK_SET);
priv->int1_mask |= (1 << ring->index);
}
/* Unlocked version of the reclaim routine */
static void __bcmgenet_tx_reclaim(struct net_device *dev,
- struct bcmgenet_tx_ring *ring)
+ struct bcmgenet_tx_ring *ring)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
int last_tx_cn, last_c_index, num_tx_bds;
@@ -879,7 +877,7 @@ static void __bcmgenet_tx_reclaim(struct net_device *dev,
struct netdev_queue *txq;
unsigned int c_index;
- /* Compute how many buffers are transmited since last xmit call */
+ /* Compute how many buffers are transmitted since last xmit call */
c_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_CONS_INDEX);
txq = netdev_get_tx_queue(dev, ring->queue);
@@ -894,9 +892,9 @@ static void __bcmgenet_tx_reclaim(struct net_device *dev,
last_tx_cn = num_tx_bds - last_c_index + c_index;
netif_dbg(priv, tx_done, dev,
- "%s ring=%d index=%d last_tx_cn=%d last_index=%d\n",
- __func__, ring->index,
- c_index, last_tx_cn, last_c_index);
+ "%s ring=%d index=%d last_tx_cn=%d last_index=%d\n",
+ __func__, ring->index,
+ c_index, last_tx_cn, last_c_index);
/* Reclaim transmitted buffers */
while (last_tx_cn-- > 0) {
@@ -904,17 +902,17 @@ static void __bcmgenet_tx_reclaim(struct net_device *dev,
if (tx_cb_ptr->skb) {
dev->stats.tx_bytes += tx_cb_ptr->skb->len;
dma_unmap_single(&dev->dev,
- dma_unmap_addr(tx_cb_ptr, dma_addr),
- tx_cb_ptr->skb->len,
- DMA_TO_DEVICE);
+ dma_unmap_addr(tx_cb_ptr, dma_addr),
+ tx_cb_ptr->skb->len,
+ DMA_TO_DEVICE);
bcmgenet_free_cb(tx_cb_ptr);
} else if (dma_unmap_addr(tx_cb_ptr, dma_addr)) {
dev->stats.tx_bytes +=
dma_unmap_len(tx_cb_ptr, dma_len);
dma_unmap_page(&dev->dev,
- dma_unmap_addr(tx_cb_ptr, dma_addr),
- dma_unmap_len(tx_cb_ptr, dma_len),
- DMA_TO_DEVICE);
+ dma_unmap_addr(tx_cb_ptr, dma_addr),
+ dma_unmap_len(tx_cb_ptr, dma_len),
+ DMA_TO_DEVICE);
dma_unmap_addr_set(tx_cb_ptr, dma_addr, 0);
}
dev->stats.tx_packets++;
@@ -934,7 +932,7 @@ static void __bcmgenet_tx_reclaim(struct net_device *dev,
}
static void bcmgenet_tx_reclaim(struct net_device *dev,
- struct bcmgenet_tx_ring *ring)
+ struct bcmgenet_tx_ring *ring)
{
unsigned long flags;
@@ -1008,11 +1006,11 @@ static int bcmgenet_xmit_single(struct net_device *dev,
return 0;
}
-/* Transmit a SKB fragement */
+/* Transmit a SKB fragment */
static int bcmgenet_xmit_frag(struct net_device *dev,
- skb_frag_t *frag,
- u16 dma_desc_flags,
- struct bcmgenet_tx_ring *ring)
+ skb_frag_t *frag,
+ u16 dma_desc_flags,
+ struct bcmgenet_tx_ring *ring)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
struct device *kdev = &priv->pdev->dev;
@@ -1027,11 +1025,11 @@ static int bcmgenet_xmit_frag(struct net_device *dev,
tx_cb_ptr->skb = NULL;
mapping = skb_frag_dma_map(kdev, frag, 0,
- skb_frag_size(frag), DMA_TO_DEVICE);
+ skb_frag_size(frag), DMA_TO_DEVICE);
ret = dma_mapping_error(kdev, mapping);
if (ret) {
netif_err(priv, tx_err, dev, "%s: Tx DMA map failed\n",
- __func__);
+ __func__);
return ret;
}
@@ -1039,8 +1037,8 @@ static int bcmgenet_xmit_frag(struct net_device *dev,
dma_unmap_len_set(tx_cb_ptr, dma_len, frag->size);
dmadesc_set(priv, tx_cb_ptr->bd_addr, mapping,
- (frag->size << DMA_BUFLENGTH_SHIFT) | dma_desc_flags |
- (priv->hw_params->qtag_mask << DMA_TX_QTAG_SHIFT));
+ (frag->size << DMA_BUFLENGTH_SHIFT) | dma_desc_flags |
+ (priv->hw_params->qtag_mask << DMA_TX_QTAG_SHIFT));
ring->free_bds -= 1;
@@ -1103,8 +1101,9 @@ static int bcmgenet_put_tx_csum(struct net_device *dev, struct sk_buff *skb)
tx_csum_info |= STATUS_TX_CSUM_LV;
if (ip_proto == IPPROTO_UDP && ip_ver == ETH_P_IP)
tx_csum_info |= STATUS_TX_CSUM_PROTO_UDP;
- } else
+ } else {
tx_csum_info = 0;
+ }
status->tx_csum_info = tx_csum_info;
}
@@ -1144,11 +1143,16 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)
if (ring->free_bds <= nr_frags + 1) {
netif_tx_stop_queue(txq);
netdev_err(dev, "%s: tx ring %d full when queue %d awake\n",
- __func__, index, ring->queue);
+ __func__, index, ring->queue);
ret = NETDEV_TX_BUSY;
goto out;
}
+ if (skb_padto(skb, ETH_ZLEN)) {
+ ret = NETDEV_TX_OK;
+ goto out;
+ }
+
/* set the SKB transmit checksum */
if (priv->desc_64b_en) {
ret = bcmgenet_put_tx_csum(dev, skb);
@@ -1172,8 +1176,9 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)
/* xmit fragment */
for (i = 0; i < nr_frags; i++) {
ret = bcmgenet_xmit_frag(dev,
- &skb_shinfo(skb)->frags[i],
- (i == nr_frags - 1) ? DMA_EOP : 0, ring);
+ &skb_shinfo(skb)->frags[i],
+ (i == nr_frags - 1) ? DMA_EOP : 0,
+ ring);
if (ret) {
ret = NETDEV_TX_OK;
goto out;
@@ -1186,7 +1191,7 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)
* producer index, now write it down to the hardware
*/
bcmgenet_tdma_ring_writel(priv, ring->index,
- ring->prod_index, TDMA_PROD_INDEX);
+ ring->prod_index, TDMA_PROD_INDEX);
if (ring->free_bds <= (MAX_SKB_FRAGS + 1)) {
netif_tx_stop_queue(txq);
@@ -1200,16 +1205,14 @@ out:
}
-static int bcmgenet_rx_refill(struct bcmgenet_priv *priv,
- struct enet_cb *cb)
+static int bcmgenet_rx_refill(struct bcmgenet_priv *priv, struct enet_cb *cb)
{
struct device *kdev = &priv->pdev->dev;
struct sk_buff *skb;
dma_addr_t mapping;
int ret;
- skb = netdev_alloc_skb(priv->dev,
- priv->rx_buf_len + SKB_ALIGNMENT);
+ skb = netdev_alloc_skb(priv->dev, priv->rx_buf_len + SKB_ALIGNMENT);
if (!skb)
return -ENOMEM;
@@ -1217,12 +1220,12 @@ static int bcmgenet_rx_refill(struct bcmgenet_priv *priv,
WARN_ON(cb->skb != NULL);
cb->skb = skb;
mapping = dma_map_single(kdev, skb->data,
- priv->rx_buf_len, DMA_FROM_DEVICE);
+ priv->rx_buf_len, DMA_FROM_DEVICE);
ret = dma_mapping_error(kdev, mapping);
if (ret) {
bcmgenet_free_cb(cb);
netif_err(priv, rx_err, priv->dev,
- "%s DMA map failed\n", __func__);
+ "%s DMA map failed\n", __func__);
return ret;
}
@@ -1257,8 +1260,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv,
unsigned int p_index;
unsigned int chksum_ok = 0;
- p_index = bcmgenet_rdma_ring_readl(priv,
- DESC_INDEX, RDMA_PROD_INDEX);
+ p_index = bcmgenet_rdma_ring_readl(priv, DESC_INDEX, RDMA_PROD_INDEX);
p_index &= DMA_P_INDEX_MASK;
if (p_index < priv->rx_c_index)
@@ -1268,11 +1270,10 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv,
rxpkttoprocess = p_index - priv->rx_c_index;
netif_dbg(priv, rx_status, dev,
- "RDMA: rxpkttoprocess=%d\n", rxpkttoprocess);
+ "RDMA: rxpkttoprocess=%d\n", rxpkttoprocess);
while ((rxpktprocessed < rxpkttoprocess) &&
- (rxpktprocessed < budget)) {
-
+ (rxpktprocessed < budget)) {
/* Unmap the packet contents such that we can use the
* RSV from the 64 bytes descriptor when enabled and save
* a 32-bits register read
@@ -1280,15 +1281,17 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv,
cb = &priv->rx_cbs[priv->rx_read_ptr];
skb = cb->skb;
dma_unmap_single(&dev->dev, dma_unmap_addr(cb, dma_addr),
- priv->rx_buf_len, DMA_FROM_DEVICE);
+ priv->rx_buf_len, DMA_FROM_DEVICE);
if (!priv->desc_64b_en) {
- dma_length_status = dmadesc_get_length_status(priv,
- priv->rx_bds +
- (priv->rx_read_ptr *
- DMA_DESC_SIZE));
+ dma_length_status =
+ dmadesc_get_length_status(priv,
+ priv->rx_bds +
+ (priv->rx_read_ptr *
+ DMA_DESC_SIZE));
} else {
struct status_64 *status;
+
status = (struct status_64 *)skb->data;
dma_length_status = status->length_status;
}
@@ -1300,9 +1303,9 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv,
len = dma_length_status >> DMA_BUFLENGTH_SHIFT;
netif_dbg(priv, rx_status, dev,
- "%s: p_ind=%d c_ind=%d read_ptr=%d len_stat=0x%08x\n",
- __func__, p_index, priv->rx_c_index, priv->rx_read_ptr,
- dma_length_status);
+ "%s:p_ind=%d c_ind=%d read_ptr=%d len_stat=0x%08x\n",
+ __func__, p_index, priv->rx_c_index,
+ priv->rx_read_ptr, dma_length_status);
rxpktprocessed++;
@@ -1318,7 +1321,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv,
if (unlikely(!(dma_flag & DMA_EOP) || !(dma_flag & DMA_SOP))) {
netif_err(priv, rx_status, dev,
- "Droping fragmented packet!\n");
+ "dropping fragmented packet!\n");
dev->stats.rx_dropped++;
dev->stats.rx_errors++;
dev_kfree_skb_any(cb->skb);
@@ -1332,7 +1335,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv,
DMA_RX_LG |
DMA_RX_RXER))) {
netif_err(priv, rx_status, dev, "dma_flag=0x%x\n",
- (unsigned int)dma_flag);
+ (unsigned int)dma_flag);
if (dma_flag & DMA_RX_CRC_ERROR)
dev->stats.rx_crc_errors++;
if (dma_flag & DMA_RX_OV)
@@ -1351,7 +1354,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv,
} /* error packet */
chksum_ok = (dma_flag & priv->dma_rx_chk_bit) &&
- priv->desc_rxchk_en;
+ priv->desc_rxchk_en;
skb_put(skb, len);
if (priv->desc_64b_en) {
@@ -1408,17 +1411,9 @@ static int bcmgenet_alloc_rx_buffers(struct bcmgenet_priv *priv)
if (cb->skb)
continue;
- /* set the DMA descriptor length once and for all
- * it will only change if we support dynamically sizing
- * priv->rx_buf_len, but we do not
- */
- dmadesc_set_length_status(priv, priv->rx_bd_assign_ptr,
- priv->rx_buf_len << DMA_BUFLENGTH_SHIFT);
-
ret = bcmgenet_rx_refill(priv, cb);
if (ret)
break;
-
}
return ret;
@@ -1434,8 +1429,8 @@ static void bcmgenet_free_rx_buffers(struct bcmgenet_priv *priv)
if (dma_unmap_addr(cb, dma_addr)) {
dma_unmap_single(&priv->dev->dev,
- dma_unmap_addr(cb, dma_addr),
- priv->rx_buf_len, DMA_FROM_DEVICE);
+ dma_unmap_addr(cb, dma_addr),
+ priv->rx_buf_len, DMA_FROM_DEVICE);
dma_unmap_addr_set(cb, dma_addr, 0);
}
@@ -1444,6 +1439,24 @@ static void bcmgenet_free_rx_buffers(struct bcmgenet_priv *priv)
}
}
+static void umac_enable_set(struct bcmgenet_priv *priv, u32 mask, bool enable)
+{
+ u32 reg;
+
+ reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+ if (enable)
+ reg |= mask;
+ else
+ reg &= ~mask;
+ bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+
+ /* UniMAC stops on a packet boundary, wait for a full-size packet
+ * to be processed
+ */
+ if (enable == 0)
+ usleep_range(1000, 2000);
+}
+
static int reset_umac(struct bcmgenet_priv *priv)
{
struct device *kdev = &priv->pdev->dev;
@@ -1469,13 +1482,24 @@ static int reset_umac(struct bcmgenet_priv *priv)
if (timeout == 1000) {
dev_err(kdev,
- "timeout waiting for MAC to come out of resetn\n");
+ "timeout waiting for MAC to come out of reset\n");
return -ETIMEDOUT;
}
return 0;
}
+static void bcmgenet_intr_disable(struct bcmgenet_priv *priv)
+{
+ /* Mask all interrupts.*/
+ bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_MASK_SET);
+ bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_CLEAR);
+ bcmgenet_intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
+ bcmgenet_intrl2_1_writel(priv, 0xFFFFFFFF, INTRL2_CPU_MASK_SET);
+ bcmgenet_intrl2_1_writel(priv, 0xFFFFFFFF, INTRL2_CPU_CLEAR);
+ bcmgenet_intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
+}
+
static int init_umac(struct bcmgenet_priv *priv)
{
struct device *kdev = &priv->pdev->dev;
@@ -1491,7 +1515,8 @@ static int init_umac(struct bcmgenet_priv *priv)
bcmgenet_umac_writel(priv, 0, UMAC_CMD);
/* clear tx/rx counter */
bcmgenet_umac_writel(priv,
- MIB_RESET_RX | MIB_RESET_TX | MIB_RESET_RUNT, UMAC_MIB_CTRL);
+ MIB_RESET_RX | MIB_RESET_TX | MIB_RESET_RUNT,
+ UMAC_MIB_CTRL);
bcmgenet_umac_writel(priv, 0, UMAC_MIB_CTRL);
bcmgenet_umac_writel(priv, ENET_MAX_MTU_SIZE, UMAC_MAX_FRAME_LEN);
@@ -1504,21 +1529,18 @@ static int init_umac(struct bcmgenet_priv *priv)
if (!GENET_IS_V1(priv) && !GENET_IS_V2(priv))
bcmgenet_rbuf_writel(priv, 1, RBUF_TBUF_SIZE_CTRL);
- /* Mask all interrupts.*/
- bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_MASK_SET);
- bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_CLEAR);
- bcmgenet_intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
+ bcmgenet_intr_disable(priv);
cpu_mask_clear = UMAC_IRQ_RXDMA_BDONE;
dev_dbg(kdev, "%s:Enabling RXDMA_BDONE interrupt\n", __func__);
- /* Monitor cable plug/unpluged event for internal PHY */
- if (phy_is_internal(priv->phydev))
+ /* Monitor cable plug/unplugged event for internal PHY */
+ if (phy_is_internal(priv->phydev)) {
cpu_mask_clear |= (UMAC_IRQ_LINK_DOWN | UMAC_IRQ_LINK_UP);
- else if (priv->ext_phy)
+ } else if (priv->ext_phy) {
cpu_mask_clear |= (UMAC_IRQ_LINK_DOWN | UMAC_IRQ_LINK_UP);
- else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) {
+ } else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) {
reg = bcmgenet_bp_mc_get(priv);
reg |= BIT(priv->hw_params->bp_in_en_shift);
@@ -1534,8 +1556,7 @@ static int init_umac(struct bcmgenet_priv *priv)
if (priv->hw_params->flags & GENET_HAS_MDIO_INTR)
cpu_mask_clear |= UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR;
- bcmgenet_intrl2_0_writel(priv, cpu_mask_clear,
- INTRL2_CPU_MASK_CLEAR);
+ bcmgenet_intrl2_0_writel(priv, cpu_mask_clear, INTRL2_CPU_MASK_CLEAR);
/* Enable rx/tx engine.*/
dev_dbg(kdev, "done init umac\n");
@@ -1584,28 +1605,28 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv,
bcmgenet_tdma_ring_writel(priv, index, 1, DMA_MBUF_DONE_THRESH);
/* Disable rate control for now */
bcmgenet_tdma_ring_writel(priv, index, flow_period_val,
- TDMA_FLOW_PERIOD);
+ TDMA_FLOW_PERIOD);
/* Unclassified traffic goes to ring 16 */
bcmgenet_tdma_ring_writel(priv, index,
- ((size << DMA_RING_SIZE_SHIFT) | RX_BUF_LENGTH),
- DMA_RING_BUF_SIZE);
+ ((size << DMA_RING_SIZE_SHIFT) |
+ RX_BUF_LENGTH), DMA_RING_BUF_SIZE);
first_bd = write_ptr;
/* Set start and end address, read and write pointers */
bcmgenet_tdma_ring_writel(priv, index, first_bd * words_per_bd,
- DMA_START_ADDR);
+ DMA_START_ADDR);
bcmgenet_tdma_ring_writel(priv, index, first_bd * words_per_bd,
- TDMA_READ_PTR);
+ TDMA_READ_PTR);
bcmgenet_tdma_ring_writel(priv, index, first_bd,
- TDMA_WRITE_PTR);
+ TDMA_WRITE_PTR);
bcmgenet_tdma_ring_writel(priv, index, end_ptr * words_per_bd - 1,
- DMA_END_ADDR);
+ DMA_END_ADDR);
}
/* Initialize a RDMA ring */
static int bcmgenet_init_rx_ring(struct bcmgenet_priv *priv,
- unsigned int index, unsigned int size)
+ unsigned int index, unsigned int size)
{
u32 words_per_bd = WORDS_PER_BD(priv);
int ret;
@@ -1616,8 +1637,8 @@ static int bcmgenet_init_rx_ring(struct bcmgenet_priv *priv,
priv->rx_bd_assign_index = 0;
priv->rx_c_index = 0;
priv->rx_read_ptr = 0;
- priv->rx_cbs = kzalloc(priv->num_rx_bds * sizeof(struct enet_cb),
- GFP_KERNEL);
+ priv->rx_cbs = kcalloc(priv->num_rx_bds, sizeof(struct enet_cb),
+ GFP_KERNEL);
if (!priv->rx_cbs)
return -ENOMEM;
@@ -1631,14 +1652,15 @@ static int bcmgenet_init_rx_ring(struct bcmgenet_priv *priv,
bcmgenet_rdma_ring_writel(priv, index, 0, RDMA_PROD_INDEX);
bcmgenet_rdma_ring_writel(priv, index, 0, RDMA_CONS_INDEX);
bcmgenet_rdma_ring_writel(priv, index,
- ((size << DMA_RING_SIZE_SHIFT) | RX_BUF_LENGTH),
- DMA_RING_BUF_SIZE);
+ ((size << DMA_RING_SIZE_SHIFT) |
+ RX_BUF_LENGTH), DMA_RING_BUF_SIZE);
bcmgenet_rdma_ring_writel(priv, index, 0, DMA_START_ADDR);
bcmgenet_rdma_ring_writel(priv, index,
- words_per_bd * size - 1, DMA_END_ADDR);
+ words_per_bd * size - 1, DMA_END_ADDR);
bcmgenet_rdma_ring_writel(priv, index,
- (DMA_FC_THRESH_LO << DMA_XOFF_THRESHOLD_SHIFT) |
- DMA_FC_THRESH_HI, RDMA_XON_XOFF_THRESH);
+ (DMA_FC_THRESH_LO <<
+ DMA_XOFF_THRESHOLD_SHIFT) |
+ DMA_FC_THRESH_HI, RDMA_XON_XOFF_THRESH);
bcmgenet_rdma_ring_writel(priv, index, 0, RDMA_READ_PTR);
return ret;
@@ -1685,10 +1707,10 @@ static void bcmgenet_init_multiq(struct net_device *dev)
* (ring 16)
*/
bcmgenet_init_tx_ring(priv, i, priv->hw_params->bds_cnt,
- i * priv->hw_params->bds_cnt,
- (i + 1) * priv->hw_params->bds_cnt);
+ i * priv->hw_params->bds_cnt,
+ (i + 1) * priv->hw_params->bds_cnt);
- /* Configure ring as decriptor ring and setup priority */
+ /* Configure ring as descriptor ring and setup priority */
ring_cfg |= 1 << i;
dma_priority |= ((GENET_Q0_PRIORITY + i) <<
(GENET_MAX_MQ_CNT + 1) * i);
@@ -1754,11 +1776,11 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv)
/* Init tDma */
bcmgenet_tdma_writel(priv, DMA_MAX_BURST_LENGTH, DMA_SCB_BURST_SIZE);
- /* Initialize commont TX ring structures */
+ /* Initialize common TX ring structures */
priv->tx_bds = priv->base + priv->hw_params->tdma_offset;
priv->num_tx_bds = TOTAL_DESC;
- priv->tx_cbs = kzalloc(priv->num_tx_bds * sizeof(struct enet_cb),
- GFP_KERNEL);
+ priv->tx_cbs = kcalloc(priv->num_tx_bds, sizeof(struct enet_cb),
+ GFP_KERNEL);
if (!priv->tx_cbs) {
bcmgenet_fini_dma(priv);
return -ENOMEM;
@@ -1769,8 +1791,9 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv)
/* initialize special ring 16 */
bcmgenet_init_tx_ring(priv, DESC_INDEX, GENET_DEFAULT_BD_CNT,
- priv->hw_params->tx_queues * priv->hw_params->bds_cnt,
- TOTAL_DESC);
+ priv->hw_params->tx_queues *
+ priv->hw_params->bds_cnt,
+ TOTAL_DESC);
return 0;
}
@@ -1791,11 +1814,11 @@ static int bcmgenet_poll(struct napi_struct *napi, int budget)
priv->rx_c_index += work_done;
priv->rx_c_index &= DMA_C_INDEX_MASK;
bcmgenet_rdma_ring_writel(priv, DESC_INDEX,
- priv->rx_c_index, RDMA_CONS_INDEX);
+ priv->rx_c_index, RDMA_CONS_INDEX);
if (work_done < budget) {
napi_complete(napi);
- bcmgenet_intrl2_0_writel(priv,
- UMAC_IRQ_RXDMA_BDONE, INTRL2_CPU_MASK_CLEAR);
+ bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_RXDMA_BDONE,
+ INTRL2_CPU_MASK_CLEAR);
}
return work_done;
@@ -1809,11 +1832,18 @@ static void bcmgenet_irq_task(struct work_struct *work)
netif_dbg(priv, intr, priv->dev, "%s\n", __func__);
+ if (priv->irq0_stat & UMAC_IRQ_MPD_R) {
+ priv->irq0_stat &= ~UMAC_IRQ_MPD_R;
+ netif_dbg(priv, wol, priv->dev,
+ "magic packet detected, waking up\n");
+ bcmgenet_power_up(priv, GENET_POWER_WOL_MAGIC);
+ }
+
/* Link UP/DOWN event */
if ((priv->hw_params->flags & GENET_HAS_MDIO_INTR) &&
- (priv->irq0_stat & (UMAC_IRQ_LINK_UP|UMAC_IRQ_LINK_DOWN))) {
+ (priv->irq0_stat & (UMAC_IRQ_LINK_UP|UMAC_IRQ_LINK_DOWN))) {
phy_mac_interrupt(priv->phydev,
- priv->irq0_stat & UMAC_IRQ_LINK_UP);
+ priv->irq0_stat & UMAC_IRQ_LINK_UP);
priv->irq0_stat &= ~(UMAC_IRQ_LINK_UP|UMAC_IRQ_LINK_DOWN);
}
}
@@ -1828,11 +1858,11 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id)
priv->irq1_stat =
bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_STAT) &
~priv->int1_mask;
- /* clear inerrupts*/
+ /* clear interrupts */
bcmgenet_intrl2_1_writel(priv, priv->irq1_stat, INTRL2_CPU_CLEAR);
netif_dbg(priv, intr, priv->dev,
- "%s: IRQ=0x%x\n", __func__, priv->irq1_stat);
+ "%s: IRQ=0x%x\n", __func__, priv->irq1_stat);
/* Check the MBDONE interrupts.
* packet is done, reclaim descriptors
*/
@@ -1841,7 +1871,7 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id)
for (index = 0; index < 16; index++) {
if (priv->irq1_stat & (1 << index))
bcmgenet_tx_reclaim(priv->dev,
- &priv->tx_rings[index]);
+ &priv->tx_rings[index]);
}
}
return IRQ_HANDLED;
@@ -1856,11 +1886,11 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id)
priv->irq0_stat =
bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_STAT) &
~bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_MASK_STATUS);
- /* clear inerrupts*/
+ /* clear interrupts */
bcmgenet_intrl2_0_writel(priv, priv->irq0_stat, INTRL2_CPU_CLEAR);
netif_dbg(priv, intr, priv->dev,
- "IRQ=0x%x\n", priv->irq0_stat);
+ "IRQ=0x%x\n", priv->irq0_stat);
if (priv->irq0_stat & (UMAC_IRQ_RXDMA_BDONE | UMAC_IRQ_RXDMA_PDONE)) {
/* We use NAPI(software interrupt throttling, if
@@ -1868,8 +1898,8 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id)
* Disable interrupt, will be enabled in the poll method.
*/
if (likely(napi_schedule_prep(&priv->napi))) {
- bcmgenet_intrl2_0_writel(priv,
- UMAC_IRQ_RXDMA_BDONE, INTRL2_CPU_MASK_SET);
+ bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_RXDMA_BDONE,
+ INTRL2_CPU_MASK_SET);
__napi_schedule(&priv->napi);
}
}
@@ -1890,7 +1920,7 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id)
}
if ((priv->hw_params->flags & GENET_HAS_MDIO_INTR) &&
- priv->irq0_stat & (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR)) {
+ priv->irq0_stat & (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR)) {
priv->irq0_stat &= ~(UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR);
wake_up(&priv->wq);
}
@@ -1898,6 +1928,15 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static irqreturn_t bcmgenet_wol_isr(int irq, void *dev_id)
+{
+ struct bcmgenet_priv *priv = dev_id;
+
+ pm_wakeup_event(&priv->pdev->dev, 0);
+
+ return IRQ_HANDLED;
+}
+
static void bcmgenet_umac_reset(struct bcmgenet_priv *priv)
{
u32 reg;
@@ -1913,7 +1952,7 @@ static void bcmgenet_umac_reset(struct bcmgenet_priv *priv)
}
static void bcmgenet_set_hw_addr(struct bcmgenet_priv *priv,
- unsigned char *addr)
+ unsigned char *addr)
{
bcmgenet_umac_writel(priv, (addr[0] << 24) | (addr[1] << 16) |
(addr[2] << 8) | addr[3], UMAC_MAC0);
@@ -1922,14 +1961,9 @@ static void bcmgenet_set_hw_addr(struct bcmgenet_priv *priv,
static int bcmgenet_wol_resume(struct bcmgenet_priv *priv)
{
- int ret;
-
/* From WOL-enabled suspend, switch to regular clock */
- clk_disable(priv->clk_wol);
- /* init umac registers to synchronize s/w with h/w */
- ret = init_umac(priv);
- if (ret)
- return ret;
+ if (priv->wolopts)
+ clk_disable_unprepare(priv->clk_wol);
phy_init_hw(priv->phydev);
/* Speed settings must be restored */
@@ -1974,6 +2008,23 @@ static void bcmgenet_enable_dma(struct bcmgenet_priv *priv, u32 dma_ctrl)
bcmgenet_tdma_writel(priv, reg, DMA_CTRL);
}
+static void bcmgenet_netif_start(struct net_device *dev)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+
+ /* Start the network engine */
+ napi_enable(&priv->napi);
+
+ umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, true);
+
+ if (phy_is_internal(priv->phydev))
+ bcmgenet_power_up(priv, GENET_POWER_PASSIVE);
+
+ netif_tx_start_all_queues(dev);
+
+ phy_start(priv->phydev);
+}
+
static int bcmgenet_open(struct net_device *dev)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
@@ -1995,18 +2046,14 @@ static int bcmgenet_open(struct net_device *dev)
goto err_clk_disable;
/* disable ethernet MAC while updating its registers */
+ umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, false);
+
+ /* Make sure we reflect the value of CRC_CMD_FWD */
reg = bcmgenet_umac_readl(priv, UMAC_CMD);
- reg &= ~(CMD_TX_EN | CMD_RX_EN);
- bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+ priv->crc_fwd_en = !!(reg & CMD_CRC_FWD);
bcmgenet_set_hw_addr(priv, dev->dev_addr);
- if (priv->wol_enabled) {
- ret = bcmgenet_wol_resume(priv);
- if (ret)
- return ret;
- }
-
if (phy_is_internal(priv->phydev)) {
reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
reg |= EXT_ENERGY_DET_MASK;
@@ -2027,37 +2074,20 @@ static int bcmgenet_open(struct net_device *dev)
bcmgenet_enable_dma(priv, dma_ctrl);
ret = request_irq(priv->irq0, bcmgenet_isr0, IRQF_SHARED,
- dev->name, priv);
+ dev->name, priv);
if (ret < 0) {
netdev_err(dev, "can't request IRQ %d\n", priv->irq0);
goto err_fini_dma;
}
ret = request_irq(priv->irq1, bcmgenet_isr1, IRQF_SHARED,
- dev->name, priv);
+ dev->name, priv);
if (ret < 0) {
netdev_err(dev, "can't request IRQ %d\n", priv->irq1);
goto err_irq0;
}
- /* Start the network engine */
- napi_enable(&priv->napi);
-
- reg = bcmgenet_umac_readl(priv, UMAC_CMD);
- reg |= (CMD_TX_EN | CMD_RX_EN);
- bcmgenet_umac_writel(priv, reg, UMAC_CMD);
-
- /* Make sure we reflect the value of CRC_CMD_FWD */
- priv->crc_fwd_en = !!(reg & CMD_CRC_FWD);
-
- device_set_wakeup_capable(&dev->dev, 1);
-
- if (phy_is_internal(priv->phydev))
- bcmgenet_power_up(priv, GENET_POWER_PASSIVE);
-
- netif_tx_start_all_queues(dev);
-
- phy_start(priv->phydev);
+ bcmgenet_netif_start(dev);
return 0;
@@ -2092,8 +2122,7 @@ static int bcmgenet_dma_teardown(struct bcmgenet_priv *priv)
}
if (timeout == DMA_TIMEOUT_VAL) {
- netdev_warn(priv->dev,
- "Timed out while disabling TX DMA\n");
+ netdev_warn(priv->dev, "Timed out while disabling TX DMA\n");
ret = -ETIMEDOUT;
}
@@ -2116,41 +2145,51 @@ static int bcmgenet_dma_teardown(struct bcmgenet_priv *priv)
}
if (timeout == DMA_TIMEOUT_VAL) {
- netdev_warn(priv->dev,
- "Timed out while disabling RX DMA\n");
- ret = -ETIMEDOUT;
+ netdev_warn(priv->dev, "Timed out while disabling RX DMA\n");
+ ret = -ETIMEDOUT;
}
return ret;
}
+static void bcmgenet_netif_stop(struct net_device *dev)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+
+ netif_tx_stop_all_queues(dev);
+ napi_disable(&priv->napi);
+ phy_stop(priv->phydev);
+
+ bcmgenet_intr_disable(priv);
+
+ /* Wait for pending work items to complete. Since interrupts are
+ * disabled no new work will be scheduled.
+ */
+ cancel_work_sync(&priv->bcmgenet_irq_work);
+
+ priv->old_pause = -1;
+ priv->old_link = -1;
+ priv->old_duplex = -1;
+}
+
static int bcmgenet_close(struct net_device *dev)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
int ret;
- u32 reg;
netif_dbg(priv, ifdown, dev, "bcmgenet_close\n");
- phy_stop(priv->phydev);
+ bcmgenet_netif_stop(dev);
/* Disable MAC receive */
- reg = bcmgenet_umac_readl(priv, UMAC_CMD);
- reg &= ~CMD_RX_EN;
- bcmgenet_umac_writel(priv, reg, UMAC_CMD);
-
- netif_tx_stop_all_queues(dev);
+ umac_enable_set(priv, CMD_RX_EN, false);
ret = bcmgenet_dma_teardown(priv);
if (ret)
return ret;
/* Disable MAC transmit. TX DMA disabled have to done before this */
- reg = bcmgenet_umac_readl(priv, UMAC_CMD);
- reg &= ~CMD_TX_EN;
- bcmgenet_umac_writel(priv, reg, UMAC_CMD);
-
- napi_disable(&priv->napi);
+ umac_enable_set(priv, CMD_TX_EN, false);
/* tx reclaim */
bcmgenet_tx_reclaim_all(dev);
@@ -2159,18 +2198,9 @@ static int bcmgenet_close(struct net_device *dev)
free_irq(priv->irq0, priv);
free_irq(priv->irq1, priv);
- /* Wait for pending work items to complete - we are stopping
- * the clock now. Since interrupts are disabled, no new work
- * will be scheduled.
- */
- cancel_work_sync(&priv->bcmgenet_irq_work);
-
if (phy_is_internal(priv->phydev))
bcmgenet_power_down(priv, GENET_POWER_PASSIVE);
- if (priv->wol_enabled)
- clk_enable(priv->clk_wol);
-
if (!IS_ERR(priv->clk))
clk_disable_unprepare(priv->clk);
@@ -2199,12 +2229,11 @@ static inline void bcmgenet_set_mdf_addr(struct bcmgenet_priv *priv,
{
u32 reg;
- bcmgenet_umac_writel(priv,
- addr[0] << 8 | addr[1], UMAC_MDF_ADDR + (*i * 4));
- bcmgenet_umac_writel(priv,
- addr[2] << 24 | addr[3] << 16 |
- addr[4] << 8 | addr[5],
- UMAC_MDF_ADDR + ((*i + 1) * 4));
+ bcmgenet_umac_writel(priv, addr[0] << 8 | addr[1],
+ UMAC_MDF_ADDR + (*i * 4));
+ bcmgenet_umac_writel(priv, addr[2] << 24 | addr[3] << 16 |
+ addr[4] << 8 | addr[5],
+ UMAC_MDF_ADDR + ((*i + 1) * 4));
reg = bcmgenet_umac_readl(priv, UMAC_MDF_CTRL);
reg |= (1 << (MAX_MC_COUNT - *mc));
bcmgenet_umac_writel(priv, reg, UMAC_MDF_CTRL);
@@ -2221,7 +2250,7 @@ static void bcmgenet_set_rx_mode(struct net_device *dev)
netif_dbg(priv, hw, dev, "%s: %08X\n", __func__, dev->flags);
- /* Promiscous mode */
+ /* Promiscuous mode */
reg = bcmgenet_umac_readl(priv, UMAC_CMD);
if (dev->flags & IFF_PROMISC) {
reg |= CMD_PROMISC;
@@ -2401,7 +2430,7 @@ static void bcmgenet_set_hw_params(struct bcmgenet_priv *priv)
/* Print the GENET core version */
dev_info(&priv->pdev->dev, "GENET " GENET_VER_FMT,
- major, (reg >> 16) & 0x0f, reg & 0xffff);
+ major, (reg >> 16) & 0x0f, reg & 0xffff);
#ifdef CONFIG_PHYS_ADDR_T_64BIT
if (!(params->flags & GENET_HAS_40BITS))
@@ -2457,6 +2486,7 @@ static int bcmgenet_probe(struct platform_device *pdev)
priv = netdev_priv(dev);
priv->irq0 = platform_get_irq(pdev, 0);
priv->irq1 = platform_get_irq(pdev, 1);
+ priv->wol_irq = platform_get_irq(pdev, 2);
if (!priv->irq0 || !priv->irq1) {
dev_err(&pdev->dev, "can't find IRQs\n");
err = -EINVAL;
@@ -2491,6 +2521,13 @@ static int bcmgenet_probe(struct platform_device *pdev)
dev->hw_features |= NETIF_F_SG | NETIF_F_IP_CSUM |
NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM;
+ /* Request the WOL interrupt and advertise suspend if available */
+ priv->wol_irq_disabled = true;
+ err = devm_request_irq(&pdev->dev, priv->wol_irq, bcmgenet_wol_isr, 0,
+ dev->name, priv);
+ if (!err)
+ device_set_wakeup_capable(&pdev->dev, 1);
+
/* Set the needed headroom to account for any possible
* features enabling/disabling at runtime
*/
@@ -2502,6 +2539,13 @@ static int bcmgenet_probe(struct platform_device *pdev)
priv->pdev = pdev;
priv->version = (enum bcmgenet_version)of_id->data;
+ priv->clk = devm_clk_get(&priv->pdev->dev, "enet");
+ if (IS_ERR(priv->clk))
+ dev_warn(&priv->pdev->dev, "failed to get enet clock\n");
+
+ if (!IS_ERR(priv->clk))
+ clk_prepare_enable(priv->clk);
+
bcmgenet_set_hw_params(priv);
/* Mii wait queue */
@@ -2510,17 +2554,10 @@ static int bcmgenet_probe(struct platform_device *pdev)
priv->rx_buf_len = RX_BUF_LENGTH;
INIT_WORK(&priv->bcmgenet_irq_work, bcmgenet_irq_task);
- priv->clk = devm_clk_get(&priv->pdev->dev, "enet");
- if (IS_ERR(priv->clk))
- dev_warn(&priv->pdev->dev, "failed to get enet clock\n");
-
priv->clk_wol = devm_clk_get(&priv->pdev->dev, "enet-wol");
if (IS_ERR(priv->clk_wol))
dev_warn(&priv->pdev->dev, "failed to get enet-wol clock\n");
- if (!IS_ERR(priv->clk))
- clk_prepare_enable(priv->clk);
-
err = reset_umac(priv);
if (err)
goto err_clk_disable;
@@ -2535,14 +2572,17 @@ static int bcmgenet_probe(struct platform_device *pdev)
netif_set_real_num_tx_queues(priv->dev, priv->hw_params->tx_queues + 1);
netif_set_real_num_rx_queues(priv->dev, priv->hw_params->rx_queues + 1);
- err = register_netdev(dev);
- if (err)
- goto err_clk_disable;
+ /* libphy will determine the link state */
+ netif_carrier_off(dev);
/* Turn off the main clock, WOL clock is handled separately */
if (!IS_ERR(priv->clk))
clk_disable_unprepare(priv->clk);
+ err = register_netdev(dev);
+ if (err)
+ goto err;
+
return err;
err_clk_disable:
@@ -2565,6 +2605,116 @@ static int bcmgenet_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int bcmgenet_suspend(struct device *d)
+{
+ struct net_device *dev = dev_get_drvdata(d);
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+ int ret;
+
+ if (!netif_running(dev))
+ return 0;
+
+ bcmgenet_netif_stop(dev);
+
+ phy_suspend(priv->phydev);
+
+ netif_device_detach(dev);
+
+ /* Disable MAC receive */
+ umac_enable_set(priv, CMD_RX_EN, false);
+
+ ret = bcmgenet_dma_teardown(priv);
+ if (ret)
+ return ret;
+
+ /* Disable MAC transmit. TX DMA disabled have to done before this */
+ umac_enable_set(priv, CMD_TX_EN, false);
+
+ /* tx reclaim */
+ bcmgenet_tx_reclaim_all(dev);
+ bcmgenet_fini_dma(priv);
+
+ /* Prepare the device for Wake-on-LAN and switch to the slow clock */
+ if (device_may_wakeup(d) && priv->wolopts) {
+ bcmgenet_power_down(priv, GENET_POWER_WOL_MAGIC);
+ clk_prepare_enable(priv->clk_wol);
+ }
+
+ /* Turn off the clocks */
+ clk_disable_unprepare(priv->clk);
+
+ return 0;
+}
+
+static int bcmgenet_resume(struct device *d)
+{
+ struct net_device *dev = dev_get_drvdata(d);
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+ unsigned long dma_ctrl;
+ int ret;
+ u32 reg;
+
+ if (!netif_running(dev))
+ return 0;
+
+ /* Turn on the clock */
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
+
+ bcmgenet_umac_reset(priv);
+
+ ret = init_umac(priv);
+ if (ret)
+ goto out_clk_disable;
+
+ ret = bcmgenet_wol_resume(priv);
+ if (ret)
+ goto out_clk_disable;
+
+ /* disable ethernet MAC while updating its registers */
+ umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, false);
+
+ bcmgenet_set_hw_addr(priv, dev->dev_addr);
+
+ if (phy_is_internal(priv->phydev)) {
+ reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
+ reg |= EXT_ENERGY_DET_MASK;
+ bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
+ }
+
+ if (priv->wolopts)
+ bcmgenet_power_up(priv, GENET_POWER_WOL_MAGIC);
+
+ /* Disable RX/TX DMA and flush TX queues */
+ dma_ctrl = bcmgenet_dma_disable(priv);
+
+ /* Reinitialize TDMA and RDMA and SW housekeeping */
+ ret = bcmgenet_init_dma(priv);
+ if (ret) {
+ netdev_err(dev, "failed to initialize DMA\n");
+ goto out_clk_disable;
+ }
+
+ /* Always enable ring 16 - descriptor ring */
+ bcmgenet_enable_dma(priv, dma_ctrl);
+
+ netif_device_attach(dev);
+
+ phy_resume(priv->phydev);
+
+ bcmgenet_netif_start(dev);
+
+ return 0;
+
+out_clk_disable:
+ clk_disable_unprepare(priv->clk);
+ return ret;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(bcmgenet_pm_ops, bcmgenet_suspend, bcmgenet_resume);
static struct platform_driver bcmgenet_driver = {
.probe = bcmgenet_probe,
@@ -2573,6 +2723,7 @@ static struct platform_driver bcmgenet_driver = {
.name = "bcmgenet",
.owner = THIS_MODULE,
.of_match_table = bcmgenet_match,
+ .pm = &bcmgenet_pm_ops,
},
};
module_platform_driver(bcmgenet_driver);
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
index 0f117105fed1..c862d0666771 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
@@ -4,18 +4,8 @@
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- *
-*/
+ */
+
#ifndef __BCMGENET_H__
#define __BCMGENET_H__
@@ -331,9 +321,9 @@ struct bcmgenet_mib_counters {
#define EXT_ENERGY_DET_MASK (1 << 12)
#define EXT_RGMII_OOB_CTRL 0x0C
-#define RGMII_MODE_EN (1 << 0)
#define RGMII_LINK (1 << 4)
#define OOB_DISABLE (1 << 5)
+#define RGMII_MODE_EN (1 << 6)
#define ID_MODE_DIS (1 << 16)
#define EXT_GPHY_CTRL 0x1C
@@ -456,6 +446,7 @@ struct enet_cb {
enum bcmgenet_power_mode {
GENET_POWER_CABLE_SENSE = 0,
GENET_POWER_PASSIVE,
+ GENET_POWER_WOL_MAGIC,
};
struct bcmgenet_priv;
@@ -513,9 +504,9 @@ struct bcmgenet_tx_ring {
unsigned int cb_ptr; /* Tx ring initial CB ptr */
unsigned int end_ptr; /* Tx ring end CB ptr */
void (*int_enable)(struct bcmgenet_priv *priv,
- struct bcmgenet_tx_ring *);
+ struct bcmgenet_tx_ring *);
void (*int_disable)(struct bcmgenet_priv *priv,
- struct bcmgenet_tx_ring *);
+ struct bcmgenet_tx_ring *);
};
/* device context */
@@ -569,6 +560,8 @@ struct bcmgenet_priv {
int irq1;
unsigned int irq0_stat;
unsigned int irq1_stat;
+ int wol_irq;
+ bool wol_irq_disabled;
/* HW descriptors/checksum variables */
bool desc_64b_en;
@@ -583,7 +576,6 @@ struct bcmgenet_priv {
struct platform_device *pdev;
/* WOL */
- unsigned long wol_enabled;
struct clk *clk_wol;
u32 wolopts;
@@ -625,4 +617,12 @@ int bcmgenet_mii_config(struct net_device *dev);
void bcmgenet_mii_exit(struct net_device *dev);
void bcmgenet_mii_reset(struct net_device *dev);
+/* Wake-on-LAN routines */
+void bcmgenet_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol);
+int bcmgenet_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol);
+int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
+ enum bcmgenet_power_mode mode);
+void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
+ enum bcmgenet_power_mode mode);
+
#endif /* __BCMGENET_H__ */
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
new file mode 100644
index 000000000000..b82b7e4e06b2
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
@@ -0,0 +1,206 @@
+/*
+ * Broadcom GENET (Gigabit Ethernet) Wake-on-LAN support
+ *
+ * Copyright (c) 2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) "bcmgenet_wol: " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/clk.h>
+#include <linux/version.h>
+#include <linux/platform_device.h>
+#include <net/arp.h>
+
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/phy.h>
+
+#include "bcmgenet.h"
+
+/* ethtool function - get WOL (Wake on LAN) settings, Only Magic Packet
+ * Detection is supported through ethtool
+ */
+void bcmgenet_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+ u32 reg;
+
+ wol->supported = WAKE_MAGIC | WAKE_MAGICSECURE;
+ wol->wolopts = priv->wolopts;
+ memset(wol->sopass, 0, sizeof(wol->sopass));
+
+ if (wol->wolopts & WAKE_MAGICSECURE) {
+ reg = bcmgenet_umac_readl(priv, UMAC_MPD_PW_MS);
+ put_unaligned_be16(reg, &wol->sopass[0]);
+ reg = bcmgenet_umac_readl(priv, UMAC_MPD_PW_LS);
+ put_unaligned_be32(reg, &wol->sopass[2]);
+ }
+}
+
+/* ethtool function - set WOL (Wake on LAN) settings.
+ * Only for magic packet detection mode.
+ */
+int bcmgenet_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+ struct device *kdev = &priv->pdev->dev;
+ u32 reg;
+
+ if (!device_can_wakeup(kdev))
+ return -ENOTSUPP;
+
+ if (wol->wolopts & ~(WAKE_MAGIC | WAKE_MAGICSECURE))
+ return -EINVAL;
+
+ if (wol->wolopts & WAKE_MAGICSECURE) {
+ bcmgenet_umac_writel(priv, get_unaligned_be16(&wol->sopass[0]),
+ UMAC_MPD_PW_MS);
+ bcmgenet_umac_writel(priv, get_unaligned_be32(&wol->sopass[2]),
+ UMAC_MPD_PW_LS);
+ reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
+ reg |= MPD_PW_EN;
+ bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
+ }
+
+ /* Flag the device and relevant IRQ as wakeup capable */
+ if (wol->wolopts) {
+ device_set_wakeup_enable(kdev, 1);
+ enable_irq_wake(priv->wol_irq);
+ priv->wol_irq_disabled = false;
+ } else {
+ device_set_wakeup_enable(kdev, 0);
+ /* Avoid unbalanced disable_irq_wake calls */
+ if (!priv->wol_irq_disabled)
+ disable_irq_wake(priv->wol_irq);
+ priv->wol_irq_disabled = true;
+ }
+
+ priv->wolopts = wol->wolopts;
+
+ return 0;
+}
+
+static int bcmgenet_poll_wol_status(struct bcmgenet_priv *priv)
+{
+ struct net_device *dev = priv->dev;
+ int retries = 0;
+
+ while (!(bcmgenet_rbuf_readl(priv, RBUF_STATUS)
+ & RBUF_STATUS_WOL)) {
+ retries++;
+ if (retries > 5) {
+ netdev_crit(dev, "polling wol mode timeout\n");
+ return -ETIMEDOUT;
+ }
+ mdelay(1);
+ }
+
+ return retries;
+}
+
+int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
+ enum bcmgenet_power_mode mode)
+{
+ struct net_device *dev = priv->dev;
+ u32 cpu_mask_clear;
+ int retries = 0;
+ u32 reg;
+
+ if (mode != GENET_POWER_WOL_MAGIC) {
+ netif_err(priv, wol, dev, "unsupported mode: %d\n", mode);
+ return -EINVAL;
+ }
+
+ /* disable RX */
+ reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+ reg &= ~CMD_RX_EN;
+ bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+ mdelay(10);
+
+ reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
+ reg |= MPD_EN;
+ bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
+
+ /* Do not leave UniMAC in MPD mode only */
+ retries = bcmgenet_poll_wol_status(priv);
+ if (retries < 0) {
+ reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
+ reg &= ~MPD_EN;
+ bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
+ return retries;
+ }
+
+ netif_dbg(priv, wol, dev, "MPD WOL-ready status set after %d msec\n",
+ retries);
+
+ /* Enable CRC forward */
+ reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+ priv->crc_fwd_en = 1;
+ reg |= CMD_CRC_FWD;
+
+ /* Receiver must be enabled for WOL MP detection */
+ reg |= CMD_RX_EN;
+ bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+
+ if (priv->hw_params->flags & GENET_HAS_EXT) {
+ reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
+ reg &= ~EXT_ENERGY_DET_MASK;
+ bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
+ }
+
+ /* Enable the MPD interrupt */
+ cpu_mask_clear = UMAC_IRQ_MPD_R;
+
+ bcmgenet_intrl2_0_writel(priv, cpu_mask_clear, INTRL2_CPU_MASK_CLEAR);
+
+ return 0;
+}
+
+void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
+ enum bcmgenet_power_mode mode)
+{
+ u32 cpu_mask_set;
+ u32 reg;
+
+ if (mode != GENET_POWER_WOL_MAGIC) {
+ netif_err(priv, wol, priv->dev, "invalid mode: %d\n", mode);
+ return;
+ }
+
+ reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
+ reg &= ~MPD_EN;
+ bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
+
+ /* Disable CRC Forward */
+ reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+ reg &= ~CMD_CRC_FWD;
+ bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+ priv->crc_fwd_en = 0;
+
+ /* Stop monitoring magic packet IRQ */
+ cpu_mask_set = UMAC_IRQ_MPD_R;
+
+ /* Stop monitoring magic packet IRQ */
+ bcmgenet_intrl2_0_writel(priv, cpu_mask_set, INTRL2_CPU_MASK_SET);
+}
diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c
index add8d8596084..c88f7ae99636 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
@@ -6,15 +6,6 @@
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
@@ -44,15 +35,15 @@ static int bcmgenet_mii_read(struct mii_bus *bus, int phy_id, int location)
u32 reg;
bcmgenet_umac_writel(priv, (MDIO_RD | (phy_id << MDIO_PMD_SHIFT) |
- (location << MDIO_REG_SHIFT)), UMAC_MDIO_CMD);
+ (location << MDIO_REG_SHIFT)), UMAC_MDIO_CMD);
/* Start MDIO transaction*/
reg = bcmgenet_umac_readl(priv, UMAC_MDIO_CMD);
reg |= MDIO_START_BUSY;
bcmgenet_umac_writel(priv, reg, UMAC_MDIO_CMD);
wait_event_timeout(priv->wq,
- !(bcmgenet_umac_readl(priv, UMAC_MDIO_CMD)
- & MDIO_START_BUSY),
- HZ / 100);
+ !(bcmgenet_umac_readl(priv, UMAC_MDIO_CMD)
+ & MDIO_START_BUSY),
+ HZ / 100);
ret = bcmgenet_umac_readl(priv, UMAC_MDIO_CMD);
if (ret & MDIO_READ_FAIL)
@@ -63,22 +54,22 @@ static int bcmgenet_mii_read(struct mii_bus *bus, int phy_id, int location)
/* write a value to the MII */
static int bcmgenet_mii_write(struct mii_bus *bus, int phy_id,
- int location, u16 val)
+ int location, u16 val)
{
struct net_device *dev = bus->priv;
struct bcmgenet_priv *priv = netdev_priv(dev);
u32 reg;
bcmgenet_umac_writel(priv, (MDIO_WR | (phy_id << MDIO_PMD_SHIFT) |
- (location << MDIO_REG_SHIFT) | (0xffff & val)),
- UMAC_MDIO_CMD);
+ (location << MDIO_REG_SHIFT) | (0xffff & val)),
+ UMAC_MDIO_CMD);
reg = bcmgenet_umac_readl(priv, UMAC_MDIO_CMD);
reg |= MDIO_START_BUSY;
bcmgenet_umac_writel(priv, reg, UMAC_MDIO_CMD);
wait_event_timeout(priv->wq,
- !(bcmgenet_umac_readl(priv, UMAC_MDIO_CMD) &
- MDIO_START_BUSY),
- HZ / 100);
+ !(bcmgenet_umac_readl(priv, UMAC_MDIO_CMD) &
+ MDIO_START_BUSY),
+ HZ / 100);
return 0;
}
@@ -136,17 +127,22 @@ static void bcmgenet_mii_setup(struct net_device *dev)
/* pause capability */
if (!phydev->pause)
cmd_bits |= CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE;
+ }
+ if (!status_changed)
+ return;
+
+ if (phydev->link) {
reg = bcmgenet_umac_readl(priv, UMAC_CMD);
reg &= ~((CMD_SPEED_MASK << CMD_SPEED_SHIFT) |
CMD_HD_EN |
CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE);
reg |= cmd_bits;
bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+
}
- if (status_changed)
- phy_print_status(phydev);
+ phy_print_status(phydev);
}
void bcmgenet_mii_reset(struct net_device *dev)
@@ -247,7 +243,7 @@ int bcmgenet_mii_config(struct net_device *dev)
phy_name = "external MII";
phydev->supported &= PHY_BASIC_FEATURES;
bcmgenet_sys_writel(priv,
- PORT_MODE_EXT_EPHY, SYS_PORT_CTRL);
+ PORT_MODE_EXT_EPHY, SYS_PORT_CTRL);
break;
case PHY_INTERFACE_MODE_REVMII:
@@ -283,7 +279,7 @@ int bcmgenet_mii_config(struct net_device *dev)
reg |= RGMII_MODE_EN | id_mode_dis;
bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
bcmgenet_sys_writel(priv,
- PORT_MODE_EXT_GPHY, SYS_PORT_CTRL);
+ PORT_MODE_EXT_GPHY, SYS_PORT_CTRL);
break;
default:
dev_err(kdev, "unknown phy mode: %d\n", priv->phy_interface);
@@ -311,12 +307,12 @@ static int bcmgenet_mii_probe(struct net_device *dev)
/* In the case of a fixed PHY, the DT node associated
* to the PHY is the Ethernet MAC DT node.
*/
- if (of_phy_is_fixed_link(dn)) {
+ if (!priv->phy_dn && of_phy_is_fixed_link(dn)) {
ret = of_phy_register_fixed_link(dn);
if (ret)
return ret;
- priv->phy_dn = dn;
+ priv->phy_dn = of_node_get(dn);
}
phydev = of_phy_connect(dev, priv->phy_dn, bcmgenet_mii_setup, 0,
@@ -362,7 +358,7 @@ static int bcmgenet_mii_probe(struct net_device *dev)
priv->mii_bus->irq[phydev->addr] = PHY_POLL;
pr_info("attached PHY at address %d [%s]\n",
- phydev->addr, phydev->drv->name);
+ phydev->addr, phydev->drv->name);
return 0;
}
@@ -387,9 +383,9 @@ static int bcmgenet_mii_alloc(struct bcmgenet_priv *priv)
bus->read = bcmgenet_mii_read;
bus->write = bcmgenet_mii_write;
snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d",
- priv->pdev->name, priv->pdev->id);
+ priv->pdev->name, priv->pdev->id);
- bus->irq = kzalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+ bus->irq = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);
if (!bus->irq) {
mdiobus_free(priv->mii_bus);
return -ENOMEM;
@@ -452,6 +448,7 @@ int bcmgenet_mii_init(struct net_device *dev)
return 0;
out:
+ of_node_put(priv->phy_dn);
mdiobus_unregister(priv->mii_bus);
out_free:
kfree(priv->mii_bus->irq);
@@ -463,6 +460,7 @@ void bcmgenet_mii_exit(struct net_device *dev)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
+ of_node_put(priv->phy_dn);
mdiobus_unregister(priv->mii_bus);
kfree(priv->mii_bus->irq);
mdiobus_free(priv->mii_bus);
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index df2792d8383d..a3dd5dc64f4c 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -3224,7 +3224,7 @@ static int tg3_nvram_read_using_eeprom(struct tg3 *tp,
return 0;
}
-#define NVRAM_CMD_TIMEOUT 100
+#define NVRAM_CMD_TIMEOUT 5000
static int tg3_nvram_exec_cmd(struct tg3 *tp, u32 nvram_cmd)
{
@@ -3232,7 +3232,7 @@ static int tg3_nvram_exec_cmd(struct tg3 *tp, u32 nvram_cmd)
tw32(NVRAM_CMD, nvram_cmd);
for (i = 0; i < NVRAM_CMD_TIMEOUT; i++) {
- udelay(10);
+ usleep_range(10, 40);
if (tr32(NVRAM_CMD) & NVRAM_CMD_DONE) {
udelay(10);
break;
@@ -7830,17 +7830,18 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi,
static netdev_tx_t tg3_start_xmit(struct sk_buff *, struct net_device *);
-/* Use GSO to workaround a rare TSO bug that may be triggered when the
- * TSO header is greater than 80 bytes.
+/* Use GSO to workaround all TSO packets that meet HW bug conditions
+ * indicated in tg3_tx_frag_set()
*/
-static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb)
+static int tg3_tso_bug(struct tg3 *tp, struct tg3_napi *tnapi,
+ struct netdev_queue *txq, struct sk_buff *skb)
{
struct sk_buff *segs, *nskb;
u32 frag_cnt_est = skb_shinfo(skb)->gso_segs * 3;
/* Estimate the number of fragments in the worst case */
- if (unlikely(tg3_tx_avail(&tp->napi[0]) <= frag_cnt_est)) {
- netif_stop_queue(tp->dev);
+ if (unlikely(tg3_tx_avail(tnapi) <= frag_cnt_est)) {
+ netif_tx_stop_queue(txq);
/* netif_tx_stop_queue() must be done before checking
* checking tx index in tg3_tx_avail() below, because in
@@ -7848,14 +7849,15 @@ static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb)
* netif_tx_queue_stopped().
*/
smp_mb();
- if (tg3_tx_avail(&tp->napi[0]) <= frag_cnt_est)
+ if (tg3_tx_avail(tnapi) <= frag_cnt_est)
return NETDEV_TX_BUSY;
- netif_wake_queue(tp->dev);
+ netif_tx_wake_queue(txq);
}
- segs = skb_gso_segment(skb, tp->dev->features & ~NETIF_F_TSO);
- if (IS_ERR(segs))
+ segs = skb_gso_segment(skb, tp->dev->features &
+ ~(NETIF_F_TSO | NETIF_F_TSO6));
+ if (IS_ERR(segs) || !segs)
goto tg3_tso_bug_end;
do {
@@ -7930,7 +7932,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (!skb_is_gso_v6(skb)) {
if (unlikely((ETH_HLEN + hdr_len) > 80) &&
tg3_flag(tp, TSO_BUG))
- return tg3_tso_bug(tp, skb);
+ return tg3_tso_bug(tp, tnapi, txq, skb);
ip_csum = iph->check;
ip_tot_len = iph->tot_len;
@@ -8061,7 +8063,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
iph->tot_len = ip_tot_len;
}
tcph->check = tcp_csum;
- return tg3_tso_bug(tp, skb);
+ return tg3_tso_bug(tp, tnapi, txq, skb);
}
/* If the workaround fails due to memory/mapping