* [PATCH iwl-next v2] ice: call netif_keep_dst() once when entering switchdev mode
From: Aleksandr Loktionov @ 2026-04-08 14:14 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov
Cc: netdev, Marcin Szycik
From: Marcin Szycik <marcin.szycik@intel.com>
netif_keep_dst() only needs to be called once for the uplink VSI, not
once for each port representor. Move it from ice_eswitch_setup_repr()
to ice_eswitch_enable_switchdev().
Fixes: defd52455aee ("ice: do Tx through PF netdev in slow-path")
Signed-off-by: Marcin Szycik <marcin.szycik@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
v1 -> v2:
- Verified Fixes: tag via bisect - defd52455aee introduced the redundant
per-repr call to netif_keep_dst(uplink_vsi->netdev) by changing the
target netdev to the uplink VSI inside the per-representor setup
function. Before that commit, each call was on a distinct repr->netdev
so no Fixes: predating it applies.
drivers/net/ethernet/intel/ice/ice_eswitch.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c
index 2e4f096..c30e27b 100644
--- a/drivers/net/ethernet/intel/ice/ice_eswitch.c
+++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c
@@ -117,8 +117,6 @@ static int ice_eswitch_setup_repr(struct ice_pf *pf, struct ice_repr *repr)
if (!repr->dst)
return -ENOMEM;
- netif_keep_dst(uplink_vsi->netdev);
-
dst = repr->dst;
dst->u.port_info.port_id = vsi->vsi_num;
dst->u.port_info.lower_dev = uplink_vsi->netdev;
@@ -312,6 +310,8 @@ static int ice_eswitch_enable_switchdev(struct ice_pf *pf)
if (ice_eswitch_br_offloads_init(pf))
goto err_br_offloads;
+ netif_keep_dst(uplink_vsi->netdev);
+
pf->eswitch.is_running = true;
return 0;
--
2.52.0
^ permalink raw reply related
* [PATCH net v2] ice: fix ice_init_link() error return preventing probe
From: Aleksandr Loktionov @ 2026-04-08 14:11 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov
Cc: netdev, Paul Greenwalt, Simon Horman
From: Paul Greenwalt <paul.greenwalt@intel.com>
ice_init_link() can return an error status from ice_update_link_info()
or ice_init_phy_user_cfg(), causing probe to fail.
An incorrect NVM update procedure can result in link/PHY errors, and
the recommended resolution is to update the NVM using the correct
procedure. If the driver fails probe due to link errors, the user
cannot update the NVM to recover. The link/PHY errors logged are
non-fatal: they are already annotated as 'not a fatal error if this
fails'.
Since none of the errors inside ice_init_link() should prevent probe
from completing, convert it to void and remove the error check in the
caller. All failures are already logged; callers have no meaningful
recovery path for link init errors.
Fixes: 5b246e533d01 ("ice: split probe into smaller functions")
Cc: stable@vger.kernel.org
Signed-off-by: Paul Greenwalt <paul.greenwalt@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
---
v1 -> v2:
- Rename the now-unused goto label err_init_link to err_deinit_pf_sw
to better describe the cleanup it performs (Simon Horman).
drivers/net/ethernet/intel/ice/ice_main.c | 16 +++++-----------
1 file changed, 5 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index cf116bb..a6b0c09 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -4856,16 +4856,14 @@ static void ice_init_wakeup(struct ice_pf *pf)
device_set_wakeup_enable(ice_pf_to_dev(pf), false);
}
-static int ice_init_link(struct ice_pf *pf)
+static void ice_init_link(struct ice_pf *pf)
{
struct device *dev = ice_pf_to_dev(pf);
int err;
err = ice_init_link_events(pf->hw.port_info);
- if (err) {
+ if (err)
dev_err(dev, "ice_init_link_events failed: %d\n", err);
- return err;
- }
/* not a fatal error if this fails */
err = ice_init_nvm_phy_type(pf->hw.port_info);
@@ -4899,8 +4897,6 @@ static int ice_init_link(struct ice_pf *pf)
} else {
set_bit(ICE_FLAG_NO_MEDIA, pf->flags);
}
-
- return err;
}
static int ice_init_pf_sw(struct ice_pf *pf)
@@ -5043,11 +5039,9 @@ static int ice_init(struct ice_pf *pf)
ice_init_wakeup(pf);
- err = ice_init_link(pf);
- if (err)
- goto err_init_link;
+ ice_init_link(pf);
err = ice_send_version(pf);
if (err)
- goto err_init_link;
+ goto err_deinit_pf_sw;
@@ -5069,7 +5063,7 @@ static int ice_init(struct ice_pf *pf)
return 0;
-err_init_link:
+err_deinit_pf_sw:
ice_deinit_pf_sw(pf);
err_init_pf_sw:
ice_dealloc_vsis(pf);
unroll_pf_init:
--
2.52.0
^ permalink raw reply related
* linux-next: manual merge of the net-next tree with the netfilter tree
From: Mark Brown @ 2026-04-08 14:10 UTC (permalink / raw)
To: David Miller, Jakub Kicinski, Paolo Abeni, Networking
Cc: Andrea Mayer, Justin Iurman, Linux Kernel Mailing List,
Linux Next Mailing List
[-- Attachment #1: Type: text/plain, Size: 1152 bytes --]
Hi all,
Today's linux-next merge of the net-next tree got a conflict in:
net/ipv6/seg6_iptunnel.c
between commit:
c3812651b522f ("seg6: separate dst_cache for input and output paths in seg6 lwtunnel")
from the netfilter tree and commit:
78723a62b969a ("seg6: add per-route tunnel source address")
from the net-next tree.
I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging. You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.
diff --cc net/ipv6/seg6_iptunnel.c
index d6a0f7df90807,e76cc0cc481ec..0000000000000
--- a/net/ipv6/seg6_iptunnel.c
+++ b/net/ipv6/seg6_iptunnel.c
@@@ -48,8 -48,8 +48,9 @@@ static size_t seg6_lwt_headroom(struct
}
struct seg6_lwt {
- struct dst_cache cache;
+ struct dst_cache cache_input;
+ struct dst_cache cache_output;
+ struct in6_addr tunsrc;
struct seg6_iptunnel_encap tuninfo[];
};
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [Intel-wired-lan] [PATCH iwl-next v2 7/8] ixgbe: use GFP_KERNEL in ixgbe_fcoe_ddp_setup()
From: Kohei Enju @ 2026-04-08 14:09 UTC (permalink / raw)
To: Aleksandr Loktionov; +Cc: intel-wired-lan, anthony.l.nguyen, netdev
In-Reply-To: <20260408131216.2662245-8-aleksandr.loktionov@intel.com>
On 04/08 15:12, Aleksandr Loktionov wrote:
> ixgbe_fcoe_ddp_setup() is always called from process context (FCoE
> offload setup paths) and never from an atomic context. Using GFP_ATOMIC
As I mentioned in v1, I don't think this path is non-atomic.
fc_exch_seq_send()
fc_exch_alloc() # acquires ep->ex_lock (spinlock) internally
fc_fcp_ddp_setup()
lport->tt.ddp_setup() == fcoe_ddp_setup()
.ndo_fcoe_ddp_setup() == ixgbe_fcoe_ddp_get()
ixgbe_fcoe_ddp_setup()
...
spin_unlock_bh(&ep->ex_lock);
So even if this runs in process context, it still appears to be in
atomic context while ep->ex_lock is held and also bh is disabled.
GFP_KERNEL still looks unsafe here for me.
If I'm misreading something, please let me know.
Thanks.
^ permalink raw reply
* Re: BUG: net-next (7.0-rc6 based and later) fails to boot on Jetson Xavier NX
From: Russell King (Oracle) @ 2026-04-08 13:59 UTC (permalink / raw)
To: netdev, linux-arm-kernel, linux-kernel, iommu, linux-ext4,
Linus Torvalds
Cc: Marek Szyprowski, Robin Murphy, Theodore Ts'o, Andreas Dilger
In-Reply-To: <adZTGOjjJrVJOcT8@shell.armlinux.org.uk>
On Wed, Apr 08, 2026 at 02:07:36PM +0100, Russell King (Oracle) wrote:
> Hi,
>
> Just a heads-up that current net-next (v7.0-rc6 based) fails to boot on
> my nVidia Jetson Xavier platform. v7.0-rc5 and v6.14 based net-next both
> boot fine. This is an arm64 platform.
>
> The problem appears to be completely random in terms of its symptoms,
> and looks like severe memory corruption - every boot seems to produce
> a different problem. The common theme is, although the kernel gets to
> userspace, it never gets anywhere close to a login prompt before
> failing in some way.
>
> The last net-next+ boot (which is currently v7.0-rc6 based) resulted
> in:
>
> tegra-mc 2c00000.memory-controller: xusb_hostw: secure write @0x00000003ffffff00: VPR violation ((null))
> ...
> irq 91: nobody cared (try booting with the "irqpoll" option)
> ...
> depmod: ERROR: could not open directory /lib/modules/7.0.0-rc6-net-next+: No such file or directory
> ...
> Unable to handle kernel paging request at virtual address 0003201fd50320cf
>
>
> A previous boot of the exact same kernel didn't oops, but was unable
> to find the block device to mount for /mnt via block UUID.
>
> A previous boot to that resulted in an oops.
>
>
> The intersting thing is - the depmod error above is incorrect:
>
> root@tegra-ubuntu:~# ls -ld /lib/modules/7.0.0-rc6-net-next+
> drwxrwxr-x 3 root root 4096 Apr 8 10:23 /lib/modules/7.0.0-rc6-net-next+
>
> The directory is definitely there, and is readable - checked after
> booting back into net-next based on 7.0-rc5. In some of these boots,
> stmmac hasn't probed yet, which rules out my changes.
>
> Rootfs is ext4, and it seems there were a lot of ext4 commits merged
> between rc5 and rc6, but nothing for rc7.
>
> My current net-next head is dfecb0c5af3b. Merging rc7 on top also
> fails, I suspect also randomly, with that I just got:
>
> EXT4-fs (mmcblk0p1): VFS: Can't find ext4 filesystem
> mount: /mnt: wrong fs type, bad option, bad superblock on /dev/mmcblk0p1, missing codepage or helper program, or other error.
> mount: /mnt/: can't find PARTUUID=741c0777-391a-4bce-a222-455e180ece2a.
> Unable to handle kernel paging request at virtual address f9bf0011ac0fb893
> Mem abort info:
> ESR = 0x0000000096000004
> EC = 0x25: DABT (current EL), IL = 32 bits
> SET = 0, FnV = 0
> EA = 0, S1PTW = 0
> FSC = 0x04: level 0 translation fault
> Data abort info:
> ISV = 0, ISS = 0x00000004, ISS2 = 0x00000000
> CM = 0, WnR = 0, TnD = 0, TagAccess = 0
> GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
> [f9bf0011ac0fb893] address between user and kernel address ranges
> Internal error: Oops: 0000000096000004 [#1] SMP
> Modules linked in:
> CPU: 1 UID: 0 PID: 936 Comm: mount Not tainted 7.0.0-rc7-net-next+ #649 PREEMPT
> Hardware name: NVIDIA NVIDIA Jetson Xavier NX Developer Kit/Jetson, BIOS 6.0-37391689 08/28/2024
> pstate: 20400009 (nzCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
> pc : refill_objects+0x298/0x5ec
> lr : refill_objects+0x1f0/0x5ec
>
> ...
>
> Call trace:
> refill_objects+0x298/0x5ec (P)
> __pcs_replace_empty_main+0x13c/0x3a8
> kmem_cache_alloc_noprof+0x324/0x3a0
> alloc_iova+0x3c/0x290
> alloc_iova_fast+0x168/0x2d4
> iommu_dma_alloc_iova+0x84/0x154
> iommu_dma_map_sg+0x2c4/0x538
> __dma_map_sg_attrs+0x124/0x2c0
> dma_map_sg_attrs+0x10/0x20
> sdhci_pre_dma_transfer+0xb8/0x164
> sdhci_pre_req+0x38/0x44
> mmc_blk_mq_issue_rq+0x3dc/0x920
> mmc_mq_queue_rq+0x104/0x2b0
> __blk_mq_issue_directly+0x38/0xb0
> blk_mq_request_issue_directly+0x54/0xb4
> blk_mq_issue_direct+0x84/0x180
> blk_mq_dispatch_queue_requests+0x1a8/0x2e0
> blk_mq_flush_plug_list+0x60/0x140
> __blk_flush_plug+0xe0/0x11c
> blk_finish_plug+0x38/0x4c
> read_pages+0x158/0x260
> page_cache_ra_unbounded+0x158/0x3e0
> force_page_cache_ra+0xb0/0xe4
> page_cache_sync_ra+0x88/0x480
> filemap_get_pages+0xd8/0x850
> filemap_read+0xdc/0x3d8
> blkdev_read_iter+0x84/0x198
> vfs_read+0x208/0x2d8
> ksys_read+0x58/0xf4
> __arm64_sys_read+0x1c/0x28
> invoke_syscall.constprop.0+0x50/0xe0
> do_el0_svc+0x40/0xc0
> el0_svc+0x48/0x2a0
> el0t_64_sync_handler+0xa0/0xe4
> el0t_64_sync+0x19c/0x1a0
> Code: 54000189 f9000022 aa0203e4 b9402ae3 (f8634840)
> ---[ end trace 0000000000000000 ]---
> Kernel panic - not syncing: Oops: Fatal exception
>
> Looking at the changes between rc5 and rc6, there's one drivers/block
> change for zram (which is used on this platform), one change in
> drivers/base for regmap, nothing for drivers/mmc, but plenty for
> fs/ext4. There are five DMA API changes.
>
> Now building straight -rc7. If that also fails, my plan is to start
> bisecting rc5..rc6, which will likely take most of the rest of the
> day. So, in the mean time I'm sending this as a heads-up that rc6
> and onwards has a problem.
Plain -rc7 fails (another random oops):
Root device found: PARTUUID=741c0777-391a-4bce-a222-455e180ece2a
depmod: ERROR: could not open directory /lib/modules/7.0.0-rc7-net-next+: No such file or directory
depmod: FATAL: could not search modules: No such file or directory
usb 2-3: new SuperSpeed Plus Gen 2x1 USB device number 2 using tegra-xusb
hub 2-3:1.0: USB hub found
hub 2-3:1.0: 4 ports detected
usb 1-3: new full-speed USB device number 3 using tegra-xusb
Unable to handle kernel paging request at virtual address 0003201fd50320cf
Mem abort info:
ESR = 0x0000000096000004
EC = 0x25: DABT (current EL), IL = 32 bits
SET = 0, FnV = 0
EA = 0, S1PTW = 0
FSC = 0x04: level 0 translation fault
Data abort info:
ISV = 0, ISS = 0x00000004, ISS2 = 0x00000000
CM = 0, WnR = 0, TnD = 0, TagAccess = 0
GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
[0003201fd50320cf] address between user and kernel address ranges
Internal error: Oops: 0000000096000004 [#1] SMP
Modules linked in:
CPU: 1 UID: 0 PID: 917 Comm: mount Not tainted 7.0.0-rc7-net-next+ #649 PREEMPT
Hardware name: NVIDIA NVIDIA Jetson Xavier NX Developer Kit/Jetson, BIOS 6.0-37391689 08/28/2024
pstate: 20400009 (nzCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
pc : refill_objects+0x298/0x5ec
lr : refill_objects+0x1f0/0x5ec
sp : ffff80008606b500
x29: ffff80008606b500 x28: 0000000000000001 x27: fffffdffc20e6200
x26: 0000000000000006 x25: 0000000000000000 x24: 000000000000003c
x23: ffff0000809e4840 x22: ffff0000809dba00 x21: ffff80008606b5a0
x20: ffff000081133820 x19: fffffdffc20e6220 x18: 0000000000000000
x17: 0000000000000000 x16: 0000000000000100 x15: 0000000000000000
x14: 0000000000000000 x13: 0000000000000000 x12: ffff800081e5faa8
x11: ffff800082192c70 x10: ffff8000814074dc x9 : 0000000000000050
x8 : ffff80008606b490 x7 : ffff000083988b40 x6 : ffff80008606b4a0
x5 : 000000080015000f x4 : d503201fd503201f x3 : 00000000000000b0
x2 : d503201fd503201f x1 : ffff000081133828 x0 : d503201fd503201f
Call trace:
refill_objects+0x298/0x5ec (P)
__pcs_replace_empty_main+0x13c/0x3a8
kmem_cache_alloc_noprof+0x324/0x3a0
mempool_alloc_slab+0x1c/0x28
mempool_alloc_noprof+0x98/0xe0
bio_alloc_bioset+0x160/0x3e0
do_mpage_readpage+0x3d0/0x618
mpage_readahead+0xb8/0x144
blkdev_readahead+0x18/0x24
read_pages+0x58/0x260
page_cache_ra_unbounded+0x158/0x3e0
force_page_cache_ra+0xb0/0xe4
page_cache_sync_ra+0x88/0x480
filemap_get_pages+0xd8/0x850
filemap_read+0xdc/0x3d8
blkdev_read_iter+0x84/0x198
vfs_read+0x208/0x2d8
ksys_read+0x58/0xf4
__arm64_sys_read+0x1c/0x28
invoke_syscall.constprop.0+0x50/0xe0
do_el0_svc+0x40/0xc0
el0_svc+0x48/0x2a0
el0t_64_sync_handler+0xa0/0xe4
el0t_64_sync+0x19c/0x1a0
Code: 54000189 f9000022 aa0203e4 b9402ae3 (f8634840)
---[ end trace 0000000000000000 ]---
Now starting the bisect between 7.0-rc5 and 7.0-rc6.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!
^ permalink raw reply
* Re: [PATCH net-next v3 0/4] net: move .getsockopt away from __user buffers
From: Stefan Metzmacher @ 2026-04-08 13:56 UTC (permalink / raw)
To: David Laight, Breno Leitao
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Kuniyuki Iwashima, Willem de Bruijn, axboe,
Stanislav Fomichev, io-uring, bpf, netdev, Linus Torvalds,
linux-kernel, kernel-team
In-Reply-To: <20260408122653.295953dd@pumpkin>
Am 08.04.26 um 13:26 schrieb David Laight:
> On Wed, 08 Apr 2026 03:30:28 -0700
> Breno Leitao <leitao@debian.org> wrote:
>
>> Currently, the .getsockopt callback requires __user pointers:
>>
>> int (*getsockopt)(struct socket *sock, int level,
>> int optname, char __user *optval, int __user *optlen);
>>
>> This prevents kernel callers (io_uring, BPF) from using getsockopt on
>> levels other than SOL_SOCKET, since they pass kernel pointers.
>>
>> Following Linus' suggestion [0], this series introduces sockopt_t, a
>> type-safe wrapper around iov_iter, and a getsockopt_iter callback that
>> works with both user and kernel buffers. AF_PACKET and CAN raw are
>> converted as initial users, with selftests covering the trickiest
>> conversion patterns.
>
> What are you doing about the cases where 'optlen' is a complete lie?
> IIRC there is one related to some form of async io where it is just
> the length of the header, the actual buffer length depends on
> data in the header.
> This doesn't matter with the existing code for applications, when they
> get it wrong they just crash.
> But kernel users will need to pass the actual buffer length separately
> from optlen.
> It also affects any code that tries to cache the actual data and copy
> it back to userspace in the syscall wrapper - which makes sense for
> most short getsockopt.
>
> (This is different from historic code where the length might be
> assumed to be 4 regardless of what was passed.)
As the insane legacy cases can only happen for keeping
compatibility with existing userspace applications,
we could get the original optval and optlen __user pointers
out of sockopt_t again via something like:
char __user * __must_check sockopt_get_insame_legacy_optval(sockopt_t *sopt);
int __user * __must_check sockopt_get_insame_legacy_optlen(sockopt_t *sopt);
And for kernel callers they return NULL and the code should
turn that into -EINVAL or something similar.
Then legacy stuff can do what they need, but most things are
sane and able to be called via io_uring and in kernel users.
Unrelated to legacy stuff I think it should be an opt-in
(or at least opt-out) for the writeback of optlen.
metze
^ permalink raw reply
* Re: [PATCH net-next v3 0/4] net: move .getsockopt away from __user buffers
From: Breno Leitao @ 2026-04-08 13:52 UTC (permalink / raw)
To: David Laight
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Kuniyuki Iwashima, Willem de Bruijn, metze, axboe,
Stanislav Fomichev, io-uring, bpf, netdev, Linus Torvalds,
linux-kernel, kernel-team
In-Reply-To: <20260408122653.295953dd@pumpkin>
Hello David,
On Wed, Apr 08, 2026 at 12:26:53PM +0100, David Laight wrote:
> On Wed, 08 Apr 2026 03:30:28 -0700
> Breno Leitao <leitao@debian.org> wrote:
>
> > Currently, the .getsockopt callback requires __user pointers:
> >
> > int (*getsockopt)(struct socket *sock, int level,
> > int optname, char __user *optval, int __user *optlen);
> >
> > This prevents kernel callers (io_uring, BPF) from using getsockopt on
> > levels other than SOL_SOCKET, since they pass kernel pointers.
> >
> > Following Linus' suggestion [0], this series introduces sockopt_t, a
> > type-safe wrapper around iov_iter, and a getsockopt_iter callback that
> > works with both user and kernel buffers. AF_PACKET and CAN raw are
> > converted as initial users, with selftests covering the trickiest
> > conversion patterns.
>
> What are you doing about the cases where 'optlen' is a complete lie?
Is this incorrect optlen originating from userspace, and getting into
the .getsockopt callbacks?
> IIRC there is one related to some form of async io where it is just
> the length of the header, the actual buffer length depends on
> data in the header.
Could you point me to the relevant code so I can examine this case?
> This doesn't matter with the existing code for applications, when they
> get it wrong they just crash.
Is this crash being triggered by the protocol callbacks?
I tried searching for this but couldn't find it. I'd appreciate any
hints you could provide about this case.
Thanks
--breno
^ permalink raw reply
* Re: [PATCH net-next] net: phy: fix a return path in get_phy_c45_ids()
From: Andrew Lunn @ 2026-04-08 13:48 UTC (permalink / raw)
To: Charles Perry
Cc: netdev, Heiner Kallweit, Russell King, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Florian Fainelli,
linux-kernel
In-Reply-To: <20260408133145.1177417-1-charles.perry@microchip.com>
On Wed, Apr 08, 2026 at 06:31:44AM -0700, Charles Perry wrote:
> The return value of phy_c45_probe_present() is store in "ret", not
> "phy_reg", fix this. "phy_reg" always has a positive value if we reach
> this return path (since it would have returned earlier otherwise), which
> means that the original goal of the patch of not considering -ENODEV
> fatal wasn't achieved.
>
> Fixes: 17b447539408 ("net: phy: c45 scanning: Don't consider -ENODEV fatal")
> Signed-off-by: Charles Perry <charles.perry@microchip.com>
Thanks for fixing this.
The Subject line should be [PATCH net] since this is a Fix.
Otherwise:
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply
* Re: [PATCH v4 net-next 02/14] dt-bindings: net: dsa: add NETC switch
From: Rob Herring @ 2026-04-08 13:43 UTC (permalink / raw)
To: Wei Fang
Cc: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, krzk+dt, conor+dt, f.fainelli,
frank.li, chleroy, horms, linux, andrew, netdev, linux-kernel,
devicetree, linuxppc-dev, linux-arm-kernel, imx
In-Reply-To: <20260331113025.1566878-3-wei.fang@nxp.com>
On Tue, Mar 31, 2026 at 07:30:13PM +0800, Wei Fang wrote:
> Add bindings for NETC switch. This switch is a PCIe function of NETC IP,
> it supports advanced QoS with 8 traffic classes and 4 drop resilience
> levels, and a full range of TSN standards capabilities. The switch CPU
> port connects to an internal ENETC port, which is also a PCIe function
> of NETC IP. So these two ports use a light-weight "pseudo MAC" instead
> of a back-to-back MAC, because the "pseudo MAC" provides the delineation
> between switch and ENETC, this translates to lower power (less logic and
> memory) and lower delay (as there is no serialization delay across this
> link).
>
> Signed-off-by: Wei Fang <wei.fang@nxp.com>
> Reviewed-by: Frank Li <Frank.Li@nxp.com>
> ---
> .../bindings/net/dsa/nxp,netc-switch.yaml | 130 ++++++++++++++++++
> 1 file changed, 130 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/net/dsa/nxp,netc-switch.yaml
>
> diff --git a/Documentation/devicetree/bindings/net/dsa/nxp,netc-switch.yaml b/Documentation/devicetree/bindings/net/dsa/nxp,netc-switch.yaml
> new file mode 100644
> index 000000000000..5577f3ef987f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/dsa/nxp,netc-switch.yaml
> @@ -0,0 +1,130 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/net/dsa/nxp,netc-switch.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: NETC Switch family
> +
> +description: >
> + The NETC presents itself as a multi-function PCIe Root Complex Integrated
> + Endpoint (RCiEP) and provides full 802.1Q Ethernet switch functionality,
> + advanced QoS with 8 traffic classes and 4 drop resilience levels, and a
> + full range of TSN standards capabilities.
> +
> + The CPU port of the switch connects to an internal ENETC. The switch and
> + the internal ENETC are fully integrated into the NETC IP, a back-to-back
> + MAC is not required. Instead, a light-weight "pseudo MAC" provides the
> + delineation between the switch and ENETC. This translates to lower power
> + (less logic and memory) and lower delay (as there is no serialization
> + delay across this link).
> +
> +maintainers:
> + - Wei Fang <wei.fang@nxp.com>
> +
> +properties:
> + compatible:
> + enum:
> + - pci1131,eef2
> +
> + reg:
> + maxItems: 1
> +
> + dsa,member:
> + description: >
> + The property indicates DSA cluster and switch index. For NETC switch,
> + the valid range of the switch index is 1 ~ 7, the index is reflected
> + in the switch tag as an indication of the switch ID where the frame
> + originated. The value 0 is reserved for ENETC VEPA switch, whose ID
> + is hardwired to zero.
> +
> +$ref: dsa.yaml#
Move this under the 'allOf' so all $ref's are together.
> +
> +patternProperties:
> + "^(ethernet-)?ports$":
'ethernet-ports' for new bindings.
> + type: object
> + additionalProperties: true
> + patternProperties:
> + "^(ethernet-)?port@[0-9a-f]$":
And 'ethernet-port'
> + type: object
> +
> + $ref: dsa-port.yaml#
> +
> + properties:
> + clocks:
> + items:
> + - description: MAC transmit/receive reference clock.
> +
> + clock-names:
> + items:
> + - const: ref
> +
> + mdio:
> + $ref: /schemas/net/mdio.yaml#
> + unevaluatedProperties: false
> + description:
> + Optional child node for switch port, otherwise use NETC EMDIO.
> +
> + unevaluatedProperties: false
> +
> +required:
> + - compatible
> + - reg
> + - dsa,member
> +
> +allOf:
> + - $ref: /schemas/pci/pci-device.yaml
> +
> +unevaluatedProperties: false
> +
> +examples:
> + - |
> + pcie {
> + #address-cells = <3>;
> + #size-cells = <2>;
> +
> + ethernet-switch@0,2 {
> + compatible = "pci1131,eef2";
> + reg = <0x200 0 0 0 0>;
> + dsa,member = <0 1>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_switch>;
> +
> + ports {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + port@0 {
> + reg = <0>;
> + phy-handle = <ðphy0>;
> + phy-mode = "mii";
> + };
> +
> + port@1 {
> + reg = <1>;
> + phy-handle = <ðphy1>;
> + phy-mode = "mii";
> + };
> +
> + port@2 {
> + reg = <2>;
> + clocks = <&scmi_clk 103>;
> + clock-names = "ref";
> + phy-handle = <ðphy2>;
> + phy-mode = "rgmii-id";
> + };
> +
> + port@3 {
> + reg = <3>;
> + ethernet = <&enetc3>;
> + phy-mode = "internal";
> +
> + fixed-link {
> + speed = <2500>;
> + full-duplex;
> + pause;
> + };
> + };
> + };
> + };
> + };
> --
> 2.34.1
>
^ permalink raw reply
* Re: [PATCH v4 net-next 01/14] dt-bindings: net: dsa: update the description of 'dsa,member' property
From: Rob Herring (Arm) @ 2026-04-08 13:40 UTC (permalink / raw)
To: Wei Fang
Cc: claudiu.manoil, kuba, andrew, linux, davem, frank.li, edumazet,
imx, pabeni, devicetree, horms, conor+dt, netdev, linuxppc-dev,
andrew+netdev, f.fainelli, linux-kernel, xiaoning.wang, krzk+dt,
vladimir.oltean, linux-arm-kernel, chleroy
In-Reply-To: <20260331113025.1566878-2-wei.fang@nxp.com>
On Tue, 31 Mar 2026 19:30:12 +0800, Wei Fang wrote:
> The current description indicates that the 'dsa,member' property cannot
> be set for a switch that is not part of any cluster. Vladimir thinks
> that this is a case where the actual technical limitation was poorly
> transposed into words when this restriction was first documented, in
> commit 8c5ad1d6179d ("net: dsa: Document new binding").
>
> The true technical limitation is that many DSA tagging protocols are
> topology-unaware, and always call dsa_conduit_find_user() with a
> switch_id of 0. Specifying a custom "dsa,member" property with a
> non-zero switch_id would break them.
>
> Therefore, for topology-aware switches, it is fine to specify this
> property for them, even if they are not part of any cluster. Our NETC
> switch is a good example which is topology-aware, the switch_id is
> carried in the switch tag, but the switch_id 0 is reserved for VEPA
> switch and cannot be used, so we need to use this property to assign
> a non-zero switch_id for it.
>
> Suggested-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> Signed-off-by: Wei Fang <wei.fang@nxp.com>
> ---
> Documentation/devicetree/bindings/net/dsa/dsa.yaml | 6 +++++-
> 1 file changed, 5 insertions(+), 1 deletion(-)
>
Acked-by: Rob Herring (Arm) <robh@kernel.org>
^ permalink raw reply
* [PATCH net-next] net: phy: fix a return path in get_phy_c45_ids()
From: Charles Perry @ 2026-04-08 13:31 UTC (permalink / raw)
To: netdev
Cc: Charles Perry, Andrew Lunn, Heiner Kallweit, Russell King,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Florian Fainelli, linux-kernel
The return value of phy_c45_probe_present() is store in "ret", not
"phy_reg", fix this. "phy_reg" always has a positive value if we reach
this return path (since it would have returned earlier otherwise), which
means that the original goal of the patch of not considering -ENODEV
fatal wasn't achieved.
Fixes: 17b447539408 ("net: phy: c45 scanning: Don't consider -ENODEV fatal")
Signed-off-by: Charles Perry <charles.perry@microchip.com>
---
drivers/net/phy/phy_device.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 81984d4ebb7c..810327fa886a 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -973,8 +973,8 @@ static int get_phy_c45_ids(struct mii_bus *bus, int addr,
/* returning -ENODEV doesn't stop bus
* scanning
*/
- return (phy_reg == -EIO ||
- phy_reg == -ENODEV) ? -ENODEV : -EIO;
+ return (ret == -EIO ||
+ ret == -ENODEV) ? -ENODEV : -EIO;
if (!ret)
continue;
--
2.47.3
^ permalink raw reply related
* [PATCH net-next v5 3/3] net: phy: add a PHY write barrier when disabling interrupts
From: Charles Perry @ 2026-04-08 13:18 UTC (permalink / raw)
To: netdev
Cc: MameMaria.Mbaye, Charles Perry, Andrew Lunn, Heiner Kallweit,
Russell King, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, linux-kernel
In-Reply-To: <20260408131821.1145334-1-charles.perry@microchip.com>
MDIO bus controllers are not required to wait for write transactions to
complete before returning as synchronization is often achieved by polling
status bits.
This can cause issues when disabling interrupts since an interrupt could
fire before the interrupt handler is unregistered and there's no status
bit to poll.
Add a phy_write_barrier() function and use it in phy_disable_interrupts()
to fix this issue. The write barrier just reads an MII register and
discards the value, which is enough to guarantee that previous writes have
completed.
Signed-off-by: Charles Perry <charles.perry@microchip.com>
---
Notes:
Changes in v5:
- Support the case where the MDIO controller only supports C45
(Russell, Andrew)
- Make the return type of phy_write_barrier() void
Changes in v4:
- Add this patch (Russell, Andrew)
drivers/net/phy/phy.c | 25 ++++++++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 13dd1691886d..b21ff204c0dc 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -1368,14 +1368,37 @@ void phy_error(struct phy_device *phydev)
}
EXPORT_SYMBOL(phy_error);
+/**
+ * phy_write_barrier - ensure the last write completed for this PHY device
+ * @phydev: target phy_device struct
+ *
+ * MDIO bus controllers are not required to wait for write transactions to
+ * complete before returning. Calling this function ensures that the previous
+ * write has completed.
+ */
+static void phy_write_barrier(struct phy_device *phydev)
+{
+ if (mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, MII_PHYSID1) ==
+ -EOPNOTSUPP)
+ mdiobus_c45_read(phydev->mdio.bus, phydev->mdio.addr,
+ MDIO_MMD_PMAPMD, MII_PHYSID1);
+}
+
/**
* phy_disable_interrupts - Disable the PHY interrupts from the PHY side
* @phydev: target phy_device struct
*/
int phy_disable_interrupts(struct phy_device *phydev)
{
+ int err;
+
/* Disable PHY interrupts */
- return phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED);
+ err = phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED);
+ if (err)
+ return err;
+
+ phy_write_barrier(phydev);
+ return 0;
}
/**
--
2.47.3
^ permalink raw reply related
* [PATCH net-next v5 2/3] net: mdio: add a driver for PIC64-HPSC/HX MDIO controller
From: Charles Perry @ 2026-04-08 13:18 UTC (permalink / raw)
To: netdev
Cc: MameMaria.Mbaye, Charles Perry, Maxime Chevallier, Andrew Lunn,
Heiner Kallweit, Russell King, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, linux-kernel
In-Reply-To: <20260408131821.1145334-1-charles.perry@microchip.com>
This adds an MDIO driver for PIC64-HPSC/HX. The hardware supports C22
and C45 but only C22 is implemented in this commit.
This MDIO hardware is based on a Microsemi design supported in Linux by
mdio-mscc-miim.c. However, The register interface is completely
different with pic64hpsc, hence the need for a separate driver.
The documentation recommends an input clock of 156.25MHz and a prescaler
of 39, which yields an MDIO clock of 1.95MHz.
The hardware supports an interrupt pin or a "TRIGGER" bit that can be
polled to signal transaction completion. This commit uses polling.
This was tested on Microchip HB1301 evalkit with a VSC8574 and a
VSC8541.
Signed-off-by: Charles Perry <charles.perry@microchip.com>
Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
---
Notes:
Changes in v5: none
Changes in v4:
- read: return FIELD_GET() directly instead of using "ret" (Russell)
Changes in v3:
- Add a MAINTAINERS entry (Jakub)
Changes in v2:
- Remove #define for unused registers (Maxime)
- Add "c22" to clause 22 read/write ops (Maxime)
- Remove the call to platform_set_drvdata() (Andrew)
- Make the clock mandatory (Andrew)
- Use 2.5MHz if no clock-frequency was specified (Andrew)
- Change the error message for bad clock-frequency (Andrew)
- Fix a use without initialization on bus_freq (Andrew)
MAINTAINERS | 6 +
drivers/net/mdio/Kconfig | 7 ++
drivers/net/mdio/Makefile | 1 +
drivers/net/mdio/mdio-pic64hpsc.c | 190 ++++++++++++++++++++++++++++++
4 files changed, 204 insertions(+)
create mode 100644 drivers/net/mdio/mdio-pic64hpsc.c
diff --git a/MAINTAINERS b/MAINTAINERS
index e08767323763..9297c46dba91 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17216,6 +17216,12 @@ L: linux-serial@vger.kernel.org
S: Maintained
F: drivers/tty/serial/8250/8250_pci1xxxx.c
+MICROCHIP PIC64-HPSC/HX DRIVERS
+M: Charles Perry <charles.perry@microchip.com>
+S: Supported
+F: Documentation/devicetree/bindings/net/microchip,pic64hpsc-mdio.yaml
+F: drivers/net/mdio/mdio-pic64hpsc.c
+
MICROCHIP POLARFIRE FPGA DRIVERS
M: Conor Dooley <conor.dooley@microchip.com>
L: linux-fpga@vger.kernel.org
diff --git a/drivers/net/mdio/Kconfig b/drivers/net/mdio/Kconfig
index 44380378911b..7bdba8c3ddef 100644
--- a/drivers/net/mdio/Kconfig
+++ b/drivers/net/mdio/Kconfig
@@ -146,6 +146,13 @@ config MDIO_OCTEON
buses. It is required by the Octeon and ThunderX ethernet device
drivers on some systems.
+config MDIO_PIC64HPSC
+ tristate "PIC64-HPSC/HX MDIO interface support"
+ depends on HAS_IOMEM && OF_MDIO
+ help
+ This driver supports the MDIO interface found on the PIC64-HPSC/HX
+ SoCs.
+
config MDIO_IPQ4019
tristate "Qualcomm IPQ4019 MDIO interface support"
depends on HAS_IOMEM && OF_MDIO
diff --git a/drivers/net/mdio/Makefile b/drivers/net/mdio/Makefile
index fbec636700e7..048586746026 100644
--- a/drivers/net/mdio/Makefile
+++ b/drivers/net/mdio/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_MDIO_MOXART) += mdio-moxart.o
obj-$(CONFIG_MDIO_MSCC_MIIM) += mdio-mscc-miim.o
obj-$(CONFIG_MDIO_MVUSB) += mdio-mvusb.o
obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o
+obj-$(CONFIG_MDIO_PIC64HPSC) += mdio-pic64hpsc.o
obj-$(CONFIG_MDIO_REALTEK_RTL9300) += mdio-realtek-rtl9300.o
obj-$(CONFIG_MDIO_REGMAP) += mdio-regmap.o
obj-$(CONFIG_MDIO_SUN4I) += mdio-sun4i.o
diff --git a/drivers/net/mdio/mdio-pic64hpsc.c b/drivers/net/mdio/mdio-pic64hpsc.c
new file mode 100644
index 000000000000..28be77ad6cf7
--- /dev/null
+++ b/drivers/net/mdio/mdio-pic64hpsc.c
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Microchip PIC64-HPSC/HX MDIO controller driver
+ *
+ * Copyright (c) 2026 Microchip Technology Inc. and its subsidiaries.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_mdio.h>
+#include <linux/platform_device.h>
+
+#define MDIO_REG_PRESCALER 0x20
+#define MDIO_CFG_PRESCALE_MASK GENMASK(7, 0)
+
+#define MDIO_REG_FRAME_CFG_1 0x24
+#define MDIO_WDATA_MASK GENMASK(15, 0)
+
+#define MDIO_REG_FRAME_CFG_2 0x28
+#define MDIO_TRIGGER_BIT BIT(31)
+#define MDIO_REG_DEV_ADDR_MASK GENMASK(20, 16)
+#define MDIO_PHY_PRT_ADDR_MASK GENMASK(8, 4)
+#define MDIO_OPERATION_MASK GENMASK(3, 2)
+#define MDIO_START_OF_FRAME_MASK GENMASK(1, 0)
+
+/* Possible value of MDIO_OPERATION_MASK */
+#define MDIO_OPERATION_WRITE BIT(0)
+#define MDIO_OPERATION_READ BIT(1)
+
+#define MDIO_REG_FRAME_STATUS 0x2C
+#define MDIO_READOK_BIT BIT(24)
+#define MDIO_RDATA_MASK GENMASK(15, 0)
+
+struct pic64hpsc_mdio_dev {
+ void __iomem *regs;
+};
+
+static int pic64hpsc_mdio_wait_trigger(struct mii_bus *bus)
+{
+ struct pic64hpsc_mdio_dev *priv = bus->priv;
+ u32 val;
+ int ret;
+
+ /* The MDIO_TRIGGER bit returns 0 when a transaction has completed. */
+ ret = readl_poll_timeout(priv->regs + MDIO_REG_FRAME_CFG_2, val,
+ !(val & MDIO_TRIGGER_BIT), 50, 10000);
+
+ if (ret < 0)
+ dev_dbg(&bus->dev, "TRIGGER bit timeout: %x\n", val);
+
+ return ret;
+}
+
+static int pic64hpsc_mdio_c22_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+ struct pic64hpsc_mdio_dev *priv = bus->priv;
+ u32 val;
+ int ret;
+
+ ret = pic64hpsc_mdio_wait_trigger(bus);
+ if (ret)
+ return ret;
+
+ writel(MDIO_TRIGGER_BIT | FIELD_PREP(MDIO_REG_DEV_ADDR_MASK, regnum) |
+ FIELD_PREP(MDIO_PHY_PRT_ADDR_MASK, mii_id) |
+ FIELD_PREP(MDIO_OPERATION_MASK, MDIO_OPERATION_READ) |
+ FIELD_PREP(MDIO_START_OF_FRAME_MASK, 1),
+ priv->regs + MDIO_REG_FRAME_CFG_2);
+
+ ret = pic64hpsc_mdio_wait_trigger(bus);
+ if (ret)
+ return ret;
+
+ val = readl(priv->regs + MDIO_REG_FRAME_STATUS);
+
+ /* The MDIO_READOK is a 1-bit value reflecting the inverse of the MDIO
+ * bus value captured during the 2nd TA cycle. A PHY/Port should drive
+ * the MDIO bus with a logic 0 on the 2nd TA cycle, however, the
+ * PHY/Port could optionally drive a logic 1, to communicate a read
+ * failure. This feature is optional, not defined by the 802.3 standard
+ * and not supported in standard external PHYs.
+ */
+ if (!(bus->phy_ignore_ta_mask & 1 << mii_id) &&
+ !FIELD_GET(MDIO_READOK_BIT, val)) {
+ dev_dbg(&bus->dev, "READOK bit cleared\n");
+ return -EIO;
+ }
+
+ return FIELD_GET(MDIO_RDATA_MASK, val);
+}
+
+static int pic64hpsc_mdio_c22_write(struct mii_bus *bus, int mii_id, int regnum,
+ u16 value)
+{
+ struct pic64hpsc_mdio_dev *priv = bus->priv;
+ int ret;
+
+ ret = pic64hpsc_mdio_wait_trigger(bus);
+ if (ret < 0)
+ return ret;
+
+ writel(FIELD_PREP(MDIO_WDATA_MASK, value),
+ priv->regs + MDIO_REG_FRAME_CFG_1);
+
+ writel(MDIO_TRIGGER_BIT | FIELD_PREP(MDIO_REG_DEV_ADDR_MASK, regnum) |
+ FIELD_PREP(MDIO_PHY_PRT_ADDR_MASK, mii_id) |
+ FIELD_PREP(MDIO_OPERATION_MASK, MDIO_OPERATION_WRITE) |
+ FIELD_PREP(MDIO_START_OF_FRAME_MASK, 1),
+ priv->regs + MDIO_REG_FRAME_CFG_2);
+
+ return 0;
+}
+
+static int pic64hpsc_mdio_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct pic64hpsc_mdio_dev *priv;
+ struct mii_bus *bus;
+ unsigned long rate;
+ struct clk *clk;
+ u32 bus_freq;
+ u32 div;
+ int ret;
+
+ bus = devm_mdiobus_alloc_size(dev, sizeof(*priv));
+ if (!bus)
+ return -ENOMEM;
+
+ priv = bus->priv;
+
+ priv->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->regs))
+ return PTR_ERR(priv->regs);
+
+ bus->name = KBUILD_MODNAME;
+ bus->read = pic64hpsc_mdio_c22_read;
+ bus->write = pic64hpsc_mdio_c22_write;
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
+ bus->parent = dev;
+
+ clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ if (of_property_read_u32(np, "clock-frequency", &bus_freq))
+ bus_freq = 2500000;
+
+ rate = clk_get_rate(clk);
+
+ div = DIV_ROUND_UP(rate, 2 * bus_freq) - 1;
+ if (div == 0 || div & ~MDIO_CFG_PRESCALE_MASK) {
+ dev_err(dev, "MDIO clock-frequency out of range\n");
+ return -EINVAL;
+ }
+
+ dev_dbg(dev, "rate=%lu bus_freq=%u real_bus_freq=%lu div=%u\n", rate,
+ bus_freq, rate / (2 * (1 + div)), div);
+ writel(div, priv->regs + MDIO_REG_PRESCALER);
+
+ ret = devm_of_mdiobus_register(dev, bus, np);
+ if (ret) {
+ dev_err(dev, "Cannot register MDIO bus (%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id pic64hpsc_mdio_match[] = {
+ { .compatible = "microchip,pic64hpsc-mdio" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, pic64hpsc_mdio_match);
+
+static struct platform_driver pic64hpsc_mdio_driver = {
+ .probe = pic64hpsc_mdio_probe,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = pic64hpsc_mdio_match,
+ },
+};
+module_platform_driver(pic64hpsc_mdio_driver);
+
+MODULE_AUTHOR("Charles Perry <charles.perry@microchip.com>");
+MODULE_DESCRIPTION("Microchip PIC64-HPSC/HX MDIO driver");
+MODULE_LICENSE("GPL");
--
2.47.3
^ permalink raw reply related
* [PATCH net-next v5 0/3] Add support for PIC64-HPSC/HX MDIO controller
From: Charles Perry @ 2026-04-08 13:18 UTC (permalink / raw)
To: netdev
Cc: MameMaria.Mbaye, Charles Perry, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Heiner Kallweit, Russell King,
devicetree
Hello,
This series adds a driver for the two MDIO controllers of PIC64-HPSC/HX.
The hardware supports C22 and C45 but only C22 is implemented for now.
This MDIO hardware is based on a Microsemi design supported in Linux by
mdio-mscc-miim.c. However, The register interface is completely different
with pic64hpsc, hence the need for a separate driver.
The documentation recommends an input clock of 156.25MHz and a prescaler of
39, which yields an MDIO clock of 1.95MHz.
This was tested on Microchip HB1301 evalkit which has a VSC8574 and a
VSC8541. I've tested with bus frequencies of 0.6, 1.95 and 2.5 MHz.
This series also adds a PHY write barrier when disabling PHY interrupts as
discussed in [1].
Thanks,
Charles
[1]: https://lore.kernel.org/all/acvUqDgepCIScs8M@shell.armlinux.org.uk/
Changes in v5:
- 1/3: Collect Conor's Acked-by
- 1/3: Remove the "|" in "description: |" (Rob)
- 1/3: Don't mention how many instances of the MDIO controller there are
(Rob)
- 1/3: Hex addresses are now in lowercase (Rob)
- 1/3: Drop the phy DT label in the example (Rob)
- 3/3: Support MDIO controllers that only support C45 (Russell, Andrew)
Changes in v4:
- 2/3: return FIELD_GET() directly instead of using "ret" (Russell)
- 3/3: Add the PHY barrier patch (Russell, Andrew)
Changes in v3:
- 2/2: Add a MAINTAINERS entry (Jakub)
Changes in v2:
- 1/2: Make "clocks" and "interrupts" required (Andrew)
- 1/2: Add a default value to "clock-frequency" (Andrew)
- 2/2: Remove #define for unused registers (Maxime)
- 2/2: Add "c22" to clause 22 read/write ops (Maxime)
- 2/2: Remove the call to platform_set_drvdata() (Andrew)
- 2/2: Make the clock mandatory (Andrew)
- 2/2: Use 2.5MHz if no clock-frequency was specified (Andrew)
- 2/2: Change the error message for bad clock-frequency (Andrew)
- 2/2: Fix a use without initialization on bus_freq (Andrew)
CC: Andrew Lunn <andrew+netdev@lunn.ch>
CC: "David S. Miller" <davem@davemloft.net>
CC: Eric Dumazet <edumazet@google.com>
CC: Jakub Kicinski <kuba@kernel.org>
CC: Paolo Abeni <pabeni@redhat.com>
CC: Rob Herring <robh@kernel.org>
CC: Krzysztof Kozlowski <krzk+dt@kernel.org>
CC: Conor Dooley <conor+dt@kernel.org>
CC: Heiner Kallweit <hkallweit1@gmail.com>
CC: Russell King <linux@armlinux.org.uk>
CC: netdev@vger.kernel.org
CC: devicetree@vger.kernel.org
Charles Perry (3):
dt-bindings: net: document Microchip PIC64-HPSC/HX MDIO controller
net: mdio: add a driver for PIC64-HPSC/HX MDIO controller
net: phy: add a PHY write barrier when disabling interrupts
.../net/microchip,pic64hpsc-mdio.yaml | 68 +++++++
MAINTAINERS | 6 +
drivers/net/mdio/Kconfig | 7 +
drivers/net/mdio/Makefile | 1 +
drivers/net/mdio/mdio-pic64hpsc.c | 190 ++++++++++++++++++
drivers/net/phy/phy.c | 25 ++-
6 files changed, 296 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/net/microchip,pic64hpsc-mdio.yaml
create mode 100644 drivers/net/mdio/mdio-pic64hpsc.c
--
2.47.3
^ permalink raw reply
* [PATCH net-next v5 1/3] dt-bindings: net: document Microchip PIC64-HPSC/HX MDIO controller
From: Charles Perry @ 2026-04-08 13:18 UTC (permalink / raw)
To: netdev
Cc: MameMaria.Mbaye, Charles Perry, Conor Dooley, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, devicetree,
linux-kernel
In-Reply-To: <20260408131821.1145334-1-charles.perry@microchip.com>
This MDIO hardware is based on a Microsemi design supported in Linux by
mdio-mscc-miim.c. However, The register interface is completely different
with pic64hpsc, hence the need for separate documentation.
The hardware supports C22 and C45.
The documentation recommends an input clock of 156.25MHz and a prescaler
of 39, which yields an MDIO clock of 1.95MHz.
The hardware supports an interrupt pin to signal transaction completion
which is not strictly needed as the software can also poll a "TRIGGER"
bit for this.
Signed-off-by: Charles Perry <charles.perry@microchip.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
---
Notes:
Changes in v5:
- Collect Conor's Acked-by
- Remove the "|" in "description: |" (Rob)
- Don't mention how many instances of the MDIO controller there are (Rob)
- Hex addresses are now in lowercase (Rob)
- Drop the phy DT label in the example (Rob)
Changes in v4: none
Changes in v3: none
Changes in v2:
- Make "clocks" and "interrupts" required (Andrew)
- Add a default value to "clock-frequency" (Andrew)
Changes in v5: none
Changes in v4: none
Changes in v3: none
Changes in v2:
- Make "clocks" and "interrupts" required (Andrew)
- Add a default value to "clock-frequency" (Andrew)
.../net/microchip,pic64hpsc-mdio.yaml | 68 +++++++++++++++++++
1 file changed, 68 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/microchip,pic64hpsc-mdio.yaml
diff --git a/Documentation/devicetree/bindings/net/microchip,pic64hpsc-mdio.yaml b/Documentation/devicetree/bindings/net/microchip,pic64hpsc-mdio.yaml
new file mode 100644
index 000000000000..20f29b71566b
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/microchip,pic64hpsc-mdio.yaml
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/microchip,pic64hpsc-mdio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Microchip PIC64-HPSC/HX MDIO controller
+
+maintainers:
+ - Charles Perry <charles.perry@microchip.com>
+
+description:
+ This is the MDIO bus controller present in Microchip PIC64-HPSC/HX SoCs. It
+ supports C22 and C45 register access and is named "MDIO Initiator" in the
+ documentation.
+
+allOf:
+ - $ref: mdio.yaml#
+
+properties:
+ compatible:
+ oneOf:
+ - const: microchip,pic64hpsc-mdio
+ - items:
+ - const: microchip,pic64hx-mdio
+ - const: microchip,pic64hpsc-mdio
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ clock-frequency:
+ default: 2500000
+
+ interrupts:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - interrupts
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ bus {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ mdio@4000c21e000 {
+ compatible = "microchip,pic64hpsc-mdio";
+ reg = <0x400 0x0c21e000 0x0 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&svc_clk>;
+ interrupt-parent = <&saplic0>;
+ interrupts = <168 IRQ_TYPE_LEVEL_HIGH>;
+
+ ethernet-phy@0 {
+ reg = <0>;
+ };
+ };
+ };
--
2.47.3
^ permalink raw reply related
* [PATCH iwl-next v2 8/8] ixgbe: use int instead of u32 for error code variables
From: Aleksandr Loktionov @ 2026-04-08 13:12 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov
Cc: netdev, Simon Horman
In-Reply-To: <20260408131216.2662245-1-aleksandr.loktionov@intel.com>
The variables used to store return values of kernel and driver functions
throughout the ixgbe driver are declared as u32 in several places. Such
functions return negative errno values on error (e.g. -EIO, -EFAULT),
which are sign-extended negative integers. Storing them in an unsigned
u32 silently wraps the value: -EIO (0xFFFFFFF7) stored in u32 becomes a
large positive number, so any "if (status)" truthiness check still works
by accident, but comparisons against specific negative error codes or
propagation up the call stack produce wrong results.
In the Linux kernel, u32 is reserved for fixed-width quantities used in
hardware interfaces or protocol structures. Using it for generic error
codes misleads reviewers into thinking the value is hardware-constrained.
Change all such local variables from u32 to int driver-wide: one in
ixgbe_main.c (ixgbe_resume), three in ixgbe_phy.c
(ixgbe_identify_phy_generic, ixgbe_tn_check_overtemp,
ixgbe_set_copper_phy_power), and six in ixgbe_x550.c
(ixgbe_check_link_t_X550em, ixgbe_get_lasi_ext_t_x550em,
ixgbe_enable_lasi_ext_t_x550em, ixgbe_handle_lasi_ext_t_x550em,
ixgbe_ext_phy_t_x550em_get_link, ixgbe_setup_internal_phy_t_x550em).
No functional change.
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
v1 -> v2:
- Carry Reviewed-by: Simon Horman from the IWL posting; add [N/M]
numbering; no code change.
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 2 +-
drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c | 6 +++---
drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c | 12 ++++++------
3 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index ed5b75b..99cfccd 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -7531,7 +7531,7 @@ static int ixgbe_resume(struct device *dev_d)
struct pci_dev *pdev = to_pci_dev(dev_d);
struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
struct net_device *netdev = adapter->netdev;
- u32 err;
+ int err;
adapter->hw.hw_addr = adapter->io_addr;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
index ab733e7..de8f6c6 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
@@ -262,7 +262,7 @@ static bool ixgbe_probe_phy(struct ixgbe_hw *hw, u16 phy_addr)
**/
int ixgbe_identify_phy_generic(struct ixgbe_hw *hw)
{
- u32 status = -EFAULT;
+ int status = -EFAULT;
u32 phy_addr;
if (!hw->phy.phy_semaphore_mask) {
@@ -2811,7 +2811,7 @@ static void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw)
bool ixgbe_tn_check_overtemp(struct ixgbe_hw *hw)
{
u16 phy_data = 0;
- u32 status;
+ int status;
if (hw->device_id != IXGBE_DEV_ID_82599_T3_LOM)
return false;
@@ -2831,7 +2831,7 @@ bool ixgbe_tn_check_overtemp(struct ixgbe_hw *hw)
**/
int ixgbe_set_copper_phy_power(struct ixgbe_hw *hw, bool on)
{
- u32 status;
+ int status;
u16 reg;
/* Bail if we don't have copper phy */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
index 76d2fa3..9b14f3b 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
@@ -1911,7 +1911,7 @@ static int ixgbe_check_link_t_X550em(struct ixgbe_hw *hw,
bool *link_up,
bool link_up_wait_to_complete)
{
- u32 status;
+ int status;
u16 i, autoneg_status;
if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper)
@@ -2330,7 +2330,7 @@ static int ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw,
static int ixgbe_get_lasi_ext_t_x550em(struct ixgbe_hw *hw, bool *lsc,
bool *is_overtemp)
{
- u32 status;
+ int status;
u16 reg;
*is_overtemp = false;
@@ -2418,7 +2418,7 @@ static int ixgbe_get_lasi_ext_t_x550em(struct ixgbe_hw *hw, bool *lsc,
static int ixgbe_enable_lasi_ext_t_x550em(struct ixgbe_hw *hw)
{
bool lsc, overtemp;
- u32 status;
+ int status;
u16 reg;
/* Clear interrupt flags */
@@ -2512,7 +2512,7 @@ static int ixgbe_handle_lasi_ext_t_x550em(struct ixgbe_hw *hw,
{
struct ixgbe_phy_info *phy = &hw->phy;
bool lsc;
- u32 status;
+ int status;
status = ixgbe_get_lasi_ext_t_x550em(hw, &lsc, is_overtemp);
if (status)
@@ -2606,7 +2606,7 @@ static int ixgbe_setup_kr_x550em(struct ixgbe_hw *hw)
**/
static int ixgbe_ext_phy_t_x550em_get_link(struct ixgbe_hw *hw, bool *link_up)
{
- u32 ret;
+ int ret;
u16 autoneg_status;
*link_up = false;
@@ -2642,7 +2642,7 @@ static int ixgbe_setup_internal_phy_t_x550em(struct ixgbe_hw *hw)
{
ixgbe_link_speed force_speed;
bool link_up;
- u32 status;
+ int status;
u16 speed;
if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper)
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-next v2 7/8] ixgbe: use GFP_KERNEL in ixgbe_fcoe_ddp_setup()
From: Aleksandr Loktionov @ 2026-04-08 13:12 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov; +Cc: netdev
In-Reply-To: <20260408131216.2662245-1-aleksandr.loktionov@intel.com>
ixgbe_fcoe_ddp_setup() is always called from process context (FCoE
offload setup paths) and never from an atomic context. Using GFP_ATOMIC
is therefore unnecessarily restrictive and wastes memory allocator
headroom reserved for genuine atomic callers.
The previous attempt to change this to GFP_KERNEL placed the allocation
inside the get_cpu()/put_cpu() section, which disables preemption.
GFP_KERNEL can sleep under direct reclaim regardless of whether the
caller is in process context, which triggers a BUG() with preemption
disabled.
Restructure the function to split the get_cpu()/put_cpu() usage into
two narrow critical sections:
1. A short initial section that reads the per-CPU pool pointer and
validates it, then immediately calls put_cpu() before any allocation.
The pool pointer is saved in a local variable for use after the pin
is dropped.
2. A second section after the allocation that re-pins the CPU solely to
update per-CPU counters (noddp, noddp_ext_buff) inside the SG loop.
The DMA mapping and pool allocation sit between these two sections with
preemption enabled, making GFP_KERNEL safe. The pool pointer saved
from section 1 remains valid because per-CPU DMA pools are only
destroyed during interface teardown under RTNL, not during normal
operation.
Suggested-by: Sebastian Basierski <sebastianx.basierski@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
v1 -> v2:
- Move dma_pool_alloc() outside the get_cpu()/put_cpu() section;
split into two narrow preempt-off regions so GFP_KERNEL is safe.
drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c | 51 +++++++++++---------
1 file changed, 35 insertions(+), 18 deletions(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
index 011fda9..064ad17 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
@@ -139,6 +139,7 @@ static int ixgbe_fcoe_ddp_setup(struct net_device *netdev, u16 xid,
struct ixgbe_fcoe *fcoe;
struct ixgbe_fcoe_ddp *ddp;
struct ixgbe_fcoe_ddp_pool *ddp_pool;
+ struct dma_pool *pool;
struct scatterlist *sg;
unsigned int i, j, dmacount;
unsigned int len;
@@ -179,29 +180,43 @@ static int ixgbe_fcoe_ddp_setup(struct net_device *netdev, u16 xid,
return 0;
}
+ /* Pin to current CPU only to read the per-CPU pool pointer; drop
+ * the pin before any allocations that may sleep under direct reclaim.
+ */
ddp_pool = per_cpu_ptr(fcoe->ddp_pool, get_cpu());
if (!ddp_pool->pool) {
e_warn(drv, "xid=0x%x no ddp pool for fcoe\n", xid);
- goto out_noddp;
+ put_cpu();
+ return 0;
}
+ pool = ddp_pool->pool;
+ put_cpu();
/* setup dma from scsi command sgl */
dmacount = dma_map_sg(&adapter->pdev->dev, sgl, sgc, DMA_FROM_DEVICE);
if (dmacount == 0) {
e_err(drv, "xid 0x%x DMA map error\n", xid);
- goto out_noddp;
+ return 0;
}
- /* alloc the udl from per cpu ddp pool */
- ddp->udl = dma_pool_alloc(ddp_pool->pool, GFP_ATOMIC, &ddp->udp);
+ /* Allocate from per-CPU pool; GFP_KERNEL is safe: preemption is
+ * re-enabled after the put_cpu() above. Per-CPU DMA pools are only
+ * destroyed under RTNL during interface teardown, so the saved pool
+ * pointer remains valid.
+ */
+ ddp->udl = dma_pool_alloc(pool, GFP_KERNEL, &ddp->udp);
if (!ddp->udl) {
e_err(drv, "failed allocated ddp context\n");
- goto out_noddp_unmap;
+ dma_unmap_sg(&adapter->pdev->dev, sgl, sgc, DMA_FROM_DEVICE);
+ return 0;
}
- ddp->pool = ddp_pool->pool;
+ ddp->pool = pool;
ddp->sgl = sgl;
ddp->sgc = sgc;
+ /* Re-pin CPU for per-CPU statistics updates inside the SG loop. */
+ ddp_pool = per_cpu_ptr(fcoe->ddp_pool, get_cpu());
+
j = 0;
for_each_sg(sgl, sg, dmacount, i) {
addr = sg_dma_address(sg);
@@ -210,7 +225,8 @@ static int ixgbe_fcoe_ddp_setup(struct net_device *netdev, u16 xid,
/* max number of buffers allowed in one DDP context */
if (j >= IXGBE_BUFFCNT_MAX) {
ddp_pool->noddp++;
- goto out_noddp_free;
+ put_cpu();
+ goto out_noddp_free_unmap;
}
/* get the offset of length of current buffer */
@@ -220,16 +236,20 @@ static int ixgbe_fcoe_ddp_setup(struct net_device *netdev, u16 xid,
* all but the 1st buffer (j == 0)
* must be aligned on bufflen
*/
- if ((j != 0) && (thisoff))
- goto out_noddp_free;
+ if (j != 0 && thisoff) {
+ put_cpu();
+ goto out_noddp_free_unmap;
+ }
/*
* all but the last buffer
* ((i == (dmacount - 1)) && (thislen == len))
* must end at bufflen
*/
- if (((i != (dmacount - 1)) || (thislen != len))
- && ((thislen + thisoff) != bufflen))
- goto out_noddp_free;
+ if ((i != (dmacount - 1) || thislen != len) &&
+ (thislen + thisoff) != bufflen) {
+ put_cpu();
+ goto out_noddp_free_unmap;
+ }
ddp->udl[j] = (u64)(addr - thisoff);
/* only the first buffer may have none-zero offset */
@@ -250,14 +270,15 @@ static int ixgbe_fcoe_ddp_setup(struct net_device *netdev, u16 xid,
if (lastsize == bufflen) {
if (j >= IXGBE_BUFFCNT_MAX) {
ddp_pool->noddp_ext_buff++;
- goto out_noddp_free;
+ put_cpu();
+ goto out_noddp_free_unmap;
}
ddp->udl[j] = (u64)(fcoe->extra_ddp_buffer_dma);
j++;
lastsize = 1;
}
put_cpu();
fcbuff = (IXGBE_FCBUFF_4KB << IXGBE_FCBUFF_BUFFSIZE_SHIFT);
fcbuff |= ((j & 0xff) << IXGBE_FCBUFF_BUFFCNT_SHIFT);
@@ -316,14 +337,10 @@ static int ixgbe_fcoe_ddp_setup(struct net_device *netdev, u16 xid,
return 1;
-out_noddp_free:
+out_noddp_free_unmap:
dma_pool_free(ddp->pool, ddp->udl, ddp->udp);
ixgbe_fcoe_clear_ddp(ddp);
-
-out_noddp_unmap:
dma_unmap_sg(&adapter->pdev->dev, sgl, sgc, DMA_FROM_DEVICE);
-out_noddp:
- put_cpu();
return 0;
}
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-next v2 6/8] ixgbe: use ktime_get_real_ns() in ixgbe_ptp_reset()
From: Aleksandr Loktionov @ 2026-04-08 13:12 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov
Cc: netdev, Jacob Keller, Marcin Szycik, Simon Horman
In-Reply-To: <20260408131216.2662245-1-aleksandr.loktionov@intel.com>
From: Jacob Keller <jacob.e.keller@intel.com>
Replace ktime_to_ns(ktime_get_real()) with the direct equivalent
ktime_get_real_ns() in ixgbe_ptp_reset(). Using the combined helper
avoids the unnecessary intermediate ktime_t variable and makes the
intent clearer.
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Marcin Szycik <marcin.szycik@linux.intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
---
v1 -> v2:
- Carry Reviewed-by: Simon Horman from reply email; add [N/M]
numbering; no code change.
drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
index 6885d23..a7d1635 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
@@ -1347,7 +1347,7 @@ void ixgbe_ptp_reset(struct ixgbe_adapter *adapter)
spin_lock_irqsave(&adapter->tmreg_lock, flags);
timecounter_init(&adapter->hw_tc, &adapter->hw_cc,
- ktime_to_ns(ktime_get_real()));
+ ktime_get_real_ns());
spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
adapter->last_overflow_check = jiffies;
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-next v2 5/8] ixgbe: remove ixgbe_ping_all_vfs() from link state change handlers
From: Aleksandr Loktionov @ 2026-04-08 13:12 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov; +Cc: netdev
In-Reply-To: <20260408131216.2662245-1-aleksandr.loktionov@intel.com>
When multiple VFs are brought up simultaneously, a VF can receive a
CTS (Clear To Send) mailbox message instead of the expected RESET |
(N)ACK response, because the watchdog fires a gratuitous ping right as
the VF mailbox transaction is in progress.
Remove the ixgbe_ping_all_vfs() call from both ixgbe_watchdog_link_is_up()
and ixgbe_watchdog_link_is_down(). Both paths contain an identical call
with the same race window during VF initialization: link-state changes
(up or down) can arrive while VFs are mid-initialization, and the
gratuitous ping from either direction collides with the VF mailbox state
machine for the same reason.
Link-state changes are already communicated to VFs through the normal
mailbox protocol; these extra pings are redundant on both paths.
Suggested-by: Sebastian Basierski <sebastianx.basierski@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
v1 -> v2:
- Extend fix to also remove ixgbe_ping_all_vfs() from
ixgbe_watchdog_link_is_down(), which carries the same race window;
justifies the asymmetry by eliminating it.
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 6 ------
1 file changed, 6 deletions(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 1885fe8..7c3d821 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -8151,9 +8151,6 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter)
/* update the default user priority for VFs */
ixgbe_update_default_up(adapter);
-
- /* ping all the active vfs to let them know link has changed */
- ixgbe_ping_all_vfs(adapter);
}
/**
@@ -8183,8 +8180,5 @@ static void ixgbe_watchdog_link_is_down(struct ixgbe_adapter *adapter)
e_info(drv, "NIC Link is Down\n");
netif_carrier_off(netdev);
-
- /* ping all the active vfs to let them know link has changed */
- ixgbe_ping_all_vfs(adapter);
}
static bool ixgbe_ring_tx_pending(struct ixgbe_adapter *adapter)
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-next v2 4/8] ixgbe: add IXGBE_ITR_ADAPTIVE_MASK_USECS constant
From: Aleksandr Loktionov @ 2026-04-08 13:12 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov; +Cc: netdev
In-Reply-To: <20260408131216.2662245-1-aleksandr.loktionov@intel.com>
From: Alexander Duyck <alexander.h.duyck@intel.com>
ixgbe_set_itr() clears the mode flag (IXGBE_ITR_ADAPTIVE_LATENCY, bit 7)
with the open-coded complement expression ~IXGBE_ITR_ADAPTIVE_LATENCY.
This is equivalent to keeping only bits [6:0], i.e. the usecs sub-field.
Add IXGBE_ITR_ADAPTIVE_MASK_USECS = IXGBE_ITR_ADAPTIVE_LATENCY - 1 =
0x7F to name this mask explicitly and replace the open-coded AND-NOT
operation with the cleaner AND form. The two expressions are
arithmetically identical; the change improves readability.
Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
v1 -> v2:
- Split from monolithic ITR cleanup; this patch only adds the
IXGBE_ITR_ADAPTIVE_MASK_USECS constant and updates ixgbe_set_itr().
drivers/net/ethernet/intel/ixgbe/ixgbe.h | 1 +
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index b3f4d21..c704cc6 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -475,6 +475,7 @@ static inline unsigned int ixgbe_rx_pg_order(struct ixgbe_ring *ring)
#define IXGBE_ITR_ADAPTIVE_MAX_USECS 84
#define IXGBE_ITR_ADAPTIVE_LATENCY 0x80
#define IXGBE_ITR_ADAPTIVE_BULK 0x00
+#define IXGBE_ITR_ADAPTIVE_MASK_USECS (IXGBE_ITR_ADAPTIVE_LATENCY - 1)
struct ixgbe_ring_container {
struct ixgbe_ring *ring; /* pointer to linked list of rings */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index d7c5e83..1885fe8 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -2960,7 +2960,7 @@ static void ixgbe_set_itr(struct ixgbe_q_vector *q_vector)
new_itr = min(q_vector->rx.itr, q_vector->tx.itr);
/* Clear latency flag if set, shift into correct position */
- new_itr &= ~IXGBE_ITR_ADAPTIVE_LATENCY;
+ new_itr &= IXGBE_ITR_ADAPTIVE_MASK_USECS;
new_itr <<= 2;
if (new_itr != q_vector->itr) {
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-next v2 3/8] ixgbe: limit ITR decrease in latency mode to prevent ACK overdrive
From: Aleksandr Loktionov @ 2026-04-08 13:12 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov; +Cc: netdev
In-Reply-To: <20260408131216.2662245-1-aleksandr.loktionov@intel.com>
From: Alexander Duyck <alexander.h.duyck@intel.com>
When operating in latency mode and the computed ITR is lower than the
current setting, the algorithm can reduce the interrupt rate too
aggressively in a single step. For a TCP workload this means the ACK
stream (a latency-sensitive, low-packet-rate workload) can drive the
moderation down to very high interrupt rates, starving CPU time from
the sender side.
After the speed-based ITR calculation is complete, check whether the
result is in latency mode and would decrease below the current setting.
If so, limit the decrease to at most IXGBE_ITR_ADAPTIVE_MIN_INC (2 us)
per update. This ensures the number of interrupts grows by no more
than 2x per adjustment step for latency-class workloads, dialling in
smoothly rather than overshooting.
Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
v1 -> v2:
- Split from monolithic ITR cleanup; this patch only adds the 2 us
per-step decrease limit for latency-mode workloads.
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index b3f4a72..d7c5e83 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -2888,6 +2888,16 @@ static void ixgbe_update_itr(struct ixgbe_q_vector *q_vector,
break;
}
+ /* In the case of a latency specific workload only allow us to
+ * reduce the ITR by at most 2us. By doing this we should dial
+ * in so that our number of interrupts is no more than 2x the number
+ * of packets for the least busy workload. So for example in the case
+ * of a TCP workload the ACK packets being received would set the
+ * interrupt rate as they are a latency specific workload.
+ */
+ if ((itr & IXGBE_ITR_ADAPTIVE_LATENCY) && itr < ring_container->itr)
+ itr = ring_container->itr - IXGBE_ITR_ADAPTIVE_MIN_INC;
+
clear_counts:
/* write back value */
ring_container->itr = itr;
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-next v2 2/8] ixgbe: add ixgbe_container_is_rx() helper and refine RX adaptive ITR
From: Aleksandr Loktionov @ 2026-04-08 13:12 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov; +Cc: netdev
In-Reply-To: <20260408131216.2662245-1-aleksandr.loktionov@intel.com>
From: Alexander Duyck <alexander.h.duyck@intel.com>
Add an ixgbe_container_is_rx() helper to cleanly distinguish RX from TX
ring containers inside ixgbe_update_itr().
Refine the RX-specific latency-detection path:
- Replace the shared "packets < 4 or bytes < 9000" threshold with an
RX-specific check of "1..23 packets and bytes < 12112". When that
condition holds, target 8x the observed byte count in the next
interval by computing avg_wire_size = (bytes + packets * 24) * 2,
clamped to [2560, 12800], and jumping directly to the speed-based
ITR calculation. This provides finer-grained control over low-rate
RX latency workloads without affecting TX.
- Remove the separate "no packets" special-case block. When packets
is 0 it falls into the "< 48" branch. The mode-tracking logic in
that branch is extended: fewer than 8 packets forces latency mode;
8..47 packets preserves the current mode. This replaces the old
unconditional "add LATENCY flag from ring_container->itr" carried
over from the removed block.
- Remove the adjust_by_size label and the associated "halve
avg_wire_size in latency mode" step. The Rx latency path now
pre-calculates avg_wire_size independently and the bulk path no
longer needs the halving to compensate for incorrect thresholds.
Rename the jump target to adjust_for_speed to reflect its purpose.
Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
v1 -> v2:
- Split from monolithic ITR cleanup; adds ixgbe_container_is_rx(),
refines RX latency thresholds (24 pkts / 12112 B), and removes the
separate no-packet and adjust_by_size code paths.
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 72 ++++++++++--------
1 file changed, 41 insertions(+), 31 deletions(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 210c7b9..b3f4a72 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -2711,6 +2711,12 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, mask);
}
+static bool ixgbe_container_is_rx(struct ixgbe_q_vector *q_vector,
+ struct ixgbe_ring_container *rc)
+{
+ return &q_vector->rx == rc;
+}
+
/**
* ixgbe_update_itr - update the dynamic ITR value based on statistics
* @q_vector: structure containing interrupt and ring information
@@ -2747,35 +2753,24 @@ static void ixgbe_update_itr(struct ixgbe_q_vector *q_vector,
goto clear_counts;
packets = ring_container->total_packets;
-
- /* We have no packets to actually measure against. This means
- * either one of the other queues on this vector is active or
- * we are a Tx queue doing TSO with too high of an interrupt rate.
- *
- * When this occurs just tick up our delay by the minimum value
- * and hope that this extra delay will prevent us from being called
- * without any work on our queue.
- */
- if (!packets) {
- itr = (q_vector->itr >> 2) + IXGBE_ITR_ADAPTIVE_MIN_INC;
- if (itr > IXGBE_ITR_ADAPTIVE_MAX_USECS)
- itr = IXGBE_ITR_ADAPTIVE_MAX_USECS;
- itr += ring_container->itr & IXGBE_ITR_ADAPTIVE_LATENCY;
- goto clear_counts;
- }
-
bytes = ring_container->total_bytes;
- /* If packets are less than 4 or bytes are less than 9000 assume
- * insufficient data to use bulk rate limiting approach. We are
- * likely latency driven.
- */
- if (packets < 4 && bytes < 9000) {
- itr = IXGBE_ITR_ADAPTIVE_LATENCY;
- goto adjust_by_size;
+ if (ixgbe_container_is_rx(q_vector, ring_container)) {
+ /* If Rx and there are 1 to 23 packets and bytes are less than
+ * 12112 assume insufficient data to use bulk rate limiting
+ * approach. Instead we will focus on simply trying to target
+ * receiving 8 times as much data in the next interrupt.
+ */
+ if (packets && packets < 24 && bytes < 12112) {
+ itr = IXGBE_ITR_ADAPTIVE_LATENCY;
+ avg_wire_size = (bytes + packets * 24) * 2;
+ avg_wire_size = clamp_t(unsigned int,
+ avg_wire_size, 2560, 12800);
+ goto adjust_for_speed;
+ }
}
- /* Between 4 and 48 we can assume that our current interrupt delay
+ /* Less than 48 packets we can assume that our current interrupt delay
* is only slightly too low. As such we should increase it by a small
* fixed amount.
*/
@@ -2783,6 +2778,20 @@ static void ixgbe_update_itr(struct ixgbe_q_vector *q_vector,
itr = (q_vector->itr >> 2) + IXGBE_ITR_ADAPTIVE_MIN_INC;
if (itr > IXGBE_ITR_ADAPTIVE_MAX_USECS)
itr = IXGBE_ITR_ADAPTIVE_MAX_USECS;
+
+ /* If sample size is 0 - 7 we should probably switch
+ * to latency mode instead of trying to control
+ * things as though we are in bulk.
+ *
+ * Otherwise if the number of packets is less than 48
+ * we should maintain whatever mode we are currently
+ * in. The range between 8 and 48 is the cross-over
+ * point between latency and bulk traffic.
+ */
+ if (packets < 8)
+ itr += IXGBE_ITR_ADAPTIVE_LATENCY;
+ else
+ itr += ring_container->itr & IXGBE_ITR_ADAPTIVE_LATENCY;
goto clear_counts;
}
@@ -2813,7 +2822,6 @@ static void ixgbe_update_itr(struct ixgbe_q_vector *q_vector,
*/
itr = IXGBE_ITR_ADAPTIVE_BULK;
-adjust_by_size:
/* If packet counts are 256 or greater we can assume we have a gross
* overestimation of what the rate should be. Instead of trying to fine
* tune it just use the formula below to try and dial in an exact value
@@ -2856,12 +2864,7 @@ static void ixgbe_update_itr(struct ixgbe_q_vector *q_vector,
avg_wire_size = 32256;
}
- /* If we are in low latency mode half our delay which doubles the rate
- * to somewhere between 100K to 16K ints/sec
- */
- if (itr & IXGBE_ITR_ADAPTIVE_LATENCY)
- avg_wire_size >>= 1;
-
+adjust_for_speed:
/* Resultant value is 256 times larger than it needs to be. This
* gives us room to adjust the value as needed to either increase
* or decrease the value based on link speeds of 10G, 2.5G, 1G, etc.
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-next v2 1/8] ixgbe: lower IXGBE_ITR_ADAPTIVE_MAX_USECS to prevent RX starvation
From: Aleksandr Loktionov @ 2026-04-08 13:12 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov; +Cc: netdev
In-Reply-To: <20260408131216.2662245-1-aleksandr.loktionov@intel.com>
From: Alexander Duyck <alexander.h.duyck@intel.com>
At the current maximum of 126 us the minimum bulk-mode interrupt rate
is ~7936 interrupts/s. Under sustained full-line-rate bulk RX traffic
this is low enough that descriptor ring starvation can occur before the
next interrupt fires.
Lower IXGBE_ITR_ADAPTIVE_MAX_USECS from 126 to 84 us. This raises the
minimum rate to ~11905 interrupts/s (~12K ints/s), providing enough
headroom to drain the ring before it wraps.
Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
v1 -> v2:
- Split from monolithic ITR cleanup patch; this patch only lowers
IXGBE_ITR_ADAPTIVE_MAX_USECS from 126 to 84.
drivers/net/ethernet/intel/ixgbe/ixgbe.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index 59a1cee4..b3f4d21 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -473,6 +473,6 @@ static inline unsigned int ixgbe_rx_pg_order(struct ixgbe_ring *ring)
#define IXGBE_ITR_ADAPTIVE_MIN_INC 2
#define IXGBE_ITR_ADAPTIVE_MIN_USECS 10
-#define IXGBE_ITR_ADAPTIVE_MAX_USECS 126
+#define IXGBE_ITR_ADAPTIVE_MAX_USECS 84
#define IXGBE_ITR_ADAPTIVE_LATENCY 0x80
#define IXGBE_ITR_ADAPTIVE_BULK 0x00
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-next v2 0/8] ixgbe: nits and improvements
From: Aleksandr Loktionov @ 2026-04-08 13:12 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov; +Cc: netdev
Eight cleanups and improvements for the ixgbe driver.
Patches 1-4 split the adaptive-ITR algorithm improvements into
independently reviewable pieces as requested by Simon Horman. Each
patch is self-contained and can be reviewed and reverted independently:
1. Lower IXGBE_ITR_ADAPTIVE_MAX_USECS from 126 to 84 to prevent RX
starvation at minimum bulk-mode rates.
2. Add ixgbe_container_is_rx() helper and refine the RX-specific
latency algorithm (thresholds, no-packet handling, mode tracking).
3. Limit ITR decrease in latency mode to at most 2 us per update so
ACK workloads do not overdrive moderation.
4. Add IXGBE_ITR_ADAPTIVE_MASK_USECS constant to replace the
open-coded ~IXGBE_ITR_ADAPTIVE_LATENCY complement in ixgbe_set_itr.
Patch 5 removes ixgbe_ping_all_vfs() from both ixgbe_watchdog_link_is_up()
and ixgbe_watchdog_link_is_down(). The original submission only removed
the call from the link-up path; this version also removes it from the
link-down path, which carries the same race window against VF mailbox
initialization.
Patch 6 replaces ktime_to_ns(ktime_get_real()) with ktime_get_real_ns().
Patch 7 restructures ixgbe_fcoe_ddp_setup() so that dma_pool_alloc()
is called outside the get_cpu()/put_cpu() preemption-disabled section,
enabling GFP_KERNEL instead of GFP_ATOMIC. The prior submission left
the allocation inside the preempt-off block (GFP_KERNEL can sleep under
direct reclaim, which triggers a BUG() with preemption disabled).
Patch 8 fixes six local variables declared as u32 that are used to
store signed kernel error codes. Reviewed by Simon Horman.
Changes in v2:
- 1-4/8: Split monolithic ITR cleanup into four independent patches
as requested by Simon Horman.
- 5/8: Extend fix to also remove ixgbe_ping_all_vfs() from
ixgbe_watchdog_link_is_down() to cover the identical race.
- 6/8: No code change; add [N/M] numbering.
- 7/8: Move dma_pool_alloc() outside get_cpu()/put_cpu() so
GFP_KERNEL is used safely without sleeping under preempt-off.
- 8/8: Add Reviewed-by: Simon Horman; no code change.
---
Alexander Duyck (4):
ixgbe: lower IXGBE_ITR_ADAPTIVE_MAX_USECS to prevent RX starvation
ixgbe: add ixgbe_container_is_rx() helper and refine RX adaptive ITR
ixgbe: limit ITR decrease in latency mode to prevent ACK overdrive
ixgbe: add IXGBE_ITR_ADAPTIVE_MASK_USECS constant
Aleksandr Loktionov (2):
ixgbe: remove ixgbe_ping_all_vfs() from link state change handlers
ixgbe: use GFP_KERNEL in ixgbe_fcoe_ddp_setup()
Jacob Keller (1):
ixgbe: use ktime_get_real_ns() in ixgbe_ptp_reset()
Aleksandr Loktionov (1):
ixgbe: use int instead of u32 for error code variables
drivers/net/ethernet/intel/ixgbe/ixgbe.h | 5 +-
drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c | 50 +++++++----
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 97 ++++++++++++------
drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c | 6 +-
drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c | 2 +-
drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c | 12 +--
6 files changed, 113 insertions(+), 59 deletions(-)
--
2.52.0
^ permalink raw reply
* [PATCH iwl-net v2 6/6] ixgbe: fix integer overflow and wrong bit position in ixgbe_validate_rtr()
From: Aleksandr Loktionov @ 2026-04-08 13:11 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov; +Cc: netdev
In-Reply-To: <20260408131154.2661818-1-aleksandr.loktionov@intel.com>
Two bugs in the same loop in ixgbe_validate_rtr():
1. The 3-bit traffic-class field was extracted by shifting a u32 and
assigning the result directly to a u8. For user priority 0 this is
harmless; for UP[5..7] the shift leaves bits [15..21] in the u32
which are then silently truncated when stored in u8. Mask with
IXGBE_RTRUP2TC_UP_MASK before the assignment so only the intended
3 bits are kept.
2. When clearing an out-of-bounds entry the mask was always shifted by
the fixed constant IXGBE_RTRUP2TC_UP_SHIFT (== 3), regardless of
which loop iteration was being processed. This means only UP1 (bit
position 3) was ever cleared; UP0,2..7 (positions 0, 6, 9, ..., 21)
were left unreset, so invalid TC mappings persisted in hardware and
could mis-steer received packets to the wrong traffic class.
Use i * IXGBE_RTRUP2TC_UP_SHIFT to target the correct 3-bit field
for each iteration.
Swap the operand order in the mask expression to place the constant
on the right per kernel coding style (noted by David Laight).
Fixes: e7589eab9291 ("ixgbe: consolidate, setup for multiple traffic classes")
Cc: stable@vger.kernel.org
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
v1 -> v2:
- Add Fixes: tag; reroute to iwl-net (wrong bit positions cause packet
mis-steering); swap to (reg >> ...) & MASK operand order per David
Laight.
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 210c7b9..c9e4f12 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -9772,11 +9772,12 @@ static void ixgbe_validate_rtr(struct ixgbe_adapter *adapter, u8 tc)
rsave = reg;
for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
- u8 up2tc = reg >> (i * IXGBE_RTRUP2TC_UP_SHIFT);
+ u8 up2tc = (reg >> (i * IXGBE_RTRUP2TC_UP_SHIFT)) &
+ IXGBE_RTRUP2TC_UP_MASK;
/* If up2tc is out of bounds default to zero */
if (up2tc > tc)
- reg &= ~(0x7 << IXGBE_RTRUP2TC_UP_SHIFT);
+ reg &= ~(IXGBE_RTRUP2TC_UP_MASK << (i * IXGBE_RTRUP2TC_UP_SHIFT));
}
if (reg != rsave)
--
2.52.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox