diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2019-10-27 21:00:19 +0300 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2019-10-27 21:00:19 +0300 |
commit | 728d90bdc9e480dc93913e59a0aa3c896c7aa697 (patch) | |
tree | 258b1b6ee711f0ef67fd225700d84eccec285194 /drivers/soc/fsl/qbman/qman_ccsr.c | |
parent | cb3efd5a38855eabd26c2b631dd027169678d60f (diff) | |
parent | d6d5df1db6e9d7f8f76d2911707f7d5877251b02 (diff) | |
download | linux-728d90bdc9e480dc93913e59a0aa3c896c7aa697.tar.xz |
Merge tag 'v5.4-rc5' into next
Sync up with mainline.
Diffstat (limited to 'drivers/soc/fsl/qbman/qman_ccsr.c')
-rw-r--r-- | drivers/soc/fsl/qbman/qman_ccsr.c | 68 |
1 files changed, 62 insertions, 6 deletions
diff --git a/drivers/soc/fsl/qbman/qman_ccsr.c b/drivers/soc/fsl/qbman/qman_ccsr.c index a6bb43007d03..157659fd033a 100644 --- a/drivers/soc/fsl/qbman/qman_ccsr.c +++ b/drivers/soc/fsl/qbman/qman_ccsr.c @@ -274,6 +274,7 @@ static u32 __iomem *qm_ccsr_start; /* A SDQCR mask comprising all the available/visible pool channels */ static u32 qm_pools_sdqcr; static int __qman_probed; +static int __qman_requires_cleanup; static inline u32 qm_ccsr_in(u32 offset) { @@ -340,19 +341,55 @@ static void qm_get_version(u16 *id, u8 *major, u8 *minor) } #define PFDR_AR_EN BIT(31) -static void qm_set_memory(enum qm_memory memory, u64 ba, u32 size) +static int qm_set_memory(enum qm_memory memory, u64 ba, u32 size) { + void *ptr; u32 offset = (memory == qm_memory_fqd) ? REG_FQD_BARE : REG_PFDR_BARE; u32 exp = ilog2(size); + u32 bar, bare; /* choke if size isn't within range */ DPAA_ASSERT((size >= 4096) && (size <= 1024*1024*1024) && is_power_of_2(size)); /* choke if 'ba' has lower-alignment than 'size' */ DPAA_ASSERT(!(ba & (size - 1))); + + /* Check to see if QMan has already been initialized */ + bar = qm_ccsr_in(offset + REG_offset_BAR); + if (bar) { + /* Maker sure ba == what was programmed) */ + bare = qm_ccsr_in(offset); + if (bare != upper_32_bits(ba) || bar != lower_32_bits(ba)) { + pr_err("Attempted to reinitialize QMan with different BAR, got 0x%llx read BARE=0x%x BAR=0x%x\n", + ba, bare, bar); + return -ENOMEM; + } + __qman_requires_cleanup = 1; + /* Return 1 to indicate memory was previously programmed */ + return 1; + } + /* Need to temporarily map the area to make sure it is zeroed */ + ptr = memremap(ba, size, MEMREMAP_WB); + if (!ptr) { + pr_crit("memremap() of QMan private memory failed\n"); + return -ENOMEM; + } + memset(ptr, 0, size); + +#ifdef CONFIG_PPC + /* + * PPC doesn't appear to flush the cache on memunmap() but the + * cache must be flushed since QMan does non coherent accesses + * to this memory + */ + flush_dcache_range((unsigned long) ptr, (unsigned long) ptr+size); +#endif + memunmap(ptr); + qm_ccsr_out(offset, upper_32_bits(ba)); qm_ccsr_out(offset + REG_offset_BAR, lower_32_bits(ba)); qm_ccsr_out(offset + REG_offset_AR, PFDR_AR_EN | (exp - 1)); + return 0; } static void qm_set_pfdr_threshold(u32 th, u8 k) @@ -455,7 +492,7 @@ RESERVEDMEM_OF_DECLARE(qman_pfdr, "fsl,qman-pfdr", qman_pfdr); #endif -static unsigned int qm_get_fqid_maxcnt(void) +unsigned int qm_get_fqid_maxcnt(void) { return fqd_sz / 64; } @@ -571,12 +608,19 @@ static int qman_init_ccsr(struct device *dev) int i, err; /* FQD memory */ - qm_set_memory(qm_memory_fqd, fqd_a, fqd_sz); + err = qm_set_memory(qm_memory_fqd, fqd_a, fqd_sz); + if (err < 0) + return err; /* PFDR memory */ - qm_set_memory(qm_memory_pfdr, pfdr_a, pfdr_sz); - err = qm_init_pfdr(dev, 8, pfdr_sz / 64 - 8); - if (err) + err = qm_set_memory(qm_memory_pfdr, pfdr_a, pfdr_sz); + if (err < 0) return err; + /* Only initialize PFDRs if the QMan was not initialized before */ + if (err == 0) { + err = qm_init_pfdr(dev, 8, pfdr_sz / 64 - 8); + if (err) + return err; + } /* thresholds */ qm_set_pfdr_threshold(512, 64); qm_set_sfdr_threshold(128); @@ -693,6 +737,18 @@ int qman_is_probed(void) } EXPORT_SYMBOL_GPL(qman_is_probed); +int qman_requires_cleanup(void) +{ + return __qman_requires_cleanup; +} + +void qman_done_cleanup(void) +{ + qman_enable_irqs(); + __qman_requires_cleanup = 0; +} + + static int fsl_qman_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; |