* [PATCH 1/3] ARM: Define KERNEL_START and KERNEL_END
From: Chris Brandt @ 2016-12-06 22:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161206195312.22354-2-f.fainelli@gmail.com>
On 12/6/2016, Florian Fainelli wrote:
> diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
> index 4001dd15818d..18ef688a796e 100644
> --- a/arch/arm/mm/mmu.c
> +++ b/arch/arm/mm/mmu.c
> @@ -1437,12 +1437,8 @@ static void __init kmap_init(void)
> static void __init map_lowmem(void)
> {
> struct memblock_region *reg;
> -#ifdef CONFIG_XIP_KERNEL
> - phys_addr_t kernel_x_start = round_down(__pa(_sdata), SECTION_SIZE);
> -#else
> - phys_addr_t kernel_x_start = round_down(__pa(_stext), SECTION_SIZE);
> -#endif
> - phys_addr_t kernel_x_end = round_up(__pa(__init_end), SECTION_SIZE);
> + phys_addr_t kernel_x_start = round_down(__pa(KERNEL_START),
> SECTION_SIZE);
> + phys_addr_t kernel_x_end = round_down(__pa(_end), SECTION_SIZE);
Why are you changing the end of executable kernel (hence the 'x' in
kernel_x_end) from __init_end to _end which basically maps the entire
kernel image including text and data?
Doing so would then change data from MT_MEMORY_RW into MT_MEMORY_RWX.
I would think it would create some type of security risk to allow
data to be executable.
^ permalink raw reply
* [PATCH 1/3] ARM: Define KERNEL_START and KERNEL_END
From: Florian Fainelli @ 2016-12-06 22:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <SG2PR06MB116569D2A9756BE11131CB4B8A820@SG2PR06MB1165.apcprd06.prod.outlook.com>
On 12/06/2016 02:43 PM, Chris Brandt wrote:
> On 12/6/2016, Florian Fainelli wrote:
>> diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
>> index 4001dd15818d..18ef688a796e 100644
>> --- a/arch/arm/mm/mmu.c
>> +++ b/arch/arm/mm/mmu.c
>> @@ -1437,12 +1437,8 @@ static void __init kmap_init(void)
>> static void __init map_lowmem(void)
>> {
>> struct memblock_region *reg;
>> -#ifdef CONFIG_XIP_KERNEL
>> - phys_addr_t kernel_x_start = round_down(__pa(_sdata), SECTION_SIZE);
>> -#else
>> - phys_addr_t kernel_x_start = round_down(__pa(_stext), SECTION_SIZE);
>> -#endif
>> - phys_addr_t kernel_x_end = round_up(__pa(__init_end), SECTION_SIZE);
>> + phys_addr_t kernel_x_start = round_down(__pa(KERNEL_START),
>> SECTION_SIZE);
>> + phys_addr_t kernel_x_end = round_down(__pa(_end), SECTION_SIZE);
>
> Why are you changing the end of executable kernel (hence the 'x' in
> kernel_x_end) from __init_end to _end which basically maps the entire
> kernel image including text and data?
That's a typo, was not intentional thanks for spotting it.
--
Florian
^ permalink raw reply
* Tearing down DMA transfer setup after DMA client has finished
From: Mason @ 2016-12-06 22:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <yw1xshq12hr9.fsf@unicorn.mansr.com>
On 06/12/2016 16:34, M?ns Rullg?rd wrote:
> Mason writes:
>
>> Meh. The two controller blocks share the I/O pins to the outside
>> world, so it's not possible to have two concurrent accesses.
>
> OK, you failed to mention that part. Why are there two controllers at
> all if only one or the other can be used?
I'd have to ask the HW designer what types of use-cases he had
in mind. Perhaps looking at what is *not* shared provides clues.
Configuration registers are duplicated, meaning it is possible
to decide "channel A for chip0, channel B for chip1" if there
are two NAND chips in the system (as is the case on dev boards).
In that case, it is unnecessary to rewrite the chip parameters
every time the driver switches chips. (I don't think the perf
impact is even measurable.)
The ECC engines are duplicated, but I don't know how long it
takes to run the BCH algorithm in HW vs performing I/O over
a slow 8-bit bus.
>> The callback is called from vchan_complete() right?
>> Is that running from interrupt context?
>
> It runs from a tasklet which is almost the same thing.
I'll read up on tasklets tomorrow.
>> I can give that a shot (if you're busy with real work).
>
> I have an idea I'd like to try out over the weekend. If I don't come
> back with something by next week, go for it.
I do have my plate full this week, with XHCI and AHCI :-)
>> Why can't we queue channel requests the same way we queue
>> transfer requests?
>
> That's in effect what we're doing. Calling it by another name doesn't
> really solve anything.
Hmmm... the difference is that "tear down" would be explicit
in the release function.
Current implementation for single transfer:
dmaengine_prep_slave_sg()
dmaengine_submit()
dma_async_issue_pending() /* A */
wait for read channel IRQ /* B */
spin until NFC idle /* C */
Setup SBOX route and program MBUS transfer happen in A.
The SBOX route is torn down a little before B (thus before C).
With the proposed implementation, where request_chan
sets up the route and release_chan tears it down:
request_chan() /* X */
dmaengine_prep_slave_sg()
dmaengine_submit()
dma_async_issue_pending() /* A */
wait for read channel IRQ /* B */
spin until NFC idle /* C */
release_chan() /* Y */
Now, the SBOX route is setup in X.
(If no MBUS channel are available, thread is put to sleep
until one becomes available.)
Program MBUS transfer in A.
When IRQ falls, cannot start new transfer yet.
vchan_complete() will at some point run the client callback.
The client driver can now spin however long until NFC idle.
In Y, we release the channel, thus calling back into the
DMA driver, at which point a new transfer can be started.
What did I get wrong in this pseudo-code?
I do see one problem with the approach:
It's no big deal for me to convert the NFC driver to
do it that way, but the Synopsys (I think) SATA driver
in tango3 and tango4 is shared across multiple SoCs,
and they probably call request_chan() only in the
probe function, as you mentioned at some point.
http://lxr.free-electrons.com/source/drivers/ata/sata_dwc_460ex.c#L366
BTW, can someone explain what the DMA_CTRL_ACK flag means?
Regards.
^ permalink raw reply
* [PATCH 1/2] dt-bindings: mmc: add DT binding for S3C24XX MMC/SD/SDIO controller
From: Rob Herring @ 2016-12-06 23:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <054a65d8-8606-eeb0-e028-1b85dbf1c8ba@samsung.com>
On Fri, Dec 02, 2016 at 09:48:45AM +0900, Jaehoon Chung wrote:
> On 12/02/2016 09:14 AM, Sergio Prado wrote:
> > Adds the device tree bindings description for Samsung S3C24XX
> > MMC/SD/SDIO controller, used as a connectivity interface with external
> > MMC, SD and SDIO storage mediums.
> >
> > Signed-off-by: Sergio Prado <sergio.prado@e-labworks.com>
> > ---
> > .../devicetree/bindings/mmc/samsung,s3cmci.txt | 38 ++++++++++++++++++++++
> > 1 file changed, 38 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/mmc/samsung,s3cmci.txt
> >
> > diff --git a/Documentation/devicetree/bindings/mmc/samsung,s3cmci.txt b/Documentation/devicetree/bindings/mmc/samsung,s3cmci.txt
> > new file mode 100644
> > index 000000000000..3f044076e69a
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/mmc/samsung,s3cmci.txt
> > @@ -0,0 +1,38 @@
> > +* Samsung's S3C24XX MMC/SD/SDIO controller device tree bindings
> > +
> > +Samsung's S3C24XX MMC/SD/SDIO controller is used as a connectivity interface
> > +with external MMC, SD and SDIO storage mediums.
> > +
> > +This file documents differences between the core mmc properties described by
> > +mmc.txt and the properties used by the Samsung S3C24XX MMC/SD/SDIO controller
> > +implementation.
> > +
> > +Required SoC Specific Properties:
> > +- compatible: should be one of the following
> > + - "samsung,s3c2410-sdi": for controllers compatible with s3c2410
> > + - "samsung,s3c2412-sdi": for controllers compatible with s3c2412
> > + - "samsung,s3c2440-sdi": for controllers compatible with s3c2440
> > +- clocks: Should reference the controller clock
> > +- clock-names: Should contain "sdi"
> > +
> > +Required Board Specific Properties:
> > +- pinctrl-0: Should specify pin control groups used for this controller.
> > +- pinctrl-names: Should contain only one value - "default".
>
> I'm not sure but i think this description doesn't need at here.
>
> > +
> > +Example:
> > + sdi: sdi at 5a000000 {
>
> I think it needs to use "mmc0: sdi at 5a000000" instead of "sdi: sdi at 5a000000"
> Because mmc is more clear than sdi.
The label doesn't matter much as it is not part of the dtb. The unit
name should be 'mmc' though.
With that,
Acked-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* [PATCH] clk: uniphier: Fix build with gcc-4.4.
From: Stephen Boyd @ 2016-12-06 23:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAK7LNATeswNhoFsA90k=qF4Jock0ytNT-pPT6j+0b9MJFJwu9Q@mail.gmail.com>
On 12/03, Masahiro Yamada wrote:
> Hi Vinson,
>
> 2016-12-03 9:37 GMT+09:00 Vinson Lee <vlee@freedesktop.org>:
> > gcc-4.4 has issues with anonymous unions in initializers.
> >
> > CC drivers/clk/uniphier/clk-uniphier-sys.o
> > drivers/clk/uniphier/clk-uniphier-sys.c:45: error: unknown field ?factor? specified in initializer
> >
> > Fixes: 1574d5722636 ("clk: uniphier: remove unneeded member name for union")
> > Signed-off-by: Vinson Lee <vlee@freedesktop.org>
>
>
> This driver has COMPILE_TEST option, but kbuild test robot
> did not mention about this.
>
>
>
> This is a bad way of fixing, I think.
> (what if a new member is inserted before the union in the future?)
>
> Rather, please revert the bad commit.
>
Reverting on top of clk-next will cause build failures though.
Can you resend the patch series without this first patch please?
I'll apply them then.
I'll go drop all three patches and wreck Andrew's merge of this
patch to -mm.
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* [PATCH 3/4] iommu/arm-smmu: Disable stalling faults for all endpoints
From: Rob Clark @ 2016-12-06 23:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1471525542-14969-4-git-send-email-will.deacon@arm.com>
On Thu, Aug 18, 2016 at 9:05 AM, Will Deacon <will.deacon@arm.com> wrote:
> Enabling stalling faults can result in hardware deadlock on poorly
> designed systems, particularly those with a PCI root complex upstream of
> the SMMU.
>
> Although it's not really Linux's job to save hardware integrators from
> their own misfortune, it *is* our job to stop userspace (e.g. VFIO
> clients) from hosing the system for everybody else, even if they might
> already be required to have elevated privileges.
>
> Given that the fault handling code currently executes entirely in IRQ
> context, there is nothing that can sensibly be done to recover from
> things like page faults anyway, so let's rip this code out for now and
> avoid the potential for deadlock.
Hi Will,
so, I'd like to re-introduce this feature, I *guess* as some sort of
opt-in quirk (ie. disabled by default unless something in DT tells you
otherwise?? But I'm open to suggestions. I'm not entirely sure what
hw was having problems due to this feature.)
On newer snapdragon devices we are using arm-smmu for the GPU, and
halting the GPU so the driver's fault handler can dump some GPU state
on faults is enormously helpful for debugging and tracking down where
in the gpu cmdstream the fault was triggered. In addition, we will
eventually want the ability to update pagetables from fault handler
and resuming the faulting transition.
Some additional comments below..
> Cc: <stable@vger.kernel.org>
> Reported-by: Matt Evans <matt.evans@arm.com>
> Signed-off-by: Will Deacon <will.deacon@arm.com>
> ---
> drivers/iommu/arm-smmu.c | 34 +++++++---------------------------
> 1 file changed, 7 insertions(+), 27 deletions(-)
>
> diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
> index 4f49fe29f202..2db74ebc3240 100644
> --- a/drivers/iommu/arm-smmu.c
> +++ b/drivers/iommu/arm-smmu.c
> @@ -686,8 +686,7 @@ static struct iommu_gather_ops arm_smmu_gather_ops = {
>
> static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
> {
> - int flags, ret;
> - u32 fsr, fsynr, resume;
> + u32 fsr, fsynr;
> unsigned long iova;
> struct iommu_domain *domain = dev;
> struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
> @@ -701,34 +700,15 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
> if (!(fsr & FSR_FAULT))
> return IRQ_NONE;
>
> - if (fsr & FSR_IGN)
> - dev_err_ratelimited(smmu->dev,
> - "Unexpected context fault (fsr 0x%x)\n",
> - fsr);
> -
> fsynr = readl_relaxed(cb_base + ARM_SMMU_CB_FSYNR0);
> - flags = fsynr & FSYNR0_WNR ? IOMMU_FAULT_WRITE : IOMMU_FAULT_READ;
> -
> iova = readq_relaxed(cb_base + ARM_SMMU_CB_FAR);
> - if (!report_iommu_fault(domain, smmu->dev, iova, flags)) {
> - ret = IRQ_HANDLED;
> - resume = RESUME_RETRY;
> - } else {
> - dev_err_ratelimited(smmu->dev,
> - "Unhandled context fault: iova=0x%08lx, fsynr=0x%x, cb=%d\n",
> - iova, fsynr, cfg->cbndx);
I would like to decouple this dev_err_ratelimit() print from the
RESUME_RETRY vs RESUME_TERMINATE behaviour. I need the ability to
indicate by return from my fault handler whether to resume or
terminate. But I already have my own ratelimted prints and would
prefer not to spam dmesg twice.
I'm thinking about report_iommu_fault() returning:
0 => RESUME_RETRY
-EFAULT => RESUME_TERMINATE but don't print
anything else (or specifically -ENOSYS?) => RESUME_TERMINATE and print
thoughts?
> - ret = IRQ_NONE;
> - resume = RESUME_TERMINATE;
> - }
> -
> - /* Clear the faulting FSR */
> - writel(fsr, cb_base + ARM_SMMU_CB_FSR);
>
> - /* Retry or terminate any stalled transactions */
> - if (fsr & FSR_SS)
> - writel_relaxed(resume, cb_base + ARM_SMMU_CB_RESUME);
This might be a bug in qcom's implementation of the smmu spec, but
seems like we don't have SS bit set, yet we still require RESUME reg
to be written, otherwise gpu is perma-wedged. Maybe topic for a
separate quirk? I'm not sure if writing RESUME reg on other hw when
SS bit is not set is likely to cause problems? If not I suppose we
could just unconditionally write it.
Anyways, I'm not super-familiar w/ arm-smmu so suggestions welcome..
in between debugging freedreno I'll try to put together some patches.
BR,
-R
> + dev_err_ratelimited(smmu->dev,
> + "Unhandled context fault: fsr=0x%x, iova=0x%08lx, fsynr=0x%x, cb=%d\n",
> + fsr, iova, fsynr, cfg->cbndx);
>
> - return ret;
> + writel(fsr, cb_base + ARM_SMMU_CB_FSR);
> + return IRQ_HANDLED;
> }
>
> static irqreturn_t arm_smmu_global_fault(int irq, void *dev)
> @@ -837,7 +817,7 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain,
> }
>
> /* SCTLR */
> - reg = SCTLR_CFCFG | SCTLR_CFIE | SCTLR_CFRE | SCTLR_M | SCTLR_EAE_SBOP;
> + reg = SCTLR_CFIE | SCTLR_CFRE | SCTLR_M | SCTLR_EAE_SBOP;
> if (stage1)
> reg |= SCTLR_S1_ASIDPNE;
> #ifdef __BIG_ENDIAN
> --
> 2.1.4
>
> _______________________________________________
> iommu mailing list
> iommu at lists.linux-foundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/iommu
^ permalink raw reply
* [PATCHv5 00/11] CONFIG_DEBUG_VIRTUAL for arm64
From: Laura Abbott @ 2016-12-06 23:50 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
This is v5 of the series to add CONFIG_DEBUG_VIRTUAL for arm64. This mostly
contains minor fixups including adding a few extra headers around and splitting
things out into a few more sub-patches.
With a few more acks I think this should be ready to go. More testing is
always appreciated though.
Thanks,
Laura
Laura Abbott (11):
lib/Kconfig.debug: Add ARCH_HAS_DEBUG_VIRTUAL
mm/cma: Cleanup highmem check
arm64: Move some macros under #ifndef __ASSEMBLY__
arm64: Add cast for virt_to_pfn
mm: Introduce lm_alias
arm64: Use __pa_symbol for kernel symbols
drivers: firmware: psci: Use __pa_symbol for kernel symbol
kexec: Switch to __pa_symbol
mm/kasan: Switch to using __pa_symbol and lm_alias
mm/usercopy: Switch to using lm_alias
arm64: Add support for CONFIG_DEBUG_VIRTUAL
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/kvm_mmu.h | 4 +-
arch/arm64/include/asm/memory.h | 66 +++++++++++++++++++++----------
arch/arm64/include/asm/mmu_context.h | 6 +--
arch/arm64/include/asm/pgtable.h | 2 +-
arch/arm64/kernel/acpi_parking_protocol.c | 3 +-
arch/arm64/kernel/cpu-reset.h | 2 +-
arch/arm64/kernel/cpufeature.c | 3 +-
arch/arm64/kernel/hibernate.c | 20 +++-------
arch/arm64/kernel/insn.c | 2 +-
arch/arm64/kernel/psci.c | 3 +-
arch/arm64/kernel/setup.c | 9 +++--
arch/arm64/kernel/smp_spin_table.c | 3 +-
arch/arm64/kernel/vdso.c | 8 +++-
arch/arm64/mm/Makefile | 2 +
arch/arm64/mm/init.c | 12 +++---
arch/arm64/mm/kasan_init.c | 22 +++++++----
arch/arm64/mm/mmu.c | 33 ++++++++++------
arch/arm64/mm/physaddr.c | 30 ++++++++++++++
arch/x86/Kconfig | 1 +
drivers/firmware/psci.c | 2 +-
include/linux/mm.h | 4 ++
kernel/kexec_core.c | 2 +-
lib/Kconfig.debug | 5 ++-
mm/cma.c | 15 +++----
mm/kasan/kasan_init.c | 15 +++----
mm/usercopy.c | 4 +-
27 files changed, 180 insertions(+), 99 deletions(-)
create mode 100644 arch/arm64/mm/physaddr.c
--
2.7.4
^ permalink raw reply
* [PATCHv5 01/11] lib/Kconfig.debug: Add ARCH_HAS_DEBUG_VIRTUAL
From: Laura Abbott @ 2016-12-06 23:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481068257-6367-1-git-send-email-labbott@redhat.com>
DEBUG_VIRTUAL currently depends on DEBUG_KERNEL && X86. arm64 is getting
the same support. Rather than add a list of architectures, switch this
to ARCH_HAS_DEBUG_VIRTUAL and let architectures select it as
appropriate.
Acked-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Mark Rutland <mark.rutland@arm.com>
Suggested-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Laura Abbott <labbott@redhat.com>
---
v5: No changes
---
arch/x86/Kconfig | 1 +
lib/Kconfig.debug | 5 ++++-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index bada636..f533321 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -23,6 +23,7 @@ config X86
select ARCH_CLOCKSOURCE_DATA
select ARCH_DISCARD_MEMBLOCK
select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI
+ select ARCH_HAS_DEBUG_VIRTUAL
select ARCH_HAS_DEVMEM_IS_ALLOWED
select ARCH_HAS_ELF_RANDOMIZE
select ARCH_HAS_FAST_MULTIPLIER
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index a6c8db1..be65e04 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -603,9 +603,12 @@ config DEBUG_VM_PGFLAGS
If unsure, say N.
+config ARCH_HAS_DEBUG_VIRTUAL
+ bool
+
config DEBUG_VIRTUAL
bool "Debug VM translations"
- depends on DEBUG_KERNEL && X86
+ depends on DEBUG_KERNEL && ARCH_HAS_DEBUG_VIRTUAL
help
Enable some costly sanity checks in virtual to page code. This can
catch mistakes with virt_to_page() and friends.
--
2.7.4
^ permalink raw reply related
* [PATCHv5 02/11] mm/cma: Cleanup highmem check
From: Laura Abbott @ 2016-12-06 23:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481068257-6367-1-git-send-email-labbott@redhat.com>
6b101e2a3ce4 ("mm/CMA: fix boot regression due to physical address of
high_memory") added checks to use __pa_nodebug on x86 since
CONFIG_DEBUG_VIRTUAL complains about high_memory not being linearlly
mapped. arm64 is now getting support for CONFIG_DEBUG_VIRTUAL as well.
Rather than add an explosion of arches to the #ifdef, switch to an
alternate method to calculate the physical start of highmem using
the page before highmem starts. This avoids the need for the #ifdef and
extra __pa_nodebug calls.
Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Laura Abbott <labbott@redhat.com>
---
v5: No changes
---
mm/cma.c | 15 +++++----------
1 file changed, 5 insertions(+), 10 deletions(-)
diff --git a/mm/cma.c b/mm/cma.c
index c960459..94b3460 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -235,18 +235,13 @@ int __init cma_declare_contiguous(phys_addr_t base,
phys_addr_t highmem_start;
int ret = 0;
-#ifdef CONFIG_X86
/*
- * high_memory isn't direct mapped memory so retrieving its physical
- * address isn't appropriate. But it would be useful to check the
- * physical address of the highmem boundary so it's justifiable to get
- * the physical address from it. On x86 there is a validation check for
- * this case, so the following workaround is needed to avoid it.
+ * We can't use __pa(high_memory) directly, since high_memory
+ * isn't a valid direct map VA, and DEBUG_VIRTUAL will (validly)
+ * complain. Find the boundary by adding one to the last valid
+ * address.
*/
- highmem_start = __pa_nodebug(high_memory);
-#else
- highmem_start = __pa(high_memory);
-#endif
+ highmem_start = __pa(high_memory - 1) + 1;
pr_debug("%s(size %pa, base %pa, limit %pa alignment %pa)\n",
__func__, &size, &base, &limit, &alignment);
--
2.7.4
^ permalink raw reply related
* [PATCHv5 03/11] arm64: Move some macros under #ifndef __ASSEMBLY__
From: Laura Abbott @ 2016-12-06 23:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481068257-6367-1-git-send-email-labbott@redhat.com>
Several macros for various x_to_y exist outside the bounds of an
__ASSEMBLY__ guard. Move them in preparation for support for
CONFIG_DEBUG_VIRTUAL.
Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Laura Abbott <labbott@redhat.com>
---
v5: No changes
---
arch/arm64/include/asm/memory.h | 38 +++++++++++++++++++-------------------
1 file changed, 19 insertions(+), 19 deletions(-)
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index b71086d..b4d2b32 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -102,25 +102,6 @@
#endif
/*
- * Physical vs virtual RAM address space conversion. These are
- * private definitions which should NOT be used outside memory.h
- * files. Use virt_to_phys/phys_to_virt/__pa/__va instead.
- */
-#define __virt_to_phys(x) ({ \
- phys_addr_t __x = (phys_addr_t)(x); \
- __x & BIT(VA_BITS - 1) ? (__x & ~PAGE_OFFSET) + PHYS_OFFSET : \
- (__x - kimage_voffset); })
-
-#define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET) | PAGE_OFFSET)
-#define __phys_to_kimg(x) ((unsigned long)((x) + kimage_voffset))
-
-/*
- * Convert a page to/from a physical address
- */
-#define page_to_phys(page) (__pfn_to_phys(page_to_pfn(page)))
-#define phys_to_page(phys) (pfn_to_page(__phys_to_pfn(phys)))
-
-/*
* Memory types available.
*/
#define MT_DEVICE_nGnRnE 0
@@ -182,6 +163,25 @@ extern u64 kimage_voffset;
#define PHYS_PFN_OFFSET (PHYS_OFFSET >> PAGE_SHIFT)
/*
+ * Physical vs virtual RAM address space conversion. These are
+ * private definitions which should NOT be used outside memory.h
+ * files. Use virt_to_phys/phys_to_virt/__pa/__va instead.
+ */
+#define __virt_to_phys(x) ({ \
+ phys_addr_t __x = (phys_addr_t)(x); \
+ __x & BIT(VA_BITS - 1) ? (__x & ~PAGE_OFFSET) + PHYS_OFFSET : \
+ (__x - kimage_voffset); })
+
+#define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET) | PAGE_OFFSET)
+#define __phys_to_kimg(x) ((unsigned long)((x) + kimage_voffset))
+
+/*
+ * Convert a page to/from a physical address
+ */
+#define page_to_phys(page) (__pfn_to_phys(page_to_pfn(page)))
+#define phys_to_page(phys) (pfn_to_page(__phys_to_pfn(phys)))
+
+/*
* Note: Drivers should NOT use these. They are the wrong
* translation for translating DMA addresses. Use the driver
* DMA support - see dma-mapping.h.
--
2.7.4
^ permalink raw reply related
* [PATCHv5 04/11] arm64: Add cast for virt_to_pfn
From: Laura Abbott @ 2016-12-06 23:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481068257-6367-1-git-send-email-labbott@redhat.com>
virt_to_pfn lacks a cast at the top level. Don't rely on __virt_to_phys
and explicitly cast to unsigned long.
Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Laura Abbott <labbott@redhat.com>
---
v5: No changes
---
arch/arm64/include/asm/memory.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index b4d2b32..d773e2c 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -204,7 +204,7 @@ static inline void *phys_to_virt(phys_addr_t x)
#define __pa(x) __virt_to_phys((unsigned long)(x))
#define __va(x) ((void *)__phys_to_virt((phys_addr_t)(x)))
#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
-#define virt_to_pfn(x) __phys_to_pfn(__virt_to_phys(x))
+#define virt_to_pfn(x) __phys_to_pfn(__virt_to_phys((unsigned long)(x)))
/*
* virt_to_page(k) convert a _valid_ virtual address to struct page *
--
2.7.4
^ permalink raw reply related
* [PATCHv5 05/11] mm: Introduce lm_alias
From: Laura Abbott @ 2016-12-06 23:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481068257-6367-1-git-send-email-labbott@redhat.com>
Certain architectures may have the kernel image mapped separately to
alias the linear map. Introduce a macro lm_alias to translate a kernel
image symbol into its linear alias. This is used in part with work to
add CONFIG_DEBUG_VIRTUAL support for arm64.
Signed-off-by: Laura Abbott <labbott@redhat.com>
---
v5: Split off from the arm64 conversion to __pa_symbol
---
include/linux/mm.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index a92c8d7..88556b8 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -76,6 +76,10 @@ extern int mmap_rnd_compat_bits __read_mostly;
#define page_to_virt(x) __va(PFN_PHYS(page_to_pfn(x)))
#endif
+#ifndef lm_alias
+#define lm_alias(x) __va(__pa_symbol(x))
+#endif
+
/*
* To prevent common memory management code establishing
* a zero page mapping on a read fault.
--
2.7.4
^ permalink raw reply related
* [PATCHv5 06/11] arm64: Use __pa_symbol for kernel symbols
From: Laura Abbott @ 2016-12-06 23:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481068257-6367-1-git-send-email-labbott@redhat.com>
__pa_symbol is technically the marcro that should be used for kernel
symbols. Switch to this as a pre-requisite for DEBUG_VIRTUAL which
will do bounds checking.
Tested-by: James Morse <james.morse@arm.com>
Signed-off-by: Laura Abbott <labbott@redhat.com>
---
v5: #include <linux/mm.h> more places, drop arm64 specific lm_alias, correct
hibernation support from James Morse
---
arch/arm64/include/asm/kvm_mmu.h | 4 ++--
arch/arm64/include/asm/memory.h | 1 +
arch/arm64/include/asm/mmu_context.h | 6 +++---
arch/arm64/include/asm/pgtable.h | 2 +-
arch/arm64/kernel/acpi_parking_protocol.c | 3 ++-
arch/arm64/kernel/cpu-reset.h | 2 +-
arch/arm64/kernel/cpufeature.c | 3 ++-
arch/arm64/kernel/hibernate.c | 20 +++++--------------
arch/arm64/kernel/insn.c | 2 +-
arch/arm64/kernel/psci.c | 3 ++-
arch/arm64/kernel/setup.c | 9 +++++----
arch/arm64/kernel/smp_spin_table.c | 3 ++-
arch/arm64/kernel/vdso.c | 8 ++++++--
arch/arm64/mm/init.c | 12 ++++++-----
arch/arm64/mm/kasan_init.c | 22 ++++++++++++++-------
arch/arm64/mm/mmu.c | 33 ++++++++++++++++++++-----------
16 files changed, 76 insertions(+), 57 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 6f72fe8..55772c1 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -47,7 +47,7 @@
* If the page is in the bottom half, we have to use the top half. If
* the page is in the top half, we have to use the bottom half:
*
- * T = __virt_to_phys(__hyp_idmap_text_start)
+ * T = __pa_symbol(__hyp_idmap_text_start)
* if (T & BIT(VA_BITS - 1))
* HYP_VA_MIN = 0 //idmap in upper half
* else
@@ -271,7 +271,7 @@ static inline void __kvm_flush_dcache_pud(pud_t pud)
kvm_flush_dcache_to_poc(page_address(page), PUD_SIZE);
}
-#define kvm_virt_to_phys(x) __virt_to_phys((unsigned long)(x))
+#define kvm_virt_to_phys(x) __pa_symbol(x)
void kvm_set_way_flush(struct kvm_vcpu *vcpu);
void kvm_toggle_cache(struct kvm_vcpu *vcpu, bool was_enabled);
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index d773e2c..041bce28 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -205,6 +205,7 @@ static inline void *phys_to_virt(phys_addr_t x)
#define __va(x) ((void *)__phys_to_virt((phys_addr_t)(x)))
#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
#define virt_to_pfn(x) __phys_to_pfn(__virt_to_phys((unsigned long)(x)))
+#define sym_to_pfn(x) __phys_to_pfn(__pa_symbol(x))
/*
* virt_to_page(k) convert a _valid_ virtual address to struct page *
diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h
index a501853..ea0f969 100644
--- a/arch/arm64/include/asm/mmu_context.h
+++ b/arch/arm64/include/asm/mmu_context.h
@@ -44,7 +44,7 @@ static inline void contextidr_thread_switch(struct task_struct *next)
*/
static inline void cpu_set_reserved_ttbr0(void)
{
- unsigned long ttbr = virt_to_phys(empty_zero_page);
+ unsigned long ttbr = __pa_symbol(empty_zero_page);
write_sysreg(ttbr, ttbr0_el1);
isb();
@@ -113,7 +113,7 @@ static inline void cpu_install_idmap(void)
local_flush_tlb_all();
cpu_set_idmap_tcr_t0sz();
- cpu_switch_mm(idmap_pg_dir, &init_mm);
+ cpu_switch_mm(lm_alias(idmap_pg_dir), &init_mm);
}
/*
@@ -128,7 +128,7 @@ static inline void cpu_replace_ttbr1(pgd_t *pgd)
phys_addr_t pgd_phys = virt_to_phys(pgd);
- replace_phys = (void *)virt_to_phys(idmap_cpu_replace_ttbr1);
+ replace_phys = (void *)__pa_symbol(idmap_cpu_replace_ttbr1);
cpu_install_idmap();
replace_phys(pgd_phys);
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index ffbb9a5..090134c 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -52,7 +52,7 @@ extern void __pgd_error(const char *file, int line, unsigned long val);
* for zero-mapped memory areas etc..
*/
extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
-#define ZERO_PAGE(vaddr) pfn_to_page(PHYS_PFN(__pa(empty_zero_page)))
+#define ZERO_PAGE(vaddr) phys_to_page(__pa_symbol(empty_zero_page))
#define pte_ERROR(pte) __pte_error(__FILE__, __LINE__, pte_val(pte))
diff --git a/arch/arm64/kernel/acpi_parking_protocol.c b/arch/arm64/kernel/acpi_parking_protocol.c
index a32b401..ca880ce 100644
--- a/arch/arm64/kernel/acpi_parking_protocol.c
+++ b/arch/arm64/kernel/acpi_parking_protocol.c
@@ -18,6 +18,7 @@
*/
#include <linux/acpi.h>
#include <linux/types.h>
+#include <linux/mm.h>
#include <asm/cpu_ops.h>
@@ -109,7 +110,7 @@ static int acpi_parking_protocol_cpu_boot(unsigned int cpu)
* that read this address need to convert this address to the
* Boot-Loader's endianness before jumping.
*/
- writeq_relaxed(__pa(secondary_entry), &mailbox->entry_point);
+ writeq_relaxed(__pa_symbol(secondary_entry), &mailbox->entry_point);
writel_relaxed(cpu_entry->gic_cpu_id, &mailbox->cpu_id);
arch_send_wakeup_ipi_mask(cpumask_of(cpu));
diff --git a/arch/arm64/kernel/cpu-reset.h b/arch/arm64/kernel/cpu-reset.h
index d4e9ecb..6c2b1b4 100644
--- a/arch/arm64/kernel/cpu-reset.h
+++ b/arch/arm64/kernel/cpu-reset.h
@@ -24,7 +24,7 @@ static inline void __noreturn cpu_soft_restart(unsigned long el2_switch,
el2_switch = el2_switch && !is_kernel_in_hyp_mode() &&
is_hyp_mode_available();
- restart = (void *)virt_to_phys(__cpu_soft_restart);
+ restart = (void *)__pa_symbol(__cpu_soft_restart);
cpu_install_idmap();
restart(el2_switch, entry, arg0, arg1, arg2);
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index c02504e..26b54aa 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -23,6 +23,7 @@
#include <linux/sort.h>
#include <linux/stop_machine.h>
#include <linux/types.h>
+#include <linux/mm.h>
#include <asm/cpu.h>
#include <asm/cpufeature.h>
#include <asm/cpu_ops.h>
@@ -736,7 +737,7 @@ static bool runs_at_el2(const struct arm64_cpu_capabilities *entry, int __unused
static bool hyp_offset_low(const struct arm64_cpu_capabilities *entry,
int __unused)
{
- phys_addr_t idmap_addr = virt_to_phys(__hyp_idmap_text_start);
+ phys_addr_t idmap_addr = __pa_symbol(__hyp_idmap_text_start);
/*
* Activate the lower HYP offset only if:
diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c
index d55a7b0..8bed26a 100644
--- a/arch/arm64/kernel/hibernate.c
+++ b/arch/arm64/kernel/hibernate.c
@@ -50,9 +50,6 @@
*/
extern int in_suspend;
-/* Find a symbols alias in the linear map */
-#define LMADDR(x) phys_to_virt(virt_to_phys(x))
-
/* Do we need to reset el2? */
#define el2_reset_needed() (is_hyp_mode_available() && !is_kernel_in_hyp_mode())
@@ -102,8 +99,8 @@ static inline void arch_hdr_invariants(struct arch_hibernate_hdr_invariants *i)
int pfn_is_nosave(unsigned long pfn)
{
- unsigned long nosave_begin_pfn = virt_to_pfn(&__nosave_begin);
- unsigned long nosave_end_pfn = virt_to_pfn(&__nosave_end - 1);
+ unsigned long nosave_begin_pfn = sym_to_pfn(&__nosave_begin);
+ unsigned long nosave_end_pfn = sym_to_pfn(&__nosave_end - 1);
return (pfn >= nosave_begin_pfn) && (pfn <= nosave_end_pfn);
}
@@ -125,12 +122,12 @@ int arch_hibernation_header_save(void *addr, unsigned int max_size)
return -EOVERFLOW;
arch_hdr_invariants(&hdr->invariants);
- hdr->ttbr1_el1 = virt_to_phys(swapper_pg_dir);
+ hdr->ttbr1_el1 = __pa_symbol(swapper_pg_dir);
hdr->reenter_kernel = _cpu_resume;
/* We can't use __hyp_get_vectors() because kvm may still be loaded */
if (el2_reset_needed())
- hdr->__hyp_stub_vectors = virt_to_phys(__hyp_stub_vectors);
+ hdr->__hyp_stub_vectors = __pa_symbol(__hyp_stub_vectors);
else
hdr->__hyp_stub_vectors = 0;
@@ -460,7 +457,6 @@ int swsusp_arch_resume(void)
void *zero_page;
size_t exit_size;
pgd_t *tmp_pg_dir;
- void *lm_restore_pblist;
phys_addr_t phys_hibernate_exit;
void __noreturn (*hibernate_exit)(phys_addr_t, phys_addr_t, void *,
void *, phys_addr_t, phys_addr_t);
@@ -481,12 +477,6 @@ int swsusp_arch_resume(void)
goto out;
/*
- * Since we only copied the linear map, we need to find restore_pblist's
- * linear map address.
- */
- lm_restore_pblist = LMADDR(restore_pblist);
-
- /*
* We need a zero page that is zero before & after resume in order to
* to break before make on the ttbr1 page tables.
*/
@@ -537,7 +527,7 @@ int swsusp_arch_resume(void)
}
hibernate_exit(virt_to_phys(tmp_pg_dir), resume_hdr.ttbr1_el1,
- resume_hdr.reenter_kernel, lm_restore_pblist,
+ resume_hdr.reenter_kernel, restore_pblist,
resume_hdr.__hyp_stub_vectors, virt_to_phys(zero_page));
out:
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
index 6f2ac4f..f607b38 100644
--- a/arch/arm64/kernel/insn.c
+++ b/arch/arm64/kernel/insn.c
@@ -97,7 +97,7 @@ static void __kprobes *patch_map(void *addr, int fixmap)
if (module && IS_ENABLED(CONFIG_DEBUG_SET_MODULE_RONX))
page = vmalloc_to_page(addr);
else if (!module)
- page = pfn_to_page(PHYS_PFN(__pa(addr)));
+ page = phys_to_page(__pa_symbol(addr));
else
return addr;
diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c
index 42816be..e8edbf1 100644
--- a/arch/arm64/kernel/psci.c
+++ b/arch/arm64/kernel/psci.c
@@ -20,6 +20,7 @@
#include <linux/smp.h>
#include <linux/delay.h>
#include <linux/psci.h>
+#include <linux/mm.h>
#include <uapi/linux/psci.h>
@@ -45,7 +46,7 @@ static int __init cpu_psci_cpu_prepare(unsigned int cpu)
static int cpu_psci_cpu_boot(unsigned int cpu)
{
- int err = psci_ops.cpu_on(cpu_logical_map(cpu), __pa(secondary_entry));
+ int err = psci_ops.cpu_on(cpu_logical_map(cpu), __pa_symbol(secondary_entry));
if (err)
pr_err("failed to boot CPU%d (%d)\n", cpu, err);
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index f534f49..bcedfa0 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -42,6 +42,7 @@
#include <linux/of_fdt.h>
#include <linux/efi.h>
#include <linux/psci.h>
+#include <linux/mm.h>
#include <asm/acpi.h>
#include <asm/fixmap.h>
@@ -199,10 +200,10 @@ static void __init request_standard_resources(void)
struct memblock_region *region;
struct resource *res;
- kernel_code.start = virt_to_phys(_text);
- kernel_code.end = virt_to_phys(__init_begin - 1);
- kernel_data.start = virt_to_phys(_sdata);
- kernel_data.end = virt_to_phys(_end - 1);
+ kernel_code.start = __pa_symbol(_text);
+ kernel_code.end = __pa_symbol(__init_begin - 1);
+ kernel_data.start = __pa_symbol(_sdata);
+ kernel_data.end = __pa_symbol(_end - 1);
for_each_memblock(memory, region) {
res = alloc_bootmem_low(sizeof(*res));
diff --git a/arch/arm64/kernel/smp_spin_table.c b/arch/arm64/kernel/smp_spin_table.c
index 9a00eee..9303465 100644
--- a/arch/arm64/kernel/smp_spin_table.c
+++ b/arch/arm64/kernel/smp_spin_table.c
@@ -21,6 +21,7 @@
#include <linux/of.h>
#include <linux/smp.h>
#include <linux/types.h>
+#include <linux/mm.h>
#include <asm/cacheflush.h>
#include <asm/cpu_ops.h>
@@ -98,7 +99,7 @@ static int smp_spin_table_cpu_prepare(unsigned int cpu)
* boot-loader's endianess before jumping. This is mandated by
* the boot protocol.
*/
- writeq_relaxed(__pa(secondary_holding_pen), release_addr);
+ writeq_relaxed(__pa_symbol(secondary_holding_pen), release_addr);
__flush_dcache_area((__force void *)release_addr,
sizeof(*release_addr));
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index a2c2478..41b6e31 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -123,6 +123,7 @@ static int __init vdso_init(void)
{
int i;
struct page **vdso_pagelist;
+ unsigned long pfn;
if (memcmp(&vdso_start, "\177ELF", 4)) {
pr_err("vDSO is not a valid ELF object!\n");
@@ -140,11 +141,14 @@ static int __init vdso_init(void)
return -ENOMEM;
/* Grab the vDSO data page. */
- vdso_pagelist[0] = pfn_to_page(PHYS_PFN(__pa(vdso_data)));
+ vdso_pagelist[0] = phys_to_page(__pa_symbol(vdso_data));
+
/* Grab the vDSO code pages. */
+ pfn = sym_to_pfn(&vdso_start);
+
for (i = 0; i < vdso_pages; i++)
- vdso_pagelist[i + 1] = pfn_to_page(PHYS_PFN(__pa(&vdso_start)) + i);
+ vdso_pagelist[i + 1] = pfn_to_page(pfn + i);
vdso_spec[0].pages = &vdso_pagelist[0];
vdso_spec[1].pages = &vdso_pagelist[1];
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 212c4d1..8af2ad6 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -36,6 +36,7 @@
#include <linux/efi.h>
#include <linux/swiotlb.h>
#include <linux/vmalloc.h>
+#include <linux/mm.h>
#include <asm/boot.h>
#include <asm/fixmap.h>
@@ -209,8 +210,8 @@ void __init arm64_memblock_init(void)
* linear mapping. Take care not to clip the kernel which may be
* high in memory.
*/
- memblock_remove(max_t(u64, memstart_addr + linear_region_size, __pa(_end)),
- ULLONG_MAX);
+ memblock_remove(max_t(u64, memstart_addr + linear_region_size,
+ __pa_symbol(_end)), ULLONG_MAX);
if (memstart_addr + linear_region_size < memblock_end_of_DRAM()) {
/* ensure that memstart_addr remains sufficiently aligned */
memstart_addr = round_up(memblock_end_of_DRAM() - linear_region_size,
@@ -225,7 +226,7 @@ void __init arm64_memblock_init(void)
*/
if (memory_limit != (phys_addr_t)ULLONG_MAX) {
memblock_mem_limit_remove_map(memory_limit);
- memblock_add(__pa(_text), (u64)(_end - _text));
+ memblock_add(__pa_symbol(_text), (u64)(_end - _text));
}
if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && initrd_start) {
@@ -278,7 +279,7 @@ void __init arm64_memblock_init(void)
* Register the kernel text, kernel data, initrd, and initial
* pagetables with memblock.
*/
- memblock_reserve(__pa(_text), _end - _text);
+ memblock_reserve(__pa_symbol(_text), _end - _text);
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start) {
memblock_reserve(initrd_start, initrd_end - initrd_start);
@@ -483,7 +484,8 @@ void __init mem_init(void)
void free_initmem(void)
{
- free_reserved_area(__va(__pa(__init_begin)), __va(__pa(__init_end)),
+ free_reserved_area(lm_alias(__init_begin),
+ lm_alias(__init_end),
0, "unused kernel");
/*
* Unmap the __init region but leave the VM area in place. This
diff --git a/arch/arm64/mm/kasan_init.c b/arch/arm64/mm/kasan_init.c
index 757009d..201d918 100644
--- a/arch/arm64/mm/kasan_init.c
+++ b/arch/arm64/mm/kasan_init.c
@@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/memblock.h>
#include <linux/start_kernel.h>
+#include <linux/mm.h>
#include <asm/mmu_context.h>
#include <asm/kernel-pgtable.h>
@@ -26,6 +27,13 @@
static pgd_t tmp_pg_dir[PTRS_PER_PGD] __initdata __aligned(PGD_SIZE);
+/*
+ * The p*d_populate functions call virt_to_phys implicitly so they can't be used
+ * directly on kernel symbols (bm_p*d). All the early functions are called too
+ * early to use lm_alias so __p*d_populate functions must be used to populate
+ * with the physical address from __pa_symbol.
+ */
+
static void __init kasan_early_pte_populate(pmd_t *pmd, unsigned long addr,
unsigned long end)
{
@@ -33,12 +41,12 @@ static void __init kasan_early_pte_populate(pmd_t *pmd, unsigned long addr,
unsigned long next;
if (pmd_none(*pmd))
- pmd_populate_kernel(&init_mm, pmd, kasan_zero_pte);
+ __pmd_populate(pmd, __pa_symbol(kasan_zero_pte), PMD_TYPE_TABLE);
pte = pte_offset_kimg(pmd, addr);
do {
next = addr + PAGE_SIZE;
- set_pte(pte, pfn_pte(virt_to_pfn(kasan_zero_page),
+ set_pte(pte, pfn_pte(sym_to_pfn(kasan_zero_page),
PAGE_KERNEL));
} while (pte++, addr = next, addr != end && pte_none(*pte));
}
@@ -51,7 +59,7 @@ static void __init kasan_early_pmd_populate(pud_t *pud,
unsigned long next;
if (pud_none(*pud))
- pud_populate(&init_mm, pud, kasan_zero_pmd);
+ __pud_populate(pud, __pa_symbol(kasan_zero_pmd), PMD_TYPE_TABLE);
pmd = pmd_offset_kimg(pud, addr);
do {
@@ -68,7 +76,7 @@ static void __init kasan_early_pud_populate(pgd_t *pgd,
unsigned long next;
if (pgd_none(*pgd))
- pgd_populate(&init_mm, pgd, kasan_zero_pud);
+ __pgd_populate(pgd, __pa_symbol(kasan_zero_pud), PUD_TYPE_TABLE);
pud = pud_offset_kimg(pgd, addr);
do {
@@ -148,7 +156,7 @@ void __init kasan_init(void)
*/
memcpy(tmp_pg_dir, swapper_pg_dir, sizeof(tmp_pg_dir));
dsb(ishst);
- cpu_replace_ttbr1(tmp_pg_dir);
+ cpu_replace_ttbr1(lm_alias(tmp_pg_dir));
clear_pgds(KASAN_SHADOW_START, KASAN_SHADOW_END);
@@ -199,10 +207,10 @@ void __init kasan_init(void)
*/
for (i = 0; i < PTRS_PER_PTE; i++)
set_pte(&kasan_zero_pte[i],
- pfn_pte(virt_to_pfn(kasan_zero_page), PAGE_KERNEL_RO));
+ pfn_pte(sym_to_pfn(kasan_zero_page), PAGE_KERNEL_RO));
memset(kasan_zero_page, 0, PAGE_SIZE);
- cpu_replace_ttbr1(swapper_pg_dir);
+ cpu_replace_ttbr1(lm_alias(swapper_pg_dir));
/* At this point kasan is fully initialized. Enable error messages */
init_task.kasan_depth = 0;
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 05615a3..33ecaff 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -30,6 +30,7 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/stop_machine.h>
+#include <linux/mm.h>
#include <asm/barrier.h>
#include <asm/cputype.h>
@@ -319,8 +320,8 @@ static void create_mapping_late(phys_addr_t phys, unsigned long virt,
static void __init __map_memblock(pgd_t *pgd, phys_addr_t start, phys_addr_t end)
{
- unsigned long kernel_start = __pa(_text);
- unsigned long kernel_end = __pa(__init_begin);
+ unsigned long kernel_start = __pa_symbol(_text);
+ unsigned long kernel_end = __pa_symbol(__init_begin);
/*
* Take care not to create a writable alias for the
@@ -387,21 +388,21 @@ void mark_rodata_ro(void)
unsigned long section_size;
section_size = (unsigned long)_etext - (unsigned long)_text;
- create_mapping_late(__pa(_text), (unsigned long)_text,
+ create_mapping_late(__pa_symbol(_text), (unsigned long)_text,
section_size, PAGE_KERNEL_ROX);
/*
* mark .rodata as read only. Use __init_begin rather than __end_rodata
* to cover NOTES and EXCEPTION_TABLE.
*/
section_size = (unsigned long)__init_begin - (unsigned long)__start_rodata;
- create_mapping_late(__pa(__start_rodata), (unsigned long)__start_rodata,
+ create_mapping_late(__pa_symbol(__start_rodata), (unsigned long)__start_rodata,
section_size, PAGE_KERNEL_RO);
}
static void __init map_kernel_segment(pgd_t *pgd, void *va_start, void *va_end,
pgprot_t prot, struct vm_struct *vma)
{
- phys_addr_t pa_start = __pa(va_start);
+ phys_addr_t pa_start = __pa_symbol(va_start);
unsigned long size = va_end - va_start;
BUG_ON(!PAGE_ALIGNED(pa_start));
@@ -449,7 +450,7 @@ static void __init map_kernel(pgd_t *pgd)
*/
BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES));
set_pud(pud_set_fixmap_offset(pgd, FIXADDR_START),
- __pud(__pa(bm_pmd) | PUD_TYPE_TABLE));
+ __pud(__pa_symbol(bm_pmd) | PUD_TYPE_TABLE));
pud_clear_fixmap();
} else {
BUG();
@@ -480,7 +481,7 @@ void __init paging_init(void)
*/
cpu_replace_ttbr1(__va(pgd_phys));
memcpy(swapper_pg_dir, pgd, PAGE_SIZE);
- cpu_replace_ttbr1(swapper_pg_dir);
+ cpu_replace_ttbr1(lm_alias(swapper_pg_dir));
pgd_clear_fixmap();
memblock_free(pgd_phys, PAGE_SIZE);
@@ -489,7 +490,7 @@ void __init paging_init(void)
* We only reuse the PGD from the swapper_pg_dir, not the pud + pmd
* allocated with it.
*/
- memblock_free(__pa(swapper_pg_dir) + PAGE_SIZE,
+ memblock_free(__pa_symbol(swapper_pg_dir) + PAGE_SIZE,
SWAPPER_DIR_SIZE - PAGE_SIZE);
}
@@ -600,6 +601,12 @@ static inline pte_t * fixmap_pte(unsigned long addr)
return &bm_pte[pte_index(addr)];
}
+/*
+ * The p*d_populate functions call virt_to_phys implicitly so they can't be used
+ * directly on kernel symbols (bm_p*d). This function is called too early to use
+ * lm_alias so __p*d_populate functions must be used to populate with the
+ * physical address from __pa_symbol.
+ */
void __init early_fixmap_init(void)
{
pgd_t *pgd;
@@ -609,7 +616,7 @@ void __init early_fixmap_init(void)
pgd = pgd_offset_k(addr);
if (CONFIG_PGTABLE_LEVELS > 3 &&
- !(pgd_none(*pgd) || pgd_page_paddr(*pgd) == __pa(bm_pud))) {
+ !(pgd_none(*pgd) || pgd_page_paddr(*pgd) == __pa_symbol(bm_pud))) {
/*
* We only end up here if the kernel mapping and the fixmap
* share the top level pgd entry, which should only happen on
@@ -618,12 +625,14 @@ void __init early_fixmap_init(void)
BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES));
pud = pud_offset_kimg(pgd, addr);
} else {
- pgd_populate(&init_mm, pgd, bm_pud);
+ if (pgd_none(*pgd))
+ __pgd_populate(pgd, __pa_symbol(bm_pud), PUD_TYPE_TABLE);
pud = fixmap_pud(addr);
}
- pud_populate(&init_mm, pud, bm_pmd);
+ if (pud_none(*pud))
+ __pud_populate(pud, __pa_symbol(bm_pmd), PMD_TYPE_TABLE);
pmd = fixmap_pmd(addr);
- pmd_populate_kernel(&init_mm, pmd, bm_pte);
+ __pmd_populate(pmd, __pa_symbol(bm_pte), PMD_TYPE_TABLE);
/*
* The boot-ioremap range spans multiple pmds, for which
--
2.7.4
^ permalink raw reply related
* [PATCHv5 07/11] drivers: firmware: psci: Use __pa_symbol for kernel symbol
From: Laura Abbott @ 2016-12-06 23:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481068257-6367-1-git-send-email-labbott@redhat.com>
__pa_symbol is technically the macro that should be used for kernel
symbols. Switch to this as a pre-requisite for DEBUG_VIRTUAL which
will do bounds checking.
Signed-off-by: Laura Abbott <labbott@redhat.com>
---
v5: Split off from arm64 __pa_symbol conversion
---
drivers/firmware/psci.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index 8263429..9defbe2 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -383,7 +383,7 @@ static int psci_suspend_finisher(unsigned long index)
u32 *state = __this_cpu_read(psci_power_state);
return psci_ops.cpu_suspend(state[index - 1],
- virt_to_phys(cpu_resume));
+ __pa_symbol(cpu_resume));
}
int psci_cpu_suspend_enter(unsigned long index)
--
2.7.4
^ permalink raw reply related
* [PATCHv5 08/11] kexec: Switch to __pa_symbol
From: Laura Abbott @ 2016-12-06 23:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481068257-6367-1-git-send-email-labbott@redhat.com>
__pa_symbol is the correct api to get the physical address of kernel
symbols. Switch to it to allow for better debug checking.
Acked-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Laura Abbott <labbott@redhat.com>
---
v5: No changes, just acks
---
kernel/kexec_core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index 5616755..e1b625e 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -1397,7 +1397,7 @@ void __weak arch_crash_save_vmcoreinfo(void)
phys_addr_t __weak paddr_vmcoreinfo_note(void)
{
- return __pa((unsigned long)(char *)&vmcoreinfo_note);
+ return __pa_symbol((unsigned long)(char *)&vmcoreinfo_note);
}
static int __init crash_save_vmcoreinfo_init(void)
--
2.7.4
^ permalink raw reply related
* [PATCHv5 09/11] mm/kasan: Switch to using __pa_symbol and lm_alias
From: Laura Abbott @ 2016-12-06 23:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481068257-6367-1-git-send-email-labbott@redhat.com>
__pa_symbol is the correct API to find the physical address of symbols.
Switch to it to allow for debugging APIs to work correctly. Other
functions such as p*d_populate may call __pa internally. Ensure that the
address passed is in the linear region by calling lm_alias.
Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Laura Abbott <labbott@redhat.com>
---
v5: Add missing lm_alias call
---
mm/kasan/kasan_init.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/mm/kasan/kasan_init.c b/mm/kasan/kasan_init.c
index 3f9a41c..922f459 100644
--- a/mm/kasan/kasan_init.c
+++ b/mm/kasan/kasan_init.c
@@ -16,6 +16,7 @@
#include <linux/kernel.h>
#include <linux/memblock.h>
#include <linux/pfn.h>
+#include <linux/mm.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
@@ -49,7 +50,7 @@ static void __init zero_pte_populate(pmd_t *pmd, unsigned long addr,
pte_t *pte = pte_offset_kernel(pmd, addr);
pte_t zero_pte;
- zero_pte = pfn_pte(PFN_DOWN(__pa(kasan_zero_page)), PAGE_KERNEL);
+ zero_pte = pfn_pte(PFN_DOWN(__pa_symbol(kasan_zero_page)), PAGE_KERNEL);
zero_pte = pte_wrprotect(zero_pte);
while (addr + PAGE_SIZE <= end) {
@@ -69,7 +70,7 @@ static void __init zero_pmd_populate(pud_t *pud, unsigned long addr,
next = pmd_addr_end(addr, end);
if (IS_ALIGNED(addr, PMD_SIZE) && end - addr >= PMD_SIZE) {
- pmd_populate_kernel(&init_mm, pmd, kasan_zero_pte);
+ pmd_populate_kernel(&init_mm, pmd, lm_alias(kasan_zero_pte));
continue;
}
@@ -92,9 +93,9 @@ static void __init zero_pud_populate(pgd_t *pgd, unsigned long addr,
if (IS_ALIGNED(addr, PUD_SIZE) && end - addr >= PUD_SIZE) {
pmd_t *pmd;
- pud_populate(&init_mm, pud, kasan_zero_pmd);
+ pud_populate(&init_mm, pud, lm_alias(kasan_zero_pmd));
pmd = pmd_offset(pud, addr);
- pmd_populate_kernel(&init_mm, pmd, kasan_zero_pte);
+ pmd_populate_kernel(&init_mm, pmd, lm_alias(kasan_zero_pte));
continue;
}
@@ -135,11 +136,11 @@ void __init kasan_populate_zero_shadow(const void *shadow_start,
* puds,pmds, so pgd_populate(), pud_populate()
* is noops.
*/
- pgd_populate(&init_mm, pgd, kasan_zero_pud);
+ pgd_populate(&init_mm, pgd, lm_alias(kasan_zero_pud));
pud = pud_offset(pgd, addr);
- pud_populate(&init_mm, pud, kasan_zero_pmd);
+ pud_populate(&init_mm, pud, lm_alias(kasan_zero_pmd));
pmd = pmd_offset(pud, addr);
- pmd_populate_kernel(&init_mm, pmd, kasan_zero_pte);
+ pmd_populate_kernel(&init_mm, pmd, lm_alias(kasan_zero_pte));
continue;
}
--
2.7.4
^ permalink raw reply related
* [PATCHv5 10/11] mm/usercopy: Switch to using lm_alias
From: Laura Abbott @ 2016-12-06 23:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481068257-6367-1-git-send-email-labbott@redhat.com>
The usercopy checking code currently calls __va(__pa(...)) to check for
aliases on symbols. Switch to using lm_alias instead.
Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Laura Abbott <labbott@redhat.com>
---
v5: No changes, just acks
---
mm/usercopy.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/mm/usercopy.c b/mm/usercopy.c
index 3c8da0a..8345299 100644
--- a/mm/usercopy.c
+++ b/mm/usercopy.c
@@ -108,13 +108,13 @@ static inline const char *check_kernel_text_object(const void *ptr,
* __pa() is not just the reverse of __va(). This can be detected
* and checked:
*/
- textlow_linear = (unsigned long)__va(__pa(textlow));
+ textlow_linear = (unsigned long)lm_alias(textlow);
/* No different mapping: we're done. */
if (textlow_linear == textlow)
return NULL;
/* Check the secondary mapping... */
- texthigh_linear = (unsigned long)__va(__pa(texthigh));
+ texthigh_linear = (unsigned long)lm_alias(texthigh);
if (overlaps(ptr, n, textlow_linear, texthigh_linear))
return "<linear kernel text>";
--
2.7.4
^ permalink raw reply related
* [PATCHv5 11/11] arm64: Add support for CONFIG_DEBUG_VIRTUAL
From: Laura Abbott @ 2016-12-06 23:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481068257-6367-1-git-send-email-labbott@redhat.com>
x86 has an option CONFIG_DEBUG_VIRTUAL to do additional checks
on virt_to_phys calls. The goal is to catch users who are calling
virt_to_phys on non-linear addresses immediately. This inclues callers
using virt_to_phys on image addresses instead of __pa_symbol. As features
such as CONFIG_VMAP_STACK get enabled for arm64, this becomes increasingly
important. Add checks to catch bad virt_to_phys usage.
Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Laura Abbott <labbott@redhat.com>
---
v5: Tweak warning output slightly, acks
---
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/memory.h | 31 ++++++++++++++++++++++++++++---
arch/arm64/mm/Makefile | 2 ++
arch/arm64/mm/physaddr.c | 30 ++++++++++++++++++++++++++++++
4 files changed, 61 insertions(+), 3 deletions(-)
create mode 100644 arch/arm64/mm/physaddr.c
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 969ef88..83b95bc 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -6,6 +6,7 @@ config ARM64
select ACPI_MCFG if ACPI
select ACPI_SPCR_TABLE if ACPI
select ARCH_CLOCKSOURCE_DATA
+ select ARCH_HAS_DEBUG_VIRTUAL
select ARCH_HAS_DEVMEM_IS_ALLOWED
select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI
select ARCH_HAS_ELF_RANDOMIZE
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index 041bce28..a405665 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -167,10 +167,33 @@ extern u64 kimage_voffset;
* private definitions which should NOT be used outside memory.h
* files. Use virt_to_phys/phys_to_virt/__pa/__va instead.
*/
-#define __virt_to_phys(x) ({ \
+
+
+/*
+ * The linear kernel range starts in the middle of the virtual adddress
+ * space. Testing the top bit for the start of the region is a
+ * sufficient check.
+ */
+#define __is_lm_address(addr) (!!((addr) & BIT(VA_BITS - 1)))
+
+#define __lm_to_phys(addr) (((addr) & ~PAGE_OFFSET) + PHYS_OFFSET)
+#define __kimg_to_phys(addr) ((addr) - kimage_voffset)
+
+#define __virt_to_phys_nodebug(x) ({ \
phys_addr_t __x = (phys_addr_t)(x); \
- __x & BIT(VA_BITS - 1) ? (__x & ~PAGE_OFFSET) + PHYS_OFFSET : \
- (__x - kimage_voffset); })
+ __is_lm_address(__x) ? __lm_to_phys(__x) : \
+ __kimg_to_phys(__x); \
+})
+
+#define __pa_symbol_nodebug(x) __kimg_to_phys((phys_addr_t)(x))
+
+#ifdef CONFIG_DEBUG_VIRTUAL
+extern phys_addr_t __virt_to_phys(unsigned long x);
+extern phys_addr_t __phys_addr_symbol(unsigned long x);
+#else
+#define __virt_to_phys(x) __virt_to_phys_nodebug(x)
+#define __phys_addr_symbol(x) __pa_symbol_nodebug(x)
+#endif
#define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET) | PAGE_OFFSET)
#define __phys_to_kimg(x) ((unsigned long)((x) + kimage_voffset))
@@ -202,6 +225,8 @@ static inline void *phys_to_virt(phys_addr_t x)
* Drivers should NOT use these either.
*/
#define __pa(x) __virt_to_phys((unsigned long)(x))
+#define __pa_symbol(x) __phys_addr_symbol(RELOC_HIDE((unsigned long)(x), 0))
+#define __pa_nodebug(x) __virt_to_phys_nodebug((unsigned long)(x))
#define __va(x) ((void *)__phys_to_virt((phys_addr_t)(x)))
#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
#define virt_to_pfn(x) __phys_to_pfn(__virt_to_phys((unsigned long)(x)))
diff --git a/arch/arm64/mm/Makefile b/arch/arm64/mm/Makefile
index 54bb209..38d3811 100644
--- a/arch/arm64/mm/Makefile
+++ b/arch/arm64/mm/Makefile
@@ -5,6 +5,8 @@ obj-y := dma-mapping.o extable.o fault.o init.o \
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
obj-$(CONFIG_ARM64_PTDUMP) += dump.o
obj-$(CONFIG_NUMA) += numa.o
+obj-$(CONFIG_DEBUG_VIRTUAL) += physaddr.o
+KASAN_SANITIZE_physaddr.o += n
obj-$(CONFIG_KASAN) += kasan_init.o
KASAN_SANITIZE_kasan_init.o := n
diff --git a/arch/arm64/mm/physaddr.c b/arch/arm64/mm/physaddr.c
new file mode 100644
index 0000000..91371da
--- /dev/null
+++ b/arch/arm64/mm/physaddr.c
@@ -0,0 +1,30 @@
+#include <linux/bug.h>
+#include <linux/export.h>
+#include <linux/types.h>
+#include <linux/mmdebug.h>
+#include <linux/mm.h>
+
+#include <asm/memory.h>
+
+phys_addr_t __virt_to_phys(unsigned long x)
+{
+ WARN(!__is_lm_address(x),
+ "virt_to_phys used for non-linear address: %pK (%pS)\n",
+ (void *)x,
+ (void *)x);
+
+ return __virt_to_phys_nodebug(x);
+}
+EXPORT_SYMBOL(__virt_to_phys);
+
+phys_addr_t __phys_addr_symbol(unsigned long x)
+{
+ /*
+ * This is bounds checking against the kernel image only.
+ * __pa_symbol should only be used on kernel symbol addresses.
+ */
+ VIRTUAL_BUG_ON(x < (unsigned long) KERNEL_START ||
+ x > (unsigned long) KERNEL_END);
+ return __pa_symbol_nodebug(x);
+}
+EXPORT_SYMBOL(__phys_addr_symbol);
--
2.7.4
^ permalink raw reply related
* [PATCH 3/4] iommu/arm-smmu: Disable stalling faults for all endpoints
From: Jordan Crouse @ 2016-12-07 0:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAF6AEGujUb37qagBZK1T13eAh=50zy0z5HpFF9FsuvkZZ7c5qw@mail.gmail.com>
On Tue, Dec 06, 2016 at 06:30:21PM -0500, Rob Clark wrote:
> On Thu, Aug 18, 2016 at 9:05 AM, Will Deacon <will.deacon@arm.com> wrote:
> > Enabling stalling faults can result in hardware deadlock on poorly
> > designed systems, particularly those with a PCI root complex upstream of
> > the SMMU.
> >
> > Although it's not really Linux's job to save hardware integrators from
> > their own misfortune, it *is* our job to stop userspace (e.g. VFIO
> > clients) from hosing the system for everybody else, even if they might
> > already be required to have elevated privileges.
> >
> > Given that the fault handling code currently executes entirely in IRQ
> > context, there is nothing that can sensibly be done to recover from
> > things like page faults anyway, so let's rip this code out for now and
> > avoid the potential for deadlock.
>
> Hi Will,
>
> so, I'd like to re-introduce this feature, I *guess* as some sort of
> opt-in quirk (ie. disabled by default unless something in DT tells you
> otherwise?? But I'm open to suggestions. I'm not entirely sure what
> hw was having problems due to this feature.)
>
> On newer snapdragon devices we are using arm-smmu for the GPU, and
> halting the GPU so the driver's fault handler can dump some GPU state
> on faults is enormously helpful for debugging and tracking down where
> in the gpu cmdstream the fault was triggered. In addition, we will
> eventually want the ability to update pagetables from fault handler
> and resuming the faulting transition.
>
> Some additional comments below..
>
> > Cc: <stable@vger.kernel.org>
> > Reported-by: Matt Evans <matt.evans@arm.com>
> > Signed-off-by: Will Deacon <will.deacon@arm.com>
> > ---
> > drivers/iommu/arm-smmu.c | 34 +++++++---------------------------
> > 1 file changed, 7 insertions(+), 27 deletions(-)
> >
> > diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
> > index 4f49fe29f202..2db74ebc3240 100644
> > --- a/drivers/iommu/arm-smmu.c
> > +++ b/drivers/iommu/arm-smmu.c
> > @@ -686,8 +686,7 @@ static struct iommu_gather_ops arm_smmu_gather_ops = {
> >
> > static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
> > {
> > - int flags, ret;
> > - u32 fsr, fsynr, resume;
> > + u32 fsr, fsynr;
> > unsigned long iova;
> > struct iommu_domain *domain = dev;
> > struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
> > @@ -701,34 +700,15 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
> > if (!(fsr & FSR_FAULT))
> > return IRQ_NONE;
> >
> > - if (fsr & FSR_IGN)
> > - dev_err_ratelimited(smmu->dev,
> > - "Unexpected context fault (fsr 0x%x)\n",
> > - fsr);
> > -
> > fsynr = readl_relaxed(cb_base + ARM_SMMU_CB_FSYNR0);
> > - flags = fsynr & FSYNR0_WNR ? IOMMU_FAULT_WRITE : IOMMU_FAULT_READ;
> > -
> > iova = readq_relaxed(cb_base + ARM_SMMU_CB_FAR);
> > - if (!report_iommu_fault(domain, smmu->dev, iova, flags)) {
> > - ret = IRQ_HANDLED;
> > - resume = RESUME_RETRY;
> > - } else {
> > - dev_err_ratelimited(smmu->dev,
> > - "Unhandled context fault: iova=0x%08lx, fsynr=0x%x, cb=%d\n",
> > - iova, fsynr, cfg->cbndx);
>
> I would like to decouple this dev_err_ratelimit() print from the
> RESUME_RETRY vs RESUME_TERMINATE behaviour. I need the ability to
> indicate by return from my fault handler whether to resume or
> terminate. But I already have my own ratelimted prints and would
> prefer not to spam dmesg twice.
>
> I'm thinking about report_iommu_fault() returning:
>
> 0 => RESUME_RETRY
> -EFAULT => RESUME_TERMINATE but don't print
> anything else (or specifically -ENOSYS?) => RESUME_TERMINATE and print
>
> thoughts?
>
> > - ret = IRQ_NONE;
> > - resume = RESUME_TERMINATE;
> > - }
> > -
> > - /* Clear the faulting FSR */
> > - writel(fsr, cb_base + ARM_SMMU_CB_FSR);
> >
> > - /* Retry or terminate any stalled transactions */
> > - if (fsr & FSR_SS)
> > - writel_relaxed(resume, cb_base + ARM_SMMU_CB_RESUME);
>
> This might be a bug in qcom's implementation of the smmu spec, but
> seems like we don't have SS bit set, yet we still require RESUME reg
> to be written, otherwise gpu is perma-wedged. Maybe topic for a
> separate quirk? I'm not sure if writing RESUME reg on other hw when
> SS bit is not set is likely to cause problems? If not I suppose we
> could just unconditionally write it.
>
> Anyways, I'm not super-familiar w/ arm-smmu so suggestions welcome..
> in between debugging freedreno I'll try to put together some patches.
>From what I can tell we need SCTLR_CFCFG to make the stall happen otherwise
the operation just gets terminated immediately and *then* we get notification
but by then the system keeps going.
I think SCTLR_HUPCF helps control that behavior (i.e. we don't go off faulting
through eternity) but I don't know how it works.
>From my very unlearned understanding I think we do want to set CFCFG and then
stall and let the interrupt handler decide to retry/terminate.
Jordan
--
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* [PATCH] ipmi: bt-bmc: Use a regmap for register access
From: Andrew Jeffery @ 2016-12-07 0:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <36014e0c-82f8-eeaf-ee2a-6c1e413b957d@kaod.org>
On Tue, 2016-12-06 at 16:02 +0100, C?dric Le Goater wrote:
> [ this is a resend bc of some mailing list issues]?
Thanks for resending.
>
> On 12/06/2016 03:57 AM, Andrew Jeffery wrote:
> > The registers for the bt-bmc device live under the Aspeed LPC
> > controller. Devicetree bindings have recently been introduced for the
> > LPC controller where the "host" portion of the LPC register space is
> > described as a syscon device. Future devicetrees describing the bt-bmc
> > device should nest its node under the appropriate "simple-mfd", "syscon"
> > compatible node.
> >
> > This change allows the bt-bmc driver to function with both syscon and
> > non-syscon- based devicetree descriptions by always using a regmap for
> > register access, either retrieved from the parent syscon device or
> > instantiated if none exists.
> >
> > The patch has been tested on an OpenPOWER Palmetto machine, successfully
> > booting, rebooting and powering down the host.
> >
> > Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
>
> It would be nice to have an example of the associated binding.?
> I did not see it.
Essentially because the approach of the patch means there's no required
change to the bindings documentation. So, pulling together the various
patches I've sent out, a partial devicetree using the new bindings
might look something like:
lpc: lpc at 1e789000 {
compatible = "aspeed,ast2500-lpc", "simple-mfd";
reg = <0x1e789000 0x1000>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 0x1e789000 0x1000>;
lpc_bmc: lpc-bmc at 0 {
compatible = "aspeed,ast2500-lpc-bmc";
reg = <0x0 0x80>;
reg-io-width = <1>;
};
lpc_host: lpc-host at 80 {
compatible = "aspeed,ast2500-lpc-host", "simple-mfd", "syscon";
reg = <0x80 0x1e0>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 0x80 0x1e0>;
reg-io-width = <4>;
ibt: ibt at c0 {
compatible = "aspeed,ast2400-bt-bmc";
reg = <0xc0 0x18>;
interrupts = <8>;
};
};
};
It's a bit tedious, but as mentioned in the commit message we need a
way to arbitrate access to other registers in the "host" portion of the
LPC controller amongst other complications, and this layout gives us
that capability without breaking any existing bindings.
Andrew
> A part from that :
>
> > Reviewed-by: C?dric Le Goater <clg@kaod.org>
>
> Thanks,
>
> C.
>
> > ---
> > ?drivers/char/ipmi/Kconfig??|??1 +
> > ?drivers/char/ipmi/bt-bmc.c | 82 ++++++++++++++++++++++++++++++++++------------
> > ?2 files changed, 62 insertions(+), 21 deletions(-)
> >
> > diff --git a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig
> > index 7f816655cbbf..b5d48d9af124 100644
> > --- a/drivers/char/ipmi/Kconfig
> > +++ b/drivers/char/ipmi/Kconfig
> > @@ -79,6 +79,7 @@ endif # IPMI_HANDLER
> > ?
> > ?config ASPEED_BT_IPMI_BMC
> > > > ? depends on ARCH_ASPEED
> > +????????depends on REGMAP && REGMAP_MMIO && MFD_SYSCON
> > > > ? tristate "BT IPMI bmc driver"
> > > > ? help
> > > > ? ??Provides a driver for the BT (Block Transfer) IPMI interface
> > diff --git a/drivers/char/ipmi/bt-bmc.c b/drivers/char/ipmi/bt-bmc.c
> > index fc9e8891eae3..ca1e20f6c6c5 100644
> > --- a/drivers/char/ipmi/bt-bmc.c
> > +++ b/drivers/char/ipmi/bt-bmc.c
> > @@ -12,10 +12,13 @@
> > ?#include <linux/errno.h>
> > ?#include <linux/interrupt.h>
> > ?#include <linux/io.h>
> > +#include <linux/mfd/syscon.h>
> > ?#include <linux/miscdevice.h>
> > ?#include <linux/module.h>
> > +#include <linux/of.h>
> > ?#include <linux/platform_device.h>
> > ?#include <linux/poll.h>
> > +#include <linux/regmap.h>
> > ?#include <linux/sched.h>
> > ?#include <linux/timer.h>
> > ?
> > @@ -60,7 +63,8 @@
> > ?struct bt_bmc {
> > > > > > ? struct device dev;
> > > > > > ? struct miscdevice miscdev;
> > > > > > - void __iomem *base;
> > > > > > + struct regmap *map;
> > > > > > + int offset;
> > > > > > ? int irq;
> > > > > > ? wait_queue_head_t queue;
> > > > > > ? struct timer_list poll_timer;
> > @@ -69,14 +73,31 @@ struct bt_bmc {
> > ?
> > ?static atomic_t open_count = ATOMIC_INIT(0);
> > ?
> > +static struct regmap_config bt_regmap_cfg = {
> > > > + .reg_bits = 32,
> > > > + .val_bits = 32,
> > > > + .reg_stride = 4,
> > +};
> > +
> > ?static u8 bt_inb(struct bt_bmc *bt_bmc, int reg)
> > ?{
> > > > - return ioread8(bt_bmc->base + reg);
> > > > + uint32_t val = 0;
> > > > + int rc;
> > +
> > > > + rc = regmap_read(bt_bmc->map, bt_bmc->offset + reg, &val);
> > > > + WARN(rc != 0, "%s:%d: regmap_read() failed: %d\n",
> > > > + __FILE__, __LINE__, rc);
> > +
> > > > + return rc == 0 ? (u8) val : 0;
> > ?}
> > ?
> > ?static void bt_outb(struct bt_bmc *bt_bmc, u8 data, int reg)
> > ?{
> > > > - iowrite8(data, bt_bmc->base + reg);
> > > > + int rc;
> > +
> > > > + rc = regmap_write(bt_bmc->map, bt_bmc->offset + reg, data);
> > > > + WARN(rc != 0, "%s:%d: regmap_write() failed: %d\n",
> > > > + __FILE__, __LINE__, rc);
> > ?}
> > ?
> > ?static void clr_rd_ptr(struct bt_bmc *bt_bmc)
> > @@ -367,14 +388,18 @@ static irqreturn_t bt_bmc_irq(int irq, void *arg)
> > ?{
> > > > ? struct bt_bmc *bt_bmc = arg;
> > > > ? u32 reg;
> > > > + int rc;
> > +
> > > > + rc = regmap_read(bt_bmc->map, bt_bmc->offset + BT_CR2, ®);
> > > > + if (rc)
> > > > + return IRQ_NONE;
> > ?
> > > > - reg = ioread32(bt_bmc->base + BT_CR2);
> > > > ? reg &= BT_CR2_IRQ_H2B | BT_CR2_IRQ_HBUSY;
> > > > ? if (!reg)
> > > > ? return IRQ_NONE;
> > ?
> > > > ? /* ack pending IRQs */
> > > > - iowrite32(reg, bt_bmc->base + BT_CR2);
> > > > + regmap_write(bt_bmc->map, bt_bmc->offset + BT_CR2, reg);
> > ?
> > > > ? wake_up(&bt_bmc->queue);
> > > > ? return IRQ_HANDLED;
> > @@ -384,7 +409,6 @@ static int bt_bmc_config_irq(struct bt_bmc *bt_bmc,
> > > > ? ?????struct platform_device *pdev)
> > ?{
> > > > ? struct device *dev = &pdev->dev;
> > > > - u32 reg;
> > > > ? int rc;
> > ?
> > > > ? bt_bmc->irq = platform_get_irq(pdev, 0);
> > @@ -405,18 +429,17 @@ static int bt_bmc_config_irq(struct bt_bmc *bt_bmc,
> > > > ? ?* will be cleared (along with B2H) when we can write the next
> > > > ? ?* message to the BT buffer
> > > > ? ?*/
> > > > - reg = ioread32(bt_bmc->base + BT_CR1);
> > > > - reg |= BT_CR1_IRQ_H2B | BT_CR1_IRQ_HBUSY;
> > > > - iowrite32(reg, bt_bmc->base + BT_CR1);
> > > > + rc = regmap_update_bits(bt_bmc->map, bt_bmc->offset + BT_CR1,
> > > > + (BT_CR1_IRQ_H2B | BT_CR1_IRQ_HBUSY),
> > > > + (BT_CR1_IRQ_H2B | BT_CR1_IRQ_HBUSY));
> > ?
> > > > - return 0;
> > > > + return rc;
> > ?}
> > ?
> > ?static int bt_bmc_probe(struct platform_device *pdev)
> > ?{
> > > > ? struct bt_bmc *bt_bmc;
> > > > ? struct device *dev;
> > > > - struct resource *res;
> > > > ? int rc;
> > ?
> > > > ? if (!pdev || !pdev->dev.of_node)
> > @@ -431,10 +454,27 @@ static int bt_bmc_probe(struct platform_device *pdev)
> > ?
> > > > ? dev_set_drvdata(&pdev->dev, bt_bmc);
> > ?
> > > > - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > > > - bt_bmc->base = devm_ioremap_resource(&pdev->dev, res);
> > > > - if (IS_ERR(bt_bmc->base))
> > > > - return PTR_ERR(bt_bmc->base);
> > > > + bt_bmc->map = syscon_node_to_regmap(pdev->dev.parent->of_node);
> > > > + if (IS_ERR(bt_bmc->map)) {
> > > > + struct resource *res;
> > > > + void __iomem *base;
> > +
> > > > + /*
> > > > + ?* Assume it's not the MFD-based devicetree description, in
> > > > + ?* which case generate a regmap ourselves
> > > > + ?*/
> > > > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > > > + base = devm_ioremap_resource(&pdev->dev, res);
> > > > + if (IS_ERR(base))
> > > > + return PTR_ERR(base);
> > +
> > > > + bt_bmc->map = devm_regmap_init_mmio(dev, base, &bt_regmap_cfg);
> > > > + bt_bmc->offset = 0;
> > > > + } else {
> > > > + rc = of_property_read_u32(dev->of_node, "reg", &bt_bmc->offset);
> > > > + if (rc)
> > > > + return rc;
> > > > + }
> > ?
> > > > ? mutex_init(&bt_bmc->mutex);
> > > > ? init_waitqueue_head(&bt_bmc->queue);
> > @@ -461,12 +501,12 @@ static int bt_bmc_probe(struct platform_device *pdev)
> > > > ? add_timer(&bt_bmc->poll_timer);
> > > > ? }
> > ?
> > > > - iowrite32((BT_IO_BASE << BT_CR0_IO_BASE) |
> > > > - ??(BT_IRQ << BT_CR0_IRQ) |
> > > > - ??BT_CR0_EN_CLR_SLV_RDP |
> > > > - ??BT_CR0_EN_CLR_SLV_WRP |
> > > > - ??BT_CR0_ENABLE_IBT,
> > > > - ??bt_bmc->base + BT_CR0);
> > > > + regmap_write(bt_bmc->map, bt_bmc->offset + BT_CR0,
> > > > + ?????(BT_IO_BASE << BT_CR0_IO_BASE) |
> > > > + ?????(BT_IRQ << BT_CR0_IRQ) |
> > > > + ?????BT_CR0_EN_CLR_SLV_RDP |
> > > > + ?????BT_CR0_EN_CLR_SLV_WRP |
> > > > + ?????BT_CR0_ENABLE_IBT);
> > ?
> > > > ? clr_b_busy(bt_bmc);
> > ?
> >
>
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161207/5506c9cf/attachment-0001.sig>
^ permalink raw reply
* [PATCH 00/16] FSI device driver introduction
From: Chris Bostic @ 2016-12-07 0:14 UTC (permalink / raw)
To: linux-arm-kernel
From: Chris Bostic <cbostic@us.ibm.com>
Introduction of the IBM 'Flexible Support Interface' (FSI) bus device
driver. FSI is a high fan out serial bus consisting of a clock and a serial
data line capable of running at speeds up to 166 MHz.
This set provides the basic framework to add FSI extensions to the
Linux bus and device models. Master specific implementations are
defined to utilize the core FSI function.
In Linux, we have a core FSI "bus type", along with drivers for FSI
masters and engines.
The FSI master drivers expose a read/write interface to the bus address
space. The master drivers are under drivers/fsi/fsi-master-*.c.
The core handles probing and discovery of slaves and slave
engines, using those read/write interfaces. It is responsible for
creating the endpoint Linux devices corresponding to the discovered
engines on each slave.
Slave engines are identified by an 'engine' type, and an optional
version. Engine, a.k.a. client, drivers are matched and bound to these
engines during discovery.
This patch set does not include extended FSI function such as:
* Hub master support
* Cascaded master support
* Application layer hot plug notification
* Application layer FSI bus status interface
Common FSI terminology:
* Master
Controller of the FSI bus. Only the master is allowed to control the
clock line and is the initiator of all transactions on a bus.
* Slave
The receiver or target of a master initiated transaction. The slave
cannot initiate communications on a bus and must respond to any
master requests for data.
* CFAM
Stands for Common Field replaceable unit Access Macro. A CFAM is an
ASIC residing in any device requiring FSI communications. CFAMs
consist of an array of hardware 'engines' used for various purposes.
I2C masters, UARTs, General Purpose IO hardware are common types of
these engines.
* Configuration Space / Table
A table contained at the beginning of each CFAM address space.
This table lists information such as the CFAM's ID, which engine types
and versions it has available, as well as its addressing range.
* FSI Engine driver
A device driver that registers with the FSI core so that it can access
devices it owns on an FSI bus.
Chris Bostic (5):
drivers/fsi: Set up links for slave communication
drivers/fsi: Set slave SMODE to init communication
drivers/fsi: Add master unscan
drivers/fsi: Add documentation for GPIO bindings
drivers/fsi: Add GPIO based FSI master
Jeremy Kerr (11):
drivers/fsi: Add empty fsi bus definitions
drivers/fsi: Add device & driver definitions
drivers/fsi: add driver to device matches
drivers/fsi: Add fsi master definition
drivers/fsi: Add fake master driver
drivers/fsi: Add slave definition
drivers/fsi: Add empty master scan
drivers/fsi: Add crc4 helpers
drivers/fsi: Implement slave initialisation
drivers/fsi: scan slaves & register devices
drivers/fsi: Add device read/write/peek functions
.../devicetree/bindings/fsi/fsi-master-gpio.txt | 21 +
drivers/Kconfig | 2 +
drivers/Makefile | 1 +
drivers/fsi/Kconfig | 29 ++
drivers/fsi/Makefile | 4 +
drivers/fsi/fsi-core.c | 514 +++++++++++++++++++
drivers/fsi/fsi-master-fake.c | 95 ++++
drivers/fsi/fsi-master-gpio.c | 552 +++++++++++++++++++++
drivers/fsi/fsi-master.h | 62 +++
include/linux/fsi.h | 60 +++
10 files changed, 1340 insertions(+)
create mode 100644 Documentation/devicetree/bindings/fsi/fsi-master-gpio.txt
create mode 100644 drivers/fsi/Kconfig
create mode 100644 drivers/fsi/Makefile
create mode 100644 drivers/fsi/fsi-core.c
create mode 100644 drivers/fsi/fsi-master-fake.c
create mode 100644 drivers/fsi/fsi-master-gpio.c
create mode 100644 drivers/fsi/fsi-master.h
create mode 100644 include/linux/fsi.h
--
1.8.2.2
^ permalink raw reply
* [PATCH 01/16] drivers/fsi: Add empty fsi bus definitions
From: Chris Bostic @ 2016-12-07 0:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481069677-53660-1-git-send-email-christopher.lee.bostic@gmail.com>
From: Jeremy Kerr <jk@ozlabs.org>
This change adds the initial (empty) fsi bus definition, and introduces
drivers/fsi/.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Chris Bostic <cbostic@us.ibm.com>
---
drivers/Kconfig | 2 ++
drivers/Makefile | 1 +
drivers/fsi/Kconfig | 12 ++++++++++++
drivers/fsi/Makefile | 2 ++
drivers/fsi/fsi-core.c | 38 ++++++++++++++++++++++++++++++++++++++
include/linux/fsi.h | 22 ++++++++++++++++++++++
6 files changed, 77 insertions(+)
create mode 100644 drivers/fsi/Kconfig
create mode 100644 drivers/fsi/Makefile
create mode 100644 drivers/fsi/fsi-core.c
create mode 100644 include/linux/fsi.h
diff --git a/drivers/Kconfig b/drivers/Kconfig
index e1e2066..117ca14c 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -202,4 +202,6 @@ source "drivers/hwtracing/intel_th/Kconfig"
source "drivers/fpga/Kconfig"
+source "drivers/fsi/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index f0afdfb..126e109 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -173,3 +173,4 @@ obj-$(CONFIG_STM) += hwtracing/stm/
obj-$(CONFIG_ANDROID) += android/
obj-$(CONFIG_NVMEM) += nvmem/
obj-$(CONFIG_FPGA) += fpga/
+obj-$(CONFIG_FSI) += fsi/
diff --git a/drivers/fsi/Kconfig b/drivers/fsi/Kconfig
new file mode 100644
index 0000000..04c1a0e
--- /dev/null
+++ b/drivers/fsi/Kconfig
@@ -0,0 +1,12 @@
+#
+# FSI subsystem
+#
+
+menu "FSI support"
+
+config FSI
+ tristate "FSI support"
+ ---help---
+ FSI - the FRU Support Interface - is a simple bus for low-level
+ access to POWER-based hardware.
+endmenu
diff --git a/drivers/fsi/Makefile b/drivers/fsi/Makefile
new file mode 100644
index 0000000..db0e5e7
--- /dev/null
+++ b/drivers/fsi/Makefile
@@ -0,0 +1,2 @@
+
+obj-$(CONFIG_FSI) += fsi-core.o
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
new file mode 100644
index 0000000..3e45306
--- /dev/null
+++ b/drivers/fsi/fsi-core.c
@@ -0,0 +1,38 @@
+/*
+ * FSI core driver
+ *
+ * Copyright (C) IBM Corporation 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/fsi.h>
+#include <linux/module.h>
+
+/* FSI core & Linux bus type definitions */
+
+struct bus_type fsi_bus_type = {
+ .name = "fsi",
+};
+EXPORT_SYMBOL_GPL(fsi_bus_type);
+
+static int fsi_init(void)
+{
+ return bus_register(&fsi_bus_type);
+}
+
+static void fsi_exit(void)
+{
+ bus_unregister(&fsi_bus_type);
+}
+
+module_init(fsi_init);
+module_exit(fsi_exit);
diff --git a/include/linux/fsi.h b/include/linux/fsi.h
new file mode 100644
index 0000000..47aa181
--- /dev/null
+++ b/include/linux/fsi.h
@@ -0,0 +1,22 @@
+/* FSI device & driver interfaces
+ *
+ * Copyright (C) IBM Corporation 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef LINUX_FSI_H
+#define LINUX_FSI_H
+
+#include <linux/device.h>
+
+extern struct bus_type fsi_bus_type;
+
+#endif /* LINUX_FSI_H */
--
1.8.2.2
^ permalink raw reply related
* [PATCH 02/16] drivers/fsi: Add device & driver definitions
From: Chris Bostic @ 2016-12-07 0:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481069677-53660-1-git-send-email-christopher.lee.bostic@gmail.com>
From: Jeremy Kerr <jk@ozlabs.org>
Add structs for fsi devices & drivers, and struct device conversion
functions.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Chris Bostic <cbostic@us.ibm.com>
---
include/linux/fsi.h | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/include/linux/fsi.h b/include/linux/fsi.h
index 47aa181..f73886a 100644
--- a/include/linux/fsi.h
+++ b/include/linux/fsi.h
@@ -17,6 +17,17 @@
#include <linux/device.h>
+struct fsi_device {
+ struct device dev;
+};
+
+struct fsi_driver {
+ struct device_driver drv;
+};
+
+#define to_fsi_dev(devp) container_of(devp, struct fsi_device, dev)
+#define to_fsi_drv(drvp) container_of(drvp, struct fsi_driver, drv)
+
extern struct bus_type fsi_bus_type;
#endif /* LINUX_FSI_H */
--
1.8.2.2
^ permalink raw reply related
* [PATCH 03/16] drivers/fsi: add driver to device matches
From: Chris Bostic @ 2016-12-07 0:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481069677-53660-1-git-send-email-christopher.lee.bostic@gmail.com>
From: Jeremy Kerr <jk@ozlabs.org>
Driver bind to devices based on the engine types & (optional) versions.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Chris Bostic <cbostic@us.ibm.com>
---
drivers/fsi/fsi-core.c | 21 +++++++++++++++++++++
include/linux/fsi.h | 21 +++++++++++++++++++--
2 files changed, 40 insertions(+), 2 deletions(-)
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index 3e45306..3d55bd5 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -19,8 +19,29 @@
/* FSI core & Linux bus type definitions */
+static int fsi_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct fsi_device *fsi_dev = to_fsi_dev(dev);
+ struct fsi_driver *fsi_drv = to_fsi_drv(drv);
+ const struct fsi_device_id *id;
+
+ if (!fsi_drv->id_table)
+ return 0;
+
+ for (id = fsi_drv->id_table; id->engine_type; id++) {
+ if (id->engine_type != fsi_dev->engine_type)
+ continue;
+ if (id->version == FSI_VERSION_ANY ||
+ id->version == fsi_dev->version)
+ return 1;
+ }
+
+ return 0;
+}
+
struct bus_type fsi_bus_type = {
.name = "fsi",
+ .match = fsi_bus_match,
};
EXPORT_SYMBOL_GPL(fsi_bus_type);
diff --git a/include/linux/fsi.h b/include/linux/fsi.h
index f73886a..273cbf6 100644
--- a/include/linux/fsi.h
+++ b/include/linux/fsi.h
@@ -18,11 +18,28 @@
#include <linux/device.h>
struct fsi_device {
- struct device dev;
+ struct device dev;
+ u8 engine_type;
+ u8 version;
};
+struct fsi_device_id {
+ u8 engine_type;
+ u8 version;
+};
+
+#define FSI_VERSION_ANY 0
+
+#define FSI_DEVICE(t) \
+ .engine_type = (t), .version = FSI_VERSION_ANY,
+
+#define FSI_DEVICE_VERSIONED(t, v) \
+ .engine_type = (t), .version = (v),
+
+
struct fsi_driver {
- struct device_driver drv;
+ struct device_driver drv;
+ const struct fsi_device_id *id_table;
};
#define to_fsi_dev(devp) container_of(devp, struct fsi_device, dev)
--
1.8.2.2
^ permalink raw reply related
* [PATCH 05/16] drivers/fsi: Add fake master driver
From: Chris Bostic @ 2016-12-07 0:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481069677-53660-1-git-send-email-christopher.lee.bostic@gmail.com>
From: Jeremy Kerr <jk@ozlabs.org>
For debugging, add a fake master driver, that only supports reads,
returning a fixed set of data.
Includes changes from Chris Bostic <cbostic@us.ibm.com>.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Chris Bostic <cbostic@us.ibm.com>
---
drivers/fsi/Kconfig | 10 +++++
drivers/fsi/Makefile | 1 +
drivers/fsi/fsi-master-fake.c | 95 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 106 insertions(+)
create mode 100644 drivers/fsi/fsi-master-fake.c
diff --git a/drivers/fsi/Kconfig b/drivers/fsi/Kconfig
index 04c1a0e..f065dbe 100644
--- a/drivers/fsi/Kconfig
+++ b/drivers/fsi/Kconfig
@@ -9,4 +9,14 @@ config FSI
---help---
FSI - the FRU Support Interface - is a simple bus for low-level
access to POWER-based hardware.
+
+if FSI
+
+config FSI_MASTER_FAKE
+ tristate "Fake FSI master"
+ depends on FSI
+ ---help---
+ This option enables a fake FSI master driver for debugging.
+endif
+
endmenu
diff --git a/drivers/fsi/Makefile b/drivers/fsi/Makefile
index db0e5e7..847c00c 100644
--- a/drivers/fsi/Makefile
+++ b/drivers/fsi/Makefile
@@ -1,2 +1,3 @@
obj-$(CONFIG_FSI) += fsi-core.o
+obj-$(CONFIG_FSI_MASTER_FAKE) += fsi-master-fake.o
diff --git a/drivers/fsi/fsi-master-fake.c b/drivers/fsi/fsi-master-fake.c
new file mode 100644
index 0000000..b42fe5b
--- /dev/null
+++ b/drivers/fsi/fsi-master-fake.c
@@ -0,0 +1,95 @@
+/*
+ * Fake FSI master driver for FSI development
+ *
+ * Copyright (C) IBM Corporation 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+
+#include "fsi-master.h"
+
+static const uint8_t data[] = {
+ 0xc0, 0x02, 0x08, 0x03, /* chip id */
+ 0x80, 0x01, 0x11, 0x00, /* peek */
+ 0x80, 0x01, 0x20, 0x3e, /* slave */
+ 0x00, 0x01, 0x10, 0xa5, /* i2c */
+};
+
+
+static int fsi_master_fake_read(struct fsi_master *_master, int link,
+ uint8_t slave, uint32_t addr, void *val, size_t size)
+{
+ if (link != 0)
+ return -ENODEV;
+
+ if (addr + size > sizeof(data))
+ memset(val, 0, size);
+ else
+ memcpy(val, data + addr, size);
+
+ return 0;
+}
+
+static int fsi_master_fake_write(struct fsi_master *_master, int link,
+ uint8_t slave, uint32_t addr, const void *val, size_t size)
+{
+ if (link != 0)
+ return -ENODEV;
+
+ return -EACCES;
+}
+
+static int fsi_master_fake_probe(struct platform_device *pdev)
+{
+ struct fsi_master *master;
+
+ master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL);
+ if (!master)
+ return -ENOMEM;
+
+ master->dev = &pdev->dev;
+ master->n_links = 1;
+ master->read = fsi_master_fake_read;
+ master->write = fsi_master_fake_write;
+
+ return fsi_master_register(master);
+}
+
+static const struct of_device_id fsi_master_fake_match[] = {
+ { .compatible = "ibm,fsi-master-fake" },
+ { },
+};
+
+static struct platform_driver fsi_master_fake_driver = {
+ .driver = {
+ .name = "fsi-master-fake",
+ .of_match_table = fsi_master_fake_match,
+ },
+ .probe = fsi_master_fake_probe,
+};
+
+static int __init fsi_master_fake_init(void)
+{
+ struct device_node *np;
+
+ platform_driver_register(&fsi_master_fake_driver);
+
+ for_each_compatible_node(np, NULL, "ibm,fsi-master-fake")
+ of_platform_device_create(np, NULL, NULL);
+
+ return 0;
+}
+
+module_init(fsi_master_fake_init);
--
1.8.2.2
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox