Re: [PATCH net-next 3/3] net: bcmgenet: Fix coalescing settings handling

2018-03-29 Thread Doug Berger
On 03/29/2018 10:51 AM, Doug Berger wrote:
> On 03/27/2018 12:47 PM, Florian Fainelli wrote:
>> There were a number of issues with setting the RX coalescing parameters:
>>
>> - we would not be preserving values that would have been configured
>>   across close/open calls, instead we would always reset to no timeout
>>   and 1 interrupt per packet, this would also prevent DIM from setting its
>>   default usec/pkts values
>>
>> - when adaptive RX would be turned on, we woud not be fetching the
>>   default parameters, we would stay with no timeout/1 packet per interrupt
>>   until the estimator kicks in and changes that
>>
>> - finally disabling adaptive RX coalescing while providing parameters
>>   would not be honored, and we would stay with whatever DIM had previously
>>   determined instead of the user requested parameters
>>
>> Fixes: 9f4ca05827a2 ("net: bcmgenet: Add support for adaptive RX coalescing")
>> Signed-off-by: Florian Fainelli <f.faine...@gmail.com>
>> ---
>>  drivers/net/ethernet/broadcom/genet/bcmgenet.c | 78 
>> ++
>>  drivers/net/ethernet/broadcom/genet/bcmgenet.h |  4 +-
>>  2 files changed, 57 insertions(+), 25 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
>> b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
>> index 7db8edc643ec..76409debb796 100644
>> --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
>> +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
>> @@ -625,18 +625,18 @@ static int bcmgenet_get_coalesce(struct net_device 
>> *dev,
>>  return 0;
>>  }
>>  
>> -static void bcmgenet_set_rx_coalesce(struct bcmgenet_rx_ring *ring)
>> +static void bcmgenet_set_rx_coalesce(struct bcmgenet_rx_ring *ring,
>> + u32 usecs, u32 pkts)
>>  {
>>  struct bcmgenet_priv *priv = ring->priv;
>>  unsigned int i = ring->index;
>>  u32 reg;
>>  
>> -bcmgenet_rdma_ring_writel(priv, i, ring->dim.coal_pkts,
>> -  DMA_MBUF_DONE_THRESH);
>> +bcmgenet_rdma_ring_writel(priv, i, pkts, DMA_MBUF_DONE_THRESH);
>>  
>>  reg = bcmgenet_rdma_readl(priv, DMA_RING0_TIMEOUT + i);
>>  reg &= ~DMA_TIMEOUT_MASK;
>> -reg |= DIV_ROUND_UP(ring->dim.coal_usecs * 1000, 8192);
>> +reg |= DIV_ROUND_UP(usecs * 1000, 8192);
>>  bcmgenet_rdma_writel(priv, reg, DMA_RING0_TIMEOUT + i);
>>  }
>>  
>> @@ -645,6 +645,8 @@ static int bcmgenet_set_coalesce(struct net_device *dev,
>>  {
>>  struct bcmgenet_priv *priv = netdev_priv(dev);
>>  struct bcmgenet_rx_ring *ring;
>> +struct net_dim_cq_moder moder;
>> +u32 usecs, pkts;
>>  unsigned int i;
>>  
>>  /* Base system clock is 125Mhz, DMA timeout is this reference clock
>> @@ -682,25 +684,37 @@ static int bcmgenet_set_coalesce(struct net_device 
>> *dev,
>>  
>>  for (i = 0; i < priv->hw_params->rx_queues; i++) {
>>  ring = >rx_rings[i];
>> -ring->dim.coal_usecs = ec->rx_coalesce_usecs;
>> -ring->dim.coal_pkts = ec->rx_max_coalesced_frames;
>> -if (!ec->use_adaptive_rx_coalesce && ring->dim.use_dim) {
>> -ring->dim.coal_pkts = 1;
>> -ring->dim.coal_usecs = 0;
>> +
>> +ring->rx_coalesce_usecs = ec->rx_coalesce_usecs;
>> +ring->rx_max_coalesced_frames = ec->rx_max_coalesced_frames;
>> +usecs = ring->rx_coalesce_usecs;
>> +pkts = ring->rx_max_coalesced_frames;
>> +
>> +if (ec->use_adaptive_rx_coalesce) {
>> +moder = net_dim_get_def_profile(ring->dim.dim.mode);
>> +usecs = moder.usec;
>> +pkts = moder.pkts;
>>  }
>> +
>>  ring->dim.use_dim = ec->use_adaptive_rx_coalesce;
>> -bcmgenet_set_rx_coalesce(ring);
>> +bcmgenet_set_rx_coalesce(ring, usecs, pkts);
> You might want to put this loop code in a separate function with ring
> and ec parameters
> 
>>  }
>>  
>>  ring = >rx_rings[DESC_INDEX];
>> -ring->dim.coal_usecs = ec->rx_coalesce_usecs;
>> -ring->dim.coal_pkts = ec->rx_max_coalesced_frames;
>> -if (!ec->use_adaptive_rx_coalesce && ring->dim.use_dim) {
>> -ring->dim.coal_pkts = 1;
>> -ring->dim.c

Re: [PATCH net-next 3/3] net: bcmgenet: Fix coalescing settings handling

2018-03-29 Thread Doug Berger
On 03/27/2018 12:47 PM, Florian Fainelli wrote:
> There were a number of issues with setting the RX coalescing parameters:
> 
> - we would not be preserving values that would have been configured
>   across close/open calls, instead we would always reset to no timeout
>   and 1 interrupt per packet, this would also prevent DIM from setting its
>   default usec/pkts values
> 
> - when adaptive RX would be turned on, we woud not be fetching the
>   default parameters, we would stay with no timeout/1 packet per interrupt
>   until the estimator kicks in and changes that
> 
> - finally disabling adaptive RX coalescing while providing parameters
>   would not be honored, and we would stay with whatever DIM had previously
>   determined instead of the user requested parameters
> 
> Fixes: 9f4ca05827a2 ("net: bcmgenet: Add support for adaptive RX coalescing")
> Signed-off-by: Florian Fainelli 
> ---
>  drivers/net/ethernet/broadcom/genet/bcmgenet.c | 78 
> ++
>  drivers/net/ethernet/broadcom/genet/bcmgenet.h |  4 +-
>  2 files changed, 57 insertions(+), 25 deletions(-)
> 
> diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
> b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> index 7db8edc643ec..76409debb796 100644
> --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> @@ -625,18 +625,18 @@ static int bcmgenet_get_coalesce(struct net_device *dev,
>   return 0;
>  }
>  
> -static void bcmgenet_set_rx_coalesce(struct bcmgenet_rx_ring *ring)
> +static void bcmgenet_set_rx_coalesce(struct bcmgenet_rx_ring *ring,
> +  u32 usecs, u32 pkts)
>  {
>   struct bcmgenet_priv *priv = ring->priv;
>   unsigned int i = ring->index;
>   u32 reg;
>  
> - bcmgenet_rdma_ring_writel(priv, i, ring->dim.coal_pkts,
> -   DMA_MBUF_DONE_THRESH);
> + bcmgenet_rdma_ring_writel(priv, i, pkts, DMA_MBUF_DONE_THRESH);
>  
>   reg = bcmgenet_rdma_readl(priv, DMA_RING0_TIMEOUT + i);
>   reg &= ~DMA_TIMEOUT_MASK;
> - reg |= DIV_ROUND_UP(ring->dim.coal_usecs * 1000, 8192);
> + reg |= DIV_ROUND_UP(usecs * 1000, 8192);
>   bcmgenet_rdma_writel(priv, reg, DMA_RING0_TIMEOUT + i);
>  }
>  
> @@ -645,6 +645,8 @@ static int bcmgenet_set_coalesce(struct net_device *dev,
>  {
>   struct bcmgenet_priv *priv = netdev_priv(dev);
>   struct bcmgenet_rx_ring *ring;
> + struct net_dim_cq_moder moder;
> + u32 usecs, pkts;
>   unsigned int i;
>  
>   /* Base system clock is 125Mhz, DMA timeout is this reference clock
> @@ -682,25 +684,37 @@ static int bcmgenet_set_coalesce(struct net_device *dev,
>  
>   for (i = 0; i < priv->hw_params->rx_queues; i++) {
>   ring = >rx_rings[i];
> - ring->dim.coal_usecs = ec->rx_coalesce_usecs;
> - ring->dim.coal_pkts = ec->rx_max_coalesced_frames;
> - if (!ec->use_adaptive_rx_coalesce && ring->dim.use_dim) {
> - ring->dim.coal_pkts = 1;
> - ring->dim.coal_usecs = 0;
> +
> + ring->rx_coalesce_usecs = ec->rx_coalesce_usecs;
> + ring->rx_max_coalesced_frames = ec->rx_max_coalesced_frames;
> + usecs = ring->rx_coalesce_usecs;
> + pkts = ring->rx_max_coalesced_frames;
> +
> + if (ec->use_adaptive_rx_coalesce) {
> + moder = net_dim_get_def_profile(ring->dim.dim.mode);
> + usecs = moder.usec;
> + pkts = moder.pkts;
>   }
> +
>   ring->dim.use_dim = ec->use_adaptive_rx_coalesce;
> - bcmgenet_set_rx_coalesce(ring);
> + bcmgenet_set_rx_coalesce(ring, usecs, pkts);
You might want to put this loop code in a separate function with ring
and ec parameters

>   }
>  
>   ring = >rx_rings[DESC_INDEX];
> - ring->dim.coal_usecs = ec->rx_coalesce_usecs;
> - ring->dim.coal_pkts = ec->rx_max_coalesced_frames;
> - if (!ec->use_adaptive_rx_coalesce && ring->dim.use_dim) {
> - ring->dim.coal_pkts = 1;
> - ring->dim.coal_usecs = 0;
> +
> + ring->rx_coalesce_usecs = ec->rx_coalesce_usecs;
> + ring->rx_max_coalesced_frames = ec->rx_max_coalesced_frames;
> + usecs = ring->rx_coalesce_usecs;
> + pkts = ring->rx_max_coalesced_frames;
> +
> + if (ec->use_adaptive_rx_coalesce) {
> + moder = net_dim_get_def_profile(ring->dim.dim.mode);
> + usecs = moder.usec;
> + pkts = moder.pkts;
>   }
> +
>   ring->dim.use_dim = ec->use_adaptive_rx_coalesce;
> - bcmgenet_set_rx_coalesce(ring);
> + bcmgenet_set_rx_coalesce(ring, usecs, pkts);
so you don't need to repeat it here. (just for maintenance reasons)

>  
>   return 0;
>  }
> @@ -1924,10 +1938,7 @@ static void bcmgenet_dim_work(struct work_struct *work)
>   struct net_dim_cq_moder cur_profile =
>   

Re: [PATCH 02/10] net: bcmgenet: free netdev on of_match_node() error

2017-12-04 Thread Doug Berger
On 12/02/2017 11:26 AM, Arvind Yadav wrote:
> The change is to call free_netdev(), If of_match_node() will fail.
> 
> Signed-off-by: Arvind Yadav 
> ---
>  drivers/net/ethernet/broadcom/genet/bcmgenet.c | 6 --
>  1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
> b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> index e2f1268..e0a8f79 100644
> --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> @@ -3363,8 +3363,10 @@ static int bcmgenet_probe(struct platform_device *pdev)
>  
>   if (dn) {
>   of_id = of_match_node(bcmgenet_match, dn);
> - if (!of_id)
> - return -EINVAL;
> + if (!of_id) {
> + err = -EINVAL;
> + goto err;
> + }
>   }
>  
>   priv = netdev_priv(dev);
> 

I agree with the fix if you want to resubmit separate from this series
and please include a "fixes" tag.

Thanks,
Doug


Re: [PATCH 1/7 v2] net: bcmgenet: Fix platform_get_irq's error checking

2017-12-04 Thread Doug Berger
On 12/04/2017 09:48 AM, Arvind Yadav wrote:
> The platform_get_irq() function returns negative number if an error occurs,
> Zero if No irq is found and positive number if irq gets successful.
> platform_get_irq() error checking only for zero is not correct.
> 
> Signed-off-by: Arvind Yadav 
> ---
> changes in v2:
>  commit message was not correct.
> 
>  drivers/net/ethernet/broadcom/genet/bcmgenet.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
> b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> index 24b4f4c..e2f1268 100644
> --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> @@ -3371,7 +3371,7 @@ static int bcmgenet_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 || !priv->irq1) {
> + if (priv->irq0 <= 0 || priv->irq1 <= 0 || priv->wol_irq <= 0) {
>   dev_err(>dev, "can't find IRQs\n");
>   err = -EINVAL;
>   goto err;
> 

The absence of a Wake-on-LAN interrupt (wol_irq <= 0) is not a terminal
error for the driver so it should not be included in this check.

The error checking for irq0 and irq1 is appropriate to add, but it
sounds like David Miller is proposing changing platform_get_irq() so
I'll let that dust settle before saying whether <= or < is appropriate.

Thanks,
Doug



Re: [PATCH net-next] net: bcmgenet: Avoid calling platform_device_put() twice in bcmgenet_mii_exit()

2017-10-30 Thread Doug Berger
On 10/27/2017 10:05 PM, Wei Yongjun wrote:
> Remove platform_device_put() call after platform_device_unregister()
> from function bcmgenet_mii_exit(), otherwise, we will call
> platform_device_put() twice.
> 
> Fixes: 9a4e79697009 ("net: bcmgenet: utilize generic Broadcom UniMAC
> MDIO controller driver")
> Signed-off-by: Wei Yongjun <weiyongj...@huawei.com>
> ---
>  drivers/net/ethernet/broadcom/genet/bcmmii.c | 1 -
>  1 file changed, 1 deletion(-)
> 
> diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c 
> b/drivers/net/ethernet/broadcom/genet/bcmmii.c
> index ba3fcfd..5333274 100644
> --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
> +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
> @@ -571,5 +571,4 @@ void bcmgenet_mii_exit(struct net_device *dev)
>   of_phy_deregister_fixed_link(dn);
>   of_node_put(priv->phy_dn);
>   platform_device_unregister(priv->mii_pdev);
> - platform_device_put(priv->mii_pdev);
>  }
> 
Acked-by: Doug Berger <open...@gmail.com>


[PATCH net-next 1/9] net: bcmgenet: correct bad merge

2017-10-25 Thread Doug Berger
As noted in the net-next submission for GENETv5 support [1], there
were merge conflicts with an earlier net submission [2] that had not
yet found its way to the net-next repository.

Unfortunately, when the branches were merged the conflicts were not
correctly resolved.  This commit attempts to correct that.

[1] https://lkml.org/lkml/2017/3/13/1145
[2] https://lkml.org/lkml/2017/3/9/890

Fixes: 101c431492d2 ("Merge 
git://git.kernel.org/pub/scm/linux/kernel/git/davem/net")
Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 18 +-
 1 file changed, 1 insertion(+), 17 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 9cebca896913..f6e8e01be1c8 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -2602,12 +2602,6 @@ static void bcmgenet_irq_task(struct work_struct *work)
priv->irq0_stat = 0;
spin_unlock_irqrestore(>lock, flags);
 
-   if (status & 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 (status & UMAC_IRQ_LINK_EVENT)
phy_mac_interrupt(priv->phydev,
@@ -2698,23 +2692,13 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id)
}
}
 
-   if (priv->irq0_stat & (UMAC_IRQ_PHY_DET_R |
-   UMAC_IRQ_PHY_DET_F |
-   UMAC_IRQ_LINK_EVENT |
-   UMAC_IRQ_HFB_SM |
-   UMAC_IRQ_HFB_MM)) {
-   /* all other interested interrupts handled in bottom half */
-   schedule_work(>bcmgenet_irq_work);
-   }
-
if ((priv->hw_params->flags & GENET_HAS_MDIO_INTR) &&
status & (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR)) {
wake_up(>wq);
}
 
/* all other interested interrupts handled in bottom half */
-   status &= (UMAC_IRQ_LINK_EVENT |
-  UMAC_IRQ_MPD_R);
+   status &= UMAC_IRQ_LINK_EVENT;
if (status) {
/* Save irq status for bottom-half processing. */
spin_lock_irqsave(>lock, flags);
-- 
2.14.1



[PATCH net-next 2/9] net: bcmgenet: prevent duplicate calls of bcmgenet_dma_teardown

2017-10-25 Thread Doug Berger
When bcmgenet_dma_teardown is called from bcmgenet_fini_dma it ends
up getting called twice from the bcmgenet_close and bcmgenet_suspend
functions (once directly and once inside the bcmgenet_fini_dma call).

This commit removes the call from bcmgenet_fini_dma and ensures that
bcmgenet_dma_teardown is called before bcmgenet_fini_dma in all paths
of execution.

Fixes: 4a0c081eff43 ("net: bcmgenet: call bcmgenet_dma_teardown in 
bcmgenet_fini_dma")
Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index f6e8e01be1c8..78368466eb70 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -2505,9 +2505,6 @@ static void bcmgenet_fini_dma(struct bcmgenet_priv *priv)
bcmgenet_fini_rx_napi(priv);
bcmgenet_fini_tx_napi(priv);
 
-   /* disable DMA */
-   bcmgenet_dma_teardown(priv);
-
for (i = 0; i < priv->num_tx_bds; i++) {
cb = priv->tx_cbs + i;
skb = bcmgenet_free_tx_cb(>pdev->dev, cb);
@@ -2930,6 +2927,7 @@ static int bcmgenet_open(struct net_device *dev)
 err_irq0:
free_irq(priv->irq0, priv);
 err_fini_dma:
+   bcmgenet_dma_teardown(priv);
bcmgenet_fini_dma(priv);
 err_clk_disable:
if (priv->internal_phy)
-- 
2.14.1



[PATCH net-next 5/9] net: bcmgenet: cleanup ring interrupt masking and unmasking

2017-10-25 Thread Doug Berger
Since the NAPI interrupts are basically ignored when NAPI is
disabled we don't need to mask them within the functions
bcmgenet_disable_tx_napi() and bcmgenet_disable_rx_napi().
So wait until all NAPI instances are disabled and mask all of the
bcmgenet driver interrupts together in bcmgenet_netif_stop().

The interrupts can still be enabled in the functions
bcmgenet_enable_tx_napi() and bcmgenet_enable_rx_napi(), but use
the ring context int_enable() method to keep the functionality
consistent and the code cleaner.

Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 28 +-
 1 file changed, 5 insertions(+), 23 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 9ce6671e8916..88aacf3bf44f 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -2147,33 +2147,24 @@ static int bcmgenet_init_rx_ring(struct bcmgenet_priv 
*priv,
 static void bcmgenet_enable_tx_napi(struct bcmgenet_priv *priv)
 {
unsigned int i;
-   u32 int0_enable = UMAC_IRQ_TXDMA_DONE;
-   u32 int1_enable = 0;
struct bcmgenet_tx_ring *ring;
 
for (i = 0; i < priv->hw_params->tx_queues; ++i) {
ring = >tx_rings[i];
napi_enable(>napi);
-   int1_enable |= (1 << i);
+   ring->int_enable(ring);
}
 
ring = >tx_rings[DESC_INDEX];
napi_enable(>napi);
-
-   bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR);
-   bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR);
+   ring->int_enable(ring);
 }
 
 static void bcmgenet_disable_tx_napi(struct bcmgenet_priv *priv)
 {
unsigned int i;
-   u32 int0_disable = UMAC_IRQ_TXDMA_DONE;
-   u32 int1_disable = 0x;
struct bcmgenet_tx_ring *ring;
 
-   bcmgenet_intrl2_0_writel(priv, int0_disable, INTRL2_CPU_MASK_SET);
-   bcmgenet_intrl2_1_writel(priv, int1_disable, INTRL2_CPU_MASK_SET);
-
for (i = 0; i < priv->hw_params->tx_queues; ++i) {
ring = >tx_rings[i];
napi_disable(>napi);
@@ -2269,33 +2260,24 @@ static void bcmgenet_init_tx_queues(struct net_device 
*dev)
 static void bcmgenet_enable_rx_napi(struct bcmgenet_priv *priv)
 {
unsigned int i;
-   u32 int0_enable = UMAC_IRQ_RXDMA_DONE;
-   u32 int1_enable = 0;
struct bcmgenet_rx_ring *ring;
 
for (i = 0; i < priv->hw_params->rx_queues; ++i) {
ring = >rx_rings[i];
napi_enable(>napi);
-   int1_enable |= (1 << (UMAC_IRQ1_RX_INTR_SHIFT + i));
+   ring->int_enable(ring);
}
 
ring = >rx_rings[DESC_INDEX];
napi_enable(>napi);
-
-   bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR);
-   bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR);
+   ring->int_enable(ring);
 }
 
 static void bcmgenet_disable_rx_napi(struct bcmgenet_priv *priv)
 {
unsigned int i;
-   u32 int0_disable = UMAC_IRQ_RXDMA_DONE;
-   u32 int1_disable = 0x << UMAC_IRQ1_RX_INTR_SHIFT;
struct bcmgenet_rx_ring *ring;
 
-   bcmgenet_intrl2_0_writel(priv, int0_disable, INTRL2_CPU_MASK_SET);
-   bcmgenet_intrl2_1_writel(priv, int1_disable, INTRL2_CPU_MASK_SET);
-
for (i = 0; i < priv->hw_params->rx_queues; ++i) {
ring = >rx_rings[i];
napi_disable(>napi);
@@ -2888,9 +2870,9 @@ static void bcmgenet_netif_stop(struct net_device *dev)
 
netif_tx_stop_all_queues(dev);
phy_stop(priv->phydev);
-   bcmgenet_intr_disable(priv);
bcmgenet_disable_rx_napi(priv);
bcmgenet_disable_tx_napi(priv);
+   bcmgenet_intr_disable(priv);
 
/* Wait for pending work items to complete. Since interrupts are
 * disabled no new work will be scheduled.
-- 
2.14.1



[PATCH net-next 3/9] net: bcmgenet: enable loopback during UniMAC sw_reset

2017-10-25 Thread Doug Berger
It is necessary for the UniMAC to be clocked at least 5 cycles
while the sw_reset is asserted to ensure a clean reset.

It was discovered that this condition was not being met when
connected to an external RGMII PHY that disabled the Rx clock in
the Power Save state.

This commit modifies the reset_umac function to place the (RG)MII
interface into a local loopback mode where the Rx clock comes
from the GENET sourced Tx clk during the sw_reset to ensure the
presence and stability of the clock.

In addition, it turns out that the sw_reset of the UniMAC is not
self clearing, but this was masked by a bug in the timeout code.

The sw_reset is now explicitly cleared by zeroing the UMAC_CMD
register before returning from reset_umac which makes it no
longer necessary to do so in init_umac and makes the clearing of
CMD_TX_EN and CMD_RX_EN by umac_enable_set redundant. The
timeout code (and its associated bug) are removed so reset_umac
no longer needs to return a result, and that means init_umac
that calls reset_umac does not need to as well.

Fixes: 1c1008c793fa ("net: bcmgenet: add main driver file")
Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 55 +-
 1 file changed, 10 insertions(+), 45 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 78368466eb70..3da177fa2659 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -1935,12 +1935,8 @@ static void umac_enable_set(struct bcmgenet_priv *priv, 
u32 mask, bool enable)
usleep_range(1000, 2000);
 }
 
-static int reset_umac(struct bcmgenet_priv *priv)
+static void reset_umac(struct bcmgenet_priv *priv)
 {
-   struct device *kdev = >pdev->dev;
-   unsigned int timeout = 0;
-   u32 reg;
-
/* 7358a0/7552a0: bad default in RBUF_FLUSH_CTRL.umac_sw_rst */
bcmgenet_rbuf_ctrl_set(priv, 0);
udelay(10);
@@ -1948,23 +1944,10 @@ static int reset_umac(struct bcmgenet_priv *priv)
/* disable MAC while updating its registers */
bcmgenet_umac_writel(priv, 0, UMAC_CMD);
 
-   /* issue soft reset, wait for it to complete */
-   bcmgenet_umac_writel(priv, CMD_SW_RESET, UMAC_CMD);
-   while (timeout++ < 1000) {
-   reg = bcmgenet_umac_readl(priv, UMAC_CMD);
-   if (!(reg & CMD_SW_RESET))
-   return 0;
-
-   udelay(1);
-   }
-
-   if (timeout == 1000) {
-   dev_err(kdev,
-   "timeout waiting for MAC to come out of reset\n");
-   return -ETIMEDOUT;
-   }
-
-   return 0;
+   /* issue soft reset with (rg)mii loopback to ensure a stable rxclk */
+   bcmgenet_umac_writel(priv, CMD_SW_RESET | CMD_LCL_LOOP_EN, UMAC_CMD);
+   udelay(2);
+   bcmgenet_umac_writel(priv, 0, UMAC_CMD);
 }
 
 static void bcmgenet_intr_disable(struct bcmgenet_priv *priv)
@@ -1994,20 +1977,16 @@ static void bcmgenet_link_intr_enable(struct 
bcmgenet_priv *priv)
bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR);
 }
 
-static int init_umac(struct bcmgenet_priv *priv)
+static void init_umac(struct bcmgenet_priv *priv)
 {
struct device *kdev = >pdev->dev;
-   int ret;
u32 reg;
u32 int0_enable = 0;
 
dev_dbg(>pdev->dev, "bcmgenet: init_umac\n");
 
-   ret = reset_umac(priv);
-   if (ret)
-   return ret;
+   reset_umac(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,
@@ -2046,8 +2025,6 @@ static int init_umac(struct bcmgenet_priv *priv)
bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR);
 
dev_dbg(kdev, "done init umac\n");
-
-   return 0;
 }
 
 /* Initialize a Tx ring along with corresponding hardware registers */
@@ -2863,12 +2840,7 @@ static int bcmgenet_open(struct net_device *dev)
/* take MAC out of reset */
bcmgenet_umac_reset(priv);
 
-   ret = init_umac(priv);
-   if (ret)
-   goto err_clk_disable;
-
-   /* disable ethernet MAC while updating its registers */
-   umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, false);
+   init_umac(priv);
 
/* Make sure we reflect the value of CRC_CMD_FWD */
reg = bcmgenet_umac_readl(priv, UMAC_CMD);
@@ -3546,9 +3518,7 @@ static int bcmgenet_probe(struct platform_device *pdev)
!strcasecmp(phy_mode_str, "internal"))
bcmgenet_power_up(priv, GENET_POWER_PASSIVE);
 
-   err = reset_umac(priv);
-   if (err)
-   goto err_clk_disable;
+   reset_umac(priv);
 
err = bcmgenet_mii_init(dev);
 

[PATCH net-next 6/9] net: bcmgenet: rework bcmgenet_netif_start and bcmgenet_netif_stop

2017-10-25 Thread Doug Berger
This commit consolidates more common functionality from
bcmgenet_close and bcmgenet_suspend into bcmgenet_netif_stop and
modifies the start and stop sequences to better suit the design
of the GENET hardware.

Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 49 +-
 1 file changed, 17 insertions(+), 32 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 88aacf3bf44f..747224714394 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -2763,11 +2763,11 @@ static void bcmgenet_netif_start(struct net_device *dev)
 
/* Start the network engine */
bcmgenet_enable_rx_napi(priv);
-   bcmgenet_enable_tx_napi(priv);
 
umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, true);
 
netif_tx_start_all_queues(dev);
+   bcmgenet_enable_tx_napi(priv);
 
/* Monitor link interrupts now */
bcmgenet_link_intr_enable(priv);
@@ -2868,10 +2868,19 @@ static void bcmgenet_netif_stop(struct net_device *dev)
 {
struct bcmgenet_priv *priv = netdev_priv(dev);
 
+   bcmgenet_disable_tx_napi(priv);
netif_tx_stop_all_queues(dev);
+
+   /* Disable MAC receive */
+   umac_enable_set(priv, CMD_RX_EN, false);
+
+   bcmgenet_dma_teardown(priv);
+
+   /* Disable MAC transmit. TX DMA disabled must be done before this */
+   umac_enable_set(priv, CMD_TX_EN, false);
+
phy_stop(priv->phydev);
bcmgenet_disable_rx_napi(priv);
-   bcmgenet_disable_tx_napi(priv);
bcmgenet_intr_disable(priv);
 
/* Wait for pending work items to complete. Since interrupts are
@@ -2883,12 +2892,16 @@ static void bcmgenet_netif_stop(struct net_device *dev)
priv->old_speed = -1;
priv->old_duplex = -1;
priv->old_pause = -1;
+
+   /* tx reclaim */
+   bcmgenet_tx_reclaim_all(dev);
+   bcmgenet_fini_dma(priv);
 }
 
 static int bcmgenet_close(struct net_device *dev)
 {
struct bcmgenet_priv *priv = netdev_priv(dev);
-   int ret;
+   int ret = 0;
 
netif_dbg(priv, ifdown, dev, "bcmgenet_close\n");
 
@@ -2897,20 +2910,6 @@ static int bcmgenet_close(struct net_device *dev)
/* Really kill the PHY state machine and disconnect from it */
phy_disconnect(priv->phydev);
 
-   /* 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 must be done before this */
-   umac_enable_set(priv, CMD_TX_EN, false);
-
-   /* tx reclaim */
-   bcmgenet_tx_reclaim_all(dev);
-   bcmgenet_fini_dma(priv);
-
free_irq(priv->irq0, priv);
free_irq(priv->irq1, priv);
 
@@ -3522,7 +3521,7 @@ static int bcmgenet_suspend(struct device *d)
 {
struct net_device *dev = dev_get_drvdata(d);
struct bcmgenet_priv *priv = netdev_priv(dev);
-   int ret;
+   int ret = 0;
 
if (!netif_running(dev))
return 0;
@@ -3534,20 +3533,6 @@ static int bcmgenet_suspend(struct device *d)
 
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 must be 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) {
ret = bcmgenet_power_down(priv, GENET_POWER_WOL_MAGIC);
-- 
2.14.1



[PATCH net-next 4/9] net: bcmgenet: move NAPI initialization to ring initialization

2017-10-25 Thread Doug Berger
Since each ring has its own NAPI instance it might as well be
initialized along with the other ring context.

Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 42 +-
 1 file changed, 8 insertions(+), 34 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 3da177fa2659..9ce6671e8916 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -2081,6 +2081,10 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv 
*priv,
  TDMA_WRITE_PTR);
bcmgenet_tdma_ring_writel(priv, index, end_ptr * words_per_bd - 1,
  DMA_END_ADDR);
+
+   /* Initialize Tx NAPI */
+   netif_napi_add(priv->dev, >napi, bcmgenet_tx_poll,
+  NAPI_POLL_WEIGHT);
 }
 
 /* Initialize a RDMA ring */
@@ -2112,6 +2116,10 @@ static int bcmgenet_init_rx_ring(struct bcmgenet_priv 
*priv,
if (ret)
return ret;
 
+   /* Initialize Rx NAPI */
+   netif_napi_add(priv->dev, >napi, bcmgenet_rx_poll,
+  NAPI_POLL_WEIGHT);
+
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, 1, DMA_MBUF_DONE_THRESH);
@@ -2136,20 +2144,6 @@ static int bcmgenet_init_rx_ring(struct bcmgenet_priv 
*priv,
return ret;
 }
 
-static void bcmgenet_init_tx_napi(struct bcmgenet_priv *priv)
-{
-   unsigned int i;
-   struct bcmgenet_tx_ring *ring;
-
-   for (i = 0; i < priv->hw_params->tx_queues; ++i) {
-   ring = >tx_rings[i];
-   netif_tx_napi_add(priv->dev, >napi, bcmgenet_tx_poll, 64);
-   }
-
-   ring = >tx_rings[DESC_INDEX];
-   netif_tx_napi_add(priv->dev, >napi, bcmgenet_tx_poll, 64);
-}
-
 static void bcmgenet_enable_tx_napi(struct bcmgenet_priv *priv)
 {
unsigned int i;
@@ -2263,9 +2257,6 @@ static void bcmgenet_init_tx_queues(struct net_device 
*dev)
bcmgenet_tdma_writel(priv, dma_priority[1], DMA_PRIORITY_1);
bcmgenet_tdma_writel(priv, dma_priority[2], DMA_PRIORITY_2);
 
-   /* Initialize Tx NAPI */
-   bcmgenet_init_tx_napi(priv);
-
/* Enable Tx queues */
bcmgenet_tdma_writel(priv, ring_cfg, DMA_RING_CFG);
 
@@ -2275,20 +2266,6 @@ static void bcmgenet_init_tx_queues(struct net_device 
*dev)
bcmgenet_tdma_writel(priv, dma_ctrl, DMA_CTRL);
 }
 
-static void bcmgenet_init_rx_napi(struct bcmgenet_priv *priv)
-{
-   unsigned int i;
-   struct bcmgenet_rx_ring *ring;
-
-   for (i = 0; i < priv->hw_params->rx_queues; ++i) {
-   ring = >rx_rings[i];
-   netif_napi_add(priv->dev, >napi, bcmgenet_rx_poll, 64);
-   }
-
-   ring = >rx_rings[DESC_INDEX];
-   netif_napi_add(priv->dev, >napi, bcmgenet_rx_poll, 64);
-}
-
 static void bcmgenet_enable_rx_napi(struct bcmgenet_priv *priv)
 {
unsigned int i;
@@ -2391,9 +2368,6 @@ static int bcmgenet_init_rx_queues(struct net_device *dev)
ring_cfg |= (1 << DESC_INDEX);
dma_ctrl |= (1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT));
 
-   /* Initialize Rx NAPI */
-   bcmgenet_init_rx_napi(priv);
-
/* Enable rings */
bcmgenet_rdma_writel(priv, ring_cfg, DMA_RING_CFG);
 
-- 
2.14.1



[PATCH net-next 9/9] net: bcmgenet: use dev->phydev instead of priv->phydev

2017-10-25 Thread Doug Berger
Now that the software reset of the PHY has been removed it is no
longer necessary to retain a private pointer to the phydev for
use when the PHY is detached (which isn't generally safe anyway).

The driver now uses the phydev member attached to the net_device.

For ethtool commands that have a PHY component, an explicit check
is made to prevent accessing an invalid phydev pointer when one
is not attached (e.g. interface is down).

Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 47 +-
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |  1 -
 drivers/net/ethernet/broadcom/genet/bcmmii.c   | 17 --
 3 files changed, 31 insertions(+), 34 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 54b09a01cb2c..9713374ebf14 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -488,15 +488,13 @@ static void bcmgenet_complete(struct net_device *dev)
 static int bcmgenet_get_link_ksettings(struct net_device *dev,
   struct ethtool_link_ksettings *cmd)
 {
-   struct bcmgenet_priv *priv = netdev_priv(dev);
-
if (!netif_running(dev))
return -EINVAL;
 
-   if (!priv->phydev)
+   if (!dev->phydev)
return -ENODEV;
 
-   phy_ethtool_ksettings_get(priv->phydev, cmd);
+   phy_ethtool_ksettings_get(dev->phydev, cmd);
 
return 0;
 }
@@ -504,15 +502,13 @@ static int bcmgenet_get_link_ksettings(struct net_device 
*dev,
 static int bcmgenet_set_link_ksettings(struct net_device *dev,
   const struct ethtool_link_ksettings *cmd)
 {
-   struct bcmgenet_priv *priv = netdev_priv(dev);
-
if (!netif_running(dev))
return -EINVAL;
 
-   if (!priv->phydev)
+   if (!dev->phydev)
return -ENODEV;
 
-   return phy_ethtool_ksettings_set(priv->phydev, cmd);
+   return phy_ethtool_ksettings_set(dev->phydev, cmd);
 }
 
 static int bcmgenet_set_rx_csum(struct net_device *dev,
@@ -1042,11 +1038,14 @@ static int bcmgenet_get_eee(struct net_device *dev, 
struct ethtool_eee *e)
if (GENET_IS_V1(priv))
return -EOPNOTSUPP;
 
+   if (!dev->phydev)
+   return -ENODEV;
+
e->eee_enabled = p->eee_enabled;
e->eee_active = p->eee_active;
e->tx_lpi_timer = bcmgenet_umac_readl(priv, UMAC_EEE_LPI_TIMER);
 
-   return phy_ethtool_get_eee(priv->phydev, e);
+   return phy_ethtool_get_eee(dev->phydev, e);
 }
 
 static int bcmgenet_set_eee(struct net_device *dev, struct ethtool_eee *e)
@@ -1058,12 +1057,15 @@ static int bcmgenet_set_eee(struct net_device *dev, 
struct ethtool_eee *e)
if (GENET_IS_V1(priv))
return -EOPNOTSUPP;
 
+   if (!dev->phydev)
+   return -ENODEV;
+
p->eee_enabled = e->eee_enabled;
 
if (!p->eee_enabled) {
bcmgenet_eee_enable_set(dev, false);
} else {
-   ret = phy_init_eee(priv->phydev, 0);
+   ret = phy_init_eee(dev->phydev, 0);
if (ret) {
netif_err(priv, hw, dev, "EEE initialization failed\n");
return ret;
@@ -1073,7 +1075,7 @@ static int bcmgenet_set_eee(struct net_device *dev, 
struct ethtool_eee *e)
bcmgenet_eee_enable_set(dev, true);
}
 
-   return phy_ethtool_set_eee(priv->phydev, e);
+   return phy_ethtool_set_eee(dev->phydev, e);
 }
 
 /* standard ethtool support functions. */
@@ -1107,7 +1109,7 @@ static int bcmgenet_power_down(struct bcmgenet_priv *priv,
 
switch (mode) {
case GENET_POWER_CABLE_SENSE:
-   phy_detach(priv->phydev);
+   phy_detach(priv->dev->phydev);
break;
 
case GENET_POWER_WOL_MAGIC:
@@ -1192,15 +1194,13 @@ static void bcmgenet_power_up(struct bcmgenet_priv 
*priv,
 /* ioctl handle special commands that are not present in ethtool. */
 static int bcmgenet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-   struct bcmgenet_priv *priv = netdev_priv(dev);
-
if (!netif_running(dev))
return -EINVAL;
 
-   if (!priv->phydev)
+   if (!dev->phydev)
return -ENODEV;
 
-   return phy_mii_ioctl(priv->phydev, rq, cmd);
+   return phy_mii_ioctl(dev->phydev, rq, cmd);
 }
 
 static struct enet_cb *bcmgenet_get_txcb(struct bcmgenet_priv *priv,
@@ -2529,7 +2529,7 @@ static void bcmgenet_irq_task(struct work_struct *work)
 
/* Link UP/DOWN event */
if (status & UMAC_IRQ_LINK_EVENT)
-   phy_mac_interrupt(priv->phydev,
+   phy_mac_interrupt(priv->dev->phydev,
  

[PATCH net-next 7/9] net: bcmgenet: relax lock constraints to reduce IRQ latency

2017-10-25 Thread Doug Berger
Since the ring locks are not used in a hard IRQ context it is often
not necessary to disable global IRQs while waiting on a lock.

Using less restrictive lock and unlock calls improves the real-time
responsiveness of the system.

Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 25 ++---
 1 file changed, 10 insertions(+), 15 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 747224714394..91f52c1b5108 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -1405,11 +1405,10 @@ static unsigned int bcmgenet_tx_reclaim(struct 
net_device *dev,
struct bcmgenet_tx_ring *ring)
 {
unsigned int released;
-   unsigned long flags;
 
-   spin_lock_irqsave(>lock, flags);
+   spin_lock_bh(>lock);
released = __bcmgenet_tx_reclaim(dev, ring);
-   spin_unlock_irqrestore(>lock, flags);
+   spin_unlock_bh(>lock);
 
return released;
 }
@@ -1420,15 +1419,14 @@ static int bcmgenet_tx_poll(struct napi_struct *napi, 
int budget)
container_of(napi, struct bcmgenet_tx_ring, napi);
unsigned int work_done = 0;
struct netdev_queue *txq;
-   unsigned long flags;
 
-   spin_lock_irqsave(>lock, flags);
+   spin_lock(>lock);
work_done = __bcmgenet_tx_reclaim(ring->priv->dev, ring);
if (ring->free_bds > (MAX_SKB_FRAGS + 1)) {
txq = netdev_get_tx_queue(ring->priv->dev, ring->queue);
netif_tx_wake_queue(txq);
}
-   spin_unlock_irqrestore(>lock, flags);
+   spin_unlock(>lock);
 
if (work_done == 0) {
napi_complete(napi);
@@ -1523,7 +1521,6 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, 
struct net_device *dev)
struct bcmgenet_tx_ring *ring = NULL;
struct enet_cb *tx_cb_ptr;
struct netdev_queue *txq;
-   unsigned long flags = 0;
int nr_frags, index;
dma_addr_t mapping;
unsigned int size;
@@ -1550,7 +1547,7 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, 
struct net_device *dev)
 
nr_frags = skb_shinfo(skb)->nr_frags;
 
-   spin_lock_irqsave(>lock, flags);
+   spin_lock(>lock);
if (ring->free_bds <= (nr_frags + 1)) {
if (!netif_tx_queue_stopped(txq)) {
netif_tx_stop_queue(txq);
@@ -1645,7 +1642,7 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, 
struct net_device *dev)
bcmgenet_tdma_ring_writel(priv, ring->index,
  ring->prod_index, TDMA_PROD_INDEX);
 out:
-   spin_unlock_irqrestore(>lock, flags);
+   spin_unlock(>lock);
 
return ret;
 
@@ -2520,17 +2517,16 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv)
 /* Interrupt bottom half */
 static void bcmgenet_irq_task(struct work_struct *work)
 {
-   unsigned long flags;
unsigned int status;
struct bcmgenet_priv *priv = container_of(
work, struct bcmgenet_priv, bcmgenet_irq_work);
 
netif_dbg(priv, intr, priv->dev, "%s\n", __func__);
 
-   spin_lock_irqsave(>lock, flags);
+   spin_lock_irq(>lock);
status = priv->irq0_stat;
priv->irq0_stat = 0;
-   spin_unlock_irqrestore(>lock, flags);
+   spin_unlock_irq(>lock);
 
/* Link UP/DOWN event */
if (status & UMAC_IRQ_LINK_EVENT)
@@ -2927,7 +2923,6 @@ static void bcmgenet_dump_tx_queue(struct 
bcmgenet_tx_ring *ring)
u32 p_index, c_index, intsts, intmsk;
struct netdev_queue *txq;
unsigned int free_bds;
-   unsigned long flags;
bool txq_stopped;
 
if (!netif_msg_tx_err(priv))
@@ -2935,7 +2930,7 @@ static void bcmgenet_dump_tx_queue(struct 
bcmgenet_tx_ring *ring)
 
txq = netdev_get_tx_queue(priv->dev, ring->queue);
 
-   spin_lock_irqsave(>lock, flags);
+   spin_lock(>lock);
if (ring->index == DESC_INDEX) {
intsts = ~bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_MASK_STATUS);
intmsk = UMAC_IRQ_TXDMA_DONE | UMAC_IRQ_TXDMA_MBDONE;
@@ -2947,7 +2942,7 @@ static void bcmgenet_dump_tx_queue(struct 
bcmgenet_tx_ring *ring)
p_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_PROD_INDEX);
txq_stopped = netif_tx_queue_stopped(txq);
free_bds = ring->free_bds;
-   spin_unlock_irqrestore(>lock, flags);
+   spin_unlock(>lock);
 
netif_err(priv, tx_err, priv->dev, "Ring %d queue %d status summary\n"
  "TX queue status: %s, interrupts: %s\n"
-- 
2.14.1



[PATCH net-next 8/9] Revert "net: bcmgenet: Software reset EPHY after power on"

2017-10-25 Thread Doug Berger
With commit f7d72996e222 ("net: bcmgenet: enable loopback during
UniMAC sw_reset") it is no longer necessary to force the software
reset of the internal EPHY before resetting the UniMAC to ensure a
clean reset.

Therefore this commit reverts commit 5dbebbb44a6a ("net: bcmgenet:
Software reset EPHY after power on").

Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c |  1 -
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |  1 -
 drivers/net/ethernet/broadcom/genet/bcmmii.c   | 16 
 3 files changed, 18 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 91f52c1b5108..54b09a01cb2c 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -1172,7 +1172,6 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv,
}
bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
bcmgenet_phy_power_set(priv->dev, true);
-   bcmgenet_mii_reset(priv->dev);
break;
 
case GENET_POWER_CABLE_SENSE:
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
index 4c49d0b97748..35f18a8d1ce6 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
@@ -711,7 +711,6 @@ int bcmgenet_mii_init(struct net_device *dev);
 int bcmgenet_mii_config(struct net_device *dev, bool init);
 int bcmgenet_mii_probe(struct net_device *dev);
 void bcmgenet_mii_exit(struct net_device *dev);
-void bcmgenet_mii_reset(struct net_device *dev);
 void bcmgenet_phy_power_set(struct net_device *dev, bool enable);
 void bcmgenet_mii_setup(struct net_device *dev);
 
diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c 
b/drivers/net/ethernet/broadcom/genet/bcmmii.c
index 18f5723be2c9..a5ae9b78389c 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
@@ -121,22 +121,6 @@ static int bcmgenet_fixed_phy_link_update(struct 
net_device *dev,
return 0;
 }
 
-/* Perform a voluntary PHY software reset, since the EPHY is very finicky about
- * not doing it and will start corrupting packets
- */
-void bcmgenet_mii_reset(struct net_device *dev)
-{
-   struct bcmgenet_priv *priv = netdev_priv(dev);
-
-   if (GENET_IS_V4(priv))
-   return;
-
-   if (priv->phydev) {
-   phy_init_hw(priv->phydev);
-   phy_start_aneg(priv->phydev);
-   }
-}
-
 void bcmgenet_phy_power_set(struct net_device *dev, bool enable)
 {
struct bcmgenet_priv *priv = netdev_priv(dev);
-- 
2.14.1



[PATCH net-next 0/9] net: bcmgenet: start/stop sequence refinement

2017-10-25 Thread Doug Berger
This commit set is the result of an investigation into an issue that
occurred when bringing the interface up and down repeatedly with an
external 100BASE-T PHY. In some cases the MAC would experience mass
receive packet duplication that could in rare cases lead to a stall
from overflow.  The fix for this is contained in the third commit.

The first 3 commits represent bug fixes that should be applied to the
net repository and are candidates for backporting to stable releases.
The remaining commits are enhancements which is why the set is being
submitted to net-next but they are implemented on top of the fixes.

The first fix is provided as justification for why the set isn't
split between a net submission and a net-next submission.

Doug Berger (9):
  net: bcmgenet: correct bad merge
  net: bcmgenet: prevent duplicate calls of bcmgenet_dma_teardown
  net: bcmgenet: enable loopback during UniMAC sw_reset
  net: bcmgenet: move NAPI initialization to ring initialization
  net: bcmgenet: cleanup ring interrupt masking and unmasking
  net: bcmgenet: rework bcmgenet_netif_start and bcmgenet_netif_stop
  net: bcmgenet: relax lock constraints to reduce IRQ latency
  Revert "net: bcmgenet: Software reset EPHY after power on"
  net: bcmgenet: use dev->phydev instead of priv->phydev

 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 269 +++--
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |   2 -
 drivers/net/ethernet/broadcom/genet/bcmmii.c   |  33 +--
 3 files changed, 83 insertions(+), 221 deletions(-)

-- 
2.14.1



Re: [PATCH net] Revert "net: bcmgenet: Remove init parameter from bcmgenet_mii_config"

2017-07-31 Thread Doug Berger
On 07/31/2017 11:05 AM, Florian Fainelli wrote:
> This reverts commit 28b45910ccda ("net: bcmgenet: Remove init parameter
> from bcmgenet_mii_config") because in the process of moving from
> dev_info() to dev_info_once() we essentially lost the helpful printed
> messages once the second instance of the driver is loaded.
> dev_info_once() does not actually print the message once per device
> instance, but once period.
> 
> Fixes: 28b45910ccda ("net: bcmgenet: Remove init parameter from 
> bcmgenet_mii_config")
> Signed-off-by: Florian Fainelli <f.faine...@gmail.com>
> ---
>  drivers/net/ethernet/broadcom/genet/bcmgenet.c | 2 +-
>  drivers/net/ethernet/broadcom/genet/bcmgenet.h | 2 +-
>  drivers/net/ethernet/broadcom/genet/bcmmii.c   | 7 ---
>  3 files changed, 6 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
> b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> index 7b0b399aaedd..a981c4ee9d72 100644
> --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> @@ -3669,7 +3669,7 @@ static int bcmgenet_resume(struct device *d)
>  
>   phy_init_hw(priv->phydev);
>   /* Speed settings must be restored */
> - bcmgenet_mii_config(priv->dev);
> + bcmgenet_mii_config(priv->dev, false);
>  
>   /* disable ethernet MAC while updating its registers */
>   umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, false);
> diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h 
> b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
> index b9344de669f8..3a34fdba5301 100644
> --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
> +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
> @@ -698,7 +698,7 @@ GENET_IO_MACRO(rbuf, GENET_RBUF_OFF);
>  
>  /* MDIO routines */
>  int bcmgenet_mii_init(struct net_device *dev);
> -int bcmgenet_mii_config(struct net_device *dev);
> +int bcmgenet_mii_config(struct net_device *dev, bool init);
>  int bcmgenet_mii_probe(struct net_device *dev);
>  void bcmgenet_mii_exit(struct net_device *dev);
>  void bcmgenet_mii_reset(struct net_device *dev);
> diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c 
> b/drivers/net/ethernet/broadcom/genet/bcmmii.c
> index 071fcbd14e6a..30cb97b4a1d7 100644
> --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
> +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
> @@ -238,7 +238,7 @@ static void bcmgenet_moca_phy_setup(struct bcmgenet_priv 
> *priv)
> bcmgenet_fixed_phy_link_update);
>  }
>  
> -int bcmgenet_mii_config(struct net_device *dev)
> +int bcmgenet_mii_config(struct net_device *dev, bool init)
>  {
>   struct bcmgenet_priv *priv = netdev_priv(dev);
>   struct phy_device *phydev = priv->phydev;
> @@ -327,7 +327,8 @@ int bcmgenet_mii_config(struct net_device *dev)
>   bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
>   }
>  
> - dev_info_once(kdev, "configuring instance for %s\n", phy_name);
> + if (init)
> + dev_info(kdev, "configuring instance for %s\n", phy_name);
>  
>   return 0;
>  }
> @@ -375,7 +376,7 @@ int bcmgenet_mii_probe(struct net_device *dev)
>* PHY speed which is needed for bcmgenet_mii_config() to configure
>* things appropriately.
>*/
> - ret = bcmgenet_mii_config(dev);
> + ret = bcmgenet_mii_config(dev, true);
>   if (ret) {
>   phy_disconnect(priv->phydev);
>   return ret;
> 

Looks good to me.

Reviewed-by: Doug Berger <open...@gmail.com>


[PATCH net 1/2] net: bcmgenet: Fix unmapping of fragments in bcmgenet_xmit()

2017-07-14 Thread Doug Berger
In case we fail to map a single fragment, we would be leaving the
transmit ring populated with stale entries.

This commit introduces the helper function bcmgenet_put_txcb()
which takes care of rewinding the per-ring write pointer back to
where we left.

It also consolidates the functionality of bcmgenet_xmit_single()
and bcmgenet_xmit_frag() into the bcmgenet_xmit() function to
make the unmapping of control blocks cleaner.

Fixes: 1c1008c793fa ("net: bcmgenet: add main driver file")
Suggested-by: Florian Fainelli <f.faine...@gmail.com>
Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 191 +++--
 1 file changed, 85 insertions(+), 106 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index daca1c9d254b..20021525f795 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -1202,6 +1202,23 @@ static struct enet_cb *bcmgenet_get_txcb(struct 
bcmgenet_priv *priv,
return tx_cb_ptr;
 }
 
+static struct enet_cb *bcmgenet_put_txcb(struct bcmgenet_priv *priv,
+struct bcmgenet_tx_ring *ring)
+{
+   struct enet_cb *tx_cb_ptr;
+
+   tx_cb_ptr = ring->cbs;
+   tx_cb_ptr += ring->write_ptr - ring->cb_ptr;
+
+   /* Rewinding local write pointer */
+   if (ring->write_ptr == ring->cb_ptr)
+   ring->write_ptr = ring->end_ptr;
+   else
+   ring->write_ptr--;
+
+   return tx_cb_ptr;
+}
+
 /* Simple helper to free a control block's resources */
 static void bcmgenet_free_cb(struct enet_cb *cb)
 {
@@ -1380,95 +1397,6 @@ static void bcmgenet_tx_reclaim_all(struct net_device 
*dev)
bcmgenet_tx_reclaim(dev, >tx_rings[DESC_INDEX]);
 }
 
-/* Transmits a single SKB (either head of a fragment or a single SKB)
- * caller must hold priv->lock
- */
-static int bcmgenet_xmit_single(struct net_device *dev,
-   struct sk_buff *skb,
-   u16 dma_desc_flags,
-   struct bcmgenet_tx_ring *ring)
-{
-   struct bcmgenet_priv *priv = netdev_priv(dev);
-   struct device *kdev = >pdev->dev;
-   struct enet_cb *tx_cb_ptr;
-   unsigned int skb_len;
-   dma_addr_t mapping;
-   u32 length_status;
-   int ret;
-
-   tx_cb_ptr = bcmgenet_get_txcb(priv, ring);
-
-   if (unlikely(!tx_cb_ptr))
-   BUG();
-
-   tx_cb_ptr->skb = skb;
-
-   skb_len = skb_headlen(skb);
-
-   mapping = dma_map_single(kdev, skb->data, skb_len, DMA_TO_DEVICE);
-   ret = dma_mapping_error(kdev, mapping);
-   if (ret) {
-   priv->mib.tx_dma_failed++;
-   netif_err(priv, tx_err, dev, "Tx DMA map failed\n");
-   dev_kfree_skb(skb);
-   return ret;
-   }
-
-   dma_unmap_addr_set(tx_cb_ptr, dma_addr, mapping);
-   dma_unmap_len_set(tx_cb_ptr, dma_len, skb_len);
-   length_status = (skb_len << DMA_BUFLENGTH_SHIFT) | dma_desc_flags |
-   (priv->hw_params->qtag_mask << DMA_TX_QTAG_SHIFT) |
-   DMA_TX_APPEND_CRC;
-
-   if (skb->ip_summed == CHECKSUM_PARTIAL)
-   length_status |= DMA_TX_DO_CSUM;
-
-   dmadesc_set(priv, tx_cb_ptr->bd_addr, mapping, length_status);
-
-   return 0;
-}
-
-/* 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)
-{
-   struct bcmgenet_priv *priv = netdev_priv(dev);
-   struct device *kdev = >pdev->dev;
-   struct enet_cb *tx_cb_ptr;
-   unsigned int frag_size;
-   dma_addr_t mapping;
-   int ret;
-
-   tx_cb_ptr = bcmgenet_get_txcb(priv, ring);
-
-   if (unlikely(!tx_cb_ptr))
-   BUG();
-
-   tx_cb_ptr->skb = NULL;
-
-   frag_size = skb_frag_size(frag);
-
-   mapping = skb_frag_dma_map(kdev, frag, 0, frag_size, DMA_TO_DEVICE);
-   ret = dma_mapping_error(kdev, mapping);
-   if (ret) {
-   priv->mib.tx_dma_failed++;
-   netif_err(priv, tx_err, dev, "%s: Tx DMA map failed\n",
- __func__);
-   return ret;
-   }
-
-   dma_unmap_addr_set(tx_cb_ptr, dma_addr, mapping);
-   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));
-
-   return 0;
-}
-
 /* Reallocate the SKB to put enough headroom in front of it and insert
  * the transm

[PATCH net 0/2] Fragmented SKB corrections

2017-07-14 Thread Doug Berger
Two issues were observed in a review of the bcmgenet driver support for
fragmented SKBs which are addressed by this patch set.

The first addresses a problem that could occur if the driver is not able
to DMA map a fragment of the SKB.  This would be a highly unusual event
but it would leave the hardware descriptors in an invalid state which
should be prevented.

The second is a hazard that could occur if the driver is able to reclaim
the first control block of a fragmented SKB before all of its fragments
have completed processing by the hardware.  In this case the SKB could
be freed leading to reuse of memory that is still in use by hardware.

Doug Berger (2):
  net: bcmgenet: Fix unmapping of fragments in bcmgenet_xmit()
  net: bcmgenet: Free skb after last Tx frag

 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 299 +
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |   2 +
 2 files changed, 152 insertions(+), 149 deletions(-)

-- 
2.13.0



[PATCH net 2/2] net: bcmgenet: Free skb after last Tx frag

2017-07-14 Thread Doug Berger
Since the skb is attached to the first control block of a fragmented
skb it is possible that the skb could be freed when reclaiming that
control block before all fragments of the skb have been consumed by
the hardware and unmapped.

This commit introduces first_cb and last_cb pointers to the skb
control block used by the driver to keep track of which transmit
control blocks within a transmit ring are the first and last ones
associated with the skb.

It then splits the bcmgenet_free_cb() function into transmit
(bcmgenet_free_tx_cb) and receive (bcmgenet_free_rx_cb) versions
that can handle the unmapping of dma mapped memory and cleaning up
the corresponding control block structure so that the skb is only
freed after the last associated transmit control block is reclaimed.

Fixes: 1c1008c793fa ("net: bcmgenet: add main driver file")
Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 142 ++---
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |   2 +
 2 files changed, 84 insertions(+), 60 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 20021525f795..7b0b399aaedd 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -1219,14 +1219,6 @@ static struct enet_cb *bcmgenet_put_txcb(struct 
bcmgenet_priv *priv,
return tx_cb_ptr;
 }
 
-/* Simple helper to free a control block's resources */
-static void bcmgenet_free_cb(struct enet_cb *cb)
-{
-   dev_kfree_skb_any(cb->skb);
-   cb->skb = NULL;
-   dma_unmap_addr_set(cb, dma_addr, 0);
-}
-
 static inline void bcmgenet_rx_ring16_int_disable(struct bcmgenet_rx_ring 
*ring)
 {
bcmgenet_intrl2_0_writel(ring->priv, UMAC_IRQ_RXDMA_DONE,
@@ -1277,18 +1269,72 @@ static inline void bcmgenet_tx_ring_int_disable(struct 
bcmgenet_tx_ring *ring)
 INTRL2_CPU_MASK_SET);
 }
 
+/* Simple helper to free a transmit control block's resources
+ * Returns an skb when the last transmit control block associated with the
+ * skb is freed.  The skb should be freed by the caller if necessary.
+ */
+static struct sk_buff *bcmgenet_free_tx_cb(struct device *dev,
+  struct enet_cb *cb)
+{
+   struct sk_buff *skb;
+
+   skb = cb->skb;
+
+   if (skb) {
+   cb->skb = NULL;
+   if (cb == GENET_CB(skb)->first_cb)
+   dma_unmap_single(dev, dma_unmap_addr(cb, dma_addr),
+dma_unmap_len(cb, dma_len),
+DMA_TO_DEVICE);
+   else
+   dma_unmap_page(dev, dma_unmap_addr(cb, dma_addr),
+  dma_unmap_len(cb, dma_len),
+  DMA_TO_DEVICE);
+   dma_unmap_addr_set(cb, dma_addr, 0);
+
+   if (cb == GENET_CB(skb)->last_cb)
+   return skb;
+
+   } else if (dma_unmap_addr(cb, dma_addr)) {
+   dma_unmap_page(dev,
+  dma_unmap_addr(cb, dma_addr),
+  dma_unmap_len(cb, dma_len),
+  DMA_TO_DEVICE);
+   dma_unmap_addr_set(cb, dma_addr, 0);
+   }
+
+   return 0;
+}
+
+/* Simple helper to free a receive control block's resources */
+static struct sk_buff *bcmgenet_free_rx_cb(struct device *dev,
+  struct enet_cb *cb)
+{
+   struct sk_buff *skb;
+
+   skb = cb->skb;
+   cb->skb = NULL;
+
+   if (dma_unmap_addr(cb, dma_addr)) {
+   dma_unmap_single(dev, dma_unmap_addr(cb, dma_addr),
+dma_unmap_len(cb, dma_len), DMA_FROM_DEVICE);
+   dma_unmap_addr_set(cb, dma_addr, 0);
+   }
+
+   return skb;
+}
+
 /* Unlocked version of the reclaim routine */
 static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev,
  struct bcmgenet_tx_ring *ring)
 {
struct bcmgenet_priv *priv = netdev_priv(dev);
-   struct device *kdev = >pdev->dev;
-   struct enet_cb *tx_cb_ptr;
-   unsigned int pkts_compl = 0;
+   unsigned int txbds_processed = 0;
unsigned int bytes_compl = 0;
-   unsigned int c_index;
+   unsigned int pkts_compl = 0;
unsigned int txbds_ready;
-   unsigned int txbds_processed = 0;
+   unsigned int c_index;
+   struct sk_buff *skb;
 
/* Clear status before servicing to reduce spurious interrupts */
if (ring->index == DESC_INDEX)
@@ -1309,21 +1355,12 @@ static unsigned int __bcmgenet_tx_reclaim(struct 
net_device *dev,
 
/* Reclaim transmitted buffers */
while (txbds_processed < txbds_ready) {
-   tx_cb_ptr = >t

[PATCH net] net: bcmgenet: remove bcmgenet_internal_phy_setup()

2017-03-21 Thread Doug Berger
Commit 6ac3ce8295e6 ("net: bcmgenet: Remove excessive PHY reset")
removed the bcmgenet_mii_reset() function from bcmgenet_power_up() and
bcmgenet_internal_phy_setup() functions.  In so doing it broke the reset
of the internal PHY devices used by the GENETv1-GENETv3 which required
this reset before the UniMAC was enabled.  It also broke the internal
GPHY devices used by the GENETv4 because the config_init that installed
the AFE workaround was no longer occurring after the reset of the GPHY
performed by bcmgenet_phy_power_set() in bcmgenet_internal_phy_setup().
In addition the code in bcmgenet_internal_phy_setup() related to the
"enable APD" comment goes with the bcmgenet_mii_reset() so it should
have also been removed.

Commit bd4060a6108b ("net: bcmgenet: Power on integrated GPHY in
bcmgenet_power_up()") moved the bcmgenet_phy_power_set() call to the
bcmgenet_power_up() function, but failed to remove it from the
bcmgenet_internal_phy_setup() function.  Had it done so, the
bcmgenet_internal_phy_setup() function would have been empty and could
have been removed at that time.

Commit 5dbebbb44a6a ("net: bcmgenet: Software reset EPHY after power on")
was submitted to correct the functional problems introduced by
commit 6ac3ce8295e6 ("net: bcmgenet: Remove excessive PHY reset"). It
was included in v4.4 and made available on 4.3-stable. Unfortunately,
it didn't fully revert the commit because this bcmgenet_mii_reset()
doesn't apply the soft reset to the internal GPHY used by GENETv4 like
the previous one did. This prevents the restoration of the AFE work-
arounds for internal GPHY devices after the bcmgenet_phy_power_set() in
bcmgenet_internal_phy_setup().

This commit takes the alternate approach of removing the unnecessary
bcmgenet_internal_phy_setup() function which shouldn't have been in v4.3
so that when bcmgenet_mii_reset() was restored it should have only gone
into bcmgenet_power_up().  This will avoid the problems while also
removing the redundancy (and hopefully some of the confusion).

Fixes: 6ac3ce8295e6 ("net: bcmgenet: Remove excessive PHY reset")
Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmmii.c | 15 ---
 1 file changed, 15 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c 
b/drivers/net/ethernet/broadcom/genet/bcmmii.c
index e87607621e62..2f9281936f0e 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
@@ -220,20 +220,6 @@ void bcmgenet_phy_power_set(struct net_device *dev, bool 
enable)
udelay(60);
 }
 
-static void bcmgenet_internal_phy_setup(struct net_device *dev)
-{
-   struct bcmgenet_priv *priv = netdev_priv(dev);
-   u32 reg;
-
-   /* Power up PHY */
-   bcmgenet_phy_power_set(dev, true);
-   /* enable APD */
-   reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
-   reg |= EXT_PWR_DN_EN_LD;
-   bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
-   bcmgenet_mii_reset(dev);
-}
-
 static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv)
 {
u32 reg;
@@ -281,7 +267,6 @@ int bcmgenet_mii_config(struct net_device *dev)
 
if (priv->internal_phy) {
phy_name = "internal PHY";
-   bcmgenet_internal_phy_setup(dev);
} else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) {
phy_name = "MoCA";
bcmgenet_moca_phy_setup(priv);
-- 
2.11.1



Re: [PATCH net-next 09/12] net: bcmgenet: return EOPNOTSUPP for unknown ioctl commands

2017-03-14 Thread Doug Berger
On 03/14/2017 04:04 AM, David Laight wrote:
> From: Doug Berger
>> Sent: 14 March 2017 00:42
>> This commit changes the ioctl handling behavior to return the
>> EOPNOTSUPP error code instead of the EINVAL error code when an
>> unknown ioctl command value is detected.
>>
>> It also removes some redundant parsing of the ioctl command value
>> and allows the SIOCSHWTSTAMP value to be handled.
> 
> A better description would seem to be:
> Remove checks on ioctl command and just forward all ioctl requests
> to phy_mii_ioctl().
That is a good description of the code change, but I felt that was
clearly conveyed by the patch content.  I thought it would be a better
use of the comment to describe the more subtle functional change that
might be less clear.

> 
> I also thought the 'generic' response to an unknown ioctl command
> was ENOTTY.
and I think it probably helped solicit this feedback :).  I would have
thought that error makes more sense if there is no ioctl handler, but I
will definitely look into it.

Thanks for the feedback,
Doug


Re: [PATCH net-next 02/12] net: phy: bcm7xxx: add support for 28nm EPHY

2017-03-14 Thread Doug Berger
On 03/13/2017 07:43 PM, Andrew Lunn wrote:
> On Mon, Mar 13, 2017 at 07:06:25PM -0700, Doug Berger wrote:
>> On 03/13/2017 06:06 PM, Andrew Lunn wrote:
>>> On Mon, Mar 13, 2017 at 05:41:32PM -0700, Doug Berger wrote:
>>>> +static int bcm7xxx_28nm_ephy_01_afe_config_init(struct phy_device *phydev)
>>>> +{
>>>> +  int ret;
>>>> +
>>>> +  /* set shadow mode 2 */
>>>> +  ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,
>>>> + MII_BCM7XXX_SHD_MODE_2, 0);
>>>> +  if (ret < 0)
>>>> +  return ret;
>>>> +
>>>> +  /* Set current trim values INT_trim = -1, Ext_trim =0 */
>>>> +  ret = phy_write(phydev, MII_BCM7XXX_SHD_2_BIAS_TRIM, 0x3BE0);
>>>> +  if (ret < 0)
>>>> +  goto reset_shadow_mode;
>>>> +
>>>> +  /* Cal reset */
>>>> +  ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
>>>> +  MII_BCM7XXX_SHD_3_TL4);
>>>> +  if (ret < 0)
>>>> +  goto reset_shadow_mode;
>>>
>>> Hi Doug
>>>
>>> It would be nice to have a few blank lines here and there...
>>>
>> Thanks for taking the time to review this.
>>
>> In general I try to keep lines of related functionality together and use
>> the blank lines to help identify boundaries.  In this particular case, I
>> believe it is clearer to keep the code that may return an error code
>> together with the code that tests for the error.
> 
> Hi Doug
> 
> I agree with that. Which is why i placed the comment between the goto
> and the next block of code. This is where i think there should be a
> blank line, to separate it from setting the trim values.
> 
OK, I see.  I thought you were referring to the code blocks above the
comment.  In that case, as described earlier, the code below the comment
is tightly coupled with the code above the comment since the pair of
transactions are how we "/* Cal reset */".  The idea of introducing a
subroutine/helper function for these paired (addr/data) transactions
might help readability so I will consider it for a future patch.

Thanks again for the feedback,
Doug


Re: [PATCH net-next 02/12] net: phy: bcm7xxx: add support for 28nm EPHY

2017-03-13 Thread Doug Berger
On 03/13/2017 06:06 PM, Andrew Lunn wrote:
> On Mon, Mar 13, 2017 at 05:41:32PM -0700, Doug Berger wrote:
>> +static int bcm7xxx_28nm_ephy_01_afe_config_init(struct phy_device *phydev)
>> +{
>> +int ret;
>> +
>> +/* set shadow mode 2 */
>> +ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,
>> +   MII_BCM7XXX_SHD_MODE_2, 0);
>> +if (ret < 0)
>> +return ret;
>> +
>> +/* Set current trim values INT_trim = -1, Ext_trim =0 */
>> +ret = phy_write(phydev, MII_BCM7XXX_SHD_2_BIAS_TRIM, 0x3BE0);
>> +if (ret < 0)
>> +goto reset_shadow_mode;
>> +
>> +/* Cal reset */
>> +ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
>> +MII_BCM7XXX_SHD_3_TL4);
>> +if (ret < 0)
>> +goto reset_shadow_mode;
> 
> Hi Doug
> 
> It would be nice to have a few blank lines here and there...
> 
Thanks for taking the time to review this.

In general I try to keep lines of related functionality together and use
the blank lines to help identify boundaries.  In this particular case, I
believe it is clearer to keep the code that may return an error code
together with the code that tests for the error.

Perhaps this would be a better alternative:
+   /* Set current trim values INT_trim = -1, Ext_trim =0 */
+   if (phy_write(phydev, MII_BCM7XXX_SHD_2_BIAS_TRIM, 0x3BE0) < 0)
+   goto reset_shadow_mode;
+
+   /* Cal reset */
+   if (phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
+ MII_BCM7XXX_SHD_3_TL4) < 0)
+   goto reset_shadow_mode;

>> +ret = phy_set_clr_bits(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
>> +   MII_BCM7XXX_TL4_RST_MSK, 0);
>> +if (ret < 0)
>> +goto reset_shadow_mode;
>> +
>> +/* Cal reset disable */
>> +ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
>> +MII_BCM7XXX_SHD_3_TL4);
>> +if (ret < 0)
>> +goto reset_shadow_mode;
> 
> ... just to break things up into readable chunks.
> 
Maybe:
+   if (phy_set_clr_bits(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
+MII_BCM7XXX_TL4_RST_MSK, 0) < 0)
+   goto reset_shadow_mode;
+
+   /* Cal reset disable */
+   if (phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
+ MII_BCM7XXX_SHD_3_TL4) < 0)
+   goto reset_shadow_mode;

>> +ret = phy_set_clr_bits(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
>> +   0, MII_BCM7XXX_TL4_RST_MSK);
>> +if (ret < 0)
>> +goto reset_shadow_mode;
>> +
>> +reset_shadow_mode:
>> +/* reset shadow mode 2 */
>> +ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0,
>> +   MII_BCM7XXX_SHD_MODE_2);
>> +if (ret < 0)
>> +return ret;
>> +
>> +return 0;
> 
> How about:
> 
>   return phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0,
>   MII_BCM7XXX_SHD_MODE_2);
> 
The trouble here is that currently the phy_set_clr_bits() function
returns the value written or a negative error and the function
bcm7xxx_28nm_ephy_01_afe_config_init() is supposed to return 0 on
success and non-zero on failure so this would not have the same
functionality.  I suppose we could change the phy_set_clr_bits() API to
return 0 on success to make this work, but I wasn't trying to change
preexisting functionality in this file.

>> +/* The 28nm EPHY does not support Clause 45 (MMD) used by bcm-phy-lib */
>> +static int bcm7xxx_28nm_ephy_apd_enable(struct phy_device *phydev)
>> +{
>> +int ret;
>> +
>> +/* set shadow mode 1 */
>> +ret = phy_set_clr_bits(phydev, MII_BRCM_FET_BRCMTEST,
>> +   MII_BRCM_FET_BT_SRE, 0);
>> +if (ret < 0)
>> +return ret;
>> +
>> +/* Enable auto-power down */
>> +ret = phy_set_clr_bits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2,
>> +   MII_BRCM_FET_SHDW_AS2_APDE, 0);
>> +if (ret < 0)
>> +return ret;
>> +
>> +/* reset shadow mode 1 */
>> +ret = phy_set_clr_bits(phydev, MII_BRCM_FET_BRCMTEST, 0,
>> +   MII_BRCM_FET_BT_SRE);
>> +if (ret < 0)
>> +return ret;
>> +
>> +return 0;
> 
> How about just
> 
> return phy_set_clr_bits(phydev, MII_BRCM_FET_BRCMTEST, 0,
>  MII_BRCM_FET_BT_SRE);
> 
Same remark as above.

>> +}
>> +
>> +static int bcm7xxx_28nm_ephy_

[PATCH net-next 02/12] net: phy: bcm7xxx: add support for 28nm EPHY

2017-03-13 Thread Doug Berger
This commit adds support for the internal fast ethernet 10/100 PHY
found in the BCM7260, BCM7268, and BCM7271 devices.

Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/phy/bcm7xxx.c | 215 +-
 include/linux/brcmphy.h   |   3 +
 2 files changed, 216 insertions(+), 2 deletions(-)

diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c
index d1c2614dad3a..caa9f6e17f34 100644
--- a/drivers/net/phy/bcm7xxx.c
+++ b/drivers/net/phy/bcm7xxx.c
@@ -1,7 +1,7 @@
 /*
  * Broadcom BCM7xxx internal transceivers support.
  *
- * Copyright (C) 2014, Broadcom Corporation
+ * Copyright (C) 2014-2017 Broadcom
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -19,7 +19,7 @@
 
 /* Broadcom BCM7xxx internal PHY registers */
 
-/* 40nm only register definitions */
+/* EPHY only register definitions */
 #define MII_BCM7XXX_100TX_AUX_CTL  0x10
 #define MII_BCM7XXX_100TX_FALSE_CAR0x13
 #define MII_BCM7XXX_100TX_DISC 0x14
@@ -27,6 +27,19 @@
 #define  MII_BCM7XXX_64CLK_MDIOBIT(12)
 #define MII_BCM7XXX_TEST   0x1f
 #define  MII_BCM7XXX_SHD_MODE_2BIT(2)
+#define MII_BCM7XXX_SHD_2_ADDR_CTRL0xe
+#define MII_BCM7XXX_SHD_2_CTRL_STAT0xf
+#define MII_BCM7XXX_SHD_2_BIAS_TRIM0x1a
+#define MII_BCM7XXX_SHD_3_AN_EEE_ADV   0x3
+#define MII_BCM7XXX_SHD_3_PCS_CTRL_2   0x6
+#define  MII_BCM7XXX_PCS_CTRL_2_DEF0x4400
+#define MII_BCM7XXX_SHD_3_AN_STAT  0xb
+#define  MII_BCM7XXX_AN_NULL_MSG_ENBIT(0)
+#define  MII_BCM7XXX_AN_EEE_EN BIT(1)
+#define MII_BCM7XXX_SHD_3_EEE_THRESH   0xe
+#define  MII_BCM7XXX_EEE_THRESH_DEF0x50
+#define MII_BCM7XXX_SHD_3_TL4  0x23
+#define  MII_BCM7XXX_TL4_RST_MSK   (BIT(2) | BIT(1))
 
 /* 28nm only register definitions */
 #define MISC_ADDR(base, channel)   base, channel
@@ -286,6 +299,181 @@ static int phy_set_clr_bits(struct phy_device *dev, int 
location,
return v;
 }
 
+static int bcm7xxx_28nm_ephy_01_afe_config_init(struct phy_device *phydev)
+{
+   int ret;
+
+   /* set shadow mode 2 */
+   ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,
+  MII_BCM7XXX_SHD_MODE_2, 0);
+   if (ret < 0)
+   return ret;
+
+   /* Set current trim values INT_trim = -1, Ext_trim =0 */
+   ret = phy_write(phydev, MII_BCM7XXX_SHD_2_BIAS_TRIM, 0x3BE0);
+   if (ret < 0)
+   goto reset_shadow_mode;
+
+   /* Cal reset */
+   ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
+   MII_BCM7XXX_SHD_3_TL4);
+   if (ret < 0)
+   goto reset_shadow_mode;
+   ret = phy_set_clr_bits(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
+  MII_BCM7XXX_TL4_RST_MSK, 0);
+   if (ret < 0)
+   goto reset_shadow_mode;
+
+   /* Cal reset disable */
+   ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
+   MII_BCM7XXX_SHD_3_TL4);
+   if (ret < 0)
+   goto reset_shadow_mode;
+   ret = phy_set_clr_bits(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
+  0, MII_BCM7XXX_TL4_RST_MSK);
+   if (ret < 0)
+   goto reset_shadow_mode;
+
+reset_shadow_mode:
+   /* reset shadow mode 2 */
+   ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0,
+  MII_BCM7XXX_SHD_MODE_2);
+   if (ret < 0)
+   return ret;
+
+   return 0;
+}
+
+/* The 28nm EPHY does not support Clause 45 (MMD) used by bcm-phy-lib */
+static int bcm7xxx_28nm_ephy_apd_enable(struct phy_device *phydev)
+{
+   int ret;
+
+   /* set shadow mode 1 */
+   ret = phy_set_clr_bits(phydev, MII_BRCM_FET_BRCMTEST,
+  MII_BRCM_FET_BT_SRE, 0);
+   if (ret < 0)
+   return ret;
+
+   /* Enable auto-power down */
+   ret = phy_set_clr_bits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2,
+  MII_BRCM_FET_SHDW_AS2_APDE, 0);
+   if (ret < 0)
+   return ret;
+
+   /* reset shadow mode 1 */
+   ret = phy_set_clr_bits(phydev, MII_BRCM_FET_BRCMTEST, 0,
+  MII_BRCM_FET_BT_SRE);
+   if (ret < 0)
+   return ret;
+
+   return 0;
+}
+
+static int bcm7xxx_28nm_ephy_eee_enable(struct phy_device *phydev)
+{
+   int ret;
+
+   /* set shadow mode 2 */
+   ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,
+  MII_BCM7XXX_SHD_MODE_2, 0);
+   if (ret < 0)
+   return ret;
+
+   /* Advertise supported modes */
+   ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
+   MII_BCM7XXX_SHD_3_AN_EEE_ADV);
+   if (ret < 0)
+   goto reset_shadow_mode;
+   ret = phy_write(phydev, MII_BCM7XXX_SHD_2_CTRL_ST

[PATCH net-next 00/12] net: bcmgenet: add support for GENETv5

2017-03-13 Thread Doug Berger
This collection of patches contains changes related to adding
support for the BCM7260, BCM7268, and BCM7271 devices that
contain a new version of the GENET MAC IP block (v5) and a new
fast ethernet (10/100BASE-T) internal PHY.

These patches were originally developed on top of the bug fixes
of the "[PATCH v2 net 0/8] net: bcmgenet: minor bug fixes" patch
set previously accepted into the net repository, but this
submission is designed to be applied to the current net-next
that does not yet include them. As a result there will be some
merge conflicts that I would be happy to help resolve if desired.

Specifically, conflicts should occur with these patches from the
minor bug fixes set:
[PATCH v2 net 3/8] net: bcmgenet: reserved phy revisions must be checked first
[PATCH v2 net 5/8] net: bcmgenet: synchronize irq0 status between the isr and 
task
[PATCH v2 net 8/8] net: bcmgenet: decouple flow control from bcmgenet_tx_reclaim

Doug Berger (12):
  net: phy: bcm-phylib: replace obsolete EEE macro references
  net: phy: bcm7xxx: add support for 28nm EPHY
  net: bcmgenet: simplify circular pointer arithmetic
  net: bcmgenet: remove meaningless lines
  net: bcmgenet: manage dma interrupts in napi code
  net: bcmgenet: remove handling of wol interrupts from isr0
  net: bcmgenet: clear status to reduce spurious interrupts
  net: bcmgenet: correct return value of __bcmgenet_tx_reclaim
  net: bcmgenet: return EOPNOTSUPP for unknown ioctl commands
  dt-bindings: net: document bcmgenet WoL interrupt
  dt-bindings: net: update bcmgenet binding for GENETv5
  net: bcmgenet: add support for the GENETv5 hardware

 .../devicetree/bindings/net/brcm,bcmgenet.txt  |  19 +-
 .../devicetree/bindings/net/brcm,unimac-mdio.txt   |   5 +-
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 214 +++-
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |  10 +-
 drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c |  13 --
 drivers/net/ethernet/broadcom/genet/bcmmii.c   |  62 +++---
 drivers/net/phy/bcm-phy-lib.c  |   6 +-
 drivers/net/phy/bcm7xxx.c  | 215 -
 include/linux/brcmphy.h|   3 +
 9 files changed, 403 insertions(+), 144 deletions(-)

-- 
2.11.1



[PATCH net-next 03/12] net: bcmgenet: simplify circular pointer arithmetic

2017-03-13 Thread Doug Berger
A 2's complement subtraction will always do a borrow, so masking
off the sign bits is the same as conditionally adding (mask+1).

Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 19 +--
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index f92896835d2a..2c008b09c4e3 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -1,7 +1,7 @@
 /*
  * Broadcom GENET (Gigabit Ethernet) controller driver
  *
- * Copyright (c) 2014 Broadcom Corporation
+ * Copyright (c) 2014-2017 Broadcom
  *
  * 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
@@ -1175,13 +1175,9 @@ static unsigned int __bcmgenet_tx_reclaim(struct 
net_device *dev,
unsigned int txbds_processed = 0;
 
/* Compute how many buffers are transmitted since last xmit call */
-   c_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_CONS_INDEX);
-   c_index &= DMA_C_INDEX_MASK;
-
-   if (likely(c_index >= ring->c_index))
-   txbds_ready = c_index - ring->c_index;
-   else
-   txbds_ready = (DMA_C_INDEX_MASK + 1) - ring->c_index + c_index;
+   c_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_CONS_INDEX)
+   & DMA_C_INDEX_MASK;
+   txbds_ready = (c_index - ring->c_index) & DMA_C_INDEX_MASK;
 
