From: Anders Berg <anders.b...@intel.com> Signed-off-by: Anders Berg <anders.b...@intel.com> --- arch/arm/mach-axxia/axxia.c | 1 - drivers/misc/lsi-ncr.c | 219 +++++++++++++++---------------------------- 2 files changed, 73 insertions(+), 147 deletions(-)
diff --git a/arch/arm/mach-axxia/axxia.c b/arch/arm/mach-axxia/axxia.c index 0753d03..7a235cd 100644 --- a/arch/arm/mach-axxia/axxia.c +++ b/arch/arm/mach-axxia/axxia.c @@ -211,7 +211,6 @@ void __init axxia_dt_init(void) axxia_auxdata_lookup, NULL); pm_power_off = NULL; /* TBD */ - ncr_init(); axxia_ddr_retention_init(); axxia_pcie_init(); diff --git a/drivers/misc/lsi-ncr.c b/drivers/misc/lsi-ncr.c index 276d72c..48244d6 100644 --- a/drivers/misc/lsi-ncr.c +++ b/drivers/misc/lsi-ncr.c @@ -21,9 +21,7 @@ */ #include <linux/module.h> -#include <linux/jiffies.h> - -#include <asm/io.h> +#include <linux/io.h> #include "lsi-ncr.h" @@ -41,11 +39,17 @@ static void __iomem *apb2ser0_address; #define WFC_TIMEOUT (400000) +/* Protect NCA PIO registers from concurrent use. */ static DEFINE_RAW_SPINLOCK(ncr_spin_lock); -static DEFINE_RAW_SPINLOCK(nca_access_lock); + +/* This lock protect each individual register read/write to the NCA registers + * due to a bug in rev 1.0 silicon where the bus interface may hang if the NCA + * is subjected to simultaneous requests from multiple masters + */ +DEFINE_RAW_SPINLOCK(nca_access_lock); EXPORT_SYMBOL(nca_access_lock); -static unsigned long ncr_spin_flags, axi_access_flags; +static unsigned long ncr_spin_flags; #define LOCK_DOMAIN 0 @@ -96,163 +100,100 @@ typedef union { } __packed bits; } __packed command_data_register_2_t; -int -ncr_read_nolock(unsigned long region, unsigned long address, int number, -void *buffer); - -#ifdef CONFIG_ARM - -/* - * like iowrite32be but without the barrier. - * The iowmb barrier in the standard macro includes a outer_cache_sync - * which we don't want for Axxia register IO. - */ -#define axxia_write32be(v, p) \ - ({ __raw_writel((__force __u32)cpu_to_be32(v), p); }) -/* - ---------------------------------------------------------------------- - ncr_register_read -*/ - -inline unsigned long +unsigned long ncr_register_read(unsigned *address) { - unsigned long value; - - value = ioread32be(address); + unsigned long value = __raw_readl(address); - return value; + return be32_to_cpu(value); } -/* - ---------------------------------------------------------------------- - ncr_register_write -*/ - void -inline ncr_register_write(const unsigned value, unsigned *address) +ncr_register_write(const unsigned value, unsigned *address) { - axxia_write32be(value, address); - asm volatile ("mcr p15,0,%0,c7,c5,4" : : "r" (0)); /* isb */ - - return; + __raw_writel(cpu_to_be32(value), address); } -#else - /* ---------------------------------------------------------------------- - ncr_register_read + nca_register_read */ -inline unsigned long -ncr_register_read(unsigned *address) +static unsigned long +nca_register_read(unsigned *address) { - unsigned long value; + unsigned long value, flags; - value = in_be32((unsigned *)address); + raw_spin_lock_irqsave(&nca_access_lock, flags); + value = ncr_register_read(address); + raw_spin_unlock_irqrestore(&nca_access_lock, flags); return value; } /* ---------------------------------------------------------------------- - ncr_register_write + nca_register_write */ -inline void -ncr_register_write(const unsigned value, unsigned *address) +static void +nca_register_write(const unsigned value, unsigned *address) { - out_be32(address, value); + unsigned long flags; - return; + raw_spin_lock_irqsave(&nca_access_lock, flags); + ncr_register_write(value, address); + raw_spin_unlock_irqrestore(&nca_access_lock, flags); } -#endif - -/* - ---------------------------------------------------------------------- - nca_register_read -*/ - -inline unsigned long -nca_register_read(unsigned *address) +/* These are only needed on platforms there AMP mode of operation is supported + * (currently only on PowerPC based Axxia platforms). In AMP mode, multiple OS + * instances may be accessing the NCA registers, thus requiring a hardware + * based spinlock like this. + */ +#ifdef CONFIG_PPC32 +static void +ncr_amp_lock(int domain) { - unsigned long value; - - raw_spin_lock_irqsave(&nca_access_lock, - axi_access_flags); - value = ncr_register_read(address); - raw_spin_unlock_irqrestore(&nca_access_lock, - axi_access_flags); + unsigned long offset = (0xff80 + (domain * 4)); - return value; + while (nca_register_read((unsigned *)(nca_address + offset)) != 0) + cpu_relax(); } -/* - ---------------------------------------------------------------------- - nca_register_write -*/ - -void -inline nca_register_write(const unsigned value, unsigned *address) +static void +ncr_amp_unlock(int domain) { - raw_spin_lock_irqsave(&nca_access_lock, - axi_access_flags); - ncr_register_write(value, address); - raw_spin_unlock_irqrestore(&nca_access_lock, - axi_access_flags); + unsigned long offset = (0xff80 + (domain * 4)); - return; + nca_register_write(0, (unsigned *)(nca_address + offset)); } +#else +static void ncr_amp_lock(int domain) {} +static void ncr_amp_unlock(int domain) {} +#endif -/* - ------------------------------------------------------------------------------ - ncr_lock -*/ - -static int +/** + * Used to serialize all access to NCA PIO interface. + */ +int ncr_lock(int domain) { - unsigned long offset; - unsigned long value; - unsigned long timeout = jiffies + msecs_to_jiffies(1000); - raw_spin_lock_irqsave(&ncr_spin_lock, ncr_spin_flags); - offset = (0xff80 + (domain * 4)); - - do { - value = nca_register_read((unsigned *)(nca_address + offset)); - } while ((0 != value) && (time_before(jiffies, timeout))); - - if (!(time_before(jiffies, timeout))) { - raw_spin_unlock_irqrestore(&ncr_spin_lock, ncr_spin_flags); - pr_err("ncr_lock() Timeout!\n"); - BUG(); - - return -1; - } - + ncr_amp_lock(domain); return 0; } EXPORT_SYMBOL(ncr_lock); -/* - ------------------------------------------------------------------------------ - ncr_unlock -*/ - -static void +/** + * Used to serialize all access to NCA PIO interface. + */ +void ncr_unlock(int domain) { - unsigned long offset; - - offset = (0xff80 + (domain * 4)); - nca_register_write(0, (unsigned *)(nca_address + offset)); + ncr_amp_unlock(domain); raw_spin_unlock_irqrestore(&ncr_spin_lock, ncr_spin_flags); - - return; } EXPORT_SYMBOL(ncr_unlock); @@ -307,7 +248,6 @@ ncr_check_pio_status(char *str) pr_err("lsi-ncr: PIO operation timeout cdr0=0x%08lx!\n", cdr0.raw); ncr_pio_error_dump(str); - ncr_unlock(LOCK_DOMAIN); BUG(); return -1; } @@ -342,7 +282,6 @@ ncr_read_nolock(unsigned long region, unsigned long address, int number, command_data_register_0_t cdr0; command_data_register_1_t cdr1; command_data_register_2_t cdr2; - int wfc_timeout = WFC_TIMEOUT; if ((NCP_NODE_ID(region) != 0x0153) && (NCP_NODE_ID(region) != 0x115)) { /* make sure any previous command has completed */ @@ -400,6 +339,8 @@ ncr_read_nolock(unsigned long region, unsigned long address, int number, } } else { #ifdef APB2SER_PHY_PHYS_ADDRESS + int wfc_timeout = WFC_TIMEOUT; + if (NCP_NODE_ID(region) != 0x115) { void __iomem *targ_address = apb2ser0_address + (address & (~0x3)); @@ -415,9 +356,8 @@ ncr_read_nolock(unsigned long region, unsigned long address, int number, } } else { void __iomem *base; - if (0xffff < address) { + if (0xffff < address) return -1; - } switch (NCP_TARGET_ID(region)) { case 0: @@ -454,9 +394,8 @@ ncr_read_nolock(unsigned long region, unsigned long address, int number, } while (0 != (*((unsigned long *) buffer) & 0x80000000) && 0 < wfc_timeout); - if (0 == wfc_timeout) { + if (0 == wfc_timeout) return -1; - } if ((NCP_TARGET_ID(region) == 0x1) || (NCP_TARGET_ID(region) == 0x4)) { @@ -481,9 +420,8 @@ EXPORT_SYMBOL(ncr_read_nolock); int ncr_read(unsigned long region, unsigned long address, int number, - void *buffer) + void *buffer) { - int rc; if (NULL == nca_address) @@ -494,9 +432,7 @@ ncr_read(unsigned long region, unsigned long address, int number, return -1; #endif /* APB2SER_PHY_PHYS_ADDRESS */ - if (0 != ncr_lock(LOCK_DOMAIN)) - return -1; - + ncr_lock(LOCK_DOMAIN); rc = ncr_read_nolock(region, address, number, buffer); @@ -513,14 +449,13 @@ EXPORT_SYMBOL(ncr_read); int ncr_write_nolock(unsigned long region, unsigned long address, int number, - void *buffer) + void *buffer) { command_data_register_0_t cdr0; command_data_register_1_t cdr1; command_data_register_2_t cdr2; unsigned long data_word_base; int dbs = (number - 1); - int wfc_timeout = WFC_TIMEOUT; if ((NCP_NODE_ID(region) != 0x0153) && (NCP_NODE_ID(region) != 0x115)) { /* make sure any previous command has completed */ @@ -585,6 +520,8 @@ ncr_write_nolock(unsigned long region, unsigned long address, int number, } else { #ifdef APB2SER_PHY_PHYS_ADDRESS + int wfc_timeout = WFC_TIMEOUT; + if (NCP_NODE_ID(region) != 0x115) { void __iomem *targ_address = apb2ser0_address + (address & (~0x3)); @@ -600,9 +537,8 @@ ncr_write_nolock(unsigned long region, unsigned long address, int number, } } else { void __iomem *base; - if (0xffff < address) { + if (0xffff < address) return -1; - } switch (NCP_TARGET_ID(region)) { case 0: @@ -641,9 +577,8 @@ ncr_write_nolock(unsigned long region, unsigned long address, int number, } while (0 != (*((unsigned long *) buffer) & 0x80000000) && 0 < wfc_timeout); - if (0 == wfc_timeout) { + if (0 == wfc_timeout) return -1; - } } #else return -1; @@ -669,8 +604,7 @@ ncr_write(unsigned long region, unsigned long address, int number, return -1; #endif /* APB2SER_PHY_PHYS_ADDRESS */ - if (0 != ncr_lock(LOCK_DOMAIN)) - return -1; + ncr_lock(LOCK_DOMAIN); rc = ncr_write_nolock(region, address, number, buffer); @@ -678,7 +612,6 @@ ncr_write(unsigned long region, unsigned long address, int number, return rc; } - EXPORT_SYMBOL(ncr_write); /* @@ -686,7 +619,7 @@ EXPORT_SYMBOL(ncr_write); ncr_init */ -int +static int ncr_init(void) { nca_address = ioremap(NCA_PHYS_ADDRESS, 0x20000); @@ -699,16 +632,14 @@ ncr_init(void) return 0; } - - -module_init(ncr_init); +core_initcall(ncr_init); /* ---------------------------------------------------------------------- ncr_exit */ -void __exit +static void __exit ncr_exit(void) { /* Unmap the NCA. */ @@ -720,12 +651,8 @@ ncr_exit(void) if (NULL != apb2ser0_address) iounmap(apb2ser0_address); #endif /* APB2SER_PHY_PHYS_ADDRESS */ - - return; } - - -module_exit(ncr_exit); +__exitcall(ncr_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Register Ring access for LSI's ACP board"); -- 1.7.9.5 -- _______________________________________________ linux-yocto mailing list linux-yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/linux-yocto