Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH net-next v2 1/2] dpll: move fractional-frequency-offset-ppt under pin-parent-device
From: Jiri Pirko @ 2026-05-04  8:48 UTC (permalink / raw)
  To: Ivan Vecera
  Cc: netdev, Andrew Lunn, Arkadiusz Kubalewski, David S. Miller,
	Donald Hunter, Eric Dumazet, Jakub Kicinski, Jonathan Corbet,
	Leon Romanovsky, Mark Bloch, Michal Schmidt, Paolo Abeni,
	Pasi Vaananen, Petr Oros, Prathosh Satish, Saeed Mahameed,
	Shuah Khan, Simon Horman, Tariq Toukan, Vadim Fedorenko,
	linux-doc, linux-kernel, linux-rdma
In-Reply-To: <20260430173611.3312596-2-ivecera@redhat.com>

Thu, Apr 30, 2026 at 07:36:10PM +0200, ivecera@redhat.com wrote:
>Move the fractional-frequency-offset-ppt attribute from the top-level
>pin attributes into the pin-parent-device nested attribute set. This
>makes it consistent with phase-offset which is already per-parent and
>clarifies that FFO PPT represents the frequency difference between
>a pin and its parent DPLL device.
>
>The top-level fractional-frequency-offset attribute (in PPM) remains
>unchanged for backward compatibility.

That is odd. The ppt one was added just for higher precision but was
semantically the same. Now you change it. Could you still treat both the
same?

>
>Distinguish the two contexts in the ffo_get callback by passing
>dpll=NULL for the top-level (rx vs tx symbol rate) call and a valid
>dpll pointer for the nested (pin vs parent DPLL) call. Update mlx5
>and zl3073x drivers to return -ENODATA for the nested context they
>do not yet support.
>
>Add documentation for both FFO attributes to dpll.rst.
>

[..]

^ permalink raw reply

* Re: [PATCH RFC net-next v3] hsr: Allow to send a specific port and with HSR header
From: Sebastian Andrzej Siewior @ 2026-05-04  8:59 UTC (permalink / raw)
  To: Willem de Bruijn
  Cc: netdev, Andrew Lunn, Chintan Vankar, Danish Anwar, Daolin Qiu,
	David S. Miller, Eric Dumazet, Felix Maurer, Jakub Kicinski,
	Neelima Muralidharan, Paolo Abeni, Praneeth Bajjuri,
	Pratheesh Gangadhar TK, Richard Cochran, Simon Horman,
	Vignesh Raghavendra
In-Reply-To: <willemdebruijn.kernel.31592d82701e5@gmail.com>

On 2026-04-29 13:46:13 [-0400], Willem de Bruijn wrote:
> 
> Great to see a solution that keeps the added logic mostly within HSR
> itself, and works for the userspace component too.

;)

> 
> > diff --git a/include/linux/if_hsr.h b/include/linux/if_hsr.h
> > index f4cf2dd36d193..220f6e5d7b24c 100644
> > --- a/include/linux/if_hsr.h
> > +++ b/include/linux/if_hsr.h
> > @@ -3,6 +3,7 @@
> >  #define _LINUX_IF_HSR_H_
> >  
> >  #include <linux/types.h>
> > +#include <linux/skbuff.h>
> >  
> >  struct net_device;
> >  
> > @@ -22,6 +23,21 @@ enum hsr_port_type {
> >  	HSR_PT_PORTS,	/* This must be the last item in the enum */
> >  };
> >  
> > +struct hsr_ptp_ext {
> > +	u8	port;
> > +	u8	header;
> > +};
> > +
> > +#define HSR_INLINE_HDR	0xaf485352
> > +struct hsr_inline_header {
> > +	uint8_t tx_port;
> > +	uint8_t hsr_hdr;
> > +	uint8_t __pad0[4];
> > +	uint32_t magic;
> > +	uint8_t __pad1[2];
> > +	uint16_t eth_type;
> > +} __packed;
> > +
> 
> No specific need to make this header ethhdr like?

What do you mean? eth_type is at the same spot or do you mean it should
be named h_proto?

> >  /* HSR Tag.
> >   * As defined in IEC-62439-3:2010, the HSR tag is really { ethertype = 0x88FB,
> >   * path, LSDU_size, sequence Nr }. But we let eth_header() create { h_dest,
> > @@ -45,6 +61,60 @@ struct net_device *hsr_get_port_ndev(struct net_device *ndev,
> >  				     enum hsr_port_type pt);
> >  int hsr_get_port_type(struct net_device *hsr_dev, struct net_device *dev,
> >  		      enum hsr_port_type *type);
> > +
> > +static inline bool hsr_skb_has_header(struct sk_buff *skb)
> > +{
> > +	struct hsr_ptp_ext *ptp_ext;
> > +
> > +	ptp_ext = skb_ext_find(skb, SKB_EXT_HSR);
> > +	if (!ptp_ext)
> > +		return false;
> > +	return ptp_ext->header;
> > +}
> > +
> > +static inline unsigned int hsr_skb_has_port(struct sk_buff *skb)
> > +{
> > +	struct hsr_ptp_ext *ptp_ext;
> > +
> > +	if (!skb)
> > +		return 0;
> > +
> > +	ptp_ext = skb_ext_find(skb, SKB_EXT_HSR);
> > +	if (!ptp_ext)
> > +		return 0;
> > +	return ptp_ext->port;
> > +}
> > +
> > +static inline bool hsr_skb_get_header_port(struct sk_buff *skb, bool *header,
> > +					   enum hsr_port_type *port_type)
> > +{
> > +	struct hsr_ptp_ext *ptp_ext;
> > +
> > +	*port_type = HSR_PT_NONE;
> > +	*header = false;
> > +
> > +	ptp_ext = skb_ext_find(skb, SKB_EXT_HSR);
> > +	if (!ptp_ext)
> > +		return false;
> > +
> > +	*port_type = ptp_ext->port;
> > +	*header = ptp_ext->header;
> > +	return true;
> > +}
> > +
> > +static inline bool hsr_skb_add_header_port(struct sk_buff *skb, bool header,
> > +					   enum hsr_port_type port)
> > +{
> > +	struct hsr_ptp_ext *ptp_ext;
> > +
> > +	ptp_ext = skb_ext_add(skb, SKB_EXT_HSR);
> > +	if (!ptp_ext)
> > +		return false;
> > +	ptp_ext->port = port;
> > +	ptp_ext->header = header;
> > +	return true;
> > +}
> > +
> > diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
> > index 5555b71ab19b5..ac39b2347aa0f 100644
> > --- a/net/hsr/hsr_device.c
> > +++ b/net/hsr/hsr_device.c
> > @@ -228,20 +228,51 @@ static netdev_tx_t hsr_dev_xmit(struct sk_buff *skb, struct net_device *dev)
> >  
> >  	rcu_read_lock();
> >  	master = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
> > -	if (master) {
> > -		skb->dev = master->dev;
> > -		skb_reset_mac_header(skb);
> > -		skb_reset_mac_len(skb);
> > -		spin_lock_bh(&hsr->seqnr_lock);
> > -		hsr_forward_skb(skb, master);
> > -		spin_unlock_bh(&hsr->seqnr_lock);
> > -	} else {
> > -		dev_core_stats_tx_dropped_inc(dev);
> > -		dev_kfree_skb_any(skb);
> > +	if (!master)
> > +		goto drop;
> > +
> > +	skb->dev = master->dev;
> > +	if (skb->len > ETH_HLEN * 2) {
> > +		struct hsr_inline_header *hsr_opt;
> > +
> > +		BUILD_BUG_ON(sizeof(struct hsr_inline_header) != sizeof(struct ethhdr));
> > +		hsr_opt = (struct hsr_inline_header *)skb_mac_header(skb);
> > +		if (hsr_opt->eth_type == htons(ETH_P_1588) &&
> > +		    hsr_opt->magic == htonl(HSR_INLINE_HDR)) {
> > +			enum hsr_port_type tx_port;
> > +			bool has_header;
> > +
> > +			has_header = hsr_opt->hsr_hdr;
> > +			tx_port = hsr_opt->tx_port;
> > +			if (tx_port != HSR_PT_SLAVE_A && tx_port != HSR_PT_SLAVE_B)
> > +				goto drop;
> > +
> > +			if (!hsr_skb_add_header_port(skb, has_header, tx_port))
> > +				goto drop;
> 
> All use of this information happens in the context of this ndo_start_xmit?

I receive it from af_packet in HSR's ndo_start_xmit, yes. Then
hsr_xmit() is forwarding it to the slave device via dev_queue_xmit().
Here the skb->cb information gets overwritten.

I need this hint in the slave eth driver in case there is hsr-offloading
available. Now that I look at it again, there a netdev-event once the
HSR-master is set/ changed. So maybe I can use this and look at the
skb frame to decide what is required. Le me see.

> If so, no skb_ext needed. Can store the data in skb->cb[], which in
> that case is assured to not be overwritten by another layer.
> 
> Among various options. skb_ext works, but is a bit heavyhanded for
> passing around state within the same layer and call stack.

Sure.

> > +
> > +			skb_pull(skb, ETH_HLEN);
> 
> Prefer sizeof(struct hsr_inline_header)

Okay.

Sebastian

^ permalink raw reply

* [PATCH v4 0/4] Rust netlink support + use in Rust Binder
From: Alice Ryhl @ 2026-05-04  9:04 UTC (permalink / raw)
  To: Carlos Llamas, Greg Kroah-Hartman, Andrew Lunn, Donald Hunter,
	Jakub Kicinski, David S. Miller, Eric Dumazet, Paolo Abeni,
	Simon Horman, Matthew Maurer
  Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Trevor Gross, Danilo Krummrich,
	Christian Brauner, linux-kernel, rust-for-linux, netdev,
	Alice Ryhl

The C Binder driver exposes messages over netlink when transactions
fail, so that a userpace daemon can respond to processes with many
failing transactions.

This patch series adds netlink support from Rust, then implements an
equivalent API in Rust Binder.

As Binder only uses broadcast messages, I did not add support for other
kinds of messages.

Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
Changes in v4:
- Fix typo in 'report netlink transactions' commit message.
- Document that some methods are for const context only.
- Rebase and pick up tags.
- Link to v3: https://lore.kernel.org/r/20260415-binder-netlink-v3-0-84be9ba63ee2@google.com

Changes in v3:
- Fix spurious 'return' statements in Rust helpers (Patch 1).
- Sashiko review:
  - Fix ynl_gen to handle empty multicast groups and correct multicast indexing (Patch 2).
  - Fix transaction failed reply logic to report via Netlink inside reply_inner() (Patch 4).
- Link to v2: https://lore.kernel.org/r/20260408-binder-netlink-v2-0-c0d327d15435@google.com

Changes in v2:
- Make inclusion of to_pid conditional too.
- Add note about file name in second patch.
- Make it clear that the sk_buff wrapper is netlink-specific.
- Better handle bitfield in patch 1.
- Link to v1: https://lore.kernel.org/r/20260306-binder-netlink-v1-0-daceb5bc83f2@google.com

---
Alice Ryhl (3):
      rust: netlink: add raw netlink abstraction
      ynl_gen: generate Rust files from yaml files
      rust_binder: add generated netlink.rs file

Carlos Llamas (1):
      rust_binder: report netlink transactions

 drivers/android/Kconfig                    |   2 +-
 drivers/android/binder/netlink.rs          | 113 ++++++++++
 drivers/android/binder/rust_binder_main.rs |   8 +-
 drivers/android/binder/thread.rs           |  10 +
 drivers/android/binder/transaction.rs      |  40 ++++
 rust/bindings/bindings_helper.h            |   3 +
 rust/helpers/genetlink.c                   |  46 ++++
 rust/helpers/helpers.c                     |   1 +
 rust/kernel/lib.rs                         |   1 +
 rust/kernel/netlink.rs                     | 336 +++++++++++++++++++++++++++++
 rust/uapi/uapi_helper.h                    |   1 +
 tools/net/ynl/pyynl/ynl_gen_c.py           | 139 +++++++++++-
 tools/net/ynl/ynl-regen.sh                 |   2 +-
 13 files changed, 697 insertions(+), 5 deletions(-)
---
base-commit: 7fd2df204f342fc17d1a0bfcd474b24232fb0f32
change-id: 20260306-binder-netlink-c82110b2fb74

Best regards,
-- 
Alice Ryhl <aliceryhl@google.com>


^ permalink raw reply

* [PATCH v4 1/4] rust: netlink: add raw netlink abstraction
From: Alice Ryhl @ 2026-05-04  9:04 UTC (permalink / raw)
  To: Carlos Llamas, Greg Kroah-Hartman, Andrew Lunn, Donald Hunter,
	Jakub Kicinski, David S. Miller, Eric Dumazet, Paolo Abeni,
	Simon Horman, Matthew Maurer
  Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Trevor Gross, Danilo Krummrich,
	Christian Brauner, linux-kernel, rust-for-linux, netdev,
	Alice Ryhl
In-Reply-To: <20260504-binder-netlink-v4-0-601b41cd25b2@google.com>

This implements a safe and relatively simple API over the netlink API,
that allows you to add different attributes to a netlink message and
broadcast it. As the first user of this API only makes use of broadcast,
only broadcast messages are supported here.

This API is intended to be safe and to be easy to use in *generated*
code. This is because netlink is generally used with yaml files that
describe the underlying API, and the python generator outputs C code
(or, soon, Rust code) that lets you use the API more easily. So for
example, if there is a string field, the code generator will output a
method that internall calls `put_string()` with the right attr type.

Reviewed-by: Matthew Maurer <mmaurer@google.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
 rust/bindings/bindings_helper.h |   3 +
 rust/helpers/genetlink.c        |  46 ++++++
 rust/helpers/helpers.c          |   1 +
 rust/kernel/lib.rs              |   1 +
 rust/kernel/netlink.rs          | 336 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 387 insertions(+)

diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 446dbeaf0866..612fa5388b7d 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -92,6 +92,8 @@
 #include <linux/wait.h>
 #include <linux/workqueue.h>
 #include <linux/xarray.h>
+#include <net/genetlink.h>
+#include <net/netlink.h>
 #include <trace/events/rust_sample.h>
 
 /*
@@ -109,6 +111,7 @@
 const size_t RUST_CONST_HELPER_ARCH_SLAB_MINALIGN = ARCH_SLAB_MINALIGN;
 const size_t RUST_CONST_HELPER_ARCH_KMALLOC_MINALIGN = ARCH_KMALLOC_MINALIGN;
 const size_t RUST_CONST_HELPER_PAGE_SIZE = PAGE_SIZE;
+const size_t RUST_CONST_HELPER_GENLMSG_DEFAULT_SIZE = GENLMSG_DEFAULT_SIZE;
 const gfp_t RUST_CONST_HELPER_GFP_ATOMIC = GFP_ATOMIC;
 const gfp_t RUST_CONST_HELPER_GFP_KERNEL = GFP_KERNEL;
 const gfp_t RUST_CONST_HELPER_GFP_KERNEL_ACCOUNT = GFP_KERNEL_ACCOUNT;
diff --git a/rust/helpers/genetlink.c b/rust/helpers/genetlink.c
new file mode 100644
index 000000000000..3530b69f6cf7
--- /dev/null
+++ b/rust/helpers/genetlink.c
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (C) 2026 Google LLC.
+ */
+
+#include <net/genetlink.h>
+
+#ifdef CONFIG_NET
+
+__rust_helper struct sk_buff *rust_helper_genlmsg_new(size_t payload, gfp_t flags)
+{
+	return genlmsg_new(payload, flags);
+}
+
+__rust_helper
+int rust_helper_genlmsg_multicast(const struct genl_family *family,
+				  struct sk_buff *skb, u32 portid,
+				  unsigned int group, gfp_t flags)
+{
+	return genlmsg_multicast(family, skb, portid, group, flags);
+}
+
+__rust_helper void rust_helper_genlmsg_cancel(struct sk_buff *skb, void *hdr)
+{
+	genlmsg_cancel(skb, hdr);
+}
+
+__rust_helper void rust_helper_genlmsg_end(struct sk_buff *skb, void *hdr)
+{
+	genlmsg_end(skb, hdr);
+}
+
+__rust_helper void rust_helper_nlmsg_free(struct sk_buff *skb)
+{
+	nlmsg_free(skb);
+}
+
+__rust_helper
+int rust_helper_genl_has_listeners(const struct genl_family *family,
+				   struct net *net, unsigned int group)
+{
+	return genl_has_listeners(family, net, group);
+}
+
+#endif
diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
index 625921e27dfb..8de05ae7d928 100644
--- a/rust/helpers/helpers.c
+++ b/rust/helpers/helpers.c
@@ -62,6 +62,7 @@
 #include "err.c"
 #include "irq.c"
 #include "fs.c"
+#include "genetlink.c"
 #include "gpu.c"
 #include "io.c"
 #include "jump_label.c"
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index b72b2fbe046d..d69f13b77845 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -96,6 +96,7 @@
 pub mod module_param;
 #[cfg(CONFIG_NET)]
 pub mod net;
+pub mod netlink;
 pub mod num;
 pub mod of;
 #[cfg(CONFIG_PM_OPP)]
diff --git a/rust/kernel/netlink.rs b/rust/kernel/netlink.rs
new file mode 100644
index 000000000000..24177fb685b4
--- /dev/null
+++ b/rust/kernel/netlink.rs
@@ -0,0 +1,336 @@
+// SPDX-License-Identifier: GPL-2.0
+
+// Copyright (C) 2026 Google LLC.
+
+//! Rust support for generic netlink.
+//!
+//! Currently only supports exposing multicast groups.
+//!
+//! C header: [`include/net/genetlink.h`](srctree/include/net/genetlink.h)
+#![cfg(CONFIG_NET)]
+
+use kernel::{
+    alloc::{self, AllocError},
+    error::to_result,
+    prelude::*,
+    transmute::AsBytes,
+    types::Opaque,
+    ThisModule,
+};
+
+use core::{
+    mem::ManuallyDrop,
+    ptr::NonNull, //
+};
+
+/// The default netlink message size.
+pub const GENLMSG_DEFAULT_SIZE: usize = bindings::GENLMSG_DEFAULT_SIZE;
+
+/// A wrapper around `struct sk_buff` for generic netlink messages.
+///
+/// This type is intended to be specific for buffers used with netlink only, and other usecases for
+/// `struct sk_buff` are out-of-scope for this abstraction.
+///
+/// # Invariants
+///
+/// The pointer has ownership over a valid `sk_buff`.
+pub struct NetlinkSkBuff {
+    skb: NonNull<kernel::bindings::sk_buff>,
+}
+
+impl NetlinkSkBuff {
+    /// Creates a new `NetlinkSkBuff` with the given size.
+    pub fn new(size: usize, flags: alloc::Flags) -> Result<NetlinkSkBuff, AllocError> {
+        // SAFETY: `genlmsg_new` only requires its arguments to be valid integers.
+        let skb = unsafe { bindings::genlmsg_new(size, flags.as_raw()) };
+        let skb = NonNull::new(skb).ok_or(AllocError)?;
+        Ok(NetlinkSkBuff { skb })
+    }
+
+    /// Puts a generic netlink header into the `NetlinkSkBuff`.
+    pub fn genlmsg_put(
+        self,
+        portid: u32,
+        seq: u32,
+        family: &'static Family,
+        cmd: u8,
+    ) -> Result<GenlMsg, AllocError> {
+        let skb = self.skb.as_ptr();
+        // SAFETY: The skb and family pointers are valid.
+        let hdr = unsafe { bindings::genlmsg_put(skb, portid, seq, family.as_raw(), 0, cmd) };
+        let hdr = NonNull::new(hdr).ok_or(AllocError)?;
+        Ok(GenlMsg { skb: self, hdr })
+    }
+}
+
+impl Drop for NetlinkSkBuff {
+    fn drop(&mut self) {
+        // SAFETY: We have ownership over the `sk_buff`, so we may free it.
+        unsafe { bindings::nlmsg_free(self.skb.as_ptr()) }
+    }
+}
+
+/// A generic netlink message being constructed.
+///
+/// # Invariants
+///
+/// `hdr` references the header in this netlink message.
+pub struct GenlMsg {
+    skb: NetlinkSkBuff,
+    hdr: NonNull<c_void>,
+}
+
+impl GenlMsg {
+    /// Puts an attribute into the message.
+    #[inline]
+    fn put<T>(&mut self, attrtype: c_int, value: &T) -> Result
+    where
+        T: ?Sized + AsBytes,
+    {
+        let skb = self.skb.skb.as_ptr();
+        let len = size_of_val(value);
+        let ptr = core::ptr::from_ref(value).cast::<c_void>();
+        // SAFETY: `skb` is valid by `NetlinkSkBuff` type invariants, and the provided value is
+        // readable and initialized for its `size_of` bytes.
+        to_result(unsafe { bindings::nla_put(skb, attrtype, len as c_int, ptr) })
+    }
+
+    /// Puts a `u32` attribute into the message.
+    #[inline]
+    pub fn put_u32(&mut self, attrtype: c_int, value: u32) -> Result {
+        self.put(attrtype, &value)
+    }
+
+    /// Puts a string attribute into the message.
+    #[inline]
+    pub fn put_string(&mut self, attrtype: c_int, value: &CStr) -> Result {
+        self.put(attrtype, value.to_bytes_with_nul())
+    }
+
+    /// Puts a flag attribute into the message.
+    #[inline]
+    pub fn put_flag(&mut self, attrtype: c_int) -> Result {
+        let skb = self.skb.skb.as_ptr();
+        // SAFETY: `skb` is valid by `NetlinkSkBuff` type invariants, and a null pointer is valid
+        // when the length is zero.
+        to_result(unsafe { bindings::nla_put(skb, attrtype, 0, core::ptr::null()) })
+    }
+
+    /// Sends the generic netlink message as a multicast message.
+    #[inline]
+    pub fn multicast(
+        self,
+        family: &'static Family,
+        portid: u32,
+        group: u32,
+        flags: alloc::Flags,
+    ) -> Result {
+        let me = ManuallyDrop::new(self);
+        // SAFETY: The `skb` and `family` pointers are valid. We pass ownership of the `skb` to
+        // `genlmsg_multicast` by not dropping `self`.
+        unsafe {
+            bindings::genlmsg_end(me.skb.skb.as_ptr(), me.hdr.as_ptr());
+            to_result(bindings::genlmsg_multicast(
+                family.as_raw(),
+                me.skb.skb.as_ptr(),
+                portid,
+                group,
+                flags.as_raw(),
+            ))
+        }
+    }
+}
+impl Drop for GenlMsg {
+    fn drop(&mut self) {
+        // SAFETY: The `hdr` pointer references the header of this generic netlink message.
+        unsafe { bindings::genlmsg_cancel(self.skb.skb.as_ptr(), self.hdr.as_ptr()) };
+    }
+}
+
+/// Flags for a generic netlink family.
+struct FamilyFlags {
+    /// Whether the family supports network namespaces.
+    netnsok: bool,
+    /// Whether the family supports parallel operations.
+    parallel_ops: bool,
+}
+
+impl FamilyFlags {
+    /// Converts the flags to the bitfield representation used by `genl_family`.
+    const fn into_bitfield(self) -> bindings::__BindgenBitfieldUnit<[u8; 1]> {
+        // The below shifts are verified correct by test_family_flags_bitfield() below.
+        //
+        // Although bindgen generates helpers to change bitfields based on the C headers, these
+        // helpers unfortunately can't be used in const context. Since `Family` needs to be filled
+        // out at build-time, we use this helper instead.
+        let mut bits = 0;
+        if self.netnsok {
+            bits |= 1 << 0;
+        }
+        if self.parallel_ops {
+            bits |= 1 << 1;
+        }
+        // SAFETY: This bitfield is represented as an u8.
+        unsafe { core::mem::transmute::<u8, bindings::__BindgenBitfieldUnit<[u8; 1]>>(bits) }
+    }
+}
+
+/// A generic netlink family.
+#[repr(transparent)]
+pub struct Family {
+    inner: Opaque<bindings::genl_family>,
+}
+
+// SAFETY: The `Family` type is thread safe.
+unsafe impl Sync for Family {}
+
+impl Family {
+    /// Creates a new `Family` instance.
+    ///
+    /// Intended to be used from const context only. Will panic if provided with invalid arguments.
+    ///
+    /// The name must be a nul-terminated string, but it is taken as `&[u8]` so that it can be used
+    /// more conveniently with the strings generated by bindgen.
+    pub const fn const_new(
+        module: &ThisModule,
+        name: &[u8],
+        version: u32,
+        mcgrps: &'static [MulticastGroup],
+    ) -> Family {
+        let n_mcgrps = mcgrps.len() as u8;
+        if n_mcgrps as usize != mcgrps.len() {
+            panic!("too many mcgrps");
+        }
+        let mut genl_family = bindings::genl_family {
+            version,
+            _bitfield_1: FamilyFlags {
+                netnsok: true,
+                parallel_ops: true,
+            }
+            .into_bitfield(),
+            module: module.as_ptr(),
+            mcgrps: mcgrps.as_ptr().cast(),
+            n_mcgrps,
+            ..pin_init::zeroed()
+        };
+        if CStr::from_bytes_with_nul(name).is_err() {
+            panic!("genl_family name not nul-terminated");
+        }
+        if genl_family.name.len() < name.len() {
+            panic!("genl_family name too long");
+        }
+        let mut i = 0;
+        while i < name.len() {
+            genl_family.name[i] = name[i];
+            i += 1;
+        }
+        Family {
+            inner: Opaque::new(genl_family),
+        }
+    }
+
+    /// Checks if there are any listeners for the given multicast group.
+    pub fn has_listeners(&self, group: u32) -> bool {
+        // SAFETY: The family and init_net pointers are valid.
+        unsafe {
+            bindings::genl_has_listeners(self.as_raw(), &raw mut bindings::init_net, group) != 0
+        }
+    }
+
+    /// Returns a raw pointer to the underlying `genl_family` structure.
+    pub fn as_raw(&self) -> *mut bindings::genl_family {
+        self.inner.get()
+    }
+}
+
+/// A generic netlink multicast group.
+#[repr(transparent)]
+pub struct MulticastGroup {
+    // No Opaque because fully immutable
+    group: bindings::genl_multicast_group,
+}
+
+// SAFETY: Pure data so thread safe.
+unsafe impl Sync for MulticastGroup {}
+
+impl MulticastGroup {
+    /// Creates a new `MulticastGroup` instance.
+    ///
+    /// Intended to be used from const context only. Will panic if provided with invalid arguments.
+    pub const fn const_new(name: &CStr) -> MulticastGroup {
+        let mut group: bindings::genl_multicast_group = pin_init::zeroed();
+
+        let name = name.to_bytes_with_nul();
+        if group.name.len() < name.len() {
+            panic!("genl_multicast_group name too long");
+        }
+        let mut i = 0;
+        while i < name.len() {
+            group.name[i] = name[i];
+            i += 1;
+        }
+
+        MulticastGroup { group }
+    }
+}
+
+/// A registration of a generic netlink family.
+///
+/// This type represents the registration of a [`Family`]. When an instance of this type is
+/// dropped, its respective generic netlink family will be unregistered from the system.
+///
+/// # Invariants
+///
+/// `self.family` always holds a valid reference to an initialized and registered [`Family`].
+pub struct Registration {
+    family: &'static Family,
+}
+
+impl Family {
+    /// Registers the generic netlink family with the kernel.
+    pub fn register(&'static self) -> Result<Registration> {
+        // SAFETY: `self.as_raw()` is a valid pointer to a `genl_family` struct.
+        // The `genl_family` struct is static, so it will outlive the registration.
+        to_result(unsafe { bindings::genl_register_family(self.as_raw()) })?;
+        Ok(Registration { family: self })
+    }
+}
+
+impl Drop for Registration {
+    fn drop(&mut self) {
+        // SAFETY: `self.family.as_raw()` is a valid pointer to a registered `genl_family` struct.
+        // The `Registration` struct ensures that `genl_unregister_family` is called exactly once
+        // for this family when it goes out of scope.
+        unsafe { bindings::genl_unregister_family(self.family.as_raw()) };
+    }
+}
+
+#[macros::kunit_tests(rust_netlink)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_family_flags_bitfield() {
+        for netnsok in [false, true] {
+            for parallel_ops in [false, true] {
+                let mut b_fam = bindings::genl_family {
+                    ..Default::default()
+                };
+                b_fam.set_netnsok(if netnsok { 1 } else { 0 });
+                b_fam.set_parallel_ops(if parallel_ops { 1 } else { 0 });
+
+                let c_bitfield = FamilyFlags {
+                    netnsok,
+                    parallel_ops,
+                }
+                .into_bitfield();
+
+                // SAFETY: The bit field is stored as u8.
+                let b_val: u8 = unsafe { core::mem::transmute(b_fam._bitfield_1) };
+                // SAFETY: The bit field is stored as u8.
+                let c_val: u8 = unsafe { core::mem::transmute(c_bitfield) };
+                assert_eq!(b_val, c_val);
+            }
+        }
+    }
+}