netif_dbg(priv, tx_done, dev,
  "%s ring=%d old_c_index=%u c_index=%u txbds_ready=%u\n",
@@ -1611,12 +1607,7 @@ static unsigned int bcmgenet_desc_rx(struct 
bcmgenet_rx_ring *ring,
}
 
p_index &= DMA_P_INDEX_MASK;
-
-   if (likely(p_index >= ring->c_index))
-   rxpkttoprocess = p_index - ring->c_index;
-   else
-   rxpkttoprocess = (DMA_C_INDEX_MASK + 1) - ring->c_index +
-p_index;
+   rxpkttoprocess = (p_index - ring->c_index) & DMA_C_INDEX_MASK;
 
netif_dbg(priv, rx_status, dev,
  "RDMA: rxpkttoprocess=%d\n", rxpkttoprocess);
-- 
2.11.1



[PATCH net-next 01/12] net: phy: bcm-phylib: replace obsolete EEE macro references

2017-03-13 Thread Doug Berger
The macros MDIO_AN_EEE_ADV_100TX and MDIO_AN_EEE_ADV_1000T are now
considered obsolete and are replaced in the kernel with the generic
macros MDIO_EEE_100TX and MDIO_EEE_1000T respectively.

Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/phy/bcm-phy-lib.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/phy/bcm-phy-lib.c b/drivers/net/phy/bcm-phy-lib.c
index ab9ad689617c..9656dbeb5de5 100644
--- a/drivers/net/phy/bcm-phy-lib.c
+++ b/drivers/net/phy/bcm-phy-lib.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Broadcom Corporation
+ * Copyright (C) 2015-2017 Broadcom
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -221,9 +221,9 @@ int bcm_phy_set_eee(struct phy_device *phydev, bool enable)
return val;
 
if (enable)
-   val |= (MDIO_AN_EEE_ADV_100TX | MDIO_AN_EEE_ADV_1000T);
+   val |= (MDIO_EEE_100TX | MDIO_EEE_1000T);
else
-   val &= ~(MDIO_AN_EEE_ADV_100TX | MDIO_AN_EEE_ADV_1000T);
+   val &= ~(MDIO_EEE_100TX | MDIO_EEE_1000T);
 
phy_write_mmd_indirect(phydev, BCM_CL45VEN_EEE_ADV,
   MDIO_MMD_AN, (u32)val);
-- 
2.11.1



[PATCH net-next 06/12] net: bcmgenet: remove handling of wol interrupts from isr0

2017-03-13 Thread Doug Berger
The bcmgenet_wol_isr() handler performs the necessary processing for
waking from a GENET event.  There is no necessary functionality behind
servicing the UMAC_IRQ_MPD_R event in the handling of isr0.  Therefore
the code that unmasks and masks this interrupt and that gets invoked
in response to it is removed by this commit.

Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 10 +-
 drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c | 15 +--
 2 files changed, 2 insertions(+), 23 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 9be884021679..661ca1b39c89 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -2455,13 +2455,6 @@ 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->irq0_stat & UMAC_IRQ_LINK_EVENT) {
phy_mac_interrupt(priv->phydev,
@@ -2558,8 +2551,7 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id)
UMAC_IRQ_PHY_DET_F |
UMAC_IRQ_LINK_EVENT |
UMAC_IRQ_HFB_SM |
-   UMAC_IRQ_HFB_MM |
-   UMAC_IRQ_MPD_R)) {
+   UMAC_IRQ_HFB_MM)) {
/* all other interested interrupts handled in bottom half */
schedule_work(>bcmgenet_irq_work);
}
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
index b97122926d3a..2fbd027f0148 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
@@ -1,7 +1,7 @@
 /*
  * Broadcom GENET (Gigabit Ethernet) Wake-on-LAN support
  *
- * Copyright (c) 2014 Broadcom Corporation
+ * Copyright (c) 2014-2017 Broadcom
  *
  * 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
@@ -127,7 +127,6 @@ 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;
 
@@ -173,18 +172,12 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv 
*priv,
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) {
@@ -201,10 +194,4 @@ void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
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);
 }
-- 
2.11.1



[PATCH net-next 04/12] net: bcmgenet: remove meaningless lines

2017-03-13 Thread Doug Berger
An assortment of non-functional lines are removed to reduce confusion
and some typos in comments are corrected.

Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 13 +++--
 1 file changed, 3 insertions(+), 10 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 2c008b09c4e3..22c92f5a9829 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -605,7 +605,7 @@ static int bcmgenet_set_coalesce(struct net_device *dev,
 
/* GENET TDMA hardware does not support a configurable timeout, but will
 * always generate an interrupt either after MBDONE packets have been
-* transmitted, or when the ring is emtpy.
+* transmitted, or when the ring is empty.
 */
