Linux Documentation
 help / color / mirror / Atom feed
* Re: [PATCH v2 0/2] selftests/mm: separate GUP microbenchmarking from functional testing
From: Sarthak Sharma @ 2026-05-20  6:53 UTC (permalink / raw)
  To: Andrew Morton
  Cc: David Hildenbrand, Jonathan Corbet, Jason Gunthorpe, John Hubbard,
	Peter Xu, Lorenzo Stoakes, Liam R . Howlett, Vlastimil Babka,
	Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Shuah Khan,
	linux-mm, linux-kselftest, linux-kernel, linux-doc
In-Reply-To: <20260519112049.a85f34eb5f2af83e11ffc777@linux-foundation.org>

Hi Andrew!

On 5/19/26 11:50 PM, Andrew Morton wrote:
> On Tue, 19 May 2026 17:35:04 +0530 Sarthak Sharma <sarthak.sharma@arm.com> wrote:
> 
>> gup_test.c currently serves two distinct purposes: microbenchmarking
>> (GUP_FAST_BENCHMARK, PIN_FAST_BENCHMARK, PIN_LONGTERM_BENCHMARK) and
>> functional correctness testing (GUP_BASIC_TEST, PIN_BASIC_TEST,
>> DUMP_USER_PAGES_TEST). Mixing these in a single binary means functional
>> tests cannot be run or reported individually, and run_vmtests.sh must
>> invoke the binary multiple times with different flag combinations to
>> cover all configurations. This patch series separates the two concerns:
>> tools/mm/gup_bench for benchmarking and tools/testing/selftests/mm/gup_test
>> for functional testing.
>>
>> Patch 1 adds tools/mm/gup_bench.c, a standalone microbenchmark for
>> GUP_FAST, PIN_FAST and PIN_LONGTERM via the CONFIG_GUP_TEST debugfs
>> interface. It runs the same matrix of configurations as the old
>> run_gup_matrix() shell function (all three commands, read/write,
>> private/shared, four page counts, THP on/off, hugetlb), but as a
>> standalone C program under tools/mm with no dependency on kselftest.
>>
>> Patch 2 rewrites gup_test.c as a kselftest harness-based selftest. It
>> covers all five GUP kernel functions (get_user_pages, get_user_pages_fast,
>> pin_user_pages, pin_user_pages_fast, pin_user_pages with FOLL_LONGTERM)
>> plus DUMP_USER_PAGES_TEST, across 12 mapping configurations (THP on,
>> THP off and hugetlb, each across private/shared and read/write variants)
>> and four batch sizes (1, 512, 123, all pages). Results are reported as
>> standard TAP output with no command-line arguments required.
> 
> Thanks.  AI review asked a few things which seem fairly minor to me,
> but probably legitimate:
> 	https://sashiko.dev/#/patchset/20260519120506.184512-1-sarthak.sharma@arm.com

Thanks for pointing it out. I'll address the review comments and send a v3.

^ permalink raw reply

* Re: [PATCH mm-new] Documentation/admin-guide/mm: Fix typos in transhuge.rst
From: Lance Yang @ 2026-05-20  5:42 UTC (permalink / raw)
  To: Leon Hwang
  Cc: Andrew Morton, David Hildenbrand, Lorenzo Stoakes, Zi Yan,
	Baolin Wang, Liam R . Howlett, Nico Pache, Ryan Roberts, linux-mm,
	Dev Jain, Barry Song, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Jonathan Corbet, Shuah Khan,
	linux-doc, linux-kernel
In-Reply-To: <20260520051751.74396-1-leon.hwang@linux.dev>



On 2026/5/20 13:17, Leon Hwang wrote:
> Fix these two typos:
> 
> 1. approporiately -> appropriately
> 2. presure -> pressure
> 
> Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
> ---

Thanks.

Reviewed-by: Lance Yang <lance.yang@linux.dev>

^ permalink raw reply

* Re: [PATCH mm-new] Documentation/admin-guide/mm: Fix typos in transhuge.rst
From: David Hildenbrand (Arm) @ 2026-05-20  5:30 UTC (permalink / raw)
  To: Leon Hwang, linux-mm
  Cc: Andrew Morton, Lorenzo Stoakes, Zi Yan, Baolin Wang,
	Liam R . Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Lance Yang, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Jonathan Corbet, Shuah Khan, linux-doc,
	linux-kernel
In-Reply-To: <20260520051751.74396-1-leon.hwang@linux.dev>

On 5/20/26 07:17, Leon Hwang wrote:
> Fix these two typos:
> 
> 1. approporiately -> appropriately
> 2. presure -> pressure
> 
> Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
> ---

Acked-by: David Hildenbrand (Arm) <david@kernel.org>

-- 
Cheers,

David

^ permalink raw reply

* Re: [PATCH v2 5/6] gpio: remove machine hogs
From: Dmitry Torokhov @ 2026-05-20  5:27 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Linus Walleij, Bartosz Golaszewski, Geert Uytterhoeven,
	Frank Rowand, Mika Westerberg, Andy Shevchenko, Aaro Koskinen,
	Janusz Krzysztofik, Tony Lindgren, Russell King, Jonathan Corbet,
	Shuah Khan, linux-gpio, linux-kernel, linux-acpi,
	linux-arm-kernel, linux-omap, linux-doc
In-Reply-To: <ag0Dn66ZVnbTc7J2@google.com>

On Tue, May 19, 2026 at 05:46:50PM -0700, Dmitry Torokhov wrote:
> On Mon, Mar 09, 2026 at 01:42:41PM +0100, Bartosz Golaszewski wrote:
> > With no more users, remove legacy machine hog API from the kernel.
> > 
> > Reviewed-by: Linus Walleij <linusw@kernel.org>
> > Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> > Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
> 
> Argh! What is the replacement for this? I have patches for rsk7203 to
> use them to get rid of legacy gpio use, like this:
> 
> diff --git a/arch/sh/boards/mach-rsk/devices-rsk7203.c b/arch/sh/boards/mach-rsk/devices-rsk7203.c
> index f8760a91e2f1..5bbd3b31cffb 100644
> --- a/arch/sh/boards/mach-rsk/devices-rsk7203.c
> +++ b/arch/sh/boards/mach-rsk/devices-rsk7203.c
> @@ -12,7 +12,7 @@
>  #include <linux/smsc911x.h>
>  #include <linux/input.h>
>  #include <linux/io.h>
> -#include <linux/gpio.h>
> +#include <linux/gpio/consumer.h>
>  #include <linux/gpio/machine.h>
>  #include <linux/gpio/property.h>
>  #include <asm/machvec.h>
> @@ -165,6 +165,19 @@ static const struct platform_device_info rsk7203_devices[] __initconst = {
>  	},
>  };
>  
> +/* The base of the function GPIOs in the flat enum */
> +#define SH7203_FN_BASE GPIO_FN_PINT7_PB
> +
> +static struct gpiod_hog rsk7203_gpio_hogs[] = {
> +	GPIO_HOG("sh7203_pfc-fn", GPIO_FN_TXD0 - SH7203_FN_BASE,
> +		 "TXD0", GPIO_ACTIVE_HIGH, GPIOD_ASIS),
> +	GPIO_HOG("sh7203_pfc-fn", GPIO_FN_RXD0 - SH7203_FN_BASE,
> +		 "RXD0", GPIO_ACTIVE_HIGH, GPIOD_ASIS),
> +	GPIO_HOG("sh7203_pfc-fn", GPIO_FN_IRQ0_PB - SH7203_FN_BASE,
> +		 "IRQ0_PB", GPIO_ACTIVE_HIGH, GPIOD_ASIS),
> +	{ }
> +};
> +
>  static int __init rsk7203_devices_setup(void)
>  {
>  	struct platform_device *pd;
> @@ -172,12 +185,10 @@ static int __init rsk7203_devices_setup(void)
>  	int i;
>  
>  	/* Select pins for SCIF0 */
> -	gpio_request(GPIO_FN_TXD0, NULL);
> -	gpio_request(GPIO_FN_RXD0, NULL);
> +	gpiod_add_hogs(rsk7203_gpio_hogs);
>  
>  	/* Setup LAN9118: CS1 in 16-bit Big Endian Mode, IRQ0 at Port B */
>  	__raw_writel(0x36db0400, 0xfffc0008); /* CS1BCR */
> -	gpio_request(GPIO_FN_IRQ0_PB, NULL);
>  
>  	error = software_node_register_node_group(rsk7203_swnodes);
>  	if (error) {
> 
> 
> If there is no replacement maybe we can resurrect this? Or shoudl we
> have add swnode support for hogs?

Hmm, I guess it is already there so I should simply switch. Sorry about
the noise.

Thanks.

-- 
Dmitry

^ permalink raw reply

* Re: [PATCH mm-new] Documentation/admin-guide/mm: Fix typos in transhuge.rst
From: Mike Rapoport @ 2026-05-20  5:20 UTC (permalink / raw)
  To: Leon Hwang
  Cc: linux-mm, Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
	Zi Yan, Baolin Wang, Liam R . Howlett, Nico Pache, Ryan Roberts,
	Dev Jain, Barry Song, Lance Yang, Vlastimil Babka,
	Suren Baghdasaryan, Michal Hocko, Jonathan Corbet, Shuah Khan,
	linux-doc, linux-kernel
In-Reply-To: <20260520051751.74396-1-leon.hwang@linux.dev>

On Wed, May 20, 2026 at 01:17:51PM +0800, Leon Hwang wrote:
> Fix these two typos:
> 
> 1. approporiately -> appropriately
> 2. presure -> pressure
> 
> Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
> ---

Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>

>  Documentation/admin-guide/mm/transhuge.rst | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)

-- 
Sincerely yours,
Mike.

^ permalink raw reply

* [PATCH mm-new] Documentation/admin-guide/mm: Fix typos in transhuge.rst
From: Leon Hwang @ 2026-05-20  5:17 UTC (permalink / raw)
  To: linux-mm
  Cc: Andrew Morton, David Hildenbrand, Lorenzo Stoakes, Zi Yan,
	Baolin Wang, Liam R . Howlett, Nico Pache, Ryan Roberts, Dev Jain,
	Barry Song, Lance Yang, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Jonathan Corbet, Shuah Khan,
	linux-doc, linux-kernel, Leon Hwang

Fix these two typos:

1. approporiately -> appropriately
2. presure -> pressure

Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
---
 Documentation/admin-guide/mm/transhuge.rst | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Documentation/admin-guide/mm/transhuge.rst b/Documentation/admin-guide/mm/transhuge.rst
index fc0127a36ef6..78a1b341a3b5 100644
--- a/Documentation/admin-guide/mm/transhuge.rst
+++ b/Documentation/admin-guide/mm/transhuge.rst
@@ -57,7 +57,7 @@ prominent because the size of each page isn't as huge as the PMD-sized
 variant and there is less memory to clear in each page fault. Some
 architectures also employ TLB compression mechanisms to squeeze more
 entries in when a set of PTEs are virtually and physically contiguous
-and approporiately aligned. In this case, TLB misses will occur less
+and appropriately aligned. In this case, TLB misses will occur less
 often.
 
 THP can be enabled system wide or restricted to certain tasks or even
@@ -211,7 +211,7 @@ PMD-mappable transparent hugepage::
 	cat /sys/kernel/mm/transparent_hugepage/hpage_pmd_size
 
 All THPs at fault and collapse time will be added to _deferred_list,
-and will therefore be split under memory presure if they are considered
+and will therefore be split under memory pressure if they are considered
 "underused". A THP is underused if the number of zero-filled pages in
 the THP is above max_ptes_none (see below). It is possible to disable
 this behaviour by writing 0 to shrink_underused, and enable it by writing
-- 
2.54.0


^ permalink raw reply related

* [PATCH v15 net-next 03/11] net/nebula-matrix: add chip related definitions
From: illusion.wang @ 2026-05-20  3:29 UTC (permalink / raw)
  To: dimon.zhao, illusion.wang, alvin.wang, sam.chen, netdev
  Cc: andrew+netdev, corbet, kuba, horms, linux-doc, pabeni,
	vadim.fedorenko, lukas.bulwahn, edumazet, enelsonmoore, skhan,
	hkallweit1, open list
In-Reply-To: <20260520032950.4874-1-illusion.wang@nebula-matrix.com>

This patch adds chip-related register definitions for the Leonis
hardware and introduces nbl_write_all_regs(), which programs a large
set of P4 configuration tables at chip initialization time.

1. nbl_hw.h/nbl_hw_leonis.h
chip-related reg definitions
2. nbl_hw_leonis_regs.c
P4 configuration that will be invoked during chip initialization
These nbl_sec*_data are used to configure P4-related registers. The
driver’s functionality depends heavily on these register settings. But
they can be not marked __initdata. Because it will be called by
pci_driver.probe.They also should not be moved into firmware files,
as the software functionality is tightly coupled with these
configurations.If they were moved to firmware,users could easily end up
with mismatched versions of the firmware and the kernel driver module,
leading to functional inconsistencies or system malfunctions.

Signed-off-by: illusion.wang <illusion.wang@nebula-matrix.com>
---
 .../net/ethernet/nebula-matrix/nbl/Makefile   |    1 +
 .../nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h  |  519 +++
 .../nbl_hw/nbl_hw_leonis/nbl_hw_leonis_regs.c | 2887 +++++++++++++++++
 .../nbl_hw/nbl_hw_leonis/nbl_hw_leonis_regs.h |   11 +
 4 files changed, 3418 insertions(+)
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis_regs.c
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis_regs.h

diff --git a/drivers/net/ethernet/nebula-matrix/nbl/Makefile b/drivers/net/ethernet/nebula-matrix/nbl/Makefile
index 271605920396..63116d1d7043 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/Makefile
+++ b/drivers/net/ethernet/nebula-matrix/nbl/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_NBL) := nbl.o
 nbl-objs +=       nbl_channel/nbl_channel.o \
 				nbl_hw/nbl_hw_leonis/nbl_hw_leonis.o \
 				nbl_hw/nbl_hw_leonis/nbl_resource_leonis.o \
+				nbl_hw/nbl_hw_leonis/nbl_hw_leonis_regs.o \
 				nbl_core/nbl_dispatch.o \
 				nbl_core/nbl_dev.o \
 				nbl_main.o
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h
index 77c67b67ba31..4f718d5873f4 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h
@@ -11,4 +11,523 @@
 #include "../../nbl_include/nbl_include.h"
 #include "../nbl_hw_reg.h"
 
+#define NBL_DRIVER_STATUS_REG			0x1300444
+#define NBL_DRIVER_STATUS_BIT			16
+
+/*  ----------  REG BASE ADDR  ----------  */
+/* Interface modules base addr */
+#define NBL_INTF_HOST_PCOMPLETER_BASE		0x00f08000
+#define NBL_INTF_HOST_PADPT_BASE		0x00f4c000
+#define NBL_INTF_HOST_MAILBOX_BASE		0x00fb0000
+#define NBL_INTF_HOST_PCIE_BASE			0X01504000
+/* DP modules base addr */
+#define NBL_DP_USTORE_BASE			0x00104000
+#define NBL_DP_UQM_BASE				0x00114000
+#define NBL_DP_UPED_BASE			0x0015c000
+#define NBL_DP_UVN_BASE				0x00244000
+#define NBL_DP_DSCH_BASE			0x00404000
+#define NBL_DP_SHAPING_BASE			0x00504000
+#define NBL_DP_DVN_BASE				0x00514000
+#define NBL_DP_DSTORE_BASE			0x00704000
+#define NBL_DP_DQM_BASE				0x00714000
+#define NBL_DP_DPED_BASE			0x0075c000
+#define NBL_DP_DDMUX_BASE			0x00984000
+/*  --------  MAILBOX BAR2 -----  */
+#define NBL_MAILBOX_NOTIFY_ADDR			0x00000000
+#define NBL_MAILBOX_BAR_REG			0x00000000
+#define NBL_MAILBOX_QINFO_CFG_RX_TABLE_ADDR	0x10
+#define NBL_MAILBOX_QINFO_CFG_TX_TABLE_ADDR	0x20
+#define NBL_MAILBOX_QINFO_CFG_DBG_TABLE_ADDR	0x30
+
+/*  --------  MAILBOX  --------  */
+
+/* mailbox BAR qinfo_cfg_table */
+#define MAILBOX_QINFO_CFG_TABLE_DWLEN	4
+union nbl_mailbox_qinfo_cfg_table_u {
+	struct nbl_mailbox_qinfo_cfg_table {
+		u32 queue_base_addr_l;
+		u32 queue_base_addr_h;
+		u32 queue_size_bwind:4;
+		u32 rsv1:28;
+		u32 queue_rst:1;
+		u32 queue_en:1;
+		u32 dif_err:1;
+		u32 ptr_err:1;
+		u32 rsv2:28;
+	} __packed info;
+	u32 data[MAILBOX_QINFO_CFG_TABLE_DWLEN];
+};
+
+/*  --------  MAILBOX BAR0 -----  */
+/* mailbox qinfo_map_table */
+#define NBL_MAILBOX_QINFO_MAP_REG_ARR(func_id) \
+	(NBL_INTF_HOST_MAILBOX_BASE + 0x00001000 + \
+	(func_id) * sizeof(union nbl_mailbox_qinfo_map_table_u))
+
+/* MAILBOX qinfo_map_table */
+union nbl_mailbox_qinfo_map_table_u {
+	struct nbl_mailbox_qinfo_map_table {
+		u32 function:3;
+		u32 devid:5;
+		u32 bus:8;
+		u32 msix_idx:13;
+		u32 msix_idx_valid:1;
+		u32 rsv:2;
+	} __packed info;
+	u32 data;
+};
+
+/*  --------  HOST_PCIE  --------  */
+#define NBL_PCIE_HOST_K_PF_MASK_REG (NBL_INTF_HOST_PCIE_BASE + 0x00001004)
+#define NBL_PCIE_HOST_TL_CFG_BUSDEV (NBL_INTF_HOST_PCIE_BASE + 0x11040)
+
+/*  --------  HOST_PADPT  --------  */
+#define NBL_HOST_PADPT_HOST_CFG_FC_PD_DN (NBL_INTF_HOST_PADPT_BASE + 0x00000160)
+#define NBL_HOST_PADPT_HOST_CFG_FC_PH_DN (NBL_INTF_HOST_PADPT_BASE + 0x00000164)
+#define NBL_HOST_PADPT_HOST_CFG_FC_NPH_DN \
+	(NBL_INTF_HOST_PADPT_BASE + 0x0000016C)
+#define NBL_HOST_PADPT_HOST_CFG_FC_CPLH_UP \
+	(NBL_INTF_HOST_PADPT_BASE + 0x00000170)
+/* host_padpt host_msix_info */
+#define NBL_PADPT_HOST_MSIX_INFO_REG_ARR(vector_id) \
+	(NBL_INTF_HOST_PADPT_BASE + 0x00010000 +    \
+	 (vector_id) * sizeof(union nbl_host_msix_info_u))
+#define NBL_HOST_MSIX_INFO_DWLEN	2
+union nbl_host_msix_info_u {
+	struct nbl_host_msix_info {
+		u32 intrl_pnum:16;
+		u32 intrl_rate:16;
+		u32 function:3;
+		u32 devid:5;
+		u32 bus:8;
+		u32 valid:1;
+		u32 msix_mask_en:1;
+		u32 rsv:14;
+	} info;
+	u32 data[NBL_HOST_MSIX_INFO_DWLEN];
+};
+
+/*  --------  HOST_PCOMPLETER  --------  */
+/* pcompleter_host pcompleter_host_virtio_qid_map_table */
+#define NBL_PCOMPLETER_FUNCTION_MSIX_MAP_REG_ARR(i)   \
+	(NBL_INTF_HOST_PCOMPLETER_BASE + 0x00004000 + \
+	 (i) * sizeof(union nbl_function_msix_map_u))
+#define NBL_PCOMPLETER_HOST_MSIX_FID_TABLE(i)         \
+	(NBL_INTF_HOST_PCOMPLETER_BASE + 0x0003a000 + \
+	 (i) * sizeof(union nbl_pcompleter_host_msix_fid_table_u))
+
+union nbl_pcompleter_host_msix_fid_table_u {
+	struct nbl_pcompleter_host_msix_fid_table {
+		u32 fid:10;
+		u32 vld:1;
+		u32 rsv:21;
+	} info;
+	u32 data;
+};
+
+#define NBL_FUNC_MSIX_MAP_DWLEN		4
+union nbl_function_msix_map_u {
+	struct nbl_function_msix_map {
+		u64 msix_map_base_addr;
+		u32 function:3;
+		u32 devid:5;
+		u32 bus:8;
+		u32 valid:1;
+		u32 rsv0:15;
+		u32 rsv1;
+	} info;
+	u32 data[NBL_FUNC_MSIX_MAP_DWLEN];
+};
+
+/*  ----------  DPED  ----------  */
+#define NBL_DPED_VLAN_OFFSET		(NBL_DP_DPED_BASE + 0x000003F4)
+#define NBL_DPED_DSCP_OFFSET_0		(NBL_DP_DPED_BASE + 0x000003F8)
+#define NBL_DPED_DSCP_OFFSET_1		(NBL_DP_DPED_BASE + 0x000003FC)
+
+/* DPED hw_edt_prof/ UPED hw_edt_prof */
+union ped_hw_edit_profile_u {
+	struct ped_hw_edit_profile {
+		u32 l4_len:2;
+	#define NBL_PED_L4_LEN_MDY_CMD_0		0
+	#define NBL_PED_L4_LEN_MDY_CMD_1		1
+	#define NBL_PED_L4_LEN_MDY_DISABLE		2
+		u32 l3_len:2;
+	#define NBL_PED_L3_LEN_MDY_CMD_0		0
+	#define NBL_PED_L3_LEN_MDY_CMD_1		1
+	#define NBL_PED_L3_LEN_MDY_DISABLE		2
+		u32 l4_ck:3;
+	#define NBL_PED_L4_CKSUM_CMD_0			0
+	#define NBL_PED_L4_CKSUM_CMD_1			1
+	#define NBL_PED_L4_CKSUM_CMD_2			2
+	#define NBL_PED_L4_CKSUM_CMD_3			3
+	#define NBL_PED_L4_CKSUM_CMD_4			4
+	#define NBL_PED_L4_CKSUM_CMD_5			5
+	#define NBL_PED_L4_CKSUM_CMD_6			6
+	#define NBL_PED_L4_CKSUM_DISABLE		7
+		u32 l3_ck:1;
+	#define NBL_PED_L3_CKSUM_ENABLE			1
+	#define NBL_PED_L3_CKSUM_DISABLE		0
+		u32 l4_ck_zero_free:1;
+	#define NBL_PED_L4_CKSUM_ZERO_FREE_ENABLE	1
+	#define NBL_PED_L4_CKSUM_ZERO_FREE_DISABLE	0
+		u32 rsv:23;
+	} info;
+	u32 data;
+};
+
+/*  ----------  UPED  ----------  */
+/* UPED uped_hw_edt_prof */
+#define NBL_UPED_HW_EDT_PROF_TABLE(i)    \
+	(NBL_DP_UPED_BASE + 0x00001000 + \
+	 (i) * sizeof(union ped_hw_edit_profile_u))
+
+/*  ---------  SHAPING  ---------  */
+#define NBL_SHAPING_NET(i)                  \
+	(NBL_DP_SHAPING_BASE + 0x00001800 + \
+	 (i) * sizeof(struct nbl_shaping_net))
+
+/* cir 1, bandwidth 1kB/s in protol environment */
+/* cir 1, bandwidth 1Mb/s */
+#define NBL_LR_LEONIS_NET_BUCKET_DEPTH		9600
+
+#define NBL_DSTORE_DROP_XOFF_TH			0xC8
+#define NBL_DSTORE_DROP_XON_TH			0x64
+
+#define NBL_DSTORE_DROP_XOFF_TH_100G		0x1F4
+#define NBL_DSTORE_DROP_XON_TH_100G		0x12C
+
+#define NBL_DSTORE_DROP_XOFF_TH_BOND_MAIN	0x180
+#define NBL_DSTORE_DROP_XON_TH_BOND_MAIN	0x180
+
+#define NBL_DSTORE_DROP_XOFF_TH_BOND_OTHER	0x64
+#define NBL_DSTORE_DROP_XON_TH_BOND_OTHER	0x64
+
+#define NBL_DSTORE_DROP_XOFF_TH_100G_BOND_MAIN	0x2D5
+#define NBL_DSTORE_DROP_XON_TH_100G_BOND_MAIN	0x2BC
+
+#define NBL_DSTORE_DROP_XOFF_TH_100G_BOND_OTHER	0x145
+#define NBL_DSTORE_DROP_XON_TH_100G_BOND_OTHER	0x12C
+
+#define NBL_DSTORE_DISC_BP_TH (NBL_DP_DSTORE_BASE + 0x00000630)
+
+union dstore_disc_bp_th_u {
+	struct dstore_disc_bp_th {
+		u32 xoff_th:10;
+		u32 rsv1:6;
+		u32 xon_th:10;
+		u32 rsv:5;
+		u32 en:1;
+	} info;
+	u32 data;
+};
+
+union dsch_psha_en_u {
+	struct dsch_psha_en {
+		u32 en:4;
+		u32 rsv:28;
+	} info;
+	u32 data;
+};
+
+/*  ----------  DSCH  ----------  */
+/* DSCH dsch maxqid */
+#define NBL_DSCH_HOST_QID_MAX (NBL_DP_DSCH_BASE + 0x00000118)
+#define NBL_DSCH_VN_QUANTA_ADDR  (NBL_DP_DSCH_BASE + 0x00000134)
+
+#define NBL_MAX_QUEUE_ID	0x7ff
+#define NBL_HOST_QUANTA		0x8000
+#define NBL_ECPU_QUANTA		0x1000
+
+union dsch_vn_quanta_u {
+	struct dsch_vn_quanta {
+		u32 h_qua:16;
+		u32 e_qua:16;
+	} info;
+	u32 data;
+};
+
+/*  ----------  DVN  ----------  */
+/* DVN dvn_queue_table */
+#define NBL_DVN_ECPU_QUEUE_NUM			(NBL_DP_DVN_BASE + 0x0000041C)
+#define NBL_DVN_DESCREQ_NUM_CFG			(NBL_DP_DVN_BASE + 0x00000430)
+#define NBL_DVN_DESC_WR_MERGE_TIMEOUT		(NBL_DP_DVN_BASE + 0x00000480)
+#define NBL_DVN_DIF_REQ_RD_RO_FLAG		(NBL_DP_DVN_BASE + 0x0000045C)
+
+#define DEFAULT_DVN_DESC_WR_MERGE_TIMEOUT_MAX	0x3FF
+
+union nbl_dvn_descreq_num_cfg_u {
+	struct nbl_dvn_descreq_num_cfg {
+		u32 avring_cfg_num:1; /* spilit ring descreq_num 0:8,1:16 */
+		u32 rsv0:3;
+		/* packet ring descreq_num
+		 * 0:8,1:12,2:16;3:20,4:24,5:26;6:32,7:32
+		 */
+		u32 packed_l1_num:3;
+		u32 rsv1:25;
+	} info;
+	u32 data;
+};
+
+union nbl_dvn_desc_wr_merge_timeout_u {
+	struct nbl_dvn_desc_wr_merge_timeout {
+		u32 cfg_cycle:10;
+		u32 rsv:22;
+	} info;
+	u32 data;
+};
+
+union nbl_dvn_dif_req_rd_ro_flag_u {
+	struct nbl_dvn_dif_req_rd_ro_flag {
+		u32 rd_desc_ro_en:1;
+		u32 rd_data_ro_en:1;
+		u32 rd_avring_ro_en:1;
+		u32 rsv:29;
+	} info;
+	u32 data;
+};
+
+/*  ----------  UVN  ----------  */
+/* UVN uvn_queue_table */
+
+#define NBL_UVN_DESC_RD_WAIT			(NBL_DP_UVN_BASE + 0x0000020C)
+#define NBL_UVN_QUEUE_ERR_MASK			(NBL_DP_UVN_BASE + 0x00000224)
+#define NBL_UVN_ECPU_QUEUE_NUM			(NBL_DP_UVN_BASE + 0x0000023C)
+#define NBL_UVN_DESC_WR_TIMEOUT			(NBL_DP_UVN_BASE + 0x00000214)
+#define NBL_UVN_DIF_REQ_RO_FLAG			(NBL_DP_UVN_BASE + 0x00000250)
+#define NBL_UVN_DESC_PREFETCH_INIT		(NBL_DP_UVN_BASE + 0x00000204)
+#define NBL_UVN_DESC_PREFETCH_NUM		4
+
+union uvn_dif_req_ro_flag_u {
+	struct uvn_dif_req_ro_flag {
+		u32 avail_rd:1;
+		u32 desc_rd:1;
+		u32 pkt_wr:1;
+		u32 desc_wr:1;
+		u32 rsv:28;
+	} info;
+	u32 data;
+};
+
+union uvn_desc_wr_timeout_u {
+	struct uvn_desc_wr_timeout {
+		u32 num:15;
+		u32 mask:1;
+		u32 rsv:16;
+	} info;
+	u32 data;
+};
+
+union uvn_queue_err_mask_u {
+	struct uvn_queue_err_mask {
+		u32 rsv0:1;
+		u32 buffer_len_err:1;
+		u32 next_err:1;
+		u32 indirect_err:1;
+		u32 split_err:1;
+		u32 dif_err:1;
+		u32 rsv1:26;
+	} info;
+	u32 data;
+};
+
+union uvn_desc_prefetch_init_u {
+	struct uvn_desc_prefetch_init {
+		u32 num:8;
+		u32 rsv1:8;
+		u32 sel:1;
+		u32 rsv:15;
+	} info;
+	u32 data;
+};
+
+/*  --------  USTORE  --------  */
+#define NBL_USTORE_PKT_LEN_ADDR (NBL_DP_USTORE_BASE + 0x00000108)
+#define NBL_USTORE_PORT_DROP_TH_REG_ARR(port_id) \
+	(NBL_DP_USTORE_BASE + 0x00000150 +       \
+	 (port_id) * sizeof(union nbl_ustore_port_drop_th_u))
+#define NBL_USTORE_BUF_PORT_DROP_PKT(eth_id) \
+	(NBL_DP_USTORE_BASE + 0x00002500 + (eth_id) * sizeof(u32))
+#define NBL_USTORE_BUF_PORT_TRUN_PKT(eth_id) \
+	(NBL_DP_USTORE_BASE + 0x00002540 + (eth_id) * sizeof(u32))
+
+#define NBL_USTORE_SINGLE_ETH_DROP_TH		0xC80
+#define NBL_USTORE_DUAL_ETH_DROP_TH		0x640
+#define NBL_USTORE_QUAD_ETH_DROP_TH		0x320
+
+/* USTORE pkt_len */
+union ustore_pkt_len_u {
+	struct ustore_pkt_len {
+		u32 min:7;
+		u32 rsv:8;
+		u32 min_chk_en:1;
+		u32 max:14;
+		u32 rsv2:1;
+		u32 max_chk_len:1;
+	} info;
+	u32 data;
+};
+
+/* USTORE port_drop_th */
+union nbl_ustore_port_drop_th_u {
+	struct nbl_ustore_port_drop_th {
+		u32 disc_th:12;
+		u32 rsv:19;
+		u32 en:1;
+	} info;
+	u32 data;
+};
+
+#define NBL_UQM_QUE_TYPE			(NBL_DP_UQM_BASE + 0x0000013c)
+#define NBL_UQM_DROP_PKT_CNT			(NBL_DP_UQM_BASE + 0x000009C0)
+#define NBL_UQM_DROP_PKT_SLICE_CNT		(NBL_DP_UQM_BASE + 0x000009C4)
+#define NBL_UQM_DROP_PKT_LEN_ADD_CNT		(NBL_DP_UQM_BASE + 0x000009C8)
+#define NBL_UQM_DROP_HEAD_PNTR_ADD_CNT		(NBL_DP_UQM_BASE + 0x000009CC)
+#define NBL_UQM_DROP_WEIGHT_ADD_CNT		(NBL_DP_UQM_BASE + 0x000009D0)
+#define NBL_UQM_PORT_DROP_PKT_CNT		(NBL_DP_UQM_BASE + 0x000009D4)
+#define NBL_UQM_PORT_DROP_PKT_SLICE_CNT		(NBL_DP_UQM_BASE + 0x000009F4)
+#define NBL_UQM_PORT_DROP_PKT_LEN_ADD_CNT	(NBL_DP_UQM_BASE + 0x00000A14)
+#define NBL_UQM_PORT_DROP_HEAD_PNTR_ADD_CNT	(NBL_DP_UQM_BASE + 0x00000A34)
+#define NBL_UQM_PORT_DROP_WEIGHT_ADD_CNT	(NBL_DP_UQM_BASE + 0x00000A54)
+#define NBL_UQM_FWD_DROP_CNT			(NBL_DP_UQM_BASE + 0x00000A80)
+#define NBL_UQM_DPORT_DROP_CNT			(NBL_DP_UQM_BASE + 0x00000B74)
+
+#define NBL_UQM_PORT_DROP_DEPTH			6
+#define NBL_UQM_DPORT_DROP_DEPTH		16
+
+union nbl_uqm_que_type_u {
+	struct nbl_uqm_que_type {
+		u32 bp_drop:1;
+		u32 rsv:31;
+	} info;
+	u32 data;
+};
+
+#define NBL_BYTES_IN_REG 4
+#define NBL_SHAPING_DPORT_ADDR 0x504700
+#define NBL_SHAPING_DPORT_DWLEN 4
+#define NBL_SHAPING_DPORT_REG(r) \
+	(NBL_SHAPING_DPORT_ADDR + (NBL_SHAPING_DPORT_DWLEN * 4) * (r))
+#define NBL_SHAPING_DVN_DPORT_ADDR 0x504750
+#define NBL_SHAPING_DVN_DPORT_DWLEN 4
+#define NBL_SHAPING_DVN_DPORT_REG(r) \
+	(NBL_SHAPING_DVN_DPORT_ADDR + (NBL_SHAPING_DVN_DPORT_DWLEN * 4) * (r))
+#define NBL_DSCH_PSHA_EN_ADDR 0x404314
+#define NBL_SHAPING_NET_ADDR 0x505800
+#define NBL_SHAPING_NET_DWLEN 4
+#define NBL_SHAPING_NET_REG(r) \
+	(NBL_SHAPING_NET_ADDR + (NBL_SHAPING_NET_DWLEN * 4) * (r))
+
+#define DPORT_VALID_MASK (0x1ULL << 0)
+#define DPORT_DEPTH_MASK (0x7FFFFULL << 1)	// [19:1]
+#define DPORT_CIR_MASK (0x7FFFFULL << 20)	// [38:20]
+#define DPORT_PIR_MASK (0x7FFFFULL << 39)	// [57:39]
+#define DPORT_CBS_MASK_LOW (0x3FULL << 58)		// [63:58]
+#define DPORT_CBS_MASK_HIGH (0x7FFFULL << (0)) // [78:64] -> high[14:0]
+#define DPORT_PBS_MASK (0x1FFFFFULL << (79 - 64)) // [99:79] -> high[35:15]
+
+/* SHAPING shaping_net */
+union nbl_shaping_net_u {
+	struct nbl_shaping_net {
+		u64 low;
+		u64 high;
+	} info;
+	u32 data[NBL_SHAPING_NET_DWLEN];
+};
+
+union nbl_shaping_dport_u {
+	struct nbl_shaping_dport {
+		u64 low;
+		u64 high;
+	} info;
+	u32 data[NBL_SHAPING_DPORT_DWLEN];
+};
+
+union nbl_shaping_dvn_dport_u {
+	struct nbl_shaping_dvn_dport {
+		u64 low;
+		u64 high;
+	} info;
+	u32 data[NBL_SHAPING_DVN_DPORT_DWLEN];
+};
+
+#define NBL_DPED_L4_CK_CMD_40_ADDR  0x75c338
+#define NBL_DPED_L4_CK_CMD_40_DEPTH 1
+#define NBL_DPED_L4_CK_CMD_40_WIDTH 32
+#define NBL_DPED_L4_CK_CMD_40_DWLEN 1
+union dped_l4_ck_cmd_40_u {
+	struct dped_l4_ck_cmd_40 {
+		u32 value:8;             /* [7:0] Default:0x0 RW */
+		u32 len_in_oft:7;        /* [14:8] Default:0x0 RW */
+		u32 len_phid:2;          /* [16:15] Default:0x0 RW */
+		u32 len_vld:1;           /* [17] Default:0x0 RW */
+		u32 data_vld:1;          /* [18] Default:0x0 RW */
+		u32 in_oft:7;            /* [25:19] Default:0x8 RW */
+		u32 phid:2;              /* [27:26] Default:0x3 RW */
+		u32 flag:1;              /* [28] Default:0x0 RW */
+		u32 mode:1;              /* [29] Default:0x1 RW */
+		u32 rsv:1;               /* [30] Default:0x0 RO */
+		u32 en:1;                /* [31] Default:0x0 RW */
+	} __packed info;
+	u32 data[NBL_DPED_L4_CK_CMD_40_DWLEN];
+} __packed;
+
+#define NBL_DSTORE_D_DPORT_FC_TH_ADDR  0x704600
+#define NBL_DSTORE_D_DPORT_FC_TH_DEPTH 5
+#define NBL_DSTORE_D_DPORT_FC_TH_WIDTH 32
+#define NBL_DSTORE_D_DPORT_FC_TH_DWLEN 1
+union dstore_d_dport_fc_th_u {
+	struct dstore_d_dport_fc_th {
+		u32 xoff_th:11;          /* [10:0] Default:200 RW */
+		u32 rsv1:5;              /* [15:11] Default:0x0 RO */
+		u32 xon_th:11;           /* [26:16] Default:100 RW */
+		u32 rsv:3;               /* [29:27] Default:0x0 RO */
+		u32 fc_set:1;            /* [30:30] Default:0x0 RW */
+		u32 fc_en:1;             /* [31:31] Default:0x0 RW */
+	} __packed info;
+	u32 data[NBL_DSTORE_D_DPORT_FC_TH_DWLEN];
+} __packed;
+#define NBL_DSTORE_D_DPORT_FC_TH_REG(r) (NBL_DSTORE_D_DPORT_FC_TH_ADDR + \
+		(NBL_DSTORE_D_DPORT_FC_TH_DWLEN * 4) * (r))
+#define NBL_DSTORE_PORT_DROP_TH_ADDR  0x704150
+#define NBL_DSTORE_PORT_DROP_TH_DEPTH 6
+#define NBL_DSTORE_PORT_DROP_TH_WIDTH 32
+#define NBL_DSTORE_PORT_DROP_TH_DWLEN 1
+union dstore_port_drop_th_u {
+	struct dstore_port_drop_th {
+		u32 disc_th:10;          /* [9:0] Default:800 RW */
+		u32 rsv:21;              /* [30:10] Default:0x0 RO */
+		u32 en:1;                /* [31] Default:0x1 RW */
+	} __packed info;
+	u32 data[NBL_DSTORE_PORT_DROP_TH_DWLEN];
+} __packed;
+#define NBL_DSTORE_PORT_DROP_TH_REG(r) (NBL_DSTORE_PORT_DROP_TH_ADDR + \
+		(NBL_DSTORE_PORT_DROP_TH_DWLEN * 4) * (r))
+
+#define NBL_FW_BOARD_CONFIG			0x200
+#define NBL_FW_BOARD_DW3_OFFSET			(NBL_FW_BOARD_CONFIG + 12)
+#define NBL_FW_BOARD_DW6_OFFSET			(NBL_FW_BOARD_CONFIG + 24)
+union nbl_fw_board_cfg_dw3 {
+	struct board_cfg_dw3 {
+		u32 port_type:1;
+		u32 port_num:7;
+		u32 port_speed:2;
+		u32 gpio_type:3;
+		u32 p4_version:1; /* 0: low version; 1: high version */
+		u32 rsv:18;
+	} __packed info;
+	u32 data;
+};
+
+union nbl_fw_board_cfg_dw6 {
+	struct board_cfg_dw6 {
+		u8 lane_bitmap;
+		u8 eth_bitmap;
+		u16 rsv;
+	} __packed info;
+	u32 data;
+};
+
+#define NBL_LEONIS_QUIRKS_OFFSET	0x00000140
+#define NBL_LEONIS_ILLEGAL_REG_VALUE	0xDEADBEEF
+
 #endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis_regs.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis_regs.c
new file mode 100644
index 000000000000..70e97356ddee
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis_regs.c
@@ -0,0 +1,2887 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+#include <linux/device.h>
+#include <linux/io.h>
+#include "nbl_hw_leonis.h"
+#include "nbl_hw_leonis_regs.h"
+
+#define NBL_SEC_BLOCK_SIZE		0x100
+#define NBL_SEC000_SIZE			1
+#define NBL_SEC000_ADDR			0x114150
+#define NBL_SEC001_SIZE			1
+#define NBL_SEC001_ADDR			0x15c190
+#define NBL_SEC002_SIZE			1
+#define NBL_SEC002_ADDR			0x10417c
+#define NBL_SEC003_SIZE			1
+#define NBL_SEC003_ADDR			0x714154
+#define NBL_SEC004_SIZE			1
+#define NBL_SEC004_ADDR			0x75c190
+#define NBL_SEC005_SIZE			1
+#define NBL_SEC005_ADDR			0x70417c
+#define NBL_SEC006_SIZE			512
+#define NBL_SEC006_ADDR			0x8f000
+#define NBL_SEC006_REGI(i)		(0x8f000 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC007_SIZE			256
+#define NBL_SEC007_ADDR			0x8f800
+#define NBL_SEC007_REGI(i)		(0x8f800 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC008_SIZE			1024
+#define NBL_SEC008_ADDR			0x90000
+#define NBL_SEC008_REGI(i)		(0x90000 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC009_SIZE			2048
+#define NBL_SEC009_ADDR			0x94000
+#define NBL_SEC009_REGI(i)		(0x94000 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC010_SIZE			256
+#define NBL_SEC010_ADDR			0x96000
+#define NBL_SEC010_REGI(i)		(0x96000 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC011_SIZE			1024
+#define NBL_SEC011_ADDR			0x91000
+#define NBL_SEC011_REGI(i)		(0x91000 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC012_SIZE			128
+#define NBL_SEC012_ADDR			0x92000
+#define NBL_SEC012_REGI(i)		(0x92000 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC013_SIZE			64
+#define NBL_SEC013_ADDR			0x92200
+#define NBL_SEC013_REGI(i)		(0x92200 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC014_SIZE			64
+#define NBL_SEC014_ADDR			0x92300
+#define NBL_SEC014_REGI(i)		(0x92300 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC015_SIZE			1
+#define NBL_SEC015_ADDR			0x8c214
+#define NBL_SEC016_SIZE			1
+#define NBL_SEC016_ADDR			0x8c220
+#define NBL_SEC017_SIZE			1
+#define NBL_SEC017_ADDR			0x8c224
+#define NBL_SEC018_SIZE			1
+#define NBL_SEC018_ADDR			0x8c228
+#define NBL_SEC019_SIZE			1
+#define NBL_SEC019_ADDR			0x8c22c
+#define NBL_SEC020_SIZE			1
+#define NBL_SEC020_ADDR			0x8c1f0
+#define NBL_SEC021_SIZE			1
+#define NBL_SEC021_ADDR			0x8c1f8
+/* HW reserved gap after 256 regs */
+#define NBL_SEC022_SIZE			256
+#define NBL_SEC022_ADDR			0x85f000
+#define NBL_SEC022_REGI(i)		(0x85f000 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC023_SIZE			128
+#define NBL_SEC023_ADDR			0x85f800
+#define NBL_SEC023_REGI(i)		(0x85f800 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC024_SIZE			512
+#define NBL_SEC024_ADDR			0x860000
+#define NBL_SEC024_REGI(i)		(0x860000 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC025_SIZE			1024
+#define NBL_SEC025_ADDR			0x864000
+#define NBL_SEC025_REGI(i)		(0x864000 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC026_SIZE			256
+#define NBL_SEC026_ADDR			0x866000
+#define NBL_SEC026_REGI(i)		(0x866000 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC027_SIZE			512
+#define NBL_SEC027_ADDR			0x861000
+#define NBL_SEC027_REGI(i)		(0x861000 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC028_SIZE			64
+#define NBL_SEC028_ADDR			0x862000
+#define NBL_SEC028_REGI(i)		(0x862000 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC029_SIZE			32
+#define NBL_SEC029_ADDR			0x862200
+#define NBL_SEC029_REGI(i)		(0x862200 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC030_SIZE			32
+#define NBL_SEC030_ADDR			0x862300
+#define NBL_SEC030_REGI(i)		(0x862300 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC031_SIZE			1
+#define NBL_SEC031_ADDR			0x85c214
+#define NBL_SEC032_SIZE			1
+#define NBL_SEC032_ADDR			0x85c220
+#define NBL_SEC033_SIZE			1
+#define NBL_SEC033_ADDR			0x85c224
+#define NBL_SEC034_SIZE			1
+#define NBL_SEC034_ADDR			0x85c228
+#define NBL_SEC035_SIZE			1
+#define NBL_SEC035_ADDR			0x85c22c
+#define NBL_SEC036_SIZE			1
+#define NBL_SEC036_ADDR			0xb04200
+#define NBL_SEC037_SIZE			1
+#define NBL_SEC037_ADDR			0xb04230
+#define NBL_SEC038_SIZE			1
+#define NBL_SEC038_ADDR			0xb04234
+#define NBL_SEC039_SIZE			64
+#define NBL_SEC039_ADDR			0xb05800
+#define NBL_SEC039_REGI(i)		(0xb05800 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC040_SIZE			32
+#define NBL_SEC040_ADDR			0xb05400
+#define NBL_SEC040_REGI(i)		(0xb05400 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC041_SIZE			16
+#define NBL_SEC041_ADDR			0xb05500
+#define NBL_SEC041_REGI(i)		(0xb05500 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC042_SIZE			1
+#define NBL_SEC042_ADDR			0xb14148
+#define NBL_SEC043_SIZE			1
+#define NBL_SEC043_ADDR			0xb14104
+#define NBL_SEC044_SIZE			1
+#define NBL_SEC044_ADDR			0xb1414c
+#define NBL_SEC045_SIZE			1
+#define NBL_SEC045_ADDR			0xb14150
+#define NBL_SEC046_SIZE			256
+#define NBL_SEC046_ADDR			0xb15000
+#define NBL_SEC046_REGI(i)		(0xb15000 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC047_SIZE			32
+#define NBL_SEC047_ADDR			0xb15800
+#define NBL_SEC047_REGI(i)		(0xb15800 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC048_SIZE			1
+#define NBL_SEC048_ADDR			0xb24148
+#define NBL_SEC049_SIZE			1
+#define NBL_SEC049_ADDR			0xb24104
+#define NBL_SEC050_SIZE			1
+#define NBL_SEC050_ADDR			0xb2414c
+#define NBL_SEC051_SIZE			1
+#define NBL_SEC051_ADDR			0xb24150
+#define NBL_SEC052_SIZE			256
+#define NBL_SEC052_ADDR			0xb25000
+#define NBL_SEC052_REGI(i)		(0xb25000 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC053_SIZE			32
+#define NBL_SEC053_ADDR			0xb25800
+#define NBL_SEC053_REGI(i)		(0xb25800 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC054_SIZE			1
+#define NBL_SEC054_ADDR			0xb34148
+#define NBL_SEC055_SIZE			1
+#define NBL_SEC055_ADDR			0xb34104
+#define NBL_SEC056_SIZE			1
+#define NBL_SEC056_ADDR			0xb3414c
+#define NBL_SEC057_SIZE			1
+#define NBL_SEC057_ADDR			0xb34150
+#define NBL_SEC058_SIZE			256
+#define NBL_SEC058_ADDR			0xb35000
+#define NBL_SEC058_REGI(i)		(0xb35000 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC059_SIZE			32
+#define NBL_SEC059_ADDR			0xb35800
+#define NBL_SEC059_REGI(i)		(0xb35800 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC060_SIZE			1
+#define NBL_SEC060_ADDR			0xe74630
+#define NBL_SEC061_SIZE			1
+#define NBL_SEC061_ADDR			0xe74634
+#define NBL_SEC062_SIZE			64
+#define NBL_SEC062_ADDR			0xe75000
+#define NBL_SEC062_REGI(i)		(0xe75000 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC063_SIZE			32
+#define NBL_SEC063_ADDR			0xe75480
+#define NBL_SEC063_REGI(i)		(0xe75480 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC064_SIZE			16
+#define NBL_SEC064_ADDR			0xe75980
+#define NBL_SEC064_REGI(i)		(0xe75980 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC065_SIZE			32
+#define NBL_SEC065_ADDR			0x15f000
+#define NBL_SEC065_REGI(i)		(0x15f000 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC066_SIZE			32
+#define NBL_SEC066_ADDR			0x75f000
+#define NBL_SEC066_REGI(i)		(0x75f000 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC067_SIZE			1
+#define NBL_SEC067_ADDR			0xb64108
+#define NBL_SEC068_SIZE			1
+#define NBL_SEC068_ADDR			0xb6410c
+#define NBL_SEC069_SIZE			1
+#define NBL_SEC069_ADDR			0xb64140
+#define NBL_SEC070_SIZE			1
+#define NBL_SEC070_ADDR			0xb64144
+#define NBL_SEC071_SIZE			512
+#define NBL_SEC071_ADDR			0xb65000
+#define NBL_SEC071_REGI(i)		(0xb65000 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC072_SIZE			32
+#define NBL_SEC072_ADDR			0xb65800
+#define NBL_SEC072_REGI(i)		(0xb65800 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC073_SIZE			1
+#define NBL_SEC073_ADDR			0x8c210
+#define NBL_SEC074_SIZE			1
+#define NBL_SEC074_ADDR			0x85c210
+#define NBL_SEC075_SIZE			4
+#define NBL_SEC075_ADDR			0x8c1b0
+#define NBL_SEC075_REGI(i)		(0x8c1b0 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC076_SIZE			4
+#define NBL_SEC076_ADDR			0x8c1c0
+#define NBL_SEC076_REGI(i)		(0x8c1c0 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC077_SIZE			4
+#define NBL_SEC077_ADDR			0x85c1b0
+#define NBL_SEC077_REGI(i)		(0x85c1b0 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC078_SIZE			1
+#define NBL_SEC078_ADDR			0x85c1ec
+#define NBL_SEC079_SIZE			1
+#define NBL_SEC079_ADDR			0x8c1ec
+#define NBL_SEC080_SIZE			1
+#define NBL_SEC080_ADDR			0xb04440
+#define NBL_SEC081_SIZE			1
+#define NBL_SEC081_ADDR			0xb04448
+#define NBL_SEC082_SIZE			1
+#define NBL_SEC082_ADDR			0xb14450
+#define NBL_SEC083_SIZE			1
+#define NBL_SEC083_ADDR			0xb24450
+#define NBL_SEC084_SIZE			1
+#define NBL_SEC084_ADDR			0xb34450
+#define NBL_SEC085_SIZE			1
+#define NBL_SEC085_ADDR			0xa04188
+#define NBL_SEC086_SIZE			1
+#define NBL_SEC086_ADDR			0xe74218
+#define NBL_SEC087_SIZE			1
+#define NBL_SEC087_ADDR			0xe7421c
+#define NBL_SEC088_SIZE			1
+#define NBL_SEC088_ADDR			0xe74220
+#define NBL_SEC089_SIZE			1
+#define NBL_SEC089_ADDR			0xe74224
+#define NBL_SEC090_SIZE			1
+#define NBL_SEC090_ADDR			0x75c22c
+#define NBL_SEC091_SIZE			1
+#define NBL_SEC091_ADDR			0x75c230
+#define NBL_SEC092_SIZE			1
+#define NBL_SEC092_ADDR			0x75c238
+#define NBL_SEC093_SIZE			1
+#define NBL_SEC093_ADDR			0x75c244
+#define NBL_SEC094_SIZE			1
+#define NBL_SEC094_ADDR			0x75c248
+#define NBL_SEC095_SIZE			1
+#define NBL_SEC095_ADDR			0x75c250
+#define NBL_SEC096_SIZE			1
+#define NBL_SEC096_ADDR			0x15c230
+#define NBL_SEC097_SIZE			1
+#define NBL_SEC097_ADDR			0x15c234
+#define NBL_SEC098_SIZE			1
+#define NBL_SEC098_ADDR			0x15c238
+#define NBL_SEC099_SIZE			1
+#define NBL_SEC099_ADDR			0x15c23c
+#define NBL_SEC100_SIZE			1
+#define NBL_SEC100_ADDR			0x15c244
+#define NBL_SEC101_SIZE			1
+#define NBL_SEC101_ADDR			0x15c248
+#define NBL_SEC102_SIZE			1
+#define NBL_SEC102_ADDR			0xb6432c
+#define NBL_SEC103_SIZE			1
+#define NBL_SEC103_ADDR			0xb64220
+#define NBL_SEC104_SIZE			1
+#define NBL_SEC104_ADDR			0xb44804
+#define NBL_SEC105_SIZE			1
+#define NBL_SEC105_ADDR			0xb44a00
+#define NBL_SEC106_SIZE			1
+#define NBL_SEC106_ADDR			0xe84210
+#define NBL_SEC107_SIZE			1
+#define NBL_SEC107_ADDR			0xe84214
+#define NBL_SEC108_SIZE			1
+#define NBL_SEC108_ADDR			0xe64228
+#define NBL_SEC109_SIZE			1
+#define NBL_SEC109_ADDR			0x65413c
+#define NBL_SEC110_SIZE			1
+#define NBL_SEC110_ADDR			0x984144
+#define NBL_SEC111_SIZE			1
+#define NBL_SEC111_ADDR			0x114130
+#define NBL_SEC112_SIZE			1
+#define NBL_SEC112_ADDR			0x714138
+#define NBL_SEC113_SIZE			1
+#define NBL_SEC113_ADDR			0x114134
+#define NBL_SEC114_SIZE			1
+#define NBL_SEC114_ADDR			0x71413c
+#define NBL_SEC115_SIZE			1
+#define NBL_SEC115_ADDR			0x90437c
+#define NBL_SEC116_SIZE			32
+#define NBL_SEC116_ADDR			0xb05000
+#define NBL_SEC116_REGI(i)		(0xb05000 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC117_SIZE			1
+#define NBL_SEC117_ADDR			0xb043e0
+#define NBL_SEC118_SIZE			1
+#define NBL_SEC118_ADDR			0xb043f0
+#define NBL_SEC119_SIZE			5
+#define NBL_SEC119_ADDR			0x8c230
+#define NBL_SEC119_REGI(i)		(0x8c230 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC120_SIZE			1
+#define NBL_SEC120_ADDR			0x8c1f4
+#define NBL_SEC121_SIZE			1
+#define NBL_SEC121_ADDR			0x2046c4
+#define NBL_SEC122_SIZE			1
+#define NBL_SEC122_ADDR			0x85c1f4
+#define NBL_SEC123_SIZE			1
+#define NBL_SEC123_ADDR			0x75c194
+#define NBL_SEC124_SIZE			256
+#define NBL_SEC124_ADDR			0xa05000
+#define NBL_SEC124_REGI(i)		(0xa05000 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC125_SIZE			256
+#define NBL_SEC125_ADDR			0xa06000
+#define NBL_SEC125_REGI(i)		(0xa06000 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC126_SIZE			256
+#define NBL_SEC126_ADDR			0xa07000
+#define NBL_SEC126_REGI(i)		(0xa07000 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC127_SIZE			1
+#define NBL_SEC127_ADDR			0x75c204
+#define NBL_SEC128_SIZE			1
+#define NBL_SEC128_ADDR			0x15c204
+#define NBL_SEC129_SIZE			1
+#define NBL_SEC129_ADDR			0x75c208
+#define NBL_SEC130_SIZE			(1)
+#define NBL_SEC130_ADDR			(0x15c208)
+#define NBL_SEC131_SIZE			1
+#define NBL_SEC131_ADDR			0x75c20c
+#define NBL_SEC132_SIZE			1
+#define NBL_SEC132_ADDR			0x15c20c
+#define NBL_SEC133_SIZE			(1)
+#define NBL_SEC133_ADDR			(0x75c210)
+#define NBL_SEC134_SIZE			1
+#define NBL_SEC134_ADDR			0x15c210
+#define NBL_SEC135_SIZE			1
+#define NBL_SEC135_ADDR			0x75c214
+#define NBL_SEC136_SIZE			1
+#define NBL_SEC136_ADDR			0x15c214
+#define NBL_SEC137_SIZE			32
+#define NBL_SEC137_ADDR			0x15d000
+#define NBL_SEC137_REGI(i)		(0x15d000 + NBL_BYTES_IN_REG * (i))
+#define NBL_SEC138_SIZE			32
+#define NBL_SEC138_ADDR			0x75d000
+#define NBL_SEC138_REGI(i)		(0x75d000 + NBL_BYTES_IN_REG * (i))
+
+static const u32 nbl_sec046_1p_data[] = {
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xa0000000,
+	0x00077c2b, 0x005c0000, 0x00000000, 0x00008100, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x20000000, 0x00073029, 0x00480000,
+	0x00000000, 0x00008100, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x20000000, 0x00073029, 0x00480000, 0x70000000, 0x00000020,
+	0x24140000, 0x00000020, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xa0000000,
+	0x00000009, 0x00000000, 0x00000000, 0x00002100, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0xb0000000, 0x00000009, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000100,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000100, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x70000000, 0x00000000, 0x20140000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x70000000, 0x00000000,
+	0x20140000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x38430000, 0x70000006, 0x00000020, 0x24140000, 0x00000020,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x98cb1180, 0x6e36d469, 0x9d8eb91c, 0x87e3ef47, 0xa2931288, 0x08405c5a,
+	0x73865086, 0x00000080, 0x30140000, 0x00000080, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0xb0000000, 0x000b3849, 0x38430000, 0x00000006, 0x0000c100,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xb0000000,
+	0x00133889, 0x08400000, 0x03865086, 0x4c016100, 0x00000014, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec071_1p_data[] = {
+	0x00000000, 0x00000000, 0x00113d00, 0x00000000, 0x00000000, 0x00000000,
+	0xe7029b00, 0x00000000, 0x00000000, 0x43000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x51e00000, 0x00000c9c, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00293d00, 0x00000000,
+	0x00000000, 0x00000000, 0x67089b00, 0x00000002, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x80000000, 0x00000000, 0xb1e00000, 0x0000189c,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00213d00, 0x00000000, 0x00000000, 0x00000000, 0xe7069b00, 0x00000001,
+	0x00000000, 0x43000000, 0x014b0c70, 0x00000000, 0x00000000, 0x00000000,
+	0x92600000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00213d00, 0x00000000, 0x00000000, 0x00000000,
+	0xe7069b00, 0x00000001, 0x00000000, 0x43000000, 0x015b0c70, 0x00000000,
+	0x00000000, 0x00000000, 0x92600000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00553d00, 0x00000000,
+	0x00000000, 0x00000000, 0xe6d29a00, 0x000149c4, 0x00000000, 0x4b000000,
+	0x00000004, 0x00000000, 0x80000000, 0x00022200, 0x62600000, 0x00000001,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00553d00, 0x00000000, 0x00000000, 0x00000000, 0xe6d2c000, 0x000149c4,
+	0x00000000, 0x5b000000, 0x00000004, 0x00000000, 0x80000000, 0x00022200,
+	0x62600000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x006d3d00, 0x00000000, 0x00000000, 0x00000000,
+	0x64d49200, 0x5e556945, 0xc666d89a, 0x4b0001a9, 0x00004c84, 0x00000000,
+	0x80000000, 0x00022200, 0xc2600000, 0x00000001, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x006d3d00, 0x00000000,
+	0x00000000, 0x00000000, 0x6ed4ba00, 0x5ef56bc5, 0xc666d8c0, 0x5b0001a9,
+	0x00004dc4, 0x00000000, 0x80000000, 0x00022200, 0xc2600000, 0x00000001,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00700000, 0x00000000, 0x08028000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec046_2p_data[] = {
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xa0000000,
+	0x00077c2b, 0x005c0000, 0x00000000, 0x00008100, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x20000000, 0x00073029, 0x00480000,
+	0x00000000, 0x00008100, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x20000000, 0x00073029, 0x00480000, 0x70000000, 0x00000020,
+	0x04140000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xa0000000,
+	0x00000009, 0x00000000, 0x00000000, 0x00002100, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0xb0000000, 0x00000009, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000100,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000100, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x70000000, 0x00000000, 0x00140000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x70000000, 0x00000000,
+	0x00140000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x38430000, 0x70000006, 0x00000020, 0x04140000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x98cb1180, 0x6e36d469, 0x9d8eb91c, 0x87e3ef47, 0xa2931288, 0x08405c5a,
+	0x73865086, 0x00000080, 0x10140000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0xb0000000, 0x000b3849, 0x38430000, 0x00000006, 0x0000c100,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xb0000000,
+	0x00133889, 0x08400000, 0x03865086, 0x4c016100, 0x00000014, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec071_2p_data[] = {
+	0x00000000, 0x00000000, 0x00113d00, 0x00000000, 0x00000000, 0x00000000,
+	0xe7029b00, 0x00000000, 0x00000000, 0x43000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x51e00000, 0x00000c9c, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00293d00, 0x00000000,
+	0x00000000, 0x00000000, 0x67089b00, 0x00000002, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x80000000, 0x00000000, 0xb1e00000, 0x0000189c,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00213d00, 0x00000000, 0x00000000, 0x00000000, 0xe7069b00, 0x00000001,
+	0x00000000, 0x43000000, 0x014b0c70, 0x00000000, 0x00000000, 0x00000000,
+	0x92600000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00213d00, 0x00000000, 0x00000000, 0x00000000,
+	0xe7069b00, 0x00000001, 0x00000000, 0x43000000, 0x015b0c70, 0x00000000,
+	0x00000000, 0x00000000, 0x92600000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00553d00, 0x00000000,
+	0x00000000, 0x00000000, 0xe6d29a00, 0x000149c4, 0x00000000, 0x4b000000,
+	0x00000004, 0x00000000, 0x80000000, 0x00022200, 0x62600000, 0x00000001,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00553d00, 0x00000000, 0x00000000, 0x00000000, 0xe6d2c000, 0x000149c4,
+	0x00000000, 0x5b000000, 0x00000004, 0x00000000, 0x80000000, 0x00022200,
+	0x62600000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x006d3d00, 0x00000000, 0x00000000, 0x00000000,
+	0x64d49200, 0x5e556945, 0xc666d89a, 0x4b0001a9, 0x00004c84, 0x00000000,
+	0x80000000, 0x00022200, 0xc2600000, 0x00000001, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x006d3d00, 0x00000000,
+	0x00000000, 0x00000000, 0x6ed4ba00, 0x5ef56bc5, 0xc666d8c0, 0x5b0001a9,
+	0x00004dc4, 0x00000000, 0x80000000, 0x00022200, 0xc2600000, 0x00000001,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00700000, 0x00000000, 0x00028000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec006_data[] = {
+	0x81008100, 0x00000001, 0x88a88100, 0x00000001, 0x810088a8, 0x00000001,
+	0x88a888a8, 0x00000001, 0x81000000, 0x00000001, 0x88a80000, 0x00000001,
+	0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x08004000, 0x00000001, 0x86dd6000, 0x00000001,
+	0x81000000, 0x00000001, 0x88a80000, 0x00000001, 0x08060000, 0x00000001,
+	0x80350000, 0x00000001, 0x88080000, 0x00000001, 0x88f70000, 0x00000001,
+	0x88cc0000, 0x00000001, 0x88090000, 0x00000001, 0x89150000, 0x00000001,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x11006000, 0x00000001,
+	0x06006000, 0x00000001, 0x02006000, 0x00000001, 0x3a006000, 0x00000001,
+	0x2f006000, 0x00000001, 0x84006000, 0x00000001, 0x32006000, 0x00000001,
+	0x2c006000, 0x00000001, 0x3c006000, 0x00000001, 0x2b006000, 0x00000001,
+	0x00006000, 0x00000001, 0x00004000, 0x00000001, 0x00004000, 0x00000001,
+	0x20004000, 0x00000001, 0x40004000, 0x00000001, 0x00000000, 0x00000001,
+	0x11000000, 0x00000001, 0x06000000, 0x00000001, 0x02000000, 0x00000001,
+	0x3a000000, 0x00000001, 0x2f000000, 0x00000001, 0x84000000, 0x00000001,
+	0x32000000, 0x00000001, 0x2c000000, 0x00000001, 0x2b000000, 0x00000001,
+	0x3c000000, 0x00000001, 0x3b000000, 0x00000001, 0x00000000, 0x00000001,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x11000000, 0x00000001, 0x06000000, 0x00000001,
+	0x02000000, 0x00000001, 0x3a000000, 0x00000001, 0x2f000000, 0x00000001,
+	0x84000000, 0x00000001, 0x32000000, 0x00000001, 0x00000000, 0x00000000,
+	0x2c000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x2b000000, 0x00000001, 0x3c000000, 0x00000001,
+	0x3b000000, 0x00000001, 0x00000000, 0x00000001, 0x06001072, 0x00000001,
+	0x06000000, 0x00000001, 0x110017c1, 0x00000001, 0x110012b7, 0x00000001,
+	0x110012b5, 0x00000001, 0x01000000, 0x00000001, 0x02000000, 0x00000001,
+	0x3a000000, 0x00000001, 0x11000043, 0x00000001, 0x11000044, 0x00000001,
+	0x11000222, 0x00000001, 0x11000000, 0x00000001, 0x2f006558, 0x00000001,
+	0x32000000, 0x00000001, 0x84000000, 0x00000001, 0x00000000, 0x00000001,
+	0x65582000, 0x00000001, 0x65583000, 0x00000001, 0x6558a000, 0x00000001,
+	0x6558b000, 0x00000001, 0x65580000, 0x00000001, 0x12b50000, 0x00000001,
+	0x02000102, 0x00000001, 0x00000000, 0x00000001, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x65580000, 0x00000001, 0x00000000, 0x00000001,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x81008100, 0x00000001,
+	0x88a88100, 0x00000001, 0x810088a8, 0x00000001, 0x88a888a8, 0x00000001,
+	0x81000000, 0x00000001, 0x88a80000, 0x00000001, 0x00000000, 0x00000001,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x08004000, 0x00000001, 0x86dd6000, 0x00000001, 0x81000000, 0x00000001,
+	0x88a80000, 0x00000001, 0x08060000, 0x00000001, 0x80350000, 0x00000001,
+	0x88080000, 0x00000001, 0x88f70000, 0x00000001, 0x88cc0000, 0x00000001,
+	0x88090000, 0x00000001, 0x89150000, 0x00000001, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000001, 0x11006000, 0x00000001, 0x06006000, 0x00000001,
+	0x02006000, 0x00000001, 0x3a006000, 0x00000001, 0x2f006000, 0x00000001,
+	0x84006000, 0x00000001, 0x32006000, 0x00000001, 0x2c006000, 0x00000001,
+	0x3c006000, 0x00000001, 0x2b006000, 0x00000001, 0x00006000, 0x00000001,
+	0x00004000, 0x00000001, 0x00004000, 0x00000001, 0x20004000, 0x00000001,
+	0x40004000, 0x00000001, 0x00000000, 0x00000001, 0x11000000, 0x00000001,
+	0x06000000, 0x00000001, 0x02000000, 0x00000001, 0x3a000000, 0x00000001,
+	0x2f000000, 0x00000001, 0x84000000, 0x00000001, 0x32000000, 0x00000001,
+	0x2c000000, 0x00000001, 0x2b000000, 0x00000001, 0x3c000000, 0x00000001,
+	0x3b000000, 0x00000001, 0x00000000, 0x00000001, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x11000000, 0x00000001, 0x06000000, 0x00000001, 0x02000000, 0x00000001,
+	0x3a000000, 0x00000001, 0x2f000000, 0x00000001, 0x84000000, 0x00000001,
+	0x32000000, 0x00000001, 0x00000000, 0x00000000, 0x2c000000, 0x00000001,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x2b000000, 0x00000001, 0x3c000000, 0x00000001, 0x3b000000, 0x00000001,
+	0x00000000, 0x00000001, 0x06001072, 0x00000001, 0x06000000, 0x00000001,
+	0x110012b7, 0x00000001, 0x01000000, 0x00000001, 0x02000000, 0x00000001,
+	0x3a000000, 0x00000001, 0x32000000, 0x00000001, 0x84000000, 0x00000001,
+	0x11000043, 0x00000001, 0x11000044, 0x00000001, 0x11000222, 0x00000001,
+	0x11000000, 0x00000001, 0x2f006558, 0x00000001, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec007_data[] = {
+	0x10001000, 0x00001000, 0x10000000, 0x00000000, 0x1000ffff, 0x0000ffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000fff, 0x00000fff,
+	0x1000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff,
+	0x0000ffff, 0x0000ffff, 0x0000ffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0x00ff0fff, 0x00ff0fff, 0x00ff0fff, 0x00ff0fff,
+	0x00ff0fff, 0x00ff0fff, 0x00ff0fff, 0x00ff0fff, 0x00ff0fff, 0x10ff0fff,
+	0xffff0fff, 0x00000fff, 0x1fff0fff, 0x1fff0fff, 0x1fff0fff, 0xffffffff,
+	0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff,
+	0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00ffffff, 0x00ffffff,
+	0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xffffffff,
+	0x00ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00ffffff, 0x00ffffff,
+	0x00ffffff, 0xffffffff, 0x00ff0000, 0x00ffffff, 0x00ff0000, 0x00ff0000,
+	0x00ff0000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ff0000, 0x00ff0000,
+	0x00ff0001, 0x00ffffff, 0x00ff0000, 0x00ffffff, 0x00ffffff, 0xffffffff,
+	0x00000fff, 0x00000fff, 0x00000fff, 0x00000fff, 0x00000fff, 0x0000ffff,
+	0xc0ff0000, 0xc0ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0000ffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0x10001000, 0x00001000, 0x10000000, 0x00000000,
+	0x1000ffff, 0x0000ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0x00000fff, 0x00000fff, 0x1000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff,
+	0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00ff0fff, 0x00ff0fff,
+	0x00ff0fff, 0x00ff0fff, 0x00ff0fff, 0x00ff0fff, 0x00ff0fff, 0x00ff0fff,
+	0x00ff0fff, 0x10ff0fff, 0xffff0fff, 0x00000fff, 0x1fff0fff, 0x1fff0fff,
+	0x1fff0fff, 0xffffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff,
+	0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff,
+	0x00ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff,
+	0x00ffffff, 0xffffffff, 0x00ffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0x00ffffff, 0x00ffffff, 0x00ffffff, 0xffffffff, 0x00ff0000, 0x00ffffff,
+	0x00ff0000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff,
+	0x00ff0000, 0x00ff0000, 0x00ff0001, 0x00ffffff, 0x00ff0000, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+};
+
+static const u32 nbl_sec008_data[] = {
+	0x00809190, 0x16009496, 0x00000100, 0x00000000, 0x00809190, 0x16009496,
+	0x00000100, 0x00000000, 0x00809190, 0x16009496, 0x00000100, 0x00000000,
+	0x00809190, 0x16009496, 0x00000100, 0x00000000, 0x00800090, 0x12009092,
+	0x00000100, 0x00000000, 0x00800090, 0x12009092, 0x00000100, 0x00000000,
+	0x00800000, 0x0e008c8e, 0x00000100, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x08909581, 0x00008680,
+	0x00000200, 0x00000000, 0x10900082, 0x28008680, 0x00000200, 0x00000000,
+	0x809b0093, 0x00000000, 0x00000100, 0x00000000, 0x809b0093, 0x00000000,
+	0x00000100, 0x00000000, 0x009b008f, 0x00000000, 0x00000100, 0x00000000,
+	0x009b008f, 0x00000000, 0x00000100, 0x00000000, 0x009b008f, 0x00000000,
+	0x00000100, 0x00000000, 0x009b008f, 0x00000000, 0x00000100, 0x00000000,
+	0x009b008f, 0x00000000, 0x00000100, 0x00000000, 0x009b008f, 0x00000000,
+	0x00000100, 0x00000000, 0x009b0000, 0x00000000, 0x00000100, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x009b0000, 0x00000000,
+	0x00000100, 0x00000000, 0x00000000, 0x00000082, 0x00000500, 0x00000000,
+	0x00000000, 0x00000082, 0x00000500, 0x00000000, 0x00000000, 0x00000082,
+	0x00000500, 0x00000000, 0x00000000, 0x00000082, 0x00000500, 0x00000000,
+	0x00000000, 0x00000082, 0x00000500, 0x00000000, 0x00000000, 0x00000082,
+	0x00000500, 0x00000000, 0x00000000, 0x00000082, 0x00000500, 0x00000000,
+	0x00ab0085, 0x08000000, 0x00000200, 0x00000000, 0x00ab0000, 0x00000000,
+	0x00000200, 0x00000000, 0x00ab0000, 0x00000000, 0x00000200, 0x00000000,
+	0x40000000, 0x01c180c2, 0x00000300, 0x00000000, 0x00000000, 0x00a089c2,
+	0x000005f0, 0x00000000, 0x000b0085, 0x00a00000, 0x000002f0, 0x00000000,
+	0x000b0085, 0x00a00000, 0x000002f0, 0x00000000, 0x00000000, 0x00a089c2,
+	0x000005f0, 0x00000000, 0x000b0000, 0x00000000, 0x00000200, 0x00000000,
+	0x00000000, 0x00000082, 0x00000500, 0x00000000, 0x00000000, 0x00000082,
+	0x00000500, 0x00000000, 0x00000000, 0x00000082, 0x00000500, 0x00000000,
+	0x00000000, 0x00000082, 0x00000500, 0x00000000, 0x00000000, 0x00000082,
+	0x00000500, 0x00000000, 0x00000000, 0x00000082, 0x00000500, 0x00000000,
+	0x00000000, 0x00000082, 0x00000500, 0x00000000, 0x00ab0085, 0x08000000,
+	0x00000300, 0x00000000, 0x00ab0000, 0x00000000, 0x00000300, 0x00000000,
+	0x00ab0000, 0x00000000, 0x00000300, 0x00000000, 0x00ab0000, 0x00000000,
+	0x00000300, 0x00000000, 0x40000000, 0x01c180c2, 0x00000400, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000082,
+	0x00000500, 0x00000000, 0x00000000, 0x00000082, 0x00000500, 0x00000000,
+	0x00000000, 0x00000082, 0x00000500, 0x00000000, 0x00000000, 0x00000082,
+	0x00000500, 0x00000000, 0x00000000, 0x00000082, 0x00000500, 0x00000000,
+	0x00000000, 0x00000082, 0x00000500, 0x00000000, 0x00000000, 0x00000082,
+	0x00000500, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00ab0085, 0x08000000, 0x00000400, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ab0000, 0x00000000,
+	0x00000400, 0x00000000, 0x00ab0000, 0x00000000, 0x00000400, 0x00000000,
+	0x00ab0000, 0x00000000, 0x00000400, 0x00000000, 0x00ab0000, 0x00000000,
+	0x00000400, 0x00000000, 0x01ab0083, 0x0ca00000, 0x0000050f, 0x00000000,
+	0x01ab0083, 0x0ca00000, 0x0000050f, 0x00000000, 0x02a00084, 0x08008890,
+	0x00000600, 0x00000000, 0x02ab848a, 0x08000000, 0x00000500, 0x00000000,
+	0x02a00084, 0x10008200, 0x00000600, 0x00000000, 0x00ab8f8e, 0x04000000,
+	0x00000500, 0x00000000, 0x00ab0000, 0x00000000, 0x00000500, 0x00000000,
+	0x00ab8f8e, 0x04000000, 0x00000500, 0x00000000, 0x02ab848f, 0x08000000,
+	0x00000500, 0x00000000, 0x02ab848f, 0x08000000, 0x00000500, 0x00000000,
+	0x02ab848f, 0x08000000, 0x00000500, 0x00000000, 0x02ab0084, 0x08000000,
+	0x00000500, 0x00000000, 0x00a00000, 0x04008280, 0x00000600, 0x00000000,
+	0x00ab0000, 0x00000000, 0x00000500, 0x00000000, 0x04ab8e84, 0x0c000000,
+	0x00000500, 0x00000000, 0x00ab0000, 0x00000000, 0x00000500, 0x00000000,
+	0x00000000, 0x0400ccd0, 0x00000800, 0x00000000, 0x00000000, 0x0800ccd0,
+	0x00000800, 0x00000000, 0x00000000, 0x0800ccd0, 0x00000800, 0x00000000,
+	0x00000000, 0x0c00ccd0, 0x00000800, 0x00000000, 0x00000000, 0x0000ccd0,
+	0x00000800, 0x00000000, 0x00000000, 0x0000ccd0, 0x00000800, 0x00000000,
+	0x00000000, 0x10008200, 0x00000700, 0x00000000, 0x00000000, 0x08008200,
+	0x00000700, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000ccd0,
+	0x00000800, 0x00000000, 0x00000000, 0x0000ccd0, 0x00000800, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00808786, 0x16009496, 0x00000900, 0x00000000,
+	0x00808786, 0x16009496, 0x00000900, 0x00000000, 0x00808786, 0x16009496,
+	0x00000900, 0x00000000, 0x00808786, 0x16009496, 0x00000900, 0x00000000,
+	0x00800086, 0x12009092, 0x00000900, 0x00000000, 0x00800086, 0x12009092,
+	0x00000900, 0x00000000, 0x00800000, 0x0e008c8e, 0x00000900, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x08908192, 0x00008680, 0x00000a00, 0x00000000, 0x10908292, 0x28008680,
+	0x00000a00, 0x00000000, 0x809b9392, 0x00000000, 0x00000900, 0x00000000,
+	0x809b9392, 0x00000000, 0x00000900, 0x00000000, 0x009b8f92, 0x00000000,
+	0x00000900, 0x00000000, 0x009b8f92, 0x00000000, 0x00000900, 0x00000000,
+	0x009b8f92, 0x00000000, 0x00000900, 0x00000000, 0x009b8f92, 0x00000000,
+	0x00000900, 0x00000000, 0x009b8f92, 0x00000000, 0x00000900, 0x00000000,
+	0x009b8f92, 0x00000000, 0x00000900, 0x00000000, 0x009b0092, 0x00000000,
+	0x00000900, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x009b0092, 0x00000000, 0x00000900, 0x00000000, 0x00000000, 0x00000082,
+	0x00000d00, 0x00000000, 0x00000000, 0x00000082, 0x00000d00, 0x00000000,
+	0x00000000, 0x00000082, 0x00000d00, 0x00000000, 0x00000000, 0x00000082,
+	0x00000d00, 0x00000000, 0x00000000, 0x00000082, 0x00000d00, 0x00000000,
+	0x00000000, 0x00000082, 0x00000d00, 0x00000000, 0x00000000, 0x00000082,
+	0x00000d00, 0x00000000, 0x00ab0085, 0x08000000, 0x00000a00, 0x00000000,
+	0x00ab0000, 0x00000000, 0x00000a00, 0x00000000, 0x00ab0000, 0x00000000,
+	0x00000a00, 0x00000000, 0x40000000, 0x01c180c2, 0x00000b00, 0x00000000,
+	0x00000000, 0x00a089c2, 0x00000df0, 0x00000000, 0x000b0085, 0x00a00000,
+	0x00000af0, 0x00000000, 0x000b0085, 0x00a00000, 0x00000af0, 0x00000000,
+	0x00000000, 0x00a089c2, 0x00000df0, 0x00000000, 0x000b0000, 0x00000000,
+	0x00000a00, 0x00000000, 0x00000000, 0x00000082, 0x00000d00, 0x00000000,
+	0x00000000, 0x00000082, 0x00000d00, 0x00000000, 0x00000000, 0x00000082,
+	0x00000d00, 0x00000000, 0x00000000, 0x00000082, 0x00000d00, 0x00000000,
+	0x00000000, 0x00000082, 0x00000d00, 0x00000000, 0x00000000, 0x00000082,
+	0x00000d00, 0x00000000, 0x00000000, 0x00000082, 0x00000d00, 0x00000000,
+	0x00ab0085, 0x08000000, 0x00000b00, 0x00000000, 0x00ab0000, 0x00000000,
+	0x00000b00, 0x00000000, 0x00ab0000, 0x00000000, 0x00000b00, 0x00000000,
+	0x00ab0000, 0x00000000, 0x00000b00, 0x00000000, 0x40000000, 0x01c180c2,
+	0x00000c00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000082, 0x00000d00, 0x00000000, 0x00000000, 0x00000082,
+	0x00000d00, 0x00000000, 0x00000000, 0x00000082, 0x00000d00, 0x00000000,
+	0x00000000, 0x00000082, 0x00000d00, 0x00000000, 0x00000000, 0x00000082,
+	0x00000d00, 0x00000000, 0x00000000, 0x00000082, 0x00000d00, 0x00000000,
+	0x00000000, 0x00000082, 0x00000d00, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00ab0085, 0x08000000, 0x00000c00, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00ab0000, 0x00000000, 0x00000c00, 0x00000000, 0x00ab0000, 0x00000000,
+	0x00000c00, 0x00000000, 0x00ab0000, 0x00000000, 0x00000c00, 0x00000000,
+	0x00ab0000, 0x00000000, 0x00000c00, 0x00000000, 0x01ab0083, 0x0ca00000,
+	0x00000d0f, 0x00000000, 0x01ab0083, 0x0ca00000, 0x00000d0f, 0x00000000,
+	0x02ab8a84, 0x08000000, 0x00000d00, 0x00000000, 0x00ab8f8e, 0x04000000,
+	0x00000d00, 0x00000000, 0x00ab0000, 0x00000000, 0x00000d00, 0x00000000,
+	0x00ab8f8e, 0x04000000, 0x00000d00, 0x00000000, 0x00ab0000, 0x00000000,
+	0x00000d00, 0x00000000, 0x04ab8e84, 0x0c000000, 0x00000d00, 0x00000000,
+	0x02ab848f, 0x08000000, 0x00000d00, 0x00000000, 0x02ab848f, 0x08000000,
+	0x00000d00, 0x00000000, 0x02ab848f, 0x08000000, 0x00000d00, 0x00000000,
+	0x02ab0084, 0x08000000, 0x00000d00, 0x00000000, 0x00ab0000, 0x04000000,
+	0x00000d00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ab0000, 0x00000000,
+	0x00000d00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec009_data[] = {
+	0x00000000, 0x00000060, 0x00000000, 0x00000090, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000050, 0x00000000, 0x000000a0,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000a0,
+	0x00000000, 0x00000050, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000800, 0x00000000, 0x00000700, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000900, 0x00000000, 0x00000600,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00008000,
+	0x00000000, 0x00007000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00009000, 0x00000000, 0x00006000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x0000a000, 0x00000000, 0x00005000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000c0000,
+	0x00000000, 0x00030000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x000d0000, 0x00000000, 0x00020000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x000e0000, 0x00000000, 0x00010000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000040,
+	0x00000000, 0x000000b0, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000070, 0x00000000, 0x00000080, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000090, 0x00000000, 0x00000060,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000080,
+	0x00000000, 0x00000070, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000700, 0x00000000, 0x00000800, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00007000, 0x00000000, 0x00008000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00080000,
+	0x00000000, 0x00070000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000c00, 0x00000000, 0x00000300, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000d00, 0x00000000, 0x00000200,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00600000,
+	0x00000000, 0x00900000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00d00000, 0x00000000, 0x00200000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00500000, 0x00000000, 0x00a00000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00700000,
+	0x00000000, 0x00800000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00e00000, 0x00000000, 0x00100000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00f00000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00f00000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00100000, 0x00000000, 0x00e00000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00300000, 0x00000000, 0x00c00000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00800000,
+	0x00000000, 0x00700000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00900000, 0x00000000, 0x00600000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00a00000, 0x00000000, 0x00500000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00b00000,
+	0x00000000, 0x00400000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000060, 0x00400000, 0x00000090, 0x00b00000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000050, 0x00400000, 0x000000a0, 0x00b00000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x000000a0, 0x00400000,
+	0x00000050, 0x00b00000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000800, 0x00400000, 0x00000700, 0x00b00000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000900, 0x00400000, 0x00000600, 0x00b00000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00008000, 0x00400000,
+	0x00007000, 0x00b00000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00009000, 0x00400000, 0x00006000, 0x00b00000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x0000a000, 0x00400000, 0x00005000, 0x00b00000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x000c0000, 0x00400000,
+	0x00030000, 0x00b00000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x000d0000, 0x00400000, 0x00020000, 0x00b00000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x000e0000, 0x00400000, 0x00010000, 0x00b00000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000070, 0x00400000,
+	0x00000080, 0x00b00000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000700, 0x00400000, 0x00000800, 0x00b00000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00007000, 0x00400000, 0x00008000, 0x00b00000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00080000, 0x00400000,
+	0x00070000, 0x00b00000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000c00, 0x00400000, 0x00000300, 0x00b00000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000d00, 0x00400000, 0x00000200, 0x00b00000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000040, 0x00400000,
+	0x000000b0, 0x00b00000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000090, 0x00400000, 0x00000060, 0x00b00000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000080, 0x00400000, 0x00000070, 0x00b00000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000060, 0x06000000,
+	0x00000090, 0x09000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000060, 0x07000000, 0x00000090, 0x08000000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000050, 0x06000000, 0x000000a0, 0x09000000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000050, 0x07000000,
+	0x000000a0, 0x08000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x000000a0, 0x06000000, 0x00000050, 0x09000000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x000000a0, 0x07000000, 0x00000050, 0x08000000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000800, 0x06000000,
+	0x00000700, 0x09000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000900, 0x06000000, 0x00000600, 0x09000000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00008000, 0x06000000, 0x00007000, 0x09000000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00009000, 0x06000000,
+	0x00006000, 0x09000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x0000a000, 0x06000000, 0x00005000, 0x09000000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x000c0000, 0x06000000, 0x00030000, 0x09000000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x000d0000, 0x06000000,
+	0x00020000, 0x09000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x000e0000, 0x06000000, 0x00010000, 0x09000000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000800, 0x07000000, 0x00000700, 0x08000000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000900, 0x07000000,
+	0x00000600, 0x08000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00008000, 0x07000000, 0x00007000, 0x08000000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00009000, 0x07000000, 0x00006000, 0x08000000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x0000a000, 0x07000000,
+	0x00005000, 0x08000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x000c0000, 0x07000000, 0x00030000, 0x08000000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x000d0000, 0x07000000, 0x00020000, 0x08000000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x000e0000, 0x07000000,
+	0x00010000, 0x08000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000070, 0x06000000, 0x00000080, 0x09000000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000070, 0x07000000, 0x00000080, 0x08000000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000700, 0x06000000,
+	0x00000800, 0x09000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00007000, 0x06000000, 0x00008000, 0x09000000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00080000, 0x06000000, 0x00070000, 0x09000000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000c00, 0x06000000,
+	0x00000300, 0x09000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000d00, 0x06000000, 0x00000200, 0x09000000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000700, 0x07000000, 0x00000800, 0x08000000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00007000, 0x07000000,
+	0x00008000, 0x08000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00080000, 0x07000000, 0x00070000, 0x08000000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000c00, 0x07000000, 0x00000300, 0x08000000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000d00, 0x07000000,
+	0x00000200, 0x08000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000040, 0x06000000, 0x000000b0, 0x09000000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000040, 0x07000000, 0x000000b0, 0x08000000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000090, 0x06000000,
+	0x00000060, 0x09000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000090, 0x07000000, 0x00000060, 0x08000000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000080, 0x06000000, 0x00000070, 0x09000000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000080, 0x07000000,
+	0x00000070, 0x08000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000060, 0x00c00000, 0x00000090, 0x00300000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000050, 0x00c00000, 0x000000a0, 0x00300000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x000000a0, 0x00c00000,
+	0x00000050, 0x00300000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000800, 0x00c00000, 0x00000700, 0x00300000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000900, 0x00c00000, 0x00000600, 0x00300000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00008000, 0x00c00000,
+	0x00007000, 0x00300000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00009000, 0x00c00000, 0x00006000, 0x00300000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x0000a000, 0x00c00000, 0x00005000, 0x00300000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x000c0000, 0x00c00000,
+	0x00030000, 0x00300000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x000d0000, 0x00c00000, 0x00020000, 0x00300000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x000e0000, 0x00c00000, 0x00010000, 0x00300000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000070, 0x00c00000,
+	0x00000080, 0x00300000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000700, 0x00c00000, 0x00000800, 0x00300000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00007000, 0x00c00000, 0x00008000, 0x00300000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00080000, 0x00c00000,
+	0x00070000, 0x00300000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000c00, 0x00c00000, 0x00000300, 0x00300000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000d00, 0x00c00000, 0x00000200, 0x00300000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000040, 0x00c00000,
+	0x000000b0, 0x00300000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000090, 0x00c00000, 0x00000060, 0x00300000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000080, 0x00c00000, 0x00000070, 0x00300000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00400000, 0x00400000,
+	0x00b00000, 0x00b00000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00600000, 0x00400000, 0x00900000, 0x00b00000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00300000, 0x00400000, 0x00c00000, 0x00b00000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00500000, 0x00400000,
+	0x00a00000, 0x00b00000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00700000, 0x00400000, 0x00800000, 0x00b00000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00200000, 0x00400000, 0x00d00000, 0x00b00000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00800000, 0x00400000,
+	0x00700000, 0x00b00000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00900000, 0x00400000, 0x00600000, 0x00b00000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00a00000, 0x00400000, 0x00500000, 0x00b00000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00b00000, 0x00400000,
+	0x00400000, 0x00b00000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00400000, 0x00f00000, 0x00b00000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00400000, 0x00f00000, 0x00b00000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00100000, 0x00400000,
+	0x00e00000, 0x00b00000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00400000, 0x06000000, 0x00b00000, 0x09000000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00400000, 0x07000000, 0x00b00000, 0x08000000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00600000, 0x06000000,
+	0x00900000, 0x09000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00600000, 0x07000000, 0x00900000, 0x08000000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00300000, 0x06000000, 0x00c00000, 0x09000000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00300000, 0x07000000,
+	0x00c00000, 0x08000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00500000, 0x06000000, 0x00a00000, 0x09000000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00500000, 0x07000000, 0x00a00000, 0x08000000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00700000, 0x06000000,
+	0x00800000, 0x09000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00700000, 0x07000000, 0x00800000, 0x08000000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00200000, 0x06000000, 0x00d00000, 0x09000000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00200000, 0x07000000,
+	0x00d00000, 0x08000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00800000, 0x06000000, 0x00700000, 0x09000000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00900000, 0x06000000, 0x00600000, 0x09000000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00a00000, 0x06000000,
+	0x00500000, 0x09000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00b00000, 0x06000000, 0x00400000, 0x09000000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00800000, 0x07000000, 0x00700000, 0x08000000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00900000, 0x07000000,
+	0x00600000, 0x08000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00a00000, 0x07000000, 0x00500000, 0x08000000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00b00000, 0x07000000, 0x00400000, 0x08000000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x06000000,
+	0x00f00000, 0x09000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x07000000, 0x00f00000, 0x08000000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x06000000, 0x00f00000, 0x09000000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00100000, 0x06000000,
+	0x00e00000, 0x09000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x07000000, 0x00f00000, 0x08000000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00100000, 0x07000000, 0x00e00000, 0x08000000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00400000, 0x00c00000,
+	0x00b00000, 0x00300000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00600000, 0x00c00000, 0x00900000, 0x00300000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00300000, 0x00c00000, 0x00c00000, 0x00300000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00500000, 0x00c00000,
+	0x00a00000, 0x00300000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00700000, 0x00c00000, 0x00800000, 0x00300000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00200000, 0x00c00000, 0x00d00000, 0x00300000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00800000, 0x00c00000,
+	0x00700000, 0x00300000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00900000, 0x00c00000, 0x00600000, 0x00300000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00a00000, 0x00c00000, 0x00500000, 0x00300000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00b00000, 0x00c00000,
+	0x00400000, 0x00300000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00c00000, 0x00f00000, 0x00300000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00c00000, 0x00f00000, 0x00300000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00100000, 0x00c00000,
+	0x00e00000, 0x00300000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x000f0000, 0x00400000, 0x00000000, 0x00b00000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00f00000, 0x00400000, 0x00000000, 0x00b00000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x000f0000, 0x06000000,
+	0x00000000, 0x09000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00f00000, 0x06000000, 0x00000000, 0x09000000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x000f0000, 0x07000000, 0x00000000, 0x08000000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00f00000, 0x07000000,
+	0x00000000, 0x08000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x000f0000, 0x00c00000, 0x00000000, 0x00300000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00f00000, 0x00c00000, 0x00000000, 0x00300000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000f0000,
+	0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00f00000, 0x00000000, 0x00000000, 0x00000001, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec010_data[] = {
+	0x0000000a, 0x0000000a, 0x0000000a, 0x0000000a, 0x0000000a, 0x0000000a,
+	0x0000000a, 0x0000000a, 0x0000000a, 0x0000000a, 0x0000000a, 0x00000000,
+	0x0000000b, 0x00000008, 0x00000009, 0x0000000f, 0x0000000f, 0x0000000f,
+	0x0000000f, 0x0000000f, 0x0000000c, 0x0000000d, 0x00000001, 0x00000001,
+	0x0000000e, 0x00000005, 0x00000002, 0x00000002, 0x00000004, 0x00000003,
+	0x00000003, 0x00000003, 0x00000003, 0x00000040, 0x00000040, 0x00000040,
+	0x00000040, 0x00000040, 0x00000040, 0x00000040, 0x00000040, 0x00000040,
+	0x00000040, 0x00000040, 0x00000045, 0x00000044, 0x00000044, 0x00000044,
+	0x00000044, 0x00000044, 0x00000041, 0x00000042, 0x00000043, 0x00000046,
+	0x00000046, 0x00000046, 0x00000046, 0x00000046, 0x00000046, 0x00000046,
+	0x00000046, 0x00000046, 0x00000046, 0x00000046, 0x00000046, 0x00000046,
+	0x00000046, 0x00000046, 0x00000046, 0x00000046, 0x00000046, 0x00000046,
+	0x00000046, 0x00000046, 0x00000046, 0x0000004b, 0x0000004b, 0x0000004a,
+	0x0000004a, 0x0000004a, 0x0000004a, 0x0000004a, 0x0000004a, 0x0000004a,
+	0x0000004a, 0x0000004a, 0x0000004a, 0x00000047, 0x00000047, 0x00000048,
+	0x00000048, 0x00000049, 0x00000049, 0x0000004c, 0x0000004c, 0x0000004c,
+	0x0000004c, 0x0000004c, 0x0000004c, 0x0000004c, 0x0000004c, 0x0000004c,
+	0x0000004c, 0x0000004c, 0x00000051, 0x00000050, 0x00000050, 0x00000050,
+	0x00000050, 0x00000050, 0x0000004d, 0x0000004e, 0x0000004f, 0x00000052,
+	0x00000053, 0x00000054, 0x00000054, 0x00000055, 0x00000056, 0x00000057,
+	0x00000057, 0x00000057, 0x00000057, 0x00000058, 0x00000059, 0x00000059,
+	0x0000005a, 0x0000005a, 0x0000005b, 0x0000005b, 0x0000005c, 0x0000005c,
+	0x0000005c, 0x0000005c, 0x0000005d, 0x0000005d, 0x0000005e, 0x0000005e,
+	0x0000005f, 0x0000005f, 0x0000005f, 0x0000005f, 0x0000005f, 0x0000005f,
+	0x0000005f, 0x0000005f, 0x00000060, 0x00000060, 0x00000061, 0x00000061,
+	0x00000061, 0x00000061, 0x00000062, 0x00000063, 0x00000064, 0x00000064,
+	0x00000065, 0x00000066, 0x00000067, 0x00000067, 0x00000067, 0x00000067,
+	0x00000068, 0x00000069, 0x00000069, 0x00000040, 0x00000040, 0x00000046,
+	0x00000046, 0x00000046, 0x00000046, 0x0000004c, 0x0000004c, 0x0000000a,
+	0x0000000a, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec011_data[] = {
+	0x0008002c, 0x00080234, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00080230, 0x00080332, 0x0008063c, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0008002c, 0x00080234,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00080230,
+	0x00080332, 0x00080738, 0x0008083c, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x0008002c, 0x00080234, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00080230, 0x00080332, 0x00080738,
+	0x0008093a, 0x00080a3c, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00080020, 0x00080228, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00080224, 0x00080326, 0x00080634, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00080020, 0x00080228,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00080224,
+	0x00080326, 0x00080730, 0x00080834, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00080020, 0x00080228, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00080224, 0x00080326, 0x00080730,
+	0x00080932, 0x00080a34, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00090200, 0x00090304, 0x00090408, 0x0009050c,
+	0x00090610, 0x00090714, 0x00090818, 0x0009121c, 0x0009131e, 0x00000000,
+	0x00000000, 0x00000000, 0x00090644, 0x00000000, 0x000d8045, 0x000d4145,
+	0x0009030c, 0x0009041c, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00090145, 0x00090944, 0x00000000, 0x00000000, 0x0009061c, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0009033a,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00090200, 0x00090304, 0x00090408, 0x0009050c,
+	0x00090610, 0x00090714, 0x00090818, 0x0009121c, 0x0009131e, 0x00000000,
+	0x00000000, 0x00000000, 0x0009063d, 0x00090740, 0x000d803f, 0x000d413f,
+	0x0009030c, 0x0009041c, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x0009013f, 0x00090840, 0x000dc93d, 0x000d093d, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000a0324, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000a003e,
+	0x000a0140, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x000a0324, 0x000a0520, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x000a003e, 0x000a0140, 0x000a0842,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x000a0124, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000a0224, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x000a003c, 0x000a0037, 0x000ec139, 0x000e0139,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x000a0036, 0x000a0138, 0x000a0742, 0x00000000, 0x00000000,
+	0x000a0d41, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000a0036,
+	0x000a0138, 0x00000000, 0x00000000, 0x00000000, 0x000a0d3e, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x000a0036, 0x000a0138, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000a0037, 0x000a0139,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00080020, 0x00080228, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00080224, 0x00080326, 0x00080634,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00080020, 0x00080228, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00080224, 0x00080326, 0x00080730, 0x00080834, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00080020, 0x00080228,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00080224,
+	0x00080326, 0x00080730, 0x00080932, 0x00080a34, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0009061c, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0009033a,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00090200, 0x00090304, 0x00090408, 0x0009050c,
+	0x00090610, 0x00090714, 0x00090818, 0x0009121c, 0x0009131e, 0x00000000,
+	0x00000000, 0x00000000, 0x0009063d, 0x00090740, 0x000d803f, 0x000d413f,
+	0x0009030c, 0x0009041c, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x0009013f, 0x00090840, 0x000dc93d, 0x000d093d, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x000a003c, 0x000a0037, 0x000ec139, 0x000e0139, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000a0036,
+	0x000a0138, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x000a0036, 0x000a0138, 0x000a0742,
+	0x00000000, 0x00000000, 0x000a0d41, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x000a0036, 0x000a0138, 0x00000000, 0x00000000, 0x00000000,
+	0x000a0d3e, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000a0037, 0x000a0139,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec012_data[] = {
+	0x00000006, 0x00000001, 0x00000004, 0x00000001, 0x00000006, 0x00000001,
+	0x00000000, 0x00000001, 0x00000004, 0x00000001, 0x00000000, 0x00000001,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000010, 0x00000001,
+	0x00000000, 0x00000001, 0x00000040, 0x00000001, 0x00000010, 0x00000001,
+	0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x06200000, 0x00000001, 0x00c00000, 0x00000001,
+	0x02c00000, 0x00000001, 0x00200000, 0x00000001, 0x00400000, 0x00000001,
+	0x00700000, 0x00000001, 0x00300000, 0x00000001, 0x00000000, 0x00000001,
+	0x00a00000, 0x00000001, 0x00b00000, 0x00000001, 0x00e00000, 0x00000001,
+	0x00500000, 0x00000001, 0x00800000, 0x00000001, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000004, 0x00000001,
+	0x00000000, 0x00000001, 0x00000000, 0x00000001, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000040, 0x00000001, 0x00000010, 0x00000001,
+	0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00500000, 0x00000001, 0x00700000, 0x00000001, 0x00a00000, 0x00000001,
+	0x00b00000, 0x00000001, 0x00200000, 0x00000001, 0x00000000, 0x00000001,
+	0x00300000, 0x00000001, 0x00800000, 0x00000001, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec013_data[] = {
+	0xf7fffff0, 0xf7fffff1, 0xfffffff0, 0xf7fffff3, 0xfffffff1, 0xfffffff3,
+	0xffffffff, 0xffffffff, 0xf7ffff0f, 0xf7ffff0f, 0xffffff0f, 0xffffff0f,
+	0xffffff0f, 0xffffffff, 0xffffffff, 0xffffffff, 0x100fffff, 0xf10fffff,
+	0xf10fffff, 0xf70fffff, 0xf70fffff, 0xff0fffff, 0xff0fffff, 0xff1fffff,
+	0xff0fffff, 0xff0fffff, 0xff0fffff, 0xff0fffff, 0xff1fffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xfffffff1, 0xfffffff3, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffff0f, 0xffffff0f,
+	0xffffff0f, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xff0fffff, 0xff0fffff, 0xff0fffff, 0xff0fffff, 0xff0fffff, 0xff1fffff,
+	0xff0fffff, 0xff1fffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+};
+
+static const u32 nbl_sec014_data[] = {
+	0x00000000, 0x00000001, 0x00000003, 0x00000002, 0x00000004, 0x00000005,
+	0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000002, 0x00000003,
+	0x00000004, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000002,
+	0x00000003, 0x00000000, 0x00000000, 0x00000004, 0x00000005, 0x00000006,
+	0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000001, 0x00000002, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001,
+	0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000003,
+	0x00000004, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec022_data[] = {
+	0x81008100, 0x00000001, 0x88a88100, 0x00000001, 0x810088a8, 0x00000001,
+	0x88a888a8, 0x00000001, 0x81000000, 0x00000001, 0x88a80000, 0x00000001,
+	0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x08004000, 0x00000001, 0x86dd6000, 0x00000001,
+	0x81000000, 0x00000001, 0x88a80000, 0x00000001, 0x08060000, 0x00000001,
+	0x80350000, 0x00000001, 0x88080000, 0x00000001, 0x88f70000, 0x00000001,
+	0x88cc0000, 0x00000001, 0x88090000, 0x00000001, 0x89150000, 0x00000001,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x11006000, 0x00000001,
+	0x06006000, 0x00000001, 0x02006000, 0x00000001, 0x3a006000, 0x00000001,
+	0x2f006000, 0x00000001, 0x84006000, 0x00000001, 0x32006000, 0x00000001,
+	0x2c006000, 0x00000001, 0x3c006000, 0x00000001, 0x2b006000, 0x00000001,
+	0x00006000, 0x00000001, 0x00004000, 0x00000001, 0x00004000, 0x00000001,
+	0x20004000, 0x00000001, 0x40004000, 0x00000001, 0x00000000, 0x00000001,
+	0x11000000, 0x00000001, 0x06000000, 0x00000001, 0x02000000, 0x00000001,
+	0x3a000000, 0x00000001, 0x2f000000, 0x00000001, 0x84000000, 0x00000001,
+	0x32000000, 0x00000001, 0x2c000000, 0x00000001, 0x2b000000, 0x00000001,
+	0x3c000000, 0x00000001, 0x3b000000, 0x00000001, 0x00000000, 0x00000001,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x11000000, 0x00000001, 0x06000000, 0x00000001,
+	0x02000000, 0x00000001, 0x3a000000, 0x00000001, 0x2f000000, 0x00000001,
+	0x84000000, 0x00000001, 0x32000000, 0x00000001, 0x00000000, 0x00000000,
+	0x2c000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x2b000000, 0x00000001, 0x3c000000, 0x00000001,
+	0x3b000000, 0x00000001, 0x00000000, 0x00000001, 0x06001072, 0x00000001,
+	0x06000000, 0x00000001, 0x110012b7, 0x00000001, 0x01000000, 0x00000001,
+	0x02000000, 0x00000001, 0x3a000000, 0x00000001, 0x32000000, 0x00000001,
+	0x84000000, 0x00000001, 0x11000043, 0x00000001, 0x11000044, 0x00000001,
+	0x11000222, 0x00000001, 0x11000000, 0x00000001, 0x2f006558, 0x00000001,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec023_data[] = {
+	0x10001000, 0x00001000, 0x10000000, 0x00000000, 0x1000ffff, 0x0000ffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000fff, 0x00000fff,
+	0x1000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff,
+	0x0000ffff, 0x0000ffff, 0x0000ffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0x00ff0fff, 0x00ff0fff, 0x00ff0fff, 0x00ff0fff,
+	0x00ff0fff, 0x00ff0fff, 0x00ff0fff, 0x00ff0fff, 0x00ff0fff, 0x10ff0fff,
+	0xffff0fff, 0x00000fff, 0x1fff0fff, 0x1fff0fff, 0x1fff0fff, 0xffffffff,
+	0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff,
+	0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00ffffff, 0x00ffffff,
+	0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xffffffff,
+	0x00ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00ffffff, 0x00ffffff,
+	0x00ffffff, 0xffffffff, 0x00ff0000, 0x00ffffff, 0x00ff0000, 0x00ffffff,
+	0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ff0000, 0x00ff0000,
+	0x00ff0001, 0x00ffffff, 0x00ff0000, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff,
+};
+
+static const u32 nbl_sec024_data[] = {
+	0x00809190, 0x16009496, 0x00000100, 0x00000000, 0x00809190, 0x16009496,
+	0x00000100, 0x00000000, 0x00809190, 0x16009496, 0x00000100, 0x00000000,
+	0x00809190, 0x16009496, 0x00000100, 0x00000000, 0x00800090, 0x12009092,
+	0x00000100, 0x00000000, 0x00800090, 0x12009092, 0x00000100, 0x00000000,
+	0x00800000, 0x0e008c8e, 0x00000100, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x08900081, 0x00008680,
+	0x00000200, 0x00000000, 0x10900082, 0x28008680, 0x00000200, 0x00000000,
+	0x809b0093, 0x00000000, 0x00000100, 0x00000000, 0x809b0093, 0x00000000,
+	0x00000100, 0x00000000, 0x009b008f, 0x00000000, 0x00000100, 0x00000000,
+	0x009b008f, 0x00000000, 0x00000100, 0x00000000, 0x009b008f, 0x00000000,
+	0x00000100, 0x00000000, 0x009b008f, 0x00000000, 0x00000100, 0x00000000,
+	0x009b008f, 0x00000000, 0x00000100, 0x00000000, 0x009b008f, 0x00000000,
+	0x00000100, 0x00000000, 0x009b0000, 0x00000000, 0x00000100, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x009b0000, 0x00000000,
+	0x00000100, 0x00000000, 0x00000000, 0x00000082, 0x00000500, 0x00000000,
+	0x00000000, 0x00000082, 0x00000500, 0x00000000, 0x00000000, 0x00000082,
+	0x00000500, 0x00000000, 0x00000000, 0x00000082, 0x00000500, 0x00000000,
+	0x00000000, 0x00000082, 0x00000500, 0x00000000, 0x00000000, 0x00000082,
+	0x00000500, 0x00000000, 0x00000000, 0x00000082, 0x00000500, 0x00000000,
+	0x00ab0085, 0x08000000, 0x00000200, 0x00000000, 0x00ab0000, 0x00000000,
+	0x00000200, 0x00000000, 0x00ab0000, 0x00000000, 0x00000200, 0x00000000,
+	0x40000000, 0x01c180c2, 0x00000300, 0x00000000, 0x00000000, 0x00a089c2,
+	0x000005f0, 0x00000000, 0x000b0085, 0x00a00000, 0x000002f0, 0x00000000,
+	0x000b0085, 0x00a00000, 0x000002f0, 0x00000000, 0x00000000, 0x00a089c2,
+	0x000005f0, 0x00000000, 0x000b0000, 0x00000000, 0x00000200, 0x00000000,
+	0x00000000, 0x00000082, 0x00000500, 0x00000000, 0x00000000, 0x00000082,
+	0x00000500, 0x00000000, 0x00000000, 0x00000082, 0x00000500, 0x00000000,
+	0x00000000, 0x00000082, 0x00000500, 0x00000000, 0x00000000, 0x00000082,
+	0x00000500, 0x00000000, 0x00000000, 0x00000082, 0x00000500, 0x00000000,
+	0x00000000, 0x00000082, 0x00000500, 0x00000000, 0x00ab0085, 0x08000000,
+	0x00000300, 0x00000000, 0x00ab0000, 0x00000000, 0x00000300, 0x00000000,
+	0x00ab0000, 0x00000000, 0x00000300, 0x00000000, 0x00ab0000, 0x00000000,
+	0x00000300, 0x00000000, 0x40000000, 0x01c180c2, 0x00000400, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000082,
+	0x00000500, 0x00000000, 0x00000000, 0x00000082, 0x00000500, 0x00000000,
+	0x00000000, 0x00000082, 0x00000500, 0x00000000, 0x00000000, 0x00000082,
+	0x00000500, 0x00000000, 0x00000000, 0x00000082, 0x00000500, 0x00000000,
+	0x00000000, 0x00000082, 0x00000500, 0x00000000, 0x00000000, 0x00000082,
+	0x00000500, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00ab0085, 0x08000000, 0x00000400, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ab0000, 0x00000000,
+	0x00000400, 0x00000000, 0x00ab0000, 0x00000000, 0x00000400, 0x00000000,
+	0x00ab0000, 0x00000000, 0x00000400, 0x00000000, 0x00ab0000, 0x00000000,
+	0x00000400, 0x00000000, 0x01ab0083, 0x0ca00000, 0x0000050f, 0x00000000,
+	0x01ab0083, 0x0ca00000, 0x0000050f, 0x00000000, 0x02ab848a, 0x08000000,
+	0x00000500, 0x00000000, 0x00ab8f8e, 0x04000000, 0x00000500, 0x00000000,
+	0x00ab0000, 0x00000000, 0x00000500, 0x00000000, 0x00ab8f8e, 0x04000000,
+	0x00000500, 0x00000000, 0x00ab0000, 0x00000000, 0x00000500, 0x00000000,
+	0x04ab8e84, 0x0c000000, 0x00000500, 0x00000000, 0x02ab848f, 0x08000000,
+	0x00000500, 0x00000000, 0x02ab848f, 0x08000000, 0x00000500, 0x00000000,
+	0x02ab848f, 0x08000000, 0x00000500, 0x00000000, 0x02ab0084, 0x08000000,
+	0x00000500, 0x00000000, 0x00ab0000, 0x04000000, 0x00000500, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00ab0000, 0x00000000, 0x00000500, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec025_data[] = {
+	0x00000060, 0x00000090, 0x00000001, 0x00000000, 0x00000050, 0x000000a0,
+	0x00000001, 0x00000000, 0x000000a0, 0x00000050, 0x00000001, 0x00000000,
+	0x00000800, 0x00000700, 0x00000001, 0x00000000, 0x00000900, 0x00000600,
+	0x00000001, 0x00000000, 0x00008000, 0x00007000, 0x00000001, 0x00000000,
+	0x00009000, 0x00006000, 0x00000001, 0x00000000, 0x0000a000, 0x00005000,
+	0x00000001, 0x00000000, 0x000c0000, 0x00030000, 0x00000001, 0x00000000,
+	0x000d0000, 0x00020000, 0x00000001, 0x00000000, 0x000e0000, 0x00010000,
+	0x00000001, 0x00000000, 0x00000040, 0x000000b0, 0x00000001, 0x00000000,
+	0x00000070, 0x00000080, 0x00000001, 0x00000000, 0x00000090, 0x00000060,
+	0x00000001, 0x00000000, 0x00000080, 0x00000070, 0x00000001, 0x00000000,
+	0x00000700, 0x00000800, 0x00000001, 0x00000000, 0x00007000, 0x00008000,
+	0x00000001, 0x00000000, 0x00080000, 0x00070000, 0x00000001, 0x00000000,
+	0x00000c00, 0x00000300, 0x00000001, 0x00000000, 0x00000d00, 0x00000200,
+	0x00000001, 0x00000000, 0x00400000, 0x00b00000, 0x00000001, 0x00000000,
+	0x00600000, 0x00900000, 0x00000001, 0x00000000, 0x00300000, 0x00c00000,
+	0x00000001, 0x00000000, 0x00500000, 0x00a00000, 0x00000001, 0x00000000,
+	0x00700000, 0x00800000, 0x00000001, 0x00000000, 0x00000000, 0x00f00000,
+	0x00000001, 0x00000000, 0x00000000, 0x00f00000, 0x00000001, 0x00000000,
+	0x00100000, 0x00e00000, 0x00000001, 0x00000000, 0x00200000, 0x00d00000,
+	0x00000001, 0x00000000, 0x00800000, 0x00700000, 0x00000001, 0x00000000,
+	0x00900000, 0x00600000, 0x00000001, 0x00000000, 0x00a00000, 0x00500000,
+	0x00000001, 0x00000000, 0x00b00000, 0x00400000, 0x00000001, 0x00000000,
+	0x000f0000, 0x00000000, 0x00000001, 0x00000000, 0x00f00000, 0x00000000,
+	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec026_data[] = {
+	0x0000000a, 0x0000000a, 0x0000000a, 0x0000000a, 0x0000000a, 0x0000000a,
+	0x0000000a, 0x0000000a, 0x0000000a, 0x0000000a, 0x0000000a, 0x00000000,
+	0x0000000b, 0x00000008, 0x00000009, 0x0000000f, 0x0000000f, 0x0000000f,
+	0x0000000f, 0x0000000f, 0x0000000c, 0x0000000d, 0x00000001, 0x00000001,
+	0x0000000e, 0x00000005, 0x00000002, 0x00000002, 0x00000004, 0x00000003,
+	0x00000003, 0x00000003, 0x00000003, 0x0000000a, 0x0000000a, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec027_data[] = {
+	0x00080020, 0x00080228, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00080224, 0x00080326, 0x00080634, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00080020, 0x00080228,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00080224,
+	0x00080326, 0x00080730, 0x00080834, 0x0008082e, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00080020, 0x00080228, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00080224, 0x00080326, 0x00080730,
+	0x00080932, 0x00080a34, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x0009061c, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x0009033a, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00090200, 0x00090304, 0x00090408, 0x0009050c, 0x00090610, 0x00090714,
+	0x00090818, 0x0009121c, 0x0009131e, 0x00000000, 0x00000000, 0x00000000,
+	0x0009063d, 0x00090740, 0x000d803f, 0x000d413f, 0x0009030c, 0x0009041c,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0009013f, 0x00090840,
+	0x000dc93d, 0x000d093d, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000a003c, 0x000a0037,
+	0x000ec139, 0x000e0139, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x000a0036, 0x000a0138, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x000a0036, 0x000a0138, 0x000a0742, 0x00000000, 0x00000000,
+	0x000a0d41, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000a0036,
+	0x000a0138, 0x00000000, 0x00000000, 0x00000000, 0x000a0d3e, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x000a0037, 0x000a0139, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec028_data[] = {
+	0x00000006, 0x00000001, 0x00000004, 0x00000001, 0x00000000, 0x00000001,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000040, 0x00000001,
+	0x00000010, 0x00000001, 0x00000000, 0x00000001, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00500000, 0x00000001, 0x00700000, 0x00000001,
+	0x00a00000, 0x00000001, 0x00b00000, 0x00000001, 0x00200000, 0x00000001,
+	0x00000000, 0x00000001, 0x00300000, 0x00000001, 0x00800000, 0x00000001,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec029_data[] = {
+	0xfffffff0, 0xfffffff1, 0xfffffff3, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffff0f, 0xffffff0f, 0xffffff0f, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff0fffff, 0xff0fffff,
+	0xff0fffff, 0xff0fffff, 0xff0fffff, 0xff1fffff, 0xff0fffff, 0xff1fffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff,
+};
+
+static const u32 nbl_sec030_data[] = {
+	0x00000000, 0x00000001, 0x00000002, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000002, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001,
+	0x00000001, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000001,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec039_data[] = {
+	0xfef80000, 0x00000002, 0x000002e0, 0x00000000, 0xfef8013e, 0x00000002,
+	0x000002e0, 0x00000000, 0x6660013e, 0x726e6802, 0x02224e42, 0x00000000,
+	0x6660013e, 0x726e6802, 0x02224e42, 0x00000000, 0x66600000, 0x726e6802,
+	0x02224e42, 0x00000000, 0x66600000, 0x726e6802, 0x02224e42, 0x00000000,
+	0x66600000, 0x00026802, 0x02224e40, 0x00000000, 0x66627800, 0x00026802,
+	0x02224e40, 0x00000000, 0x66600000, 0x00026a76, 0x02224e40, 0x00000000,
+	0x66600000, 0x00026802, 0x00024e40, 0x00000000, 0x66600000, 0x00026802,
+	0x00024e40, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec040_data[] = {
+	0x0040fb3f, 0x00000001, 0x0440fb3f, 0x00000001, 0x0502fa00, 0x00000001,
+	0x0602f900, 0x00000001, 0x0903e600, 0x00000001, 0x0a03e500, 0x00000001,
+	0x1101e600, 0x00000001, 0x1201e500, 0x00000001, 0x0000ff00, 0x00000001,
+	0x0008ff07, 0x00000001, 0x00ffff00, 0x00000001, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec046_4p_data[] = {
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xa0000000,
+	0x00077c2b, 0x005c0000, 0x00000000, 0x00008100, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x20000000, 0x00073029, 0x00480000,
+	0x00000000, 0x00008100, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x20000000, 0x00073029, 0x00480000, 0x70000000, 0x00000020,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xa0000000,
+	0x00000009, 0x00000000, 0x00000000, 0x00002100, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0xb0000000, 0x00000009, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000100,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000100, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x70000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x70000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x38430000, 0x70000006, 0x00000020, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x98cb1180, 0x6e36d469, 0x9d8eb91c, 0x87e3ef47, 0xa2931288, 0x08405c5a,
+	0x73865086, 0x00000080, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0xb0000000, 0x000b3849, 0x38430000, 0x00000006, 0x0000c100,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xb0000000,
+	0x00133889, 0x08400000, 0x03865086, 0x4c016100, 0x00000014, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec047_data[] = {
+	0x2040dc3f, 0x00000001, 0x2000dcff, 0x00000001, 0x2200dcff, 0x00000001,
+	0x0008dc01, 0x00000001, 0x0001de00, 0x00000001, 0x2900c4ff, 0x00000001,
+	0x3100c4ff, 0x00000001, 0x2b00c4ff, 0x00000001, 0x3300c4ff, 0x00000001,
+	0x2700d8ff, 0x00000001, 0x2300d8ff, 0x00000001, 0x2502d800, 0x00000001,
+	0x2102d800, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec052_data[] = {
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x30000000,
+	0x000b844c, 0xc8580000, 0x00000006, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x20000000, 0xb0d3668b, 0xb0555e12,
+	0x03b055c6, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x20000000, 0xa64b3449, 0x405a3cc1, 0x00000006, 0x3d2d3300,
+	0x00000010, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x20000000,
+	0x26473429, 0x00482cc1, 0x00000000, 0x00ccd300, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec053_data[] = {
+	0x0840f03f, 0x00000001, 0x0040f03f, 0x00000001, 0x0140fa3f, 0x00000001,
+	0x0100fa0f, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec058_data[] = {
+	0x00000000, 0x00000000, 0x59f89400, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00470000, 0x00000000, 0x3c000000, 0xa2e40006, 0x00000017,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x19fa1400, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x28440000,
+	0x038e5186, 0x3c000000, 0xa8e40012, 0x00000047, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0001f3d0, 0x00000000,
+	0x00000000, 0xb0000000, 0x00133889, 0x38c30000, 0x0000000a, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x0001f3d0, 0x00000000, 0x00000000, 0xb0000000,
+	0x00133889, 0x38c30000, 0x0000000a, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x000113d0, 0x00000000, 0x00000000, 0xb0000000, 0x00073829, 0x00430000,
+	0x00000000, 0x3c000000, 0x0000000a, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000293d0, 0x00000000,
+	0x00000000, 0xb0000000, 0x00133889, 0x08400000, 0x03865086, 0x3c000000,
+	0x00000016, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec059_data[] = {
+	0x0200e4ff, 0x00000001, 0x0400e2ff, 0x00000001, 0x1300ecff, 0x00000001,
+	0x1500eaff, 0x00000001, 0x0300e4ff, 0x00000001, 0x0500e2ff, 0x00000001,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec062_data[] = {
+	0x90939899, 0x88809c9b, 0x0000013d, 0x00000000, 0x90939899, 0x88809c9b,
+	0x0000013d, 0x00000000, 0x90939899, 0x88809c9b, 0x0000013d, 0x00000000,
+	0x90939899, 0x88809c9b, 0x0000013d, 0x00000000, 0x90939899, 0x88809c9b,
+	0x0000013d, 0x00000000, 0x90939899, 0x88809c9b, 0x0000013d, 0x00000000,
+	0x90939899, 0x88809c9b, 0x0000013d, 0x00000000, 0x90939899, 0x88809c9b,
+	0x0000013d, 0x00000000, 0x90939899, 0x88809c9b, 0x0000013d, 0x00000000,
+	0x90939899, 0x88809c9b, 0x0000013d, 0x00000000, 0x90939899, 0x88809c9b,
+	0x0000013d, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec063_data[] = {
+	0x0500e2ff, 0x00000001, 0x0900e2ff, 0x00000001, 0x1900e2ff, 0x00000001,
+	0x1100e2ff, 0x00000001, 0x0100e2ff, 0x00000001, 0x0600e1ff, 0x00000001,
+	0x0a00e1ff, 0x00000001, 0x1a00e1ff, 0x00000001, 0x1200e1ff, 0x00000001,
+	0x0200e1ff, 0x00000001, 0x0000fcff, 0x00000001, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec065_data[] = {
+	0x006e120c, 0x006e1210, 0x006e4208, 0x006e4218, 0x00200b02, 0x00200b00,
+	0x000e1900, 0x000e1906, 0x00580208, 0x00580204, 0x004c0208, 0x004c0207,
+	0x0002110c, 0x0002110c, 0x0012010c, 0x00100110, 0x0010010c, 0x000a010c,
+	0x0008010c, 0x00060000, 0x00160000, 0x00140000, 0x001e0000, 0x001e0000,
+	0x001e0000, 0x001e0000, 0x001e0000, 0x001e0000, 0x001e0000, 0x001e0000,
+	0x001e0000, 0x001e0000,
+};
+
+static const u32 nbl_sec066_data[] = {
+	0x006e120c, 0x006e1210, 0x006e4208, 0x006e4218, 0x00200b02, 0x00200b00,
+	0x000e1900, 0x000e1906, 0x00580208, 0x00580204, 0x004c0208, 0x004c0207,
+	0x0002110c, 0x0002110c, 0x0012010c, 0x00100110, 0x0010010c, 0x000a010c,
+	0x0008010c, 0x00060000, 0x00160000, 0x00140000, 0x001e0000, 0x001e0000,
+	0x001e0000, 0x001e0000, 0x001e0000, 0x001e0000, 0x001e0000, 0x001e0000,
+	0x001e0000, 0x001e0000,
+};
+
+static const u32 nbl_sec071_4p_data[] = {
+	0x00000000, 0x00000000, 0x00113d00, 0x00000000, 0x00000000, 0x00000000,
+	0xe7029b00, 0x00000000, 0x00000000, 0x43000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x51e00000, 0x00000c9c, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00293d00, 0x00000000,
+	0x00000000, 0x00000000, 0x67089b00, 0x00000002, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x80000000, 0x00000000, 0xb1e00000, 0x0000189c,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00213d00, 0x00000000, 0x00000000, 0x00000000, 0xe7069b00, 0x00000001,
+	0x00000000, 0x43000000, 0x014b0c70, 0x00000000, 0x00000000, 0x00000000,
+	0x92600000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00213d00, 0x00000000, 0x00000000, 0x00000000,
+	0xe7069b00, 0x00000001, 0x00000000, 0x43000000, 0x015b0c70, 0x00000000,
+	0x00000000, 0x00000000, 0x92600000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00553d00, 0x00000000,
+	0x00000000, 0x00000000, 0xe6d29a00, 0x000149c4, 0x00000000, 0x4b000000,
+	0x00000004, 0x00000000, 0x80000000, 0x00022200, 0x62600000, 0x00000001,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00553d00, 0x00000000, 0x00000000, 0x00000000, 0xe6d2c000, 0x000149c4,
+	0x00000000, 0x5b000000, 0x00000004, 0x00000000, 0x80000000, 0x00022200,
+	0x62600000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x006d3d00, 0x00000000, 0x00000000, 0x00000000,
+	0x64d49200, 0x5e556945, 0xc666d89a, 0x4b0001a9, 0x00004c84, 0x00000000,
+	0x80000000, 0x00022200, 0xc2600000, 0x00000001, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x006d3d00, 0x00000000,
+	0x00000000, 0x00000000, 0x6ed4ba00, 0x5ef56bc5, 0xc666d8c0, 0x5b0001a9,
+	0x00004dc4, 0x00000000, 0x80000000, 0x00022200, 0xc2600000, 0x00000001,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00700000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec072_data[] = {
+	0x84006aff, 0x00000001, 0x880066ff, 0x00000001, 0x140040ff, 0x00000001,
+	0x70000cff, 0x00000001, 0x180040ff, 0x00000001, 0x30000cff, 0x00000001,
+	0x10004cff, 0x00000001, 0x30004cff, 0x00000001, 0x0100ecff, 0x00000001,
+	0x0300ecff, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec116_data[] = {
+	0x00000000, 0x00000000, 0x3fff8000, 0x00000007, 0x3fff8000, 0x00000007,
+	0x3fff8000, 0x00000007, 0x3fff8000, 0x00000003, 0x3fff8000, 0x00000003,
+	0x3fff8000, 0x00000007, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec124_data[] = {
+	0xfffffffc, 0xffffffff, 0x00300000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000500, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xfffffffc, 0xffffffff,
+	0x00300010, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000500, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xfffffffc, 0xffffffff, 0x00300010, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000500, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xfffffffc, 0xffffffff, 0x00300fff, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000580, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xfffffffc, 0xffffffff,
+	0x00301fff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000580, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xfffffffc, 0xffffffff, 0x0030ffff, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000580, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xfffffffc, 0xffffffff, 0x0030ffff, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000580, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xfffffffc, 0xffffffff,
+	0x0030ffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000580, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xfffffffc, 0xffffffff, 0x0030ffff, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000580, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xfffffffc, 0xffffffff, 0x00300000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000500, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000fffe, 0x00000000,
+	0x00300000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000480, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xfffffffc, 0x00ffffff, 0x00300000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000480, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xfffffffe, 0x0000000f, 0x00300000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000580, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec125_data[] = {
+	0xfffffffc, 0x01ffffff, 0x00300000, 0x70000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000480, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xfffffffe, 0x00000001,
+	0x00300000, 0x70000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000540, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xfffffffe, 0x011003ff, 0x00300000, 0x70000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000005c0, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xfffffffc, 0x103fffff, 0x00300001, 0x70000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000480, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec126_data[] = {
+	0xfffffffc, 0xffffffff, 0x00300001, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000500, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xfffffffe, 0x000001ff,
+	0x00300000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x000005c0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00002013, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000400, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00002013, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000400, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xfffffffc, 0x01ffffff,
+	0x00300000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000480, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xfffffffe, 0x00000001, 0x00300000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000540, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+static const u32 nbl_sec137_data[] = {
+	0x0000017a, 0x000000f2, 0x00000076, 0x0000017a, 0x0000017a, 0x00000080,
+	0x00000024, 0x0000017a, 0x0000017a, 0x00000191, 0x00000035, 0x0000017a,
+	0x0000017a, 0x0000017a, 0x0000017a, 0x0000017a, 0x0000017a, 0x000000d2,
+	0x00000066, 0x0000017a, 0x0000017a, 0x0000017a, 0x0000017a, 0x0000017a,
+	0x0000017a, 0x000000f2, 0x00000076, 0x0000017a, 0x0000017a, 0x0000017a,
+	0x0000017a, 0x0000017a,
+};
+
+static const u32 nbl_sec138_data[] = {
+	0x0000017a, 0x000000f2, 0x00000076, 0x0000017a, 0x0000017a, 0x00000080,
+	0x00000024, 0x0000017a, 0x0000017a, 0x00000191, 0x00000035, 0x0000017a,
+	0x0000017a, 0x0000017a, 0x0000017a, 0x0000017a, 0x0000017a, 0x000000d2,
+	0x00000066, 0x0000017a, 0x0000017a, 0x0000017a, 0x0000017a, 0x0000017a,
+	0x0000017a, 0x000000f2, 0x00000076, 0x0000017a, 0x0000017a, 0x0000017a,
+	0x0000017a, 0x0000017a,
+};
+
+/*
+ * nbl_write_all_regs - Write initial register values during probe
+ *
+ * Context: This function is called ONLY during PCI probe (single-threaded,
+ * before any interrupts or concurrent access are possible). The reg_lock
+ * is intentionally NOT acquired here because:
+ * 1. Probe runs before device is registered to subsystem
+ * 2. No other thread can access this device yet
+ * 3. reg_lock is a spinlock_t (safe in atomic), but acquiring it
+ *    here is redundant since probe is single-threaded before
+ *    device registration
+ * Note: SEC block sizes are multiples of NBL_SEC_BLOCK_SIZE (>= 2x for
+ * multi-block sections). flush_writes() is placed inside the loop at
+ * block boundaries for multi-block sections, and outside for single-block
+ * or sub-block sections.
+ *
+ * The 139 sections are intentionally identified by index rather than by
+ * name. The hardware block layout is fixed and documented internally;
+ * adding string names would increase the binary size without providing
+ * any functional benefit to the driver or to users.
+ */
+int nbl_write_all_regs(struct nbl_hw_mgt *hw_mgt)
+{
+	struct nbl_common_info *common = hw_mgt->common;
+	u8 eth_num = common->eth_num;
+	const u32 *nbl_sec046_data;
+	const u32 *nbl_sec071_data;
+	u32 i;
+
+	switch (eth_num) {
+	case 1:
+		nbl_sec046_data = nbl_sec046_1p_data;
+		nbl_sec071_data = nbl_sec071_1p_data;
+		break;
+	case 2:
+		nbl_sec046_data = nbl_sec046_2p_data;
+		nbl_sec071_data = nbl_sec071_2p_data;
+		break;
+	case 4:
+		nbl_sec046_data = nbl_sec046_4p_data;
+		nbl_sec071_data = nbl_sec071_4p_data;
+		break;
+	default:
+		dev_err(common->dev, "Invalid eth_num %u\n", eth_num);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < NBL_SEC006_SIZE; i++) {
+		nbl_hw_wr32(hw_mgt, NBL_SEC006_REGI(i), nbl_sec006_data[i]);
+		if ((i + 1) % NBL_SEC_BLOCK_SIZE == 0)
+			nbl_flush_writes(hw_mgt);
+	}
+
+	for (i = 0; i < NBL_SEC007_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC007_REGI(i), nbl_sec007_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC008_SIZE; i++) {
+		nbl_hw_wr32(hw_mgt, NBL_SEC008_REGI(i), nbl_sec008_data[i]);
+		if ((i + 1) % NBL_SEC_BLOCK_SIZE == 0)
+			nbl_flush_writes(hw_mgt);
+	}
+
+	for (i = 0; i < NBL_SEC009_SIZE; i++) {
+		nbl_hw_wr32(hw_mgt, NBL_SEC009_REGI(i), nbl_sec009_data[i]);
+		if ((i + 1) % NBL_SEC_BLOCK_SIZE == 0)
+			nbl_flush_writes(hw_mgt);
+	}
+
+	for (i = 0; i < NBL_SEC010_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC010_REGI(i), nbl_sec010_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC011_SIZE; i++) {
+		nbl_hw_wr32(hw_mgt, NBL_SEC011_REGI(i), nbl_sec011_data[i]);
+		if ((i + 1) % NBL_SEC_BLOCK_SIZE == 0)
+			nbl_flush_writes(hw_mgt);
+	}
+
+	for (i = 0; i < NBL_SEC012_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC012_REGI(i), nbl_sec012_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC013_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC013_REGI(i), nbl_sec013_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC014_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC014_REGI(i), nbl_sec014_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC022_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC022_REGI(i), nbl_sec022_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC023_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC023_REGI(i), nbl_sec023_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC024_SIZE; i++) {
+		nbl_hw_wr32(hw_mgt, NBL_SEC024_REGI(i), nbl_sec024_data[i]);
+		if ((i + 1) % NBL_SEC_BLOCK_SIZE == 0)
+			nbl_flush_writes(hw_mgt);
+	}
+
+	for (i = 0; i < NBL_SEC025_SIZE; i++) {
+		nbl_hw_wr32(hw_mgt, NBL_SEC025_REGI(i), nbl_sec025_data[i]);
+		if ((i + 1) % NBL_SEC_BLOCK_SIZE == 0)
+			nbl_flush_writes(hw_mgt);
+	}
+
+	for (i = 0; i < NBL_SEC026_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC026_REGI(i), nbl_sec026_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC027_SIZE; i++) {
+		nbl_hw_wr32(hw_mgt, NBL_SEC027_REGI(i), nbl_sec027_data[i]);
+		if ((i + 1) % NBL_SEC_BLOCK_SIZE == 0)
+			nbl_flush_writes(hw_mgt);
+	}
+
+	for (i = 0; i < NBL_SEC028_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC028_REGI(i), nbl_sec028_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC029_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC029_REGI(i), nbl_sec029_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC030_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC030_REGI(i), nbl_sec030_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC039_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC039_REGI(i), nbl_sec039_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC040_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC040_REGI(i), nbl_sec040_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC046_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC046_REGI(i), nbl_sec046_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC047_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC047_REGI(i), nbl_sec047_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC052_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC052_REGI(i), nbl_sec052_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC053_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC053_REGI(i), nbl_sec053_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC058_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC058_REGI(i), nbl_sec058_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC059_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC059_REGI(i), nbl_sec059_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC062_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC062_REGI(i), nbl_sec062_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC063_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC063_REGI(i), nbl_sec063_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC065_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC065_REGI(i), nbl_sec065_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC066_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC066_REGI(i), nbl_sec066_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC071_SIZE; i++) {
+		nbl_hw_wr32(hw_mgt, NBL_SEC071_REGI(i), nbl_sec071_data[i]);
+		if ((i + 1) % NBL_SEC_BLOCK_SIZE == 0)
+			nbl_flush_writes(hw_mgt);
+	}
+
+	for (i = 0; i < NBL_SEC072_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC072_REGI(i), nbl_sec072_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC116_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC116_REGI(i), nbl_sec116_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC124_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC124_REGI(i), nbl_sec124_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC125_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC125_REGI(i), nbl_sec125_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC126_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC126_REGI(i), nbl_sec126_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC137_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC137_REGI(i), nbl_sec137_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	for (i = 0; i < NBL_SEC138_SIZE; i++)
+		nbl_hw_wr32(hw_mgt, NBL_SEC138_REGI(i), nbl_sec138_data[i]);
+	nbl_flush_writes(hw_mgt);
+
+	nbl_hw_wr32(hw_mgt, NBL_SEC000_ADDR, 0x00000001);
+	nbl_hw_wr32(hw_mgt, NBL_SEC001_ADDR, 0x00000001);
+	nbl_hw_wr32(hw_mgt, NBL_SEC002_ADDR, 0x00000001);
+	nbl_hw_wr32(hw_mgt, NBL_SEC003_ADDR, 0x00000001);
+	nbl_hw_wr32(hw_mgt, NBL_SEC004_ADDR, 0x00000001);
+	nbl_hw_wr32(hw_mgt, NBL_SEC005_ADDR, 0x00000001);
+	nbl_hw_wr32(hw_mgt, NBL_SEC015_ADDR, 0x000f0908);
+	nbl_hw_wr32(hw_mgt, NBL_SEC016_ADDR, 0x10110607);
+	nbl_hw_wr32(hw_mgt, NBL_SEC017_ADDR, 0x383a3032);
+	nbl_hw_wr32(hw_mgt, NBL_SEC018_ADDR, 0x0201453f);
+	nbl_hw_wr32(hw_mgt, NBL_SEC019_ADDR, 0x00000a41);
+	nbl_hw_wr32(hw_mgt, NBL_SEC020_ADDR, 0x000000c8);
+	nbl_hw_wr32(hw_mgt, NBL_SEC021_ADDR, 0x00000400);
+	nbl_hw_wr32(hw_mgt, NBL_SEC031_ADDR, 0x000f0908);
+	nbl_hw_wr32(hw_mgt, NBL_SEC032_ADDR, 0x00001011);
+	nbl_hw_wr32(hw_mgt, NBL_SEC033_ADDR, 0x00003032);
+	nbl_hw_wr32(hw_mgt, NBL_SEC034_ADDR, 0x0201003f);
+	nbl_hw_wr32(hw_mgt, NBL_SEC035_ADDR, 0x0000000a);
+	nbl_hw_wr32(hw_mgt, NBL_SEC036_ADDR, 0x00001701);
+	nbl_hw_wr32(hw_mgt, NBL_SEC037_ADDR, 0x009238a1);
+	nbl_hw_wr32(hw_mgt, NBL_SEC038_ADDR, 0x0000002e);
+	nbl_hw_wr32(hw_mgt, NBL_SEC041_REGI(0), 0x00000200);
+	nbl_hw_wr32(hw_mgt, NBL_SEC041_REGI(1), 0x00000300);
+	nbl_hw_wr32(hw_mgt, NBL_SEC041_REGI(2), 0x00000105);
+	nbl_hw_wr32(hw_mgt, NBL_SEC041_REGI(3), 0x00000106);
+	nbl_hw_wr32(hw_mgt, NBL_SEC041_REGI(4), 0x00000009);
+	nbl_hw_wr32(hw_mgt, NBL_SEC041_REGI(5), 0x0000000a);
+	nbl_hw_wr32(hw_mgt, NBL_SEC041_REGI(6), 0x00000041);
+	nbl_hw_wr32(hw_mgt, NBL_SEC041_REGI(7), 0x00000082);
+	nbl_hw_wr32(hw_mgt, NBL_SEC041_REGI(8), 0x00000020);
+	nbl_hw_wr32(hw_mgt, NBL_SEC041_REGI(9), 0x00000000);
+	nbl_hw_wr32(hw_mgt, NBL_SEC041_REGI(10), 0x00000000);
+	nbl_hw_wr32(hw_mgt, NBL_SEC041_REGI(11), 0x00000000);
+	nbl_hw_wr32(hw_mgt, NBL_SEC041_REGI(12), 0x00000000);
+	nbl_hw_wr32(hw_mgt, NBL_SEC041_REGI(13), 0x00000000);
+	nbl_hw_wr32(hw_mgt, NBL_SEC041_REGI(14), 0x00000000);
+	nbl_hw_wr32(hw_mgt, NBL_SEC041_REGI(15), 0x00000000);
+	nbl_hw_wr32(hw_mgt, NBL_SEC042_ADDR, 0x00000001);
+	nbl_hw_wr32(hw_mgt, NBL_SEC043_ADDR, 0x00000002);
+	nbl_hw_wr32(hw_mgt, NBL_SEC044_ADDR, 0x28212000);
+	nbl_hw_wr32(hw_mgt, NBL_SEC045_ADDR, 0x00002b29);
+	nbl_hw_wr32(hw_mgt, NBL_SEC048_ADDR, 0x00000001);
+	nbl_hw_wr32(hw_mgt, NBL_SEC049_ADDR, 0x00000002);
+	nbl_hw_wr32(hw_mgt, NBL_SEC050_ADDR, 0x352b2000);
+	nbl_hw_wr32(hw_mgt, NBL_SEC051_ADDR, 0x00000000);
+	nbl_hw_wr32(hw_mgt, NBL_SEC054_ADDR, 0x00000001);
+	nbl_hw_wr32(hw_mgt, NBL_SEC055_ADDR, 0x00000002);
+	nbl_hw_wr32(hw_mgt, NBL_SEC056_ADDR, 0x2b222100);
+	nbl_hw_wr32(hw_mgt, NBL_SEC057_ADDR, 0x00000038);
+	nbl_hw_wr32(hw_mgt, NBL_SEC060_ADDR, 0x24232221);
+	nbl_hw_wr32(hw_mgt, NBL_SEC061_ADDR, 0x0000002e);
+	nbl_hw_wr32(hw_mgt, NBL_SEC064_REGI(0), 0x00000009);
+	nbl_hw_wr32(hw_mgt, NBL_SEC064_REGI(1), 0x00000005);
+	nbl_hw_wr32(hw_mgt, NBL_SEC064_REGI(2), 0x00000011);
+	nbl_hw_wr32(hw_mgt, NBL_SEC064_REGI(3), 0x00000005);
+	nbl_hw_wr32(hw_mgt, NBL_SEC064_REGI(4), 0x00000001);
+	nbl_hw_wr32(hw_mgt, NBL_SEC064_REGI(5), 0x0000000a);
+	nbl_hw_wr32(hw_mgt, NBL_SEC064_REGI(6), 0x00000006);
+	nbl_hw_wr32(hw_mgt, NBL_SEC064_REGI(7), 0x00000012);
+	nbl_hw_wr32(hw_mgt, NBL_SEC064_REGI(8), 0x00000006);
+	nbl_hw_wr32(hw_mgt, NBL_SEC064_REGI(9), 0x00000002);
+	nbl_hw_wr32(hw_mgt, NBL_SEC064_REGI(10), 0x00000000);
+	nbl_hw_wr32(hw_mgt, NBL_SEC064_REGI(11), 0x00000000);
+	nbl_hw_wr32(hw_mgt, NBL_SEC064_REGI(12), 0x00000000);
+	nbl_hw_wr32(hw_mgt, NBL_SEC064_REGI(13), 0x00000000);
+	nbl_hw_wr32(hw_mgt, NBL_SEC064_REGI(14), 0x00000000);
+	nbl_hw_wr32(hw_mgt, NBL_SEC064_REGI(15), 0x00000000);
+	nbl_hw_wr32(hw_mgt, NBL_SEC067_ADDR, 0x00000001);
+	nbl_hw_wr32(hw_mgt, NBL_SEC068_ADDR, 0x00000001);
+	nbl_hw_wr32(hw_mgt, NBL_SEC069_ADDR, 0x22212000);
+	nbl_hw_wr32(hw_mgt, NBL_SEC070_ADDR, 0x3835322b);
+	nbl_hw_wr32(hw_mgt, NBL_SEC073_ADDR, 0x0316a5ff);
+	nbl_hw_wr32(hw_mgt, NBL_SEC074_ADDR, 0x0316a5ff);
+	nbl_hw_wr32(hw_mgt, NBL_SEC075_REGI(0), 0x08802080);
+	nbl_hw_wr32(hw_mgt, NBL_SEC075_REGI(1), 0x12a05080);
+	nbl_hw_wr32(hw_mgt, NBL_SEC075_REGI(2), 0xffffffff);
+	nbl_hw_wr32(hw_mgt, NBL_SEC075_REGI(3), 0xffffffff);
+	nbl_hw_wr32(hw_mgt, NBL_SEC076_REGI(0), 0x08802080);
+	nbl_hw_wr32(hw_mgt, NBL_SEC076_REGI(1), 0x12a05080);
+	nbl_hw_wr32(hw_mgt, NBL_SEC076_REGI(2), 0xffffffff);
+	nbl_hw_wr32(hw_mgt, NBL_SEC076_REGI(3), 0xffffffff);
+	nbl_hw_wr32(hw_mgt, NBL_SEC077_REGI(0), 0x08802080);
+	nbl_hw_wr32(hw_mgt, NBL_SEC077_REGI(1), 0x12a05080);
+	nbl_hw_wr32(hw_mgt, NBL_SEC077_REGI(2), 0xffffffff);
+	nbl_hw_wr32(hw_mgt, NBL_SEC077_REGI(3), 0xffffffff);
+	nbl_hw_wr32(hw_mgt, NBL_SEC078_ADDR, 0x00000009);
+	nbl_hw_wr32(hw_mgt, NBL_SEC079_ADDR, 0x00000009);
+	nbl_hw_wr32(hw_mgt, NBL_SEC080_ADDR, 0x0014a248);
+	nbl_hw_wr32(hw_mgt, NBL_SEC081_ADDR, 0x00000d33);
+	nbl_hw_wr32(hw_mgt, NBL_SEC082_ADDR, 0x00000009);
+	nbl_hw_wr32(hw_mgt, NBL_SEC083_ADDR, 0x00000009);
+	nbl_hw_wr32(hw_mgt, NBL_SEC084_ADDR, 0x00000009);
+	nbl_hw_wr32(hw_mgt, NBL_SEC085_ADDR, 0x000144d2);
+	nbl_hw_wr32(hw_mgt, NBL_SEC086_ADDR, 0x31322e2f);
+	nbl_hw_wr32(hw_mgt, NBL_SEC087_ADDR, 0x0a092d2c);
+	nbl_hw_wr32(hw_mgt, NBL_SEC088_ADDR, 0x33050804);
+	nbl_hw_wr32(hw_mgt, NBL_SEC089_ADDR, 0x14131535);
+	nbl_hw_wr32(hw_mgt, NBL_SEC090_ADDR, 0x0000000a);
+	nbl_hw_wr32(hw_mgt, NBL_SEC091_ADDR, 0x00000009);
+	nbl_hw_wr32(hw_mgt, NBL_SEC092_ADDR, 0x00000008);
+	nbl_hw_wr32(hw_mgt, NBL_SEC093_ADDR, 0x0000000e);
+	nbl_hw_wr32(hw_mgt, NBL_SEC094_ADDR, 0x0000000f);
+	nbl_hw_wr32(hw_mgt, NBL_SEC095_ADDR, 0x00000015);
+	nbl_hw_wr32(hw_mgt, NBL_SEC096_ADDR, 0x00000009);
+	nbl_hw_wr32(hw_mgt, NBL_SEC097_ADDR, 0x0000000a);
+	nbl_hw_wr32(hw_mgt, NBL_SEC098_ADDR, 0x00000008);
+	nbl_hw_wr32(hw_mgt, NBL_SEC099_ADDR, 0x00000011);
+	nbl_hw_wr32(hw_mgt, NBL_SEC100_ADDR, 0x00000013);
+	nbl_hw_wr32(hw_mgt, NBL_SEC101_ADDR, 0x00000014);
+	nbl_hw_wr32(hw_mgt, NBL_SEC102_ADDR, 0x00000010);
+	nbl_hw_wr32(hw_mgt, NBL_SEC103_ADDR, 0x00000009);
+	nbl_hw_wr32(hw_mgt, NBL_SEC104_ADDR, 0x0000004d);
+	nbl_hw_wr32(hw_mgt, NBL_SEC105_ADDR, 0x08020a09);
+	nbl_hw_wr32(hw_mgt, NBL_SEC106_ADDR, 0x00000005);
+	nbl_hw_wr32(hw_mgt, NBL_SEC107_ADDR, 0x00000006);
+	nbl_hw_wr32(hw_mgt, NBL_SEC108_ADDR, 0x00000009);
+	nbl_hw_wr32(hw_mgt, NBL_SEC109_ADDR, 0x00110a09);
+	nbl_hw_wr32(hw_mgt, NBL_SEC110_ADDR, 0x00000009);
+	nbl_hw_wr32(hw_mgt, NBL_SEC111_ADDR, 0x00000009);
+	nbl_hw_wr32(hw_mgt, NBL_SEC112_ADDR, 0x00000009);
+	nbl_hw_wr32(hw_mgt, NBL_SEC113_ADDR, 0x0000000a);
+	nbl_hw_wr32(hw_mgt, NBL_SEC114_ADDR, 0x0000000a);
+	nbl_hw_wr32(hw_mgt, NBL_SEC115_ADDR, 0x00000009);
+	nbl_hw_wr32(hw_mgt, NBL_SEC117_ADDR, 0x0000000a);
+	nbl_hw_wr32(hw_mgt, NBL_SEC118_ADDR, 0x00000001);
+	nbl_hw_wr32(hw_mgt, NBL_SEC119_REGI(0), 0x00000000);
+	nbl_hw_wr32(hw_mgt, NBL_SEC119_REGI(1), 0x00000000);
+	nbl_hw_wr32(hw_mgt, NBL_SEC119_REGI(2), 0x00000000);
+	nbl_hw_wr32(hw_mgt, NBL_SEC119_REGI(3), 0x00000000);
+	nbl_hw_wr32(hw_mgt, NBL_SEC119_REGI(4), 0x00000100);
+	nbl_hw_wr32(hw_mgt, NBL_SEC120_ADDR, 0x0000003c);
+	nbl_hw_wr32(hw_mgt, NBL_SEC121_ADDR, 0x00000003);
+	nbl_hw_wr32(hw_mgt, NBL_SEC122_ADDR, 0x000000bc);
+	nbl_hw_wr32(hw_mgt, NBL_SEC123_ADDR, 0x0000023b);
+	nbl_hw_wr32(hw_mgt, NBL_SEC127_ADDR, 0x00000001);
+	nbl_hw_wr32(hw_mgt, NBL_SEC128_ADDR, 0x00000001);
+	nbl_hw_wr32(hw_mgt, NBL_SEC129_ADDR, 0x00000002);
+	nbl_hw_wr32(hw_mgt, NBL_SEC130_ADDR, 0x00000002);
+	nbl_hw_wr32(hw_mgt, NBL_SEC131_ADDR, 0x00000003);
+	nbl_hw_wr32(hw_mgt, NBL_SEC132_ADDR, 0x00000003);
+	nbl_hw_wr32(hw_mgt, NBL_SEC133_ADDR, 0x00000004);
+	nbl_hw_wr32(hw_mgt, NBL_SEC134_ADDR, 0x00000004);
+	nbl_hw_wr32(hw_mgt, NBL_SEC135_ADDR, 0x0000000e);
+	nbl_hw_wr32(hw_mgt, NBL_SEC136_ADDR, 0x0000000e);
+	nbl_flush_writes(hw_mgt);
+
+	return 0;
+}
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis_regs.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis_regs.h
new file mode 100644
index 000000000000..0a534ac596da
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis_regs.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+
+#ifndef _NBL_HW_LEONIS_REGS_H_
+#define _NBL_HW_LEONIS_REGS_H_
+
+int nbl_write_all_regs(struct nbl_hw_mgt *hw_mgt);
+
+#endif
-- 
2.47.3


^ permalink raw reply related

* [PATCH v15 net-next 11/11] net/nebula-matrix: add common dev start/stop operation
From: illusion.wang @ 2026-05-20  3:29 UTC (permalink / raw)
  To: dimon.zhao, illusion.wang, alvin.wang, sam.chen, netdev
  Cc: andrew+netdev, corbet, kuba, horms, linux-doc, pabeni,
	vadim.fedorenko, lukas.bulwahn, edumazet, enelsonmoore, skhan,
	hkallweit1, open list
In-Reply-To: <20260520032950.4874-1-illusion.wang@nebula-matrix.com>

This patch wires up nbl_dev_start() and nbl_dev_stop() to configure
the MSI-X map, allocate vectors, and request/enable the mailbox IRQ.
It also replaces module_pci_driver() with explicit init/exit functions
that additionally create and destroy the driver's workqueue via
nbl_common_create_wq() / nbl_common_destroy_wq(), which is needed
because the new IRQ handler schedules work through
nbl_common_queue_work().

Signed-off-by: illusion.wang <illusion.wang@nebula-matrix.com>
---
 .../nebula-matrix/nbl/nbl_common/nbl_common.c |  34 +++
 .../nebula-matrix/nbl/nbl_core/nbl_dev.c      | 220 ++++++++++++++++++
 .../nbl/nbl_include/nbl_def_common.h          |   4 +
 .../net/ethernet/nebula-matrix/nbl/nbl_main.c |  31 ++-
 4 files changed, 288 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_common/nbl_common.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_common/nbl_common.c
index 11b1948658d9..3ee08b0cb9f4 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_common/nbl_common.c
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_common/nbl_common.c
@@ -6,6 +6,40 @@
 #include <linux/device.h>
 #include "nbl_common.h"
 
+static struct nbl_common_wq_mgt *wq_mgt;
+
+void nbl_common_queue_work(struct work_struct *task)
+{
+	queue_work(wq_mgt->ctrl_dev_wq, task);
+}
+
+void nbl_common_destroy_wq(void)
+{
+	destroy_workqueue(wq_mgt->ctrl_dev_wq);
+	kfree(wq_mgt);
+	wq_mgt = NULL;
+}
+
+int nbl_common_create_wq(void)
+{
+	wq_mgt = kzalloc_obj(*wq_mgt);
+	if (!wq_mgt)
+		return -ENOMEM;
+
+	wq_mgt->ctrl_dev_wq = alloc_workqueue("%s", WQ_MEM_RECLAIM | WQ_UNBOUND,
+					      0, "nbl_ctrldev_wq");
+	if (!wq_mgt->ctrl_dev_wq) {
+		pr_err("Failed to create workqueue nbl_ctrldev_wq\n");
+		goto alloc_ctrl_dev_wq_failed;
+	}
+
+	return 0;
+alloc_ctrl_dev_wq_failed:
+	kfree(wq_mgt);
+	wq_mgt = NULL;
+	return -ENOMEM;
+}
+
 u32 nbl_common_pf_id_subtraction_mgtpf_id(struct nbl_common_info *common,
 					  u32 pf_id)
 {
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.c
index eb5d2b33a300..9b5627c245e1 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.c
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.c
@@ -6,6 +6,17 @@
 #include <linux/pci.h>
 #include "nbl_dev.h"
 
+static void nbl_dev_clean_mailbox_schedule(struct nbl_dev_mgt *dev_mgt);
+
+/* ----------  Interrupt config  ---------- */
+static irqreturn_t nbl_dev_clean_mailbox(int __always_unused irq, void *data)
+{
+	struct nbl_dev_mgt *dev_mgt = (struct nbl_dev_mgt *)data;
+
+	nbl_dev_clean_mailbox_schedule(dev_mgt);
+	return IRQ_HANDLED;
+}
+
 static void nbl_dev_init_msix_cnt(struct nbl_dev_mgt *dev_mgt)
 {
 	struct nbl_dev_common *dev_common = dev_mgt->common_dev;
@@ -14,6 +25,173 @@ static void nbl_dev_init_msix_cnt(struct nbl_dev_mgt *dev_mgt)
 	msix_info->serv_info[NBL_MSIX_MAILBOX_TYPE].num = 1;
 }
 
+static int nbl_dev_request_mailbox_irq(struct nbl_dev_mgt *dev_mgt)
+{
+	struct nbl_dev_common *dev_common = dev_mgt->common_dev;
+	struct nbl_msix_info *msix_info = &dev_common->msix_info;
+	struct nbl_common_info *common = dev_mgt->common;
+	u16 local_vec_id;
+	int irq_num;
+	int err;
+
+	if (!msix_info->serv_info[NBL_MSIX_MAILBOX_TYPE].num)
+		return 0;
+
+	local_vec_id =
+		msix_info->serv_info[NBL_MSIX_MAILBOX_TYPE].base_vector_id;
+	irq_num = pci_irq_vector(common->pdev, local_vec_id);
+	if (irq_num < 0) {
+		dev_err(common->dev, "Failed to get mailbox IRQ vector: %d\n",
+			irq_num);
+		return irq_num;
+	}
+
+	snprintf(dev_common->mailbox_name, sizeof(dev_common->mailbox_name),
+		 "nbl_mailbox@pci:%s", pci_name(common->pdev));
+	err = request_irq(irq_num, nbl_dev_clean_mailbox, 0,
+			  dev_common->mailbox_name, dev_mgt);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static void nbl_dev_free_mailbox_irq(struct nbl_dev_mgt *dev_mgt)
+{
+	struct nbl_dev_common *dev_common = dev_mgt->common_dev;
+	struct nbl_msix_info *msix_info = &dev_common->msix_info;
+	struct nbl_common_info *common = dev_mgt->common;
+	u16 local_vec_id;
+	int irq_num;
+
+	if (!msix_info->serv_info[NBL_MSIX_MAILBOX_TYPE].num)
+		return;
+
+	local_vec_id =
+		msix_info->serv_info[NBL_MSIX_MAILBOX_TYPE].base_vector_id;
+	irq_num = pci_irq_vector(common->pdev, local_vec_id);
+	if (irq_num >= 0)
+		free_irq(irq_num, dev_mgt);
+}
+
+static int nbl_dev_enable_mailbox_irq(struct nbl_dev_mgt *dev_mgt)
+{
+	struct nbl_dispatch_ops *disp_ops = dev_mgt->disp_ops_tbl->ops;
+	struct nbl_channel_ops *chan_ops = dev_mgt->chan_ops_tbl->ops;
+	struct nbl_dev_common *dev_common = dev_mgt->common_dev;
+	struct nbl_msix_info *msix_info = &dev_common->msix_info;
+	u16 local_vec_id;
+
+	if (!msix_info->serv_info[NBL_MSIX_MAILBOX_TYPE].num)
+		return 0;
+
+	local_vec_id =
+		msix_info->serv_info[NBL_MSIX_MAILBOX_TYPE].base_vector_id;
+	chan_ops->set_queue_state(dev_mgt->chan_ops_tbl->priv,
+				  NBL_CHAN_INTERRUPT_READY,
+				  NBL_CHAN_TYPE_MAILBOX, true);
+
+	return disp_ops->set_mailbox_irq(dev_mgt->disp_ops_tbl->priv,
+					    local_vec_id, true);
+}
+
+static int nbl_dev_disable_mailbox_irq(struct nbl_dev_mgt *dev_mgt)
+{
+	struct nbl_dispatch_ops *disp_ops = dev_mgt->disp_ops_tbl->ops;
+	struct nbl_channel_ops *chan_ops = dev_mgt->chan_ops_tbl->ops;
+	struct nbl_dev_common *dev_common = dev_mgt->common_dev;
+	struct nbl_msix_info *msix_info = &dev_common->msix_info;
+	u16 local_vec_id;
+
+	if (!msix_info->serv_info[NBL_MSIX_MAILBOX_TYPE].num)
+		return 0;
+
+	local_vec_id =
+		msix_info->serv_info[NBL_MSIX_MAILBOX_TYPE].base_vector_id;
+	chan_ops->set_queue_state(dev_mgt->chan_ops_tbl->priv,
+				  NBL_CHAN_INTERRUPT_READY,
+				  NBL_CHAN_TYPE_MAILBOX, false);
+
+	return disp_ops->set_mailbox_irq(dev_mgt->disp_ops_tbl->priv,
+					    local_vec_id, false);
+}
+
+static int nbl_dev_configure_msix_map(struct nbl_dev_mgt *dev_mgt)
+{
+	struct nbl_dispatch_ops *disp_ops = dev_mgt->disp_ops_tbl->ops;
+	struct nbl_dev_common *dev_common = dev_mgt->common_dev;
+	struct nbl_msix_info *msix_info = &dev_common->msix_info;
+	bool mask_en = msix_info->serv_info[NBL_MSIX_NET_TYPE].hw_self_mask_en;
+	u16 msix_net_num = msix_info->serv_info[NBL_MSIX_NET_TYPE].num;
+	u16 msix_not_net_num = 0;
+	int err, i;
+
+	msix_info->serv_info[NBL_MSIX_VIRTIO_TYPE].base_vector_id = 0;
+	for (i = NBL_MSIX_NET_TYPE; i < NBL_MSIX_TYPE_MAX; i++)
+		msix_info->serv_info[i].base_vector_id =
+			msix_info->serv_info[i - 1].base_vector_id +
+			msix_info->serv_info[i - 1].num;
+
+	for (i = NBL_MSIX_MAILBOX_TYPE; i < NBL_MSIX_TYPE_MAX; i++)
+		msix_not_net_num += msix_info->serv_info[i].num;
+
+	err = disp_ops->configure_msix_map(dev_mgt->disp_ops_tbl->priv,
+					   msix_net_num, msix_not_net_num,
+					   mask_en);
+
+	return err;
+}
+
+static int nbl_dev_destroy_msix_map(struct nbl_dev_mgt *dev_mgt)
+{
+	struct nbl_dispatch_ops *disp_ops = dev_mgt->disp_ops_tbl->ops;
+
+	return disp_ops->destroy_msix_map(dev_mgt->disp_ops_tbl->priv);
+}
+
+static int nbl_dev_alloc_msix_intr(struct nbl_dev_mgt *dev_mgt)
+{
+	struct nbl_dev_common *dev_common = dev_mgt->common_dev;
+	struct nbl_msix_info *msix_info = &dev_common->msix_info;
+	struct nbl_common_info *common = dev_mgt->common;
+	int needed = 0;
+	int err;
+	int i;
+
+	for (i = 0; i < NBL_MSIX_TYPE_MAX; i++)
+		needed += msix_info->serv_info[i].num;
+
+	err = pci_alloc_irq_vectors(common->pdev, needed, needed,
+				    PCI_IRQ_MSIX | PCI_IRQ_AFFINITY);
+	if (err < 0) {
+		dev_err(common->dev,
+			"pci_alloc_irq_vectors failed, err = %d\n", err);
+		return err;
+	}
+
+	return 0;
+}
+
+static int nbl_dev_init_interrupt_scheme(struct nbl_dev_mgt *dev_mgt)
+{
+	int err;
+
+	err = nbl_dev_alloc_msix_intr(dev_mgt);
+	if (err) {
+		dev_err(dev_mgt->common->dev,
+			"Failed to enable MSI-X vectors\n");
+		return err;
+	}
+	return 0;
+}
+
+static void nbl_dev_clear_interrupt_scheme(struct nbl_dev_mgt *dev_mgt)
+{
+	struct nbl_common_info *common = dev_mgt->common;
+
+	pci_free_irq_vectors(common->pdev);
+}
+
 /* ----------  Channel config  ---------- */
 static void nbl_dev_setup_chan_qinfo(struct nbl_dev_mgt *dev_mgt, u8 chan_type)
 {
@@ -72,6 +250,13 @@ static void nbl_dev_clean_mailbox_task(struct work_struct *work)
 				      NBL_CHAN_TYPE_MAILBOX);
 }
 
+static void nbl_dev_clean_mailbox_schedule(struct nbl_dev_mgt *dev_mgt)
+{
+	struct nbl_dev_common *common_dev = dev_mgt->common_dev;
+
+	nbl_common_queue_work(&common_dev->clean_mbx_task);
+}
+
 /* ----------  Dev init process  ---------- */
 static int nbl_dev_setup_common_dev(struct nbl_adapter *adapter)
 {
@@ -222,9 +407,44 @@ void nbl_dev_remove(struct nbl_adapter *adapter)
 /* ----------  Dev start process  ---------- */
 int nbl_dev_start(struct nbl_adapter *adapter)
 {
+	struct nbl_dev_mgt *dev_mgt = adapter->core.dev_mgt;
+	struct nbl_dev_common *common_dev = dev_mgt->common_dev;
+	int ret;
+
+	ret = nbl_dev_configure_msix_map(dev_mgt);
+	if (ret)
+		return ret;
+
+	ret = nbl_dev_init_interrupt_scheme(dev_mgt);
+	if (ret)
+		goto init_interrupt_scheme_err;
+	ret = nbl_dev_request_mailbox_irq(dev_mgt);
+	if (ret)
+		goto mailbox_request_irq_err;
+	ret = nbl_dev_enable_mailbox_irq(dev_mgt);
+	if (ret)
+		goto enable_mailbox_irq_err;
+
 	return 0;
+enable_mailbox_irq_err:
+	cancel_work_sync(&common_dev->clean_mbx_task);
+	nbl_dev_disable_mailbox_irq(dev_mgt);
+	nbl_dev_free_mailbox_irq(dev_mgt);
+mailbox_request_irq_err:
+	nbl_dev_clear_interrupt_scheme(dev_mgt);
+init_interrupt_scheme_err:
+	nbl_dev_destroy_msix_map(dev_mgt);
+	return ret;
 }
 
 void nbl_dev_stop(struct nbl_adapter *adapter)
 {
+	struct nbl_dev_mgt *dev_mgt = adapter->core.dev_mgt;
+	struct nbl_dev_common *common_dev = dev_mgt->common_dev;
+
+	cancel_work_sync(&common_dev->clean_mbx_task);
+	nbl_dev_disable_mailbox_irq(dev_mgt);
+	nbl_dev_free_mailbox_irq(dev_mgt);
+	nbl_dev_clear_interrupt_scheme(dev_mgt);
+	nbl_dev_destroy_msix_map(dev_mgt);
 }
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_common.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_common.h
index 09d20d3235fe..2a35399cd1ec 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_common.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_common.h
@@ -62,6 +62,10 @@ struct nbl_hash_tbl_del_key {
 	void (*action_func)(void *priv, void *key, void *data);
 };
 
+void nbl_common_queue_work(struct work_struct *task);
+
+void nbl_common_destroy_wq(void);
+int nbl_common_create_wq(void);
 u32 nbl_common_pf_id_subtraction_mgtpf_id(struct nbl_common_info *common,
 					  u32 pf_id);
 
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_main.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_main.c
index 4cf3a804d5a5..b4cef26130a9 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_main.c
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_main.c
@@ -297,7 +297,36 @@ static struct pci_driver nbl_driver = {
 	.remove = nbl_remove,
 };
 
-module_pci_driver(nbl_driver);
+static int __init nbl_module_init(void)
+{
+	int status;
+
+	status = nbl_common_create_wq();
+	if (status) {
+		pr_err("Failed to create wq, err = %d\n", status);
+		goto wq_create_failed;
+	}
+	status = pci_register_driver(&nbl_driver);
+	if (status) {
+		pr_err("Failed to register PCI driver, err = %d\n", status);
+		goto pci_register_driver_failed;
+	}
+
+	return 0;
+
+pci_register_driver_failed:
+	nbl_common_destroy_wq();
+wq_create_failed:
+	return status;
+}
+
+static void __exit nbl_module_exit(void)
+{
+	pci_unregister_driver(&nbl_driver);
+	nbl_common_destroy_wq();
+}
 
+module_init(nbl_module_init);
+module_exit(nbl_module_exit);
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Nebula Matrix Network Driver");
-- 
2.47.3


^ permalink raw reply related

* [PATCH v15 net-next 04/11] net/nebula-matrix: channel msg value and msg struct
From: illusion.wang @ 2026-05-20  3:29 UTC (permalink / raw)
  To: dimon.zhao, illusion.wang, alvin.wang, sam.chen, netdev
  Cc: andrew+netdev, corbet, kuba, horms, linux-doc, pabeni,
	vadim.fedorenko, lukas.bulwahn, edumazet, enelsonmoore, skhan,
	hkallweit1, open list
In-Reply-To: <20260520032950.4874-1-illusion.wang@nebula-matrix.com>

This patch introduces the channel message ID enumeration and several
message parameter structures for the nebula-matrix driver.

To ensure compatibility, the msg ID values are fixed, and fields can
only be appended to existing structures, not removed. Additionally,
any newly added fields must be placed on new Data Words (DWs) to
maintain alignment and compatibility. For array-type fields,
the length of individual array members cannot be changed once defined.

When modifying request structures, if a new field is added, the
corresponding response function must define a new stack variable
of the updated request message structure. The newly added fields
should be initialized to invalid values, and a minimal copy of the
original data should be performed to preserve compatibility with
existing implementations.

Signed-off-by: illusion.wang <illusion.wang@nebula-matrix.com>
---
 .../nbl/nbl_include/nbl_def_channel.h         | 251 ++++++++++++++++++
 1 file changed, 251 insertions(+)

diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_channel.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_channel.h
index ff03a53b9f5d..88470f15c619 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_channel.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_channel.h
@@ -6,8 +6,259 @@
 #ifndef _NBL_DEF_CHANNEL_H_
 #define _NBL_DEF_CHANNEL_H_
 
+#include <linux/types.h>
+
 struct nbl_channel_mgt;
 struct nbl_adapter;
+enum nbl_chan_msg_type {
+	NBL_CHAN_MSG_ACK,
+	NBL_CHAN_MSG_ADD_MACVLAN,
+	NBL_CHAN_MSG_DEL_MACVLAN,
+	NBL_CHAN_MSG_ADD_MULTI_RULE,
+	NBL_CHAN_MSG_DEL_MULTI_RULE,
+	NBL_CHAN_MSG_SETUP_MULTI_GROUP,
+	NBL_CHAN_MSG_REMOVE_MULTI_GROUP,
+	NBL_CHAN_MSG_REGISTER_NET,
+	NBL_CHAN_MSG_UNREGISTER_NET,
+	NBL_CHAN_MSG_ALLOC_TXRX_QUEUES,
+	NBL_CHAN_MSG_FREE_TXRX_QUEUES,
+	NBL_CHAN_MSG_SETUP_QUEUE,
+	NBL_CHAN_MSG_REMOVE_ALL_QUEUES,
+	NBL_CHAN_MSG_CFG_DSCH,
+	NBL_CHAN_MSG_SETUP_CQS,
+	NBL_CHAN_MSG_REMOVE_CQS,
+	NBL_CHAN_MSG_CFG_QDISC_MQPRIO,
+	NBL_CHAN_MSG_CONFIGURE_MSIX_MAP,
+	NBL_CHAN_MSG_DESTROY_MSIX_MAP,
+	NBL_CHAN_MSG_MAILBOX_ENABLE_IRQ,
+	NBL_CHAN_MSG_GET_GLOBAL_VECTOR,
+	NBL_CHAN_MSG_GET_VSI_ID,
+	NBL_CHAN_MSG_SET_PROMISC_MODE,
+	NBL_CHAN_MSG_GET_FIRMWARE_VERSION,
+	NBL_CHAN_MSG_GET_QUEUE_ERR_STATS,
+	NBL_CHAN_MSG_GET_COALESCE,
+	NBL_CHAN_MSG_SET_COALESCE,
+	NBL_CHAN_MSG_SET_SPOOF_CHECK_ADDR,
+	NBL_CHAN_MSG_SET_VF_SPOOF_CHECK,
+	NBL_CHAN_MSG_GET_RXFH_INDIR_SIZE,
+	NBL_CHAN_MSG_GET_RXFH_INDIR,
+	NBL_CHAN_MSG_GET_RXFH_RSS_KEY,
+	NBL_CHAN_MSG_GET_RXFH_RSS_ALG_SEL,
+	NBL_CHAN_MSG_GET_HW_CAPS,
+	NBL_CHAN_MSG_GET_HW_STATE,
+	NBL_CHAN_MSG_REGISTER_RDMA,
+	NBL_CHAN_MSG_UNREGISTER_RDMA,
+	NBL_CHAN_MSG_GET_REAL_HW_ADDR,
+	NBL_CHAN_MSG_GET_REAL_BDF,
+	NBL_CHAN_MSG_GRC_PROCESS,
+	NBL_CHAN_MSG_SET_SFP_STATE,
+	NBL_CHAN_MSG_SET_ETH_LOOPBACK,
+	NBL_CHAN_MSG_CHECK_ACTIVE_VF,
+	NBL_CHAN_MSG_GET_PRODUCT_FLEX_CAP,
+	NBL_CHAN_MSG_ALLOC_KTLS_TX_INDEX,
+	NBL_CHAN_MSG_FREE_KTLS_TX_INDEX,
+	NBL_CHAN_MSG_CFG_KTLS_TX_KEYMAT,
+	NBL_CHAN_MSG_ALLOC_KTLS_RX_INDEX,
+	NBL_CHAN_MSG_FREE_KTLS_RX_INDEX,
+	NBL_CHAN_MSG_CFG_KTLS_RX_KEYMAT,
+	NBL_CHAN_MSG_CFG_KTLS_RX_RECORD,
+	NBL_CHAN_MSG_ADD_KTLS_RX_FLOW,
+	NBL_CHAN_MSG_DEL_KTLS_RX_FLOW,
+	NBL_CHAN_MSG_ALLOC_IPSEC_TX_INDEX,
+	NBL_CHAN_MSG_FREE_IPSEC_TX_INDEX,
+	NBL_CHAN_MSG_ALLOC_IPSEC_RX_INDEX,
+	NBL_CHAN_MSG_FREE_IPSEC_RX_INDEX,
+	NBL_CHAN_MSG_CFG_IPSEC_TX_SAD,
+	NBL_CHAN_MSG_CFG_IPSEC_RX_SAD,
+	NBL_CHAN_MSG_ADD_IPSEC_TX_FLOW,
+	NBL_CHAN_MSG_DEL_IPSEC_TX_FLOW,
+	NBL_CHAN_MSG_ADD_IPSEC_RX_FLOW,
+	NBL_CHAN_MSG_DEL_IPSEC_RX_FLOW,
+	NBL_CHAN_MSG_NOTIFY_IPSEC_HARD_EXPIRE,
+	NBL_CHAN_MSG_GET_MBX_IRQ_NUM,
+	NBL_CHAN_MSG_CLEAR_FLOW,
+	NBL_CHAN_MSG_CLEAR_QUEUE,
+	NBL_CHAN_MSG_GET_ETH_ID,
+	NBL_CHAN_MSG_SET_OFFLOAD_STATUS,
+	NBL_CHAN_MSG_INIT_OFLD,
+	NBL_CHAN_MSG_INIT_CMDQ,
+	NBL_CHAN_MSG_DESTROY_CMDQ,
+	NBL_CHAN_MSG_RESET_CMDQ,
+	NBL_CHAN_MSG_INIT_FLOW,
+	NBL_CHAN_MSG_DEINIT_FLOW,
+	NBL_CHAN_MSG_OFFLOAD_FLOW_RULE,
+	NBL_CHAN_MSG_GET_ACL_SWITCH,
+	NBL_CHAN_MSG_GET_VSI_GLOBAL_QUEUE_ID,
+	NBL_CHAN_MSG_INIT_REP,
+	NBL_CHAN_MSG_GET_LINE_RATE_INFO,
+	NBL_CHAN_MSG_REGISTER_NET_REP,
+	NBL_CHAN_MSG_UNREGISTER_NET_REP,
+	NBL_CHAN_MSG_REGISTER_ETH_REP,
+	NBL_CHAN_MSG_UNREGISTER_ETH_REP,
+	NBL_CHAN_MSG_REGISTER_UPCALL_PORT,
+	NBL_CHAN_MSG_UNREGISTER_UPCALL_PORT,
+	NBL_CHAN_MSG_GET_PORT_STATE,
+	NBL_CHAN_MSG_SET_PORT_ADVERTISING,
+	NBL_CHAN_MSG_GET_MODULE_INFO,
+	NBL_CHAN_MSG_GET_MODULE_EEPROM,
+	NBL_CHAN_MSG_GET_LINK_STATE,
+	NBL_CHAN_MSG_NOTIFY_LINK_STATE,
+	NBL_CHAN_MSG_GET_QUEUE_CXT,
+	NBL_CHAN_MSG_CFG_LOG,
+	NBL_CHAN_MSG_INIT_VDPAQ,
+	NBL_CHAN_MSG_DESTROY_VDPAQ,
+	NBL_CHAN_MSG_GET_UPCALL_PORT,
+	NBL_CHAN_MSG_NOTIFY_ETH_REP_LINK_STATE,
+	NBL_CHAN_MSG_SET_ETH_MAC_ADDR,
+	NBL_CHAN_MSG_GET_FUNCTION_ID,
+	NBL_CHAN_MSG_GET_CHIP_TEMPERATURE,
+	NBL_CHAN_MSG_DISABLE_HW_FLOW,
+	NBL_CHAN_MSG_ENABLE_HW_FLOW,
+	NBL_CHAN_MSG_SET_UPCALL_RULE,
+	NBL_CHAN_MSG_UNSET_UPCALL_RULE,
+	NBL_CHAN_MSG_GET_REG_DUMP,
+	NBL_CHAN_MSG_GET_REG_DUMP_LEN,
+	NBL_CHAN_MSG_CFG_LAG_HASH_ALGORITHM,
+	NBL_CHAN_MSG_CFG_LAG_MEMBER_FWD,
+	NBL_CHAN_MSG_CFG_LAG_MEMBER_LIST,
+	NBL_CHAN_MSG_CFG_LAG_MEMBER_UP_ATTR,
+	NBL_CHAN_MSG_ADD_LAG_FLOW,
+	NBL_CHAN_MSG_DEL_LAG_FLOW,
+	NBL_CHAN_MSG_SWITCHDEV_INIT_CMDQ,
+	NBL_CHAN_MSG_SWITCHDEV_DEINIT_CMDQ,
+	NBL_CHAN_MSG_SET_TC_FLOW_INFO,
+	NBL_CHAN_MSG_UNSET_TC_FLOW_INFO,
+	NBL_CHAN_MSG_INIT_ACL,
+	NBL_CHAN_MSG_UNINIT_ACL,
+	NBL_CHAN_MSG_CFG_LAG_MCC,
+	NBL_CHAN_MSG_REGISTER_VSI2Q,
+	NBL_CHAN_MSG_SETUP_Q2VSI,
+	NBL_CHAN_MSG_REMOVE_Q2VSI,
+	NBL_CHAN_MSG_SETUP_RSS,
+	NBL_CHAN_MSG_REMOVE_RSS,
+	NBL_CHAN_MSG_GET_REP_QUEUE_INFO,
+	NBL_CHAN_MSG_CTRL_PORT_LED,
+	NBL_CHAN_MSG_NWAY_RESET,
+	NBL_CHAN_MSG_SET_INTL_SUPPRESS_LEVEL,
+	NBL_CHAN_MSG_GET_ETH_STATS,
+	NBL_CHAN_MSG_GET_MODULE_TEMPERATURE,
+	NBL_CHAN_MSG_GET_BOARD_INFO,
+	NBL_CHAN_MSG_GET_P4_USED,
+	NBL_CHAN_MSG_GET_VF_BASE_VSI_ID,
+	NBL_CHAN_MSG_ADD_LLDP_FLOW,
+	NBL_CHAN_MSG_DEL_LLDP_FLOW,
+	NBL_CHAN_MSG_CFG_ETH_BOND_INFO,
+	NBL_CHAN_MSG_CFG_DUPPKT_MCC,
+	NBL_CHAN_MSG_ADD_ND_UPCALL_FLOW,
+	NBL_CHAN_MSG_DEL_ND_UPCALL_FLOW,
+	NBL_CHAN_MSG_GET_BOARD_ID,
+	NBL_CHAN_MSG_SET_SHAPING_DPORT_VLD,
+	NBL_CHAN_MSG_SET_DPORT_FC_TH_VLD,
+	NBL_CHAN_MSG_REGISTER_RDMA_BOND,
+	NBL_CHAN_MSG_UNREGISTER_RDMA_BOND,
+	NBL_CHAN_MSG_RESTORE_NETDEV_QUEUE,
+	NBL_CHAN_MSG_RESTART_NETDEV_QUEUE,
+	NBL_CHAN_MSG_RESTORE_HW_QUEUE,
+	NBL_CHAN_MSG_KEEP_ALIVE,
+	NBL_CHAN_MSG_GET_BASE_MAC_ADDR,
+	NBL_CHAN_MSG_CFG_BOND_SHAPING,
+	NBL_CHAN_MSG_CFG_BGID_BACK_PRESSURE,
+	NBL_CHAN_MSG_ALLOC_KT_BLOCK,
+	NBL_CHAN_MSG_FREE_KT_BLOCK,
+	NBL_CHAN_MSG_GET_USER_QUEUE_INFO,
+	NBL_CHAN_MSG_GET_ETH_BOND_INFO,
+	NBL_CHAN_MSG_CLEAR_ACCEL_FLOW,
+	NBL_CHAN_MSG_SET_BRIDGE_MODE,
+	NBL_CHAN_MSG_GET_VF_FUNCTION_ID,
+	NBL_CHAN_MSG_NOTIFY_LINK_FORCED,
+	NBL_CHAN_MSG_SET_PMD_DEBUG,
+	NBL_CHAN_MSG_REGISTER_FUNC_MAC,
+	NBL_CHAN_MSG_SET_TX_RATE,
+	NBL_CHAN_MSG_REGISTER_FUNC_LINK_FORCED,
+	NBL_CHAN_MSG_GET_LINK_FORCED,
+	NBL_CHAN_MSG_REGISTER_FUNC_VLAN,
+	NBL_CHAN_MSG_GET_FD_FLOW,
+	NBL_CHAN_MSG_GET_FD_FLOW_CNT,
+	NBL_CHAN_MSG_GET_FD_FLOW_ALL,
+	NBL_CHAN_MSG_GET_FD_FLOW_MAX,
+	NBL_CHAN_MSG_REPLACE_FD_FLOW,
+	NBL_CHAN_MSG_REMOVE_FD_FLOW,
+	NBL_CHAN_MSG_CFG_FD_FLOW_STATE,
+	NBL_CHAN_MSG_REGISTER_FUNC_RATE,
+	NBL_CHAN_MSG_NOTIFY_VLAN,
+	NBL_CHAN_MSG_GET_XDP_QUEUE_INFO,
+	NBL_CHAN_MSG_STOP_ABNORMAL_SW_QUEUE,
+	NBL_CHAN_MSG_STOP_ABNORMAL_HW_QUEUE,
+	NBL_CHAN_MSG_NOTIFY_RESET_EVENT,
+	NBL_CHAN_MSG_ACK_RESET_EVENT,
+	NBL_CHAN_MSG_GET_VF_VSI_ID,
+	NBL_CHAN_MSG_CONFIGURE_QOS,
+	NBL_CHAN_MSG_GET_PFC_BUFFER_SIZE,
+	NBL_CHAN_MSG_SET_PFC_BUFFER_SIZE,
+	NBL_CHAN_MSG_GET_VF_STATS,
+	NBL_CHAN_MSG_REGISTER_FUNC_TRUST,
+	NBL_CHAN_MSG_NOTIFY_TRUST,
+	NBL_CHAN_MSG_CHECK_VF_IS_ACTIVE,
+	NBL_CHAN_MSG_GET_ETH_ABNORMAL_STATS,
+	NBL_CHAN_MSG_GET_ETH_CTRL_STATS,
+	NBL_CHAN_MSG_GET_PAUSE_STATS,
+	NBL_CHAN_MSG_GET_ETH_MAC_STATS,
+	NBL_CHAN_MSG_GET_FEC_STATS,
+	NBL_CHAN_MSG_CFG_MULTI_MCAST_RULE,
+	NBL_CHAN_MSG_GET_LINK_DOWN_COUNT,
+	NBL_CHAN_MSG_GET_LINK_STATUS_OPCODE,
+	NBL_CHAN_MSG_GET_RMON_STATS,
+	NBL_CHAN_MSG_REGISTER_PF_NAME,
+	NBL_CHAN_MSG_GET_PF_NAME,
+	NBL_CHAN_MSG_CONFIGURE_RDMA_BW,
+	NBL_CHAN_MSG_SET_RATE_LIMIT,
+	NBL_CHAN_MSG_SET_TC_WGT,
+	NBL_CHAN_MSG_REMOVE_QUEUE,
+	NBL_CHAN_MSG_GET_MIRROR_TABLE_ID,
+	NBL_CHAN_MSG_CONFIGURE_MIRROR,
+	NBL_CHAN_MSG_CONFIGURE_MIRROR_TABLE,
+	NBL_CHAN_MSG_CLEAR_MIRROR_CFG,
+	NBL_CHAN_MSG_MIRROR_OUTPUTPORT_NOTIFY,
+	NBL_CHAN_MSG_CHECK_FLOWTABLE_SPEC,
+	NBL_CHAN_MSG_CHECK_VF_IS_VDPA,
+	NBL_CHAN_MSG_GET_VDPA_VF_STATS,
+	NBL_CHAN_MSG_SET_RX_RATE,
+	NBL_CHAN_MSG_GET_UVN_PKT_DROP_STATS,
+	NBL_CHAN_MSG_GET_USTORE_PKT_DROP_STATS,
+	NBL_CHAN_MSG_GET_USTORE_TOTAL_PKT_DROP_STATS,
+	NBL_CHAN_MSG_SET_WOL,
+	NBL_CHAN_MSG_INIT_VF_MSIX_MAP,
+	NBL_CHAN_MSG_GET_ST_NAME,
+	/* mailbox msg end */
+	NBL_CHAN_MSG_MAILBOX_MAX,
+};
+
+struct nbl_chan_param_cfg_msix_map {
+	__le16 num_net_msix;
+	__le16 num_others_msix;
+	__le16 msix_mask_en;
+	__le16 rsvd;
+};
+
+struct nbl_chan_param_set_mailbox_irq {
+	__le16 vector_id;
+	u8 enable_msix;
+	u8 rsvd;
+};
+
+struct nbl_chan_param_get_vsi_id {
+	__le16 vsi_id;
+	__le16 type;
+};
+
+struct nbl_chan_param_get_eth_id {
+	__le16 vsi_id;
+	u8 eth_num;
+	u8 eth_id;
+	u8 logic_eth_id;
+	u8 rsvd[3];
+};
+
 enum nbl_channel_type {
 	NBL_CHAN_TYPE_MAILBOX,
 	NBL_CHAN_TYPE_MAX
-- 
2.47.3


^ permalink raw reply related

* [PATCH v15 net-next 06/11] net/nebula-matrix: add common resource implementation
From: illusion.wang @ 2026-05-20  3:29 UTC (permalink / raw)
  To: dimon.zhao, illusion.wang, alvin.wang, sam.chen, netdev
  Cc: andrew+netdev, corbet, kuba, horms, linux-doc, pabeni,
	vadim.fedorenko, lukas.bulwahn, edumazet, enelsonmoore, skhan,
	hkallweit1, open list
In-Reply-To: <20260520032950.4874-1-illusion.wang@nebula-matrix.com>

The Resource layer processes the entries/data of various modules within
the processing chip to accomplish specific entry management operations,
this describes the module business capabilities of the chip and the data
it manages.
The resource layer comprises the following sub-modules: common,
interrupt, and vsi(txrx,queue not contained this time)

This patch provides the common part, including the conversion
relationships among vsi_id, func_id, eth_id, and pf_id. These
relationships may be utilized in the upper layer or the resource layer.

Key Assumptions:
- nbl_res_start() initializes VSI/Eth/PF data structures **only for
control devices** (`common->has_ctrl == true`).
- APIs like nbl_res_func_id_to_vsi_id() **are guaranteed to be called
 only on control devices** by the framework's dispatch layer.

Signed-off-by: illusion.wang <illusion.wang@nebula-matrix.com>
---
 .../net/ethernet/nebula-matrix/nbl/Makefile   |   1 +
 .../nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c  |  56 ++++++
 .../nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h  |   2 +
 .../nbl_hw_leonis/nbl_resource_leonis.c       | 181 ++++++++++++++++++
 .../nebula-matrix/nbl/nbl_hw/nbl_resource.c   | 134 +++++++++++++
 .../nebula-matrix/nbl/nbl_hw/nbl_resource.h   |  50 +++++
 .../nbl/nbl_include/nbl_def_common.h          |  15 ++
 .../nbl/nbl_include/nbl_def_resource.h        |  15 ++
 .../nbl/nbl_include/nbl_include.h             |   8 +
 9 files changed, 462 insertions(+)
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_resource.c

diff --git a/drivers/net/ethernet/nebula-matrix/nbl/Makefile b/drivers/net/ethernet/nebula-matrix/nbl/Makefile
index c9bc060732e7..b03c20f9988e 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/Makefile
+++ b/drivers/net/ethernet/nebula-matrix/nbl/Makefile
@@ -8,6 +8,7 @@ nbl-objs +=       nbl_common/nbl_common.o \
 				nbl_hw/nbl_hw_leonis/nbl_hw_leonis.o \
 				nbl_hw/nbl_hw_leonis/nbl_resource_leonis.o \
 				nbl_hw/nbl_hw_leonis/nbl_hw_leonis_regs.o \
+				nbl_hw/nbl_resource.o \
 				nbl_core/nbl_dispatch.o \
 				nbl_core/nbl_dev.o \
 				nbl_main.o
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c
index 822066d6cecd..99f425568040 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c
@@ -7,8 +7,21 @@
 #include <linux/bits.h>
 #include <linux/io.h>
 #include <linux/spinlock.h>
+#include <linux/bitfield.h>
 #include "nbl_hw_leonis.h"
 
+static void nbl_hw_read_mbx_regs(struct nbl_hw_mgt *hw_mgt, u64 reg,
+				 u32 *data, u32 len)
+{
+	u32 i;
+
+	if (len % 4)
+		return;
+
+	for (i = 0; i < len / 4; i++)
+		data[i] = nbl_mbx_rd32(hw_mgt, reg + i * sizeof(u32));
+}
+
 static void nbl_hw_write_mbx_regs(struct nbl_hw_mgt *hw_mgt, u64 reg,
 				  const u32 *data, u32 len)
 {
@@ -136,6 +149,14 @@ static u32 nbl_hw_get_host_pf_mask(struct nbl_hw_mgt *hw_mgt)
 	return data;
 }
 
+static u8 nbl_hw_get_real_bus(struct nbl_hw_mgt *hw_mgt)
+{
+	u32 data;
+
+	data = nbl_hw_rd32(hw_mgt, NBL_PCIE_HOST_TL_CFG_BUSDEV);
+	return FIELD_GET(NBL_PCIE_BUS_MASK, data);
+}
+
 static void nbl_hw_cfg_mailbox_qinfo(struct nbl_hw_mgt *hw_mgt, u16 func_id,
 				     u8 bus, u8 devid, u8 function)
 {
@@ -150,6 +171,36 @@ static void nbl_hw_cfg_mailbox_qinfo(struct nbl_hw_mgt *hw_mgt, u16 func_id,
 		       &mb_qinfo_map.data, sizeof(mb_qinfo_map));
 }
 
+static void nbl_hw_get_board_info(struct nbl_hw_mgt *hw_mgt,
+				  struct nbl_board_port_info *board_info)
+{
+	union nbl_fw_board_cfg_dw3 dw3 = { .info = { 0 } };
+
+	nbl_hw_read_mbx_regs(hw_mgt, NBL_FW_BOARD_DW3_OFFSET, &dw3.data,
+			     sizeof(dw3));
+	board_info->eth_num = dw3.info.port_num;
+	board_info->eth_speed = dw3.info.port_speed;
+	board_info->p4_version = dw3.info.p4_version;
+}
+
+static u32 nbl_hw_get_fw_eth_num(struct nbl_hw_mgt *hw_mgt)
+{
+	union nbl_fw_board_cfg_dw3 dw3 = { .info = { 0 } };
+
+	nbl_hw_read_mbx_regs(hw_mgt, NBL_FW_BOARD_DW3_OFFSET, &dw3.data,
+			     sizeof(dw3));
+	return dw3.info.port_num;
+}
+
+static u32 nbl_hw_get_fw_eth_map(struct nbl_hw_mgt *hw_mgt)
+{
+	union nbl_fw_board_cfg_dw6 dw6 = { .info = { 0 } };
+
+	nbl_hw_read_mbx_regs(hw_mgt, NBL_FW_BOARD_DW6_OFFSET, &dw6.data,
+			     sizeof(dw6));
+	return dw6.info.eth_bitmap;
+}
+
 static struct nbl_hw_ops hw_ops = {
 	.update_mailbox_queue_tail_ptr = nbl_hw_update_mailbox_queue_tail_ptr,
 	.config_mailbox_rxq = nbl_hw_config_mailbox_rxq,
@@ -157,8 +208,13 @@ static struct nbl_hw_ops hw_ops = {
 	.stop_mailbox_rxq = nbl_hw_stop_mailbox_rxq,
 	.stop_mailbox_txq = nbl_hw_stop_mailbox_txq,
 	.get_host_pf_mask = nbl_hw_get_host_pf_mask,
+	.get_real_bus = nbl_hw_get_real_bus,
+
 	.cfg_mailbox_qinfo = nbl_hw_cfg_mailbox_qinfo,
 
+	.get_fw_eth_num = nbl_hw_get_fw_eth_num,
+	.get_fw_eth_map = nbl_hw_get_fw_eth_map,
+	.get_board_info = nbl_hw_get_board_info,
 };
 
 /* Structure starts here, adding an op should not modify anything below */
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h
index 4f718d5873f4..966c30d97f5f 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h
@@ -527,6 +527,8 @@ union nbl_fw_board_cfg_dw6 {
 	u32 data;
 };
 
+#define NBL_PCIE_BUS_MASK	GENMASK(12, 5)
+#define NBL_PCIE_BUS_SHIFT	5
 #define NBL_LEONIS_QUIRKS_OFFSET	0x00000140
 #define NBL_LEONIS_ILLEGAL_REG_VALUE	0xDEADBEEF
 
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.c
index 4b4f8e2e7fe7..36366cd47753 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.c
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.c
@@ -4,9 +4,12 @@
  */
 #include <linux/device.h>
 #include <linux/pci.h>
+#include <linux/bits.h>
 #include "nbl_resource_leonis.h"
 
 static struct nbl_resource_ops res_ops = {
+	.get_vsi_id = nbl_res_func_id_to_vsi_id,
+	.get_eth_id = nbl_res_get_eth_id,
 };
 
 static struct nbl_resource_mgt *
@@ -45,8 +48,186 @@ nbl_res_setup_ops(struct device *dev, struct nbl_resource_mgt *res_mgt)
 	return res_ops_tbl;
 }
 
+static int nbl_res_ctrl_dev_setup_eth_info(struct nbl_resource_mgt *res_mgt)
+{
+	struct nbl_hw_ops *hw_ops = res_mgt->hw_ops_tbl->ops;
+	struct device *dev = res_mgt->common->dev;
+	struct nbl_eth_info *eth_info;
+	u32 eth_bitmap, eth_id;
+	u32 eth_num = 0;
+	u32 fw_port_num;
+	int i;
+
+	eth_info = devm_kzalloc(dev, sizeof(*eth_info), GFP_KERNEL);
+	if (!eth_info)
+		return -ENOMEM;
+
+	res_mgt->resource_info->eth_info = eth_info;
+
+	fw_port_num = hw_ops->get_fw_eth_num(res_mgt->hw_ops_tbl->priv);
+	eth_bitmap = hw_ops->get_fw_eth_map(res_mgt->hw_ops_tbl->priv);
+	if (fw_port_num !=  hweight32(eth_bitmap)) {
+		dev_err(dev, "FW inconsistency: port_num=%u, bitmap=0x%x\n",
+			fw_port_num, eth_bitmap);
+		return -EINVAL;
+	}
+
+	/* eth_num is guaranteed to be 1/2/4 here, so NBL_VSI_ID_GAP()
+	 * will always hit one of the explicit branches. Values 3 or any
+	 * other unsupported count are rejected above.
+	 */
+	if (fw_port_num > NBL_MAX_ETHERNET || fw_port_num == 3) {
+		dev_warn(dev, "FW reports %u Ethernet ports, not supported\n",
+			 fw_port_num);
+		return -EINVAL;
+	}
+	eth_info->eth_num = fw_port_num;
+	if (res_mgt->resource_info->max_pf != eth_info->eth_num) {
+		dev_err(dev, "Invalid PF-to-port topology: max_pf=%u, eth_num=%u\n",
+			res_mgt->resource_info->max_pf, eth_info->eth_num);
+		return -EINVAL;
+	}
+
+	/* for 2 eth port board, the eth_id is 0, 2 */
+	for (i = 0; i < NBL_MAX_ETHERNET; i++) {
+		if ((1 << i) & eth_bitmap) {
+			set_bit(i, eth_info->eth_bitmap);
+			eth_info->eth_id[eth_num] = i;
+			eth_info->logic_eth_id[i] = eth_num;
+			eth_num++;
+		}
+	}
+
+	for (i = 0; i < res_mgt->resource_info->max_pf; i++) {
+		eth_id = eth_info->eth_id[i];
+		eth_info->pf_bitmap[eth_id] |= BIT(i);
+	}
+
+	return 0;
+}
+
+static int nbl_res_ctrl_dev_sriov_info_init(struct nbl_resource_mgt *res_mgt)
+{
+	struct nbl_hw_ops *hw_ops = res_mgt->hw_ops_tbl->ops;
+	struct nbl_hw_mgt *p = res_mgt->hw_ops_tbl->priv;
+	struct nbl_common_info *common = res_mgt->common;
+	struct nbl_sriov_info *sriov_info;
+	struct device *dev = common->dev;
+	u16 function;
+	u16 func_id;
+
+	sriov_info = devm_kcalloc(dev, res_mgt->resource_info->max_pf,
+				  sizeof(*sriov_info), GFP_KERNEL);
+	if (!sriov_info)
+		return -ENOMEM;
+
+	res_mgt->resource_info->sriov_info = sriov_info;
+	common->hw_bus = hw_ops->get_real_bus(p);
+	if (common->function + res_mgt->resource_info->max_pf > NBL_MAX_PF) {
+		dev_err(dev, "PF count exceeds available function space\n");
+		return -EINVAL;
+	}
+	for (func_id = 0; func_id < res_mgt->resource_info->max_pf; func_id++) {
+		sriov_info = res_mgt->resource_info->sriov_info + func_id;
+		function = common->function + func_id;
+		sriov_info->bdf = PCI_DEVID(common->hw_bus,
+					    PCI_DEVFN(common->devid, function));
+	}
+
+	return 0;
+}
+
+static int nbl_res_ctrl_dev_vsi_info_init(struct nbl_resource_mgt *res_mgt)
+{
+	struct nbl_eth_info *eth_info = res_mgt->resource_info->eth_info;
+	struct nbl_common_info *common = res_mgt->common;
+	struct device *dev = common->dev;
+	struct nbl_vsi_info *vsi_info;
+	int i;
+
+	vsi_info = devm_kzalloc(dev, sizeof(*vsi_info), GFP_KERNEL);
+	if (!vsi_info)
+		return -ENOMEM;
+
+	res_mgt->resource_info->vsi_info = vsi_info;
+	/*
+	 * case 1 one port(1pf)
+	 * pf0 (NBL_VSI_SERV_PF_DATA_TYPE) vsi is 0
+	 * case 2 two port(2pf)
+	 * pf0,pf1(NBL_VSI_SERV_PF_DATA_TYPE) vsi is 0,512
+	 * case 3 four port(4pf)
+	 * pf0,pf1,pf2,pf3(NBL_VSI_SERV_PF_DATA_TYPE) vsi is 0,256,512,768
+
+	 */
+
+	vsi_info->num = eth_info->eth_num;
+	for (i = 0; i < vsi_info->num; i++) {
+		vsi_info->serv_info[i][NBL_VSI_SERV_PF_DATA_TYPE].base_id =
+			i * NBL_VSI_ID_GAP(vsi_info->num);
+		vsi_info->serv_info[i][NBL_VSI_SERV_PF_DATA_TYPE].num = 1;
+	}
+
+	return 0;
+}
+
+static int nbl_res_init_pf_num(struct nbl_resource_mgt *res_mgt)
+{
+	struct nbl_hw_ops *hw_ops = res_mgt->hw_ops_tbl->ops;
+	u32 pf_num = 0;
+	u32 pf_mask;
+	int i;
+
+	pf_mask = hw_ops->get_host_pf_mask(res_mgt->hw_ops_tbl->priv);
+	/*
+	 * Hardware guarantees pf_mask has contiguous cleared bits
+	 * starting from bit 0 (e.g., 0b11111100, not 0b01010101).
+	 * This allows us to stop at the first set bit.
+	 */
+	for (i = 0; i < NBL_MAX_PF; i++) {
+		if (!(pf_mask & (1 << i)))
+			pf_num++;
+		else
+			break;
+	}
+	if (pf_num == 0)
+		return -EINVAL;
+	res_mgt->resource_info->max_pf = pf_num;
+
+	return 0;
+}
+
+static void nbl_res_init_board_info(struct nbl_resource_mgt *res_mgt)
+{
+	struct nbl_hw_ops *hw_ops = res_mgt->hw_ops_tbl->ops;
+
+	hw_ops->get_board_info(res_mgt->hw_ops_tbl->priv,
+			       &res_mgt->resource_info->board_info);
+}
+
 static int nbl_res_start(struct nbl_resource_mgt *res_mgt)
 {
+	struct nbl_common_info *common = res_mgt->common;
+	int ret = 0;
+
+	if (common->has_ctrl) {
+		nbl_res_init_board_info(res_mgt);
+
+		ret = nbl_res_init_pf_num(res_mgt);
+		if (ret)
+			return ret;
+
+		ret = nbl_res_ctrl_dev_sriov_info_init(res_mgt);
+		if (ret)
+			return ret;
+
+		ret = nbl_res_ctrl_dev_setup_eth_info(res_mgt);
+		if (ret)
+			return ret;
+
+		ret = nbl_res_ctrl_dev_vsi_info_init(res_mgt);
+		if (ret)
+			return ret;
+	}
 	return 0;
 }
 
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_resource.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_resource.c
new file mode 100644
index 000000000000..a8234038f1d7
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_resource.c
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+
+#include <linux/pci.h>
+#include "nbl_resource.h"
+
+u16 nbl_res_func_id_to_vsi_id(struct nbl_resource_mgt *res_mgt, u16 func_id,
+			      u16 type)
+{
+	struct nbl_vsi_info *vsi_info = res_mgt->resource_info->vsi_info;
+	enum nbl_vsi_serv_type dst_type = NBL_VSI_SERV_PF_DATA_TYPE;
+	struct nbl_common_info *common = res_mgt->common;
+	struct device *dev = res_mgt->common->dev;
+	u16 vsi_id = U16_MAX;
+	int pfid = func_id;
+	u32 diff;
+
+	if (!common->has_ctrl) {
+		dev_dbg(dev, "No control plane available\n");
+		return vsi_id;
+	}
+	diff = nbl_common_pf_id_subtraction_mgtpf_id(common, pfid);
+	if (diff == U32_MAX) {
+		dev_dbg(dev, "Invalid PF ID subtraction result\n");
+		return vsi_id;
+	}
+	if (diff >= vsi_info->num) {
+		dev_err(dev, "PF %d (diff=%u) exceeds vsi_info->num (%u)\n",
+			pfid, diff, vsi_info->num);
+		return U16_MAX;
+	}
+
+	nbl_res_pf_dev_vsi_type_to_hw_vsi_type(type, &dst_type);
+	vsi_id = vsi_info->serv_info[diff][dst_type].base_id;
+
+	return vsi_id;
+}
+
+int nbl_res_vsi_id_to_pf_id(struct nbl_resource_mgt *res_mgt, u16 vsi_id)
+{
+	struct nbl_vsi_info *vsi_info = res_mgt->resource_info->vsi_info;
+	struct nbl_common_info *common = res_mgt->common;
+	struct device *dev = res_mgt->common->dev;
+	int j = NBL_VSI_SERV_PF_DATA_TYPE;
+	int pf_id, i;
+
+	if (!common->has_ctrl) {
+		dev_dbg(dev, "No control plane available\n");
+		return -EINVAL;
+	}
+	for (i = 0; i < vsi_info->num; i++) {
+		if (vsi_id >= vsi_info->serv_info[i][j].base_id &&
+		    (vsi_id < vsi_info->serv_info[i][j].base_id +
+					vsi_info->serv_info[i][j].num)) {
+			pf_id = i + common->mgt_pf;
+			if (pf_id >= NBL_MAX_PF) {
+				dev_err(dev, "PF ID overflow\n");
+				return -ERANGE;
+			}
+			return pf_id;
+		}
+	}
+
+	dev_dbg(dev, "VSI ID %u not found\n", vsi_id);
+	return -ENOENT;
+}
+
+int nbl_res_func_id_to_bdf(struct nbl_resource_mgt *res_mgt, u16 func_id,
+			   u8 *bus, u8 *dev, u8 *function)
+{
+	struct nbl_common_info *common = res_mgt->common;
+	struct nbl_sriov_info *sriov_info;
+	int pfid = func_id;
+	u8 pf_bus, devfn;
+	u32 diff;
+
+	if (!common->has_ctrl || !bus || !dev || !function)
+		return -EINVAL;
+	diff = nbl_common_pf_id_subtraction_mgtpf_id(common, pfid);
+	if (diff == U32_MAX)
+		return -EINVAL;
+	if (diff >= res_mgt->resource_info->max_pf) {
+		dev_err(common->dev, "PF ID %u exceeds maximum supported PF count %u\n",
+			pfid, res_mgt->resource_info->max_pf);
+		return -ERANGE;
+	}
+	sriov_info = res_mgt->resource_info->sriov_info + diff;
+	pf_bus = PCI_BUS_NUM(sriov_info->bdf);
+	devfn = sriov_info->bdf & 0xff;
+	*bus = pf_bus;
+	*dev = PCI_SLOT(devfn);
+	*function = PCI_FUNC(devfn);
+
+	return 0;
+}
+
+int nbl_res_get_eth_id(struct nbl_resource_mgt *res_mgt, u16 vsi_id,
+		       u8 *eth_num, u8 *eth_id, u8 *logic_eth_id)
+{
+	struct nbl_eth_info *eth_info = res_mgt->resource_info->eth_info;
+	struct nbl_common_info *common = res_mgt->common;
+	struct device *dev = res_mgt->common->dev;
+	int rel_pf_id;
+	int abs_pf_id;
+
+	if (!common->has_ctrl || !eth_num || !eth_id || !logic_eth_id)
+		return -EINVAL;
+	abs_pf_id = nbl_res_vsi_id_to_pf_id(res_mgt, vsi_id);
+	if (abs_pf_id < 0) {
+		dev_err(dev, "Failed to get PF ID from VSI ID %u\n", vsi_id);
+		return -EINVAL;
+	}
+	rel_pf_id = abs_pf_id - common->mgt_pf;
+
+	if (rel_pf_id < 0 || rel_pf_id >= eth_info->eth_num) {
+		dev_err(dev, "rel_pf_id %d out of range [0, %u)\n",
+			rel_pf_id, eth_info->eth_num);
+		return -ERANGE;
+	}
+
+	*eth_num = eth_info->eth_num;
+	*eth_id = eth_info->eth_id[rel_pf_id];
+	*logic_eth_id = rel_pf_id;
+	return 0;
+}
+
+void nbl_res_pf_dev_vsi_type_to_hw_vsi_type(u16 src_type,
+					    enum nbl_vsi_serv_type *dst_type)
+{
+	if (src_type == NBL_VSI_DATA)
+		*dst_type = NBL_VSI_SERV_PF_DATA_TYPE;
+}
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_resource.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_resource.h
index e08b6237da32..15dc7f78afc0 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_resource.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_resource.h
@@ -16,7 +16,48 @@
 #include "../nbl_include/nbl_def_common.h"
 #include "../nbl_core.h"
 
+struct nbl_resource_mgt;
+
+/* --------- INFO ---------- */
+struct nbl_sriov_info {
+	unsigned int bdf;
+};
+
+struct nbl_eth_info {
+	DECLARE_BITMAP(eth_bitmap, NBL_MAX_ETHERNET);
+	u8 pf_bitmap[NBL_MAX_ETHERNET];
+	u8 eth_num;
+	u8 resv[3];
+	u8 eth_id[NBL_MAX_PF];
+	u8 logic_eth_id[NBL_MAX_PF];
+};
+
+enum nbl_vsi_serv_type {
+	NBL_VSI_SERV_PF_DATA_TYPE,
+	NBL_VSI_SERV_MAX_TYPE,
+};
+
+struct nbl_vsi_serv_info {
+	u16 base_id;
+	u16 num;
+};
+
+struct nbl_vsi_info {
+	u16 num;
+	struct nbl_vsi_serv_info serv_info[NBL_MAX_ETHERNET]
+					  [NBL_VSI_SERV_MAX_TYPE];
+};
+
 struct nbl_resource_info {
+	/* ctrl-dev owned pfs */
+	DECLARE_BITMAP(func_bitmap, NBL_MAX_FUNC);
+	struct nbl_sriov_info *sriov_info;
+	struct nbl_eth_info *eth_info;
+	struct nbl_vsi_info *vsi_info;
+	u32 base_qid;
+	u32 max_vf_num;
+	u8 max_pf;
+	struct nbl_board_port_info board_info;
 };
 
 struct nbl_resource_mgt {
@@ -27,4 +68,13 @@ struct nbl_resource_mgt {
 	struct nbl_interrupt_mgt *intr_mgt;
 };
 
+int nbl_res_vsi_id_to_pf_id(struct nbl_resource_mgt *res_mgt, u16 vsi_id);
+u16 nbl_res_func_id_to_vsi_id(struct nbl_resource_mgt *res_mgt, u16 func_id,
+			      u16 type);
+int nbl_res_func_id_to_bdf(struct nbl_resource_mgt *res_mgt, u16 func_id,
+			   u8 *bus, u8 *dev, u8 *function);
+int nbl_res_get_eth_id(struct nbl_resource_mgt *res_mgt, u16 vsi_id,
+		       u8 *eth_num, u8 *eth_id, u8 *logic_eth_id);
+void nbl_res_pf_dev_vsi_type_to_hw_vsi_type(u16 src_type,
+					    enum nbl_vsi_serv_type *dst_type);
 #endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_common.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_common.h
index 176df51f9e6e..09d20d3235fe 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_common.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_common.h
@@ -12,6 +12,21 @@
 #include "nbl_include.h"
 
 struct nbl_hash_tbl_mgt;
+#define NBL_TWO_ETHERNET_PORT			2
+#define NBL_FOUR_ETHERNET_PORT			4
+#define NBL_DEFAULT_VSI_ID_GAP			1024
+#define NBL_TWO_ETHERNET_VSI_ID_GAP		512
+#define NBL_FOUR_ETHERNET_VSI_ID_GAP		256
+
+#define NBL_VSI_ID_GAP(m)					\
+	({							\
+		typeof(m) _m = (m);				\
+		_m == NBL_FOUR_ETHERNET_PORT ?			\
+			NBL_FOUR_ETHERNET_VSI_ID_GAP :		\
+			(_m == NBL_TWO_ETHERNET_PORT ?		\
+				 NBL_TWO_ETHERNET_VSI_ID_GAP :	\
+				 NBL_DEFAULT_VSI_ID_GAP);	\
+	})
 
 struct nbl_common_info {
 	struct pci_dev *pdev;
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_resource.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_resource.h
index d55934af5a9a..54717dbccde8 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_resource.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_resource.h
@@ -6,10 +6,25 @@
 #ifndef _NBL_DEF_RESOURCE_H_
 #define _NBL_DEF_RESOURCE_H_
 
+#include <linux/types.h>
+
 struct nbl_resource_mgt;
 struct nbl_adapter;
 
 struct nbl_resource_ops {
+	int (*init_chip_module)(struct nbl_resource_mgt *res_mgt);
+	void (*deinit_chip_module)(struct nbl_resource_mgt *res_mgt);
+
+	int (*configure_msix_map)(struct nbl_resource_mgt *res_mgt, u16 func_id,
+				  u16 num_net_msix, u16 num_others_msix,
+				  bool net_msix_mask_en);
+	int (*destroy_msix_map)(struct nbl_resource_mgt *res_mgt, u16 func_id);
+	int (*set_mailbox_irq)(struct nbl_resource_mgt *res_mgt, u16 func_id,
+			       u16 vector_id, bool enable_msix);
+	u16 (*get_vsi_id)(struct nbl_resource_mgt *res_mgt, u16 func_id,
+			  u16 type);
+	int (*get_eth_id)(struct nbl_resource_mgt *res_mgt, u16 vsi_id,
+			  u8 *eth_num, u8 *eth_id, u8 *logic_eth_id);
 };
 
 struct nbl_resource_ops_tbl {
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h
index a01c32f57d84..6a0bf5e8ca32 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h
@@ -17,11 +17,19 @@
 		((_id) == (max) ? 0 : (_id) + 1);	\
 	})
 
+#define NBL_MAX_FUNC					520
+#define NBL_MAX_ETHERNET				4
+
 enum nbl_product_type {
 	NBL_LEONIS_TYPE,
 	NBL_PRODUCT_MAX,
 };
 
+enum {
+	NBL_VSI_DATA = 0,
+	NBL_VSI_MAX,
+};
+
 struct nbl_func_caps {
 	u32 has_ctrl:1;
 	u32 has_net:1;
-- 
2.47.3


^ permalink raw reply related

* [PATCH] video: console: mdacon: remove this obsolete driver
From: Ethan Nelson-Moore @ 2026-05-20  3:31 UTC (permalink / raw)
  To: linux-doc, linux-alpha, linux-serial, linux-fbdev
  Cc: Ethan Nelson-Moore, Jonathan Corbet, Shuah Khan,
	Richard Henderson, Matt Turner, Magnus Lindholm,
	Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
	Christophe Leroy (CS GROUP), Greg Kroah-Hartman, Jiri Slaby,
	Helge Deller, Nicolas Pitre

The mdacon driver supports using ISA MDA or Hercules-compatible display
adapters as a secondary text console. This was commonly used in the
1990s and earlier for debugging software which took over the primary
display. It is highly unlikely anyone is doing so nowadays because
serial consoles and much better methods of debugging exist.

The driver is not enabled by any defconfig, nor any of the
dozens of distro configs collected at [1]. It has been relegated to VTs
13-16 since commit 0b9cf3aa6b1e ("mdacon messing up default vc's - set
default to vc13-16 again") in Linux 2.6.27 (and before Linux 2.5.53 -
see the link in the message of the above commit). The change in 2.6.27
was done because it was incorrectly detecting non-MDA adapters as MDA
and taking over all VTs, rendering them unusable.

Furthermore, vgacon supports using MDA/Hercules-compatible adapters as
the primary text console, so any systems with only one of these
adapters were already using vgacon and will not experience any loss in
functionality from the removal of this driver.

Given all of these factors, the mdacon driver is likely entirely
unused. Remove it.

[1] https://github.com/nyrahul/linux-kernel-configs/tree/f0bee86a135a0406ea427855f52702dd00d770f9

Signed-off-by: Ethan Nelson-Moore <enelsonmoore@gmail.com>
---
 .../admin-guide/kernel-parameters.txt         |   5 -
 arch/alpha/kernel/io.c                        |   2 +-
 arch/powerpc/include/asm/vga.h                |   4 +-
 drivers/tty/vt/vt.c                           |   3 -
 drivers/video/console/Kconfig                 |  15 -
 drivers/video/console/Makefile                |   1 -
 drivers/video/console/mdacon.c                | 566 ------------------
 include/linux/console.h                       |   2 -
 include/linux/vt_buffer.h                     |   2 +-
 9 files changed, 4 insertions(+), 596 deletions(-)
 delete mode 100644 drivers/video/console/mdacon.c

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 4d0f545fb3ec..e873b27cdd30 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -36,7 +36,6 @@
 	M68k	M68k architecture is enabled.
 			These options have more detailed description inside of
 			Documentation/arch/m68k/kernel-options.rst.
-	MDA	MDA console support is enabled.
 	MIPS	MIPS architecture is enabled.
 	MOUSE	Appropriate mouse support is enabled.
 	MSI	Message Signaled Interrupts (PCI).
@@ -3816,10 +3815,6 @@ Kernel parameters
 	md=		[HW] RAID subsystems devices and level
 			See Documentation/admin-guide/md.rst.
 
-	mdacon=		[MDA]
-			Format: <first>,<last>
-			Specifies range of consoles to be captured by the MDA.
-
 	mds=		[X86,INTEL,EARLY]
 			Control mitigation for the Micro-architectural Data
 			Sampling (MDS) vulnerability.
diff --git a/arch/alpha/kernel/io.c b/arch/alpha/kernel/io.c
index c28035d6d1e6..2bad1b4fb240 100644
--- a/arch/alpha/kernel/io.c
+++ b/arch/alpha/kernel/io.c
@@ -647,7 +647,7 @@ void _memset_c_io(volatile void __iomem *to, unsigned long c, long count)
 
 EXPORT_SYMBOL(_memset_c_io);
 
-#if IS_ENABLED(CONFIG_VGA_CONSOLE) || IS_ENABLED(CONFIG_MDA_CONSOLE)
+#if IS_ENABLED(CONFIG_VGA_CONSOLE)
 
 #include <asm/vga.h>
 
diff --git a/arch/powerpc/include/asm/vga.h b/arch/powerpc/include/asm/vga.h
index f2dc40e1c52a..e45063b02b45 100644
--- a/arch/powerpc/include/asm/vga.h
+++ b/arch/powerpc/include/asm/vga.h
@@ -14,7 +14,7 @@
 #include <asm/io.h>
 
 
-#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_MDA_CONSOLE)
+#ifdef CONFIG_VGA_CONSOLE
 
 #define VT_BUF_HAVE_RW
 /*
@@ -40,7 +40,7 @@ static inline void scr_memsetw(u16 *s, u16 v, unsigned int n)
 	memset16(s, cpu_to_le16(v), n / 2);
 }
 
-#endif /* !CONFIG_VGA_CONSOLE && !CONFIG_MDA_CONSOLE */
+#endif /* !CONFIG_VGA_CONSOLE */
 
 #ifdef __powerpc64__
 #define VGA_MAP_MEM(x,s) ((unsigned long) ioremap((x), s))
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index e99636ab9db5..3ca5e3dc5ac0 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -3978,9 +3978,6 @@ int __init vty_init(const struct file_operations *console_fops)
 		panic("Couldn't register console driver\n");
 	kbd_init();
 	console_map_init();
-#ifdef CONFIG_MDA_CONSOLE
-	mda_console_init();
-#endif
 	return 0;
 }
 
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index 12f54480f57f..9f81af3506da 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -23,21 +23,6 @@ config VGA_CONSOLE
 
 	  Say Y.
 
-config MDA_CONSOLE
-	depends on VGA_CONSOLE && ISA
-	tristate "MDA text console (dual-headed)"
-	help
-	  Say Y here if you have an old MDA or monochrome Hercules graphics
-	  adapter in your system acting as a second head ( = video card). You
-	  will then be able to use two monitors with your Linux system. Do not
-	  say Y here if your MDA card is the primary card in your system; the
-	  normal VGA driver will handle it.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called mdacon.
-
-	  If unsure, say N.
-
 config SGI_NEWPORT_CONSOLE
 	tristate "SGI Newport Console support"
 	depends on SGI_IP22 && HAS_IOMEM
diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile
index fd79016a0d95..f1000605210c 100644
--- a/drivers/video/console/Makefile
+++ b/drivers/video/console/Makefile
@@ -7,4 +7,3 @@ obj-$(CONFIG_DUMMY_CONSOLE)       += dummycon.o
 obj-$(CONFIG_SGI_NEWPORT_CONSOLE) += newport_con.o
 obj-$(CONFIG_STI_CONSOLE)         += sticon.o
 obj-$(CONFIG_VGA_CONSOLE)         += vgacon.o
-obj-$(CONFIG_MDA_CONSOLE)         += mdacon.o
diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c
deleted file mode 100644
index d52cd99cd18b..000000000000
--- a/drivers/video/console/mdacon.c
+++ /dev/null
@@ -1,566 +0,0 @@
-/*
- *  linux/drivers/video/mdacon.c -- Low level MDA based console driver
- *
- *	(c) 1998 Andrew Apted <ajapted@netspace.net.au>
- *
- *      including portions (c) 1995-1998 Patrick Caulfield.
- *
- *      slight improvements (c) 2000 Edward Betts <edward@debian.org>
- *
- *  This file is based on the VGA console driver (vgacon.c):
- *	
- *	Created 28 Sep 1997 by Geert Uytterhoeven
- *
- *	Rewritten by Martin Mares <mj@ucw.cz>, July 1998
- *
- *  and on the old console.c, vga.c and vesa_blank.c drivers:
- *
- *	Copyright (C) 1991, 1992  Linus Torvalds
- *			    1995  Jay Estabrook
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive for
- *  more details.
- *
- *  Changelog:
- *  Paul G. (03/2001) Fix mdacon= boot prompt to use __setup().
- */
-
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/console.h>
-#include <linux/string.h>
-#include <linux/kd.h>
-#include <linux/vt_kern.h>
-#include <linux/vt_buffer.h>
-#include <linux/selection.h>
-#include <linux/spinlock.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/vga.h>
-
-static DEFINE_SPINLOCK(mda_lock);
-
-/* description of the hardware layout */
-
-static u16		*mda_vram_base;		/* Base of video memory */
-static unsigned long	mda_vram_len;		/* Size of video memory */
-static unsigned int	mda_num_columns;	/* Number of text columns */
-static unsigned int	mda_num_lines;		/* Number of text lines */
-
-static unsigned int	mda_index_port;		/* Register select port */
-static unsigned int	mda_value_port;		/* Register value port */
-static unsigned int	mda_mode_port;		/* Mode control port */
-static unsigned int	mda_status_port;	/* Status and Config port */
-static unsigned int	mda_gfx_port;		/* Graphics control port */
-
-/* current hardware state */
-
-static int	mda_cursor_loc=-1;
-static int	mda_cursor_size_from=-1;
-static int	mda_cursor_size_to=-1;
-
-static enum { TYPE_MDA, TYPE_HERC, TYPE_HERCPLUS, TYPE_HERCCOLOR } mda_type;
-static char *mda_type_name;
-
-/* console information */
-
-static int	mda_first_vc = 13;
-static int	mda_last_vc  = 16;
-
-static struct vc_data	*mda_display_fg = NULL;
-
-module_param(mda_first_vc, int, 0);
-MODULE_PARM_DESC(mda_first_vc, "First virtual console. Default: 13");
-module_param(mda_last_vc, int, 0);
-MODULE_PARM_DESC(mda_last_vc, "Last virtual console. Default: 16");
-
-/* MDA register values
- */
-
-#define MDA_CURSOR_BLINKING	0x00
-#define MDA_CURSOR_OFF		0x20
-#define MDA_CURSOR_SLOWBLINK	0x60
-
-#define MDA_MODE_GRAPHICS	0x02
-#define MDA_MODE_VIDEO_EN	0x08
-#define MDA_MODE_BLINK_EN	0x20
-#define MDA_MODE_GFX_PAGE1	0x80
-
-#define MDA_STATUS_HSYNC	0x01
-#define MDA_STATUS_VSYNC	0x80
-#define MDA_STATUS_VIDEO	0x08
-
-#define MDA_CONFIG_COL132	0x08
-#define MDA_GFX_MODE_EN		0x01
-#define MDA_GFX_PAGE_EN		0x02
-
-
-/*
- * MDA could easily be classified as "pre-dinosaur hardware".
- */
-
-static void write_mda_b(unsigned int val, unsigned char reg)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&mda_lock, flags);	
-
-	outb_p(reg, mda_index_port); 
-	outb_p(val, mda_value_port);
-
-	spin_unlock_irqrestore(&mda_lock, flags);
-}
-
-static void write_mda_w(unsigned int val, unsigned char reg)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&mda_lock, flags);
-
-	outb_p(reg,   mda_index_port); outb_p(val >> 8,   mda_value_port);
-	outb_p(reg+1, mda_index_port); outb_p(val & 0xff, mda_value_port);
-
-	spin_unlock_irqrestore(&mda_lock, flags);
-}
-
-#ifdef TEST_MDA_B
-static int test_mda_b(unsigned char val, unsigned char reg)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&mda_lock, flags);
-
-	outb_p(reg, mda_index_port); 
-	outb  (val, mda_value_port);
-
-	udelay(20); val = (inb_p(mda_value_port) == val);
-
-	spin_unlock_irqrestore(&mda_lock, flags);
-	return val;
-}
-#endif
-
-static inline void mda_set_cursor(unsigned int location) 
-{
-	if (mda_cursor_loc == location)
-		return;
-
-	write_mda_w(location >> 1, 0x0e);
-
-	mda_cursor_loc = location;
-}
-
-static inline void mda_set_cursor_size(int from, int to)
-{
-	if (mda_cursor_size_from==from && mda_cursor_size_to==to)
-		return;
-	
-	if (from > to) {
-		write_mda_b(MDA_CURSOR_OFF, 0x0a);	/* disable cursor */
-	} else {
-		write_mda_b(from, 0x0a);	/* cursor start */
-		write_mda_b(to,   0x0b);	/* cursor end */
-	}
-
-	mda_cursor_size_from = from;
-	mda_cursor_size_to   = to;
-}
-
-
-#ifndef MODULE
-static int __init mdacon_setup(char *str)
-{
-	/* command line format: mdacon=<first>,<last> */
-
-	int ints[3];
-
-	str = get_options(str, ARRAY_SIZE(ints), ints);
-
-	if (ints[0] < 2)
-		return 0;
-
-	if (ints[1] < 1 || ints[1] > MAX_NR_CONSOLES || 
-	    ints[2] < 1 || ints[2] > MAX_NR_CONSOLES)
-		return 0;
-
-	mda_first_vc = ints[1];
-	mda_last_vc  = ints[2];
-	return 1;
-}
-
-__setup("mdacon=", mdacon_setup);
-#endif
-
-static int mda_detect(void)
-{
-	int count=0;
-	u16 *p, p_save;
-	u16 *q, q_save;
-
-	/* do a memory check */
-
-	p = mda_vram_base;
-	q = mda_vram_base + 0x01000 / 2;
-
-	p_save = scr_readw(p);
-	q_save = scr_readw(q);
-
-	scr_writew(0xAA55, p);
-	if (scr_readw(p) == 0xAA55)
-		count++;
-
-	scr_writew(0x55AA, p);
-	if (scr_readw(p) == 0x55AA)
-		count++;
-
-	scr_writew(p_save, p);
-
-	if (count != 2) {
-		return 0;
-	}
-
-	/* check if we have 4K or 8K */
-
-	scr_writew(0xA55A, q);
-	scr_writew(0x0000, p);
-	if (scr_readw(q) == 0xA55A)
-		count++;
-	
-	scr_writew(0x5AA5, q);
-	scr_writew(0x0000, p);
-	if (scr_readw(q) == 0x5AA5)
-		count++;
-
-	scr_writew(p_save, p);
-	scr_writew(q_save, q);
-	
-	if (count == 4) {
-		mda_vram_len = 0x02000;
-	}
-	
-	/* Ok, there is definitely a card registering at the correct
-	 * memory location, so now we do an I/O port test.
-	 */
-
-#ifdef TEST_MDA_B
-	/* Edward: These two mess `tests' mess up my cursor on bootup */
-
-	/* cursor low register */
-	if (!test_mda_b(0x66, 0x0f))
-		return 0;
-
-	/* cursor low register */
-	if (!test_mda_b(0x99, 0x0f))
-		return 0;
-#endif
-
-	/* See if the card is a Hercules, by checking whether the vsync
-	 * bit of the status register is changing.  This test lasts for
-	 * approximately 1/10th of a second.
-	 */
-	
-	p_save = q_save = inb_p(mda_status_port) & MDA_STATUS_VSYNC;
-
-	for (count = 0; count < 50000 && p_save == q_save; count++) {
-		q_save = inb(mda_status_port) & MDA_STATUS_VSYNC;
-		udelay(2);
-	}
-
-	if (p_save != q_save) {
-		switch (inb_p(mda_status_port) & 0x70) {
-		case 0x10:
-			mda_type = TYPE_HERCPLUS;
-			mda_type_name = "HerculesPlus";
-			break;
-		case 0x50:
-			mda_type = TYPE_HERCCOLOR;
-			mda_type_name = "HerculesColor";
-			break;
-		default:
-			mda_type = TYPE_HERC;
-			mda_type_name = "Hercules";
-			break;
-		}
-	}
-
-	return 1;
-}
-
-static void mda_initialize(void)
-{
-	write_mda_b(97, 0x00);		/* horizontal total */
-	write_mda_b(80, 0x01);		/* horizontal displayed */
-	write_mda_b(82, 0x02);		/* horizontal sync pos */
-	write_mda_b(15, 0x03);		/* horizontal sync width */
-
-	write_mda_b(25, 0x04);		/* vertical total */
-	write_mda_b(6,  0x05);		/* vertical total adjust */
-	write_mda_b(25, 0x06);		/* vertical displayed */
-	write_mda_b(25, 0x07);		/* vertical sync pos */
-
-	write_mda_b(2,  0x08);		/* interlace mode */
-	write_mda_b(13, 0x09);		/* maximum scanline */
-	write_mda_b(12, 0x0a);		/* cursor start */
-	write_mda_b(13, 0x0b);		/* cursor end */
-
-	write_mda_w(0x0000, 0x0c);	/* start address */
-	write_mda_w(0x0000, 0x0e);	/* cursor location */
-
-	outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN, mda_mode_port);
-	outb_p(0x00, mda_status_port);
-	outb_p(0x00, mda_gfx_port);
-}
-
-static const char *mdacon_startup(void)
-{
-	mda_num_columns = 80;
-	mda_num_lines   = 25;
-
-	mda_vram_len  = 0x01000;
-	mda_vram_base = (u16 *)VGA_MAP_MEM(0xb0000, mda_vram_len);
-
-	mda_index_port  = 0x3b4;
-	mda_value_port  = 0x3b5;
-	mda_mode_port   = 0x3b8;
-	mda_status_port = 0x3ba;
-	mda_gfx_port    = 0x3bf;
-
-	mda_type = TYPE_MDA;
-	mda_type_name = "MDA";
-
-	if (! mda_detect()) {
-		printk("mdacon: MDA card not detected.\n");
-		return NULL;
-	}
-
-	if (mda_type != TYPE_MDA) {
-		mda_initialize();
-	}
-
-	/* cursor looks ugly during boot-up, so turn it off */
-	mda_set_cursor(mda_vram_len - 1);
-
-	printk("mdacon: %s with %ldK of memory detected.\n",
-		mda_type_name, mda_vram_len/1024);
-
-	return "MDA-2";
-}
-
-static void mdacon_init(struct vc_data *c, bool init)
-{
-	c->vc_complement_mask = 0x0800;	 /* reverse video */
-	c->vc_display_fg = &mda_display_fg;
-
-	if (init) {
-		c->vc_cols = mda_num_columns;
-		c->vc_rows = mda_num_lines;
-	} else
-		vc_resize(c, mda_num_columns, mda_num_lines);
-
-	/* make the first MDA console visible */
-
-	if (mda_display_fg == NULL)
-		mda_display_fg = c;
-}
-
-static void mdacon_deinit(struct vc_data *c)
-{
-	/* con_set_default_unimap(c->vc_num); */
-
-	if (mda_display_fg == c)
-		mda_display_fg = NULL;
-}
-
-static inline u16 mda_convert_attr(u16 ch)
-{
-	u16 attr = 0x0700;
-
-	/* Underline and reverse-video are mutually exclusive on MDA.
-	 * Since reverse-video is used for cursors and selected areas,
-	 * it takes precedence. 
-	 */
-
-	if (ch & 0x0800)	attr = 0x7000;	/* reverse */
-	else if (ch & 0x0400)	attr = 0x0100;	/* underline */
-
-	return ((ch & 0x0200) << 2) | 		/* intensity */ 
-		(ch & 0x8000) |			/* blink */ 
-		(ch & 0x00ff) | attr;
-}
-
-static u8 mdacon_build_attr(struct vc_data *c, u8 color,
-			    enum vc_intensity intensity,
-			    bool blink, bool underline, bool reverse,
-			    bool italic)
-{
-	/* The attribute is just a bit vector:
-	 *
-	 *	Bit 0..1 : intensity (0..2)
-	 *	Bit 2    : underline
-	 *	Bit 3    : reverse
-	 *	Bit 7    : blink
-	 */
-
-	return (intensity & VCI_MASK) |
-		(underline << 2) |
-		(reverse << 3) |
-		(italic << 4) |
-		(blink << 7);
-}
-
-static void mdacon_invert_region(struct vc_data *c, u16 *p, int count)
-{
-	for (; count > 0; count--) {
-		scr_writew(scr_readw(p) ^ 0x0800, p);
-		p++;
-	}
-}
-
-static inline u16 *mda_addr(unsigned int x, unsigned int y)
-{
-	return mda_vram_base + y * mda_num_columns + x;
-}
-
-static void mdacon_putcs(struct vc_data *c, const u16 *s, unsigned int count,
-			 unsigned int y, unsigned int x)
-{
-	u16 *dest = mda_addr(x, y);
-
-	for (; count > 0; count--) {
-		scr_writew(mda_convert_attr(scr_readw(s++)), dest++);
-	}
-}
-
-static void mdacon_clear(struct vc_data *c, unsigned int y, unsigned int x,
-			 unsigned int width)
-{
-	u16 *dest = mda_addr(x, y);
-	u16 eattr = mda_convert_attr(c->vc_video_erase_char);
-
-	scr_memsetw(dest, eattr, width * 2);
-}
-
-static bool mdacon_switch(struct vc_data *c)
-{
-	return true;	/* redrawing needed */
-}
-
-static bool mdacon_blank(struct vc_data *c, enum vesa_blank_mode blank,
-			 bool mode_switch)
-{
-	if (mda_type == TYPE_MDA) {
-		if (blank) 
-			scr_memsetw(mda_vram_base,
-				mda_convert_attr(c->vc_video_erase_char),
-				c->vc_screenbuf_size);
-		/* Tell console.c that it has to restore the screen itself */
-		return true;
-	} else {
-		if (blank)
-			outb_p(0x00, mda_mode_port);	/* disable video */
-		else
-			outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN, 
-				mda_mode_port);
-		return false;
-	}
-}
-
-static void mdacon_cursor(struct vc_data *c, bool enable)
-{
-	if (!enable) {
-		mda_set_cursor(mda_vram_len - 1);
-		return;
-	}
-
-	mda_set_cursor(c->state.y * mda_num_columns * 2 + c->state.x * 2);
-
-	switch (CUR_SIZE(c->vc_cursor_type)) {
-
-		case CUR_LOWER_THIRD:	mda_set_cursor_size(10, 13); break;
-		case CUR_LOWER_HALF:	mda_set_cursor_size(7,  13); break;
-		case CUR_TWO_THIRDS:	mda_set_cursor_size(4,  13); break;
-		case CUR_BLOCK:		mda_set_cursor_size(1,  13); break;
-		case CUR_NONE:		mda_set_cursor_size(14, 13); break;
-		default:		mda_set_cursor_size(12, 13); break;
-	}
-}
-
-static bool mdacon_scroll(struct vc_data *c, unsigned int t, unsigned int b,
-		enum con_scroll dir, unsigned int lines)
-{
-	u16 eattr = mda_convert_attr(c->vc_video_erase_char);
-
-	if (!lines)
-		return false;
-
-	if (lines > c->vc_rows)   /* maximum realistic size */
-		lines = c->vc_rows;
-
-	switch (dir) {
-
-	case SM_UP:
-		scr_memmovew(mda_addr(0, t), mda_addr(0, t + lines),
-				(b-t-lines)*mda_num_columns*2);
-		scr_memsetw(mda_addr(0, b - lines), eattr,
-				lines*mda_num_columns*2);
-		break;
-
-	case SM_DOWN:
-		scr_memmovew(mda_addr(0, t + lines), mda_addr(0, t),
-				(b-t-lines)*mda_num_columns*2);
-		scr_memsetw(mda_addr(0, t), eattr, lines*mda_num_columns*2);
-		break;
-	}
-
-	return false;
-}
-
-
-/*
- *  The console `switch' structure for the MDA based console
- */
-
-static const struct consw mda_con = {
-	.owner =		THIS_MODULE,
-	.con_startup =		mdacon_startup,
-	.con_init =		mdacon_init,
-	.con_deinit =		mdacon_deinit,
-	.con_clear =		mdacon_clear,
-	.con_putcs =		mdacon_putcs,
-	.con_cursor =		mdacon_cursor,
-	.con_scroll =		mdacon_scroll,
-	.con_switch =		mdacon_switch,
-	.con_blank =		mdacon_blank,
-	.con_build_attr =	mdacon_build_attr,
-	.con_invert_region =	mdacon_invert_region,
-};
-
-int __init mda_console_init(void)
-{
-	int err;
-
-	if (mda_first_vc > mda_last_vc)
-		return 1;
-	console_lock();
-	err = do_take_over_console(&mda_con, mda_first_vc-1, mda_last_vc-1, 0);
-	console_unlock();
-	return err;
-}
-
-static void __exit mda_console_exit(void)
-{
-	give_up_console(&mda_con);
-}
-
-module_init(mda_console_init);
-module_exit(mda_console_exit);
-
-MODULE_DESCRIPTION("MDA based console driver");
-MODULE_LICENSE("GPL");
-
diff --git a/include/linux/console.h b/include/linux/console.h
index 5520e4477ad7..d624200cfc17 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -718,8 +718,6 @@ extern bool console_suspend_enabled;
 extern void console_suspend_all(void);
 extern void console_resume_all(void);
 
-int mda_console_init(void);
-
 void vcs_make_sysfs(int index);
 void vcs_remove_sysfs(int index);
 
diff --git a/include/linux/vt_buffer.h b/include/linux/vt_buffer.h
index b6eeb8cb6070..6c15c6a15f74 100644
--- a/include/linux/vt_buffer.h
+++ b/include/linux/vt_buffer.h
@@ -16,7 +16,7 @@
 
 #include <linux/string.h>
 
-#if IS_ENABLED(CONFIG_VGA_CONSOLE) || IS_ENABLED(CONFIG_MDA_CONSOLE)
+#if IS_ENABLED(CONFIG_VGA_CONSOLE)
 #include <asm/vga.h>
 #endif
 
-- 
2.43.0


^ permalink raw reply related

* [PATCH v15 net-next 08/11] net/nebula-matrix: add vsi resource implementation
From: illusion.wang @ 2026-05-20  3:29 UTC (permalink / raw)
  To: dimon.zhao, illusion.wang, alvin.wang, sam.chen, netdev
  Cc: andrew+netdev, corbet, kuba, horms, linux-doc, pabeni,
	vadim.fedorenko, lukas.bulwahn, edumazet, enelsonmoore, skhan,
	hkallweit1, open list
In-Reply-To: <20260520032950.4874-1-illusion.wang@nebula-matrix.com>

This patch adds the VSI (Virtual Station Interface) resource
implementation for the Nebula Matrix Leonis hardware.

This driver only supports little-endian architecture

HW layer overview:
The HW layer code is highly chip-specific and may benefit from
additional review since it cannot be cross-checked against other
implementations.

DP sub-init modules (called from nbl_dp_init()):
- dped, uped:     Data/User Packet Engine Driver
- dsch, ustore, dstore: Scheduling and Store modules
- dvn, uvn, uqm:  Virtual Network and Queue Management
- nbl_shaping_init():      Traffic shaping configuration

Chip init sequence (nbl_hw_init_chip_module()):
1. nbl_dp_init()          — All DP sub-modules above
2. nbl_intf_init()        — Host adapter padpt flow control
   - nbl_host_padpt_init() — Host padpt flow control registers
3. nbl_write_all_regs()   — Bulk P4 register data loading
4. nbl_hw_set_driver_status() + nbl_flush_writes()

Signed-off-by: illusion.wang <illusion.wang@nebula-matrix.com>
---
 .../net/ethernet/nebula-matrix/nbl/Makefile   |   1 +
 .../nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c  | 429 ++++++++++++++++++
 .../nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h  |  15 +-
 .../nbl_hw_leonis/nbl_resource_leonis.c       |   2 +
 .../nbl_hw_leonis/nbl_resource_leonis.h       |   1 +
 .../nebula-matrix/nbl/nbl_hw/nbl_vsi.c        |  26 ++
 .../nebula-matrix/nbl/nbl_hw/nbl_vsi.h        |  12 +
 .../nbl/nbl_include/nbl_def_hw.h              |   4 +
 .../nbl/nbl_include/nbl_include.h             |  31 ++
 9 files changed, 520 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_vsi.c
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_vsi.h

diff --git a/drivers/net/ethernet/nebula-matrix/nbl/Makefile b/drivers/net/ethernet/nebula-matrix/nbl/Makefile
index a56e722a5ac7..241bbb572b5e 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/Makefile
+++ b/drivers/net/ethernet/nebula-matrix/nbl/Makefile
@@ -10,6 +10,7 @@ nbl-objs +=       nbl_common/nbl_common.o \
 				nbl_hw/nbl_hw_leonis/nbl_hw_leonis_regs.o \
 				nbl_hw/nbl_resource.o \
 				nbl_hw/nbl_interrupt.o \
+				nbl_hw/nbl_vsi.o \
 				nbl_core/nbl_dispatch.o \
 				nbl_core/nbl_dev.o \
 				nbl_main.o
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c
index 599e408075e7..20d1aeb192ec 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c
@@ -9,6 +9,7 @@
 #include <linux/spinlock.h>
 #include <linux/bitfield.h>
 #include "nbl_hw_leonis.h"
+#include "nbl_hw_leonis_regs.h"
 
 static void nbl_hw_read_mbx_regs(struct nbl_hw_mgt *hw_mgt, u64 reg,
 				 u32 *data, u32 len)
@@ -64,6 +65,431 @@ static void nbl_hw_wr_regs(struct nbl_hw_mgt *hw_mgt, u64 reg, const u32 *data,
 	spin_unlock(&hw_mgt->reg_lock);
 }
 
+static u32 nbl_hw_get_quirks(struct nbl_hw_mgt *hw_mgt)
+{
+	u32 quirks;
+
+	nbl_hw_read_mbx_regs(hw_mgt, NBL_LEONIS_QUIRKS_OFFSET, &quirks,
+			     sizeof(u32));
+
+	if (quirks == NBL_LEONIS_ILLEGAL_REG_VALUE)
+		return 0;
+
+	return quirks;
+}
+
+static void nbl_configure_dped_checksum(struct nbl_hw_mgt *hw_mgt)
+{
+	union dped_l4_ck_cmd_40_u l4_ck_cmd_40;
+
+	/* DPED dped_l4_ck_cmd_40 for sctp */
+	nbl_hw_rd_regs(hw_mgt, NBL_DPED_L4_CK_CMD_40_ADDR, l4_ck_cmd_40.data,
+		       sizeof(l4_ck_cmd_40));
+	l4_ck_cmd_40.info.en = 1;
+	nbl_hw_wr_regs(hw_mgt, NBL_DPED_L4_CK_CMD_40_ADDR, l4_ck_cmd_40.data,
+		       sizeof(l4_ck_cmd_40));
+}
+
+static void nbl_dped_init(struct nbl_hw_mgt *hw_mgt)
+{
+	nbl_hw_wr32(hw_mgt, NBL_DPED_VLAN_OFFSET, 0xC);
+	nbl_hw_wr32(hw_mgt, NBL_DPED_DSCP_OFFSET_0, 0x8);
+	nbl_hw_wr32(hw_mgt, NBL_DPED_DSCP_OFFSET_1, 0x4);
+
+	/* dped checksum offload */
+	nbl_configure_dped_checksum(hw_mgt);
+}
+
+static void nbl_uped_init(struct nbl_hw_mgt *hw_mgt)
+{
+	union ped_hw_edit_profile_u hw_edit;
+
+	nbl_hw_rd_regs(hw_mgt, NBL_UPED_HW_EDT_PROF_TABLE(NBL_UPED_V4_TCP_IDX),
+		       &hw_edit.data, sizeof(hw_edit));
+	hw_edit.info.l3_len = 0;
+	nbl_hw_wr_regs(hw_mgt, NBL_UPED_HW_EDT_PROF_TABLE(NBL_UPED_V4_TCP_IDX),
+		       &hw_edit.data, sizeof(hw_edit));
+
+	nbl_hw_rd_regs(hw_mgt, NBL_UPED_HW_EDT_PROF_TABLE(NBL_UPED_V6_TCP_IDX),
+		       &hw_edit.data, sizeof(hw_edit));
+	hw_edit.info.l3_len = 1;
+	nbl_hw_wr_regs(hw_mgt, NBL_UPED_HW_EDT_PROF_TABLE(NBL_UPED_V6_TCP_IDX),
+		       &hw_edit.data, sizeof(hw_edit));
+}
+
+static int nbl_shaping_eth_init(struct nbl_hw_mgt *hw_mgt, u8 eth_id, u8 speed)
+{
+	union nbl_shaping_dvn_dport_u dvn_dport = { 0 };
+	union nbl_shaping_dport_u dport = { 0 };
+	u32 rate, half_rate;
+	u32 depth;
+
+	switch (speed) {
+	case NBL_FW_PORT_SPEED_100G:
+		rate = 100000;
+		break;
+	case NBL_FW_PORT_SPEED_50G:
+		rate = 50000;
+		break;
+	case NBL_FW_PORT_SPEED_25G:
+		rate = 25000;
+		break;
+	case NBL_FW_PORT_SPEED_10G:
+		rate = 10000;
+		break;
+	default:
+		dev_err(hw_mgt->common->dev, "Unsupported port speed %u for eth%u\n",
+			speed, eth_id);
+		return -EINVAL;
+	}
+
+	half_rate = rate / 2;
+	depth =  max(rate * 2, NBL_LR_LEONIS_NET_BUCKET_DEPTH);
+	dport.info.low |= FIELD_PREP(DPORT_CIR_MASK, rate);
+	dport.info.low |= FIELD_PREP(DPORT_PIR_MASK, rate);
+	dport.info.low |= FIELD_PREP(DPORT_DEPTH_MASK, depth);
+	dport.info.low  |= FIELD_PREP(DPORT_CBS_MASK_LOW, depth & 0x3F);
+	dport.info.high  |= FIELD_PREP(DPORT_CBS_MASK_HIGH, depth >> 6);
+	dport.info.high  |= FIELD_PREP(DPORT_PBS_MASK, depth);
+	dport.info.low |= FIELD_PREP(DPORT_VALID_MASK, 1);
+
+	dvn_dport.info.low |= FIELD_PREP(DPORT_CIR_MASK, half_rate);
+	dvn_dport.info.low |= FIELD_PREP(DPORT_PIR_MASK, rate);
+	dvn_dport.info.low |= FIELD_PREP(DPORT_DEPTH_MASK, depth);
+	dvn_dport.info.low |= FIELD_PREP(DPORT_CBS_MASK_LOW, depth & 0x3F);
+	dvn_dport.info.high |= FIELD_PREP(DPORT_CBS_MASK_HIGH, depth >> 6);
+	dvn_dport.info.high |= FIELD_PREP(DPORT_PBS_MASK, depth);
+	dvn_dport.info.low |= FIELD_PREP(DPORT_VALID_MASK, 1);
+
+	nbl_hw_wr_regs(hw_mgt, NBL_SHAPING_DPORT_REG(eth_id), dport.data,
+		       sizeof(dport));
+	nbl_hw_wr_regs(hw_mgt, NBL_SHAPING_DVN_DPORT_REG(eth_id),
+		       dvn_dport.data, sizeof(dvn_dport));
+	return 0;
+}
+
+static int nbl_shaping_init(struct nbl_hw_mgt *hw_mgt, u8 speed)
+{
+#define NBL_SHAPING_FLUSH_INTERVAL 128
+	union nbl_shaping_net_u net_shaping = { 0 };
+	union dsch_psha_en_u psha_en = { 0 };
+	int ret;
+	int i;
+
+	for (i = 0; i < NBL_MAX_ETHERNET; i++) {
+		ret = nbl_shaping_eth_init(hw_mgt, i, speed);
+		if (ret)
+			return ret;
+	}
+
+	psha_en.info.en = 0xF;
+	nbl_hw_wr_regs(hw_mgt, NBL_DSCH_PSHA_EN_ADDR, &psha_en.data,
+		       sizeof(psha_en));
+
+	for (i = 0; i < NBL_MAX_FUNC; i++) {
+		nbl_hw_wr_regs(hw_mgt, NBL_SHAPING_NET_REG(i),
+			       net_shaping.data, sizeof(net_shaping));
+		if ((i % NBL_SHAPING_FLUSH_INTERVAL) == 0)
+			nbl_flush_writes(hw_mgt);
+	}
+	nbl_flush_writes(hw_mgt);
+	return 0;
+}
+
+static void nbl_dsch_qid_max_init(struct nbl_hw_mgt *hw_mgt)
+{
+	union dsch_vn_quanta_u quanta = { 0 };
+
+	quanta.info.h_qua = NBL_HOST_QUANTA;
+	quanta.info.e_qua = NBL_ECPU_QUANTA;
+	nbl_hw_wr_regs(hw_mgt, NBL_DSCH_VN_QUANTA_ADDR, &quanta.data,
+		       sizeof(quanta));
+	nbl_hw_wr32(hw_mgt, NBL_DSCH_HOST_QID_MAX, NBL_MAX_QUEUE_ID);
+
+	nbl_hw_wr32(hw_mgt, NBL_DVN_ECPU_QUEUE_NUM, 0);
+	nbl_hw_wr32(hw_mgt, NBL_UVN_ECPU_QUEUE_NUM, 0);
+}
+
+static int nbl_ustore_init(struct nbl_hw_mgt *hw_mgt, u8 eth_num)
+{
+	union nbl_ustore_port_drop_th_u drop_th = { 0 };
+	union ustore_pkt_len_u pkt_len;
+	int i;
+
+	/* Read current packet length config
+	 *(to preserve other fields while updating 'min')
+	 */
+	nbl_hw_rd_regs(hw_mgt, NBL_USTORE_PKT_LEN_ADDR, &pkt_len.data,
+		       sizeof(pkt_len));
+	/* min arp packet length 42 (14 + 28) */
+	pkt_len.info.min = 42;
+	nbl_hw_wr_regs(hw_mgt, NBL_USTORE_PKT_LEN_ADDR, &pkt_len.data,
+		       sizeof(pkt_len));
+
+	drop_th.info.en = 1;
+	if (eth_num == 1)
+		drop_th.info.disc_th = NBL_USTORE_SINGLE_ETH_DROP_TH;
+	else if (eth_num == 2)
+		drop_th.info.disc_th = NBL_USTORE_DUAL_ETH_DROP_TH;
+	else if (eth_num == 4)
+		drop_th.info.disc_th = NBL_USTORE_QUAD_ETH_DROP_TH;
+	else
+		return -EINVAL;
+
+	for (i = 0; i < NBL_MAX_ETHERNET; i++)
+		nbl_hw_wr_regs(hw_mgt, NBL_USTORE_PORT_DROP_TH_REG_ARR(i),
+			       &drop_th.data, sizeof(drop_th));
+
+	/* Clear port drop/truncate counters by reading them
+	 * (hardware has read-to-clear behavior for these registers)
+	 */
+	for (i = 0; i < NBL_MAX_ETHERNET; i++) {
+		nbl_hw_rd32(hw_mgt, NBL_USTORE_BUF_PORT_DROP_PKT(i));
+		nbl_hw_rd32(hw_mgt, NBL_USTORE_BUF_PORT_TRUN_PKT(i));
+	}
+	return 0;
+}
+
+static void nbl_dstore_init(struct nbl_hw_mgt *hw_mgt, u8 speed)
+{
+	union dstore_port_drop_th_u drop_th;
+	union dstore_d_dport_fc_th_u fc_th;
+	union dstore_disc_bp_th_u bp_th;
+	int i;
+
+	for (i = 0; i < NBL_DSTORE_PORT_DROP_TH_DEPTH; i++) {
+		nbl_hw_rd_regs(hw_mgt, NBL_DSTORE_PORT_DROP_TH_REG(i),
+			       drop_th.data, sizeof(drop_th));
+		drop_th.info.en = 0;
+		nbl_hw_wr_regs(hw_mgt, NBL_DSTORE_PORT_DROP_TH_REG(i),
+			       drop_th.data, sizeof(drop_th));
+	}
+
+	nbl_hw_rd_regs(hw_mgt, NBL_DSTORE_DISC_BP_TH, &bp_th.data,
+		       sizeof(bp_th));
+	bp_th.info.en = 1;
+	nbl_hw_wr_regs(hw_mgt, NBL_DSTORE_DISC_BP_TH, &bp_th.data,
+		       sizeof(bp_th));
+
+	for (i = 0; i < NBL_MAX_ETHERNET; i++) {
+		nbl_hw_rd_regs(hw_mgt, NBL_DSTORE_D_DPORT_FC_TH_REG(i),
+			       fc_th.data, sizeof(fc_th));
+		if (speed == NBL_FW_PORT_SPEED_100G) {
+			fc_th.info.xoff_th = NBL_DSTORE_DROP_XOFF_TH_100G;
+			fc_th.info.xon_th = NBL_DSTORE_DROP_XON_TH_100G;
+		} else {
+			fc_th.info.xoff_th = NBL_DSTORE_DROP_XOFF_TH;
+			fc_th.info.xon_th = NBL_DSTORE_DROP_XON_TH;
+		}
+
+		fc_th.info.fc_en = 1;
+		nbl_hw_wr_regs(hw_mgt, NBL_DSTORE_D_DPORT_FC_TH_REG(i),
+			       fc_th.data, sizeof(fc_th));
+	}
+}
+
+static void nbl_dvn_descreq_num_cfg(struct nbl_hw_mgt *hw_mgt, u8 descreq_num)
+{
+	u8 packet_ring_num = descreq_num & 0x7;
+	union nbl_dvn_descreq_num_cfg_u num_cfg = { 0 };
+	u8 split_ring_num = (descreq_num >> 3) & 0x1;
+
+	num_cfg.info.packed_l1_num = packet_ring_num;
+	num_cfg.info.avring_cfg_num = split_ring_num;
+
+	nbl_hw_wr_regs(hw_mgt, NBL_DVN_DESCREQ_NUM_CFG, &num_cfg.data,
+		       sizeof(num_cfg));
+}
+
+static void nbl_dvn_init(struct nbl_hw_mgt *hw_mgt, u8 speed)
+{
+	union nbl_dvn_desc_wr_merge_timeout_u timeout = { 0 };
+	union nbl_dvn_dif_req_rd_ro_flag_u ro_flag = { 0 };
+
+	timeout.info.cfg_cycle = DEFAULT_DVN_DESC_WR_MERGE_TIMEOUT_MAX;
+	nbl_hw_wr_regs(hw_mgt, NBL_DVN_DESC_WR_MERGE_TIMEOUT, &timeout.data,
+		       sizeof(timeout));
+
+	ro_flag.info.rd_desc_ro_en = 1;
+	ro_flag.info.rd_data_ro_en = 1;
+	ro_flag.info.rd_avring_ro_en = 1;
+	nbl_hw_wr_regs(hw_mgt, NBL_DVN_DIF_REQ_RD_RO_FLAG, &ro_flag.data,
+		       sizeof(ro_flag));
+
+	if (speed == NBL_FW_PORT_SPEED_100G)
+		nbl_dvn_descreq_num_cfg(hw_mgt,
+					DEFAULT_DVN_100G_DESCREQ_NUMCFG);
+	else
+		nbl_dvn_descreq_num_cfg(hw_mgt, DEFAULT_DVN_DESCREQ_NUMCFG);
+}
+
+static void nbl_uvn_init(struct nbl_hw_mgt *hw_mgt)
+{
+	union uvn_desc_prefetch_init_u prefetch_init = { 0 };
+	union uvn_desc_wr_timeout_u desc_wr_timeout = { 0 };
+	union uvn_dif_req_ro_flag_u flag = { 0 };
+	union uvn_queue_err_mask_u mask = { 0 };
+	u16 wr_timeout = NBL_UVN_DESC_WR_TIMEOUT_VAL;
+	u32 timeout = NBL_UVN_DESC_RD_WAIT_TICKS;
+	u32 quirks;
+
+	nbl_hw_wr32(hw_mgt, NBL_UVN_DESC_RD_WAIT, timeout);
+
+	desc_wr_timeout.info.num = wr_timeout;
+	nbl_hw_wr_regs(hw_mgt, NBL_UVN_DESC_WR_TIMEOUT, &desc_wr_timeout.data,
+		       sizeof(desc_wr_timeout));
+
+	flag.info.avail_rd = 1;
+	flag.info.desc_rd = 1;
+	flag.info.pkt_wr = 1;
+	flag.info.desc_wr = 0;
+	nbl_hw_wr_regs(hw_mgt, NBL_UVN_DIF_REQ_RO_FLAG, &flag.data,
+		       sizeof(flag));
+
+	nbl_hw_rd_regs(hw_mgt, NBL_UVN_QUEUE_ERR_MASK, &mask.data,
+		       sizeof(mask));
+	mask.info.dif_err = 1;
+	nbl_hw_wr_regs(hw_mgt, NBL_UVN_QUEUE_ERR_MASK, &mask.data,
+		       sizeof(mask));
+
+	prefetch_init.info.num = NBL_UVN_DESC_PREFETCH_NUM;
+	prefetch_init.info.sel = 0;
+	quirks = nbl_hw_get_quirks(hw_mgt);
+	/* sel=0: use configured num; sel=1: use internal calc (max 32)
+	 * Default sel=1. When NBL_QUIRKS_UVN_PREFETCH_ALIGN quirk IS set,
+	 * override to sel=0.
+	 */
+	if (!(quirks & BIT(NBL_QUIRKS_UVN_PREFETCH_ALIGN)))
+		prefetch_init.info.sel = 1;
+	nbl_hw_wr_regs(hw_mgt, NBL_UVN_DESC_PREFETCH_INIT,
+		       &prefetch_init.data, sizeof(prefetch_init));
+}
+
+static void nbl_uqm_init(struct nbl_hw_mgt *hw_mgt)
+{
+	union nbl_uqm_que_type_u que_type = { 0 };
+	u32 cnt = 0;
+	int i;
+
+	nbl_hw_wr_regs(hw_mgt, NBL_UQM_FWD_DROP_CNT, &cnt, sizeof(cnt));
+
+	nbl_hw_wr_regs(hw_mgt, NBL_UQM_DROP_PKT_CNT, &cnt, sizeof(cnt));
+	nbl_hw_wr_regs(hw_mgt, NBL_UQM_DROP_PKT_SLICE_CNT, &cnt,
+		       sizeof(cnt));
+	nbl_hw_wr_regs(hw_mgt, NBL_UQM_DROP_PKT_LEN_ADD_CNT, &cnt,
+		       sizeof(cnt));
+	nbl_hw_wr_regs(hw_mgt, NBL_UQM_DROP_HEAD_PNTR_ADD_CNT, &cnt,
+		       sizeof(cnt));
+	nbl_hw_wr_regs(hw_mgt, NBL_UQM_DROP_WEIGHT_ADD_CNT, &cnt,
+		       sizeof(cnt));
+
+	for (i = 0; i < NBL_UQM_PORT_DROP_DEPTH; i++) {
+		nbl_hw_wr_regs(hw_mgt,
+			       NBL_UQM_PORT_DROP_PKT_CNT + (sizeof(cnt) * i),
+			       &cnt, sizeof(cnt));
+		nbl_hw_wr_regs(hw_mgt,
+			       NBL_UQM_PORT_DROP_PKT_SLICE_CNT +
+				       (sizeof(cnt) * i),
+			       &cnt, sizeof(cnt));
+		nbl_hw_wr_regs(hw_mgt,
+			       NBL_UQM_PORT_DROP_PKT_LEN_ADD_CNT +
+				       (sizeof(cnt) * i),
+			       &cnt, sizeof(cnt));
+		nbl_hw_wr_regs(hw_mgt,
+			       NBL_UQM_PORT_DROP_HEAD_PNTR_ADD_CNT +
+				       (sizeof(cnt) * i),
+			       &cnt, sizeof(cnt));
+		nbl_hw_wr_regs(hw_mgt,
+			       NBL_UQM_PORT_DROP_WEIGHT_ADD_CNT +
+				       (sizeof(cnt) * i),
+			       &cnt, sizeof(cnt));
+	}
+
+	for (i = 0; i < NBL_UQM_DPORT_DROP_DEPTH; i++)
+		nbl_hw_wr_regs(hw_mgt,
+			       NBL_UQM_DPORT_DROP_CNT + (sizeof(cnt) * i),
+			       &cnt, sizeof(cnt));
+
+	que_type.info.bp_drop = 0;
+	nbl_hw_wr_regs(hw_mgt, NBL_UQM_QUE_TYPE, &que_type.data,
+		       sizeof(que_type));
+}
+
+static int nbl_dp_init(struct nbl_hw_mgt *hw_mgt, u8 speed, u8 eth_num)
+{
+	int ret;
+
+	nbl_dped_init(hw_mgt);
+	nbl_uped_init(hw_mgt);
+	ret = nbl_shaping_init(hw_mgt, speed);
+	if (ret)
+		return ret;
+	nbl_dsch_qid_max_init(hw_mgt);
+	ret = nbl_ustore_init(hw_mgt, eth_num);
+	if (ret)
+		return ret;
+	nbl_dstore_init(hw_mgt, speed);
+	nbl_dvn_init(hw_mgt, speed);
+	nbl_uvn_init(hw_mgt);
+	nbl_uqm_init(hw_mgt);
+	return 0;
+}
+
+static void nbl_host_padpt_init(struct nbl_hw_mgt *hw_mgt)
+{
+	/* padpt flow  control register */
+	nbl_hw_wr32(hw_mgt, NBL_HOST_PADPT_HOST_CFG_FC_CPLH_UP,
+		    NBL_HOST_PADPT_CFG_FC_CPLH_UP_VAL);
+	nbl_hw_wr32(hw_mgt, NBL_HOST_PADPT_HOST_CFG_FC_PD_DN,
+		    NBL_HOST_PADPT_CFG_FC_PD_DN_VAL);
+	nbl_hw_wr32(hw_mgt, NBL_HOST_PADPT_HOST_CFG_FC_PH_DN,
+		    NBL_HOST_PADPT_CFG_FC_PH_DN_VAL);
+	nbl_hw_wr32(hw_mgt, NBL_HOST_PADPT_HOST_CFG_FC_NPH_DN,
+		    NBL_HOST_PADPT_HOST_CFG_FC_NPH_DN_VAL);
+}
+
+static void nbl_intf_init(struct nbl_hw_mgt *hw_mgt)
+{
+	nbl_host_padpt_init(hw_mgt);
+}
+
+static void nbl_hw_set_driver_status(struct nbl_hw_mgt *hw_mgt, bool active)
+{
+	u32 status;
+
+	status = nbl_hw_rd32(hw_mgt, NBL_DRIVER_STATUS_REG);
+
+	status = (status & ~(1 << NBL_DRIVER_STATUS_BIT)) |
+		 (active << NBL_DRIVER_STATUS_BIT);
+
+	nbl_hw_wr32(hw_mgt, NBL_DRIVER_STATUS_REG, status);
+}
+
+static void nbl_hw_deinit_chip_module(struct nbl_hw_mgt *hw_mgt)
+{
+	nbl_hw_set_driver_status(hw_mgt, false);
+}
+
+static int nbl_hw_init_chip_module(struct nbl_hw_mgt *hw_mgt, u8 eth_speed,
+				   u8 eth_num)
+{
+	int ret;
+
+	ret = nbl_dp_init(hw_mgt, eth_speed, eth_num);
+	if (ret)
+		return ret;
+	nbl_intf_init(hw_mgt);
+
+	ret = nbl_write_all_regs(hw_mgt);
+	if (ret)
+		return ret;
+	nbl_hw_set_driver_status(hw_mgt, true);
+	/*ensure registers written*/
+	nbl_flush_writes(hw_mgt);
+
+	return 0;
+}
+
 static void nbl_hw_set_mailbox_irq(struct nbl_hw_mgt *hw_mgt, u16 func_id,
 				   bool enable_msix, u16 global_vec_id)
 {
@@ -274,6 +700,9 @@ static u32 nbl_hw_get_fw_eth_map(struct nbl_hw_mgt *hw_mgt)
 }
 
 static struct nbl_hw_ops hw_ops = {
+	.init_chip_module = nbl_hw_init_chip_module,
+	.deinit_chip_module = nbl_hw_deinit_chip_module,
+
 	.configure_msix_map = nbl_hw_configure_msix_map,
 	.configure_msix_info = nbl_hw_configure_msix_info,
 
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h
index 966c30d97f5f..6558cb7bfaa7 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h
@@ -92,6 +92,11 @@ union nbl_mailbox_qinfo_map_table_u {
 #define NBL_PADPT_HOST_MSIX_INFO_REG_ARR(vector_id) \
 	(NBL_INTF_HOST_PADPT_BASE + 0x00010000 +    \
 	 (vector_id) * sizeof(union nbl_host_msix_info_u))
+
+#define NBL_HOST_PADPT_CFG_FC_CPLH_UP_VAL      0x10400
+#define NBL_HOST_PADPT_CFG_FC_PD_DN_VAL        0x10080
+#define NBL_HOST_PADPT_CFG_FC_PH_DN_VAL        0x10010
+#define NBL_HOST_PADPT_HOST_CFG_FC_NPH_DN_VAL  0x10010
 #define NBL_HOST_MSIX_INFO_DWLEN	2
 union nbl_host_msix_info_u {
 	struct nbl_host_msix_info {
@@ -143,7 +148,8 @@ union nbl_function_msix_map_u {
 #define NBL_DPED_VLAN_OFFSET		(NBL_DP_DPED_BASE + 0x000003F4)
 #define NBL_DPED_DSCP_OFFSET_0		(NBL_DP_DPED_BASE + 0x000003F8)
 #define NBL_DPED_DSCP_OFFSET_1		(NBL_DP_DPED_BASE + 0x000003FC)
-
+#define NBL_UPED_V4_TCP_IDX		5
+#define NBL_UPED_V6_TCP_IDX		6
 /* DPED hw_edt_prof/ UPED hw_edt_prof */
 union ped_hw_edit_profile_u {
 	struct ped_hw_edit_profile {
@@ -253,6 +259,9 @@ union dsch_vn_quanta_u {
 #define NBL_DVN_DESC_WR_MERGE_TIMEOUT		(NBL_DP_DVN_BASE + 0x00000480)
 #define NBL_DVN_DIF_REQ_RD_RO_FLAG		(NBL_DP_DVN_BASE + 0x0000045C)
 
+#define DEFAULT_DVN_DESCREQ_NUMCFG		0x03
+#define DEFAULT_DVN_100G_DESCREQ_NUMCFG		0x07
+
 #define DEFAULT_DVN_DESC_WR_MERGE_TIMEOUT_MAX	0x3FF
 
 union nbl_dvn_descreq_num_cfg_u {
@@ -340,6 +349,10 @@ union uvn_desc_prefetch_init_u {
 	u32 data;
 };
 
+#define NBL_UVN_DESC_WR_TIMEOUT_VAL      0x12c
+/* 200us = 200000ns / 1.67ns per tick = 119760 ticks */
+#define NBL_UVN_DESC_RD_WAIT_TICKS       119760
+
 /*  --------  USTORE  --------  */
 #define NBL_USTORE_PKT_LEN_ADDR (NBL_DP_USTORE_BASE + 0x00000108)
 #define NBL_USTORE_PORT_DROP_TH_REG_ARR(port_id) \
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.c
index fa3e120dc506..6d0e135eac3e 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.c
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.c
@@ -13,6 +13,8 @@ static struct nbl_resource_ops res_ops = {
 	.configure_msix_map = nbl_res_intr_configure_msix_map,
 	.destroy_msix_map = nbl_res_intr_destroy_msix_map,
 	.set_mailbox_irq = nbl_res_intr_set_mailbox_irq,
+	.init_chip_module = nbl_res_vsi_init_chip_module,
+	.deinit_chip_module = nbl_res_vsi_deinit_chip_module,
 };
 
 static struct nbl_resource_mgt *
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.h
index 1da2abcaf00f..5c41983890bd 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.h
@@ -8,4 +8,5 @@
 
 #include "../nbl_resource.h"
 #include "../nbl_interrupt.h"
+#include "../nbl_vsi.h"
 #endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_vsi.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_vsi.c
new file mode 100644
index 000000000000..5d0076933eb8
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_vsi.c
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+#include <linux/device.h>
+#include "nbl_vsi.h"
+
+void nbl_res_vsi_deinit_chip_module(struct nbl_resource_mgt *res_mgt)
+{
+	struct nbl_hw_ops *hw_ops = res_mgt->hw_ops_tbl->ops;
+
+	hw_ops->deinit_chip_module(res_mgt->hw_ops_tbl->priv);
+}
+
+int nbl_res_vsi_init_chip_module(struct nbl_resource_mgt *res_mgt)
+{
+	u8 eth_speed = res_mgt->resource_info->board_info.eth_speed;
+	u8 eth_num = res_mgt->resource_info->board_info.eth_num;
+	struct nbl_hw_ops *hw_ops = res_mgt->hw_ops_tbl->ops;
+	struct nbl_hw_mgt *p = res_mgt->hw_ops_tbl->priv;
+	int ret;
+
+	ret = hw_ops->init_chip_module(p, eth_speed, eth_num);
+
+	return ret;
+}
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_vsi.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_vsi.h
new file mode 100644
index 000000000000..6089874fefae
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_vsi.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+
+#ifndef _NBL_VSI_H_
+#define _NBL_VSI_H_
+
+#include "nbl_resource.h"
+int nbl_res_vsi_init_chip_module(struct nbl_resource_mgt *res_mgt);
+void nbl_res_vsi_deinit_chip_module(struct nbl_resource_mgt *res_mgt);
+#endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_hw.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_hw.h
index 3d421bcbc353..8b12c301cdab 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_hw.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_hw.h
@@ -11,6 +11,10 @@
 struct nbl_hw_mgt;
 struct nbl_adapter;
 struct nbl_hw_ops {
+	int (*init_chip_module)(struct nbl_hw_mgt *hw_mgt, u8 eth_speed,
+				u8 eth_num);
+	void (*deinit_chip_module)(struct nbl_hw_mgt *hw_mgt);
+
 	void (*configure_msix_map)(struct nbl_hw_mgt *hw_mgt, u16 func_id,
 				   bool valid, dma_addr_t dma_addr, u8 bus,
 				   u8 devid, u8 function);
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h
index e4f11e6ded94..5203bb2a9a5f 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h
@@ -45,4 +45,35 @@ struct nbl_init_param {
 	bool pci_using_dac;
 };
 
+enum nbl_fw_port_speed {
+	NBL_FW_PORT_SPEED_10G,
+	NBL_FW_PORT_SPEED_25G,
+	NBL_FW_PORT_SPEED_50G,
+	NBL_FW_PORT_SPEED_100G,
+};
+
+#define NBL_OPS_CALL(func, para)		\
+do {						\
+	typeof(func) _func = (func);		\
+	if (_func)				\
+		_func para;			\
+} while (0)
+
+#define NBL_OPS_CALL_RET(func, para)		\
+({						\
+	typeof(func) _func = (func);		\
+	_func ? _func para : 0;			\
+})
+
+#define NBL_OPS_CALL_RET_PTR(func, para)	\
+({						\
+	typeof(func) _func = (func);		\
+	_func ? _func para : NULL;		\
+})
+
+enum nbl_performance_mode {
+	NBL_QUIRKS_NO_TOE,
+	NBL_QUIRKS_UVN_PREFETCH_ALIGN,
+};
+
 #endif
-- 
2.47.3


^ permalink raw reply related

* [PATCH v15 net-next 10/11] net/nebula-matrix: add common/ctrl dev init/reinit operation
From: illusion.wang @ 2026-05-20  3:29 UTC (permalink / raw)
  To: dimon.zhao, illusion.wang, alvin.wang, sam.chen, netdev
  Cc: andrew+netdev, corbet, kuba, horms, linux-doc, pabeni,
	vadim.fedorenko, lukas.bulwahn, edumazet, enelsonmoore, skhan,
	hkallweit1, open list
In-Reply-To: <20260520032950.4874-1-illusion.wang@nebula-matrix.com>

Common Device Setup: nbl_dev_setup_common_dev configures mailbox queues,
registers cleanup tasks, and MSI-X interrupt counter initialization.
Control Device Setup (optional): nbl_dev_setup_ctrl_dev initializes
the chip and configures all channel queues.

Signed-off-by: illusion.wang <illusion.wang@nebula-matrix.com>
---
 .../nebula-matrix/nbl/nbl_core/nbl_dev.c      | 174 ++++++++++++++++++
 .../nebula-matrix/nbl/nbl_core/nbl_dev.h      |  31 ++++
 2 files changed, 205 insertions(+)

diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.c
index 5deb21e35f8e..eb5d2b33a300 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.c
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.c
@@ -6,6 +6,161 @@
 #include <linux/pci.h>
 #include "nbl_dev.h"
 
+static void nbl_dev_init_msix_cnt(struct nbl_dev_mgt *dev_mgt)
+{
+	struct nbl_dev_common *dev_common = dev_mgt->common_dev;
+	struct nbl_msix_info *msix_info = &dev_common->msix_info;
+
+	msix_info->serv_info[NBL_MSIX_MAILBOX_TYPE].num = 1;
+}
+
+/* ----------  Channel config  ---------- */
+static void nbl_dev_setup_chan_qinfo(struct nbl_dev_mgt *dev_mgt, u8 chan_type)
+{
+	struct nbl_channel_ops *chan_ops = dev_mgt->chan_ops_tbl->ops;
+	struct nbl_channel_mgt *priv = dev_mgt->chan_ops_tbl->priv;
+
+	if (!chan_ops->check_queue_exist(priv, chan_type))
+		return;
+
+	chan_ops->cfg_chan_qinfo_map_table(priv);
+}
+
+static int nbl_dev_setup_chan_queue(struct nbl_dev_mgt *dev_mgt, u8 chan_type)
+{
+	struct nbl_channel_ops *chan_ops = dev_mgt->chan_ops_tbl->ops;
+	struct nbl_channel_mgt *priv = dev_mgt->chan_ops_tbl->priv;
+	int ret = 0;
+
+	if (chan_ops->check_queue_exist(priv, chan_type))
+		ret = chan_ops->setup_queue(priv, chan_type);
+
+	return ret;
+}
+
+static int nbl_dev_remove_chan_queue(struct nbl_dev_mgt *dev_mgt, u8 chan_type)
+{
+	struct nbl_channel_ops *chan_ops = dev_mgt->chan_ops_tbl->ops;
+	struct nbl_channel_mgt *priv = dev_mgt->chan_ops_tbl->priv;
+	int ret = 0;
+
+	if (chan_ops->check_queue_exist(priv, chan_type))
+		ret = chan_ops->teardown_queue(priv, chan_type);
+
+	return ret;
+}
+
+static void nbl_dev_register_chan_task(struct nbl_dev_mgt *dev_mgt,
+				       u8 chan_type, struct work_struct *task)
+{
+	struct nbl_channel_ops *chan_ops = dev_mgt->chan_ops_tbl->ops;
+
+	if (chan_ops->check_queue_exist(dev_mgt->chan_ops_tbl->priv, chan_type))
+		chan_ops->register_chan_task(dev_mgt->chan_ops_tbl->priv,
+					     chan_type, task);
+}
+
+/* ----------  Tasks config  ---------- */
+static void nbl_dev_clean_mailbox_task(struct work_struct *work)
+{
+	struct nbl_dev_common *common_dev =
+		container_of(work, struct nbl_dev_common, clean_mbx_task);
+	struct nbl_dev_mgt *dev_mgt = common_dev->dev_mgt;
+	struct nbl_channel_ops *chan_ops = dev_mgt->chan_ops_tbl->ops;
+
+	chan_ops->clean_queue_subtask(dev_mgt->chan_ops_tbl->priv,
+				      NBL_CHAN_TYPE_MAILBOX);
+}
+
+/* ----------  Dev init process  ---------- */
+static int nbl_dev_setup_common_dev(struct nbl_adapter *adapter)
+{
+	struct nbl_dev_mgt *dev_mgt = adapter->core.dev_mgt;
+	struct nbl_dispatch_ops *disp_ops = dev_mgt->disp_ops_tbl->ops;
+	struct nbl_dispatch_mgt *priv = dev_mgt->disp_ops_tbl->priv;
+	struct nbl_common_info *common = dev_mgt->common;
+	struct nbl_dev_common *common_dev;
+	int ret;
+
+	common_dev = devm_kzalloc(&adapter->pdev->dev, sizeof(*common_dev),
+				  GFP_KERNEL);
+	if (!common_dev)
+		return -ENOMEM;
+	common_dev->dev_mgt = dev_mgt;
+
+	ret = nbl_dev_setup_chan_queue(dev_mgt, NBL_CHAN_TYPE_MAILBOX);
+	if (ret)
+		return ret;
+
+	INIT_WORK(&common_dev->clean_mbx_task, nbl_dev_clean_mailbox_task);
+	common->vsi_id = disp_ops->get_vsi_id(priv, NBL_VSI_DATA);
+	if (common->vsi_id == U32_MAX) {
+		ret = -ENOENT;
+		goto err_cleanup;
+	}
+	ret = disp_ops->get_eth_id(priv, common->vsi_id, &common->eth_num,
+			     &common->eth_id, &common->logic_eth_id);
+	if (ret)
+		goto err_cleanup;
+	nbl_dev_register_chan_task(dev_mgt, NBL_CHAN_TYPE_MAILBOX,
+				   &common_dev->clean_mbx_task);
+
+	dev_mgt->common_dev = common_dev;
+	nbl_dev_init_msix_cnt(dev_mgt);
+
+	return 0;
+err_cleanup:
+	nbl_dev_remove_chan_queue(dev_mgt, NBL_CHAN_TYPE_MAILBOX);
+	return ret;
+}
+
+static void nbl_dev_remove_common_dev(struct nbl_adapter *adapter)
+{
+	struct nbl_dev_mgt *dev_mgt = adapter->core.dev_mgt;
+	struct nbl_dev_common *common_dev = dev_mgt->common_dev;
+
+	if (!common_dev)
+		return;
+	cancel_work_sync(&common_dev->clean_mbx_task);
+	nbl_dev_register_chan_task(dev_mgt, NBL_CHAN_TYPE_MAILBOX, NULL);
+	nbl_dev_remove_chan_queue(dev_mgt, NBL_CHAN_TYPE_MAILBOX);
+}
+
+static int nbl_dev_setup_ctrl_dev(struct nbl_adapter *adapter)
+{
+	struct nbl_dev_mgt *dev_mgt = adapter->core.dev_mgt;
+	struct nbl_dispatch_ops *disp_ops = dev_mgt->disp_ops_tbl->ops;
+	int i, ret;
+
+	ret = disp_ops->init_chip_module(dev_mgt->disp_ops_tbl->priv);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < NBL_CHAN_TYPE_MAX; i++)
+		nbl_dev_setup_chan_qinfo(dev_mgt, i);
+
+	return 0;
+}
+
+/*
+ * This is intentional.  The qinfo registers are managed by the chip
+ * firmware, not by the driver.  Setting driver status to false is the
+ * designed teardown mechanism — it notifies the firmware, which then
+ * performs its own cleanup of all per-PF state including the qinfo
+ * registers.
+ * An inverse helper would duplicate work that the firmware already
+ * does, and would add error-path complexity for no benefit.  We keep
+ * the deinit path minimal and rely on the firmware cleanup for
+ * correctness, including in abnormal reset scenarios.
+ */
+static void nbl_dev_remove_ctrl_dev(struct nbl_adapter *adapter)
+{
+	struct nbl_dev_mgt *dev_mgt = adapter->core.dev_mgt;
+	struct nbl_dispatch_ops *disp_ops = dev_mgt->disp_ops_tbl->ops;
+
+	disp_ops->deinit_chip_module(dev_mgt->disp_ops_tbl->priv);
+}
+
 static struct nbl_dev_mgt *nbl_dev_setup_dev_mgt(struct nbl_common_info *common)
 {
 	struct nbl_dev_mgt *dev_mgt;
@@ -38,11 +193,30 @@ int nbl_dev_init(struct nbl_adapter *adapter)
 	dev_mgt->chan_ops_tbl = chan_ops_tbl;
 	adapter->core.dev_mgt = dev_mgt;
 
+	ret = nbl_dev_setup_common_dev(adapter);
+	if (ret)
+		return ret;
+
+	if (common->has_ctrl) {
+		ret = nbl_dev_setup_ctrl_dev(adapter);
+		if (ret)
+			goto setup_ctrl_dev_fail;
+	}
+
 	return 0;
+
+setup_ctrl_dev_fail:
+	nbl_dev_remove_common_dev(adapter);
+	return ret;
 }
 
 void nbl_dev_remove(struct nbl_adapter *adapter)
 {
+	struct nbl_common_info *common = &adapter->common;
+
+	if (common->has_ctrl)
+		nbl_dev_remove_ctrl_dev(adapter);
+	nbl_dev_remove_common_dev(adapter);
 }
 
 /* ----------  Dev start process  ---------- */
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.h
index 9b71092b99a0..b51c8a4424c5 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.h
@@ -18,10 +18,41 @@
 #include "../nbl_include/nbl_def_common.h"
 #include "../nbl_core.h"
 
+#define NBL_STRING_NAME_LEN			32
+
+enum nbl_msix_serv_type {
+	/* virtio_dev has a config vector_id, and the vector_id need is 0 */
+	NBL_MSIX_VIRTIO_TYPE = 0,
+	NBL_MSIX_NET_TYPE,
+	NBL_MSIX_MAILBOX_TYPE,
+	NBL_MSIX_TYPE_MAX
+};
+
+struct nbl_msix_serv_info {
+	char irq_name[NBL_STRING_NAME_LEN];
+	u16 num;
+	u16 base_vector_id;
+	/* true: hw report msix, hw need to mask actively */
+	bool hw_self_mask_en;
+};
+
+struct nbl_msix_info {
+	struct nbl_msix_serv_info serv_info[NBL_MSIX_TYPE_MAX];
+};
+
+struct nbl_dev_common {
+	struct nbl_dev_mgt *dev_mgt;
+	struct nbl_msix_info msix_info;
+	char mailbox_name[NBL_STRING_NAME_LEN];
+	/* for ctrl-dev/net-dev mailbox recv msg */
+	struct work_struct clean_mbx_task;
+};
+
 struct nbl_dev_mgt {
 	struct nbl_common_info *common;
 	struct nbl_dispatch_ops_tbl *disp_ops_tbl;
 	struct nbl_channel_ops_tbl *chan_ops_tbl;
+	struct nbl_dev_common *common_dev;
 };
 
 #endif
-- 
2.47.3


^ permalink raw reply related

* [PATCH v15 net-next 07/11] net/nebula-matrix: add intr resource implementation
From: illusion.wang @ 2026-05-20  3:29 UTC (permalink / raw)
  To: dimon.zhao, illusion.wang, alvin.wang, sam.chen, netdev
  Cc: andrew+netdev, corbet, kuba, horms, linux-doc, pabeni,
	vadim.fedorenko, lukas.bulwahn, edumazet, enelsonmoore, skhan,
	hkallweit1, open list
In-Reply-To: <20260520032950.4874-1-illusion.wang@nebula-matrix.com>

This patch adds the nbl_interrupt module for management of driver-private
MSI-X indices, plus hw_ops callbacks to program the function MSI-X mapping
registers, configure MSI-X info, and enable mailbox interrupts.

Key interfaces:
- configure_msix_map:   Allocates driver-private global MSI-X indices
                          (interrupt_net_bitmap / interrupt_others_bitmap)
                          and programs the hardware MSI-X mapping registers
                          (NBL_PCOMPLETER_FUNCTION_MSIX_MAP).
                          The actual PCI MSI-X vector allocation is done
                          by nbl_dev_alloc_msix_intr().
- destroy_msix_map:     Releases MSI-X indices and tears down the mapping.
- set_mailbox_irq:       Enables/disables a specific mailbox interrupt.
- configure_msix_info:   Programs PADPT_HOST_MSIX_INFO and
                          PCOMPLETER_HOST_MSIX_FID_TABLE.

The patch does not use kernel MSI-X allocation primitives
(pci_alloc_irq_vectors, pci_msix_alloc_irq_at, irq_domain). It manages
a driver-private global index space and programs vendor-specific
MSI-X mapping registers.

Note: Mutual exclusion for configure_msix_map, destroy_msix_map, and
enable_mailbox_irq is handled by the dispatch layer; these functions
assume the caller already holds the necessary lock.

Signed-off-by: illusion.wang <illusion.wang@nebula-matrix.com>
---
 .../net/ethernet/nebula-matrix/nbl/Makefile   |   1 +
 .../nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c  |  76 +++++
 .../nbl_hw_leonis/nbl_resource_leonis.c       |   8 +
 .../nbl_hw_leonis/nbl_resource_leonis.h       |   1 +
 .../nebula-matrix/nbl/nbl_hw/nbl_interrupt.c  | 267 ++++++++++++++++++
 .../nebula-matrix/nbl/nbl_hw/nbl_interrupt.h  |  21 ++
 .../nebula-matrix/nbl/nbl_hw/nbl_resource.h   |  30 ++
 .../nbl/nbl_include/nbl_include.h             |   2 +
 8 files changed, 406 insertions(+)
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_interrupt.c
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_interrupt.h

diff --git a/drivers/net/ethernet/nebula-matrix/nbl/Makefile b/drivers/net/ethernet/nebula-matrix/nbl/Makefile
index b03c20f9988e..a56e722a5ac7 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/Makefile
+++ b/drivers/net/ethernet/nebula-matrix/nbl/Makefile
@@ -9,6 +9,7 @@ nbl-objs +=       nbl_common/nbl_common.o \
 				nbl_hw/nbl_hw_leonis/nbl_resource_leonis.o \
 				nbl_hw/nbl_hw_leonis/nbl_hw_leonis_regs.o \
 				nbl_hw/nbl_resource.o \
+				nbl_hw/nbl_interrupt.o \
 				nbl_core/nbl_dispatch.o \
 				nbl_core/nbl_dev.o \
 				nbl_main.o
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c
index 99f425568040..599e408075e7 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c
@@ -64,6 +64,78 @@ static void nbl_hw_wr_regs(struct nbl_hw_mgt *hw_mgt, u64 reg, const u32 *data,
 	spin_unlock(&hw_mgt->reg_lock);
 }
 
+static void nbl_hw_set_mailbox_irq(struct nbl_hw_mgt *hw_mgt, u16 func_id,
+				   bool enable_msix, u16 global_vec_id)
+{
+	union nbl_mailbox_qinfo_map_table_u mb_qinfo_map = { 0 };
+
+	nbl_hw_rd_regs(hw_mgt, NBL_MAILBOX_QINFO_MAP_REG_ARR(func_id),
+		       &mb_qinfo_map.data, sizeof(mb_qinfo_map));
+
+	if (enable_msix) {
+		mb_qinfo_map.info.msix_idx = global_vec_id;
+		mb_qinfo_map.info.msix_idx_valid = 1;
+	} else {
+		mb_qinfo_map.info.msix_idx = 0;
+		mb_qinfo_map.info.msix_idx_valid = 0;
+	}
+
+	nbl_hw_wr_regs(hw_mgt, NBL_MAILBOX_QINFO_MAP_REG_ARR(func_id),
+		       &mb_qinfo_map.data, sizeof(mb_qinfo_map));
+}
+
+static void nbl_hw_configure_msix_map(struct nbl_hw_mgt *hw_mgt, u16 func_id,
+				      bool valid, dma_addr_t dma_addr, u8 bus,
+				      u8 devid, u8 function)
+{
+	union nbl_function_msix_map_u function_msix_map;
+
+	memset(&function_msix_map, 0, sizeof(function_msix_map));
+	if (valid) {
+		function_msix_map.info.msix_map_base_addr = dma_addr;
+		/* use ctrl dev's bdf, because the dma memory was
+		 * allocated by it
+		 */
+		function_msix_map.info.function = function & 0x7;
+		function_msix_map.info.devid = devid & 0x1F;
+		function_msix_map.info.bus = bus;
+		function_msix_map.info.valid = 1;
+	}
+
+	nbl_hw_wr_regs(hw_mgt,
+		       NBL_PCOMPLETER_FUNCTION_MSIX_MAP_REG_ARR(func_id),
+		       function_msix_map.data, sizeof(function_msix_map));
+}
+
+static void nbl_hw_configure_msix_info(struct nbl_hw_mgt *hw_mgt, u16 func_id,
+				       bool valid, u16 interrupt_id, u8 bus,
+				       u8 devid, u8 function, bool msix_mask_en)
+{
+	union nbl_pcompleter_host_msix_fid_table_u host_msix_fid;
+	union nbl_host_msix_info_u msix_info;
+
+	memset(&host_msix_fid, 0, sizeof(host_msix_fid));
+	memset(&msix_info, 0, sizeof(msix_info));
+	if (valid) {
+		host_msix_fid.info.vld = 1;
+		host_msix_fid.info.fid = func_id;
+
+		msix_info.info.intrl_pnum = 0;
+		msix_info.info.intrl_rate = 0;
+		msix_info.info.function = function & 0x7;
+		msix_info.info.devid = devid & 0x1F;
+		msix_info.info.bus = bus;
+		msix_info.info.valid = 1;
+		if (msix_mask_en)
+			msix_info.info.msix_mask_en = 1;
+	}
+
+	nbl_hw_wr_regs(hw_mgt, NBL_PADPT_HOST_MSIX_INFO_REG_ARR(interrupt_id),
+		       msix_info.data, sizeof(msix_info));
+	nbl_hw_wr_regs(hw_mgt, NBL_PCOMPLETER_HOST_MSIX_FID_TABLE(interrupt_id),
+		       &host_msix_fid.data, sizeof(host_msix_fid));
+}
+
 static void nbl_hw_update_mailbox_queue_tail_ptr(struct nbl_hw_mgt *hw_mgt,
 						 u16 tail_ptr, u8 txrx)
 {
@@ -202,6 +274,9 @@ static u32 nbl_hw_get_fw_eth_map(struct nbl_hw_mgt *hw_mgt)
 }
 
 static struct nbl_hw_ops hw_ops = {
+	.configure_msix_map = nbl_hw_configure_msix_map,
+	.configure_msix_info = nbl_hw_configure_msix_info,
+
 	.update_mailbox_queue_tail_ptr = nbl_hw_update_mailbox_queue_tail_ptr,
 	.config_mailbox_rxq = nbl_hw_config_mailbox_rxq,
 	.config_mailbox_txq = nbl_hw_config_mailbox_txq,
@@ -211,6 +286,7 @@ static struct nbl_hw_ops hw_ops = {
 	.get_real_bus = nbl_hw_get_real_bus,
 
 	.cfg_mailbox_qinfo = nbl_hw_cfg_mailbox_qinfo,
+	.set_mailbox_irq = nbl_hw_set_mailbox_irq,
 
 	.get_fw_eth_num = nbl_hw_get_fw_eth_num,
 	.get_fw_eth_map = nbl_hw_get_fw_eth_map,
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.c
index 36366cd47753..fa3e120dc506 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.c
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.c
@@ -10,6 +10,9 @@
 static struct nbl_resource_ops res_ops = {
 	.get_vsi_id = nbl_res_func_id_to_vsi_id,
 	.get_eth_id = nbl_res_get_eth_id,
+	.configure_msix_map = nbl_res_intr_configure_msix_map,
+	.destroy_msix_map = nbl_res_intr_destroy_msix_map,
+	.set_mailbox_irq = nbl_res_intr_set_mailbox_irq,
 };
 
 static struct nbl_resource_mgt *
@@ -227,7 +230,12 @@ static int nbl_res_start(struct nbl_resource_mgt *res_mgt)
 		ret = nbl_res_ctrl_dev_vsi_info_init(res_mgt);
 		if (ret)
 			return ret;
+
+		ret = nbl_intr_mgt_start(res_mgt);
+		if (ret)
+			return ret;
 	}
+
 	return 0;
 }
 
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.h
index 4e61a5c141e5..1da2abcaf00f 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.h
@@ -7,4 +7,5 @@
 #define _NBL_RESOURCE_LEONIS_H_
 
 #include "../nbl_resource.h"
+#include "../nbl_interrupt.h"
 #endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_interrupt.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_interrupt.c
new file mode 100644
index 000000000000..c9d030e55fa1
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_interrupt.c
@@ -0,0 +1,267 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include "nbl_interrupt.h"
+
+int nbl_res_intr_destroy_msix_map(struct nbl_resource_mgt *res_mgt,
+				  u16 func_id)
+{
+	struct nbl_interrupt_mgt *intr_mgt = res_mgt->intr_mgt;
+	struct nbl_hw_ops *hw_ops = res_mgt->hw_ops_tbl->ops;
+	struct device *dev = res_mgt->common->dev;
+	struct nbl_msix_map_table *msix_map_table;
+	u16 *interrupts;
+	u16 intr_num, i;
+
+	if (func_id >= NBL_MAX_FUNC) {
+		dev_err(dev, "Invalid func_id %u\n", func_id);
+		return -EINVAL;
+	}
+
+	intr_num = intr_mgt->func_intr_res[func_id].num_interrupts;
+	interrupts = intr_mgt->func_intr_res[func_id].interrupts;
+	msix_map_table = &intr_mgt->func_intr_res[func_id].msix_map_table;
+
+	if (!interrupts || !msix_map_table->base_addr) {
+		dev_err(dev, "No interrupts to clr for func_id %u\n", func_id);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < intr_num; i++) {
+		if (interrupts[i] >= NBL_MAX_OTHER_INTERRUPT)
+			clear_bit(interrupts[i] - NBL_MAX_OTHER_INTERRUPT,
+				  intr_mgt->interrupt_net_bitmap);
+		else
+			clear_bit(interrupts[i],
+				  intr_mgt->interrupt_others_bitmap);
+
+		hw_ops->configure_msix_info(res_mgt->hw_ops_tbl->priv, func_id,
+					    false, interrupts[i], 0, 0, 0,
+					    false);
+	}
+
+	/* Ensure completion of DMA memory write operation */
+	dma_wmb();
+	/* use ctrl dev bdf */
+	hw_ops->configure_msix_map(res_mgt->hw_ops_tbl->priv, func_id, false, 0,
+				   0, 0, 0);
+	kfree(interrupts);
+	intr_mgt->func_intr_res[func_id].interrupts = NULL;
+	intr_mgt->func_intr_res[func_id].num_interrupts = 0;
+
+	dma_free_coherent(dev, msix_map_table->size, msix_map_table->base_addr,
+			  msix_map_table->dma);
+	msix_map_table->size = 0;
+	msix_map_table->base_addr = NULL;
+	msix_map_table->dma = 0;
+
+	return 0;
+}
+
+int nbl_res_intr_configure_msix_map(struct nbl_resource_mgt *res_mgt,
+				    u16 func_id, u16 num_net_msix,
+				    u16 num_others_msix,
+				    bool net_msix_mask_en)
+{
+	struct nbl_interrupt_mgt *intr_mgt = res_mgt->intr_mgt;
+	struct nbl_hw_ops *hw_ops = res_mgt->hw_ops_tbl->ops;
+	struct nbl_common_info *common = res_mgt->common;
+	struct nbl_msix_map_table *msix_map_table;
+	struct nbl_msix_map *msix_map_entries;
+	struct device *dev = common->dev;
+	u16 requested, intr_index;
+	u8 bus, devid, function;
+	bool msix_mask_en;
+	u16 *interrupts;
+	int ret = 0;
+	u16 i;
+
+	if (func_id >= NBL_MAX_FUNC) {
+		dev_err(dev, "Invalid func_id %u\n", func_id);
+		return -EINVAL;
+	}
+	if (num_net_msix == 0 && num_others_msix == 0) {
+		dev_err(dev, "MSI-X count cannot be zero\n");
+		return -EINVAL;
+	}
+	if (num_net_msix > NBL_MSIX_MAP_TABLE_MAX_ENTRIES ||
+	    num_others_msix > NBL_MSIX_MAP_TABLE_MAX_ENTRIES) {
+		dev_err(dev, "Invalid MSI-X count: net=%u, others=%u\n",
+			num_net_msix, num_others_msix);
+		return -EINVAL;
+	}
+
+	if (check_add_overflow(num_net_msix, num_others_msix, &requested) ||
+	    requested > NBL_MSIX_MAP_TABLE_MAX_ENTRIES) {
+		dev_err(dev, "MSI-X total %u exceeds max %u\n",
+			requested, NBL_MSIX_MAP_TABLE_MAX_ENTRIES);
+		return -EINVAL;
+	}
+
+	ret = nbl_res_func_id_to_bdf(res_mgt, func_id, &bus, &devid, &function);
+	if (ret)
+		return ret;
+
+	/* Clean up old resources (if they exist) */
+	if (intr_mgt->func_intr_res[func_id].interrupts) {
+		ret = nbl_res_intr_destroy_msix_map(res_mgt, func_id);
+		if (ret) {
+			dev_err(dev, "Failed to destroy old MSIX map: %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	msix_map_table = &intr_mgt->func_intr_res[func_id].msix_map_table;
+	WARN_ON(msix_map_table->base_addr);
+	msix_map_table->size =
+		sizeof(struct nbl_msix_map) * NBL_MSIX_MAP_TABLE_MAX_ENTRIES;
+	/* HW indexes the MSI-X map table with a fixed stride of 1024 entries,
+	 * so we must allocate the full table even if fewer vectors are used.
+	 */
+	msix_map_table->base_addr = dma_alloc_coherent(dev,
+						       msix_map_table->size,
+						       &msix_map_table->dma,
+						       GFP_KERNEL);
+	if (!msix_map_table->base_addr) {
+		dev_err(dev, "Allocate DMA memory for function msix map table failed\n");
+		msix_map_table->size = 0;
+		return -ENOMEM;
+	}
+
+	interrupts = kcalloc(requested, sizeof(interrupts[0]), GFP_KERNEL);
+	if (!interrupts) {
+		ret = -ENOMEM;
+		goto alloc_interrupts_err;
+	}
+
+	intr_mgt->func_intr_res[func_id].interrupts = interrupts;
+	intr_mgt->func_intr_res[func_id].num_interrupts = requested;
+	intr_mgt->func_intr_res[func_id].num_net_interrupts = num_net_msix;
+
+	for (i = 0; i < num_net_msix; i++) {
+		intr_index = find_first_zero_bit(intr_mgt->interrupt_net_bitmap,
+						 NBL_MAX_NET_INTERRUPT);
+		if (intr_index == NBL_MAX_NET_INTERRUPT) {
+			dev_err(dev, "There is no available interrupt left\n");
+			ret = -EAGAIN;
+			goto get_interrupt_err;
+		}
+		interrupts[i] = intr_index + NBL_MAX_OTHER_INTERRUPT;
+		set_bit(intr_index, intr_mgt->interrupt_net_bitmap);
+	}
+
+	for (i = num_net_msix; i < requested; i++) {
+		intr_index =
+			find_first_zero_bit(intr_mgt->interrupt_others_bitmap,
+					    NBL_MAX_OTHER_INTERRUPT);
+		if (intr_index == NBL_MAX_OTHER_INTERRUPT) {
+			dev_err(dev, "There is no available interrupt left\n");
+			ret = -EAGAIN;
+			goto get_interrupt_err;
+		}
+		interrupts[i] = intr_index;
+		set_bit(intr_index, intr_mgt->interrupt_others_bitmap);
+	}
+
+	msix_map_entries = msix_map_table->base_addr;
+	for (i = 0; i < requested; i++) {
+		msix_map_entries[i].global_msix_index = interrupts[i];
+		msix_map_entries[i].valid = 1;
+
+		if (i < num_net_msix && net_msix_mask_en)
+			msix_mask_en = 1;
+		else
+			msix_mask_en = 0;
+		hw_ops->configure_msix_info(res_mgt->hw_ops_tbl->priv, func_id,
+					    true, interrupts[i], bus, devid,
+					    function, msix_mask_en);
+	}
+	/* Ensure completion of DMA memory write operation */
+	dma_wmb();
+	/* use ctrl dev bdf */
+	hw_ops->configure_msix_map(res_mgt->hw_ops_tbl->priv, func_id, true,
+				   msix_map_table->dma, common->hw_bus,
+				   common->devid, common->function);
+
+	return 0;
+
+get_interrupt_err:
+	while (i--) {
+		intr_index = interrupts[i];
+		if (intr_index >= NBL_MAX_OTHER_INTERRUPT)
+			clear_bit(intr_index - NBL_MAX_OTHER_INTERRUPT,
+				  intr_mgt->interrupt_net_bitmap);
+		else
+			clear_bit(intr_index,
+				  intr_mgt->interrupt_others_bitmap);
+	}
+	kfree(interrupts);
+	intr_mgt->func_intr_res[func_id].num_interrupts = 0;
+	intr_mgt->func_intr_res[func_id].interrupts = NULL;
+
+alloc_interrupts_err:
+	dma_free_coherent(dev, msix_map_table->size, msix_map_table->base_addr,
+			  msix_map_table->dma);
+	msix_map_table->size = 0;
+	msix_map_table->base_addr = NULL;
+	msix_map_table->dma = 0;
+
+	return ret;
+}
+
+int nbl_res_intr_set_mailbox_irq(struct nbl_resource_mgt *res_mgt,
+				 u16 func_id, u16 vector_id,
+				 bool enable_msix)
+{
+	struct nbl_interrupt_mgt *intr_mgt = res_mgt->intr_mgt;
+	struct nbl_hw_ops *hw_ops = res_mgt->hw_ops_tbl->ops;
+	struct nbl_common_info *common = res_mgt->common;
+	struct device *dev = common->dev;
+	u16 global_vec_id;
+
+	if (func_id >= NBL_MAX_FUNC ||
+	    !intr_mgt->func_intr_res[func_id].interrupts ||
+	    vector_id >= intr_mgt->func_intr_res[func_id].num_interrupts) {
+		dev_err(dev, "Invalid func_id %u or vector_id %u\n",
+			func_id, vector_id);
+		return -EINVAL;
+	}
+
+	global_vec_id = intr_mgt->func_intr_res[func_id].interrupts[vector_id];
+	hw_ops->set_mailbox_irq(res_mgt->hw_ops_tbl->priv, func_id,
+				   enable_msix, global_vec_id);
+
+	return 0;
+}
+
+/* Structure starts here, adding an op should not modify anything below */
+static struct nbl_interrupt_mgt *nbl_intr_setup_mgt(struct device *dev)
+{
+	struct nbl_interrupt_mgt *intr_mgt;
+
+	intr_mgt = devm_kzalloc(dev, sizeof(*intr_mgt), GFP_KERNEL);
+	if (!intr_mgt)
+		return ERR_PTR(-ENOMEM);
+
+	return intr_mgt;
+}
+
+int nbl_intr_mgt_start(struct nbl_resource_mgt *res_mgt)
+{
+	struct device *dev = res_mgt->common->dev;
+	struct nbl_interrupt_mgt *intr_mgt;
+	int ret;
+
+	intr_mgt = nbl_intr_setup_mgt(dev);
+	if (IS_ERR(intr_mgt)) {
+		ret = PTR_ERR(intr_mgt);
+		return ret;
+	}
+	res_mgt->intr_mgt = intr_mgt;
+	return 0;
+}
+
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_interrupt.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_interrupt.h
new file mode 100644
index 000000000000..5aa46a4fce4c
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_interrupt.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+
+#ifndef _NBL_INTERRUPT_H_
+#define _NBL_INTERRUPT_H_
+
+#include "nbl_resource.h"
+
+#define NBL_MSIX_MAP_TABLE_MAX_ENTRIES	1024
+int nbl_res_intr_destroy_msix_map(struct nbl_resource_mgt *res_mgt,
+				  u16 func_id);
+int nbl_res_intr_configure_msix_map(struct nbl_resource_mgt *res_mgt,
+				    u16 func_id, u16 num_net_msix,
+				    u16 num_others_msix,
+				    bool net_msix_mask_en);
+int nbl_res_intr_set_mailbox_irq(struct nbl_resource_mgt *res_mgt,
+				 u16 func_id, u16 vector_id,
+				 bool enable_msix);
+#endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_resource.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_resource.h
index 15dc7f78afc0..b1f5724e727a 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_resource.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_resource.h
@@ -18,6 +18,35 @@
 
 struct nbl_resource_mgt;
 
+/* --------- INTERRUPT ---------- */
+#define NBL_MAX_OTHER_INTERRUPT			1024
+#define NBL_MAX_NET_INTERRUPT			4096
+
+struct nbl_msix_map {
+	u16 valid:1;
+	u16 global_msix_index:13;
+	u16 rsv:2;
+};
+
+struct nbl_msix_map_table {
+	struct nbl_msix_map *base_addr;
+	dma_addr_t dma;
+	size_t size;
+};
+
+struct nbl_func_interrupt_resource_mng {
+	u16 num_interrupts;
+	u16 num_net_interrupts;
+	u16 *interrupts;
+	struct nbl_msix_map_table msix_map_table;
+};
+
+struct nbl_interrupt_mgt {
+	DECLARE_BITMAP(interrupt_net_bitmap, NBL_MAX_NET_INTERRUPT);
+	DECLARE_BITMAP(interrupt_others_bitmap, NBL_MAX_OTHER_INTERRUPT);
+	struct nbl_func_interrupt_resource_mng func_intr_res[NBL_MAX_FUNC];
+};
+
 /* --------- INFO ---------- */
 struct nbl_sriov_info {
 	unsigned int bdf;
@@ -75,6 +104,7 @@ int nbl_res_func_id_to_bdf(struct nbl_resource_mgt *res_mgt, u16 func_id,
 			   u8 *bus, u8 *dev, u8 *function);
 int nbl_res_get_eth_id(struct nbl_resource_mgt *res_mgt, u16 vsi_id,
 		       u8 *eth_num, u8 *eth_id, u8 *logic_eth_id);
+int nbl_intr_mgt_start(struct nbl_resource_mgt *res_mgt);
 void nbl_res_pf_dev_vsi_type_to_hw_vsi_type(u16 src_type,
 					    enum nbl_vsi_serv_type *dst_type);
 #endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h
index 6a0bf5e8ca32..e4f11e6ded94 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h
@@ -19,6 +19,8 @@
 
 #define NBL_MAX_FUNC					520
 #define NBL_MAX_ETHERNET				4
+/* Used for macros to pass checkpatch */
+#define NBL_NAME(x)					x
 
 enum nbl_product_type {
 	NBL_LEONIS_TYPE,
-- 
2.47.3


^ permalink raw reply related

* [PATCH v15 net-next 01/11] net/nebula-matrix: add minimum nbl build framework
From: illusion.wang @ 2026-05-20  3:29 UTC (permalink / raw)
  To: dimon.zhao, illusion.wang, alvin.wang, sam.chen, netdev
  Cc: andrew+netdev, corbet, kuba, horms, linux-doc, pabeni,
	vadim.fedorenko, lukas.bulwahn, edumazet, enelsonmoore, skhan,
	hkallweit1, open list
In-Reply-To: <20260520032950.4874-1-illusion.wang@nebula-matrix.com>

1.Add nbl min build infrastructure for nbl driver.

2.Add PCI driver skeleton with empty stubs for nbl driver.

Signed-off-by: illusion.wang <illusion.wang@nebula-matrix.com>
---
 .../device_drivers/ethernet/index.rst         |   1 +
 .../ethernet/nebula-matrix/nbl.rst            |  28 +++++
 MAINTAINERS                                   |  10 ++
 drivers/net/ethernet/Kconfig                  |   1 +
 drivers/net/ethernet/Makefile                 |   1 +
 drivers/net/ethernet/nebula-matrix/Kconfig    |  34 ++++++
 drivers/net/ethernet/nebula-matrix/Makefile   |   6 +
 .../net/ethernet/nebula-matrix/nbl/Makefile   |   6 +
 .../net/ethernet/nebula-matrix/nbl/nbl_core.h |  16 +++
 .../nbl/nbl_include/nbl_include.h             |  21 ++++
 .../net/ethernet/nebula-matrix/nbl/nbl_main.c | 113 ++++++++++++++++++
 11 files changed, 237 insertions(+)
 create mode 100644 Documentation/networking/device_drivers/ethernet/nebula-matrix/nbl.rst
 create mode 100644 drivers/net/ethernet/nebula-matrix/Kconfig
 create mode 100644 drivers/net/ethernet/nebula-matrix/Makefile
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/Makefile
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_core.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_main.c

diff --git a/Documentation/networking/device_drivers/ethernet/index.rst b/Documentation/networking/device_drivers/ethernet/index.rst
index fd3be5d20397..00b87a6ebe6d 100644
--- a/Documentation/networking/device_drivers/ethernet/index.rst
+++ b/Documentation/networking/device_drivers/ethernet/index.rst
@@ -46,6 +46,7 @@ Contents:
    meta/fbnic
    microsoft/netvsc
    mucse/rnpgbe
+   nebula-matrix/nbl
    netronome/nfp
    pensando/ionic
    pensando/ionic_rdma
diff --git a/Documentation/networking/device_drivers/ethernet/nebula-matrix/nbl.rst b/Documentation/networking/device_drivers/ethernet/nebula-matrix/nbl.rst
new file mode 100644
index 000000000000..95b7ef4ee6dc
--- /dev/null
+++ b/Documentation/networking/device_drivers/ethernet/nebula-matrix/nbl.rst
@@ -0,0 +1,28 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+================================================================
+Linux Base Driver for Nebula-matrix m18110-NIC/m18000-NIC family
+================================================================
+
+Overview:
+=========
+The m18110-NIC/m18000-NIC is a series of network interface cards for the Data
+Center Area.
+
+The driver supports link-speed 100GbE/25GE/10GE.
+
+m18110-NIC/m18000-NIC devices support MSI-X interrupt vector for each Tx/Rx
+queue and interrupt moderation.
+
+m18110-NIC/m18000-NIC devices support also various offload features such as
+checksum offload, Receive-Side Scaling(RSS).
+
+Support
+=======
+
+For more information about m18110-NIC/m18000-NIC, please visit the following URL:
+https://www.nebula-matrix.com/
+
+If an issue is identified with the released source code on the supported kernel
+with a supported adapter, email the specific information related to the issue to
+open@nebula-matrix.com.
diff --git a/MAINTAINERS b/MAINTAINERS
index 5db1a2923dd2..051fd86583ee 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18383,6 +18383,16 @@ F:	Documentation/devicetree/bindings/hwmon/nuvoton,nct7363.yaml
 F:	Documentation/hwmon/nct7363.rst
 F:	drivers/hwmon/nct7363.c
 
+NEBULA-MATRIX ETHERNET DRIVER (nebula-matrix)
+M:	Illusion Wang <illusion.wang@nebula-matrix.com>
+M:	Dimon Zhao <dimon.zhao@nebula-matrix.com>
+M:	Alvin Wang <alvin.wang@nebula-matrix.com>
+M:	Sam Chen <sam.chen@nebula-matrix.com>
+L:	netdev@vger.kernel.org
+S:	Maintained
+F:	Documentation/networking/device_drivers/ethernet/nebula-matrix/
+F:	drivers/net/ethernet/nebula-matrix/
+
 NETCONSOLE
 M:	Breno Leitao <leitao@debian.org>
 S:	Maintained
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index 78c79ad7bba5..5c21d02c4e11 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -130,6 +130,7 @@ config FEALNX
 
 source "drivers/net/ethernet/ni/Kconfig"
 source "drivers/net/ethernet/natsemi/Kconfig"
+source "drivers/net/ethernet/nebula-matrix/Kconfig"
 source "drivers/net/ethernet/netronome/Kconfig"
 source "drivers/net/ethernet/8390/Kconfig"
 source "drivers/net/ethernet/nvidia/Kconfig"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index bba55d9af387..accce62a79a6 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_NET_VENDOR_MUCSE) += mucse/
 obj-$(CONFIG_NET_VENDOR_MYRI) += myricom/
 obj-$(CONFIG_FEALNX) += fealnx.o
 obj-$(CONFIG_NET_VENDOR_NATSEMI) += natsemi/
+obj-$(CONFIG_NET_VENDOR_NEBULA_MATRIX) += nebula-matrix/
 obj-$(CONFIG_NET_VENDOR_NETRONOME) += netronome/
 obj-$(CONFIG_NET_VENDOR_NI) += ni/
 obj-$(CONFIG_NET_VENDOR_NVIDIA) += nvidia/
diff --git a/drivers/net/ethernet/nebula-matrix/Kconfig b/drivers/net/ethernet/nebula-matrix/Kconfig
new file mode 100644
index 000000000000..99cd53fcc52e
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/Kconfig
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Nebula-matrix network device configuration
+#
+
+config NET_VENDOR_NEBULA_MATRIX
+	bool "Nebula-matrix devices"
+	default y
+	help
+	  If you have a network (Ethernet) card belonging to this class, say Y.
+	  Note that the answer to this question doesn't directly affect the
+	  kernel: saying N will just cause the configurator to skip all
+	  the questions about Nebula-matrix cards. If you say Y, you will be asked
+	  for your specific card in the following questions.
+
+if NET_VENDOR_NEBULA_MATRIX
+
+config NBL
+	tristate "Nebula-matrix Ethernet Controller m18110/m18000 support"
+	depends on PCI && (64BIT || COMPILE_TEST) && !CPU_BIG_ENDIAN
+	help
+	  This driver supports Nebula-matrix Ethernet Controller m18110/m18000
+	  Family of devices.  For more information about this product, go to
+	  the product description with smart NIC:
+
+	  <http://www.nebula-matrix.com>
+
+	  More specific information on configuring the driver is in
+	  <file:Documentation/networking/device_drivers/ethernet/nebula-matrix/nbl.rst>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called nbl.
+
+endif # NET_VENDOR_NEBULA_MATRIX
diff --git a/drivers/net/ethernet/nebula-matrix/Makefile b/drivers/net/ethernet/nebula-matrix/Makefile
new file mode 100644
index 000000000000..42cdf2db8f0c
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the Nebula-matrix network device drivers.
+#
+
+obj-$(CONFIG_NBL) += nbl/
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/Makefile b/drivers/net/ethernet/nebula-matrix/nbl/Makefile
new file mode 100644
index 000000000000..b90fba239401
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2025 Nebula Matrix Limited.
+
+obj-$(CONFIG_NBL) := nbl.o
+
+nbl-objs +=      nbl_main.o
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_core.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_core.h
new file mode 100644
index 000000000000..c525114297b4
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_core.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+
+#ifndef _NBL_CORE_H_
+#define _NBL_CORE_H_
+
+enum {
+	NBL_CAP_HAS_CTRL_BIT,
+	NBL_CAP_HAS_NET_BIT,
+	NBL_CAP_IS_NIC_BIT,
+	NBL_CAP_IS_LEONIS_BIT,
+};
+
+#endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h
new file mode 100644
index 000000000000..1046e6517b15
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+
+#ifndef _NBL_INCLUDE_H_
+#define _NBL_INCLUDE_H_
+
+#include <linux/types.h>
+
+/*  ------  Basic definitions  -------  */
+#define NBL_DRIVER_NAME					"nbl"
+
+struct nbl_func_caps {
+	u32 has_ctrl:1;
+	u32 has_net:1;
+	u32 is_nic:1;
+	u32 rsv:29;
+};
+
+#endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_main.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_main.c
new file mode 100644
index 000000000000..10c3536b327b
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_main.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include "nbl_include/nbl_include.h"
+#include "nbl_core.h"
+
+static int nbl_probe(struct pci_dev *pdev,
+		     const struct pci_device_id *id)
+{
+	return 0;
+}
+
+static void nbl_remove(struct pci_dev *pdev)
+{
+}
+
+/*
+ * PCI Device IDs for Leonis/NBL Network Controllers
+ *
+ * Vendor ID: 0x1F0F
+ * SNIC v3r1 product Device IDs range: 0x3403-0x3412
+ */
+#define NBL_VENDOR_ID				0x1F0F
+
+#define NBL_DEVICE_ID_M18110			0x3403
+#define NBL_DEVICE_ID_M18110_LX			0x3404
+#define NBL_DEVICE_ID_M18110_BASE_T		0x3405
+#define NBL_DEVICE_ID_M18110_LX_BASE_T		0x3406
+#define NBL_DEVICE_ID_M18110_OCP		0x3407
+#define NBL_DEVICE_ID_M18110_LX_OCP		0x3408
+#define NBL_DEVICE_ID_M18110_BASE_T_OCP		0x3409
+#define NBL_DEVICE_ID_M18110_LX_BASE_T_OCP	0x340a
+#define NBL_DEVICE_ID_M18000			0x340b
+#define NBL_DEVICE_ID_M18000_LX			0x340c
+#define NBL_DEVICE_ID_M18000_BASE_T		0x340d
+#define NBL_DEVICE_ID_M18000_LX_BASE_T		0x340e
+#define NBL_DEVICE_ID_M18000_OCP		0x340f
+#define NBL_DEVICE_ID_M18000_LX_OCP		0x3410
+#define NBL_DEVICE_ID_M18000_BASE_T_OCP		0x3411
+#define NBL_DEVICE_ID_M18000_LX_BASE_T_OCP	0x3412
+
+static const struct pci_device_id nbl_id_table[] = {
+	{ PCI_DEVICE(NBL_VENDOR_ID, NBL_DEVICE_ID_M18110),
+	  .driver_data = BIT(NBL_CAP_HAS_NET_BIT) | BIT(NBL_CAP_IS_NIC_BIT) |
+			 BIT(NBL_CAP_IS_LEONIS_BIT) },
+	{ PCI_DEVICE(NBL_VENDOR_ID, NBL_DEVICE_ID_M18110_LX),
+	  .driver_data = BIT(NBL_CAP_HAS_NET_BIT) | BIT(NBL_CAP_IS_NIC_BIT) |
+			 BIT(NBL_CAP_IS_LEONIS_BIT) },
+	{ PCI_DEVICE(NBL_VENDOR_ID, NBL_DEVICE_ID_M18110_BASE_T),
+	  .driver_data = BIT(NBL_CAP_HAS_NET_BIT) | BIT(NBL_CAP_IS_NIC_BIT) |
+			 BIT(NBL_CAP_IS_LEONIS_BIT) },
+	{ PCI_DEVICE(NBL_VENDOR_ID, NBL_DEVICE_ID_M18110_LX_BASE_T),
+	  .driver_data = BIT(NBL_CAP_HAS_NET_BIT) | BIT(NBL_CAP_IS_NIC_BIT) |
+			 BIT(NBL_CAP_IS_LEONIS_BIT) },
+	{ PCI_DEVICE(NBL_VENDOR_ID, NBL_DEVICE_ID_M18110_OCP),
+	  .driver_data = BIT(NBL_CAP_HAS_NET_BIT) | BIT(NBL_CAP_IS_NIC_BIT) |
+			 BIT(NBL_CAP_IS_LEONIS_BIT) },
+	{ PCI_DEVICE(NBL_VENDOR_ID, NBL_DEVICE_ID_M18110_LX_OCP),
+	  .driver_data = BIT(NBL_CAP_HAS_NET_BIT) | BIT(NBL_CAP_IS_NIC_BIT) |
+			 BIT(NBL_CAP_IS_LEONIS_BIT) },
+	{ PCI_DEVICE(NBL_VENDOR_ID, NBL_DEVICE_ID_M18110_BASE_T_OCP),
+	  .driver_data = BIT(NBL_CAP_HAS_NET_BIT) | BIT(NBL_CAP_IS_NIC_BIT) |
+			 BIT(NBL_CAP_IS_LEONIS_BIT) },
+	{ PCI_DEVICE(NBL_VENDOR_ID, NBL_DEVICE_ID_M18110_LX_BASE_T_OCP),
+	  .driver_data = BIT(NBL_CAP_HAS_NET_BIT) | BIT(NBL_CAP_IS_NIC_BIT) |
+			 BIT(NBL_CAP_IS_LEONIS_BIT) },
+	{ PCI_DEVICE(NBL_VENDOR_ID, NBL_DEVICE_ID_M18000),
+	  .driver_data = BIT(NBL_CAP_HAS_NET_BIT) | BIT(NBL_CAP_IS_NIC_BIT) |
+			 BIT(NBL_CAP_IS_LEONIS_BIT) },
+	{ PCI_DEVICE(NBL_VENDOR_ID, NBL_DEVICE_ID_M18000_LX),
+	  .driver_data = BIT(NBL_CAP_HAS_NET_BIT) | BIT(NBL_CAP_IS_NIC_BIT) |
+			 BIT(NBL_CAP_IS_LEONIS_BIT) },
+	{ PCI_DEVICE(NBL_VENDOR_ID, NBL_DEVICE_ID_M18000_BASE_T),
+	  .driver_data = BIT(NBL_CAP_HAS_NET_BIT) | BIT(NBL_CAP_IS_NIC_BIT) |
+			 BIT(NBL_CAP_IS_LEONIS_BIT) },
+	{ PCI_DEVICE(NBL_VENDOR_ID, NBL_DEVICE_ID_M18000_LX_BASE_T),
+	  .driver_data = BIT(NBL_CAP_HAS_NET_BIT) | BIT(NBL_CAP_IS_NIC_BIT) |
+			 BIT(NBL_CAP_IS_LEONIS_BIT) },
+	{ PCI_DEVICE(NBL_VENDOR_ID, NBL_DEVICE_ID_M18000_OCP),
+	  .driver_data = BIT(NBL_CAP_HAS_NET_BIT) | BIT(NBL_CAP_IS_NIC_BIT) |
+			 BIT(NBL_CAP_IS_LEONIS_BIT) },
+	{ PCI_DEVICE(NBL_VENDOR_ID, NBL_DEVICE_ID_M18000_LX_OCP),
+	  .driver_data = BIT(NBL_CAP_HAS_NET_BIT) | BIT(NBL_CAP_IS_NIC_BIT) |
+			 BIT(NBL_CAP_IS_LEONIS_BIT) },
+	{ PCI_DEVICE(NBL_VENDOR_ID, NBL_DEVICE_ID_M18000_BASE_T_OCP),
+	  .driver_data = BIT(NBL_CAP_HAS_NET_BIT) | BIT(NBL_CAP_IS_NIC_BIT) |
+			 BIT(NBL_CAP_IS_LEONIS_BIT) },
+	{ PCI_DEVICE(NBL_VENDOR_ID, NBL_DEVICE_ID_M18000_LX_BASE_T_OCP),
+	  .driver_data = BIT(NBL_CAP_HAS_NET_BIT) | BIT(NBL_CAP_IS_NIC_BIT) |
+			 BIT(NBL_CAP_IS_LEONIS_BIT) },
+	/* required as sentinel */
+	{
+		0,
+	}
+};
+MODULE_DEVICE_TABLE(pci, nbl_id_table);
+
+static struct pci_driver nbl_driver = {
+	.name = NBL_DRIVER_NAME,
+	.id_table = nbl_id_table,
+	.probe = nbl_probe,
+	.remove = nbl_remove,
+};
+
+module_pci_driver(nbl_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Nebula Matrix Network Driver");
-- 
2.47.3


^ permalink raw reply related

* [PATCH v15 net-next 05/11] net/nebula-matrix: add channel layer
From: illusion.wang @ 2026-05-20  3:29 UTC (permalink / raw)
  To: dimon.zhao, illusion.wang, alvin.wang, sam.chen, netdev
  Cc: andrew+netdev, corbet, kuba, horms, linux-doc, pabeni,
	vadim.fedorenko, lukas.bulwahn, edumazet, enelsonmoore, skhan,
	hkallweit1, open list
In-Reply-To: <20260520032950.4874-1-illusion.wang@nebula-matrix.com>

A channel management layer provides a structured approach to handle
communication between different components and drivers. Here's a summary
of its key functionalities:

1. Message Handling Framework
   Message Registration: Functions (nbl_chan_register_msg) allow dynamic
   registration of message handlers for specific message types, enabling
   extensible communication protocols.

   Message Sending/Acknowledgment: Core functions (nbl_chan_send_msg,
   nbl_chan_send_ack) handle message transmission, including asynchronous
   operations with acknowledgment (ACK) support. Received ACKs are
   processed via nbl_chan_recv_ack_msg.

   Hash-Based Handler Lookup: A hash table (`handle_hash_tbl`) stores
   message handlers for efficient O(1) lookup by message type. The
   entire table is removed via `nbl_chan_remove_msg_handler` during
   driver teardown (per-message-type removal is not implemented
   in this version).

2. Channel Types and Queue Management
   Mailbox Channel: For direct communication between PF0 and Other PF.

   Queue Initialization: Functions (nbl_chan_init_queue,
   nbl_chan_init_tx_queue) allocate resources:
   - TX descriptors: dmam_alloc_coherent()
   - RX descriptors and metadata: devm_kcalloc()

   Queue Teardown: nbl_chan_teardown_queue() stops queues but does NOT
   free DMA memory or cancel pending work items.

   IMPORTANT - Resource Lifecycle Design:
   DMA memory allocated with dmam_alloc_coherent() is intentionally NOT
   freed in nbl_chan_teardown_queue(). The queues are allocated once
   during driver probe and freed only during driver remove (when all
   devm_ resources are released). This assumes queues are NOT dynamically
   torn down and recreated per-PF during normal operation.

   Queue Configuration: Hardware-specific queue parameters (e.g., buffer
   sizes, entry counts) are set via nbl_chan_config_queue, with hardware
   interactions delegated to hw_ops.

3. Hardware Abstraction Layer (HW Ops)
   Hardware-Specific Operations: The nbl_hw_ops structure abstracts
   hardware interactions: queue configuration (config_mailbox_txq/rxq),
   tail pointer updates (update_mailbox_queue_tail_ptr).

Signed-off-by: illusion.wang <illusion.wang@nebula-matrix.com>
---
 .../net/ethernet/nebula-matrix/nbl/Makefile   |   3 +-
 .../nbl/nbl_channel/nbl_channel.c             | 874 +++++++++++++++++-
 .../nbl/nbl_channel/nbl_channel.h             | 144 +++
 .../nebula-matrix/nbl/nbl_common/nbl_common.c | 180 ++++
 .../nebula-matrix/nbl/nbl_common/nbl_common.h |  33 +
 .../nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c  | 151 +++
 .../nebula-matrix/nbl/nbl_hw/nbl_hw_reg.h     |   1 +
 .../nbl/nbl_include/nbl_def_channel.h         |  84 ++
 .../nbl/nbl_include/nbl_def_common.h          |  26 +
 .../nbl/nbl_include/nbl_def_hw.h              |  28 +
 .../nbl/nbl_include/nbl_include.h             |   6 +
 11 files changed, 1526 insertions(+), 4 deletions(-)
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_common/nbl_common.c
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_common/nbl_common.h

diff --git a/drivers/net/ethernet/nebula-matrix/nbl/Makefile b/drivers/net/ethernet/nebula-matrix/nbl/Makefile
index 63116d1d7043..c9bc060732e7 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/Makefile
+++ b/drivers/net/ethernet/nebula-matrix/nbl/Makefile
@@ -3,7 +3,8 @@
 
 obj-$(CONFIG_NBL) := nbl.o
 
-nbl-objs +=       nbl_channel/nbl_channel.o \
+nbl-objs +=       nbl_common/nbl_common.o \
+				nbl_channel/nbl_channel.o \
 				nbl_hw/nbl_hw_leonis/nbl_hw_leonis.o \
 				nbl_hw/nbl_hw_leonis/nbl_resource_leonis.o \
 				nbl_hw/nbl_hw_leonis/nbl_hw_leonis_regs.o \
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_channel/nbl_channel.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_channel/nbl_channel.c
index c7689f0e4029..971f499189a4 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_channel/nbl_channel.c
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_channel/nbl_channel.c
@@ -2,12 +2,851 @@
 /*
  * Copyright (c) 2025 Nebula Matrix Limited.
  */
-
+#include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/pci.h>
+#include <linux/bits.h>
+#include <linux/dma-mapping.h>
 #include "nbl_channel.h"
 
+static int nbl_chan_add_msg_handler(struct nbl_channel_mgt *chan_mgt,
+				    u16 msg_type, nbl_chan_resp func,
+				    void *priv)
+{
+	struct nbl_chan_msg_node_data handler = { 0 };
+	int ret;
+
+	handler.func = func;
+	handler.priv = priv;
+	ret = nbl_common_alloc_hash_node(chan_mgt->handle_hash_tbl, &msg_type,
+					 &handler, NULL);
+
+	return ret;
+}
+
+static int nbl_chan_init_msg_handler(struct nbl_channel_mgt *chan_mgt)
+{
+	struct nbl_common_info *common = chan_mgt->common;
+	struct nbl_hash_tbl_key tbl_key;
+
+	tbl_key.dev = common->dev;
+	tbl_key.key_size = sizeof(u16);
+	tbl_key.data_size = sizeof(struct nbl_chan_msg_node_data);
+	tbl_key.bucket_size = NBL_CHAN_HANDLER_TBL_BUCKET_SIZE;
+
+	chan_mgt->handle_hash_tbl = nbl_common_init_hash_table(&tbl_key);
+	if (!chan_mgt->handle_hash_tbl)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void nbl_chan_remove_msg_handler(struct nbl_channel_mgt *chan_mgt)
+{
+	nbl_common_remove_hash_table(chan_mgt->handle_hash_tbl, NULL);
+
+	chan_mgt->handle_hash_tbl = NULL;
+}
+
+static void nbl_chan_init_queue_param(struct nbl_chan_info *chan_info,
+				      u16 num_txq_entries, u16 num_rxq_entries,
+				      u16 txq_buf_size, u16 rxq_buf_size)
+{
+	mutex_init(&chan_info->txq_lock);
+	mutex_init(&chan_info->rxq_lock);
+	chan_info->num_txq_entries = num_txq_entries;
+	chan_info->num_rxq_entries = num_rxq_entries;
+	chan_info->txq_buf_size = txq_buf_size;
+	chan_info->rxq_buf_size = rxq_buf_size;
+}
+
+static int nbl_chan_init_tx_queue(struct nbl_common_info *common,
+				  struct nbl_chan_info *chan_info)
+{
+	struct nbl_chan_ring *txq = &chan_info->txq;
+	struct device *dev = common->dev;
+	size_t size =
+		chan_info->num_txq_entries * sizeof(struct nbl_chan_tx_desc);
+	int i;
+
+	txq->desc.tx_desc = dmam_alloc_coherent(dev, size, &txq->dma,
+						GFP_KERNEL);
+	if (!txq->desc.tx_desc)
+		return -ENOMEM;
+
+	chan_info->wait = devm_kcalloc(dev, chan_info->num_txq_entries,
+				       sizeof(*chan_info->wait),
+				       GFP_KERNEL);
+	if (!chan_info->wait)
+		return -ENOMEM;
+	for (i = 0; i < chan_info->num_txq_entries; i++) {
+		init_waitqueue_head(&chan_info->wait[i].wait_queue);
+		atomic_set(&chan_info->wait[i].status, NBL_MBX_STATUS_IDLE);
+	}
+
+	txq->buf = devm_kcalloc(dev, chan_info->num_txq_entries,
+				sizeof(*txq->buf), GFP_KERNEL);
+	if (!txq->buf)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int nbl_chan_init_rx_queue(struct nbl_common_info *common,
+				  struct nbl_chan_info *chan_info)
+{
+	struct nbl_chan_ring *rxq = &chan_info->rxq;
+	struct device *dev = common->dev;
+	size_t size =
+		chan_info->num_rxq_entries * sizeof(struct nbl_chan_rx_desc);
+
+	rxq->desc.rx_desc = dmam_alloc_coherent(dev, size, &rxq->dma,
+						GFP_KERNEL);
+	if (!rxq->desc.rx_desc) {
+		dev_err(dev,
+			"Allocate DMA for chan rx descriptor ring failed\n");
+		return -ENOMEM;
+	}
+
+	rxq->buf = devm_kcalloc(dev, chan_info->num_rxq_entries,
+				sizeof(*rxq->buf), GFP_KERNEL);
+	if (!rxq->buf)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int nbl_chan_init_queue(struct nbl_common_info *common,
+			       struct nbl_chan_info *chan_info)
+{
+	int err;
+
+	err = nbl_chan_init_tx_queue(common, chan_info);
+	if (err)
+		return err;
+
+	err = nbl_chan_init_rx_queue(common, chan_info);
+
+	return err;
+}
+
+static void nbl_chan_config_queue(struct nbl_channel_mgt *chan_mgt,
+				  struct nbl_chan_info *chan_info, bool tx)
+{
+	struct nbl_hw_ops *hw_ops = chan_mgt->hw_ops_tbl->ops;
+	struct nbl_hw_mgt *p = chan_mgt->hw_ops_tbl->priv;
+	int size_bwid;
+	struct nbl_chan_ring *ring;
+	dma_addr_t dma_addr;
+
+	if (tx)
+		ring = &chan_info->txq;
+	else
+		ring = &chan_info->rxq;
+	dma_addr = ring->dma;
+	if (tx) {
+		size_bwid = ilog2(chan_info->num_txq_entries);
+		hw_ops->config_mailbox_txq(p, dma_addr, size_bwid);
+	} else {
+		size_bwid = ilog2(chan_info->num_rxq_entries);
+		hw_ops->config_mailbox_rxq(p, dma_addr, size_bwid);
+	}
+}
+
+static int nbl_chan_alloc_all_tx_bufs(struct nbl_channel_mgt *chan_mgt,
+				      struct nbl_chan_info *chan_info)
+{
+	struct nbl_chan_ring *txq = &chan_info->txq;
+	struct device *dev = chan_mgt->common->dev;
+	struct nbl_chan_buf *buf;
+	u16 i;
+
+	for (i = 0; i < chan_info->num_txq_entries; i++) {
+		buf = &txq->buf[i];
+		buf->va = dmam_alloc_coherent(dev, chan_info->txq_buf_size,
+					      &buf->pa,
+					      GFP_KERNEL);
+		if (!buf->va) {
+			dev_err(dev,
+				"Allocate buffer for chan tx queue failed\n");
+			return -ENOMEM;
+		}
+	}
+
+	txq->next_to_clean = 0;
+	txq->next_to_use = 0;
+	txq->tail_ptr = 0;
+
+	return 0;
+}
+
+static void nbl_chan_cfg_qinfo_map_table(struct nbl_channel_mgt *chan_mgt)
+{
+	struct nbl_hw_ops *hw_ops = chan_mgt->hw_ops_tbl->ops;
+	struct nbl_common_info *common = chan_mgt->common;
+	struct nbl_hw_mgt *p = chan_mgt->hw_ops_tbl->priv;
+	u8 func_id;
+	u32 pf_mask;
+
+	pf_mask = hw_ops->get_host_pf_mask(p);
+	for (func_id = 0; func_id < NBL_MAX_PF; func_id++) {
+		if (!(pf_mask & (1 << func_id)))
+			hw_ops->cfg_mailbox_qinfo(p, func_id, common->hw_bus,
+						  common->devid,
+						  common->function + func_id);
+	}
+}
+
+#define NBL_UPDATE_QUEUE_TAIL_PTR(chan_info, hw_ops, chan_mgt, tail_ptr, qid)\
+do {									\
+	(void)(chan_info);						\
+	typeof(hw_ops) _hw_ops = (hw_ops);				\
+	typeof(chan_mgt) _chan_mgt = (chan_mgt);			\
+	typeof(tail_ptr) _tail_ptr = (tail_ptr);			\
+	typeof(qid) _qid = (qid);					\
+	(_hw_ops)->update_mailbox_queue_tail_ptr(			\
+		_chan_mgt->hw_ops_tbl->priv, _tail_ptr, _qid);	\
+} while (0)
+
+static int nbl_chan_alloc_all_rx_bufs(struct nbl_channel_mgt *chan_mgt,
+				      struct nbl_chan_info *chan_info)
+{
+	struct nbl_hw_ops *hw_ops = chan_mgt->hw_ops_tbl->ops;
+	struct nbl_chan_ring *rxq = &chan_info->rxq;
+	struct device *dev = chan_mgt->common->dev;
+	struct nbl_chan_rx_desc *desc;
+	struct nbl_chan_buf *buf;
+	u16 i;
+
+	for (i = 0; i < chan_info->num_rxq_entries; i++) {
+		buf = &rxq->buf[i];
+		buf->va = dmam_alloc_coherent(dev, chan_info->rxq_buf_size,
+					      &buf->pa,
+					      GFP_KERNEL);
+		if (!buf->va) {
+			dev_err(dev,
+				"Allocate buffer for chan rx queue failed\n");
+			goto err;
+		}
+	}
+
+	desc = rxq->desc.rx_desc;
+	for (i = 0; i < chan_info->num_rxq_entries - 1; i++) {
+		buf = &rxq->buf[i];
+		desc[i].buf_addr = cpu_to_le64(buf->pa);
+		desc[i].buf_len = cpu_to_le32(chan_info->rxq_buf_size);
+		desc[i].flags = cpu_to_le16(BIT(NBL_CHAN_RX_DESC_AVAIL));
+	}
+
+	rxq->next_to_clean = 0;
+	rxq->next_to_use = chan_info->num_rxq_entries - 1;
+	rxq->tail_ptr = chan_info->num_rxq_entries - 1;
+
+	NBL_UPDATE_QUEUE_TAIL_PTR(chan_info, hw_ops, chan_mgt, rxq->tail_ptr,
+				  NBL_MB_RX_QID);
+
+	return 0;
+err:
+	return -ENOMEM;
+}
+
+static int nbl_chan_alloc_all_bufs(struct nbl_channel_mgt *chan_mgt,
+				   struct nbl_chan_info *chan_info)
+{
+	int err;
+
+	err = nbl_chan_alloc_all_tx_bufs(chan_mgt, chan_info);
+	if (err)
+		return err;
+	err = nbl_chan_alloc_all_rx_bufs(chan_mgt, chan_info);
+
+	return err;
+}
+
+static void nbl_chan_stop_queue(struct nbl_channel_mgt *chan_mgt)
+{
+	struct nbl_hw_ops *hw_ops = chan_mgt->hw_ops_tbl->ops;
+
+	hw_ops->stop_mailbox_rxq(chan_mgt->hw_ops_tbl->priv);
+	hw_ops->stop_mailbox_txq(chan_mgt->hw_ops_tbl->priv);
+}
+
+static int nbl_chan_teardown_queue(struct nbl_channel_mgt *chan_mgt,
+				   u8 chan_type)
+{
+	struct nbl_chan_info *chan_info = chan_mgt->chan_info[chan_type];
+
+	if (chan_info->clean_task)
+		cancel_work_sync(chan_info->clean_task);
+	nbl_chan_stop_queue(chan_mgt);
+	mutex_destroy(&chan_info->txq_lock);
+	mutex_destroy(&chan_info->rxq_lock);
+
+	return 0;
+}
+
+static int nbl_chan_setup_queue(struct nbl_channel_mgt *chan_mgt, u8 chan_type)
+{
+	struct nbl_chan_info *chan_info = chan_mgt->chan_info[chan_type];
+	struct nbl_common_info *common = chan_mgt->common;
+	int err;
+
+	nbl_chan_init_queue_param(chan_info, NBL_CHAN_QUEUE_LEN,
+				  NBL_CHAN_QUEUE_LEN, NBL_CHAN_BUF_LEN,
+				  NBL_CHAN_BUF_LEN);
+	err = nbl_chan_init_queue(common, chan_info);
+	if (err)
+		return err;
+
+	nbl_chan_config_queue(chan_mgt, chan_info, true); /* tx */
+	nbl_chan_config_queue(chan_mgt, chan_info, false); /* rx */
+
+	err = nbl_chan_alloc_all_bufs(chan_mgt, chan_info);
+	if (err)
+		goto chan_q_setup_fail;
+
+	return 0;
+
+chan_q_setup_fail:
+	nbl_chan_teardown_queue(chan_mgt, chan_type);
+	return err;
+}
+
+static int nbl_chan_update_txqueue(struct nbl_channel_mgt *chan_mgt,
+				   struct nbl_chan_info *chan_info,
+				   struct nbl_chan_tx_param *param)
+{
+	struct nbl_chan_ring *txq = &chan_info->txq;
+	struct nbl_chan_tx_desc *tx_desc =
+		NBL_CHAN_TX_RING_TO_DESC(txq, txq->next_to_use);
+	struct nbl_chan_buf *tx_buf =
+		NBL_CHAN_TX_RING_TO_BUF(txq, txq->next_to_use);
+
+	if (param->arg_len > NBL_CHAN_BUF_LEN - sizeof(*tx_desc))
+		return -EINVAL;
+
+	tx_desc->dstid = cpu_to_le16(param->dstid);
+	tx_desc->msg_type = cpu_to_le16(param->msg_type);
+	tx_desc->msgid = cpu_to_le16(param->msgid);
+
+	if (param->arg_len > NBL_CHAN_TX_DESC_EMBEDDED_DATA_LEN) {
+		memcpy(tx_buf->va, param->arg, param->arg_len);
+		tx_desc->buf_addr = cpu_to_le64(tx_buf->pa);
+		tx_desc->buf_len = cpu_to_le16(param->arg_len);
+		tx_desc->data_len = 0;
+	} else {
+		memcpy(tx_desc->data, param->arg, param->arg_len);
+		tx_desc->buf_len = 0;
+		tx_desc->data_len = cpu_to_le16(param->arg_len);
+	}
+	/* Ensure desc body is visible to DMA before writing AVAIL flag */
+	dma_wmb();
+	tx_desc->flags = cpu_to_le16(BIT(NBL_CHAN_TX_DESC_AVAIL));
+
+	txq->next_to_use =
+		NBL_NEXT_ID(txq->next_to_use, chan_info->num_txq_entries - 1);
+	txq->tail_ptr++;
+
+	return 0;
+}
+
+static int nbl_chan_kick_tx_ring(struct nbl_channel_mgt *chan_mgt,
+				 struct nbl_chan_info *chan_info)
+{
+	struct nbl_hw_ops *hw_ops = chan_mgt->hw_ops_tbl->ops;
+	struct nbl_chan_ring *txq = &chan_info->txq;
+	struct device *dev = chan_mgt->common->dev;
+	int max_retries = NBL_CHAN_TX_WAIT_TIMES;
+	struct nbl_chan_tx_desc *tx_desc;
+	int retry_count = 0;
+
+	NBL_UPDATE_QUEUE_TAIL_PTR(chan_info, hw_ops, chan_mgt, txq->tail_ptr,
+				  NBL_MB_TX_QID);
+
+	tx_desc = NBL_CHAN_TX_RING_TO_DESC(txq, txq->next_to_clean);
+	while (retry_count < max_retries) {
+		if (le16_to_cpu(READ_ONCE(tx_desc->flags)) &
+		    BIT(NBL_CHAN_TX_DESC_USED)) {
+			dma_rmb();
+			break;
+		}
+
+		if (!(retry_count % NBL_CHAN_TX_REKICK_WAIT_TIMES))
+			NBL_UPDATE_QUEUE_TAIL_PTR(chan_info, hw_ops, chan_mgt,
+						  txq->tail_ptr, NBL_MB_TX_QID);
+		retry_count++;
+
+		usleep_range(NBL_CHAN_TX_WAIT_US, NBL_CHAN_TX_WAIT_US_MAX);
+	}
+
+	txq->next_to_clean = txq->next_to_use;
+	if (retry_count >= max_retries) {
+		dev_err(dev, "chan send message type: %d timeout\n",
+			le16_to_cpu(READ_ONCE(tx_desc->msg_type)));
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static void nbl_chan_recv_ack_msg(void *priv, u16 srcid, u16 msgid, void *data,
+				  u32 data_len)
+{
+	struct nbl_channel_mgt *chan_mgt = (struct nbl_channel_mgt *)priv;
+	struct nbl_chan_waitqueue_head *wait_head = NULL;
+	union nbl_chan_msg_id ack_msgid = { { 0 } };
+	struct device *dev = chan_mgt->common->dev;
+	struct nbl_chan_info *chan_info =
+		chan_mgt->chan_info[NBL_CHAN_TYPE_MAILBOX];
+	u32 *payload = data;
+	u32 ack_datalen, ack_msgtype = 0;
+	u32 copy_len;
+
+	if (data_len > NBL_CHAN_BUF_LEN ||
+	    data_len < NBL_CHAN_ACK_HEAD_LEN * sizeof(u32)) {
+		dev_err(dev, "Invalid ACK data_len: %u\n", data_len);
+		return;
+	}
+	ack_datalen = data_len - NBL_CHAN_ACK_HEAD_LEN * sizeof(u32);
+	ack_msgtype = le16_to_cpu(*(__le16 *)(payload + NBL_CHAN_MSG_TYPE_POS));
+	ack_msgid.id = le16_to_cpu(*(__le16 *)(payload + NBL_CHAN_MSG_ID_POS));
+	if (ack_msgid.info.loc >= NBL_CHAN_QUEUE_LEN) {
+		dev_err(dev, "chan recv msg loc: %d err\n", ack_msgid.info.loc);
+		return;
+	}
+	wait_head = &chan_info->wait[ack_msgid.info.loc];
+	if (wait_head->msg_type != ack_msgtype) {
+		dev_err(dev, "Skip ack msg type donot match, wait_head msgtype:%u msg_index:%u status:%d ack_data_len:%d, ack msgtype:%u msgid:%u datalen:%d\n",
+			wait_head->msg_type, wait_head->msg_index,
+			atomic_read(&wait_head->status),
+			wait_head->ack_data_len, ack_msgtype,
+			ack_msgid.id, ack_datalen);
+		return;
+	}
+	if (ack_msgid.info.index != wait_head->msg_index) {
+		dev_err(dev, "Stale ACK: expected index=%u, got %u for loc=%u\n",
+			wait_head->msg_index, ack_msgid.info.index,
+			ack_msgid.info.loc);
+		return;
+	}
+
+	wait_head->ack_err = *(payload + NBL_CHAN_ACK_RET_POS);
+
+	if (atomic_cmpxchg(&wait_head->status, NBL_MBX_STATUS_WAITING,
+			   NBL_MBX_STATUS_ACKD) != NBL_MBX_STATUS_WAITING) {
+		dev_err(dev, "Skip ack with invalid status, wait_head msgtype:%u msg_index:%u status:%d ack_data_len:%d, ack msgtype:%u msgid:%u datalen:%d\n",
+			wait_head->msg_type, wait_head->msg_index,
+			atomic_read(&wait_head->status),
+			wait_head->ack_data_len, ack_msgtype,
+			ack_msgid.id, ack_datalen);
+		return;
+	}
+
+	copy_len = min_t(u32, wait_head->ack_data_len, ack_datalen);
+	if (wait_head->ack_err >= 0 && copy_len > 0) {
+		if (NBL_CHAN_ACK_HEAD_LEN * sizeof(u32) + copy_len > data_len) {
+			dev_err(dev, "ACK payload overflow\n");
+			return;
+		}
+		memcpy((char *)wait_head->ack_data,
+		       payload + NBL_CHAN_ACK_HEAD_LEN, copy_len);
+		wait_head->ack_data_len = (u16)copy_len;
+	} else {
+		wait_head->ack_data_len = 0;
+	}
+
+	/*
+	 * Ensure all writes to ack_data and ack_data_len are completed
+	 * before setting the 'acked' flag. This prevents other threads
+	 * from observing stale or partially updated data.
+	 */
+	wmb();
+	wait_head->acked = 1;
+	if (wait_head->need_waked)
+		wake_up(&wait_head->wait_queue);
+}
+
+static void nbl_chan_recv_msg(struct nbl_channel_mgt *chan_mgt, void *data)
+{
+	struct device *dev = chan_mgt->common->dev;
+	struct nbl_chan_msg_node_data *msg_handler;
+	u16 msg_type, payload_len, srcid, msgid;
+	struct nbl_chan_tx_desc *tx_desc;
+	void *payload;
+
+	tx_desc = data;
+	msg_type = le16_to_cpu(tx_desc->msg_type);
+	dev_dbg(dev, "recv msg_type: %d\n", msg_type);
+
+	srcid = le16_to_cpu(tx_desc->srcid);
+	msgid = le16_to_cpu(tx_desc->msgid);
+	/* Only check if the value exceeds the maximum, relying on the hash
+	 * table to filter invalid message IDs.
+	 * The gap values are reserved for future protocol extensions.
+	 */
+	if (msg_type >= NBL_CHAN_MSG_MAILBOX_MAX)
+		return;
+
+	if (tx_desc->data_len) {
+		payload_len = le16_to_cpu(tx_desc->data_len);
+		if (payload_len > NBL_CHAN_TX_DESC_EMBEDDED_DATA_LEN) {
+			dev_err(dev, "data_len=%u exceeds embedded buffer size=%u\n",
+				payload_len,
+				NBL_CHAN_TX_DESC_EMBEDDED_DATA_LEN);
+			return;
+		}
+		payload = tx_desc->data;
+	} else {
+		payload_len = le16_to_cpu(tx_desc->buf_len);
+		if (payload_len > NBL_CHAN_BUF_LEN - sizeof(*tx_desc)) {
+			dev_err(dev, "buf_len=%u exceeds external buffer size=%lu\n",
+				payload_len,
+				NBL_CHAN_BUF_LEN - sizeof(*tx_desc));
+			return;
+		}
+		payload = tx_desc + 1;
+	}
+
+	msg_handler =
+		nbl_common_get_hash_node(chan_mgt->handle_hash_tbl, &msg_type);
+	if (!msg_handler || !msg_handler->func) {
+		dev_err(dev, "No handler for msg_type: %u (srcid=%u, msgid=%u)\n",
+			msg_type, srcid, msgid);
+		return;
+	}
+	msg_handler->func(msg_handler->priv, srcid, msgid, payload,
+			  payload_len);
+}
+
+static void nbl_chan_advance_rx_ring(struct nbl_channel_mgt *chan_mgt,
+				     struct nbl_chan_info *chan_info,
+				     struct nbl_chan_ring *rxq)
+{
+	struct nbl_hw_ops *hw_ops = chan_mgt->hw_ops_tbl->ops;
+	struct nbl_chan_rx_desc *rx_desc;
+	struct nbl_chan_buf *rx_buf;
+	u16 next_to_use;
+
+	next_to_use = rxq->next_to_use;
+	rx_desc = NBL_CHAN_RX_RING_TO_DESC(rxq, next_to_use);
+	rx_buf = NBL_CHAN_RX_RING_TO_BUF(rxq, next_to_use);
+
+	rx_desc->buf_addr = cpu_to_le64(rx_buf->pa);
+	rx_desc->buf_len = cpu_to_le32(chan_info->rxq_buf_size);
+
+	/*
+	 * DMA Write Memory Barrier:
+	 * Ensures all previous DMA-mapped writes (buffer address/length)
+	 * are completed before the descriptor flags are updated.
+	 * This prevents hardware from seeing a partially updated descriptor
+	 * where flags are set but buffer info isn't ready yet.
+	 */
+	dma_wmb();
+
+	rx_desc->flags = cpu_to_le16(BIT(NBL_CHAN_RX_DESC_AVAIL));
+
+	/*
+	 * CPU Write Memory Barrier:
+	 * Ensures the descriptor flags update is visible to other CPUs
+	 * before we update the tail pointer. This is important for:
+	 * 1. Software cleaning threads that might be checking the tail pointer
+	 * 2. Maintaining proper memory ordering in multi-core systems
+	 */
+	wmb();
+	rxq->next_to_use++;
+	if (rxq->next_to_use == chan_info->num_rxq_entries)
+		rxq->next_to_use = 0;
+	rxq->tail_ptr++;
+
+	NBL_UPDATE_QUEUE_TAIL_PTR(chan_info, hw_ops, chan_mgt, rxq->tail_ptr,
+				  NBL_MB_RX_QID);
+}
+
+static void nbl_chan_clean_queue(struct nbl_channel_mgt *chan_mgt,
+				 struct nbl_chan_info *chan_info)
+{
+	struct nbl_chan_ring *rxq = &chan_info->rxq;
+	struct device *dev = chan_mgt->common->dev;
+	struct nbl_chan_rx_desc *rx_desc;
+	struct nbl_chan_buf *rx_buf;
+	u16 next_to_clean;
+
+	mutex_lock(&chan_info->rxq_lock);
+	next_to_clean = rxq->next_to_clean;
+	rx_desc = NBL_CHAN_RX_RING_TO_DESC(rxq, next_to_clean);
+	rx_buf = NBL_CHAN_RX_RING_TO_BUF(rxq, next_to_clean);
+	while (le16_to_cpu(rx_desc->flags) & BIT(NBL_CHAN_RX_DESC_USED)) {
+		if (!(le16_to_cpu(rx_desc->flags) &
+		    BIT(NBL_CHAN_RX_DESC_WRITE)))
+			dev_dbg(dev,
+				"mailbox rx flag 0x%x has no NBL_CHAN_RX_DESC_WRITE\n",
+				le16_to_cpu(rx_desc->flags));
+
+		dma_rmb();
+		nbl_chan_recv_msg(chan_mgt, rx_buf->va);
+		nbl_chan_advance_rx_ring(chan_mgt, chan_info, rxq);
+		next_to_clean++;
+		if (next_to_clean == chan_info->num_rxq_entries)
+			next_to_clean = 0;
+		rx_desc = NBL_CHAN_RX_RING_TO_DESC(rxq, next_to_clean);
+		rx_buf = NBL_CHAN_RX_RING_TO_BUF(rxq, next_to_clean);
+	}
+	rxq->next_to_clean = next_to_clean;
+	mutex_unlock(&chan_info->rxq_lock);
+}
+
+static void nbl_chan_clean_queue_subtask(struct nbl_channel_mgt *chan_mgt,
+					 u8 chan_type)
+{
+	struct nbl_chan_info *chan_info = chan_mgt->chan_info[chan_type];
+
+	if (!test_bit(NBL_CHAN_INTERRUPT_READY, chan_info->state) ||
+	    test_bit(NBL_CHAN_RESETTING, chan_info->state))
+		return;
+
+	nbl_chan_clean_queue(chan_mgt, chan_info);
+}
+
+static int nbl_chan_get_msg_id(struct nbl_chan_info *chan_info,
+			       union nbl_chan_msg_id *msgid)
+{
+	int valid_loc = chan_info->wait_head_index, i;
+	struct nbl_chan_waitqueue_head *wait = NULL;
+	int status;
+
+	for (i = 0; i < NBL_CHAN_QUEUE_LEN; i++) {
+		wait = &chan_info->wait[valid_loc];
+		status = atomic_read(&wait->status);
+		if (status == NBL_MBX_STATUS_IDLE ||
+		    status == NBL_MBX_STATUS_TIMEOUT) {
+			wait->msg_index = NBL_NEXT_ID(wait->msg_index,
+						      NBL_CHAN_MSG_INDEX_MAX);
+			msgid->info.index = wait->msg_index;
+			msgid->info.loc = valid_loc;
+			valid_loc = NBL_NEXT_ID(valid_loc,
+						chan_info->num_txq_entries - 1);
+			chan_info->wait_head_index = valid_loc;
+			return 0;
+		}
+
+		valid_loc =
+			NBL_NEXT_ID(valid_loc, chan_info->num_txq_entries - 1);
+	}
+
+	/*
+	 * the current NBL_CHAN_QUEUE_LEN configuration meets the design
+	 * requirements and theoretically should not return errors, the
+	 * following scenarios may still cause the waiting queue to
+	 * become full:
+	 * High-concurrency scenarios:
+	 * If the sender (calling nbl_chan_send_msg()) generates messages
+	 * at a rate far exceeding the receiver's ability to process
+	 * acknowledgments (ACKs),the waiting queue may become fully occupied.
+	 * Delayed or failed ACK handling by the receiver:
+	 * The receiver may fail to send ACKs in a timely manner due to
+	 * processing delays, blocking, or faults, causing the sender's
+	 * waiting queue slots to remain occupied for an extended period.
+	 */
+	return -EAGAIN;
+}
+
+static int nbl_chan_send_msg(struct nbl_channel_mgt *chan_mgt,
+			     struct nbl_chan_send_info *chan_send)
+{
+	struct nbl_common_info *common = chan_mgt->common;
+	struct nbl_chan_waitqueue_head *wait_head;
+	struct nbl_chan_tx_param tx_param = { 0 };
+	union nbl_chan_msg_id msgid = { { 0 } };
+	int i = NBL_CHAN_TX_WAIT_ACK_TIMES, ret;
+	struct nbl_chan_info *chan_info =
+		chan_mgt->chan_info[NBL_CHAN_TYPE_MAILBOX];
+	struct device *dev = common->dev;
+
+	if (test_bit(NBL_CHAN_ABNORMAL, chan_info->state))
+		return -EIO;
+
+	mutex_lock(&chan_info->txq_lock);
+
+	ret = nbl_chan_get_msg_id(chan_info, &msgid);
+	if (ret) {
+		mutex_unlock(&chan_info->txq_lock);
+		dev_err(dev,
+			"Channel tx wait head full, send msgtype:%u to dstid:%u failed\n",
+			chan_send->msg_type, chan_send->dstid);
+		return ret;
+	}
+
+	tx_param.msg_type = chan_send->msg_type;
+	tx_param.arg = chan_send->arg;
+	tx_param.arg_len = chan_send->arg_len;
+	tx_param.dstid = chan_send->dstid;
+	tx_param.msgid = msgid.id;
+
+	ret = nbl_chan_update_txqueue(chan_mgt, chan_info, &tx_param);
+	if (ret) {
+		mutex_unlock(&chan_info->txq_lock);
+		dev_err(dev,
+			"Channel tx queue full, send msgtype:%u to dstid:%u failed\n",
+			chan_send->msg_type, chan_send->dstid);
+		return ret;
+	}
+
+	wait_head = &chan_info->wait[msgid.info.loc];
+	wait_head->acked = 0;
+	wait_head->ack_data = chan_send->resp;
+	wait_head->ack_data_len = chan_send->resp_len;
+	wait_head->msg_type = chan_send->msg_type;
+	wait_head->need_waked = chan_send->ack;
+	wait_head->msg_index = msgid.info.index;
+	atomic_set(&wait_head->status, chan_send->ack ? NBL_MBX_STATUS_WAITING :
+		   NBL_MBX_STATUS_IDLE);
+
+	ret = nbl_chan_kick_tx_ring(chan_mgt, chan_info);
+	mutex_unlock(&chan_info->txq_lock);
+	if (ret) {
+		mutex_lock(&chan_info->txq_lock);
+		atomic_set(&wait_head->status, NBL_MBX_STATUS_TIMEOUT);
+		mutex_unlock(&chan_info->txq_lock);
+		return ret;
+	}
+
+	if (!chan_send->ack)
+		return 0;
+
+	if (test_bit(NBL_CHAN_INTERRUPT_READY, chan_info->state)) {
+wait_again:
+		ret = wait_event_timeout(wait_head->wait_queue,
+					 wait_head->acked,
+					 NBL_CHAN_ACK_WAIT_TIME);
+		if (!ret) {
+			if (atomic_cmpxchg(&wait_head->status,
+					   NBL_MBX_STATUS_WAITING,
+					   NBL_MBX_STATUS_TIMEOUT)
+					   != NBL_MBX_STATUS_WAITING)
+				goto wait_again;
+
+			dev_err(dev,
+				"Channel waiting ack failed, message type: %d, msg id: %u\n",
+				chan_send->msg_type, msgid.id);
+			wait_head->acked = 0;
+			ret = -ETIMEDOUT;
+		} else {
+			/*
+			 * ensure that after observing 'acked == 1', all
+			 * subsequent reads (ack_data_len, ack_err) observe
+			 * the latest values written by the sender
+			 * (nbl_chan_recv_ack_msg()). This prevents stale reads
+			 * of ACK data or status.
+			 */
+			rmb();
+			chan_send->ack_len = wait_head->ack_data_len;
+			atomic_set(&wait_head->status, NBL_MBX_STATUS_IDLE);
+			ret = READ_ONCE(wait_head->ack_err);
+		}
+		return ret;
+	}
+
+	/*polling wait mailbox ack*/
+
+	while (i--) {
+		nbl_chan_clean_queue(chan_mgt, chan_info);
+
+		if (wait_head->acked) {
+			chan_send->ack_len = wait_head->ack_data_len;
+			atomic_set(&wait_head->status, NBL_MBX_STATUS_IDLE);
+			ret = READ_ONCE(wait_head->ack_err);
+			return ret;
+		}
+		usleep_range(NBL_CHAN_TX_WAIT_ACK_US_MIN,
+			     NBL_CHAN_TX_WAIT_ACK_US_MAX);
+	}
+	wait_head->acked = 0;
+	atomic_set(&wait_head->status, NBL_MBX_STATUS_TIMEOUT);
+	dev_err(dev,
+		"Channel polling ack failed, message type: %d msg id: %u\n",
+		chan_send->msg_type, msgid.id);
+	return -ETIMEDOUT;
+}
+
+static int nbl_chan_send_ack(struct nbl_channel_mgt *chan_mgt,
+			     struct nbl_chan_ack_info *chan_ack)
+{
+	size_t head_len = NBL_CHAN_ACK_HEAD_LEN * sizeof(u32);
+	size_t data_len = chan_ack->data_len;
+	struct nbl_chan_send_info chan_send;
+	__le32 *tmp;
+	size_t len;
+	int ret;
+
+	if (data_len > NBL_CHAN_BUF_LEN - head_len)
+		return -EINVAL;
+
+	len = head_len + data_len;
+	tmp = kzalloc(len, GFP_KERNEL);
+	if (!tmp)
+		return -ENOMEM;
+
+	*(__le16 *)&tmp[NBL_CHAN_MSG_TYPE_POS] =
+		cpu_to_le16(chan_ack->msg_type);
+	*(__le16 *)&tmp[NBL_CHAN_MSG_ID_POS] = cpu_to_le16(chan_ack->msgid);
+	tmp[NBL_CHAN_ACK_RET_POS] = cpu_to_le32(chan_ack->err);
+	if (chan_ack->data && chan_ack->data_len)
+		memcpy(&tmp[NBL_CHAN_ACK_HEAD_LEN], chan_ack->data,
+		       chan_ack->data_len);
+
+	NBL_CHAN_SEND(chan_send, chan_ack->dstid, NBL_CHAN_MSG_ACK, tmp, len,
+		      NULL, 0, 0);
+	ret = nbl_chan_send_msg(chan_mgt, &chan_send);
+	kfree(tmp);
+
+	return ret;
+}
+
+static int nbl_chan_register_msg(struct nbl_channel_mgt *chan_mgt, u16 msg_type,
+				 nbl_chan_resp func, void *callback)
+{
+	return nbl_chan_add_msg_handler(chan_mgt, msg_type, func, callback);
+}
+
+static bool nbl_chan_check_queue_exist(struct nbl_channel_mgt *chan_mgt,
+				       u8 chan_type)
+{
+	struct nbl_chan_info *chan_info = chan_mgt->chan_info[chan_type];
+
+	return chan_info ? true : false;
+}
+
+static void nbl_chan_register_chan_task(struct nbl_channel_mgt *chan_mgt,
+					u8 chan_type, struct work_struct *task)
+{
+	struct nbl_chan_info *chan_info = chan_mgt->chan_info[chan_type];
+
+	chan_info->clean_task = task;
+}
+
+static void nbl_chan_set_queue_state(struct nbl_channel_mgt *chan_mgt,
+				     enum nbl_chan_state state, u8 chan_type,
+				     u8 set)
+{
+	struct nbl_chan_info *chan_info = chan_mgt->chan_info[chan_type];
+
+	if (set)
+		set_bit(state, chan_info->state);
+	else
+		clear_bit(state, chan_info->state);
+}
+
 static struct nbl_channel_ops chan_ops = {
+	.send_msg			= nbl_chan_send_msg,
+	.send_ack			= nbl_chan_send_ack,
+	.register_msg			= nbl_chan_register_msg,
+	.cfg_chan_qinfo_map_table	= nbl_chan_cfg_qinfo_map_table,
+	.check_queue_exist		= nbl_chan_check_queue_exist,
+	.setup_queue			= nbl_chan_setup_queue,
+	.teardown_queue			= nbl_chan_teardown_queue,
+	.clean_queue_subtask		= nbl_chan_clean_queue_subtask,
+	.register_chan_task		= nbl_chan_register_chan_task,
+	.set_queue_state		= nbl_chan_set_queue_state,
 };
 
 static struct nbl_channel_mgt *
@@ -18,6 +857,7 @@ nbl_chan_setup_chan_mgt(struct nbl_adapter *adapter)
 	struct device *dev = &adapter->pdev->dev;
 	struct nbl_channel_mgt *chan_mgt;
 	struct nbl_chan_info *mailbox;
+	int ret;
 
 	chan_mgt = devm_kzalloc(dev, sizeof(*chan_mgt), GFP_KERNEL);
 	if (!chan_mgt)
@@ -32,6 +872,10 @@ nbl_chan_setup_chan_mgt(struct nbl_adapter *adapter)
 	mailbox->chan_type = NBL_CHAN_TYPE_MAILBOX;
 	chan_mgt->chan_info[NBL_CHAN_TYPE_MAILBOX] = mailbox;
 
+	ret = nbl_chan_init_msg_handler(chan_mgt);
+	if (ret)
+		return ERR_PTR(-ENOMEM);
+
 	return chan_mgt;
 }
 
@@ -39,6 +883,7 @@ static struct nbl_channel_ops_tbl *
 nbl_chan_setup_ops(struct device *dev, struct nbl_channel_mgt *chan_mgt)
 {
 	struct nbl_channel_ops_tbl *chan_ops_tbl;
+	int ret;
 
 	chan_ops_tbl = devm_kzalloc(dev, sizeof(*chan_ops_tbl), GFP_KERNEL);
 	if (!chan_ops_tbl)
@@ -47,6 +892,11 @@ nbl_chan_setup_ops(struct device *dev, struct nbl_channel_mgt *chan_mgt)
 	chan_ops_tbl->ops = &chan_ops;
 	chan_ops_tbl->priv = chan_mgt;
 
+	ret = nbl_chan_register_msg(chan_mgt, NBL_CHAN_MSG_ACK,
+				    nbl_chan_recv_ack_msg, chan_mgt);
+	if (ret)
+		return ERR_PTR(-ENOMEM);
+
 	return chan_ops_tbl;
 }
 
@@ -57,22 +907,40 @@ int nbl_chan_init_common(struct nbl_adapter *adap)
 	struct nbl_channel_mgt *chan_mgt;
 	int ret;
 
+	BUILD_BUG_ON(sizeof(struct nbl_chan_param_cfg_msix_map) != 8);
+	BUILD_BUG_ON(sizeof(struct nbl_chan_param_set_mailbox_irq) != 4);
+	BUILD_BUG_ON(sizeof(struct nbl_chan_param_get_vsi_id) != 4);
+	BUILD_BUG_ON(sizeof(struct nbl_chan_param_get_eth_id) != 8);
+	BUILD_BUG_ON(sizeof(struct nbl_board_port_info) != 8);
 	chan_mgt = nbl_chan_setup_chan_mgt(adap);
 	if (IS_ERR(chan_mgt)) {
 		ret = PTR_ERR(chan_mgt);
-		return ret;
+		goto exit;
 	}
 
 	chan_ops_tbl = nbl_chan_setup_ops(dev, chan_mgt);
 	if (IS_ERR(chan_ops_tbl)) {
 		ret = PTR_ERR(chan_ops_tbl);
-		return ret;
+		goto exit;
 	}
 	adap->intf.channel_ops_tbl = chan_ops_tbl;
 	adap->core.chan_mgt = chan_mgt;
 	return 0;
+
+exit:
+	if (!IS_ERR(chan_mgt)) {
+		nbl_chan_remove_msg_handler(chan_mgt);
+		adap->core.chan_mgt = NULL;
+	}
+	return ret;
 }
 
 void nbl_chan_remove_common(struct nbl_adapter *adap)
 {
+	struct nbl_channel_mgt *chan_mgt = adap->core.chan_mgt;
+
+	if (chan_mgt) {
+		nbl_chan_remove_msg_handler(chan_mgt);
+		adap->core.chan_mgt = NULL;
+	}
 }
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_channel/nbl_channel.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_channel/nbl_channel.h
index 637912d1e806..e8848fb97e2c 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_channel/nbl_channel.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_channel/nbl_channel.h
@@ -15,10 +15,154 @@
 #include "../nbl_include/nbl_def_common.h"
 #include "../nbl_core.h"
 
+#define NBL_CHAN_TX_RING_TO_DESC(tx_ring, i) \
+	(&((((tx_ring)->desc.tx_desc))[i]))
+#define NBL_CHAN_RX_RING_TO_DESC(rx_ring, i) \
+	(&((((rx_ring)->desc.rx_desc))[i]))
+#define NBL_CHAN_TX_RING_TO_BUF(tx_ring, i) (&(((tx_ring)->buf)[i]))
+#define NBL_CHAN_RX_RING_TO_BUF(rx_ring, i) (&(((rx_ring)->buf)[i]))
+
+#define NBL_CHAN_TX_WAIT_US			100
+#define NBL_CHAN_TX_WAIT_US_MAX			120
+#define NBL_CHAN_TX_REKICK_WAIT_TIMES		2000
+#define NBL_CHAN_TX_WAIT_TIMES			30000
+#define NBL_CHAN_TX_WAIT_ACK_US_MIN		100
+#define NBL_CHAN_TX_WAIT_ACK_US_MAX		120
+#define NBL_CHAN_TX_WAIT_ACK_TIMES		50000
+#define NBL_CHAN_QUEUE_LEN			256
+#define NBL_CHAN_BUF_LEN			4096
+#define NBL_CHAN_TX_DESC_EMBEDDED_DATA_LEN	16
+
+#define NBL_CHAN_TX_DESC_AVAIL			0
+#define NBL_CHAN_TX_DESC_USED			1
+#define NBL_CHAN_RX_DESC_WRITE			1
+#define NBL_CHAN_RX_DESC_AVAIL			3
+#define NBL_CHAN_RX_DESC_USED			4
+
+#define NBL_CHAN_ACK_HEAD_LEN			3
+#define NBL_CHAN_ACK_RET_POS			2
+#define NBL_CHAN_MSG_ID_POS			1
+#define NBL_CHAN_MSG_TYPE_POS			0
+
+#define NBL_CHAN_ACK_WAIT_TIME			(3 * HZ)
+
+#define NBL_CHAN_HANDLER_TBL_BUCKET_SIZE	512
+
+enum {
+	NBL_MB_RX_QID = 0,
+	NBL_MB_TX_QID = 1,
+};
+
+enum {
+	NBL_MBX_STATUS_IDLE = 0,
+	NBL_MBX_STATUS_WAITING,
+	NBL_MBX_STATUS_ACKD,
+	NBL_MBX_STATUS_TIMEOUT,
+};
+
+struct nbl_chan_tx_param {
+	enum nbl_chan_msg_type msg_type;
+	void *arg;
+	size_t arg_len;
+	u16 dstid;
+	u16 msgid;
+};
+
+struct nbl_chan_buf {
+	void *va;
+	dma_addr_t pa;
+	size_t size;
+};
+
+struct nbl_chan_tx_desc {
+	__le16 flags;
+	__le16 srcid;
+	__le16 dstid;
+	__le16 data_len;
+	__le16 buf_len;
+	__le64 buf_addr;
+	__le16 msg_type;
+	u8 data[16];
+	__le16 msgid;
+	u8 rsv[26];
+} __packed;
+
+struct nbl_chan_rx_desc {
+	__le16 flags;
+	__le32 buf_len;
+	__le16 buf_id;
+	__le64 buf_addr;
+} __packed;
+
+union nbl_chan_desc_ptr {
+	struct nbl_chan_tx_desc *tx_desc;
+	struct nbl_chan_rx_desc *rx_desc;
+};
+
+struct nbl_chan_ring {
+	union nbl_chan_desc_ptr desc;
+	struct nbl_chan_buf *buf;
+	u16 next_to_use;
+	u16 tail_ptr;
+	u16 next_to_clean;
+	dma_addr_t dma;
+};
+
+#define NBL_CHAN_MSG_INDEX_MAX 63
+
+union nbl_chan_msg_id {
+	struct nbl_chan_msg_id_info {
+		u16 index : 6;
+		u16 loc : 8;
+		u16 resv : 2;
+	} info;
+	u16 id;
+};
+
+struct nbl_chan_waitqueue_head {
+	struct wait_queue_head wait_queue;
+	char *ack_data;
+	int acked;
+	int ack_err;
+	u16 ack_data_len;
+	u16 need_waked;
+	u16 msg_type;
+	atomic_t status;
+	u8 msg_index;
+};
+
 struct nbl_chan_info {
+	struct nbl_chan_ring txq;
+	struct nbl_chan_ring rxq;
+	struct nbl_chan_waitqueue_head *wait;
+	/*
+	 *Protects access to the TX queue (txq) and related metadata.
+	 *This mutex ensures exclusive access when updating the TX queue
+	 */
+	struct mutex txq_lock;
+	/*
+	 * Acquire the RX queue lock to protect against concurrent access.
+	 * This mutex serializes access to:
+	 * - The next_to_clean pointer
+	 * - The ring buffer descriptors and buffers
+	 * - Any shared state between cleaning and enqueueing operations
+	 */
+	struct mutex rxq_lock;
+	struct work_struct *clean_task;
+	u16 wait_head_index;
+	u16 num_txq_entries;
+	u16 num_rxq_entries;
+	u16 txq_buf_size;
+	u16 rxq_buf_size;
+	DECLARE_BITMAP(state, NBL_CHAN_STATE_NBITS);
 	u8 chan_type;
 };
 
+struct nbl_chan_msg_node_data {
+	nbl_chan_resp func;
+	void *priv;
+};
+
 struct nbl_channel_mgt {
 	struct nbl_common_info *common;
 	struct nbl_hw_ops_tbl *hw_ops_tbl;
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_common/nbl_common.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_common/nbl_common.c
new file mode 100644
index 000000000000..11b1948658d9
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_common/nbl_common.c
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+
+#include <linux/device.h>
+#include "nbl_common.h"
+
+u32 nbl_common_pf_id_subtraction_mgtpf_id(struct nbl_common_info *common,
+					  u32 pf_id)
+{
+	u32 diff = U32_MAX;
+
+	if (pf_id >= common->mgt_pf)
+		diff = pf_id - common->mgt_pf;
+
+	return diff;
+}
+
+#define FNV_PRIME_32 0x01000193
+#define FNV_OFFSET_32 0x811C9DC5
+static u32 nbl_common_calc_hash_key(void *key, u32 key_size, u32 bucket_size)
+{
+	u32 hash = FNV_OFFSET_32;
+	u8 *p = (u8 *)key;
+	u32 i;
+
+	if (bucket_size == 0 || bucket_size == NBL_HASH_TBL_LIST_BUCKET_SIZE)
+		return 0;
+
+	for (i = 0; i < key_size; i++) {
+		hash ^= p[i];
+		hash *= FNV_PRIME_32;
+	}
+	/* Use bitmask if bucket_size is a power of 2 */
+	if ((bucket_size & (bucket_size - 1)) == 0)
+		return hash & (bucket_size - 1);
+	else
+		return hash % bucket_size;
+}
+
+/*
+ * alloc a hash table
+ * the table support multi thread
+ */
+struct nbl_hash_tbl_mgt *
+nbl_common_init_hash_table(struct nbl_hash_tbl_key *key)
+{
+	struct nbl_hash_tbl_mgt *tbl_mgt;
+	int bucket_size;
+	int i;
+
+	tbl_mgt = devm_kzalloc(key->dev, sizeof(*tbl_mgt), GFP_KERNEL);
+	if (!tbl_mgt)
+		return NULL;
+
+	bucket_size = key->bucket_size;
+	tbl_mgt->hash = devm_kcalloc(key->dev, bucket_size,
+				     sizeof(struct hlist_head), GFP_KERNEL);
+	if (!tbl_mgt->hash)
+		goto alloc_hash_failed;
+
+	for (i = 0; i < bucket_size; i++)
+		INIT_HLIST_HEAD(tbl_mgt->hash + i);
+
+	memcpy(&tbl_mgt->tbl_key, key, sizeof(struct nbl_hash_tbl_key));
+
+	return tbl_mgt;
+
+alloc_hash_failed:
+	return NULL;
+}
+
+/*
+ * alloc a hash node, and add to hlist_head
+ * The hash table is only accessed from a single context
+ * no locking required.
+ */
+int nbl_common_alloc_hash_node(struct nbl_hash_tbl_mgt *tbl_mgt, void *key,
+			       void *data, void **out_data)
+{
+	struct nbl_hash_entry_node *hash_node;
+	u16 data_size;
+	u32 hash_val;
+	u16 key_size;
+
+	hash_node = devm_kzalloc(tbl_mgt->tbl_key.dev, sizeof(*hash_node),
+				 GFP_KERNEL);
+	if (!hash_node)
+		return -ENOMEM;
+
+	key_size = tbl_mgt->tbl_key.key_size;
+	hash_node->key =
+		devm_kzalloc(tbl_mgt->tbl_key.dev, key_size, GFP_KERNEL);
+	if (!hash_node->key)
+		goto alloc_key_failed;
+
+	data_size = tbl_mgt->tbl_key.data_size;
+	hash_node->data =
+		devm_kzalloc(tbl_mgt->tbl_key.dev, data_size, GFP_KERNEL);
+	if (!hash_node->data)
+		goto alloc_data_failed;
+
+	memcpy(hash_node->key, key, key_size);
+	memcpy(hash_node->data, data, data_size);
+
+	hash_val = nbl_common_calc_hash_key(key, key_size,
+					    tbl_mgt->tbl_key.bucket_size);
+
+	hlist_add_head(&hash_node->node, tbl_mgt->hash + hash_val);
+	tbl_mgt->node_num++;
+	if (out_data)
+		*out_data = hash_node->data;
+
+	return 0;
+
+alloc_data_failed:
+	devm_kfree(tbl_mgt->tbl_key.dev, hash_node->key);
+alloc_key_failed:
+	devm_kfree(tbl_mgt->tbl_key.dev, hash_node);
+	return -ENOMEM;
+}
+
+/*
+ * get a hash node, return the data if node exist
+ */
+void *nbl_common_get_hash_node(struct nbl_hash_tbl_mgt *tbl_mgt, void *key)
+{
+	struct nbl_hash_entry_node *hash_node;
+	struct hlist_head *head;
+	void *data = NULL;
+	u32 hash_val;
+	u16 key_size;
+
+	key_size = tbl_mgt->tbl_key.key_size;
+	hash_val = nbl_common_calc_hash_key(key, key_size,
+					    tbl_mgt->tbl_key.bucket_size);
+	head = tbl_mgt->hash + hash_val;
+
+	hlist_for_each_entry(hash_node, head, node)
+		if (!memcmp(hash_node->key, key, key_size)) {
+			data = hash_node->data;
+			break;
+		}
+
+	return data;
+}
+
+static void nbl_common_detach_hash_node(struct nbl_hash_tbl_mgt *tbl_mgt,
+					struct nbl_hash_entry_node *hash_node)
+{
+	hlist_del(&hash_node->node);
+	devm_kfree(tbl_mgt->tbl_key.dev, hash_node->key);
+	devm_kfree(tbl_mgt->tbl_key.dev, hash_node->data);
+	devm_kfree(tbl_mgt->tbl_key.dev, hash_node);
+	tbl_mgt->node_num--;
+}
+
+/*
+ * free a hash node
+ */
+void nbl_common_remove_hash_table(struct nbl_hash_tbl_mgt *tbl_mgt,
+				  struct nbl_hash_tbl_del_key *key)
+{
+	struct nbl_hash_entry_node *hash_node;
+	struct hlist_node *safe_node;
+	struct hlist_head *head;
+	u32 i;
+
+	for (i = 0; i < tbl_mgt->tbl_key.bucket_size; i++) {
+		head = tbl_mgt->hash + i;
+		hlist_for_each_entry_safe(hash_node, safe_node, head, node) {
+			if (key && key->action_func)
+				key->action_func(key->action_priv,
+						 hash_node->key,
+						 hash_node->data);
+			nbl_common_detach_hash_node(tbl_mgt, hash_node);
+		}
+	}
+}
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_common/nbl_common.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_common/nbl_common.h
new file mode 100644
index 000000000000..7a91d4eca105
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_common/nbl_common.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+
+#ifndef _NBL_COMMON_H_
+#define _NBL_COMMON_H_
+
+#include <linux/types.h>
+
+#include "../nbl_include/nbl_include.h"
+#include "../nbl_include/nbl_def_common.h"
+
+/* list only need one bucket size */
+#define NBL_HASH_TBL_LIST_BUCKET_SIZE 1
+
+struct nbl_common_wq_mgt {
+	struct workqueue_struct *ctrl_dev_wq;
+};
+
+struct nbl_hash_tbl_mgt {
+	struct nbl_hash_tbl_key tbl_key;
+	struct hlist_head *hash;
+	u16 node_num;
+};
+
+struct nbl_hash_entry_node {
+	struct hlist_node node;
+	void *key;
+	void *data;
+};
+
+#endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c
index bf4feaea4b4a..822066d6cecd 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c
@@ -9,7 +9,156 @@
 #include <linux/spinlock.h>
 #include "nbl_hw_leonis.h"
 
+static void nbl_hw_write_mbx_regs(struct nbl_hw_mgt *hw_mgt, u64 reg,
+				  const u32 *data, u32 len)
+{
+	u32 i;
+
+	if (len % 4)
+		return;
+
+	for (i = 0; i < len / 4; i++)
+		nbl_mbx_wr32(hw_mgt, reg + i * sizeof(u32), data[i]);
+}
+
+static void nbl_hw_rd_regs(struct nbl_hw_mgt *hw_mgt, u64 reg, u32 *data,
+			   u32 len)
+{
+	u32 size = len / 4;
+	u32 i;
+
+	if (len % 4)
+		return;
+
+	spin_lock(&hw_mgt->reg_lock);
+
+	for (i = 0; i < size; i++)
+		data[i] = rd32(hw_mgt->hw_addr, reg + i * sizeof(u32));
+	spin_unlock(&hw_mgt->reg_lock);
+}
+
+static void nbl_hw_wr_regs(struct nbl_hw_mgt *hw_mgt, u64 reg, const u32 *data,
+			   u32 len)
+{
+	u32 size = len / 4;
+	u32 i;
+
+	if (len % 4)
+		return;
+	spin_lock(&hw_mgt->reg_lock);
+	for (i = 0; i < size; i++)
+		wr32(hw_mgt->hw_addr, reg + i * sizeof(u32), data[i]);
+	spin_unlock(&hw_mgt->reg_lock);
+}
+
+static void nbl_hw_update_mailbox_queue_tail_ptr(struct nbl_hw_mgt *hw_mgt,
+						 u16 tail_ptr, u8 txrx)
+{
+	/* local_qid 0 and 1 denote rx and tx queue respectively */
+	u32 local_qid = txrx;
+	u32 value = ((u32)tail_ptr << 16) | local_qid;
+
+	/* wmb for doorbell */
+	wmb();
+	nbl_mbx_wr32(hw_mgt, NBL_MAILBOX_NOTIFY_ADDR, value);
+}
+
+static void nbl_hw_config_mailbox_rxq(struct nbl_hw_mgt *hw_mgt,
+				      dma_addr_t dma_addr, int size_bwid)
+{
+	union nbl_mailbox_qinfo_cfg_table_u qinfo_cfg_rx_tbl;
+
+	memset(&qinfo_cfg_rx_tbl, 0, sizeof(qinfo_cfg_rx_tbl));
+	qinfo_cfg_rx_tbl.info.queue_rst = 1;
+	nbl_hw_write_mbx_regs(hw_mgt, NBL_MAILBOX_QINFO_CFG_RX_TABLE_ADDR,
+			      qinfo_cfg_rx_tbl.data,
+			      sizeof(qinfo_cfg_rx_tbl));
+
+	qinfo_cfg_rx_tbl.info.queue_base_addr_l = (u32)(dma_addr & 0xFFFFFFFF);
+	qinfo_cfg_rx_tbl.info.queue_base_addr_h = (u32)(dma_addr >> 32);
+	qinfo_cfg_rx_tbl.info.queue_size_bwind = (u32)size_bwid;
+	qinfo_cfg_rx_tbl.info.queue_rst = 0;
+	qinfo_cfg_rx_tbl.info.queue_en = 1;
+	nbl_hw_write_mbx_regs(hw_mgt, NBL_MAILBOX_QINFO_CFG_RX_TABLE_ADDR,
+			      qinfo_cfg_rx_tbl.data,
+			      sizeof(qinfo_cfg_rx_tbl));
+}
+
+static void nbl_hw_config_mailbox_txq(struct nbl_hw_mgt *hw_mgt,
+				      dma_addr_t dma_addr, int size_bwid)
+{
+	union nbl_mailbox_qinfo_cfg_table_u qinfo_cfg_tx_tbl;
+
+	memset(&qinfo_cfg_tx_tbl, 0, sizeof(qinfo_cfg_tx_tbl));
+	qinfo_cfg_tx_tbl.info.queue_rst = 1;
+	nbl_hw_write_mbx_regs(hw_mgt, NBL_MAILBOX_QINFO_CFG_TX_TABLE_ADDR,
+			      qinfo_cfg_tx_tbl.data,
+			      sizeof(qinfo_cfg_tx_tbl));
+
+	qinfo_cfg_tx_tbl.info.queue_base_addr_l = (u32)(dma_addr & 0xFFFFFFFF);
+	qinfo_cfg_tx_tbl.info.queue_base_addr_h = (u32)(dma_addr >> 32);
+	qinfo_cfg_tx_tbl.info.queue_size_bwind = (u32)size_bwid;
+	qinfo_cfg_tx_tbl.info.queue_rst = 0;
+	qinfo_cfg_tx_tbl.info.queue_en = 1;
+	nbl_hw_write_mbx_regs(hw_mgt, NBL_MAILBOX_QINFO_CFG_TX_TABLE_ADDR,
+			      qinfo_cfg_tx_tbl.data,
+			      sizeof(qinfo_cfg_tx_tbl));
+}
+
+static void nbl_hw_stop_mailbox_rxq(struct nbl_hw_mgt *hw_mgt)
+{
+	union nbl_mailbox_qinfo_cfg_table_u qinfo_cfg_rx_tbl;
+
+	memset(&qinfo_cfg_rx_tbl, 0, sizeof(qinfo_cfg_rx_tbl));
+	qinfo_cfg_rx_tbl.info.queue_rst = 1;
+	nbl_hw_write_mbx_regs(hw_mgt, NBL_MAILBOX_QINFO_CFG_RX_TABLE_ADDR,
+			      qinfo_cfg_rx_tbl.data,
+			      sizeof(qinfo_cfg_rx_tbl));
+}
+
+static void nbl_hw_stop_mailbox_txq(struct nbl_hw_mgt *hw_mgt)
+{
+	union nbl_mailbox_qinfo_cfg_table_u qinfo_cfg_tx_tbl;
+
+	memset(&qinfo_cfg_tx_tbl, 0, sizeof(qinfo_cfg_tx_tbl));
+	qinfo_cfg_tx_tbl.info.queue_rst = 1;
+	nbl_hw_write_mbx_regs(hw_mgt, NBL_MAILBOX_QINFO_CFG_TX_TABLE_ADDR,
+			      qinfo_cfg_tx_tbl.data,
+			      sizeof(qinfo_cfg_tx_tbl));
+}
+
+static u32 nbl_hw_get_host_pf_mask(struct nbl_hw_mgt *hw_mgt)
+{
+	u32 data;
+
+	nbl_hw_rd_regs(hw_mgt, NBL_PCIE_HOST_K_PF_MASK_REG, &data,
+		       sizeof(data));
+	return data;
+}
+
+static void nbl_hw_cfg_mailbox_qinfo(struct nbl_hw_mgt *hw_mgt, u16 func_id,
+				     u8 bus, u8 devid, u8 function)
+{
+	union nbl_mailbox_qinfo_map_table_u mb_qinfo_map;
+
+	memset(&mb_qinfo_map, 0, sizeof(mb_qinfo_map));
+	mb_qinfo_map.info.function = function & 0x7;
+	mb_qinfo_map.info.devid = devid & 0x1F;
+	mb_qinfo_map.info.bus = bus & 0xFF;
+	mb_qinfo_map.info.msix_idx_valid = 0;
+	nbl_hw_wr_regs(hw_mgt, NBL_MAILBOX_QINFO_MAP_REG_ARR(func_id),
+		       &mb_qinfo_map.data, sizeof(mb_qinfo_map));
+}
+
 static struct nbl_hw_ops hw_ops = {
+	.update_mailbox_queue_tail_ptr = nbl_hw_update_mailbox_queue_tail_ptr,
+	.config_mailbox_rxq = nbl_hw_config_mailbox_rxq,
+	.config_mailbox_txq = nbl_hw_config_mailbox_txq,
+	.stop_mailbox_rxq = nbl_hw_stop_mailbox_rxq,
+	.stop_mailbox_txq = nbl_hw_stop_mailbox_txq,
+	.get_host_pf_mask = nbl_hw_get_host_pf_mask,
+	.cfg_mailbox_qinfo = nbl_hw_cfg_mailbox_qinfo,
+
 };
 
 /* Structure starts here, adding an op should not modify anything below */
@@ -102,6 +251,8 @@ int nbl_hw_init_leonis(struct nbl_adapter *adapter)
 		goto mailbox_ioremap_err;
 	}
 
+	spin_lock_init(&hw_mgt->reg_lock);
+
 	hw_ops_tbl = nbl_hw_setup_ops(common, hw_mgt);
 	if (IS_ERR(hw_ops_tbl)) {
 		ret = PTR_ERR(hw_ops_tbl);
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_reg.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_reg.h
index fbea8d074064..781b05405963 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_reg.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_reg.h
@@ -25,6 +25,7 @@ struct nbl_hw_mgt {
 	u8 __iomem *mailbox_bar_hw_addr;
 	u64 notify_offset;
 	resource_size_t hw_size;
+	spinlock_t reg_lock; /* Protect reg access */
 };
 
 static inline u32 rd32(u8 __iomem *addr, u64 reg)
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_channel.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_channel.h
index 88470f15c619..16d29d2fb7f7 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_channel.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_channel.h
@@ -10,6 +10,38 @@
 
 struct nbl_channel_mgt;
 struct nbl_adapter;
+#define NBL_CHAN_SEND(chan_send, dst_id, mesg_type, argument, arg_length,\
+		      response, resp_length, need_ack)			\
+do {									\
+	typeof(chan_send)	*__chan_send = &(chan_send);		\
+	__chan_send->dstid	= (dst_id);				\
+	__chan_send->msg_type	= (mesg_type);				\
+	__chan_send->arg	= (argument);				\
+	__chan_send->arg_len	= (arg_length);				\
+	__chan_send->resp	= (response);				\
+	__chan_send->resp_len	= (resp_length);			\
+	__chan_send->ack	= (need_ack);				\
+} while (0)
+
+#define NBL_CHAN_ACK(chan_ack, dst_id, mesg_type, msg_id, err_code, ack_data, \
+		     data_length)					\
+do {									\
+	typeof(chan_ack)	*__chan_ack = &(chan_ack);		\
+	__chan_ack->dstid	= (dst_id);				\
+	__chan_ack->msg_type	= (mesg_type);				\
+	__chan_ack->msgid	= (msg_id);				\
+	__chan_ack->err		= (err_code);				\
+	__chan_ack->data	= (ack_data);				\
+	__chan_ack->data_len	= (data_length);			\
+} while (0)
+
+typedef void (*nbl_chan_resp)(void *, u16, u16, void *, u32);
+
+enum {
+	NBL_CHAN_RESP_OK,
+	NBL_CHAN_RESP_ERR,
+};
+
 enum nbl_chan_msg_type {
 	NBL_CHAN_MSG_ACK,
 	NBL_CHAN_MSG_ADD_MACVLAN,
@@ -233,6 +265,13 @@ enum nbl_chan_msg_type {
 	NBL_CHAN_MSG_MAILBOX_MAX,
 };
 
+enum nbl_chan_state {
+	NBL_CHAN_INTERRUPT_READY,
+	NBL_CHAN_RESETTING,
+	NBL_CHAN_ABNORMAL,
+	NBL_CHAN_STATE_NBITS
+};
+
 struct nbl_chan_param_cfg_msix_map {
 	__le16 num_net_msix;
 	__le16 num_others_msix;
@@ -259,12 +298,57 @@ struct nbl_chan_param_get_eth_id {
 	u8 rsvd[3];
 };
 
+struct nbl_board_port_info {
+	u8 eth_num;
+	u8 eth_speed;
+	u8 p4_version;
+	u8 rsv[5];
+};
+
+struct nbl_chan_send_info {
+	void *arg;
+	size_t arg_len;
+	void *resp;
+	size_t resp_len;
+	u16 dstid;
+	u16 msg_type;
+	u16 ack;
+	u16 ack_len;
+};
+
+struct nbl_chan_ack_info {
+	void *data;
+	int err;
+	u32 data_len;
+	u16 dstid;
+	u16 msg_type;
+	u16 msgid;
+};
+
 enum nbl_channel_type {
 	NBL_CHAN_TYPE_MAILBOX,
 	NBL_CHAN_TYPE_MAX
 };
 
 struct nbl_channel_ops {
+	int (*send_msg)(struct nbl_channel_mgt *chan_mgt,
+			struct nbl_chan_send_info *chan_send);
+	int (*send_ack)(struct nbl_channel_mgt *chan_mgt,
+			struct nbl_chan_ack_info *chan_ack);
+	int (*register_msg)(struct nbl_channel_mgt *chan_mgt, u16 msg_type,
+			    nbl_chan_resp func, void *callback_priv);
+	void (*cfg_chan_qinfo_map_table)(struct nbl_channel_mgt *chan_mgt);
+	bool (*check_queue_exist)(struct nbl_channel_mgt *chan_mgt,
+				  u8 chan_type);
+	int (*setup_queue)(struct nbl_channel_mgt *chan_mgt, u8 chan_type);
+	int (*teardown_queue)(struct nbl_channel_mgt *chan_mgt, u8 chan_type);
+	void (*clean_queue_subtask)(struct nbl_channel_mgt *chan_mgt,
+				    u8 chan_type);
+	void (*register_chan_task)(struct nbl_channel_mgt *chan_mgt,
+				   u8 chan_type, struct work_struct *task);
+	void (*set_queue_state)(struct nbl_channel_mgt *chan_mgt,
+				enum nbl_chan_state state, u8 chan_type,
+				u8 set);
 };
 
 struct nbl_channel_ops_tbl {
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_common.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_common.h
index d93da0f22835..176df51f9e6e 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_common.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_common.h
@@ -11,6 +11,8 @@
 #include <linux/device.h>
 #include "nbl_include.h"
 
+struct nbl_hash_tbl_mgt;
+
 struct nbl_common_info {
 	struct pci_dev *pdev;
 	struct device *dev;
@@ -32,4 +34,28 @@ struct nbl_common_info {
 	u8 has_net;
 };
 
+struct nbl_hash_tbl_key {
+	struct device *dev;
+	u16 key_size;
+	u16 data_size; /* no include key or node member */
+	u16 bucket_size;
+	u16 resv;
+};
+
+struct nbl_hash_tbl_del_key {
+	void *action_priv;
+	void (*action_func)(void *priv, void *key, void *data);
+};
+
+u32 nbl_common_pf_id_subtraction_mgtpf_id(struct nbl_common_info *common,
+					  u32 pf_id);
+
+struct nbl_hash_tbl_mgt *
+nbl_common_init_hash_table(struct nbl_hash_tbl_key *key);
+void nbl_common_remove_hash_table(struct nbl_hash_tbl_mgt *tbl_mgt,
+				  struct nbl_hash_tbl_del_key *key);
+int nbl_common_alloc_hash_node(struct nbl_hash_tbl_mgt *tbl_mgt, void *key,
+			       void *data, void **out_data);
+void *nbl_common_get_hash_node(struct nbl_hash_tbl_mgt *tbl_mgt, void *key);
+
 #endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_hw.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_hw.h
index 168504b30973..3d421bcbc353 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_hw.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_hw.h
@@ -6,9 +6,37 @@
 #ifndef _NBL_DEF_HW_H_
 #define _NBL_DEF_HW_H_
 
+#include <linux/types.h>
+
 struct nbl_hw_mgt;
 struct nbl_adapter;
 struct nbl_hw_ops {
+	void (*configure_msix_map)(struct nbl_hw_mgt *hw_mgt, u16 func_id,
+				   bool valid, dma_addr_t dma_addr, u8 bus,
+				   u8 devid, u8 function);
+	void (*configure_msix_info)(struct nbl_hw_mgt *hw_mgt, u16 func_id,
+				    bool valid, u16 interrupt_id, u8 bus,
+				    u8 devid, u8 function,
+				    bool net_msix_mask_en);
+	void (*update_mailbox_queue_tail_ptr)(struct nbl_hw_mgt *hw_mgt,
+					      u16 tail_ptr, u8 txrx);
+	void (*config_mailbox_rxq)(struct nbl_hw_mgt *hw_mgt,
+				   dma_addr_t dma_addr, int size_bwid);
+	void (*config_mailbox_txq)(struct nbl_hw_mgt *hw_mgt,
+				   dma_addr_t dma_addr, int size_bwid);
+	void (*stop_mailbox_rxq)(struct nbl_hw_mgt *hw_mgt);
+	void (*stop_mailbox_txq)(struct nbl_hw_mgt *hw_mgt);
+	u32 (*get_host_pf_mask)(struct nbl_hw_mgt *hw_mgt);
+	u8 (*get_real_bus)(struct nbl_hw_mgt *hw_mgt);
+
+	void (*cfg_mailbox_qinfo)(struct nbl_hw_mgt *hw_mgt, u16 func_id,
+				  u8 bus, u8 devid, u8 function);
+	void (*set_mailbox_irq)(struct nbl_hw_mgt *hw_mgt, u16 func_id,
+				bool enable_msix, u16 global_vec_id);
+	u32 (*get_fw_eth_num)(struct nbl_hw_mgt *hw_mgt);
+	u32 (*get_fw_eth_map)(struct nbl_hw_mgt *hw_mgt);
+	void (*get_board_info)(struct nbl_hw_mgt *hw_mgt,
+			       struct nbl_board_port_info *board);
 };
 
 struct nbl_hw_ops_tbl {
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h
index 50f30f756bf3..a01c32f57d84 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h
@@ -10,6 +10,12 @@
 
 /*  ------  Basic definitions  -------  */
 #define NBL_DRIVER_NAME					"nbl"
+#define NBL_MAX_PF					8
+#define NBL_NEXT_ID(id, max)				\
+	({						\
+		typeof(id) _id = (id);			\
+		((_id) == (max) ? 0 : (_id) + 1);	\
+	})
 
 enum nbl_product_type {
 	NBL_LEONIS_TYPE,
-- 
2.47.3


^ permalink raw reply related

* [PATCH v15 net-next 09/11] net/nebula-matrix: add Dispatch layer implementation
From: illusion.wang @ 2026-05-20  3:29 UTC (permalink / raw)
  To: dimon.zhao, illusion.wang, alvin.wang, sam.chen, netdev
  Cc: andrew+netdev, corbet, kuba, horms, linux-doc, pabeni,
	vadim.fedorenko, lukas.bulwahn, edumazet, enelsonmoore, skhan,
	hkallweit1, open list
In-Reply-To: <20260520032950.4874-1-illusion.wang@nebula-matrix.com>

This patch introduces a control-level routing mechanism for the Dispatch layer.

The Dispatch layer supports two routing paths:
- Direct path: Dispatch Layer -> Resource Layer -> HW Layer
  Tasks are dispatched to Resource Layer, which may interact with HW Layer
  for hardware writes.
- Channel path: Dispatch Layer -> Channel Layer
  Tasks are redirected to the Channel Layer for processing.

Routing is controlled by two components:

1. Interface-declared control levels (per operation)
   Each operation interface declares its required control level:
   - NBL_DISP_CTRL_LVL_MGT: management operations
   - NBL_DISP_CTRL_LVL_NET: network operations (reserved, not yet wired)

2. Upper-layer configured control levels (per PF driver)
   The PF driver configures which control levels use the direct path
   via nbl_disp_init(). Currently only the CTRL_LVL_MGT branch is
   implemented and reachable in nbl_disp_init().

Current state:
- Regular PF: configures NET_LVL at Dispatch layer.
  Since NBL_DISP_CTRL_LVL_NET is not yet wired in nbl_disp_init(),
  all operations currently fall through to the CTRL_LVL_MGT branch
  and use the channel path. The direct path for NET_LVL is a
  framework extension point reserved for future use.

- Management PF: configures both NET_LVL and CTRL_LVL.
  However, since every operation in NBL_DISP_OPS_TBL declares
  ctrl=NBL_DISP_CTRL_LVL_MGT, the MGT bit is always set in ctrl_lvl.
  When nbl_disp_setup_ctrl_lvl() is called with NBL_DISP_CTRL_LVL_MGT,
  test_bit(MGT, ctrl_lvl) is true for every op, so all ops resolve
  to func (direct path), not msg_req (channel path).

Future work:
Implement the has_net / NBL_DISP_CTRL_LVL_NET branch in nbl_disp_init()
to enable direct path routing for network operations.

Message Handling Framework:
The Channel path is used by all current operations because the
NBL_DISP_CTRL_LVL_NET branch is not yet implemented. This design
allows the framework to be extended later to support direct HW
access for high-performance network operations without changing
the channel layer or existing control-plane operations.

Resource Layer Locking Strategy (related to this patch):

Mutex protection in nbl_dispatch_mgt:
- configure_msix_map():   LOCKED (via NBL_OPS_CALL_LOCK_RET)
- destroy_msix_map():     LOCKED
- set_mailbox_irq():   LOCKED
- init_chip_module():     UNLOCKED
- deinit_chip_module():   UNLOCKED
- get_vsi_id():           UNLOCKED
- get_eth_id():           UNLOCKED

Design rationale for unlocked call sites:

1. init_chip_module() / deinit_chip_module():
   - Called ONLY from control path (PF0)
   - These are init/teardown functions that run sequentially
   - No concurrent access possible because:
     a) Called during driver probe/remove
     b) Only one control device exists
   - Safe to call without mutex

2. get_vsi_id() / get_eth_id():
   - These are READ-ONLY operations
   - They only query existing state, never modify it
   - Even if called concurrently with locked operations:
     a) Reading shared state without lock is safe on most
        architectures (torn reads are acceptable for IDs)
     b) The locked operations that MODIFY state are:
        - configure_msix_map (allocates resources)
        - destroy_msix_map (frees resources)
        - set_mailbox_irq (modifies hw state)
     c) Reading while writing is safe if:
        - Writer holds lock (prevents concurrent writes)
        - Reader doesn't care about torn reads (IDs are atomic)

Mutex purpose:
The ops_mutex_lock protects MODIFY operations on shared
resource state (MSI-X map allocation, hardware configuration).
It does NOT protect read-only queries or ctrl-path init/teardown.

This is a deliberate design choice: locking only the
critical sections minimizes contention while maintaining
safety for the common case (concurrent reads).

Signed-off-by: illusion.wang <illusion.wang@nebula-matrix.com>
---
 .../nebula-matrix/nbl/nbl_core/nbl_dispatch.c | 428 +++++++++++++++++-
 .../nebula-matrix/nbl/nbl_core/nbl_dispatch.h |  31 ++
 .../nbl/nbl_include/nbl_def_dispatch.h        |  13 +
 3 files changed, 471 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dispatch.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dispatch.c
index 281d33051185..2e121863b9d2 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dispatch.c
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dispatch.c
@@ -6,6 +6,417 @@
 #include <linux/pci.h>
 #include "nbl_dispatch.h"
 
+static u16 nbl_disp_chan_get_vsi_id_req(struct nbl_dispatch_mgt *disp_mgt,
+					u16 type)
+{
+	struct nbl_channel_ops *chan_ops = disp_mgt->chan_ops_tbl->ops;
+	struct nbl_common_info *common = disp_mgt->common;
+	struct nbl_chan_param_get_vsi_id result = { 0 };
+	struct nbl_chan_param_get_vsi_id param = { 0 };
+	struct nbl_chan_send_info chan_send;
+
+	param.type = cpu_to_le16(type);
+
+	NBL_CHAN_SEND(chan_send, common->mgt_pf, NBL_CHAN_MSG_GET_VSI_ID,
+		      &param, sizeof(param), &result, sizeof(result), 1);
+	if (chan_ops->send_msg(disp_mgt->chan_ops_tbl->priv, &chan_send))
+		return U16_MAX;
+
+	return le16_to_cpu(result.vsi_id);
+}
+
+static void nbl_disp_chan_get_vsi_id_resp(void *priv, u16 src_id, u16 msg_id,
+					  void *data, u32 data_len)
+{
+	struct nbl_dispatch_mgt *disp_mgt = (struct nbl_dispatch_mgt *)priv;
+	struct nbl_channel_ops *chan_ops = disp_mgt->chan_ops_tbl->ops;
+	struct nbl_resource_ops *res_ops = disp_mgt->res_ops_tbl->ops;
+	struct nbl_resource_mgt *p = disp_mgt->res_ops_tbl->priv;
+	struct device *dev = disp_mgt->common->dev;
+	struct nbl_chan_param_get_vsi_id result = { 0 };
+	struct nbl_chan_param_get_vsi_id param = { 0 };
+	struct nbl_chan_ack_info chan_ack;
+	int err = NBL_CHAN_RESP_OK;
+	int copy_len;
+	u16 vsi_id;
+	int ret;
+
+	copy_len = data_len < sizeof(param) ? data_len : sizeof(param);
+	memcpy(&param, data, copy_len);
+	vsi_id = NBL_OPS_CALL_RET(res_ops->get_vsi_id,
+				  (p, src_id, le16_to_cpu(param.type)));
+	result.vsi_id = cpu_to_le16(vsi_id);
+	NBL_CHAN_ACK(chan_ack, src_id, NBL_CHAN_MSG_GET_VSI_ID, msg_id, err,
+		     &result, sizeof(result));
+	ret = chan_ops->send_ack(disp_mgt->chan_ops_tbl->priv, &chan_ack);
+	if (ret)
+		dev_err(dev,
+			"channel send ack failed with ret: %d, msg_type: %d\n",
+			ret, NBL_CHAN_MSG_GET_VSI_ID);
+}
+
+static int nbl_disp_chan_get_eth_id_req(struct nbl_dispatch_mgt *disp_mgt,
+					u16 vsi_id, u8 *eth_num, u8 *eth_id,
+					u8 *logic_eth_id)
+{
+	struct nbl_channel_ops *chan_ops = disp_mgt->chan_ops_tbl->ops;
+	struct nbl_common_info *common = disp_mgt->common;
+	struct nbl_chan_param_get_eth_id result = { 0 };
+	struct nbl_chan_param_get_eth_id param = { 0 };
+	struct nbl_chan_send_info chan_send;
+	int ret;
+
+	param.vsi_id = cpu_to_le16(vsi_id);
+
+	NBL_CHAN_SEND(chan_send, common->mgt_pf, NBL_CHAN_MSG_GET_ETH_ID,
+		      &param, sizeof(param), &result, sizeof(result), 1);
+	ret = chan_ops->send_msg(disp_mgt->chan_ops_tbl->priv, &chan_send);
+	if (ret)
+		return ret;
+	*eth_num = result.eth_num;
+	*eth_id = result.eth_id;
+	*logic_eth_id = result.logic_eth_id;
+
+	return 0;
+}
+
+static void nbl_disp_chan_get_eth_id_resp(void *priv, u16 src_id, u16 msg_id,
+					  void *data, u32 data_len)
+{
+	struct nbl_dispatch_mgt *disp_mgt = (struct nbl_dispatch_mgt *)priv;
+	struct nbl_channel_ops *chan_ops = disp_mgt->chan_ops_tbl->ops;
+	struct nbl_resource_ops *res_ops = disp_mgt->res_ops_tbl->ops;
+	struct nbl_resource_mgt *p = disp_mgt->res_ops_tbl->priv;
+	struct nbl_chan_param_get_eth_id result = { 0 };
+	struct nbl_chan_param_get_eth_id param = { 0 };
+	struct device *dev = disp_mgt->common->dev;
+	struct nbl_chan_ack_info chan_ack;
+	int err = NBL_CHAN_RESP_OK;
+	int copy_len;
+	int ret;
+
+	copy_len = data_len < sizeof(param) ? data_len : sizeof(param);
+	memcpy(&param, data, copy_len);
+	ret = NBL_OPS_CALL_RET(res_ops->get_eth_id,
+			       (p, le16_to_cpu(param.vsi_id), &result.eth_num,
+			       &result.eth_id, &result.logic_eth_id));
+	if (ret)
+		err = NBL_CHAN_RESP_ERR;
+
+	NBL_CHAN_ACK(chan_ack, src_id, NBL_CHAN_MSG_GET_ETH_ID, msg_id, err,
+		     &result, sizeof(result));
+	ret = chan_ops->send_ack(disp_mgt->chan_ops_tbl->priv, &chan_ack);
+	if (ret)
+		dev_err(dev,
+			"channel send ack failed with ret: %d, msg_type: %d\n",
+			ret, NBL_CHAN_MSG_GET_ETH_ID);
+}
+
+static void nbl_disp_deinit_chip_module(struct nbl_dispatch_mgt *disp_mgt)
+{
+	struct nbl_resource_ops *res_ops = disp_mgt->res_ops_tbl->ops;
+	struct nbl_resource_mgt *p = disp_mgt->res_ops_tbl->priv;
+
+	NBL_OPS_CALL(res_ops->deinit_chip_module, (p));
+}
+
+static int nbl_disp_init_chip_module(struct nbl_dispatch_mgt *disp_mgt)
+{
+	struct nbl_resource_ops *res_ops = disp_mgt->res_ops_tbl->ops;
+	struct nbl_resource_mgt *p = disp_mgt->res_ops_tbl->priv;
+
+	return NBL_OPS_CALL_RET(res_ops->init_chip_module, (p));
+}
+
+static int nbl_disp_configure_msix_map(struct nbl_dispatch_mgt *disp_mgt,
+				       u16 num_net_msix, u16 num_others_msix,
+				       bool net_msix_mask_en)
+{
+	struct nbl_resource_ops *res_ops = disp_mgt->res_ops_tbl->ops;
+	struct nbl_resource_mgt *p = disp_mgt->res_ops_tbl->priv;
+
+	return NBL_OPS_CALL_LOCK_RET(disp_mgt, res_ops->configure_msix_map, p,
+				     0, num_net_msix, num_others_msix,
+				     net_msix_mask_en);
+}
+
+static int
+nbl_disp_chan_configure_msix_map_req(struct nbl_dispatch_mgt *disp_mgt,
+				     u16 num_net_msix, u16 num_others_msix,
+				     bool net_msix_mask_en)
+{
+	struct nbl_channel_ops *chan_ops = disp_mgt->chan_ops_tbl->ops;
+	struct nbl_common_info *common = disp_mgt->common;
+	struct nbl_chan_param_cfg_msix_map param = { 0 };
+	struct nbl_chan_send_info chan_send;
+
+	param.num_net_msix = cpu_to_le16(num_net_msix);
+	param.num_others_msix = cpu_to_le16(num_others_msix);
+	param.msix_mask_en = cpu_to_le16(!!net_msix_mask_en);
+
+	NBL_CHAN_SEND(chan_send, common->mgt_pf,
+		      NBL_CHAN_MSG_CONFIGURE_MSIX_MAP, &param, sizeof(param),
+		      NULL, 0, 1);
+	return chan_ops->send_msg(disp_mgt->chan_ops_tbl->priv, &chan_send);
+}
+
+static void nbl_disp_chan_configure_msix_map_resp(void *priv, u16 src_id,
+						  u16 msg_id, void *data,
+						  u32 data_len)
+{
+	struct nbl_dispatch_mgt *disp_mgt = (struct nbl_dispatch_mgt *)priv;
+	struct nbl_channel_ops *chan_ops = disp_mgt->chan_ops_tbl->ops;
+	struct nbl_resource_ops *res_ops = disp_mgt->res_ops_tbl->ops;
+	struct nbl_resource_mgt *p = disp_mgt->res_ops_tbl->priv;
+	struct device *dev = disp_mgt->common->dev;
+	struct nbl_chan_param_cfg_msix_map param = { 0 };
+	struct nbl_chan_ack_info chan_ack;
+	int err = NBL_CHAN_RESP_OK;
+	int copy_len;
+	int ret;
+
+	copy_len = data_len < sizeof(param) ? data_len : sizeof(param);
+	memcpy(&param, data, copy_len);
+	ret = NBL_OPS_CALL_LOCK_RET(disp_mgt, res_ops->configure_msix_map, p,
+				    src_id, le16_to_cpu(param.num_net_msix),
+				    le16_to_cpu(param.num_others_msix),
+				    le16_to_cpu(param.msix_mask_en));
+	if (ret)
+		err = NBL_CHAN_RESP_ERR;
+
+	NBL_CHAN_ACK(chan_ack, src_id, NBL_CHAN_MSG_CONFIGURE_MSIX_MAP, msg_id,
+		     err, NULL, 0);
+	ret = chan_ops->send_ack(disp_mgt->chan_ops_tbl->priv, &chan_ack);
+	if (ret)
+		dev_err(dev,
+			"channel send ack failed with ret: %d, msg_type: %d\n",
+			ret, NBL_CHAN_MSG_CONFIGURE_MSIX_MAP);
+}
+
+static int nbl_disp_chan_destroy_msix_map_req(struct nbl_dispatch_mgt *disp_mgt)
+{
+	struct nbl_channel_ops *chan_ops = disp_mgt->chan_ops_tbl->ops;
+	struct nbl_common_info *common = disp_mgt->common;
+	struct nbl_chan_send_info chan_send;
+
+	NBL_CHAN_SEND(chan_send, common->mgt_pf, NBL_CHAN_MSG_DESTROY_MSIX_MAP,
+		      NULL, 0, NULL, 0, 1);
+	return chan_ops->send_msg(disp_mgt->chan_ops_tbl->priv, &chan_send);
+}
+
+static void nbl_disp_chan_destroy_msix_map_resp(void *priv, u16 src_id,
+						u16 msg_id, void *data,
+						u32 data_len)
+{
+	struct nbl_dispatch_mgt *disp_mgt = (struct nbl_dispatch_mgt *)priv;
+	struct nbl_channel_ops *chan_ops = disp_mgt->chan_ops_tbl->ops;
+	struct nbl_resource_ops *res_ops = disp_mgt->res_ops_tbl->ops;
+	struct nbl_resource_mgt *p = disp_mgt->res_ops_tbl->priv;
+	struct device *dev = disp_mgt->common->dev;
+	struct nbl_chan_ack_info chan_ack;
+	int err = NBL_CHAN_RESP_OK;
+	int ret;
+
+	ret = NBL_OPS_CALL_LOCK_RET(disp_mgt, res_ops->destroy_msix_map, p,
+				    src_id);
+	if (ret)
+		err = NBL_CHAN_RESP_ERR;
+
+	NBL_CHAN_ACK(chan_ack, src_id, NBL_CHAN_MSG_DESTROY_MSIX_MAP, msg_id,
+		     err, NULL, 0);
+	ret = chan_ops->send_ack(disp_mgt->chan_ops_tbl->priv, &chan_ack);
+	if (ret)
+		dev_err(dev,
+			"channel send ack failed with ret: %d, msg_type: %d\n",
+			ret, NBL_CHAN_MSG_DESTROY_MSIX_MAP);
+}
+
+static int
+nbl_disp_chan_set_mailbox_irq_req(struct nbl_dispatch_mgt *disp_mgt,
+				  u16 vector_id, bool enable_msix)
+{
+	struct nbl_channel_ops *chan_ops = disp_mgt->chan_ops_tbl->ops;
+	struct nbl_chan_param_set_mailbox_irq param = { 0 };
+	struct nbl_common_info *common = disp_mgt->common;
+	struct nbl_chan_send_info chan_send;
+
+	param.vector_id = cpu_to_le16(vector_id);
+	param.enable_msix = enable_msix;
+
+	NBL_CHAN_SEND(chan_send, common->mgt_pf,
+		      NBL_CHAN_MSG_MAILBOX_ENABLE_IRQ, &param, sizeof(param),
+		      NULL, 0, 1);
+	return chan_ops->send_msg(disp_mgt->chan_ops_tbl->priv, &chan_send);
+}
+
+static void nbl_disp_chan_set_mailbox_irq_resp(void *priv, u16 src_id,
+					       u16 msg_id, void *data,
+					       u32 data_len)
+{
+	struct nbl_dispatch_mgt *disp_mgt = (struct nbl_dispatch_mgt *)priv;
+	struct nbl_channel_ops *chan_ops = disp_mgt->chan_ops_tbl->ops;
+	struct nbl_resource_ops *res_ops = disp_mgt->res_ops_tbl->ops;
+	struct nbl_resource_mgt *p = disp_mgt->res_ops_tbl->priv;
+	struct nbl_chan_param_set_mailbox_irq param = {0};
+	struct device *dev = disp_mgt->common->dev;
+	struct nbl_chan_ack_info chan_ack;
+	int err = NBL_CHAN_RESP_OK;
+	bool enable_msix;
+	u16 vector_id;
+	int copy_len;
+	int ret;
+
+	copy_len = data_len < sizeof(param) ? data_len : sizeof(param);
+	memcpy(&param, data, copy_len);
+	vector_id = le16_to_cpu(param.vector_id);
+	enable_msix = !!param.enable_msix;
+	ret = NBL_OPS_CALL_LOCK_RET(disp_mgt, res_ops->set_mailbox_irq, p,
+				    src_id, vector_id, enable_msix);
+	if (ret)
+		err = NBL_CHAN_RESP_ERR;
+
+	NBL_CHAN_ACK(chan_ack, src_id, NBL_CHAN_MSG_MAILBOX_ENABLE_IRQ, msg_id,
+		     err, NULL, 0);
+	ret = chan_ops->send_ack(disp_mgt->chan_ops_tbl->priv, &chan_ack);
+	if (ret)
+		dev_err(dev,
+			"channel send ack failed with ret: %d, msg_type: %d\n",
+			ret, NBL_CHAN_MSG_MAILBOX_ENABLE_IRQ);
+}
+
+static int nbl_disp_destroy_msix_map(struct nbl_dispatch_mgt *disp_mgt)
+{
+	struct nbl_resource_ops *res_ops = disp_mgt->res_ops_tbl->ops;
+	struct nbl_resource_mgt *p = disp_mgt->res_ops_tbl->priv;
+
+	return NBL_OPS_CALL_LOCK_RET(disp_mgt, res_ops->destroy_msix_map, p, 0);
+}
+
+static int nbl_disp_set_mailbox_irq(struct nbl_dispatch_mgt *disp_mgt,
+				    u16 vector_id, bool enable_msix)
+{
+	struct nbl_resource_ops *res_ops = disp_mgt->res_ops_tbl->ops;
+	struct nbl_resource_mgt *p = disp_mgt->res_ops_tbl->priv;
+
+	return NBL_OPS_CALL_LOCK_RET(disp_mgt, res_ops->set_mailbox_irq, p,
+				     0, vector_id, enable_msix);
+}
+
+static u16 nbl_disp_get_vsi_id(struct nbl_dispatch_mgt *disp_mgt, u16 type)
+{
+	struct nbl_resource_ops *res_ops = disp_mgt->res_ops_tbl->ops;
+	struct nbl_resource_mgt *p = disp_mgt->res_ops_tbl->priv;
+	struct nbl_common_info *common = disp_mgt->common;
+
+	return NBL_OPS_CALL_RET(res_ops->get_vsi_id, (p, common->mgt_pf, type));
+}
+
+static int nbl_disp_get_eth_id(struct nbl_dispatch_mgt *disp_mgt, u16 vsi_id,
+			       u8 *eth_num, u8 *eth_id, u8 *logic_eth_id)
+{
+	struct nbl_resource_ops *res_ops = disp_mgt->res_ops_tbl->ops;
+	struct nbl_resource_mgt *p = disp_mgt->res_ops_tbl->priv;
+
+	return NBL_OPS_CALL_RET(res_ops->get_eth_id,
+		     (p, vsi_id, eth_num, eth_id, logic_eth_id));
+}
+
+/* NBL_DISP_SET_OPS(disp_op_name, func, ctrl_lvl, msg_type, msg_req, msg_resp)
+ * ctrl_lvl is to define when this disp_op should go directly to res_op,
+ * not sending a channel msg.
+ * Use X Macros to reduce codes in channel_op and disp_op setup/remove
+ */
+#define NBL_DISP_OPS_TBL						\
+do {									\
+	NBL_DISP_SET_OPS(init_chip_module, nbl_disp_init_chip_module,	\
+			 NBL_DISP_CTRL_LVL_MGT, -1, NULL, NULL);	\
+	NBL_DISP_SET_OPS(deinit_chip_module,				\
+			 nbl_disp_deinit_chip_module,			\
+			 NBL_DISP_CTRL_LVL_MGT, -1, NULL, NULL);	\
+	NBL_DISP_SET_OPS(configure_msix_map,				\
+			 nbl_disp_configure_msix_map,			\
+			 NBL_DISP_CTRL_LVL_MGT,				\
+			 NBL_CHAN_MSG_CONFIGURE_MSIX_MAP,		\
+			 nbl_disp_chan_configure_msix_map_req,		\
+			 nbl_disp_chan_configure_msix_map_resp);	\
+	NBL_DISP_SET_OPS(destroy_msix_map, nbl_disp_destroy_msix_map,	\
+			 NBL_DISP_CTRL_LVL_MGT,				\
+			 NBL_CHAN_MSG_DESTROY_MSIX_MAP,			\
+			 nbl_disp_chan_destroy_msix_map_req,		\
+			 nbl_disp_chan_destroy_msix_map_resp);		\
+	NBL_DISP_SET_OPS(set_mailbox_irq,				\
+			 nbl_disp_set_mailbox_irq,			\
+			 NBL_DISP_CTRL_LVL_MGT,				\
+			 NBL_CHAN_MSG_MAILBOX_ENABLE_IRQ,		\
+			 nbl_disp_chan_set_mailbox_irq_req,		\
+			 nbl_disp_chan_set_mailbox_irq_resp);	\
+	NBL_DISP_SET_OPS(get_vsi_id, nbl_disp_get_vsi_id,		\
+			 NBL_DISP_CTRL_LVL_MGT, NBL_CHAN_MSG_GET_VSI_ID,\
+			 nbl_disp_chan_get_vsi_id_req,			\
+			 nbl_disp_chan_get_vsi_id_resp);		\
+	NBL_DISP_SET_OPS(get_eth_id, nbl_disp_get_eth_id,		\
+			 NBL_DISP_CTRL_LVL_MGT, NBL_CHAN_MSG_GET_ETH_ID,\
+			 nbl_disp_chan_get_eth_id_req,			\
+			 nbl_disp_chan_get_eth_id_resp);		\
+} while (0)
+
+/* Structure starts here, adding an op should not modify anything below */
+static int nbl_disp_setup_msg(struct nbl_dispatch_mgt *disp_mgt)
+{
+	struct nbl_dispatch_ops *disp_ops = disp_mgt->disp_ops_tbl->ops;
+	struct nbl_channel_ops *chan_ops = disp_mgt->chan_ops_tbl->ops;
+	struct nbl_channel_mgt *p = disp_mgt->chan_ops_tbl->priv;
+	int ret = 0;
+	int _ret;
+
+	mutex_init(&disp_mgt->ops_mutex_lock);
+
+#define NBL_DISP_SET_OPS(disp_op, func, ctrl, msg_type, msg_req, resp) \
+do {									\
+	typeof(msg_type) _msg_type = (msg_type);			\
+	typeof(ctrl) _ctrl_lvl = (ctrl);				\
+	(void)(disp_ops->NBL_NAME(disp_op));				\
+	(void)(func);							\
+	(void)(msg_req);						\
+	(void)_ctrl_lvl;						\
+	if (_msg_type >= 0) {						\
+		_ret = chan_ops->register_msg(p, _msg_type, resp, disp_mgt);\
+		if (_ret < 0 && !ret)					\
+			ret = _ret;					\
+	}								\
+} while (0)
+	NBL_DISP_OPS_TBL;
+#undef  NBL_DISP_SET_OPS
+	/* On failure, message unregistration is handled in
+	 * nbl_chan_remove_common
+	 */
+	if (ret)
+		mutex_destroy(&disp_mgt->ops_mutex_lock);
+	return ret;
+}
+
+/* Ctrl lvl means that if a certain level is set, then all disp_ops that
+ * declared this lvl will go directly to res_ops, rather than send a
+ * channel msg, and vice versa.
+ */
+static void nbl_disp_setup_ctrl_lvl(struct nbl_dispatch_mgt *disp_mgt, u32 lvl)
+{
+	struct nbl_dispatch_ops *disp_ops = disp_mgt->disp_ops_tbl->ops;
+
+	set_bit(lvl, disp_mgt->ctrl_lvl);
+
+#define NBL_DISP_SET_OPS(disp_op, func, ctrl, msg_type, msg_req, msg_resp) \
+do {									\
+	typeof(msg_type) _msg_type = (msg_type);			\
+	(void)(_msg_type);						\
+	(void)(msg_resp);						\
+	disp_ops->NBL_NAME(disp_op) =					\
+		test_bit(ctrl, disp_mgt->ctrl_lvl) ? func : msg_req;	\
+} while (0)
+	NBL_DISP_OPS_TBL;
+#undef  NBL_DISP_SET_OPS
+}
+
 static struct nbl_dispatch_mgt *
 nbl_disp_setup_disp_mgt(struct nbl_common_info *common)
 {
@@ -71,9 +482,24 @@ int nbl_disp_init(struct nbl_adapter *adapter)
 	adapter->core.disp_mgt = disp_mgt;
 	adapter->intf.dispatch_ops_tbl = disp_ops_tbl;
 
-	return 0;
+	ret = nbl_disp_setup_msg(disp_mgt);
+	if (ret)
+		return ret;
+
+	if (common->has_ctrl)
+		nbl_disp_setup_ctrl_lvl(disp_mgt, NBL_DISP_CTRL_LVL_MGT);
+
+	if (common->has_net)
+		nbl_disp_setup_ctrl_lvl(disp_mgt, NBL_DISP_CTRL_LVL_NET);
+
+	nbl_disp_setup_ctrl_lvl(disp_mgt, NBL_DISP_CTRL_LVL_ALWAYS);
+
+	return ret;
 }
 
 void nbl_disp_remove(struct nbl_adapter *adapter)
 {
+	struct nbl_dispatch_mgt *disp_mgt = adapter->core.disp_mgt;
+
+	mutex_destroy(&disp_mgt->ops_mutex_lock);
 }
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dispatch.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dispatch.h
index fa7f4597febe..3ef5fff59f14 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dispatch.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dispatch.h
@@ -14,12 +14,43 @@
 #include "../nbl_include/nbl_def_common.h"
 #include "../nbl_core.h"
 
+#define NBL_OPS_CALL_LOCK(disp_mgt, func, ...)				\
+do {									\
+	typeof(disp_mgt) _disp_mgt = (disp_mgt);			\
+	typeof(func) _func = (func);					\
+									\
+	mutex_lock(&_disp_mgt->ops_mutex_lock);				\
+									\
+	if (_func)							\
+		_func(__VA_ARGS__);					\
+									\
+	mutex_unlock(&_disp_mgt->ops_mutex_lock);			\
+} while (0)
+
+#define NBL_OPS_CALL_LOCK_RET(disp_mgt, func, ...)			\
+({									\
+	typeof(disp_mgt) _disp_mgt = (disp_mgt);			\
+	typeof(func) _func = (func);					\
+	typeof(_func(__VA_ARGS__)) _ret = 0;				\
+									\
+	mutex_lock(&_disp_mgt->ops_mutex_lock);				\
+									\
+	if (_func)							\
+		_ret = _func(__VA_ARGS__);				\
+									\
+	mutex_unlock(&_disp_mgt->ops_mutex_lock);			\
+									\
+	_ret;								\
+})
+
 struct nbl_dispatch_mgt {
 	struct nbl_common_info *common;
 	struct nbl_resource_ops_tbl *res_ops_tbl;
 	struct nbl_channel_ops_tbl *chan_ops_tbl;
 	struct nbl_dispatch_ops_tbl *disp_ops_tbl;
 	DECLARE_BITMAP(ctrl_lvl, NBL_DISP_CTRL_LVL_MAX);
+	/* use for the caller not in interrupt */
+	struct mutex ops_mutex_lock;
 };
 
 #endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_dispatch.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_dispatch.h
index 7dc3746b350d..18fc15d37500 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_dispatch.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_dispatch.h
@@ -6,6 +6,8 @@
 #ifndef _NBL_DEF_DISPATCH_H_
 #define _NBL_DEF_DISPATCH_H_
 
+#include <linux/types.h>
+
 struct nbl_dispatch_mgt;
 struct nbl_adapter;
 enum {
@@ -17,6 +19,17 @@ enum {
 };
 
 struct nbl_dispatch_ops {
+	int (*init_chip_module)(struct nbl_dispatch_mgt *disp_mgt);
+	void (*deinit_chip_module)(struct nbl_dispatch_mgt *disp_mgt);
+	int (*configure_msix_map)(struct nbl_dispatch_mgt *disp_mgt,
+				  u16 num_net_msix, u16 num_others_msix,
+				  bool net_msix_mask_en);
+	int (*destroy_msix_map)(struct nbl_dispatch_mgt *disp_mgt);
+	int (*set_mailbox_irq)(struct nbl_dispatch_mgt *disp_mgt,
+			       u16 vector_id, bool enable_msix);
+	u16 (*get_vsi_id)(struct nbl_dispatch_mgt *disp_mgt, u16 type);
+	int (*get_eth_id)(struct nbl_dispatch_mgt *disp_mgt, u16 vsi_id,
+			  u8 *eth_mode, u8 *eth_id, u8 *logic_eth_id);
 };
 
 struct nbl_dispatch_ops_tbl {
-- 
2.47.3


^ permalink raw reply related

* [PATCH v15 net-next 02/11] net/nebula-matrix: add our driver architecture
From: illusion.wang @ 2026-05-20  3:29 UTC (permalink / raw)
  To: dimon.zhao, illusion.wang, alvin.wang, sam.chen, netdev
  Cc: andrew+netdev, corbet, kuba, horms, linux-doc, pabeni,
	vadim.fedorenko, lukas.bulwahn, edumazet, enelsonmoore, skhan,
	hkallweit1, open list
In-Reply-To: <20260520032950.4874-1-illusion.wang@nebula-matrix.com>

This commit introduces the baseline driver architecture for the
nebula-matrix networking device. It establishes the Hardware, Channel,
Resource, Dispatch, and Device layers for device management.

our driver architecture:
Hardware (HW), Channel, Resource, Dispatch, and Device Layer
Struct Initialization/Deinitialization, and Operation Set Registration/
Unregistration

Our driver architecture is relatively complex because the code is highly
reusable and designed to support multiple features. Additionally, the
codebase supports multiple chip variants, each with distinct
hardware-software interactions.
To ensure compatibility, our architecture is divided into the following
layers:

1. Dev Layer (Device Layer)
The top-level business logic layer where all operations are
device-centric. Every operation is performed relative to the device
context. The intergration of base functions encompasses:
management(ctrl only for leonis pf0), network(net_dev,this time not
contained),common.

2. Dispatch Layer
The distribution from services to specific data operations is mainly
divided into two types: direct pass-through and handling by the
management PF. It shields the upper layer from the differences in
specific underlying locations.
It describes the processing locations and paths of the services.

3. Resource Layer
Handles tasks dispatched from Dispatch Layer. These tasks fall into two
categories:
3.1 Hardware control
The Resource Layer further invokes the HW Layer when hardware access is
needed, as only the HW Layer has OS-level privileges.
3.2 Software resource management
Operations like packet statistics collection that don't require hardware
access.

4. HW Layer (Hardware Layer)
Serves the Resource Layer by interacting with different hardware
chipsets.Writes to hardware registers to drive the hardware based on
Resource Layer directives.

5. Channel Layer

Handle communication between PF0(has ctrl func) and other PF,and provide
basic interaction channels.

6. Common Layer
Provides fundamental services

Signed-off-by: illusion.wang <illusion.wang@nebula-matrix.com>
---
 .../net/ethernet/nebula-matrix/nbl/Makefile   |   7 +-
 .../nbl/nbl_channel/nbl_channel.c             |  78 +++++++
 .../nbl/nbl_channel/nbl_channel.h             |  29 +++
 .../net/ethernet/nebula-matrix/nbl/nbl_core.h |  43 ++++
 .../nebula-matrix/nbl/nbl_core/nbl_dev.c      |  56 ++++++
 .../nebula-matrix/nbl/nbl_core/nbl_dev.h      |  27 +++
 .../nebula-matrix/nbl/nbl_core/nbl_dispatch.c |  79 ++++++++
 .../nebula-matrix/nbl/nbl_core/nbl_dispatch.h |  25 +++
 .../nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c  | 141 +++++++++++++
 .../nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h  |  14 ++
 .../nbl_hw_leonis/nbl_resource_leonis.c       |  87 ++++++++
 .../nbl_hw_leonis/nbl_resource_leonis.h       |  10 +
 .../nebula-matrix/nbl/nbl_hw/nbl_hw_reg.h     |  72 +++++++
 .../nebula-matrix/nbl/nbl_hw/nbl_resource.h   |  30 +++
 .../nbl/nbl_include/nbl_def_channel.h         |  26 +++
 .../nbl/nbl_include/nbl_def_common.h          |  35 ++++
 .../nbl/nbl_include/nbl_def_dev.h             |  16 ++
 .../nbl/nbl_include/nbl_def_dispatch.h        |  29 +++
 .../nbl/nbl_include/nbl_def_hw.h              |  22 ++
 .../nbl/nbl_include/nbl_def_resource.h        |  22 ++
 .../nbl/nbl_include/nbl_include.h             |  11 +
 .../nbl/nbl_include/nbl_product_base.h        |  19 ++
 .../net/ethernet/nebula-matrix/nbl/nbl_main.c | 190 ++++++++++++++++++
 23 files changed, 1067 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_channel/nbl_channel.c
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_channel/nbl_channel.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.c
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dispatch.c
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dispatch.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.c
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_reg.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_resource.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_channel.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_common.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_dev.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_dispatch.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_hw.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_resource.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_product_base.h

diff --git a/drivers/net/ethernet/nebula-matrix/nbl/Makefile b/drivers/net/ethernet/nebula-matrix/nbl/Makefile
index b90fba239401..271605920396 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/Makefile
+++ b/drivers/net/ethernet/nebula-matrix/nbl/Makefile
@@ -3,4 +3,9 @@
 
 obj-$(CONFIG_NBL) := nbl.o
 
-nbl-objs +=      nbl_main.o
+nbl-objs +=       nbl_channel/nbl_channel.o \
+				nbl_hw/nbl_hw_leonis/nbl_hw_leonis.o \
+				nbl_hw/nbl_hw_leonis/nbl_resource_leonis.o \
+				nbl_core/nbl_dispatch.o \
+				nbl_core/nbl_dev.o \
+				nbl_main.o
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_channel/nbl_channel.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_channel/nbl_channel.c
new file mode 100644
index 000000000000..c7689f0e4029
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_channel/nbl_channel.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+
+#include <linux/device.h>
+#include <linux/pci.h>
+#include "nbl_channel.h"
+
+static struct nbl_channel_ops chan_ops = {
+};
+
+static struct nbl_channel_mgt *
+nbl_chan_setup_chan_mgt(struct nbl_adapter *adapter)
+{
+	struct nbl_hw_ops_tbl *hw_ops_tbl = adapter->intf.hw_ops_tbl;
+	struct nbl_common_info *common = &adapter->common;
+	struct device *dev = &adapter->pdev->dev;
+	struct nbl_channel_mgt *chan_mgt;
+	struct nbl_chan_info *mailbox;
+
+	chan_mgt = devm_kzalloc(dev, sizeof(*chan_mgt), GFP_KERNEL);
+	if (!chan_mgt)
+		return ERR_PTR(-ENOMEM);
+
+	chan_mgt->common = common;
+	chan_mgt->hw_ops_tbl = hw_ops_tbl;
+
+	mailbox = devm_kzalloc(dev, sizeof(*mailbox), GFP_KERNEL);
+	if (!mailbox)
+		return ERR_PTR(-ENOMEM);
+	mailbox->chan_type = NBL_CHAN_TYPE_MAILBOX;
+	chan_mgt->chan_info[NBL_CHAN_TYPE_MAILBOX] = mailbox;
+
+	return chan_mgt;
+}
+
+static struct nbl_channel_ops_tbl *
+nbl_chan_setup_ops(struct device *dev, struct nbl_channel_mgt *chan_mgt)
+{
+	struct nbl_channel_ops_tbl *chan_ops_tbl;
+
+	chan_ops_tbl = devm_kzalloc(dev, sizeof(*chan_ops_tbl), GFP_KERNEL);
+	if (!chan_ops_tbl)
+		return ERR_PTR(-ENOMEM);
+
+	chan_ops_tbl->ops = &chan_ops;
+	chan_ops_tbl->priv = chan_mgt;
+
+	return chan_ops_tbl;
+}
+
+int nbl_chan_init_common(struct nbl_adapter *adap)
+{
+	struct nbl_channel_ops_tbl *chan_ops_tbl;
+	struct device *dev = &adap->pdev->dev;
+	struct nbl_channel_mgt *chan_mgt;
+	int ret;
+
+	chan_mgt = nbl_chan_setup_chan_mgt(adap);
+	if (IS_ERR(chan_mgt)) {
+		ret = PTR_ERR(chan_mgt);
+		return ret;
+	}
+
+	chan_ops_tbl = nbl_chan_setup_ops(dev, chan_mgt);
+	if (IS_ERR(chan_ops_tbl)) {
+		ret = PTR_ERR(chan_ops_tbl);
+		return ret;
+	}
+	adap->intf.channel_ops_tbl = chan_ops_tbl;
+	adap->core.chan_mgt = chan_mgt;
+	return 0;
+}
+
+void nbl_chan_remove_common(struct nbl_adapter *adap)
+{
+}
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_channel/nbl_channel.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_channel/nbl_channel.h
new file mode 100644
index 000000000000..637912d1e806
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_channel/nbl_channel.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+
+#ifndef _NBL_CHANNEL_H_
+#define _NBL_CHANNEL_H_
+
+#include <linux/types.h>
+
+#include "../nbl_include/nbl_include.h"
+#include "../nbl_include/nbl_product_base.h"
+#include "../nbl_include/nbl_def_channel.h"
+#include "../nbl_include/nbl_def_hw.h"
+#include "../nbl_include/nbl_def_common.h"
+#include "../nbl_core.h"
+
+struct nbl_chan_info {
+	u8 chan_type;
+};
+
+struct nbl_channel_mgt {
+	struct nbl_common_info *common;
+	struct nbl_hw_ops_tbl *hw_ops_tbl;
+	struct nbl_chan_info *chan_info[NBL_CHAN_TYPE_MAX];
+	struct nbl_hash_tbl_mgt *handle_hash_tbl;
+};
+
+#endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_core.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_core.h
index c525114297b4..8c186d95d3e7 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_core.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_core.h
@@ -6,6 +6,20 @@
 #ifndef _NBL_CORE_H_
 #define _NBL_CORE_H_
 
+#include <linux/pci.h>
+#include "nbl_include/nbl_include.h"
+#include "nbl_include/nbl_def_common.h"
+
+struct nbl_hw_mgt;
+struct nbl_hw_ops_tbl;
+struct nbl_resource_mgt;
+struct nbl_resource_ops_tbl;
+struct nbl_dispatch_mgt;
+struct nbl_dispatch_ops_tbl;
+struct nbl_channel_ops_tbl;
+struct nbl_channel_mgt;
+struct nbl_dev_mgt;
+
 enum {
 	NBL_CAP_HAS_CTRL_BIT,
 	NBL_CAP_HAS_NET_BIT,
@@ -13,4 +27,33 @@ enum {
 	NBL_CAP_IS_LEONIS_BIT,
 };
 
+struct nbl_interface {
+	struct nbl_hw_ops_tbl *hw_ops_tbl;
+	struct nbl_resource_ops_tbl *resource_ops_tbl;
+	struct nbl_dispatch_ops_tbl *dispatch_ops_tbl;
+	struct nbl_channel_ops_tbl *channel_ops_tbl;
+};
+
+struct nbl_core {
+	struct nbl_hw_mgt *hw_mgt;
+	struct nbl_resource_mgt *res_mgt;
+	struct nbl_dispatch_mgt *disp_mgt;
+	struct nbl_dev_mgt *dev_mgt;
+	struct nbl_channel_mgt *chan_mgt;
+};
+
+struct nbl_adapter {
+	struct pci_dev *pdev;
+	struct nbl_core core;
+	struct nbl_interface intf;
+	struct nbl_common_info common;
+	struct nbl_product_base_ops *product_base_ops;
+};
+
+struct nbl_adapter *nbl_core_init(struct pci_dev *pdev,
+				  struct nbl_init_param *param);
+void nbl_core_remove(struct nbl_adapter *adapter);
+int nbl_core_start(struct nbl_adapter *adapter);
+void nbl_core_stop(struct nbl_adapter *adapter);
+
 #endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.c
new file mode 100644
index 000000000000..5deb21e35f8e
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+#include <linux/device.h>
+#include <linux/pci.h>
+#include "nbl_dev.h"
+
+static struct nbl_dev_mgt *nbl_dev_setup_dev_mgt(struct nbl_common_info *common)
+{
+	struct nbl_dev_mgt *dev_mgt;
+
+	dev_mgt = devm_kzalloc(common->dev, sizeof(*dev_mgt), GFP_KERNEL);
+	if (!dev_mgt)
+		return ERR_PTR(-ENOMEM);
+
+	dev_mgt->common = common;
+	return dev_mgt;
+}
+
+int nbl_dev_init(struct nbl_adapter *adapter)
+{
+	struct nbl_common_info *common = &adapter->common;
+	struct nbl_dispatch_ops_tbl *disp_ops_tbl =
+		adapter->intf.dispatch_ops_tbl;
+	struct nbl_channel_ops_tbl *chan_ops_tbl =
+		adapter->intf.channel_ops_tbl;
+	struct nbl_dev_mgt *dev_mgt;
+	int ret;
+
+	dev_mgt = nbl_dev_setup_dev_mgt(common);
+	if (IS_ERR(dev_mgt)) {
+		ret = PTR_ERR(dev_mgt);
+		return ret;
+	}
+
+	dev_mgt->disp_ops_tbl = disp_ops_tbl;
+	dev_mgt->chan_ops_tbl = chan_ops_tbl;
+	adapter->core.dev_mgt = dev_mgt;
+
+	return 0;
+}
+
+void nbl_dev_remove(struct nbl_adapter *adapter)
+{
+}
+
+/* ----------  Dev start process  ---------- */
+int nbl_dev_start(struct nbl_adapter *adapter)
+{
+	return 0;
+}
+
+void nbl_dev_stop(struct nbl_adapter *adapter)
+{
+}
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.h
new file mode 100644
index 000000000000..9b71092b99a0
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+
+#ifndef _NBL_DEV_H_
+#define _NBL_DEV_H_
+
+#include <linux/types.h>
+
+#include "../nbl_include/nbl_include.h"
+#include "../nbl_include/nbl_product_base.h"
+#include "../nbl_include/nbl_def_channel.h"
+#include "../nbl_include/nbl_def_hw.h"
+#include "../nbl_include/nbl_def_resource.h"
+#include "../nbl_include/nbl_def_dispatch.h"
+#include "../nbl_include/nbl_def_dev.h"
+#include "../nbl_include/nbl_def_common.h"
+#include "../nbl_core.h"
+
+struct nbl_dev_mgt {
+	struct nbl_common_info *common;
+	struct nbl_dispatch_ops_tbl *disp_ops_tbl;
+	struct nbl_channel_ops_tbl *chan_ops_tbl;
+};
+
+#endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dispatch.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dispatch.c
new file mode 100644
index 000000000000..281d33051185
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dispatch.c
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+#include <linux/device.h>
+#include <linux/pci.h>
+#include "nbl_dispatch.h"
+
+static struct nbl_dispatch_mgt *
+nbl_disp_setup_disp_mgt(struct nbl_common_info *common)
+{
+	struct nbl_dispatch_mgt *disp_mgt;
+	struct device *dev = common->dev;
+
+	disp_mgt = devm_kzalloc(dev, sizeof(*disp_mgt), GFP_KERNEL);
+	if (!disp_mgt)
+		return ERR_PTR(-ENOMEM);
+
+	disp_mgt->common = common;
+	return disp_mgt;
+}
+
+static struct nbl_dispatch_ops_tbl *
+nbl_disp_setup_ops(struct device *dev, struct nbl_dispatch_mgt *disp_mgt)
+{
+	struct nbl_dispatch_ops_tbl *disp_ops_tbl;
+	struct nbl_dispatch_ops *disp_ops;
+
+	disp_ops_tbl = devm_kzalloc(dev, sizeof(*disp_ops_tbl), GFP_KERNEL);
+	if (!disp_ops_tbl)
+		return ERR_PTR(-ENOMEM);
+
+	disp_ops =
+		devm_kzalloc(dev, sizeof(*disp_ops), GFP_KERNEL);
+	if (!disp_ops)
+		return ERR_PTR(-ENOMEM);
+
+	disp_ops_tbl->ops = disp_ops;
+	disp_ops_tbl->priv = disp_mgt;
+
+	return disp_ops_tbl;
+}
+
+int nbl_disp_init(struct nbl_adapter *adapter)
+{
+	struct nbl_common_info *common = &adapter->common;
+	struct nbl_dispatch_ops_tbl *disp_ops_tbl;
+	struct nbl_resource_ops_tbl *res_ops_tbl =
+		adapter->intf.resource_ops_tbl;
+	struct nbl_channel_ops_tbl *chan_ops_tbl =
+		adapter->intf.channel_ops_tbl;
+	struct device *dev = &adapter->pdev->dev;
+	struct nbl_dispatch_mgt *disp_mgt;
+	int ret;
+
+	disp_mgt = nbl_disp_setup_disp_mgt(common);
+	if (IS_ERR(disp_mgt)) {
+		ret = PTR_ERR(disp_mgt);
+		return ret;
+	}
+
+	disp_ops_tbl = nbl_disp_setup_ops(dev, disp_mgt);
+	if (IS_ERR(disp_ops_tbl)) {
+		ret = PTR_ERR(disp_ops_tbl);
+		return ret;
+	}
+
+	disp_mgt->res_ops_tbl = res_ops_tbl;
+	disp_mgt->chan_ops_tbl = chan_ops_tbl;
+	disp_mgt->disp_ops_tbl = disp_ops_tbl;
+	adapter->core.disp_mgt = disp_mgt;
+	adapter->intf.dispatch_ops_tbl = disp_ops_tbl;
+
+	return 0;
+}
+
+void nbl_disp_remove(struct nbl_adapter *adapter)
+{
+}
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dispatch.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dispatch.h
new file mode 100644
index 000000000000..fa7f4597febe
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dispatch.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+
+#ifndef _NBL_DISPATCH_H_
+#define _NBL_DISPATCH_H_
+#include "../nbl_include/nbl_include.h"
+#include "../nbl_include/nbl_product_base.h"
+#include "../nbl_include/nbl_def_channel.h"
+#include "../nbl_include/nbl_def_hw.h"
+#include "../nbl_include/nbl_def_resource.h"
+#include "../nbl_include/nbl_def_dispatch.h"
+#include "../nbl_include/nbl_def_common.h"
+#include "../nbl_core.h"
+
+struct nbl_dispatch_mgt {
+	struct nbl_common_info *common;
+	struct nbl_resource_ops_tbl *res_ops_tbl;
+	struct nbl_channel_ops_tbl *chan_ops_tbl;
+	struct nbl_dispatch_ops_tbl *disp_ops_tbl;
+	DECLARE_BITMAP(ctrl_lvl, NBL_DISP_CTRL_LVL_MAX);
+};
+
+#endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c
new file mode 100644
index 000000000000..bf4feaea4b4a
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/bits.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include "nbl_hw_leonis.h"
+
+static struct nbl_hw_ops hw_ops = {
+};
+
+/* Structure starts here, adding an op should not modify anything below */
+static struct nbl_hw_mgt *nbl_hw_setup_hw_mgt(struct nbl_common_info *common)
+{
+	struct device *dev = common->dev;
+	struct nbl_hw_mgt *hw_mgt;
+
+	hw_mgt = devm_kzalloc(dev, sizeof(*hw_mgt), GFP_KERNEL);
+	if (!hw_mgt)
+		return ERR_PTR(-ENOMEM);
+
+	hw_mgt->common = common;
+
+	return hw_mgt;
+}
+
+static struct nbl_hw_ops_tbl *nbl_hw_setup_ops(struct nbl_common_info *common,
+					       struct nbl_hw_mgt *hw_mgt)
+{
+	struct nbl_hw_ops_tbl *hw_ops_tbl;
+	struct device *dev;
+
+	dev = common->dev;
+	hw_ops_tbl =
+		devm_kzalloc(dev, sizeof(*hw_ops_tbl), GFP_KERNEL);
+	if (!hw_ops_tbl)
+		return ERR_PTR(-ENOMEM);
+
+	hw_ops_tbl->ops = &hw_ops;
+	hw_ops_tbl->priv = hw_mgt;
+
+	return hw_ops_tbl;
+}
+
+int nbl_hw_init_leonis(struct nbl_adapter *adapter)
+{
+	struct nbl_common_info *common = &adapter->common;
+	struct pci_dev *pdev = common->pdev;
+	struct nbl_hw_ops_tbl *hw_ops_tbl;
+	struct nbl_hw_mgt *hw_mgt;
+	resource_size_t bar_len;
+	unsigned long bar_start;
+	int bar_mask;
+	int ret;
+
+	hw_mgt = nbl_hw_setup_hw_mgt(common);
+	if (IS_ERR(hw_mgt)) {
+		ret = PTR_ERR(hw_mgt);
+		goto setup_mgt_fail;
+	}
+	bar_mask = BIT(NBL_MEMORY_BAR) | BIT(NBL_MAILBOX_BAR);
+	ret = pci_request_selected_regions(pdev, bar_mask, NBL_DRIVER_NAME);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"Request memory bar and mailbox bar failed, err = %d\n",
+			ret);
+		goto request_bar_region_fail;
+	}
+
+	bar_len = pci_resource_len(pdev, NBL_MEMORY_BAR);
+	bar_start  = pci_resource_start(pdev, NBL_MEMORY_BAR);
+	if (!(pci_resource_flags(pdev, NBL_MEMORY_BAR) & IORESOURCE_MEM) ||
+	    bar_len <= NBL_RDMA_NOTIFY_OFF) {
+		dev_err(&pdev->dev, "Invalid BAR: unassigned or length too small\n");
+		ret = -EINVAL;
+		goto ioremap_err;
+	}
+	if (common->has_ctrl) {
+		hw_mgt->hw_addr =
+			ioremap(bar_start,
+				bar_len - NBL_RDMA_NOTIFY_OFF);
+		hw_mgt->hw_size = bar_len - NBL_RDMA_NOTIFY_OFF;
+	} else {
+		hw_mgt->hw_addr =
+			ioremap(bar_start,
+				NBL_RDMA_NOTIFY_OFF);
+		hw_mgt->hw_size = NBL_RDMA_NOTIFY_OFF;
+	}
+	if (!hw_mgt->hw_addr) {
+		dev_err(&pdev->dev, "Memory bar ioremap failed\n");
+		ret = -EIO;
+		goto ioremap_err;
+	}
+
+	hw_mgt->mailbox_bar_hw_addr = pci_ioremap_bar(pdev, NBL_MAILBOX_BAR);
+	if (!hw_mgt->mailbox_bar_hw_addr) {
+		dev_err(&pdev->dev, "Mailbox bar ioremap failed\n");
+		ret = -EIO;
+		goto mailbox_ioremap_err;
+	}
+
+	hw_ops_tbl = nbl_hw_setup_ops(common, hw_mgt);
+	if (IS_ERR(hw_ops_tbl)) {
+		ret = PTR_ERR(hw_ops_tbl);
+		goto setup_ops_fail;
+	}
+	hw_mgt->notify_offset = 0;
+	adapter->intf.hw_ops_tbl = hw_ops_tbl;
+	adapter->core.hw_mgt = hw_mgt;
+
+	return 0;
+
+setup_ops_fail:
+	iounmap(hw_mgt->mailbox_bar_hw_addr);
+mailbox_ioremap_err:
+	iounmap(hw_mgt->hw_addr);
+ioremap_err:
+	pci_release_selected_regions(pdev, bar_mask);
+request_bar_region_fail:
+setup_mgt_fail:
+	return ret;
+}
+
+void nbl_hw_remove_leonis(struct nbl_adapter *adapter)
+{
+	int bar_mask = BIT(NBL_MEMORY_BAR) | BIT(NBL_MAILBOX_BAR);
+	struct nbl_common_info *common = &adapter->common;
+	struct nbl_hw_mgt *hw_mgt = adapter->core.hw_mgt;
+	u8 __iomem *hw_addr = hw_mgt->hw_addr;
+	struct pci_dev *pdev = common->pdev;
+	u8 __iomem *mailbox_bar_hw_addr;
+
+	mailbox_bar_hw_addr = hw_mgt->mailbox_bar_hw_addr;
+
+	iounmap(mailbox_bar_hw_addr);
+	iounmap(hw_addr);
+	pci_release_selected_regions(pdev, bar_mask);
+}
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h
new file mode 100644
index 000000000000..77c67b67ba31
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+
+#ifndef _NBL_HW_LEONIS_H_
+#define _NBL_HW_LEONIS_H_
+
+#include <linux/types.h>
+
+#include "../../nbl_include/nbl_include.h"
+#include "../nbl_hw_reg.h"
+
+#endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.c
new file mode 100644
index 000000000000..4b4f8e2e7fe7
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+#include <linux/device.h>
+#include <linux/pci.h>
+#include "nbl_resource_leonis.h"
+
+static struct nbl_resource_ops res_ops = {
+};
+
+static struct nbl_resource_mgt *
+nbl_res_setup_res_mgt(struct nbl_common_info *common)
+{
+	struct nbl_resource_info *resource_info;
+	struct nbl_resource_mgt *res_mgt;
+	struct device *dev = common->dev;
+
+	res_mgt = devm_kzalloc(dev, sizeof(*res_mgt), GFP_KERNEL);
+	if (!res_mgt)
+		return ERR_PTR(-ENOMEM);
+	res_mgt->common = common;
+
+	resource_info =
+		devm_kzalloc(dev, sizeof(*resource_info), GFP_KERNEL);
+	if (!resource_info)
+		return ERR_PTR(-ENOMEM);
+	res_mgt->resource_info = resource_info;
+
+	return res_mgt;
+}
+
+static struct nbl_resource_ops_tbl *
+nbl_res_setup_ops(struct device *dev, struct nbl_resource_mgt *res_mgt)
+{
+	struct nbl_resource_ops_tbl *res_ops_tbl;
+
+	res_ops_tbl = devm_kzalloc(dev, sizeof(*res_ops_tbl), GFP_KERNEL);
+	if (!res_ops_tbl)
+		return ERR_PTR(-ENOMEM);
+
+	res_ops_tbl->ops = &res_ops;
+	res_ops_tbl->priv = res_mgt;
+
+	return res_ops_tbl;
+}
+
+static int nbl_res_start(struct nbl_resource_mgt *res_mgt)
+{
+	return 0;
+}
+
+int nbl_res_init_leonis(struct nbl_adapter *adap)
+{
+	struct nbl_channel_ops_tbl *chan_ops_tbl = adap->intf.channel_ops_tbl;
+	struct nbl_hw_ops_tbl *hw_ops_tbl = adap->intf.hw_ops_tbl;
+	struct nbl_common_info *common = &adap->common;
+	struct nbl_resource_ops_tbl *res_ops_tbl;
+	struct device *dev = &adap->pdev->dev;
+	struct nbl_resource_mgt *res_mgt;
+	int ret;
+
+	res_mgt = nbl_res_setup_res_mgt(common);
+	if (IS_ERR(res_mgt)) {
+		ret = PTR_ERR(res_mgt);
+		return ret;
+	}
+	res_mgt->chan_ops_tbl = chan_ops_tbl;
+	res_mgt->hw_ops_tbl = hw_ops_tbl;
+
+	ret = nbl_res_start(res_mgt);
+	if (ret)
+		return ret;
+
+	res_ops_tbl = nbl_res_setup_ops(dev, res_mgt);
+	if (IS_ERR(res_ops_tbl)) {
+		ret = PTR_ERR(res_ops_tbl);
+		return ret;
+	}
+	adap->intf.resource_ops_tbl = res_ops_tbl;
+	adap->core.res_mgt = res_mgt;
+	return 0;
+}
+
+void nbl_res_remove_leonis(struct nbl_adapter *adap)
+{
+}
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.h
new file mode 100644
index 000000000000..4e61a5c141e5
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+
+#ifndef _NBL_RESOURCE_LEONIS_H_
+#define _NBL_RESOURCE_LEONIS_H_
+
+#include "../nbl_resource.h"
+#endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_reg.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_reg.h
new file mode 100644
index 000000000000..fbea8d074064
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_reg.h
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+
+#ifndef _NBL_HW_REG_H_
+#define _NBL_HW_REG_H_
+
+#include <linux/types.h>
+
+#include "../nbl_include/nbl_product_base.h"
+#include "../nbl_include/nbl_def_channel.h"
+#include "../nbl_include/nbl_def_hw.h"
+#include "../nbl_include/nbl_def_common.h"
+#include "../nbl_core.h"
+
+#define NBL_MEMORY_BAR				0
+#define NBL_MAILBOX_BAR				2
+#define NBL_RDMA_NOTIFY_OFF			8192
+#define NBL_HW_DUMMY_REG			0x1300904
+
+struct nbl_hw_mgt {
+	struct nbl_common_info *common;
+	u8 __iomem *hw_addr;
+	u8 __iomem *mailbox_bar_hw_addr;
+	u64 notify_offset;
+	resource_size_t hw_size;
+};
+
+static inline u32 rd32(u8 __iomem *addr, u64 reg)
+{
+	return readl(addr + reg);
+}
+
+static inline void wr32(u8 __iomem *addr, u64 reg, u32 value)
+{
+	writel(value, addr + reg);
+}
+
+static inline void nbl_hw_wr32(struct nbl_hw_mgt *hw_mgt, u64 reg, u32 value)
+{
+	/* Used for emu, make sure that we won't write too frequently */
+	wr32(hw_mgt->hw_addr, reg, value);
+}
+
+static inline u32 nbl_hw_rd32(struct nbl_hw_mgt *hw_mgt, u64 reg)
+{
+	return rd32(hw_mgt->hw_addr, reg);
+}
+
+static inline void nbl_mbx_wr32(struct nbl_hw_mgt *hw_mgt, u64 reg, u32 value)
+{
+	writel(value, hw_mgt->mailbox_bar_hw_addr + reg);
+}
+
+/*
+ * Only call this when has_ctrl=true, which maps enough space
+ * (bar_len - 8192) to cover NBL_HW_DUMMY_REG (0x1300904).
+ * The flow/design guarantees this is only called in the
+ * has_ctrl path.
+ */
+static inline void nbl_flush_writes(struct nbl_hw_mgt *hw_mgt)
+{
+	nbl_hw_rd32(hw_mgt, NBL_HW_DUMMY_REG);
+}
+
+static inline u32 nbl_mbx_rd32(struct nbl_hw_mgt *hw_mgt, u64 reg)
+{
+	return readl(hw_mgt->mailbox_bar_hw_addr + reg);
+}
+
+#endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_resource.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_resource.h
new file mode 100644
index 000000000000..e08b6237da32
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_resource.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+
+#ifndef _NBL_RESOURCE_H_
+#define _NBL_RESOURCE_H_
+
+#include <linux/types.h>
+
+#include "../nbl_include/nbl_include.h"
+#include "../nbl_include/nbl_product_base.h"
+#include "../nbl_include/nbl_def_channel.h"
+#include "../nbl_include/nbl_def_hw.h"
+#include "../nbl_include/nbl_def_resource.h"
+#include "../nbl_include/nbl_def_common.h"
+#include "../nbl_core.h"
+
+struct nbl_resource_info {
+};
+
+struct nbl_resource_mgt {
+	struct nbl_common_info *common;
+	struct nbl_resource_info *resource_info;
+	struct nbl_channel_ops_tbl *chan_ops_tbl;
+	struct nbl_hw_ops_tbl *hw_ops_tbl;
+	struct nbl_interrupt_mgt *intr_mgt;
+};
+
+#endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_channel.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_channel.h
new file mode 100644
index 000000000000..ff03a53b9f5d
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_channel.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+
+#ifndef _NBL_DEF_CHANNEL_H_
+#define _NBL_DEF_CHANNEL_H_
+
+struct nbl_channel_mgt;
+struct nbl_adapter;
+enum nbl_channel_type {
+	NBL_CHAN_TYPE_MAILBOX,
+	NBL_CHAN_TYPE_MAX
+};
+
+struct nbl_channel_ops {
+};
+
+struct nbl_channel_ops_tbl {
+	struct nbl_channel_ops *ops;
+	struct nbl_channel_mgt *priv;
+};
+
+int nbl_chan_init_common(struct nbl_adapter *adapter);
+void nbl_chan_remove_common(struct nbl_adapter *adapter);
+#endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_common.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_common.h
new file mode 100644
index 000000000000..d93da0f22835
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_common.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+
+#ifndef _NBL_DEF_COMMON_H_
+#define _NBL_DEF_COMMON_H_
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/device.h>
+#include "nbl_include.h"
+
+struct nbl_common_info {
+	struct pci_dev *pdev;
+	struct device *dev;
+	u32 msg_enable;
+	u16 vsi_id;
+	u8 eth_id;
+	u8 logic_eth_id;
+	u8 eth_num;
+
+	u8 function;
+	u8 devid;
+	u8 bus;
+	u8 hw_bus;
+	u16 mgt_pf;
+
+	bool pci_using_dac;
+	enum nbl_product_type product_type;
+	u8 has_ctrl;
+	u8 has_net;
+};
+
+#endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_dev.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_dev.h
new file mode 100644
index 000000000000..32e6cce38d39
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_dev.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+
+#ifndef _NBL_DEF_DEV_H_
+#define _NBL_DEF_DEV_H_
+
+struct nbl_adapter;
+
+int nbl_dev_init(struct nbl_adapter *adapter);
+void nbl_dev_remove(struct nbl_adapter *adapter);
+int nbl_dev_start(struct nbl_adapter *adapter);
+void nbl_dev_stop(struct nbl_adapter *adapter);
+
+#endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_dispatch.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_dispatch.h
new file mode 100644
index 000000000000..7dc3746b350d
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_dispatch.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+
+#ifndef _NBL_DEF_DISPATCH_H_
+#define _NBL_DEF_DISPATCH_H_
+
+struct nbl_dispatch_mgt;
+struct nbl_adapter;
+enum {
+	NBL_DISP_CTRL_LVL_NEVER = 0,
+	NBL_DISP_CTRL_LVL_MGT,
+	NBL_DISP_CTRL_LVL_NET,
+	NBL_DISP_CTRL_LVL_ALWAYS,
+	NBL_DISP_CTRL_LVL_MAX,
+};
+
+struct nbl_dispatch_ops {
+};
+
+struct nbl_dispatch_ops_tbl {
+	struct nbl_dispatch_ops *ops;
+	struct nbl_dispatch_mgt *priv;
+};
+
+int nbl_disp_init(struct nbl_adapter *adapter);
+void nbl_disp_remove(struct nbl_adapter *adapter);
+#endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_hw.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_hw.h
new file mode 100644
index 000000000000..168504b30973
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_hw.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+
+#ifndef _NBL_DEF_HW_H_
+#define _NBL_DEF_HW_H_
+
+struct nbl_hw_mgt;
+struct nbl_adapter;
+struct nbl_hw_ops {
+};
+
+struct nbl_hw_ops_tbl {
+	struct nbl_hw_ops *ops;
+	struct nbl_hw_mgt *priv;
+};
+
+int nbl_hw_init_leonis(struct nbl_adapter *adapter);
+void nbl_hw_remove_leonis(struct nbl_adapter *adapter);
+
+#endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_resource.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_resource.h
new file mode 100644
index 000000000000..d55934af5a9a
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_resource.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+
+#ifndef _NBL_DEF_RESOURCE_H_
+#define _NBL_DEF_RESOURCE_H_
+
+struct nbl_resource_mgt;
+struct nbl_adapter;
+
+struct nbl_resource_ops {
+};
+
+struct nbl_resource_ops_tbl {
+	struct nbl_resource_ops *ops;
+	struct nbl_resource_mgt *priv;
+};
+
+int nbl_res_init_leonis(struct nbl_adapter *adapter);
+void nbl_res_remove_leonis(struct nbl_adapter *adapter);
+#endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h
index 1046e6517b15..50f30f756bf3 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h
@@ -11,6 +11,11 @@
 /*  ------  Basic definitions  -------  */
 #define NBL_DRIVER_NAME					"nbl"
 
+enum nbl_product_type {
+	NBL_LEONIS_TYPE,
+	NBL_PRODUCT_MAX,
+};
+
 struct nbl_func_caps {
 	u32 has_ctrl:1;
 	u32 has_net:1;
@@ -18,4 +23,10 @@ struct nbl_func_caps {
 	u32 rsv:29;
 };
 
+struct nbl_init_param {
+	struct nbl_func_caps caps;
+	enum nbl_product_type product_type;
+	bool pci_using_dac;
+};
+
 #endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_product_base.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_product_base.h
new file mode 100644
index 000000000000..fe4245d0ca99
--- /dev/null
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_product_base.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Nebula Matrix Limited.
+ */
+
+#ifndef _NBL_DEF_PRODUCT_BASE_H_
+#define _NBL_DEF_PRODUCT_BASE_H_
+
+struct nbl_adapter;
+struct nbl_product_base_ops {
+	int (*hw_init)(struct nbl_adapter *p);
+	void (*hw_remove)(struct nbl_adapter *p);
+	int (*res_init)(struct nbl_adapter *p);
+	void (*res_remove)(struct nbl_adapter *p);
+	int (*chan_init)(struct nbl_adapter *p);
+	void (*chan_remove)(struct nbl_adapter *p);
+};
+
+#endif
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_main.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_main.c
index 10c3536b327b..4cf3a804d5a5 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_main.c
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_main.c
@@ -6,17 +6,207 @@
 #include <linux/device.h>
 #include <linux/pci.h>
 #include <linux/module.h>
+#include <linux/bits.h>
 #include "nbl_include/nbl_include.h"
+#include "nbl_include/nbl_product_base.h"
+#include "nbl_include/nbl_def_channel.h"
+#include "nbl_include/nbl_def_hw.h"
+#include "nbl_include/nbl_def_resource.h"
+#include "nbl_include/nbl_def_dispatch.h"
+#include "nbl_include/nbl_def_dev.h"
+#include "nbl_include/nbl_def_common.h"
 #include "nbl_core.h"
 
+static struct nbl_product_base_ops nbl_product_base_ops[NBL_PRODUCT_MAX] = {
+	{
+		.hw_init	= nbl_hw_init_leonis,
+		.hw_remove	= nbl_hw_remove_leonis,
+		.res_init	= nbl_res_init_leonis,
+		.res_remove	= nbl_res_remove_leonis,
+		.chan_init	= nbl_chan_init_common,
+		.chan_remove	= nbl_chan_remove_common,
+	},
+};
+
+int nbl_core_start(struct nbl_adapter *adapter)
+{
+	return nbl_dev_start(adapter);
+}
+
+void nbl_core_stop(struct nbl_adapter *adapter)
+{
+	nbl_dev_stop(adapter);
+}
+
+static struct nbl_product_base_ops *
+nbl_core_setup_product_ops(struct nbl_adapter *adapter,
+			   struct nbl_init_param *param)
+{
+	adapter->product_base_ops = &nbl_product_base_ops[param->product_type];
+	return adapter->product_base_ops;
+}
+
+struct nbl_adapter *nbl_core_init(struct pci_dev *pdev,
+				  struct nbl_init_param *param)
+{
+	struct nbl_product_base_ops *product_base_ops;
+	struct nbl_common_info *common;
+	struct nbl_adapter *adapter;
+	int ret;
+
+	adapter = devm_kzalloc(&pdev->dev, sizeof(*adapter), GFP_KERNEL);
+	if (!adapter)
+		return NULL;
+
+	adapter->pdev = pdev;
+	common = &adapter->common;
+
+	common->pdev = pdev;
+	common->dev = &pdev->dev;
+	common->has_ctrl = param->caps.has_ctrl;
+	common->has_net = param->caps.has_net;
+	common->pci_using_dac = param->pci_using_dac;
+	common->function = PCI_FUNC(pdev->devfn);
+	common->devid = PCI_SLOT(pdev->devfn);
+	common->bus = pdev->bus->number;
+	common->product_type = param->product_type;
+
+	product_base_ops = nbl_core_setup_product_ops(adapter, param);
+
+	/*
+	 *every product's hw/chan/res layer has a great difference,
+	 *so call their own init ops
+	 */
+	ret = product_base_ops->hw_init(adapter);
+	if (ret)
+		goto hw_init_fail;
+
+	ret = product_base_ops->chan_init(adapter);
+	if (ret)
+		goto chan_init_fail;
+
+	ret = product_base_ops->res_init(adapter);
+	if (ret)
+		goto res_init_fail;
+
+	ret = nbl_disp_init(adapter);
+	if (ret)
+		goto disp_init_fail;
+
+	ret = nbl_dev_init(adapter);
+	if (ret)
+		goto dev_init_fail;
+	return adapter ? adapter : ERR_PTR(ret);
+
+dev_init_fail:
+	nbl_disp_remove(adapter);
+disp_init_fail:
+	product_base_ops->res_remove(adapter);
+res_init_fail:
+	product_base_ops->chan_remove(adapter);
+chan_init_fail:
+	product_base_ops->hw_remove(adapter);
+hw_init_fail:
+	return ERR_PTR(ret);
+}
+
+void nbl_core_remove(struct nbl_adapter *adapter)
+{
+	struct nbl_product_base_ops *product_base_ops;
+
+	product_base_ops = adapter->product_base_ops;
+	nbl_dev_remove(adapter);
+	nbl_disp_remove(adapter);
+	product_base_ops->res_remove(adapter);
+	product_base_ops->chan_remove(adapter);
+	product_base_ops->hw_remove(adapter);
+}
+
+static void nbl_get_func_param(struct pci_dev *pdev, kernel_ulong_t driver_data,
+			       struct nbl_init_param *param)
+{
+	param->caps.has_ctrl = !!(driver_data & BIT(NBL_CAP_HAS_CTRL_BIT));
+	param->caps.has_net = !!(driver_data & BIT(NBL_CAP_HAS_NET_BIT));
+	param->caps.is_nic = !!(driver_data & BIT(NBL_CAP_IS_NIC_BIT));
+
+	if (!!(driver_data & BIT(NBL_CAP_IS_LEONIS_BIT)))
+		param->product_type = NBL_LEONIS_TYPE;
+	else
+		param->product_type = NBL_PRODUCT_MAX;
+
+	/*
+	 * Leonis only PF0 has ctrl capability, but PF0's pcie device_id
+	 * is same with other PF.So handle it special.
+	 */
+	if (param->product_type == NBL_LEONIS_TYPE &&
+	    (PCI_FUNC(pdev->devfn) == 0) && !pdev->is_virtfn)
+		param->caps.has_ctrl = 1;
+	else if ((PCI_FUNC(pdev->devfn) == 0) && !pdev->is_virtfn)
+		dev_warn(&pdev->dev, "PF0 has_ctrl forced but product_type is not LEONIS\n");
+}
+
 static int nbl_probe(struct pci_dev *pdev,
 		     const struct pci_device_id *id)
 {
+	struct nbl_init_param param = { { 0 } };
+	struct device *dev = &pdev->dev;
+	struct nbl_adapter *adapter;
+	int err;
+
+	err = pci_enable_device(pdev);
+	if (err) {
+		dev_err(&pdev->dev, "Failed to enable PCI dev, err=%d\n", err);
+		return err;
+	}
+
+	param.pci_using_dac = true;
+	nbl_get_func_param(pdev, id->driver_data, &param);
+
+	err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
+	if (err) {
+		dev_dbg(dev, "Configure DMA 64 bit mask failed, err = %d\n",
+			err);
+		param.pci_using_dac = false;
+		err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+		if (err) {
+			dev_err(dev,
+				"Configure DMA 32 bit mask failed, err = %d\n",
+				err);
+			goto configure_dma_err;
+		}
+	}
+	pci_set_master(pdev);
+
+	adapter = nbl_core_init(pdev, &param);
+	if (IS_ERR(adapter)) {
+		dev_err(dev, "Nbl adapter init fail%ld\n", PTR_ERR(adapter));
+		err = PTR_ERR(adapter);
+		goto adapter_init_err;
+	}
+	pci_set_drvdata(pdev, adapter);
+	err = nbl_core_start(adapter);
+	if (err)
+		goto core_start_err;
+
 	return 0;
+core_start_err:
+	nbl_core_remove(adapter);
+adapter_init_err:
+	pci_clear_master(pdev);
+configure_dma_err:
+	pci_disable_device(pdev);
+	return err;
 }
 
 static void nbl_remove(struct pci_dev *pdev)
 {
+	struct nbl_adapter *adapter = pci_get_drvdata(pdev);
+
+	nbl_core_stop(adapter);
+	nbl_core_remove(adapter);
+
+	pci_clear_master(pdev);
+	pci_disable_device(pdev);
 }
 
 /*
-- 
2.47.3


^ permalink raw reply related

* [PATCH v15 net-next 00/11] nbl driver for Nebulamatrix NICs
From: illusion.wang @ 2026-05-20  3:29 UTC (permalink / raw)
  To: dimon.zhao, illusion.wang, alvin.wang, sam.chen, netdev
  Cc: andrew+netdev, corbet, kuba, horms, linux-doc, pabeni,
	vadim.fedorenko, lukas.bulwahn, edumazet, enelsonmoore, skhan,
	hkallweit1, open list

This patch series represents the first phase. We plan to integrate it in
two phases: the first phase covers mailbox and chip configuration,
while the second phase involves net dev configuration.
Together, they will provide basic PF-based Ethernet port transmission and
reception capabilities.

After that, we will consider other features, such as ethtool support,
flow management, adminq messaging, VF support, debugfs support, etc.

changes v14->v15
Link to v13:https://lore.kernel.org/netdev/20260513011649.4404-1-illusion.wang@nebula-matrix.com/
AI review issues
changes v13->v14
Link to v13:https://lore.kernel.org/netdev/20260428114910.2616-1-illusion.wang@nebula-matrix.com/
AI review issues
changes v12->v13
Link to v12:https://lore.kernel.org/netdev/20260415033608.2438-1-illusion.wang@nebula-matrix.com/
AI review issues
changes v11->v12
Link to v11:https://lore.kernel.org/netdev/20260408093739.56001-1-illusion.wang@nebula-matrix.com/
AI review issues
changes v10->v11
Link to v10:https://lore.kernel.org/netdev/20260401022318.28550-1-illusion.wang@nebula-matrix.com/
1.Issues found by Mohsin
2.AI review issues
changes v9->v10
Link to v9:https://lore.kernel.org/netdev/20260325040048.2313-1-illusion.wang@nebula-matrix.com/
1.Issues found by Jakub
2.AI review issue
changes v8->v9
Link to v8:https://lore.kernel.org/netdev/20260317034533.5600-1-illusion.wang@nebula-matrix.com/
1.Issues found by Jakub
2.AI review issue
Changes v7→v8
Link to v7:https://lore.kernel.org/netdev/20260310120959.22015-1-illusion.wang@nebula-matrix.com/
1.Issues found by Paolo
Changes v6->v7
Link to v6:https://lore.kernel.org/netdev/20260306033451.5196-1-illusion.wang@nebula-matrix.com/
1.Issue found by Jakub
2.AI review issue
Changes v5->v6
Link to V5:https://lore.kernel.org/netdev/20260226073840.3222-1-illusion.wang@nebula-matrix.com/
1.put all standard linux includes files the .c file which needs it & others
--Andrew
2.AI review issue
Changes v4->v5
Link to V4:https://lore.kernel.org/netdev/20260206021608.85381-1-illusion.wang@nebula-matrix.com/
1.change nbl_core to nbl & change ** pointers to *pointers & others
--Andrew
2.AI review issue
Changes v3->v4
Link to v3: https://lore.kernel.org/netdev/20260123011804.31263-1-illusion.wang@nebula-matrix.com
1.cut down to part of a mini driver(mailbox and chip init)
--Jakub Kicinski Simon Horman(some sort of staged approached)
2.modify issues found by ai.
3. Reverse Christmas tree/nbl_err/devm_kfree/remove some macros/
void type to real type/others
--Andrew Lunn
4.change deprecated pci_enable_msix_range to pci_alloc_irq_vectors
5.delete service layer
6.the style of kconfig---Randy Dunlap
7.add to Documentation/networking/device_drivers/ethernet/index.rst
--Simon Horman
Changes v2 →v3
Link to v2: https://lore.kernel.org/netdev/20260109100146.63569-1-illusion.wang@nebula-matrix.com/
1.cut down to a mini driver:
    delete vf support
    use promisc mode to cut down flow management
    drop patch15 in v2
    delete adminq msg
    delete abnormal handling
    delete some unimportant interfaces
2.modify issues found by ai review
Changes v1->v2
Link to v1: https://lore.kernel.org/netdev/20251223035113.31122-1-illusion.wang@nebula-matrix.com/
1.Format Issues and Compilation Issues
- Paolo Abeni
2.add sysfs patch and drop coexisting patch
- Andrew Lunn
3.delete some unimportant ndo operations
4.add machine generated headers patch
5.Modify the issues found in patch1-2 and apply the same fixes to other
patches
6.modify issues found by nipa

illusion.wang (11):
  net/nebula-matrix: add minimum nbl build framework
  net/nebula-matrix: add our driver architecture
  net/nebula-matrix: add chip related definitions
  net/nebula-matrix: channel msg value and msg struct
  net/nebula-matrix: add channel layer
  net/nebula-matrix: add common resource implementation
  net/nebula-matrix: add intr resource implementation
  net/nebula-matrix: add vsi resource implementation
  net/nebula-matrix: add Dispatch layer implementation
  net/nebula-matrix: add common/ctrl dev init/reinit operation
  net/nebula-matrix: add common dev start/stop operation

 .../device_drivers/ethernet/index.rst         |    1 +
 .../ethernet/nebula-matrix/nbl.rst            |   28 +
 MAINTAINERS                                   |   10 +
 drivers/net/ethernet/Kconfig                  |    1 +
 drivers/net/ethernet/Makefile                 |    1 +
 drivers/net/ethernet/nebula-matrix/Kconfig    |   34 +
 drivers/net/ethernet/nebula-matrix/Makefile   |    6 +
 .../net/ethernet/nebula-matrix/nbl/Makefile   |   16 +
 .../nbl/nbl_channel/nbl_channel.c             |  946 ++++++
 .../nbl/nbl_channel/nbl_channel.h             |  173 +
 .../nebula-matrix/nbl/nbl_common/nbl_common.c |  214 ++
 .../nebula-matrix/nbl/nbl_common/nbl_common.h |   33 +
 .../net/ethernet/nebula-matrix/nbl/nbl_core.h |   59 +
 .../nebula-matrix/nbl/nbl_core/nbl_dev.c      |  450 +++
 .../nebula-matrix/nbl/nbl_core/nbl_dev.h      |   58 +
 .../nebula-matrix/nbl/nbl_core/nbl_dispatch.c |  505 +++
 .../nebula-matrix/nbl/nbl_core/nbl_dispatch.h |   56 +
 .../nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c  |  853 +++++
 .../nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h  |  548 ++++
 .../nbl_hw/nbl_hw_leonis/nbl_hw_leonis_regs.c | 2887 +++++++++++++++++
 .../nbl_hw/nbl_hw_leonis/nbl_hw_leonis_regs.h |   11 +
 .../nbl_hw_leonis/nbl_resource_leonis.c       |  278 ++
 .../nbl_hw_leonis/nbl_resource_leonis.h       |   12 +
 .../nebula-matrix/nbl/nbl_hw/nbl_hw_reg.h     |   73 +
 .../nebula-matrix/nbl/nbl_hw/nbl_interrupt.c  |  267 ++
 .../nebula-matrix/nbl/nbl_hw/nbl_interrupt.h  |   21 +
 .../nebula-matrix/nbl/nbl_hw/nbl_resource.c   |  134 +
 .../nebula-matrix/nbl/nbl_hw/nbl_resource.h   |  110 +
 .../nebula-matrix/nbl/nbl_hw/nbl_vsi.c        |   26 +
 .../nebula-matrix/nbl/nbl_hw/nbl_vsi.h        |   12 +
 .../nbl/nbl_include/nbl_def_channel.h         |  361 +++
 .../nbl/nbl_include/nbl_def_common.h          |   80 +
 .../nbl/nbl_include/nbl_def_dev.h             |   16 +
 .../nbl/nbl_include/nbl_def_dispatch.h        |   42 +
 .../nbl/nbl_include/nbl_def_hw.h              |   54 +
 .../nbl/nbl_include/nbl_def_resource.h        |   37 +
 .../nbl/nbl_include/nbl_include.h             |   79 +
 .../nbl/nbl_include/nbl_product_base.h        |   19 +
 .../net/ethernet/nebula-matrix/nbl/nbl_main.c |  332 ++
 39 files changed, 8843 insertions(+)
 create mode 100644 Documentation/networking/device_drivers/ethernet/nebula-matrix/nbl.rst
 create mode 100644 drivers/net/ethernet/nebula-matrix/Kconfig
 create mode 100644 drivers/net/ethernet/nebula-matrix/Makefile
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/Makefile
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_channel/nbl_channel.c
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_channel/nbl_channel.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_common/nbl_common.c
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_common/nbl_common.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_core.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.c
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dispatch.c
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dispatch.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis_regs.c
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis_regs.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.c
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_reg.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_interrupt.c
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_interrupt.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_resource.c
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_resource.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_vsi.c
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_vsi.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_channel.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_common.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_dev.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_dispatch.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_hw.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_resource.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_product_base.h
 create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_main.c

-- 
2.47.3


^ permalink raw reply

* Re: [PATCH v2 0/7] seg6: add SRv6 Mobile User Plane (RFC 9433) behaviors
From: Yuya Kusakabe @ 2026-05-20  3:12 UTC (permalink / raw)
  To: Andrea Mayer
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Justin Iurman, Shuah Khan, Jonathan Corbet,
	Shuah Khan, linux-kernel, netdev, linux-kselftest, linux-doc,
	stefano.salsano, ahabdels
In-Reply-To: <20260516182556.66af27a9c63208435911990b@uniroma2.it>

On Sun, May 17, 2026 at 1:26 AM Andrea Mayer <andrea.mayer@uniroma2.it> wrote:
> RFC 9433 Section 6 is titled "SRv6 Segment Endpoint Mobility Behaviors",
> but Section 6.7 defines H.M.GTP4.D as "SR Policy Headend with tunnel
> decapsulation and map to an SRv6 policy". This behavior receives IPv4
> packets and is not bound to any SID, so it does not fit the endpoint
> model that seg6_local implements. Placing it there required relaxing the
> ETH_P_IPV6 guard to accept ETH_P_IP and adding input_family to
> seg6_action_desc, for a single behavior that does not share the endpoint
> model.
>
> seg6_local is not the natural place for this behavior. The UAPI cannot
> be undone once merged, so where it should live needs discussion on the
> list before we proceed.
>
> Given the volume, moving the MUP code into a separate seg6_mobile.c
> (say CONFIG_IPV6_SEG6_MUP) would keep seg6_local focused on the RFC
> 8986 endpoint framework.

I will move the MUP code out of seg6_local into a new
net/ipv6/seg6_mobile.c under a new Kconfig symbol, and register the
behaviors under a new lwtunnel encap type rather than
LWTUNNEL_ENCAP_SEG6_LOCAL.

For naming I was thinking CONFIG_IPV6_SEG6_MOBILE and
LWTUNNEL_ENCAP_SEG6_MOBILE to match the file name, but I have no strong
preference over CONFIG_IPV6_SEG6_MUP if the list prefers that.

Once LWTUNNEL_ENCAP_SEG6_MOBILE is its own encap type, it feels
natural to me to put H.M.GTP4.D there too rather than adding a
separate LWTUNNEL_ENCAP_SEG6_MOBILE_HEADEND. What do you think?

> I think this patchset should be broken into smaller patchsets, one per
> behavior, each with the behavior, its selftest, and any needed helpers as
> separate patches. The same approach was used for End.DT4/End.DT6 and
> End.DT46. End.M.GTP4.E alone is ~1.2k lines in a single diff.

Will do, following the End.DT4/End.DT6/End.DT46 model: one patchset
per behavior, with the behavior, helpers, and selftest as separate
patches. The new code will be aligned with seg6_local.c style as
part of this rework.

> The series reuses SEG6_LOCAL_NH6, SEG6_LOCAL_SRH and SEG6_LOCAL_OIF with
> semantics that differ from the existing behaviors. NH6 today means
> next-hop in End.X/DX6. This series reuses it as DA replacement in
> End.MAP and as prefix template in H.M.GTP4.D.
> SRH is inserted verbatim in End.B6/B6.Encaps but augmented per-packet in
> the mobile behaviors. These attributes have established UAPI semantics
> from their existing behaviors. Giving them a different meaning in new
> behaviors is a UAPI semantic divergence.

The mobile behaviors will define their own SEG6_MOBILE_* attribute
namespace under LWTUNNEL_ENCAP_SEG6_MOBILE, with no reuse of any
SEG6_LOCAL_* attribute. That keeps the established SEG6_LOCAL_*
semantics untouched.

> The selftests use OIF on all five GTP behaviors to select a VRF for the
> lookup, but that is what TABLE and VRFTABLE are for (End.DT4, End.DT6).
> OIF in the existing behaviors means output interface (End.X) or L2
> egress device (End.DX2). VRF support is a nice-to-have that can be added
> later as a separate optional attribute.

I will drop VRF support from the initial behaviors and revisit it
later as a separate optional attribute.

> The user-facing parameter names and their semantics are defined in the
> iproute2 series (where the man page lives), so that is probably the
> better place to discuss keyword choices and attribute naming.

Thanks for the pointer.

> We could think about a prep patch introducing SRv6-level drop reasons
> (SEG6_INVALID_SRH, SEG6_HMAC, etc.) that both the existing behaviors and
> the MUP ones can share.

Good idea. The prep patchset would introduce the SRv6-level reasons
(SEG6_INVALID_SRH, SEG6_HMAC, ...) and convert the existing seg6_local
and seg6_iptunnel call sites to use them. The mobile-specific reasons
(BAD_SID, BAD_GTPU) would then be added together with the first
behavior that uses them and reused by subsequent behaviors. NOMEM and
MTU_EXCEEDED would be dropped in favor of the existing generic
reasons, and the current INVALID_SRH_SL / BAD_INNER misuses would be
replaced by the new SRv6-level reasons from the prep patchset.

Would you prefer to lead on the prep patchset yourself, or would you
like me to prepare it?

> Selftests for the five GTP behaviors heavily depend on python3 and scapy
> heredocs embedded in the shell scripts for packet construction and
> validation, which adds an external runtime dependency. A statically
> compiled C helper would remove it and avoid embedding python heredocs
> in shell scripts.
> A few cases worth covering: SRH and no-SRH input paths where the
> behavior accepts both, missing SRH where the behavior requires
> it, malformed SRH, and invalid attribute values.

I will replace the python3/scapy heredocs with a statically compiled
C helper for packet construction and validation, and extend the
selftests to cover the cases you mention (SRH / no-SRH input paths,
missing SRH where required, malformed SRH, and invalid attribute
values).

> The dst problem is pre-existing from 7a3f5b0de364 ("netfilter: add
> netfilter hooks to SRv6 data plane") and affects seg6_iptunnel too. Both
> issues need a robust fix before this series can go in. I want to look at
> this myself and will Cc you when I do, as the five new behaviors may need
> to be adjusted on top.

Thanks for taking that on. Given the cb/dst issues you described, I
am inclined to drop NF_HOOK support from the initial mobile behaviors
and add it in a follow-up patchset once your fix lands. The initial
behaviors would then do a direct input -> output flow without the
cb-context/finish-callback pattern, which avoids the issues entirely
on day one and decouples this series from the pre-existing fix. Does
that work for you, or would you prefer NF_HOOK to be present from the
start and rebased on top of your fix?

Thanks,
Yuya

^ permalink raw reply

* [PATCH v3] cpu/hotplug: Fix NULL kobject warning in cpuhp_smt_enable()
From: Jinjie Ruan @ 2026-05-20  2:20 UTC (permalink / raw)
  To: catalin.marinas, will, corbet, skhan, punit.agrawal, jic23,
	osama.abdelkader, chenl311, fengchengwen, suzuki.poulose, maz,
	lpieralisi, timothy.hayes, sascha.bischoff, arnd,
	mrigendra.chaubey, pierre.gondois, dietmar.eggemann, yangyicong,
	sudeep.holla, linux-arm-kernel, linux-doc, linux-kernel
  Cc: ruanjinjie

On arm64, when booting with `maxcpus` greater than the number of present
CPUs (e.g., QEMU -smp cpus=4,maxcpus=8), some CPUs are marked as 'present'
but have not yet been registered via register_cpu(). Consequently,
the per-cpu device objects for these CPUs are not yet initialized.

In cpuhp_smt_enable(), the code iterates over all present CPUs. Calling
_cpu_up() for these unregistered CPUs eventually leads to
sysfs_create_group() being called with a NULL kobject (or a kobject
without a directory), triggering the following warning in
fs/sysfs/group.c:

	if (WARN_ON(!kobj || (!update && !kobj->sd)))
		return -EINVAL;

When booting with ACPI, arm64 smp_prepare_cpus() currently sets all
enumerated CPUs as "present" regardless of their status in the MADT. This
causes issues with SMT hotplug control. For instance, with QEMU's
"-smp 4,maxcpus=8" configuration, the MADT GICC entries are populated as
follows: the first four CPUs are marked Enabled while the remaining four
are marked Online Capable to support potential hot-plugging.

Fix this by:

1. When booting with ACPI, checking the ACPI_MADT_ENABLED flag in the GICC
   entry before calling set_cpu_present() during SMP initialization.

2. Properly managing the present mask in acpi_map_cpu() and
   acpi_unmap_cpu() to support actual CPU hotplug events, This aligns with
   other architectures like x86 and LoongArch.

3. Update the arm64 CPU hotplug documentation to no longer state that all
   online-capable vCPUs are marked as present by the kernel at boot time.

This ensures that only physically available or explicitly enabled CPUs
are in the present mask, keeping the SMT control logic consistent with
the actual hardware state.

How to reproduce:

	1. echo off > /sys/devices/system/cpu/smt/control
		psci: CPU1 killed (polled 0 ms)
		psci: CPU3 killed (polled 0 ms)

	2. echo 2 > /sys/devices/system/cpu/smt/control

	Detected PIPT I-cache on CPU1
	GICv3: CPU1: found redistributor 1 region 0:0x00000000080c0000
	CPU1: Booted secondary processor 0x0000000001 [0x410fd082]
	Detected PIPT I-cache on CPU3
	GICv3: CPU3: found redistributor 3 region 0:0x0000000008100000
	CPU3: Booted secondary processor 0x0000000003 [0x410fd082]
	------------[ cut here ]------------
	WARNING: fs/sysfs/group.c:137 at internal_create_group+0x41c/0x4bc, CPU#2: sh/181
	Modules linked in:
	CPU: 2 UID: 0 PID: 181 Comm: sh Not tainted 7.0.0-rc1-00010-g8d13386c7624 #142 PREEMPT
	Hardware name: QEMU KVM Virtual Machine, BIOS 0.0.0 02/06/2015
	pstate: 20000005 (nzCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
	pc : internal_create_group+0x41c/0x4bc
	lr : sysfs_create_group+0x18/0x24
	sp : ffff80008078ba40
	x29: ffff80008078ba40 x28: ffff296c980ad000 x27: ffff00007fb94128
	x26: 0000000000000054 x25: ffffd693e845f3f0 x24: 0000000000000001
	x23: 0000000000000001 x22: 0000000000000004 x21: 0000000000000000
	x20: ffffd693e845fc10 x19: 0000000000000004 x18: 00000000ffffffff
	x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000
	x14: 0000000000000358 x13: 0000000000000007 x12: 0000000000000350
	x11: 0000000000000008 x10: 0000000000000407 x9 : 0000000000000400
	x8 : ffff00007fbf3b60 x7 : 0000000000000000 x6 : ffffd693e845f3f0
	x5 : ffff00007fb94128 x4 : 0000000000000000 x3 : ffff000000f4eac0
	x2 : ffffd693e7095a08 x1 : 0000000000000000 x0 : 0000000000000000
	Call trace:
	 internal_create_group+0x41c/0x4bc (P)
	 sysfs_create_group+0x18/0x24
	 topology_add_dev+0x1c/0x28
	 cpuhp_invoke_callback+0x104/0x20c
	 __cpuhp_invoke_callback_range+0x94/0x11c
	 _cpu_up+0x200/0x37c
	 cpuhp_smt_enable+0xbc/0x114
	 control_store+0xe8/0x1d4
	 dev_attr_store+0x18/0x2c
	 sysfs_kf_write+0x7c/0x94
	 kernfs_fop_write_iter+0x128/0x1b8
	 vfs_write+0x2b0/0x354
	 ksys_write+0x68/0xfc
	 __arm64_sys_write+0x1c/0x28
	 invoke_syscall+0x48/0x10c
	 el0_svc_common.constprop.0+0x40/0xe8
	 do_el0_svc+0x20/0x2c
	 el0_svc+0x34/0x124
	 el0t_64_sync_handler+0xa0/0xe4
	 el0t_64_sync+0x198/0x19c
	---[ end trace 0000000000000000 ]---

Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Jonathan Cameron <jic23@kernel.org>
Cc: James Morse <james.morse@arm.com>
Cc: Yicong Yang <yangyicong@hisilicon.com>
Cc: stable@vger.kernel.org
Link: https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html#gic-cpu-interface-gicc-structure
Fixes: eed4583bcf9a6 ("arm64: Kconfig: Enable HOTPLUG_SMT")
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Suggested-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
v3:
- Update the arm64 cpu-hotplug documentation as Catalin suggested.
- Update the commit message.
v2:
- Update the fix way.
---
 Documentation/arch/arm64/cpu-hotplug.rst | 11 +++++++----
 arch/arm64/kernel/acpi.c                 |  2 ++
 arch/arm64/kernel/smp.c                  | 12 +++++++++++-
 3 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/Documentation/arch/arm64/cpu-hotplug.rst b/Documentation/arch/arm64/cpu-hotplug.rst
index 8fb438bf7781..60f7f51d7b96 100644
--- a/Documentation/arch/arm64/cpu-hotplug.rst
+++ b/Documentation/arch/arm64/cpu-hotplug.rst
@@ -47,8 +47,9 @@ ever have can be described at boot. There are no power-domain considerations
 as such devices are emulated.
 
 CPU Hotplug on virtual systems is supported. It is distinct from physical
-CPU Hotplug as all resources are described as ``present``, but CPUs may be
-marked as disabled by firmware. Only the CPU's online/offline behaviour is
+CPU Hotplug as all resources are described in the static configuration tables,
+but vCPUs that are not enabled at boot are not marked as ``present`` by the
+kernel until they are hotplugged. Only the CPU's online/offline behaviour is
 influenced by firmware. An example is where a virtual machine boots with a
 single CPU, and additional CPUs are added once a cloud orchestrator deploys
 the workload.
@@ -68,8 +69,10 @@ redistributors.
 
 CPUs described as ``online capable`` but not ``enabled`` can be set to enabled
 by the DSDT's Processor object's _STA method. On virtual systems the _STA method
-must always report the CPU as ``present``. Changes to the firmware policy can
-be notified to the OS via device-check or eject-request.
+must report the CPU as ``present`` when it is activated by the firmware.
+The kernel will then set the vCPU as ``present`` dynamically during the hotplug
+configuration process. Changes can be notified to the OS via device-check or
+eject-request.
 
 CPUs described as ``enabled`` in the static table, should not have their _STA
 modified dynamically by firmware. Soft-restart features such as kexec will
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index 5891f92c2035..681aa2bbc399 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -448,12 +448,14 @@ int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 apci_id,
 		return *pcpu;
 	}
 
+	set_cpu_present(*pcpu, true);
 	return 0;
 }
 EXPORT_SYMBOL(acpi_map_cpu);
 
 int acpi_unmap_cpu(int cpu)
 {
+	set_cpu_present(cpu, false);
 	return 0;
 }
 EXPORT_SYMBOL(acpi_unmap_cpu);
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 1aa324104afb..5932e5b30b71 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -566,6 +566,11 @@ struct acpi_madt_generic_interrupt *acpi_cpu_get_madt_gicc(int cpu)
 }
 EXPORT_SYMBOL_GPL(acpi_cpu_get_madt_gicc);
 
+static bool acpi_cpu_is_present(int cpu)
+{
+	return acpi_cpu_get_madt_gicc(cpu)->flags & ACPI_MADT_ENABLED;
+}
+
 /*
  * acpi_map_gic_cpu_interface - parse processor MADT entry
  *
@@ -670,6 +675,10 @@ static void __init acpi_parse_and_init_cpus(void)
 		early_map_cpu_to_node(i, acpi_numa_get_nid(i));
 }
 #else
+static bool acpi_cpu_is_present(int cpu)
+{
+	return false;
+}
 #define acpi_parse_and_init_cpus(...)	do { } while (0)
 #endif
 
@@ -808,7 +817,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
 		if (err)
 			continue;
 
-		set_cpu_present(cpu, true);
+		if (acpi_disabled || acpi_cpu_is_present(cpu))
+			set_cpu_present(cpu, true);
 		numa_store_cpu_info(cpu);
 	}
 }
-- 
2.34.1


^ permalink raw reply related

* [PATCH v7 4/4] HID: hid-msi: Add Rumble Intensity Attributes
From: Derek J. Clark @ 2026-05-20  1:31 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires
  Cc: Pierre-Loup A . Griffais, Denis Benato, Zhouwang Huang,
	Derek J . Clark, linux-input, linux-doc, linux-kernel
In-Reply-To: <20260520013158.3633277-1-derekjohn.clark@gmail.com>

Adds intensity adjustment for the left and right rumble motors.

Claude was used during the reverse-engineering data gathering for this
feature done by Zhouwang Huang. As the code had already been affected,
I used Claude to create the initial framing for the feature, then did
manual cleanup of the _show and _store functions afterwards to fix bugs
and keep the coding style consistent. Claude was also used as an initial
reviewer of this patch.

Assisted-by: Claude:claude-sonnet-4-6
Co-developed-by: Zhouwang Huang <honjow311@gmail.com>
Signed-off-by: Zhouwang Huang <honjow311@gmail.com>
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
---
v7:
  - Match on write address for rumble reports to prevent late ACK
    from causing synchronization errors.
  - Use spinlock for read/write profile_pending.
  - Use smp_[store_release|load_acquire] pattern for checking
    gamepad_registered to avoid possible races during teardown.
  - Use struct for rumble reports.
v6:
  - Make all timeouts 25ms to ensure at least 2 jiffies in a 100Hz
    config.
  - Add spinlock_irqsave for read/write access on rumble_intensity
    variables.
  - Gate all attribute show/store functions with gamepad_registered.
v5:
  - Remove mkey related changes.
v2:
  - Use pending_profile and sync to rom mutexes.
---
 drivers/hid/hid-msi.c | 192 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 192 insertions(+)

diff --git a/drivers/hid/hid-msi.c b/drivers/hid/hid-msi.c
index 61917902e38d3..4adc5588618df 100644
--- a/drivers/hid/hid-msi.c
+++ b/drivers/hid/hid-msi.c
@@ -79,6 +79,8 @@ enum claw_profile_ack_pending {
 	CLAW_M1_PENDING,
 	CLAW_M2_PENDING,
 	CLAW_RGB_PENDING,
+	CLAW_RUMBLE_LEFT_PENDING,
+	CLAW_RUMBLE_RIGHT_PENDING,
 };
 
 enum claw_key_index {
@@ -266,6 +268,11 @@ static const u16 button_mapping_addr_new[] = {
 static const u16 rgb_addr_old = 0x01fa;
 static const u16 rgb_addr_new = 0x024a;
 
+static const u16 rumble_addr[] = {
+	0x0022,  /* left  */
+	0x0023,  /* right */
+};
+
 struct claw_command_report {
 	u8 report_id;
 	u8 padding[2];
@@ -308,6 +315,12 @@ struct claw_rgb_report {
 	struct rgb_frame zone_data;
 } __packed;
 
+struct claw_rumble_report {
+	struct claw_profile_report;
+	u8 padding;
+	u8 intensity;
+} __packed;
+
 struct claw_drvdata {
 	/* MCU General Variables */
 	enum claw_profile_ack_pending profile_pending;
@@ -331,9 +344,13 @@ struct claw_drvdata {
 	enum claw_gamepad_mode_index gamepad_mode;
 	u8 m1_codes[CLAW_KEYS_MAX];
 	u8 m2_codes[CLAW_KEYS_MAX];
+	u8 rumble_intensity_right;
+	u8 rumble_intensity_left;
 	bool gamepad_registered;
+	spinlock_t rumble_lock; /* lock for rumble_intensity read/write */
 	spinlock_t mode_lock; /* Lock for mode data read/write */
 	const u16 *bmap_addr;
+	bool rumble_support;
 	bool bmap_support;
 
 	/* RGB Variables */
@@ -381,6 +398,7 @@ static int claw_gamepad_mode_event(struct claw_drvdata *drvdata,
 static int claw_profile_event(struct claw_drvdata *drvdata, struct claw_command_report *cmd_rep)
 {
 	enum claw_profile_ack_pending profile;
+	struct claw_rumble_report *rumble;
 	struct claw_mkey_report *mkeys;
 	struct claw_rgb_report *frame;
 	u16 rgb_addr, read_addr;
@@ -430,6 +448,20 @@ static int claw_profile_event(struct claw_drvdata *drvdata, struct claw_command_
 		}
 
 		break;
+	case CLAW_RUMBLE_LEFT_PENDING:
+		rumble = (struct claw_rumble_report *)cmd_rep->data;
+		if (be16_to_cpu(rumble->read_addr) != rumble_addr[0])
+			return -EINVAL;
+		scoped_guard(spinlock, &drvdata->rumble_lock)
+			drvdata->rumble_intensity_left = rumble->intensity;
+		break;
+	case CLAW_RUMBLE_RIGHT_PENDING:
+		rumble = (struct claw_rumble_report *)cmd_rep->data;
+		if (be16_to_cpu(rumble->read_addr) != rumble_addr[1])
+			return -EINVAL;
+		scoped_guard(spinlock, &drvdata->rumble_lock)
+			drvdata->rumble_intensity_right = rumble->intensity;
+		break;
 	default:
 		dev_dbg(&drvdata->hdev->dev,
 			"Got profile event without changes pending from command: %x\n",
@@ -919,6 +951,154 @@ static ssize_t button_mapping_options_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(button_mapping_options);
 
+static ssize_t rumble_intensity_left_store(struct device *dev,
+					   struct device_attribute *attr,
+					   const char *buf, size_t count)
+{
+	struct claw_rumble_report report = { {0x01, cpu_to_be16(rumble_addr[0])}, 0x01 };
+	struct hid_device *hdev = to_hid_device(dev);
+	struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+	u8 val;
+	int ret;
+
+	/* Pairs with smp_store_release from cfg_setup_fn in system_wq context */
+	if (!smp_load_acquire(&drvdata->gamepad_registered))
+		return -ENODEV;
+
+	ret = kstrtou8(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	if (val > 100)
+		return -EINVAL;
+
+	report.intensity = val;
+
+	guard(mutex)(&drvdata->rom_mutex);
+	ret = claw_hw_output_report(hdev, CLAW_COMMAND_TYPE_WRITE_PROFILE_DATA,
+				    (u8 *)&report, sizeof(report), 25);
+	if (ret)
+		return ret;
+
+	/* MCU will not send ACK until the USB transaction completes. ACK is sent
+	 * immediately after and will hit the stale state machine, before the next
+	 * command re-arms the state machine. Timeout 0 ensures no deadlock waiting
+	 * for ACK that ill never come.
+	 */
+	ret = claw_hw_output_report(hdev, CLAW_COMMAND_TYPE_SYNC_TO_ROM, NULL, 0, 0);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static ssize_t rumble_intensity_left_show(struct device *dev,
+					  struct device_attribute *attr,
+					  char *buf)
+{
+	struct claw_rumble_report report = { {0x01, cpu_to_be16(rumble_addr[0])}, 0x01 };
+	struct hid_device *hdev = to_hid_device(dev);
+	struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+	int ret;
+	u8 val;
+
+	/* Pairs with smp_store_release from cfg_setup_fn in system_wq context */
+	if (!smp_load_acquire(&drvdata->gamepad_registered))
+		return -ENODEV;
+
+	guard(mutex)(&drvdata->profile_mutex);
+	scoped_guard(spinlock_irqsave, &drvdata->profile_lock)
+		drvdata->profile_pending = CLAW_RUMBLE_LEFT_PENDING;
+	ret = claw_hw_output_report(hdev, CLAW_COMMAND_TYPE_READ_PROFILE,
+				    (u8 *)&report, sizeof(report), 25);
+	if (ret)
+		return ret;
+
+	scoped_guard(spinlock_irqsave, &drvdata->rumble_lock)
+		val = drvdata->rumble_intensity_left;
+
+	return sysfs_emit(buf, "%u\n", val);
+}
+static DEVICE_ATTR_RW(rumble_intensity_left);
+
+static ssize_t rumble_intensity_right_store(struct device *dev,
+					    struct device_attribute *attr,
+					    const char *buf, size_t count)
+{
+	struct claw_rumble_report report = { {0x01, cpu_to_be16(rumble_addr[1])}, 0x01 };
+	struct hid_device *hdev = to_hid_device(dev);
+	struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+	u8 val;
+	int ret;
+
+	/* Pairs with smp_store_release from cfg_setup_fn in system_wq context */
+	if (!smp_load_acquire(&drvdata->gamepad_registered))
+		return -ENODEV;
+
+	ret = kstrtou8(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	if (val > 100)
+		return -EINVAL;
+
+	report.intensity = val;
+
+	guard(mutex)(&drvdata->rom_mutex);
+	ret = claw_hw_output_report(hdev, CLAW_COMMAND_TYPE_WRITE_PROFILE_DATA,
+				    (u8 *)&report, sizeof(report), 25);
+	if (ret)
+		return ret;
+
+	/* MCU will not send ACK until the USB transaction completes. ACK is sent
+	 * immediately after and will hit the stale state machine, before the next
+	 * command re-arms the state machine. Timeout 0 ensures no deadlock waiting
+	 * for ACK that ill never come.
+	 */
+	ret = claw_hw_output_report(hdev, CLAW_COMMAND_TYPE_SYNC_TO_ROM, NULL, 0, 0);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static ssize_t rumble_intensity_right_show(struct device *dev,
+					   struct device_attribute *attr,
+					   char *buf)
+{
+	struct claw_rumble_report report = { {0x01, cpu_to_be16(rumble_addr[1])}, 0x01 };
+	struct hid_device *hdev = to_hid_device(dev);
+	struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+	int ret;
+	u8 val;
+
+	/* Pairs with smp_store_release from cfg_setup_fn in system_wq context */
+	if (!smp_load_acquire(&drvdata->gamepad_registered))
+		return -ENODEV;
+
+	guard(mutex)(&drvdata->profile_mutex);
+	scoped_guard(spinlock_irqsave, &drvdata->profile_lock)
+		drvdata->profile_pending = CLAW_RUMBLE_RIGHT_PENDING;
+	ret = claw_hw_output_report(hdev, CLAW_COMMAND_TYPE_READ_PROFILE,
+				    (u8 *)&report, sizeof(report), 25);
+	if (ret)
+		return ret;
+
+	scoped_guard(spinlock_irqsave, &drvdata->rumble_lock)
+		val = drvdata->rumble_intensity_right;
+
+	return sysfs_emit(buf, "%u\n", val);
+}
+static DEVICE_ATTR_RW(rumble_intensity_right);
+
+static ssize_t rumble_intensity_range_show(struct device *dev,
+					   struct device_attribute *attr,
+					   char *buf)
+{
+	return sysfs_emit(buf, "0-100\n");
+}
+static DEVICE_ATTR_RO(rumble_intensity_range);
+
 static umode_t claw_gamepad_attr_is_visible(struct kobject *kobj, struct attribute *attr,
 					    int n)
 {
@@ -939,6 +1119,12 @@ static umode_t claw_gamepad_attr_is_visible(struct kobject *kobj, struct attribu
 	    attr == &dev_attr_reset.attr)
 		return attr->mode;
 
+	/* Hide rumble attrs if not supported */
+	if (attr == &dev_attr_rumble_intensity_left.attr ||
+	    attr == &dev_attr_rumble_intensity_right.attr ||
+	    attr == &dev_attr_rumble_intensity_range.attr)
+		return drvdata->rumble_support ? attr->mode : 0;
+
 	/* Hide button mapping attrs if it isn't supported */
 	return drvdata->bmap_support ? attr->mode : 0;
 }
@@ -952,6 +1138,9 @@ static struct attribute *claw_gamepad_attrs[] = {
 	&dev_attr_mkeys_function.attr,
 	&dev_attr_mkeys_function_index.attr,
 	&dev_attr_reset.attr,
+	&dev_attr_rumble_intensity_left.attr,
+	&dev_attr_rumble_intensity_right.attr,
+	&dev_attr_rumble_intensity_range.attr,
 	NULL,
 };
 
@@ -1498,6 +1687,7 @@ static void claw_features_supported(struct claw_drvdata *drvdata)
 		drvdata->bmap_support = true;
 		if (minor >= 0x66) {
 			drvdata->bmap_addr = button_mapping_addr_new;
+			drvdata->rumble_support = true;
 			drvdata->rgb_addr = rgb_addr_new;
 		} else {
 			drvdata->bmap_addr = button_mapping_addr_old;
@@ -1509,6 +1699,7 @@ static void claw_features_supported(struct claw_drvdata *drvdata)
 	if ((major == 0x02 && minor >= 0x17) || major >= 0x03) {
 		drvdata->bmap_support = true;
 		drvdata->bmap_addr = button_mapping_addr_new;
+		drvdata->rumble_support = true;
 		drvdata->rgb_addr = rgb_addr_new;
 		return;
 	}
@@ -1557,6 +1748,7 @@ static int claw_probe(struct hid_device *hdev, u8 ep)
 	spin_lock_init(&drvdata->mode_lock);
 	spin_lock_init(&drvdata->profile_lock);
 	spin_lock_init(&drvdata->frame_lock);
+	spin_lock_init(&drvdata->rumble_lock);
 	init_completion(&drvdata->send_cmd_complete);
 	INIT_DELAYED_WORK(&drvdata->cfg_resume, &cfg_resume_fn);
 	INIT_DELAYED_WORK(&drvdata->cfg_setup, &cfg_setup_fn);
-- 
2.53.0


^ permalink raw reply related

* [PATCH v7 3/4] HID: hid-msi: Add RGB control interface
From: Derek J. Clark @ 2026-05-20  1:31 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires
  Cc: Pierre-Loup A . Griffais, Denis Benato, Zhouwang Huang,
	Derek J . Clark, linux-input, linux-doc, linux-kernel
In-Reply-To: <20260520013158.3633277-1-derekjohn.clark@gmail.com>

Adds RGB control interface for MSI Claw devices. The MSI Claw uses a
fairly unique RGB interface. It has 9 total zones (4 per joystick ring
and 1 for the ABXY buttons), and supports up to 8 sequential frames of
RGB zone data. Each frame is written to a specific area of MCU memory by
the profile command, the value of which changes based on the firmware of
the device. Unlike other devices (such as the Legion Go or the OneXPlayer
devices), there are no hard coded effects built into the MCU. Instead,
the basic effects are provided as a series of frame data. I have
mirrored the effects available in Windows in this driver, while keeping
the effect names consistent with the Lenovo drivers for the effects that
are similar.

Initial reverse-engineering and implementation of this feature was done
by Zhouwang Huang. I refactored the overall format to conform to kernel
driver best practices and style guides. Claude was used as an initial
reviewer of this patch.

Assisted-by: Claude:claude-sonnet-4-6
Co-developed-by: Zhouwang Huang <honjow311@gmail.com>
Signed-off-by: Zhouwang Huang <honjow311@gmail.com>
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
---
v7:
  - Use smp_[store_release|load_acquire] pattern for checking
    rgb_registered to avoid possible races during teardown.
  - Add gating to cfg_setup_fn, allowing either gamepad settings or rgb
    settings to populate if the other fails for any reason.
  - Use spinlock when writing profile_pending.
v6:
  - Make all timeouts 25ms to ensure at least 2 jiffies in a 100Hz
    config.
  - Gate all attribute show/store functions with rgb_registered,
    enabling use of devm_device_add_group.
v5:
  - Move adding the RGB device into cfg_setup to prevent led core
    attributes from being written to prior to setup completing.
  - Ensure frame_lock is properly init.
  - Change variable names in RGB functions from frame and zone to f and
    z respectively to fit all scoped_guard actions in 100 columns.
v4:
  - Fix frame_calc validity check to use >=.
  - USe spinlock instead of mutex in raw_event and related attribute
    _store function.
  - Ensure delayed work is canceled in suspend & canceled before sysfs
    attribute removal.
v3:
  - Add mutex for read/write of rgb frame data.
  - Remove setting rgb_frame_count when reading rgb profiles as it always
    returns garbage data.
  - Ensure rgb_speed is getting drvdata from a valid lookup (not hdev).
v2:
  - Use pending_profile mutex
---
 drivers/hid/hid-msi.c | 637 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 621 insertions(+), 16 deletions(-)

diff --git a/drivers/hid/hid-msi.c b/drivers/hid/hid-msi.c
index 193435ec9386c..61917902e38d3 100644
--- a/drivers/hid/hid-msi.c
+++ b/drivers/hid/hid-msi.c
@@ -21,6 +21,7 @@
 #include <linux/device.h>
 #include <linux/hid.h>
 #include <linux/kobject.h>
+#include <linux/led-class-multicolor.h>
 #include <linux/leds.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
@@ -44,6 +45,10 @@
 
 #define CLAW_KEYS_MAX		5
 
+#define CLAW_RGB_ZONES		9
+#define CLAW_RGB_MAX_FRAMES	8
+#define CLAW_RGB_FRAME_OFFSET	0x24
+
 enum claw_command_index {
 	CLAW_COMMAND_TYPE_NONE =			0x00,
 	CLAW_COMMAND_TYPE_READ_PROFILE =		0x04,
@@ -73,6 +78,7 @@ enum claw_profile_ack_pending {
 	CLAW_NO_PENDING,
 	CLAW_M1_PENDING,
 	CLAW_M2_PENDING,
+	CLAW_RGB_PENDING,
 };
 
 enum claw_key_index {
@@ -231,6 +237,22 @@ static const struct {
 	{ 0xff, "DISABLED" },
 };
 
+enum claw_rgb_effect_index {
+	CLAW_RGB_EFFECT_MONOCOLOR,
+	CLAW_RGB_EFFECT_BREATHE,
+	CLAW_RGB_EFFECT_CHROMA,
+	CLAW_RGB_EFFECT_RAINBOW,
+	CLAW_RGB_EFFECT_FROSTFIRE,
+};
+
+static const char * const claw_rgb_effect_text[] = {
+	[CLAW_RGB_EFFECT_MONOCOLOR] =	"monocolor",
+	[CLAW_RGB_EFFECT_BREATHE] =	"breathe",
+	[CLAW_RGB_EFFECT_CHROMA] =	"chroma",
+	[CLAW_RGB_EFFECT_RAINBOW] =	"rainbow",
+	[CLAW_RGB_EFFECT_FROSTFIRE] =	"frostfire",
+};
+
 static const u16 button_mapping_addr_old[] = {
 	0x007a,  /* M1 */
 	0x011f,  /* M2 */
@@ -241,6 +263,9 @@ static const u16 button_mapping_addr_new[] = {
 	0x0164,  /* M2 */
 };
 
+static const u16 rgb_addr_old = 0x01fa;
+static const u16 rgb_addr_new = 0x024a;
+
 struct claw_command_report {
 	u8 report_id;
 	u8 padding[2];
@@ -262,6 +287,27 @@ struct claw_mkey_report {
 	u8 codes[5];
 } __packed;
 
+struct rgb_zone {
+	u8 red;
+	u8 green;
+	u8 blue;
+};
+
+struct rgb_frame {
+	struct rgb_zone zone[CLAW_RGB_ZONES];
+};
+
+struct claw_rgb_report {
+	struct claw_profile_report;
+	u8 frame_bytes;
+	u8 padding;
+	u8 frame_count;
+	u8 state; /* Always 0x09 */
+	u8 speed;
+	u8 brightness;
+	struct rgb_frame zone_data;
+} __packed;
+
 struct claw_drvdata {
 	/* MCU General Variables */
 	enum claw_profile_ack_pending profile_pending;
@@ -289,6 +335,18 @@ struct claw_drvdata {
 	spinlock_t mode_lock; /* Lock for mode data read/write */
 	const u16 *bmap_addr;
 	bool bmap_support;
+
+	/* RGB Variables */
+	struct rgb_frame rgb_frames[CLAW_RGB_MAX_FRAMES];
+	enum claw_rgb_effect_index rgb_effect;
+	struct led_classdev_mc led_mc;
+	struct delayed_work rgb_queue;
+	spinlock_t frame_lock; /* lock for rgb_frames read/write */
+	bool rgb_registered;
+	u8 rgb_frame_count;
+	bool rgb_enabled;
+	u8 rgb_speed;
+	u16 rgb_addr;
 };
 
 static int get_endpoint_address(struct hid_device *hdev)
@@ -324,8 +382,11 @@ static int claw_profile_event(struct claw_drvdata *drvdata, struct claw_command_
 {
 	enum claw_profile_ack_pending profile;
 	struct claw_mkey_report *mkeys;
-	u8 *codes, key;
-	int i;
+	struct claw_rgb_report *frame;
+	u16 rgb_addr, read_addr;
+	u8 *codes, key, f_idx;
+	u16 frame_calc;
+	int i, ret = 0;
 
 	scoped_guard(spinlock, &drvdata->profile_lock)
 		profile = drvdata->profile_pending;
@@ -341,6 +402,34 @@ static int claw_profile_event(struct claw_drvdata *drvdata, struct claw_command_
 		for (i = 0; i < CLAW_KEYS_MAX; i++)
 			codes[i] = (mkeys->codes[i]);
 		break;
+	case CLAW_RGB_PENDING:
+		frame = (struct claw_rgb_report *)cmd_rep->data;
+		rgb_addr = drvdata->rgb_addr;
+		read_addr = be16_to_cpu(frame->read_addr);
+		frame_calc = (read_addr - rgb_addr) / CLAW_RGB_FRAME_OFFSET;
+		if (frame_calc >= CLAW_RGB_MAX_FRAMES) {
+			dev_err(&drvdata->hdev->dev, "Got unsupported frame index: %x\n",
+				frame_calc);
+			return -EINVAL;
+		}
+		f_idx = frame_calc;
+
+		scoped_guard(spinlock, &drvdata->frame_lock) {
+			memcpy(&drvdata->rgb_frames[f_idx], &frame->zone_data,
+			       sizeof(struct rgb_frame));
+
+			/* Only use frame 0 for remaining variable assignment */
+			if (f_idx != 0)
+				break;
+
+			drvdata->rgb_speed = frame->speed;
+			drvdata->led_mc.led_cdev.brightness = frame->brightness;
+			drvdata->led_mc.subled_info[0].intensity = frame->zone_data.zone[0].red;
+			drvdata->led_mc.subled_info[1].intensity = frame->zone_data.zone[0].green;
+			drvdata->led_mc.subled_info[2].intensity = frame->zone_data.zone[0].blue;
+		}
+
+		break;
 	default:
 		dev_dbg(&drvdata->hdev->dev,
 			"Got profile event without changes pending from command: %x\n",
@@ -350,7 +439,7 @@ static int claw_profile_event(struct claw_drvdata *drvdata, struct claw_command_
 	scoped_guard(spinlock, &drvdata->profile_lock)
 		drvdata->profile_pending = CLAW_NO_PENDING;
 
-	return 0;
+	return ret;
 }
 
 static int claw_raw_event(struct claw_drvdata *drvdata, struct hid_report *report,
@@ -871,31 +960,521 @@ static const struct attribute_group claw_gamepad_attr_group = {
 	.is_visible = claw_gamepad_attr_is_visible,
 };
 
+/* Read RGB config from device */
+static int claw_read_rgb_config(struct hid_device *hdev)
+{
+	u8 data[4] = { 0x01, 0x00, 0x00, CLAW_RGB_FRAME_OFFSET };
+	struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+	u16 read_addr = drvdata->rgb_addr;
+	size_t len = ARRAY_SIZE(data);
+	int ret, i;
+
+	if (!drvdata->rgb_addr)
+		return -ENODEV;
+
+	/* Loop through all 8 pages of RGB data */
+	guard(mutex)(&drvdata->profile_mutex);
+	for (i = 0; i < CLAW_RGB_MAX_FRAMES; i++) {
+		scoped_guard(spinlock_irqsave, &drvdata->profile_lock)
+			drvdata->profile_pending = CLAW_RGB_PENDING;
+		data[1] = (read_addr >> 8) & 0xff;
+		data[2] = read_addr & 0x00ff;
+		ret = claw_hw_output_report(hdev, CLAW_COMMAND_TYPE_READ_PROFILE, data, len, 25);
+		if (ret)
+			return ret;
+
+		read_addr += CLAW_RGB_FRAME_OFFSET;
+	}
+
+	return 0;
+}
+
+/* Send RGB configuration to device */
+static int claw_write_rgb_state(struct claw_drvdata *drvdata)
+{
+	struct claw_rgb_report report = { {0x01, 0}, CLAW_RGB_FRAME_OFFSET, 0x00,
+			drvdata->rgb_frame_count, 0x09, drvdata->rgb_speed,
+			drvdata->led_mc.led_cdev.brightness };
+	u16 write_addr = drvdata->rgb_addr;
+	int f, ret;
+
+	if (!drvdata->rgb_addr)
+		return -ENODEV;
+
+	if (!drvdata->rgb_frame_count)
+		return -EINVAL;
+
+	guard(mutex)(&drvdata->rom_mutex);
+	/* Loop through (up to) 8 pages of RGB data */
+	for (f = 0; f < drvdata->rgb_frame_count; f++) {
+		scoped_guard(spinlock_irqsave, &drvdata->frame_lock)
+			report.zone_data = drvdata->rgb_frames[f];
+
+		/* Set the MCU address to write the frame data to */
+		report.read_addr = cpu_to_be16(write_addr);
+
+		/* Serialize the rgb_report and write it to MCU */
+		ret = claw_hw_output_report(drvdata->hdev, CLAW_COMMAND_TYPE_WRITE_PROFILE_DATA,
+					    (u8 *)&report, sizeof(report), 25);
+		if (ret)
+			return ret;
+
+		/* Increment the write addr by the offset for the next frame */
+		write_addr += CLAW_RGB_FRAME_OFFSET;
+	}
+
+	/* MCU will not send ACK until the USB transaction completes. ACK is sent
+	 * immediately after and will hit the stale state machine, before the next
+	 * command re-arms the state machine. Timeout 0 ensures no deadlock waiting
+	 * for ACK that ill never come.
+	 */
+	ret = claw_hw_output_report(drvdata->hdev, CLAW_COMMAND_TYPE_SYNC_TO_ROM, NULL, 0, 0);
+
+	return ret;
+}
+
+/* Fill all zones with the same color */
+static void claw_frame_fill_solid(struct rgb_frame *frame, struct rgb_zone zone)
+{
+	int z;
+
+	for (z = 0; z < CLAW_RGB_ZONES; z++)
+		frame->zone[z] = zone;
+}
+
+/* Apply solid effect (1 frame, no color) */
+static int claw_apply_disabled(struct claw_drvdata *drvdata)
+{
+	struct rgb_zone off = { 0x00, 0x00, 0x00};
+
+	scoped_guard(spinlock_irqsave, &drvdata->frame_lock) {
+		drvdata->rgb_frame_count = 1;
+		claw_frame_fill_solid(&drvdata->rgb_frames[0], off);
+	}
+
+	return claw_write_rgb_state(drvdata);
+}
+
+/* Apply solid effect (1 frame, all zones same color) */
+static int claw_apply_monocolor(struct claw_drvdata *drvdata)
+{
+	struct mc_subled *subleds = drvdata->led_mc.subled_info;
+	struct rgb_zone zone = { subleds[0].intensity, subleds[1].intensity,
+				 subleds[2].intensity };
+
+	scoped_guard(spinlock_irqsave, &drvdata->frame_lock) {
+		drvdata->rgb_frame_count = 1;
+		claw_frame_fill_solid(&drvdata->rgb_frames[0], zone);
+	}
+
+	return claw_write_rgb_state(drvdata);
+}
+
+/* Apply breathe effect (2 frames: color -> off) */
+static int claw_apply_breathe(struct claw_drvdata *drvdata)
+{
+	struct mc_subled *subleds = drvdata->led_mc.subled_info;
+	struct rgb_zone zone = { subleds[0].intensity, subleds[1].intensity,
+				 subleds[2].intensity };
+	static const struct rgb_zone off = { 0, 0, 0 };
+
+	scoped_guard(spinlock_irqsave, &drvdata->frame_lock) {
+		drvdata->rgb_frame_count = 2;
+		claw_frame_fill_solid(&drvdata->rgb_frames[0], zone);
+		claw_frame_fill_solid(&drvdata->rgb_frames[1], off);
+	}
+
+	return claw_write_rgb_state(drvdata);
+}
+
+/* Apply chroma effect (6 frames: rainbow cycle, all zones sync) */
+static int claw_apply_chroma(struct claw_drvdata *drvdata)
+{
+	static const struct rgb_zone colors[] = {
+		{255,   0,   0},  /* red     */
+		{255, 255,   0},  /* yellow  */
+		{  0, 255,   0},  /* green   */
+		{  0, 255, 255},  /* cyan    */
+		{  0,   0, 255},  /* blue    */
+		{255,   0, 255},  /* magenta */
+	};
+	u8 frame_count = ARRAY_SIZE(colors);
+	int f;
+
+	scoped_guard(spinlock_irqsave, &drvdata->frame_lock) {
+		drvdata->rgb_frame_count = frame_count;
+
+		for (f = 0; f < frame_count; f++)
+			claw_frame_fill_solid(&drvdata->rgb_frames[f], colors[f]);
+	}
+
+	return claw_write_rgb_state(drvdata);
+}
+
+/* Apply rainbow effect (4 frames: rotating colors around joysticks) */
+static int claw_apply_rainbow(struct claw_drvdata *drvdata)
+{
+	static const struct rgb_zone colors[] = {
+		{255,   0,   0},  /* red   */
+		{  0, 255,   0},  /* green */
+		{  0, 255, 255},  /* cyan  */
+		{  0,   0, 255},  /* blue  */
+	};
+	u8 frame_count = ARRAY_SIZE(colors);
+	int f, z;
+
+	scoped_guard(spinlock_irqsave, &drvdata->frame_lock) {
+		drvdata->rgb_frame_count = frame_count;
+
+		for (f = 0; f < frame_count; f++) {
+			for (z = 0; z < 4; z++) {
+				drvdata->rgb_frames[f].zone[z]     = colors[(z + f) % 4];
+				drvdata->rgb_frames[f].zone[z + 4] = colors[(z + f) % 4];
+			}
+			drvdata->rgb_frames[f].zone[8] = colors[f];
+		}
+	}
+
+	return claw_write_rgb_state(drvdata);
+}
+
+/*
+ * Apply frostfire effect (4 frames: fire vs ice rotating)
+ * Right joystick: fire red -> dark -> ice blue -> dark (clockwise)
+ * Left joystick: ice blue -> dark -> fire red -> dark (counter-clockwise)
+ * ABXY: fire red -> dark -> ice blue -> dark
+ */
+static int claw_apply_frostfire(struct claw_drvdata *drvdata)
+{
+	static const struct rgb_zone colors[] = {
+		{255,   0,   0},  /* fire red */
+		{  0,   0,   0},  /* dark     */
+		{  0,   0, 255},  /* ice blue */
+		{  0,   0,   0},  /* dark     */
+	};
+	u8 frame_count = ARRAY_SIZE(colors);
+	int f, z;
+
+	scoped_guard(spinlock_irqsave, &drvdata->frame_lock) {
+		drvdata->rgb_frame_count = frame_count;
+
+		for (f = 0; f < frame_count; f++) {
+			for (z = 0; z < 4; z++) {
+				drvdata->rgb_frames[f].zone[z]     = colors[(z + f) % 4];
+				drvdata->rgb_frames[f].zone[z + 4] = colors[(z - f + 6) % 4];
+			}
+			drvdata->rgb_frames[f].zone[8] = colors[f];
+		}
+	}
+
+	return claw_write_rgb_state(drvdata);
+}
+
+/* Apply current state to device */
+static int claw_apply_rgb_state(struct claw_drvdata *drvdata)
+{
+	if (!drvdata->rgb_enabled)
+		return claw_apply_disabled(drvdata);
+
+	switch (drvdata->rgb_effect) {
+	case CLAW_RGB_EFFECT_MONOCOLOR:
+		return claw_apply_monocolor(drvdata);
+	case CLAW_RGB_EFFECT_BREATHE:
+		return claw_apply_breathe(drvdata);
+	case CLAW_RGB_EFFECT_CHROMA:
+		return claw_apply_chroma(drvdata);
+	case CLAW_RGB_EFFECT_RAINBOW:
+		return claw_apply_rainbow(drvdata);
+	case CLAW_RGB_EFFECT_FROSTFIRE:
+		return claw_apply_frostfire(drvdata);
+	default:
+		dev_err(drvdata->led_mc.led_cdev.dev,
+			"No supported rgb_effect selected\n");
+		return -EINVAL;
+	}
+}
+
+static void claw_rgb_queue_fn(struct work_struct *work)
+{
+	struct delayed_work *dwork = container_of(work, struct delayed_work, work);
+	struct claw_drvdata *drvdata = container_of(dwork, struct claw_drvdata, rgb_queue);
+	int ret;
+
+	/* Pairs with smp_store_release from cfg_setup_fn in system_wq context */
+	if (!smp_load_acquire(&drvdata->rgb_registered))
+		return;
+
+	ret = claw_apply_rgb_state(drvdata);
+	if (ret)
+		dev_err(drvdata->led_mc.led_cdev.dev,
+			"Failed to apply RGB state: %d\n", ret);
+}
+
+static ssize_t effect_store(struct device *dev,
+			    struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct led_classdev_mc *led_mc = container_of(led_cdev, struct led_classdev_mc, led_cdev);
+	struct claw_drvdata *drvdata = container_of(led_mc, struct claw_drvdata, led_mc);
+	int ret;
+
+	/* Pairs with smp_store_release from cfg_setup_fn in system_wq context */
+	if (!smp_load_acquire(&drvdata->rgb_registered))
+		return -ENODEV;
+
+	ret = sysfs_match_string(claw_rgb_effect_text, buf);
+	if (ret < 0)
+		return ret;
+
+	drvdata->rgb_effect = ret;
+	mod_delayed_work(system_wq, &drvdata->rgb_queue, msecs_to_jiffies(50));
+
+	return count;
+}
+
+static ssize_t effect_show(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct led_classdev_mc *led_mc = container_of(led_cdev, struct led_classdev_mc, led_cdev);
+	struct claw_drvdata *drvdata = container_of(led_mc, struct claw_drvdata, led_mc);
+
+	/* Pairs with smp_store_release from cfg_setup_fn in system_wq context */
+	if (!smp_load_acquire(&drvdata->rgb_registered))
+		return -ENODEV;
+
+	if (drvdata->rgb_effect >= ARRAY_SIZE(claw_rgb_effect_text))
+		return -EINVAL;
+
+	return sysfs_emit(buf, "%s\n", claw_rgb_effect_text[drvdata->rgb_effect]);
+}
+
+static DEVICE_ATTR_RW(effect);
+
+static ssize_t effect_index_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	int i, count = 0;
+
+	for (i = 0; i < ARRAY_SIZE(claw_rgb_effect_text); i++)
+		count += sysfs_emit_at(buf, count, "%s ", claw_rgb_effect_text[i]);
+
+	if (count)
+		buf[count - 1] = '\n';
+
+	return count;
+}
+static DEVICE_ATTR_RO(effect_index);
+
+static ssize_t enabled_store(struct device *dev,
+			     struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct led_classdev_mc *led_mc = container_of(led_cdev, struct led_classdev_mc, led_cdev);
+	struct claw_drvdata *drvdata = container_of(led_mc, struct claw_drvdata, led_mc);
+	bool val;
+	int ret;
+
+	/* Pairs with smp_store_release from cfg_setup_fn in system_wq context */
+	if (!smp_load_acquire(&drvdata->rgb_registered))
+		return -ENODEV;
+
+	ret = kstrtobool(buf, &val);
+	if (ret)
+		return ret;
+
+	drvdata->rgb_enabled = val;
+	mod_delayed_work(system_wq, &drvdata->rgb_queue, msecs_to_jiffies(50));
+
+	return count;
+}
+
+static ssize_t enabled_show(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct led_classdev_mc *led_mc = container_of(led_cdev, struct led_classdev_mc, led_cdev);
+	struct claw_drvdata *drvdata = container_of(led_mc, struct claw_drvdata, led_mc);
+
+	/* Pairs with smp_store_release from cfg_setup_fn in system_wq context */
+	if (!smp_load_acquire(&drvdata->rgb_registered))
+		return -ENODEV;
+
+	return sysfs_emit(buf, "%s\n", drvdata->rgb_enabled ? "true" : "false");
+}
+static DEVICE_ATTR_RW(enabled);
+
+static ssize_t enabled_index_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	return sysfs_emit(buf, "true false\n");
+}
+static DEVICE_ATTR_RO(enabled_index);
+
+static ssize_t speed_store(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct led_classdev_mc *led_mc = container_of(led_cdev, struct led_classdev_mc, led_cdev);
+	struct claw_drvdata *drvdata = container_of(led_mc, struct claw_drvdata, led_mc);
+	unsigned int val, speed;
+	int ret;
+
+	/* Pairs with smp_store_release from cfg_setup_fn in system_wq context */
+	if (!smp_load_acquire(&drvdata->rgb_registered))
+		return -ENODEV;
+
+	ret = kstrtouint(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	if (val > 20)
+		return -EINVAL;
+
+	/* 0 is fastest, invert value for intuitive userspace speed */
+	speed = 20 - val;
+
+	drvdata->rgb_speed = speed;
+	mod_delayed_work(system_wq, &drvdata->rgb_queue, msecs_to_jiffies(50));
+
+	return count;
+}
+
+static ssize_t speed_show(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct led_classdev_mc *led_mc = container_of(led_cdev, struct led_classdev_mc, led_cdev);
+	struct claw_drvdata *drvdata = container_of(led_mc, struct claw_drvdata, led_mc);
+	u8 speed = 20 - drvdata->rgb_speed;
+
+	/* Pairs with smp_store_release from cfg_setup_fn in system_wq context */
+	if (!smp_load_acquire(&drvdata->rgb_registered))
+		return -ENODEV;
+
+	return sysfs_emit(buf, "%u\n", speed);
+}
+static DEVICE_ATTR_RW(speed);
+
+static ssize_t speed_range_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	return sysfs_emit(buf, "0-20\n");
+}
+static DEVICE_ATTR_RO(speed_range);
+
+static void claw_led_brightness_set(struct led_classdev *led_cdev,
+				    enum led_brightness _brightness)
+{
+	struct led_classdev_mc *led_mc = container_of(led_cdev, struct led_classdev_mc, led_cdev);
+	struct claw_drvdata *drvdata = container_of(led_mc, struct claw_drvdata, led_mc);
+
+	/* Pairs with smp_store_release from cfg_setup_fn in system_wq context */
+	if (!smp_load_acquire(&drvdata->rgb_registered))
+		return;
+
+	mod_delayed_work(system_wq, &drvdata->rgb_queue, msecs_to_jiffies(50));
+}
+
+static struct attribute *claw_rgb_attrs[] = {
+	&dev_attr_effect.attr,
+	&dev_attr_effect_index.attr,
+	&dev_attr_enabled.attr,
+	&dev_attr_enabled_index.attr,
+	&dev_attr_speed.attr,
+	&dev_attr_speed_range.attr,
+	NULL,
+};
+
+static const struct attribute_group claw_rgb_attr_group = {
+	.attrs = claw_rgb_attrs,
+};
+
+static struct mc_subled claw_rgb_subled_info[] = {
+	{
+		.color_index = LED_COLOR_ID_RED,
+		.channel = 0x1,
+	},
+	{
+		.color_index = LED_COLOR_ID_GREEN,
+		.channel = 0x2,
+	},
+	{
+		.color_index = LED_COLOR_ID_BLUE,
+		.channel = 0x3,
+	},
+};
+
 static void cfg_setup_fn(struct work_struct *work)
 {
 	struct delayed_work *dwork = container_of(work, struct delayed_work, work);
 	struct claw_drvdata *drvdata = container_of(dwork, struct claw_drvdata, cfg_setup);
+	bool gamepad_ready = false, rgb_ready = false;
 	int ret;
 
 	ret = claw_hw_output_report(drvdata->hdev, CLAW_COMMAND_TYPE_READ_GAMEPAD_MODE,
 				    NULL, 0, 25);
 	if (ret) {
 		dev_err(&drvdata->hdev->dev,
-			"Failed to setup device, can't read gamepad mode: %d\n", ret);
-		return;
+			"Failed to read gamepad mode: %d\n", ret);
+		goto prep_rgb;
 	}
+	gamepad_ready = true;
 
-	/* Add sysfs attributes after we get the device state */
-	ret = devm_device_add_group(&drvdata->hdev->dev, &claw_gamepad_attr_group);
+prep_rgb:
+	ret = claw_read_rgb_config(drvdata->hdev);
 	if (ret) {
 		dev_err(&drvdata->hdev->dev,
-			"Failed to setup device, can't create gamepad attrs: %d\n", ret);
-		return;
+			"Failed to read RGB config: %d\n", ret);
+		goto try_gamepad;
 	}
-	/* Pairs with smp_load_acquire in attribute show/store functions */
-	smp_store_release(&drvdata->gamepad_registered, true);
+	rgb_ready = true;
 
-	kobject_uevent(&drvdata->hdev->dev.kobj, KOBJ_CHANGE);
+try_gamepad:
+	/* Add sysfs attributes after we get the device state */
+	/* Pairs with smp_store_release from below */
+	if (!smp_load_acquire(&drvdata->gamepad_registered) && gamepad_ready) {
+		ret = devm_device_add_group(&drvdata->hdev->dev, &claw_gamepad_attr_group);
+		if (ret) {
+			dev_err(&drvdata->hdev->dev,
+				"Failed to create gamepad attrs: %d\n", ret);
+			goto try_rgb;
+		}
+		/* Pairs with smp_load_acquire in attribute show/store functions */
+		smp_store_release(&drvdata->gamepad_registered, true);
+	}
+
+try_rgb:
+	/* Add and enable RGB interface once we have the device state */
+	/* Pairs with smp_store_release from below */
+	if (!smp_load_acquire(&drvdata->rgb_registered) && rgb_ready) {
+		ret = devm_led_classdev_multicolor_register(&drvdata->hdev->dev, &drvdata->led_mc);
+		if (ret) {
+			dev_err(&drvdata->hdev->dev,
+				"Failed to create led device: %d\n", ret);
+			goto update_kobjects;
+		}
+
+		ret = device_add_group(drvdata->led_mc.led_cdev.dev, &claw_rgb_attr_group);
+		if (ret) {
+			dev_err(&drvdata->hdev->dev,
+				"Failed to create RGB attrs: %d\n", ret);
+			goto update_kobjects;
+		}
+
+		/* Pairs with smp_load_acquire in attribute show/store functions */
+		smp_store_release(&drvdata->rgb_registered, true);
+	}
+
+update_kobjects:
+	/* Pairs with smp_store_release from above */
+	if (smp_load_acquire(&drvdata->gamepad_registered))
+		kobject_uevent(&drvdata->hdev->dev.kobj, KOBJ_CHANGE);
+	/* Pairs with smp_store_release from above */
+	if (smp_load_acquire(&drvdata->rgb_registered))
+		kobject_uevent(&drvdata->led_mc.led_cdev.dev->kobj, KOBJ_CHANGE);
 }
 
 static void cfg_resume_fn(struct work_struct *work)
@@ -903,8 +1482,10 @@ static void cfg_resume_fn(struct work_struct *work)
 	struct delayed_work *dwork = container_of(work, struct delayed_work, work);
 	struct claw_drvdata *drvdata = container_of(dwork, struct claw_drvdata, cfg_resume);
 
-	/* Pairs with smp_store_release from cfg_setup_fn in system_wq context */
-	if (!smp_load_acquire(&drvdata->gamepad_registered))
+	    /* Pairs with smp_store_release from cfg_setup_fn in system_wq context */
+	if (!smp_load_acquire(&drvdata->gamepad_registered) ||
+	    /* Pairs with smp_store_release from cfg_setup_fn in system_wq context */
+	    !smp_load_acquire(&drvdata->rgb_registered))
 		schedule_delayed_work(&drvdata->cfg_setup, msecs_to_jiffies(500));
 }
 
@@ -915,18 +1496,24 @@ static void claw_features_supported(struct claw_drvdata *drvdata)
 
 	if (major == 0x01) {
 		drvdata->bmap_support = true;
-		if (minor >= 0x66)
+		if (minor >= 0x66) {
 			drvdata->bmap_addr = button_mapping_addr_new;
-		else
+			drvdata->rgb_addr = rgb_addr_new;
+		} else {
 			drvdata->bmap_addr = button_mapping_addr_old;
+			drvdata->rgb_addr = rgb_addr_old;
+		}
 		return;
 	}
 
 	if ((major == 0x02 && minor >= 0x17) || major >= 0x03) {
 		drvdata->bmap_support = true;
 		drvdata->bmap_addr = button_mapping_addr_new;
+		drvdata->rgb_addr = rgb_addr_new;
 		return;
 	}
+
+	drvdata->rgb_addr = rgb_addr_old;
 }
 
 static int claw_probe(struct hid_device *hdev, u8 ep)
@@ -941,6 +1528,7 @@ static int claw_probe(struct hid_device *hdev, u8 ep)
 		return -ENOMEM;
 
 	drvdata->gamepad_mode = CLAW_GAMEPAD_MODE_XINPUT;
+	drvdata->rgb_enabled = true;
 	drvdata->hdev = hdev;
 	drvdata->ep = ep;
 
@@ -951,15 +1539,28 @@ static int claw_probe(struct hid_device *hdev, u8 ep)
 	if (!drvdata->bmap_support)
 		dev_dbg(&hdev->dev, "M-Key mapping is not supported. Update firmware to enable.\n");
 
+	drvdata->led_mc.led_cdev.name = "msi_claw:rgb:joystick_rings";
+	drvdata->led_mc.led_cdev.brightness = 0x50;
+	drvdata->led_mc.led_cdev.max_brightness = 0x64;
+	drvdata->led_mc.led_cdev.color = LED_COLOR_ID_RGB;
+	drvdata->led_mc.led_cdev.brightness_set = claw_led_brightness_set;
+	drvdata->led_mc.num_colors = 3;
+	drvdata->led_mc.subled_info = devm_kmemdup(&hdev->dev, claw_rgb_subled_info,
+						   sizeof(claw_rgb_subled_info), GFP_KERNEL);
+	if (!drvdata->led_mc.subled_info)
+		return -ENOMEM;
+
 	mutex_init(&drvdata->cfg_mutex);
 	mutex_init(&drvdata->profile_mutex);
 	mutex_init(&drvdata->rom_mutex);
 	spin_lock_init(&drvdata->cmd_lock);
 	spin_lock_init(&drvdata->mode_lock);
 	spin_lock_init(&drvdata->profile_lock);
+	spin_lock_init(&drvdata->frame_lock);
 	init_completion(&drvdata->send_cmd_complete);
 	INIT_DELAYED_WORK(&drvdata->cfg_resume, &cfg_resume_fn);
 	INIT_DELAYED_WORK(&drvdata->cfg_setup, &cfg_setup_fn);
+	INIT_DELAYED_WORK(&drvdata->rgb_queue, &claw_rgb_queue_fn);
 
 	/* For control interface: open the HID transport for sending commands. */
 	ret = hid_hw_open(hdev);
@@ -1021,11 +1622,15 @@ static void claw_remove(struct hid_device *hdev)
 		return;
 	}
 
+	/* Block writes to brightness/multi_intensity during teardown */
 	cancel_delayed_work_sync(&drvdata->cfg_resume);
 	cancel_delayed_work_sync(&drvdata->cfg_setup);
+	cancel_delayed_work_sync(&drvdata->rgb_queue);
 
 	/* Pairs with smp_load_acquire in attribute show/store functions */
 	smp_store_release(&drvdata->gamepad_registered, false);
+	/* Pairs with smp_load_acquire in attribute show/store functions */
+	smp_store_release(&drvdata->rgb_registered, false);
 
 	hid_hw_close(hdev);
 }
-- 
2.53.0


^ permalink raw reply related

* [PATCH v7 2/4] HID: hid-msi: Add M-key mapping attributes
From: Derek J. Clark @ 2026-05-20  1:31 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires
  Cc: Pierre-Loup A . Griffais, Denis Benato, Zhouwang Huang,
	Derek J . Clark, linux-input, linux-doc, linux-kernel
In-Reply-To: <20260520013158.3633277-1-derekjohn.clark@gmail.com>

Adds attributes that allow for remapping the M-keys with up to 5 values
when in macro mode. There are 2 mappable buttons on the rear of the
device, M1 on the right and M2 on the left. When mapped, the events will
fire from one of three event devices: gamepad buttons will fire from the
device handled by xpad, while keyboard and mouse events will fire from
respectively typed evdevs provided by the input core. Names of each
mapping have been kept as close to the event that will fire from the evdev
as possible, with context added to the ABS_ events on the direction of the
movement.

Initial reverse-engineering and implementation of this feature was done
by Zhouwang Huang. I refactored the overall format to conform to kernel
driver best practices and style guides. Claude was used as an initial
reviewer of this patch.

Assisted-by: Claude:claude-sonnet-4-6
Co-developed-by: Zhouwang Huang <honjow311@gmail.com>
Signed-off-by: Zhouwang Huang <honjow311@gmail.com>
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
---
v7:
  - Use smp_[store_release|load_acquire] pattern for checking
    gamepad_registered to avoid possible races during teardown.
  - Add profile_lock for read/write profile_pending.
  - Match on write address for mkey reports to prevent late ACK
    from causing synchronization errors.
  - Use struct for mkey reports.
v6:
  - Make all timeouts 25ms to ensure at least 2 jiffies in a 100Hz
    config.
  - Gate all attribute show/store functions with gamepad_registered.
  - Remove duplicated argv_free macro.
v5:
  - Ensure adding "DISABLED" key to valid entries is done in the correct
    patch.
  - Re-enable sending an empty string to clear button mappings in
    addition to setting DISABLED.
v4:
  - Change dev_warn to dev_dbg in claw_profile_event.
  - use __free with DEFINE_FREE macro for argv instead of manually
    running argv_free, cleaining up scoped_guard goto.
v3:
  - Use scoped_guard where necessary.
v2:
  - Add mutex for SYNC_TO_ROM commands to ensure every SYNC is completed
    before more data is written to the MCU volatile memory.
  - Add mutex for profile_pending to ensure every profile action
    response is  serialized to the generating command.
---
 drivers/hid/hid-msi.c | 444 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 443 insertions(+), 1 deletion(-)

diff --git a/drivers/hid/hid-msi.c b/drivers/hid/hid-msi.c
index d95483907a5e5..193435ec9386c 100644
--- a/drivers/hid/hid-msi.c
+++ b/drivers/hid/hid-msi.c
@@ -42,6 +42,8 @@
 #define CLAW_DINPUT_CFG_INTF_IN	0x82
 #define CLAW_XINPUT_CFG_INTF_IN	0x83
 
+#define CLAW_KEYS_MAX		5
+
 enum claw_command_index {
 	CLAW_COMMAND_TYPE_NONE =			0x00,
 	CLAW_COMMAND_TYPE_READ_PROFILE =		0x04,
@@ -67,6 +69,17 @@ static const char * const claw_gamepad_mode_text[] = {
 	[CLAW_GAMEPAD_MODE_DESKTOP] =	"desktop",
 };
 
+enum claw_profile_ack_pending {
+	CLAW_NO_PENDING,
+	CLAW_M1_PENDING,
+	CLAW_M2_PENDING,
+};
+
+enum claw_key_index {
+	CLAW_KEY_M1,
+	CLAW_KEY_M2,
+};
+
 enum claw_mkeys_function_index {
 	CLAW_MKEY_FUNCTION_MACRO,
 	CLAW_MKEY_FUNCTION_DISABLED,
@@ -79,6 +92,155 @@ static const char * const claw_mkeys_function_text[] = {
 	[CLAW_MKEY_FUNCTION_COMBO] =	"combination",
 };
 
+static const struct {
+	u8 code;
+	const char *name;
+} claw_button_mapping_key_map[] = {
+	/* Gamepad buttons */
+	{ 0x01, "ABS_HAT0Y_UP" },
+	{ 0x02, "ABS_HAT0Y_DOWN" },
+	{ 0x03, "ABS_HAT0X_LEFT" },
+	{ 0x04, "ABS_HAT0X_RIGHT" },
+	{ 0x05, "BTN_TL" },
+	{ 0x06, "BTN_TR" },
+	{ 0x07, "BTN_THUMBL" },
+	{ 0x08, "BTN_THUMBR" },
+	{ 0x09, "BTN_SOUTH" },
+	{ 0x0a, "BTN_EAST" },
+	{ 0x0b, "BTN_NORTH" },
+	{ 0x0c, "BTN_WEST" },
+	{ 0x0d, "BTN_MODE" },
+	{ 0x0e, "BTN_SELECT" },
+	{ 0x0f, "BTN_START" },
+	{ 0x13, "BTN_TL2"},
+	{ 0x14, "BTN_TR2"},
+	{ 0x15, "ABS_Y_UP"},
+	{ 0x16, "ABS_Y_DOWN"},
+	{ 0x17, "ABS_X_LEFT"},
+	{ 0x18, "ABS_X_RIGHT"},
+	{ 0x19, "ABS_RY_UP"},
+	{ 0x1a, "ABS_RY_DOWN"},
+	{ 0x1b, "ABS_RX_LEFT"},
+	{ 0x1c, "ABS_RX_RIGHT"},
+	/* Keyboard keys */
+	{ 0x32, "KEY_ESC" },
+	{ 0x33, "KEY_F1" },
+	{ 0x34, "KEY_F2" },
+	{ 0x35, "KEY_F3" },
+	{ 0x36, "KEY_F4" },
+	{ 0x37, "KEY_F5" },
+	{ 0x38, "KEY_F6" },
+	{ 0x39, "KEY_F7" },
+	{ 0x3a, "KEY_F8" },
+	{ 0x3b, "KEY_F9" },
+	{ 0x3c, "KEY_F10" },
+	{ 0x3d, "KEY_F11" },
+	{ 0x3e, "KEY_F12" },
+	{ 0x3f, "KEY_GRAVE" },
+	{ 0x40, "KEY_1" },
+	{ 0x41, "KEY_2" },
+	{ 0x42, "KEY_3" },
+	{ 0x43, "KEY_4" },
+	{ 0x44, "KEY_5" },
+	{ 0x45, "KEY_6" },
+	{ 0x46, "KEY_7" },
+	{ 0x47, "KEY_8" },
+	{ 0x48, "KEY_9" },
+	{ 0x49, "KEY_0" },
+	{ 0x4a, "KEY_MINUS" },
+	{ 0x4b, "KEY_EQUAL" },
+	{ 0x4c, "KEY_BACKSPACE" },
+	{ 0x4d, "KEY_TAB" },
+	{ 0x4e, "KEY_Q" },
+	{ 0x4f, "KEY_W" },
+	{ 0x50, "KEY_E" },
+	{ 0x51, "KEY_R" },
+	{ 0x52, "KEY_T" },
+	{ 0x53, "KEY_Y" },
+	{ 0x54, "KEY_U" },
+	{ 0x55, "KEY_I" },
+	{ 0x56, "KEY_O" },
+	{ 0x57, "KEY_P" },
+	{ 0x58, "KEY_LEFTBRACE" },
+	{ 0x59, "KEY_RIGHTBRACE" },
+	{ 0x5a, "KEY_BACKSLASH" },
+	{ 0x5b, "KEY_CAPSLOCK" },
+	{ 0x5c, "KEY_A" },
+	{ 0x5d, "KEY_S" },
+	{ 0x5e, "KEY_D" },
+	{ 0x5f, "KEY_F" },
+	{ 0x60, "KEY_G" },
+	{ 0x61, "KEY_H" },
+	{ 0x62, "KEY_J" },
+	{ 0x63, "KEY_K" },
+	{ 0x64, "KEY_L" },
+	{ 0x65, "KEY_SEMICOLON" },
+	{ 0x66, "KEY_APOSTROPHE" },
+	{ 0x67, "KEY_ENTER" },
+	{ 0x68, "KEY_LEFTSHIFT" },
+	{ 0x69, "KEY_Z" },
+	{ 0x6a, "KEY_X" },
+	{ 0x6b, "KEY_C" },
+	{ 0x6c, "KEY_V" },
+	{ 0x6d, "KEY_B" },
+	{ 0x6e, "KEY_N" },
+	{ 0x6f, "KEY_M" },
+	{ 0x70, "KEY_COMMA" },
+	{ 0x71, "KEY_DOT" },
+	{ 0x72, "KEY_SLASH" },
+	{ 0x73, "KEY_RIGHTSHIFT" },
+	{ 0x74, "KEY_LEFTCTRL" },
+	{ 0x75, "KEY_LEFTMETA" },
+	{ 0x76, "KEY_LEFTALT" },
+	{ 0x77, "KEY_SPACE" },
+	{ 0x78, "KEY_RIGHTALT" },
+	{ 0x79, "KEY_RIGHTCTRL" },
+	{ 0x7a, "KEY_INSERT" },
+	{ 0x7b, "KEY_HOME" },
+	{ 0x7c, "KEY_PAGEUP" },
+	{ 0x7d, "KEY_DELETE" },
+	{ 0x7e, "KEY_END" },
+	{ 0x7f, "KEY_PAGEDOWN" },
+	{ 0x8a, "KEY_KPENTER" },
+	{ 0x8b, "KEY_KP0" },
+	{ 0x8c, "KEY_KP1" },
+	{ 0x8d, "KEY_KP2" },
+	{ 0x8e, "KEY_KP3" },
+	{ 0x8f, "KEY_KP4" },
+	{ 0x90, "KEY_KP5" },
+	{ 0x91, "KEY_KP6" },
+	{ 0x92, "KEY_KP7" },
+	{ 0x93, "KEY_KP8" },
+	{ 0x94, "KEY_KP9" },
+	{ 0x95, "MD_PLAY" },
+	{ 0x96, "MD_STOP" },
+	{ 0x97, "MD_NEXT" },
+	{ 0x98, "MD_PREV" },
+	{ 0x99, "MD_VOL_UP" },
+	{ 0x9a, "MD_VOL_DOWN" },
+	{ 0x9b, "MD_VOL_MUTE" },
+	{ 0x9c, "KEY_F23" },
+	/* Mouse events */
+	{ 0xc8, "BTN_LEFT" },
+	{ 0xc9, "BTN_MIDDLE" },
+	{ 0xca, "BTN_RIGHT" },
+	{ 0xcb, "BTN_SIDE" },
+	{ 0xcc, "BTN_EXTRA" },
+	{ 0xcd, "REL_WHEEL_UP" },
+	{ 0xce, "REL_WHEEL_DOWN" },
+	{ 0xff, "DISABLED" },
+};
+
+static const u16 button_mapping_addr_old[] = {
+	0x007a,  /* M1 */
+	0x011f,  /* M2 */
+};
+
+static const u16 button_mapping_addr_new[] = {
+	0x00bb,  /* M1 */
+	0x0164,  /* M2 */
+};
+
 struct claw_command_report {
 	u8 report_id;
 	u8 padding[2];
@@ -87,24 +249,46 @@ struct claw_command_report {
 	u8 data[59];
 } __packed;
 
+struct claw_profile_report {
+	u8 profile;
+	__be16 read_addr;
+} __packed;
+
+struct claw_mkey_report {
+	struct claw_profile_report;
+	u8 padding_0;
+	u8 padding_1;
+	u8 padding_2;
+	u8 codes[5];
+} __packed;
+
 struct claw_drvdata {
 	/* MCU General Variables */
+	enum claw_profile_ack_pending profile_pending;
 	struct completion send_cmd_complete;
 	struct delayed_work cfg_resume;
 	struct delayed_work cfg_setup;
+	struct mutex profile_mutex; /* mutex for profile_pending calls */
+	spinlock_t profile_lock; /* Lock for profile_pending read/write */
 	struct hid_device *hdev;
 	struct mutex cfg_mutex; /* mutex for synchronous data */
+	struct mutex rom_mutex; /* mutex for SYNC_TO_ROM calls */
 	bool waiting_for_ack;
 	spinlock_t cmd_lock; /* Lock for cmd data read/write */
 	u8 waiting_cmd;
 	int cmd_status;
+	u16 bcd_device;
 	u8 ep;
 
 	/* Gamepad Variables */
 	enum claw_mkeys_function_index mkeys_function;
 	enum claw_gamepad_mode_index gamepad_mode;
+	u8 m1_codes[CLAW_KEYS_MAX];
+	u8 m2_codes[CLAW_KEYS_MAX];
 	bool gamepad_registered;
 	spinlock_t mode_lock; /* Lock for mode data read/write */
+	const u16 *bmap_addr;
+	bool bmap_support;
 };
 
 static int get_endpoint_address(struct hid_device *hdev)
@@ -136,6 +320,39 @@ static int claw_gamepad_mode_event(struct claw_drvdata *drvdata,
 	return 0;
 }
 
+static int claw_profile_event(struct claw_drvdata *drvdata, struct claw_command_report *cmd_rep)
+{
+	enum claw_profile_ack_pending profile;
+	struct claw_mkey_report *mkeys;
+	u8 *codes, key;
+	int i;
+
+	scoped_guard(spinlock, &drvdata->profile_lock)
+		profile = drvdata->profile_pending;
+
+	switch (profile) {
+	case CLAW_M1_PENDING:
+	case CLAW_M2_PENDING:
+		key = (profile == CLAW_M1_PENDING) ? CLAW_KEY_M1 : CLAW_KEY_M2;
+		mkeys = (struct claw_mkey_report *)cmd_rep->data;
+		if (be16_to_cpu(mkeys->read_addr) != drvdata->bmap_addr[key])
+			return -EINVAL;
+		codes = (profile == CLAW_M1_PENDING) ? drvdata->m1_codes : drvdata->m2_codes;
+		for (i = 0; i < CLAW_KEYS_MAX; i++)
+			codes[i] = (mkeys->codes[i]);
+		break;
+	default:
+		dev_dbg(&drvdata->hdev->dev,
+			"Got profile event without changes pending from command: %x\n",
+			cmd_rep->cmd);
+		return -EINVAL;
+	}
+	scoped_guard(spinlock, &drvdata->profile_lock)
+		drvdata->profile_pending = CLAW_NO_PENDING;
+
+	return 0;
+}
+
 static int claw_raw_event(struct claw_drvdata *drvdata, struct hid_report *report,
 			  u8 *data, int size)
 {
@@ -166,6 +383,19 @@ static int claw_raw_event(struct claw_drvdata *drvdata, struct hid_report *repor
 			}
 		}
 
+		break;
+	case CLAW_COMMAND_TYPE_READ_PROFILE_ACK:
+		ret = claw_profile_event(drvdata, cmd_rep);
+
+		scoped_guard(spinlock, &drvdata->cmd_lock) {
+			if (drvdata->waiting_for_ack &&
+			    drvdata->waiting_cmd == CLAW_COMMAND_TYPE_READ_PROFILE) {
+				drvdata->cmd_status = ret;
+				drvdata->waiting_for_ack = false;
+				complete(&drvdata->send_cmd_complete);
+			}
+		}
+
 		break;
 	case CLAW_COMMAND_TYPE_ACK:
 		scoped_guard(spinlock, &drvdata->cmd_lock) {
@@ -433,6 +663,173 @@ static ssize_t reset_store(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR_WO(reset);
 
+static int mkey_mapping_name_to_code(const char *name)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(claw_button_mapping_key_map); i++) {
+		if (!strcmp(name, claw_button_mapping_key_map[i].name))
+			return claw_button_mapping_key_map[i].code;
+	}
+
+	return -EINVAL;
+}
+
+static const char *mkey_mapping_code_to_name(u8 code)
+{
+	int i;
+
+	if (code == 0xff)
+		return NULL;
+
+	for (i = 0; i < ARRAY_SIZE(claw_button_mapping_key_map); i++) {
+		if (claw_button_mapping_key_map[i].code == code)
+			return claw_button_mapping_key_map[i].name;
+	}
+
+	return NULL;
+}
+
+static int claw_mkey_store(struct device *dev, const char *buf, u8 mkey)
+{
+	struct hid_device *hdev = to_hid_device(dev);
+	struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+	struct claw_mkey_report report = { {0x01, cpu_to_be16(drvdata->bmap_addr[mkey])},
+				   0x07, 0x04, 0x00, {0xff, 0xff, 0xff, 0xff, 0xff} };
+	char **raw_keys __free(argv_free) = NULL;
+	int ret, key_count, i;
+
+	/* Pairs with smp_store_release from cfg_setup_fn in system_wq context */
+	if (!smp_load_acquire(&drvdata->gamepad_registered))
+		return -ENODEV;
+
+	raw_keys = argv_split(GFP_KERNEL, buf, &key_count);
+	if (!raw_keys)
+		return -ENOMEM;
+
+	if (key_count > CLAW_KEYS_MAX)
+		return -EINVAL;
+
+	if (key_count == 0)
+		goto set_buttons;
+
+	for (i = 0; i < key_count; i++) {
+		ret = mkey_mapping_name_to_code(raw_keys[i]);
+		if (ret < 0)
+			return ret;
+
+		report.codes[i] = ret;
+	}
+
+set_buttons:
+	scoped_guard(mutex, &drvdata->rom_mutex) {
+		ret = claw_hw_output_report(hdev, CLAW_COMMAND_TYPE_WRITE_PROFILE_DATA,
+					    (u8 *)&report, sizeof(report), 25);
+		if (ret)
+			return ret;
+		/* MCU will not send ACK until the USB transaction completes. ACK is sent
+		 * immediately after and will hit the stale state machine, before the next
+		 * command re-arms the state machine. Timeout 0 ensures no deadlock waiting
+		 * for ACK that ill never come.
+		 */
+		ret = claw_hw_output_report(hdev, CLAW_COMMAND_TYPE_SYNC_TO_ROM, NULL, 0, 0);
+	}
+
+	return ret;
+}
+
+static int claw_mkey_show(struct device *dev, char *buf, enum claw_key_index m_key)
+{
+	struct hid_device *hdev = to_hid_device(dev);
+	struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+	struct claw_mkey_report report = { {0x01, cpu_to_be16(drvdata->bmap_addr[m_key])}, 0x07 };
+	int i, ret, count = 0;
+	const char *name;
+	u8 *codes;
+
+	/* Pairs with smp_store_release from cfg_setup_fn in system_wq context */
+	if (!smp_load_acquire(&drvdata->gamepad_registered))
+		return -ENODEV;
+
+	codes = (m_key == CLAW_KEY_M1) ? drvdata->m1_codes : drvdata->m2_codes;
+
+	guard(mutex)(&drvdata->profile_mutex);
+	scoped_guard(spinlock_irqsave, &drvdata->profile_lock)
+		drvdata->profile_pending = (m_key == CLAW_KEY_M1) ? CLAW_M1_PENDING
+								  : CLAW_M2_PENDING;
+
+	ret = claw_hw_output_report(hdev, CLAW_COMMAND_TYPE_READ_PROFILE,
+				    (u8 *)&report, sizeof(report), 25);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < CLAW_KEYS_MAX; i++) {
+		name = mkey_mapping_code_to_name(codes[i]);
+		if (name)
+			count += sysfs_emit_at(buf, count, "%s ", name);
+	}
+
+	if (!count)
+		return sysfs_emit(buf, "(not set)\n");
+
+	buf[count - 1] = '\n';
+
+	return count;
+}
+
+static ssize_t button_m1_store(struct device *dev, struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	int ret;
+
+	ret = claw_mkey_store(dev, buf, CLAW_KEY_M1);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static ssize_t button_m1_show(struct device *dev, struct device_attribute *attr,
+			      char *buf)
+{
+	return claw_mkey_show(dev, buf, CLAW_KEY_M1);
+}
+static DEVICE_ATTR_RW(button_m1);
+
+static ssize_t button_m2_store(struct device *dev, struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	int ret;
+
+	ret = claw_mkey_store(dev, buf, CLAW_KEY_M2);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static ssize_t button_m2_show(struct device *dev, struct device_attribute *attr,
+			      char *buf)
+{
+	return claw_mkey_show(dev, buf, CLAW_KEY_M2);
+}
+static DEVICE_ATTR_RW(button_m2);
+
+static ssize_t button_mapping_options_show(struct device *dev,
+					   struct device_attribute *attr, char *buf)
+{
+	int i, count = 0;
+
+	for (i = 0; i < ARRAY_SIZE(claw_button_mapping_key_map); i++)
+		count += sysfs_emit_at(buf, count, "%s ", claw_button_mapping_key_map[i].name);
+
+	if (count)
+		buf[count - 1] = '\n';
+
+	return count;
+}
+static DEVICE_ATTR_RO(button_mapping_options);
+
 static umode_t claw_gamepad_attr_is_visible(struct kobject *kobj, struct attribute *attr,
 					    int n)
 {
@@ -445,10 +842,22 @@ static umode_t claw_gamepad_attr_is_visible(struct kobject *kobj, struct attribu
 		return 0;
 	}
 
-	return attr->mode;
+	/* Always show attrs available on all firmware */
+	if (attr == &dev_attr_gamepad_mode.attr ||
+	    attr == &dev_attr_gamepad_mode_index.attr ||
+	    attr == &dev_attr_mkeys_function.attr ||
+	    attr == &dev_attr_mkeys_function_index.attr ||
+	    attr == &dev_attr_reset.attr)
+		return attr->mode;
+
+	/* Hide button mapping attrs if it isn't supported */
+	return drvdata->bmap_support ? attr->mode : 0;
 }
 
 static struct attribute *claw_gamepad_attrs[] = {
+	&dev_attr_button_m1.attr,
+	&dev_attr_button_m2.attr,
+	&dev_attr_button_mapping_options.attr,
 	&dev_attr_gamepad_mode.attr,
 	&dev_attr_gamepad_mode_index.attr,
 	&dev_attr_mkeys_function.attr,
@@ -499,8 +908,31 @@ static void cfg_resume_fn(struct work_struct *work)
 		schedule_delayed_work(&drvdata->cfg_setup, msecs_to_jiffies(500));
 }
 
+static void claw_features_supported(struct claw_drvdata *drvdata)
+{
+	u8 major = (drvdata->bcd_device >> 8) & 0xff;
+	u8 minor = drvdata->bcd_device & 0xff;
+
+	if (major == 0x01) {
+		drvdata->bmap_support = true;
+		if (minor >= 0x66)
+			drvdata->bmap_addr = button_mapping_addr_new;
+		else
+			drvdata->bmap_addr = button_mapping_addr_old;
+		return;
+	}
+
+	if ((major == 0x02 && minor >= 0x17) || major >= 0x03) {
+		drvdata->bmap_support = true;
+		drvdata->bmap_addr = button_mapping_addr_new;
+		return;
+	}
+}
+
 static int claw_probe(struct hid_device *hdev, u8 ep)
 {
+	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+	struct usb_device *udev = interface_to_usbdev(intf);
 	struct claw_drvdata *drvdata;
 	int ret;
 
@@ -512,9 +944,19 @@ static int claw_probe(struct hid_device *hdev, u8 ep)
 	drvdata->hdev = hdev;
 	drvdata->ep = ep;
 
+	/* Determine feature level from firmware version */
+	drvdata->bcd_device = le16_to_cpu(udev->descriptor.bcdDevice);
+	claw_features_supported(drvdata);
+
+	if (!drvdata->bmap_support)
+		dev_dbg(&hdev->dev, "M-Key mapping is not supported. Update firmware to enable.\n");
+
 	mutex_init(&drvdata->cfg_mutex);
+	mutex_init(&drvdata->profile_mutex);
+	mutex_init(&drvdata->rom_mutex);
 	spin_lock_init(&drvdata->cmd_lock);
 	spin_lock_init(&drvdata->mode_lock);
+	spin_lock_init(&drvdata->profile_lock);
 	init_completion(&drvdata->send_cmd_complete);
 	INIT_DELAYED_WORK(&drvdata->cfg_resume, &cfg_resume_fn);
 	INIT_DELAYED_WORK(&drvdata->cfg_setup, &cfg_setup_fn);
-- 
2.53.0


^ permalink raw reply related

* [PATCH v7 1/4] HID: hid-msi: Add MSI Claw configuration driver
From: Derek J. Clark @ 2026-05-20  1:31 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires
  Cc: Pierre-Loup A . Griffais, Denis Benato, Zhouwang Huang,
	Derek J . Clark, linux-input, linux-doc, linux-kernel
In-Reply-To: <20260520013158.3633277-1-derekjohn.clark@gmail.com>

Adds configuration HID driver for the MSI Claw series of handheld PC's.
In this initial patch add the initial driver outline and attributes for
changing the gamepad mode, M-key behavior, and add a WO reset function.

Sending the SWITCH_MODE and RESET commands causes a USB disconnect in
the device. The completion will therefore never get hit and would trigger
an -EIO. To avoid showing the user an error for every write to these
attrs a bypass for the completion handling is introduced when timeout ==
0.

The initial version of this patch was written by Denis Benato, which
contained the initial reverse-engineering and implementation for the
gamepad mode switching. This work was later expanded by Zhouwang Huang
to include more gamepad modes. Finally, I refactored the drivers data
in/out flow and overall format to conform to kernel driver best
practices and style guides. Claude was used as an initial reviewer of
this patch.

Assisted-by: Claude:claude-sonnet-4-6
Co-developed-by: Denis Benato <denis.benato@linux.dev>
Signed-off-by: Denis Benato <denis.benato@linux.dev>
Co-developed-by: Zhouwang Huang <honjow311@gmail.com>
Signed-off-by: Zhouwang Huang <honjow311@gmail.com>
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
---
v7:
  - Use smp_[store_release|load_acquire] pattern for checking
    gamepad_registered to avoid possible races during teardown.
  - Reorder reinit_completion in claw_hw_output_report to avoid race
    with possible incoming ACKs.
  - Reorder cancel_delayed_work_sync to ensure setup can't be re-armed
    after cancel.
  - Reset command state machine if hw_output_report has an error.
  - Add comments to (hopefully) silence sashinko-bot warnings about the
    use of endpoint matching and the impossible scenario of switching to
    the alternate endpoint from userspace while the driver is bound.
  - Don't use spinlock_irqsave when already in irq context.
v6:
  - Add send/ack pattern to ensure synchronous acks.
  - Use spinlock_irqsave instead of mutex for read/write MODE event
    data.
  - add select NEW_LEDS to kconfig.
  - Make all timeouts 25ms to ensure at least 2 jiffies in a 100Hz
    config.
  - Gate all attribute show/store functions with gamepad_registered,
    enabling use of devm_device_add_group.
  - Re-arm cfg_setup in resume if it was canceled in an early suspend.
  - Don't set gamepad_mode on resume, MCU preserves state.
  - Ensure all count variables are checked for > 0 characters before
    setting buf - 1 to \n.
v5:
  - Swap disabled & combination mkeys_function enum values.
  - Ensure mode_mutex is properly init.
  - Ensure claw_remove is calling hid_hw_close and not hid_hw_stop for
    all paths.
v4:
  - Add msi_suspend/claw_suspend.
  - Reorder claw_remove to cancel all work before removing sysfs.
  - Add mutex lock for removing sysfs attributes.
  - Add mutex lock for MODE command data read/write.
v3:
  - Ensure claw_hw_output_report is properly guarded.
  - Reoder claw_probe to ensure all mutex, completion, and variable
    assignments are in place prior to setting drvdata.
  - Ensure gamepad_mode is set to a valid enum value in claw_probe.
v2:
  - Rename driver to hid-msi from hid-msi-claw.
  - Rename reusable/generic functions to msi_* from claw_*, retaining
    claw specific functions.
  - Add generic entrypoints for probe, remove, and raw event that route
    to claw specific functions.
---
 MAINTAINERS           |   6 +
 drivers/hid/Kconfig   |  13 +
 drivers/hid/Makefile  |   1 +
 drivers/hid/hid-ids.h |   5 +
 drivers/hid/hid-msi.c | 692 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 717 insertions(+)
 create mode 100644 drivers/hid/hid-msi.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 6f6517bf4f970..8e2de98b768f7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17965,6 +17965,12 @@ S:	Odd Fixes
 F:	Documentation/devicetree/bindings/net/ieee802154/mrf24j40.txt
 F:	drivers/net/ieee802154/mrf24j40.c
 
+MSI HID DRIVER
+M:	Derek J. Clark <derekjohn.clark@gmail.com>
+L:	linux-input@vger.kernel.org
+S:	Maintained
+F:	drivers/hid/hid-msi.c
+
 MSI EC DRIVER
 M:	Nikita Kravets <teackot@gmail.com>
 L:	platform-driver-x86@vger.kernel.org
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 10c12d8e65579..7766676051a52 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -492,6 +492,19 @@ config HID_GT683R
 	Currently the following devices are know to be supported:
 	  - MSI GT683R
 
+config HID_MSI
+	tristate "MSI Claw Gamepad Support"
+	depends on USB_HID
+	select NEW_LEDS
+	select LEDS_CLASS
+	select LEDS_CLASS_MULTICOLOR
+	help
+	Support for the MSI Claw RGB and controller configuration
+
+	Say Y here to include configuration interface support for the MSI Claw Line
+	of Handheld Console Controllers. Say M here to compile this driver as a
+	module. The module will be called hid-msi.
+
 config HID_KEYTOUCH
 	tristate "Keytouch HID devices"
 	help
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 07dfdb6a49c59..80925a17b059c 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -92,6 +92,7 @@ obj-$(CONFIG_HID_MAYFLASH)	+= hid-mf.o
 obj-$(CONFIG_HID_MEGAWORLD_FF)	+= hid-megaworld.o
 obj-$(CONFIG_HID_MICROSOFT)	+= hid-microsoft.o
 obj-$(CONFIG_HID_MONTEREY)	+= hid-monterey.o
+obj-$(CONFIG_HID_MSI)		+= hid-msi.o
 obj-$(CONFIG_HID_MULTITOUCH)	+= hid-multitouch.o
 obj-$(CONFIG_HID_NINTENDO)	+= hid-nintendo.o
 obj-$(CONFIG_HID_NTI)			+= hid-nti.o
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 933b7943bdb50..94a9b89dc240a 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -1047,7 +1047,12 @@
 #define USB_DEVICE_ID_MOZA_R16_R21_2	0x0010
 
 #define USB_VENDOR_ID_MSI		0x1770
+#define USB_VENDOR_ID_MSI_2		0x0db0
 #define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00
+#define USB_DEVICE_ID_MSI_CLAW_XINPUT	0x1901
+#define USB_DEVICE_ID_MSI_CLAW_DINPUT	0x1902
+#define USB_DEVICE_ID_MSI_CLAW_DESKTOP	0x1903
+#define USB_DEVICE_ID_MSI_CLAW_BIOS	0x1904
 
 #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400
 #define USB_DEVICE_ID_N_S_HARMONY	0xc359
diff --git a/drivers/hid/hid-msi.c b/drivers/hid/hid-msi.c
new file mode 100644
index 0000000000000..d95483907a5e5
--- /dev/null
+++ b/drivers/hid/hid-msi.c
@@ -0,0 +1,692 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  HID driver for MSI Claw Handheld PC gamepads.
+ *
+ *  Provides configuration support for the MSI Claw series of handheld PC
+ *  gamepads. Multiple iterations of the device firmware has led to some
+ *  quirks for how certain attributes are handled. The original firmware
+ *  did not support remapping of the M1 (right) and M2 (left) rear paddles.
+ *  Additionally, the MCU RAM address for writing configuration data has
+ *  changed twice. Checks are done during probe to enumerate these variances.
+ *
+ *  Copyright (c) 2026 Zhouwang Huang <honjow311@gmail.com>
+ *  Copyright (c) 2026 Denis Benato <denis.benato@linux.dev>
+ *  Copyright (c) 2026 Valve Corporation
+ */
+
+#include <linux/array_size.h>
+#include <linux/cleanup.h>
+#include <linux/completion.h>
+#include <linux/container_of.h>
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/kobject.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pm.h>
+#include <linux/spinlock.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+#include <linux/usb.h>
+#include <linux/workqueue.h>
+
+#include "hid-ids.h"
+
+#define CLAW_OUTPUT_REPORT_ID	0x0f
+#define CLAW_INPUT_REPORT_ID	0x10
+
+#define CLAW_PACKET_SIZE	64
+
+#define CLAW_DINPUT_CFG_INTF_IN	0x82
+#define CLAW_XINPUT_CFG_INTF_IN	0x83
+
+enum claw_command_index {
+	CLAW_COMMAND_TYPE_NONE =			0x00,
+	CLAW_COMMAND_TYPE_READ_PROFILE =		0x04,
+	CLAW_COMMAND_TYPE_READ_PROFILE_ACK =		0x05,
+	CLAW_COMMAND_TYPE_ACK =				0x06,
+	CLAW_COMMAND_TYPE_WRITE_PROFILE_DATA =		0x21,
+	CLAW_COMMAND_TYPE_SYNC_TO_ROM =			0x22,
+	CLAW_COMMAND_TYPE_SWITCH_MODE =			0x24,
+	CLAW_COMMAND_TYPE_READ_GAMEPAD_MODE =		0x26,
+	CLAW_COMMAND_TYPE_GAMEPAD_MODE_ACK =		0x27,
+	CLAW_COMMAND_TYPE_RESET_DEVICE =		0x28,
+};
+
+enum claw_gamepad_mode_index {
+	CLAW_GAMEPAD_MODE_XINPUT =	0x01,
+	CLAW_GAMEPAD_MODE_DINPUT =	0x02,
+	CLAW_GAMEPAD_MODE_DESKTOP =	0x04,
+};
+
+static const char * const claw_gamepad_mode_text[] = {
+	[CLAW_GAMEPAD_MODE_XINPUT] =	"xinput",
+	[CLAW_GAMEPAD_MODE_DINPUT] =	"dinput",
+	[CLAW_GAMEPAD_MODE_DESKTOP] =	"desktop",
+};
+
+enum claw_mkeys_function_index {
+	CLAW_MKEY_FUNCTION_MACRO,
+	CLAW_MKEY_FUNCTION_DISABLED,
+	CLAW_MKEY_FUNCTION_COMBO,
+};
+
+static const char * const claw_mkeys_function_text[] = {
+	[CLAW_MKEY_FUNCTION_MACRO] =	"macro",
+	[CLAW_MKEY_FUNCTION_DISABLED] =	"disabled",
+	[CLAW_MKEY_FUNCTION_COMBO] =	"combination",
+};
+
+struct claw_command_report {
+	u8 report_id;
+	u8 padding[2];
+	u8 header_tail;
+	u8 cmd;
+	u8 data[59];
+} __packed;
+
+struct claw_drvdata {
+	/* MCU General Variables */
+	struct completion send_cmd_complete;
+	struct delayed_work cfg_resume;
+	struct delayed_work cfg_setup;
+	struct hid_device *hdev;
+	struct mutex cfg_mutex; /* mutex for synchronous data */
+	bool waiting_for_ack;
+	spinlock_t cmd_lock; /* Lock for cmd data read/write */
+	u8 waiting_cmd;
+	int cmd_status;
+	u8 ep;
+
+	/* Gamepad Variables */
+	enum claw_mkeys_function_index mkeys_function;
+	enum claw_gamepad_mode_index gamepad_mode;
+	bool gamepad_registered;
+	spinlock_t mode_lock; /* Lock for mode data read/write */
+};
+
+static int get_endpoint_address(struct hid_device *hdev)
+{
+	struct usb_host_endpoint *ep;
+	struct usb_interface *intf;
+
+	intf = to_usb_interface(hdev->dev.parent);
+	ep = intf->cur_altsetting->endpoint;
+	if (ep)
+		return ep->desc.bEndpointAddress;
+
+	return -ENODEV;
+}
+
+static int claw_gamepad_mode_event(struct claw_drvdata *drvdata,
+				   struct claw_command_report *cmd_rep)
+{
+	if (cmd_rep->data[0] >= ARRAY_SIZE(claw_gamepad_mode_text) ||
+	    !claw_gamepad_mode_text[cmd_rep->data[0]] ||
+	    cmd_rep->data[1] >= ARRAY_SIZE(claw_mkeys_function_text))
+		return -EINVAL;
+
+	scoped_guard(spinlock, &drvdata->mode_lock) {
+		drvdata->gamepad_mode = cmd_rep->data[0];
+		drvdata->mkeys_function = cmd_rep->data[1];
+	}
+
+	return 0;
+}
+
+static int claw_raw_event(struct claw_drvdata *drvdata, struct hid_report *report,
+			  u8 *data, int size)
+{
+	struct claw_command_report *cmd_rep;
+	int ret = 0;
+
+	if (size != CLAW_PACKET_SIZE)
+		return 0;
+
+	cmd_rep = (struct claw_command_report *)data;
+
+	if (cmd_rep->report_id != CLAW_INPUT_REPORT_ID || cmd_rep->header_tail != 0x3c)
+		return 0;
+
+	dev_dbg(&drvdata->hdev->dev, "Rx data as raw input report: [%*ph]\n",
+		CLAW_PACKET_SIZE, data);
+
+	switch (cmd_rep->cmd) {
+	case CLAW_COMMAND_TYPE_GAMEPAD_MODE_ACK:
+		ret = claw_gamepad_mode_event(drvdata, cmd_rep);
+
+		scoped_guard(spinlock, &drvdata->cmd_lock) {
+			if (drvdata->waiting_for_ack &&
+			    drvdata->waiting_cmd == CLAW_COMMAND_TYPE_READ_GAMEPAD_MODE) {
+				drvdata->cmd_status = ret;
+				drvdata->waiting_for_ack = false;
+				complete(&drvdata->send_cmd_complete);
+			}
+		}
+
+		break;
+	case CLAW_COMMAND_TYPE_ACK:
+		scoped_guard(spinlock, &drvdata->cmd_lock) {
+			if (drvdata->waiting_for_ack) {
+				drvdata->cmd_status = 0;
+				drvdata->waiting_for_ack = false;
+				complete(&drvdata->send_cmd_complete);
+			}
+			dev_dbg(&drvdata->hdev->dev, "Waiting CMD: %x\n", drvdata->waiting_cmd);
+		}
+
+		break;
+	default:
+		dev_dbg(&drvdata->hdev->dev, "Unknown command: %x\n", cmd_rep->cmd);
+		return 0;
+	}
+
+	return ret;
+}
+
+static int msi_raw_event(struct hid_device *hdev, struct hid_report *report,
+			 u8 *data, int size)
+{
+	struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+
+	if (!drvdata || (drvdata->ep != CLAW_XINPUT_CFG_INTF_IN &&
+			 drvdata->ep != CLAW_DINPUT_CFG_INTF_IN))
+		return 0;
+
+	return claw_raw_event(drvdata, report, data, size);
+}
+
+static int claw_hw_output_report(struct hid_device *hdev, u8 index, u8 *data,
+				 size_t len, unsigned int timeout)
+{
+	unsigned char *dmabuf __free(kfree) = NULL;
+	u8 header[] = { CLAW_OUTPUT_REPORT_ID, 0, 0, 0x3c, index };
+	struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+	size_t header_size = ARRAY_SIZE(header);
+	int ret;
+
+	if (header_size + len > CLAW_PACKET_SIZE)
+		return -EINVAL;
+
+	/* We can't use a devm_alloc reusable buffer without side effects during suspend */
+	dmabuf = kzalloc(CLAW_PACKET_SIZE, GFP_KERNEL);
+	if (!dmabuf)
+		return -ENOMEM;
+
+	memcpy(dmabuf, header, header_size);
+	if (data && len)
+		memcpy(dmabuf + header_size, data, len);
+
+	guard(mutex)(&drvdata->cfg_mutex);
+	if (timeout) {
+		reinit_completion(&drvdata->send_cmd_complete);
+		scoped_guard(spinlock_irqsave, &drvdata->cmd_lock) {
+			drvdata->waiting_cmd = index;
+			drvdata->waiting_for_ack = true;
+			drvdata->cmd_status = -ETIMEDOUT;
+		}
+	}
+
+	dev_dbg(&hdev->dev, "Send data as raw output report: [%*ph]\n",
+		CLAW_PACKET_SIZE, dmabuf);
+
+	ret = hid_hw_output_report(hdev, dmabuf, CLAW_PACKET_SIZE);
+	if (ret < 0)
+		return ret;
+
+	ret = ret == CLAW_PACKET_SIZE ? 0 : -EIO;
+	if (ret) {
+		scoped_guard(spinlock_irqsave, &drvdata->cmd_lock) {
+			drvdata->waiting_cmd = CLAW_COMMAND_TYPE_NONE;
+			drvdata->waiting_for_ack = false;
+		}
+		return ret;
+	}
+
+	if (timeout) {
+		ret = wait_for_completion_interruptible_timeout(&drvdata->send_cmd_complete,
+								msecs_to_jiffies(timeout));
+
+		dev_dbg(&hdev->dev, "Remaining timeout: %u\n", ret);
+		ret = ret > 0 ? drvdata->cmd_status : ret ?: -EBUSY;
+		scoped_guard(spinlock_irqsave, &drvdata->cmd_lock)
+			drvdata->waiting_for_ack = false;
+	}
+
+	return ret;
+}
+
+static ssize_t gamepad_mode_store(struct device *dev, struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct hid_device *hdev = to_hid_device(dev);
+	struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+	int i, ret = -EINVAL;
+	u8 data[2];
+
+	/* Pairs with smp_store_release from cfg_setup_fn in system_wq context */
+	if (!smp_load_acquire(&drvdata->gamepad_registered))
+		return -ENODEV;
+
+	for (i = 0; i < ARRAY_SIZE(claw_gamepad_mode_text); i++) {
+		if (claw_gamepad_mode_text[i] && sysfs_streq(buf, claw_gamepad_mode_text[i])) {
+			ret = i;
+			break;
+		}
+	}
+	if (ret < 0)
+		return ret;
+
+	data[0] = ret;
+	scoped_guard(spinlock_irqsave, &drvdata->mode_lock)
+		data[1] = drvdata->mkeys_function;
+
+	ret = claw_hw_output_report(hdev, CLAW_COMMAND_TYPE_SWITCH_MODE, data, ARRAY_SIZE(data), 0);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static ssize_t gamepad_mode_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct hid_device *hdev = to_hid_device(dev);
+	struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+	int ret, i;
+
+	/* Pairs with smp_store_release from cfg_setup_fn in system_wq context */
+	if (!smp_load_acquire(&drvdata->gamepad_registered))
+		return -ENODEV;
+
+	ret = claw_hw_output_report(hdev, CLAW_COMMAND_TYPE_READ_GAMEPAD_MODE, NULL, 0, 25);
+	if (ret)
+		return ret;
+
+	scoped_guard(spinlock_irqsave, &drvdata->mode_lock)
+		i = drvdata->gamepad_mode;
+
+	if (!claw_gamepad_mode_text[i] || claw_gamepad_mode_text[i][0] == '\0')
+		return sysfs_emit(buf, "unsupported\n");
+
+	return sysfs_emit(buf, "%s\n", claw_gamepad_mode_text[i]);
+}
+static DEVICE_ATTR_RW(gamepad_mode);
+
+static ssize_t gamepad_mode_index_show(struct device *dev,
+				       struct device_attribute *attr, char *buf)
+{
+	ssize_t count = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(claw_gamepad_mode_text); i++) {
+		if (!claw_gamepad_mode_text[i] || claw_gamepad_mode_text[i][0] == '\0')
+			continue;
+		count += sysfs_emit_at(buf, count, "%s ", claw_gamepad_mode_text[i]);
+	}
+
+	if (count)
+		buf[count - 1] = '\n';
+
+	return count;
+}
+static DEVICE_ATTR_RO(gamepad_mode_index);
+
+static ssize_t mkeys_function_store(struct device *dev, struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	struct hid_device *hdev = to_hid_device(dev);
+	struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+	int i, ret = -EINVAL;
+	u8 data[2];
+
+	/* Pairs with smp_store_release from cfg_setup_fn in system_wq context */
+	if (!smp_load_acquire(&drvdata->gamepad_registered))
+		return -ENODEV;
+
+	for (i = 0; i < ARRAY_SIZE(claw_mkeys_function_text); i++) {
+		if (claw_mkeys_function_text[i] && sysfs_streq(buf, claw_mkeys_function_text[i])) {
+			ret = i;
+			break;
+		}
+	}
+	if (ret < 0)
+		return ret;
+
+	scoped_guard(spinlock_irqsave, &drvdata->mode_lock)
+		data[0] = drvdata->gamepad_mode;
+	data[1] = ret;
+
+	ret = claw_hw_output_report(hdev, CLAW_COMMAND_TYPE_SWITCH_MODE, data, ARRAY_SIZE(data), 0);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static ssize_t mkeys_function_show(struct device *dev, struct device_attribute *attr,
+				   char *buf)
+{
+	struct hid_device *hdev = to_hid_device(dev);
+	struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+	int ret, i;
+
+	/* Pairs with smp_store_release from cfg_setup_fn in system_wq context */
+	if (!smp_load_acquire(&drvdata->gamepad_registered))
+		return -ENODEV;
+
+	ret = claw_hw_output_report(hdev, CLAW_COMMAND_TYPE_READ_GAMEPAD_MODE, NULL, 0, 25);
+	if (ret)
+		return ret;
+
+	scoped_guard(spinlock_irqsave, &drvdata->mode_lock)
+		i = drvdata->mkeys_function;
+
+	if (i >= ARRAY_SIZE(claw_mkeys_function_text))
+		return sysfs_emit(buf, "unsupported\n");
+
+	return sysfs_emit(buf, "%s\n", claw_mkeys_function_text[i]);
+}
+static DEVICE_ATTR_RW(mkeys_function);
+
+static ssize_t mkeys_function_index_show(struct device *dev,
+					 struct device_attribute *attr, char *buf)
+{
+	int i, count = 0;
+
+	for (i = 0; i < ARRAY_SIZE(claw_mkeys_function_text); i++)
+		count += sysfs_emit_at(buf, count, "%s ", claw_mkeys_function_text[i]);
+
+	if (count)
+		buf[count - 1] = '\n';
+
+	return count;
+}
+static DEVICE_ATTR_RO(mkeys_function_index);
+
+static ssize_t reset_store(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct hid_device *hdev = to_hid_device(dev);
+	struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+	bool val;
+	int ret;
+
+	/* Pairs with smp_store_release from cfg_setup_fn in system_wq context */
+	if (!smp_load_acquire(&drvdata->gamepad_registered))
+		return -ENODEV;
+
+	ret = kstrtobool(buf, &val);
+	if (ret)
+		return ret;
+
+	if (!val)
+		return -EINVAL;
+
+	ret = claw_hw_output_report(hdev, CLAW_COMMAND_TYPE_RESET_DEVICE, NULL, 0, 0);
+	if (ret)
+		return ret;
+
+	return count;
+}
+static DEVICE_ATTR_WO(reset);
+
+static umode_t claw_gamepad_attr_is_visible(struct kobject *kobj, struct attribute *attr,
+					    int n)
+{
+	struct hid_device *hdev = to_hid_device(kobj_to_dev(kobj));
+	struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+
+	if (!drvdata) {
+		dev_warn(&hdev->dev,
+			 "Failed to get drvdata from kobj. Gamepad attributes are not available.\n");
+		return 0;
+	}
+
+	return attr->mode;
+}
+
+static struct attribute *claw_gamepad_attrs[] = {
+	&dev_attr_gamepad_mode.attr,
+	&dev_attr_gamepad_mode_index.attr,
+	&dev_attr_mkeys_function.attr,
+	&dev_attr_mkeys_function_index.attr,
+	&dev_attr_reset.attr,
+	NULL,
+};
+
+static const struct attribute_group claw_gamepad_attr_group = {
+	.attrs = claw_gamepad_attrs,
+	.is_visible = claw_gamepad_attr_is_visible,
+};
+
+static void cfg_setup_fn(struct work_struct *work)
+{
+	struct delayed_work *dwork = container_of(work, struct delayed_work, work);
+	struct claw_drvdata *drvdata = container_of(dwork, struct claw_drvdata, cfg_setup);
+	int ret;
+
+	ret = claw_hw_output_report(drvdata->hdev, CLAW_COMMAND_TYPE_READ_GAMEPAD_MODE,
+				    NULL, 0, 25);
+	if (ret) {
+		dev_err(&drvdata->hdev->dev,
+			"Failed to setup device, can't read gamepad mode: %d\n", ret);
+		return;
+	}
+
+	/* Add sysfs attributes after we get the device state */
+	ret = devm_device_add_group(&drvdata->hdev->dev, &claw_gamepad_attr_group);
+	if (ret) {
+		dev_err(&drvdata->hdev->dev,
+			"Failed to setup device, can't create gamepad attrs: %d\n", ret);
+		return;
+	}
+	/* Pairs with smp_load_acquire in attribute show/store functions */
+	smp_store_release(&drvdata->gamepad_registered, true);
+
+	kobject_uevent(&drvdata->hdev->dev.kobj, KOBJ_CHANGE);
+}
+
+static void cfg_resume_fn(struct work_struct *work)
+{
+	struct delayed_work *dwork = container_of(work, struct delayed_work, work);
+	struct claw_drvdata *drvdata = container_of(dwork, struct claw_drvdata, cfg_resume);
+
+	/* Pairs with smp_store_release from cfg_setup_fn in system_wq context */
+	if (!smp_load_acquire(&drvdata->gamepad_registered))
+		schedule_delayed_work(&drvdata->cfg_setup, msecs_to_jiffies(500));
+}
+
+static int claw_probe(struct hid_device *hdev, u8 ep)
+{
+	struct claw_drvdata *drvdata;
+	int ret;
+
+	drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+
+	drvdata->gamepad_mode = CLAW_GAMEPAD_MODE_XINPUT;
+	drvdata->hdev = hdev;
+	drvdata->ep = ep;
+
+	mutex_init(&drvdata->cfg_mutex);
+	spin_lock_init(&drvdata->cmd_lock);
+	spin_lock_init(&drvdata->mode_lock);
+	init_completion(&drvdata->send_cmd_complete);
+	INIT_DELAYED_WORK(&drvdata->cfg_resume, &cfg_resume_fn);
+	INIT_DELAYED_WORK(&drvdata->cfg_setup, &cfg_setup_fn);
+
+	/* For control interface: open the HID transport for sending commands. */
+	ret = hid_hw_open(hdev);
+	if (ret)
+		return ret;
+
+	hid_set_drvdata(hdev, drvdata);
+	schedule_delayed_work(&drvdata->cfg_setup, msecs_to_jiffies(500));
+
+	return 0;
+}
+
+static int msi_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+	int ret;
+	u8 ep;
+
+	if (!hid_is_usb(hdev)) {
+		ret = -ENODEV;
+		goto err_probe;
+	}
+
+	ret = hid_parse(hdev);
+	if (ret)
+		goto err_probe;
+
+	/* Set quirk to create separate input devices per HID application */
+	hdev->quirks |= HID_QUIRK_INPUT_PER_APP | HID_QUIRK_MULTI_INPUT;
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+	if (ret)
+		goto err_probe;
+
+	/* For non-control interfaces (keyboard/mouse), allow userspace to grab the devices. */
+	ret = get_endpoint_address(hdev);
+	if (ret < 0)
+		goto err_stop_hw;
+
+	ep = ret;
+	if (ep == CLAW_XINPUT_CFG_INTF_IN || ep == CLAW_DINPUT_CFG_INTF_IN) {
+		ret = claw_probe(hdev, ep);
+		if (ret)
+			goto err_stop_hw;
+	}
+
+	return 0;
+
+err_stop_hw:
+	hid_hw_stop(hdev);
+err_probe:
+	return dev_err_probe(&hdev->dev, ret, "Failed to init device\n");
+}
+
+static void claw_remove(struct hid_device *hdev)
+{
+	struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+
+	if (!drvdata) {
+		hid_hw_close(hdev);
+		return;
+	}
+
+	cancel_delayed_work_sync(&drvdata->cfg_resume);
+	cancel_delayed_work_sync(&drvdata->cfg_setup);
+
+	/* Pairs with smp_load_acquire in attribute show/store functions */
+	smp_store_release(&drvdata->gamepad_registered, false);
+
+	hid_hw_close(hdev);
+}
+
+static void msi_remove(struct hid_device *hdev)
+{
+	int ret;
+	u8 ep;
+
+	/* Safe assumption. SET_INTERFACE ioctl can't be used while driver is bound */
+	ret = get_endpoint_address(hdev);
+	if (ret <= 0)
+		goto hw_stop;
+
+	ep = ret;
+	if (ep == CLAW_XINPUT_CFG_INTF_IN || ep == CLAW_DINPUT_CFG_INTF_IN)
+		claw_remove(hdev);
+
+hw_stop:
+	hid_hw_stop(hdev);
+}
+
+static int claw_resume(struct hid_device *hdev)
+{
+	struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+
+	if (!drvdata)
+		return -ENODEV;
+
+	/* MCU can take up to 500ms to be ready after resume */
+	schedule_delayed_work(&drvdata->cfg_resume, msecs_to_jiffies(500));
+	return 0;
+}
+
+static int msi_resume(struct hid_device *hdev)
+{
+	int ret;
+	u8 ep;
+
+	/* Safe assumption. SET_INTERFACE ioctl can't be used while driver is bound */
+	ret = get_endpoint_address(hdev);
+	if (ret <= 0)
+		return 0;
+
+	ep = ret;
+	if (ep == CLAW_XINPUT_CFG_INTF_IN || ep == CLAW_DINPUT_CFG_INTF_IN)
+		return claw_resume(hdev);
+
+	return 0;
+}
+
+static int claw_suspend(struct hid_device *hdev)
+{
+	struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+
+	if (!drvdata)
+		return -ENODEV;
+
+	cancel_delayed_work_sync(&drvdata->cfg_resume);
+	cancel_delayed_work_sync(&drvdata->cfg_setup);
+
+	return 0;
+}
+
+static int msi_suspend(struct hid_device *hdev, pm_message_t msg)
+{
+	int ret;
+	u8 ep;
+
+	/* Safe assumption. SET_INTERFACE ioctl can't be used while driver is bound */
+	ret = get_endpoint_address(hdev);
+	if (ret <= 0)
+		return 0;
+
+	ep = ret;
+	if (ep == CLAW_XINPUT_CFG_INTF_IN || ep == CLAW_DINPUT_CFG_INTF_IN)
+		return claw_suspend(hdev);
+
+	return 0;
+}
+
+static const struct hid_device_id msi_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MSI_2, USB_DEVICE_ID_MSI_CLAW_XINPUT) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MSI_2, USB_DEVICE_ID_MSI_CLAW_DINPUT) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MSI_2, USB_DEVICE_ID_MSI_CLAW_DESKTOP) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MSI_2, USB_DEVICE_ID_MSI_CLAW_BIOS) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, msi_devices);
+
+static struct hid_driver msi_driver = {
+	.name		= "hid-msi",
+	.id_table	= msi_devices,
+	.raw_event	= msi_raw_event,
+	.probe		= msi_probe,
+	.remove		= msi_remove,
+	.resume		= msi_resume,
+	.suspend	= pm_ptr(msi_suspend),
+};
+module_hid_driver(msi_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Denis Benato <denis.benato@linux.dev>");
+MODULE_AUTHOR("Zhouwang Huang <honjow311@gmail.com>");
+MODULE_AUTHOR("Derek J. Clark <derekjohn.clark@gmail.com>");
+MODULE_DESCRIPTION("HID driver for MSI Claw Handheld PC gamepads");
-- 
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