-- 
2.54.0.545.g6539524ca2-goog


^ permalink raw reply related

* [PATCH v4 2/4] ynl_gen: generate Rust files from yaml files
From: Alice Ryhl @ 2026-05-04  9:04 UTC (permalink / raw)
  To: Carlos Llamas, Greg Kroah-Hartman, Andrew Lunn, Donald Hunter,
	Jakub Kicinski, David S. Miller, Eric Dumazet, Paolo Abeni,
	Simon Horman, Matthew Maurer
  Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Trevor Gross, Danilo Krummrich,
	Christian Brauner, linux-kernel, rust-for-linux, netdev,
	Alice Ryhl
In-Reply-To: <20260504-binder-netlink-v4-0-601b41cd25b2@google.com>

To generate netlink frames from Rust code easily, generate Rust
libraries with methods for generating different netlink messages as
appropriate.

The new 'rust' type corresponds to a Rust version of the C target
'kernel'. There is no Rust version of the 'uapi' target since Rust code
exports its uapi via C headers - choice of language is opaque to
userspace.

This logic is kept in the existing ynl_gen_c.py file to reuse CodeWriter
and other shared pieces of logic in the existing python file. This has
the disadvantage that the gen_c part of the name is now wrong, as it
also generates Rust. One possible solution to this could be to rename
the file.

Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
 tools/net/ynl/pyynl/ynl_gen_c.py | 139 ++++++++++++++++++++++++++++++++++++++-
 tools/net/ynl/ynl-regen.sh       |   2 +-
 2 files changed, 139 insertions(+), 2 deletions(-)

diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py
index 0e1e486c1185..76b8b2f1ac16 100755
--- a/tools/net/ynl/pyynl/ynl_gen_c.py
+++ b/tools/net/ynl/pyynl/ynl_gen_c.py
@@ -19,6 +19,7 @@ import pathlib
 import os
 import re
 import shutil
+import subprocess
 import sys
 import tempfile
 import yaml as pyyaml
@@ -1744,6 +1745,19 @@ class CodeWriter:
         else:
             self.p('}' + line)
 
+    def array_start(self, line=''):
+        if line:
+            line = line + ' '
+        self.p(line + '[')
+        self._ind += 1
+
+    def array_end(self, line=''):
+        if line and line[0] not in {';', ','}:
+            line = ' ' + line
+        self._ind -= 1
+        self._nl = False
+        self.p(']' + line)
+
     def write_doc_line(self, doc, indent=True):
         words = doc.split()
         line = ' *'
@@ -3415,10 +3429,126 @@ def find_kernel_root(full_path):
             return full_path, sub_path[:-1]
 
 
+def render_rust(family, cw):
+    cw.p('#![allow(unreachable_pub, clippy::wrong_self_convention)]')
+    cw.p('use kernel::netlink::{Family, MulticastGroup};')
+    cw.p('use kernel::prelude::*;')
+    cw.nl()
+
+    family_upper = c_upper(family.ident_name)
+    family_name = f'{family_upper}_NL_FAMILY'
+    mcgrps_name = f'{family_name}_MCGRPS'
+
+    cw.p(f'pub static {family_name}: Family = Family::const_new(')
+    cw._ind += 1
+    cw.p('&crate::THIS_MODULE,')
+    cw.p(f'kernel::uapi::{family.fam_key},')
+    cw.p(f'kernel::uapi::{family.ver_key},')
+    if family.mcgrps['list']:
+        cw.p(f'&{mcgrps_name},')
+    else:
+        cw.p('&[],')
+    cw._ind -= 1
+    cw.p(');')
+    cw.nl()
+
+    if family.mcgrps['list']:
+        cw.array_start(f'static {mcgrps_name}: [MulticastGroup; {len(family.mcgrps["list"])}] = ')
+        for grp in family.mcgrps['list']:
+            cw.p(f'MulticastGroup::const_new(c"{grp["name"]}"),')
+        cw.array_end(';')
+        cw.nl()
+
+    for idx, (op_name, op) in enumerate(item for item in family.msgs.items() if 'event' in item[1]):
+        struct_name = op_name.capitalize()
+
+        if 'doc' in op:
+            doc_lines = op['doc'].strip().split('\n')
+            for line in doc_lines:
+                cw.p(f'/// {line.strip()}')
+
+        cw.block_start(f'pub struct {struct_name}')
+        cw.p('skb: kernel::netlink::GenlMsg,')
+        cw.block_end()
+        cw.nl()
+
+        cw.block_start(f'impl {struct_name}')
+        cw.p('/// Create a new multicast message.')
+        cw.p('pub fn new(')
+        cw._ind += 1
+        cw.p('size: usize,')
+        cw.p('portid: u32,')
+        cw.p('seq: u32,')
+        cw.p('flags: kernel::alloc::Flags,')
+        cw._ind -= 1
+        cw.block_start(') -> Result<Self, kernel::alloc::AllocError>')
+        cw.p(f'const {op.enum_name}: u8 = kernel::uapi::{op.enum_name} as u8;')
+        cw.p('let skb = kernel::netlink::NetlinkSkBuff::new(size, flags)?;')
+        cw.p(f'let skb = skb.genlmsg_put(portid, seq, &{family_name}, {op.enum_name})?;')
+        cw.p('Ok(Self { skb })')
+        cw.block_end()
+        cw.nl()
+
+        grp_idx = 0
+        if 'mcgrp' in op:
+            grp_idx = next(i for i, grp in enumerate(family.mcgrps['list']) if grp['name'] == op['mcgrp'])
+
+        cw.p('/// Broadcast this message.')
+        cw.block_start('pub fn multicast(self, portid: u32, flags: kernel::alloc::Flags) -> Result')
+        cw.p(f'self.skb.multicast(&{family_name}, portid, {grp_idx}, flags)')
+        cw.block_end()
+        cw.nl()
+
+        cw.p('/// Check if this message type has listeners.')
+        cw.block_start('pub fn has_listeners() -> bool')
+        cw.p(f'{family_name}.has_listeners({grp_idx})')
+        cw.block_end()
+
+        attr_set_name = op['attribute-set']
+        attr_set = family.attr_sets[attr_set_name]
+        event_attrs = op['event']['attributes']
+
+        for attr_name in event_attrs:
+            attr = attr_set[attr_name]
+            method_name = attr_name.replace('-', '_')
+
+            if attr.type == 'u32':
+                put_fn = 'put_u32'
+                arg_str = ', val'
+                method_args = '(&mut self, val: u32)'
+            elif attr.type == 'string':
+                put_fn = 'put_string'
+                arg_str = ', val'
+                method_args = '(&mut self, val: &CStr)'
+            elif attr.type == 'flag':
+                put_fn = 'put_flag'
+                arg_str = ''
+                method_args = '(&mut self)'
+            else:
+                put_fn = f'put_{attr.type}'
+                arg_str = ', val'
+                method_args = f'(&mut self, val: {attr.type})'
+
+            cw.nl()
+            if 'doc' in attr.yaml:
+                doc_lines = attr.yaml['doc'].strip().split('\n')
+                for line in doc_lines:
+                    cw.p(f'/// {line.strip()}')
+
+            cw.block_start(f'pub fn {method_name}{method_args} -> Result')
+            cw.p(f'const {attr.enum_name}: c_int = kernel::uapi::{attr.enum_name} as c_int;')
+            cw.p(f'self.skb.{put_fn}({attr.enum_name}{arg_str})')
+            cw.block_end()
+
+        cw.block_end()
+        cw.nl()
+    cw.p(' ')
+
+
 def main():
     parser = argparse.ArgumentParser(description='Netlink simple parsing generator')
     parser.add_argument('--mode', dest='mode', type=str, required=True,
-                        choices=('user', 'kernel', 'uapi'))
+                        choices=('user', 'kernel', 'uapi', 'rust'))
     parser.add_argument('--spec', dest='spec', type=str, required=True)
     parser.add_argument('--header', dest='header', action='store_true', default=None)
     parser.add_argument('--source', dest='header', action='store_false')
@@ -3471,6 +3601,13 @@ def main():
         render_uapi(parsed, cw)
         return
 
+    if args.mode == 'rust':
+        render_rust(parsed, cw)
+        cw.close_out_file()
+        if args.out_file:
+            subprocess.run(['rustfmt', '--edition', '2021', args.out_file])
+        return
+
     hdr_prot = f"_LINUX_{parsed.c_name.upper()}_GEN_H"
     if args.header:
         cw.p('#ifndef ' + hdr_prot)
diff --git a/tools/net/ynl/ynl-regen.sh b/tools/net/ynl/ynl-regen.sh
index d9809276db98..4f5ceb4fe147 100755
--- a/tools/net/ynl/ynl-regen.sh
+++ b/tools/net/ynl/ynl-regen.sh
@@ -17,7 +17,7 @@ done
 KDIR=$(dirname $(dirname $(dirname $(dirname $(realpath $0)))))
 pushd ${search:-$KDIR} >>/dev/null
 
-files=$(git grep --files-with-matches '^/\* YNL-GEN \(kernel\|uapi\|user\)')
+files=$(git grep --files-with-matches '^/\* YNL-GEN \(kernel\|uapi\|user\|rust\)')
 for f in $files; do
     # params:     0       1      2     3
     #         $YAML YNL-GEN kernel $mode

-- 
2.54.0.545.g6539524ca2-goog


^ permalink raw reply related

* [PATCH v4 3/4] rust_binder: add generated netlink.rs file
From: Alice Ryhl @ 2026-05-04  9:04 UTC (permalink / raw)
  To: Carlos Llamas, Greg Kroah-Hartman, Andrew Lunn, Donald Hunter,
	Jakub Kicinski, David S. Miller, Eric Dumazet, Paolo Abeni,
	Simon Horman, Matthew Maurer
  Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Trevor Gross, Danilo Krummrich,
	Christian Brauner, linux-kernel, rust-for-linux, netdev,
	Alice Ryhl
In-Reply-To: <20260504-binder-netlink-v4-0-601b41cd25b2@google.com>

To use netlink from Rust Binder, add a new generated netlink file using
the new script and Documentation/netlink/specs/binder.yaml.

Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
 drivers/android/Kconfig                    |   2 +-
 drivers/android/binder/netlink.rs          | 113 +++++++++++++++++++++++++++++
 drivers/android/binder/rust_binder_main.rs |   9 ++-
 rust/uapi/uapi_helper.h                    |   1 +
 4 files changed, 122 insertions(+), 3 deletions(-)

diff --git a/drivers/android/Kconfig b/drivers/android/Kconfig
index e2e402c9d175..606a9d07f774 100644
--- a/drivers/android/Kconfig
+++ b/drivers/android/Kconfig
@@ -16,7 +16,7 @@ config ANDROID_BINDER_IPC
 
 config ANDROID_BINDER_IPC_RUST
 	bool "Rust version of Android Binder IPC Driver"
-	depends on RUST && MMU && !ANDROID_BINDER_IPC
+	depends on RUST && MMU && NET && !ANDROID_BINDER_IPC
 	help
 	  This enables the Rust implementation of the Binder driver.
 
diff --git a/drivers/android/binder/netlink.rs b/drivers/android/binder/netlink.rs
new file mode 100644
index 000000000000..2a842c7b1b33
--- /dev/null
+++ b/drivers/android/binder/netlink.rs
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
+/* Do not edit directly, auto-generated from: */
+/*	Documentation/netlink/specs/binder.yaml */
+/* YNL-GEN rust source */
+/* To regenerate run: tools/net/ynl/ynl-regen.sh */
+
+#![allow(unreachable_pub, clippy::wrong_self_convention)]
+use kernel::netlink::{Family, MulticastGroup};
+use kernel::prelude::*;
+
+pub static BINDER_NL_FAMILY: Family = Family::const_new(
+    &crate::THIS_MODULE,
+    kernel::uapi::BINDER_FAMILY_NAME,
+    kernel::uapi::BINDER_FAMILY_VERSION,
+    &BINDER_NL_FAMILY_MCGRPS,
+);
+
+static BINDER_NL_FAMILY_MCGRPS: [MulticastGroup; 1] = [MulticastGroup::const_new(c"report")];
+
+/// A multicast event sent to userspace subscribers to notify them about
+/// binder transaction failures. The generated report provides the full
+/// details of the specific transaction that failed. The intention is for
+/// programs to monitor these events and react to the failures as needed.
+pub struct Report {
+    skb: kernel::netlink::GenlMsg,
+}
+
+impl Report {
+    /// Create a new multicast message.
+    pub fn new(
+        size: usize,
+        portid: u32,
+        seq: u32,
+        flags: kernel::alloc::Flags,
+    ) -> Result<Self, kernel::alloc::AllocError> {
+        const BINDER_CMD_REPORT: u8 = kernel::uapi::BINDER_CMD_REPORT as u8;
+        let skb = kernel::netlink::NetlinkSkBuff::new(size, flags)?;
+        let skb = skb.genlmsg_put(portid, seq, &BINDER_NL_FAMILY, BINDER_CMD_REPORT)?;
+        Ok(Self { skb })
+    }
+
+    /// Broadcast this message.
+    pub fn multicast(self, portid: u32, flags: kernel::alloc::Flags) -> Result {
+        self.skb.multicast(&BINDER_NL_FAMILY, portid, 0, flags)
+    }
+
+    /// Check if this message type has listeners.
+    pub fn has_listeners() -> bool {
+        BINDER_NL_FAMILY.has_listeners(0)
+    }
+
+    /// The enum binder_driver_return_protocol returned to the sender.
+    pub fn error(&mut self, val: u32) -> Result {
+        const BINDER_A_REPORT_ERROR: c_int = kernel::uapi::BINDER_A_REPORT_ERROR as c_int;
+        self.skb.put_u32(BINDER_A_REPORT_ERROR, val)
+    }
+
+    /// The binder context where the transaction occurred.
+    pub fn context(&mut self, val: &CStr) -> Result {
+        const BINDER_A_REPORT_CONTEXT: c_int = kernel::uapi::BINDER_A_REPORT_CONTEXT as c_int;
+        self.skb.put_string(BINDER_A_REPORT_CONTEXT, val)
+    }
+
+    /// The PID of the sender process.
+    pub fn from_pid(&mut self, val: u32) -> Result {
+        const BINDER_A_REPORT_FROM_PID: c_int = kernel::uapi::BINDER_A_REPORT_FROM_PID as c_int;
+        self.skb.put_u32(BINDER_A_REPORT_FROM_PID, val)
+    }
+
+    /// The TID of the sender thread.
+    pub fn from_tid(&mut self, val: u32) -> Result {
+        const BINDER_A_REPORT_FROM_TID: c_int = kernel::uapi::BINDER_A_REPORT_FROM_TID as c_int;
+        self.skb.put_u32(BINDER_A_REPORT_FROM_TID, val)
+    }
+
+    /// The PID of the recipient process. This attribute may not be present
+    /// if the target could not be determined.
+    pub fn to_pid(&mut self, val: u32) -> Result {
+        const BINDER_A_REPORT_TO_PID: c_int = kernel::uapi::BINDER_A_REPORT_TO_PID as c_int;
+        self.skb.put_u32(BINDER_A_REPORT_TO_PID, val)
+    }
+
+    /// The TID of the recipient thread. This attribute may not be present
+    /// if the target could not be determined.
+    pub fn to_tid(&mut self, val: u32) -> Result {
+        const BINDER_A_REPORT_TO_TID: c_int = kernel::uapi::BINDER_A_REPORT_TO_TID as c_int;
+        self.skb.put_u32(BINDER_A_REPORT_TO_TID, val)
+    }
+
+    /// When present, indicates the failed transaction is a reply.
+    pub fn is_reply(&mut self) -> Result {
+        const BINDER_A_REPORT_IS_REPLY: c_int = kernel::uapi::BINDER_A_REPORT_IS_REPLY as c_int;
+        self.skb.put_flag(BINDER_A_REPORT_IS_REPLY)
+    }
+
+    /// The bitmask of enum transaction_flags from the transaction.
+    pub fn flags(&mut self, val: u32) -> Result {
+        const BINDER_A_REPORT_FLAGS: c_int = kernel::uapi::BINDER_A_REPORT_FLAGS as c_int;
+        self.skb.put_u32(BINDER_A_REPORT_FLAGS, val)
+    }
+
+    /// The application-defined code from the transaction.
+    pub fn code(&mut self, val: u32) -> Result {
+        const BINDER_A_REPORT_CODE: c_int = kernel::uapi::BINDER_A_REPORT_CODE as c_int;
+        self.skb.put_u32(BINDER_A_REPORT_CODE, val)
+    }
+
+    /// The transaction payload size in bytes.
+    pub fn data_size(&mut self, val: u32) -> Result {
+        const BINDER_A_REPORT_DATA_SIZE: c_int = kernel::uapi::BINDER_A_REPORT_DATA_SIZE as c_int;
+        self.skb.put_u32(BINDER_A_REPORT_DATA_SIZE, val)
+    }
+}
diff --git a/drivers/android/binder/rust_binder_main.rs b/drivers/android/binder/rust_binder_main.rs
index dc1941cd2407..2cb9f4897ad7 100644
--- a/drivers/android/binder/rust_binder_main.rs
+++ b/drivers/android/binder/rust_binder_main.rs
@@ -38,6 +38,8 @@
 mod deferred_close;
 mod defs;
 mod error;
+#[allow(dead_code)]
+mod netlink;
 mod node;
 mod page_range;
 mod process;
@@ -288,19 +290,22 @@ fn ptr_align(value: usize) -> Option<usize> {
 // SAFETY: We call register in `init`.
 static BINDER_SHRINKER: Shrinker = unsafe { Shrinker::new() };
 
-struct BinderModule {}
+struct BinderModule {
+    _netlink: kernel::netlink::Registration,
+}
 
 impl kernel::Module for BinderModule {
     fn init(_module: &'static kernel::ThisModule) -> Result<Self> {
         // SAFETY: The module initializer never runs twice, so we only call this once.
         unsafe { crate::context::CONTEXTS.init() };
 
+        let netlink = crate::netlink::BINDER_NL_FAMILY.register()?;
         BINDER_SHRINKER.register(c"android-binder")?;
 
         // SAFETY: The module is being loaded, so we can initialize binderfs.
         unsafe { kernel::error::to_result(binderfs::init_rust_binderfs())? };
 
-        Ok(Self {})
+        Ok(Self { _netlink: netlink })
     }
 }
 
diff --git a/rust/uapi/uapi_helper.h b/rust/uapi/uapi_helper.h
index 06d7d1a2e8da..86c7b6b284b0 100644
--- a/rust/uapi/uapi_helper.h
+++ b/rust/uapi/uapi_helper.h
@@ -11,6 +11,7 @@
 #include <uapi/drm/nova_drm.h>
 #include <uapi/drm/panthor_drm.h>
 #include <uapi/linux/android/binder.h>
+#include <uapi/linux/android/binder_netlink.h>
 #include <uapi/linux/mdio.h>
 #include <uapi/linux/mii.h>
 #include <uapi/linux/ethtool.h>

-- 
2.54.0.545.g6539524ca2-goog


^ permalink raw reply related

* [PATCH v4 4/4] rust_binder: report netlink transactions
From: Alice Ryhl @ 2026-05-04  9:04 UTC (permalink / raw)
  To: Carlos Llamas, Greg Kroah-Hartman, Andrew Lunn, Donald Hunter,
	Jakub Kicinski, David S. Miller, Eric Dumazet, Paolo Abeni,
	Simon Horman, Matthew Maurer
  Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Trevor Gross, Danilo Krummrich,
	Christian Brauner, linux-kernel, rust-for-linux, netdev,
	Alice Ryhl
In-Reply-To: <20260504-binder-netlink-v4-0-601b41cd25b2@google.com>

From: Carlos Llamas <cmllamas@google.com>

The Android Binder driver supports a netlink API that reports
transaction *failures* to a userspace daemon. This allows devices to
monitor processes with many failed transactions so that it can e.g. kill
misbehaving apps.

One very important thing that this monitors is when many oneway messages
are sent to a frozen process, so there is special handling to ensure
this scenario is surfaced over netlink.

Signed-off-by: Carlos Llamas <cmllamas@google.com>
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
 drivers/android/binder/rust_binder_main.rs |  1 -
 drivers/android/binder/thread.rs           | 10 ++++++++
 drivers/android/binder/transaction.rs      | 40 ++++++++++++++++++++++++++++++
 3 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/drivers/android/binder/rust_binder_main.rs b/drivers/android/binder/rust_binder_main.rs
index 2cb9f4897ad7..bbef68993b8d 100644
--- a/drivers/android/binder/rust_binder_main.rs
+++ b/drivers/android/binder/rust_binder_main.rs
@@ -38,7 +38,6 @@
 mod deferred_close;
 mod defs;
 mod error;
-#[allow(dead_code)]
 mod netlink;
 mod node;
 mod page_range;
diff --git a/drivers/android/binder/thread.rs b/drivers/android/binder/thread.rs
index 97d5f31e8fe3..aa4e93a877ac 100644
--- a/drivers/android/binder/thread.rs
+++ b/drivers/android/binder/thread.rs
@@ -1263,6 +1263,15 @@ fn transaction(self: &Arc<Self>, cmd: u32, reader: &mut UserSliceReader) -> Resu
             }
         }
 
