* Re: [PATCH net 11/18] drivers: net: cirrus: cs89x0: Remove this driver
From: Geert Uytterhoeven @ 2026-04-22 7:31 UTC (permalink / raw)
To: Andrew Lunn
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan,
linux-kernel, netdev, linux-doc
In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-11-69517c689d1f@lunn.ch>
Hi Andrew,
On Wed, 22 Apr 2026 at 03:04, Andrew Lunn <andrew@lunn.ch> wrote:
> The cs89x0 was written by Bonald Becker 1993 to 1994. It is an ISA
> device, so unlikely to be used with modern kernels.
>
> Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Thanks for your patch!
> --- a/drivers/net/ethernet/cirrus/Kconfig
> +++ b/drivers/net/ethernet/cirrus/Kconfig
> @@ -17,36 +17,6 @@ config NET_VENDOR_CIRRUS
>
> if NET_VENDOR_CIRRUS
>
> -config CS89x0
> - tristate
> -
> -config CS89x0_ISA
> - tristate "CS89x0 ISA driver support"
> - depends on HAS_IOPORT_MAP
> - depends on ISA
> - depends on !PPC32
> - depends on CS89x0_PLATFORM=n
> - select NETDEV_LEGACY_INIT
> - select CS89x0
> - help
> - Support for CS89x0 chipset based Ethernet cards. If you have a
> - network (Ethernet) card of this type, say Y and read the file
> - <file:Documentation/networking/device_drivers/ethernet/cirrus/cs89x0.rst>.
> -
> - To compile this driver as a module, choose M here. The module
> - will be called cs89x0.
This is the driver for the old twentieth-century ISA device...
> -
> -config CS89x0_PLATFORM
> - tristate "CS89x0 platform driver support"
> - depends on ARM || (COMPILE_TEST && !PPC)
> - select CS89x0
> - help
> - Say Y to compile the cs89x0 platform driver. This makes this driver
> - suitable for use on certain evaluation boards such as the iMX21ADS.
> -
> - To compile this driver as a module, choose M here. The module
> - will be called cs89x0.
This is the more modern DT-based part...
> --- a/drivers/net/ethernet/cirrus/cs89x0.c
> +++ /dev/null
> -#if IS_ENABLED(CONFIG_CS89x0_PLATFORM)
[...]
> -static const struct of_device_id __maybe_unused cs89x0_match[] = {
> - { .compatible = "cirrus,cs8900", },
> - { .compatible = "cirrus,cs8920", },
> - { },
> -};
> -MODULE_DEVICE_TABLE(of, cs89x0_match);
[...]
> -#endif /* CONFIG_CS89x0_PLATFORM */
However, no users of these compatible values ever appeared upstream.
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH net v8 03/15] net: cache snapshot entries for ndo_set_rx_mode_async
From: Paolo Abeni @ 2026-04-22 7:27 UTC (permalink / raw)
To: Stanislav Fomichev; +Cc: netdev, davem, edumazet, kuba
In-Reply-To: <aef3wzOywP8_LhCh@devvm17672.vll0.facebook.com>
On 4/22/26 12:19 AM, Stanislav Fomichev wrote:
> On 04/21, Paolo Abeni wrote:
>> On 4/21/26 11:52 AM, Paolo Abeni wrote:
>>> On 4/16/26 8:57 PM, Stanislav Fomichev wrote:
>>>> Add a per-device netdev_hw_addr_list cache (rx_mode_addr_cache) that
>>>> allows __hw_addr_list_snapshot() and __hw_addr_list_reconcile() to
>>>> reuse previously allocated entries instead of hitting GFP_ATOMIC on
>>>> every snapshot cycle.
>>>>
>>>> snapshot pops entries from the cache when available, falling back to
>>>> __hw_addr_create(). reconcile splices both snapshot lists back into
>>>> the cache via __hw_addr_splice(). The cache is flushed in
>>>> free_netdev().
>>>>
>>>> Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
>>>> (cherry picked from commit ba3ab1832a511f660fdc6231245b14bf610c05bd)
>>>
>>> Are you backporting from 7.2 via time machine??? :-P
>>>
>>>> @@ -611,8 +633,8 @@ void __hw_addr_list_reconcile(struct netdev_hw_addr_list *real_list,
>>>> }
>>>> }
>>>>
>>>> - __hw_addr_flush(work);
>>>> - __hw_addr_flush(ref);
>>>> + __hw_addr_splice(cache, work);
>>>> + __hw_addr_splice(cache, ref);
>>>
>>> I think here sashiko has a point, with the cache size being unbounded. I
>>> guess syzkaller or the like will find a way to make it grow too much.
>>>
>>> What about hard-limit it to some reasonable value?!?
>>
>> There are a few more remarks from sashiko at the driver level, but
>> AFAICS are all pre-existing issues.
>>
>> I think even the above one it's better handled as a follow-up, so I'm
>> applying the series as-is (I'll just drop the cherry-pick statement above).
>
> I have a follow-up series to add retries here, but not sure it's the
> right direction. I can send it once net-next opens just to opinions.
I'm not sure how you are going to use retries with cache access?!?
Likely some code could clarify.
I was wondering about a dumb limit for such cache, possibly netns-wide,
possibly with a paired sysctl.
/P
^ permalink raw reply
* [PATCH net] net: txgbe: fix firmware version check
From: Jiawen Wu @ 2026-04-22 7:18 UTC (permalink / raw)
To: netdev
Cc: Mengyuan Lou, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Jacob Keller,
Jiawen Wu, stable
For the device SP, the firmware version is a 32-bit value where the
lower 20 bits represent the base version number. And the customized
firmware version populates the upper 12 bits with a specific
identification number.
For other devices AML 25G and 40G, the upper 12 bits of the firmware
version is always non-zero, and they have other naming conventions.
Only SP devices need to check this to tell if XPCS will work properly.
So the judgement of MAC type is added here.
And the original logic compared the entire 32-bit value against 0x20010,
which caused the outdated base firmwares bypass the version check
without a warning. Apply a mask 0xfffff to isolate the lower 20 bits for
an accurate base version comparison.
Fixes: ab928c24e6cd ("net: txgbe: add FW version warning")
Cc: stable@vger.kernel.org
Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
---
drivers/net/ethernet/wangxun/txgbe/txgbe_main.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
index ec32a5f422f2..8b7c3753bb6a 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
@@ -864,7 +864,8 @@ static int txgbe_probe(struct pci_dev *pdev,
"0x%08x", etrack_id);
}
- if (etrack_id < 0x20010)
+ if (wx->mac.type == wx_mac_sp &&
+ ((etrack_id & 0xfffff) < 0x20010))
dev_warn(&pdev->dev, "Please upgrade the firmware to 0x20010 or above.\n");
err = txgbe_test_hostif(wx);
--
2.51.0
^ permalink raw reply related
* Re: [PATCH net v4 2/2] selftests/bpf: check epoll readiness during reuseport migration
From: Zhenzhong Wu @ 2026-04-22 7:14 UTC (permalink / raw)
To: Kuniyuki Iwashima
Cc: Tamir Duberstein, netdev, edumazet, ncardwell, davem, dsahern,
kuba, pabeni, horms, shuah, linux-kernel, linux-kselftest
In-Reply-To: <CAAVpQUAKCDVPHhFjWch2-zpKp2rHEPzvwE4R1UrDTMd_6Y2HYA@mail.gmail.com>
Thanks both. Keeping the goto for consistency with the rest of the test.
On Wed, Apr 22, 2026 at 2:40 PM Kuniyuki Iwashima <kuniyu@google.com> wrote:
>
> On Tue, Apr 21, 2026 at 11:34 PM Zhenzhong Wu <jt26wzz@gmail.com> wrote:
> >
> > Thanks Tamir, I will fold this into v5 - there's already a precedent
> > in socket_helpers.h, so I will just include it from there.
>
> The test does not use cleanup in other places,
> no need to mix them up.
>
>
> >
> > On Wed, Apr 22, 2026 at 11:04 AM Tamir Duberstein <tamird@kernel.org> wrote:
> > >
> > > On Tue, Apr 21, 2026 at 7:46 PM Zhenzhong Wu <jt26wzz@gmail.com> wrote:
> > > >
> > > > Inside migrate_dance(), add epoll checks around shutdown() to
> > > > verify that the target listener is not ready before shutdown()
> > > > and becomes ready immediately after shutdown() triggers migration.
> > > >
> > > > Cover TCP_ESTABLISHED and TCP_SYN_RECV. Exclude TCP_NEW_SYN_RECV
> > > > as it depends on later handshake completion.
> > > >
> > > > Suggested-by: Kuniyuki Iwashima <kuniyu@google.com>
> > > > Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
> > > > Signed-off-by: Zhenzhong Wu <jt26wzz@gmail.com>
> > > > ---
> > > > .../bpf/prog_tests/migrate_reuseport.c | 49 ++++++++++++++++---
> > > > 1 file changed, 42 insertions(+), 7 deletions(-)
> > > >
> > > > diff --git a/tools/testing/selftests/bpf/prog_tests/migrate_reuseport.c b/tools/testing/selftests/bpf/prog_tests/migrate_reuseport.c
> > > > index 653b0a20f..c62907732 100644
> > > > --- a/tools/testing/selftests/bpf/prog_tests/migrate_reuseport.c
> > > > +++ b/tools/testing/selftests/bpf/prog_tests/migrate_reuseport.c
> > > > @@ -7,24 +7,29 @@
> > > > * 3. call listen() for 1 server socket. (migration target)
> > > > * 4. update a map to migrate all child sockets
> > > > * to the last server socket (migrate_map[cookie] = 4)
> > > > - * 5. call shutdown() for first 4 server sockets
> > > > + * 5. for TCP_ESTABLISHED and TCP_SYN_RECV cases, verify via epoll
> > > > + * that the last server socket is not ready before migration.
> > > > + * 6. call shutdown() for first 4 server sockets
> > > > * and migrate the requests in the accept queue
> > > > * to the last server socket.
> > > > - * 6. call listen() for the second server socket.
> > > > - * 7. call shutdown() for the last server
> > > > + * 7. for TCP_ESTABLISHED and TCP_SYN_RECV cases, verify via epoll
> > > > + * that the last server socket is ready after migration.
> > > > + * 8. call listen() for the second server socket.
> > > > + * 9. call shutdown() for the last server
> > > > * and migrate the requests in the accept queue
> > > > * to the second server socket.
> > > > - * 8. call listen() for the last server.
> > > > - * 9. call shutdown() for the second server
> > > > + * 10. call listen() for the last server.
> > > > + * 11. call shutdown() for the second server
> > > > * and migrate the requests in the accept queue
> > > > * to the last server socket.
> > > > - * 10. call accept() for the last server socket.
> > > > + * 12. call accept() for the last server socket.
> > > > *
> > > > * Author: Kuniyuki Iwashima <kuniyu@amazon.co.jp>
> > > > */
> > > >
> > > > #include <bpf/bpf.h>
> > > > #include <bpf/libbpf.h>
> > > > +#include <sys/epoll.h>
> > > >
> > > > #include "test_progs.h"
> > > > #include "test_migrate_reuseport.skel.h"
> > > > @@ -350,21 +355,51 @@ static int update_maps(struct migrate_reuseport_test_case *test_case,
> > > >
> > > > static int migrate_dance(struct migrate_reuseport_test_case *test_case)
> > > > {
> > > > + struct epoll_event ev = {
> > > > + .events = EPOLLIN,
> > > > + };
> > > > + int epoll = -1, nfds;
> > > > int i, err;
> > > >
> > > > + if (test_case->state != BPF_TCP_NEW_SYN_RECV) {
> > > > + epoll = epoll_create1(0);
> > > > + if (!ASSERT_NEQ(epoll, -1, "epoll_create1"))
> > > > + return -1;
> > > > +
> > > > + ev.data.fd = test_case->servers[MIGRATED_TO];
> > > > + if (!ASSERT_OK(epoll_ctl(epoll, EPOLL_CTL_ADD,
> > > > + test_case->servers[MIGRATED_TO], &ev),
> > > > + "epoll_ctl"))
> > > > + goto close_epoll;
> > > > +
> > > > + nfds = epoll_wait(epoll, &ev, 1, 0);
> > > > + if (!ASSERT_EQ(nfds, 0, "epoll_wait 1"))
> > > > + goto close_epoll;
> > > > + }
> > > > +
> > > > /* Migrate TCP_ESTABLISHED and TCP_SYN_RECV requests
> > > > * to the last listener based on eBPF.
> > > > */
> > > > for (i = 0; i < MIGRATED_TO; i++) {
> > > > err = shutdown(test_case->servers[i], SHUT_RDWR);
> > > > if (!ASSERT_OK(err, "shutdown"))
> > > > - return -1;
> > > > + goto close_epoll;
> > > > }
> > > >
> > > > /* No dance for TCP_NEW_SYN_RECV to migrate based on eBPF */
> > > > if (test_case->state == BPF_TCP_NEW_SYN_RECV)
> > > > return 0;
> > > >
> > > > + nfds = epoll_wait(epoll, &ev, 1, 0);
> > > > + if (!ASSERT_EQ(nfds, 1, "epoll_wait 2")) {
> > > > +close_epoll:
> > > > + if (epoll >= 0)
> > > > + close(epoll);
> > > > + return -1;
> > > > + }
> > >
> > > I think you can avoid this goto using `__attribute__((cleanup(...))`:
> > >
> > > static void close_fd(int *fd)
> > > {
> > > if (*fd >= 0)
> > > close(*fd);
> > > }
> > >
> > > #define __close_fd __attribute__((cleanup(close_fd)))
> > >
> > > then in the test:
> > >
> > > __close_fd int epoll = -1;
> > >
> > > there's an example of this in
> > > tools/testing/selftests/bpf/prog_tests/socket_helpers.h.
^ permalink raw reply
* Re: [PATCH net-deletions v2] net: remove unused ATM protocols and legacy ATM device drivers
From: Andy Shevchenko @ 2026-04-22 7:08 UTC (permalink / raw)
To: Jakub Kicinski
Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms, corbet,
skhan, linux, tsbogend, maddy, mpe, npiggin, chleroy, 3chas3,
razor, idosch, jani.nikula, mchehab+huawei, tytso, herbert, geert,
ebiggers, johannes.berg, jonathan.cameron, kees, kuniyu,
fourier.thomas, rdunlap, akpm, linux-doc, linux-mips,
linuxppc-dev, bridge, dwmw2
In-Reply-To: <20260422041846.2035118-1-kuba@kernel.org>
On Tue, Apr 21, 2026 at 09:18:44PM -0700, Jakub Kicinski wrote:
> Remove the ATM protocol modules and PCI/SBUS ATM device drivers
> that are no longer in active use.
>
> The ATM core protocol stack, PPPoATM, BR2684, and USB DSL modem
> drivers (drivers/usb/atm/) are retained in-tree to maintain PPP
> over ATM (PPPoA) and PPPoE-over-BR2684 support for DSL connections.
>
> Removed ATM protocol modules:
> - net/atm/clip.c - Classical IP over ATM (RFC 2225)
> - net/atm/lec.c - LAN Emulation Client (LANE)
> - net/atm/mpc.c, mpoa_caches.c, mpoa_proc.c - Multi-Protocol Over ATM
>
> Removed PCI/SBUS ATM device drivers (drivers/atm/):
> - adummy, atmtcp - software/testing ATM devices
> - eni - Efficient Networks ENI155P (OC-3, ~1995)
> - fore200e - FORE Systems 200E PCI/SBUS (OC-3, ~1999)
> - he - ForeRunner HE (OC-3/OC-12, ~2000)
> - idt77105 - IDT 77105 25 Mbps ATM PHY
> - idt77252 - IDT 77252 NICStAR II (OC-3, ~2000)
> - iphase - Interphase ATM PCI (OC-3/DS3/E3)
> - lanai - Efficient Networks Speedstream 3010
> - nicstar - IDT 77201 NICStAR (155/25 Mbps, ~1999)
> - solos-pci - Traverse Technologies ADSL2+ PCI
> - suni - PMC S/UNI SONET PHY library
>
> Also clean up references in:
> - net/bridge/ - remove ATM LANE hook (br_fdb_test_addr_hook,
> br_fdb_test_addr)
> - net/core/dev.c - remove br_fdb_test_addr_hook export
> - defconfig files - remove ATM driver config options
>
> The removed code is moved to an out-of-tree module package (mod-orphan).
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
> v2:
> - keep BR2684
> - correct the claim that Traverse Technologies is defunct,
> I'm still deleting the solos driver, chances are nobody uses it.
> Easy enough to revert back in since core is still around.
> The guiding principle is to keep USB modems and delete
> the rest as USB ADSL2+ CPEs were most popular historically.
> v1: https://lore.kernel.org/20260421021943.1295109-1-kuba@kernel.org
>
> CC: corbet@lwn.net
> CC: skhan@linuxfoundation.org
> CC: linux@armlinux.org.uk
> CC: tsbogend@alpha.franken.de
> CC: maddy@linux.ibm.com
> CC: mpe@ellerman.id.au
> CC: npiggin@gmail.com
> CC: chleroy@kernel.org
> CC: 3chas3@gmail.com
> CC: razor@blackwall.org
> CC: idosch@nvidia.com
> CC: jani.nikula@intel.com
> CC: mchehab+huawei@kernel.org
> CC: tytso@mit.edu
> CC: herbert@gondor.apana.org.au
> CC: geert@linux-m68k.org
> CC: ebiggers@kernel.org
> CC: johannes.berg@intel.com
> CC: jonathan.cameron@huawei.com
> CC: kees@kernel.org
> CC: kuniyu@google.com
> CC: fourier.thomas@gmail.com
> CC: andriy.shevchenko@intel.com
> CC: rdunlap@infradead.org
> CC: akpm@linux-foundation.org
> CC: linux-doc@vger.kernel.org
> CC: linux-mips@vger.kernel.org
> CC: linuxppc-dev@lists.ozlabs.org
> CC: bridge@lists.linux.dev
> CC: dwmw2@infradead.org
> CC: herbert@gondor.apana.org.au
Acked-by: Andy Shevchenko <andriy.shevchenko@intel.com>
P.S.
Since it's almost removal and it will go via netdev tree (same tree you are
maintaining, I suppose) the -D would have a big help to review the changes
(and not see removals at all, as 32k lines of one email is too much).
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [net-next PATCH 08/10] net: dsa: realtek: rtl8365mb: add FDB support
From: Luiz Angelo Daros de Luca @ 2026-04-22 6:56 UTC (permalink / raw)
To: Linus Walleij
Cc: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Alvin Šipraga,
Yury Norov, Rasmus Villemoes, Russell King, netdev, linux-kernel
In-Reply-To: <CAD++jLnbZ6q+Noe9abWWRNrvYVjCU-X3w4jpzKKYQDUcKNcKew@mail.gmail.com>
> I actually at one point started to implement FDB accessors to the RTL8366RB
> before I got sidetracked (for the same reasons of being able to do hardware
> offloading), here is how far I got before I got distracted:
> https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-integrator.git/patch/?id=9941b129f91e92423803d6e2869022ffa66e9654
>
> You can see that it also has an L2 table albeit with 4 entries rather than 6,
> and an additional "CAM" (content adressable memory...) table that I don't quite
> understand.
I will look into the CAM table info in rtl8367c family.
> On Wed, Apr 1, 2026 at 1:01 AM Luiz Angelo Daros de Luca
> <luizluca@gmail.com> wrote:
>
> > +int rtl8365mb_l2_del_mc(struct realtek_priv *priv, u16 port,
> > + const unsigned char mac_addr[static ETH_ALEN],
> > + u16 vid)
> > +int rtl8365mb_l2_get_next_uc(struct realtek_priv *priv, u16 *addr, u16 port,
> > + struct rtl8365mb_l2_uc *uc);
> > +int rtl8365mb_l2_add_uc(struct realtek_priv *priv, u16 port,
> > + const unsigned char addr[static ETH_ALEN],
> > + u16 efid, u16 vid);
> > +int rtl8365mb_l2_del_uc(struct realtek_priv *priv, u16 port,
> > + const unsigned char addr[static ETH_ALEN],
> > + u16 efid, u16 vid);
> > +int rtl8365mb_l2_flush(struct realtek_priv *priv, int port, u16 vid);
> > +
> > +int rtl8365mb_l2_add_mc(struct realtek_priv *priv, u16 port,
> > + const unsigned char mac_addr[static ETH_ALEN],
> > + u16 vid);
> > +int rtl8365mb_l2_del_mc(struct realtek_priv *priv, u16 port,
> > + const unsigned char mac_addr[static ETH_ALEN],
> > + u16 vid);
>
> I think it would make sense to add these to struct realtek_ops and
> make them available for all RTL8366 variants.
Agreed. I will add these to struct realtek_ops. I'll need to create a
generic replacement for struct rtl8365mb_l2_uc, but the rest of the
migration should be straightforward. For now, the efid argument can
simply be ignored by the RTL8366 implementation.
> Possibly it would even make sense to move rtl8365mb_table_query()
> to struct realtek_ops under the name .table_query and all of
> these helpers to rtl8366-core.c as rtl8366_l2_del_mc() etc
> just calling the per-chip table query variant. I'm not sure
> but you can perhaps see what makes most sense?
I suspect rtl8365mb_table_query() might be too complex to abstract
effectively without first seeing how the RTL8366 handles table
lookups, as hardware-specific behaviors can vary significantly here. I
suggest we implement it for the RTL8366 first; once we have a
reference point, we can discuss the best way to consolidate the logic.
> > + struct mutex l2_lock;
>
> Move to struct realtek_priv, every chip will need an l2 lock.
Sure.
> > +static void rtl8365mb_port_fast_age(struct dsa_switch *ds, int port)
> > +static int rtl8365mb_port_fdb_add(struct dsa_switch *ds, int port,
> > + const unsigned char *addr, u16 vid,
> > + struct dsa_db db)
> > +static int rtl8365mb_port_fdb_del(struct dsa_switch *ds, int port,
> > + const unsigned char *addr, u16 vid,
> > + struct dsa_db db)
> > +static int rtl8365mb_port_fdb_dump(struct dsa_switch *ds, int port,
> > + dsa_fdb_dump_cb_t *cb, void *data)
> > +static int rtl8365mb_port_mdb_add(struct dsa_switch *ds, int port,
> > + const struct switchdev_obj_port_mdb *mdb,
> > + struct dsa_db db)
> > +static int rtl8365mb_port_mdb_del(struct dsa_switch *ds, int port,
> > + const struct switchdev_obj_port_mdb *mdb,
> > + struct dsa_db db)
>
> I think you should rename all of these rtl8366_port_* and move them
> to rtl8366-core.c. They are generic.
Yes. Once rtl8365mb_l2_* is moved to realtek_ops, these functions
become generic wrappers and fit perfectly in rtl83xx.c.
> > @@ -2498,6 +2687,12 @@ static const struct dsa_switch_ops rtl8365mb_switch_ops = {
> > .port_bridge_join = rtl8365mb_port_bridge_join,
> > .port_bridge_leave = rtl8365mb_port_bridge_leave,
> > .port_stp_state_set = rtl8365mb_port_stp_state_set,
> > + .port_fast_age = rtl8365mb_port_fast_age,
>
> .port_fast_age = rtl8366_port_fast_age,
I will update the ops to use the new generics.
Regards,
Luiz
^ permalink raw reply
* RE: a bug in drivers/net/macsec.c ? (ssci endianness)
From: Karol Gajdos (Nokia) @ 2026-04-22 6:47 UTC (permalink / raw)
To: Sabrina Dubroca; +Cc: netdev@vger.kernel.org
In-Reply-To: <aed1wCDC2Oh4eZ1h@krikkit>
Ok, so it's not a bug, but let's say an unusual agreement between user space and kernel,
as netlink generally uses the host byte order for encoding and decoding integers.
Anyhow thanks for the clarification and the great work done on MACsec.
Karol
-----Original Message-----
From: Sabrina Dubroca <sd@queasysnail.net>
Sent: Tuesday, April 21, 2026 3:04 PM
To: Karol Gajdos (Nokia) <karol.gajdos@nokia.com>
Cc: netdev@vger.kernel.org
Subject: Re: a bug in drivers/net/macsec.c ? (ssci endianness)
CAUTION: This is an external email. Please be very careful when clicking links or opening attachments. See the URL nok.it/ext for additional information.
2026-04-21, 11:37:53 +0000, Karol Gajdos (Nokia) wrote:
> Hi,
>
> there seems to be a bug in the function filling IV for the XPN case.
> Can you confirm please ?
We expect userspace to provide the SSCI in network byte order via the netlink API (same as SCI). As long as we're handling it that way consistently, which I think is the case, there is no bug.
--
Sabrina
^ permalink raw reply
* Re: [PATCH net v4 2/2] selftests/bpf: check epoll readiness during reuseport migration
From: Kuniyuki Iwashima @ 2026-04-22 6:40 UTC (permalink / raw)
To: Zhenzhong Wu
Cc: Tamir Duberstein, netdev, edumazet, ncardwell, davem, dsahern,
kuba, pabeni, horms, shuah, linux-kernel, linux-kselftest
In-Reply-To: <CALgi0XnM49xUZm2-YAjPFoc_8j_F=y4gmVemGHacyH8aXeXaHw@mail.gmail.com>
On Tue, Apr 21, 2026 at 11:34 PM Zhenzhong Wu <jt26wzz@gmail.com> wrote:
>
> Thanks Tamir, I will fold this into v5 - there's already a precedent
> in socket_helpers.h, so I will just include it from there.
The test does not use cleanup in other places,
no need to mix them up.
>
> On Wed, Apr 22, 2026 at 11:04 AM Tamir Duberstein <tamird@kernel.org> wrote:
> >
> > On Tue, Apr 21, 2026 at 7:46 PM Zhenzhong Wu <jt26wzz@gmail.com> wrote:
> > >
> > > Inside migrate_dance(), add epoll checks around shutdown() to
> > > verify that the target listener is not ready before shutdown()
> > > and becomes ready immediately after shutdown() triggers migration.
> > >
> > > Cover TCP_ESTABLISHED and TCP_SYN_RECV. Exclude TCP_NEW_SYN_RECV
> > > as it depends on later handshake completion.
> > >
> > > Suggested-by: Kuniyuki Iwashima <kuniyu@google.com>
> > > Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
> > > Signed-off-by: Zhenzhong Wu <jt26wzz@gmail.com>
> > > ---
> > > .../bpf/prog_tests/migrate_reuseport.c | 49 ++++++++++++++++---
> > > 1 file changed, 42 insertions(+), 7 deletions(-)
> > >
> > > diff --git a/tools/testing/selftests/bpf/prog_tests/migrate_reuseport.c b/tools/testing/selftests/bpf/prog_tests/migrate_reuseport.c
> > > index 653b0a20f..c62907732 100644
> > > --- a/tools/testing/selftests/bpf/prog_tests/migrate_reuseport.c
> > > +++ b/tools/testing/selftests/bpf/prog_tests/migrate_reuseport.c
> > > @@ -7,24 +7,29 @@
> > > * 3. call listen() for 1 server socket. (migration target)
> > > * 4. update a map to migrate all child sockets
> > > * to the last server socket (migrate_map[cookie] = 4)
> > > - * 5. call shutdown() for first 4 server sockets
> > > + * 5. for TCP_ESTABLISHED and TCP_SYN_RECV cases, verify via epoll
> > > + * that the last server socket is not ready before migration.
> > > + * 6. call shutdown() for first 4 server sockets
> > > * and migrate the requests in the accept queue
> > > * to the last server socket.
> > > - * 6. call listen() for the second server socket.
> > > - * 7. call shutdown() for the last server
> > > + * 7. for TCP_ESTABLISHED and TCP_SYN_RECV cases, verify via epoll
> > > + * that the last server socket is ready after migration.
> > > + * 8. call listen() for the second server socket.
> > > + * 9. call shutdown() for the last server
> > > * and migrate the requests in the accept queue
> > > * to the second server socket.
> > > - * 8. call listen() for the last server.
> > > - * 9. call shutdown() for the second server
> > > + * 10. call listen() for the last server.
> > > + * 11. call shutdown() for the second server
> > > * and migrate the requests in the accept queue
> > > * to the last server socket.
> > > - * 10. call accept() for the last server socket.
> > > + * 12. call accept() for the last server socket.
> > > *
> > > * Author: Kuniyuki Iwashima <kuniyu@amazon.co.jp>
> > > */
> > >
> > > #include <bpf/bpf.h>
> > > #include <bpf/libbpf.h>
> > > +#include <sys/epoll.h>
> > >
> > > #include "test_progs.h"
> > > #include "test_migrate_reuseport.skel.h"
> > > @@ -350,21 +355,51 @@ static int update_maps(struct migrate_reuseport_test_case *test_case,
> > >
> > > static int migrate_dance(struct migrate_reuseport_test_case *test_case)
> > > {
> > > + struct epoll_event ev = {
> > > + .events = EPOLLIN,
> > > + };
> > > + int epoll = -1, nfds;
> > > int i, err;
> > >
> > > + if (test_case->state != BPF_TCP_NEW_SYN_RECV) {
> > > + epoll = epoll_create1(0);
> > > + if (!ASSERT_NEQ(epoll, -1, "epoll_create1"))
> > > + return -1;
> > > +
> > > + ev.data.fd = test_case->servers[MIGRATED_TO];
> > > + if (!ASSERT_OK(epoll_ctl(epoll, EPOLL_CTL_ADD,
> > > + test_case->servers[MIGRATED_TO], &ev),
> > > + "epoll_ctl"))
> > > + goto close_epoll;
> > > +
> > > + nfds = epoll_wait(epoll, &ev, 1, 0);
> > > + if (!ASSERT_EQ(nfds, 0, "epoll_wait 1"))
> > > + goto close_epoll;
> > > + }
> > > +
> > > /* Migrate TCP_ESTABLISHED and TCP_SYN_RECV requests
> > > * to the last listener based on eBPF.
> > > */
> > > for (i = 0; i < MIGRATED_TO; i++) {
> > > err = shutdown(test_case->servers[i], SHUT_RDWR);
> > > if (!ASSERT_OK(err, "shutdown"))
> > > - return -1;
> > > + goto close_epoll;
> > > }
> > >
> > > /* No dance for TCP_NEW_SYN_RECV to migrate based on eBPF */
> > > if (test_case->state == BPF_TCP_NEW_SYN_RECV)
> > > return 0;
> > >
> > > + nfds = epoll_wait(epoll, &ev, 1, 0);
> > > + if (!ASSERT_EQ(nfds, 1, "epoll_wait 2")) {
> > > +close_epoll:
> > > + if (epoll >= 0)
> > > + close(epoll);
> > > + return -1;
> > > + }
> >
> > I think you can avoid this goto using `__attribute__((cleanup(...))`:
> >
> > static void close_fd(int *fd)
> > {
> > if (*fd >= 0)
> > close(*fd);
> > }
> >
> > #define __close_fd __attribute__((cleanup(close_fd)))
> >
> > then in the test:
> >
> > __close_fd int epoll = -1;
> >
> > there's an example of this in
> > tools/testing/selftests/bpf/prog_tests/socket_helpers.h.
^ permalink raw reply
* Re: [PATCH 02/23] sched/isolation: Enhance housekeeping_update() to support updating more than one HK cpumask
From: Chen Ridong @ 2026-04-22 6:39 UTC (permalink / raw)
To: Waiman Long, Tejun Heo, Johannes Weiner, Michal Koutný,
Jonathan Corbet, Shuah Khan, Catalin Marinas, Will Deacon,
K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui, Long Li,
Guenter Roeck, Frederic Weisbecker, Paul E. McKenney,
Neeraj Upadhyay, Joel Fernandes, Josh Triplett, Boqun Feng,
Uladzislau Rezki, Steven Rostedt, Mathieu Desnoyers,
Lai Jiangshan, Zqiang, Anna-Maria Behnsen, Ingo Molnar,
Thomas Gleixner, Peter Zijlstra, Juri Lelli, Vincent Guittot,
Dietmar Eggemann, Ben Segall, Mel Gorman, Valentin Schneider,
K Prateek Nayak, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman
Cc: cgroups, linux-doc, linux-kernel, linux-arm-kernel, linux-hyperv,
linux-hwmon, rcu, netdev, linux-kselftest, Costa Shulyupin,
Qiliang Yuan
In-Reply-To: <20260421030351.281436-3-longman@redhat.com>
On 2026/4/21 11:03, Waiman Long wrote:
> The housekeeping_update() function currently allows update to the
> HK_TYPE_DOMAIN cpumask only. As we are going to enable dynamic
> modification of the other housekeeping cpumasks, we need to extend
> it to support passing in the information about the HK cpumask(s) to
> be updated. In cases where some HK cpumasks happen to be the same,
> it will be more efficient to update multiple HK cpumasks in one single
> call instead of calling it multiple times. Extend housekeeping_update()
> to support that as well.
>
> Also add the restriction that passed in isolated cpumask parameter
> of housekeeping_update() must include all the CPUs isolated at boot
> time. This is currently the case for cpuset anyway.
>
> Signed-off-by: Waiman Long <longman@redhat.com>
> ---
> include/linux/sched/isolation.h | 2 +-
> kernel/cgroup/cpuset.c | 2 +-
> kernel/sched/isolation.c | 99 +++++++++++++++++++++++----------
> 3 files changed, 71 insertions(+), 32 deletions(-)
>
> diff --git a/include/linux/sched/isolation.h b/include/linux/sched/isolation.h
> index d1707f121e20..a17f16e0156e 100644
> --- a/include/linux/sched/isolation.h
> +++ b/include/linux/sched/isolation.h
> @@ -51,7 +51,7 @@ extern const struct cpumask *housekeeping_cpumask(enum hk_type type);
> extern bool housekeeping_enabled(enum hk_type type);
> extern void housekeeping_affine(struct task_struct *t, enum hk_type type);
> extern bool housekeeping_test_cpu(int cpu, enum hk_type type);
> -extern int housekeeping_update(struct cpumask *isol_mask);
> +extern int housekeeping_update(struct cpumask *isol_mask, unsigned long flags);
> extern void __init housekeeping_init(void);
>
> #else
> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> index 1335e437098e..a4eccb0ec0d1 100644
> --- a/kernel/cgroup/cpuset.c
> +++ b/kernel/cgroup/cpuset.c
> @@ -1354,7 +1354,7 @@ static void cpuset_update_sd_hk_unlock(void)
> */
> mutex_unlock(&cpuset_mutex);
> cpus_read_unlock();
> - WARN_ON_ONCE(housekeeping_update(isolated_hk_cpus));
> + WARN_ON_ONCE(housekeeping_update(isolated_hk_cpus, BIT(HK_TYPE_DOMAIN)));
> mutex_unlock(&cpuset_top_mutex);
> } else {
> cpuset_full_unlock();
> diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c
> index 9ec9ae510dc7..965d6f8fe344 100644
> --- a/kernel/sched/isolation.c
> +++ b/kernel/sched/isolation.c
> @@ -120,48 +120,87 @@ bool housekeeping_test_cpu(int cpu, enum hk_type type)
> }
> EXPORT_SYMBOL_GPL(housekeeping_test_cpu);
>
> -int housekeeping_update(struct cpumask *isol_mask)
> -{
> - struct cpumask *trial, *old = NULL;
> - int err;
> +/* HK type processing table */
> +static struct {
> + int type;
> + int boot_type;
> +} hk_types[] = {
> + { HK_TYPE_DOMAIN, HK_TYPE_DOMAIN_BOOT },
> + { HK_TYPE_MANAGED_IRQ, HK_TYPE_MANAGED_IRQ_BOOT },
> + { HK_TYPE_KERNEL_NOISE, HK_TYPE_KERNEL_NOISE_BOOT }
> +};
>
> - trial = kmalloc(cpumask_size(), GFP_KERNEL);
> - if (!trial)
> - return -ENOMEM;
> +#define HK_TYPE_CNT ARRAY_SIZE(hk_types)
>
> - cpumask_andnot(trial, housekeeping_cpumask(HK_TYPE_DOMAIN_BOOT), isol_mask);
> - if (!cpumask_intersects(trial, cpu_online_mask)) {
> - kfree(trial);
> - return -EINVAL;
> +int housekeeping_update(struct cpumask *isol_mask, unsigned long flags)
> +{
> + struct cpumask *trial[HK_TYPE_CNT];
> + int i, err = 0;
> +
> + for (i = 0; i < HK_TYPE_CNT; i++) {
> + int type = hk_types[i].type;
> + int boot = hk_types[i].boot_type;
> +
> + trial[i] = NULL;
> + if (flags & BIT(type)) {
> + trial[i] = kmalloc(cpumask_size(), GFP_KERNEL);
> + if (!trial[i]) {
> + err = -ENOMEM;
> + goto out;
> + }
> + /*
> + * The new HK cpumask must be a subset of its boot
> + * cpumask.
> + */
> + cpumask_andnot(trial[i], cpu_possible_mask, isol_mask);
> + if (!cpumask_intersects(trial[i], cpu_online_mask) ||
> + !cpumask_subset(trial[i], housekeeping_cpumask(boot))) {
> + i++;
> + err = -EINVAL;
> + goto out;
> + }
> + }
> }
>
The i++ here is confusing. Wouldn't it be more readable to just use
kfree(trial[i]) and then break out?
> if (!housekeeping.flags)
> static_branch_enable(&housekeeping_overridden);
>
> - if (housekeeping.flags & HK_FLAG_DOMAIN)
> - old = housekeeping_cpumask_dereference(HK_TYPE_DOMAIN);
> - else
> - WRITE_ONCE(housekeeping.flags, housekeeping.flags | HK_FLAG_DOMAIN);
> - rcu_assign_pointer(housekeeping.cpumasks[HK_TYPE_DOMAIN], trial);
> -
> - synchronize_rcu();
> -
> - pci_probe_flush_workqueue();
> - mem_cgroup_flush_workqueue();
> - vmstat_flush_workqueue();
> + for (i = 0; i < HK_TYPE_CNT; i++) {
> + int type = hk_types[i].type;
> + struct cpumask *old;
>
> - err = workqueue_unbound_housekeeping_update(housekeeping_cpumask(HK_TYPE_DOMAIN));
> - WARN_ON_ONCE(err < 0);
> + if (!trial[i])
> + continue;
> + old = NULL;
> + if (housekeeping.flags & BIT(type))
> + old = housekeeping_cpumask_dereference(type);
> + rcu_assign_pointer(housekeeping.cpumasks[type], trial[i]);
> + trial[i] = old;
> + }
>
> - err = tmigr_isolated_exclude_cpumask(isol_mask);
> - WARN_ON_ONCE(err < 0);
> + if ((housekeeping.flags & flags) != flags)
> + WRITE_ONCE(housekeeping.flags, housekeeping.flags | flags);
>
> - err = kthreads_update_housekeeping();
> - WARN_ON_ONCE(err < 0);
> + synchronize_rcu();
>
> - kfree(old);
> + if (flags & HK_FLAG_DOMAIN) {
> + /*
> + * HK_TYPE_DOMAIN specific callbacks
> + */
> + pci_probe_flush_workqueue();
> + mem_cgroup_flush_workqueue();
> + vmstat_flush_workqueue();
> +
> + WARN_ON_ONCE(workqueue_unbound_housekeeping_update(
> + housekeeping_cpumask(HK_TYPE_DOMAIN)) < 0);
> + WARN_ON_ONCE(tmigr_isolated_exclude_cpumask(isol_mask) < 0);
> + WARN_ON_ONCE(kthreads_update_housekeeping() < 0);
> + }
>
> - return 0;
> +out:
> + while (--i >= 0)
> + kfree(trial[i]);
> + return err;
> }
>
> void __init housekeeping_init(void)
--
Best regards,
Ridong
^ permalink raw reply
* Re: [PATCH net v4 2/2] selftests/bpf: check epoll readiness during reuseport migration
From: Zhenzhong Wu @ 2026-04-22 6:34 UTC (permalink / raw)
To: Tamir Duberstein
Cc: netdev, edumazet, ncardwell, kuniyu, davem, dsahern, kuba, pabeni,
horms, shuah, linux-kernel, linux-kselftest
In-Reply-To: <CAJ-ks9=FKMoczH+Z=GQ7C40T42=zdknYzzHCa8UVFOtq2H69cw@mail.gmail.com>
Thanks Tamir, I will fold this into v5 - there's already a precedent
in socket_helpers.h, so I will just include it from there.
On Wed, Apr 22, 2026 at 11:04 AM Tamir Duberstein <tamird@kernel.org> wrote:
>
> On Tue, Apr 21, 2026 at 7:46 PM Zhenzhong Wu <jt26wzz@gmail.com> wrote:
> >
> > Inside migrate_dance(), add epoll checks around shutdown() to
> > verify that the target listener is not ready before shutdown()
> > and becomes ready immediately after shutdown() triggers migration.
> >
> > Cover TCP_ESTABLISHED and TCP_SYN_RECV. Exclude TCP_NEW_SYN_RECV
> > as it depends on later handshake completion.
> >
> > Suggested-by: Kuniyuki Iwashima <kuniyu@google.com>
> > Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
> > Signed-off-by: Zhenzhong Wu <jt26wzz@gmail.com>
> > ---
> > .../bpf/prog_tests/migrate_reuseport.c | 49 ++++++++++++++++---
> > 1 file changed, 42 insertions(+), 7 deletions(-)
> >
> > diff --git a/tools/testing/selftests/bpf/prog_tests/migrate_reuseport.c b/tools/testing/selftests/bpf/prog_tests/migrate_reuseport.c
> > index 653b0a20f..c62907732 100644
> > --- a/tools/testing/selftests/bpf/prog_tests/migrate_reuseport.c
> > +++ b/tools/testing/selftests/bpf/prog_tests/migrate_reuseport.c
> > @@ -7,24 +7,29 @@
> > * 3. call listen() for 1 server socket. (migration target)
> > * 4. update a map to migrate all child sockets
> > * to the last server socket (migrate_map[cookie] = 4)
> > - * 5. call shutdown() for first 4 server sockets
> > + * 5. for TCP_ESTABLISHED and TCP_SYN_RECV cases, verify via epoll
> > + * that the last server socket is not ready before migration.
> > + * 6. call shutdown() for first 4 server sockets
> > * and migrate the requests in the accept queue
> > * to the last server socket.
> > - * 6. call listen() for the second server socket.
> > - * 7. call shutdown() for the last server
> > + * 7. for TCP_ESTABLISHED and TCP_SYN_RECV cases, verify via epoll
> > + * that the last server socket is ready after migration.
> > + * 8. call listen() for the second server socket.
> > + * 9. call shutdown() for the last server
> > * and migrate the requests in the accept queue
> > * to the second server socket.
> > - * 8. call listen() for the last server.
> > - * 9. call shutdown() for the second server
> > + * 10. call listen() for the last server.
> > + * 11. call shutdown() for the second server
> > * and migrate the requests in the accept queue
> > * to the last server socket.
> > - * 10. call accept() for the last server socket.
> > + * 12. call accept() for the last server socket.
> > *
> > * Author: Kuniyuki Iwashima <kuniyu@amazon.co.jp>
> > */
> >
> > #include <bpf/bpf.h>
> > #include <bpf/libbpf.h>
> > +#include <sys/epoll.h>
> >
> > #include "test_progs.h"
> > #include "test_migrate_reuseport.skel.h"
> > @@ -350,21 +355,51 @@ static int update_maps(struct migrate_reuseport_test_case *test_case,
> >
> > static int migrate_dance(struct migrate_reuseport_test_case *test_case)
> > {
> > + struct epoll_event ev = {
> > + .events = EPOLLIN,
> > + };
> > + int epoll = -1, nfds;
> > int i, err;
> >
> > + if (test_case->state != BPF_TCP_NEW_SYN_RECV) {
> > + epoll = epoll_create1(0);
> > + if (!ASSERT_NEQ(epoll, -1, "epoll_create1"))
> > + return -1;
> > +
> > + ev.data.fd = test_case->servers[MIGRATED_TO];
> > + if (!ASSERT_OK(epoll_ctl(epoll, EPOLL_CTL_ADD,
> > + test_case->servers[MIGRATED_TO], &ev),
> > + "epoll_ctl"))
> > + goto close_epoll;
> > +
> > + nfds = epoll_wait(epoll, &ev, 1, 0);
> > + if (!ASSERT_EQ(nfds, 0, "epoll_wait 1"))
> > + goto close_epoll;
> > + }
> > +
> > /* Migrate TCP_ESTABLISHED and TCP_SYN_RECV requests
> > * to the last listener based on eBPF.
> > */
> > for (i = 0; i < MIGRATED_TO; i++) {
> > err = shutdown(test_case->servers[i], SHUT_RDWR);
> > if (!ASSERT_OK(err, "shutdown"))
> > - return -1;
> > + goto close_epoll;
> > }
> >
> > /* No dance for TCP_NEW_SYN_RECV to migrate based on eBPF */
> > if (test_case->state == BPF_TCP_NEW_SYN_RECV)
> > return 0;
> >
> > + nfds = epoll_wait(epoll, &ev, 1, 0);
> > + if (!ASSERT_EQ(nfds, 1, "epoll_wait 2")) {
> > +close_epoll:
> > + if (epoll >= 0)
> > + close(epoll);
> > + return -1;
> > + }
>
> I think you can avoid this goto using `__attribute__((cleanup(...))`:
>
> static void close_fd(int *fd)
> {
> if (*fd >= 0)
> close(*fd);
> }
>
> #define __close_fd __attribute__((cleanup(close_fd)))
>
> then in the test:
>
> __close_fd int epoll = -1;
>
> there's an example of this in
> tools/testing/selftests/bpf/prog_tests/socket_helpers.h.
^ permalink raw reply
* Re: [PATCH] smb: smbdirect: move fs/smb/common/smbdirect/ to fs/smb/smbdirect/
From: Christoph Hellwig @ 2026-04-22 6:31 UTC (permalink / raw)
To: Stefan Metzmacher
Cc: linux-cifs, samba-technical, Linus Torvalds, Steve French,
Tom Talpey, Long Li, Namjae Jeon, linux-rdma, netdev
In-Reply-To: <20260419192018.3046449-1-metze@samba.org>
> diff --git a/fs/smb/Makefile b/fs/smb/Makefile
> index 9a1bf59a1a65..353b1c2eefc4 100644
> --- a/fs/smb/Makefile
> +++ b/fs/smb/Makefile
> @@ -1,5 +1,6 @@
> # SPDX-License-Identifier: GPL-2.0
>
> obj-$(CONFIG_SMBFS) += common/
> +obj-$(CONFIG_SMBDIRECT) += smbdirect/
Why is this not in net/smbdirect/ or driver/infiniband/ulp/smdirect?
As far as I can tell there is zero file system logic in this code.
> -#include "../common/smbdirect/smbdirect_public.h"
> +#include "../smbdirect/public.h"
And all these relative includes suggest you really want a
include/linux/smdirect/ instead.
While we're at it: __SMBDIRECT_EXPORT_SYMBOL__ is really odd.
One thing is the __ pre- and postfix that make it look weird.
The other is that EXPORT_SYMBOL_FOR_MODULES is for very specific
symbols that really should not exported. What this warrants instead
is a normal EXPORT_SYMBOL_NS_GPL.
^ permalink raw reply
* Re: [PATCH net 14/18] drivers: net: xircom: xirc2ps: Remove this driver
From: Michael Fritscher @ 2026-04-22 6:21 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
Cc: linux-kernel, netdev, linux-doc, Andrew Lunn
Good day,
actually, I do use Xircom PCMCIA network cards (yes, the 16 bit ones) on
Lenovo X60/X61 laptops as a second LAN card for server maintenances with
current 64 bit distros (e.g. Debian Trixie, which I plan to update to
Trixie+1 when available). Why? Because I have them and they are working ;-)
Best regards
Michael Fritscher
^ permalink raw reply
* Re: [PATCH] wifi: mac80211: check ieee80211_rx_data_set_link return in pubsta MLO path
From: Johannes Berg @ 2026-04-22 6:27 UTC (permalink / raw)
To: Michael Bommarito, linux-wireless
Cc: Felix Fietkau, Benjamin Berg, netdev, linux-kernel
In-Reply-To: <20260422000651.4184602-1-michael.bommarito@gmail.com>
On Tue, 2026-04-21 at 20:06 -0400, Michael Bommarito wrote:
> Benjamin Berg's 2026-02 RFC v2 "wifi: mac80211: refactor RX
> link_id and station handling"
> (20260223133818.9f5550ab445f.I...@changeid) touches the same
> code and may supersede or subsume this patch; happy to fold /
> rebase / drop.
Yeah, Benjamin, what's up with that :)
OTOH we perhaps wants this patch in wireless, and then yours in
wireless-next.
johannes
^ permalink raw reply
* Re: [PATCH v1 05/11] drm/xe/sysctrl: Add system controller interrupt handler
From: Raag Jadav @ 2026-04-22 6:25 UTC (permalink / raw)
To: Tauro, Riana
Cc: intel-xe, dri-devel, netdev, simona.vetter, airlied, kuba,
lijo.lazar, Hawking.Zhang, davem, pabeni, edumazet, maarten,
zachary.mckevitt, rodrigo.vivi, michal.wajdeczko, matthew.d.roper,
umesh.nerlige.ramappa, mallesh.koujalagi, soham.purkait,
anoop.c.vijay, aravind.iddamsetty
In-Reply-To: <c5ae7bab-ee42-430f-abf1-e062439c1356@intel.com>
On Wed, Apr 22, 2026 at 11:25:44AM +0530, Tauro, Riana wrote:
> On 4/18/2026 2:46 AM, Raag Jadav wrote:
> > Add system controller interrupt handler which is denoted by 11th bit in
> > GFX master interrupt register. While at it, add worker for scheduling
> > system controller work.
>
> Why do we need this series in the threshold patch. From what i see, we need
> only structures
> Can't we only redefine those here?
>
> I know you will have to rebase again once any patch is merged. But this is
> unnecessary noise
> for the drm patch.
We have threshold crossed event so I thought it was relevant here. We can
merge it independently if you're okay with it.
Raag
> > Co-developed-by: Soham Purkait <soham.purkait@intel.com>
> > Signed-off-by: Soham Purkait <soham.purkait@intel.com>
> > Signed-off-by: Raag Jadav <raag.jadav@intel.com>
> > Reviewed-by: Mallesh Koujalagi <mallesh.koujalagi@intel.com>
> > Reviewed-by: Riana Tauro <riana.tauro@intel.com>
> > ---
> > drivers/gpu/drm/xe/regs/xe_irq_regs.h | 1 +
> > drivers/gpu/drm/xe/xe_irq.c | 2 ++
> > drivers/gpu/drm/xe/xe_sysctrl.c | 35 +++++++++++++++++++++------
> > drivers/gpu/drm/xe/xe_sysctrl.h | 1 +
> > drivers/gpu/drm/xe/xe_sysctrl_types.h | 4 +++
> > 5 files changed, 36 insertions(+), 7 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/xe/regs/xe_irq_regs.h b/drivers/gpu/drm/xe/regs/xe_irq_regs.h
> > index 9d74f454d3ff..1d6b976c4de0 100644
> > --- a/drivers/gpu/drm/xe/regs/xe_irq_regs.h
> > +++ b/drivers/gpu/drm/xe/regs/xe_irq_regs.h
> > @@ -22,6 +22,7 @@
> > #define DISPLAY_IRQ REG_BIT(16)
> > #define SOC_H2DMEMINT_IRQ REG_BIT(13)
> > #define I2C_IRQ REG_BIT(12)
> > +#define SYSCTRL_IRQ REG_BIT(11)
> > #define GT_DW_IRQ(x) REG_BIT(x)
> > /*
> > diff --git a/drivers/gpu/drm/xe/xe_irq.c b/drivers/gpu/drm/xe/xe_irq.c
> > index 9a775c6588dc..e9f0b3cad06d 100644
> > --- a/drivers/gpu/drm/xe/xe_irq.c
> > +++ b/drivers/gpu/drm/xe/xe_irq.c
> > @@ -24,6 +24,7 @@
> > #include "xe_mmio.h"
> > #include "xe_pxp.h"
> > #include "xe_sriov.h"
> > +#include "xe_sysctrl.h"
> > #include "xe_tile.h"
> > /*
> > @@ -525,6 +526,7 @@ static irqreturn_t dg1_irq_handler(int irq, void *arg)
> > xe_heci_csc_irq_handler(xe, master_ctl);
> > xe_display_irq_handler(xe, master_ctl);
> > xe_i2c_irq_handler(xe, master_ctl);
> > + xe_sysctrl_irq_handler(xe, master_ctl);
> > xe_mert_irq_handler(xe, master_ctl);
> > gu_misc_iir = gu_misc_irq_ack(xe, master_ctl);
> > }
> > diff --git a/drivers/gpu/drm/xe/xe_sysctrl.c b/drivers/gpu/drm/xe/xe_sysctrl.c
> > index 2bcef304eb9a..7de3e73bd8e0 100644
> > --- a/drivers/gpu/drm/xe/xe_sysctrl.c
> > +++ b/drivers/gpu/drm/xe/xe_sysctrl.c
> > @@ -8,6 +8,7 @@
> > #include <drm/drm_managed.h>
> > +#include "regs/xe_irq_regs.h"
> > #include "regs/xe_sysctrl_regs.h"
> > #include "xe_device.h"
> > #include "xe_mmio.h"
> > @@ -30,10 +31,16 @@
> > static void sysctrl_fini(void *arg)
> > {
> > struct xe_device *xe = arg;
> > + struct xe_sysctrl *sc = &xe->sc;
> > + disable_work_sync(&sc->work);
> > xe->soc_remapper.set_sysctrl_region(xe, 0);
> > }
> > +static void xe_sysctrl_work(struct work_struct *work)
> > +{
> > +}
> > +
> > /**
> > * xe_sysctrl_init() - Initialize System Controller subsystem
> > * @xe: xe device instance
> > @@ -55,12 +62,6 @@ int xe_sysctrl_init(struct xe_device *xe)
> > if (!xe->info.has_sysctrl)
> > return 0;
> > - xe->soc_remapper.set_sysctrl_region(xe, SYSCTRL_MAILBOX_INDEX);
> > -
> > - ret = devm_add_action_or_reset(xe->drm.dev, sysctrl_fini, xe);
> > - if (ret)
> > - return ret;
> > -
> > sc->mmio = devm_kzalloc(xe->drm.dev, sizeof(*sc->mmio), GFP_KERNEL);
> > if (!sc->mmio)
> > return -ENOMEM;
> > @@ -73,9 +74,29 @@ int xe_sysctrl_init(struct xe_device *xe)
> > if (ret)
> > return ret;
> > + xe->soc_remapper.set_sysctrl_region(xe, SYSCTRL_MAILBOX_INDEX);
> > xe_sysctrl_mailbox_init(sc);
> > + INIT_WORK(&sc->work, xe_sysctrl_work);
> > - return 0;
> > + return devm_add_action_or_reset(xe->drm.dev, sysctrl_fini, xe);
> > +}
> > +
> > +/**
> > + * xe_sysctrl_irq_handler() - Handler for System Controller interrupts
> > + * @xe: xe device instance
> > + * @master_ctl: interrupt register
> > + *
> > + * Handle interrupts generated by System Controller.
> > + */
> > +void xe_sysctrl_irq_handler(struct xe_device *xe, u32 master_ctl)
> > +{
> > + struct xe_sysctrl *sc = &xe->sc;
> > +
> > + if (!xe->info.has_sysctrl || !sc->work.func)
> > + return;
> > +
> > + if (master_ctl & SYSCTRL_IRQ)
> > + schedule_work(&sc->work);
> > }
> > /**
> > diff --git a/drivers/gpu/drm/xe/xe_sysctrl.h b/drivers/gpu/drm/xe/xe_sysctrl.h
> > index f3b0f3716b2f..f7469bfc9324 100644
> > --- a/drivers/gpu/drm/xe/xe_sysctrl.h
> > +++ b/drivers/gpu/drm/xe/xe_sysctrl.h
> > @@ -17,6 +17,7 @@ static inline struct xe_device *sc_to_xe(struct xe_sysctrl *sc)
> > }
> > int xe_sysctrl_init(struct xe_device *xe);
> > +void xe_sysctrl_irq_handler(struct xe_device *xe, u32 master_ctl);
> > void xe_sysctrl_pm_resume(struct xe_device *xe);
> > #endif
> > diff --git a/drivers/gpu/drm/xe/xe_sysctrl_types.h b/drivers/gpu/drm/xe/xe_sysctrl_types.h
> > index 8217f6befe70..5f408d6491ef 100644
> > --- a/drivers/gpu/drm/xe/xe_sysctrl_types.h
> > +++ b/drivers/gpu/drm/xe/xe_sysctrl_types.h
> > @@ -8,6 +8,7 @@
> > #include <linux/mutex.h>
> > #include <linux/types.h>
> > +#include <linux/workqueue_types.h>
> > struct xe_mmio;
> > @@ -27,6 +28,9 @@ struct xe_sysctrl {
> > /** @phase_bit: Message boundary phase toggle bit (0 or 1) */
> > bool phase_bit;
> > +
> > + /** @work: Pending events worker */
> > + struct work_struct work;
> > };
> > #endif
^ permalink raw reply
* Re: [PATCH v1 02/11] drm/ras: Introduce get-error-threshold
From: Raag Jadav @ 2026-04-22 6:21 UTC (permalink / raw)
To: Tauro, Riana
Cc: intel-xe, dri-devel, netdev, simona.vetter, airlied, kuba,
lijo.lazar, Hawking.Zhang, davem, pabeni, edumazet, maarten,
zachary.mckevitt, rodrigo.vivi, michal.wajdeczko, matthew.d.roper,
umesh.nerlige.ramappa, mallesh.koujalagi, soham.purkait,
anoop.c.vijay, aravind.iddamsetty
In-Reply-To: <0c855393-be55-497d-aabe-fbe72e37321f@intel.com>
On Wed, Apr 22, 2026 at 11:19:36AM +0530, Tauro, Riana wrote:
> On 4/18/2026 2:46 AM, Raag Jadav wrote:
> > Add get-error-threshold command support which allows querying threshold
> > value of the error. Threshold in RAS context means the number of errors
> > the hardware is expected to accumulate before it raises them to software.
> > This is to have a fine grained control over error notifications that are
> > raised by the hardware.
> >
> > Signed-off-by: Raag Jadav <raag.jadav@intel.com>
> > ---
> > Documentation/gpu/drm-ras.rst | 8 ++
> > Documentation/netlink/specs/drm_ras.yaml | 37 ++++++++
> > drivers/gpu/drm/drm_ras.c | 103 +++++++++++++++++++++++
> > drivers/gpu/drm/drm_ras_nl.c | 13 +++
> > drivers/gpu/drm/drm_ras_nl.h | 2 +
> > include/drm/drm_ras.h | 14 +++
> > include/uapi/drm/drm_ras.h | 11 +++
> > 7 files changed, 188 insertions(+)
> >
> > diff --git a/Documentation/gpu/drm-ras.rst b/Documentation/gpu/drm-ras.rst
> > index 70b246a78fc8..6443dfd1677f 100644
> > --- a/Documentation/gpu/drm-ras.rst
> > +++ b/Documentation/gpu/drm-ras.rst
> > @@ -52,6 +52,8 @@ User space tools can:
> > as a parameter.
> > * Query specific error counter values with the ``get-error-counter`` command, using both
> > ``node-id`` and ``error-id`` as parameters.
> > +* Query specific error threshold value with the ``get-error-threshold`` command, using both
> > + ``node-id`` and ``error-id`` as parameters.
> Also define what is a thresold. How can it be used?
Sure, I'll append commit message description here.
> > YAML-based Interface
> > --------------------
> > @@ -101,3 +103,9 @@ Example: Query an error counter for a given node
> > sudo ynl --family drm_ras --do get-error-counter --json '{"node-id":0, "error-id":1}'
> > {'error-id': 1, 'error-name': 'error_name1', 'error-value': 0}
> > +Example: Query threshold value of a given error
> > +
> > +.. code-block:: bash
> > +
> > + sudo ynl --family drm_ras --do get-error-threshold --json '{"node-id":0, "error-id":1}'
> > + {'error-id': 1, 'error-name': 'error_name1', 'error-threshold': 0}
> > diff --git a/Documentation/netlink/specs/drm_ras.yaml b/Documentation/netlink/specs/drm_ras.yaml
> > index 79af25dac3c5..95a939fb987d 100644
> > --- a/Documentation/netlink/specs/drm_ras.yaml
> > +++ b/Documentation/netlink/specs/drm_ras.yaml
> > @@ -69,6 +69,25 @@ attribute-sets:
> > name: error-value
> > type: u32
> > doc: Current value of the requested error counter.
> > + -
> > + name: error-threshold-attrs
> > + attributes:
> > + -
> > + name: node-id
> > + type: u32
> > + doc: Node ID targeted by this operation.
> > + -
> > + name: error-id
> > + type: u32
> > + doc: Unique identifier for a specific error within the node.
> > + -
> > + name: error-name
> > + type: string
> > + doc: Name of the error.
> > + -
> > + name: error-threshold
> > + type: u32
> > + doc: Threshold value of the error.
> > operations:
> > list:
> > @@ -113,3 +132,21 @@ operations:
> > - node-id
> > reply:
> > attributes: *errorinfo
> > + -
> > + name: get-error-threshold
> > + doc: >-
> > + Retrieve threshold value of the error.
> > + The response includes the id, the name, and current threshold
> > + value of the error.
> > + attribute-set: error-threshold-attrs
> > + flags: [admin-perm]
> > + do:
> > + request:
> > + attributes:
> > + - node-id
> > + - error-id
> > + reply:
> > + attributes:
> > + - error-id
> > + - error-name
> > + - error-threshold
> > diff --git a/drivers/gpu/drm/drm_ras.c b/drivers/gpu/drm/drm_ras.c
> > index 1f7435d60f11..d2d853d5d69c 100644
> > --- a/drivers/gpu/drm/drm_ras.c
> > +++ b/drivers/gpu/drm/drm_ras.c
> > @@ -37,6 +37,10 @@
> > * Returns all counters of a node if only Node ID is provided or specific
> > * error counters.
> > *
> > + * 3. GET_ERROR_THRESHOLD: Query threshold value of the error.
> > + * Userspace must provide Node ID and Error ID.
> > + * Returns the threshold value of a specific error.
> > + *
> > * Node registration:
> > *
> > * - drm_ras_node_register(): Registers a new node and assigns
> > @@ -66,6 +70,8 @@
> > * operation, fetching all counters from a specific node.
> > * - drm_ras_nl_get_error_counter_doit(): Implements the GET_ERROR_COUNTER doit
> > * operation, fetching a counter value from a specific node.
> > + * - drm_ras_nl_get_error_threshold_doit(): Implements the GET_ERROR_THRESHOLD doit
> > + * operation, fetching the threshold value of a specific error.
> > */
> > static DEFINE_XARRAY_ALLOC(drm_ras_xa);
> > @@ -162,6 +168,22 @@ static int get_node_error_counter(u32 node_id, u32 error_id,
> > return node->query_error_counter(node, error_id, name, value);
> > }
> > +static int get_node_error_threshold(u32 node_id, u32 error_id,
> > + const char **name, u32 *value)
> > +{
> > + struct drm_ras_node *node;
> > +
> > + node = xa_load(&drm_ras_xa, node_id);
> > + if (!node || !node->query_error_threshold)
> > + return -ENOENT;
>
> For the absence of the function, return -EOPNOTSUPP
Works for me, but then it should be consistent for all commands.
> > +
> > + if (error_id < node->error_counter_range.first ||
> > + error_id > node->error_counter_range.last)
> > + return -EINVAL;
> > +
> > + return node->query_error_threshold(node, error_id, name, value);
> > +}
> > +
> > static int msg_reply_counter_value(struct sk_buff *msg, u32 error_id,
> > const char *error_name, u32 value)
> > {
> > @@ -180,6 +202,24 @@ static int msg_reply_counter_value(struct sk_buff *msg, u32 error_id,
> > value);
> > }
> > +static int msg_reply_threshold_value(struct sk_buff *msg, u32 error_id,
> > + const char *error_name, u32 value)
> > +{
> > + int ret;
> > +
> > + ret = nla_put_u32(msg, DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID, error_id);
> > + if (ret)
> > + return ret;
> > +
> > + ret = nla_put_string(msg, DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_NAME,
> > + error_name);
> > + if (ret)
> > + return ret;
> > +
> > + return nla_put_u32(msg, DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_THRESHOLD,
> > + value);
> > +}
> > +
> > static int doit_reply_counter_value(struct genl_info *info, u32 node_id,
> > u32 error_id)
> > {
> > @@ -216,6 +256,42 @@ static int doit_reply_counter_value(struct genl_info *info, u32 node_id,
> > return genlmsg_reply(msg, info);
> > }
> > +static int doit_reply_threshold_value(struct genl_info *info, u32 node_id,
> > + u32 error_id)
> > +{
> > + struct sk_buff *msg;
> > + struct nlattr *hdr;
> > + const char *error_name;
> > + u32 value;
> > + int ret;
> > +
> > + msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
> > + if (!msg)
> > + return -ENOMEM;
> > +
> > + hdr = genlmsg_iput(msg, info);
> > + if (!hdr) {
> > + nlmsg_free(msg);
> > + return -EMSGSIZE;
> > + }
> > +
> > + ret = get_node_error_threshold(node_id, error_id,
> > + &error_name, &value);
> > + if (ret)
> > + return ret;
>
> You have to cancel and free genlmsg here.
> Looks like the counter patch also has the same issue. Will send out a fix.
Yeah, failed attempt at stealing your code :(
Raag
> > + ret = msg_reply_threshold_value(msg, error_id, error_name, value);
> > + if (ret) {
> > + genlmsg_cancel(msg, hdr);
> > + nlmsg_free(msg);
> > + return ret;
> > + }
> > +
> > + genlmsg_end(msg, hdr);
> > +
> > + return genlmsg_reply(msg, info);
> > +}
> > +
> > /**
> > * drm_ras_nl_get_error_counter_dumpit() - Dump all Error Counters
> > * @skb: Netlink message buffer
> > @@ -314,6 +390,33 @@ int drm_ras_nl_get_error_counter_doit(struct sk_buff *skb,
> > return doit_reply_counter_value(info, node_id, error_id);
> > }
> > +/**
> > + * drm_ras_nl_get_error_threshold_doit() - Query threshold value of the error
> Nit: an
>
> Thanks
> Riana
> > + * @skb: Netlink message buffer
> > + * @info: Generic Netlink info containing attributes of the request
> > + *
> > + * Extracts the node ID and error ID from the netlink attributes and
> > + * retrieves the current threshold of the corresponding error. Sends the
> > + * result back to the requesting user via the standard Genl reply.
> > + *
> > + * Return: 0 on success, or negative errno on failure.
> > + */
> > +int drm_ras_nl_get_error_threshold_doit(struct sk_buff *skb,
> > + struct genl_info *info)
> > +{
> > + u32 node_id, error_id;
> > +
> > + if (!info->attrs ||
> > + GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_ERROR_THRESHOLD_ATTRS_NODE_ID) ||
> > + GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID))
> > + return -EINVAL;
> > +
> > + node_id = nla_get_u32(info->attrs[DRM_RAS_A_ERROR_THRESHOLD_ATTRS_NODE_ID]);
> > + error_id = nla_get_u32(info->attrs[DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID]);
> > +
> > + return doit_reply_threshold_value(info, node_id, error_id);
> > +}
> > +
> > /**
> > * drm_ras_node_register() - Register a new RAS node
> > * @node: Node structure to register
> > diff --git a/drivers/gpu/drm/drm_ras_nl.c b/drivers/gpu/drm/drm_ras_nl.c
> > index 16803d0c4a44..48e231734f4d 100644
> > --- a/drivers/gpu/drm/drm_ras_nl.c
> > +++ b/drivers/gpu/drm/drm_ras_nl.c
> > @@ -22,6 +22,12 @@ static const struct nla_policy drm_ras_get_error_counter_dump_nl_policy[DRM_RAS_
> > [DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID] = { .type = NLA_U32, },
> > };
> > +/* DRM_RAS_CMD_GET_ERROR_THRESHOLD - do */
> > +static const struct nla_policy drm_ras_get_error_threshold_nl_policy[DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID + 1] = {
> > + [DRM_RAS_A_ERROR_THRESHOLD_ATTRS_NODE_ID] = { .type = NLA_U32, },
> > + [DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID] = { .type = NLA_U32, },
> > +};
> > +
> > /* Ops table for drm_ras */
> > static const struct genl_split_ops drm_ras_nl_ops[] = {
> > {
> > @@ -43,6 +49,13 @@ static const struct genl_split_ops drm_ras_nl_ops[] = {
> > .maxattr = DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID,
> > .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP,
> > },
> > + {
> > + .cmd = DRM_RAS_CMD_GET_ERROR_THRESHOLD,
> > + .doit = drm_ras_nl_get_error_threshold_doit,
> > + .policy = drm_ras_get_error_threshold_nl_policy,
> > + .maxattr = DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID,
> > + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
> > + },
> > };
> > struct genl_family drm_ras_nl_family __ro_after_init = {
> > diff --git a/drivers/gpu/drm/drm_ras_nl.h b/drivers/gpu/drm/drm_ras_nl.h
> > index 06ccd9342773..540fe22e2312 100644
> > --- a/drivers/gpu/drm/drm_ras_nl.h
> > +++ b/drivers/gpu/drm/drm_ras_nl.h
> > @@ -18,6 +18,8 @@ int drm_ras_nl_get_error_counter_doit(struct sk_buff *skb,
> > struct genl_info *info);
> > int drm_ras_nl_get_error_counter_dumpit(struct sk_buff *skb,
> > struct netlink_callback *cb);
> > +int drm_ras_nl_get_error_threshold_doit(struct sk_buff *skb,
> > + struct genl_info *info);
> > extern struct genl_family drm_ras_nl_family;
> > diff --git a/include/drm/drm_ras.h b/include/drm/drm_ras.h
> > index 5d50209e51db..50cee70bd065 100644
> > --- a/include/drm/drm_ras.h
> > +++ b/include/drm/drm_ras.h
> > @@ -57,6 +57,20 @@ struct drm_ras_node {
> > */
> > int (*query_error_counter)(struct drm_ras_node *node, u32 error_id,
> > const char **name, u32 *val);
> > + /**
> > + * @query_error_threshold:
> > + *
> > + * This callback is used by drm-ras to query threshold value of a
> > + * specific error.
> > + *
> > + * Driver should expect query_error_threshold() to be called with
> > + * error_id from `error_counter_range.first` to
> > + * `error_counter_range.last`.
> > + *
> > + * Returns: 0 on success, negative error code on failure.
> > + */
> > + int (*query_error_threshold)(struct drm_ras_node *node, u32 error_id,
> > + const char **name, u32 *val);
> > /** @priv: Driver private data */
> > void *priv;
> > diff --git a/include/uapi/drm/drm_ras.h b/include/uapi/drm/drm_ras.h
> > index 5f40fa5b869d..49c5ca497d73 100644
> > --- a/include/uapi/drm/drm_ras.h
> > +++ b/include/uapi/drm/drm_ras.h
> > @@ -38,9 +38,20 @@ enum {
> > DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX = (__DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX - 1)
> > };
> > +enum {
> > + DRM_RAS_A_ERROR_THRESHOLD_ATTRS_NODE_ID = 1,
> > + DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID,
> > + DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_NAME,
> > + DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_THRESHOLD,
> > +
> > + __DRM_RAS_A_ERROR_THRESHOLD_ATTRS_MAX,
> > + DRM_RAS_A_ERROR_THRESHOLD_ATTRS_MAX = (__DRM_RAS_A_ERROR_THRESHOLD_ATTRS_MAX - 1)
> > +};
> > +
> > enum {
> > DRM_RAS_CMD_LIST_NODES = 1,
> > DRM_RAS_CMD_GET_ERROR_COUNTER,
> > + DRM_RAS_CMD_GET_ERROR_THRESHOLD,
> > __DRM_RAS_CMD_MAX,
> > DRM_RAS_CMD_MAX = (__DRM_RAS_CMD_MAX - 1)
^ permalink raw reply
* Re: [PATCH v1 03/11] drm/ras: Introduce set-error-threshold
From: Tauro, Riana @ 2026-04-22 6:12 UTC (permalink / raw)
To: Raag Jadav, intel-xe, dri-devel, netdev
Cc: simona.vetter, airlied, kuba, lijo.lazar, Hawking.Zhang, davem,
pabeni, edumazet, maarten, zachary.mckevitt, rodrigo.vivi,
michal.wajdeczko, matthew.d.roper, umesh.nerlige.ramappa,
mallesh.koujalagi, soham.purkait, anoop.c.vijay,
aravind.iddamsetty
In-Reply-To: <20260417211730.837345-4-raag.jadav@intel.com>
On 4/18/2026 2:46 AM, Raag Jadav wrote:
> Add set-error-threshold command support which allows setting threshold
> value of the error. Threshold in RAS context means the number of errors
> the hardware is expected to accumulate before it raises them to software.
> This is to have a fine grained control over error notifications that are
> raised by the hardware.
>
> Signed-off-by: Raag Jadav <raag.jadav@intel.com>
> ---
> Documentation/gpu/drm-ras.rst | 9 +++++
> Documentation/netlink/specs/drm_ras.yaml | 12 ++++++
> drivers/gpu/drm/drm_ras.c | 48 ++++++++++++++++++++++++
> drivers/gpu/drm/drm_ras_nl.c | 14 +++++++
> drivers/gpu/drm/drm_ras_nl.h | 2 +
> include/drm/drm_ras.h | 13 +++++++
> include/uapi/drm/drm_ras.h | 1 +
> 7 files changed, 99 insertions(+)
>
> diff --git a/Documentation/gpu/drm-ras.rst b/Documentation/gpu/drm-ras.rst
> index 6443dfd1677f..a819aa150604 100644
> --- a/Documentation/gpu/drm-ras.rst
> +++ b/Documentation/gpu/drm-ras.rst
> @@ -54,6 +54,8 @@ User space tools can:
> ``node-id`` and ``error-id`` as parameters.
> * Query specific error threshold value with the ``get-error-threshold`` command, using both
> ``node-id`` and ``error-id`` as parameters.
> +* Set specific error threshold value with the ``set-error-threshold`` command, using
> + ``node-id``, ``error-id`` and ``error-threshold`` as parameters.
>
> YAML-based Interface
> --------------------
> @@ -109,3 +111,10 @@ Example: Query threshold value of a given error
>
> sudo ynl --family drm_ras --do get-error-threshold --json '{"node-id":0, "error-id":1}'
> {'error-id': 1, 'error-name': 'error_name1', 'error-threshold': 0}
> +
> +Example: Set threshold value of a given error
> +
> +.. code-block:: bash
> +
> + sudo ynl --family drm_ras --do set-error-threshold --json '{"node-id":0, "error-id":1, "error-threshold":8}'
> + None
> diff --git a/Documentation/netlink/specs/drm_ras.yaml b/Documentation/netlink/specs/drm_ras.yaml
> index 95a939fb987d..09824309cdff 100644
> --- a/Documentation/netlink/specs/drm_ras.yaml
> +++ b/Documentation/netlink/specs/drm_ras.yaml
> @@ -150,3 +150,15 @@ operations:
> - error-id
> - error-name
> - error-threshold
> + -
> + name: set-error-threshold
> + doc: >-
> + Set threshold value of the error.
> + attribute-set: error-threshold-attrs
> + flags: [admin-perm]
> + do:
> + request:
> + attributes:
> + - node-id
> + - error-id
> + - error-threshold
> diff --git a/drivers/gpu/drm/drm_ras.c b/drivers/gpu/drm/drm_ras.c
> index d2d853d5d69c..e4ff6d87f824 100644
> --- a/drivers/gpu/drm/drm_ras.c
> +++ b/drivers/gpu/drm/drm_ras.c
> @@ -41,6 +41,9 @@
> * Userspace must provide Node ID and Error ID.
> * Returns the threshold value of a specific error.
> *
> + * 4. SET_ERROR_THRESHOLD: Set threshold value of the error.
> + * Userspace must provide Node ID, Error ID and Threshold value to be set.
> + *
> * Node registration:
> *
> * - drm_ras_node_register(): Registers a new node and assigns
> @@ -72,6 +75,8 @@
> * operation, fetching a counter value from a specific node.
> * - drm_ras_nl_get_error_threshold_doit(): Implements the GET_ERROR_THRESHOLD doit
> * operation, fetching the threshold value of a specific error.
> + * - drm_ras_nl_set_error_threshold_doit(): Implements the SET_ERROR_THRESHOLD doit
> + * operation, setting the threshold value of a specific error.
> */
>
> static DEFINE_XARRAY_ALLOC(drm_ras_xa);
> @@ -184,6 +189,21 @@ static int get_node_error_threshold(u32 node_id, u32 error_id,
> return node->query_error_threshold(node, error_id, name, value);
> }
>
> +static int set_node_error_threshold(u32 node_id, u32 error_id, u32 value)
> +{
> + struct drm_ras_node *node;
> +
> + node = xa_load(&drm_ras_xa, node_id);
> + if (!node || !node->set_error_threshold)
> + return -ENOENT;
Use -EOPNOTSUPP for absence of function
> +
> + if (error_id < node->error_counter_range.first ||
> + error_id > node->error_counter_range.last)
> + return -EINVAL;
> +
> + return node->set_error_threshold(node, error_id, value);
> +}
> +
> static int msg_reply_counter_value(struct sk_buff *msg, u32 error_id,
> const char *error_name, u32 value)
> {
> @@ -417,6 +437,34 @@ int drm_ras_nl_get_error_threshold_doit(struct sk_buff *skb,
> return doit_reply_threshold_value(info, node_id, error_id);
> }
>
> +/**
> + * drm_ras_nl_set_error_threshold_doit() - Set threshold value of the error
> + * @skb: Netlink message buffer
> + * @info: Generic Netlink info containing attributes of the request
> + *
> + * Extracts the node ID, error ID and threshold value from the netlink attributes
> + * and sets the threshold of the corresponding error.
> + *
> + * Return: 0 on success, or negative errno on failure.
> + */
> +int drm_ras_nl_set_error_threshold_doit(struct sk_buff *skb,
> + struct genl_info *info)
> +{
> + u32 node_id, error_id, value;
> +
> + if (!info->attrs ||
> + GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_ERROR_THRESHOLD_ATTRS_NODE_ID) ||
> + GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID) ||
> + GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_THRESHOLD))
> + return -EINVAL;
> +
> + node_id = nla_get_u32(info->attrs[DRM_RAS_A_ERROR_THRESHOLD_ATTRS_NODE_ID]);
> + error_id = nla_get_u32(info->attrs[DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID]);
> + value = nla_get_u32(info->attrs[DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_THRESHOLD]);
do we need a check for max threshold here? Probably configured by drivers?
Or is it upto the driver to check? If its upto the driver, please add it
in the document
Thanks
Riana
> +
> + return set_node_error_threshold(node_id, error_id, value);
> +}
> +
> /**
> * drm_ras_node_register() - Register a new RAS node
> * @node: Node structure to register
> diff --git a/drivers/gpu/drm/drm_ras_nl.c b/drivers/gpu/drm/drm_ras_nl.c
> index 48e231734f4d..8b202d773dac 100644
> --- a/drivers/gpu/drm/drm_ras_nl.c
> +++ b/drivers/gpu/drm/drm_ras_nl.c
> @@ -28,6 +28,13 @@ static const struct nla_policy drm_ras_get_error_threshold_nl_policy[DRM_RAS_A_E
> [DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID] = { .type = NLA_U32, },
> };
>
> +/* DRM_RAS_CMD_SET_ERROR_THRESHOLD - do */
> +static const struct nla_policy drm_ras_set_error_threshold_nl_policy[DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_THRESHOLD + 1] = {
> + [DRM_RAS_A_ERROR_THRESHOLD_ATTRS_NODE_ID] = { .type = NLA_U32, },
> + [DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID] = { .type = NLA_U32, },
> + [DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_THRESHOLD] = { .type = NLA_U32, },
> +};
> +
> /* Ops table for drm_ras */
> static const struct genl_split_ops drm_ras_nl_ops[] = {
> {
> @@ -56,6 +63,13 @@ static const struct genl_split_ops drm_ras_nl_ops[] = {
> .maxattr = DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID,
> .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
> },
> + {
> + .cmd = DRM_RAS_CMD_SET_ERROR_THRESHOLD,
> + .doit = drm_ras_nl_set_error_threshold_doit,
> + .policy = drm_ras_set_error_threshold_nl_policy,
> + .maxattr = DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_THRESHOLD,
> + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
> + },
> };
>
> struct genl_family drm_ras_nl_family __ro_after_init = {
> diff --git a/drivers/gpu/drm/drm_ras_nl.h b/drivers/gpu/drm/drm_ras_nl.h
> index 540fe22e2312..9db7f5d00201 100644
> --- a/drivers/gpu/drm/drm_ras_nl.h
> +++ b/drivers/gpu/drm/drm_ras_nl.h
> @@ -20,6 +20,8 @@ int drm_ras_nl_get_error_counter_dumpit(struct sk_buff *skb,
> struct netlink_callback *cb);
> int drm_ras_nl_get_error_threshold_doit(struct sk_buff *skb,
> struct genl_info *info);
> +int drm_ras_nl_set_error_threshold_doit(struct sk_buff *skb,
> + struct genl_info *info);
>
> extern struct genl_family drm_ras_nl_family;
>
> diff --git a/include/drm/drm_ras.h b/include/drm/drm_ras.h
> index 50cee70bd065..7a69821b8b78 100644
> --- a/include/drm/drm_ras.h
> +++ b/include/drm/drm_ras.h
> @@ -71,6 +71,19 @@ struct drm_ras_node {
> */
> int (*query_error_threshold)(struct drm_ras_node *node, u32 error_id,
> const char **name, u32 *val);
> + /**
> + * @set_error_threshold:
> + *
> + * This callback is used by drm-ras to set threshold value of a specific
> + * error.
> + *
> + * Driver should expect set_error_threshold() to be called with error_id
> + * from `error_counter_range.first` to `error_counter_range.last`.
> + *
> + * Returns: 0 on success, negative error code on failure.
> + */
> + int (*set_error_threshold)(struct drm_ras_node *node, u32 error_id,
> + u32 val);
>
> /** @priv: Driver private data */
> void *priv;
> diff --git a/include/uapi/drm/drm_ras.h b/include/uapi/drm/drm_ras.h
> index 49c5ca497d73..8ff0311d0d63 100644
> --- a/include/uapi/drm/drm_ras.h
> +++ b/include/uapi/drm/drm_ras.h
> @@ -52,6 +52,7 @@ enum {
> DRM_RAS_CMD_LIST_NODES = 1,
> DRM_RAS_CMD_GET_ERROR_COUNTER,
> DRM_RAS_CMD_GET_ERROR_THRESHOLD,
> + DRM_RAS_CMD_SET_ERROR_THRESHOLD,
>
> __DRM_RAS_CMD_MAX,
> DRM_RAS_CMD_MAX = (__DRM_RAS_CMD_MAX - 1)
^ permalink raw reply
* Re: [net-next PATCH 09/10] net: dsa: realtek: rtl8365mb: add bridge port flags
From: Luiz Angelo Daros de Luca @ 2026-04-22 6:06 UTC (permalink / raw)
To: Linus Walleij
Cc: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Alvin Šipraga,
Yury Norov, Rasmus Villemoes, Russell King, netdev, linux-kernel
In-Reply-To: <CAD++jL=v6qe+dVF-wk3cPg3aw8Qp7pS6BVtAqmWURJ=JvMvDHA@mail.gmail.com>
> > +static int rtl8365mb_port_set_ucast_flood(struct realtek_priv *priv, int port,
> > + bool enable)
> > +static int rtl8365mb_port_set_mcast_flood(struct realtek_priv *priv, int port,
> > + bool enable)
> > +static int rtl8365mb_port_set_bcast_flood(struct realtek_priv *priv, int port,
> > + bool enable)
>
> Those are small and just writing registers so I guess they can be kept local,
> but I think they should be accessed indirectly through
> struct realtek_ops .rtl8366_port_set_ucast_flood() etc.
Sure.
> > +static int rtl8365mb_port_bridge_flags(struct dsa_switch *ds, int port,
> > + struct switchdev_brport_flags flags,
> > + struct netlink_ext_ack *exack)
>
> Move this one to rtl8366-core.c under the name rtl8366_port_[pre_]bridge_flags()
> and use the abstract accessors to do the register writes.
OK
> > @@ -1691,6 +1797,8 @@ static int rtl8365mb_port_bridge_join(struct dsa_switch *ds, int port,
> > int ret;
> > int i;
> >
> > + dev_dbg(priv->dev, "bridge %d join port %d\n", port, bridge.num);
> > +
> > /* Add this port to the isolation group of every other port
> > * offloading this bridge.
> > */
> > @@ -1730,6 +1838,8 @@ static void rtl8365mb_port_bridge_leave(struct dsa_switch *ds, int port,
> > u32 mask = 0;
> > int i;
> >
> > + dev_dbg(priv->dev, "bridge %d leave port %d\n", port, bridge.num);
> > +
> > /* Remove this port from the isolation group of every other
> > * port offloading this bridge.
> > */
>
> These debug prints seem unrelated to this patch?
Yes, sorry. I'll move them.
>
> > @@ -2547,6 +2657,19 @@ static int rtl8365mb_setup(struct dsa_switch *ds)
> > if (ret)
> > goto out_teardown_irq;
> >
> > + /* Enable all types of flooding */
> > + ret = rtl8365mb_port_set_ucast_flood(priv, i, true);
> > + if (ret)
> > + goto out_teardown_irq;
> > +
> > + ret = rtl8365mb_port_set_mcast_flood(priv, i, true);
> > + if (ret)
> > + goto out_teardown_irq;
> > +
> > + ret = rtl8365mb_port_set_bcast_flood(priv, i, true);
> > + if (ret)
> > + goto out_teardown_irq;
>
> Create rtl8366_setup_flood_control() in realtek-core.c and add these
> three calls as a helper using the rtl8366_* generic calls there. It will be
> done the same on all chips.
OK. I think
rtl83xx_setup_port_flood_control(struct realtek_priv *priv, int port);
might be better as we can avoid looping again over the ports.
Regards,
Luiz
^ permalink raw reply
* Re: [PATCH net v1] vhost_net: fix sleeping with preempt-disabled in vhost_net_busy_poll()
From: Michael S. Tsirkin @ 2026-04-22 6:05 UTC (permalink / raw)
To: Kohei Enju
Cc: Jason Wang, Eugenio Pérez, kvm, virtualization, netdev,
syzbot+6985cb8e543ea90ba8ee
In-Reply-To: <20260422023026.81960-1-kohei@enjuk.jp>
On Wed, Apr 22, 2026 at 02:30:24AM +0000, Kohei Enju wrote:
> syzbot reported "sleeping function called from invalid context" in
> vhost_net_busy_poll().
>
> Commit 030881372460 ("vhost_net: basic polling support") introduced a
> busy-poll loop and preempt_{disable,enable}() around it, where each
> iteration calls a sleepable function inside the loop.
>
> The purpose of disabling preemption was to keep local_clock()-based
> timeout accounting on a single CPU, rather than as a requirement of
> busy-poll itself:
>
> https://lore.kernel.org/netdev/1448435489-5949-4-git-send-email-jasowang@redhat.com/T/#u
>
> Changes from RFC V1:
> ...
> - Disable preemption during busy looping to make sure local_clock()
> was correctly used.
>
> >From this perspective, migrate_disable() is sufficient here, so replace
> preempt_disable() with migrate_disable(), avoiding sleepable accesses
> from a preempt-disabled context.
>
> Fixes: 030881372460 ("vhost_net: basic polling support")
> Tested-by: syzbot+6985cb8e543ea90ba8ee@syzkaller.appspotmail.com
> Reported-by: syzbot+6985cb8e543ea90ba8ee@syzkaller.appspotmail.com
> Closes: https://lore.kernel.org/all/69e6a414.050a0220.24bfd3.002d.GAE@google.com/T/
> Signed-off-by: Kohei Enju <kohei@enjuk.jp>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
> ---
> drivers/vhost/net.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
> index 80965181920c..c6536cad9c4f 100644
> --- a/drivers/vhost/net.c
> +++ b/drivers/vhost/net.c
> @@ -560,7 +560,7 @@ static void vhost_net_busy_poll(struct vhost_net *net,
> busyloop_timeout = poll_rx ? rvq->busyloop_timeout:
> tvq->busyloop_timeout;
>
> - preempt_disable();
> + migrate_disable();
> endtime = busy_clock() + busyloop_timeout;
>
> while (vhost_can_busy_poll(endtime)) {
> @@ -577,7 +577,7 @@ static void vhost_net_busy_poll(struct vhost_net *net,
> cpu_relax();
> }
>
> - preempt_enable();
> + migrate_enable();
>
> if (poll_rx || sock_has_rx_data(sock))
> vhost_net_busy_poll_try_queue(net, vq);
> --
> 2.51.0
^ permalink raw reply
* Re: [PATCH v1 05/11] drm/xe/sysctrl: Add system controller interrupt handler
From: Tauro, Riana @ 2026-04-22 5:55 UTC (permalink / raw)
To: Raag Jadav, intel-xe, dri-devel, netdev
Cc: simona.vetter, airlied, kuba, lijo.lazar, Hawking.Zhang, davem,
pabeni, edumazet, maarten, zachary.mckevitt, rodrigo.vivi,
michal.wajdeczko, matthew.d.roper, umesh.nerlige.ramappa,
mallesh.koujalagi, soham.purkait, anoop.c.vijay,
aravind.iddamsetty
In-Reply-To: <20260417211730.837345-6-raag.jadav@intel.com>
On 4/18/2026 2:46 AM, Raag Jadav wrote:
> Add system controller interrupt handler which is denoted by 11th bit in
> GFX master interrupt register. While at it, add worker for scheduling
> system controller work.
Why do we need this series in the threshold patch. From what i see, we
need only structures
Can't we only redefine those here?
I know you will have to rebase again once any patch is merged. But this
is unnecessary noise
for the drm patch.
Thanks
Riana
>
> Co-developed-by: Soham Purkait <soham.purkait@intel.com>
> Signed-off-by: Soham Purkait <soham.purkait@intel.com>
> Signed-off-by: Raag Jadav <raag.jadav@intel.com>
> Reviewed-by: Mallesh Koujalagi <mallesh.koujalagi@intel.com>
> Reviewed-by: Riana Tauro <riana.tauro@intel.com>
> ---
> drivers/gpu/drm/xe/regs/xe_irq_regs.h | 1 +
> drivers/gpu/drm/xe/xe_irq.c | 2 ++
> drivers/gpu/drm/xe/xe_sysctrl.c | 35 +++++++++++++++++++++------
> drivers/gpu/drm/xe/xe_sysctrl.h | 1 +
> drivers/gpu/drm/xe/xe_sysctrl_types.h | 4 +++
> 5 files changed, 36 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/gpu/drm/xe/regs/xe_irq_regs.h b/drivers/gpu/drm/xe/regs/xe_irq_regs.h
> index 9d74f454d3ff..1d6b976c4de0 100644
> --- a/drivers/gpu/drm/xe/regs/xe_irq_regs.h
> +++ b/drivers/gpu/drm/xe/regs/xe_irq_regs.h
> @@ -22,6 +22,7 @@
> #define DISPLAY_IRQ REG_BIT(16)
> #define SOC_H2DMEMINT_IRQ REG_BIT(13)
> #define I2C_IRQ REG_BIT(12)
> +#define SYSCTRL_IRQ REG_BIT(11)
> #define GT_DW_IRQ(x) REG_BIT(x)
>
> /*
> diff --git a/drivers/gpu/drm/xe/xe_irq.c b/drivers/gpu/drm/xe/xe_irq.c
> index 9a775c6588dc..e9f0b3cad06d 100644
> --- a/drivers/gpu/drm/xe/xe_irq.c
> +++ b/drivers/gpu/drm/xe/xe_irq.c
> @@ -24,6 +24,7 @@
> #include "xe_mmio.h"
> #include "xe_pxp.h"
> #include "xe_sriov.h"
> +#include "xe_sysctrl.h"
> #include "xe_tile.h"
>
> /*
> @@ -525,6 +526,7 @@ static irqreturn_t dg1_irq_handler(int irq, void *arg)
> xe_heci_csc_irq_handler(xe, master_ctl);
> xe_display_irq_handler(xe, master_ctl);
> xe_i2c_irq_handler(xe, master_ctl);
> + xe_sysctrl_irq_handler(xe, master_ctl);
> xe_mert_irq_handler(xe, master_ctl);
> gu_misc_iir = gu_misc_irq_ack(xe, master_ctl);
> }
> diff --git a/drivers/gpu/drm/xe/xe_sysctrl.c b/drivers/gpu/drm/xe/xe_sysctrl.c
> index 2bcef304eb9a..7de3e73bd8e0 100644
> --- a/drivers/gpu/drm/xe/xe_sysctrl.c
> +++ b/drivers/gpu/drm/xe/xe_sysctrl.c
> @@ -8,6 +8,7 @@
>
> #include <drm/drm_managed.h>
>
> +#include "regs/xe_irq_regs.h"
> #include "regs/xe_sysctrl_regs.h"
> #include "xe_device.h"
> #include "xe_mmio.h"
> @@ -30,10 +31,16 @@
> static void sysctrl_fini(void *arg)
> {
> struct xe_device *xe = arg;
> + struct xe_sysctrl *sc = &xe->sc;
>
> + disable_work_sync(&sc->work);
> xe->soc_remapper.set_sysctrl_region(xe, 0);
> }
>
> +static void xe_sysctrl_work(struct work_struct *work)
> +{
> +}
> +
> /**
> * xe_sysctrl_init() - Initialize System Controller subsystem
> * @xe: xe device instance
> @@ -55,12 +62,6 @@ int xe_sysctrl_init(struct xe_device *xe)
> if (!xe->info.has_sysctrl)
> return 0;
>
> - xe->soc_remapper.set_sysctrl_region(xe, SYSCTRL_MAILBOX_INDEX);
> -
> - ret = devm_add_action_or_reset(xe->drm.dev, sysctrl_fini, xe);
> - if (ret)
> - return ret;
> -
> sc->mmio = devm_kzalloc(xe->drm.dev, sizeof(*sc->mmio), GFP_KERNEL);
> if (!sc->mmio)
> return -ENOMEM;
> @@ -73,9 +74,29 @@ int xe_sysctrl_init(struct xe_device *xe)
> if (ret)
> return ret;
>
> + xe->soc_remapper.set_sysctrl_region(xe, SYSCTRL_MAILBOX_INDEX);
> xe_sysctrl_mailbox_init(sc);
> + INIT_WORK(&sc->work, xe_sysctrl_work);
>
> - return 0;
> + return devm_add_action_or_reset(xe->drm.dev, sysctrl_fini, xe);
> +}
> +
> +/**
> + * xe_sysctrl_irq_handler() - Handler for System Controller interrupts
> + * @xe: xe device instance
> + * @master_ctl: interrupt register
> + *
> + * Handle interrupts generated by System Controller.
> + */
> +void xe_sysctrl_irq_handler(struct xe_device *xe, u32 master_ctl)
> +{
> + struct xe_sysctrl *sc = &xe->sc;
> +
> + if (!xe->info.has_sysctrl || !sc->work.func)
> + return;
> +
> + if (master_ctl & SYSCTRL_IRQ)
> + schedule_work(&sc->work);
> }
>
> /**
> diff --git a/drivers/gpu/drm/xe/xe_sysctrl.h b/drivers/gpu/drm/xe/xe_sysctrl.h
> index f3b0f3716b2f..f7469bfc9324 100644
> --- a/drivers/gpu/drm/xe/xe_sysctrl.h
> +++ b/drivers/gpu/drm/xe/xe_sysctrl.h
> @@ -17,6 +17,7 @@ static inline struct xe_device *sc_to_xe(struct xe_sysctrl *sc)
> }
>
> int xe_sysctrl_init(struct xe_device *xe);
> +void xe_sysctrl_irq_handler(struct xe_device *xe, u32 master_ctl);
> void xe_sysctrl_pm_resume(struct xe_device *xe);
>
> #endif
> diff --git a/drivers/gpu/drm/xe/xe_sysctrl_types.h b/drivers/gpu/drm/xe/xe_sysctrl_types.h
> index 8217f6befe70..5f408d6491ef 100644
> --- a/drivers/gpu/drm/xe/xe_sysctrl_types.h
> +++ b/drivers/gpu/drm/xe/xe_sysctrl_types.h
> @@ -8,6 +8,7 @@
>
> #include <linux/mutex.h>
> #include <linux/types.h>
> +#include <linux/workqueue_types.h>
>
> struct xe_mmio;
>
> @@ -27,6 +28,9 @@ struct xe_sysctrl {
>
> /** @phase_bit: Message boundary phase toggle bit (0 or 1) */
> bool phase_bit;
> +
> + /** @work: Pending events worker */
> + struct work_struct work;
> };
>
> #endif
^ permalink raw reply
* Re: [PATCH v1 02/11] drm/ras: Introduce get-error-threshold
From: Tauro, Riana @ 2026-04-22 5:49 UTC (permalink / raw)
To: Raag Jadav, intel-xe, dri-devel, netdev
Cc: simona.vetter, airlied, kuba, lijo.lazar, Hawking.Zhang, davem,
pabeni, edumazet, maarten, zachary.mckevitt, rodrigo.vivi,
michal.wajdeczko, matthew.d.roper, umesh.nerlige.ramappa,
mallesh.koujalagi, soham.purkait, anoop.c.vijay,
aravind.iddamsetty
In-Reply-To: <20260417211730.837345-3-raag.jadav@intel.com>
On 4/18/2026 2:46 AM, Raag Jadav wrote:
> Add get-error-threshold command support which allows querying threshold
> value of the error. Threshold in RAS context means the number of errors
> the hardware is expected to accumulate before it raises them to software.
> This is to have a fine grained control over error notifications that are
> raised by the hardware.
>
> Signed-off-by: Raag Jadav <raag.jadav@intel.com>
> ---
> Documentation/gpu/drm-ras.rst | 8 ++
> Documentation/netlink/specs/drm_ras.yaml | 37 ++++++++
> drivers/gpu/drm/drm_ras.c | 103 +++++++++++++++++++++++
> drivers/gpu/drm/drm_ras_nl.c | 13 +++
> drivers/gpu/drm/drm_ras_nl.h | 2 +
> include/drm/drm_ras.h | 14 +++
> include/uapi/drm/drm_ras.h | 11 +++
> 7 files changed, 188 insertions(+)
>
> diff --git a/Documentation/gpu/drm-ras.rst b/Documentation/gpu/drm-ras.rst
> index 70b246a78fc8..6443dfd1677f 100644
> --- a/Documentation/gpu/drm-ras.rst
> +++ b/Documentation/gpu/drm-ras.rst
> @@ -52,6 +52,8 @@ User space tools can:
> as a parameter.
> * Query specific error counter values with the ``get-error-counter`` command, using both
> ``node-id`` and ``error-id`` as parameters.
> +* Query specific error threshold value with the ``get-error-threshold`` command, using both
> + ``node-id`` and ``error-id`` as parameters.
Also define what is a thresold. How can it be used?
>
> YAML-based Interface
> --------------------
> @@ -101,3 +103,9 @@ Example: Query an error counter for a given node
> sudo ynl --family drm_ras --do get-error-counter --json '{"node-id":0, "error-id":1}'
> {'error-id': 1, 'error-name': 'error_name1', 'error-value': 0}
>
> +Example: Query threshold value of a given error
> +
> +.. code-block:: bash
> +
> + sudo ynl --family drm_ras --do get-error-threshold --json '{"node-id":0, "error-id":1}'
> + {'error-id': 1, 'error-name': 'error_name1', 'error-threshold': 0}
> diff --git a/Documentation/netlink/specs/drm_ras.yaml b/Documentation/netlink/specs/drm_ras.yaml
> index 79af25dac3c5..95a939fb987d 100644
> --- a/Documentation/netlink/specs/drm_ras.yaml
> +++ b/Documentation/netlink/specs/drm_ras.yaml
> @@ -69,6 +69,25 @@ attribute-sets:
> name: error-value
> type: u32
> doc: Current value of the requested error counter.
> + -
> + name: error-threshold-attrs
> + attributes:
> + -
> + name: node-id
> + type: u32
> + doc: Node ID targeted by this operation.
> + -
> + name: error-id
> + type: u32
> + doc: Unique identifier for a specific error within the node.
> + -
> + name: error-name
> + type: string
> + doc: Name of the error.
> + -
> + name: error-threshold
> + type: u32
> + doc: Threshold value of the error.
>
> operations:
> list:
> @@ -113,3 +132,21 @@ operations:
> - node-id
> reply:
> attributes: *errorinfo
> + -
> + name: get-error-threshold
> + doc: >-
> + Retrieve threshold value of the error.
> + The response includes the id, the name, and current threshold
> + value of the error.
> + attribute-set: error-threshold-attrs
> + flags: [admin-perm]
> + do:
> + request:
> + attributes:
> + - node-id
> + - error-id
> + reply:
> + attributes:
> + - error-id
> + - error-name
> + - error-threshold
> diff --git a/drivers/gpu/drm/drm_ras.c b/drivers/gpu/drm/drm_ras.c
> index 1f7435d60f11..d2d853d5d69c 100644
> --- a/drivers/gpu/drm/drm_ras.c
> +++ b/drivers/gpu/drm/drm_ras.c
> @@ -37,6 +37,10 @@
> * Returns all counters of a node if only Node ID is provided or specific
> * error counters.
> *
> + * 3. GET_ERROR_THRESHOLD: Query threshold value of the error.
> + * Userspace must provide Node ID and Error ID.
> + * Returns the threshold value of a specific error.
> + *
> * Node registration:
> *
> * - drm_ras_node_register(): Registers a new node and assigns
> @@ -66,6 +70,8 @@
> * operation, fetching all counters from a specific node.
> * - drm_ras_nl_get_error_counter_doit(): Implements the GET_ERROR_COUNTER doit
> * operation, fetching a counter value from a specific node.
> + * - drm_ras_nl_get_error_threshold_doit(): Implements the GET_ERROR_THRESHOLD doit
> + * operation, fetching the threshold value of a specific error.
> */
>
> static DEFINE_XARRAY_ALLOC(drm_ras_xa);
> @@ -162,6 +168,22 @@ static int get_node_error_counter(u32 node_id, u32 error_id,
> return node->query_error_counter(node, error_id, name, value);
> }
>
> +static int get_node_error_threshold(u32 node_id, u32 error_id,
> + const char **name, u32 *value)
> +{
> + struct drm_ras_node *node;
> +
> + node = xa_load(&drm_ras_xa, node_id);
> + if (!node || !node->query_error_threshold)
> + return -ENOENT;
For the absence of the function, return -EOPNOTSUPP
> +
> + if (error_id < node->error_counter_range.first ||
> + error_id > node->error_counter_range.last)
> + return -EINVAL;
> +
> + return node->query_error_threshold(node, error_id, name, value);
> +}
> +
> static int msg_reply_counter_value(struct sk_buff *msg, u32 error_id,
> const char *error_name, u32 value)
> {
> @@ -180,6 +202,24 @@ static int msg_reply_counter_value(struct sk_buff *msg, u32 error_id,
> value);
> }
>
> +static int msg_reply_threshold_value(struct sk_buff *msg, u32 error_id,
> + const char *error_name, u32 value)
> +{
> + int ret;
> +
> + ret = nla_put_u32(msg, DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID, error_id);
> + if (ret)
> + return ret;
> +
> + ret = nla_put_string(msg, DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_NAME,
> + error_name);
> + if (ret)
> + return ret;
> +
> + return nla_put_u32(msg, DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_THRESHOLD,
> + value);
> +}
> +
> static int doit_reply_counter_value(struct genl_info *info, u32 node_id,
> u32 error_id)
> {
> @@ -216,6 +256,42 @@ static int doit_reply_counter_value(struct genl_info *info, u32 node_id,
> return genlmsg_reply(msg, info);
> }
>
> +static int doit_reply_threshold_value(struct genl_info *info, u32 node_id,
> + u32 error_id)
> +{
> + struct sk_buff *msg;
> + struct nlattr *hdr;
> + const char *error_name;
> + u32 value;
> + int ret;
> +
> + msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
> + if (!msg)
> + return -ENOMEM;
> +
> + hdr = genlmsg_iput(msg, info);
> + if (!hdr) {
> + nlmsg_free(msg);
> + return -EMSGSIZE;
> + }
> +
> + ret = get_node_error_threshold(node_id, error_id,
> + &error_name, &value);
> + if (ret)
> + return ret;
You have to cancel and free genlmsg here.
Looks like the counter patch also has the same issue. Will send out a fix.
> +
> + ret = msg_reply_threshold_value(msg, error_id, error_name, value);
> + if (ret) {
> + genlmsg_cancel(msg, hdr);
> + nlmsg_free(msg);
> + return ret;
> + }
> +
> + genlmsg_end(msg, hdr);
> +
> + return genlmsg_reply(msg, info);
> +}
> +
> /**
> * drm_ras_nl_get_error_counter_dumpit() - Dump all Error Counters
> * @skb: Netlink message buffer
> @@ -314,6 +390,33 @@ int drm_ras_nl_get_error_counter_doit(struct sk_buff *skb,
> return doit_reply_counter_value(info, node_id, error_id);
> }
>
> +/**
> + * drm_ras_nl_get_error_threshold_doit() - Query threshold value of the error
Nit: an
Thanks
Riana
> + * @skb: Netlink message buffer
> + * @info: Generic Netlink info containing attributes of the request
> + *
> + * Extracts the node ID and error ID from the netlink attributes and
> + * retrieves the current threshold of the corresponding error. Sends the
> + * result back to the requesting user via the standard Genl reply.
> + *
> + * Return: 0 on success, or negative errno on failure.
> + */
> +int drm_ras_nl_get_error_threshold_doit(struct sk_buff *skb,
> + struct genl_info *info)
> +{
> + u32 node_id, error_id;
> +
> + if (!info->attrs ||
> + GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_ERROR_THRESHOLD_ATTRS_NODE_ID) ||
> + GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID))
> + return -EINVAL;
> +
> + node_id = nla_get_u32(info->attrs[DRM_RAS_A_ERROR_THRESHOLD_ATTRS_NODE_ID]);
> + error_id = nla_get_u32(info->attrs[DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID]);
> +
> + return doit_reply_threshold_value(info, node_id, error_id);
> +}
> +
> /**
> * drm_ras_node_register() - Register a new RAS node
> * @node: Node structure to register
> diff --git a/drivers/gpu/drm/drm_ras_nl.c b/drivers/gpu/drm/drm_ras_nl.c
> index 16803d0c4a44..48e231734f4d 100644
> --- a/drivers/gpu/drm/drm_ras_nl.c
> +++ b/drivers/gpu/drm/drm_ras_nl.c
> @@ -22,6 +22,12 @@ static const struct nla_policy drm_ras_get_error_counter_dump_nl_policy[DRM_RAS_
> [DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID] = { .type = NLA_U32, },
> };
>
> +/* DRM_RAS_CMD_GET_ERROR_THRESHOLD - do */
> +static const struct nla_policy drm_ras_get_error_threshold_nl_policy[DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID + 1] = {
> + [DRM_RAS_A_ERROR_THRESHOLD_ATTRS_NODE_ID] = { .type = NLA_U32, },
> + [DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID] = { .type = NLA_U32, },
> +};
> +
> /* Ops table for drm_ras */
> static const struct genl_split_ops drm_ras_nl_ops[] = {
> {
> @@ -43,6 +49,13 @@ static const struct genl_split_ops drm_ras_nl_ops[] = {
> .maxattr = DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID,
> .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP,
> },
> + {
> + .cmd = DRM_RAS_CMD_GET_ERROR_THRESHOLD,
> + .doit = drm_ras_nl_get_error_threshold_doit,
> + .policy = drm_ras_get_error_threshold_nl_policy,
> + .maxattr = DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID,
> + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
> + },
> };
>
> struct genl_family drm_ras_nl_family __ro_after_init = {
> diff --git a/drivers/gpu/drm/drm_ras_nl.h b/drivers/gpu/drm/drm_ras_nl.h
> index 06ccd9342773..540fe22e2312 100644
> --- a/drivers/gpu/drm/drm_ras_nl.h
> +++ b/drivers/gpu/drm/drm_ras_nl.h
> @@ -18,6 +18,8 @@ int drm_ras_nl_get_error_counter_doit(struct sk_buff *skb,
> struct genl_info *info);
> int drm_ras_nl_get_error_counter_dumpit(struct sk_buff *skb,
> struct netlink_callback *cb);
> +int drm_ras_nl_get_error_threshold_doit(struct sk_buff *skb,
> + struct genl_info *info);
>
> extern struct genl_family drm_ras_nl_family;
>
> diff --git a/include/drm/drm_ras.h b/include/drm/drm_ras.h
> index 5d50209e51db..50cee70bd065 100644
> --- a/include/drm/drm_ras.h
> +++ b/include/drm/drm_ras.h
> @@ -57,6 +57,20 @@ struct drm_ras_node {
> */
> int (*query_error_counter)(struct drm_ras_node *node, u32 error_id,
> const char **name, u32 *val);
> + /**
> + * @query_error_threshold:
> + *
> + * This callback is used by drm-ras to query threshold value of a
> + * specific error.
> + *
> + * Driver should expect query_error_threshold() to be called with
> + * error_id from `error_counter_range.first` to
> + * `error_counter_range.last`.
> + *
> + * Returns: 0 on success, negative error code on failure.
> + */
> + int (*query_error_threshold)(struct drm_ras_node *node, u32 error_id,
> + const char **name, u32 *val);
>
> /** @priv: Driver private data */
> void *priv;
> diff --git a/include/uapi/drm/drm_ras.h b/include/uapi/drm/drm_ras.h
> index 5f40fa5b869d..49c5ca497d73 100644
> --- a/include/uapi/drm/drm_ras.h
> +++ b/include/uapi/drm/drm_ras.h
> @@ -38,9 +38,20 @@ enum {
> DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX = (__DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX - 1)
> };
>
> +enum {
> + DRM_RAS_A_ERROR_THRESHOLD_ATTRS_NODE_ID = 1,
> + DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_ID,
> + DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_NAME,
> + DRM_RAS_A_ERROR_THRESHOLD_ATTRS_ERROR_THRESHOLD,
> +
> + __DRM_RAS_A_ERROR_THRESHOLD_ATTRS_MAX,
> + DRM_RAS_A_ERROR_THRESHOLD_ATTRS_MAX = (__DRM_RAS_A_ERROR_THRESHOLD_ATTRS_MAX - 1)
> +};
> +
> enum {
> DRM_RAS_CMD_LIST_NODES = 1,
> DRM_RAS_CMD_GET_ERROR_COUNTER,
> + DRM_RAS_CMD_GET_ERROR_THRESHOLD,
>
> __DRM_RAS_CMD_MAX,
> DRM_RAS_CMD_MAX = (__DRM_RAS_CMD_MAX - 1)
^ permalink raw reply
* Re: [PATCH] dt-bindings: Fix phandle-array constraints, again
From: Greg Kroah-Hartman @ 2026-04-22 5:46 UTC (permalink / raw)
To: Rob Herring (Arm)
Cc: Maarten Lankhorst, Maxime Ripard, Krzysztof Kozlowski,
Conor Dooley, Ulf Hansson, Stephan Gerhold, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Johannes Berg, Jeff Johnson, Bjorn Helgaas, Lorenzo Pieralisi,
Krzysztof Wilczyński, Manivannan Sadhasivam, Bjorn Andersson,
Mathieu Poirier, Sylwester Nawrocki, Mark Brown, Maxime Coquelin,
Yang Xiwen, Alex Elder, Chaitanya Chundru, Sibi Sankar,
Rao Mandadapu, Patrice Chotard, Xu Yang, Peng Fan,
Thomas Zimmermann, devicetree, linux-kernel, linux-mmc,
linux-arm-msm, netdev, linux-wireless, ath10k, ath11k, linux-pci,
linux-remoteproc, linux-sound, linux-spi, linux-usb
In-Reply-To: <20260421195836.1547469-1-robh@kernel.org>
On Tue, Apr 21, 2026 at 02:55:25PM -0500, Rob Herring (Arm) wrote:
> The unfortunately named 'phandle-array' property type is really a matrix
> with phandle and fixed arg cells entries. A matrix property should have 2
> levels of items constraints.
>
> Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
> ---
> Can someone from QCom provide some descriptions for 'qcom,smem-states'
> properties.
> ---
> .../display/rockchip/rockchip,rk3399-cdn-dp.yaml | 2 ++
> .../bindings/mmc/hisilicon,hi3798cv200-dw-mshc.yaml | 7 ++++---
> Documentation/devicetree/bindings/net/qcom,bam-dmux.yaml | 6 ++++++
> Documentation/devicetree/bindings/net/qcom,ipa.yaml | 6 ++++++
> .../devicetree/bindings/net/wireless/qcom,ath10k.yaml | 5 ++++-
> .../devicetree/bindings/net/wireless/qcom,ath11k.yaml | 5 ++++-
> .../bindings/net/wireless/qcom,ipq5332-wifi.yaml | 9 +++++++++
> .../devicetree/bindings/pci/toshiba,tc9563.yaml | 5 +++--
> .../bindings/remoteproc/qcom,msm8916-mss-pil.yaml | 3 +++
> .../bindings/remoteproc/qcom,msm8996-mss-pil.yaml | 3 +++
> .../devicetree/bindings/remoteproc/qcom,pas-common.yaml | 4 ++++
> .../bindings/remoteproc/qcom,qcs404-cdsp-pil.yaml | 4 ++++
> .../bindings/remoteproc/qcom,sc7180-mss-pil.yaml | 3 +++
> .../bindings/remoteproc/qcom,sc7280-adsp-pil.yaml | 3 +++
> .../bindings/remoteproc/qcom,sc7280-mss-pil.yaml | 3 +++
> .../bindings/remoteproc/qcom,sc7280-wpss-pil.yaml | 3 +++
> .../bindings/remoteproc/qcom,sdm845-adsp-pil.yaml | 3 +++
> .../devicetree/bindings/remoteproc/qcom,wcnss-pil.yaml | 3 +++
> Documentation/devicetree/bindings/sound/samsung,tm2.yaml | 2 ++
> .../devicetree/bindings/spi/st,stm32mp25-ospi.yaml | 5 +++--
> .../devicetree/bindings/usb/chipidea,usb2-common.yaml | 2 ++
> Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml | 7 ++++---
> 22 files changed, 81 insertions(+), 12 deletions(-)
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
^ permalink raw reply
* Re: [net-next PATCH 07/10] net: dsa: realtek: rtl8365mb: add port_bridge_{join,leave}
From: Luiz Angelo Daros de Luca @ 2026-04-22 5:42 UTC (permalink / raw)
To: Linus Walleij
Cc: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Alvin Šipraga,
Yury Norov, Rasmus Villemoes, Russell King, netdev, linux-kernel
In-Reply-To: <CAD++jLn1gWBmSN7bDkVr_8RmbM3KptKx-z5cycYv+jG-d7FHPg@mail.gmail.com>
> > +static int rtl8365mb_port_bridge_join(struct dsa_switch *ds, int port,
> > + struct dsa_bridge bridge,
> > + bool *tx_forward_offload,
> > + struct netlink_ext_ack *extack)
> > +static void rtl8365mb_port_bridge_leave(struct dsa_switch *ds, int port,
> > + struct dsa_bridge bridge)
>
> The content of these functions are very similar to
> rtl8366rb_port_bridge_join() and rtl8366rb_port_bridge_leave().
It is likely that these functions are a variant of those or they share
a common origin.
> What about moving this code to the shared library rtl8366-core as
> rtl8366_port_bridge_join() and rtl8366_port_bridge_leave()
> and add per-variant callbacks for ->port_set_isolation()
> ->port_add_isolation() and ->port_remove_isolation() to
> struct realtek_ops and share this with rtl8366rb by refactoring
> rtl8366rb.c to use the same callbacks.
I agree that moving this logic to rtl83xx.c and introducing the
necessary abstractions makes sense. However, I would prefer not to
refactor rtl8366rb.c within this specific patchset to keep the scope
manageable.
I will also use dsa_switch_for_each_user_port, as
dsa_port_offloads_bridge() already ensures that CPU ports are skipped
and it aligns with RTL8366RB logic.
> Using shared code will help us to avoid having to fix the same
> bugs in more than one place.
>
> I don't know about this EFID stuff in rtl8365mb_port_set_efid()
> (maybe RTL8366RB needs something like that too) but certainly that
> can be an optional callback in struct realtek_ops for now.
I will keep this as an optional callback for now. If it eventually
becomes clear that the RTL8366RB requires it, we can update the logic
later to make the callback mandatory.
> Yours,
> Linus Walleij
Regards,
Luiz
^ permalink raw reply
* Re: [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers
From: John Paul Adrian Glaubitz @ 2026-04-22 5:42 UTC (permalink / raw)
To: Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Jonathan Corbet,
Shuah Khan
Cc: linux-kernel, netdev, linux-doc
In-Reply-To: <20260421-v7-0-0-net-next-driver-removal-v1-v1-0-69517c689d1f@lunn.ch>
Hi Andrew,
On Tue, 2026-04-21 at 14:31 -0500, Andrew Lunn wrote:
> These old drivers have not been much of a Maintenance burden until
> recently. Now there are more newbies using AI and fuzzers finding
> issues, resulting in more work for Maintainers. Fixing these old
> drivers make little sense, if it is not clear they have users.
>
> These are all ISA and PCMCIA Ethernet devices, mostly from the last
> century, a couple from 2001 or 2002. It seems unlikely they are still
> used. However, remove them one patch at a time so they can be brought
> back if somebody still has the hardware, runs modern kernels and wants
> to take up the roll of driver Maintainer.
They might still be used for retro-computing on various non-x86 computers
such as Alphas, older SPARC systems, PA-RISC and 68000 systems. Please don't
assume that every computer is just an x86 computer.
As for the AI-generated bug reports, I assume this will settle down sooner
or later when reporters realize not every issue is being addressed. Anyone
who is still using this old hardware won't be using them on machines directly
connected to the internet.
So, why bother? Just ignore those bug reports.
Adrian
--
.''`. John Paul Adrian Glaubitz
: :' : Debian Developer
`. `' Physicist
`- GPG: 62FF 8A75 84E0 2956 9546 0006 7426 3B37 F5B5 F913
^ permalink raw reply
* Re: [PATCH bpf-next v4 2/4] bpf: Reject TCP_NODELAY in bpf-tcp-cc
From: Jiayuan Chen @ 2026-04-22 5:05 UTC (permalink / raw)
To: KaFai Wan, ast, daniel, john.fastabend, andrii, martin.lau,
eddyz87, memxor, song, yonghong.song, jolsa, sdf, davem, edumazet,
kuba, pabeni, horms, dsahern, shuah, ihor.solodrai, jiayuan.chen,
hoyeon.lee, ameryhung, bpf, linux-kernel, netdev, linux-kselftest
In-Reply-To: <20260421155804.135786-3-kafai.wan@linux.dev>
On 4/21/26 11:58 PM, KaFai Wan wrote:
> A BPF TCP congestion control program can call bpf_setsockopt() from
> its callbacks. In current kernels, if it calls
> bpf_setsockopt(TCP_NODELAY) from cwnd_event_tx_start(), the call can
> re-enter the TCP transmit path before the outer tcp_transmit_skb()
> has completed and advanced the send head.
>
> This can re-trigger CA_EVENT_TX_START and lead to unbounded recursion:
>
> tcp_transmit_skb()
> -> tcp_event_data_sent()
> -> tcp_ca_event(sk, CA_EVENT_TX_START)
> -> cwnd_event_tx_start()
> -> bpf_setsockopt(TCP_NODELAY)
> -> tcp_push_pending_frames()
> -> tcp_write_xmit()
> -> tcp_transmit_skb()
>
> This leads to unbounded recursion and can overflow the kernel stack.
>
> Reject TCP_NODELAY with -EOPNOTSUPP for bpf-tcp-cc by introducing
> a dedicated setsockopt proto for BPF_PROG_TYPE_STRUCT_OPS TCP
> congestion control programs.
>
> Fixes: 7e41df5dbba2 ("bpf: Add a few optnames to bpf_setsockopt")
> Suggested-by: Martin KaFai Lau <martin.lau@linux.dev>
> Signed-off-by: KaFai Wan <kafai.wan@linux.dev>
Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>
^ permalink raw reply
* [PATCH 2/2] net: packetengines: remove obsolete yellowfin driver and vendor dir
From: Mingyu Wang @ 2026-04-22 4:48 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni
Cc: tglx, mingo, netdev, linux-kernel, Mingyu Wang
In-Reply-To: <20260422044820.485660-1-25181214217@stu.xidian.edu.cn>
Similar to the hamachi driver, the yellowfin driver supports hardware
that is over two decades old and no longer in active use.
Since yellowfin was the last remaining driver in the packetengines
vendor directory, we can now safely remove the entire directory and
drop its associated references from the parent Kconfig and Makefile.
This eliminates dead code and reduces the overall maintenance burden
on the netdev subsystem.
Signed-off-by: Mingyu Wang <25181214217@stu.xidian.edu.cn>
---
drivers/net/ethernet/Kconfig | 1 -
drivers/net/ethernet/Makefile | 1 -
drivers/net/ethernet/packetengines/Kconfig | 34 -
drivers/net/ethernet/packetengines/Makefile | 6 -
.../net/ethernet/packetengines/yellowfin.c | 1438 -----------------
5 files changed, 1480 deletions(-)
delete mode 100644 drivers/net/ethernet/packetengines/Kconfig
delete mode 100644 drivers/net/ethernet/packetengines/Makefile
delete mode 100644 drivers/net/ethernet/packetengines/yellowfin.c
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index bdc29d143160..65edd786099e 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -157,7 +157,6 @@ config OA_TC6
To know the implementation details, refer documentation in
<file:Documentation/networking/oa-tc6-framework.rst>.
-source "drivers/net/ethernet/packetengines/Kconfig"
source "drivers/net/ethernet/pasemi/Kconfig"
source "drivers/net/ethernet/pensando/Kconfig"
source "drivers/net/ethernet/qlogic/Kconfig"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index 6bffb60ba644..ba4f7c340fab 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -73,7 +73,6 @@ obj-$(CONFIG_NET_VENDOR_NVIDIA) += nvidia/
obj-$(CONFIG_LPC_ENET) += nxp/
obj-$(CONFIG_NET_VENDOR_OKI) += oki-semi/
obj-$(CONFIG_ETHOC) += ethoc.o
-obj-$(CONFIG_NET_VENDOR_PACKET_ENGINES) += packetengines/
obj-$(CONFIG_NET_VENDOR_PASEMI) += pasemi/
obj-$(CONFIG_NET_VENDOR_QLOGIC) += qlogic/
obj-$(CONFIG_NET_VENDOR_QUALCOMM) += qualcomm/
diff --git a/drivers/net/ethernet/packetengines/Kconfig b/drivers/net/ethernet/packetengines/Kconfig
deleted file mode 100644
index 8a255f0e7b44..000000000000
--- a/drivers/net/ethernet/packetengines/Kconfig
+++ /dev/null
@@ -1,34 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Packet Engines device configuration
-#
-
-config NET_VENDOR_PACKET_ENGINES
- bool "Packet Engines devices"
- default y
- depends on PCI
- help
- If you have a network (Ethernet) card belonging to this class, say Y.
-
- Note that the answer to this question doesn't directly affect the
- kernel: saying N will just cause the configurator to skip all
- the questions about Packet Engines devices. If you say Y, you will
- be asked for your specific card in the following questions.
-
-if NET_VENDOR_PACKET_ENGINES
-
-config YELLOWFIN
- tristate "Packet Engines Yellowfin Gigabit-NIC support"
- depends on PCI
- select CRC32
- help
- Say Y here if you have a Packet Engines G-NIC PCI Gigabit Ethernet
- adapter or the SYM53C885 Ethernet controller. The Gigabit adapter is
- used by the Beowulf Linux cluster project. See
- <http://cesdis.gsfc.nasa.gov/linux/drivers/yellowfin.html> for more
- information about this driver in particular and Beowulf in general.
-
- To compile this driver as a module, choose M here: the module
- will be called yellowfin. This is recommended.
-
-endif # NET_VENDOR_PACKET_ENGINES
diff --git a/drivers/net/ethernet/packetengines/Makefile b/drivers/net/ethernet/packetengines/Makefile
deleted file mode 100644
index 62a165ff2b26..000000000000
--- a/drivers/net/ethernet/packetengines/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Makefile for the Packet Engines network device drivers.
-#
-
-obj-$(CONFIG_YELLOWFIN) += yellowfin.o
diff --git a/drivers/net/ethernet/packetengines/yellowfin.c b/drivers/net/ethernet/packetengines/yellowfin.c
deleted file mode 100644
index 1e25ac13a7d8..000000000000
--- a/drivers/net/ethernet/packetengines/yellowfin.c
+++ /dev/null
@@ -1,1438 +0,0 @@
-/* yellowfin.c: A Packet Engines G-NIC ethernet driver for linux. */
-/*
- Written 1997-2001 by Donald Becker.
-
- This software may be used and distributed according to the terms of
- the GNU General Public License (GPL), incorporated herein by reference.
- Drivers based on or derived from this code fall under the GPL and must
- retain the authorship, copyright and license notice. This file is not
- a complete program and may only be used when the entire operating
- system is licensed under the GPL.
-
- This driver is for the Packet Engines G-NIC PCI Gigabit Ethernet adapter.
- It also supports the Symbios Logic version of the same chip core.
-
- The author may be reached as becker@scyld.com, or C/O
- Scyld Computing Corporation
- 410 Severn Ave., Suite 210
- Annapolis MD 21403
-
- Support and updates available at
- http://www.scyld.com/network/yellowfin.html
- [link no longer provides useful info -jgarzik]
-
-*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#define DRV_NAME "yellowfin"
-#define DRV_VERSION "2.1"
-#define DRV_RELDATE "Sep 11, 2006"
-
-/* The user-configurable values.
- These may be modified when a driver module is loaded.*/
-
-static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
-static int mtu;
-#ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */
-/* System-wide count of bogus-rx frames. */
-static int bogus_rx;
-static int dma_ctrl = 0x004A0263; /* Constrained by errata */
-static int fifo_cfg = 0x0020; /* Bypass external Tx FIFO. */
-#elif defined(YF_NEW) /* A future perfect board :->. */
-static int dma_ctrl = 0x00CAC277; /* Override when loading module! */
-static int fifo_cfg = 0x0028;
-#else
-static const int dma_ctrl = 0x004A0263; /* Constrained by errata */
-static const int fifo_cfg = 0x0020; /* Bypass external Tx FIFO. */
-#endif
-
-/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
- Setting to > 1514 effectively disables this feature. */
-static int rx_copybreak;
-
-/* Used to pass the media type, etc.
- No media types are currently defined. These exist for driver
- interoperability.
-*/
-#define MAX_UNITS 8 /* More are supported, limit only on options */
-static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-
-/* Do ugly workaround for GX server chipset errata. */
-static int gx_fix;
-
-/* Operational parameters that are set at compile time. */
-
-/* Keep the ring sizes a power of two for efficiency.
- Making the Tx ring too long decreases the effectiveness of channel
- bonding and packet priority.
- There are no ill effects from too-large receive rings. */
-#define TX_RING_SIZE 16
-#define TX_QUEUE_SIZE 12 /* Must be > 4 && <= TX_RING_SIZE */
-#define RX_RING_SIZE 64
-#define STATUS_TOTAL_SIZE TX_RING_SIZE*sizeof(struct tx_status_words)
-#define TX_TOTAL_SIZE 2*TX_RING_SIZE*sizeof(struct yellowfin_desc)
-#define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct yellowfin_desc)
-
-/* Operational parameters that usually are not changed. */
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT (2*HZ)
-#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
-
-#define yellowfin_debug debug
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/mii.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/ethtool.h>
-#include <linux/crc32.h>
-#include <linux/bitops.h>
-#include <linux/uaccess.h>
-#include <asm/processor.h> /* Processor type for cache alignment. */
-#include <linux/unaligned.h>
-#include <asm/io.h>
-
-/* These identify the driver base version and may not be removed. */
-static const char version[] =
- KERN_INFO DRV_NAME ".c:v1.05 1/09/2001 Written by Donald Becker <becker@scyld.com>\n"
- " (unofficial 2.4.x port, " DRV_VERSION ", " DRV_RELDATE ")\n";
-
-MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
-MODULE_DESCRIPTION("Packet Engines Yellowfin G-NIC Gigabit Ethernet driver");
-MODULE_LICENSE("GPL");
-
-module_param(max_interrupt_work, int, 0);
-module_param(mtu, int, 0);
-module_param(debug, int, 0);
-module_param(rx_copybreak, int, 0);
-module_param_array(options, int, NULL, 0);
-module_param_array(full_duplex, int, NULL, 0);
-module_param(gx_fix, int, 0);
-MODULE_PARM_DESC(max_interrupt_work, "G-NIC maximum events handled per interrupt");
-MODULE_PARM_DESC(mtu, "G-NIC MTU (all boards)");
-MODULE_PARM_DESC(debug, "G-NIC debug level (0-7)");
-MODULE_PARM_DESC(rx_copybreak, "G-NIC copy breakpoint for copy-only-tiny-frames");
-MODULE_PARM_DESC(options, "G-NIC: Bits 0-3: media type, bit 17: full duplex");
-MODULE_PARM_DESC(full_duplex, "G-NIC full duplex setting(s) (1)");
-MODULE_PARM_DESC(gx_fix, "G-NIC: enable GX server chipset bug workaround (0-1)");
-
-/*
- Theory of Operation
-
-I. Board Compatibility
-
-This device driver is designed for the Packet Engines "Yellowfin" Gigabit
-Ethernet adapter. The G-NIC 64-bit PCI card is supported, as well as the
-Symbios 53C885E dual function chip.
-
-II. Board-specific settings
-
-PCI bus devices are configured by the system at boot time, so no jumpers
-need to be set on the board. The system BIOS preferably should assign the
-PCI INTA signal to an otherwise unused system IRQ line.
-Note: Kernel versions earlier than 1.3.73 do not support shared PCI
-interrupt lines.
-
-III. Driver operation
-
-IIIa. Ring buffers
-
-The Yellowfin uses the Descriptor Based DMA Architecture specified by Apple.
-This is a descriptor list scheme similar to that used by the EEPro100 and
-Tulip. This driver uses two statically allocated fixed-size descriptor lists
-formed into rings by a branch from the final descriptor to the beginning of
-the list. The ring sizes are set at compile time by RX/TX_RING_SIZE.
-
-The driver allocates full frame size skbuffs for the Rx ring buffers at
-open() time and passes the skb->data field to the Yellowfin as receive data
-buffers. When an incoming frame is less than RX_COPYBREAK bytes long,
-a fresh skbuff is allocated and the frame is copied to the new skbuff.
-When the incoming frame is larger, the skbuff is passed directly up the
-protocol stack and replaced by a newly allocated skbuff.
-
-The RX_COPYBREAK value is chosen to trade-off the memory wasted by
-using a full-sized skbuff for small frames vs. the copying costs of larger
-frames. For small frames the copying cost is negligible (esp. considering
-that we are pre-loading the cache with immediately useful header
-information). For large frames the copying cost is non-trivial, and the
-larger copy might flush the cache of useful data.
-
-IIIC. Synchronization
-
-The driver runs as two independent, single-threaded flows of control. One
-is the send-packet routine, which enforces single-threaded use by the
-dev->tbusy flag. The other thread is the interrupt handler, which is single
-threaded by the hardware and other software.
-
-The send packet thread has partial control over the Tx ring and 'dev->tbusy'
-flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next
-queue slot is empty, it clears the tbusy flag when finished otherwise it sets
-the 'yp->tx_full' flag.
-
-The interrupt handler has exclusive control over the Rx ring and records stats
-from the Tx ring. After reaping the stats, it marks the Tx queue entry as
-empty by incrementing the dirty_tx mark. Iff the 'yp->tx_full' flag is set, it
-clears both the tx_full and tbusy flags.
-
-IV. Notes
-
-Thanks to Kim Stearns of Packet Engines for providing a pair of G-NIC boards.
-Thanks to Bruce Faust of Digitalscape for providing both their SYM53C885 board
-and an AlphaStation to verify the Alpha port!
-
-IVb. References
-
-Yellowfin Engineering Design Specification, 4/23/97 Preliminary/Confidential
-Symbios SYM53C885 PCI-SCSI/Fast Ethernet Multifunction Controller Preliminary
- Data Manual v3.0
-http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
-http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html
-
-IVc. Errata
-
-See Packet Engines confidential appendix (prototype chips only).
-*/
-
-
-
-enum capability_flags {
- HasMII=1, FullTxStatus=2, IsGigabit=4, HasMulticastBug=8, FullRxStatus=16,
- HasMACAddrBug=32, /* Only on early revs. */
- DontUseEeprom=64, /* Don't read the MAC from the EEPROm. */
-};
-
-/* The PCI I/O space extent. */
-enum {
- YELLOWFIN_SIZE = 0x100,
-};
-
-struct pci_id_info {
- const char *name;
- struct match_info {
- int pci, pci_mask, subsystem, subsystem_mask;
- int revision, revision_mask; /* Only 8 bits. */
- } id;
- int drv_flags; /* Driver use, intended as capability flags. */
-};
-
-static const struct pci_id_info pci_id_tbl[] = {
- {"Yellowfin G-NIC Gigabit Ethernet", { 0x07021000, 0xffffffff},
- FullTxStatus | IsGigabit | HasMulticastBug | HasMACAddrBug | DontUseEeprom},
- {"Symbios SYM83C885", { 0x07011000, 0xffffffff},
- HasMII | DontUseEeprom },
- { }
-};
-
-static const struct pci_device_id yellowfin_pci_tbl[] = {
- { 0x1000, 0x0702, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- { 0x1000, 0x0701, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
- { }
-};
-MODULE_DEVICE_TABLE (pci, yellowfin_pci_tbl);
-
-
-/* Offsets to the Yellowfin registers. Various sizes and alignments. */
-enum yellowfin_offsets {
- TxCtrl=0x00, TxStatus=0x04, TxPtr=0x0C,
- TxIntrSel=0x10, TxBranchSel=0x14, TxWaitSel=0x18,
- RxCtrl=0x40, RxStatus=0x44, RxPtr=0x4C,
- RxIntrSel=0x50, RxBranchSel=0x54, RxWaitSel=0x58,
- EventStatus=0x80, IntrEnb=0x82, IntrClear=0x84, IntrStatus=0x86,
- ChipRev=0x8C, DMACtrl=0x90, TxThreshold=0x94,
- Cnfg=0xA0, FrameGap0=0xA2, FrameGap1=0xA4,
- MII_Cmd=0xA6, MII_Addr=0xA8, MII_Wr_Data=0xAA, MII_Rd_Data=0xAC,
- MII_Status=0xAE,
- RxDepth=0xB8, FlowCtrl=0xBC,
- AddrMode=0xD0, StnAddr=0xD2, HashTbl=0xD8, FIFOcfg=0xF8,
- EEStatus=0xF0, EECtrl=0xF1, EEAddr=0xF2, EERead=0xF3, EEWrite=0xF4,
- EEFeature=0xF5,
-};
-
-/* The Yellowfin Rx and Tx buffer descriptors.
- Elements are written as 32 bit for endian portability. */
-struct yellowfin_desc {
- __le32 dbdma_cmd;
- __le32 addr;
- __le32 branch_addr;
- __le32 result_status;
-};
-
-struct tx_status_words {
-#ifdef __BIG_ENDIAN
- u16 tx_errs;
- u16 tx_cnt;
- u16 paused;
- u16 total_tx_cnt;
-#else /* Little endian chips. */
- u16 tx_cnt;
- u16 tx_errs;
- u16 total_tx_cnt;
- u16 paused;
-#endif /* __BIG_ENDIAN */
-};
-
-/* Bits in yellowfin_desc.cmd */
-enum desc_cmd_bits {
- CMD_TX_PKT=0x10000000, CMD_RX_BUF=0x20000000, CMD_TXSTATUS=0x30000000,
- CMD_NOP=0x60000000, CMD_STOP=0x70000000,
- BRANCH_ALWAYS=0x0C0000, INTR_ALWAYS=0x300000, WAIT_ALWAYS=0x030000,
- BRANCH_IFTRUE=0x040000,
-};
-
-/* Bits in yellowfin_desc.status */
-enum desc_status_bits { RX_EOP=0x0040, };
-
-/* Bits in the interrupt status/mask registers. */
-enum intr_status_bits {
- IntrRxDone=0x01, IntrRxInvalid=0x02, IntrRxPCIFault=0x04,IntrRxPCIErr=0x08,
- IntrTxDone=0x10, IntrTxInvalid=0x20, IntrTxPCIFault=0x40,IntrTxPCIErr=0x80,
- IntrEarlyRx=0x100, IntrWakeup=0x200, };
-
-#define PRIV_ALIGN 31 /* Required alignment mask */
-#define MII_CNT 4
-struct yellowfin_private {
- /* Descriptor rings first for alignment.
- Tx requires a second descriptor for status. */
- struct yellowfin_desc *rx_ring;
- struct yellowfin_desc *tx_ring;
- struct sk_buff* rx_skbuff[RX_RING_SIZE];
- struct sk_buff* tx_skbuff[TX_RING_SIZE];
- dma_addr_t rx_ring_dma;
- dma_addr_t tx_ring_dma;
-
- struct tx_status_words *tx_status;
- dma_addr_t tx_status_dma;
-
- struct timer_list timer; /* Media selection timer. */
- /* Frequently used and paired value: keep adjacent for cache effect. */
- int chip_id, drv_flags;
- struct pci_dev *pci_dev;
- unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
- unsigned int rx_buf_sz; /* Based on MTU+slack. */
- struct tx_status_words *tx_tail_desc;
- unsigned int cur_tx, dirty_tx;
- int tx_threshold;
- unsigned int tx_full:1; /* The Tx queue is full. */
- unsigned int full_duplex:1; /* Full-duplex operation requested. */
- unsigned int duplex_lock:1;
- unsigned int medialock:1; /* Do not sense media. */
- unsigned int default_port:4; /* Last dev->if_port value. */
- /* MII transceiver section. */
- int mii_cnt; /* MII device addresses. */
- u16 advertising; /* NWay media advertisement */
- unsigned char phys[MII_CNT]; /* MII device addresses, only first one used */
- spinlock_t lock;
- void __iomem *base;
-};
-
-static int read_eeprom(void __iomem *ioaddr, int location);
-static int mdio_read(void __iomem *ioaddr, int phy_id, int location);
-static void mdio_write(void __iomem *ioaddr, int phy_id, int location, int value);
-static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static int yellowfin_open(struct net_device *dev);
-static void yellowfin_timer(struct timer_list *t);
-static void yellowfin_tx_timeout(struct net_device *dev, unsigned int txqueue);
-static int yellowfin_init_ring(struct net_device *dev);
-static netdev_tx_t yellowfin_start_xmit(struct sk_buff *skb,
- struct net_device *dev);
-static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance);
-static int yellowfin_rx(struct net_device *dev);
-static void yellowfin_error(struct net_device *dev, int intr_status);
-static int yellowfin_close(struct net_device *dev);
-static void set_rx_mode(struct net_device *dev);
-static const struct ethtool_ops ethtool_ops;
-
-static const struct net_device_ops netdev_ops = {
- .ndo_open = yellowfin_open,
- .ndo_stop = yellowfin_close,
- .ndo_start_xmit = yellowfin_start_xmit,
- .ndo_set_rx_mode = set_rx_mode,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_eth_ioctl = netdev_ioctl,
- .ndo_tx_timeout = yellowfin_tx_timeout,
-};
-
-static int yellowfin_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- struct net_device *dev;
- struct yellowfin_private *np;
- int irq;
- int chip_idx = ent->driver_data;
- static int find_cnt;
- void __iomem *ioaddr;
- int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0;
- int drv_flags = pci_id_tbl[chip_idx].drv_flags;
- void *ring_space;
- dma_addr_t ring_dma;
-#ifdef USE_IO_OPS
- int bar = 0;
-#else
- int bar = 1;
-#endif
- u8 addr[ETH_ALEN];
-
-/* when built into the kernel, we only print version if device is found */
-#ifndef MODULE
- static int printed_version;
- if (!printed_version++)
- printk(version);
-#endif
-
- i = pci_enable_device(pdev);
- if (i) return i;
-
- dev = alloc_etherdev(sizeof(*np));
- if (!dev)
- return -ENOMEM;
-
- SET_NETDEV_DEV(dev, &pdev->dev);
-
- np = netdev_priv(dev);
-
- if (pci_request_regions(pdev, DRV_NAME))
- goto err_out_free_netdev;
-
- pci_set_master (pdev);
-
- ioaddr = pci_iomap(pdev, bar, YELLOWFIN_SIZE);
- if (!ioaddr)
- goto err_out_free_res;
-
- irq = pdev->irq;
-
- if (drv_flags & DontUseEeprom)
- for (i = 0; i < 6; i++)
- addr[i] = ioread8(ioaddr + StnAddr + i);
- else {
- int ee_offset = (read_eeprom(ioaddr, 6) == 0xff ? 0x100 : 0);
- for (i = 0; i < 6; i++)
- addr[i] = read_eeprom(ioaddr, ee_offset + i);
- }
- eth_hw_addr_set(dev, addr);
-
- /* Reset the chip. */
- iowrite32(0x80000000, ioaddr + DMACtrl);
-
- pci_set_drvdata(pdev, dev);
- spin_lock_init(&np->lock);
-
- np->pci_dev = pdev;
- np->chip_id = chip_idx;
- np->drv_flags = drv_flags;
- np->base = ioaddr;
-
- ring_space = dma_alloc_coherent(&pdev->dev, TX_TOTAL_SIZE, &ring_dma,
- GFP_KERNEL);
- if (!ring_space)
- goto err_out_cleardev;
- np->tx_ring = ring_space;
- np->tx_ring_dma = ring_dma;
-
- ring_space = dma_alloc_coherent(&pdev->dev, RX_TOTAL_SIZE, &ring_dma,
- GFP_KERNEL);
- if (!ring_space)
- goto err_out_unmap_tx;
- np->rx_ring = ring_space;
- np->rx_ring_dma = ring_dma;
-
- ring_space = dma_alloc_coherent(&pdev->dev, STATUS_TOTAL_SIZE,
- &ring_dma, GFP_KERNEL);
- if (!ring_space)
- goto err_out_unmap_rx;
- np->tx_status = ring_space;
- np->tx_status_dma = ring_dma;
-
- if (dev->mem_start)
- option = dev->mem_start;
-
- /* The lower four bits are the media type. */
- if (option > 0) {
- if (option & 0x200)
- np->full_duplex = 1;
- np->default_port = option & 15;
- if (np->default_port)
- np->medialock = 1;
- }
- if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0)
- np->full_duplex = 1;
-
- if (np->full_duplex)
- np->duplex_lock = 1;
-
- /* The Yellowfin-specific entries in the device structure. */
- dev->netdev_ops = &netdev_ops;
- dev->ethtool_ops = ðtool_ops;
- dev->watchdog_timeo = TX_TIMEOUT;
-
- if (mtu)
- dev->mtu = mtu;
-
- i = register_netdev(dev);
- if (i)
- goto err_out_unmap_status;
-
- netdev_info(dev, "%s type %8x at %p, %pM, IRQ %d\n",
- pci_id_tbl[chip_idx].name,
- ioread32(ioaddr + ChipRev), ioaddr,
- dev->dev_addr, irq);
-
- if (np->drv_flags & HasMII) {
- int phy, phy_idx = 0;
- for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) {
- int mii_status = mdio_read(ioaddr, phy, 1);
- if (mii_status != 0xffff && mii_status != 0x0000) {
- np->phys[phy_idx++] = phy;
- np->advertising = mdio_read(ioaddr, phy, 4);
- netdev_info(dev, "MII PHY found at address %d, status 0x%04x advertising %04x\n",
- phy, mii_status, np->advertising);
- }
- }
- np->mii_cnt = phy_idx;
- }
-
- find_cnt++;
-
- return 0;
-
-err_out_unmap_status:
- dma_free_coherent(&pdev->dev, STATUS_TOTAL_SIZE, np->tx_status,
- np->tx_status_dma);
-err_out_unmap_rx:
- dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, np->rx_ring,
- np->rx_ring_dma);
-err_out_unmap_tx:
- dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, np->tx_ring,
- np->tx_ring_dma);
-err_out_cleardev:
- pci_iounmap(pdev, ioaddr);
-err_out_free_res:
- pci_release_regions(pdev);
-err_out_free_netdev:
- free_netdev (dev);
- return -ENODEV;
-}
-
-static int read_eeprom(void __iomem *ioaddr, int location)
-{
- int bogus_cnt = 10000; /* Typical 33Mhz: 1050 ticks */
-
- iowrite8(location, ioaddr + EEAddr);
- iowrite8(0x30 | ((location >> 8) & 7), ioaddr + EECtrl);
- while ((ioread8(ioaddr + EEStatus) & 0x80) && --bogus_cnt > 0)
- ;
- return ioread8(ioaddr + EERead);
-}
-
-/* MII Managemen Data I/O accesses.
- These routines assume the MDIO controller is idle, and do not exit until
- the command is finished. */
-
-static int mdio_read(void __iomem *ioaddr, int phy_id, int location)
-{
- int i;
-
- iowrite16((phy_id<<8) + location, ioaddr + MII_Addr);
- iowrite16(1, ioaddr + MII_Cmd);
- for (i = 10000; i >= 0; i--)
- if ((ioread16(ioaddr + MII_Status) & 1) == 0)
- break;
- return ioread16(ioaddr + MII_Rd_Data);
-}
-
-static void mdio_write(void __iomem *ioaddr, int phy_id, int location, int value)
-{
- int i;
-
- iowrite16((phy_id<<8) + location, ioaddr + MII_Addr);
- iowrite16(value, ioaddr + MII_Wr_Data);
-
- /* Wait for the command to finish. */
- for (i = 10000; i >= 0; i--)
- if ((ioread16(ioaddr + MII_Status) & 1) == 0)
- break;
-}
-
-
-static int yellowfin_open(struct net_device *dev)
-{
- struct yellowfin_private *yp = netdev_priv(dev);
- const int irq = yp->pci_dev->irq;
- void __iomem *ioaddr = yp->base;
- int i, rc;
-
- /* Reset the chip. */
- iowrite32(0x80000000, ioaddr + DMACtrl);
-
- rc = request_irq(irq, yellowfin_interrupt, IRQF_SHARED, dev->name, dev);
- if (rc)
- return rc;
-
- rc = yellowfin_init_ring(dev);
- if (rc < 0)
- goto err_free_irq;
-
- iowrite32(yp->rx_ring_dma, ioaddr + RxPtr);
- iowrite32(yp->tx_ring_dma, ioaddr + TxPtr);
-
- for (i = 0; i < 6; i++)
- iowrite8(dev->dev_addr[i], ioaddr + StnAddr + i);
-
- /* Set up various condition 'select' registers.
- There are no options here. */
- iowrite32(0x00800080, ioaddr + TxIntrSel); /* Interrupt on Tx abort */
- iowrite32(0x00800080, ioaddr + TxBranchSel); /* Branch on Tx abort */
- iowrite32(0x00400040, ioaddr + TxWaitSel); /* Wait on Tx status */
- iowrite32(0x00400040, ioaddr + RxIntrSel); /* Interrupt on Rx done */
- iowrite32(0x00400040, ioaddr + RxBranchSel); /* Branch on Rx error */
- iowrite32(0x00400040, ioaddr + RxWaitSel); /* Wait on Rx done */
-
- /* Initialize other registers: with so many this eventually this will
- converted to an offset/value list. */
- iowrite32(dma_ctrl, ioaddr + DMACtrl);
- iowrite16(fifo_cfg, ioaddr + FIFOcfg);
- /* Enable automatic generation of flow control frames, period 0xffff. */
- iowrite32(0x0030FFFF, ioaddr + FlowCtrl);
-
- yp->tx_threshold = 32;
- iowrite32(yp->tx_threshold, ioaddr + TxThreshold);
-
- if (dev->if_port == 0)
- dev->if_port = yp->default_port;
-
- netif_start_queue(dev);
-
- /* Setting the Rx mode will start the Rx process. */
- if (yp->drv_flags & IsGigabit) {
- /* We are always in full-duplex mode with gigabit! */
- yp->full_duplex = 1;
- iowrite16(0x01CF, ioaddr + Cnfg);
- } else {
- iowrite16(0x0018, ioaddr + FrameGap0); /* 0060/4060 for non-MII 10baseT */
- iowrite16(0x1018, ioaddr + FrameGap1);
- iowrite16(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg);
- }
- set_rx_mode(dev);
-
- /* Enable interrupts by setting the interrupt mask. */
- iowrite16(0x81ff, ioaddr + IntrEnb); /* See enum intr_status_bits */
- iowrite16(0x0000, ioaddr + EventStatus); /* Clear non-interrupting events */
- iowrite32(0x80008000, ioaddr + RxCtrl); /* Start Rx and Tx channels. */
- iowrite32(0x80008000, ioaddr + TxCtrl);
-
- if (yellowfin_debug > 2) {
- netdev_printk(KERN_DEBUG, dev, "Done %s()\n", __func__);
- }
-
- /* Set the timer to check for link beat. */
- timer_setup(&yp->timer, yellowfin_timer, 0);
- yp->timer.expires = jiffies + 3*HZ;
- add_timer(&yp->timer);
-out:
- return rc;
-
-err_free_irq:
- free_irq(irq, dev);
- goto out;
-}
-
-static void yellowfin_timer(struct timer_list *t)
-{
- struct yellowfin_private *yp = timer_container_of(yp, t, timer);
- struct net_device *dev = pci_get_drvdata(yp->pci_dev);
- void __iomem *ioaddr = yp->base;
- int next_tick = 60*HZ;
-
- if (yellowfin_debug > 3) {
- netdev_printk(KERN_DEBUG, dev, "Yellowfin timer tick, status %08x\n",
- ioread16(ioaddr + IntrStatus));
- }
-
- if (yp->mii_cnt) {
- int bmsr = mdio_read(ioaddr, yp->phys[0], MII_BMSR);
- int lpa = mdio_read(ioaddr, yp->phys[0], MII_LPA);
- int negotiated = lpa & yp->advertising;
- if (yellowfin_debug > 1)
- netdev_printk(KERN_DEBUG, dev, "MII #%d status register is %04x, link partner capability %04x\n",
- yp->phys[0], bmsr, lpa);
-
- yp->full_duplex = mii_duplex(yp->duplex_lock, negotiated);
-
- iowrite16(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg);
-
- if (bmsr & BMSR_LSTATUS)
- next_tick = 60*HZ;
- else
- next_tick = 3*HZ;
- }
-
- yp->timer.expires = jiffies + next_tick;
- add_timer(&yp->timer);
-}
-
-static void yellowfin_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
- struct yellowfin_private *yp = netdev_priv(dev);
- void __iomem *ioaddr = yp->base;
-
- netdev_warn(dev, "Yellowfin transmit timed out at %d/%d Tx status %04x, Rx status %04x, resetting...\n",
- yp->cur_tx, yp->dirty_tx,
- ioread32(ioaddr + TxStatus),
- ioread32(ioaddr + RxStatus));
-
- /* Note: these should be KERN_DEBUG. */
- if (yellowfin_debug) {
- int i;
- pr_warn(" Rx ring %p: ", yp->rx_ring);
- for (i = 0; i < RX_RING_SIZE; i++)
- pr_cont(" %08x", yp->rx_ring[i].result_status);
- pr_cont("\n");
- pr_warn(" Tx ring %p: ", yp->tx_ring);
- for (i = 0; i < TX_RING_SIZE; i++)
- pr_cont(" %04x /%08x",
- yp->tx_status[i].tx_errs,
- yp->tx_ring[i].result_status);
- pr_cont("\n");
- }
-
- /* If the hardware is found to hang regularly, we will update the code
- to reinitialize the chip here. */
- dev->if_port = 0;
-
- /* Wake the potentially-idle transmit channel. */
- iowrite32(0x10001000, yp->base + TxCtrl);
- if (yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE)
- netif_wake_queue (dev); /* Typical path */
-
- netif_trans_update(dev); /* prevent tx timeout */
- dev->stats.tx_errors++;
-}
-
-/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-static int yellowfin_init_ring(struct net_device *dev)
-{
- struct yellowfin_private *yp = netdev_priv(dev);
- int i, j;
-
- yp->tx_full = 0;
- yp->cur_rx = yp->cur_tx = 0;
- yp->dirty_tx = 0;
-
- yp->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
-
- for (i = 0; i < RX_RING_SIZE; i++) {
- yp->rx_ring[i].dbdma_cmd =
- cpu_to_le32(CMD_RX_BUF | INTR_ALWAYS | yp->rx_buf_sz);
- yp->rx_ring[i].branch_addr = cpu_to_le32(yp->rx_ring_dma +
- ((i+1)%RX_RING_SIZE)*sizeof(struct yellowfin_desc));
- }
-
- for (i = 0; i < RX_RING_SIZE; i++) {
- struct sk_buff *skb = netdev_alloc_skb(dev, yp->rx_buf_sz + 2);
- yp->rx_skbuff[i] = skb;
- if (skb == NULL)
- break;
- skb_reserve(skb, 2); /* 16 byte align the IP header. */
- yp->rx_ring[i].addr = cpu_to_le32(dma_map_single(&yp->pci_dev->dev,
- skb->data,
- yp->rx_buf_sz,
- DMA_FROM_DEVICE));
- }
- if (i != RX_RING_SIZE) {
- for (j = 0; j < i; j++)
- dev_kfree_skb(yp->rx_skbuff[j]);
- return -ENOMEM;
- }
- yp->rx_ring[i-1].dbdma_cmd = cpu_to_le32(CMD_STOP);
- yp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
-
-#define NO_TXSTATS
-#ifdef NO_TXSTATS
- /* In this mode the Tx ring needs only a single descriptor. */
- for (i = 0; i < TX_RING_SIZE; i++) {
- yp->tx_skbuff[i] = NULL;
- yp->tx_ring[i].dbdma_cmd = cpu_to_le32(CMD_STOP);
- yp->tx_ring[i].branch_addr = cpu_to_le32(yp->tx_ring_dma +
- ((i+1)%TX_RING_SIZE)*sizeof(struct yellowfin_desc));
- }
- /* Wrap ring */
- yp->tx_ring[--i].dbdma_cmd = cpu_to_le32(CMD_STOP | BRANCH_ALWAYS);
-#else
-{
- /* Tx ring needs a pair of descriptors, the second for the status. */
- for (i = 0; i < TX_RING_SIZE; i++) {
- j = 2*i;
- yp->tx_skbuff[i] = 0;
- /* Branch on Tx error. */
- yp->tx_ring[j].dbdma_cmd = cpu_to_le32(CMD_STOP);
- yp->tx_ring[j].branch_addr = cpu_to_le32(yp->tx_ring_dma +
- (j+1)*sizeof(struct yellowfin_desc));
- j++;
- if (yp->flags & FullTxStatus) {
- yp->tx_ring[j].dbdma_cmd =
- cpu_to_le32(CMD_TXSTATUS | sizeof(*yp->tx_status));
- yp->tx_ring[j].request_cnt = sizeof(*yp->tx_status);
- yp->tx_ring[j].addr = cpu_to_le32(yp->tx_status_dma +
- i*sizeof(struct tx_status_words));
- } else {
- /* Symbios chips write only tx_errs word. */
- yp->tx_ring[j].dbdma_cmd =
- cpu_to_le32(CMD_TXSTATUS | INTR_ALWAYS | 2);
- yp->tx_ring[j].request_cnt = 2;
- /* Om pade ummmmm... */
- yp->tx_ring[j].addr = cpu_to_le32(yp->tx_status_dma +
- i*sizeof(struct tx_status_words) +
- &(yp->tx_status[0].tx_errs) -
- &(yp->tx_status[0]));
- }
- yp->tx_ring[j].branch_addr = cpu_to_le32(yp->tx_ring_dma +
- ((j+1)%(2*TX_RING_SIZE))*sizeof(struct yellowfin_desc));
- }
- /* Wrap ring */
- yp->tx_ring[++j].dbdma_cmd |= cpu_to_le32(BRANCH_ALWAYS | INTR_ALWAYS);
-}
-#endif
- yp->tx_tail_desc = &yp->tx_status[0];
- return 0;
-}
-
-static netdev_tx_t yellowfin_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct yellowfin_private *yp = netdev_priv(dev);
- unsigned entry;
- int len = skb->len;
-
- netif_stop_queue (dev);
-
- /* Note: Ordering is important here, set the field with the
- "ownership" bit last, and only then increment cur_tx. */
-
- /* Calculate the next Tx descriptor entry. */
- entry = yp->cur_tx % TX_RING_SIZE;
-
- if (gx_fix) { /* Note: only works for paddable protocols e.g. IP. */
- int cacheline_end = ((unsigned long)skb->data + skb->len) % 32;
- /* Fix GX chipset errata. */
- if (cacheline_end > 24 || cacheline_end == 0) {
- len = skb->len + 32 - cacheline_end + 1;
- if (skb_padto(skb, len)) {
- yp->tx_skbuff[entry] = NULL;
- netif_wake_queue(dev);
- return NETDEV_TX_OK;
- }
- }
- }
- yp->tx_skbuff[entry] = skb;
-
-#ifdef NO_TXSTATS
- yp->tx_ring[entry].addr = cpu_to_le32(dma_map_single(&yp->pci_dev->dev,
- skb->data,
- len, DMA_TO_DEVICE));
- yp->tx_ring[entry].result_status = 0;
- if (entry >= TX_RING_SIZE-1) {
- /* New stop command. */
- yp->tx_ring[0].dbdma_cmd = cpu_to_le32(CMD_STOP);
- yp->tx_ring[TX_RING_SIZE-1].dbdma_cmd =
- cpu_to_le32(CMD_TX_PKT|BRANCH_ALWAYS | len);
- } else {
- yp->tx_ring[entry+1].dbdma_cmd = cpu_to_le32(CMD_STOP);
- yp->tx_ring[entry].dbdma_cmd =
- cpu_to_le32(CMD_TX_PKT | BRANCH_IFTRUE | len);
- }
- yp->cur_tx++;
-#else
- yp->tx_ring[entry<<1].request_cnt = len;
- yp->tx_ring[entry<<1].addr = cpu_to_le32(dma_map_single(&yp->pci_dev->dev,
- skb->data,
- len, DMA_TO_DEVICE));
- /* The input_last (status-write) command is constant, but we must
- rewrite the subsequent 'stop' command. */
-
- yp->cur_tx++;
- {
- unsigned next_entry = yp->cur_tx % TX_RING_SIZE;
- yp->tx_ring[next_entry<<1].dbdma_cmd = cpu_to_le32(CMD_STOP);
- }
- /* Final step -- overwrite the old 'stop' command. */
-
- yp->tx_ring[entry<<1].dbdma_cmd =
- cpu_to_le32( ((entry % 6) == 0 ? CMD_TX_PKT|INTR_ALWAYS|BRANCH_IFTRUE :
- CMD_TX_PKT | BRANCH_IFTRUE) | len);
-#endif
-
- /* Non-x86 Todo: explicitly flush cache lines here. */
-
- /* Wake the potentially-idle transmit channel. */
- iowrite32(0x10001000, yp->base + TxCtrl);
-
- if (yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE)
- netif_start_queue (dev); /* Typical path */
- else
- yp->tx_full = 1;
-
- if (yellowfin_debug > 4) {
- netdev_printk(KERN_DEBUG, dev, "Yellowfin transmit frame #%d queued in slot %d\n",
- yp->cur_tx, entry);
- }
- return NETDEV_TX_OK;
-}
-
-/* The interrupt handler does all of the Rx thread work and cleans up
- after the Tx thread. */
-static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance)
-{
- struct net_device *dev = dev_instance;
- struct yellowfin_private *yp;
- void __iomem *ioaddr;
- int boguscnt = max_interrupt_work;
- unsigned int handled = 0;
-
- yp = netdev_priv(dev);
- ioaddr = yp->base;
-
- spin_lock (&yp->lock);
-
- do {
- u16 intr_status = ioread16(ioaddr + IntrClear);
-
- if (yellowfin_debug > 4)
- netdev_printk(KERN_DEBUG, dev, "Yellowfin interrupt, status %04x\n",
- intr_status);
-
- if (intr_status == 0)
- break;
- handled = 1;
-
- if (intr_status & (IntrRxDone | IntrEarlyRx)) {
- yellowfin_rx(dev);
- iowrite32(0x10001000, ioaddr + RxCtrl); /* Wake Rx engine. */
- }
-
-#ifdef NO_TXSTATS
- for (; yp->cur_tx - yp->dirty_tx > 0; yp->dirty_tx++) {
- int entry = yp->dirty_tx % TX_RING_SIZE;
- struct sk_buff *skb;
-
- if (yp->tx_ring[entry].result_status == 0)
- break;
- skb = yp->tx_skbuff[entry];
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += skb->len;
- /* Free the original skb. */
- dma_unmap_single(&yp->pci_dev->dev,
- le32_to_cpu(yp->tx_ring[entry].addr),
- skb->len, DMA_TO_DEVICE);
- dev_consume_skb_irq(skb);
- yp->tx_skbuff[entry] = NULL;
- }
- if (yp->tx_full &&
- yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE - 4) {
- /* The ring is no longer full, clear tbusy. */
- yp->tx_full = 0;
- netif_wake_queue(dev);
- }
-#else
- if ((intr_status & IntrTxDone) || (yp->tx_tail_desc->tx_errs)) {
- unsigned dirty_tx = yp->dirty_tx;
-
- for (dirty_tx = yp->dirty_tx; yp->cur_tx - dirty_tx > 0;
- dirty_tx++) {
- /* Todo: optimize this. */
- int entry = dirty_tx % TX_RING_SIZE;
- u16 tx_errs = yp->tx_status[entry].tx_errs;
- struct sk_buff *skb;
-
-#ifndef final_version
- if (yellowfin_debug > 5)
- netdev_printk(KERN_DEBUG, dev, "Tx queue %d check, Tx status %04x %04x %04x %04x\n",
- entry,
- yp->tx_status[entry].tx_cnt,
- yp->tx_status[entry].tx_errs,
- yp->tx_status[entry].total_tx_cnt,
- yp->tx_status[entry].paused);
-#endif
- if (tx_errs == 0)
- break; /* It still hasn't been Txed */
- skb = yp->tx_skbuff[entry];
- if (tx_errs & 0xF810) {
- /* There was an major error, log it. */
-#ifndef final_version
- if (yellowfin_debug > 1)
- netdev_printk(KERN_DEBUG, dev, "Transmit error, Tx status %04x\n",
- tx_errs);
-#endif
- dev->stats.tx_errors++;
- if (tx_errs & 0xF800) dev->stats.tx_aborted_errors++;
- if (tx_errs & 0x0800) dev->stats.tx_carrier_errors++;
- if (tx_errs & 0x2000) dev->stats.tx_window_errors++;
- if (tx_errs & 0x8000) dev->stats.tx_fifo_errors++;
- } else {
-#ifndef final_version
- if (yellowfin_debug > 4)
- netdev_printk(KERN_DEBUG, dev, "Normal transmit, Tx status %04x\n",
- tx_errs);
-#endif
- dev->stats.tx_bytes += skb->len;
- dev->stats.collisions += tx_errs & 15;
- dev->stats.tx_packets++;
- }
- /* Free the original skb. */
- dma_unmap_single(&yp->pci_dev->dev,
- yp->tx_ring[entry << 1].addr,
- skb->len, DMA_TO_DEVICE);
- dev_consume_skb_irq(skb);
- yp->tx_skbuff[entry] = 0;
- /* Mark status as empty. */
- yp->tx_status[entry].tx_errs = 0;
- }
-
-#ifndef final_version
- if (yp->cur_tx - dirty_tx > TX_RING_SIZE) {
- netdev_err(dev, "Out-of-sync dirty pointer, %d vs. %d, full=%d\n",
- dirty_tx, yp->cur_tx, yp->tx_full);
- dirty_tx += TX_RING_SIZE;
- }
-#endif
-
- if (yp->tx_full &&
- yp->cur_tx - dirty_tx < TX_QUEUE_SIZE - 2) {
- /* The ring is no longer full, clear tbusy. */
- yp->tx_full = 0;
- netif_wake_queue(dev);
- }
-
- yp->dirty_tx = dirty_tx;
- yp->tx_tail_desc = &yp->tx_status[dirty_tx % TX_RING_SIZE];
- }
-#endif
-
- /* Log errors and other uncommon events. */
- if (intr_status & 0x2ee) /* Abnormal error summary. */
- yellowfin_error(dev, intr_status);
-
- if (--boguscnt < 0) {
- netdev_warn(dev, "Too much work at interrupt, status=%#04x\n",
- intr_status);
- break;
- }
- } while (1);
-
- if (yellowfin_debug > 3)
- netdev_printk(KERN_DEBUG, dev, "exiting interrupt, status=%#04x\n",
- ioread16(ioaddr + IntrStatus));
-
- spin_unlock (&yp->lock);
- return IRQ_RETVAL(handled);
-}
-
-/* This routine is logically part of the interrupt handler, but separated
- for clarity and better register allocation. */
-static int yellowfin_rx(struct net_device *dev)
-{
- struct yellowfin_private *yp = netdev_priv(dev);
- int entry = yp->cur_rx % RX_RING_SIZE;
- int boguscnt = yp->dirty_rx + RX_RING_SIZE - yp->cur_rx;
-
- if (yellowfin_debug > 4) {
- printk(KERN_DEBUG " In yellowfin_rx(), entry %d status %08x\n",
- entry, yp->rx_ring[entry].result_status);
- printk(KERN_DEBUG " #%d desc. %08x %08x %08x\n",
- entry, yp->rx_ring[entry].dbdma_cmd, yp->rx_ring[entry].addr,
- yp->rx_ring[entry].result_status);
- }
-
- /* If EOP is set on the next entry, it's a new packet. Send it up. */
- while (1) {
- struct yellowfin_desc *desc = &yp->rx_ring[entry];
- struct sk_buff *rx_skb = yp->rx_skbuff[entry];
- s16 frame_status;
- u16 desc_status;
- int data_size, __maybe_unused yf_size;
- u8 *buf_addr;
-
- if(!desc->result_status)
- break;
- dma_sync_single_for_cpu(&yp->pci_dev->dev,
- le32_to_cpu(desc->addr),
- yp->rx_buf_sz, DMA_FROM_DEVICE);
- desc_status = le32_to_cpu(desc->result_status) >> 16;
- buf_addr = rx_skb->data;
- data_size = (le32_to_cpu(desc->dbdma_cmd) -
- le32_to_cpu(desc->result_status)) & 0xffff;
- frame_status = get_unaligned_le16(&(buf_addr[data_size - 2]));
- if (yellowfin_debug > 4)
- printk(KERN_DEBUG " %s() status was %04x\n",
- __func__, frame_status);
- if (--boguscnt < 0)
- break;
-
- yf_size = sizeof(struct yellowfin_desc);
-
- if ( ! (desc_status & RX_EOP)) {
- if (data_size != 0)
- netdev_warn(dev, "Oversized Ethernet frame spanned multiple buffers, status %04x, data_size %d!\n",
- desc_status, data_size);
- dev->stats.rx_length_errors++;
- } else if ((yp->drv_flags & IsGigabit) && (frame_status & 0x0038)) {
- /* There was a error. */
- if (yellowfin_debug > 3)
- printk(KERN_DEBUG " %s() Rx error was %04x\n",
- __func__, frame_status);
- dev->stats.rx_errors++;
- if (frame_status & 0x0060) dev->stats.rx_length_errors++;
- if (frame_status & 0x0008) dev->stats.rx_frame_errors++;
- if (frame_status & 0x0010) dev->stats.rx_crc_errors++;
- if (frame_status < 0) dev->stats.rx_dropped++;
- } else if ( !(yp->drv_flags & IsGigabit) &&
- ((buf_addr[data_size-1] & 0x85) || buf_addr[data_size-2] & 0xC0)) {
- u8 status1 = buf_addr[data_size-2];
- u8 status2 = buf_addr[data_size-1];
- dev->stats.rx_errors++;
- if (status1 & 0xC0) dev->stats.rx_length_errors++;
- if (status2 & 0x03) dev->stats.rx_frame_errors++;
- if (status2 & 0x04) dev->stats.rx_crc_errors++;
- if (status2 & 0x80) dev->stats.rx_dropped++;
-#ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */
- } else if ((yp->flags & HasMACAddrBug) &&
- !ether_addr_equal(le32_to_cpu(yp->rx_ring_dma +
- entry * yf_size),
- dev->dev_addr) &&
- !ether_addr_equal(le32_to_cpu(yp->rx_ring_dma +
- entry * yf_size),
- "\377\377\377\377\377\377")) {
- if (bogus_rx++ == 0)
- netdev_warn(dev, "Bad frame to %pM\n",
- buf_addr);
-#endif
- } else {
- struct sk_buff *skb;
- int pkt_len = data_size -
- (yp->chip_id ? 7 : 8 + buf_addr[data_size - 8]);
- /* To verify: Yellowfin Length should omit the CRC! */
-
-#ifndef final_version
- if (yellowfin_debug > 4)
- printk(KERN_DEBUG " %s() normal Rx pkt length %d of %d, bogus_cnt %d\n",
- __func__, pkt_len, data_size, boguscnt);
-#endif
- /* Check if the packet is long enough to just pass up the skbuff
- without copying to a properly sized skbuff. */
- if (pkt_len > rx_copybreak) {
- skb_put(skb = rx_skb, pkt_len);
- dma_unmap_single(&yp->pci_dev->dev,
- le32_to_cpu(yp->rx_ring[entry].addr),
- yp->rx_buf_sz,
- DMA_FROM_DEVICE);
- yp->rx_skbuff[entry] = NULL;
- } else {
- skb = netdev_alloc_skb(dev, pkt_len + 2);
- if (skb == NULL)
- break;
- skb_reserve(skb, 2); /* 16 byte align the IP header */
- skb_copy_to_linear_data(skb, rx_skb->data, pkt_len);
- skb_put(skb, pkt_len);
- dma_sync_single_for_device(&yp->pci_dev->dev,
- le32_to_cpu(desc->addr),
- yp->rx_buf_sz,
- DMA_FROM_DEVICE);
- }
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += pkt_len;
- }
- entry = (++yp->cur_rx) % RX_RING_SIZE;
- }
-
- /* Refill the Rx ring buffers. */
- for (; yp->cur_rx - yp->dirty_rx > 0; yp->dirty_rx++) {
- entry = yp->dirty_rx % RX_RING_SIZE;
- if (yp->rx_skbuff[entry] == NULL) {
- struct sk_buff *skb = netdev_alloc_skb(dev, yp->rx_buf_sz + 2);
- if (skb == NULL)
- break; /* Better luck next round. */
- yp->rx_skbuff[entry] = skb;
- skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- yp->rx_ring[entry].addr = cpu_to_le32(dma_map_single(&yp->pci_dev->dev,
- skb->data,
- yp->rx_buf_sz,
- DMA_FROM_DEVICE));
- }
- yp->rx_ring[entry].dbdma_cmd = cpu_to_le32(CMD_STOP);
- yp->rx_ring[entry].result_status = 0; /* Clear complete bit. */
- if (entry != 0)
- yp->rx_ring[entry - 1].dbdma_cmd =
- cpu_to_le32(CMD_RX_BUF | INTR_ALWAYS | yp->rx_buf_sz);
- else
- yp->rx_ring[RX_RING_SIZE - 1].dbdma_cmd =
- cpu_to_le32(CMD_RX_BUF | INTR_ALWAYS | BRANCH_ALWAYS
- | yp->rx_buf_sz);
- }
-
- return 0;
-}
-
-static void yellowfin_error(struct net_device *dev, int intr_status)
-{
- netdev_err(dev, "Something Wicked happened! %04x\n", intr_status);
- /* Hmmmmm, it's not clear what to do here. */
- if (intr_status & (IntrTxPCIErr | IntrTxPCIFault))
- dev->stats.tx_errors++;
- if (intr_status & (IntrRxPCIErr | IntrRxPCIFault))
- dev->stats.rx_errors++;
-}
-
-static int yellowfin_close(struct net_device *dev)
-{
- struct yellowfin_private *yp = netdev_priv(dev);
- void __iomem *ioaddr = yp->base;
- int i;
-
- netif_stop_queue (dev);
-
- if (yellowfin_debug > 1) {
- netdev_printk(KERN_DEBUG, dev, "Shutting down ethercard, status was Tx %04x Rx %04x Int %02x\n",
- ioread16(ioaddr + TxStatus),
- ioread16(ioaddr + RxStatus),
- ioread16(ioaddr + IntrStatus));
- netdev_printk(KERN_DEBUG, dev, "Queue pointers were Tx %d / %d, Rx %d / %d\n",
- yp->cur_tx, yp->dirty_tx,
- yp->cur_rx, yp->dirty_rx);
- }
-
- /* Disable interrupts by clearing the interrupt mask. */
- iowrite16(0x0000, ioaddr + IntrEnb);
-
- /* Stop the chip's Tx and Rx processes. */
- iowrite32(0x80000000, ioaddr + RxCtrl);
- iowrite32(0x80000000, ioaddr + TxCtrl);
-
- timer_delete(&yp->timer);
-
-#if defined(__i386__)
- if (yellowfin_debug > 2) {
- printk(KERN_DEBUG " Tx ring at %08llx:\n",
- (unsigned long long)yp->tx_ring_dma);
- for (i = 0; i < TX_RING_SIZE*2; i++)
- printk(KERN_DEBUG " %c #%d desc. %08x %08x %08x %08x\n",
- ioread32(ioaddr + TxPtr) == (long)&yp->tx_ring[i] ? '>' : ' ',
- i, yp->tx_ring[i].dbdma_cmd, yp->tx_ring[i].addr,
- yp->tx_ring[i].branch_addr, yp->tx_ring[i].result_status);
- printk(KERN_DEBUG " Tx status %p:\n", yp->tx_status);
- for (i = 0; i < TX_RING_SIZE; i++)
- printk(KERN_DEBUG " #%d status %04x %04x %04x %04x\n",
- i, yp->tx_status[i].tx_cnt, yp->tx_status[i].tx_errs,
- yp->tx_status[i].total_tx_cnt, yp->tx_status[i].paused);
-
- printk(KERN_DEBUG " Rx ring %08llx:\n",
- (unsigned long long)yp->rx_ring_dma);
- for (i = 0; i < RX_RING_SIZE; i++) {
- printk(KERN_DEBUG " %c #%d desc. %08x %08x %08x\n",
- ioread32(ioaddr + RxPtr) == (long)&yp->rx_ring[i] ? '>' : ' ',
- i, yp->rx_ring[i].dbdma_cmd, yp->rx_ring[i].addr,
- yp->rx_ring[i].result_status);
- if (yellowfin_debug > 6) {
- if (get_unaligned((u8*)yp->rx_ring[i].addr) != 0x69) {
- int j;
-
- printk(KERN_DEBUG);
- for (j = 0; j < 0x50; j++)
- pr_cont(" %04x",
- get_unaligned(((u16*)yp->rx_ring[i].addr) + j));
- pr_cont("\n");
- }
- }
- }
- }
-#endif /* __i386__ debugging only */
-
- free_irq(yp->pci_dev->irq, dev);
-
- /* Free all the skbuffs in the Rx queue. */
- for (i = 0; i < RX_RING_SIZE; i++) {
- yp->rx_ring[i].dbdma_cmd = cpu_to_le32(CMD_STOP);
- yp->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
- if (yp->rx_skbuff[i]) {
- dev_kfree_skb(yp->rx_skbuff[i]);
- }
- yp->rx_skbuff[i] = NULL;
- }
- for (i = 0; i < TX_RING_SIZE; i++) {
- dev_kfree_skb(yp->tx_skbuff[i]);
- yp->tx_skbuff[i] = NULL;
- }
-
-#ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */
- if (yellowfin_debug > 0) {
- netdev_printk(KERN_DEBUG, dev, "Received %d frames that we should not have\n",
- bogus_rx);
- }
-#endif
-
- return 0;
-}
-
-/* Set or clear the multicast filter for this adaptor. */
-
-static void set_rx_mode(struct net_device *dev)
-{
- struct yellowfin_private *yp = netdev_priv(dev);
- void __iomem *ioaddr = yp->base;
- u16 cfg_value = ioread16(ioaddr + Cnfg);
-
- /* Stop the Rx process to change any value. */
- iowrite16(cfg_value & ~0x1000, ioaddr + Cnfg);
- if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
- iowrite16(0x000F, ioaddr + AddrMode);
- } else if ((netdev_mc_count(dev) > 64) ||
- (dev->flags & IFF_ALLMULTI)) {
- /* Too many to filter well, or accept all multicasts. */
- iowrite16(0x000B, ioaddr + AddrMode);
- } else if (!netdev_mc_empty(dev)) { /* Must use the multicast hash table. */
- struct netdev_hw_addr *ha;
- u16 hash_table[4];
- int i;
-
- memset(hash_table, 0, sizeof(hash_table));
- netdev_for_each_mc_addr(ha, dev) {
- unsigned int bit;
-
- /* Due to a bug in the early chip versions, multiple filter
- slots must be set for each address. */
- if (yp->drv_flags & HasMulticastBug) {
- bit = (ether_crc_le(3, ha->addr) >> 3) & 0x3f;
- hash_table[bit >> 4] |= (1 << bit);
- bit = (ether_crc_le(4, ha->addr) >> 3) & 0x3f;
- hash_table[bit >> 4] |= (1 << bit);
- bit = (ether_crc_le(5, ha->addr) >> 3) & 0x3f;
- hash_table[bit >> 4] |= (1 << bit);
- }
- bit = (ether_crc_le(6, ha->addr) >> 3) & 0x3f;
- hash_table[bit >> 4] |= (1 << bit);
- }
- /* Copy the hash table to the chip. */
- for (i = 0; i < 4; i++)
- iowrite16(hash_table[i], ioaddr + HashTbl + i*2);
- iowrite16(0x0003, ioaddr + AddrMode);
- } else { /* Normal, unicast/broadcast-only mode. */
- iowrite16(0x0001, ioaddr + AddrMode);
- }
- /* Restart the Rx process. */
- iowrite16(cfg_value | 0x1000, ioaddr + Cnfg);
-}
-
-static void yellowfin_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
- struct yellowfin_private *np = netdev_priv(dev);
-
- strscpy(info->driver, DRV_NAME, sizeof(info->driver));
- strscpy(info->version, DRV_VERSION, sizeof(info->version));
- strscpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info));
-}
-
-static const struct ethtool_ops ethtool_ops = {
- .get_drvinfo = yellowfin_get_drvinfo
-};
-
-static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
- struct yellowfin_private *np = netdev_priv(dev);
- void __iomem *ioaddr = np->base;
- struct mii_ioctl_data *data = if_mii(rq);
-
- switch(cmd) {
- case SIOCGMIIPHY: /* Get address of MII PHY in use. */
- data->phy_id = np->phys[0] & 0x1f;
- fallthrough;
-
- case SIOCGMIIREG: /* Read MII PHY register. */
- data->val_out = mdio_read(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f);
- return 0;
-
- case SIOCSMIIREG: /* Write MII PHY register. */
- if (data->phy_id == np->phys[0]) {
- u16 value = data->val_in;
- switch (data->reg_num) {
- case 0:
- /* Check for autonegotiation on or reset. */
- np->medialock = (value & 0x9000) ? 0 : 1;
- if (np->medialock)
- np->full_duplex = (value & 0x0100) ? 1 : 0;
- break;
- case 4: np->advertising = value; break;
- }
- /* Perhaps check_duplex(dev), depending on chip semantics. */
- }
- mdio_write(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
-
-
-static void yellowfin_remove_one(struct pci_dev *pdev)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct yellowfin_private *np;
-
- BUG_ON(!dev);
- np = netdev_priv(dev);
-
- dma_free_coherent(&pdev->dev, STATUS_TOTAL_SIZE, np->tx_status,
- np->tx_status_dma);
- dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, np->rx_ring,
- np->rx_ring_dma);
- dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, np->tx_ring,
- np->tx_ring_dma);
- unregister_netdev (dev);
-
- pci_iounmap(pdev, np->base);
-
- pci_release_regions (pdev);
-
- free_netdev (dev);
-}
-
-
-static struct pci_driver yellowfin_driver = {
- .name = DRV_NAME,
- .id_table = yellowfin_pci_tbl,
- .probe = yellowfin_init_one,
- .remove = yellowfin_remove_one,
-};
-
-
-static int __init yellowfin_init (void)
-{
-/* when a module, this is printed whether or not devices are found in probe */
-#ifdef MODULE
- printk(version);
-#endif
- return pci_register_driver(&yellowfin_driver);
-}
-
-
-static void __exit yellowfin_cleanup (void)
-{
- pci_unregister_driver (&yellowfin_driver);
-}
-
-
-module_init(yellowfin_init);
-module_exit(yellowfin_cleanup);
--
2.34.1
^ 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