Re: [PATCH] net: bcmgenet: fix mask check in bcmgenet_validate_flow()

2020-09-02 Thread Doug Berger
On 9/2/2020 4:18 AM, Denis Efremov wrote:
> VALIDATE_MASK(eth_mask->h_source) is checked twice in a row in
> bcmgenet_validate_flow(). Add VALIDATE_MASK(eth_mask->h_dest)
> instead.
> 
> Fixes: 3e370952287c ("net: bcmgenet: add support for ethtool rxnfc flows")
> Cc: sta...@vger.kernel.org
> Signed-off-by: Denis Efremov 
> ---
> I'm not sure that h_dest check is required here, it's only my guess.
> Compile tested only.
> 
>  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 0ca8436d2e9d..be85dad2e3bc 100644
> --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> @@ -1364,7 +1364,7 @@ static int bcmgenet_validate_flow(struct net_device 
> *dev,
>   case ETHER_FLOW:
>   eth_mask = >fs.m_u.ether_spec;
>   /* don't allow mask which isn't valid */
> - if (VALIDATE_MASK(eth_mask->h_source) ||
> + if (VALIDATE_MASK(eth_mask->h_dest) ||
>   VALIDATE_MASK(eth_mask->h_source) ||
>   VALIDATE_MASK(eth_mask->h_proto)) {
>   netdev_err(dev, "rxnfc: Unsupported mask\n");
> 
Well spotted. Thanks!

Acked-by: Doug Berger 


Re: RFC: backport of commit a32c1c61212d

2020-09-01 Thread Doug Berger
On 9/1/2020 9:36 AM, Florian Fainelli wrote:
> 
> 
> On 9/1/2020 9:06 AM, Doug Berger wrote:
>> On 9/1/2020 7:00 AM, Greg Kroah-Hartman wrote:
> 
> [snip]
> 
>> [snip]
>>
>> My best guess at this point is to submit patches to the affected stable
>> branches like the one in my RFC and reference a32c1c61212d as the
>> upstream commit. This would be confusing to anyone that tried to compare
>> the submitted patch with the upstream patch since they
>> wouldn't look at all alike, but the fixes and upstream tags would define
>> the affected range in Linus' tree.
>>
>> I would appreciate any guidance on how best to handle this kind of
>> situation.
> 
> You could submit various patches with [PATCH stable x.y] in the subject
> to indicate they are targeting a specific stable branch, copy
> sta...@vger.kernel.org as well as all recipients in this email and see
> if that works.
> 
> Not sure if there is a more documented process than that.
Yes, that is what I had in mind based on the "Option 3" for patch
submission. The sticking point is this requirement:
"You must note the upstream commit ID in the changelog of your submission"

My best guess is to use a32c1c61212d, but that could easily cause
confusion in this case. My hope is that now I can reference this
discussion to provide additional clarity.

Thanks,
Doug


Re: RFC: backport of commit a32c1c61212d

2020-09-01 Thread Doug Berger
On 9/1/2020 7:00 AM, Greg Kroah-Hartman wrote:
> On Tue, Aug 25, 2020 at 03:58:27PM -0700, Doug Berger wrote:
>> I recently tracked down a problem I observed when booting a v5.4 kernel
>> on a sparsemem UMA arm platform which includes a no-map reserved-memory
>> region in the middle of its HighMem zone.
>>
>> When memmap_init_zone() is invoked the pfn's that correspond to the
>> no-map region fail the early_pfn_valid() check and the struct page
>> structures are not initialized creating a "hole" in the memmap. Later in
>> my boot sequence the sock_init() initcall leads to a bpf_prog_alloc()
>> which ends up stealing a page from the block containing the no-map
>> region which then leads to a call of move_freepages_block() to
>> reclassify the migratetype of the entire block.
>>
>> The function move_freepages() includes a check of pfn_valid_within for
>> each page in the range, but since the arm architecture doesn't include
>> HOLES_IN_ZONE this check is optimized out and the uninitialized struct
>> page is accessed. Specifically, PageLRU() calls compound_head() on the
>> page and if the page->compound_head value is odd the value is used as a
>> pointer to the head struct page. For uninitialized memory there is a
>> high chance that a random value of compound head will be odd and contain
>> an invalid pointer value that causes the kernel to abort and panic.
>>
>> As you might imagine specifying HOLES_IN_ZONE for the arm build allows
>> pfn_valid_within to protect against accessing the uninitialized struct
>> page. However, the performance penalty this incurs seems unnecessary.
>>
>> Commit 35fd1eb1e821 ("mm/sparse: abstract sparse buffer allocations") as
>> part of the "sparse_init rewrite" series introduced in v4.19 changed the
>> way sparsemem memmaps are initialized. Prior to this patch the sparsemem
>> memmaps are initialized to all 0's. I observed that on older kernels the
>> "uninitialized" struct page access also occurs, but the 0
>> page->compound_head indicates no compound head and the page pointer is
>> therefore not corrupted. The other logic ends up causing the page to be
>> skipped and everything "happens to work".
>>
>> While considering solutions to this issue I observed that the problem
>> does not occur in the current upstream as a result of a combination of
>> other commits. The following commits provided functionality to
>> initialize struct page structures for pages that are unavailable like
>> the no-map region in my system:
>> commit a4a3ede2132a ("mm: zero reserved and unavailable struct pages")
>> commit 907ec5fca3dc ("mm: zero remaining unavailable struct pages")
>> commit ec393a0f014e ("mm: return zero_resv_unavail optimization")
>> commit e822969cab48 ("mm/page_alloc.c: fix uninitialized memmaps on a
>> partially populated last section")
>> commit 4b094b7851bf ("mm/page_alloc.c: initialize memmap of unavailable
>> memory directly")
>>
>> However, those commits added the functionality to the free_area_init()
>> and free_area_init_nodes() functions and the non-NUMA arm architecture
>> did not begin calling free_area_init() until the following commit in v5.8:
>> commit a32c1c61212d ("arm: simplify detection of memory zone boundaries")
>>
>> Prior to that commit the non-NUMA arm architecture called
>> free_area_init_node() directly at the end of zone_sizes_init().
>>
>> So while the problem appears to be fixed upstream by commit a32c1c61212d
>> ("arm: simplify detection of memory zone boundaries") it is still
>> present in stable branches between v4.19.y and v5.7.y inclusive and
>> probably for architectures other than arm as well that didn't call
>> free_area_init(). This upstream commit is not easily/safely backportable
>> to stable branches, but if we focus on the sliver of functionality that
>> adds the initialization code from free_area_init() to the
>> zones_sizes_init() function used by non-NUMA arm kernels I believe a
>> simple patch could be developed for each relevant stable branch to
>> resolve the issue I am observing. Similar patches could also be applied
>> for other architectures that now call free_area_init() upstream but not
>> in one of these stable branches, but I am not in a position to test
>> those architectures.
>>
>> For the linux-5.4.y branch such a patch might look like this:
>> >From 671c341b5cdb8360349c33ade43115e28ca56a8a Mon Sep 17 00:00:00 2001
>> From: Doug Berger 
>> Date: Tue, 25 Au

RFC: backport of commit a32c1c61212d

2020-08-25 Thread Doug Berger
I recently tracked down a problem I observed when booting a v5.4 kernel
on a sparsemem UMA arm platform which includes a no-map reserved-memory
region in the middle of its HighMem zone.

When memmap_init_zone() is invoked the pfn's that correspond to the
no-map region fail the early_pfn_valid() check and the struct page
structures are not initialized creating a "hole" in the memmap. Later in
my boot sequence the sock_init() initcall leads to a bpf_prog_alloc()
which ends up stealing a page from the block containing the no-map
region which then leads to a call of move_freepages_block() to
reclassify the migratetype of the entire block.

The function move_freepages() includes a check of pfn_valid_within for
each page in the range, but since the arm architecture doesn't include
HOLES_IN_ZONE this check is optimized out and the uninitialized struct
page is accessed. Specifically, PageLRU() calls compound_head() on the
page and if the page->compound_head value is odd the value is used as a
pointer to the head struct page. For uninitialized memory there is a
high chance that a random value of compound head will be odd and contain
an invalid pointer value that causes the kernel to abort and panic.

As you might imagine specifying HOLES_IN_ZONE for the arm build allows
pfn_valid_within to protect against accessing the uninitialized struct
page. However, the performance penalty this incurs seems unnecessary.

Commit 35fd1eb1e821 ("mm/sparse: abstract sparse buffer allocations") as
part of the "sparse_init rewrite" series introduced in v4.19 changed the
way sparsemem memmaps are initialized. Prior to this patch the sparsemem
memmaps are initialized to all 0's. I observed that on older kernels the
"uninitialized" struct page access also occurs, but the 0
page->compound_head indicates no compound head and the page pointer is
therefore not corrupted. The other logic ends up causing the page to be
skipped and everything "happens to work".

While considering solutions to this issue I observed that the problem
does not occur in the current upstream as a result of a combination of
other commits. The following commits provided functionality to
initialize struct page structures for pages that are unavailable like
the no-map region in my system:
commit a4a3ede2132a ("mm: zero reserved and unavailable struct pages")
commit 907ec5fca3dc ("mm: zero remaining unavailable struct pages")
commit ec393a0f014e ("mm: return zero_resv_unavail optimization")
commit e822969cab48 ("mm/page_alloc.c: fix uninitialized memmaps on a
partially populated last section")
commit 4b094b7851bf ("mm/page_alloc.c: initialize memmap of unavailable
memory directly")

However, those commits added the functionality to the free_area_init()
and free_area_init_nodes() functions and the non-NUMA arm architecture
did not begin calling free_area_init() until the following commit in v5.8:
commit a32c1c61212d ("arm: simplify detection of memory zone boundaries")

Prior to that commit the non-NUMA arm architecture called
free_area_init_node() directly at the end of zone_sizes_init().

So while the problem appears to be fixed upstream by commit a32c1c61212d
("arm: simplify detection of memory zone boundaries") it is still
present in stable branches between v4.19.y and v5.7.y inclusive and
probably for architectures other than arm as well that didn't call
free_area_init(). This upstream commit is not easily/safely backportable
to stable branches, but if we focus on the sliver of functionality that
adds the initialization code from free_area_init() to the
zones_sizes_init() function used by non-NUMA arm kernels I believe a
simple patch could be developed for each relevant stable branch to
resolve the issue I am observing. Similar patches could also be applied
for other architectures that now call free_area_init() upstream but not
in one of these stable branches, but I am not in a position to test
those architectures.

For the linux-5.4.y branch such a patch might look like this:
>From 671c341b5cdb8360349c33ade43115e28ca56a8a Mon Sep 17 00:00:00 2001
From: Doug Berger 
Date: Tue, 25 Aug 2020 14:39:43 -0700
Subject: [PATCH] ARM: mm: sync zone_sizes_init with free_area_init

The arm architecture does not invoke the common function
free_area_init(). Instead for non-NUMA builds it invokes
free_area_init_node() directly from zone_sizes_init().

As a result recent changes in free_area_init() are not
picked up by arm architecture builds.

This commit adds the updates to the zone_sizes_init()
function to achieve parity with the free_area_init()
functionality.

Fixes: 35fd1eb1e821 ("mm/sparse: abstract sparse buffer allocations")
Signed-off-by: Doug Berger 
Cc: sta...@vger.kernel.org
---
 arch/arm/mm/init.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 6f19ba53fd1f..4f171d834c60 10064

Re: [PATCH v2] mm: include CMA pages in lowmem_reserve at boot

2020-08-19 Thread Doug Berger
On 8/19/2020 10:40 AM, Andrew Morton wrote:
> On Wed, 19 Aug 2020 10:30:25 -0700 Florian Fainelli  
> wrote:
> 
>> On 8/19/20 10:22 AM, Andrew Morton wrote:
>>> On Wed, 19 Aug 2020 10:15:53 -0700 Florian Fainelli  
>>> wrote:
>>>
>> In many cases the difference is not significant, but for example
>> an ARM platform with 1GB of memory and the following memory layout
>> [0.00] cma: Reserved 256 MiB at 0x3000
>> [0.00] Zone ranges:
>> [0.00]   DMA  [mem 0x-0x2fff]
>> [0.00]   Normal   empty
>> [0.00]   HighMem  [mem 0x3000-0x3fff]
>>
>> would result in 0 lowmem_reserve for the DMA zone. This would allow
>> userspace to deplete the DMA zone easily.
>
> Sounds fairly serious for thos machines.  Was a cc:stable considered?

 Since there is a Fixes: tag, it may have been assumed that the patch
 would be picked up and as soon as it reaches Linus' tree it would be
 picked up by the stable selection.
>>>
>>> It doesn't work that way - sometimes a fix isn't considered important
>>> enough to backport.  It could just fix a typo in a comment!
>>
>> Then can this be applied ASAP and back ported?
> 
> Sure.
> 
As Florian guessed, I assumed the Fixes: tag was a sufficient clue since
I wouldn't normally apply a Fixes tag to a typo correction in a comment.
I suspect I have been spoiled by David Miller :).

Thanks for the quick turn-around and applying the cc:stable to the mmotm,
Doug


[PATCH v2] mm: include CMA pages in lowmem_reserve at boot

2020-08-14 Thread Doug Berger
The lowmem_reserve arrays provide a means of applying pressure
against allocations from lower zones that were targeted at
higher zones. Its values are a function of the number of pages
managed by higher zones and are assigned by a call to the
setup_per_zone_lowmem_reserve() function.

The function is initially called at boot time by the function
init_per_zone_wmark_min() and may be called later by accesses
of the /proc/sys/vm/lowmem_reserve_ratio sysctl file.

The function init_per_zone_wmark_min() was moved up from a
module_init to a core_initcall to resolve a sequencing issue
with khugepaged. Unfortunately this created a sequencing issue
with CMA page accounting.

The CMA pages are added to the managed page count of a zone
when cma_init_reserved_areas() is called at boot also as a
core_initcall. This makes it uncertain whether the CMA pages
will be added to the managed page counts of their zones before
or after the call to init_per_zone_wmark_min() as it becomes
dependent on link order. With the current link order the pages
are added to the managed count after the lowmem_reserve arrays
are initialized at boot.

This means the lowmem_reserve values at boot may be lower than
the values used later if /proc/sys/vm/lowmem_reserve_ratio is
accessed even if the ratio values are unchanged.

In many cases the difference is not significant, but for example
an ARM platform with 1GB of memory and the following memory layout
[0.00] cma: Reserved 256 MiB at 0x3000
[0.00] Zone ranges:
[0.00]   DMA  [mem 0x-0x2fff]
[0.00]   Normal   empty
[0.00]   HighMem  [mem 0x3000-0x3fff]

would result in 0 lowmem_reserve for the DMA zone. This would allow
userspace to deplete the DMA zone easily. Funnily enough
$ cat /proc/sys/vm/lowmem_reserve_ratio
would fix up the situation because it forces
setup_per_zone_lowmem_reserve as a side effect.

This commit breaks the link order dependency by invoking
init_per_zone_wmark_min() as a postcore_initcall so that the
CMA pages have the chance to be properly accounted in their
zone(s) and allowing the lowmem_reserve arrays to receive
consistent values.

Fixes: bc22af74f271 ("mm: update min_free_kbytes from khugepaged after core 
initialization")
Signed-off-by: Doug Berger 
Acked-by: Michal Hocko 
---
 mm/page_alloc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 8b7d0ecf30b1..f3e340ec2b6b 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -7887,7 +7887,7 @@ int __meminit init_per_zone_wmark_min(void)
 
return 0;
 }
-core_initcall(init_per_zone_wmark_min)
+postcore_initcall(init_per_zone_wmark_min)
 
 /*
  * min_free_kbytes_sysctl_handler - just a wrapper around proc_dointvec() so
-- 
2.7.4



Re: [PATCH] mm: include CMA pages in lowmem_reserve at boot

2020-08-13 Thread Doug Berger
On 8/13/2020 4:17 AM, Michal Hocko wrote:
> On Wed 12-08-20 20:51:38, Doug Berger wrote:
>> The lowmem_reserve arrays provide a means of applying pressure
>> against allocations from lower zones that were targeted at
>> higher zones. Its values are a function of the number of pages
>> managed by higher zones and are assigned by a call to the
>> setup_per_zone_lowmem_reserve() function.
>>
>> The function is initially called at boot time by the function
>> init_per_zone_wmark_min() and may be called later by accesses
>> of the /proc/sys/vm/lowmem_reserve_ratio sysctl file.
>>
>> The function init_per_zone_wmark_min() was moved up from a
>> module_init to a core_initcall to resolve a sequencing issue
>> with khugepaged. Unfortunately this created a sequencing issue
>> with CMA page accounting.
>>
>> The CMA pages are added to the managed page count of a zone
>> when cma_init_reserved_areas() is called at boot also as a
>> core_initcall. This makes it uncertain whether the CMA pages
>> will be added to the managed page counts of their zones before
>> or after the call to init_per_zone_wmark_min() as it becomes
>> dependent on link order. With the current link order the pages
>> are added to the managed count after the lowmem_reserve arrays
>> are initialized at boot.
>>
>> This means the lowmem_reserve values at boot may be lower than
>> the values used later if /proc/sys/vm/lowmem_reserve_ratio is
>> accessed even if the ratio values are unchanged.
>>
>> In many cases the difference is not significant, but in others
>> it may have an affect.
> 
> Could you be more specific please?

One example might be a 1GB arm platform that defines a 256MB default CMA
region. The default zones might map as follows:
[0.00] cma: Reserved 256 MiB at 0x3000
[0.00] Zone ranges:
[0.00]   DMA  [mem 0x-0x2fff]
[0.00]   Normal   empty
[0.00]   HighMem  [mem 0x3000-0x3fff]

At boot the memory info would be:
# echo m > /proc/sysrq-trigger
[   21.559673] sysrq: Show Memory
[   21.562758] Mem-Info:
[   21.565053] active_anon:9783 inactive_anon:770 isolated_anon:0
[   21.565053]  active_file:0 inactive_file:0 isolated_file:0
[   21.565053]  unevictable:0 dirty:0 writeback:0
[   21.565053]  slab_reclaimable:1827 slab_unreclaimable:1867
[   21.565053]  mapped:716 shmem:10363 pagetables:26 bounce:0
[   21.565053]  free:221995 free_pcp:444 free_cma:54917
[   21.596744] Node 0 active_anon:39132kB inactive_anon:3080kB
active_file:0kB inactive_file:0kB unevictable:0kB isolated(anon):0kB
isolated(file):0kB mapped:2864kB dirty:0kB writeback:0kB shmem:41452kB
writeback_tmp:0kB kernel_stack:472kB all_unreclaimable? no
[   21.619650] DMA free:668312kB min:3288kB low:4108kB high:4928kB
reserved_highatomic:0KB active_anon:0kB inactive_anon:0kB
active_file:0kB inactive_file:0kB unevictable:0kB writepending:0kB
present:786432kB managed:690364kB mlocked:0kB pagetables:104kB
bounce:0kB free_pcp:1776kB local_pcp:324kB free_cma:0kB
[   21.646810] lowmem_reserve[]: 0 0 0 0
[   21.650498] HighMem free:219668kB min:128kB low:128kB high:128kB
reserved_highatomic:0KB active_anon:39132kB inactive_anon:3080kB
active_file:0kB inactive_file:0kB unevictable:0kB writepending:0kB
present:262144kB managed:262144kB mlocked:0kB pagetables:0kB bounce:0kB
free_pcp:0kB local_pcp:0kB free_cma:219668kB
[   21.678184] lowmem_reserve[]: 0 0 0 0
[   21.681866] DMA: 20*4kB (UME) 9*8kB (UME) 7*16kB (UME) 6*32kB (M)
7*64kB (ME) 4*128kB (M) 7*256kB (UM) 7*512kB (ME) 6*1024kB (M) 8*2048kB
(UM) 156*4096kB (M) = 668296kB
[   21.696970] HighMem: 1*4kB (C) 3*8kB (C) 3*16kB (C) 4*32kB (C) 1*64kB
(C) 0*128kB 1*256kB (C) 0*512kB 0*1024kB 1*2048kB (C) 53*4096kB (C) =
219660kB
[   21.710328] 10363 total pagecache pages
[   21.714188] 0 pages in swap cache
[   21.717518] Swap cache stats: add 0, delete 0, find 0/0
[   21.722761] Free swap  = 0kB
[   21.725655] Total swap = 0kB
[   21.728549] 262144 pages RAM
[   21.731443] 65536 pages HighMem/MovableOnly
[   21.735641] 24017 pages reserved
[   21.738882] 65536 pages cma reserved

Here you can see that the lowmem_reserve array for the DMA zone is all
0's. This is because the HighMem zone is consumed by the CMA region
whose pages haven't been activated to increase the zone managed count
when init_per_zone_wmark_min() is invoked at boot.

If we access the /proc/sys/vm/lowmem_reserve_ratio sysctl with:
# cat /proc/sys/vm/lowmem_reserve_ratio
256 32  0   0

That is sufficient to recalculate the lowmem_reserve arrays which now show:
# echo m > /proc/sysrq-trigger
[   38.848640] sysrq: Show Memory
[   38.851712] Mem-Info:
[   38.854004] active_anon:9783 inactive_anon:773 isolated_anon:0
[   38.854004]  active_file:0 inactive_file:0 isolated

[PATCH] mm: include CMA pages in lowmem_reserve at boot

2020-08-12 Thread Doug Berger
The lowmem_reserve arrays provide a means of applying pressure
against allocations from lower zones that were targeted at
higher zones. Its values are a function of the number of pages
managed by higher zones and are assigned by a call to the
setup_per_zone_lowmem_reserve() function.

The function is initially called at boot time by the function
init_per_zone_wmark_min() and may be called later by accesses
of the /proc/sys/vm/lowmem_reserve_ratio sysctl file.

The function init_per_zone_wmark_min() was moved up from a
module_init to a core_initcall to resolve a sequencing issue
with khugepaged. Unfortunately this created a sequencing issue
with CMA page accounting.

The CMA pages are added to the managed page count of a zone
when cma_init_reserved_areas() is called at boot also as a
core_initcall. This makes it uncertain whether the CMA pages
will be added to the managed page counts of their zones before
or after the call to init_per_zone_wmark_min() as it becomes
dependent on link order. With the current link order the pages
are added to the managed count after the lowmem_reserve arrays
are initialized at boot.

This means the lowmem_reserve values at boot may be lower than
the values used later if /proc/sys/vm/lowmem_reserve_ratio is
accessed even if the ratio values are unchanged.

In many cases the difference is not significant, but in others
it may have an affect.

This commit breaks the link order dependency by invoking
init_per_zone_wmark_min() as a postcore_initcall so that the
CMA pages have the chance to be properly accounted in their
zone(s) and allowing the lowmem_reserve arrays to receive
consistent values.

Fixes: bc22af74f271 ("mm: update min_free_kbytes from khugepaged after core 
initialization")
Signed-off-by: Doug Berger 
---
 mm/page_alloc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 8b7d0ecf30b1..f3e340ec2b6b 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -7887,7 +7887,7 @@ int __meminit init_per_zone_wmark_min(void)
 
return 0;
 }
-core_initcall(init_per_zone_wmark_min)
+postcore_initcall(init_per_zone_wmark_min)
 
 /*
  * min_free_kbytes_sysctl_handler - just a wrapper around proc_dointvec() so
-- 
2.7.4



Re: [PATCH net] net: bcmgenet: fix error returns in bcmgenet_probe()

2020-07-20 Thread Doug Berger
On 7/20/2020 12:18 AM, Zhang Changzhong wrote:
> The driver forgets to call clk_disable_unprepare() in error path after
> a success calling for clk_prepare_enable().
> 
> Fix to goto err_clk_disable if clk_prepare_enable() is successful.
> 
> Fixes: 99d55638d4b0 ("net: bcmgenet: enable NETIF_F_HIGHDMA flag")
> Signed-off-by: Zhang Changzhong 
> ---
>  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 368e05b..903811e 100644
> --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> @@ -3988,7 +3988,7 @@ static int bcmgenet_probe(struct platform_device *pdev)
>   if (err)
>   err = dma_set_mask_and_coherent(>dev, DMA_BIT_MASK(32));
>   if (err)
> - goto err;
> + goto err_clk_disable;
>  
>   /* Mii wait queue */
>   init_waitqueue_head(>wq);
> 
Acked-by: Doug Berger 

Thanks!


Re: [PATCH net] net: bcmgenet: add missed clk_disable_unprepare in bcmgenet_probe

2020-07-20 Thread Doug Berger
On 7/20/2020 2:36 AM, Zhang Changzhong wrote:
> The driver forgets to call clk_disable_unprepare() in error path after
> a success calling for clk_prepare_enable().
> 
> Fix to goto err_clk_disable if clk_prepare_enable() is successful.
> 
> Fixes: c80d36ff63a5 ("net: bcmgenet: Use devm_clk_get_optional() to get the 
> clocks")
> Signed-off-by: Zhang Changzhong 
> ---
>  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 368e05b..79d27be 100644
> --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> @@ -4000,14 +4000,14 @@ static int bcmgenet_probe(struct platform_device 
> *pdev)
>   if (IS_ERR(priv->clk_wol)) {
>   dev_dbg(>pdev->dev, "failed to get enet-wol clock\n");
>   err = PTR_ERR(priv->clk_wol);
> - goto err;
> + goto err_clk_disable;
>   }
>  
>   priv->clk_eee = devm_clk_get_optional(>pdev->dev, "enet-eee");
>   if (IS_ERR(priv->clk_eee)) {
>   dev_dbg(>pdev->dev, "failed to get enet-eee clock\n");
>   err = PTR_ERR(priv->clk_eee);
> -     goto err;
> + goto err_clk_disable;
>   }
>  
>   /* If this is an internal GPHY, power it on now, before UniMAC is
> 
Acked-by: Doug Berger 

Thanks!


Re: [PATCH net-next] net: bcmgenet: fix error returns in bcmgenet_probe()

2020-07-17 Thread Doug Berger
On 7/17/2020 1:19 AM, Zhang Changzhong wrote:
> The driver forgets to call clk_disable_unprepare() in error path after
> a success calling for clk_prepare_enable().
> 
> Fix to goto err_clk_disable if clk_prepare_enable() is successful.
> 
> Signed-off-by: Zhang Changzhong 
> ---
>  drivers/net/ethernet/broadcom/genet/bcmgenet.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
> b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> index ee84a26..23df6f2 100644
> --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> @@ -4016,7 +4016,7 @@ static int bcmgenet_probe(struct platform_device *pdev)
>   if (err)
>   err = dma_set_mask_and_coherent(>dev, DMA_BIT_MASK(32));
>   if (err)
> - goto err;
> + goto err_clk_disable;
Please split this clause out as a separate pull-request with this fixes tag:
Fixes: 99d55638d4b0 ("net: bcmgenet: enable NETIF_F_HIGHDMA flag")

>  
>   /* Mii wait queue */
>   init_waitqueue_head(>wq);
> @@ -4028,14 +4028,14 @@ static int bcmgenet_probe(struct platform_device 
> *pdev)
>   if (IS_ERR(priv->clk_wol)) {
>   dev_dbg(>pdev->dev, "failed to get enet-wol clock\n");
>   err = PTR_ERR(priv->clk_wol);
> - goto err;
> + goto err_clk_disable;
>   }
>  
>   priv->clk_eee = devm_clk_get_optional(>pdev->dev, "enet-eee");
>   if (IS_ERR(priv->clk_eee)) {
>   dev_dbg(>pdev->dev, "failed to get enet-eee clock\n");
>   err = PTR_ERR(priv->clk_eee);
> - goto err;
> + goto err_clk_disable;
>   }
>  
>   /* If this is an internal GPHY, power it on now, before UniMAC is
> 
Please split these changes into a pull-request with fixes tag:
Fixes: c80d36ff63a5 ("net: bcmgenet: Use devm_clk_get_optional() to get
the clocks")

Resubmit the pull-requests with [PATCH net].
That will make them easier to apply to stable branches.

Otherwise:
Acked-by: Doug Berger 

Thanks!


[PATCH net 3/3] net: bcmgenet: restore HFB filters on resume

2020-07-16 Thread Doug Berger
The Hardware Filter Block RAM may not be preserved when the GENET
block is reset during a deep sleep, so it is not sufficient to
only backup and restore the enables.

This commit clears out the HFB block and reprograms the rxnfc
rules when the system resumes from a suspended state. To support
this the bcmgenet_hfb_create_rxnfc_filter() function is modified
to access the register space directly so that it can't fail due
to memory allocation issues.

Fixes: f50932cca632 ("net: bcmgenet: add WAKE_FILTER support")
Signed-off-by: Doug Berger 
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 138 +++--
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |   1 -
 2 files changed, 62 insertions(+), 77 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index af924a8b885f..368e05b16ae9 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -543,14 +543,14 @@ static int bcmgenet_hfb_validate_mask(void *mask, size_t 
size)
 #define VALIDATE_MASK(x) \
bcmgenet_hfb_validate_mask(&(x), sizeof(x))
 
-static int bcmgenet_hfb_insert_data(u32 *f, int offset,
-   void *val, void *mask, size_t size)
+static int bcmgenet_hfb_insert_data(struct bcmgenet_priv *priv, u32 f_index,
+   u32 offset, void *val, void *mask,
+   size_t size)
 {
-   int index;
-   u32 tmp;
+   u32 index, tmp;
 
-   index = offset / 2;
-   tmp = f[index];
+   index = f_index * priv->hw_params->hfb_filter_size + offset / 2;
+   tmp = bcmgenet_hfb_readl(priv, index * sizeof(u32));
 
while (size--) {
if (offset++ & 1) {
@@ -567,9 +567,10 @@ static int bcmgenet_hfb_insert_data(u32 *f, int offset,
tmp |= 0x1;
break;
}
-   f[index++] = tmp;
+   bcmgenet_hfb_writel(priv, tmp, index++ * sizeof(u32));
if (size)
-   tmp = f[index];
+   tmp = bcmgenet_hfb_readl(priv,
+index * sizeof(u32));
} else {
tmp &= ~0xCFF00;
tmp |= (*(unsigned char *)val++) << 8;
@@ -585,44 +586,26 @@ static int bcmgenet_hfb_insert_data(u32 *f, int offset,
break;
}
if (!size)
-   f[index] = tmp;
+   bcmgenet_hfb_writel(priv, tmp, index * 
sizeof(u32));
}
}
 
return 0;
 }
 
-static void bcmgenet_hfb_set_filter(struct bcmgenet_priv *priv, u32 *f_data,
-   u32 f_length, u32 rx_queue, int f_index)
-{
-   u32 base = f_index * priv->hw_params->hfb_filter_size;
-   int i;
-
-   for (i = 0; i < f_length; i++)
-   bcmgenet_hfb_writel(priv, f_data[i], (base + i) * sizeof(u32));
-
-   bcmgenet_hfb_set_filter_length(priv, f_index, 2 * f_length);
-   bcmgenet_hfb_set_filter_rx_queue_mapping(priv, f_index, rx_queue);
-}
-
-static int bcmgenet_hfb_create_rxnfc_filter(struct bcmgenet_priv *priv,
-   struct bcmgenet_rxnfc_rule *rule)
+static void bcmgenet_hfb_create_rxnfc_filter(struct bcmgenet_priv *priv,
+struct bcmgenet_rxnfc_rule *rule)
 {
struct ethtool_rx_flow_spec *fs = >fs;
-   int err = 0, offset = 0, f_length = 0;
+   u32 offset = 0, f_length = 0, f;
u8 val_8, mask_8;
__be16 val_16;
u16 mask_16;
size_t size;
-   u32 *f_data;
-
-   f_data = kcalloc(priv->hw_params->hfb_filter_size, sizeof(u32),
-GFP_KERNEL);
-   if (!f_data)
-   return -ENOMEM;
 
+   f = fs->location;
if (fs->flow_type & FLOW_MAC_EXT) {
-   bcmgenet_hfb_insert_data(f_data, 0,
+   bcmgenet_hfb_insert_data(priv, f, 0,
 >h_ext.h_dest, >m_ext.h_dest,
 sizeof(fs->h_ext.h_dest));
}
@@ -630,11 +613,11 @@ static int bcmgenet_hfb_create_rxnfc_filter(struct 
bcmgenet_priv *priv,
if (fs->flow_type & FLOW_EXT) {
if (fs->m_ext.vlan_etype ||
fs->m_ext.vlan_tci) {
-   bcmgenet_hfb_insert_data(f_data, 12,
+   bcmgenet_hfb_insert_data(priv, f, 12,
 >h_ext.vlan_etype,
 >m_ext.vlan_etype,
  

[PATCH net 2/3] net: bcmgenet: test RBUF_ACPI_EN when resuming

2020-07-16 Thread Doug Berger
When the GENET driver resumes from deep sleep the UMAC_CMD
register may not be accessible and therefore should not be
accessed from bcmgenet_wol_power_up_cfg() if the GENET has
been reset.

This commit adds a check of the RBUF_ACPI_EN flag when Wake
on Filter is enabled. A clear flag indicates that the GENET
hardware must have been reset so the remainder of the
hardware programming is bypassed.

Fixes: f50932cca632 ("net: bcmgenet: add WAKE_FILTER support")
Signed-off-by: Doug Berger 
---
 drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c | 10 +++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
index def990dbf34f..1c86eddb1b51 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
@@ -229,9 +229,13 @@ void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
}
 
/* Disable WAKE_FILTER Detection */
-   reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL);
-   reg &= ~(RBUF_HFB_EN | RBUF_ACPI_EN);
-   bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL);
+   if (priv->wolopts & WAKE_FILTER) {
+   reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL);
+   if (!(reg & RBUF_ACPI_EN))
+   return; /* already reset so skip the rest */
+   reg &= ~(RBUF_HFB_EN | RBUF_ACPI_EN);
+   bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL);
+   }
 
/* Disable CRC Forward */
reg = bcmgenet_umac_readl(priv, UMAC_CMD);
-- 
2.7.4



[PATCH net 1/3] net: bcmgenet: test MPD_EN when resuming

2020-07-16 Thread Doug Berger
When the GENET driver resumes from deep sleep the UMAC_CMD
register may not be accessible and therefore should not be
accessed from bcmgenet_wol_power_up_cfg() if the GENET has
been reset.

This commit adds a check of the MPD_EN flag when Wake on
Magic Packet is enabled. A clear flag indicates that the
GENET hardware must have been reset so the remainder of the
hardware programming is bypassed.

Fixes: 1a1d5106c1e3 ("net: bcmgenet: move clk_wol management to bcmgenet_wol")
Signed-off-by: Doug Berger 
---
 drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c | 12 
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
index 4ea6a26b04f7..def990dbf34f 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
@@ -217,11 +217,16 @@ void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
 
priv->wol_active = 0;
clk_disable_unprepare(priv->clk_wol);
+   priv->crc_fwd_en = 0;
 
/* Disable Magic Packet Detection */
-   reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
-   reg &= ~(MPD_EN | MPD_PW_EN);
-   bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
+   if (priv->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE)) {
+   reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
+   if (!(reg & MPD_EN))
+   return; /* already reset so skip the rest */
+   reg &= ~(MPD_EN | MPD_PW_EN);
+   bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
+   }
 
/* Disable WAKE_FILTER Detection */
reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL);
@@ -232,5 +237,4 @@ void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
reg = bcmgenet_umac_readl(priv, UMAC_CMD);
reg &= ~CMD_CRC_FWD;
bcmgenet_umac_writel(priv, reg, UMAC_CMD);
-   priv->crc_fwd_en = 0;
 }