if (ec->tx_coalesce_usecs || ec->tx_coalesce_usecs_high ||
ec->tx_coalesce_usecs_irq || ec->tx_coalesce_usecs_low)
@@ -1834,10 +1834,8 @@ static void bcmgenet_intr_disable(struct bcmgenet_priv 
*priv)
/* Mask all interrupts.*/
bcmgenet_intrl2_0_writel(priv, 0x, INTRL2_CPU_MASK_SET);
bcmgenet_intrl2_0_writel(priv, 0x, INTRL2_CPU_CLEAR);
-   bcmgenet_intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
bcmgenet_intrl2_1_writel(priv, 0x, INTRL2_CPU_MASK_SET);
bcmgenet_intrl2_1_writel(priv, 0x, INTRL2_CPU_CLEAR);
-   bcmgenet_intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
 }
 
 static void bcmgenet_link_intr_enable(struct bcmgenet_priv *priv)
@@ -1926,7 +1924,6 @@ static int init_umac(struct bcmgenet_priv *priv)
bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR);
bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR);
 
-   /* Enable rx/tx engine.*/
dev_dbg(kdev, "done init umac\n");
 
return 0;
@@ -2836,7 +2833,7 @@ static int bcmgenet_close(struct net_device *dev)
if (ret)
return ret;
 
-   /* Disable MAC transmit. TX DMA disabled have to done before this */
+   /* Disable MAC transmit. TX DMA disabled must be done before this */
umac_enable_set(priv, CMD_TX_EN, false);
 
/* tx reclaim */
@@ -3115,22 +3112,18 @@ static void bcmgenet_set_hw_params(struct bcmgenet_priv 
*priv)
bcmgenet_dma_regs = bcmgenet_dma_regs_v3plus;
genet_dma_ring_regs = genet_dma_ring_regs_v4;
priv->dma_rx_chk_bit = DMA_RX_CHK_V3PLUS;
-   priv->version = GENET_V4;
} else if (GENET_IS_V3(priv)) {
bcmgenet_dma_regs = bcmgenet_dma_regs_v3plus;
genet_dma_ring_regs = genet_dma_ring_regs_v123;
priv->dma_rx_chk_bit = DMA_RX_CHK_V3PLUS;
-   priv->version = GENET_V3;
} else if (GENET_IS_V2(priv)) {
bcmgenet_dma_regs = bcmgenet_dma_regs_v2;
genet_dma_ring_regs = genet_dma_ring_regs_v123;
priv->dma_rx_chk_bit = DMA_RX_CHK_V12;
-   priv->version = GENET_V2;
} else if (GENET_IS_V1(priv)) {
bcmgenet_dma_regs = bcmgenet_dma_regs_v1;
genet_dma_ring_regs = genet_dma_ring_regs_v123;
priv->dma_rx_chk_bit = DMA_RX_CHK_V12;
-   priv->version = GENET_V1;
}
 
/* enum genet_version starts at 1 */
@@ -3397,7 +3390,7 @@ static int bcmgenet_suspend(struct device *d)
if (ret)
return ret;
 
-   /* Disable MAC transmit. TX DMA disabled have to done before this */
+   /* Disable MAC transmit. TX DMA disabled must be done before this */
umac_enable_set(priv, CMD_TX_EN, false);
 
/* tx reclaim */
-- 
2.11.1



[PATCH net-next 11/12] dt-bindings: net: update bcmgenet binding for GENETv5

2017-03-13 Thread Doug Berger
The device tree documentation must be updated to reflect the new compatible
strings "brcm,genet-v5" and "brcm,genet-mdio-v5" used by the GENETv5 driver.

Signed-off-by: Doug Berger <open...@gmail.com>
---
 Documentation/devicetree/bindings/net/brcm,bcmgenet.txt| 10 +-
 Documentation/devicetree/bindings/net/brcm,unimac-mdio.txt |  5 +++--
 2 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/brcm,bcmgenet.txt 
b/Documentation/devicetree/bindings/net/brcm,bcmgenet.txt
index 01a70463cbc5..26c77d985faf 100644
--- a/Documentation/devicetree/bindings/net/brcm,bcmgenet.txt
+++ b/Documentation/devicetree/bindings/net/brcm,bcmgenet.txt
@@ -2,7 +2,7 @@
 
 Required properties:
 - compatible: should contain one of "brcm,genet-v1", "brcm,genet-v2",
-  "brcm,genet-v3", "brcm,genet-v4".
+  "brcm,genet-v3", "brcm,genet-v4", "brcm,genet-v5".
 - reg: address and length of the register set for the device
 - interrupts and/or interrupts-extended: must be two cells, the first cell
   is the general purpose interrupt line, while the second cell is the
@@ -32,15 +32,15 @@ Optional properties:
 
 Required child nodes:
 
-- mdio bus node: this node should always be present regarless of the PHY
+- mdio bus node: this node should always be present regardless of the PHY
   configuration of the GENET instance
 
 MDIO bus node required properties:
 
 - compatible: should contain one of "brcm,genet-mdio-v1", "brcm,genet-mdio-v2"
-  "brcm,genet-mdio-v3", "brcm,genet-mdio-v4", the version has to match the
-  parent node compatible property (e.g: brcm,genet-v4 pairs with
-  brcm,genet-mdio-v4)
+  "brcm,genet-mdio-v3", "brcm,genet-mdio-v4", "brcm,genet-mdio-v5", the version
+  has to match the parent node compatible property (e.g: brcm,genet-v4 pairs
+  with brcm,genet-mdio-v4)
 - reg: address and length relative to the parent node base register address
 - #address-cells: address cell for MDIO bus addressing, should be 1
 - #size-cells: size of the cells for MDIO bus addressing, should be 0
diff --git a/Documentation/devicetree/bindings/net/brcm,unimac-mdio.txt 
b/Documentation/devicetree/bindings/net/brcm,unimac-mdio.txt
index ab0bb4247d14..4648948f7c3b 100644
--- a/Documentation/devicetree/bindings/net/brcm,unimac-mdio.txt
+++ b/Documentation/devicetree/bindings/net/brcm,unimac-mdio.txt
@@ -2,8 +2,9 @@
 
 Required properties:
 - compatible: should one from "brcm,genet-mdio-v1", "brcm,genet-mdio-v2",
-  "brcm,genet-mdio-v3", "brcm,genet-mdio-v4" or "brcm,unimac-mdio"
-- reg: address and length of the regsiter set for the device, first one is the
+  "brcm,genet-mdio-v3", "brcm,genet-mdio-v4", "brcm,genet-mdio-v5" or
+  "brcm,unimac-mdio"
+- reg: address and length of the register set for the device, first one is the
   base register, and the second one is optional and for indirect accesses to
   larger than 16-bits MDIO transactions
 - reg-names: name(s) of the register must be "mdio" and optional 
"mdio_indir_rw"
-- 
2.11.1



[PATCH net-next 05/12] net: bcmgenet: manage dma interrupts in napi code

2017-03-13 Thread Doug Berger
This commit moves DMA interrupt enabling out of init_umac() and adds
the masking of these interrupts to the napi enable and disable code.

Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 39 +++---
 1 file changed, 22 insertions(+), 17 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 22c92f5a9829..9be884021679 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -1862,8 +1862,6 @@ static int init_umac(struct bcmgenet_priv *priv)
int ret;
u32 reg;
u32 int0_enable = 0;
-   u32 int1_enable = 0;
-   int i;
 
dev_dbg(>pdev->dev, "bcmgenet: init_umac\n");
 
@@ -1890,12 +1888,6 @@ static int init_umac(struct bcmgenet_priv *priv)
 
bcmgenet_intr_disable(priv);
 