+        if info.oneway_spam_suspect {
+            // If this is both a oneway spam suspect and a failure, we report it twice. This is
+            // useful in case the transaction failed with BR_TRANSACTION_PENDING_FROZEN.
+            info.report_netlink(BR_ONEWAY_SPAM_SUSPECT, &self.process.ctx);
+        }
+        if info.reply != 0 {
+            info.report_netlink(info.reply, &self.process.ctx);
+        }
+
         Ok(())
     }
 
@@ -1332,6 +1341,7 @@ fn reply_inner(self: &Arc<Self>, info: &mut TransactionInfo) -> BinderResult {
             );
             let reply = Err(BR_FAILED_REPLY);
             orig.from.deliver_reply(reply, &orig);
+            info.reply = BR_FAILED_REPLY;
             err.reply = BR_TRANSACTION_COMPLETE;
             err
         });
diff --git a/drivers/android/binder/transaction.rs b/drivers/android/binder/transaction.rs
index 47d5e4d88b07..3fa7091ed8a6 100644
--- a/drivers/android/binder/transaction.rs
+++ b/drivers/android/binder/transaction.rs
@@ -3,6 +3,7 @@
 // Copyright (C) 2025 Google LLC.
 
 use kernel::{
+    netlink::GENLMSG_DEFAULT_SIZE,
     prelude::*,
     seq_file::SeqFile,
     seq_print,
@@ -17,6 +18,7 @@
     allocation::{Allocation, TranslatedFds},
     defs::*,
     error::{BinderError, BinderResult},
+    netlink::Report,
     node::{Node, NodeRef},
     process::{Process, ProcessInner},
     ptr_align,
@@ -49,6 +51,44 @@ impl TransactionInfo {
     pub(crate) fn is_oneway(&self) -> bool {
         self.flags & TF_ONE_WAY != 0
     }
+
+    pub(crate) fn report_netlink(&self, reply: u32, ctx: &crate::Context) {
+        if let Err(err) = self.report_netlink_inner(reply, ctx) {
+            pr_warn!(
+                "{}:{} netlink report failed: {err:?}\n",
+                self.from_pid,
+                self.from_tid
+            );
+        }
+    }
+
+    fn report_netlink_inner(&self, reply: u32, ctx: &crate::Context) -> kernel::error::Result {
+        if !Report::has_listeners() {
+            return Ok(());
+        }
+        let mut report = Report::new(GENLMSG_DEFAULT_SIZE, 0, 0, GFP_KERNEL)?;
+
+        report.error(reply)?;
+        report.context(&ctx.name)?;
+        report.from_pid(self.from_pid as u32)?;
+        report.from_tid(self.from_tid as u32)?;
+        if self.to_pid != 0 {
+            report.to_pid(self.to_pid as u32)?;
+        }
+        if self.to_tid != 0 {
+            report.to_tid(self.to_tid as u32)?;
+        }
+
+        if self.is_reply {
+            report.is_reply()?;
+        }
+        report.flags(self.flags)?;
+        report.code(self.code)?;
+        report.data_size(self.data_size as u32)?;
+
+        report.multicast(0, GFP_KERNEL)?;
+        Ok(())
+    }
 }
 
 use core::mem::offset_of;

-- 
2.54.0.545.g6539524ca2-goog


^ permalink raw reply related

* Re: [PATCH 2/4] tools: ynl-gen-c: optionally emit structs and helpers
From: Christoph Böhmwalder @ 2026-05-04  9:05 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Jens Axboe, drbd-dev, linux-kernel, Lars Ellenberg,
	Philipp Reisner, linux-block, Donald Hunter, Eric Dumazet, netdev
In-Reply-To: <20260414083548.02f76970@kernel.org>

On Tue, Apr 14, 2026 at 08:35:48AM -0700, Jakub Kicinski wrote:
>On Tue, 14 Apr 2026 14:08:58 +0200 Christoph Böhmwalder wrote:
>> But we still need to support the current family via a compat path, and
>> I would much rather have two YNL-based families than one genl_magic and
>> one YNL-based. Carrying both sounds like a nightmare.
>>
>> So the spec proposed in this series would never actually be used to
>> generate a userspace client, if that's what you're asking. We would
>> continue to use the current libgenl-based approach, with some userspace
>> compat shims to make it work with YNL. Then, when "drbd2" comes along,
>> we could "do things properly".
>
>Let's jump to the drbd2 work.

We have a bit of a chicken-egg situation there.

The drbd2 work depends on the DRBD 9 upstreaming series, since the drbd2
netlink family will use the new DRBD 9 semantics.
However, the DRBD 9 series depends on the current DRBD module already
using YNL (or rather, *not* using genl_magic anymore).

Our plan is to convert the current family to YNL in-place first, then
incrementally add the new modern drbd2 family with DRBD 9 semantics in
another series.

How would you prefer to handle the YNL switch? If it makes it easier for
you, just committing the YNL-generated code without the generator is
fine for me. The old family is effectively frozen, so that would work.

Thanks,
Christoph

^ permalink raw reply

* [PATCH] genetlink: free the skb on 'group >= family->n_mcgrps'
From: Alice Ryhl @ 2026-05-04  9:17 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Andrew Lunn, Matthew Maurer
  Cc: netdev, linux-kernel, Alice Ryhl

These methods generally consume ownership of the provided skb, so even
if an error path is encountered, the skb is freed. This is because the
very first thing they do after some initial setup is to unconditionally
consume the skb via consume_skb(skb). Any subsequent errors lead to the
core netlink layer freeing the skb.

However, there is one check that occurs before ownership is passed,
which is the check for the group index. So if this error condition is
encountered, then the skb is leaked. This error condition is generally
considered a violation of the netlink API, so it's not expected to occur
under normal circumstances. For the same reason, no callers check for
this error condition, and no callers need to be adjusted. However, we
should still follow the same ownership semantics of the rest of the
function. Thus, free the skb in this codepath.

Assisted-by: Antigravity:gemini
Suggested-by: Andrew Lunn <andrew@lunn.ch>
Suggested-by: Matthew Maurer <mmaurer@google.com>
Link: https://lore.kernel.org/r/845b36ba-7b3a-41f2-acb2-b284f253e2ca@lunn.ch
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
 include/net/genetlink.h | 4 +++-
 net/netlink/genetlink.c | 8 ++++++--
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/include/net/genetlink.h b/include/net/genetlink.h
index 7b84f2cef8b1..d70510ac31ab 100644
--- a/include/net/genetlink.h
+++ b/include/net/genetlink.h
@@ -489,8 +489,10 @@ genlmsg_multicast_netns_filtered(const struct genl_family *family,
 				 netlink_filter_fn filter,
 				 void *filter_data)
 {
-	if (WARN_ON_ONCE(group >= family->n_mcgrps))
+	if (WARN_ON_ONCE(group >= family->n_mcgrps)) {
+		nlmsg_free(skb);
 		return -EINVAL;
+	}
 	group = family->mcgrp_offset + group;
 	return nlmsg_multicast_filtered(net->genl_sock, skb, portid, group,
 					flags, filter, filter_data);
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index d251d894afd4..0da39eaed255 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -1972,8 +1972,10 @@ int genlmsg_multicast_allns(const struct genl_family *family,
 			    struct sk_buff *skb, u32 portid,
 			    unsigned int group)
 {
-	if (WARN_ON_ONCE(group >= family->n_mcgrps))
+	if (WARN_ON_ONCE(group >= family->n_mcgrps)) {
+		kfree_skb(skb);
 		return -EINVAL;
+	}
 
 	group = family->mcgrp_offset + group;
 	return genlmsg_mcast(skb, portid, group);
@@ -1986,8 +1988,10 @@ void genl_notify(const struct genl_family *family, struct sk_buff *skb,
 	struct net *net = genl_info_net(info);
 	struct sock *sk = net->genl_sock;
 
-	if (WARN_ON_ONCE(group >= family->n_mcgrps))
+	if (WARN_ON_ONCE(group >= family->n_mcgrps)) {
+		kfree_skb(skb);
 		return;
+	}
 
 	group = family->mcgrp_offset + group;
 	nlmsg_notify(sk, skb, info->snd_portid, group,

---
base-commit: 7fd2df204f342fc17d1a0bfcd474b24232fb0f32
change-id: 20260504-genlmsg-return-1e5d6a74d440

Best regards,
-- 
Alice Ryhl <aliceryhl@google.com>


^ permalink raw reply related

* Re: [PATCH v4 02/15] firmware: qcom: Add a generic PAS service
From: Harshal Dev @ 2026-05-04  9:20 UTC (permalink / raw)
  To: Sumit Garg
  Cc: linux-arm-msm, devicetree, dri-devel, freedreno, linux-media,
	netdev, linux-wireless, ath12k, linux-remoteproc, robh, krzk+dt,
	conor+dt, robin.clark, sean, akhilpo, lumag, abhinav.kumar,
	jesszhan0024, marijn.suijten, airlied, simona, vikash.garodia,
	dikshita.agarwal, bod, mchehab, elder, andrew+netdev, davem,
	edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
	trilokkumar.soni, mukesh.ojha, pavan.kondeti, jorge.ramirez,
	tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
	op-tee, apurupa, skare, linux-kernel, Sumit Garg, Konrad Dybcio,
	Bjorn Andersson
In-Reply-To: <20260427095603.1157963-3-sumit.garg@kernel.org>



On 4/27/2026 3:25 PM, Sumit Garg via OP-TEE wrote:
> From: Sumit Garg <sumit.garg@oss.qualcomm.com>
> 
> Qcom platforms has the legacy of using non-standard SCM calls
> splintered over the various kernel drivers. These SCM calls aren't
> compliant with the standard SMC calling conventions which is a
> prerequisite to enable migration to the FF-A specifications from Arm.
> 
> OP-TEE as an alternative trusted OS to Qualcomm TEE (QTEE) can't
> support these non-standard SCM calls. And even for newer architectures
> using S-EL2 with Hafnium support, QTEE won't be able to support SCM
> calls either with FF-A requirements coming in. And with both OP-TEE
> and QTEE drivers well integrated in the TEE subsystem, it makes further
> sense to reuse the TEE bus client drivers infrastructure.
> 
> The added benefit of TEE bus infrastructure is that there is support
> for discoverable/enumerable services. With that client drivers don't
> have to manually invoke a special SCM call to know the service status.
> 
> So enable the generic Peripheral Authentication Service (PAS) provided
> by the firmware. It acts as the common layer with different TZ
> backends plugged in whether it's an SCM implementation or a proper
> TEE bus based PAS service implementation.
> 
> Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
> ---

Reviewed-by: Harshal Dev <harshal.dev@oss.qualcomm.com>

Regards,
Harshal


^ permalink raw reply

* Re: [PATCH v4 03/15] firmware: qcom_scm: Migrate to generic PAS service
From: Harshal Dev @ 2026-05-04  9:22 UTC (permalink / raw)
  To: Sumit Garg
  Cc: linux-arm-msm, devicetree, dri-devel, freedreno, linux-media,
	netdev, linux-wireless, ath12k, linux-remoteproc, robh, krzk+dt,
	conor+dt, robin.clark, sean, akhilpo, lumag, abhinav.kumar,
	jesszhan0024, marijn.suijten, airlied, simona, vikash.garodia,
	dikshita.agarwal, bod, mchehab, elder, andrew+netdev, davem,
	edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
	trilokkumar.soni, mukesh.ojha, pavan.kondeti, jorge.ramirez,
	tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
	op-tee, apurupa, skare, linux-kernel, Sumit Garg, Konrad Dybcio,
	Bjorn Andersson
In-Reply-To: <20260427095603.1157963-4-sumit.garg@kernel.org>



On 4/27/2026 3:25 PM, Sumit Garg via OP-TEE wrote:
> From: Sumit Garg <sumit.garg@oss.qualcomm.com>
> 
> With the availability of generic PAS service, let's add SCM calls as
> a backend to keep supporting legacy QTEE interfaces. The exported
> qcom_scm* wrappers will get dropped once all the client drivers get
> migrated as part of future patches.
> 
> Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>

Reviewed-by: Harshal Dev <harshal.dev@oss.qualcomm.com>

Regards,
Harshal


^ permalink raw reply

* Re: [PATCH v2] nfc: nxp-nci: remove interrupt trigger type
From: Bartosz Golaszewski @ 2026-05-04  9:33 UTC (permalink / raw)
  To: Carl Lee
  Cc: Luca Stefani, netdev, linux-kernel, krzk, peter.shen,
	colin.huang2, carl.lee
In-Reply-To: <abE6yxLHNqvq2Imz@carl-amd>

On Wed, Mar 11, 2026 at 11:01 AM Carl Lee <qq1145099@gmail.com> wrote:
>
> On Mon, Mar 09, 2026 at 07:13:18PM +0100, Luca Stefani wrote:
> >
> > On 05/02/2026 12:11, Carl Lee wrote:
> > > For NXP NCI devices (e.g. PN7150), the interrupt is level-triggered and
> > > active high, not edge-triggered.
> > >
> > > Using IRQF_TRIGGER_RISING in the driver can cause interrupts to fail
> > > to trigger correctly.
> > >
> > > Remove IRQF_TRIGGER_RISING and rely on the IRQ trigger type configured
> > > via Device Tree.
> > >
> > > Signed-off-by: Carl Lee <carl.lee@amd.com>
> > > ---
> > > This v2 of the series includes Krzysztof Kozlowski in the review list
> > > for NXP-NCI NFC.
> > >
> > > This series removes IRQF_TRIGGER_RISING in nxp-nci driver,
> > > relying on the IRQ trigger type specified via Device Tree.
> > > ---
> > > Changes in v2:
> > > - Include Krzysztof Kozlowski in the review list for NXP-NCI NFC.
> > > - Link to v1: https://lore.kernel.org/r/20260204-fc-nxp-nci-remove-interrupt-trigger-type-v1-1-3bde91593173@amd.com
> > > ---
> > >   drivers/nfc/nxp-nci/i2c.c | 2 +-
> > >   1 file changed, 1 insertion(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c
> > > index 049662ffdf97..6a5ce8ff91f0 100644
> > > --- a/drivers/nfc/nxp-nci/i2c.c
> > > +++ b/drivers/nfc/nxp-nci/i2c.c
> > > @@ -305,7 +305,7 @@ static int nxp_nci_i2c_probe(struct i2c_client *client)
> > >     r = request_threaded_irq(client->irq, NULL,
> > >                              nxp_nci_i2c_irq_thread_fn,
> > > -                            IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> > > +                            IRQF_ONESHOT,
> >
> > This is causing an IRQ storm on my ACPI device that eats away a core of my
> > cpu...
> >
> > I'm not sure how this should be fixed but by looking at other drivers they
> > all use irq_get_trigger_type() and then apply extra bits on top.
> >
> > If there's no clear path that handles both ACPI+DT I'll upload a revert.
> >
>
> Thanks for the report.
>
> I’ve sent a follow-up patch series that restores a fallback to the
> historically used rising-edge trigger when the firmware does not provide
> a trigger type. This should prevent the IRQ storm on ACPI platforms
> while keeping proper behavior on DT-based systems.
>
> Patch series link: https://lore.kernel.org/all/20260311-nfc-nxp-nci-i2c-restore-irq-trigger-fallback-v1-1-9e20714411d7@amd.com/
>

Hi!

I'm experiencing the same issue since v6.19.5 (still present on
v7.0.3) and the linked patch *does not* fix the problem - only
reverting the offending commit
(57be33f85e369ce9f69f61eaa34734e0d3bd47a7 in mainline) does. I'm
running a T14s laptop with AMD Ryzen 7 PRO 6850U.

Best Regards,
Bartosz Golaszewski

^ permalink raw reply

* Re: [PATCH net-next v2 1/2] dpll: move fractional-frequency-offset-ppt under pin-parent-device
From: Ivan Vecera @ 2026-05-04  9:36 UTC (permalink / raw)
  To: Jiri Pirko
  Cc: netdev, Andrew Lunn, Arkadiusz Kubalewski, David S. Miller,
	Donald Hunter, Eric Dumazet, Jakub Kicinski, Jonathan Corbet,
	Leon Romanovsky, Mark Bloch, Michal Schmidt, Paolo Abeni,
	Pasi Vaananen, Petr Oros, Prathosh Satish, Saeed Mahameed,
	Shuah Khan, Simon Horman, Tariq Toukan, Vadim Fedorenko,
	linux-doc, linux-kernel, linux-rdma
In-Reply-To: <afhdCnT0ns-PgZD8@FV6GYCPJ69>

Hi Jiri,

On 5/4/26 10:48 AM, Jiri Pirko wrote:
> Thu, Apr 30, 2026 at 07:36:10PM +0200, ivecera@redhat.com wrote:
>> Move the fractional-frequency-offset-ppt attribute from the top-level
>> pin attributes into the pin-parent-device nested attribute set. This
>> makes it consistent with phase-offset which is already per-parent and
>> clarifies that FFO PPT represents the frequency difference between
>> a pin and its parent DPLL device.
>>
>> The top-level fractional-frequency-offset attribute (in PPM) remains
>> unchanged for backward compatibility.
> 
> That is odd. The ppt one was added just for higher precision but was
> semantically the same. Now you change it. Could you still treat both the
> same?
> 
WDYM?

Keep fractional-frequency-offset-ppt at the top-level and add both
fractional-frequency-offset and fractional-frequency-offset-ppt into
pin-parent-device nested attribute set?

Thanks,
Ivan


^ permalink raw reply

* Re: [PATCH] mptcp: zero opts->ext_copy in mptcp_established_options_dss()
From: Matthieu Baerts @ 2026-05-04  9:37 UTC (permalink / raw)
  To: Deepanshu Kartikey, martineau, geliang, davem, edumazet, kuba,
	pabeni, horms
  Cc: cpaasch, netdev, mptcp, linux-kernel, syzbot+ff020673c5e3d94d9478
In-Reply-To: <20260504003156.11125-1-kartikey406@gmail.com>

Hi Deepanshu,

On 04/05/2026 02:31, Deepanshu Kartikey wrote:
> syzbot reported a KMSAN uninit-value in mptcp_write_data_fin() reached
> via tcp_send_ack() from the subflow shutdown path:
> 
>   BUG: KMSAN: uninit-value in mptcp_write_data_fin net/mptcp/options.c:542
>    mptcp_established_options_dss net/mptcp/options.c:590
>    mptcp_established_options net/mptcp/options.c:874
>    tcp_established_options net/ipv4/tcp_output.c:1192
>    __tcp_transmit_skb net/ipv4/tcp_output.c:1575
>    __tcp_send_ack net/ipv4/tcp_output.c:4499
>    tcp_send_ack net/ipv4/tcp_output.c:4505
>    mptcp_subflow_shutdown net/mptcp/protocol.c:3137
>    mptcp_check_send_data_fin net/mptcp/protocol.c:3218
>    __mptcp_wr_shutdown net/mptcp/protocol.c:3234
>    __mptcp_close net/mptcp/protocol.c:3313
> 
>   Local variable opts created at:
>    __tcp_transmit_skb net/ipv4/tcp_output.c:1536
> 
> __tcp_transmit_skb() partially clears its on-stack tcp_out_options via
> "memset(&opts.cleared, ...)" which does not cover opts.mptcp, so MPTCP
> is responsible for initializing opts->ext_copy before use.
> 
> mptcp_established_options_dss() only writes opts->ext_copy when an
> MPTCP extension is attached to the skb ("opts->ext_copy = *mpext").
> When tcp_send_ack() builds a fresh pure-ACK skb during subflow
> shutdown, the skb has no extension and that assignment is skipped, but
> the function still calls mptcp_write_data_fin(&opts->ext_copy) because
> snd_data_fin_enable is set. mptcp_write_data_fin() then reads
> ext->use_map to choose between writing a synthetic DATA_FIN mapping or
> extending an existing one, and that read hits uninitialized stack
> memory.
> 
> Zero opts->ext_copy at the top of mptcp_established_options_dss() so
> mptcp_write_data_fin() takes its synthetic-mapping branch on clean
> memory.
Thank you for sharing this patch!

Kuniyuki already shared the same patch on the MPTCP ML a few days ago:

https://lore.kernel.org/mptcp/20260501061939.1808489-1-kuniyu@google.com/T/#u

A v2 has been shared a few hours ago:

https://lore.kernel.org/mptcp/20260504044051.3725846-1-kuniyu@google.com/T/#u

(and apparently, a v3 will be needed)

Cheers,
Matt
-- 
pw-bot: Rejected
Sponsored by the NGI0 Core fund.


^ permalink raw reply

* RE: [PATCH net-next 12/15] ice: access @pp through netmem_desc instead of page
From: Loktionov, Aleksandr @ 2026-05-04  9:48 UTC (permalink / raw)
  To: Keller, Jacob E, Kitszel, Przemyslaw, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Lobakin, Aleksander, Simon Horman, Michal Swiatkowski,
	Jagielski, Jedrzej, Nitka, Grzegorz, Vecera, Ivan,
	Kubalewski, Arkadiusz, Nguyen, Anthony L, Wegrzyn, Stefan
  Cc: Kwapulinski, Piotr, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, Byungchul Park, Nowlin, Alexander,
	Rinitha, SX, David Hildenbrand (Arm)
In-Reply-To: <20260430-jk-iwl-net-next-2026-04-30-v1-12-6f27ae1cd073@intel.com>



> -----Original Message-----
> From: Keller, Jacob E <jacob.e.keller@intel.com>
> Sent: Friday, May 1, 2026 8:37 AM
> To: Kitszel, Przemyslaw <przemyslaw.kitszel@intel.com>; Andrew Lunn
> <andrew+netdev@lunn.ch>; David S. Miller <davem@davemloft.net>; Eric
> Dumazet <edumazet@google.com>; Jakub Kicinski <kuba@kernel.org>; Paolo
> Abeni <pabeni@redhat.com>; Lobakin, Aleksander
> <aleksander.lobakin@intel.com>; Simon Horman <horms@kernel.org>;
> Michal Swiatkowski <michal.swiatkowski@linux.intel.com>; Jagielski,
> Jedrzej <jedrzej.jagielski@intel.com>; Loktionov, Aleksandr
> <aleksandr.loktionov@intel.com>; Nitka, Grzegorz
> <grzegorz.nitka@intel.com>; Vecera, Ivan <ivecera@redhat.com>;
> Kubalewski, Arkadiusz <arkadiusz.kubalewski@intel.com>; Nguyen,
> Anthony L <anthony.l.nguyen@intel.com>; Wegrzyn, Stefan
> <stefan.wegrzyn@intel.com>
> Cc: Kwapulinski, Piotr <piotr.kwapulinski@intel.com>;
> netdev@vger.kernel.org; linux-kernel@vger.kernel.org; Keller, Jacob E
> <jacob.e.keller@intel.com>; Byungchul Park <byungchul@sk.com>; Nowlin,
> Alexander <alexander.nowlin@intel.com>; Rinitha, SX
> <sx.rinitha@intel.com>; David Hildenbrand (Arm) <david@kernel.org>
> Subject: [PATCH net-next 12/15] ice: access @pp through netmem_desc
> instead of page
> 
> From: Byungchul Park <byungchul@sk.com>
> 
> To eliminate the use of struct page in page pool, the page pool users
> should use netmem descriptor and APIs instead.
> 
> Make ice driver access @pp through netmem_desc instead of page.
> 
> Signed-off-by: Byungchul Park <byungchul@sk.com>
> Tested-by: Alexander Nowlin <alexander.nowlin@intel.com>
> Tested-by: Rinitha S <sx.rinitha@intel.com>
> Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
> Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
> ---
>  drivers/net/ethernet/intel/ice/ice_ethtool.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c
> b/drivers/net/ethernet/intel/ice/ice_ethtool.c
> index f28416a707d7..236d293aba98 100644
> --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c
> +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c
> @@ -1251,7 +1251,7 @@ static int ice_lbtest_receive_frames(struct
> ice_rx_ring *rx_ring)
>  		rx_buf = &rx_ring->rx_fqes[i];
>  		page = __netmem_to_page(rx_buf->netmem);
>  		received_buf = page_address(page) + rx_buf->offset +
> -			       page->pp->p.offset;
> +			       pp_page_to_nmdesc(page)->pp->p.offset;
> 
>  		if (ice_lbtest_check_frame(received_buf))
>  			valid_frames++;
> 
> --
> 2.54.0.rc2.531.gaf818d63126a

Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>

^ permalink raw reply

* Re: [PATCH v4 04/15] firmware: qcom: Add a PAS TEE service
From: Harshal Dev @ 2026-05-04 10:03 UTC (permalink / raw)
  To: Sumit Garg
  Cc: linux-arm-msm, devicetree, dri-devel, freedreno, linux-media,
	netdev, linux-wireless, ath12k, linux-remoteproc, robh, krzk+dt,
	conor+dt, robin.clark, sean, akhilpo, lumag, abhinav.kumar,
	jesszhan0024, marijn.suijten, airlied, simona, vikash.garodia,
	dikshita.agarwal, bod, mchehab, elder, andrew+netdev, davem,
	edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
	trilokkumar.soni, mukesh.ojha, pavan.kondeti, jorge.ramirez,
	tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
	op-tee, apurupa, skare, linux-kernel, Sumit Garg, Bjorn Andersson,
	Konrad Dybcio
In-Reply-To: <20260427095603.1157963-5-sumit.garg@kernel.org>

Hi Sumit,

On 4/27/2026 3:25 PM, Sumit Garg via OP-TEE wrote:
> From: Sumit Garg <sumit.garg@oss.qualcomm.com>
> 
> Add support for Peripheral Authentication Service (PAS) driver based
> on TEE bus with OP-TEE providing the backend PAS service implementation.
> 
> The TEE PAS service ABI is designed to be extensible with additional API
> as PTA_QCOM_PAS_CAPABILITIES. This allows to accommodate any future
> extensions of the PAS service needed while still maintaining backwards
> compatibility.
> 
> Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
> ---
>  drivers/firmware/qcom/Kconfig        |  10 +
>  drivers/firmware/qcom/Makefile       |   1 +
>  drivers/firmware/qcom/qcom_pas_tee.c | 479 +++++++++++++++++++++++++++
>  3 files changed, 490 insertions(+)
>  create mode 100644 drivers/firmware/qcom/qcom_pas_tee.c

[...]

> diff --git a/drivers/firmware/qcom/qcom_pas_tee.c b/drivers/firmware/qcom/qcom_pas_tee.c

> +static int qcom_pas_tee_mem_setup(struct device *dev, u32 pas_id,
> +				  phys_addr_t addr, phys_addr_t size)
> +{

[...]

> +
> +	ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
> +	if (ret < 0 || inv_arg.ret != 0) {
> +		dev_err(dev, "PAS mem setup failed, pas_id: %d, ret: %d, err: 0x%x\n",
> +			pas_id, ret, inv_arg.ret);
> +		return ret ?: -EINVAL;

Following the example from qcom_scm_pas_mem_setup() here:
https://elixir.bootlin.com/linux/v7.0.1/source/drivers/firmware/qcom/qcom_scm.c#L778

I think it should be:
return ret ?: inv_arg.ret;

This way the client (say mdt_loader) knows what error OPTEE PAS service returned.
I can see that is tries to print this error:
https://elixir.bootlin.com/linux/v7.0.1/source/drivers/soc/qcom/mdt_loader.c#L286

With that,
Reviewed-by: Harshal Dev <harshal.dev@oss.qualcomm.com>

Regards,
Harshal

^ permalink raw reply

* Re: [PATCH net] net/sched: sch_sfq: annotate data-races from sfq_dump_class_stats()
From: Eric Dumazet @ 2026-05-04 10:03 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, Jamal Hadi Salim, Jiri Pirko, netdev, eric.dumazet
In-Reply-To: <20260504055558.3470994-1-edumazet@google.com>

On Sun, May 3, 2026 at 10:55 PM Eric Dumazet <edumazet@google.com> wrote:
>
> sfq_dump_class_stats() runs locklessly, add needed READ_ONCE()
> and WRITE_ONCE() annotations.
>
> Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump")
> Signed-off-by: Eric Dumazet <edumazet@google.com>
> ---
>  net/sched/sch_sfq.c | 48 +++++++++++++++++++++++----------------------
>  1 file changed, 25 insertions(+), 23 deletions(-)
>
> diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
> index c3f3181dba5424eb9d26362a1628653bb9392e89..bf55e3d71ef4da24eaa5a73444c14d809268ef54 100644
> --- a/net/sched/sch_sfq.c
> +++ b/net/sched/sch_sfq.c
> @@ -225,7 +225,8 @@ static inline void sfq_dec(struct sfq_sched_data *q, sfq_index x)
>
>         sfq_unlink(q, x, n, p);
>
> -       d = q->slots[x].qlen--;
> +       d = q->slots[x].qlen - 1;
> +       WRITE_ONCE(q->slots[x].qlen, d);
>         if (n == p && q->cur_depth == d)

Oh well, silly bug. I will fix in V2

This should have been:

-       d = q->slots[x].qlen--;
+       d = q->slots[x].qlen;
+       WRITE_ONCE(q->slots[x].qlen, d - 1);

^ permalink raw reply

* Re: [PATCH net] net/sched: sch_fq_codel: annotate data-races from fq_codel_dump_class_stats()
From: Eric Dumazet @ 2026-05-04 10:06 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, Jamal Hadi Salim, Jiri Pirko, netdev, eric.dumazet
In-Reply-To: <20260503170257.2782962-1-edumazet@google.com>

On Sun, May 3, 2026 at 10:02 AM Eric Dumazet <edumazet@google.com> wrote:
>
> fq_codel_dump_class_stats() acquires qdisc spinlock only when requested
> to follow flow->head chain.
>
> As we did in sch_cake recently, add the missing READ_ONCE()/WRITE_ONCE()
> annotations.
>
> Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump")
> Signed-off-by: Eric Dumazet <edumazet@google.com>
> ---
>  net/sched/sch_fq_codel.c | 37 +++++++++++++++++++------------------
>  1 file changed, 19 insertions(+), 18 deletions(-)
>
> diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c
> index 0664b2f2d6f28041e5250a44fc92311116ae0cf1..f52198ea849b0cc966b455905a62d6c413441260 100644
> --- a/net/sched/sch_fq_codel.c
> +++ b/net/sched/sch_fq_codel.c
> @@ -117,7 +117,7 @@ static inline struct sk_buff *dequeue_head(struct fq_codel_flow *flow)
>  {
>         struct sk_buff *skb = flow->head;
>
> -       flow->head = skb->next;
> +       WRITE_ONCE(flow->head, skb->next);
>         skb_mark_not_on_list(skb);
>         return skb;
>  }
> @@ -127,7 +127,7 @@ static inline void flow_queue_add(struct fq_codel_flow *flow,
>                                   struct sk_buff *skb)
>  {
>         if (flow->head == NULL)
> -               flow->head = skb;
> +               WRITE_ONCE(flow->head, skb);
>         else
>                 flow->tail->next = skb;
>         flow->tail = skb;
> @@ -174,7 +174,7 @@ static unsigned int fq_codel_drop(struct Qdisc *sch, unsigned int max_packets,
>
>         /* Tell codel to increase its signal strength also */
>         flow->cvars.count += i;

I missed this also needs:

WRITE_ONCE(flow->cvars.count, flow->cvars.count + i);

I will fix this in a V2

pw-bot: cr

^ permalink raw reply

* [PATCH v4 0/2] pinctrl: qcom: add support for the TLMM controller on Nord platforms
From: Bartosz Golaszewski @ 2026-05-04 10:07 UTC (permalink / raw)
  To: Bjorn Andersson, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Richard Cochran, Bartosz Golaszewski, Shawn Guo,
	Arnd Bergmann, Dmitry Baryshkov
  Cc: linux-arm-msm, linux-gpio, devicetree, linux-kernel, netdev,
	Bartosz Golaszewski, Krzysztof Kozlowski, Maulik Shah,
	Pankaj Patil

This adds DT bindings describing the TLMM controller on Qualcomm Nord
platforms and implements the pinctrl driver.

More info on the platform here:
    https://lore.kernel.org/all/20260427003531.229671-1-shengchao.guo@oss.qualcomm.com/

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
Changes in v4:
- Move MODULE_DEVICE_TABLE() to the bottom of the file for consistency
  with the rest of the Qualcomm drivers
- Make the module description uniform with other Qualcomm drivers
- Collected tags
- Link to v3: https://patch.msgid.link/20260428-nord-tlmm-v3-0-f16f08d084cc@oss.qualcomm.com

Changes in v3:
- Unify even more fine-grained pin functions into larger groups
- Fix the UFS_RESET() implementation and use correct offset for the IO
  register
- Don't use uppercase hex numbers
- Make usage of the vendor name consistent with recent changes
- Make the driver default to ARCH_QCOM
- Link to v2: https://patch.msgid.link/20260427-nord-tlmm-v2-0-ade8e0f3d803@oss.qualcomm.com

Changes in v2:
- Order Kconfig entries alphabetically
- Fix the regex for the pin state pattern
- Fix maxItems for gpio-line-names
- Drop unneeded line break from bindings
- Rework the pin function naming to make resulting state entries in
  devicetree more concise (drop the line number suffix)
- drop .intr_target_reg from PINGROUP()
- fix values for interrupt entries in PINGROUP()
- drop unused SDC_QDSD_PINGROUP() and QUP_I3C()
- drop the arm64 defconfig updates from series
- rebased on top of v7.1-rc1
- Link to v1: https://patch.msgid.link/20260403-nord-tlmm-v1-0-4864f400c700@oss.qualcomm.com

---
Bartosz Golaszewski (2):
      dt-bindings: pinctrl: describe the Qualcomm nord-tlmm
      pinctrl: qcom: add the TLMM driver for the Nord platforms

 .../bindings/pinctrl/qcom,nord-tlmm.yaml           |  141 ++
 drivers/pinctrl/qcom/Kconfig.msm                   |    8 +
 drivers/pinctrl/qcom/Makefile                      |    1 +
 drivers/pinctrl/qcom/pinctrl-nord.c                | 1771 ++++++++++++++++++++
 4 files changed, 1921 insertions(+)
---
base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
change-id: 20260403-nord-tlmm-b5878960cec6

Best regards,
-- 
Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>


^ permalink raw reply

* [PATCH v4 1/2] dt-bindings: pinctrl: describe the Qualcomm nord-tlmm
From: Bartosz Golaszewski @ 2026-05-04 10:07 UTC (permalink / raw)
  To: Bjorn Andersson, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Richard Cochran, Bartosz Golaszewski, Shawn Guo,
	Arnd Bergmann, Dmitry Baryshkov
  Cc: linux-arm-msm, linux-gpio, devicetree, linux-kernel, netdev,
	Bartosz Golaszewski, Krzysztof Kozlowski
In-Reply-To: <20260504-nord-tlmm-v4-0-ccaa731ee8b3@oss.qualcomm.com>

Add a DT binding document describing the TLMM pin controller available
on the Nord platforms from Qualcomm.

Co-developed-by: Shawn Guo <shengchao.guo@oss.qualcomm.com>
Signed-off-by: Shawn Guo <shengchao.guo@oss.qualcomm.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
 .../bindings/pinctrl/qcom,nord-tlmm.yaml           | 141 +++++++++++++++++++++
 1 file changed, 141 insertions(+)

diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,nord-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,nord-tlmm.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..4bb511719f3130fc208011b4a8b45f4cfcde8c9b
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,nord-tlmm.yaml
@@ -0,0 +1,141 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/qcom,nord-tlmm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Technologies, Inc. SA8797P TLMM block
+
+maintainers:
+  - Bartosz Golaszewski <brgl@kernel.org>
+
+description:
+  Top Level Mode Multiplexer pin controller in Qualcomm SA8797P SoC.
+
+allOf:
+  - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml#
+
+properties:
+  compatible:
+    const: qcom,nord-tlmm
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  gpio-reserved-ranges:
+    minItems: 1
+    maxItems: 90
+
+  gpio-line-names:
+    maxItems: 181
+
+patternProperties:
+  "-state$":
+    oneOf:
+      - $ref: "#/$defs/qcom-nord-tlmm-state"
+      - patternProperties:
+          "-pins$":
+            $ref: "#/$defs/qcom-nord-tlmm-state"
+        additionalProperties: false
+
+$defs:
+  qcom-nord-tlmm-state:
+    type: object
+    description:
+      Pinctrl node's client devices use subnodes for desired pin configuration.
+      Client device subnodes use below standard properties.
+    $ref: qcom,tlmm-common.yaml#/$defs/qcom-tlmm-state
+    unevaluatedProperties: false
+
+    properties:
+      pins:
+        description:
+          List of gpio pins affected by the properties specified in this
+          subnode.
+        items:
+          oneOf:
+            - pattern: "^gpio([0-9]|[1-9][0-9]|1[0-7][0-9]|180)$"
+            - enum: [ ufs_reset ]
+        minItems: 1
+        maxItems: 16
+
+      function:
+        description:
+          Specify the alternative function to be configured for the specified
+          pins.
+
+        enum: [ aoss_cti, atest_char, atest_usb20, atest_usb21,
+                aud_intfc0_clk, aud_intfc0_data, aud_intfc0_ws,
+                aud_intfc10_clk, aud_intfc10_data, aud_intfc10_ws,
+                aud_intfc1_clk, aud_intfc1_data, aud_intfc1_ws,
+                aud_intfc2_clk, aud_intfc2_data, aud_intfc2_ws,
+                aud_intfc3_clk, aud_intfc3_data, aud_intfc3_ws,
+                aud_intfc4_clk, aud_intfc4_data, aud_intfc4_ws,
+                aud_intfc5_clk, aud_intfc5_data, aud_intfc5_ws,
+                aud_intfc6_clk, aud_intfc6_data, aud_intfc6_ws,
+                aud_intfc7_clk, aud_intfc7_data, aud_intfc7_ws,
+                aud_intfc8_clk, aud_intfc8_data, aud_intfc8_ws,
+                aud_intfc9_clk, aud_intfc9_data, aud_intfc9_ws,
+                aud_mclk0_mira, aud_mclk0_mirb, aud_mclk1_mira, aud_mclk1_mirb,
+                aud_mclk2_mira, aud_mclk2_mirb, aud_refclk0, aud_refclk1,
+                bist_done, ccu_async_in, ccu_i2c_scl, ccu_i2c_sda, ccu_timer,
+                clink_debug, dbg_out, dbg_out_clk,
+                ddr_bist_complete, ddr_bist_fail, ddr_bist_start, ddr_bist_stop,
+                ddr_pxi, dp_rx0, dp_rx00, dp_rx01, dp_rx0_mute, dp_rx1, dp_rx10,
+                dp_rx11, dp_rx1_mute,
+                edp0_hot, edp0_lcd, edp1_hot, edp1_lcd, edp2_hot, edp2_lcd,
+                edp3_hot, edp3_lcd,
+                emac0_mcg, emac0_mdc, emac0_mdio, emac0_ptp, emac1_mcg,
+                emac1_mdc, emac1_mdio, emac1_ptp,
+                gcc_gp1_clk, gcc_gp2_clk, gcc_gp3_clk, gcc_gp4_clk, gcc_gp5_clk,
+                gcc_gp6_clk, gcc_gp7_clk, gcc_gp8_clk, jitter_bist, lbist_pass,
+                mbist_pass, mdp0_vsync_out, mdp1_vsync_out, mdp_vsync_e,
+                mdp_vsync_p, mdp_vsync_s,
+                pcie0_clk_req_n, pcie1_clk_req_n, pcie2_clk_req_n,
+                pcie3_clk_req_n, phase_flag, pll_bist_sync, pll_clk_aux,
+                prng_rosc0, prng_rosc1, pwrbrk_i_n, qdss, qdss_cti, qspi,
+                qup0_se0, qup0_se1, qup0_se2, qup0_se3, qup0_se4, qup0_se5,
+                qup1_se0, qup1_se1, qup1_se3, qup1_se2, qup1_se4, qup1_se5,
+                qup1_se6, qup2_se0, qup2_se1, qup2_se2, qup2_se3, qup2_se4,
+                qup2_se5, qup2_se6,
+                sailss_ospi, sdc4_clk, sdc4_cmd, sdc4_data, smb_alert,
+                smb_alert_n, smb_clk, smb_dat, tb_trig_sdc4, tmess_prng0,
+                tmess_prng1, tsc_timer, tsense_pwm, usb0_hs,
+                usb0_phy_ps, usb1_hs, usb1_phy_ps, usb2_hs, usxgmii0_phy,
+                usxgmii1_phy, vsense_trigger_mirnat, wcn_sw, wcn_sw_ctrl]
+
+    required:
+      - pins
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    tlmm: pinctrl@f100000 {
+        compatible = "qcom,nord-tlmm";
+        reg = <0x0f100000 0xc0000>;
+        interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
+        gpio-controller;
+        #gpio-cells = <2>;
+        interrupt-controller;
+        #interrupt-cells = <2>;
+        gpio-ranges = <&tlmm 0 0 181>;
+        wakeup-parent = <&pdc>;
+
+        qup_uart15_default: qup-uart15-default-state {
+            pins = "gpio147", "gpio148";
+            function = "qup2_se2";
+            drive-strength = <2>;
+            bias-disable;
+        };
+    };
+...

-- 
2.47.3


^ permalink raw reply related

* [PATCH v4 2/2] pinctrl: qcom: add the TLMM driver for the Nord platforms
From: Bartosz Golaszewski @ 2026-05-04 10:07 UTC (permalink / raw)
  To: Bjorn Andersson, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Richard Cochran, Bartosz Golaszewski, Shawn Guo,
	Arnd Bergmann, Dmitry Baryshkov
  Cc: linux-arm-msm, linux-gpio, devicetree, linux-kernel, netdev,
	Bartosz Golaszewski, Maulik Shah, Pankaj Patil
In-Reply-To: <20260504-nord-tlmm-v4-0-ccaa731ee8b3@oss.qualcomm.com>

Add support for the TLMM controller on the Qualcomm Nord platform.

Co-developed-by: Shawn Guo <shengchao.guo@oss.qualcomm.com>
Signed-off-by: Shawn Guo <shengchao.guo@oss.qualcomm.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Maulik Shah <maulik.shah@oss.qualcomm.com>
Reviewed-by: Pankaj Patil <pankaj.patil@oss.qualcomm.com>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
 drivers/pinctrl/qcom/Kconfig.msm    |    8 +
 drivers/pinctrl/qcom/Makefile       |    1 +
 drivers/pinctrl/qcom/pinctrl-nord.c | 1771 +++++++++++++++++++++++++++++++++++
 3 files changed, 1780 insertions(+)

diff --git a/drivers/pinctrl/qcom/Kconfig.msm b/drivers/pinctrl/qcom/Kconfig.msm
index 836cdeca1006ff7ad5030ac5c537d775d3f0261b..6d63b3302df1d218436ab599584ba4619e8502d3 100644
--- a/drivers/pinctrl/qcom/Kconfig.msm
+++ b/drivers/pinctrl/qcom/Kconfig.msm
@@ -229,6 +229,14 @@ config PINCTRL_MSM8998
 	  This is the pinctrl, pinmux, pinconf and gpiolib driver for the
 	  Qualcomm TLMM block found in the Qualcomm MSM8998 platform.
 
+config PINCTRL_NORD
+	tristate "Qualcomm Nord pin controller driver"
+	depends on ARM64 || COMPILE_TEST
+	default ARCH_QCOM
+	help
+	  This is the pinctrl, pinmux and pinconf driver for the Qualcomm
+	  TLMM block found on the Qualcomm NORD platforms.
+
 config PINCTRL_QCM2290
 	tristate "Qualcomm QCM2290 pin controller driver"
 	depends on ARM64 || COMPILE_TEST
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index 84bda3ada8749e89077c2d4d1065d0db0e4e4181..12e7a51ad894261a37b00dc5520484803ecb8607 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_PINCTRL_MDM9607)	+= pinctrl-mdm9607.o
 obj-$(CONFIG_PINCTRL_MDM9615)	+= pinctrl-mdm9615.o
 obj-$(CONFIG_PINCTRL_MILOS) += pinctrl-milos.o
 obj-$(CONFIG_PINCTRL_MILOS_LPASS_LPI) += pinctrl-milos-lpass-lpi.o
+obj-$(CONFIG_PINCTRL_NORD)	+= pinctrl-nord.o
 obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-gpio.o
 obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-mpp.o
 obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-gpio.o
diff --git a/drivers/pinctrl/qcom/pinctrl-nord.c b/drivers/pinctrl/qcom/pinctrl-nord.c
new file mode 100644
index 0000000000000000000000000000000000000000..f14361101bf49b985f3fde3e991050a6162a3ac2
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-nord.c
@@ -0,0 +1,1771 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-msm.h"
+
+#define REG_SIZE 0x1000
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11)    \
+	{                                                             \
+		.grp = PINCTRL_PINGROUP("gpio" #id,                   \
+					gpio##id##_pins,              \
+					ARRAY_SIZE(gpio##id##_pins)), \
+		.ctl_reg = REG_SIZE * id,                             \
+		.io_reg = 0x4 + REG_SIZE * id,                        \
+		.intr_cfg_reg = 0x8 + REG_SIZE * id,                  \
+		.intr_status_reg = 0xc + REG_SIZE * id,               \
+		.mux_bit = 2,                                         \
+		.pull_bit = 0,                                        \
+		.drv_bit = 6,                                         \
+		.egpio_enable = 12,                                   \
+		.egpio_present = 11,                                  \
+		.oe_bit = 9,                                          \
+		.in_bit = 0,                                          \
+		.out_bit = 1,                                         \
+		.intr_enable_bit = 0,                                 \
+		.intr_status_bit = 0,                                 \
+		.intr_wakeup_present_bit = 6,                         \
+		.intr_wakeup_enable_bit = 7,                          \
+		.intr_target_bit = 8,                                 \
+		.intr_target_kpss_val = 3,                            \
+		.intr_raw_status_bit = 4,                             \
+		.intr_polarity_bit = 1,                               \
+		.intr_detection_bit = 2,                              \
+		.intr_detection_width = 2,                            \
+		.funcs = (int[]){                                     \
+			msm_mux_gpio, /* gpio mode */                 \
+			msm_mux_##f1,                                 \
+			msm_mux_##f2,                                 \
+			msm_mux_##f3,                                 \
+			msm_mux_##f4,                                 \
+			msm_mux_##f5,                                 \
+			msm_mux_##f6,                                 \
+			msm_mux_##f7,                                 \
+			msm_mux_##f8,                                 \
+			msm_mux_##f9,                                 \
+			msm_mux_##f10,                                \
+			msm_mux_##f11 /* egpio mode */                \
+		},                                                    \
+		.nfuncs = 12,                                         \
+	}
+
+#define UFS_RESET(pg_name, ctl, io)                                  \
+	{                                                            \
+		.grp = PINCTRL_PINGROUP(#pg_name,                    \
+					pg_name##_pins,              \
+					ARRAY_SIZE(pg_name##_pins)), \
+		.ctl_reg = ctl,                                      \
+		.io_reg = io,                                        \
+		.intr_cfg_reg = 0,                                   \
+		.intr_status_reg = 0,                                \
+		.mux_bit = -1,                                       \
+		.pull_bit = 3,                                       \
+		.drv_bit = 0,                                        \
+		.oe_bit = -1,                                        \
+		.in_bit = -1,                                        \
+		.out_bit = 0,                                        \
+		.intr_enable_bit = -1,                               \
+		.intr_status_bit = -1,                               \
+		.intr_target_bit = -1,                               \
+		.intr_raw_status_bit = -1,                           \
+		.intr_polarity_bit = -1,                             \
+		.intr_detection_bit = -1,                            \
+		.intr_detection_width = -1,                          \
+	}
+
+static const struct pinctrl_pin_desc nord_pins[] = {
+	PINCTRL_PIN(0, "GPIO_0"),
+	PINCTRL_PIN(1, "GPIO_1"),
+	PINCTRL_PIN(2, "GPIO_2"),
+	PINCTRL_PIN(3, "GPIO_3"),
+	PINCTRL_PIN(4, "GPIO_4"),
+	PINCTRL_PIN(5, "GPIO_5"),
+	PINCTRL_PIN(6, "GPIO_6"),
+	PINCTRL_PIN(7, "GPIO_7"),
+	PINCTRL_PIN(8, "GPIO_8"),
+	PINCTRL_PIN(9, "GPIO_9"),
+	PINCTRL_PIN(10, "GPIO_10"),
+	PINCTRL_PIN(11, "GPIO_11"),
+	PINCTRL_PIN(12, "GPIO_12"),
+	PINCTRL_PIN(13, "GPIO_13"),
+	PINCTRL_PIN(14, "GPIO_14"),
+	PINCTRL_PIN(15, "GPIO_15"),
+	PINCTRL_PIN(16, "GPIO_16"),
+	PINCTRL_PIN(17, "GPIO_17"),
+	PINCTRL_PIN(18, "GPIO_18"),
+	PINCTRL_PIN(19, "GPIO_19"),
+	PINCTRL_PIN(20, "GPIO_20"),
+	PINCTRL_PIN(21, "GPIO_21"),
+	PINCTRL_PIN(22, "GPIO_22"),
+	PINCTRL_PIN(23, "GPIO_23"),
+	PINCTRL_PIN(24, "GPIO_24"),
+	PINCTRL_PIN(25, "GPIO_25"),
+	PINCTRL_PIN(26, "GPIO_26"),
+	PINCTRL_PIN(27, "GPIO_27"),
+	PINCTRL_PIN(28, "GPIO_28"),
+	PINCTRL_PIN(29, "GPIO_29"),
+	PINCTRL_PIN(30, "GPIO_30"),
+	PINCTRL_PIN(31, "GPIO_31"),
+	PINCTRL_PIN(32, "GPIO_32"),
+	PINCTRL_PIN(33, "GPIO_33"),
+	PINCTRL_PIN(34, "GPIO_34"),
+	PINCTRL_PIN(35, "GPIO_35"),
+	PINCTRL_PIN(36, "GPIO_36"),
+	PINCTRL_PIN(37, "GPIO_37"),
+	PINCTRL_PIN(38, "GPIO_38"),
+	PINCTRL_PIN(39, "GPIO_39"),
+	PINCTRL_PIN(40, "GPIO_40"),
+	PINCTRL_PIN(41, "GPIO_41"),
+	PINCTRL_PIN(42, "GPIO_42"),
+	PINCTRL_PIN(43, "GPIO_43"),
+	PINCTRL_PIN(44, "GPIO_44"),
+	PINCTRL_PIN(45, "GPIO_45"),
+	PINCTRL_PIN(46, "GPIO_46"),
+	PINCTRL_PIN(47, "GPIO_47"),
+	PINCTRL_PIN(48, "GPIO_48"),
+	PINCTRL_PIN(49, "GPIO_49"),
+	PINCTRL_PIN(50, "GPIO_50"),
+	PINCTRL_PIN(51, "GPIO_51"),
+	PINCTRL_PIN(52, "GPIO_52"),
+	PINCTRL_PIN(53, "GPIO_53"),
+	PINCTRL_PIN(54, "GPIO_54"),
+	PINCTRL_PIN(55, "GPIO_55"),
+	PINCTRL_PIN(56, "GPIO_56"),
+	PINCTRL_PIN(57, "GPIO_57"),
+	PINCTRL_PIN(58, "GPIO_58"),
+	PINCTRL_PIN(59, "GPIO_59"),
+	PINCTRL_PIN(60, "GPIO_60"),
+	PINCTRL_PIN(61, "GPIO_61"),
+	PINCTRL_PIN(62, "GPIO_62"),
+	PINCTRL_PIN(63, "GPIO_63"),
+	PINCTRL_PIN(64, "GPIO_64"),
+	PINCTRL_PIN(65, "GPIO_65"),
+	PINCTRL_PIN(66, "GPIO_66"),
+	PINCTRL_PIN(67, "GPIO_67"),
+	PINCTRL_PIN(68, "GPIO_68"),
+	PINCTRL_PIN(69, "GPIO_69"),
+	PINCTRL_PIN(70, "GPIO_70"),
+	PINCTRL_PIN(71, "GPIO_71"),
+	PINCTRL_PIN(72, "GPIO_72"),
+	PINCTRL_PIN(73, "GPIO_73"),
+	PINCTRL_PIN(74, "GPIO_74"),
+	PINCTRL_PIN(75, "GPIO_75"),
+	PINCTRL_PIN(76, "GPIO_76"),
+	PINCTRL_PIN(77, "GPIO_77"),
+	PINCTRL_PIN(78, "GPIO_78"),
+	PINCTRL_PIN(79, "GPIO_79"),
+	PINCTRL_PIN(80, "GPIO_80"),
+	PINCTRL_PIN(81, "GPIO_81"),
+	PINCTRL_PIN(82, "GPIO_82"),
+	PINCTRL_PIN(83, "GPIO_83"),
+	PINCTRL_PIN(84, "GPIO_84"),
+	PINCTRL_PIN(85, "GPIO_85"),
+	PINCTRL_PIN(86, "GPIO_86"),
+	PINCTRL_PIN(87, "GPIO_87"),
+	PINCTRL_PIN(88, "GPIO_88"),
+	PINCTRL_PIN(89, "GPIO_89"),
+	PINCTRL_PIN(90, "GPIO_90"),
+	PINCTRL_PIN(91, "GPIO_91"),
+	PINCTRL_PIN(92, "GPIO_92"),
+	PINCTRL_PIN(93, "GPIO_93"),
+	PINCTRL_PIN(94, "GPIO_94"),
+	PINCTRL_PIN(95, "GPIO_95"),
+	PINCTRL_PIN(96, "GPIO_96"),
+	PINCTRL_PIN(97, "GPIO_97"),
+	PINCTRL_PIN(98, "GPIO_98"),
+	PINCTRL_PIN(99, "GPIO_99"),
+	PINCTRL_PIN(100, "GPIO_100"),
+	PINCTRL_PIN(101, "GPIO_101"),
+	PINCTRL_PIN(102, "GPIO_102"),
+	PINCTRL_PIN(103, "GPIO_103"),
+	PINCTRL_PIN(104, "GPIO_104"),
+	PINCTRL_PIN(105, "GPIO_105"),
+	PINCTRL_PIN(106, "GPIO_106"),
+	PINCTRL_PIN(107, "GPIO_107"),
+	PINCTRL_PIN(108, "GPIO_108"),
+	PINCTRL_PIN(109, "GPIO_109"),
+	PINCTRL_PIN(110, "GPIO_110"),
+	PINCTRL_PIN(111, "GPIO_111"),
+	PINCTRL_PIN(112, "GPIO_112"),
+	PINCTRL_PIN(113, "GPIO_113"),
+	PINCTRL_PIN(114, "GPIO_114"),
+	PINCTRL_PIN(115, "GPIO_115"),
+	PINCTRL_PIN(116, "GPIO_116"),
+	PINCTRL_PIN(117, "GPIO_117"),
+	PINCTRL_PIN(118, "GPIO_118"),
+	PINCTRL_PIN(119, "GPIO_119"),
+	PINCTRL_PIN(120, "GPIO_120"),
+	PINCTRL_PIN(121, "GPIO_121"),
+	PINCTRL_PIN(122, "GPIO_122"),
+	PINCTRL_PIN(123, "GPIO_123"),
+	PINCTRL_PIN(124, "GPIO_124"),
+	PINCTRL_PIN(125, "GPIO_125"),
+	PINCTRL_PIN(126, "GPIO_126"),
+	PINCTRL_PIN(127, "GPIO_127"),
+	PINCTRL_PIN(128, "GPIO_128"),
+	PINCTRL_PIN(129, "GPIO_129"),
+	PINCTRL_PIN(130, "GPIO_130"),
+	PINCTRL_PIN(131, "GPIO_131"),
+	PINCTRL_PIN(132, "GPIO_132"),
+	PINCTRL_PIN(133, "GPIO_133"),
+	PINCTRL_PIN(134, "GPIO_134"),
+	PINCTRL_PIN(135, "GPIO_135"),
+	PINCTRL_PIN(136, "GPIO_136"),
+	PINCTRL_PIN(137, "GPIO_137"),
+	PINCTRL_PIN(138, "GPIO_138"),
+	PINCTRL_PIN(139, "GPIO_139"),
+	PINCTRL_PIN(140, "GPIO_140"),
+	PINCTRL_PIN(141, "GPIO_141"),
+	PINCTRL_PIN(142, "GPIO_142"),
+	PINCTRL_PIN(143, "GPIO_143"),
+	PINCTRL_PIN(144, "GPIO_144"),
+	PINCTRL_PIN(145, "GPIO_145"),
+	PINCTRL_PIN(146, "GPIO_146"),
+	PINCTRL_PIN(147, "GPIO_147"),
+	PINCTRL_PIN(148, "GPIO_148"),
+	PINCTRL_PIN(149, "GPIO_149"),
+	PINCTRL_PIN(150, "GPIO_150"),
+	PINCTRL_PIN(151, "GPIO_151"),
+	PINCTRL_PIN(152, "GPIO_152"),
+	PINCTRL_PIN(153, "GPIO_153"),
+	PINCTRL_PIN(154, "GPIO_154"),
+	PINCTRL_PIN(155, "GPIO_155"),
+	PINCTRL_PIN(156, "GPIO_156"),
+	PINCTRL_PIN(157, "GPIO_157"),
+	PINCTRL_PIN(158, "GPIO_158"),
+	PINCTRL_PIN(159, "GPIO_159"),
+	PINCTRL_PIN(160, "GPIO_160"),
+	PINCTRL_PIN(161, "GPIO_161"),
+	PINCTRL_PIN(162, "GPIO_162"),
+	PINCTRL_PIN(163, "GPIO_163"),
+	PINCTRL_PIN(164, "GPIO_164"),
+	PINCTRL_PIN(165, "GPIO_165"),
+	PINCTRL_PIN(166, "GPIO_166"),
+	PINCTRL_PIN(167, "GPIO_167"),
+	PINCTRL_PIN(168, "GPIO_168"),
+	PINCTRL_PIN(169, "GPIO_169"),
+	PINCTRL_PIN(170, "GPIO_170"),
+	PINCTRL_PIN(171, "GPIO_171"),
+	PINCTRL_PIN(172, "GPIO_172"),
+	PINCTRL_PIN(173, "GPIO_173"),
+	PINCTRL_PIN(174, "GPIO_174"),
+	PINCTRL_PIN(175, "GPIO_175"),
+	PINCTRL_PIN(176, "GPIO_176"),
+	PINCTRL_PIN(177, "GPIO_177"),
+	PINCTRL_PIN(178, "GPIO_178"),
+	PINCTRL_PIN(179, "GPIO_179"),
+	PINCTRL_PIN(180, "GPIO_180"),
+	PINCTRL_PIN(181, "UFS_RESET"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+	static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+DECLARE_MSM_GPIO_PINS(54);
+DECLARE_MSM_GPIO_PINS(55);
+DECLARE_MSM_GPIO_PINS(56);
+DECLARE_MSM_GPIO_PINS(57);
+DECLARE_MSM_GPIO_PINS(58);
+DECLARE_MSM_GPIO_PINS(59);
+DECLARE_MSM_GPIO_PINS(60);
+DECLARE_MSM_GPIO_PINS(61);
+DECLARE_MSM_GPIO_PINS(62);
+DECLARE_MSM_GPIO_PINS(63);
+DECLARE_MSM_GPIO_PINS(64);
+DECLARE_MSM_GPIO_PINS(65);
+DECLARE_MSM_GPIO_PINS(66);
+DECLARE_MSM_GPIO_PINS(67);
+DECLARE_MSM_GPIO_PINS(68);
+DECLARE_MSM_GPIO_PINS(69);
+DECLARE_MSM_GPIO_PINS(70);
+DECLARE_MSM_GPIO_PINS(71);
+DECLARE_MSM_GPIO_PINS(72);
+DECLARE_MSM_GPIO_PINS(73);
+DECLARE_MSM_GPIO_PINS(74);
+DECLARE_MSM_GPIO_PINS(75);
+DECLARE_MSM_GPIO_PINS(76);
+DECLARE_MSM_GPIO_PINS(77);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+DECLARE_MSM_GPIO_PINS(100);
+DECLARE_MSM_GPIO_PINS(101);
+DECLARE_MSM_GPIO_PINS(102);
+DECLARE_MSM_GPIO_PINS(103);
+DECLARE_MSM_GPIO_PINS(104);
+DECLARE_MSM_GPIO_PINS(105);
+DECLARE_MSM_GPIO_PINS(106);
+DECLARE_MSM_GPIO_PINS(107);
+DECLARE_MSM_GPIO_PINS(108);
+DECLARE_MSM_GPIO_PINS(109);
+DECLARE_MSM_GPIO_PINS(110);
+DECLARE_MSM_GPIO_PINS(111);
+DECLARE_MSM_GPIO_PINS(112);
+DECLARE_MSM_GPIO_PINS(113);
+DECLARE_MSM_GPIO_PINS(114);
+DECLARE_MSM_GPIO_PINS(115);
+DECLARE_MSM_GPIO_PINS(116);
+DECLARE_MSM_GPIO_PINS(117);
+DECLARE_MSM_GPIO_PINS(118);
+DECLARE_MSM_GPIO_PINS(119);
+DECLARE_MSM_GPIO_PINS(120);
+DECLARE_MSM_GPIO_PINS(121);
+DECLARE_MSM_GPIO_PINS(122);
+DECLARE_MSM_GPIO_PINS(123);
+DECLARE_MSM_GPIO_PINS(124);
+DECLARE_MSM_GPIO_PINS(125);
+DECLARE_MSM_GPIO_PINS(126);
+DECLARE_MSM_GPIO_PINS(127);
+DECLARE_MSM_GPIO_PINS(128);
+DECLARE_MSM_GPIO_PINS(129);
+DECLARE_MSM_GPIO_PINS(130);
+DECLARE_MSM_GPIO_PINS(131);
+DECLARE_MSM_GPIO_PINS(132);
+DECLARE_MSM_GPIO_PINS(133);
+DECLARE_MSM_GPIO_PINS(134);
+DECLARE_MSM_GPIO_PINS(135);
+DECLARE_MSM_GPIO_PINS(136);
+DECLARE_MSM_GPIO_PINS(137);
+DECLARE_MSM_GPIO_PINS(138);
+DECLARE_MSM_GPIO_PINS(139);
+DECLARE_MSM_GPIO_PINS(140);
+DECLARE_MSM_GPIO_PINS(141);
+DECLARE_MSM_GPIO_PINS(142);
+DECLARE_MSM_GPIO_PINS(143);
+DECLARE_MSM_GPIO_PINS(144);
+DECLARE_MSM_GPIO_PINS(145);
+DECLARE_MSM_GPIO_PINS(146);
+DECLARE_MSM_GPIO_PINS(147);
+DECLARE_MSM_GPIO_PINS(148);
+DECLARE_MSM_GPIO_PINS(149);
+DECLARE_MSM_GPIO_PINS(150);
+DECLARE_MSM_GPIO_PINS(151);
+DECLARE_MSM_GPIO_PINS(152);
+DECLARE_MSM_GPIO_PINS(153);
+DECLARE_MSM_GPIO_PINS(154);
+DECLARE_MSM_GPIO_PINS(155);
+DECLARE_MSM_GPIO_PINS(156);
+DECLARE_MSM_GPIO_PINS(157);
+DECLARE_MSM_GPIO_PINS(158);
+DECLARE_MSM_GPIO_PINS(159);
+DECLARE_MSM_GPIO_PINS(160);
+DECLARE_MSM_GPIO_PINS(161);
+DECLARE_MSM_GPIO_PINS(162);
+DECLARE_MSM_GPIO_PINS(163);
+DECLARE_MSM_GPIO_PINS(164);
+DECLARE_MSM_GPIO_PINS(165);
+DECLARE_MSM_GPIO_PINS(166);
+DECLARE_MSM_GPIO_PINS(167);
+DECLARE_MSM_GPIO_PINS(168);
+DECLARE_MSM_GPIO_PINS(169);
+DECLARE_MSM_GPIO_PINS(170);
+DECLARE_MSM_GPIO_PINS(171);
+DECLARE_MSM_GPIO_PINS(172);
+DECLARE_MSM_GPIO_PINS(173);
+DECLARE_MSM_GPIO_PINS(174);
+DECLARE_MSM_GPIO_PINS(175);
+DECLARE_MSM_GPIO_PINS(176);
+DECLARE_MSM_GPIO_PINS(177);
+DECLARE_MSM_GPIO_PINS(178);
+DECLARE_MSM_GPIO_PINS(179);
+DECLARE_MSM_GPIO_PINS(180);
+
+static const unsigned int ufs_reset_pins[] = { 181 };
+
+enum nord_functions {
+	msm_mux_gpio,
+	msm_mux_aoss_cti,
+	msm_mux_atest_char,
+	msm_mux_atest_usb20,
+	msm_mux_atest_usb21,
+	msm_mux_aud_intfc0_clk,
+	msm_mux_aud_intfc0_data,
+	msm_mux_aud_intfc0_ws,
+	msm_mux_aud_intfc10_clk,
+	msm_mux_aud_intfc10_data,
+	msm_mux_aud_intfc10_ws,
+	msm_mux_aud_intfc1_clk,
+	msm_mux_aud_intfc1_data,
+	msm_mux_aud_intfc1_ws,
+	msm_mux_aud_intfc2_clk,
+	msm_mux_aud_intfc2_data,
+	msm_mux_aud_intfc2_ws,
+	msm_mux_aud_intfc3_clk,
+	msm_mux_aud_intfc3_data,
+	msm_mux_aud_intfc3_ws,
+	msm_mux_aud_intfc4_clk,
+	msm_mux_aud_intfc4_data,
+	msm_mux_aud_intfc4_ws,
+	msm_mux_aud_intfc5_clk,
+	msm_mux_aud_intfc5_data,
+	msm_mux_aud_intfc5_ws,
+	msm_mux_aud_intfc6_clk,
+	msm_mux_aud_intfc6_data,
+	msm_mux_aud_intfc6_ws,
+	msm_mux_aud_intfc7_clk,
+	msm_mux_aud_intfc7_data,
+	msm_mux_aud_intfc7_ws,
+	msm_mux_aud_intfc8_clk,
+	msm_mux_aud_intfc8_data,
+	msm_mux_aud_intfc8_ws,
+	msm_mux_aud_intfc9_clk,
+	msm_mux_aud_intfc9_data,
+	msm_mux_aud_intfc9_ws,
+	msm_mux_aud_mclk0_mira,
+	msm_mux_aud_mclk0_mirb,
+	msm_mux_aud_mclk1_mira,
+	msm_mux_aud_mclk1_mirb,
+	msm_mux_aud_mclk2_mira,
+	msm_mux_aud_mclk2_mirb,
+	msm_mux_aud_refclk0,
+	msm_mux_aud_refclk1,
+	msm_mux_bist_done,
+	msm_mux_ccu_async_in,
+	msm_mux_ccu_i2c_scl,
+	msm_mux_ccu_i2c_sda,
+	msm_mux_ccu_timer,
+	msm_mux_clink_debug,
+	msm_mux_dbg_out,
+	msm_mux_dbg_out_clk,
+	msm_mux_ddr_bist_complete,
+	msm_mux_ddr_bist_fail,
+	msm_mux_ddr_bist_start,
+	msm_mux_ddr_bist_stop,
+	msm_mux_ddr_pxi,
+	msm_mux_dp_rx0,
+	msm_mux_dp_rx00,
+	msm_mux_dp_rx01,
+	msm_mux_dp_rx0_mute,
+	msm_mux_dp_rx1,
+	msm_mux_dp_rx10,
+	msm_mux_dp_rx11,
+	msm_mux_dp_rx1_mute,
+	msm_mux_edp0_hot,
+	msm_mux_edp0_lcd,
+	msm_mux_edp1_hot,
+	msm_mux_edp1_lcd,
+	msm_mux_edp2_hot,
+	msm_mux_edp2_lcd,
+	msm_mux_edp3_hot,
+	msm_mux_edp3_lcd,
+	msm_mux_emac0_mcg,
+	msm_mux_emac0_mdc,
+	msm_mux_emac0_mdio,
+	msm_mux_emac0_ptp,
+	msm_mux_emac1_mcg,
+	msm_mux_emac1_mdc,
+	msm_mux_emac1_mdio,
+	msm_mux_emac1_ptp,
+	msm_mux_gcc_gp1_clk,
+	msm_mux_gcc_gp2_clk,
+	msm_mux_gcc_gp3_clk,
+	msm_mux_gcc_gp4_clk,
+	msm_mux_gcc_gp5_clk,
+	msm_mux_gcc_gp6_clk,
+	msm_mux_gcc_gp7_clk,
+	msm_mux_gcc_gp8_clk,
+	msm_mux_jitter_bist,
+	msm_mux_lbist_pass,
+	msm_mux_mbist_pass,
+	msm_mux_mdp0_vsync_out,
+	msm_mux_mdp1_vsync_out,
+	msm_mux_mdp_vsync_e,
+	msm_mux_mdp_vsync_p,
+	msm_mux_mdp_vsync_s,
+	msm_mux_pcie0_clk_req_n,
+	msm_mux_pcie1_clk_req_n,
+	msm_mux_pcie2_clk_req_n,
+	msm_mux_pcie3_clk_req_n,
+	msm_mux_phase_flag,
+	msm_mux_pll_bist_sync,
+	msm_mux_pll_clk_aux,
+	msm_mux_prng_rosc0,
+	msm_mux_prng_rosc1,
+	msm_mux_pwrbrk_i_n,
+	msm_mux_qdss,
+	msm_mux_qdss_cti,
+	msm_mux_qspi,
+	msm_mux_qup0_se0,
+	msm_mux_qup0_se1,
+	msm_mux_qup0_se2,
+	msm_mux_qup0_se3,
+	msm_mux_qup0_se4,
+	msm_mux_qup0_se5,
+	msm_mux_qup1_se0,
+	msm_mux_qup1_se1,
+	msm_mux_qup1_se2,
+	msm_mux_qup1_se3,
+	msm_mux_qup1_se4,
+	msm_mux_qup1_se5,
+	msm_mux_qup1_se6,
+	msm_mux_qup2_se0,
+	msm_mux_qup2_se1,
+	msm_mux_qup2_se2,
+	msm_mux_qup2_se3,
+	msm_mux_qup2_se4,
+	msm_mux_qup2_se5,
+	msm_mux_qup2_se6,
+	msm_mux_qup3_se0_mira,
+	msm_mux_qup3_se0_mirb,
+	msm_mux_sailss_ospi,
+	msm_mux_sdc4_clk,
+	msm_mux_sdc4_cmd,
+	msm_mux_sdc4_data,
+	msm_mux_smb_alert,
+	msm_mux_smb_alert_n,
+	msm_mux_smb_clk,
+	msm_mux_smb_dat,
+	msm_mux_tb_trig_sdc4,
+	msm_mux_tmess_prng0,
+	msm_mux_tmess_prng1,
+	msm_mux_tsc_timer,
+	msm_mux_tsense_pwm,
+	msm_mux_usb0_hs,
+	msm_mux_usb0_phy_ps,
+	msm_mux_usb1_hs,
+	msm_mux_usb1_phy_ps,
+	msm_mux_usb2_hs,
+	msm_mux_usxgmii0_phy,
+	msm_mux_usxgmii1_phy,
+	msm_mux_vsense_trigger_mirnat,
+	msm_mux_wcn_sw,
+	msm_mux_wcn_sw_ctrl,
+	msm_mux__,
+};
+
+static const char *const gpio_groups[] = {
+	"gpio0",   "gpio1",   "gpio2",	 "gpio3",   "gpio4",   "gpio5",
+	"gpio6",   "gpio7",   "gpio8",	 "gpio9",   "gpio10",  "gpio11",
+	"gpio12",  "gpio13",  "gpio14",	 "gpio15",  "gpio16",  "gpio17",
+	"gpio18",  "gpio19",  "gpio20",	 "gpio21",  "gpio22",  "gpio23",
+	"gpio24",  "gpio25",  "gpio26",	 "gpio27",  "gpio28",  "gpio29",
+	"gpio30",  "gpio31",  "gpio32",	 "gpio33",  "gpio34",  "gpio35",
+	"gpio36",  "gpio37",  "gpio38",	 "gpio39",  "gpio40",  "gpio41",
+	"gpio42",  "gpio43",  "gpio44",	 "gpio45",  "gpio46",  "gpio47",
+	"gpio48",  "gpio49",  "gpio50",	 "gpio51",  "gpio52",  "gpio53",
+	"gpio54",  "gpio55",  "gpio56",	 "gpio57",  "gpio58",  "gpio59",
+	"gpio60",  "gpio61",  "gpio62",	 "gpio63",  "gpio64",  "gpio65",
+	"gpio66",  "gpio67",  "gpio68",	 "gpio69",  "gpio70",  "gpio71",
+	"gpio72",  "gpio73",  "gpio74",	 "gpio75",  "gpio76",  "gpio77",
+	"gpio78",  "gpio79",  "gpio80",	 "gpio81",  "gpio82",  "gpio83",
+	"gpio84",  "gpio85",  "gpio86",	 "gpio87",  "gpio88",  "gpio89",
+	"gpio90",  "gpio91",  "gpio92",	 "gpio93",  "gpio94",  "gpio95",
+	"gpio96",  "gpio97",  "gpio98",	 "gpio99",  "gpio100", "gpio101",
+	"gpio102", "gpio103", "gpio104", "gpio105", "gpio106", "gpio107",
+	"gpio108", "gpio109", "gpio110", "gpio111", "gpio112", "gpio113",
+	"gpio114", "gpio115", "gpio116", "gpio117", "gpio118", "gpio119",
+	"gpio120", "gpio121", "gpio122", "gpio123", "gpio124", "gpio125",
+	"gpio126", "gpio127", "gpio128", "gpio129", "gpio130", "gpio131",
+	"gpio132", "gpio133", "gpio134", "gpio135", "gpio136", "gpio137",
+	"gpio138", "gpio139", "gpio140", "gpio141", "gpio142", "gpio143",
+	"gpio144", "gpio145", "gpio146", "gpio147", "gpio148", "gpio149",
+	"gpio150", "gpio151", "gpio152", "gpio153", "gpio154", "gpio155",
+	"gpio156", "gpio157", "gpio158", "gpio159", "gpio160", "gpio161",
+	"gpio162", "gpio163", "gpio164", "gpio165", "gpio166", "gpio167",
+	"gpio168", "gpio169", "gpio170", "gpio171", "gpio172", "gpio173",
+	"gpio174", "gpio175", "gpio176", "gpio177", "gpio178", "gpio179",
+	"gpio180",
+};
+
+static const char *const aoss_cti_groups[] = {
+	"gpio83",
+	"gpio84",
+	"gpio85",
+	"gpio86",
+};
+
+static const char *const atest_char_groups[] = {
+	"gpio176", "gpio177", "gpio178", "gpio179", "gpio180",
+};
+
+static const char *const atest_usb20_groups[] = {
+	"gpio126",
+	"gpio128",
+	"gpio130",
+};
+
+static const char *const atest_usb21_groups[] = {
+	"gpio127",
+	"gpio129",
+	"gpio131",
+};
+
+static const char *const aud_intfc0_clk_groups[] = {
+	"gpio57",
+};
+
+static const char *const aud_intfc0_data_groups[] = {
+	"gpio59", "gpio60", "gpio61", "gpio62", "gpio63", "gpio64", "gpio65", "gpio66",
+};
+
+static const char *const aud_intfc0_ws_groups[] = {
+	"gpio58",
+};
+
+static const char *const aud_intfc10_clk_groups[] = {
+	"gpio61",
+};
+
+static const char *const aud_intfc10_data_groups[] = {
+	"gpio81", "gpio82",
+};
+
+static const char *const aud_intfc10_ws_groups[] = {
+	"gpio62",
+};
+
+static const char *const aud_intfc1_clk_groups[] = {
+	"gpio67",
+};
+
+static const char *const aud_intfc1_data_groups[] = {
+	"gpio69", "gpio70", "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76",
+};
+
+static const char *const aud_intfc1_ws_groups[] = {
+	"gpio68",
+};
+
+static const char *const aud_intfc2_clk_groups[] = {
+	"gpio77",
+};
+
+static const char *const aud_intfc2_data_groups[] = {
+	"gpio79", "gpio80", "gpio81", "gpio82",
+};
+
+static const char *const aud_intfc2_ws_groups[] = {
+	"gpio78",
+};
+
+static const char *const aud_intfc3_clk_groups[] = {
+	"gpio83",
+};
+
+static const char *const aud_intfc3_data_groups[] = {
+	"gpio85", "gpio86",
+};
+
+static const char *const aud_intfc3_ws_groups[] = {
+	"gpio84",
+};
+
+static const char *const aud_intfc4_clk_groups[] = {
+	"gpio87",
+};
+
+static const char *const aud_intfc4_data_groups[] = {
+	"gpio89", "gpio90",
+};
+
+static const char *const aud_intfc4_ws_groups[] = {
+	"gpio88",
+};
+
+static const char *const aud_intfc5_clk_groups[] = {
+	"gpio91",
+};
+
+static const char *const aud_intfc5_data_groups[] = {
+	"gpio93", "gpio94",
+};
+
+static const char *const aud_intfc5_ws_groups[] = {
+	"gpio92",
+};
+
+static const char *const aud_intfc6_clk_groups[] = {
+	"gpio95",
+};
+
+static const char *const aud_intfc6_data_groups[] = {
+	"gpio97", "gpio98",
+};
+
+static const char *const aud_intfc6_ws_groups[] = {
+	"gpio96",
+};
+
+static const char *const aud_intfc7_clk_groups[] = {
+	"gpio63",
+};
+
+static const char *const aud_intfc7_data_groups[] = {
+	"gpio65", "gpio66",
+};
+
+static const char *const aud_intfc7_ws_groups[] = {
+	"gpio64",
+};
+
+static const char *const aud_intfc8_clk_groups[] = {
+	"gpio73",
+};
+
+static const char *const aud_intfc8_data_groups[] = {
+	"gpio75", "gpio76",
+};
+
+static const char *const aud_intfc8_ws_groups[] = {
+	"gpio74",
+};
+
+static const char *const aud_intfc9_clk_groups[] = {
+	"gpio70",
+};
+
+static const char *const aud_intfc9_data_groups[] = {
+	"gpio72",
+};
+
+static const char *const aud_intfc9_ws_groups[] = {
+	"gpio71",
+};
+
+static const char *const aud_mclk0_mira_groups[] = {
+	"gpio99",
+};
+
+static const char *const aud_mclk0_mirb_groups[] = {
+	"gpio86",
+};
+
+static const char *const aud_mclk1_mira_groups[] = {
+	"gpio100",
+};
+
+static const char *const aud_mclk1_mirb_groups[] = {
+	"gpio90",
+};
+
+static const char *const aud_mclk2_mira_groups[] = {
+	"gpio101",
+};
+
+static const char *const aud_mclk2_mirb_groups[] = {
+	"gpio94",
+};
+
+static const char *const aud_refclk0_groups[] = {
+	"gpio100",
+};
+
+static const char *const aud_refclk1_groups[] = {
+	"gpio101",
+};
+
+static const char *const bist_done_groups[] = {
+	"gpio168",
+};
+
+static const char *const ccu_async_in_groups[] = {
+	"gpio45", "gpio176", "gpio177", "gpio178", "gpio179", "gpio180",
+};
+
+static const char *const ccu_i2c_scl_groups[] = {
+	"gpio16", "gpio18", "gpio20", "gpio22", "gpio24",
+	"gpio114", "gpio116", "gpio126", "gpio130", "gpio132",
+};
+
+static const char *const ccu_i2c_sda_groups[] = {
+	"gpio15", "gpio17", "gpio19", "gpio21", "gpio23",
+	"gpio113", "gpio115", "gpio125", "gpio129", "gpio131",
+};
+
+static const char *const ccu_timer_groups[] = {
+	"gpio25", "gpio26", "gpio27", "gpio28", "gpio29", "gpio30",
+	"gpio31", "gpio32", "gpio33", "gpio34", "gpio143", "gpio144",
+	"gpio150", "gpio151", "gpio152", "gpio153",
+};
+
+static const char *const clink_debug_groups[] = {
+	"gpio12", "gpio13", "gpio14", "gpio51",
+	"gpio52", "gpio53", "gpio54", "gpio55",
+};
+
+static const char *const dbg_out_groups[] = {
+	"gpio113",
+};
+
+static const char *const dbg_out_clk_groups[] = {
+	"gpio165",
+};
+
+static const char *const ddr_bist_complete_groups[] = {
+	"gpio37",
+};
+
+static const char *const ddr_bist_fail_groups[] = {
+	"gpio39",
+};
+
+static const char *const ddr_bist_start_groups[] = {
+	"gpio36",
+};
+
+static const char *const ddr_bist_stop_groups[] = {
+	"gpio38",
+};
+
+static const char *const ddr_pxi_groups[] = {
+	"gpio99",  "gpio100", "gpio109", "gpio110", "gpio113", "gpio114",
+	"gpio115", "gpio116", "gpio117", "gpio118", "gpio119", "gpio120",
+	"gpio121", "gpio122", "gpio126", "gpio127", "gpio128", "gpio129",
+	"gpio130", "gpio131", "gpio132", "gpio133", "gpio134", "gpio135",
+	"gpio136", "gpio137", "gpio138", "gpio139", "gpio162", "gpio163",
+	"gpio164", "gpio165",
+};
+
+static const char *const dp_rx0_groups[] = {
+	"gpio55", "gpio83", "gpio84",  "gpio85",  "gpio86",
+	"gpio88", "gpio89", "gpio137", "gpio138",
+};
+
+static const char *const dp_rx00_groups[] = {
+	"gpio99",
+};
+
+static const char *const dp_rx01_groups[] = {
+	"gpio100",
+};
+
+static const char *const dp_rx0_mute_groups[] = {
+	"gpio35",
+};
+
+static const char *const dp_rx1_groups[] = {
+	"gpio56", "gpio92", "gpio93",  "gpio95",  "gpio96",
+	"gpio97", "gpio98", "gpio158", "gpio159",
+};
+
+static const char *const dp_rx10_groups[] = {
+	"gpio121",
+};
+
+static const char *const dp_rx11_groups[] = {
+	"gpio122",
+};
+
+static const char *const dp_rx1_mute_groups[] = {
+	"gpio36",
+};
+
+static const char *const edp0_hot_groups[] = {
+	"gpio51",
+};
+
+static const char *const edp0_lcd_groups[] = {
+	"gpio47",
+};
+
+static const char *const edp1_hot_groups[] = {
+	"gpio52",
+};
+
+static const char *const edp1_lcd_groups[] = {
+	"gpio48",
+};
+
+static const char *const edp2_hot_groups[] = {
+	"gpio53",
+};
+
+static const char *const edp2_lcd_groups[] = {
+	"gpio49",
+};
+
+static const char *const edp3_hot_groups[] = {
+	"gpio54",
+};
+
+static const char *const edp3_lcd_groups[] = {
+	"gpio50",
+};
+
+static const char *const emac0_mcg_groups[] = {
+	"gpio16", "gpio17", "gpio18", "gpio19",
+};
+
+static const char *const emac0_mdc_groups[] = {
+	"gpio47",
+};
+
+static const char *const emac0_mdio_groups[] = {
+	"gpio48",
+};
+
+static const char *const emac0_ptp_groups[] = {
+	"gpio133", "gpio134", "gpio135", "gpio136",
+	"gpio139", "gpio140", "gpio141", "gpio142",
+};
+
+static const char *const emac1_mcg_groups[] = {
+	"gpio20", "gpio21", "gpio22", "gpio23",
+};
+
+static const char *const emac1_mdc_groups[] = {
+	"gpio49",
+};
+
+static const char *const emac1_mdio_groups[] = {
+	"gpio50",
+};
+
+static const char *const emac1_ptp_groups[] = {
+	"gpio37", "gpio38", "gpio39", "gpio40",
+	"gpio41", "gpio42", "gpio43", "gpio44",
+};
+
+static const char *const gcc_gp1_clk_groups[] = {
+	"gpio51",
+};
+
+static const char *const gcc_gp2_clk_groups[] = {
+	"gpio52",
+};
+
+static const char *const gcc_gp3_clk_groups[] = {
+	"gpio42",
+};
+
+static const char *const gcc_gp4_clk_groups[] = {
+	"gpio43",
+};
+
+static const char *const gcc_gp5_clk_groups[] = {
+	"gpio105",
+};
+
+static const char *const gcc_gp6_clk_groups[] = {
+	"gpio106",
+};
+
+static const char *const gcc_gp7_clk_groups[] = {
+	"gpio13",
+};
+
+static const char *const gcc_gp8_clk_groups[] = {
+	"gpio14",
+};
+
+static const char *const jitter_bist_groups[] = {
+	"gpio123",
+	"gpio138",
+};
+
+static const char *const lbist_pass_groups[] = {
+	"gpio121",
+};
+
+static const char *const mbist_pass_groups[] = {
+	"gpio122",
+};
+
+static const char *const mdp0_vsync_out_groups[] = {
+	"gpio113", "gpio114", "gpio115", "gpio116", "gpio121", "gpio122",
+	"gpio139", "gpio140", "gpio141", "gpio142", "gpio143",
+};
+
+static const char *const mdp1_vsync_out_groups[] = {
+	"gpio123", "gpio124", "gpio125", "gpio126", "gpio129", "gpio130",
+	"gpio131", "gpio132", "gpio133", "gpio134", "gpio135",
+};
+
+static const char *const mdp_vsync_e_groups[] = {
+	"gpio109",
+};
+
+static const char *const mdp_vsync_p_groups[] = {
+	"gpio110",
+};
+
+static const char *const mdp_vsync_s_groups[] = {
+	"gpio144",
+};
+
+static const char *const pcie0_clk_req_n_groups[] = {
+	"gpio1",
+};
+
+static const char *const pcie1_clk_req_n_groups[] = {
+	"gpio4",
+};
+
+static const char *const pcie2_clk_req_n_groups[] = {
+	"gpio7",
+};
+
+static const char *const pcie3_clk_req_n_groups[] = {
+	"gpio10",
+};
+
+static const char *const phase_flag_groups[] = {
+	"gpio67", "gpio68", "gpio69", "gpio70", "gpio71", "gpio72", "gpio73", "gpio74",
+	"gpio75", "gpio76", "gpio77", "gpio78", "gpio79", "gpio80", "gpio81", "gpio82",
+	"gpio83", "gpio84", "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90",
+	"gpio91", "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio98", "gpio101",
+};
+
+static const char *const pll_bist_sync_groups[] = {
+	"gpio176",
+};
+
+static const char *const pll_clk_aux_groups[] = {
+	"gpio100",
+};
+
+static const char *const prng_rosc0_groups[] = {
+	"gpio117",
+};
+
+static const char *const prng_rosc1_groups[] = {
+	"gpio118",
+};
+
+static const char *const pwrbrk_i_n_groups[] = {
+	"gpio167",
+};
+
+static const char *const qdss_cti_groups[] = {
+	"gpio41",  "gpio42",  "gpio110", "gpio138",
+	"gpio142", "gpio144", "gpio162", "gpio163",
+};
+
+static const char *const qdss_groups[] = {
+	"gpio67", "gpio68", "gpio69", "gpio70", "gpio71", "gpio72", "gpio73", "gpio74",
+	"gpio75", "gpio76", "gpio77", "gpio78", "gpio79", "gpio80", "gpio81", "gpio82",
+	"gpio83", "gpio84", "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90",
+	"gpio91", "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98",
+	"gpio99", "gpio100", "gpio101", "gpio108",
+};
+
+static const char *const qspi_groups[] = {
+	"gpio102", "gpio103", "gpio104", "gpio105", "gpio106", "gpio107", "gpio108",
+};
+
+static const char *const qup0_se0_groups[] = {
+	"gpio109", "gpio110", "gpio111", "gpio112",
+};
+
+static const char *const qup0_se1_groups[] = {
+	"gpio109", "gpio110", "gpio111", "gpio112",
+};
+
+static const char *const qup0_se2_groups[] = {
+	"gpio113", "gpio114", "gpio115", "gpio116",
+};
+
+static const char *const qup0_se3_groups[] = {
+	"gpio113", "gpio114", "gpio115", "gpio116",
+};
+
+static const char *const qup0_se4_groups[] = {
+	"gpio117", "gpio118", "gpio119", "gpio120",
+};
+
+static const char *const qup0_se5_groups[] = {
+	"gpio109", "gpio110", "gpio121", "gpio122",
+};
+
+static const char *const qup1_se0_groups[] = {
+	"gpio123", "gpio124", "gpio125", "gpio126",
+};
+
+static const char *const qup1_se1_groups[] = {
+	"gpio123", "gpio124", "gpio125", "gpio126",
+};
+
+static const char *const qup1_se2_groups[] = {
+	"gpio127", "gpio128", "gpio129", "gpio130",
+};
+
+static const char *const qup1_se3_groups[] = {
+	"gpio129", "gpio130",
+};
+
+static const char *const qup1_se4_groups[] = {
+	"gpio131", "gpio132", "gpio137", "gpio138",
+};
+
+static const char *const qup1_se5_groups[] = {
+	"gpio133", "gpio134", "gpio135", "gpio136",
+};
+
+static const char *const qup1_se6_groups[] = {
+	"gpio131", "gpio132", "gpio137", "gpio138",
+};
+
+static const char *const qup2_se0_groups[] = {
+	"gpio139", "gpio140", "gpio141", "gpio142",
+};
+
+static const char *const qup2_se1_groups[] = {
+	"gpio143", "gpio144", "gpio154", "gpio155",
+};
+
+static const char *const qup2_se2_groups[] = {
+	"gpio145", "gpio146", "gpio147", "gpio148", "gpio149",
+};
+
+static const char *const qup2_se3_groups[] = {
+	"gpio150", "gpio151", "gpio152", "gpio153",
+};
+
+static const char *const qup2_se4_groups[] = {
+	"gpio143", "gpio144", "gpio150", "gpio151",
+	"gpio152", "gpio154", "gpio155",
+};
+
+static const char *const qup2_se5_groups[] = {
+	"gpio156", "gpio157", "gpio158", "gpio159",
+};
+
+static const char *const qup2_se6_groups[] = {
+	"gpio156", "gpio157", "gpio158", "gpio159",
+};
+
+static const char *const qup3_se0_mira_groups[] = {
+	"gpio102", "gpio103", "gpio104", "gpio105",
+	"gpio106", "gpio107", "gpio108",
+};
+
+static const char *const qup3_se0_mirb_groups[] = {
+	"gpio102", "gpio103",
+};
+
+static const char *const sailss_ospi_groups[] = {
+	"gpio164",
+	"gpio165",
+};
+
+static const char *const sdc4_clk_groups[] = {
+	"gpio175",
+};
+
+static const char *const sdc4_cmd_groups[] = {
+	"gpio174",
+};
+
+static const char *const sdc4_data_groups[] = {
+	"gpio170",
+	"gpio171",
+	"gpio172",
+	"gpio173",
+};
+
+static const char *const smb_alert_groups[] = {
+	"gpio110",
+};
+
+static const char *const smb_alert_n_groups[] = {
+	"gpio109",
+};
+
+static const char *const smb_clk_groups[] = {
+	"gpio112",
+};
+
+static const char *const smb_dat_groups[] = {
+	"gpio111",
+};
+
+static const char *const tb_trig_sdc4_groups[] = {
+	"gpio169",
+};
+
+static const char *const tmess_prng0_groups[] = {
+	"gpio94",
+};
+
+static const char *const tmess_prng1_groups[] = {
+	"gpio95",
+};
+
+static const char *const tsc_timer_groups[] = {
+	"gpio25", "gpio26", "gpio27", "gpio28", "gpio29",
+	"gpio30", "gpio31", "gpio32", "gpio33", "gpio34",
+};
+
+static const char *const tsense_pwm_groups[] = {
+	"gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49", "gpio50",
+};
+
+static const char *const usb0_hs_groups[] = {
+	"gpio12",
+};
+
+static const char *const usb0_phy_ps_groups[] = {
+	"gpio164",
+};
+
+static const char *const usb1_hs_groups[] = {
+	"gpio13",
+};
+
+static const char *const usb1_phy_ps_groups[] = {
+	"gpio165",
+};
+
+static const char *const usb2_hs_groups[] = {
+	"gpio14",
+};
+
+static const char *const usxgmii0_phy_groups[] = {
+	"gpio45",
+};
+
+static const char *const usxgmii1_phy_groups[] = {
+	"gpio46",
+};
+
+static const char *const vsense_trigger_mirnat_groups[] = {
+	"gpio132",
+};
+
+static const char *const wcn_sw_groups[] = {
+	"gpio161",
+};
+
+static const char *const wcn_sw_ctrl_groups[] = {
+	"gpio160",
+};
+
+static const struct pinfunction nord_functions[] = {
+	MSM_GPIO_PIN_FUNCTION(gpio),
+	MSM_PIN_FUNCTION(aoss_cti),
+	MSM_PIN_FUNCTION(atest_char),
+	MSM_PIN_FUNCTION(atest_usb20),
+	MSM_PIN_FUNCTION(atest_usb21),
+	MSM_PIN_FUNCTION(aud_intfc0_clk),
+	MSM_PIN_FUNCTION(aud_intfc0_data),
+	MSM_PIN_FUNCTION(aud_intfc0_ws),
+	MSM_PIN_FUNCTION(aud_intfc10_clk),
+	MSM_PIN_FUNCTION(aud_intfc10_data),
+	MSM_PIN_FUNCTION(aud_intfc10_ws),
+	MSM_PIN_FUNCTION(aud_intfc1_clk),
+	MSM_PIN_FUNCTION(aud_intfc1_data),
+	MSM_PIN_FUNCTION(aud_intfc1_ws),
+	MSM_PIN_FUNCTION(aud_intfc2_clk),
+	MSM_PIN_FUNCTION(aud_intfc2_data),
+	MSM_PIN_FUNCTION(aud_intfc2_ws),
+	MSM_PIN_FUNCTION(aud_intfc3_clk),
+	MSM_PIN_FUNCTION(aud_intfc3_data),
+	MSM_PIN_FUNCTION(aud_intfc3_ws),
+	MSM_PIN_FUNCTION(aud_intfc4_clk),
+	MSM_PIN_FUNCTION(aud_intfc4_data),
+	MSM_PIN_FUNCTION(aud_intfc4_ws),
+	MSM_PIN_FUNCTION(aud_intfc5_clk),
+	MSM_PIN_FUNCTION(aud_intfc5_data),
+	MSM_PIN_FUNCTION(aud_intfc5_ws),
+	MSM_PIN_FUNCTION(aud_intfc6_clk),
+	MSM_PIN_FUNCTION(aud_intfc6_data),
+	MSM_PIN_FUNCTION(aud_intfc6_ws),
+	MSM_PIN_FUNCTION(aud_intfc7_clk),
+	MSM_PIN_FUNCTION(aud_intfc7_data),
+	MSM_PIN_FUNCTION(aud_intfc7_ws),
+	MSM_PIN_FUNCTION(aud_intfc8_clk),
+	MSM_PIN_FUNCTION(aud_intfc8_data),
+	MSM_PIN_FUNCTION(aud_intfc8_ws),
+	MSM_PIN_FUNCTION(aud_intfc9_clk),
+	MSM_PIN_FUNCTION(aud_intfc9_data),
+	MSM_PIN_FUNCTION(aud_intfc9_ws),
+	MSM_PIN_FUNCTION(aud_mclk0_mira),
+	MSM_PIN_FUNCTION(aud_mclk0_mirb),
+	MSM_PIN_FUNCTION(aud_mclk1_mira),
+	MSM_PIN_FUNCTION(aud_mclk1_mirb),
+	MSM_PIN_FUNCTION(aud_mclk2_mira),
+	MSM_PIN_FUNCTION(aud_mclk2_mirb),
+	MSM_PIN_FUNCTION(aud_refclk0),
+	MSM_PIN_FUNCTION(aud_refclk1),
+	MSM_PIN_FUNCTION(bist_done),
+	MSM_PIN_FUNCTION(ccu_async_in),
+	MSM_PIN_FUNCTION(ccu_i2c_scl),
+	MSM_PIN_FUNCTION(ccu_i2c_sda),
+	MSM_PIN_FUNCTION(ccu_timer),
+	MSM_PIN_FUNCTION(clink_debug),
+	MSM_PIN_FUNCTION(dbg_out),
+	MSM_PIN_FUNCTION(dbg_out_clk),
+	MSM_PIN_FUNCTION(ddr_bist_complete),
+	MSM_PIN_FUNCTION(ddr_bist_fail),
+	MSM_PIN_FUNCTION(ddr_bist_start),
+	MSM_PIN_FUNCTION(ddr_bist_stop),
+	MSM_PIN_FUNCTION(ddr_pxi),
+	MSM_PIN_FUNCTION(dp_rx0),
+	MSM_PIN_FUNCTION(dp_rx00),
+	MSM_PIN_FUNCTION(dp_rx01),
+	MSM_PIN_FUNCTION(dp_rx0_mute),
+	MSM_PIN_FUNCTION(dp_rx1),
+	MSM_PIN_FUNCTION(dp_rx10),
+	MSM_PIN_FUNCTION(dp_rx11),
+	MSM_PIN_FUNCTION(dp_rx1_mute),
+	MSM_PIN_FUNCTION(edp0_hot),
+	MSM_PIN_FUNCTION(edp0_lcd),
+	MSM_PIN_FUNCTION(edp1_hot),
+	MSM_PIN_FUNCTION(edp1_lcd),
+	MSM_PIN_FUNCTION(edp2_hot),
+	MSM_PIN_FUNCTION(edp2_lcd),
+	MSM_PIN_FUNCTION(edp3_hot),
+	MSM_PIN_FUNCTION(edp3_lcd),
+	MSM_PIN_FUNCTION(emac0_mcg),
+	MSM_PIN_FUNCTION(emac0_mdc),
+	MSM_PIN_FUNCTION(emac0_mdio),
+	MSM_PIN_FUNCTION(emac0_ptp),
+	MSM_PIN_FUNCTION(emac1_mcg),
+	MSM_PIN_FUNCTION(emac1_mdc),
+	MSM_PIN_FUNCTION(emac1_mdio),
+	MSM_PIN_FUNCTION(emac1_ptp),
+	MSM_PIN_FUNCTION(gcc_gp1_clk),
+	MSM_PIN_FUNCTION(gcc_gp2_clk),
+	MSM_PIN_FUNCTION(gcc_gp3_clk),
+	MSM_PIN_FUNCTION(gcc_gp4_clk),
+	MSM_PIN_FUNCTION(gcc_gp5_clk),
+	MSM_PIN_FUNCTION(gcc_gp6_clk),
+	MSM_PIN_FUNCTION(gcc_gp7_clk),
+	MSM_PIN_FUNCTION(gcc_gp8_clk),
+	MSM_PIN_FUNCTION(jitter_bist),
+	MSM_PIN_FUNCTION(lbist_pass),
+	MSM_PIN_FUNCTION(mbist_pass),
+	MSM_PIN_FUNCTION(mdp0_vsync_out),
+	MSM_PIN_FUNCTION(mdp1_vsync_out),
+	MSM_PIN_FUNCTION(mdp_vsync_e),
+	MSM_PIN_FUNCTION(mdp_vsync_p),
+	MSM_PIN_FUNCTION(mdp_vsync_s),
+	MSM_PIN_FUNCTION(pcie0_clk_req_n),
+	MSM_PIN_FUNCTION(pcie1_clk_req_n),
+	MSM_PIN_FUNCTION(pcie2_clk_req_n),
+	MSM_PIN_FUNCTION(pcie3_clk_req_n),
+	MSM_PIN_FUNCTION(phase_flag),
+	MSM_PIN_FUNCTION(pll_bist_sync),
+	MSM_PIN_FUNCTION(pll_clk_aux),
+	MSM_PIN_FUNCTION(prng_rosc0),
+	MSM_PIN_FUNCTION(prng_rosc1),
+	MSM_PIN_FUNCTION(pwrbrk_i_n),
+	MSM_PIN_FUNCTION(qdss_cti),
+	MSM_PIN_FUNCTION(qdss),
+	MSM_PIN_FUNCTION(qdss_cti),
+	MSM_PIN_FUNCTION(qspi),
+	MSM_PIN_FUNCTION(qup0_se0),
+	MSM_PIN_FUNCTION(qup0_se1),
+	MSM_PIN_FUNCTION(qup0_se2),
+	MSM_PIN_FUNCTION(qup0_se3),
+	MSM_PIN_FUNCTION(qup0_se4),
+	MSM_PIN_FUNCTION(qup0_se5),
+	MSM_PIN_FUNCTION(qup1_se0),
+	MSM_PIN_FUNCTION(qup1_se1),
+	MSM_PIN_FUNCTION(qup1_se2),
+	MSM_PIN_FUNCTION(qup1_se3),
+	MSM_PIN_FUNCTION(qup1_se4),
+	MSM_PIN_FUNCTION(qup1_se5),
+	MSM_PIN_FUNCTION(qup1_se6),
+	MSM_PIN_FUNCTION(qup2_se0),
+	MSM_PIN_FUNCTION(qup2_se1),
+	MSM_PIN_FUNCTION(qup2_se2),
+	MSM_PIN_FUNCTION(qup2_se3),
+	MSM_PIN_FUNCTION(qup2_se4),
+	MSM_PIN_FUNCTION(qup2_se5),
+	MSM_PIN_FUNCTION(qup2_se6),
+	MSM_PIN_FUNCTION(qup3_se0_mira),
+	MSM_PIN_FUNCTION(qup3_se0_mirb),
+	MSM_PIN_FUNCTION(sailss_ospi),
+	MSM_PIN_FUNCTION(sdc4_clk),
+	MSM_PIN_FUNCTION(sdc4_cmd),
+	MSM_PIN_FUNCTION(sdc4_data),
+	MSM_PIN_FUNCTION(smb_alert),
+	MSM_PIN_FUNCTION(smb_alert_n),
+	MSM_PIN_FUNCTION(smb_clk),
+	MSM_PIN_FUNCTION(smb_dat),
+	MSM_PIN_FUNCTION(tb_trig_sdc4),
+	MSM_PIN_FUNCTION(tmess_prng0),
+	MSM_PIN_FUNCTION(tmess_prng1),
+	MSM_PIN_FUNCTION(tsc_timer),
+	MSM_PIN_FUNCTION(tsense_pwm),
+	MSM_PIN_FUNCTION(usb0_hs),
+	MSM_PIN_FUNCTION(usb0_phy_ps),
+	MSM_PIN_FUNCTION(usb1_hs),
+	MSM_PIN_FUNCTION(usb1_phy_ps),
+	MSM_PIN_FUNCTION(usb2_hs),
+	MSM_PIN_FUNCTION(usxgmii0_phy),
+	MSM_PIN_FUNCTION(usxgmii1_phy),
+	MSM_PIN_FUNCTION(vsense_trigger_mirnat),
+	MSM_PIN_FUNCTION(wcn_sw),
+	MSM_PIN_FUNCTION(wcn_sw_ctrl),
+};
+
+/* Every pin is maintained as a single group, and missing or non-existing pin
+ * would be maintained as dummy group to synchronize pin group index with
+ * pin descriptor registered with pinctrl core.
+ * Clients would not be able to request these dummy pin groups.
+ */
+static const struct msm_pingroup nord_groups[] = {
+	[0] = PINGROUP(0, _, _, _, _, _, _, _, _, _, _, _),
+	[1] = PINGROUP(1, pcie0_clk_req_n, _, _, _, _, _, _, _, _, _, _),
+	[2] = PINGROUP(2, _, _, _, _, _, _, _, _, _, _, _),
+	[3] = PINGROUP(3, _, _, _, _, _, _, _, _, _, _, _),
+	[4] = PINGROUP(4, pcie1_clk_req_n, _, _, _, _, _, _, _, _, _, _),
+	[5] = PINGROUP(5, _, _, _, _, _, _, _, _, _, _, _),
+	[6] = PINGROUP(6, _, _, _, _, _, _, _, _, _, _, _),
+	[7] = PINGROUP(7, pcie2_clk_req_n, _, _, _, _, _, _, _, _, _, _),
+	[8] = PINGROUP(8, _, _, _, _, _, _, _, _, _, _, _),
+	[9] = PINGROUP(9, _, _, _, _, _, _, _, _, _, _, _),
+	[10] = PINGROUP(10, pcie3_clk_req_n, _, _, _, _, _, _, _, _, _, _),
+	[11] = PINGROUP(11, _, _, _, _, _, _, _, _, _, _, _),
+	[12] = PINGROUP(12, usb0_hs, clink_debug, _, _, _, _, _, _, _, _, _),
+	[13] = PINGROUP(13, usb1_hs, clink_debug, gcc_gp7_clk, _, _, _, _, _, _, _, _),
+	[14] = PINGROUP(14, usb2_hs, clink_debug, gcc_gp8_clk, _, _, _, _, _, _, _, _),
+	[15] = PINGROUP(15, ccu_i2c_sda, _, _, _, _, _, _, _, _, _, _),
+	[16] = PINGROUP(16, ccu_i2c_scl, emac0_mcg, _, _, _, _, _, _, _, _, _),
+	[17] = PINGROUP(17, ccu_i2c_sda, emac0_mcg, _, _, _, _, _, _, _, _, _),
+	[18] = PINGROUP(18, ccu_i2c_scl, emac0_mcg, _, _, _, _, _, _, _, _, _),
+	[19] = PINGROUP(19, ccu_i2c_sda, emac0_mcg, _, _, _, _, _, _, _, _, _),
+	[20] = PINGROUP(20, ccu_i2c_scl, emac1_mcg, _, _, _, _, _, _, _, _, _),
+	[21] = PINGROUP(21, ccu_i2c_sda, emac1_mcg, _, _, _, _, _, _, _, _, _),
+	[22] = PINGROUP(22, ccu_i2c_scl, emac1_mcg, _, _, _, _, _, _, _, _, _),
+	[23] = PINGROUP(23, ccu_i2c_sda, emac1_mcg, _, _, _, _, _, _, _, _, _),
+	[24] = PINGROUP(24, ccu_i2c_scl, _, _, _, _, _, _, _, _, _, _),
+	[25] = PINGROUP(25, ccu_timer, tsc_timer, _, _, _, _, _, _, _, _, _),
+	[26] = PINGROUP(26, ccu_timer, tsc_timer, _, _, _, _, _, _, _, _, _),
+	[27] = PINGROUP(27, ccu_timer, tsc_timer, _, _, _, _, _, _, _, _, _),
+	[28] = PINGROUP(28, ccu_timer, tsc_timer, _, _, _, _, _, _, _, _, _),
+	[29] = PINGROUP(29, ccu_timer, tsc_timer, _, _, _, _, _, _, _, _, _),
+	[30] = PINGROUP(30, ccu_timer, tsc_timer, _, _, _, _, _, _, _, _, _),
+	[31] = PINGROUP(31, ccu_timer, tsc_timer, _, _, _, _, _, _, _, _, _),
+	[32] = PINGROUP(32, ccu_timer, tsc_timer, _, _, _, _, _, _, _, _, _),
+	[33] = PINGROUP(33, ccu_timer, tsc_timer, _, _, _, _, _, _, _, _, _),
+	[34] = PINGROUP(34, ccu_timer, tsc_timer, _, _, _, _, _, _, _, _, _),
+	[35] = PINGROUP(35, dp_rx0_mute, _, _, _, _, _, _, _, _, _, _),
+	[36] = PINGROUP(36, dp_rx1_mute, ddr_bist_start, _, _, _, _, _, _, _, _, _),
+	[37] = PINGROUP(37, emac1_ptp, ddr_bist_complete, _, _, _, _, _, _, _, _, _),
+	[38] = PINGROUP(38, emac1_ptp, ddr_bist_stop, _, _, _, _, _, _, _, _, _),
+	[39] = PINGROUP(39, emac1_ptp, ddr_bist_fail, _, _, _, _, _, _, _, _, _),
+	[40] = PINGROUP(40, emac1_ptp, _, _, _, _, _, _, _, _, _, _),
+	[41] = PINGROUP(41, emac1_ptp, qdss_cti, _, _, _, _, _, _, _, _, _),
+	[42] = PINGROUP(42, emac1_ptp, qdss_cti, gcc_gp3_clk, _, _, _, _, _, _, _, _),
+	[43] = PINGROUP(43, emac1_ptp, gcc_gp4_clk, tsense_pwm, _, _, _, _, _, _, _, _),
+	[44] = PINGROUP(44, emac1_ptp, tsense_pwm, _, _, _, _, _, _, _, _, _),
+	[45] = PINGROUP(45, usxgmii0_phy, ccu_async_in, tsense_pwm, _, _, _, _, _, _, _, _),
+	[46] = PINGROUP(46, usxgmii1_phy, tsense_pwm, _, _, _, _, _, _, _, _, _),
+	[47] = PINGROUP(47, emac0_mdc, edp0_lcd, tsense_pwm, _, _, _, _, _, _, _, _),
+	[48] = PINGROUP(48, emac0_mdio, edp1_lcd, tsense_pwm, _, _, _, _, _, _, _, _),
+	[49] = PINGROUP(49, emac1_mdc, edp2_lcd, tsense_pwm, _, _, _, _, _, _, _, _),
+	[50] = PINGROUP(50, emac1_mdio, edp3_lcd, tsense_pwm, _, _, _, _, _, _, _, _),
+	[51] = PINGROUP(51, edp0_hot, clink_debug, gcc_gp1_clk, _, _, _, _, _, _, _, _),
+	[52] = PINGROUP(52, edp1_hot, clink_debug, gcc_gp2_clk, _, _, _, _, _, _, _, _),
+	[53] = PINGROUP(53, edp2_hot, clink_debug, _, _, _, _, _, _, _, _, _),
+	[54] = PINGROUP(54, edp3_hot, clink_debug, _, _, _, _, _, _, _, _, _),
+	[55] = PINGROUP(55, dp_rx0, clink_debug, _, _, _, _, _, _, _, _, _),
+	[56] = PINGROUP(56, dp_rx1, _, _, _, _, _, _, _, _, _, _),
+	[57] = PINGROUP(57, aud_intfc0_clk, _, _, _, _, _, _, _, _, _, _),
+	[58] = PINGROUP(58, aud_intfc0_ws, _, _, _, _, _, _, _, _, _, _),
+	[59] = PINGROUP(59, aud_intfc0_data, _, _, _, _, _, _, _, _, _, _),
+	[60] = PINGROUP(60, aud_intfc0_data, _, _, _, _, _, _, _, _, _, _),
+	[61] = PINGROUP(61, aud_intfc0_data, aud_intfc10_clk, _, _, _, _, _, _, _, _, _),
+	[62] = PINGROUP(62, aud_intfc0_data, aud_intfc10_ws, _, _, _, _, _, _, _, _, _),
+	[63] = PINGROUP(63, aud_intfc0_data, aud_intfc7_clk, _, _, _, _, _, _, _, _, _),
+	[64] = PINGROUP(64, aud_intfc0_data, aud_intfc7_ws, _, _, _, _, _, _, _, _, _),
+	[65] = PINGROUP(65, aud_intfc0_data, aud_intfc7_data, _, _, _, _, _, _, _, _, _),
+	[66] = PINGROUP(66, aud_intfc0_data, aud_intfc7_data, _, _, _, _, _, _, _, _, _),
+	[67] = PINGROUP(67, aud_intfc1_clk, phase_flag, _, qdss, _, _, _, _, _, _, _),
+	[68] = PINGROUP(68, aud_intfc1_ws, phase_flag, _, qdss, _, _, _, _, _, _, _),
+	[69] = PINGROUP(69, aud_intfc1_data, phase_flag, _, qdss, _, _, _, _, _, _, _),
+	[70] = PINGROUP(70, aud_intfc1_data, aud_intfc9_clk, phase_flag,
+			_, qdss, _, _, _, _, _, _),
+	[71] = PINGROUP(71, aud_intfc1_data, aud_intfc9_ws, phase_flag,
+			_, qdss, _, _, _, _, _, _),
+	[72] = PINGROUP(72, aud_intfc1_data, aud_intfc9_data, phase_flag,
+			_, qdss, _, _, _, _, _, _),
+	[73] = PINGROUP(73, aud_intfc1_data, aud_intfc8_clk, phase_flag,
+			_, qdss, _, _, _, _, _, _),
+	[74] = PINGROUP(74, aud_intfc1_data, aud_intfc8_ws, phase_flag,
+			_, qdss, _, _, _, _, _, _),
+	[75] = PINGROUP(75, aud_intfc1_data, aud_intfc8_data, phase_flag,
+			_, qdss, _, _, _, _, _, _),
+	[76] = PINGROUP(76, aud_intfc1_data, aud_intfc8_data, phase_flag,
+			_, qdss, _, _, _, _, _, _),
+	[77] = PINGROUP(77, aud_intfc2_clk, phase_flag, _, qdss, _, _, _, _, _, _, _),
+	[78] = PINGROUP(78, aud_intfc2_ws, phase_flag, _, qdss, _, _, _, _, _, _, _),
+	[79] = PINGROUP(79, aud_intfc2_data, phase_flag, _, qdss, _, _, _, _, _, _, _),
+	[80] = PINGROUP(80, aud_intfc2_data, phase_flag, _, _, qdss, _, _, _, _, _, _),
+	[81] = PINGROUP(81, aud_intfc2_data, aud_intfc10_data, phase_flag,
+			_, _, qdss, _, _, _, _, _),
+	[82] = PINGROUP(82, aud_intfc2_data, aud_intfc10_data, phase_flag,
+			_, qdss, _, _, _, _, _, _),
+	[83] = PINGROUP(83, aud_intfc3_clk, dp_rx0, aoss_cti, phase_flag, _, qdss,
+			_, _, _, _, _),
+	[84] = PINGROUP(84, aud_intfc3_ws, dp_rx0, aoss_cti, phase_flag, _, qdss,
+			_, _, _, _, _),
+	[85] = PINGROUP(85, aud_intfc3_data, dp_rx0, aoss_cti, phase_flag,
+			_, qdss, _, _, _, _, _),
+	[86] = PINGROUP(86, aud_intfc3_data, aud_mclk0_mirb, dp_rx0, aoss_cti, phase_flag,
+			_, qdss, _, _, _, _),
+	[87] = PINGROUP(87, aud_intfc4_clk, phase_flag, _, qdss, _, _, _, _, _, _, _),
+	[88] = PINGROUP(88, aud_intfc4_ws, dp_rx0, phase_flag, _, qdss, _, _, _, _, _, _),
+	[89] = PINGROUP(89, aud_intfc4_data, dp_rx0, phase_flag, _, qdss,
+			_, _, _, _, _, _),
+	[90] = PINGROUP(90, aud_intfc4_data, aud_mclk1_mirb, phase_flag,
+			_, qdss, _, _, _, _, _, _),
+	[91] = PINGROUP(91, aud_intfc5_clk, phase_flag, _, qdss, _, _, _, _, _, _, _),
+	[92] = PINGROUP(92, aud_intfc5_ws, dp_rx1, phase_flag, _, qdss, _, _, _, _, _, _),
+	[93] = PINGROUP(93, aud_intfc5_data, dp_rx1, phase_flag, _, qdss,
+			_, _, _, _, _, _),
+	[94] = PINGROUP(94, aud_intfc5_data, aud_mclk2_mirb, phase_flag, tmess_prng0,
+			_, qdss, _, _, _, _, _),
+	[95] = PINGROUP(95, aud_intfc6_clk, dp_rx1, phase_flag, tmess_prng1,
+			_, qdss, _, _, _, _, _),
+	[96] = PINGROUP(96, aud_intfc6_ws, dp_rx1, phase_flag, _, qdss,
+			_, _, _, _, _, _),
+	[97] = PINGROUP(97, aud_intfc6_data, dp_rx1, qdss, _, _, _, _, _, _, _, _),
+	[98] = PINGROUP(98, aud_intfc6_data, dp_rx1, phase_flag, _, qdss,
+			_, _, _, _, _, _),
+	[99] = PINGROUP(99, aud_mclk0_mira, qdss, dp_rx00, ddr_pxi, _, _, _, _, _, _, _),
+	[100] = PINGROUP(100, aud_mclk1_mira, aud_refclk0, pll_clk_aux,
+			 qdss, dp_rx01, ddr_pxi, _, _, _, _, _),
+	[101] = PINGROUP(101, aud_mclk2_mira, aud_refclk1, phase_flag, _, qdss,
+			 _, _, _, _, _, _),
+	[102] = PINGROUP(102, qspi, qup3_se0_mira, qup3_se0_mirb, _, _, _, _, _, _, _, _),
+	[103] = PINGROUP(103, qspi, qup3_se0_mira, qup3_se0_mirb, _, _, _, _, _, _, _, _),
+	[104] = PINGROUP(104, qspi, qup3_se0_mira, _, _, _, _, _, _, _, _, _),
+	[105] = PINGROUP(105, qspi, qup3_se0_mira, gcc_gp5_clk, _, _, _, _, _, _, _, _),
+	[106] = PINGROUP(106, qspi, qup3_se0_mira, gcc_gp6_clk, _, _, _, _, _, _, _, _),
+	[107] = PINGROUP(107, qspi, qup3_se0_mira, _, _, _, _, _, _, _, _, _),
+	[108] = PINGROUP(108, qspi, qup3_se0_mira, qdss, _, _, _, _, _, _, _, _),
+	[109] = PINGROUP(109, qup0_se0, qup0_se1, qup0_se5, mdp_vsync_e,
+			 smb_alert_n, _, ddr_pxi, _, _, _, _),
+	[110] = PINGROUP(110, qup0_se0, qup0_se1, qup0_se5, qdss_cti,
+			 mdp_vsync_p, smb_alert, _, ddr_pxi, _, _, _),
+	[111] = PINGROUP(111, qup0_se1, qup0_se0, smb_dat, _, _, _, _, _, _, _, _),
+	[112] = PINGROUP(112, qup0_se1, qup0_se0, smb_clk, _, _, _, _, _, _, _, _),
+	[113] = PINGROUP(113, qup0_se2, qup0_se3, ccu_i2c_sda, mdp0_vsync_out,
+			 dbg_out, ddr_pxi, _, _, _, _, _),
+	[114] = PINGROUP(114, qup0_se2, qup0_se3, ccu_i2c_scl, mdp0_vsync_out,
+			 _, ddr_pxi, _, _, _, _, _),
+	[115] = PINGROUP(115, qup0_se3, qup0_se2, ccu_i2c_sda, mdp0_vsync_out,
+			 _, ddr_pxi, _, _, _, _, _),
+	[116] = PINGROUP(116, qup0_se3, qup0_se2, ccu_i2c_scl, mdp0_vsync_out,
+			 _, ddr_pxi, _, _, _, _, _),
+	[117] = PINGROUP(117, qup0_se4, prng_rosc0, _, ddr_pxi, _, _, _, _, _, _, _),
+	[118] = PINGROUP(118, qup0_se4, prng_rosc1, _, ddr_pxi, _, _, _, _, _, _, _),
+	[119] = PINGROUP(119, qup0_se4, _, ddr_pxi, _, _, _, _, _, _, _, _),
+	[120] = PINGROUP(120, qup0_se4, _, ddr_pxi, _, _, _, _, _, _, _, _),
+	[121] = PINGROUP(121, qup0_se5, lbist_pass, mdp0_vsync_out, _, dp_rx10, ddr_pxi,
+			 _, _, _, _, _),
+	[122] = PINGROUP(122, qup0_se5, mbist_pass, mdp0_vsync_out, _, dp_rx11, ddr_pxi,
+			 _, _, _, _, _),
+	[123] = PINGROUP(123, qup1_se0, qup1_se1, mdp1_vsync_out, jitter_bist,
+			 _, _, _, _, _, _, _),
+	[124] = PINGROUP(124, qup1_se0, qup1_se1, mdp1_vsync_out, _, _, _, _, _, _, _, _),
+	[125] = PINGROUP(125, qup1_se1, qup1_se0, ccu_i2c_sda, mdp1_vsync_out,
+			 _, _, _, _, _, _, _),
+	[126] = PINGROUP(126, qup1_se1, qup1_se0, ccu_i2c_scl, mdp1_vsync_out,
+			 _, atest_usb20, ddr_pxi, _, _, _, _),
+	[127] = PINGROUP(127, qup1_se2, qup1_se2, _, atest_usb21, ddr_pxi,
+			 _, _, _, _, _, _),
+	[128] = PINGROUP(128, qup1_se2, qup1_se2, _, atest_usb20, ddr_pxi,
+			 _, _, _, _, _, _),
+	[129] = PINGROUP(129, qup1_se3, qup1_se3, ccu_i2c_sda, mdp1_vsync_out,
+			 _, atest_usb21, ddr_pxi, _, _, _, _),
+	[130] = PINGROUP(130, qup1_se3, qup1_se3, ccu_i2c_scl, mdp1_vsync_out,
+			 _, atest_usb20, ddr_pxi, _, _, _, _),
+	[131] = PINGROUP(131, qup1_se4, qup1_se6, ccu_i2c_sda, mdp1_vsync_out,
+			 _, atest_usb21, ddr_pxi, _, _, _, _),
+	[132] = PINGROUP(132, qup1_se4, qup1_se6, ccu_i2c_scl, mdp1_vsync_out,
+			 _, vsense_trigger_mirnat, ddr_pxi, _, _, _, _),
+	[133] = PINGROUP(133, qup1_se5, emac0_ptp, mdp1_vsync_out, _, ddr_pxi,
+			 _, _, _, _, _, _),
+	[134] = PINGROUP(134, qup1_se5, emac0_ptp, mdp1_vsync_out, _, ddr_pxi,
+			 _, _, _, _, _, _),
+	[135] = PINGROUP(135, qup1_se5, emac0_ptp, mdp1_vsync_out, _, ddr_pxi,
+			 _, _, _, _, _, _),
+	[136] = PINGROUP(136, qup1_se5, emac0_ptp, _, ddr_pxi, _, _, _, _, _, _, _),
+	[137] = PINGROUP(137, qup1_se6, qup1_se4, dp_rx0, _, ddr_pxi, _, _, _, _, _, _),
+	[138] = PINGROUP(138, qup1_se6, qup1_se4, dp_rx0, qdss_cti, jitter_bist, ddr_pxi,
+			 _, _, _, _, _),
+	[139] = PINGROUP(139, qup2_se0, emac0_ptp, mdp0_vsync_out, ddr_pxi,
+			 _, _, _, _, _, _, _),
+	[140] = PINGROUP(140, qup2_se0, emac0_ptp, mdp0_vsync_out, _, _, _, _, _, _, _, _),
+	[141] = PINGROUP(141, qup2_se0, emac0_ptp, mdp0_vsync_out, _, _, _, _, _, _, _, _),
+	[142] = PINGROUP(142, qup2_se0, emac0_ptp, qdss_cti, mdp0_vsync_out, _, _, _, _, _, _, _),
+	[143] = PINGROUP(143, qup2_se1, qup2_se4, ccu_timer, mdp0_vsync_out,
+			 _, _, _, _, _, _, _),
+	[144] = PINGROUP(144, qup2_se1, qup2_se4, ccu_timer, qdss_cti, mdp_vsync_s,
+			 _, _, _, _, _, _),
+	[145] = PINGROUP(145, qup2_se2, _, _, _, _, _, _, _, _, _, _),
+	[146] = PINGROUP(146, qup2_se2, _, _, _, _, _, _, _, _, _, _),
+	[147] = PINGROUP(147, qup2_se2, _, _, _, _, _, _, _, _, _, _),
+	[148] = PINGROUP(148, qup2_se2, _, _, _, _, _, _, _, _, _, _),
+	[149] = PINGROUP(149, qup2_se2, _, _, _, _, _, _, _, _, _, _),
+	[150] = PINGROUP(150, qup2_se3, qup2_se4, ccu_timer, _, _, _, _, _, _, _, _),
+	[151] = PINGROUP(151, qup2_se3, qup2_se4, ccu_timer, _, _, _, _, _, _, _, _),
+	[152] = PINGROUP(152, qup2_se3, qup2_se4, ccu_timer, _, _, _, _, _, _, _, _),
+	[153] = PINGROUP(153, qup2_se3, ccu_timer, _, _, _, _, _, _, _, _, _),
+	[154] = PINGROUP(154, qup2_se4, qup2_se1, _, _, _, _, _, _, _, _, _),
+	[155] = PINGROUP(155, qup2_se4, qup2_se1, _, _, _, _, _, _, _, _, _),
+	[156] = PINGROUP(156, qup2_se5, qup2_se6, _, _, _, _, _, _, _, _, _),
+	[157] = PINGROUP(157, qup2_se5, qup2_se6, _, _, _, _, _, _, _, _, _),
+	[158] = PINGROUP(158, qup2_se6, qup2_se5, dp_rx1, _, _, _, _, _, _, _, _),
+	[159] = PINGROUP(159, qup2_se6, qup2_se5, dp_rx1, _, _, _, _, _, _, _, _),
+	[160] = PINGROUP(160, wcn_sw_ctrl, _, _, _, _, _, _, _, _, _, _),
+	[161] = PINGROUP(161, wcn_sw, _, _, _, _, _, _, _, _, _, _),
+	[162] = PINGROUP(162, qdss_cti, _, ddr_pxi, _, _, _, _, _, _, _, _),
+	[163] = PINGROUP(163, qdss_cti, _, ddr_pxi, _, _, _, _, _, _, _, _),
+	[164] = PINGROUP(164, usb0_phy_ps, _, sailss_ospi, ddr_pxi, _, _, _, _, _, _, _),
+	[165] = PINGROUP(165, usb1_phy_ps, dbg_out_clk, sailss_ospi, ddr_pxi,
+			 _, _, _, _, _, _, _),
+	[166] = PINGROUP(166, _, _, _, _, _, _, _, _, _, _, _),
+	[167] = PINGROUP(167, pwrbrk_i_n, _, _, _, _, _, _, _, _, _, _),
+	[168] = PINGROUP(168, bist_done, _, _, _, _, _, _, _, _, _, _),
+	[169] = PINGROUP(169, tb_trig_sdc4, _, _, _, _, _, _, _, _, _, _),
+	[170] = PINGROUP(170, sdc4_data, _, _, _, _, _, _, _, _, _, _),
+	[171] = PINGROUP(171, sdc4_data, _, _, _, _, _, _, _, _, _, _),
+	[172] = PINGROUP(172, sdc4_data, _, _, _, _, _, _, _, _, _, _),
+	[173] = PINGROUP(173, sdc4_data, _, _, _, _, _, _, _, _, _, _),
+	[174] = PINGROUP(174, sdc4_cmd, _, _, _, _, _, _, _, _, _, _),
+	[175] = PINGROUP(175, sdc4_clk, _, _, _, _, _, _, _, _, _, _),
+	[176] = PINGROUP(176, ccu_async_in, pll_bist_sync, atest_char,
+			 _, _, _, _, _, _, _, _),
+	[177] = PINGROUP(177, ccu_async_in, atest_char, _, _, _, _, _, _, _, _, _),
+	[178] = PINGROUP(178, ccu_async_in, atest_char, _, _, _, _, _, _, _, _, _),
+	[179] = PINGROUP(179, ccu_async_in, atest_char, _, _, _, _, _, _, _, _, _),
+	[180] = PINGROUP(180, ccu_async_in, atest_char, _, _, _, _, _, _, _, _, _),
+	[181] = UFS_RESET(ufs_reset, 0xbd004, 0xbe000),
+};
+
+static const struct msm_gpio_wakeirq_map nord_pdc_map[] = {
+	{ 0, 67 },    { 1, 68 },    { 2, 82 },	  { 3, 69 },	{ 4, 70 },
+	{ 5, 83 },    { 6, 71 },    { 7, 72 },	  { 8, 84 },	{ 9, 73 },
+	{ 10, 119 },  { 11, 85 },   { 45, 107 },  { 46, 98 },	{ 102, 77 },
+	{ 108, 78 },  { 110, 120 }, { 114, 80 },  { 116, 81 },	{ 120, 117 },
+	{ 124, 108 }, { 126, 99 },  { 128, 100 }, { 132, 101 }, { 138, 87 },
+	{ 142, 88 },  { 144, 89 },  { 153, 90 },  { 157, 91 },	{ 159, 118 },
+	{ 160, 110 }, { 161, 79 },  { 166, 109 }, { 168, 111 },
+};
+
+static const struct msm_pinctrl_soc_data nord_tlmm = {
+	.pins = nord_pins,
+	.npins = ARRAY_SIZE(nord_pins),
+	.functions = nord_functions,
+	.nfunctions = ARRAY_SIZE(nord_functions),
+	.groups = nord_groups,
+	.ngroups = ARRAY_SIZE(nord_groups),
+	.ngpios = 182,
+	.wakeirq_map = nord_pdc_map,
+	.nwakeirq_map = ARRAY_SIZE(nord_pdc_map),
+	.egpio_func = 11,
+};
+
+static const struct of_device_id nord_tlmm_of_match[] = {
+	{ .compatible = "qcom,nord-tlmm", .data = &nord_tlmm },
+	{},
+};
+
+static int nord_tlmm_probe(struct platform_device *pdev)
+{
+	const struct msm_pinctrl_soc_data *pinctrl_data;
+	struct device *dev = &pdev->dev;
+
+	pinctrl_data = device_get_match_data(dev);
+	if (!pinctrl_data)
+		return -EINVAL;
+
+	return msm_pinctrl_probe(pdev, &nord_tlmm);
+}
+
+static struct platform_driver nord_tlmm_driver = {
+	.driver = {
+		.name = "nord-tlmm",
+		.of_match_table = nord_tlmm_of_match,
+	},
+	.probe = nord_tlmm_probe,
+};
+
+static int __init nord_tlmm_init(void)
+{
+	return platform_driver_register(&nord_tlmm_driver);
+}
+arch_initcall(nord_tlmm_init);
+
+static void __exit nord_tlmm_exit(void)
+{
+	platform_driver_unregister(&nord_tlmm_driver);
+}
+module_exit(nord_tlmm_exit);
+
+MODULE_DESCRIPTION("QTI Nord TLMM driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, nord_tlmm_of_match);

-- 
2.47.3


^ permalink raw reply related

* [PATCH net-next v2 0/3] net: dsa: yt921x: Add port qdisc tbf support
From: David Yang @ 2026-05-04 10:12 UTC (permalink / raw)
  To: netdev
  Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Jamal Hadi Salim,
	Jiri Pirko, Simon Horman, linux-kernel

v1: https://lore.kernel.org/r/20260502215314.917687-1-mmyangfl@gmail.com
  - remove queue related register definiations
  - add missing extack param during tbf setup
v0: https://lore.kernel.org/r/20260409171209.2575583-1-mmyangfl@gmail.com
  - picked from old series
  - add extack to the offload struct
  - add all params to the offload struct

David Yang (3):
  net: sched: tbf: add extack to offload params
  net: sched: tbf: pass all params to offload users
  net: dsa: yt921x: Add port qdisc tbf support

 drivers/net/dsa/yt921x.c | 126 +++++++++++++++++++++++++++++++++++++++
 drivers/net/dsa/yt921x.h |  18 ++++++
 include/net/pkt_cls.h    |   7 ++-
 net/sched/sch_tbf.c      |  15 ++++-
 4 files changed, 162 insertions(+), 4 deletions(-)

-- 
2.53.0


^ permalink raw reply

* [PATCH net-next v2 1/3] net: sched: tbf: add extack to offload params
From: David Yang @ 2026-05-04 10:12 UTC (permalink / raw)
  To: netdev
  Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Jamal Hadi Salim,
	Jiri Pirko, Simon Horman, linux-kernel
In-Reply-To: <20260504101258.1608004-1-mmyangfl@gmail.com>

Drivers might have error messages to propagate to user space. Propagate
the netlink extack so that they can inform user space in a verbal way of
their limitations.

Signed-off-by: David Yang <mmyangfl@gmail.com>
---
 include/net/pkt_cls.h | 1 +
 net/sched/sch_tbf.c   | 9 +++++++--
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index 99ac747b7906..3bd08d7f39c1 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -1046,6 +1046,7 @@ struct tc_tbf_qopt_offload_replace_params {
 };
 
 struct tc_tbf_qopt_offload {
+	struct netlink_ext_ack *extack;
 	enum tc_tbf_command command;
 	u32 handle;
 	u32 parent;
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index f2340164f579..4576111fe075 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -139,7 +139,8 @@ static u64 psched_ns_t2l(const struct psched_ratecfg *r,
 	return len;
 }
 
-static void tbf_offload_change(struct Qdisc *sch)
+static void tbf_offload_change(struct Qdisc *sch,
+			       struct netlink_ext_ack *extack)
 {
 	struct tbf_sched_data *q = qdisc_priv(sch);
 	struct net_device *dev = qdisc_dev(sch);
@@ -148,6 +149,7 @@ static void tbf_offload_change(struct Qdisc *sch)
 	if (!tc_can_offload(dev) || !dev->netdev_ops->ndo_setup_tc)
 		return;
 
+	qopt.extack = extack;
 	qopt.command = TC_TBF_REPLACE;
 	qopt.handle = sch->handle;
 	qopt.parent = sch->parent;
@@ -166,6 +168,7 @@ static void tbf_offload_destroy(struct Qdisc *sch)
 	if (!tc_can_offload(dev) || !dev->netdev_ops->ndo_setup_tc)
 		return;
 
+	qopt.extack = NULL;
 	qopt.command = TC_TBF_DESTROY;
 	qopt.handle = sch->handle;
 	qopt.parent = sch->parent;
@@ -176,6 +179,7 @@ static int tbf_offload_dump(struct Qdisc *sch)
 {
 	struct tc_tbf_qopt_offload qopt;
 
+	qopt.extack = NULL;
 	qopt.command = TC_TBF_STATS;
 	qopt.handle = sch->handle;
 	qopt.parent = sch->parent;
@@ -193,6 +197,7 @@ static void tbf_offload_graft(struct Qdisc *sch, struct Qdisc *new,
 		.parent		= sch->parent,
 		.child_handle	= new->handle,
 		.command	= TC_TBF_GRAFT,
+		.extack		= extack,
 	};
 
 	qdisc_offload_graft_helper(qdisc_dev(sch), sch, new, old,
@@ -477,7 +482,7 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt,
 	qdisc_put(old);
 	err = 0;
 
-	tbf_offload_change(sch);
+	tbf_offload_change(sch, extack);
 done:
 	return err;
 }
-- 
2.53.0


^ permalink raw reply related

* [PATCH net-next v2 2/3] net: sched: tbf: pass all params to offload users
From: David Yang @ 2026-05-04 10:12 UTC (permalink / raw)
  To: netdev
  Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Jamal Hadi Salim,
	Jiri Pirko, Simon Horman, linux-kernel
In-Reply-To: <20260504101258.1608004-1-mmyangfl@gmail.com>

Drivers might have fine-grained control over queues. Pass all available
params so they can make use of them.

Signed-off-by: David Yang <mmyangfl@gmail.com>
---
 include/net/pkt_cls.h | 6 +++++-
 net/sched/sch_tbf.c   | 6 +++++-
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index 3bd08d7f39c1..d73c04e3d919 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -1040,8 +1040,12 @@ enum tc_tbf_command {
 };
 
 struct tc_tbf_qopt_offload_replace_params {
+	u32		limit;
+	u32		max_size;
+	s64		buffer;
+	s64		mtu;
 	struct psched_ratecfg rate;
-	u32 max_size;
+	struct psched_ratecfg peak;
 	struct gnet_stats_queue *qstats;
 };
 
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index 4576111fe075..8a1110d59dec 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -153,8 +153,12 @@ static void tbf_offload_change(struct Qdisc *sch,
 	qopt.command = TC_TBF_REPLACE;
 	qopt.handle = sch->handle;
 	qopt.parent = sch->parent;
-	qopt.replace_params.rate = q->rate;
+	qopt.replace_params.limit = q->limit;
 	qopt.replace_params.max_size = q->max_size;
+	qopt.replace_params.buffer = q->buffer;
+	qopt.replace_params.mtu = q->mtu;
+	qopt.replace_params.rate = q->rate;
+	qopt.replace_params.peak = q->peak;
 	qopt.replace_params.qstats = &sch->qstats;
 
 	dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_TBF, &qopt);
-- 
2.53.0


^ permalink raw reply related

* [PATCH net-next v2 3/3] net: dsa: yt921x: Add port qdisc tbf support
From: David Yang @ 2026-05-04 10:12 UTC (permalink / raw)
  To: netdev
  Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Jamal Hadi Salim,
	Jiri Pirko, Simon Horman, linux-kernel
In-Reply-To: <20260504101258.1608004-1-mmyangfl@gmail.com>

Enable port shaping and support limiting the rate of outgoing traffic.

Signed-off-by: David Yang <mmyangfl@gmail.com>
---
 drivers/net/dsa/yt921x.c | 126 +++++++++++++++++++++++++++++++++++++++
 drivers/net/dsa/yt921x.h |  18 ++++++
 2 files changed, 144 insertions(+)

diff --git a/drivers/net/dsa/yt921x.c b/drivers/net/dsa/yt921x.c
index fd1fdcd5f9a3..fd77e1ef53bb 100644
--- a/drivers/net/dsa/yt921x.c
+++ b/drivers/net/dsa/yt921x.c
@@ -24,6 +24,7 @@
 #include <net/dsa.h>
 #include <net/dscp.h>
 #include <net/ieee8021q.h>
+#include <net/pkt_cls.h>
 
 #include "yt921x.h"
 
@@ -1272,6 +1273,17 @@ yt921x_marker_tfm_police(struct yt921x_marker *marker,
 				 priv, port, extack);
 }
 
+static int
+yt921x_marker_tfm_shape(struct yt921x_marker *marker, u64 rate, u64 burst,
+			unsigned int flags, struct yt921x_priv *priv, int port,
+			struct netlink_ext_ack *extack)
+{
+	return yt921x_marker_tfm(marker, rate, burst, flags,
+				 priv->port_shape_slot_ns, YT921X_SHAPE_CIR_MAX,
+				 YT921X_SHAPE_CBS_MAX, YT921X_SHAPE_UNIT_MAX,
+				 priv, port, extack);
+}
+
 static int
 yt921x_police_validate(const struct flow_action_police *police,
 		       const struct flow_action *action,
@@ -1378,6 +1390,112 @@ yt921x_dsa_port_policer_add(struct dsa_switch *ds, int port,
 	return res;
 }
 
+static int
+yt921x_tbf_validate(struct yt921x_priv *priv,
+		    const struct tc_tbf_qopt_offload *qopt)
+{
+	struct netlink_ext_ack *extack = qopt->extack;
+
+	if (qopt->parent != TC_H_ROOT) {
+		NL_SET_ERR_MSG_MOD(extack, "Parent should be \"root\"");
+		return -EOPNOTSUPP;
+	}
+
+	switch (qopt->command) {
+	case TC_TBF_REPLACE: {
+		const struct tc_tbf_qopt_offload_replace_params *p;
+
+		p = &qopt->replace_params;
+
+		if (p->mtu || p->peak.rate_bytes_ps) {
+			NL_SET_ERR_MSG_MOD(extack,
+					   "Offload not supported when mtu/peakrate is configured");
+			return -EOPNOTSUPP;
+		}
+
+		if (!p->rate.mpu) {
+			NL_SET_ERR_MSG_MOD(extack, "Assuming mpu = 64");
+		} else if (p->rate.mpu != 64) {
+			NL_SET_ERR_MSG_MOD(extack,
+					   "Offload not supported when mpu is other than 64");
+			return -EOPNOTSUPP;
+		}
+
+		break;
+	}
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int
+yt921x_dsa_port_setup_tc_tbf_port(struct dsa_switch *ds, int port,
+				  const struct tc_tbf_qopt_offload *qopt)
+{
+	struct yt921x_priv *priv = to_yt921x_priv(ds);
+	struct netlink_ext_ack *extack = qopt->extack;
+	u32 ctrls[2];
+	int res;
+
+	switch (qopt->command) {
+	case TC_TBF_DESTROY:
+		ctrls[0] = 0;
+		ctrls[1] = 0;
+		break;
+	case TC_TBF_REPLACE: {
+		const struct tc_tbf_qopt_offload_replace_params *p;
+		struct yt921x_marker marker;
+
+		p = &qopt->replace_params;
+
+		res = yt921x_marker_tfm_shape(&marker, p->rate.rate_bytes_ps,
+					      p->max_size,
+					      YT921X_MARKER_SINGLE_BUCKET,
+					      priv, port, extack);
+		if (res)
+			return res;
+
+		ctrls[0] = YT921X_PORT_SHAPE_CTRLa_CIR(marker.cir) |
+			   YT921X_PORT_SHAPE_CTRLa_CBS(marker.cbs);
+		ctrls[1] = YT921X_PORT_SHAPE_CTRLb_UNIT(marker.unit) |
+			   YT921X_PORT_SHAPE_CTRLb_EN;
+		break;
+	}
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	mutex_lock(&priv->reg_lock);
+	res = yt921x_reg64_write(priv, YT921X_PORTn_SHAPE_CTRL(port), ctrls);
+	mutex_unlock(&priv->reg_lock);
+
+	return res;
+}
+
+static int
+yt921x_dsa_port_setup_tc(struct dsa_switch *ds, int port,
+			 enum tc_setup_type type, void *type_data)
+{
+	struct yt921x_priv *priv = to_yt921x_priv(ds);
+	int res;
+
+	switch (type) {
+	case TC_SETUP_QDISC_TBF: {
+		const struct tc_tbf_qopt_offload *qopt = type_data;
+
+		res = yt921x_tbf_validate(priv, qopt);
+		if (res)
+			return res;
+
+		return yt921x_dsa_port_setup_tc_tbf_port(ds, port, qopt);
+	}
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
 static int
 yt921x_mirror_del(struct yt921x_priv *priv, int port, bool ingress)
 {
@@ -3524,6 +3642,13 @@ static int yt921x_chip_setup_tc(struct yt921x_priv *priv)
 		return res;
 	priv->meter_slot_ns = ctrl * op_ns;
 
+	ctrl = max(priv->port_shape_slot_ns / op_ns,
+		   YT921X_PORT_SHAPE_SLOT_MIN);
+	res = yt921x_reg_write(priv, YT921X_PORT_SHAPE_SLOT, ctrl);
+	if (res)
+		return res;
+	priv->port_shape_slot_ns = ctrl * op_ns;
+
 	return 0;
 }
 
@@ -3680,6 +3805,7 @@ static const struct dsa_switch_ops yt921x_dsa_switch_ops = {
 	/* rate */
 	.port_policer_del	= yt921x_dsa_port_policer_del,
 	.port_policer_add	= yt921x_dsa_port_policer_add,
+	.port_setup_tc		= yt921x_dsa_port_setup_tc,
 	/* hsr */
 	.port_hsr_leave		= dsa_port_simple_hsr_leave,
 	.port_hsr_join		= dsa_port_simple_hsr_join,
diff --git a/drivers/net/dsa/yt921x.h b/drivers/net/dsa/yt921x.h
index 546b12a8994a..70fa780c337f 100644
--- a/drivers/net/dsa/yt921x.h
+++ b/drivers/net/dsa/yt921x.h
@@ -531,6 +531,19 @@ enum yt921x_app_selector {
 #define  YT921X_MIRROR_PORT_M			GENMASK(3, 0)
 #define   YT921X_MIRROR_PORT(x)				FIELD_PREP(YT921X_MIRROR_PORT_M, (x))
 
+#define YT921X_PORT_SHAPE_SLOT		0x34000c
+#define  YT921X_PORT_SHAPE_SLOT_SLOT_M		GENMASK(11, 0)
+#define YT921X_PORTn_SHAPE_CTRL(port)	(0x354000 + 8 * (port))
+#define  YT921X_PORT_SHAPE_CTRLb_EN		BIT(4)
+#define  YT921X_PORT_SHAPE_CTRLb_PKT_MODE	BIT(3)	/* 0: byte rate mode */
+#define  YT921X_PORT_SHAPE_CTRLb_UNIT_M		GENMASK(2, 0)
+#define   YT921X_PORT_SHAPE_CTRLb_UNIT(x)		FIELD_PREP(YT921X_PORT_SHAPE_CTRLb_UNIT_M, (x))
+#define  YT921X_PORT_SHAPE_CTRLa_CBS_M		GENMASK(31, 18)
+#define   YT921X_PORT_SHAPE_CTRLa_CBS(x)		FIELD_PREP(YT921X_PORT_SHAPE_CTRLa_CBS_M, (x))
+#define  YT921X_PORT_SHAPE_CTRLa_CIR_M		GENMASK(17, 0)
+#define   YT921X_PORT_SHAPE_CTRLa_CIR(x)		FIELD_PREP(YT921X_PORT_SHAPE_CTRLa_CIR_M, (x))
+#define YT921X_PORTn_SHAPE_STAT(port)	(0x356000 + 4 * (port))
+
 #define YT921X_EDATA_EXTMODE	0xfb
 #define YT921X_EDATA_LEN	0x100
 
@@ -556,6 +569,10 @@ enum yt921x_fdb_entry_status {
 #define YT921X_METER_UNIT_MAX	((1 << 3) - 1)
 #define YT921X_METER_CIR_MAX	((1 << 18) - 1)
 #define YT921X_METER_CBS_MAX	((1 << 16) - 1)
+#define YT921X_PORT_SHAPE_SLOT_MIN	80
+#define YT921X_SHAPE_UNIT_MAX	((1 << 3) - 1)
+#define YT921X_SHAPE_CIR_MAX	((1 << 18) - 1)
+#define YT921X_SHAPE_CBS_MAX	((1 << 14) - 1)
 
 #define YT921X_LAG_NUM		2
 #define YT921X_LAG_PORT_NUM	4
@@ -652,6 +669,7 @@ struct yt921x_priv {
 
 	const struct yt921x_info *info;
 	unsigned int meter_slot_ns;
+	unsigned int port_shape_slot_ns;
 	/* cache of dsa_cpu_ports(ds) */
 	u16 cpu_ports_mask;
 	unsigned char cycle_ns;
-- 
2.53.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox