diff options
author | Hauke Mehrtens <hauke@openwrt.org> | 2015-12-02 15:23:08 +0000 |
---|---|---|
committer | Hauke Mehrtens <hauke@openwrt.org> | 2015-12-02 15:23:08 +0000 |
commit | 8fdb4d2eaa72125879fb3e05ede6913a3733f86a (patch) | |
tree | 24384c705928c2f8a8896aa8456922a0910bb460 /target/linux/bcm53xx/patches-4.3/130-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch | |
parent | 83ce86dec975da392a44c2f4287459df2b7027a4 (diff) | |
download | master-187ad058-8fdb4d2eaa72125879fb3e05ede6913a3733f86a.tar.gz master-187ad058-8fdb4d2eaa72125879fb3e05ede6913a3733f86a.tar.bz2 master-187ad058-8fdb4d2eaa72125879fb3e05ede6913a3733f86a.zip |
bcm53xx: update SMP patches
Broadcom submitted new SMP patches for this SoC to upstream Linux, add
them to OpenWrt.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@47687 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/bcm53xx/patches-4.3/130-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch')
-rw-r--r-- | target/linux/bcm53xx/patches-4.3/130-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch | 635 |
1 files changed, 0 insertions, 635 deletions
diff --git a/target/linux/bcm53xx/patches-4.3/130-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch b/target/linux/bcm53xx/patches-4.3/130-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch deleted file mode 100644 index 5e3bd7793d..0000000000 --- a/target/linux/bcm53xx/patches-4.3/130-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch +++ /dev/null @@ -1,635 +0,0 @@ -From a0ad1511d5805b95ac4c454d7904c670a1696055 Mon Sep 17 00:00:00 2001 -From: Kapil Hali <kapilh@broadcom.com> -Date: Wed, 14 Oct 2015 13:47:00 -0400 -Subject: [PATCH] ARM: BCM: Add SMP support for Broadcom NSP - -Add SMP support for Broadcom's Northstar Plus SoC, -cpu enable method and pen_release procedures. This -changes also consolidates iProc family's - BCM NSP -and BCM Kona, SMP handling in a common file. - -Northstar Plus SoC is based on ARM Cortex-A9 -revision r3p0 which requires configuration for ARM -Errata 764369 for SMP. This change adds the needed -configuration option. - -Signed-off-by: Kapil Hali <kapilh@broadcom.com> ---- - arch/arm/mach-bcm/Makefile | 2 +- - arch/arm/mach-bcm/bcm_nsp.h | 19 +++ - arch/arm/mach-bcm/headsmp.S | 37 +++++ - arch/arm/mach-bcm/kona_smp.c | 202 --------------------------- - arch/arm/mach-bcm/platsmp.c | 326 +++++++++++++++++++++++++++++++++++++++++++ - 5 files changed, 383 insertions(+), 203 deletions(-) - create mode 100644 arch/arm/mach-bcm/bcm_nsp.h - create mode 100644 arch/arm/mach-bcm/headsmp.S - delete mode 100644 arch/arm/mach-bcm/kona_smp.c - create mode 100644 arch/arm/mach-bcm/platsmp.c - ---- a/arch/arm/mach-bcm/Makefile -+++ b/arch/arm/mach-bcm/Makefile -@@ -20,7 +20,7 @@ obj-$(CONFIG_ARCH_BCM_281XX) += board_bc - obj-$(CONFIG_ARCH_BCM_21664) += board_bcm21664.o - - # BCM281XX and BCM21664 SMP support --obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += kona_smp.o -+obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += platsmp.o - - # BCM281XX and BCM21664 L2 cache control - obj-$(CONFIG_ARCH_BCM_MOBILE_L2_CACHE) += kona_l2_cache.o ---- /dev/null -+++ b/arch/arm/mach-bcm/bcm_nsp.h -@@ -0,0 +1,19 @@ -+/* -+ * Copyright (C) 2015 Broadcom Corporation -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License as -+ * published by the Free Software Foundation version 2. -+ * -+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any -+ * kind, whether express or implied; without even the implied warranty -+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#ifndef __BCM_NSP_H -+#define __BCM_NSP_H -+ -+extern void nsp_secondary_startup(void); -+ -+#endif /* __BCM_NSP_H */ ---- /dev/null -+++ b/arch/arm/mach-bcm/headsmp.S -@@ -0,0 +1,37 @@ -+/* -+ * Copyright (C) 2015 Broadcom Corporation -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License as -+ * published by the Free Software Foundation version 2. -+ * -+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any -+ * kind, whether express or implied; without even the implied warranty -+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include <linux/linkage.h> -+ -+/* -+ * iProc specific entry point for secondary CPUs. This provides -+ * a "holding pen" into which all secondary cores are held until -+ * we are ready for them to initialise. -+ */ -+ENTRY(nsp_secondary_startup) -+ mrc p15, 0, r0, c0, c0, 5 -+ and r0, r0, #15 -+ adr r4, 1f -+ ldmia r4, {r5, r6} -+ sub r4, r4, r5 -+ add r6, r6, r4 -+pen: ldr r7, [r6] -+ cmp r7, r0 -+ bne pen -+ -+ b secondary_startup -+ -+1: .long . -+ .long pen_release -+ -+ENDPROC(nsp_secondary_startup) ---- a/arch/arm/mach-bcm/kona_smp.c -+++ /dev/null -@@ -1,202 +0,0 @@ --/* -- * Copyright (C) 2014 Broadcom Corporation -- * Copyright 2014 Linaro Limited -- * -- * This program is free software; you can redistribute it and/or -- * modify it under the terms of the GNU General Public License as -- * published by the Free Software Foundation version 2. -- * -- * This program is distributed "as is" WITHOUT ANY WARRANTY of any -- * kind, whether express or implied; without even the implied warranty -- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- * GNU General Public License for more details. -- */ -- --#include <linux/init.h> --#include <linux/errno.h> --#include <linux/io.h> --#include <linux/of.h> --#include <linux/sched.h> -- --#include <asm/smp.h> --#include <asm/smp_plat.h> --#include <asm/smp_scu.h> -- --/* Size of mapped Cortex A9 SCU address space */ --#define CORTEX_A9_SCU_SIZE 0x58 -- --#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */ --#define BOOT_ADDR_CPUID_MASK 0x3 -- --/* Name of device node property defining secondary boot register location */ --#define OF_SECONDARY_BOOT "secondary-boot-reg" -- --/* I/O address of register used to coordinate secondary core startup */ --static u32 secondary_boot; -- --/* -- * Enable the Cortex A9 Snoop Control Unit -- * -- * By the time this is called we already know there are multiple -- * cores present. We assume we're running on a Cortex A9 processor, -- * so any trouble getting the base address register or getting the -- * SCU base is a problem. -- * -- * Return 0 if successful or an error code otherwise. -- */ --static int __init scu_a9_enable(void) --{ -- unsigned long config_base; -- void __iomem *scu_base; -- -- if (!scu_a9_has_base()) { -- pr_err("no configuration base address register!\n"); -- return -ENXIO; -- } -- -- /* Config base address register value is zero for uniprocessor */ -- config_base = scu_a9_get_base(); -- if (!config_base) { -- pr_err("hardware reports only one core\n"); -- return -ENOENT; -- } -- -- scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE); -- if (!scu_base) { -- pr_err("failed to remap config base (%lu/%u) for SCU\n", -- config_base, CORTEX_A9_SCU_SIZE); -- return -ENOMEM; -- } -- -- scu_enable(scu_base); -- -- iounmap(scu_base); /* That's the last we'll need of this */ -- -- return 0; --} -- --static void __init bcm_smp_prepare_cpus(unsigned int max_cpus) --{ -- static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 }; -- struct device_node *node; -- int ret; -- -- BUG_ON(secondary_boot); /* We're called only once */ -- -- /* -- * This function is only called via smp_ops->smp_prepare_cpu(). -- * That only happens if a "/cpus" device tree node exists -- * and has an "enable-method" property that selects the SMP -- * operations defined herein. -- */ -- node = of_find_node_by_path("/cpus"); -- BUG_ON(!node); -- -- /* -- * Our secondary enable method requires a "secondary-boot-reg" -- * property to specify a register address used to request the -- * ROM code boot a secondary code. If we have any trouble -- * getting this we fall back to uniprocessor mode. -- */ -- if (of_property_read_u32(node, OF_SECONDARY_BOOT, &secondary_boot)) { -- pr_err("%s: missing/invalid " OF_SECONDARY_BOOT " property\n", -- node->name); -- ret = -ENOENT; /* Arrange to disable SMP */ -- goto out; -- } -- -- /* -- * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is -- * returned, the SoC reported a uniprocessor configuration. -- * We bail on any other error. -- */ -- ret = scu_a9_enable(); --out: -- of_node_put(node); -- if (ret) { -- /* Update the CPU present map to reflect uniprocessor mode */ -- BUG_ON(ret != -ENOENT); -- pr_warn("disabling SMP\n"); -- init_cpu_present(&only_cpu_0); -- } --} -- --/* -- * The ROM code has the secondary cores looping, waiting for an event. -- * When an event occurs each core examines the bottom two bits of the -- * secondary boot register. When a core finds those bits contain its -- * own core id, it performs initialization, including computing its boot -- * address by clearing the boot register value's bottom two bits. The -- * core signals that it is beginning its execution by writing its boot -- * address back to the secondary boot register, and finally jumps to -- * that address. -- * -- * So to start a core executing we need to: -- * - Encode the (hardware) CPU id with the bottom bits of the secondary -- * start address. -- * - Write that value into the secondary boot register. -- * - Generate an event to wake up the secondary CPU(s). -- * - Wait for the secondary boot register to be re-written, which -- * indicates the secondary core has started. -- */ --static int bcm_boot_secondary(unsigned int cpu, struct task_struct *idle) --{ -- void __iomem *boot_reg; -- phys_addr_t boot_func; -- u64 start_clock; -- u32 cpu_id; -- u32 boot_val; -- bool timeout = false; -- -- cpu_id = cpu_logical_map(cpu); -- if (cpu_id & ~BOOT_ADDR_CPUID_MASK) { -- pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK); -- return -EINVAL; -- } -- -- if (!secondary_boot) { -- pr_err("required secondary boot register not specified\n"); -- return -EINVAL; -- } -- -- boot_reg = ioremap_nocache((phys_addr_t)secondary_boot, sizeof(u32)); -- if (!boot_reg) { -- pr_err("unable to map boot register for cpu %u\n", cpu_id); -- return -ENOSYS; -- } -- -- /* -- * Secondary cores will start in secondary_startup(), -- * defined in "arch/arm/kernel/head.S" -- */ -- boot_func = virt_to_phys(secondary_startup); -- BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK); -- BUG_ON(boot_func > (phys_addr_t)U32_MAX); -- -- /* The core to start is encoded in the low bits */ -- boot_val = (u32)boot_func | cpu_id; -- writel_relaxed(boot_val, boot_reg); -- -- sev(); -- -- /* The low bits will be cleared once the core has started */ -- start_clock = local_clock(); -- while (!timeout && readl_relaxed(boot_reg) == boot_val) -- timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS; -- -- iounmap(boot_reg); -- -- if (!timeout) -- return 0; -- -- pr_err("timeout waiting for cpu %u to start\n", cpu_id); -- -- return -ENOSYS; --} -- --static struct smp_operations bcm_smp_ops __initdata = { -- .smp_prepare_cpus = bcm_smp_prepare_cpus, -- .smp_boot_secondary = bcm_boot_secondary, --}; --CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method", -- &bcm_smp_ops); ---- /dev/null -+++ b/arch/arm/mach-bcm/platsmp.c -@@ -0,0 +1,326 @@ -+/* -+ * Copyright (C) 2014-2015 Broadcom Corporation -+ * Copyright 2014 Linaro Limited -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License as -+ * published by the Free Software Foundation version 2. -+ * -+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any -+ * kind, whether express or implied; without even the implied warranty -+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include <linux/cpumask.h> -+#include <linux/delay.h> -+#include <linux/errno.h> -+#include <linux/init.h> -+#include <linux/io.h> -+#include <linux/jiffies.h> -+#include <linux/of.h> -+#include <linux/sched.h> -+#include <linux/smp.h> -+ -+#include <asm/cacheflush.h> -+#include <asm/smp.h> -+#include <asm/smp_plat.h> -+#include <asm/smp_scu.h> -+ -+#include "bcm_nsp.h" -+ -+/* Size of mapped Cortex A9 SCU address space */ -+#define CORTEX_A9_SCU_SIZE 0x58 -+ -+#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */ -+#define BOOT_ADDR_CPUID_MASK 0x3 -+ -+/* Name of device node property defining secondary boot register location */ -+#define OF_SECONDARY_BOOT "secondary-boot-reg" -+ -+/* I/O address of register used to coordinate secondary core startup */ -+static u32 secondary_boot; -+ -+static DEFINE_SPINLOCK(boot_lock); -+ -+/* -+ * Write pen_release in a way that is guaranteed to be visible to all -+ * observers, irrespective of whether they're taking part in coherency -+ * or not. This is necessary for the hotplug code to work reliably. -+ */ -+static void write_pen_release(int val) -+{ -+ pen_release = val; -+ /* -+ * Ensure write to pen_release is visible to the other cores, -+ * here - primary core -+ */ -+ smp_wmb(); -+ sync_cache_w(&pen_release); -+} -+ -+/* -+ * Enable the Cortex A9 Snoop Control Unit -+ * -+ * By the time this is called we already know there are multiple -+ * cores present. We assume we're running on a Cortex A9 processor, -+ * so any trouble getting the base address register or getting the -+ * SCU base is a problem. -+ * -+ * Return 0 if successful or an error code otherwise. -+ */ -+static int __init scu_a9_enable(void) -+{ -+ unsigned long config_base; -+ void __iomem *scu_base; -+ -+ if (!scu_a9_has_base()) { -+ pr_err("no configuration base address register!\n"); -+ return -ENXIO; -+ } -+ -+ /* Config base address register value is zero for uniprocessor */ -+ config_base = scu_a9_get_base(); -+ if (!config_base) { -+ pr_err("hardware reports only one core\n"); -+ return -ENOENT; -+ } -+ -+ scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE); -+ if (!scu_base) { -+ pr_err("failed to remap config base (%lu/%u) for SCU\n", -+ config_base, CORTEX_A9_SCU_SIZE); -+ return -ENOMEM; -+ } -+ -+ scu_enable(scu_base); -+ -+ iounmap(scu_base); /* That's the last we'll need of this */ -+ -+ return 0; -+} -+ -+static int nsp_write_lut(void (*secondary_startup) (void)) -+{ -+ void __iomem *sku_rom_lut; -+ phys_addr_t secondary_startup_phy; -+ -+ if (!secondary_boot) { -+ pr_warn("required secondary boot register not specified\n"); -+ return -EINVAL; -+ } -+ -+ sku_rom_lut = ioremap_nocache((phys_addr_t)secondary_boot, -+ sizeof(secondary_boot)); -+ if (!sku_rom_lut) { -+ pr_warn("unable to ioremap SKU-ROM LUT register\n"); -+ return -ENOMEM; -+ } -+ -+ secondary_startup_phy = virt_to_phys(secondary_startup); -+ BUG_ON(secondary_startup_phy > (phys_addr_t)U32_MAX); -+ -+ writel_relaxed(secondary_startup_phy, sku_rom_lut); -+ /* -+ * Ensure the write is visible to the secondary core. -+ */ -+ smp_wmb(); -+ -+ iounmap(sku_rom_lut); -+ -+ return 0; -+} -+ -+static void nsp_secondary_init(unsigned int cpu) -+{ -+ /* -+ * Let the primary cpu know we are out of holding pen. -+ */ -+ write_pen_release(-1); -+ -+ /* -+ * Synchronise with the boot thread. -+ */ -+ spin_lock(&boot_lock); -+ spin_unlock(&boot_lock); -+} -+ -+static void __init bcm_smp_prepare_cpus(unsigned int max_cpus) -+{ -+ static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 }; -+ struct device_node *node; -+ int ret; -+ -+ BUG_ON(secondary_boot); /* We're called only once */ -+ -+ /* -+ * This function is only called via smp_ops->smp_prepare_cpu(). -+ * That only happens if a "/cpus" device tree node exists -+ * and has an "enable-method" property that selects the SMP -+ * operations defined herein. -+ */ -+ node = of_find_node_by_path("/cpus"); -+ BUG_ON(!node); -+ -+ /* -+ * Our secondary enable method requires a "secondary-boot-reg" -+ * property to specify a register address used to request the -+ * ROM code boot a secondary core. If we have any trouble -+ * getting this we fall back to uniprocessor mode. -+ */ -+ if (of_property_read_u32(node, OF_SECONDARY_BOOT, &secondary_boot)) { -+ pr_warn("%s: missing/invalid " OF_SECONDARY_BOOT " property\n", -+ node->name); -+ ret = -ENOENT; /* Arrange to disable SMP */ -+ goto out; -+ } -+ -+ /* -+ * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is -+ * returned, the SoC reported a uniprocessor configuration. -+ * We bail on any other error. -+ */ -+ ret = scu_a9_enable(); -+out: -+ of_node_put(node); -+ if (ret) { -+ /* Update the CPU present map to reflect uniprocessor mode */ -+ pr_warn("disabling SMP\n"); -+ init_cpu_present(&only_cpu_0); -+ } -+} -+ -+/* -+ * The ROM code has the secondary cores looping, waiting for an event. -+ * When an event occurs each core examines the bottom two bits of the -+ * secondary boot register. When a core finds those bits contain its -+ * own core id, it performs initialization, including computing its boot -+ * address by clearing the boot register value's bottom two bits. The -+ * core signals that it is beginning its execution by writing its boot -+ * address back to the secondary boot register, and finally jumps to -+ * that address. -+ * -+ * So to start a core executing we need to: -+ * - Encode the (hardware) CPU id with the bottom bits of the secondary -+ * start address. -+ * - Write that value into the secondary boot register. -+ * - Generate an event to wake up the secondary CPU(s). -+ * - Wait for the secondary boot register to be re-written, which -+ * indicates the secondary core has started. -+ */ -+static int kona_boot_secondary(unsigned int cpu, struct task_struct *idle) -+{ -+ void __iomem *boot_reg; -+ phys_addr_t boot_func; -+ u64 start_clock; -+ u32 cpu_id; -+ u32 boot_val; -+ bool timeout = false; -+ -+ cpu_id = cpu_logical_map(cpu); -+ if (cpu_id & ~BOOT_ADDR_CPUID_MASK) { -+ pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK); -+ return -EINVAL; -+ } -+ -+ if (!secondary_boot) { -+ pr_err("required secondary boot register not specified\n"); -+ return -EINVAL; -+ } -+ -+ boot_reg = ioremap_nocache((phys_addr_t)secondary_boot, sizeof(u32)); -+ if (!boot_reg) { -+ pr_err("unable to map boot register for cpu %u\n", cpu_id); -+ return -ENOMEM; -+ } -+ -+ /* -+ * Secondary cores will start in secondary_startup(), -+ * defined in "arch/arm/kernel/head.S" -+ */ -+ boot_func = virt_to_phys(secondary_startup); -+ BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK); -+ BUG_ON(boot_func > (phys_addr_t)U32_MAX); -+ -+ /* The core to start is encoded in the low bits */ -+ boot_val = (u32)boot_func | cpu_id; -+ writel_relaxed(boot_val, boot_reg); -+ -+ sev(); -+ -+ /* The low bits will be cleared once the core has started */ -+ start_clock = local_clock(); -+ while (!timeout && readl_relaxed(boot_reg) == boot_val) -+ timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS; -+ -+ iounmap(boot_reg); -+ -+ if (!timeout) -+ return 0; -+ -+ pr_err("timeout waiting for cpu %u to start\n", cpu_id); -+ -+ return -ENXIO; -+} -+ -+static int nsp_boot_secondary(unsigned int cpu, struct task_struct *idle) -+{ -+ unsigned long timeout; -+ int ret; -+ -+ /* -+ * After wake up, secondary core branches to the startup -+ * address programmed at SKU ROM LUT location. -+ */ -+ ret = nsp_write_lut(nsp_secondary_startup); -+ if (ret) { -+ pr_err("unable to write startup addr to SKU ROM LUT\n"); -+ goto out; -+ } -+ -+ /* -+ * The secondary processor is waiting to be released from -+ * the holding pen - release it, then wait for it to flag -+ * that it has been released by resetting pen_release. -+ */ -+ spin_lock(&boot_lock); -+ -+ write_pen_release(cpu_logical_map(cpu)); -+ /* -+ * Send an Event to wake up the secondary core which is in -+ * WFE state. Updated pen_release should also be visible to -+ * the secondary core. -+ */ -+ dsb_sev(); -+ -+ timeout = jiffies + (1 * HZ); -+ while (time_before(jiffies, timeout)) { -+ /* Make sure loads on other CPU is visible */ -+ smp_rmb(); -+ if (pen_release == -1) -+ break; -+ -+ udelay(10); -+ } -+ -+ spin_unlock(&boot_lock); -+ -+ ret = pen_release != -1 ? -ENXIO : 0; -+ -+out: -+ return ret; -+} -+ -+static struct smp_operations bcm_smp_ops __initdata = { -+ .smp_prepare_cpus = bcm_smp_prepare_cpus, -+ .smp_boot_secondary = kona_boot_secondary, -+}; -+CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method", -+ &bcm_smp_ops); -+ -+struct smp_operations nsp_smp_ops __initdata = { -+ .smp_prepare_cpus = bcm_smp_prepare_cpus, -+ .smp_secondary_init = nsp_secondary_init, -+ .smp_boot_secondary = nsp_boot_secondary, -+}; -+CPU_METHOD_OF_DECLARE(bcm_smp_nsp, "brcm,bcm-nsp-smp", &nsp_smp_ops); |