-   /* Enable Rx default queue 16 interrupts */
-   int0_enable |= UMAC_IRQ_RXDMA_DONE;
-
-   /* Enable Tx default queue 16 interrupts */
-   int0_enable |= UMAC_IRQ_TXDMA_DONE;
-
/* Configure backpressure vectors for MoCA */
if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) {
reg = bcmgenet_bp_mc_get(priv);
@@ -1913,16 +1905,7 @@ static int init_umac(struct bcmgenet_priv *priv)
if (priv->hw_params->flags & GENET_HAS_MDIO_INTR)
int0_enable |= (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR);
 
-   /* Enable Rx priority queue interrupts */
-   for (i = 0; i < priv->hw_params->rx_queues; ++i)
-   int1_enable |= (1 << (UMAC_IRQ1_RX_INTR_SHIFT + i));
-
-   /* Enable Tx priority queue interrupts */
-   for (i = 0; i < priv->hw_params->tx_queues; ++i)
-   int1_enable |= (1 << i);
-
bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR);
-   bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR);
 
dev_dbg(kdev, "done init umac\n");
 
@@ -2055,22 +2038,33 @@ static void bcmgenet_init_tx_napi(struct bcmgenet_priv 
*priv)
 static void bcmgenet_enable_tx_napi(struct bcmgenet_priv *priv)
 {
unsigned int i;
+   u32 int0_enable = UMAC_IRQ_TXDMA_DONE;
+   u32 int1_enable = 0;
struct bcmgenet_tx_ring *ring;
 
for (i = 0; i < priv->hw_params->tx_queues; ++i) {
ring = >tx_rings[i];
napi_enable(>napi);
+   int1_enable |= (1 << i);
}
 
ring = >tx_rings[DESC_INDEX];
napi_enable(>napi);
+
+   bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR);
+   bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR);
 }
 
 static void bcmgenet_disable_tx_napi(struct bcmgenet_priv *priv)
 {
unsigned int i;
+   u32 int0_disable = UMAC_IRQ_TXDMA_DONE;
+   u32 int1_disable = 0x;
struct bcmgenet_tx_ring *ring;
 
+   bcmgenet_intrl2_0_writel(priv, int0_disable, INTRL2_CPU_MASK_SET);
+   bcmgenet_intrl2_1_writel(priv, int1_disable, INTRL2_CPU_MASK_SET);
+
for (i = 0; i < priv->hw_params->tx_queues; ++i) {
ring = >tx_rings[i];
napi_disable(>napi);
@@ -2183,22 +2177,33 @@ static void bcmgenet_init_rx_napi(struct bcmgenet_priv 
*priv)
 static void bcmgenet_enable_rx_napi(struct bcmgenet_priv *priv)
 {
unsigned int i;
+   u32 int0_enable = UMAC_IRQ_RXDMA_DONE;
+   u32 int1_enable = 0;
struct bcmgenet_rx_ring *ring;
 
for (i = 0; i < priv->hw_params->rx_queues; ++i) {
ring = >rx_rings[i];
napi_enable(>napi);
+   int1_enable |= (1 << (UMAC_IRQ1_RX_INTR_SHIFT + i));
}
 
ring = >rx_rings[DESC_INDEX];
napi_enable(>napi);
+
+   bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR);
+   bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR);
 }
 
 static void bcmgenet_disable_rx_napi(struct bcmgenet_priv *priv)
 {
unsigned int i;
+   u32 int0_disable = UMAC_IRQ_RXDMA_DONE;
+   u32 int1_disable = 0x << UMAC_IRQ1_RX_INTR_SHIFT;
struct bcmgenet_rx_ring *ring;
 
+   bcmgenet_intrl2_0_writel(priv, int0_disable, INTRL2_CPU_MASK_SET);
+   bcmgenet_intrl2_1_writel(priv, int1_disable, INTRL2_CPU_MASK_SET);
+
for (i = 0; i < priv->hw_params->rx_queues; ++i) {
ring = >rx_rings[i];
napi_disable(>napi);
-- 
2.11.1



[PATCH net-next 10/12] dt-bindings: net: document bcmgenet WoL interrupt

2017-03-13 Thread Doug Berger
A third interrupt cell can be provided to optionally specify
the interrupt used for handling Wake on LAN events.

Typically the wake up handling uses a separate interrupt
controller, so the interrupts-extended property is used to
accommodate this.

Signed-off-by: Doug Berger <open...@gmail.com>
---
 Documentation/devicetree/bindings/net/brcm,bcmgenet.txt | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/brcm,bcmgenet.txt 
b/Documentation/devicetree/bindings/net/brcm,bcmgenet.txt
index 10587bdadbbe..01a70463cbc5 100644
--- a/Documentation/devicetree/bindings/net/brcm,bcmgenet.txt
+++ b/Documentation/devicetree/bindings/net/brcm,bcmgenet.txt
@@ -4,9 +4,12 @@ Required properties:
 - compatible: should contain one of "brcm,genet-v1", "brcm,genet-v2",
   "brcm,genet-v3", "brcm,genet-v4".
 - reg: address and length of the register set for the device
-- interrupts: must be two cells, the first cell is the general purpose
-  interrupt line, while the second cell is the interrupt for the ring
-  RX and TX queues operating in ring mode
+- interrupts and/or interrupts-extended: must be two cells, the first cell
+  is the general purpose interrupt line, while the second cell is the
+  interrupt for the ring RX and TX queues operating in ring mode.  An
+  optional third interrupt cell for Wake-on-LAN can be specified.
+  See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+  for information on the property specifics.
 - phy-mode: see ethernet.txt file in the same directory
 - #address-cells: should be 1
 - #size-cells: should be 1
-- 
2.11.1



[PATCH net-next 07/12] net: bcmgenet: clear status to reduce spurious interrupts

2017-03-13 Thread Doug Berger
Since the DMA interrupt status is latched and the DMA servicing can be
polled, it is a good idea to clear the latched status of a DMA interrupt
before performing the service that would be invoked by the interrupt.

This prevents old status from causing spurious interrupts when the
interrupt is unmasked at a later time.

Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 21 -
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 661ca1b39c89..1f94ba1773dd 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -1174,6 +1174,14 @@ static unsigned int __bcmgenet_tx_reclaim(struct 
net_device *dev,
unsigned int txbds_ready;
unsigned int txbds_processed = 0;
 
+   /* Clear status before servicing to reduce spurious interrupts */
+   if (ring->index == DESC_INDEX)
+   bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_TXDMA_DONE,
+INTRL2_CPU_CLEAR);
+   else
+   bcmgenet_intrl2_1_writel(priv, (1 << ring->index),
+INTRL2_CPU_CLEAR);
+
/* Compute how many buffers are transmitted since last xmit call */
c_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_CONS_INDEX)
& DMA_C_INDEX_MASK;
@@ -1584,10 +1592,21 @@ static unsigned int bcmgenet_desc_rx(struct 
bcmgenet_rx_ring *ring,
unsigned long dma_flag;
int len;
unsigned int rxpktprocessed = 0, rxpkttoprocess;
-   unsigned int p_index;
+   unsigned int p_index, mask;
unsigned int discards;
unsigned int chksum_ok = 0;
 
+   /* Clear status before servicing to reduce spurious interrupts */
+   if (ring->index == DESC_INDEX) {
+   bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_RXDMA_DONE,
+INTRL2_CPU_CLEAR);
+   } else {
+   mask = 1 << (UMAC_IRQ1_RX_INTR_SHIFT + ring->index);
+   bcmgenet_intrl2_1_writel(priv,
+mask,
+INTRL2_CPU_CLEAR);
+   }
+
p_index = bcmgenet_rdma_ring_readl(priv, ring->index, RDMA_PROD_INDEX);
 
discards = (p_index >> DMA_P_INDEX_DISCARD_CNT_SHIFT) &
-- 
2.11.1



[PATCH net-next 12/12] net: bcmgenet: add support for the GENETv5 hardware

2017-03-13 Thread Doug Berger
This commit adds support for the GENETv5 implementation.

The GENETv5 reports a major version of 6 instead of 5 so compensate
for this when verifying the configuration of the driver.  Also the
EPHY revision is now contained in the MDIO registers of the PHY so
the EPHY revision of 0 in GENET_VER_FMT is expected for GENETv5.

Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 91 --
 drivers/net/ethernet/broadcom/genet/bcmgenet.h | 12 +++-
 drivers/net/ethernet/broadcom/genet/bcmmii.c   | 62 ++
 drivers/net/phy/mdio-bcm-unimac.c  |  3 +-
 4 files changed, 118 insertions(+), 50 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 3b49c14128e2..d848ac58189c 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -1011,8 +1011,17 @@ static int bcmgenet_power_down(struct bcmgenet_priv 
*priv,
/* Power down LED */
if (priv->hw_params->flags & GENET_HAS_EXT) {
reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
-   reg |= (EXT_PWR_DOWN_PHY |
-   EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_BIAS);
+   if (GENET_IS_V5(priv))
+   reg |= EXT_PWR_DOWN_PHY_EN |
+  EXT_PWR_DOWN_PHY_RD |
+  EXT_PWR_DOWN_PHY_SD |
+  EXT_PWR_DOWN_PHY_RX |
+  EXT_PWR_DOWN_PHY_TX |
+  EXT_IDDQ_GLBL_PWR;
+   else
+   reg |= EXT_PWR_DOWN_PHY;
+
+   reg |= (EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_BIAS);
bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
 
bcmgenet_phy_power_set(priv->dev, false);
@@ -1037,12 +1046,34 @@ static void bcmgenet_power_up(struct bcmgenet_priv 
*priv,
 
switch (mode) {
case GENET_POWER_PASSIVE:
-   reg &= ~(EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_PHY |
-   EXT_PWR_DOWN_BIAS);
-   /* fallthrough */
+   reg &= ~(EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_BIAS);
+   if (GENET_IS_V5(priv)) {
+   reg &= ~(EXT_PWR_DOWN_PHY_EN |
+EXT_PWR_DOWN_PHY_RD |
+EXT_PWR_DOWN_PHY_SD |
+EXT_PWR_DOWN_PHY_RX |
+EXT_PWR_DOWN_PHY_TX |
+EXT_IDDQ_GLBL_PWR);
+   reg |=   EXT_PHY_RESET;
+   bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
+   mdelay(1);
+
+   reg &=  ~EXT_PHY_RESET;
+   } else {
+   reg &= ~EXT_PWR_DOWN_PHY;
+   reg |= EXT_PWR_DN_EN_LD;
+   }
+   bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
+   bcmgenet_phy_power_set(priv->dev, true);
+   bcmgenet_mii_reset(priv->dev);
+   break;
+
case GENET_POWER_CABLE_SENSE:
/* enable APD */
-   reg |= EXT_PWR_DN_EN_LD;
+   if (!GENET_IS_V5(priv)) {
+   reg |= EXT_PWR_DN_EN_LD;
+   bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
+   }
break;
case GENET_POWER_WOL_MAGIC:
bcmgenet_wol_power_up_cfg(priv, mode);
@@ -1050,12 +1081,6 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv,
default:
break;
}
-
-   bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
-   if (mode == GENET_POWER_PASSIVE) {
-   bcmgenet_phy_power_set(priv->dev, true);
-   bcmgenet_mii_reset(priv->dev);
-   }
 }
 
 /* ioctl handle special commands that are not present in ethtool. */
@@ -3101,6 +3126,25 @@ static struct bcmgenet_hw_params bcmgenet_hw_params[] = {
.flags = GENET_HAS_40BITS | GENET_HAS_EXT |
 GENET_HAS_MDIO_INTR | GENET_HAS_MOCA_LINK_DET,
},
+   [GENET_V5] = {
+   .tx_queues = 4,
+   .tx_bds_per_q = 32,
+   .rx_queues = 0,
+   .rx_bds_per_q = 0,
+   .bp_in_en_shift = 17,
+   .bp_in_mask = 0x1,
+   .hfb_filter_cnt = 48,
+   .hfb_filter_size = 128,
+   .qtag_mask = 0x3F,
+   .tbuf_offset = 0x0600,
+   .hfb_offset = 0x8000,
+   .hfb_reg_offset = 0xfc00,
+   .rdma_offset = 0x2000,
+   .tdma_offset = 0x4000,
+   .words_pe

[PATCH net-next 09/12] net: bcmgenet: return EOPNOTSUPP for unknown ioctl commands

2017-03-13 Thread Doug Berger
This commit changes the ioctl handling behavior to return the
EOPNOTSUPP error code instead of the EINVAL error code when an
unknown ioctl command value is detected.

It also removes some redundant parsing of the ioctl command value
and allows the SIOCSHWTSTAMP value to be handled.

Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 19 +++
 1 file changed, 3 insertions(+), 16 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index d90d366b286f..3b49c14128e2 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -1062,27 +1062,14 @@ static void bcmgenet_power_up(struct bcmgenet_priv 
*priv,
 static int bcmgenet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
struct bcmgenet_priv *priv = netdev_priv(dev);
-   int val = 0;
 
if (!netif_running(dev))
return -EINVAL;
 
-   switch (cmd) {
-   case SIOCGMIIPHY:
-   case SIOCGMIIREG:
-   case SIOCSMIIREG:
-   if (!priv->phydev)
-   val = -ENODEV;
-   else
-   val = phy_mii_ioctl(priv->phydev, rq, cmd);
-   break;
-
-   default:
-   val = -EINVAL;
-   break;
-   }
+   if (!priv->phydev)
+   return -ENODEV;
 
-   return val;
+   return phy_mii_ioctl(priv->phydev, rq, cmd);
 }
 
 static struct enet_cb *bcmgenet_get_txcb(struct bcmgenet_priv *priv,
-- 
2.11.1



[PATCH net-next 08/12] net: bcmgenet: correct return value of __bcmgenet_tx_reclaim

2017-03-13 Thread Doug Berger
The reclaim function should return the number of buffer descriptors
reclaimed, not just the number corresponding to skb packets.

Also, remove the unnecessary computation when updating the consumer
index.

While this is not a functional problem it could degrade performance
of napi in a fragmented transmit stream.

Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 1f94ba1773dd..d90d366b286f 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -1218,7 +1218,7 @@ static unsigned int __bcmgenet_tx_reclaim(struct 
net_device *dev,
}
 
ring->free_bds += txbds_processed;
-   ring->c_index = (ring->c_index + txbds_processed) & DMA_C_INDEX_MASK;
+   ring->c_index = c_index;
 
dev->stats.tx_packets += pkts_compl;
dev->stats.tx_bytes += bytes_compl;
@@ -1231,7 +1231,7 @@ static unsigned int __bcmgenet_tx_reclaim(struct 
net_device *dev,
netif_tx_wake_queue(txq);
}
 
-   return pkts_compl;
+   return txbds_processed;
 }
 
 static unsigned int bcmgenet_tx_reclaim(struct net_device *dev,
-- 
2.11.1



[PATCH v2 net 0/8] net: bcmgenet: minor bug fixes

2017-03-09 Thread Doug Berger
v2: Accidentally sent the wrong set after rebasing.

This collection contains a number of fixes for minor issues with the
bcmgenet driver most of which were present in the initial submission
of the driver.

Some bugs were uncovered by inspection prior to the upcoming update for
GENETv5 support:
  net: bcmgenet: correct the RBUF_OVFL_CNT and RBUF_ERR_CNT MIB values
  net: bcmgenet: correct MIB access of UniMAC RUNT counters
  net: bcmgenet: reserved phy revisions must be checked first
  net: bcmgenet: synchronize irq0 status between the isr and task

Others bugs were found in power management testing:
  net: bcmgenet: power down internal phy if open or resume fails
  net: bcmgenet: Power up the internal PHY before probing the MII
  net: bcmgenet: decouple flow control from bcmgenet_tx_reclaim
  net: bcmgenet: add begin/complete ethtool ops

Doug Berger (7):
  net: bcmgenet: correct the RBUF_OVFL_CNT and RBUF_ERR_CNT MIB values
  net: bcmgenet: correct MIB access of UniMAC RUNT counters
  net: bcmgenet: reserved phy revisions must be checked first
  net: bcmgenet: power down internal phy if open or resume fails
  net: bcmgenet: synchronize irq0 status between the isr and task
  net: bcmgenet: Power up the internal PHY before probing the MII
  net: bcmgenet: decouple flow control from bcmgenet_tx_reclaim

Edwin Chan (1):
  net: bcmgenet: add begin/complete ethtool ops

 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 206 ++---
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |  16 +-
 2 files changed, 158 insertions(+), 64 deletions(-)

-- 
2.11.1



[PATCH v2 net 1/8] net: bcmgenet: correct the RBUF_OVFL_CNT and RBUF_ERR_CNT MIB values

2017-03-09 Thread Doug Berger
The location of the RBUF overflow and error counters has moved between
different version of the GENET MAC.  This commit corrects the driver to
read from the correct locations depending on the version of the GENET
MAC.

Fixes: 1c1008c793fa ("net: bcmgenet: add main driver file")
Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 60 +++---
 drivers/net/ethernet/broadcom/genet/bcmgenet.h | 10 +++--
 2 files changed, 60 insertions(+), 10 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index f92896835d2a..f0fb7eca8eb4 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -1,7 +1,7 @@
 /*
  * Broadcom GENET (Gigabit Ethernet) controller driver
  *
- * Copyright (c) 2014 Broadcom Corporation
+ * Copyright (c) 2014-2017 Broadcom
  *
  * 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
@@ -778,8 +778,9 @@ static const struct bcmgenet_stats 
bcmgenet_gstrings_stats[] = {
STAT_GENET_RUNT("rx_runt_bytes", mib.rx_runt_bytes),
/* Misc UniMAC counters */
STAT_GENET_MISC("rbuf_ovflow_cnt", mib.rbuf_ovflow_cnt,
-   UMAC_RBUF_OVFL_CNT),
-   STAT_GENET_MISC("rbuf_err_cnt", mib.rbuf_err_cnt, UMAC_RBUF_ERR_CNT),
+   UMAC_RBUF_OVFL_CNT_V1),
+   STAT_GENET_MISC("rbuf_err_cnt", mib.rbuf_err_cnt,
+   UMAC_RBUF_ERR_CNT_V1),
STAT_GENET_MISC("mdf_err_cnt", mib.mdf_err_cnt, UMAC_MDF_ERR_CNT),
STAT_GENET_SOFT_MIB("alloc_rx_buff_failed", mib.alloc_rx_buff_failed),
STAT_GENET_SOFT_MIB("rx_dma_failed", mib.rx_dma_failed),
@@ -821,6 +822,45 @@ static void bcmgenet_get_strings(struct net_device *dev, 
u32 stringset,
}
 }
 
+static u32 bcmgenet_update_stat_misc(struct bcmgenet_priv *priv, u16 offset)
+{
+   u16 new_offset;
+   u32 val;
+
+   switch (offset) {
+   case UMAC_RBUF_OVFL_CNT_V1:
+   if (GENET_IS_V2(priv))
+   new_offset = RBUF_OVFL_CNT_V2;
+   else
+   new_offset = RBUF_OVFL_CNT_V3PLUS;
+
+   val = bcmgenet_rbuf_readl(priv, new_offset);
+   /* clear if overflowed */
+   if (val == ~0)
+   bcmgenet_rbuf_writel(priv, 0, new_offset);
+   break;
+   case UMAC_RBUF_ERR_CNT_V1:
+   if (GENET_IS_V2(priv))
+   new_offset = RBUF_ERR_CNT_V2;
+   else
+   new_offset = RBUF_ERR_CNT_V3PLUS;
+
+   val = bcmgenet_rbuf_readl(priv, new_offset);
+   /* clear if overflowed */
+   if (val == ~0)
+   bcmgenet_rbuf_writel(priv, 0, new_offset);
+   break;
+   default:
+   val = bcmgenet_umac_readl(priv, offset);
+   /* clear if overflowed */
+   if (val == ~0)
+   bcmgenet_umac_writel(priv, 0, offset);
+   break;
+   }
+
+   return val;
+}
+
 static void bcmgenet_update_mib_counters(struct bcmgenet_priv *priv)
 {
int i, j = 0;
@@ -845,10 +885,16 @@ static void bcmgenet_update_mib_counters(struct 
bcmgenet_priv *priv)
  UMAC_MIB_START + j + offset);
break;
case BCMGENET_STAT_MISC:
-   val = bcmgenet_umac_readl(priv, s->reg_offset);
-   /* clear if overflowed */
-   if (val == ~0)
-   bcmgenet_umac_writel(priv, 0, s->reg_offset);
+   if (GENET_IS_V1(priv)) {
+   val = bcmgenet_umac_readl(priv, s->reg_offset);
+   /* clear if overflowed */
+   if (val == ~0)
+   bcmgenet_umac_writel(priv, 0,
+s->reg_offset);
+   } else {
+   val = bcmgenet_update_stat_misc(priv,
+   s->reg_offset);
+   }
break;
}
 
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
index 1e2dc34d331a..d5fb0d772dcd 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Broadcom Corporation
+ * Copyright (c) 2014-2017 Broadcom
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the 

[PATCH v2 net 3/8] net: bcmgenet: reserved phy revisions must be checked first

2017-03-09 Thread Doug Berger
The reserved gphy_rev value of 0x01ff must be tested before the old
or new scheme for GPHY major versioning are tested, otherwise it will
be treated as 0xff00 according to the old scheme.

Fixes: b04a2f5b9ff5 ("net: bcmgenet: add support for new GENET PHY revision 
scheme")
Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 01a172d95328..99f8d9024633 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -3226,6 +3226,12 @@ static void bcmgenet_set_hw_params(struct bcmgenet_priv 
*priv)
 */
gphy_rev = reg & 0x;
 
+   /* This is reserved so should require special treatment */
+   if (gphy_rev == 0 || gphy_rev == 0x01ff) {
+   pr_warn("Invalid GPHY revision detected: 0x%04x\n", gphy_rev);
+   return;
+   }
+
/* This is the good old scheme, just GPHY major, no minor nor patch */
if ((gphy_rev & 0xf0) != 0)
priv->gphy_rev = gphy_rev << 8;
@@ -3234,12 +3240,6 @@ static void bcmgenet_set_hw_params(struct bcmgenet_priv 
*priv)
else if ((gphy_rev & 0xff00) != 0)
priv->gphy_rev = gphy_rev;
 
-   /* This is reserved so should require special treatment */
-   else if (gphy_rev == 0 || gphy_rev == 0x01ff) {
-   pr_warn("Invalid GPHY revision detected: 0x%04x\n", gphy_rev);
-   return;
-   }
-
 #ifdef CONFIG_PHYS_ADDR_T_64BIT
if (!(params->flags & GENET_HAS_40BITS))
pr_warn("GENET does not support 40-bits PA\n");
-- 
2.11.1



[PATCH v2 net 2/8] net: bcmgenet: correct MIB access of UniMAC RUNT counters

2017-03-09 Thread Doug Berger
The gap between the Tx status counters and the Rx RUNT counters is now
being added to allow correct reporting of the registers.

Fixes: 1c1008c793fa ("net: bcmgenet: add main driver file")
Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 11 +++
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index f0fb7eca8eb4..01a172d95328 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -876,13 +876,16 @@ static void bcmgenet_update_mib_counters(struct 
bcmgenet_priv *priv)
case BCMGENET_STAT_NETDEV:
case BCMGENET_STAT_SOFT:
continue;
-   case BCMGENET_STAT_MIB_RX:
-   case BCMGENET_STAT_MIB_TX:
case BCMGENET_STAT_RUNT:
-   if (s->type != BCMGENET_STAT_MIB_RX)
-   offset = BCMGENET_STAT_OFFSET;
+   offset += BCMGENET_STAT_OFFSET;
+   /* fall through */
+   case BCMGENET_STAT_MIB_TX:
+   offset += BCMGENET_STAT_OFFSET;
+   /* fall through */
+   case BCMGENET_STAT_MIB_RX:
val = bcmgenet_umac_readl(priv,
  UMAC_MIB_START + j + offset);
+   offset = 0; /* Reset Offset */
break;
case BCMGENET_STAT_MISC:
if (GENET_IS_V1(priv)) {
-- 
2.11.1



[PATCH v2 net 7/8] net: bcmgenet: add begin/complete ethtool ops

2017-03-09 Thread Doug Berger
From: Edwin Chan <edwin.c...@broadcom.com>

Make sure clock is enabled for ethtool ops.

Fixes: 1c1008c793fa ("net: bcmgenet: add main driver file")
Signed-off-by: Edwin Chan <edwin.c...@broadcom.com>
Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 18 ++
 1 file changed, 18 insertions(+)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index f93098840775..ec1f3014e410 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -450,6 +450,22 @@ static inline void bcmgenet_rdma_ring_writel(struct 
bcmgenet_priv *priv,
genet_dma_ring_regs[r]);
 }
 
+static int bcmgenet_begin(struct net_device *dev)
+{
+   struct bcmgenet_priv *priv = netdev_priv(dev);
+
+   /* Turn on the clock */
+   return clk_prepare_enable(priv->clk);
+}
+
+static void bcmgenet_complete(struct net_device *dev)
+{
+   struct bcmgenet_priv *priv = netdev_priv(dev);
+
+   /* Turn off the clock */
+   clk_disable_unprepare(priv->clk);
+}
+
 static int bcmgenet_get_link_ksettings(struct net_device *dev,
   struct ethtool_link_ksettings *cmd)
 {
@@ -1022,6 +1038,8 @@ static int bcmgenet_set_eee(struct net_device *dev, 
struct ethtool_eee *e)
 
 /* standard ethtool support functions. */
 static const struct ethtool_ops bcmgenet_ethtool_ops = {
+   .begin  = bcmgenet_begin,
+   .complete   = bcmgenet_complete,
.get_strings= bcmgenet_get_strings,
.get_sset_count = bcmgenet_get_sset_count,
.get_ethtool_stats  = bcmgenet_get_ethtool_stats,
-- 
2.11.1



[PATCH v2 net 6/8] net: bcmgenet: Power up the internal PHY before probing the MII

2017-03-09 Thread Doug Berger
When using the internal PHY it must be powered up when the MII is probed
or the PHY will not be detected.  Since the PHY is powered up at reset
this has not been a problem.  However, when the kernel is restarted with
kexec the PHY will likely be powered down when the kernel starts so it
will not be detected and the Ethernet link will not be established.

This commit explicitly powers up the internal PHY when the GENET driver
is probed to correct this behavior.

Fixes: 1c1008c793fa ("net: bcmgenet: add main driver file")
Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 527cecaf12c1..f93098840775 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -3289,6 +3289,7 @@ static int bcmgenet_probe(struct platform_device *pdev)
const void *macaddr;
struct resource *r;
int err = -EIO;
+   const char *phy_mode_str;
 
/* Up to GENET_MAX_MQ_CNT + 1 TX queues and RX queues */
dev = alloc_etherdev_mqs(sizeof(*priv), GENET_MAX_MQ_CNT + 1,
@@ -3396,6 +3397,13 @@ static int bcmgenet_probe(struct platform_device *pdev)
priv->clk_eee = NULL;
}
 
+   /* If this is an internal GPHY, power it on now, before UniMAC is
+* brought out of reset as absolutely no UniMAC activity is allowed
+*/
+   if (dn && !of_property_read_string(dn, "phy-mode", _mode_str) &&
+   !strcasecmp(phy_mode_str, "internal"))
+   bcmgenet_power_up(priv, GENET_POWER_PASSIVE);
+
err = reset_umac(priv);
if (err)
goto err_clk_disable;
-- 
2.11.1



[PATCH v2 net 8/8] net: bcmgenet: decouple flow control from bcmgenet_tx_reclaim

2017-03-09 Thread Doug Berger
The bcmgenet_tx_reclaim() function is used to reclaim transmit
resources in different places within the driver.  Most of them
should not affect the state of the transmit flow control.

This commit relocates the logic for waking tx queues based on
freed resources to the napi polling function where it is more
appropriate.

Fixes: 1c1008c793fa ("net: bcmgenet: add main driver file")
Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 20 +++-
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index ec1f3014e410..69015fa50f20 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -1234,7 +1234,6 @@ static unsigned int __bcmgenet_tx_reclaim(struct 
net_device *dev,
struct bcmgenet_priv *priv = netdev_priv(dev);
struct device *kdev = >pdev->dev;
struct enet_cb *tx_cb_ptr;
-   struct netdev_queue *txq;
unsigned int pkts_compl = 0;
unsigned int bytes_compl = 0;
unsigned int c_index;
@@ -1286,13 +1285,8 @@ static unsigned int __bcmgenet_tx_reclaim(struct 
net_device *dev,
dev->stats.tx_packets += pkts_compl;
dev->stats.tx_bytes += bytes_compl;
 
-   txq = netdev_get_tx_queue(dev, ring->queue);
-   netdev_tx_completed_queue(txq, pkts_compl, bytes_compl);
-
-   if (ring->free_bds > (MAX_SKB_FRAGS + 1)) {
-   if (netif_tx_queue_stopped(txq))
-   netif_tx_wake_queue(txq);
-   }
+   netdev_tx_completed_queue(netdev_get_tx_queue(dev, ring->queue),
+ pkts_compl, bytes_compl);
 
return pkts_compl;
 }
@@ -1315,8 +1309,16 @@ static int bcmgenet_tx_poll(struct napi_struct *napi, 
int budget)
struct bcmgenet_tx_ring *ring =
container_of(napi, struct bcmgenet_tx_ring, napi);
unsigned int work_done = 0;
+   struct netdev_queue *txq;
+   unsigned long flags;
 
-   work_done = bcmgenet_tx_reclaim(ring->priv->dev, ring);
+   spin_lock_irqsave(>lock, flags);
+   work_done = __bcmgenet_tx_reclaim(ring->priv->dev, ring);
+   if (ring->free_bds > (MAX_SKB_FRAGS + 1)) {
+   txq = netdev_get_tx_queue(ring->priv->dev, ring->queue);
+   netif_tx_wake_queue(txq);
+   }
+   spin_unlock_irqrestore(>lock, flags);
 
if (work_done == 0) {
napi_complete(napi);
-- 
2.11.1



[PATCH v2 net 4/8] net: bcmgenet: power down internal phy if open or resume fails

2017-03-09 Thread Doug Berger
Since the internal PHY is powered up during the open and resume
functions it should be powered back down if the functions fail.

Fixes: 1c1008c793fa ("net: bcmgenet: add main driver file")
Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 99f8d9024633..475dc14931af 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -2850,6 +2850,8 @@ static int bcmgenet_open(struct net_device *dev)
 err_fini_dma:
bcmgenet_fini_dma(priv);
 err_clk_disable:
+   if (priv->internal_phy)
+   bcmgenet_power_down(priv, GENET_POWER_PASSIVE);
clk_disable_unprepare(priv->clk);
return ret;
 }
@@ -3551,6 +3553,8 @@ static int bcmgenet_resume(struct device *d)
return 0;
 
 out_clk_disable:
+   if (priv->internal_phy)
+   bcmgenet_power_down(priv, GENET_POWER_PASSIVE);
clk_disable_unprepare(priv->clk);
return ret;
 }
-- 
2.11.1



[PATCH v2 net 5/8] net: bcmgenet: synchronize irq0 status between the isr and task

2017-03-09 Thread Doug Berger
Add a spinlock to ensure that irq0_stat is not unintentionally altered
as the result of preemption.  Also removed unserviced irq0 interrupts
and removed irq1_stat since there is no bottom half service for those
interrupts.

Fixes: 1c1008c793fa ("net: bcmgenet: add main driver file")
Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 73 ++
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |  6 ++-
 2 files changed, 44 insertions(+), 35 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 475dc14931af..527cecaf12c1 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -2506,24 +2506,28 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv)
 /* Interrupt bottom half */
 static void bcmgenet_irq_task(struct work_struct *work)
 {
+   unsigned long flags;
+   unsigned int status;
struct bcmgenet_priv *priv = container_of(
work, struct bcmgenet_priv, bcmgenet_irq_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;
+   spin_lock_irqsave(>lock, flags);
+   status = priv->irq0_stat;
+   priv->irq0_stat = 0;
+   spin_unlock_irqrestore(>lock, flags);
+
+   if (status & 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->irq0_stat & UMAC_IRQ_LINK_EVENT) {
+   if (status & UMAC_IRQ_LINK_EVENT)
phy_mac_interrupt(priv->phydev,
- !!(priv->irq0_stat & UMAC_IRQ_LINK_UP));
-   priv->irq0_stat &= ~UMAC_IRQ_LINK_EVENT;
-   }
+ !!(status & UMAC_IRQ_LINK_UP));
 }
 
 /* bcmgenet_isr1: handle Rx and Tx priority queues */
@@ -2532,22 +2536,21 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id)
struct bcmgenet_priv *priv = dev_id;
struct bcmgenet_rx_ring *rx_ring;
struct bcmgenet_tx_ring *tx_ring;
-   unsigned int index;
+   unsigned int index, status;
 
-   /* Save irq status for bottom-half processing. */
-   priv->irq1_stat =
-   bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_STAT) &
+   /* Read irq status */
+   status = bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_STAT) &
~bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_MASK_STATUS);
 
/* clear interrupts */
-   bcmgenet_intrl2_1_writel(priv, priv->irq1_stat, INTRL2_CPU_CLEAR);
+   bcmgenet_intrl2_1_writel(priv, status, INTRL2_CPU_CLEAR);
 
netif_dbg(priv, intr, priv->dev,
- "%s: IRQ=0x%x\n", __func__, priv->irq1_stat);
+ "%s: IRQ=0x%x\n", __func__, status);
 
/* Check Rx priority queue interrupts */
for (index = 0; index < priv->hw_params->rx_queues; index++) {
-   if (!(priv->irq1_stat & BIT(UMAC_IRQ1_RX_INTR_SHIFT + index)))
+   if (!(status & BIT(UMAC_IRQ1_RX_INTR_SHIFT + index)))
continue;
 
rx_ring = >rx_rings[index];
@@ -2560,7 +2563,7 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id)
 
/* Check Tx priority queue interrupts */
for (index = 0; index < priv->hw_params->tx_queues; index++) {
-   if (!(priv->irq1_stat & BIT(index)))
+   if (!(status & BIT(index)))
continue;
 
tx_ring = >tx_rings[index];
@@ -2580,19 +2583,20 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id)
struct bcmgenet_priv *priv = dev_id;
struct bcmgenet_rx_ring *rx_ring;
struct bcmgenet_tx_ring *tx_ring;
+   unsigned int status;
+   unsigned long flags;
 
-   /* Save irq status for bottom-half processing. */
-   priv->irq0_stat =
-   bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_STAT) &
+   /* Read irq status */
+   status = bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_STAT) &
~bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_MASK_STATUS);
 
/* clear interrupts */
-   bcmgenet_intrl2_0_writel(priv, priv->irq0_stat, INTRL2_CPU_CLEAR);
+   bcmgenet_intrl2_0_writel(priv, status, INTRL2_CPU_CLEAR);
 
netif_dbg(priv, intr, priv->dev,
- "IRQ=0x%x\n", priv->irq0_stat);
+ "IRQ=0x%x\n", status);
 
-   if (priv->irq0_stat & UMAC_IRQ_RXDMA_DONE)

[PATCH net 0/8] net: bcmgenet: minor bug fixes

2017-03-09 Thread Doug Berger
This collection contains a number of fixes for minor issues with the
bcmgenet driver most of which were present in the initial submission
of the driver.

Some bugs were uncovered by inspection prior to the upcoming update for
GENETv5 support:
  net: bcmgenet: correct the RBUF_OVFL_CNT and RBUF_ERR_CNT MIB values
  net: bcmgenet: correct MIB access of UniMAC RUNT counters
  net: bcmgenet: reserved phy revisions must be checked first
  net: bcmgenet: synchronize irq0 status between the isr and task

Others bugs were found in power management testing:
  net: bcmgenet: power down internal phy if open or resume fails
  net: bcmgenet: Power up the internal PHY before probing the MII
  net: bcmgenet: decouple flow control from bcmgenet_tx_reclaim
  net: bcmgenet: add begin/complete ethtool ops

Doug Berger (7):
  net: bcmgenet: correct the RBUF_OVFL_CNT and RBUF_ERR_CNT MIB values
  net: bcmgenet: correct MIB access of UniMAC RUNT counters
  net: bcmgenet: reserved phy revisions must be checked first
  net: bcmgenet: power down internal phy if open or resume fails
  net: bcmgenet: synchronize irq0 status between the isr and task
  net: bcmgenet: Power up the internal PHY before probing the MII
  net: bcmgenet: decouple flow control from bcmgenet_tx_reclaim

Edwin Chan (1):
  net: bcmgenet: add begin/complete ethtool ops

 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 206 ++---
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |  16 +-
 2 files changed, 158 insertions(+), 64 deletions(-)

-- 
2.11.1



[PATCH net 1/8] net: bcmgenet: correct the RBUF_OVFL_CNT and RBUF_ERR_CNT MIB values

2017-03-09 Thread Doug Berger
From: Doug Berger <doug.ber...@broadcom.com>

The location of the RBUF overflow and error counters has moved between
different version of the GENET MAC.  This commit corrects the driver to
read from the correct locations depending on the version of the GENET
MAC.

refs #SWLINUX-4311