-- 
2.7.4



[PATCH net 0/3] net: bcmgenet: fix WAKE_FILTER resume from deep sleep

2020-07-16 Thread Doug Berger
The WAKE_FILTER logic can only wake the system from the standby
power state. However, some systems that include the GENET IP
support deeper power saving states and the driver should suspend
and resume correctly from those states as well.

This commit set squashes a few issues uncovered while testing
suspend and resume from these deep sleep states.

Doug Berger (3):
  net: bcmgenet: test MPD_EN when resuming
  net: bcmgenet: test RBUF_ACPI_EN  when resuming
  net: bcmgenet: restore HFB filters on resume

 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 138 +
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |   1 -
 drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c |  22 ++--
 3 files changed, 77 insertions(+), 84 deletions(-)

-- 
2.7.4



[PATCH net 2/3] net: bcmgenet: use __be16 for htons(ETH_P_IP)

2020-06-24 Thread Doug Berger
The 16-bit value that holds a short in network byte order should
be declared as a restricted big endian type to allow type checks
to succeed during assignment.

Fixes: 3e370952287c ("net: bcmgenet: add support for ethtool rxnfc flows")
Reported-by: kbuild test robot 
Signed-off-by: Doug Berger 
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index f1fa11665319..c63f01e2bb03 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -610,8 +610,9 @@ static int bcmgenet_hfb_create_rxnfc_filter(struct 
bcmgenet_priv *priv,
 {
struct ethtool_rx_flow_spec *fs = >fs;
int err = 0, offset = 0, f_length = 0;
-   u16 val_16, mask_16;
u8 val_8, mask_8;
+   __be16 val_16;
+   u16 mask_16;
size_t size;
u32 *f_data;
 
-- 
2.7.4



[PATCH net 1/3] net: bcmgenet: re-remove bcmgenet_hfb_add_filter

2020-06-24 Thread Doug Berger
This function was originally removed by Baoyou Xie in
commit e2072600a241 ("net: bcmgenet: remove unused function in
bcmgenet.c") to prevent a build warning.

Some of the functions removed by Baoyou Xie are now used for
WAKE_FILTER support so his commit was reverted, but this function
is still unused and the kbuild test robot dutifully reported the
warning.

This commit once again removes the remaining unused hfb functions.

Fixes: 14da1510fedc ("Revert "net: bcmgenet: remove unused function in 
bcmgenet.c"")
Reported-by: kbuild test robot 
Signed-off-by: Doug Berger 
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 77 --
 1 file changed, 77 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index ff31da0ed846..f1fa11665319 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -459,17 +459,6 @@ static inline void bcmgenet_rdma_ring_writel(struct 
bcmgenet_priv *priv,
genet_dma_ring_regs[r]);
 }
 
-static bool bcmgenet_hfb_is_filter_enabled(struct bcmgenet_priv *priv,
-  u32 f_index)
-{
-   u32 offset;
-   u32 reg;
-
-   offset = HFB_FLT_ENABLE_V3PLUS + (f_index < 32) * sizeof(u32);
-   reg = bcmgenet_hfb_reg_readl(priv, offset);
-   return !!(reg & (1 << (f_index % 32)));
-}
-
 static void bcmgenet_hfb_enable_filter(struct bcmgenet_priv *priv, u32 f_index)
 {
u32 offset;
@@ -533,19 +522,6 @@ static void bcmgenet_hfb_set_filter_length(struct 
bcmgenet_priv *priv,
bcmgenet_hfb_reg_writel(priv, reg, offset);
 }
 
-static int bcmgenet_hfb_find_unused_filter(struct bcmgenet_priv *priv)
-{
-   u32 f_index;
-
-   /* First MAX_NUM_OF_FS_RULES are reserved for Rx NFC filters */
-   for (f_index = MAX_NUM_OF_FS_RULES;
-f_index < priv->hw_params->hfb_filter_cnt; f_index++)
-   if (!bcmgenet_hfb_is_filter_enabled(priv, f_index))
-   return f_index;
-
-   return -ENOMEM;
-}
-
 static int bcmgenet_hfb_validate_mask(void *mask, size_t size)
 {
while (size) {
@@ -744,59 +720,6 @@ static int bcmgenet_hfb_create_rxnfc_filter(struct 
bcmgenet_priv *priv,
return err;
 }
 
-/* bcmgenet_hfb_add_filter
- *
- * Add new filter to Hardware Filter Block to match and direct Rx traffic to
- * desired Rx queue.
- *
- * f_data is an array of unsigned 32-bit integers where each 32-bit integer
- * provides filter data for 2 bytes (4 nibbles) of Rx frame:
- *
- * bits 31:20 - unused
- * bit  19- nibble 0 match enable
- * bit  18- nibble 1 match enable
- * bit  17- nibble 2 match enable
- * bit  16- nibble 3 match enable
- * bits 15:12 - nibble 0 data
- * bits 11:8  - nibble 1 data
- * bits 7:4   - nibble 2 data
- * bits 3:0   - nibble 3 data
- *
- * Example:
- * In order to match:
- * - Ethernet frame type = 0x0800 (IP)
- * - IP version field = 4
- * - IP protocol field = 0x11 (UDP)
- *
- * The following filter is needed:
- * u32 hfb_filter_ipv4_udp[] = {
- *   Rx frame offset 0x00: 0x, 0x, 0x, 0x,
- *   Rx frame offset 0x08: 0x, 0x, 0x000F0800, 0x00084000,
- *   Rx frame offset 0x10: 0x, 0x, 0x, 0x00030011,
- * };
- *
- * To add the filter to HFB and direct the traffic to Rx queue 0, call:
- * bcmgenet_hfb_add_filter(priv, hfb_filter_ipv4_udp,
- * ARRAY_SIZE(hfb_filter_ipv4_udp), 0);
- */
-int bcmgenet_hfb_add_filter(struct bcmgenet_priv *priv, u32 *f_data,
-   u32 f_length, u32 rx_queue)
-{
-   int f_index;
-
-   f_index = bcmgenet_hfb_find_unused_filter(priv);
-   if (f_index < 0)
-   return -ENOMEM;
-
-   if (f_length > priv->hw_params->hfb_filter_size)
-   return -EINVAL;
-
-   bcmgenet_hfb_set_filter(priv, f_data, f_length, rx_queue, f_index);
-   bcmgenet_hfb_enable_filter(priv, f_index);
-
-   return 0;
-}
-
 /* bcmgenet_hfb_clear
  *
  * Clear Hardware Filter Block and disable all filtering.
-- 
2.7.4



[PATCH net 3/3] net: bcmgenet: use hardware padding of runt frames

2020-06-24 Thread Doug Berger
When commit 474ea9cafc45 ("net: bcmgenet: correctly pad short
packets") added the call to skb_padto() it should have been
located before the nr_frags parameter was read since that value
could be changed when padding packets with lengths between 55
and 59 bytes (inclusive).

The use of a stale nr_frags value can cause corruption of the
pad data when tx-scatter-gather is enabled. This corruption of
the pad can cause invalid checksum computation when hardware
offload of tx-checksum is also enabled.

Since the original reason for the padding was corrected by
commit 7dd399130efb ("net: bcmgenet: fix skb_len in
bcmgenet_xmit_single()") we can remove the software padding all
together and make use of hardware padding of short frames as
long as the hardware also always appends the FCS value to the
frame.

Fixes: 474ea9cafc45 ("net: bcmgenet: correctly pad short packets")
Signed-off-by: Doug Berger 
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 8 +++-
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index c63f01e2bb03..af924a8b885f 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -2042,11 +2042,6 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, 
struct net_device *dev)
goto out;
}
 
-   if (skb_padto(skb, ETH_ZLEN)) {
-   ret = NETDEV_TX_OK;
-   goto out;
-   }
-
/* Retain how many bytes will be sent on the wire, without TSB inserted
 * by transmit checksum offload
 */
@@ -2093,6 +2088,9 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, 
struct net_device *dev)
len_stat = (size << DMA_BUFLENGTH_SHIFT) |
   (priv->hw_params->qtag_mask << DMA_TX_QTAG_SHIFT);
 
+   /* Note: if we ever change from DMA_TX_APPEND_CRC below we
+* will need to restore software padding of "runt" packets
+*/
if (!i) {
len_stat |= DMA_TX_APPEND_CRC | DMA_SOP;
if (skb->ip_summed == CHECKSUM_PARTIAL)
-- 
2.7.4



[PATCH net 0/3] net: bcmgenet: use hardware padding of runt frames

2020-06-24 Thread Doug Berger
Now that scatter-gather and tx-checksumming are enabled by default
it revealed a packet corruption issue that can occur for very short
fragmented packets.

When padding these frames to the minimum length it is possible for
the non-linear (fragment) data to be added to the end of the linear
header in an SKB. Since the number of fragments is read before the
padding and used afterward without reloading, the fragment that
should have been consumed can be tacked on in place of part of the
padding.

The third commit in this set corrects this by removing the software
padding and allowing the hardware to add the pad bytes if necessary.

The first two commits resolve warnings observed by the kbuild test
robot and are included here for simplicity of application.

Doug Berger (3):
  net: bcmgenet: re-remove bcmgenet_hfb_add_filter
  net: bcmgenet: use __be16 for htons(ETH_P_IP)
  net: bcmgenet: use hardware padding of runt frames

 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 88 ++
 1 file changed, 5 insertions(+), 83 deletions(-)

-- 
2.7.4



[PATCH net-next] net: phy: simplify phy_link_change arguments

2020-05-18 Thread Doug Berger
This function was introduced to allow for different handling of
link up and link down events particularly with regard to the
netif_carrier. The third argument do_carrier allowed the flag to
be left unchanged.

Since then the phylink has introduced an implementation that
completely ignores the third parameter since it never wants to
change the flag and the phylib always sets the third parameter
to true so the flag is always changed.

Therefore the third argument (i.e. do_carrier) is no longer
necessary and can be removed. This also means that the phylib
phy_link_down() function no longer needs its second argument.

Signed-off-by: Doug Berger 
---
 drivers/net/phy/phy.c| 12 ++--
 drivers/net/phy/phy_device.c | 12 +---
 drivers/net/phy/phylink.c|  3 +--
 include/linux/phy.h  |  2 +-
 4 files changed, 13 insertions(+), 16 deletions(-)

diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index d4bbf79dab6c..d584701187db 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -58,13 +58,13 @@ static const char *phy_state_to_str(enum phy_state st)
 
 static void phy_link_up(struct phy_device *phydev)
 {
-   phydev->phy_link_change(phydev, true, true);
+   phydev->phy_link_change(phydev, true);
phy_led_trigger_change_speed(phydev);
 }
 
-static void phy_link_down(struct phy_device *phydev, bool do_carrier)
+static void phy_link_down(struct phy_device *phydev)
 {
-   phydev->phy_link_change(phydev, false, do_carrier);
+   phydev->phy_link_change(phydev, false);
phy_led_trigger_change_speed(phydev);
 }
 
@@ -524,7 +524,7 @@ int phy_start_cable_test(struct phy_device *phydev,
goto out;
 
/* Mark the carrier down until the test is complete */
-   phy_link_down(phydev, true);
+   phy_link_down(phydev);
 
netif_testing_on(dev);
err = phydev->drv->cable_test_start(phydev);
@@ -595,7 +595,7 @@ static int phy_check_link_status(struct phy_device *phydev)
phy_link_up(phydev);
} else if (!phydev->link && phydev->state != PHY_NOLINK) {
phydev->state = PHY_NOLINK;
-   phy_link_down(phydev, true);
+   phy_link_down(phydev);
}
 
return 0;
@@ -999,7 +999,7 @@ void phy_state_machine(struct work_struct *work)
case PHY_HALTED:
if (phydev->link) {
phydev->link = 0;
-   phy_link_down(phydev, true);
+   phy_link_down(phydev);
}
do_suspend = true;
break;
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index c3a107cf578e..7481135d27ab 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -916,16 +916,14 @@ struct phy_device *phy_find_first(struct mii_bus *bus)
 }
 EXPORT_SYMBOL(phy_find_first);
 
-static void phy_link_change(struct phy_device *phydev, bool up, bool 
do_carrier)
+static void phy_link_change(struct phy_device *phydev, bool up)
 {
struct net_device *netdev = phydev->attached_dev;
 
-   if (do_carrier) {
-   if (up)
-   netif_carrier_on(netdev);
-   else
-   netif_carrier_off(netdev);
-   }
+   if (up)
+   netif_carrier_on(netdev);
+   else
+   netif_carrier_off(netdev);
phydev->adjust_link(netdev);
if (phydev->mii_ts && phydev->mii_ts->link_state)
phydev->mii_ts->link_state(phydev->mii_ts, phydev);
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 0f23bec431c1..b6b1f77bba58 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -803,8 +803,7 @@ void phylink_destroy(struct phylink *pl)
 }
 EXPORT_SYMBOL_GPL(phylink_destroy);
 
-static void phylink_phy_change(struct phy_device *phydev, bool up,
-  bool do_carrier)
+static void phylink_phy_change(struct phy_device *phydev, bool up)
 {
struct phylink *pl = phydev->phylink;
bool tx_pause, rx_pause;
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 5d8ff5428010..467aa8bf9f64 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -543,7 +543,7 @@ struct phy_device {
u8 mdix;
u8 mdix_ctrl;
 
-   void (*phy_link_change)(struct phy_device *, bool up, bool do_carrier);
+   void (*phy_link_change)(struct phy_device *phydev, bool up);
void (*adjust_link)(struct net_device *dev);
 
 #if IS_ENABLED(CONFIG_MACSEC)
-- 
2.7.4



Re: [PATCH net-next 1/4] net: ethernet: validate pause autoneg setting

2020-05-13 Thread Doug Berger
On 5/13/2020 6:49 AM, Andrew Lunn wrote:
>> So, I think consistency of implementation is more important than fixing
>> this; the current behaviour has been established for many years now.
> 
> Hi Russell, Doug
> 
> With netlink ethtool we have the possibility of adding a new API to
> control this. And we can leave the IOCTL API alone, and the current
> ethtool commands. We can add a new command to ethtool which uses the new API.
> 
> Question is, do we want to do this? Would we be introducing yet more
> confusion, rather than making the situation better?
> 
>   Andrew
> 
I think it is likely to introduce more confusion.
-Doug


Re: [PATCH net-next 4/4] net: bcmgenet: add support for ethtool flow control

2020-05-13 Thread Doug Berger
On 5/13/2020 2:52 AM, Russell King - ARM Linux admin wrote:
> On Mon, May 11, 2020 at 05:24:10PM -0700, Doug Berger wrote:
>> diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c 
>> b/drivers/net/ethernet/broadcom/genet/bcmmii.c
>> index 511d553a4d11..788da1ecea0c 100644
>> --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
>> +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
>> @@ -25,6 +25,21 @@
>>  
>>  #include "bcmgenet.h"
>>  
>> +static u32 _flow_control_autoneg(struct phy_device *phydev)
>> +{
>> +bool tx_pause, rx_pause;
>> +u32 cmd_bits = 0;
>> +
>> +phy_get_pause(phydev, _pause, _pause);
>> +
>> +if (!tx_pause)
>> +cmd_bits |= CMD_TX_PAUSE_IGNORE;
>> +if (!rx_pause)
>> +cmd_bits |= CMD_RX_PAUSE_IGNORE;
>> +
>> +return cmd_bits;
>> +}
>> +
>>  /* setup netdev link state when PHY link status change and
>>   * update UMAC and RGMII block when link up
>>   */
>> @@ -71,12 +86,20 @@ void bcmgenet_mii_setup(struct net_device *dev)
>>  cmd_bits <<= CMD_SPEED_SHIFT;
>>  
>>  /* duplex */
>> -if (phydev->duplex != DUPLEX_FULL)
>> -cmd_bits |= CMD_HD_EN;
>> -
>> -/* pause capability */
>> -if (!phydev->pause)
>> -cmd_bits |= CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE;
>> +if (phydev->duplex != DUPLEX_FULL) {
>> +cmd_bits |= CMD_HD_EN |
>> +CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE;
> 
> phy_get_pause() already takes account of whether the PHY is in half
> duplex mode.  So:
> 
>   bool tx_pause, rx_pause;
> 
>   if (phydev->autoneg && priv->autoneg_pause) {
>   phy_get_pause(phydev, _pause, _pause);
>   } else if (phydev->duplex == DUPLEX_FULL) {
>   tx_pause = priv->tx_pause;
>   rx_pause = priv->rx_pause;
>   } else {
>   tx_pause = false;
>   rx_pause = false;
>   }
> 
>   if (!tx_pause)
>   cmd_bits |= CMD_TX_PAUSE_IGNORE;
>   if (!rx_pause)
>   cmd_bits |= CMD_RX_PAUSE_IGNORE;
> 
> would be entirely sufficient here.
I need to check the duplex to configure the HD bit in the same register
with the pause controls so I am covering both with one compare.

This also includes a bug here that I mentioned in one of my responses to
the first patch of the set. The call to phy_get_pause() should only be
conditioned on phydev->autoneg_pause here.

The idea is that both directions of pause default to on, but if
autoneg_pause is on then phy_get_pause() has an opportunity to disable
any direction if the capability can't be negotiated for that direction.
Finally, the pause feature can be explicitly disabled by the tx_pause
and rx_pause parameters.
> I wonder whether your implementation (which mine follows) is really
> correct though.  Consider this:
> 
> # ethtool -A eth0 autoneg on tx on rx on
> # ethtool -s eth0 autoneg off speed 1000 duplex full
> 
> At this point, what do you expect the resulting pause state to be?  It
> may not be what you actually think it should be - it will be tx and rx
> pause enabled (it's easier to see why that happens with my rewritten
> version of your implementation, which is functionally identical.)
> 
> If we take the view that if link autoneg is disabled, and therefore the
> link partner's advertisement is zero, shouldn't it result in tx and rx
> pause being disabled?
So with the bug fixed as described above, after these commands
autoneg_pause would be on and autoneg would be off. The logic would call
phy_get_pause() which should return tx_pause = rx_pause = false turning
pause off in both directions.



Re: [PATCH net-next 3/4] net: ethernet: introduce phy_set_pause

2020-05-13 Thread Doug Berger
On 5/13/2020 2:42 AM, Russell King - ARM Linux admin wrote:
> On Mon, May 11, 2020 at 05:24:09PM -0700, Doug Berger wrote:
>> This commit introduces the phy_set_pause function to the phylib as
>> a helper to support the set_pauseparam ethtool method.
>>
>> It is hoped that the new behavior introduced by this function will
>> be widely embraced and the phy_set_sym_pause and phy_set_asym_pause
>> functions can be deprecated. Those functions are retained for all
>> existing users and for any desenting opinions on my interpretation
>> of the functionality.
>>
>> Signed-off-by: Doug Berger 
>> ---
>>  drivers/net/phy/phy_device.c | 31 +++
>>  include/linux/phy.h  |  1 +
>>  2 files changed, 32 insertions(+)
>>
>> diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
>> index 48ab9efa0166..e6dafb3c3e5f 100644
>> --- a/drivers/net/phy/phy_device.c
>> +++ b/drivers/net/phy/phy_device.c
>> @@ -2614,6 +2614,37 @@ void phy_set_asym_pause(struct phy_device *phydev, 
>> bool rx, bool tx)
>>  EXPORT_SYMBOL(phy_set_asym_pause);
>>  
>>  /**
>> + * phy_set_pause - Configure Pause and Asym Pause with autoneg
>> + * @phydev: target phy_device struct
>> + * @rx: Receiver Pause is supported
>> + * @tx: Transmit Pause is supported
>> + * @autoneg: Auto neg should be used
>> + *
>> + * Description: Configure advertised Pause support depending on if
>> + * receiver pause and pause auto neg is supported. Generally called
>> + * from the set_pauseparam ethtool_ops.
>> + *
>> + * Note: Since pause is really a MAC level function it should be
>> + * notified via adjust_link to update its pause functions.
>> + */
>> +void phy_set_pause(struct phy_device *phydev, bool rx, bool tx, bool 
>> autoneg)
>> +{
>> +linkmode_set_pause(phydev->advertising, tx, rx, autoneg);
>> +
>> +/* Reset the state of an already running link to force a new
>> + * link up event when advertising doesn't change or when PHY
>> + * autoneg is disabled.
>> + */
>> +mutex_lock(>lock);
>> +if (phydev->state == PHY_RUNNING)
>> +phydev->state = PHY_UP;
>> +mutex_unlock(>lock);
> 
> I wonder about this - will drivers cope with having two link-up events
> via adjust_link without a corresponding link-down event?  What if they
> touch registers that are only supposed to be touched while the link is
> down?  Obviously, drivers have to opt-in to this interface, so it may
> be okay provided we don't get wholesale changes.
I too wonder about this. That's why I brought it up in the cover letter
to this set. I would prefer a cleaner service interface for this kind of
behavior for the reasons described in the cover letter, but thought this
might be acceptable.

>> +
>> +phy_start_aneg(phydev);
> 
> Should we be making that conditional on something changing and autoneg
> being enabled, like phy_set_asym_pause() does?  There is no point
> interrupting an established link if the advertisement didn't change.
Again this is described in the cover letter but repeated here:
"The third introduces the phy_set_pause() function based on the existing
phy_set_asym_pause() implementation. One aberration here is the direct
manipulation of the phy state machine to allow a new link up event to
notify the MAC that the pause parameters may have changed. This is a
convenience to simplify the MAC driver by allowing one implementation
of the pause configuration logic to be located in its adjust_link
callback. Otherwise, the MAC driver would need to handle configuring
the pause parameters for an already active PHY link which would likely
require additional synchronization logic to protect the logic from
asynchronous changes in the PHY state.

The logic in phy_set_asym_pause() that looks for a change in
advertising is not particularly helpful here since now a change from
tx=1 rx=1 to tx=0 rx=1 no longer changes the advertising if autoneg is
enabled so phy_start_aneg() would not be called. I took the alternate
approach of unconditionally calling phy_start_aneg() since it
accommodates both manual and autoneg configured links. The "aberrant"
logic allows manually configured and autonegotiated links that don't
change their advertised parameters to receive an adjust_link call to
act on pause parameters that have no effect on the PHY layer.

It seemed excessive to bring the PHY down and back up when nogotiation
is not necessary, but that could be an alternative approach. I am
certainly open to any suggestions on how to improve that portion of
the code if it is controversial and a consensus can be reached."

>> +}
>&

Re: [PATCH net-next 1/4] net: ethernet: validate pause autoneg setting

2020-05-13 Thread Doug Berger
On 5/13/2020 2:20 AM, Russell King - ARM Linux admin wrote:
> On Wed, May 13, 2020 at 06:34:05AM +0100, Russell King - ARM Linux admin 
> wrote:
>> On Tue, May 12, 2020 at 08:48:22PM -0700, Doug Berger wrote:
>>> On 5/12/2020 11:55 AM, Russell King - ARM Linux admin wrote:
>>>> On Tue, May 12, 2020 at 11:31:39AM -0700, Doug Berger wrote:
>>>>> This was intended as a fix, but I thought it would be better to keep it
>>>>> as part of this set for context and since net-next is currently open.
>>>>>
>>>>> The context is trying to improve the phylib support for offloading
>>>>> ethtool pause configuration and this is something that could be checked
>>>>> in a single location rather than by individual drivers.
>>>>>
>>>>> I included it here to get feedback about its appropriateness as a common
>>>>> behavior. I should have been more explicit about that.
>>>>>
>>>>> Personally, I'm actually not that fond of this change since it can
>>>>> easily be a source of confusion with the ethtool interface because the
>>>>> link autonegotiation and the pause autonegotiation are controlled by
>>>>> different commands.
>>>>>
>>>>> Since the ethtool -A command performs a read/modify/write of pause
>>>>> parameters, you can get strange results like these:
>>>>> # ethtool -s eth0 speed 100 duplex full autoneg off
>>>>> # ethtool -A eth0 tx off
>>>>> Cannot set device pause parameters: Invalid argument
>>>>> #
>>>>> Because, the get read pause autoneg as enabled and only the tx_pause
>>>>> member of the structure was updated.
>>>>
>>>> This looks like the same argument I've been having with Heiner over
>>>> the EEE interface, except there's a difference here.
>>>>
>>>> # ethtool -A eth0 autoneg on
>>>> # ethtool -s eth0 autoneg off speed 100 duplex full
>>>>
>>>> After those two commands, what is the state of pause mode?  The answer
>>>> is, it's disabled.
>>>>
>>>> # ethtool -A eth0 autoneg off rx on tx on
>>>>
>>>> is perfectly acceptable, as we are forcing pause modes at the local
>>>> end of the link.
>>>>
>>>> # ethtool -A eth0 autoneg on
>>>>
>>>> Now, the question is whether that should be allowed or not - but this
>>>> is merely restoring the "pause" settings that were in effect prior
>>>> to the previous command.  It does not enable pause negotiation,
>>>> because autoneg as a whole is disabled, but it _allows_ pause
>>>> negotiation to occur when autoneg is enabled at some point in the
>>>> future.
>>>>
>>>> Also, allowing "ethtool -A eth0 autoneg on" when "ethtool -s eth0
>>>> autoneg off" means you can configure the negotiation parameters
>>>> _before_ triggering a negotiation cycle on the link.  In other words,
>>>> it would avoid:
>>>>
>>>> # ethtool -s eth0 autoneg on
>>>> # # Link renegotiates
>>>> # ethtool -A eth0 autoneg on
>>>> # # Link renegotiates a second time
>>>>
>>>> and it also means that if stuff has already been scripted to avoid
>>>> this, nothing breaks.
>>>>
>>>> If we start rejecting ethtool -A because autoneg is disabled, then
>>>> things get difficult to configure - we would need ethtool documentation
>>>> to state that autoneg must be enabled before configuration of pause
>>>> and EEE can be done.  IMHO, that hurts usability, and adds confusion.
>>>>
>>> Thanks for your input and I agree with what you have said here. I will
>>> remove this commit from the set when I resubmit and I assume that, like
>>> Michal, you would like to see the comment in ethtool.h revised.
>>>
>>> I think the crux of the matter is that the meaning of the autoneg pause
>>> parameter is not well specified, and that is fundamentally what I am
>>> trying to clarify in a common implementation that might help unify a
>>> consistent behavior across network drivers.
>>>
>>> My interpretation is that the link autonegotiation and the pause
>>> autonegotiation can be meaningfully set independently from each other
>>> and that the interplay between the two has easily overlooked subtleties.
>>>
>>> My opini

Re: [PATCH net-next 1/4] net: ethernet: validate pause autoneg setting

2020-05-13 Thread Doug Berger
On 5/12/2020 10:34 PM, Russell King - ARM Linux admin wrote:
> On Tue, May 12, 2020 at 08:48:22PM -0700, Doug Berger wrote:
>> On 5/12/2020 11:55 AM, Russell King - ARM Linux admin wrote:
>>> On Tue, May 12, 2020 at 11:31:39AM -0700, Doug Berger wrote:
>>>> This was intended as a fix, but I thought it would be better to keep it
>>>> as part of this set for context and since net-next is currently open.
>>>>
>>>> The context is trying to improve the phylib support for offloading
>>>> ethtool pause configuration and this is something that could be checked
>>>> in a single location rather than by individual drivers.
>>>>
>>>> I included it here to get feedback about its appropriateness as a common
>>>> behavior. I should have been more explicit about that.
>>>>
>>>> Personally, I'm actually not that fond of this change since it can
>>>> easily be a source of confusion with the ethtool interface because the
>>>> link autonegotiation and the pause autonegotiation are controlled by
>>>> different commands.
>>>>
>>>> Since the ethtool -A command performs a read/modify/write of pause
>>>> parameters, you can get strange results like these:
>>>> # ethtool -s eth0 speed 100 duplex full autoneg off
>>>> # ethtool -A eth0 tx off
>>>> Cannot set device pause parameters: Invalid argument
>>>> #
>>>> Because, the get read pause autoneg as enabled and only the tx_pause
>>>> member of the structure was updated.
>>>
>>> This looks like the same argument I've been having with Heiner over
>>> the EEE interface, except there's a difference here.
>>>
>>> # ethtool -A eth0 autoneg on
>>> # ethtool -s eth0 autoneg off speed 100 duplex full
>>>
>>> After those two commands, what is the state of pause mode?  The answer
>>> is, it's disabled.
>>>
>>> # ethtool -A eth0 autoneg off rx on tx on
>>>
>>> is perfectly acceptable, as we are forcing pause modes at the local
>>> end of the link.
>>>
>>> # ethtool -A eth0 autoneg on
>>>
>>> Now, the question is whether that should be allowed or not - but this
>>> is merely restoring the "pause" settings that were in effect prior
>>> to the previous command.  It does not enable pause negotiation,
>>> because autoneg as a whole is disabled, but it _allows_ pause
>>> negotiation to occur when autoneg is enabled at some point in the
>>> future.
>>>
>>> Also, allowing "ethtool -A eth0 autoneg on" when "ethtool -s eth0
>>> autoneg off" means you can configure the negotiation parameters
>>> _before_ triggering a negotiation cycle on the link.  In other words,
>>> it would avoid:
>>>
>>> # ethtool -s eth0 autoneg on
>>> # # Link renegotiates
>>> # ethtool -A eth0 autoneg on
>>> # # Link renegotiates a second time
>>>
>>> and it also means that if stuff has already been scripted to avoid
>>> this, nothing breaks.
>>>
>>> If we start rejecting ethtool -A because autoneg is disabled, then
>>> things get difficult to configure - we would need ethtool documentation
>>> to state that autoneg must be enabled before configuration of pause
>>> and EEE can be done.  IMHO, that hurts usability, and adds confusion.
>>>
>> Thanks for your input and I agree with what you have said here. I will
>> remove this commit from the set when I resubmit and I assume that, like
>> Michal, you would like to see the comment in ethtool.h revised.
>>
>> I think the crux of the matter is that the meaning of the autoneg pause
>> parameter is not well specified, and that is fundamentally what I am
>> trying to clarify in a common implementation that might help unify a
>> consistent behavior across network drivers.
>>
>> My interpretation is that the link autonegotiation and the pause
>> autonegotiation can be meaningfully set independently from each other
>> and that the interplay between the two has easily overlooked subtleties.
>>
>> My opinion (which is at least in part drawn from my interpretation of
>> your opinion) is as follows with regard to pause behaviors:
>>
>> The link autonegotiation parameter concerns itself with whether the
>> Pause capabilities are advertised as part of autonegotiation of link
>> parameters.
>>
>> The pause autonegotiation parameter concerns itself with whether the
>> local node is

Re: [PATCH net-next 1/4] net: ethernet: validate pause autoneg setting

2020-05-12 Thread Doug Berger
On 5/12/2020 11:55 AM, Russell King - ARM Linux admin wrote:
> On Tue, May 12, 2020 at 11:31:39AM -0700, Doug Berger wrote:
>> This was intended as a fix, but I thought it would be better to keep it
>> as part of this set for context and since net-next is currently open.
>>
>> The context is trying to improve the phylib support for offloading
>> ethtool pause configuration and this is something that could be checked
>> in a single location rather than by individual drivers.
>>
>> I included it here to get feedback about its appropriateness as a common
>> behavior. I should have been more explicit about that.
>>
>> Personally, I'm actually not that fond of this change since it can
>> easily be a source of confusion with the ethtool interface because the
>> link autonegotiation and the pause autonegotiation are controlled by
>> different commands.
>>
>> Since the ethtool -A command performs a read/modify/write of pause
>> parameters, you can get strange results like these:
>> # ethtool -s eth0 speed 100 duplex full autoneg off
>> # ethtool -A eth0 tx off
>> Cannot set device pause parameters: Invalid argument
>> #
>> Because, the get read pause autoneg as enabled and only the tx_pause
>> member of the structure was updated.
> 
> This looks like the same argument I've been having with Heiner over
> the EEE interface, except there's a difference here.
> 
> # ethtool -A eth0 autoneg on
> # ethtool -s eth0 autoneg off speed 100 duplex full
> 
> After those two commands, what is the state of pause mode?  The answer
> is, it's disabled.
> 
> # ethtool -A eth0 autoneg off rx on tx on
> 
> is perfectly acceptable, as we are forcing pause modes at the local
> end of the link.
> 
> # ethtool -A eth0 autoneg on
> 
> Now, the question is whether that should be allowed or not - but this
> is merely restoring the "pause" settings that were in effect prior
> to the previous command.  It does not enable pause negotiation,
> because autoneg as a whole is disabled, but it _allows_ pause
> negotiation to occur when autoneg is enabled at some point in the
> future.
> 
> Also, allowing "ethtool -A eth0 autoneg on" when "ethtool -s eth0
> autoneg off" means you can configure the negotiation parameters
> _before_ triggering a negotiation cycle on the link.  In other words,
> it would avoid:
> 
> # ethtool -s eth0 autoneg on
> # # Link renegotiates
> # ethtool -A eth0 autoneg on
> # # Link renegotiates a second time
> 
> and it also means that if stuff has already been scripted to avoid
> this, nothing breaks.
> 
> If we start rejecting ethtool -A because autoneg is disabled, then
> things get difficult to configure - we would need ethtool documentation
> to state that autoneg must be enabled before configuration of pause
> and EEE can be done.  IMHO, that hurts usability, and adds confusion.
> 
Thanks for your input and I agree with what you have said here. I will
remove this commit from the set when I resubmit and I assume that, like
Michal, you would like to see the comment in ethtool.h revised.

I think the crux of the matter is that the meaning of the autoneg pause
parameter is not well specified, and that is fundamentally what I am
trying to clarify in a common implementation that might help unify a
consistent behavior across network drivers.

My interpretation is that the link autonegotiation and the pause
autonegotiation can be meaningfully set independently from each other
and that the interplay between the two has easily overlooked subtleties.

My opinion (which is at least in part drawn from my interpretation of
your opinion) is as follows with regard to pause behaviors:

The link autonegotiation parameter concerns itself with whether the
Pause capabilities are advertised as part of autonegotiation of link
parameters.

The pause autonegotiation parameter concerns itself with whether the
local node is willing to accept the advertised capabilities of its peer
as input into its pause configuration.

The Tx_Pause and Rx_Pause parameters indicate in which directions pause
frames should be supported.

If the pause autonegotiation is off, the MAC is allowed to act
exclusively according to the Tx_Pause and Rx_Pause parameters. If
Tx_Pause is on the MAC should send pause control frames whenever it
needs to assert back pressure to ease the load on its receiver. If
Tx_Pause is off the MAC should not transmit any pause control frames. If
Rx_Pause is on the MAC should delay its transmissions in response to any
pause control frames it receives. If Rx_Pause is off received pause
control frames should be ignored. If link autonegotiation is on the
Tx_Pause and Rx_Pause values should be advertised in the PHY Pause and
AsymPause bits for 

Re: [PATCH net-next 1/4] net: ethernet: validate pause autoneg setting

2020-05-12 Thread Doug Berger
On 5/12/2020 12:08 PM, Michal Kubecek wrote:
> On Tue, May 12, 2020 at 11:31:39AM -0700, Doug Berger wrote:
>> On 5/11/2020 5:47 PM, Andrew Lunn wrote:
>>> On Mon, May 11, 2020 at 05:24:07PM -0700, Doug Berger wrote:
>>>> A comment in uapi/linux/ethtool.h states "Drivers should reject a
>>>> non-zero setting of @autoneg when autoneogotiation is disabled (or
>>>> not supported) for the link".
>>>>
>>>> That check should be added to phy_validate_pause() to consolidate
>>>> the code where possible.
>>>>
>>>> Fixes: 22b7d29926b5 ("net: ethernet: Add helper to determine if pause 
>>>> configuration is supported")
>>>
>>> Hi Doug
>>>
>>> If this is a real fix, please submit this to net, not net-next.
>>>
>>>Andrew
>>>
>> This was intended as a fix, but I thought it would be better to keep it
>> as part of this set for context and since net-next is currently open.
>>
>> The context is trying to improve the phylib support for offloading
>> ethtool pause configuration and this is something that could be checked
>> in a single location rather than by individual drivers.
>>
>> I included it here to get feedback about its appropriateness as a common
>> behavior. I should have been more explicit about that.
>>
>> Personally, I'm actually not that fond of this change since it can
>> easily be a source of confusion with the ethtool interface because the
>> link autonegotiation and the pause autonegotiation are controlled by
>> different commands.
>>
>> Since the ethtool -A command performs a read/modify/write of pause
>> parameters, you can get strange results like these:
>> # ethtool -s eth0 speed 100 duplex full autoneg off
>> # ethtool -A eth0 tx off
>> Cannot set device pause parameters: Invalid argument
>> #
>> Because, the get read pause autoneg as enabled and only the tx_pause
>> member of the structure was updated.
> 
> This would be indeed unfortunate. We could use extack to make the error
> message easier to understand but the real problem IMHO is that
> ethtool_ops::get_pauseparam() returns value which is rejected by
> ethtool_ops::set_pauseparam(). This is something we should avoid.
> 
> If we really wanted to reject ethtool_pauseparam::autoneg on when
> general autonegotiation is off, we would have to disable pause
> autonegotiation whenever general autonegotiation is disabled. I don't
> like that idea, however, as that would mean that
> 
>   ethtool -s dev autoneg off ...
>   ethtool -s dev autoneg on ...
> 
> would reset the setting of pause autonegotiation.
> 
> Therefore I believe the comment should be rather replaced by a warning
> that even if ethtool_pauseparam::autoneg is enabled, pause
> autonegotiation is only active if general autonegotiation is also
> enabled.
> 
> Michal
> 
Thanks for your reply.

I agree with your concerns and will remove this commit from the set when
I resubmit. I also favor replacing the comment in ethtool.h.

-Doug


Re: [PATCH net-next 3/4] net: ethernet: introduce phy_set_pause

2020-05-12 Thread Doug Berger
On 5/11/2020 5:51 PM, Andrew Lunn wrote:
> On Mon, May 11, 2020 at 05:24:09PM -0700, Doug Berger wrote:
>> This commit introduces the phy_set_pause function to the phylib as
>> a helper to support the set_pauseparam ethtool method.
>>
>> It is hoped that the new behavior introduced by this function will
>> be widely embraced and the phy_set_sym_pause and phy_set_asym_pause
>> functions can be deprecated. Those functions are retained for all
>> existing users and for any desenting opinions on my interpretation
>> of the functionality.
> 
> It would be good to add comments to phy_set_sym_pause and
> phy_set_asym_pause indicating they are deprecated and point to
> phy_set_pause().
> 
>   Andrew
> 

To be clear, this patch set reflects the pauseparam implementation I
desire for the bcmgenet driver. I attempted to implement it as a common
phylib service with the hope that it would help other network driver
maintainers add support for pause in a common way.

I would like to get feedback/consensus that it is desirable behavior for
other drivers to implement before promoting the change of existing
implementations.

In particular, I would like to know Russell King's opinion since he has
clearly observed (and documented) the short comings of current
implementations as part of his phylink work.

If others agree with this being the way to move forward, I will submit
another revision with your suggested comments about deprecation within
the specified functions.

Thanks for the feedback,
Doug


Re: [PATCH net-next 1/4] net: ethernet: validate pause autoneg setting

2020-05-12 Thread Doug Berger
On 5/11/2020 5:47 PM, Andrew Lunn wrote:
> On Mon, May 11, 2020 at 05:24:07PM -0700, Doug Berger wrote:
>> A comment in uapi/linux/ethtool.h states "Drivers should reject a
>> non-zero setting of @autoneg when autoneogotiation is disabled (or
>> not supported) for the link".
>>
>> That check should be added to phy_validate_pause() to consolidate
>> the code where possible.
>>
>> Fixes: 22b7d29926b5 ("net: ethernet: Add helper to determine if pause 
>> configuration is supported")
> 
> Hi Doug
> 
> If this is a real fix, please submit this to net, not net-next.
> 
>Andrew
> 
This was intended as a fix, but I thought it would be better to keep it
as part of this set for context and since net-next is currently open.

The context is trying to improve the phylib support for offloading
ethtool pause configuration and this is something that could be checked
in a single location rather than by individual drivers.

I included it here to get feedback about its appropriateness as a common
behavior. I should have been more explicit about that.

Personally, I'm actually not that fond of this change since it can
easily be a source of confusion with the ethtool interface because the
link autonegotiation and the pause autonegotiation are controlled by
different commands.

Since the ethtool -A command performs a read/modify/write of pause
parameters, you can get strange results like these:
# ethtool -s eth0 speed 100 duplex full autoneg off
# ethtool -A eth0 tx off
Cannot set device pause parameters: Invalid argument
#
Because, the get read pause autoneg as enabled and only the tx_pause
member of the structure was updated.

The network driver could attempt to change one in response to the other,
but it might be difficult to reach consensus and it adds more
"worthless" code to the network driver in opposition to the intent.

I would like to get more feedback about the approach of the patch set as
a whole before I resubmit, and would be happy to drop this commit at
that time.

But there is still a question of how the comment "Drivers should reject
a non-zero setting of @autoneg when autoneogotiation is disabled (or not
supported) for the link" in ethtool.h should be interpreted.

Should that comment be removed?

Thanks for taking the time to look at this,
Doug


[PATCH net-next 2/4] net: add autoneg parameter to linkmode_set_pause

2020-05-11 Thread Doug Berger
This commit introduces a new parameter to linkmode_set_pause to
provide a mechanism to specify two alternative mappings of the
pause parameters for advertisement by the PHY.

An argument is made that the advertisement through Pause and
AsymPause of the desired Rx and Tx pause frame use should be
different depending on whether pause autonegotiation is enabled.

The existing behavior is kept unchanged by setting autoneg=0 in
this new parameter and existing users of the function are made
to do just that.

Fixes: 45c767faef15 ("net: add linkmode helper for setting flow control 
advertisement")
Signed-off-by: Doug Berger 
---
 drivers/net/phy/linkmode.c   | 104 +--
 drivers/net/phy/phy_device.c |   3 +-
 drivers/net/phy/phylink.c|   6 +--
 include/linux/linkmode.h |   3 +-
 4 files changed, 88 insertions(+), 28 deletions(-)

diff --git a/drivers/net/phy/linkmode.c b/drivers/net/phy/linkmode.c
index f60560fe3499..5658ba9ba94d 100644
--- a/drivers/net/phy/linkmode.c
+++ b/drivers/net/phy/linkmode.c
@@ -48,48 +48,106 @@ EXPORT_SYMBOL_GPL(linkmode_resolve_pause);
  * @advertisement: advertisement in ethtool format
  * @tx: boolean from ethtool struct ethtool_pauseparam tx_pause member
  * @rx: boolean from ethtool struct ethtool_pauseparam rx_pause member
+ * @autoneg: boolean from ethtool struct ethtool_pauseparam autoneg member
  *
  * Configure the advertised Pause and Asym_Pause bits according to the
- * capabilities of provided in @tx and @rx.
+ * capabilities specified by @tx, @rx, and @autoneg.
  *
- * We convert as follows:
+ * If autoneg is true, we convert as follows:
+ *  tx rx  Pause AsymDir
+ *  0  0   0 0
+ *  0  1   1 1
+ *  1  0   0 1
+ *  1  1   1 1
+ *
+ * Otherwise, we convert as follows:
  *  tx rx  Pause AsymDir
  *  0  0   0 0
  *  0  1   1 1
  *  1  0   0 1
  *  1  1   1 0
  *
- * Note: this translation from ethtool tx/rx notation to the advertisement
- * is actually very problematical. Here are some examples:
+ * To the extent that pause frame generation and consumption are defined as
+ * MAC layer functionalities and that the PHY layer should only concern
+ * itself with the advertising of these capabilities, this implementation
+ * is intended to address the problematic behaviors of the previous version
+ * while allowing equivalent behavior when an implementation is unwilling
+ * to negotiate with its peer.
+ *
+ * When autoneg is enabled for pause parameters it indicates a willingness
+ * to negotiate the parameters with a peer. Negotiation implies that a node
+ * is willing to accept a subset of its requested parameters as long as it
+ * is compatible with those requested parameters. This mapping agrees with
+ * the encoding specified in IEEE Std 802.3-2018 by Table 37-2.
+ *
+ * The negotiation is specified in IEEE Std 802.3-2018 by Table 37-4 and
+ * is implemented here by linkmode_resolve_pause.
+ *
+ * Allowing  to set both Pause and AsymDir prevents
+ * the previous problematic behaviors as follows:
  *
  * For tx=0 rx=1, meaning transmit is unsupported, receive is supported:
  *
  *  Local device  Link partner
- *  Pause AsymDir Pause AsymDir Result
- *1 1   1 0 TX + RX - but we have no TX support.
- *1 1   0 1Only this gives RX only
+ *  Pause AsymDir Pause AsymDir Result of negotiation at local device
+ *1 1   0 0No pause frames allowed
+ *1 1   0 1Only RX pause frames allowed
+ *1 1   1 0TX + RX pause frames are allowed
+ *1 1   1 1TX + RX pause frames are allowed
+ *
+ * While the TX + RX results may seem problematic they are only an
+ * indication that a MAC that receives a pause MAC control frame in the
+ * specified direction will comply with the specified behavior. The tx=0
+ * parameter is made visible to the local MAC layer by the set_pauseparam
+ * ethtool method so it should disable the generation of pause frames at
+ * the MAC layer regardless of what the PHY negotiates.
  *
  * For tx=1 rx=1, meaning we have the capability to transmit and receive
- * pause frames:
+ * pause frames, the results are the same as above. However, now the PHY
+ * negotiation result that reports "Only Rx pause frames allowed" must be
+ * used by the MAC to override the fact that tx=1 so that pause frame
+ * generation is disabled for this combination.
+ *
+ * When autoneg is disabled for pause parameters, it indicates an
+ * unwillingness to negotiate the parameters with a peer. In this case,
+ * the advertisement is more informational and mapping tx=1 rx=1 to only
+ * Symmetric Pause may be a better communication of intent.
  *
  *  Local device  Link partner
- *  Pause AsymDir Pause AsymDir Result
- *1 0   0 1 Disabled - but since we do support tx and rx,
- * this should resolve to RX only.
- *
- * Hence, asking for:
- *  r

[PATCH net-next 4/4] net: bcmgenet: add support for ethtool flow control

2020-05-11 Thread Doug Berger
This commit extends the supported ethtool operations to allow MAC
level flow control to be configured for the bcmgenet driver. It
provides an example of how the new phy_set_pause function and the
phy_validate_pause function can be used to configure the desired
PHY advertising as well as how the phy_get_pause function can be
used for resolving negotiated pause modes which may be overridden
by the MAC.

The ethtool utility can be used to change the configuration to enable
auto-negotiated symmetric and asymmetric modes as well as manually
enabling support for RX and TX Pause frames individually.

Signed-off-by: Doug Berger 
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 54 ++
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |  4 ++
 drivers/net/ethernet/broadcom/genet/bcmmii.c   | 38 ++
 3 files changed, 89 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index ff31da0ed846..c0e22da7ac53 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -1017,6 +1017,53 @@ static int bcmgenet_set_coalesce(struct net_device *dev,
return 0;
 }
 
+static void bcmgenet_get_pauseparam(struct net_device *dev,
+   struct ethtool_pauseparam *epause)
+{
+   struct bcmgenet_priv *priv;
+   u32 umac_cmd;
+
+   priv = netdev_priv(dev);
+
+   epause->autoneg = priv->autoneg_pause;
+
+   if (priv->old_link > 0) {
+   /* report active state when link is up */
+   umac_cmd = bcmgenet_umac_readl(priv, UMAC_CMD);
+   epause->tx_pause = !(umac_cmd & CMD_TX_PAUSE_IGNORE);
+   epause->rx_pause = !(umac_cmd & CMD_RX_PAUSE_IGNORE);
+   } else {
+   /* otherwise report stored settings */
+   epause->tx_pause = priv->tx_pause;
+   epause->rx_pause = priv->rx_pause;
+   }
+}
+
+static int bcmgenet_set_pauseparam(struct net_device *dev,
+  struct ethtool_pauseparam *epause)
+{
+   struct bcmgenet_priv *priv = netdev_priv(dev);
+
+   if (!dev->phydev)
+   return -ENODEV;
+
+   if (!phy_validate_pause(dev->phydev, epause))
+   return -EINVAL;
+
+   priv->autoneg_pause = !!epause->autoneg;
+   priv->tx_pause = !!epause->tx_pause;
+   priv->rx_pause = !!epause->rx_pause;
+
+   /* Restart the PHY */
+   if (netif_running(dev))
+   priv->old_link = -1;
+
+   phy_set_pause(dev->phydev, priv->rx_pause, priv->tx_pause,
+ priv->autoneg_pause);
+
+   return 0;
+}
+
 /* standard ethtool support functions. */
 enum bcmgenet_stat_type {
BCMGENET_STAT_NETDEV = -1,
@@ -1670,6 +1717,8 @@ static const struct ethtool_ops bcmgenet_ethtool_ops = {
.get_ts_info= ethtool_op_get_ts_info,
.get_rxnfc  = bcmgenet_get_rxnfc,
.set_rxnfc  = bcmgenet_set_rxnfc,
+   .get_pauseparam = bcmgenet_get_pauseparam,
+   .set_pauseparam = bcmgenet_set_pauseparam,
 };
 
 /* Power down the unimac, based on mode. */
@@ -4018,6 +4067,11 @@ static int bcmgenet_probe(struct platform_device *pdev)
 
spin_lock_init(>lock);
 
+   /* Set default pause parameters */
+   priv->autoneg_pause = 1;
+   priv->tx_pause = 1;
+   priv->rx_pause = 1;
+
SET_NETDEV_DEV(dev, >dev);
dev_set_drvdata(>dev, dev);
dev->watchdog_timeo = 2 * HZ;
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
index a12cb59298f4..e44830b3aa4a 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
@@ -683,6 +683,10 @@ struct bcmgenet_priv {
/* HW descriptors/checksum variables */
bool crc_fwd_en;
 
+   unsigned autoneg_pause:1;
+   unsigned tx_pause:1;
+   unsigned rx_pause:1;
+
u32 dma_max_burst_length;
 
u32 msg_enable;
diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c 
b/drivers/net/ethernet/broadcom/genet/bcmmii.c
index 511d553a4d11..788da1ecea0c 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
@@ -25,6 +25,21 @@
 
 #include "bcmgenet.h"
 
+static u32 _flow_control_autoneg(struct phy_device *phydev)
+{
+   bool tx_pause, rx_pause;
+   u32 cmd_bits = 0;
+
+   phy_get_pause(phydev, _pause, _pause);
+
+   if (!tx_pause)
+   cmd_bits |= CMD_TX_PAUSE_IGNORE;
+   if (!rx_pause)
+   cmd_bits |= CMD_RX_PAUSE_IGNORE;
+
+   return cmd_bits;
+}
+
 /* setup netdev link state when PHY link status change and
  * update UMAC and RGMII block wh

[PATCH net-next 1/4] net: ethernet: validate pause autoneg setting

2020-05-11 Thread Doug Berger
A comment in uapi/linux/ethtool.h states "Drivers should reject a
non-zero setting of @autoneg when autoneogotiation is disabled (or
not supported) for the link".

That check should be added to phy_validate_pause() to consolidate
the code where possible.

Fixes: 22b7d29926b5 ("net: ethernet: Add helper to determine if pause 
configuration is supported")
Signed-off-by: Doug Berger 
---
 drivers/net/phy/phy_device.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index c3a107cf578e..5a9618ba232e 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -2624,6 +2624,9 @@ EXPORT_SYMBOL(phy_set_asym_pause);
 bool phy_validate_pause(struct phy_device *phydev,
struct ethtool_pauseparam *pp)
 {
+   if (pp->autoneg && !phydev->autoneg)
+   return false;
+
if (!linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
   phydev->supported) && pp->rx_pause)
return false;
-- 
2.7.4



[PATCH net-next 0/4] Extend phylib implementation of pause support

2020-05-11 Thread Doug Berger
This commit set extends the implementation introduced by
commit 5652b46e4e80 ("Merge branch 'Pause-updates-for-phylib-and-phylink'")
to support the less problematic behavior alluded to by Russell King's
comment in commit f904f15ea9b5 ("net: phylink: allow ethtool -A to
change flow control advertisement").

+   /*
+* See the comments for linkmode_set_pause(), wrt the deficiencies
+* with the current implementation.  A solution to this issue would
+* be:
+* ethtool  Local device
+*  rx  tx  Pause AsymDir
+*  0   0   0 0
+*  1   0   1 1
+*  0   1   0 1
+*  1   1   1 1
+* and then use the ethtool rx/tx enablement status to mask the
+* rx/tx pause resolution.
+*/

Specifically, the linkmode_set_pause() function is extended to support
both the existing Pause/AsymPause mapping and the mapping specified by
the IEEE standard (and Russell). A phy_set_pause() function is added to
the phylib that can make use of this extension based on the value of
the pause autoneg parameter. The bcmgenet driver adds support for the
ethtool pauseparam ops based on these phylib services and uses "the
ethtool rx/tx enablement status to mask the rx/tx pause resolution".

The first commit in this set addresses a small deficiency in the 
phy_validate_pause() function.

The second extends linkmode_set_pause() with an autoneg parameter to
allow selection of the desired mapping for advertisement.

The third introduces the phy_set_pause() function based on the existing
phy_set_asym_pause() implementation. One aberration here is the direct
manipulation of the phy state machine to allow a new link up event to
notify the MAC that the pause parameters may have changed. This is a
convenience to simplify the MAC driver by allowing one implementation
of the pause configuration logic to be located in its adjust_link
callback. Otherwise, the MAC driver would need to handle configuring
the pause parameters for an already active PHY link which would likely
require additional synchronization logic to protect the logic from
asynchronous changes in the PHY state.

The logic in phy_set_asym_pause() that looks for a change in
advertising is not particularly helpful here since now a change from
tx=1 rx=1 to tx=0 rx=1 no longer changes the advertising if autoneg is
enabled so phy_start_aneg() would not be called. I took the alternate
approach of unconditionally calling phy_start_aneg() since it
accommodates both manual and autoneg configured links. The "aberrant"
logic allows manually configured and autonegotiated links that don't
change their advertised parameters to receive an adjust_link call to
act on pause parameters that have no effect on the PHY layer.

It seemed excessive to bring the PHY down and back up when nogotiation
is not necessary, but that could be an alternative approach. I am
certainly open to any suggestions on how to improve that portion of
the code if it is controversial and a consensus can be reached.

The last commit is a reference implementation of pause support by the
bcmgenet driver based on my preferences for the functionality. It is my
desire that other network drivers prefer this behavior and the changes
to the phylib will make it easier for them to support.

Many thanks to Russell King and Andrew Lunn for their efforts to clean
up and centralize support for pause and to document its shortcommings.

Doug Berger (4):
  net: ethernet: validate pause autoneg setting
  net: add autoneg parameter to linkmode_set_pause
  net: ethernet: introduce phy_set_pause
  net: bcmgenet: add support for ethtool flow control

 drivers/net/ethernet/broadcom/genet/bcmgenet.c |  54 +
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |   4 +
 drivers/net/ethernet/broadcom/genet/bcmmii.c   |  38 +++--
 drivers/net/phy/linkmode.c | 104 +++--
 drivers/net/phy/phy_device.c   |  37 -
 drivers/net/phy/phylink.c  |   6 +-
 include/linux/linkmode.h   |   3 +-
 include/linux/phy.h|   1 +
 8 files changed, 212 insertions(+), 35 deletions(-)

-- 
2.7.4



[PATCH net-next 3/4] net: ethernet: introduce phy_set_pause

2020-05-11 Thread Doug Berger
This commit introduces the phy_set_pause function to the phylib as
a helper to support the set_pauseparam ethtool method.

It is hoped that the new behavior introduced by this function will
be widely embraced and the phy_set_sym_pause and phy_set_asym_pause
functions can be deprecated. Those functions are retained for all
existing users and for any desenting opinions on my interpretation
of the functionality.

Signed-off-by: Doug Berger 
---
 drivers/net/phy/phy_device.c | 31 +++
 include/linux/phy.h  |  1 +
 2 files changed, 32 insertions(+)

diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 48ab9efa0166..e6dafb3c3e5f 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -2614,6 +2614,37 @@ void phy_set_asym_pause(struct phy_device *phydev, bool 
rx, bool tx)
 EXPORT_SYMBOL(phy_set_asym_pause);
 
 /**
+ * phy_set_pause - Configure Pause and Asym Pause with autoneg
+ * @phydev: target phy_device struct
+ * @rx: Receiver Pause is supported
+ * @tx: Transmit Pause is supported
+ * @autoneg: Auto neg should be used
+ *
+ * Description: Configure advertised Pause support depending on if
+ * receiver pause and pause auto neg is supported. Generally called
+ * from the set_pauseparam ethtool_ops.
+ *
+ * Note: Since pause is really a MAC level function it should be
+ * notified via adjust_link to update its pause functions.
+ */
+void phy_set_pause(struct phy_device *phydev, bool rx, bool tx, bool autoneg)
+{
+   linkmode_set_pause(phydev->advertising, tx, rx, autoneg);
+
+   /* Reset the state of an already running link to force a new
+* link up event when advertising doesn't change or when PHY
+* autoneg is disabled.
+*/
+   mutex_lock(>lock);
+   if (phydev->state == PHY_RUNNING)
+   phydev->state = PHY_UP;
+   mutex_unlock(>lock);
+
+   phy_start_aneg(phydev);
+}
+EXPORT_SYMBOL(phy_set_pause);
+
+/**
  * phy_validate_pause - Test if the PHY/MAC support the pause configuration
  * @phydev: phy_device struct
  * @pp: requested pause configuration
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 5d8ff5428010..71e484424e68 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -1403,6 +1403,7 @@ void phy_support_asym_pause(struct phy_device *phydev);
 void phy_set_sym_pause(struct phy_device *phydev, bool rx, bool tx,
   bool autoneg);
 void phy_set_asym_pause(struct phy_device *phydev, bool rx, bool tx);
+void phy_set_pause(struct phy_device *phydev, bool rx, bool tx, bool autoneg);
 bool phy_validate_pause(struct phy_device *phydev,
struct ethtool_pauseparam *pp);
 void phy_get_pause(struct phy_device *phydev, bool *tx_pause, bool *rx_pause);
-- 
2.7.4



[PATCH net-next] net: bcmgenet: Move wake-up event out of side band ISR

2020-04-30 Thread Doug Berger
The side band interrupt service routine is not available on chips
like 7211, or rather, it does not permit the signaling of wake-up
events due to the complex interrupt hierarchy.

Move the wake-up event accounting into a .resume_noirq function,
account for possible wake-up events and clear the MPD/HFB interrupts
from there, while leaving the hardware untouched until the resume
function proceeds with doing its usual business.

Because bcmgenet_wol_power_down_cfg() now enables the MPD and HFB
interrupts, it is invoked by a .suspend_noirq function to prevent
the servicing of interrupts after the clocks have been disabled.

Signed-off-by: Doug Berger 
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 72 ++
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |  2 +
 drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c |  6 ++
 3 files changed, 67 insertions(+), 13 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index ad614d7201bd..ff31da0ed846 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -3270,10 +3270,7 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id)
 
 static irqreturn_t bcmgenet_wol_isr(int irq, void *dev_id)
 {
-   struct bcmgenet_priv *priv = dev_id;
-
-   pm_wakeup_event(>pdev->dev, 0);
-
+   /* Acknowledge the interrupt */
return IRQ_HANDLED;
 }
 
@@ -4174,13 +4171,12 @@ static void bcmgenet_shutdown(struct platform_device 
*pdev)
 }
 
 #ifdef CONFIG_PM_SLEEP
-static int bcmgenet_resume(struct device *d)
+static int bcmgenet_resume_noirq(struct device *d)
 {
struct net_device *dev = dev_get_drvdata(d);
struct bcmgenet_priv *priv = netdev_priv(dev);
-   unsigned long dma_ctrl;
-   u32 offset, reg;
int ret;
+   u32 reg;
 
if (!netif_running(dev))
return 0;
@@ -4190,6 +4186,34 @@ static int bcmgenet_resume(struct device *d)
if (ret)
return ret;
 
+   if (device_may_wakeup(d) && priv->wolopts) {
+   /* Account for Wake-on-LAN events and clear those events
+* (Some devices need more time between enabling the clocks
+*  and the interrupt register reflecting the wake event so
+*  read the register twice)
+*/
+   reg = bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_STAT);
+   reg = bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_STAT);
+   if (reg & UMAC_IRQ_WAKE_EVENT)
+   pm_wakeup_event(>pdev->dev, 0);
+   }
+
+   bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_WAKE_EVENT, INTRL2_CPU_CLEAR);
+
+   return 0;
+}
+
+static int bcmgenet_resume(struct device *d)
+{
+   struct net_device *dev = dev_get_drvdata(d);
+   struct bcmgenet_priv *priv = netdev_priv(dev);
+   unsigned long dma_ctrl;
+   u32 offset, reg;
+   int ret;
+
+   if (!netif_running(dev))
+   return 0;
+
/* From WOL-enabled suspend, switch to regular clock */
if (device_may_wakeup(d) && priv->wolopts)
bcmgenet_power_up(priv, GENET_POWER_WOL_MAGIC);
@@ -4262,7 +4286,6 @@ static int bcmgenet_suspend(struct device *d)
 {
struct net_device *dev = dev_get_drvdata(d);
struct bcmgenet_priv *priv = netdev_priv(dev);
-   int ret = 0;
u32 offset;
 
if (!netif_running(dev))
@@ -4282,23 +4305,46 @@ static int bcmgenet_suspend(struct device *d)
priv->hfb_en[2] = bcmgenet_hfb_reg_readl(priv, offset + sizeof(u32));
bcmgenet_hfb_reg_writel(priv, 0, HFB_CTRL);
 
+   return 0;
+}
+
+static int bcmgenet_suspend_noirq(struct device *d)
+{
+   struct net_device *dev = dev_get_drvdata(d);
+   struct bcmgenet_priv *priv = netdev_priv(dev);
+   int ret = 0;
+
+   if (!netif_running(dev))
+   return 0;
+
/* 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);
else if (priv->internal_phy)
ret = bcmgenet_power_down(priv, GENET_POWER_PASSIVE);
 
+   /* Let the framework handle resumption and leave the clocks on */
+   if (ret)
+   return ret;
+
/* Turn off the clocks */
clk_disable_unprepare(priv->clk);
 
-   if (ret)
-   bcmgenet_resume(d);
-
-   return ret;
+   return 0;
 }
+#else
+#define bcmgenet_suspend   NULL
+#define bcmgenet_suspend_noirq NULL
+#define bcmgenet_resumeNULL
+#define bcmgenet_resume_noirq  NULL
 #endif /* CONFIG_PM_SLEEP */
 
-static SIMPLE_DEV_PM_OPS(bcmgenet_pm_ops, bcmgenet_suspend, bcmgenet_resume);
+static const struct dev_pm_ops bcmgenet_pm_ops = {
+   .suspend= bcmgenet

Re: [PATCH net-next v2 0/7] net: bcmgenet: add support for Wake on Filter

2020-04-29 Thread Doug Berger
On 4/29/20 3:07 PM, Doug Berger wrote:
> On 4/29/20 1:01 PM, Doug Berger wrote:
>> Changes in v2:
>>  Corrected Signed-off-by for commit 3/7.
>>
>> This commit set adds support for waking from 'standby' using a
>> Rx Network Flow Classification filter specified with ethtool.
>>
>> The first two commits are bug fixes that should be applied to the
>> stable branches, but are included in this patch set to reduce merge
>> conflicts that might occur if not applied before the other commits
>> in this set.
>>
>> The next commit consolidates WoL clock managment as a part of the
>> overall WoL configuration.
>>
>> The next commit restores a set of functions that were removed from
>> the driver just prior to the 4.9 kernel release.
>>
>> The following commit relocates the functions in the file to prevent
>> the need for additional forward declarations.
>>
>> Next, support for the Rx Network Flow Classification interface of
>> ethtool is added.
>>
>> Finally, support for the WAKE_FILTER wol method is added.
>>
>> Doug Berger (7):
>>   net: bcmgenet: set Rx mode before starting netif
>>   net: bcmgenet: Fix WoL with password after deep sleep
>>   net: bcmgenet: move clk_wol management to bcmgenet_wol
>>   Revert "net: bcmgenet: remove unused function in bcmgenet.c"
>>   net: bcmgenet: code movement
>>   net: bcmgenet: add support for ethtool rxnfc flows
>>   net: bcmgenet: add WAKE_FILTER support
>>
>>  drivers/net/ethernet/broadcom/genet/bcmgenet.c | 673 
>> +++--
>>  drivers/net/ethernet/broadcom/genet/bcmgenet.h |  21 +-
>>  drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c |  90 ++-
>>  3 files changed, 708 insertions(+), 76 deletions(-)
>>
> Please holdoff on this version as there is a bug here that I'd like to
> patch first.
> 
> Thanks,
> Doug
> 
Apparently the bug was in my head. This should be good to go.

Sorry for the confusion,
Doug


Re: [PATCH net-next v2 0/7] net: bcmgenet: add support for Wake on Filter

2020-04-29 Thread Doug Berger
On 4/29/20 1:01 PM, Doug Berger wrote:
> Changes in v2:
>   Corrected Signed-off-by for commit 3/7.
> 
> This commit set adds support for waking from 'standby' using a
> Rx Network Flow Classification filter specified with ethtool.
> 
> The first two commits are bug fixes that should be applied to the
> stable branches, but are included in this patch set to reduce merge
> conflicts that might occur if not applied before the other commits
> in this set.
> 
> The next commit consolidates WoL clock managment as a part of the
> overall WoL configuration.
> 
> The next commit restores a set of functions that were removed from
> the driver just prior to the 4.9 kernel release.
> 
> The following commit relocates the functions in the file to prevent
> the need for additional forward declarations.
> 
> Next, support for the Rx Network Flow Classification interface of
> ethtool is added.
> 
> Finally, support for the WAKE_FILTER wol method is added.
> 
> Doug Berger (7):
>   net: bcmgenet: set Rx mode before starting netif
>   net: bcmgenet: Fix WoL with password after deep sleep
>   net: bcmgenet: move clk_wol management to bcmgenet_wol
>   Revert "net: bcmgenet: remove unused function in bcmgenet.c"
>   net: bcmgenet: code movement
>   net: bcmgenet: add support for ethtool rxnfc flows
>   net: bcmgenet: add WAKE_FILTER support
> 
>  drivers/net/ethernet/broadcom/genet/bcmgenet.c | 673 
> +++--
>  drivers/net/ethernet/broadcom/genet/bcmgenet.h |  21 +-
>  drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c |  90 ++-
>  3 files changed, 708 insertions(+), 76 deletions(-)
> 
Please holdoff on this version as there is a bug here that I'd like to
patch first.

Thanks,
Doug


[PATCH net-next v2 5/7] net: bcmgenet: code movement

2020-04-29 Thread Doug Berger
The Hardware Filter Block code will be used by ethtool functions
when defining flow types so this commit moves the functions in the
file to prevent the need for prototype declarations.

This is broken out to facilitate review.

Signed-off-by: Doug Berger 
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 308 -
 1 file changed, 154 insertions(+), 154 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index b37ef05c5083..ad41944d2cc0 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -459,6 +459,160 @@ static inline void bcmgenet_rdma_ring_writel(struct 
bcmgenet_priv *priv,
genet_dma_ring_regs[r]);
 }
 
+static bool bcmgenet_hfb_is_filter_enabled(struct bcmgenet_priv *priv,
+  u32 f_index)
+{
+   u32 offset;
+   u32 reg;
+
+   offset = HFB_FLT_ENABLE_V3PLUS + (f_index < 32) * sizeof(u32);
+   reg = bcmgenet_hfb_reg_readl(priv, offset);
+   return !!(reg & (1 << (f_index % 32)));
+}
+
+static void bcmgenet_hfb_enable_filter(struct bcmgenet_priv *priv, u32 f_index)
+{
+   u32 offset;
+   u32 reg;
+
+   offset = HFB_FLT_ENABLE_V3PLUS + (f_index < 32) * sizeof(u32);
+   reg = bcmgenet_hfb_reg_readl(priv, offset);
+   reg |= (1 << (f_index % 32));
+   bcmgenet_hfb_reg_writel(priv, reg, offset);
+}
+
+static void bcmgenet_hfb_set_filter_rx_queue_mapping(struct bcmgenet_priv 
*priv,
+u32 f_index, u32 rx_queue)
+{
+   u32 offset;
+   u32 reg;
+
+   offset = f_index / 8;
+   reg = bcmgenet_rdma_readl(priv, DMA_INDEX2RING_0 + offset);
+   reg &= ~(0xF << (4 * (f_index % 8)));
+   reg |= ((rx_queue & 0xF) << (4 * (f_index % 8)));
+   bcmgenet_rdma_writel(priv, reg, DMA_INDEX2RING_0 + offset);
+}
+
+static void bcmgenet_hfb_set_filter_length(struct bcmgenet_priv *priv,
+  u32 f_index, u32 f_length)
+{
+   u32 offset;
+   u32 reg;
+
+   offset = HFB_FLT_LEN_V3PLUS +
+((priv->hw_params->hfb_filter_cnt - 1 - f_index) / 4) *
+sizeof(u32);
+   reg = bcmgenet_hfb_reg_readl(priv, offset);
+   reg &= ~(0xFF << (8 * (f_index % 4)));
+   reg |= ((f_length & 0xFF) << (8 * (f_index % 4)));
+   bcmgenet_hfb_reg_writel(priv, reg, offset);
+}
+
+static int bcmgenet_hfb_find_unused_filter(struct bcmgenet_priv *priv)
+{
+   u32 f_index;
+
+   for (f_index = 0; f_index < priv->hw_params->hfb_filter_cnt; f_index++)
+   if (!bcmgenet_hfb_is_filter_enabled(priv, f_index))
+   return f_index;
+
+   return -ENOMEM;
+}
+
+/* bcmgenet_hfb_add_filter
+ *
+ * Add new filter to Hardware Filter Block to match and direct Rx traffic to
+ * desired Rx queue.
+ *
+ * f_data is an array of unsigned 32-bit integers where each 32-bit integer
+ * provides filter data for 2 bytes (4 nibbles) of Rx frame:
+ *
+ * bits 31:20 - unused
+ * bit  19- nibble 0 match enable
+ * bit  18- nibble 1 match enable
+ * bit  17- nibble 2 match enable
+ * bit  16- nibble 3 match enable
+ * bits 15:12 - nibble 0 data
+ * bits 11:8  - nibble 1 data
+ * bits 7:4   - nibble 2 data
+ * bits 3:0   - nibble 3 data
+ *
+ * Example:
+ * In order to match:
+ * - Ethernet frame type = 0x0800 (IP)
+ * - IP version field = 4
+ * - IP protocol field = 0x11 (UDP)
+ *
+ * The following filter is needed:
+ * u32 hfb_filter_ipv4_udp[] = {
+ *   Rx frame offset 0x00: 0x, 0x, 0x, 0x,
+ *   Rx frame offset 0x08: 0x, 0x, 0x000F0800, 0x00084000,
+ *   Rx frame offset 0x10: 0x, 0x, 0x, 0x00030011,
+ * };
+ *
+ * To add the filter to HFB and direct the traffic to Rx queue 0, call:
+ * bcmgenet_hfb_add_filter(priv, hfb_filter_ipv4_udp,
+ * ARRAY_SIZE(hfb_filter_ipv4_udp), 0);
+ */
+int bcmgenet_hfb_add_filter(struct bcmgenet_priv *priv, u32 *f_data,
+   u32 f_length, u32 rx_queue)
+{
+   int f_index;
+   u32 i;
+
+   f_index = bcmgenet_hfb_find_unused_filter(priv);
+   if (f_index < 0)
+   return -ENOMEM;
+
+   if (f_length > priv->hw_params->hfb_filter_size)
+   return -EINVAL;
+
+   for (i = 0; i < f_length; i++)
+   bcmgenet_hfb_writel(priv, f_data[i],
+   (f_index * priv->hw_params->hfb_filter_size + i) *
+   sizeof(u32));
+
+   bcmgenet_hfb_set_filter_length(priv, f_index, 2 * f_length);
+   bcmgenet_hfb_set_filter_rx_queue_mapping(priv, f_index, rx_queue);
+   bcmgenet_hfb_enable_filter(priv, f_index);
+   bcmgenet_hfb_reg_writel(priv, 0x1, HFB_CTRL);
+

[PATCH net-next v2 6/7] net: bcmgenet: add support for ethtool rxnfc flows

2020-04-29 Thread Doug Berger
This commit enables driver support for ethtool commands of this form:
ethtool -N|-U|--config-nfc|--config-ntuple devname
flow-type ether|ip4
[src xx:yy:zz:aa:bb:cc [m xx:yy:zz:aa:bb:cc]]
[dst xx:yy:zz:aa:bb:cc [m xx:yy:zz:aa:bb:cc]] [proto N [m N]]
[src-ip x.x.x.x [m x.x.x.x]] [dst-ip x.x.x.x [m x.x.x.x]] [tos N [m N]]
[l4proto N [m N]] [src-port N [m N]] [dst-port N [m N]] [spi N [m N]]
[l4data N [m N]] [vlan-etype N [m N]] [vlan N [m N]]
[dst-mac xx:yy:zz:aa:bb:cc [m xx:yy:zz:aa:bb:cc]] [action 0] [loc N] |
delete N

Since there is only one Rx Ring in this implementation action 0 behaves no
differently from not specifying a rule.

The rules can be seen with ethtool commands of this form:
ethtool -n|-u|--show-nfc|--show-ntuple devname [rule N]

Signed-off-by: Doug Berger 
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 483 -
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |  16 +
 2 files changed, 488 insertions(+), 11 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index ad41944d2cc0..5ef1ea7e5312 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -479,6 +479,30 @@ static void bcmgenet_hfb_enable_filter(struct 
bcmgenet_priv *priv, u32 f_index)
reg = bcmgenet_hfb_reg_readl(priv, offset);
reg |= (1 << (f_index % 32));
bcmgenet_hfb_reg_writel(priv, reg, offset);
+   reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL);
+   reg |= RBUF_HFB_EN;
+   bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL);
+}
+
+static void bcmgenet_hfb_disable_filter(struct bcmgenet_priv *priv, u32 
f_index)
+{
+   u32 offset, reg, reg1;
+
+   offset = HFB_FLT_ENABLE_V3PLUS;
+   reg = bcmgenet_hfb_reg_readl(priv, offset);
+   reg1 = bcmgenet_hfb_reg_readl(priv, offset + sizeof(u32));
+   if  (f_index < 32) {
+   reg1 &= ~(1 << (f_index % 32));
+   bcmgenet_hfb_reg_writel(priv, reg1, offset + sizeof(u32));
+   } else {
+   reg &= ~(1 << (f_index % 32));
+   bcmgenet_hfb_reg_writel(priv, reg, offset);
+   }
+   if (!reg && !reg1) {
+   reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL);
+   reg &= ~RBUF_HFB_EN;
+   bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL);
+   }
 }
 
 static void bcmgenet_hfb_set_filter_rx_queue_mapping(struct bcmgenet_priv 
*priv,
@@ -513,13 +537,213 @@ static int bcmgenet_hfb_find_unused_filter(struct 
bcmgenet_priv *priv)
 {
u32 f_index;
 
-   for (f_index = 0; f_index < priv->hw_params->hfb_filter_cnt; f_index++)
+   /* First MAX_NUM_OF_FS_RULES are reserved for Rx NFC filters */
+   for (f_index = MAX_NUM_OF_FS_RULES;
+f_index < priv->hw_params->hfb_filter_cnt; f_index++)
if (!bcmgenet_hfb_is_filter_enabled(priv, f_index))
return f_index;
 
return -ENOMEM;
 }
 
+static int bcmgenet_hfb_validate_mask(void *mask, size_t size)
+{
+   while (size) {
+   switch (*(unsigned char *)mask++) {
+   case 0x00:
+   case 0x0f:
+   case 0xf0:
+   case 0xff:
+   size--;
+   continue;
+   default:
+   return -EINVAL;
+   }
+   }
+
+   return 0;
+}
+
+#define VALIDATE_MASK(x) \
+   bcmgenet_hfb_validate_mask(&(x), sizeof(x))
+
+static int bcmgenet_hfb_insert_data(u32 *f, int offset,
+   void *val, void *mask, size_t size)
+{
+   int index;
+   u32 tmp;
+
+   index = offset / 2;
+   tmp = f[index];
+
+   while (size--) {
+   if (offset++ & 1) {
+   tmp &= ~0x300FF;
+   tmp |= (*(unsigned char *)val++);
+   switch ((*(unsigned char *)mask++)) {
+   case 0xFF:
+   tmp |= 0x3;
+   break;
+   case 0xF0:
+   tmp |= 0x2;
+   break;
+   case 0x0F:
+   tmp |= 0x1;
+   break;
+   }
+   f[index++] = tmp;
+   if (size)
+   tmp = f[index];
+   } else {
+   tmp &= ~0xCFF00;
+   tmp |= (*(unsigned char *)val++) << 8;
+   switch ((*(unsigned char *)mask++)) {
+   case 0xFF:
+   tmp |= 0xC;
+   break;
+   case 0xF0:
+   tmp |= 

[PATCH net-next v2 7/7] net: bcmgenet: add WAKE_FILTER support

2020-04-29 Thread Doug Berger
This commit enables support for the WAKE_FILTER method of Wake on
LAN for the GENET driver. The method can be enabled by adding 'f'
to the interface 'wol' setting specified by ethtool.

Rx network flow rules can be specified using ethtool. Rules that
define a flow-type with the RX_CLS_FLOW_WAKE action (i.e. -2) can
wake the system from the 'standby' power state when the WAKE_FILTER
WoL method is enabled.

Signed-off-by: Doug Berger 
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c |  5 ++-
 drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c | 43 +-
 2 files changed, 37 insertions(+), 11 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 5ef1ea7e5312..ad614d7201bd 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -724,7 +724,7 @@ static int bcmgenet_hfb_create_rxnfc_filter(struct 
bcmgenet_priv *priv,
break;
}
 
-   if (!fs->ring_cookie) {
+   if (!fs->ring_cookie || fs->ring_cookie == RX_CLS_FLOW_WAKE) {
/* Ring 0 flows can be handled by the default Descriptor Ring
 * We'll map them to ring 0, but don't enable the filter
 */
@@ -1499,7 +1499,8 @@ static int bcmgenet_insert_flow(struct net_device *dev,
return -EINVAL;
}
 
-   if (cmd->fs.ring_cookie > priv->hw_params->rx_queues) {
+   if (cmd->fs.ring_cookie > priv->hw_params->rx_queues &&
+   cmd->fs.ring_cookie != RX_CLS_FLOW_WAKE) {
netdev_err(dev, "rxnfc: Unsupported action (%llu)\n",
   cmd->fs.ring_cookie);
return -EINVAL;
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
index da45a4645b94..4b9d65f392c2 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
@@ -42,7 +42,7 @@ void bcmgenet_get_wol(struct net_device *dev, struct 
ethtool_wolinfo *wol)
 {
struct bcmgenet_priv *priv = netdev_priv(dev);
 
-   wol->supported = WAKE_MAGIC | WAKE_MAGICSECURE;
+   wol->supported = WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_FILTER;
wol->wolopts = priv->wolopts;
memset(wol->sopass, 0, sizeof(wol->sopass));
 
@@ -61,7 +61,7 @@ int bcmgenet_set_wol(struct net_device *dev, struct 
ethtool_wolinfo *wol)
if (!device_can_wakeup(kdev))
return -ENOTSUPP;
 
-   if (wol->wolopts & ~(WAKE_MAGIC | WAKE_MAGICSECURE))
+   if (wol->wolopts & ~(WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_FILTER))
return -EINVAL;
 
if (wol->wolopts & WAKE_MAGICSECURE)
@@ -117,8 +117,9 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
enum bcmgenet_power_mode mode)
 {
struct net_device *dev = priv->dev;
+   struct bcmgenet_rxnfc_rule *rule;
+   u32 reg, hfb_ctrl_reg, hfb_enable = 0;
int retries = 0;
-   u32 reg;
 
if (mode != GENET_POWER_WOL_MAGIC) {
netif_err(priv, wol, dev, "unsupported mode: %d\n", mode);
@@ -135,13 +136,24 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv 
*priv,
bcmgenet_umac_writel(priv, reg, UMAC_CMD);
mdelay(10);
 
-   reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
-   reg |= MPD_EN;
-   if (priv->wolopts & WAKE_MAGICSECURE) {
-   bcmgenet_set_mpd_password(priv);
-   reg |= MPD_PW_EN;
+   if (priv->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE)) {
+   reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
+   reg |= MPD_EN;
+   if (priv->wolopts & WAKE_MAGICSECURE) {
+   bcmgenet_set_mpd_password(priv);
+   reg |= MPD_PW_EN;
+   }
+   bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
+   }
+
+   hfb_ctrl_reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL);
+   if (priv->wolopts & WAKE_FILTER) {
+   list_for_each_entry(rule, >rxnfc_list, list)
+   if (rule->fs.ring_cookie == RX_CLS_FLOW_WAKE)
+   hfb_enable |= (1 << rule->fs.location);
+   reg = (hfb_ctrl_reg & ~RBUF_HFB_EN) | RBUF_ACPI_EN;
+   bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL);
}
-   bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
 
/* Do not leave UniMAC in MPD mode only */
retries = bcmgenet_poll_wol_status(priv);
@@ -149,6 +161,7 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
reg &= ~(MPD_EN | MPD_PW_EN);
bcmgenet_umac_writel(priv, 

[PATCH net-next v2 4/7] Revert "net: bcmgenet: remove unused function in bcmgenet.c"

2020-04-29 Thread Doug Berger
This reverts commit e2072600a24161b7ddcfb26814f69f5fbc8ef85a.

This commit restores the previous implementation of Hardware Filter
Block functions to the file for use in subsequent commits.

Signed-off-by: Doug Berger 
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 122 +
 1 file changed, 122 insertions(+)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 57b8608feae1..b37ef05c5083 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -2759,6 +2759,128 @@ static void bcmgenet_enable_dma(struct bcmgenet_priv 
*priv, u32 dma_ctrl)
bcmgenet_tdma_writel(priv, reg, DMA_CTRL);
 }
 
+static bool bcmgenet_hfb_is_filter_enabled(struct bcmgenet_priv *priv,
+  u32 f_index)
+{
+   u32 offset;
+   u32 reg;
+
+   offset = HFB_FLT_ENABLE_V3PLUS + (f_index < 32) * sizeof(u32);
+   reg = bcmgenet_hfb_reg_readl(priv, offset);
+   return !!(reg & (1 << (f_index % 32)));
+}
+
+static void bcmgenet_hfb_enable_filter(struct bcmgenet_priv *priv, u32 f_index)
+{
+   u32 offset;
+   u32 reg;
+
+   offset = HFB_FLT_ENABLE_V3PLUS + (f_index < 32) * sizeof(u32);
+   reg = bcmgenet_hfb_reg_readl(priv, offset);
+   reg |= (1 << (f_index % 32));
+   bcmgenet_hfb_reg_writel(priv, reg, offset);
+}
+
+static void bcmgenet_hfb_set_filter_rx_queue_mapping(struct bcmgenet_priv 
*priv,
+u32 f_index, u32 rx_queue)
+{
+   u32 offset;
+   u32 reg;
+
+   offset = f_index / 8;
+   reg = bcmgenet_rdma_readl(priv, DMA_INDEX2RING_0 + offset);
+   reg &= ~(0xF << (4 * (f_index % 8)));
+   reg |= ((rx_queue & 0xF) << (4 * (f_index % 8)));
+   bcmgenet_rdma_writel(priv, reg, DMA_INDEX2RING_0 + offset);
+}
+
+static void bcmgenet_hfb_set_filter_length(struct bcmgenet_priv *priv,
+  u32 f_index, u32 f_length)
+{
+   u32 offset;
+   u32 reg;
+
+   offset = HFB_FLT_LEN_V3PLUS +
+((priv->hw_params->hfb_filter_cnt - 1 - f_index) / 4) *
+sizeof(u32);
+   reg = bcmgenet_hfb_reg_readl(priv, offset);
+   reg &= ~(0xFF << (8 * (f_index % 4)));
+   reg |= ((f_length & 0xFF) << (8 * (f_index % 4)));
+   bcmgenet_hfb_reg_writel(priv, reg, offset);
+}
+
+static int bcmgenet_hfb_find_unused_filter(struct bcmgenet_priv *priv)
+{
+   u32 f_index;
+
+   for (f_index = 0; f_index < priv->hw_params->hfb_filter_cnt; f_index++)
+   if (!bcmgenet_hfb_is_filter_enabled(priv, f_index))
+   return f_index;
+
+   return -ENOMEM;
+}
+
+/* bcmgenet_hfb_add_filter
+ *
+ * Add new filter to Hardware Filter Block to match and direct Rx traffic to
+ * desired Rx queue.
+ *
+ * f_data is an array of unsigned 32-bit integers where each 32-bit integer
+ * provides filter data for 2 bytes (4 nibbles) of Rx frame:
+ *
+ * bits 31:20 - unused
+ * bit  19- nibble 0 match enable
+ * bit  18- nibble 1 match enable
+ * bit  17- nibble 2 match enable
+ * bit  16- nibble 3 match enable
+ * bits 15:12 - nibble 0 data
+ * bits 11:8  - nibble 1 data
+ * bits 7:4   - nibble 2 data
+ * bits 3:0   - nibble 3 data
+ *
+ * Example:
+ * In order to match:
+ * - Ethernet frame type = 0x0800 (IP)
+ * - IP version field = 4
+ * - IP protocol field = 0x11 (UDP)
+ *
+ * The following filter is needed:
+ * u32 hfb_filter_ipv4_udp[] = {
+ *   Rx frame offset 0x00: 0x, 0x, 0x, 0x,
+ *   Rx frame offset 0x08: 0x, 0x, 0x000F0800, 0x00084000,
+ *   Rx frame offset 0x10: 0x, 0x, 0x, 0x00030011,
+ * };
+ *
+ * To add the filter to HFB and direct the traffic to Rx queue 0, call:
+ * bcmgenet_hfb_add_filter(priv, hfb_filter_ipv4_udp,
+ * ARRAY_SIZE(hfb_filter_ipv4_udp), 0);
+ */
+int bcmgenet_hfb_add_filter(struct bcmgenet_priv *priv, u32 *f_data,
+   u32 f_length, u32 rx_queue)
+{
+   int f_index;
+   u32 i;
+
+   f_index = bcmgenet_hfb_find_unused_filter(priv);
+   if (f_index < 0)
+   return -ENOMEM;
+
+   if (f_length > priv->hw_params->hfb_filter_size)
+   return -EINVAL;
+
+   for (i = 0; i < f_length; i++)
+   bcmgenet_hfb_writel(priv, f_data[i],
+   (f_index * priv->hw_params->hfb_filter_size + i) *
+   sizeof(u32));
+
+   bcmgenet_hfb_set_filter_length(priv, f_index, 2 * f_length);
+   bcmgenet_hfb_set_filter_rx_queue_mapping(priv, f_index, rx_queue);
+   bcmgenet_hfb_enable_filter(priv, f_index);
+   bcmgenet_hfb_reg_writel(priv, 0x1, HFB_CTRL);
+
+   return 0;
+}
+
 /* bcmgenet_hfb_clear
  *
  * Clear Hardware Filter Block and disable all filtering.
-- 
2.7.4



[PATCH net-next v2 2/7] net: bcmgenet: Fix WoL with password after deep sleep

2020-04-29 Thread Doug Berger
Broadcom STB chips support a deep sleep mode where all register contents
are lost. Because we were stashing the MagicPacket password into some of
these registers a suspend into that deep sleep then a resumption would
not lead to being able to wake-up from MagicPacket with password again.

Fix this by keeping a software copy of the password and program it
during suspend.

Fixes: c51de7f3976b ("net: bcmgenet: add Wake-on-LAN support code")
Suggested-by: Florian Fainelli 
Signed-off-by: Doug Berger 
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |  2 ++
 drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c | 39 ++
 2 files changed, 20 insertions(+), 21 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
index daf8fb2c39b6..c3bfe97f2e5c 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
@@ -14,6 +14,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* total number of Buffer Descriptors, same for Rx/Tx */
 #define TOTAL_DESC 256
@@ -676,6 +677,7 @@ struct bcmgenet_priv {
/* WOL */
struct clk *clk_wol;
u32 wolopts;
+   u8 sopass[SOPASS_MAX];
 
struct bcmgenet_mib_counters mib;
 
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
index c9a43695b182..597c0498689a 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
@@ -41,18 +41,13 @@
 void bcmgenet_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
struct bcmgenet_priv *priv = netdev_priv(dev);
-   u32 reg;
 
wol->supported = WAKE_MAGIC | WAKE_MAGICSECURE;
wol->wolopts = priv->wolopts;
memset(wol->sopass, 0, sizeof(wol->sopass));
 
-   if (wol->wolopts & WAKE_MAGICSECURE) {
-   reg = bcmgenet_umac_readl(priv, UMAC_MPD_PW_MS);
-   put_unaligned_be16(reg, >sopass[0]);
-   reg = bcmgenet_umac_readl(priv, UMAC_MPD_PW_LS);
-   put_unaligned_be32(reg, >sopass[2]);
-   }
+   if (wol->wolopts & WAKE_MAGICSECURE)
+   memcpy(wol->sopass, priv->sopass, sizeof(priv->sopass));
 }
 
 /* ethtool function - set WOL (Wake on LAN) settings.
@@ -62,7 +57,6 @@ int bcmgenet_set_wol(struct net_device *dev, struct 
ethtool_wolinfo *wol)
 {
struct bcmgenet_priv *priv = netdev_priv(dev);
struct device *kdev = >pdev->dev;
-   u32 reg;
 
if (!device_can_wakeup(kdev))
return -ENOTSUPP;
@@ -70,17 +64,8 @@ int bcmgenet_set_wol(struct net_device *dev, struct 
ethtool_wolinfo *wol)
if (wol->wolopts & ~(WAKE_MAGIC | WAKE_MAGICSECURE))
return -EINVAL;
 
-   reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
-   if (wol->wolopts & WAKE_MAGICSECURE) {
-   bcmgenet_umac_writel(priv, get_unaligned_be16(>sopass[0]),
-UMAC_MPD_PW_MS);
-   bcmgenet_umac_writel(priv, get_unaligned_be32(>sopass[2]),
-UMAC_MPD_PW_LS);
-   reg |= MPD_PW_EN;
-   } else {
-   reg &= ~MPD_PW_EN;
-   }
-   bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
+   if (wol->wolopts & WAKE_MAGICSECURE)
+   memcpy(priv->sopass, wol->sopass, sizeof(priv->sopass));
 
/* Flag the device and relevant IRQ as wakeup capable */
if (wol->wolopts) {
@@ -120,6 +105,14 @@ static int bcmgenet_poll_wol_status(struct bcmgenet_priv 
*priv)
return retries;
 }
 
+static void bcmgenet_set_mpd_password(struct bcmgenet_priv *priv)
+{
+   bcmgenet_umac_writel(priv, get_unaligned_be16(>sopass[0]),
+UMAC_MPD_PW_MS);
+   bcmgenet_umac_writel(priv, get_unaligned_be32(>sopass[2]),
+UMAC_MPD_PW_LS);
+}
+
 int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
enum bcmgenet_power_mode mode)
 {
@@ -144,13 +137,17 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv 
*priv,
 
reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
reg |= MPD_EN;
+   if (priv->wolopts & WAKE_MAGICSECURE) {
+   bcmgenet_set_mpd_password(priv);
+   reg |= MPD_PW_EN;
+   }
bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
 
/* Do not leave UniMAC in MPD mode only */
retries = bcmgenet_poll_wol_status(priv);
if (retries < 0) {
reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
-   reg &= ~MPD_EN;
+   reg &= ~(MPD_EN | MPD_PW_EN);
bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
return retries;
}
@@ -1

[PATCH net-next v2 3/7] net: bcmgenet: move clk_wol management to bcmgenet_wol

2020-04-29 Thread Doug Berger
The GENET_POWER_WOL_MAGIC power up and power down code configures
the device for WoL when suspending and disables the WoL logic when
resuming. It makes sense that this code should also manage the WoL
clocking.

This commit consolidates the logic and moves it earlier in the
resume sequence.

Since the clock is now only enabled if WoL is successfully entered
the wol_active flag is introduced to track that state to keep the
clock enables and disables balanced in case a suspend is aborted.
The MPD_EN hardware bit can't be used because it can be cleared
when the MAC is reset by a deep sleep.

Signed-off-by: Doug Berger 
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 19 +++
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |  3 ++-
 drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c | 14 +++---
 3 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index eb0dd4d4800c..57b8608feae1 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -2,7 +2,7 @@
 /*
  * Broadcom GENET (Gigabit Ethernet) controller driver
  *
- * Copyright (c) 2014-2019 Broadcom
+ * Copyright (c) 2014-2020 Broadcom
  */
 
 #define pr_fmt(fmt)"bcmgenet: " fmt
@@ -3619,6 +3619,10 @@ static int bcmgenet_resume(struct device *d)
if (ret)
return ret;
 
+   /* From WOL-enabled suspend, switch to regular clock */
+   if (device_may_wakeup(d) && priv->wolopts)
+   bcmgenet_power_up(priv, GENET_POWER_WOL_MAGIC);
+
/* If this is an internal GPHY, power it back on now, before UniMAC is
 * brought out of reset as absolutely no UniMAC activity is allowed
 */
@@ -3629,10 +3633,6 @@ static int bcmgenet_resume(struct device *d)
 
init_umac(priv);
 
-   /* From WOL-enabled suspend, switch to regular clock */
-   if (priv->wolopts)
-   clk_disable_unprepare(priv->clk_wol);
-
phy_init_hw(dev->phydev);
 
/* Speed settings must be restored */
@@ -3650,9 +3650,6 @@ static int bcmgenet_resume(struct device *d)
bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
}
 
-   if (priv->wolopts)
-   bcmgenet_power_up(priv, GENET_POWER_WOL_MAGIC);
-
/* Disable RX/TX DMA and flush TX queues */
dma_ctrl = bcmgenet_dma_disable(priv);
 
@@ -3702,12 +3699,10 @@ static int bcmgenet_suspend(struct device *d)
phy_suspend(dev->phydev);
 
/* Prepare the device for Wake-on-LAN and switch to the slow clock */
-   if (device_may_wakeup(d) && priv->wolopts) {
+   if (device_may_wakeup(d) && priv->wolopts)
ret = bcmgenet_power_down(priv, GENET_POWER_WOL_MAGIC);
-   clk_prepare_enable(priv->clk_wol);
-   } else if (priv->internal_phy) {
+   else if (priv->internal_phy)
ret = bcmgenet_power_down(priv, GENET_POWER_PASSIVE);
-   }
 
/* Turn off the clocks */
clk_disable_unprepare(priv->clk);
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
index c3bfe97f2e5c..a858b7305832 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2014-2017 Broadcom
+ * Copyright (c) 2014-2020 Broadcom
  */
 
 #ifndef __BCMGENET_H__
@@ -678,6 +678,7 @@ struct bcmgenet_priv {
struct clk *clk_wol;
u32 wolopts;
u8 sopass[SOPASS_MAX];
+   bool wol_active;
 
struct bcmgenet_mib_counters mib;
 
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
index 597c0498689a..da45a4645b94 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
@@ -2,7 +2,7 @@
 /*
  * Broadcom GENET (Gigabit Ethernet) Wake-on-LAN support
  *
- * Copyright (c) 2014-2017 Broadcom
+ * Copyright (c) 2014-2020 Broadcom
  */
 
 #define pr_fmt(fmt)"bcmgenet_wol: " fmt
@@ -155,6 +155,9 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
netif_dbg(priv, wol, dev, "MPD WOL-ready status set after %d msec\n",
  retries);
 
+   clk_prepare_enable(priv->clk_wol);
+   priv->wol_active = 1;
+
/* Enable CRC forward */
reg = bcmgenet_umac_readl(priv, UMAC_CMD);
priv->crc_fwd_en = 1;
@@ -183,9 +186,14 @@ void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
return;
}
 
+   if (!priv->wol_active)
+   return; /* failed to suspend so skip the rest */
+
+   priv->

[PATCH net-next v2 1/7] net: bcmgenet: set Rx mode before starting netif

2020-04-29 Thread Doug Berger
This commit explicitly calls the bcmgenet_set_rx_mode() function when
the network interface is started. This function is normally called by
ndo_set_rx_mode when the flags are changed, but apparently not when
the driver is suspended and resumed.

This change ensures that address filtering or promiscuous mode are
properly restored by the driver after the MAC may have been reset.

Fixes: b6e978e50444 ("net: bcmgenet: add suspend/resume callbacks")
Signed-off-by: Doug Berger 
---
 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 351d0282f199..eb0dd4d4800c 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -65,6 +65,9 @@
 #define GENET_RDMA_REG_OFF (priv->hw_params->rdma_offset + \
TOTAL_DESC * DMA_DESC_SIZE)
 
+/* Forward declarations */
+static void bcmgenet_set_rx_mode(struct net_device *dev);
+
 static inline void bcmgenet_writel(u32 value, void __iomem *offset)
 {
/* MIPS chips strapped for BE will automagically configure the
@@ -2793,6 +2796,7 @@ static void bcmgenet_netif_start(struct net_device *dev)
struct bcmgenet_priv *priv = netdev_priv(dev);
 
/* Start the network engine */
+   bcmgenet_set_rx_mode(dev);
bcmgenet_enable_rx_napi(priv);
 
umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, true);
-- 
2.7.4



[PATCH net-next v2 0/7] net: bcmgenet: add support for Wake on Filter

2020-04-29 Thread Doug Berger


Changes in v2:
Corrected Signed-off-by for commit 3/7.

This commit set adds support for waking from 'standby' using a
Rx Network Flow Classification filter specified with ethtool.

The first two commits are bug fixes that should be applied to the
stable branches, but are included in this patch set to reduce merge
conflicts that might occur if not applied before the other commits
in this set.

The next commit consolidates WoL clock managment as a part of the
overall WoL configuration.

The next commit restores a set of functions that were removed from
the driver just prior to the 4.9 kernel release.

The following commit relocates the functions in the file to prevent
the need for additional forward declarations.

Next, support for the Rx Network Flow Classification interface of
ethtool is added.

Finally, support for the WAKE_FILTER wol method is added.

Doug Berger (7):
  net: bcmgenet: set Rx mode before starting netif
  net: bcmgenet: Fix WoL with password after deep sleep
  net: bcmgenet: move clk_wol management to bcmgenet_wol
  Revert "net: bcmgenet: remove unused function in bcmgenet.c"
  net: bcmgenet: code movement
  net: bcmgenet: add support for ethtool rxnfc flows
  net: bcmgenet: add WAKE_FILTER support

 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 673 +++--
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |  21 +-
 drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c |  90 ++-
 3 files changed, 708 insertions(+), 76 deletions(-)

-- 
2.7.4



[PATCH net-next 3/7] net: bcmgenet: move clk_wol management to bcmgenet_wol

2020-04-29 Thread Doug Berger
From: Doug Berger 

The GENET_POWER_WOL_MAGIC power up and power down code configures
the device for WoL when suspending and disables the WoL logic when
resuming. It makes sense that this code should also manage the WoL
clocking.

This commit consolidates the logic and moves it earlier in the
resume sequence.

Since the clock is now only enabled if WoL is successfully entered
the wol_active flag is introduced to track that state to keep the
clock enables and disables balanced in case a suspend is aborted.
The MPD_EN hardware bit can't be used because it can be cleared
when the MAC is reset by a deep sleep.
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 19 +++
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |  3 ++-
 drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c | 14 +++---
 3 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index eb0dd4d4800c..57b8608feae1 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -2,7 +2,7 @@
 /*
  * Broadcom GENET (Gigabit Ethernet) controller driver
  *
- * Copyright (c) 2014-2019 Broadcom
+ * Copyright (c) 2014-2020 Broadcom
  */
 
 #define pr_fmt(fmt)"bcmgenet: " fmt
@@ -3619,6 +3619,10 @@ static int bcmgenet_resume(struct device *d)
if (ret)
return ret;
 
+   /* From WOL-enabled suspend, switch to regular clock */
+   if (device_may_wakeup(d) && priv->wolopts)
+   bcmgenet_power_up(priv, GENET_POWER_WOL_MAGIC);
+
/* If this is an internal GPHY, power it back on now, before UniMAC is
 * brought out of reset as absolutely no UniMAC activity is allowed
 */
@@ -3629,10 +3633,6 @@ static int bcmgenet_resume(struct device *d)
 
init_umac(priv);
 
-   /* From WOL-enabled suspend, switch to regular clock */
-   if (priv->wolopts)
-   clk_disable_unprepare(priv->clk_wol);
-
phy_init_hw(dev->phydev);
 
/* Speed settings must be restored */
@@ -3650,9 +3650,6 @@ static int bcmgenet_resume(struct device *d)
bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
}
 
-   if (priv->wolopts)
-   bcmgenet_power_up(priv, GENET_POWER_WOL_MAGIC);
-
/* Disable RX/TX DMA and flush TX queues */
dma_ctrl = bcmgenet_dma_disable(priv);
 
@@ -3702,12 +3699,10 @@ static int bcmgenet_suspend(struct device *d)
phy_suspend(dev->phydev);
 
/* Prepare the device for Wake-on-LAN and switch to the slow clock */
-   if (device_may_wakeup(d) && priv->wolopts) {
+   if (device_may_wakeup(d) && priv->wolopts)
ret = bcmgenet_power_down(priv, GENET_POWER_WOL_MAGIC);
-   clk_prepare_enable(priv->clk_wol);
-   } else if (priv->internal_phy) {
+   else if (priv->internal_phy)
ret = bcmgenet_power_down(priv, GENET_POWER_PASSIVE);
-   }
 
/* Turn off the clocks */
clk_disable_unprepare(priv->clk);
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
index c3bfe97f2e5c..a858b7305832 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2014-2017 Broadcom
+ * Copyright (c) 2014-2020 Broadcom
  */
 
 #ifndef __BCMGENET_H__
@@ -678,6 +678,7 @@ struct bcmgenet_priv {
struct clk *clk_wol;
u32 wolopts;
u8 sopass[SOPASS_MAX];
+   bool wol_active;
 
struct bcmgenet_mib_counters mib;
 
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
index 597c0498689a..da45a4645b94 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
@@ -2,7 +2,7 @@
 /*
  * Broadcom GENET (Gigabit Ethernet) Wake-on-LAN support
  *
- * Copyright (c) 2014-2017 Broadcom
+ * Copyright (c) 2014-2020 Broadcom
  */
 
 #define pr_fmt(fmt)"bcmgenet_wol: " fmt
@@ -155,6 +155,9 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
netif_dbg(priv, wol, dev, "MPD WOL-ready status set after %d msec\n",
  retries);
 
+   clk_prepare_enable(priv->clk_wol);
+   priv->wol_active = 1;
+
/* Enable CRC forward */
reg = bcmgenet_umac_readl(priv, UMAC_CMD);
priv->crc_fwd_en = 1;
@@ -183,9 +186,14 @@ void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
return;
}
 
+   if (!priv->wol_active)
+   return; /* failed to suspend so skip the rest */
+
+   priv->wol_active = 0;

[PATCH net-next 2/7] net: bcmgenet: Fix WoL with password after deep sleep

2020-04-29 Thread Doug Berger
Broadcom STB chips support a deep sleep mode where all register contents
are lost. Because we were stashing the MagicPacket password into some of
these registers a suspend into that deep sleep then a resumption would
not lead to being able to wake-up from MagicPacket with password again.

Fix this by keeping a software copy of the password and program it
during suspend.

Fixes: c51de7f3976b ("net: bcmgenet: add Wake-on-LAN support code")
Suggested-by: Florian Fainelli 
Signed-off-by: Doug Berger 
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |  2 ++
 drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c | 39 ++
 2 files changed, 20 insertions(+), 21 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
index daf8fb2c39b6..c3bfe97f2e5c 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
@@ -14,6 +14,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* total number of Buffer Descriptors, same for Rx/Tx */
 #define TOTAL_DESC 256
@@ -676,6 +677,7 @@ struct bcmgenet_priv {
/* WOL */
struct clk *clk_wol;
u32 wolopts;
+   u8 sopass[SOPASS_MAX];
 
struct bcmgenet_mib_counters mib;
 
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
index c9a43695b182..597c0498689a 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
@@ -41,18 +41,13 @@
 void bcmgenet_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
struct bcmgenet_priv *priv = netdev_priv(dev);
-   u32 reg;
 
wol->supported = WAKE_MAGIC | WAKE_MAGICSECURE;
wol->wolopts = priv->wolopts;
memset(wol->sopass, 0, sizeof(wol->sopass));
 
-   if (wol->wolopts & WAKE_MAGICSECURE) {
-   reg = bcmgenet_umac_readl(priv, UMAC_MPD_PW_MS);
-   put_unaligned_be16(reg, >sopass[0]);
-   reg = bcmgenet_umac_readl(priv, UMAC_MPD_PW_LS);
-   put_unaligned_be32(reg, >sopass[2]);
-   }
+   if (wol->wolopts & WAKE_MAGICSECURE)
+   memcpy(wol->sopass, priv->sopass, sizeof(priv->sopass));
 }
 
 /* ethtool function - set WOL (Wake on LAN) settings.
@@ -62,7 +57,6 @@ int bcmgenet_set_wol(struct net_device *dev, struct 
ethtool_wolinfo *wol)
 {
struct bcmgenet_priv *priv = netdev_priv(dev);
struct device *kdev = >pdev->dev;
-   u32 reg;
 
if (!device_can_wakeup(kdev))
return -ENOTSUPP;
@@ -70,17 +64,8 @@ int bcmgenet_set_wol(struct net_device *dev, struct 
ethtool_wolinfo *wol)
if (wol->wolopts & ~(WAKE_MAGIC | WAKE_MAGICSECURE))
return -EINVAL;
 
-   reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
-   if (wol->wolopts & WAKE_MAGICSECURE) {
-   bcmgenet_umac_writel(priv, get_unaligned_be16(>sopass[0]),
-UMAC_MPD_PW_MS);
-   bcmgenet_umac_writel(priv, get_unaligned_be32(>sopass[2]),
-UMAC_MPD_PW_LS);
-   reg |= MPD_PW_EN;
-   } else {
-   reg &= ~MPD_PW_EN;
-   }
-   bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
+   if (wol->wolopts & WAKE_MAGICSECURE)
+   memcpy(priv->sopass, wol->sopass, sizeof(priv->sopass));
 
/* Flag the device and relevant IRQ as wakeup capable */
if (wol->wolopts) {
@@ -120,6 +105,14 @@ static int bcmgenet_poll_wol_status(struct bcmgenet_priv 
*priv)
return retries;
 }
 
+static void bcmgenet_set_mpd_password(struct bcmgenet_priv *priv)
+{
+   bcmgenet_umac_writel(priv, get_unaligned_be16(>sopass[0]),
+UMAC_MPD_PW_MS);
+   bcmgenet_umac_writel(priv, get_unaligned_be32(>sopass[2]),
+UMAC_MPD_PW_LS);
+}
+
 int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
enum bcmgenet_power_mode mode)
 {
@@ -144,13 +137,17 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv 
*priv,
 
reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
reg |= MPD_EN;
+   if (priv->wolopts & WAKE_MAGICSECURE) {
+   bcmgenet_set_mpd_password(priv);
+   reg |= MPD_PW_EN;
+   }
bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
 
/* Do not leave UniMAC in MPD mode only */
retries = bcmgenet_poll_wol_status(priv);
if (retries < 0) {
reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
-   reg &= ~MPD_EN;
+   reg &= ~(MPD_EN | MPD_PW_EN);
bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
return retries;
}
@@ -1

[PATCH net-next 5/7] net: bcmgenet: code movement

2020-04-29 Thread Doug Berger
The Hardware Filter Block code will be used by ethtool functions
when defining flow types so this commit moves the functions in the
file to prevent the need for prototype declarations.

This is broken out to facilitate review.

Signed-off-by: Doug Berger 
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 308 -
 1 file changed, 154 insertions(+), 154 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index b37ef05c5083..ad41944d2cc0 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -459,6 +459,160 @@ static inline void bcmgenet_rdma_ring_writel(struct 
bcmgenet_priv *priv,
genet_dma_ring_regs[r]);
 }
 
+static bool bcmgenet_hfb_is_filter_enabled(struct bcmgenet_priv *priv,
+  u32 f_index)
+{
+   u32 offset;
+   u32 reg;
+
+   offset = HFB_FLT_ENABLE_V3PLUS + (f_index < 32) * sizeof(u32);
+   reg = bcmgenet_hfb_reg_readl(priv, offset);
+   return !!(reg & (1 << (f_index % 32)));
+}
+
+static void bcmgenet_hfb_enable_filter(struct bcmgenet_priv *priv, u32 f_index)
+{
+   u32 offset;
+   u32 reg;
+
+   offset = HFB_FLT_ENABLE_V3PLUS + (f_index < 32) * sizeof(u32);
+   reg = bcmgenet_hfb_reg_readl(priv, offset);
+   reg |= (1 << (f_index % 32));
+   bcmgenet_hfb_reg_writel(priv, reg, offset);
+}
+
+static void bcmgenet_hfb_set_filter_rx_queue_mapping(struct bcmgenet_priv 
*priv,
+u32 f_index, u32 rx_queue)
+{
+   u32 offset;
+   u32 reg;
+
+   offset = f_index / 8;
+   reg = bcmgenet_rdma_readl(priv, DMA_INDEX2RING_0 + offset);
+   reg &= ~(0xF << (4 * (f_index % 8)));
+   reg |= ((rx_queue & 0xF) << (4 * (f_index % 8)));
+   bcmgenet_rdma_writel(priv, reg, DMA_INDEX2RING_0 + offset);
+}
+
+static void bcmgenet_hfb_set_filter_length(struct bcmgenet_priv *priv,
+  u32 f_index, u32 f_length)
+{
+   u32 offset;
+   u32 reg;
+
+   offset = HFB_FLT_LEN_V3PLUS +
+((priv->hw_params->hfb_filter_cnt - 1 - f_index) / 4) *
+sizeof(u32);
+   reg = bcmgenet_hfb_reg_readl(priv, offset);
+   reg &= ~(0xFF << (8 * (f_index % 4)));
+   reg |= ((f_length & 0xFF) << (8 * (f_index % 4)));
+   bcmgenet_hfb_reg_writel(priv, reg, offset);
+}
+
+static int bcmgenet_hfb_find_unused_filter(struct bcmgenet_priv *priv)
+{
+   u32 f_index;
+
+   for (f_index = 0; f_index < priv->hw_params->hfb_filter_cnt; f_index++)
+   if (!bcmgenet_hfb_is_filter_enabled(priv, f_index))
+   return f_index;
+
+   return -ENOMEM;
+}
+
+/* bcmgenet_hfb_add_filter
+ *
+ * Add new filter to Hardware Filter Block to match and direct Rx traffic to
+ * desired Rx queue.
+ *
+ * f_data is an array of unsigned 32-bit integers where each 32-bit integer
+ * provides filter data for 2 bytes (4 nibbles) of Rx frame:
+ *
+ * bits 31:20 - unused
+ * bit  19- nibble 0 match enable
+ * bit  18- nibble 1 match enable
+ * bit  17- nibble 2 match enable
+ * bit  16- nibble 3 match enable
+ * bits 15:12 - nibble 0 data
+ * bits 11:8  - nibble 1 data
+ * bits 7:4   - nibble 2 data
+ * bits 3:0   - nibble 3 data
+ *
+ * Example:
+ * In order to match:
+ * - Ethernet frame type = 0x0800 (IP)
+ * - IP version field = 4
+ * - IP protocol field = 0x11 (UDP)
+ *
+ * The following filter is needed:
+ * u32 hfb_filter_ipv4_udp[] = {
+ *   Rx frame offset 0x00: 0x, 0x, 0x, 0x,
+ *   Rx frame offset 0x08: 0x, 0x, 0x000F0800, 0x00084000,
+ *   Rx frame offset 0x10: 0x, 0x, 0x, 0x00030011,
+ * };
+ *
+ * To add the filter to HFB and direct the traffic to Rx queue 0, call:
+ * bcmgenet_hfb_add_filter(priv, hfb_filter_ipv4_udp,
+ * ARRAY_SIZE(hfb_filter_ipv4_udp), 0);
+ */
+int bcmgenet_hfb_add_filter(struct bcmgenet_priv *priv, u32 *f_data,
+   u32 f_length, u32 rx_queue)
+{
+   int f_index;
+   u32 i;
+
+   f_index = bcmgenet_hfb_find_unused_filter(priv);
+   if (f_index < 0)
+   return -ENOMEM;
+
+   if (f_length > priv->hw_params->hfb_filter_size)
+   return -EINVAL;
+
+   for (i = 0; i < f_length; i++)
+   bcmgenet_hfb_writel(priv, f_data[i],
+   (f_index * priv->hw_params->hfb_filter_size + i) *
+   sizeof(u32));
+
+   bcmgenet_hfb_set_filter_length(priv, f_index, 2 * f_length);
+   bcmgenet_hfb_set_filter_rx_queue_mapping(priv, f_index, rx_queue);
+   bcmgenet_hfb_enable_filter(priv, f_index);
+   bcmgenet_hfb_reg_writel(priv, 0x1, HFB_CTRL);
+

[PATCH net-next 0/7] net: bcmgenet: add support for Wake on Filter

2020-04-29 Thread Doug Berger
This commit set adds support for waking from 'standby' using a
Rx Network Flow Classification filter specified with ethtool.

The first two commits are bug fixes that should be applied to the
stable branches, but are included in this patch set to reduce merge
conflicts that might occur if not applied before the other commits
in this set.

The next commit consolidates WoL clock managment as a part of the
overall WoL configuration.

The next commit restores a set of functions that were removed from
the driver just prior to the 4.9 kernel release.

The following commit relocates the functions in the file to prevent
the need for additional forward declarations.

Next, support for the Rx Network Flow Classification interface of
ethtool is added.

Finally, support for the WAKE_FILTER wol method is added.

Doug Berger (7):
  net: bcmgenet: set Rx mode before starting netif
  net: bcmgenet: Fix WoL with password after deep sleep
  net: bcmgenet: move clk_wol management to bcmgenet_wol
  Revert "net: bcmgenet: remove unused function in bcmgenet.c"
  net: bcmgenet: code movement
  net: bcmgenet: add support for ethtool rxnfc flows
  net: bcmgenet: add WAKE_FILTER support

 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 673 +++--
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |  21 +-
 drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c |  90 ++-
 3 files changed, 708 insertions(+), 76 deletions(-)

-- 
2.7.4


[PATCH net-next 4/7] Revert "net: bcmgenet: remove unused function in bcmgenet.c"

2020-04-29 Thread Doug Berger
This reverts commit e2072600a24161b7ddcfb26814f69f5fbc8ef85a.

This commit restores the previous implementation of Hardware Filter
Block functions to the file for use in subsequent commits.

Signed-off-by: Doug Berger 
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 122 +
 1 file changed, 122 insertions(+)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 57b8608feae1..b37ef05c5083 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -2759,6 +2759,128 @@ static void bcmgenet_enable_dma(struct bcmgenet_priv 
*priv, u32 dma_ctrl)
bcmgenet_tdma_writel(priv, reg, DMA_CTRL);
 }
 
+static bool bcmgenet_hfb_is_filter_enabled(struct bcmgenet_priv *priv,
+  u32 f_index)
+{
+   u32 offset;
+   u32 reg;
+
+   offset = HFB_FLT_ENABLE_V3PLUS + (f_index < 32) * sizeof(u32);
+   reg = bcmgenet_hfb_reg_readl(priv, offset);
+   return !!(reg & (1 << (f_index % 32)));
+}
+
+static void bcmgenet_hfb_enable_filter(struct bcmgenet_priv *priv, u32 f_index)
+{
+   u32 offset;
+   u32 reg;
+
+   offset = HFB_FLT_ENABLE_V3PLUS + (f_index < 32) * sizeof(u32);
+   reg = bcmgenet_hfb_reg_readl(priv, offset);
+   reg |= (1 << (f_index % 32));
+   bcmgenet_hfb_reg_writel(priv, reg, offset);
+}
+
+static void bcmgenet_hfb_set_filter_rx_queue_mapping(struct bcmgenet_priv 
*priv,
+u32 f_index, u32 rx_queue)
+{
+   u32 offset;
+   u32 reg;
+
+   offset = f_index / 8;
+   reg = bcmgenet_rdma_readl(priv, DMA_INDEX2RING_0 + offset);
+   reg &= ~(0xF << (4 * (f_index % 8)));
+   reg |= ((rx_queue & 0xF) << (4 * (f_index % 8)));
+   bcmgenet_rdma_writel(priv, reg, DMA_INDEX2RING_0 + offset);
+}
+
+static void bcmgenet_hfb_set_filter_length(struct bcmgenet_priv *priv,
+  u32 f_index, u32 f_length)
+{
+   u32 offset;
+   u32 reg;
+
+   offset = HFB_FLT_LEN_V3PLUS +
+((priv->hw_params->hfb_filter_cnt - 1 - f_index) / 4) *
+sizeof(u32);
+   reg = bcmgenet_hfb_reg_readl(priv, offset);
+   reg &= ~(0xFF << (8 * (f_index % 4)));
+   reg |= ((f_length & 0xFF) << (8 * (f_index % 4)));
+   bcmgenet_hfb_reg_writel(priv, reg, offset);
+}
+
+static int bcmgenet_hfb_find_unused_filter(struct bcmgenet_priv *priv)
+{
+   u32 f_index;
+
+   for (f_index = 0; f_index < priv->hw_params->hfb_filter_cnt; f_index++)
+   if (!bcmgenet_hfb_is_filter_enabled(priv, f_index))
+   return f_index;
+
+   return -ENOMEM;
+}
+
+/* bcmgenet_hfb_add_filter
+ *
+ * Add new filter to Hardware Filter Block to match and direct Rx traffic to
+ * desired Rx queue.
+ *
+ * f_data is an array of unsigned 32-bit integers where each 32-bit integer
+ * provides filter data for 2 bytes (4 nibbles) of Rx frame:
+ *
+ * bits 31:20 - unused
+ * bit  19- nibble 0 match enable
+ * bit  18- nibble 1 match enable
+ * bit  17- nibble 2 match enable
+ * bit  16- nibble 3 match enable
+ * bits 15:12 - nibble 0 data
+ * bits 11:8  - nibble 1 data
+ * bits 7:4   - nibble 2 data
+ * bits 3:0   - nibble 3 data
+ *
+ * Example:
+ * In order to match:
+ * - Ethernet frame type = 0x0800 (IP)
+ * - IP version field = 4
+ * - IP protocol field = 0x11 (UDP)
+ *
+ * The following filter is needed:
+ * u32 hfb_filter_ipv4_udp[] = {
+ *   Rx frame offset 0x00: 0x, 0x, 0x, 0x,
+ *   Rx frame offset 0x08: 0x, 0x, 0x000F0800, 0x00084000,
+ *   Rx frame offset 0x10: 0x, 0x, 0x, 0x00030011,
+ * };
+ *
+ * To add the filter to HFB and direct the traffic to Rx queue 0, call:
+ * bcmgenet_hfb_add_filter(priv, hfb_filter_ipv4_udp,
+ * ARRAY_SIZE(hfb_filter_ipv4_udp), 0);
+ */
+int bcmgenet_hfb_add_filter(struct bcmgenet_priv *priv, u32 *f_data,
+   u32 f_length, u32 rx_queue)
+{
+   int f_index;
+   u32 i;
+
+   f_index = bcmgenet_hfb_find_unused_filter(priv);
+   if (f_index < 0)
+   return -ENOMEM;
+
+   if (f_length > priv->hw_params->hfb_filter_size)
+   return -EINVAL;
+
+   for (i = 0; i < f_length; i++)
+   bcmgenet_hfb_writel(priv, f_data[i],
+   (f_index * priv->hw_params->hfb_filter_size + i) *
+   sizeof(u32));
+
+   bcmgenet_hfb_set_filter_length(priv, f_index, 2 * f_length);
+   bcmgenet_hfb_set_filter_rx_queue_mapping(priv, f_index, rx_queue);
+   bcmgenet_hfb_enable_filter(priv, f_index);
+   bcmgenet_hfb_reg_writel(priv, 0x1, HFB_CTRL);
+
+   return 0;
+}
+
 /* bcmgenet_hfb_clear
  *
  * Clear Hardware Filter Block and disable all filtering.
-- 
2.7.4



[PATCH net-next 1/7] net: bcmgenet: set Rx mode before starting netif

2020-04-29 Thread Doug Berger
This commit explicitly calls the bcmgenet_set_rx_mode() function when
the network interface is started. This function is normally called by
ndo_set_rx_mode when the flags are changed, but apparently not when
the driver is suspended and resumed.

This change ensures that address filtering or promiscuous mode are
properly restored by the driver after the MAC may have been reset.

Fixes: b6e978e50444 ("net: bcmgenet: add suspend/resume callbacks")
Signed-off-by: Doug Berger 
---
 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 351d0282f199..eb0dd4d4800c 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -65,6 +65,9 @@
 #define GENET_RDMA_REG_OFF (priv->hw_params->rdma_offset + \
TOTAL_DESC * DMA_DESC_SIZE)
 
+/* Forward declarations */
+static void bcmgenet_set_rx_mode(struct net_device *dev);
+
 static inline void bcmgenet_writel(u32 value, void __iomem *offset)
 {
/* MIPS chips strapped for BE will automagically configure the
@@ -2793,6 +2796,7 @@ static void bcmgenet_netif_start(struct net_device *dev)
struct bcmgenet_priv *priv = netdev_priv(dev);
 
/* Start the network engine */
+   bcmgenet_set_rx_mode(dev);
bcmgenet_enable_rx_napi(priv);
 
umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, true);
-- 
2.7.4



[PATCH net-next 6/7] net: bcmgenet: add support for ethtool rxnfc flows

2020-04-29 Thread Doug Berger
This commit enables driver support for ethtool commands of this form:
ethtool -N|-U|--config-nfc|--config-ntuple devname
flow-type ether|ip4
[src xx:yy:zz:aa:bb:cc [m xx:yy:zz:aa:bb:cc]]
[dst xx:yy:zz:aa:bb:cc [m xx:yy:zz:aa:bb:cc]] [proto N [m N]]
[src-ip x.x.x.x [m x.x.x.x]] [dst-ip x.x.x.x [m x.x.x.x]] [tos N [m N]]
[l4proto N [m N]] [src-port N [m N]] [dst-port N [m N]] [spi N [m N]]
[l4data N [m N]] [vlan-etype N [m N]] [vlan N [m N]]
[dst-mac xx:yy:zz:aa:bb:cc [m xx:yy:zz:aa:bb:cc]] [action 0] [loc N] |
delete N

Since there is only one Rx Ring in this implementation action 0 behaves no
differently from not specifying a rule.

The rules can be seen with ethtool commands of this form:
ethtool -n|-u|--show-nfc|--show-ntuple devname [rule N]

Signed-off-by: Doug Berger 
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 483 -
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |  16 +
 2 files changed, 488 insertions(+), 11 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index ad41944d2cc0..5ef1ea7e5312 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -479,6 +479,30 @@ static void bcmgenet_hfb_enable_filter(struct 
bcmgenet_priv *priv, u32 f_index)
reg = bcmgenet_hfb_reg_readl(priv, offset);
reg |= (1 << (f_index % 32));
bcmgenet_hfb_reg_writel(priv, reg, offset);
+   reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL);
+   reg |= RBUF_HFB_EN;
+   bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL);
+}
+
+static void bcmgenet_hfb_disable_filter(struct bcmgenet_priv *priv, u32 
f_index)
+{
+   u32 offset, reg, reg1;
+
+   offset = HFB_FLT_ENABLE_V3PLUS;
+   reg = bcmgenet_hfb_reg_readl(priv, offset);
+   reg1 = bcmgenet_hfb_reg_readl(priv, offset + sizeof(u32));
+   if  (f_index < 32) {
+   reg1 &= ~(1 << (f_index % 32));
+   bcmgenet_hfb_reg_writel(priv, reg1, offset + sizeof(u32));
+   } else {
+   reg &= ~(1 << (f_index % 32));
+   bcmgenet_hfb_reg_writel(priv, reg, offset);
+   }
+   if (!reg && !reg1) {
+   reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL);
+   reg &= ~RBUF_HFB_EN;
+   bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL);
+   }
 }
 
 static void bcmgenet_hfb_set_filter_rx_queue_mapping(struct bcmgenet_priv 
*priv,
@@ -513,13 +537,213 @@ static int bcmgenet_hfb_find_unused_filter(struct 
bcmgenet_priv *priv)
 {
u32 f_index;
 
-   for (f_index = 0; f_index < priv->hw_params->hfb_filter_cnt; f_index++)
+   /* First MAX_NUM_OF_FS_RULES are reserved for Rx NFC filters */
+   for (f_index = MAX_NUM_OF_FS_RULES;
+f_index < priv->hw_params->hfb_filter_cnt; f_index++)
if (!bcmgenet_hfb_is_filter_enabled(priv, f_index))
return f_index;
 
return -ENOMEM;
 }
 
+static int bcmgenet_hfb_validate_mask(void *mask, size_t size)
+{
+   while (size) {
+   switch (*(unsigned char *)mask++) {
+   case 0x00:
+   case 0x0f:
+   case 0xf0:
+   case 0xff:
+   size--;
+   continue;
+   default:
+   return -EINVAL;
+   }
+   }
+
+   return 0;
+}
+
+#define VALIDATE_MASK(x) \
+   bcmgenet_hfb_validate_mask(&(x), sizeof(x))
+
+static int bcmgenet_hfb_insert_data(u32 *f, int offset,
+   void *val, void *mask, size_t size)
+{
+   int index;
+   u32 tmp;
+
+   index = offset / 2;
+   tmp = f[index];
+
+   while (size--) {
+   if (offset++ & 1) {
+   tmp &= ~0x300FF;
+   tmp |= (*(unsigned char *)val++);
+   switch ((*(unsigned char *)mask++)) {
+   case 0xFF:
+   tmp |= 0x3;
+   break;
+   case 0xF0:
+   tmp |= 0x2;
+   break;
+   case 0x0F:
+   tmp |= 0x1;
+   break;
+   }
+   f[index++] = tmp;
+   if (size)
+   tmp = f[index];
+   } else {
+   tmp &= ~0xCFF00;
+   tmp |= (*(unsigned char *)val++) << 8;
+   switch ((*(unsigned char *)mask++)) {
+   case 0xFF:
+   tmp |= 0xC;
+   break;
+   case 0xF0:
+   tmp |= 

[PATCH net-next 7/7] net: bcmgenet: add WAKE_FILTER support

2020-04-29 Thread Doug Berger
This commit enables support for the WAKE_FILTER method of Wake on
LAN for the GENET driver. The method can be enabled by adding 'f'
to the interface 'wol' setting specified by ethtool.

Rx network flow rules can be specified using ethtool. Rules that
define a flow-type with the RX_CLS_FLOW_WAKE action (i.e. -2) can
wake the system from the 'standby' power state when the WAKE_FILTER
WoL method is enabled.

Signed-off-by: Doug Berger 
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c |  5 ++-
 drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c | 43 +-
 2 files changed, 37 insertions(+), 11 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 5ef1ea7e5312..ad614d7201bd 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -724,7 +724,7 @@ static int bcmgenet_hfb_create_rxnfc_filter(struct 
bcmgenet_priv *priv,
break;
}
 
-   if (!fs->ring_cookie) {
+   if (!fs->ring_cookie || fs->ring_cookie == RX_CLS_FLOW_WAKE) {
/* Ring 0 flows can be handled by the default Descriptor Ring
 * We'll map them to ring 0, but don't enable the filter
 */
@@ -1499,7 +1499,8 @@ static int bcmgenet_insert_flow(struct net_device *dev,
return -EINVAL;
}
 
-   if (cmd->fs.ring_cookie > priv->hw_params->rx_queues) {
+   if (cmd->fs.ring_cookie > priv->hw_params->rx_queues &&
+   cmd->fs.ring_cookie != RX_CLS_FLOW_WAKE) {
netdev_err(dev, "rxnfc: Unsupported action (%llu)\n",
   cmd->fs.ring_cookie);
return -EINVAL;
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
index da45a4645b94..4b9d65f392c2 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
@@ -42,7 +42,7 @@ void bcmgenet_get_wol(struct net_device *dev, struct 
ethtool_wolinfo *wol)
 {
struct bcmgenet_priv *priv = netdev_priv(dev);
 
-   wol->supported = WAKE_MAGIC | WAKE_MAGICSECURE;
+   wol->supported = WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_FILTER;
wol->wolopts = priv->wolopts;
memset(wol->sopass, 0, sizeof(wol->sopass));
 
@@ -61,7 +61,7 @@ int bcmgenet_set_wol(struct net_device *dev, struct 
ethtool_wolinfo *wol)
if (!device_can_wakeup(kdev))
return -ENOTSUPP;
 
-   if (wol->wolopts & ~(WAKE_MAGIC | WAKE_MAGICSECURE))
+   if (wol->wolopts & ~(WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_FILTER))
return -EINVAL;
 
if (wol->wolopts & WAKE_MAGICSECURE)
@@ -117,8 +117,9 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
enum bcmgenet_power_mode mode)
 {
struct net_device *dev = priv->dev;
+   struct bcmgenet_rxnfc_rule *rule;
+   u32 reg, hfb_ctrl_reg, hfb_enable = 0;
int retries = 0;
-   u32 reg;
 
if (mode != GENET_POWER_WOL_MAGIC) {
netif_err(priv, wol, dev, "unsupported mode: %d\n", mode);
@@ -135,13 +136,24 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv 
*priv,
bcmgenet_umac_writel(priv, reg, UMAC_CMD);
mdelay(10);
 
-   reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
-   reg |= MPD_EN;
-   if (priv->wolopts & WAKE_MAGICSECURE) {
-   bcmgenet_set_mpd_password(priv);
-   reg |= MPD_PW_EN;
+   if (priv->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE)) {
+   reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
+   reg |= MPD_EN;
+   if (priv->wolopts & WAKE_MAGICSECURE) {
+   bcmgenet_set_mpd_password(priv);
+   reg |= MPD_PW_EN;
+   }
+   bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
+   }
+
+   hfb_ctrl_reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL);
+   if (priv->wolopts & WAKE_FILTER) {
+   list_for_each_entry(rule, >rxnfc_list, list)
+   if (rule->fs.ring_cookie == RX_CLS_FLOW_WAKE)
+   hfb_enable |= (1 << rule->fs.location);
+   reg = (hfb_ctrl_reg & ~RBUF_HFB_EN) | RBUF_ACPI_EN;
+   bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL);
}
-   bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
 
/* Do not leave UniMAC in MPD mode only */
retries = bcmgenet_poll_wol_status(priv);
@@ -149,6 +161,7 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
reg &= ~(MPD_EN | MPD_PW_EN);
bcmgenet_umac_writel(priv, 

[PATCH net 3/4] net: bcmgenet: soft reset 40nm EPHYs before MAC init

2019-10-16 Thread Doug Berger
It turns out that the "Workaround for putting the PHY in IDDQ mode"
used by the internal EPHYs on 40nm Set-Top Box chips when powering
down puts the interface to the GENET MAC in a state that can cause
subsequent MAC resets to be incomplete.

Rather than restore the forced soft reset when powering up internal
PHYs, this commit moves the invocation of phy_init_hw earlier in
the MAC initialization sequence to just before the MAC reset in the
open and resume functions. This allows the interface to be stable
and allows the MAC resets to be successful.

The bcmgenet_mii_probe() function is split in two to accommodate
this. The new function bcmgenet_mii_connect() handles the first
half of the functionality before the MAC initialization, and the
bcmgenet_mii_config() function is extended to provide the remaining
PHY configuration following the MAC initialization.

Fixes: 484bfa1507bf ("Revert "net: bcmgenet: Software reset EPHY after power 
on"")
Signed-off-by: Doug Berger 
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c |  28 ---
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |   2 +-
 drivers/net/ethernet/broadcom/genet/bcmmii.c   | 112 +++--
 3 files changed, 69 insertions(+), 73 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 10d68017ff6c..f0937c650e3c 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -2872,6 +2872,12 @@ static int bcmgenet_open(struct net_device *dev)
if (priv->internal_phy)
bcmgenet_power_up(priv, GENET_POWER_PASSIVE);
 
+   ret = bcmgenet_mii_connect(dev);
+   if (ret) {
+   netdev_err(dev, "failed to connect to PHY\n");
+   goto err_clk_disable;
+   }
+
/* take MAC out of reset */
bcmgenet_umac_reset(priv);
 
@@ -2881,6 +2887,12 @@ static int bcmgenet_open(struct net_device *dev)
reg = bcmgenet_umac_readl(priv, UMAC_CMD);
priv->crc_fwd_en = !!(reg & CMD_CRC_FWD);
 
+   ret = bcmgenet_mii_config(dev, true);
+   if (ret) {
+   netdev_err(dev, "unsupported PHY\n");
+   goto err_disconnect_phy;
+   }
+
bcmgenet_set_hw_addr(priv, dev->dev_addr);
 
if (priv->internal_phy) {
@@ -2896,7 +2908,7 @@ static int bcmgenet_open(struct net_device *dev)
ret = bcmgenet_init_dma(priv);
if (ret) {
netdev_err(dev, "failed to initialize DMA\n");
-   goto err_clk_disable;
+   goto err_disconnect_phy;
}
 
/* Always enable ring 16 - descriptor ring */
@@ -2919,25 +2931,19 @@ static int bcmgenet_open(struct net_device *dev)
goto err_irq0;
}
 
-   ret = bcmgenet_mii_probe(dev);
-   if (ret) {
-   netdev_err(dev, "failed to connect to PHY\n");
-   goto err_irq1;
-   }
-
bcmgenet_netif_start(dev);
 
netif_tx_start_all_queues(dev);
 
return 0;
 
-err_irq1:
-   free_irq(priv->irq1, priv);
 err_irq0:
free_irq(priv->irq0, priv);
 err_fini_dma:
bcmgenet_dma_teardown(priv);
bcmgenet_fini_dma(priv);
+err_disconnect_phy:
+   phy_disconnect(dev->phydev);
 err_clk_disable:
if (priv->internal_phy)
bcmgenet_power_down(priv, GENET_POWER_PASSIVE);
@@ -3618,6 +3624,8 @@ static int bcmgenet_resume(struct device *d)
if (priv->internal_phy)
bcmgenet_power_up(priv, GENET_POWER_PASSIVE);
 
+   phy_init_hw(dev->phydev);
+
bcmgenet_umac_reset(priv);
 
init_umac(priv);
@@ -3626,8 +3634,6 @@ static int bcmgenet_resume(struct device *d)
if (priv->wolopts)
clk_disable_unprepare(priv->clk_wol);
 
-   phy_init_hw(dev->phydev);
-
/* Speed settings must be restored */
bcmgenet_mii_config(priv->dev, false);
 
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
index dbc69d8fa05f..7fbf573d8d52 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
@@ -720,8 +720,8 @@ GENET_IO_MACRO(rbuf, GENET_RBUF_OFF);
 
 /* MDIO routines */
 int bcmgenet_mii_init(struct net_device *dev);
+int bcmgenet_mii_connect(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_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 e7c291bf4ed1..17bb8d60a157 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
+++ b/drivers/net/e

[PATCH net 1/4] net: bcmgenet: don't set phydev->link from MAC

2019-10-16 Thread Doug Berger
When commit 28b2e0d2cd13 ("net: phy: remove parameter new_link from
phy_mac_interrupt()") removed the new_link parameter it set the
phydev->link state from the MAC before invoking phy_mac_interrupt().

However, once commit 88d6272acaaa ("net: phy: avoid unneeded MDIO
reads in genphy_read_status") was added this initialization prevents
the proper determination of the connection parameters by the function
genphy_read_status().

This commit removes that initialization to restore the proper
functionality.

Fixes: 88d6272acaaa ("net: phy: avoid unneeded MDIO reads in 
genphy_read_status")
Signed-off-by: Doug Berger 
---
 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 12cb77ef1081..10d68017ff6c 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -2612,10 +2612,8 @@ static void bcmgenet_irq_task(struct work_struct *work)
spin_unlock_irq(>lock);
 
/* Link UP/DOWN event */
-   if (status & UMAC_IRQ_LINK_EVENT) {
-   priv->dev->phydev->link = !!(status & UMAC_IRQ_LINK_UP);
+   if (status & UMAC_IRQ_LINK_EVENT)
phy_mac_interrupt(priv->dev->phydev);
-   }
 }
 
 /* bcmgenet_isr1: handle Rx and Tx priority queues */
-- 
2.7.4



[PATCH net 4/4] net: bcmgenet: reset 40nm EPHY on energy detect

2019-10-16 Thread Doug Berger
The EPHY integrated into the 40nm Set-Top Box devices can falsely
detect energy when connected to a disabled peer interface. When the
peer interface is enabled the EPHY will detect and report the link
as active, but on occasion may get into a state where it is not
able to exchange data with the connected GENET MAC. This issue has
not been observed when the link parameters are auto-negotiated;
however, it has been observed with a manually configured link.

It has been empirically determined that issuing a soft reset to the
EPHY when energy is detected prevents it from getting into this bad
state.

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

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index f0937c650e3c..0f138280315a 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -2018,6 +2018,8 @@ static void bcmgenet_link_intr_enable(struct 
bcmgenet_priv *priv)
 */
if (priv->internal_phy) {
int0_enable |= UMAC_IRQ_LINK_EVENT;
+   if (GENET_IS_V1(priv) || GENET_IS_V2(priv) || GENET_IS_V3(priv))
+   int0_enable |= UMAC_IRQ_PHY_DET_R;
} else if (priv->ext_phy) {
int0_enable |= UMAC_IRQ_LINK_EVENT;
} else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) {
@@ -2611,9 +2613,14 @@ static void bcmgenet_irq_task(struct work_struct *work)
priv->irq0_stat = 0;
spin_unlock_irq(>lock);
 
+   if (status & UMAC_IRQ_PHY_DET_R &&
+   priv->dev->phydev->autoneg != AUTONEG_ENABLE)
+   phy_init_hw(priv->dev->phydev);
+
/* Link UP/DOWN event */
if (status & UMAC_IRQ_LINK_EVENT)
phy_mac_interrupt(priv->dev->phydev);
+
 }
 
 /* bcmgenet_isr1: handle Rx and Tx priority queues */
@@ -2708,7 +2715,7 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id)
}
 
/* all other interested interrupts handled in bottom half */
-   status &= UMAC_IRQ_LINK_EVENT;
+   status &= (UMAC_IRQ_LINK_EVENT | UMAC_IRQ_PHY_DET_R);
if (status) {
/* Save irq status for bottom-half processing. */
spin_lock_irqsave(>lock, flags);
-- 
2.7.4



[PATCH net 2/4] net: phy: bcm7xxx: define soft_reset for 40nm EPHY

2019-10-16 Thread Doug Berger
The internal 40nm EPHYs use a "Workaround for putting the PHY in
IDDQ mode." These PHYs require a soft reset to restore functionality
after they are powered back up.

This commit defines the soft_reset function to use genphy_soft_reset
during phy_init_hw to accommodate this.

Fixes: 6e2d85ec0559 ("net: phy: Stop with excessive soft reset")
Signed-off-by: Doug Berger 
---
 drivers/net/phy/bcm7xxx.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c
index 8fc33867e524..af8eabe7a6d4 100644
--- a/drivers/net/phy/bcm7xxx.c
+++ b/drivers/net/phy/bcm7xxx.c
@@ -572,6 +572,7 @@ static int bcm7xxx_28nm_probe(struct phy_device *phydev)
.name   = _name,\
/* PHY_BASIC_FEATURES */\
.flags  = PHY_IS_INTERNAL,  \
+   .soft_reset = genphy_soft_reset,\
.config_init= bcm7xxx_config_init,  \
.suspend= bcm7xxx_suspend,  \
.resume = bcm7xxx_config_init,  \
-- 
2.7.4



[PATCH net 0/4] net: bcmgenet: restore internal EPHY support

2019-10-16 Thread Doug Berger
I managed to get my hands on an old BCM97435SVMB board to do some
testing with the latest kernel and uncovered a number of things
that managed to get broken over the years (some by me ;).

This commit set attempts to correct the errors I observed in my
testing.

The first commit applies to all internal PHYs to restore proper
reporting of link status when a link comes up.

The second commit restores the soft reset to the initialization of
the older internal EPHYs used by 40nm Set-Top Box devices.

The third corrects a bug I introduced when removing excessive soft
resets by altering the initialization sequence in a way that keeps
the GENETv3 MAC interface happy.

Finally, I observed a number of issues when manually configuring
the network interface of the older EPHYs that appear to be resolved
by the fourth commit.

Doug Berger (4):
  net: bcmgenet: don't set phydev->link from MAC
  net: phy: bcm7xxx: define soft_reset for 40nm EPHY
  net: bcmgenet: soft reset 40nm EPHYs before MAC init
  net: bcmgenet: reset 40nm EPHY on energy detect

 drivers/net/ethernet/broadcom/genet/bcmgenet.c |  41 +
 drivers/net/ethernet/broadcom/genet/bcmgenet.h |   2 +-
 drivers/net/ethernet/broadcom/genet/bcmmii.c   | 112 +++--
 drivers/net/phy/bcm7xxx.c  |   1 +
 4 files changed, 79 insertions(+), 77 deletions(-)

-- 
2.7.4



Re: [PATCH net] net: bcmgenet: Fix RGMII_MODE_EN value for GENET v1/2/3

2019-10-15 Thread Doug Berger
On 10/15/19 10:45 AM, Florian Fainelli wrote:
> The RGMII_MODE_EN bit value was 0 for GENET versions 1 through 3, and
> became 6 for GENET v4 and above, account for that difference.
> 
> Fixes: aa09677cba42 ("net: bcmgenet: add MDIO routines")
> Signed-off-by: Florian Fainelli 
> ---
>  drivers/net/ethernet/broadcom/genet/bcmgenet.h | 1 +
>  drivers/net/ethernet/broadcom/genet/bcmmii.c   | 6 +-
>  2 files changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h 
> b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
> index 4a8fc03d82fd..dbc69d8fa05f 100644
> --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
> +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
> @@ -366,6 +366,7 @@ struct bcmgenet_mib_counters {
>  #define  EXT_PWR_DOWN_PHY_EN (1 << 20)
>  
>  #define EXT_RGMII_OOB_CTRL   0x0C
> +#define  RGMII_MODE_EN_V123  (1 << 0)
>  #define  RGMII_LINK  (1 << 4)
>  #define  OOB_DISABLE (1 << 5)
>  #define  RGMII_MODE_EN   (1 << 6)
> diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c 
> b/drivers/net/ethernet/broadcom/genet/bcmmii.c
> index 94d1dd5d56bf..e7c291bf4ed1 100644
> --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
> +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
> @@ -258,7 +258,11 @@ int bcmgenet_mii_config(struct net_device *dev, bool 
> init)
>*/
>   if (priv->ext_phy) {
>   reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL);
> - reg |= RGMII_MODE_EN | id_mode_dis;
> + reg |= id_mode_dis;
> + if (GENET_IS_V1(priv) || GENET_IS_V2(priv) || GENET_IS_V3(priv))
> + reg |= RGMII_MODE_EN_V123;
> +     else
> + reg |= RGMII_MODE_EN;
>   bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
>   }
>  
> 

Acked-by: Doug Berger 


Re: [PATCH net-next] net: bcmgenet: Add a shutdown callback

2019-10-15 Thread Doug Berger
On 10/15/19 10:36 AM, Florian Fainelli wrote:
> Make sure that we completely quiesce the network device, including its
> DMA to avoid having it continue to receive packets while there is no
> software alive to service those.
> 
> Signed-off-by: Florian Fainelli 
> ---
>  drivers/net/ethernet/broadcom/genet/bcmgenet.c | 6 ++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
> b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> index 12cb77ef1081..ecbb1e7353ba 100644
> --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> @@ -3597,6 +3597,11 @@ static int bcmgenet_remove(struct platform_device 
> *pdev)
>   return 0;
>  }
>  
> +static void bcmgenet_shutdown(struct platform_device *pdev)
> +{
> + bcmgenet_remove(pdev);
> +}
> +
>  #ifdef CONFIG_PM_SLEEP
>  static int bcmgenet_resume(struct device *d)
>  {
> @@ -3715,6 +3720,7 @@ static SIMPLE_DEV_PM_OPS(bcmgenet_pm_ops, 
> bcmgenet_suspend, bcmgenet_resume);
>  static struct platform_driver bcmgenet_driver = {
>   .probe  = bcmgenet_probe,
>   .remove = bcmgenet_remove,
> + .shutdown = bcmgenet_shutdown,
>   .driver = {
>   .name   = "bcmgenet",
>   .of_match_table = bcmgenet_match,
> 

Acked-by: Doug Berger 


Re: [PATCH net-next v2] net: bcmgenet: Generate a random MAC if none is valid

2019-10-14 Thread Doug Berger
On 10/14/19 2:20 PM, Florian Fainelli wrote:
> Instead of having a hard failure and stopping the driver's probe
> routine, generate a random Ethernet MAC address to keep going.
> 
> Signed-off-by: Florian Fainelli 
> ---
> Changes in v2:
> 
> - provide a message that a random MAC is used, the same message that
>   bcmsysport.c uses
> 
>  drivers/net/ethernet/broadcom/genet/bcmgenet.c | 17 -
>  1 file changed, 8 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
> b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> index 12cb77ef1081..dd4e4f1dd384 100644
> --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> @@ -3461,16 +3461,10 @@ static int bcmgenet_probe(struct platform_device 
> *pdev)
>   goto err;
>   }
>  
> - if (dn) {
> + if (dn)
>   macaddr = of_get_mac_address(dn);
> - if (IS_ERR(macaddr)) {
> - dev_err(>dev, "can't find MAC address\n");
> - err = -EINVAL;
> - goto err;
> - }
> - } else {
> + else
>   macaddr = pd->mac_address;
> - }
>  
>   priv->base = devm_platform_ioremap_resource(pdev, 0);
>   if (IS_ERR(priv->base)) {
> @@ -3482,7 +3476,12 @@ static int bcmgenet_probe(struct platform_device *pdev)
>  
>   SET_NETDEV_DEV(dev, >dev);
>   dev_set_drvdata(>dev, dev);
> - ether_addr_copy(dev->dev_addr, macaddr);
> + if (IS_ERR_OR_NULL(macaddr) || !is_valid_ether_addr(macaddr)) {
> + dev_warn(>dev, "using random Ethernet MAC\n");
> + eth_hw_addr_random(dev);
> + } else {
> +     ether_addr_copy(dev->dev_addr, macaddr);
> + }
>   dev->watchdog_timeo = 2 * HZ;
>   dev->ethtool_ops = _ethtool_ops;
>   dev->netdev_ops = _netdev_ops;
> 
Acked-by: Doug Berger 


Re: [PATCH net] net: bcmgenet: Set phydev->dev_flags only for internal PHYs

2019-10-14 Thread Doug Berger
On 10/11/19 12:57 PM, Florian Fainelli wrote:
> On 10/11/19 12:53 PM, Florian Fainelli wrote:
>> phydev->dev_flags is entirely dependent on the PHY device driver which
>> is going to be used, setting the internal GENET PHY revision in those
>> bits only makes sense when drivers/net/phy/bcm7xxx.c is the PHY driver
>> being used.
>>
>> Fixes: 487320c54143 ("net: bcmgenet: communicate integrated PHY revision to 
>> PHY driver")
>> Signed-off-by: Florian Fainelli 
> 
> FWIW, I am preparing net-next material which allows the phy_flags to be
> scoped towards a specific PHY driver, and not broadly applied, but until
> this happens, we should probably go with this change.
> 
>> ---
>>  drivers/net/ethernet/broadcom/genet/bcmmii.c | 5 +++--
>>  1 file changed, 3 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c 
>> b/drivers/net/ethernet/broadcom/genet/bcmmii.c
>> index 970e478a9017..94d1dd5d56bf 100644
>> --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
>> +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
>> @@ -273,11 +273,12 @@ int bcmgenet_mii_probe(struct net_device *dev)
>>  struct bcmgenet_priv *priv = netdev_priv(dev);
>>  struct device_node *dn = priv->pdev->dev.of_node;
>>  struct phy_device *phydev;
>> -u32 phy_flags;
>> +u32 phy_flags = 0;
>>  int ret;
>>  
>>  /* Communicate the integrated PHY revision */
>> -phy_flags = priv->gphy_rev;
>> +if (priv->internal_phy)
>> +phy_flags = priv->gphy_rev;
>>  
>>  /* Initialize link state variables that bcmgenet_mii_setup() uses */
>>  priv->old_link = -1;
>>
> 
> 
Acked-by: Doug Berger 


Re: [PATCH] net: bcmgenet: use ethtool_op_get_ts_info()

2019-08-30 Thread Doug Berger
On 8/30/19 11:51 AM, Florian Fainelli wrote:
> On 8/30/19 11:49 AM, Ryan M. Collins wrote:
>> This change enables the use of SW timestamping on the Raspberry Pi 4.
> 
> Finally the first bcmgenet patch that was tested on the Pi 4!
> 
>>
>> bcmgenet's transmit function bcmgenet_xmit() implements software
>> timestamping. However the SOF_TIMESTAMPING_TX_SOFTWARE capability was
>> missing and only SOF_TIMESTAMPING_RX_SOFTWARE was announced. By using
>> ethtool_ops bcmgenet_ethtool_ops() as get_ts_info(), the
>> SOF_TIMESTAMPING_TX_SOFTWARE capability is announced.
>>
>> Similar to commit a8f5cb9e7991 ("smsc95xx: use ethtool_op_get_ts_info()")
>>
>> Signed-off-by: Ryan M. Collins 
> 
> Acked-by: Florian Fainelli 
> 
Thanks Ryan!

Acked-by: Doug Berger 



Re: [PATCH net-next] net: bcmgenet: use devm_platform_ioremap_resource() to simplify code

2019-08-21 Thread Doug Berger
On 8/21/19 6:41 AM, YueHaibing wrote:
> Use devm_platform_ioremap_resource() to simplify the code a bit.
> This is detected by coccinelle.
> 
> Reported-by: Hulk Robot 
> Signed-off-by: YueHaibing 
> ---
>  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 d3a0b61..2108e59 100644
> --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> @@ -3437,7 +3437,6 @@ static int bcmgenet_probe(struct platform_device *pdev)
>   struct bcmgenet_priv *priv;
>   struct net_device *dev;
>   const void *macaddr;
> - struct resource *r;
>   unsigned int i;
>   int err = -EIO;
>   const char *phy_mode_str;
> @@ -3477,8 +3476,7 @@ static int bcmgenet_probe(struct platform_device *pdev)
>   macaddr = pd->mac_address;
>   }
>  
> - r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> - priv->base = devm_ioremap_resource(>dev, r);
> + priv->base = devm_platform_ioremap_resource(pdev, 0);
>   if (IS_ERR(priv->base)) {
>   err = PTR_ERR(priv->base);
>   goto err;
> 

Acked-by: Doug Berger 


Re: [PATCH] net: bcmgenet: use promisc for unsupported filters

2019-07-18 Thread Doug Berger
On 7/17/19 2:58 PM, justinpo...@gmail.com wrote:
> From: Justin Chen 
> 
> Currently we silently ignore filters if we cannot meet the filter
> requirements. This will lead to the MAC dropping packets that are
> expected to pass. A better solution would be to set the NIC to promisc
> mode when the required filters cannot be met.
> 
> Also correct the number of MDF filters supported. It should be 17,
> not 16.
> 
> Signed-off-by: Justin Chen 

Acked-by: Doug Berger 

Thanks Justin :)
Doug


[PATCH] ARM: mm: only adjust sections of valid mm structures

2019-06-27 Thread Doug Berger
A timing hazard exists when an early fork/exec thread begins
exiting and sets its mm pointer to NULL while a separate core
tries to update the section information.

This commit ensures that the mm pointer is not NULL before
setting its section parameters. The arguments provided by
commit 11ce4b33aedc ("ARM: 8672/1: mm: remove tasklist locking
from update_sections_early()") are equally valid for not
requiring grabbing the task_lock around this check.

Fixes: 08925c2f124f ("ARM: 8464/1: Update all mm structures with section 
adjustments")
Signed-off-by: Doug Berger 
---
 arch/arm/mm/init.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index be0b42937888..bdc70dff477b 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -616,7 +616,8 @@ static void update_sections_early(struct section_perm 
perms[], int n)
if (t->flags & PF_KTHREAD)
continue;
for_each_thread(t, s)
-   set_section_perms(perms, n, true, s->mm);
+   if (s->mm)
+   set_section_perms(perms, n, true, s->mm);
}
set_section_perms(perms, n, true, current->active_mm);
set_section_perms(perms, n, true, _mm);
-- 
2.7.4



[PATCH] cma: fail if fixed declaration can't be honored

2019-06-24 Thread Doug Berger
The description of the cma_declare_contiguous() function indicates
that if the 'fixed' argument is true the reserved contiguous area
must be exactly at the address of the 'base' argument.

However, the function currently allows the 'base', 'size', and
'limit' arguments to be silently adjusted to meet alignment
constraints. This commit enforces the documented behavior through
explicit checks that return an error if the region does not fit
within a specified region.

Fixes: 5ea3b1b2f8ad ("cma: add placement specifier for "cma=" kernel parameter")
Signed-off-by: Doug Berger 
---
 mm/cma.c | 13 +
 1 file changed, 13 insertions(+)

diff --git a/mm/cma.c b/mm/cma.c
index 3340ef34c154..4973d253dc83 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -278,6 +278,12 @@ int __init cma_declare_contiguous(phys_addr_t base,
 */
alignment = max(alignment,  (phys_addr_t)PAGE_SIZE <<
  max_t(unsigned long, MAX_ORDER - 1, pageblock_order));
+   if (fixed && base & (alignment - 1)) {
+   ret = -EINVAL;
+   pr_err("Region at %pa must be aligned to %pa bytes\n",
+   , );
+   goto err;
+   }
base = ALIGN(base, alignment);
size = ALIGN(size, alignment);
limit &= ~(alignment - 1);
@@ -308,6 +314,13 @@ int __init cma_declare_contiguous(phys_addr_t base,
if (limit == 0 || limit > memblock_end)
limit = memblock_end;
 
+   if (base + size > limit) {
+   ret = -EINVAL;
+   pr_err("Size (%pa) of region at %pa exceeds limit (%pa)\n",
+   , , );
+   goto err;
+   }
+
/* Reserve memory */
if (fixed) {
if (memblock_is_region_reserved(base, size) ||
-- 
2.7.4



Re: [PATCH] ARM: mm: initialize pfn limits with find_limits()

2019-01-10 Thread Doug Berger
On 12/27/18 3:47 PM, Doug Berger wrote:
> The max_low_pfn value must be set before sparse_init() is called to
> keep the early memblock allocations and frees balanced for kmemleak
> initialization when sparsemem is enabled.
> 
> This commit accomplishes that by replacing the local variables min,
> max_low, and max_high with the global limit variables min_low_pfn,
> max_low_pfn, and max_pfn respectively in bootmem_init(). The global
> variables are initialized directly by find_limits() and used in the
> remainder of the function.
> 
> Fixes: 9099daed9c69 ("mm: kmemleak: avoid using __va() on addresses that 
> don't have a lowmem mapping")
> Signed-off-by: Doug Berger 
> ---
>  arch/arm/mm/init.c | 20 
>  1 file changed, 4 insertions(+), 16 deletions(-)
> 
> diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
> index 32e4845af2b6..98a733f3a5b9 100644
> --- a/arch/arm/mm/init.c
> +++ b/arch/arm/mm/init.c
> @@ -302,15 +302,12 @@ void __init arm_memblock_init(const struct machine_desc 
> *mdesc)
>  
>  void __init bootmem_init(void)
>  {
> - unsigned long min, max_low, max_high;
> -
>   memblock_allow_resize();
> - max_low = max_high = 0;
>  
> - find_limits(, _low, _high);
> + find_limits(_low_pfn, _low_pfn, _pfn);
>  
> - early_memtest((phys_addr_t)min << PAGE_SHIFT,
> -   (phys_addr_t)max_low << PAGE_SHIFT);
> + early_memtest((phys_addr_t)min_low_pfn << PAGE_SHIFT,
> +   (phys_addr_t)max_low_pfn << PAGE_SHIFT);
>  
>   /*
>* Sparsemem tries to allocate bootmem in memory_present(),
> @@ -328,16 +325,7 @@ void __init bootmem_init(void)
>* the sparse mem_map arrays initialized by sparse_init()
>* for memmap_init_zone(), otherwise all PFNs are invalid.
>*/
> - zone_sizes_init(min, max_low, max_high);
> -
> - /*
> -  * This doesn't seem to be used by the Linux memory manager any
> -  * more, but is used by ll_rw_block.  If we can get rid of it, we
> -  * also get rid of some of the stuff above as well.
> -  */
> - min_low_pfn = min;
> - max_low_pfn = max_low;
> - max_pfn = max_high;
> + zone_sizes_init(min_low_pfn, max_low_pfn, max_pfn);
>  }
>  
>  /*
> 

Any feedback on this patch?

Thanks,
Doug



[PATCH] ARM: mm: initialize pfn limits with find_limits()

2018-12-27 Thread Doug Berger
The max_low_pfn value must be set before sparse_init() is called to
keep the early memblock allocations and frees balanced for kmemleak
initialization when sparsemem is enabled.

This commit accomplishes that by replacing the local variables min,
max_low, and max_high with the global limit variables min_low_pfn,
max_low_pfn, and max_pfn respectively in bootmem_init(). The global
variables are initialized directly by find_limits() and used in the
remainder of the function.

Fixes: 9099daed9c69 ("mm: kmemleak: avoid using __va() on addresses that don't 
have a lowmem mapping")
Signed-off-by: Doug Berger 
---
 arch/arm/mm/init.c | 20 
 1 file changed, 4 insertions(+), 16 deletions(-)

diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 32e4845af2b6..98a733f3a5b9 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -302,15 +302,12 @@ void __init arm_memblock_init(const struct machine_desc 
*mdesc)
 
 void __init bootmem_init(void)
 {
-   unsigned long min, max_low, max_high;
-
memblock_allow_resize();
-   max_low = max_high = 0;
 
-   find_limits(, _low, _high);
+   find_limits(_low_pfn, _low_pfn, _pfn);
 
-   early_memtest((phys_addr_t)min << PAGE_SHIFT,
- (phys_addr_t)max_low << PAGE_SHIFT);
+   early_memtest((phys_addr_t)min_low_pfn << PAGE_SHIFT,
+ (phys_addr_t)max_low_pfn << PAGE_SHIFT);
 
/*
 * Sparsemem tries to allocate bootmem in memory_present(),
@@ -328,16 +325,7 @@ void __init bootmem_init(void)
 * the sparse mem_map arrays initialized by sparse_init()
 * for memmap_init_zone(), otherwise all PFNs are invalid.
 */
-   zone_sizes_init(min, max_low, max_high);
-
-   /*
-* This doesn't seem to be used by the Linux memory manager any
-* more, but is used by ll_rw_block.  If we can get rid of it, we
-* also get rid of some of the stuff above as well.
-*/
-   min_low_pfn = min;
-   max_low_pfn = max_low;
-   max_pfn = max_high;
+   zone_sizes_init(min_low_pfn, max_low_pfn, max_pfn);
 }
 
 /*
-- 
2.7.4



Re: [PATCH] PM / Sleep: only update last time for active wakeup sources

2018-04-26 Thread Doug Berger
On 04/25/2018 11:30 PM, Rafael J. Wysocki wrote:
> On Thu, Apr 26, 2018 at 1:40 AM, Doug Berger <open...@gmail.com> wrote:
>> When wakelock support was added, the wakeup_source_add() function
>> was updated to set the last_time value of the wakeup source. This
>> has the unintended side effect of producing confusing output from
>> pm_print_active_wakeup_sources() when a wakeup source is added
>> prior to a sleep that is blocked by a different wakeup source.
>>
>> The function pm_print_active_wakeup_sources() will search for the
>> most recently active wakeup source when no active source is found.
>> If a wakeup source is added after a different wakeup source blocks
>> the system from going to sleep it may have a later last_time value
>> than the blocking source and be output as the last active wakeup
>> source even if it has never actually been active.
>>
>> It looks to me like the change to wakeup_source_add() was made to
>> prevent the wakelock garbage collection from accidentally dropping
>> a wakelock during the narrow window between adding the wakelock to
>> the wakelock list in wakelock_lookup_add() and the activation of
>> the wakeup source in pm_wake_lock().
>>
>> This commit changes the behavior so that only the last_time of the
>> wakeup source used by a wakelock is initialized prior to adding it
>> to the wakeup source list. This preserves the meaning of the
>> last_time value as the last time the wakeup source was active and
>> allows a wakeup source that has never been active to have a
>> last_time value of 0.
>>
>> Fixes: b86ff982 ("PM / Sleep: Add user space interface for manipulating 
>> wakeup sources, v3")
>> Signed-off-by: Doug Berger <open...@gmail.com>
>> ---
>>  drivers/base/power/wakeup.c | 1 -
>>  kernel/power/wakelock.c | 1 +
>>  2 files changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
>> index ea01621..230160e 100644
>> --- a/drivers/base/power/wakeup.c
>> +++ b/drivers/base/power/wakeup.c
>> @@ -183,7 +183,6 @@ void wakeup_source_add(struct wakeup_source *ws)
>> spin_lock_init(>lock);
>> timer_setup(>timer, pm_wakeup_timer_fn, 0);
>> ws->active = false;
>> -   ws->last_time = ktime_get();
> 
> If it is not initialized here, max_time may not be updated correctly later on.
> 
> If you don't want to initialize it to ktime_get() (to avoid the issue
> you're trying to avoid), initialize it to something special and then
> check for that explicitly in wakeup_source_deactivate() when computing
> max_time.
> 

I'm a little confused by your meaning. If you are concerned that the
duration calculation in wakeup_source_deactivate() may be compromised by
not initializing last_time in wakeup_source_add() and that an incorrect
duration could find its way into the comparison and update of max_time
then I don't believe that is a realizable concern.

As far as I can see there are no execution paths to
wakeup_source_deactivate() that don't require a call to
wakeup_source_activate() earlier in the path. The call to
wakeup_source_activate() will set the last_time to its proper value for
use by wakeup_source_deactivate().

So it should be safe to leave last_time at its initial 0 value in
wakeup_source_add() without impacting wakeup_source_deactivate() or
print_wakeup_source_stats().

This is the behavior of your original implementation of wakeup sources.
It wasn't changed until the wakelock support was added and as I said it
only appears to be necessary to protect against the timing hazard with
the garbage collecting thread possibly finding the wakeup_source from
the wakelock list before the pm_wake_lock() function has the opportunity
to activate the associated wakeup source.

>>
>> spin_lock_irqsave(_lock, flags);
>> list_add_rcu(>entry, _sources);
>> diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c
>> index dfba59b..4210152 100644
>> --- a/kernel/power/wakelock.c
>> +++ b/kernel/power/wakelock.c
>> @@ -188,6 +188,7 @@ static struct wakelock *wakelock_lookup_add(const char 
>> *name, size_t len,
>> return ERR_PTR(-ENOMEM);
>> }
>> wl->ws.name = wl->name;
>> +   wl->ws.last_time = ktime_get();

This proposed change forces an early initialization of the last_time for
wakelocks only to protect against accidental garbage collection between
wakelock_lookup_add() and the subsequent call of __pm_wakeup_event() or
__pm_stay_awake() where last_time will be initialized again.


>> wakeup_source_add(>ws);
>> rb_link_node(>node, parent, node);
>> rb_insert_color(>node, _tree);
>> --
>> 2.7.4
>>

Thank you for your timely review and consideration of this patch,
Doug


Re: [PATCH] PM / Sleep: only update last time for active wakeup sources

2018-04-26 Thread Doug Berger
On 04/25/2018 11:30 PM, Rafael J. Wysocki wrote:
> On Thu, Apr 26, 2018 at 1:40 AM, Doug Berger  wrote:
>> When wakelock support was added, the wakeup_source_add() function
>> was updated to set the last_time value of the wakeup source. This
>> has the unintended side effect of producing confusing output from
>> pm_print_active_wakeup_sources() when a wakeup source is added
>> prior to a sleep that is blocked by a different wakeup source.
>>
>> The function pm_print_active_wakeup_sources() will search for the
>> most recently active wakeup source when no active source is found.
>> If a wakeup source is added after a different wakeup source blocks
>> the system from going to sleep it may have a later last_time value
>> than the blocking source and be output as the last active wakeup
>> source even if it has never actually been active.
>>
>> It looks to me like the change to wakeup_source_add() was made to
>> prevent the wakelock garbage collection from accidentally dropping
>> a wakelock during the narrow window between adding the wakelock to
>> the wakelock list in wakelock_lookup_add() and the activation of
>> the wakeup source in pm_wake_lock().
>>
>> This commit changes the behavior so that only the last_time of the
>> wakeup source used by a wakelock is initialized prior to adding it
>> to the wakeup source list. This preserves the meaning of the
>> last_time value as the last time the wakeup source was active and
>> allows a wakeup source that has never been active to have a
>> last_time value of 0.
>>
>> Fixes: b86ff982 ("PM / Sleep: Add user space interface for manipulating 
>> wakeup sources, v3")
>> Signed-off-by: Doug Berger 
>> ---
>>  drivers/base/power/wakeup.c | 1 -
>>  kernel/power/wakelock.c | 1 +
>>  2 files changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
>> index ea01621..230160e 100644
>> --- a/drivers/base/power/wakeup.c
>> +++ b/drivers/base/power/wakeup.c
>> @@ -183,7 +183,6 @@ void wakeup_source_add(struct wakeup_source *ws)
>> spin_lock_init(>lock);
>> timer_setup(>timer, pm_wakeup_timer_fn, 0);
>> ws->active = false;
>> -   ws->last_time = ktime_get();
> 
> If it is not initialized here, max_time may not be updated correctly later on.
> 
> If you don't want to initialize it to ktime_get() (to avoid the issue
> you're trying to avoid), initialize it to something special and then
> check for that explicitly in wakeup_source_deactivate() when computing
> max_time.
> 

I'm a little confused by your meaning. If you are concerned that the
duration calculation in wakeup_source_deactivate() may be compromised by
not initializing last_time in wakeup_source_add() and that an incorrect
duration could find its way into the comparison and update of max_time
then I don't believe that is a realizable concern.

As far as I can see there are no execution paths to
wakeup_source_deactivate() that don't require a call to
wakeup_source_activate() earlier in the path. The call to
wakeup_source_activate() will set the last_time to its proper value for
use by wakeup_source_deactivate().

So it should be safe to leave last_time at its initial 0 value in
wakeup_source_add() without impacting wakeup_source_deactivate() or
print_wakeup_source_stats().

This is the behavior of your original implementation of wakeup sources.
It wasn't changed until the wakelock support was added and as I said it
only appears to be necessary to protect against the timing hazard with
the garbage collecting thread possibly finding the wakeup_source from
the wakelock list before the pm_wake_lock() function has the opportunity
to activate the associated wakeup source.

>>
>> spin_lock_irqsave(_lock, flags);
>> list_add_rcu(>entry, _sources);
>> diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c
>> index dfba59b..4210152 100644
>> --- a/kernel/power/wakelock.c
>> +++ b/kernel/power/wakelock.c
>> @@ -188,6 +188,7 @@ static struct wakelock *wakelock_lookup_add(const char 
>> *name, size_t len,
>> return ERR_PTR(-ENOMEM);
>> }
>> wl->ws.name = wl->name;
>> +   wl->ws.last_time = ktime_get();

This proposed change forces an early initialization of the last_time for
wakelocks only to protect against accidental garbage collection between
wakelock_lookup_add() and the subsequent call of __pm_wakeup_event() or
__pm_stay_awake() where last_time will be initialized again.


>> wakeup_source_add(>ws);
>> rb_link_node(>node, parent, node);
>> rb_insert_color(>node, _tree);
>> --
>> 2.7.4
>>

Thank you for your timely review and consideration of this patch,
Doug


[PATCH] PM / Sleep: only update last time for active wakeup sources

2018-04-25 Thread Doug Berger
When wakelock support was added, the wakeup_source_add() function
was updated to set the last_time value of the wakeup source. This
has the unintended side effect of producing confusing output from
pm_print_active_wakeup_sources() when a wakeup source is added
prior to a sleep that is blocked by a different wakeup source.

The function pm_print_active_wakeup_sources() will search for the
most recently active wakeup source when no active source is found.
If a wakeup source is added after a different wakeup source blocks
the system from going to sleep it may have a later last_time value
than the blocking source and be output as the last active wakeup
source even if it has never actually been active.

It looks to me like the change to wakeup_source_add() was made to
prevent the wakelock garbage collection from accidentally dropping
a wakelock during the narrow window between adding the wakelock to
the wakelock list in wakelock_lookup_add() and the activation of
the wakeup source in pm_wake_lock().

This commit changes the behavior so that only the last_time of the
wakeup source used by a wakelock is initialized prior to adding it
to the wakeup source list. This preserves the meaning of the
last_time value as the last time the wakeup source was active and
allows a wakeup source that has never been active to have a
last_time value of 0.

Fixes: b86ff982 ("PM / Sleep: Add user space interface for manipulating wakeup 
sources, v3")
Signed-off-by: Doug Berger <open...@gmail.com>
---
 drivers/base/power/wakeup.c | 1 -
 kernel/power/wakelock.c | 1 +
 2 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index ea01621..230160e 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -183,7 +183,6 @@ void wakeup_source_add(struct wakeup_source *ws)
spin_lock_init(>lock);
timer_setup(>timer, pm_wakeup_timer_fn, 0);
ws->active = false;
-   ws->last_time = ktime_get();
 
spin_lock_irqsave(_lock, flags);
list_add_rcu(>entry, _sources);
diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c
index dfba59b..4210152 100644
--- a/kernel/power/wakelock.c
+++ b/kernel/power/wakelock.c
@@ -188,6 +188,7 @@ static struct wakelock *wakelock_lookup_add(const char 
*name, size_t len,
return ERR_PTR(-ENOMEM);
}
wl->ws.name = wl->name;
+   wl->ws.last_time = ktime_get();
wakeup_source_add(>ws);
rb_link_node(>node, parent, node);
rb_insert_color(>node, _tree);
-- 
2.7.4



[PATCH] PM / Sleep: only update last time for active wakeup sources

2018-04-25 Thread Doug Berger
When wakelock support was added, the wakeup_source_add() function
was updated to set the last_time value of the wakeup source. This
has the unintended side effect of producing confusing output from
pm_print_active_wakeup_sources() when a wakeup source is added
prior to a sleep that is blocked by a different wakeup source.

The function pm_print_active_wakeup_sources() will search for the
most recently active wakeup source when no active source is found.
If a wakeup source is added after a different wakeup source blocks
the system from going to sleep it may have a later last_time value
than the blocking source and be output as the last active wakeup
source even if it has never actually been active.

It looks to me like the change to wakeup_source_add() was made to
prevent the wakelock garbage collection from accidentally dropping
a wakelock during the narrow window between adding the wakelock to
the wakelock list in wakelock_lookup_add() and the activation of
the wakeup source in pm_wake_lock().

This commit changes the behavior so that only the last_time of the
wakeup source used by a wakelock is initialized prior to adding it
to the wakeup source list. This preserves the meaning of the
last_time value as the last time the wakeup source was active and
allows a wakeup source that has never been active to have a
last_time value of 0.

Fixes: b86ff982 ("PM / Sleep: Add user space interface for manipulating wakeup 
sources, v3")
Signed-off-by: Doug Berger 
---
 drivers/base/power/wakeup.c | 1 -
 kernel/power/wakelock.c | 1 +
 2 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index ea01621..230160e 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -183,7 +183,6 @@ void wakeup_source_add(struct wakeup_source *ws)
spin_lock_init(>lock);
timer_setup(>timer, pm_wakeup_timer_fn, 0);
ws->active = false;
-   ws->last_time = ktime_get();
 
spin_lock_irqsave(_lock, flags);
list_add_rcu(>entry, _sources);
diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c
index dfba59b..4210152 100644
--- a/kernel/power/wakelock.c
+++ b/kernel/power/wakelock.c
@@ -188,6 +188,7 @@ static struct wakelock *wakelock_lookup_add(const char 
*name, size_t len,
return ERR_PTR(-ENOMEM);
}
wl->ws.name = wl->name;
+   wl->ws.last_time = ktime_get();
wakeup_source_add(>ws);
rb_link_node(>node, parent, node);
rb_insert_color(>node, _tree);
-- 
2.7.4



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 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 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



[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 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 
---
 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 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 
---
 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 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 
---
 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 
---
 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);
if (err)
@@ -3660,9 +3630,7 @@

[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 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 
---
 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 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 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 
---
 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 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 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 
---
 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 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 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 
---
 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 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



[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



[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 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 
---
 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 v2 1/7] gpio: brcmstb: Do not use gc->pin2mask()

2017-10-24 Thread Doug Berger
From: Linus Walleij 

The pin2mask() accessor only shuffles BIT ORDER in big endian systems,
i.e. the bitstuffing is swizzled big endian so "bit 0" is bit 7 or
bit 15 or bit 31 or so.

The brcmstb only uses big endian BYTE ORDER which will be taken car of
by the ->write_reg() callback.

Just use BIT(offset) to assign the bit.

Cc: Gregory Fong 
Cc: Florian Fainelli 
Signed-off-by: Linus Walleij 
---
 drivers/gpio/gpio-brcmstb.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c
index 27e92e57adae..9b8fcca7ad17 100644
--- a/drivers/gpio/gpio-brcmstb.c
+++ b/drivers/gpio/gpio-brcmstb.c
@@ -20,6 +20,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #define GIO_BANK_SIZE   0x20
 #define GIO_ODEN(bank)  (((bank) * GIO_BANK_SIZE) + 0x00)
@@ -68,16 +69,15 @@ static void brcmstb_gpio_set_imask(struct brcmstb_gpio_bank 
*bank,
 {
struct gpio_chip *gc = >gc;
struct brcmstb_gpio_priv *priv = bank->parent_priv;
-   u32 mask = gc->pin2mask(gc, offset);
u32 imask;
unsigned long flags;
 
spin_lock_irqsave(>bgpio_lock, flags);
imask = gc->read_reg(priv->reg_base + GIO_MASK(bank->id));
if (enable)
-   imask |= mask;
+   imask |= BIT(offset);
else
-   imask &= ~mask;
+   imask &= ~BIT(offset);
gc->write_reg(priv->reg_base + GIO_MASK(bank->id), imask);
spin_unlock_irqrestore(>bgpio_lock, flags);
 }
-- 
2.14.1



[PATCH v2 1/7] gpio: brcmstb: Do not use gc->pin2mask()

2017-10-24 Thread Doug Berger
From: Linus Walleij 

The pin2mask() accessor only shuffles BIT ORDER in big endian systems,
i.e. the bitstuffing is swizzled big endian so "bit 0" is bit 7 or
bit 15 or bit 31 or so.

The brcmstb only uses big endian BYTE ORDER which will be taken car of
by the ->write_reg() callback.

Just use BIT(offset) to assign the bit.

Cc: Gregory Fong 
Cc: Florian Fainelli 
Signed-off-by: Linus Walleij 
---
 drivers/gpio/gpio-brcmstb.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c
index 27e92e57adae..9b8fcca7ad17 100644
--- a/drivers/gpio/gpio-brcmstb.c
+++ b/drivers/gpio/gpio-brcmstb.c
@@ -20,6 +20,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #define GIO_BANK_SIZE   0x20
 #define GIO_ODEN(bank)  (((bank) * GIO_BANK_SIZE) + 0x00)
@@ -68,16 +69,15 @@ static void brcmstb_gpio_set_imask(struct brcmstb_gpio_bank 
*bank,
 {
struct gpio_chip *gc = >gc;
struct brcmstb_gpio_priv *priv = bank->parent_priv;
-   u32 mask = gc->pin2mask(gc, offset);
u32 imask;
unsigned long flags;
 
spin_lock_irqsave(>bgpio_lock, flags);
imask = gc->read_reg(priv->reg_base + GIO_MASK(bank->id));
if (enable)
-   imask |= mask;
+   imask |= BIT(offset);
else
-   imask &= ~mask;
+   imask &= ~BIT(offset);
gc->write_reg(priv->reg_base + GIO_MASK(bank->id), imask);
spin_unlock_irqrestore(>bgpio_lock, flags);
 }
-- 
2.14.1



[PATCH v2 5/7] gpio: brcmstb: correct the configuration of level interrupts

2017-10-24 Thread Doug Berger
This commit corrects a bug when configuring the GPIO hardware for
IRQ_TYPE_LEVEL_LOW and IRQ_TYPE_LEVEL_HIGH interrupt types. The
hardware is now correctly configured to support those types.

Fixes: 19a7b6940b78 ("gpio: brcmstb: Add interrupt and wakeup source support")
Signed-off-by: Doug Berger <open...@gmail.com>
Reviewed-by: Florian Fainelli <f.faine...@gmail.com>
Acked-by: Gregory Fong <gregory.0...@gmail.com>
---
 drivers/gpio/gpio-brcmstb.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c
index 513de4936a25..183863902f7f 100644
--- a/drivers/gpio/gpio-brcmstb.c
+++ b/drivers/gpio/gpio-brcmstb.c
@@ -137,13 +137,13 @@ static int brcmstb_gpio_irq_set_type(struct irq_data *d, 
unsigned int type)
 
switch (type) {
case IRQ_TYPE_LEVEL_LOW:
-   level = 0;
+   level = mask;
edge_config = 0;
edge_insensitive = 0;
break;
case IRQ_TYPE_LEVEL_HIGH:
level = mask;
-   edge_config = 0;
+   edge_config = mask;
edge_insensitive = 0;
break;
case IRQ_TYPE_EDGE_FALLING:
-- 
2.14.1



  1   2   3   4   >