Fixes: 1c1008c793fa ("net: bcmgenet: add main driver file")
Signed-off-by: Doug Berger <doug.ber...@broadcom.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 60 +++---
 drivers/net/ethernet/broadcom/genet/bcmgenet.h | 10 +++--
 2 files changed, 60 insertions(+), 10 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index f92896835d2a..f0fb7eca8eb4 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -1,7 +1,7 @@
 /*
  * Broadcom GENET (Gigabit Ethernet) controller driver
  *
- * Copyright (c) 2014 Broadcom Corporation
+ * Copyright (c) 2014-2017 Broadcom
  *
  * 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
@@ -778,8 +778,9 @@ static const struct bcmgenet_stats 
bcmgenet_gstrings_stats[] = {
STAT_GENET_RUNT("rx_runt_bytes", mib.rx_runt_bytes),
/* Misc UniMAC counters */
STAT_GENET_MISC("rbuf_ovflow_cnt", mib.rbuf_ovflow_cnt,
-   UMAC_RBUF_OVFL_CNT),
-   STAT_GENET_MISC("rbuf_err_cnt", mib.rbuf_err_cnt, UMAC_RBUF_ERR_CNT),
+   UMAC_RBUF_OVFL_CNT_V1),
+   STAT_GENET_MISC("rbuf_err_cnt", mib.rbuf_err_cnt,
+   UMAC_RBUF_ERR_CNT_V1),
STAT_GENET_MISC("mdf_err_cnt", mib.mdf_err_cnt, UMAC_MDF_ERR_CNT),
STAT_GENET_SOFT_MIB("alloc_rx_buff_failed", mib.alloc_rx_buff_failed),
STAT_GENET_SOFT_MIB("rx_dma_failed", mib.rx_dma_failed),
@@ -821,6 +822,45 @@ static void bcmgenet_get_strings(struct net_device *dev, 
u32 stringset,
}
 }
 
+static u32 bcmgenet_update_stat_misc(struct bcmgenet_priv *priv, u16 offset)
+{
+   u16 new_offset;
+   u32 val;
+
+   switch (offset) {
+   case UMAC_RBUF_OVFL_CNT_V1:
+   if (GENET_IS_V2(priv))
+   new_offset = RBUF_OVFL_CNT_V2;
+   else
+   new_offset = RBUF_OVFL_CNT_V3PLUS;
+
+   val = bcmgenet_rbuf_readl(priv, new_offset);
+   /* clear if overflowed */
+   if (val == ~0)
+   bcmgenet_rbuf_writel(priv, 0, new_offset);
+   break;
+   case UMAC_RBUF_ERR_CNT_V1:
+   if (GENET_IS_V2(priv))
+   new_offset = RBUF_ERR_CNT_V2;
+   else
+   new_offset = RBUF_ERR_CNT_V3PLUS;
+
+   val = bcmgenet_rbuf_readl(priv, new_offset);
+   /* clear if overflowed */
+   if (val == ~0)
+   bcmgenet_rbuf_writel(priv, 0, new_offset);
+   break;
+   default:
+   val = bcmgenet_umac_readl(priv, offset);
+   /* clear if overflowed */
+   if (val == ~0)
+   bcmgenet_umac_writel(priv, 0, offset);
+   break;
+   }
+
+   return val;
+}
+
 static void bcmgenet_update_mib_counters(struct bcmgenet_priv *priv)
 {
int i, j = 0;
@@ -845,10 +885,16 @@ static void bcmgenet_update_mib_counters(struct 
bcmgenet_priv *priv)
  UMAC_MIB_START + j + offset);
break;
case BCMGENET_STAT_MISC:
-   val = bcmgenet_umac_readl(priv, s->reg_offset);
-   /* clear if overflowed */
-   if (val == ~0)
-   bcmgenet_umac_writel(priv, 0, s->reg_offset);
+   if (GENET_IS_V1(priv)) {
+   val = bcmgenet_umac_readl(priv, s->reg_offset);
+   /* clear if overflowed */
+   if (val == ~0)
+   bcmgenet_umac_writel(priv, 0,
+s->reg_offset);
+   } else {
+   val = bcmgenet_update_stat_misc(priv,
+   s->reg_offset);
+   }
break;
}
 
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
index 1e2dc34d331a..d5fb0d772dcd 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Broadcom Corporation
+ * Copyright (c) 2014-2017 Broadcom
  *
  * Thi

[PATCH net 3/8] net: bcmgenet: reserved phy revisions must be checked first

2017-03-09 Thread Doug Berger
From: Doug Berger <doug.ber...@broadcom.com>

The reserved gphy_rev value of 0x01ff must be tested before the old
or new scheme for GPHY major versioning are tested, otherwise it will
be treated as 0xff00 according to the old scheme.

refs #SWLINUX-4311

Fixes: b04a2f5b9ff5 ("net: bcmgenet: add support for new GENET PHY revision 
scheme")
Signed-off-by: Doug Berger <doug.ber...@broadcom.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 01a172d95328..99f8d9024633 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -3226,6 +3226,12 @@ static void bcmgenet_set_hw_params(struct bcmgenet_priv 
*priv)
 */
gphy_rev = reg & 0x;
 
+   /* This is reserved so should require special treatment */
+   if (gphy_rev == 0 || gphy_rev == 0x01ff) {
+   pr_warn("Invalid GPHY revision detected: 0x%04x\n", gphy_rev);
+   return;
+   }
+
/* This is the good old scheme, just GPHY major, no minor nor patch */
if ((gphy_rev & 0xf0) != 0)
priv->gphy_rev = gphy_rev << 8;
@@ -3234,12 +3240,6 @@ static void bcmgenet_set_hw_params(struct bcmgenet_priv 
*priv)
else if ((gphy_rev & 0xff00) != 0)
priv->gphy_rev = gphy_rev;
 
-   /* This is reserved so should require special treatment */
-   else if (gphy_rev == 0 || gphy_rev == 0x01ff) {
-   pr_warn("Invalid GPHY revision detected: 0x%04x\n", gphy_rev);
-   return;
-   }
-
 #ifdef CONFIG_PHYS_ADDR_T_64BIT
if (!(params->flags & GENET_HAS_40BITS))
pr_warn("GENET does not support 40-bits PA\n");
-- 
2.11.1



[PATCH net 4/8] net: bcmgenet: power down internal phy if open or resume fails

2017-03-09 Thread Doug Berger
From: Doug Berger <doug.ber...@broadcom.com>

Since the internal PHY is powered up during the open and resume
functions it should be powered back down if the functions fail.

refs #SWLINUX-4311

Fixes: 1c1008c793fa ("net: bcmgenet: add main driver file")
Signed-off-by: Doug Berger <doug.ber...@broadcom.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 99f8d9024633..475dc14931af 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -2850,6 +2850,8 @@ static int bcmgenet_open(struct net_device *dev)
 err_fini_dma:
bcmgenet_fini_dma(priv);
 err_clk_disable:
+   if (priv->internal_phy)
+   bcmgenet_power_down(priv, GENET_POWER_PASSIVE);
clk_disable_unprepare(priv->clk);
return ret;
 }
@@ -3551,6 +3553,8 @@ static int bcmgenet_resume(struct device *d)
return 0;
 
 out_clk_disable:
+   if (priv->internal_phy)
+   bcmgenet_power_down(priv, GENET_POWER_PASSIVE);
clk_disable_unprepare(priv->clk);
return ret;
 }
-- 
2.11.1



[PATCH net 6/8] net: bcmgenet: Power up the internal PHY before probing the MII

2017-03-09 Thread Doug Berger
From: Doug Berger <doug.ber...@broadcom.com>

When using the internal PHY it must be powered up when the MII is probed
or the PHY will not be detected.  Since the PHY is powered up at reset
this has not been a problem.  However, when the kernel is restarted with
kexec the PHY will likely be powered down when the kernel starts so it
will not be detected and the Ethernet link will not be established.

This commit explicitly powers up the internal PHY when the GENET driver
is probed to correct this behavior.

refs #SWLINUX-4311

Fixes: 1c1008c793fa ("net: bcmgenet: add main driver file")
Signed-off-by: Doug Berger <doug.ber...@broadcom.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 527cecaf12c1..f93098840775 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -3289,6 +3289,7 @@ static int bcmgenet_probe(struct platform_device *pdev)
const void *macaddr;
struct resource *r;
int err = -EIO;
+   const char *phy_mode_str;
 
/* Up to GENET_MAX_MQ_CNT + 1 TX queues and RX queues */
dev = alloc_etherdev_mqs(sizeof(*priv), GENET_MAX_MQ_CNT + 1,
@@ -3396,6 +3397,13 @@ static int bcmgenet_probe(struct platform_device *pdev)
priv->clk_eee = NULL;
}
 
+   /* If this is an internal GPHY, power it on now, before UniMAC is
+* brought out of reset as absolutely no UniMAC activity is allowed
+*/
+   if (dn && !of_property_read_string(dn, "phy-mode", _mode_str) &&
+   !strcasecmp(phy_mode_str, "internal"))
+   bcmgenet_power_up(priv, GENET_POWER_PASSIVE);
+
err = reset_umac(priv);
if (err)
goto err_clk_disable;
-- 
2.11.1



[PATCH net 2/8] net: bcmgenet: correct MIB access of UniMAC RUNT counters

2017-03-09 Thread Doug Berger
From: Doug Berger <doug.ber...@broadcom.com>

The gap between the Tx status counters and the Rx RUNT counters is now
being added to allow correct reporting of the registers.

refs #SWLINUX-4311

Fixes: 1c1008c793fa ("net: bcmgenet: add main driver file")
Signed-off-by: Doug Berger <doug.ber...@broadcom.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 11 +++
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index f0fb7eca8eb4..01a172d95328 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -876,13 +876,16 @@ static void bcmgenet_update_mib_counters(struct 
bcmgenet_priv *priv)
case BCMGENET_STAT_NETDEV:
case BCMGENET_STAT_SOFT:
continue;
-   case BCMGENET_STAT_MIB_RX:
-   case BCMGENET_STAT_MIB_TX:
case BCMGENET_STAT_RUNT:
-   if (s->type != BCMGENET_STAT_MIB_RX)
-   offset = BCMGENET_STAT_OFFSET;
+   offset += BCMGENET_STAT_OFFSET;
+   /* fall through */
+   case BCMGENET_STAT_MIB_TX:
+   offset += BCMGENET_STAT_OFFSET;
+   /* fall through */
+   case BCMGENET_STAT_MIB_RX:
val = bcmgenet_umac_readl(priv,
  UMAC_MIB_START + j + offset);
+   offset = 0; /* Reset Offset */
break;
case BCMGENET_STAT_MISC:
if (GENET_IS_V1(priv)) {
-- 
2.11.1



[PATCH net 8/8] net: bcmgenet: decouple flow control from bcmgenet_tx_reclaim

2017-03-09 Thread Doug Berger
From: Doug Berger <doug.ber...@broadcom.com>

The bcmgenet_tx_reclaim() function is used to reclaim transmit
resources in different places within the driver.  Most of them
should not affect the state of the transmit flow control.

This commit relocates the logic for waking tx queues based on
freed resources to the napi polling function where it is more
appropriate.

refs #SWLINUX-4311

Fixes: 1c1008c793fa ("net: bcmgenet: add main driver file")
Signed-off-by: Doug Berger <doug.ber...@broadcom.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 20 +++-
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index ec1f3014e410..69015fa50f20 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -1234,7 +1234,6 @@ static unsigned int __bcmgenet_tx_reclaim(struct 
net_device *dev,
struct bcmgenet_priv *priv = netdev_priv(dev);
struct device *kdev = >pdev->dev;
struct enet_cb *tx_cb_ptr;
-   struct netdev_queue *txq;
unsigned int pkts_compl = 0;
unsigned int bytes_compl = 0;
unsigned int c_index;
@@ -1286,13 +1285,8 @@ static unsigned int __bcmgenet_tx_reclaim(struct 
net_device *dev,
dev->stats.tx_packets += pkts_compl;
dev->stats.tx_bytes += bytes_compl;
 
-   txq = netdev_get_tx_queue(dev, ring->queue);
-   netdev_tx_completed_queue(txq, pkts_compl, bytes_compl);
-
-   if (ring->free_bds > (MAX_SKB_FRAGS + 1)) {
-   if (netif_tx_queue_stopped(txq))
-   netif_tx_wake_queue(txq);
-   }
+   netdev_tx_completed_queue(netdev_get_tx_queue(dev, ring->queue),
+ pkts_compl, bytes_compl);
 
return pkts_compl;
 }
@@ -1315,8 +1309,16 @@ static int bcmgenet_tx_poll(struct napi_struct *napi, 
int budget)
struct bcmgenet_tx_ring *ring =
container_of(napi, struct bcmgenet_tx_ring, napi);
unsigned int work_done = 0;
+   struct netdev_queue *txq;
+   unsigned long flags;
 
-   work_done = bcmgenet_tx_reclaim(ring->priv->dev, ring);
+   spin_lock_irqsave(>lock, flags);
+   work_done = __bcmgenet_tx_reclaim(ring->priv->dev, ring);
+   if (ring->free_bds > (MAX_SKB_FRAGS + 1)) {
+   txq = netdev_get_tx_queue(ring->priv->dev, ring->queue);
+   netif_tx_wake_queue(txq);
+   }
+   spin_unlock_irqrestore(>lock, flags);
 
if (work_done == 0) {
napi_complete(napi);
-- 
2.11.1



[PATCH net 7/8] net: bcmgenet: add begin/complete ethtool ops

2017-03-09 Thread Doug Berger
From: Edwin Chan <edwin.c...@broadcom.com>

Make sure clock is enabled for ethtool ops.

refs #SWLINUX-4311

Fixes: 1c1008c793fa ("net: bcmgenet: add main driver file")
Signed-off-by: Edwin Chan <edwin.c...@broadcom.com>
Signed-off-by: Doug Berger <doug.ber...@broadcom.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 18 ++
 1 file changed, 18 insertions(+)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index f93098840775..ec1f3014e410 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -450,6 +450,22 @@ static inline void bcmgenet_rdma_ring_writel(struct 
bcmgenet_priv *priv,
genet_dma_ring_regs[r]);
 }
 
+static int bcmgenet_begin(struct net_device *dev)
+{
+   struct bcmgenet_priv *priv = netdev_priv(dev);
+
+   /* Turn on the clock */
+   return clk_prepare_enable(priv->clk);
+}
+
+static void bcmgenet_complete(struct net_device *dev)
+{
+   struct bcmgenet_priv *priv = netdev_priv(dev);
+
+   /* Turn off the clock */
+   clk_disable_unprepare(priv->clk);
+}
+
 static int bcmgenet_get_link_ksettings(struct net_device *dev,
   struct ethtool_link_ksettings *cmd)
 {
@@ -1022,6 +1038,8 @@ static int bcmgenet_set_eee(struct net_device *dev, 
struct ethtool_eee *e)
 
 /* standard ethtool support functions. */
 static const struct ethtool_ops bcmgenet_ethtool_ops = {
+   .begin  = bcmgenet_begin,
+   .complete   = bcmgenet_complete,
.get_strings= bcmgenet_get_strings,
.get_sset_count = bcmgenet_get_sset_count,
.get_ethtool_stats  = bcmgenet_get_ethtool_stats,
-- 
2.11.1



[PATCH net 5/8] net: bcmgenet: synchronize irq0 status between the isr and task

2017-03-09 Thread Doug Berger
From: Doug Berger <doug.ber...@broadcom.com>

Add a spinlock to ensure that irq0_stat is not unintentionally altered
as the result of preemption.  Also removed unserviced irq0 interrupts
and removed irq1_stat since there is no bottom half service for those
interrupts.

refs #SWLINUX-4311

Fixes: 1c1008c793fa ("net: bcmgenet: add main driver file")
Signed-off-by: Doug Berger <doug.ber...@broadcom.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 73 ++
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |  6 ++-
 2 files changed, 44 insertions(+), 35 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 475dc14931af..527cecaf12c1 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -2506,24 +2506,28 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv)
 /* Interrupt bottom half */
 static void bcmgenet_irq_task(struct work_struct *work)
 {
+   unsigned long flags;
+   unsigned int status;
struct bcmgenet_priv *priv = container_of(
work, struct bcmgenet_priv, bcmgenet_irq_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;
+   spin_lock_irqsave(>lock, flags);
+   status = priv->irq0_stat;
+   priv->irq0_stat = 0;
+   spin_unlock_irqrestore(>lock, flags);
+
+   if (status & 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->irq0_stat & UMAC_IRQ_LINK_EVENT) {
+   if (status & UMAC_IRQ_LINK_EVENT)
phy_mac_interrupt(priv->phydev,
- !!(priv->irq0_stat & UMAC_IRQ_LINK_UP));
-   priv->irq0_stat &= ~UMAC_IRQ_LINK_EVENT;
-   }
+ !!(status & UMAC_IRQ_LINK_UP));
 }
 
 /* bcmgenet_isr1: handle Rx and Tx priority queues */
@@ -2532,22 +2536,21 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id)
struct bcmgenet_priv *priv = dev_id;
struct bcmgenet_rx_ring *rx_ring;
struct bcmgenet_tx_ring *tx_ring;
-   unsigned int index;
+   unsigned int index, status;
 
-   /* Save irq status for bottom-half processing. */
-   priv->irq1_stat =
-   bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_STAT) &
+   /* Read irq status */
+   status = bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_STAT) &
~bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_MASK_STATUS);
 
/* clear interrupts */
-   bcmgenet_intrl2_1_writel(priv, priv->irq1_stat, INTRL2_CPU_CLEAR);
+   bcmgenet_intrl2_1_writel(priv, status, INTRL2_CPU_CLEAR);
 
netif_dbg(priv, intr, priv->dev,
- "%s: IRQ=0x%x\n", __func__, priv->irq1_stat);
+ "%s: IRQ=0x%x\n", __func__, status);
 
/* Check Rx priority queue interrupts */
for (index = 0; index < priv->hw_params->rx_queues; index++) {
-   if (!(priv->irq1_stat & BIT(UMAC_IRQ1_RX_INTR_SHIFT + index)))
+   if (!(status & BIT(UMAC_IRQ1_RX_INTR_SHIFT + index)))
continue;
 
rx_ring = >rx_rings[index];
@@ -2560,7 +2563,7 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id)
 
/* Check Tx priority queue interrupts */
for (index = 0; index < priv->hw_params->tx_queues; index++) {
-   if (!(priv->irq1_stat & BIT(index)))
+   if (!(status & BIT(index)))
continue;
 
tx_ring = >tx_rings[index];
@@ -2580,19 +2583,20 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id)
struct bcmgenet_priv *priv = dev_id;
struct bcmgenet_rx_ring *rx_ring;
struct bcmgenet_tx_ring *tx_ring;
+   unsigned int status;
+   unsigned long flags;
 
-   /* Save irq status for bottom-half processing. */
-   priv->irq0_stat =
-   bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_STAT) &
+   /* Read irq status */
+   status = bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_STAT) &
~bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_MASK_STATUS);
 
/* clear interrupts */
-   bcmgenet_intrl2_0_writel(priv, priv->irq0_stat, INTRL2_CPU_CLEAR);
+   bcmgenet_intrl2_0_writel(priv, status, INTRL2_CPU_CLEAR);
 
netif_dbg(priv, intr, priv->dev,
- "IRQ=0x%x\n", priv->irq0_stat);
+ "IRQ=0x%x\n", status);
 
-   if (pri