* Re: [PATCH] cpuidle/pseries: Fixup CEDE0 latency only for POWER10 onwards
From: Vaidyanathan Srinivasan @ 2021-04-22 17:57 UTC (permalink / raw)
To: Gautham R. Shenoy
Cc: linux-pm, Daniel Lezcano, Rafael J. Wysocki, joedecke,
Aneesh Kumar K.V, linuxppc-dev
In-Reply-To: <1619104049-5118-1-git-send-email-ego@linux.vnet.ibm.com>
* Gautham R Shenoy <ego@linux.vnet.ibm.com> [2021-04-22 20:37:29]:
> From: "Gautham R. Shenoy" <ego@linux.vnet.ibm.com>
>
> Commit d947fb4c965c ("cpuidle: pseries: Fixup exit latency for
> CEDE(0)") sets the exit latency of CEDE(0) based on the latency values
> of the Extended CEDE states advertised by the platform
>
> On some of the POWER9 LPARs, the older firmwares advertise a very low
> value of 2us for CEDE1 exit latency on a Dedicated LPAR. However the
> measured value is 5us on an average. Due to the low advertised exit
> latency, we are entering CEDE(0) more aggressively on such
> platforms. While this helps achieve SMT folding faster, we pay the
> penalty of having to send an IPI to wakeup the CPU when the target
> residency is very short. This is showing up as a performance
> regression on the newer kernels running on the LPARs with older
> firmware.
>
> Hence, set the exit latency of CEDE(0) based on the latency values
> advertized by platform only from POWER10 onwards. The values
> advertized on POWER10 platforms is more realistic and informed by the
> latency measurements.
>
> For platforms older than POWER10, retain the hardcoded value of exit
> latency, which is 10us. Though this is higher than the measured
> values, we would be erring on the side of caution.
>
> Reported-by: Enrico Joedecke <joedecke@de.ibm.com>
> Fixes: commit d947fb4c965c ("cpuidle: pseries: Fixup exit latency for
> CEDE(0)")
> Signed-off-by: Gautham R. Shenoy <ego@linux.vnet.ibm.com>
Reviewed-by: Vaidyanathan Srinivasan <svaidy@linux.ibm.com>
> ---
> drivers/cpuidle/cpuidle-pseries.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/cpuidle/cpuidle-pseries.c b/drivers/cpuidle/cpuidle-pseries.c
> index a2b5c6f..7207467 100644
> --- a/drivers/cpuidle/cpuidle-pseries.c
> +++ b/drivers/cpuidle/cpuidle-pseries.c
> @@ -419,7 +419,8 @@ static int pseries_idle_probe(void)
> cpuidle_state_table = shared_states;
> max_idle_state = ARRAY_SIZE(shared_states);
> } else {
> - fixup_cede0_latency();
> + if (pvr_version_is(PVR_POWER10))
> + fixup_cede0_latency();
> cpuidle_state_table = dedicated_states;
> max_idle_state = NR_DEDICATED_STATES;
> }
Thanks for the fix. We should have such safeguards or fallbacks while
running on older platforms. This fix is needed because of the
unfortunate regression on some older platforms that we failed to
notice while designing and testing the original feature.
--Vaidy
^ permalink raw reply
* Re: [PATCH 1/2] powerpc/sstep: Add emulation support for ‘setb’ instruction
From: Segher Boessenkool @ 2021-04-22 19:13 UTC (permalink / raw)
To: Daniel Axtens; +Cc: Sathvika Vasireddy, naveen.n.rao, linuxppc-dev
In-Reply-To: <875z0mfzbf.fsf@linkitivity.dja.id.au>
Hi!
On Fri, Apr 16, 2021 at 05:44:52PM +1000, Daniel Axtens wrote:
> Sathvika Vasireddy <sathvika@linux.vnet.ibm.com> writes:
> Ok, if I've understood correctly...
>
> > + ra = ra & ~0x3;
>
> This masks off the bits of RA that are not part of BTF:
>
> ra is in [0, 31] which is [0b00000, 0b11111]
> Then ~0x3 = ~0b00011
> ra = ra & 0b11100
>
> This gives us then,
> ra = btf << 2; or
> btf = ra >> 2;
Yes. In effect, you want the offset in bits of the CR field, which is
just fine like this. But a comment would not hurt.
> Let's then check to see if your calculations read the right fields.
>
> > + if ((regs->ccr) & (1 << (31 - ra)))
> > + op->val = -1;
> > + else if ((regs->ccr) & (1 << (30 - ra)))
> > + op->val = 1;
> > + else
> > + op->val = 0;
It imo is clearer if written
if ((regs->ccr << ra) & 0x80000000)
op->val = -1;
else if ((regs->ccr << ra) & 0x40000000)
op->val = 1;
else
op->val = 0;
but I guess not everyone agrees :-)
> CR field: 7 6 5 4 3 2 1 0
> bit: 0123 0123 0123 0123 0123 0123 0123 0123
> normal bit #: 0.....................................31
> ibm bit #: 31.....................................0
The bit numbers in CR fields are *always* numbered left-to-right. I
have never seen anyone use LE for it, anyway.
Also, even people who write LE have the bigger end on the left normally
(they just write some things right-to-left, and other things
left-to-right).
> Checkpatch does have one complaint:
>
> CHECK:UNNECESSARY_PARENTHESES: Unnecessary parentheses around 'regs->ccr'
> #30: FILE: arch/powerpc/lib/sstep.c:1971:
> + if ((regs->ccr) & (1 << (31 - ra)))
>
> I don't really mind the parenteses: I think you are safe to ignore
> checkpatch here unless someone else complains :)
I find them annoying. If there are too many parentheses, it is hard to
see at a glance what groups where. Also, a suspicious reader might
think there is something special going on (with macros for example).
This is simple code of course, but :-)
> If you do end up respinning the patch, I think it would be good to make
> the maths a bit clearer. I think it works because a left shift of 2 is
> the same as multiplying by 4, but it would be easier to follow if you
> used a temporary variable for btf.
It is very simple. The BFA instruction field is closely related to the
BI instruction field, which is 5 bits, and selects one of the 32 bits in
the CR. If you have "BFA00 BFA01 BFA10 BFA11", that gives the bit
numbers of all four bits in the selected CR field. So the "& ~3" does
all you need. It is quite pretty :-)
Segher
^ permalink raw reply
* [PATCH] powerpc/powernv/pci: remove dead code from !CONFIG_EEH
From: Nick Desaulniers @ 2021-04-22 19:54 UTC (permalink / raw)
To: Michael Ellerman
Cc: Alexey Kardashevskiy, Nick Desaulniers, linux-kernel,
Nathan Chancellor, Oliver O'Halloran, Joe Perches,
Paul Mackerras, linuxppc-dev
While looking at -Wundef warnings, the #if CONFIG_EEH stood out as a
possible candidate to convert to #ifdef CONFIG_EEH, but it seems that
based on Kconfig dependencies it's not possible to build this file
without CONFIG_EEH enabled.
Suggested-by: Nathan Chancellor <nathan@kernel.org>
Suggested-by: Joe Perches <joe@perches.com>
Link: https://github.com/ClangBuiltLinux/linux/issues/570
Link: https://lore.kernel.org/lkml/67f6cd269684c9aa8463ff4812c3b4605e6739c3.camel@perches.com/
Signed-off-by: Nick Desaulniers <ndesaulniers@google.com>
---
arch/powerpc/platforms/powernv/pci.c | 7 -------
1 file changed, 7 deletions(-)
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index 9b9bca169275..591480a37b05 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -711,7 +711,6 @@ int pnv_pci_cfg_write(struct pci_dn *pdn,
return PCIBIOS_SUCCESSFUL;
}
-#if CONFIG_EEH
static bool pnv_pci_cfg_check(struct pci_dn *pdn)
{
struct eeh_dev *edev = NULL;
@@ -734,12 +733,6 @@ static bool pnv_pci_cfg_check(struct pci_dn *pdn)
return true;
}
-#else
-static inline pnv_pci_cfg_check(struct pci_dn *pdn)
-{
- return true;
-}
-#endif /* CONFIG_EEH */
static int pnv_pci_read_config(struct pci_bus *bus,
unsigned int devfn,
base-commit: 16fc44d6387e260f4932e9248b985837324705d8
prerequisite-patch-id: 950233069fb22099a8ff8990f620f5c3586a3cbd
--
2.31.1.498.g6c1eba8ee3d-goog
^ permalink raw reply related
* Re: [PATCH 1/2] powerpc/sstep: Add emulation support for ‘setb’ instruction
From: Gabriel Paubert @ 2021-04-22 22:16 UTC (permalink / raw)
To: Segher Boessenkool
Cc: Sathvika Vasireddy, naveen.n.rao, linuxppc-dev, Daniel Axtens
In-Reply-To: <20210422191334.GE27473@gate.crashing.org>
Hi,
On Thu, Apr 22, 2021 at 02:13:34PM -0500, Segher Boessenkool wrote:
> Hi!
>
> On Fri, Apr 16, 2021 at 05:44:52PM +1000, Daniel Axtens wrote:
> > Sathvika Vasireddy <sathvika@linux.vnet.ibm.com> writes:
> > Ok, if I've understood correctly...
> >
> > > + ra = ra & ~0x3;
> >
> > This masks off the bits of RA that are not part of BTF:
> >
> > ra is in [0, 31] which is [0b00000, 0b11111]
> > Then ~0x3 = ~0b00011
> > ra = ra & 0b11100
> >
> > This gives us then,
> > ra = btf << 2; or
> > btf = ra >> 2;
>
> Yes. In effect, you want the offset in bits of the CR field, which is
> just fine like this. But a comment would not hurt.
>
> > Let's then check to see if your calculations read the right fields.
> >
> > > + if ((regs->ccr) & (1 << (31 - ra)))
> > > + op->val = -1;
> > > + else if ((regs->ccr) & (1 << (30 - ra)))
> > > + op->val = 1;
> > > + else
> > > + op->val = 0;
>
> It imo is clearer if written
>
> if ((regs->ccr << ra) & 0x80000000)
> op->val = -1;
> else if ((regs->ccr << ra) & 0x40000000)
> op->val = 1;
> else
> op->val = 0;
>
> but I guess not everyone agrees :-)
>
But this can be made jump free :-):
int tmp = regs->ccr << ra;
op->val = (tmp >> 31) | ((tmp >> 30) & 1);
(IIRC the srawi instruction sign-extends its result to 64 bits).
> > CR field: 7 6 5 4 3 2 1 0
> > bit: 0123 0123 0123 0123 0123 0123 0123 0123
> > normal bit #: 0.....................................31
> > ibm bit #: 31.....................................0
>
> The bit numbers in CR fields are *always* numbered left-to-right. I
> have never seen anyone use LE for it, anyway.
>
> Also, even people who write LE have the bigger end on the left normally
> (they just write some things right-to-left, and other things
> left-to-right).
Around 1985, I had a documentation for the the National's 32032
(little-endian) processor family, and all the instruction encodings were
presented with the LSB on the left and MSB on the right.
BTW on these processors, the immediate operands and the offsets (1, 2 or
4 bytes) for the addressing modes were encoded in big-endian byte order,
but I digress. Consistency is overrated ;-)
Gabriel
>
> > Checkpatch does have one complaint:
> >
> > CHECK:UNNECESSARY_PARENTHESES: Unnecessary parentheses around 'regs->ccr'
> > #30: FILE: arch/powerpc/lib/sstep.c:1971:
> > + if ((regs->ccr) & (1 << (31 - ra)))
> >
> > I don't really mind the parenteses: I think you are safe to ignore
> > checkpatch here unless someone else complains :)
>
> I find them annoying. If there are too many parentheses, it is hard to
> see at a glance what groups where. Also, a suspicious reader might
> think there is something special going on (with macros for example).
>
> This is simple code of course, but :-)
>
> > If you do end up respinning the patch, I think it would be good to make
> > the maths a bit clearer. I think it works because a left shift of 2 is
> > the same as multiplying by 4, but it would be easier to follow if you
> > used a temporary variable for btf.
>
> It is very simple. The BFA instruction field is closely related to the
> BI instruction field, which is 5 bits, and selects one of the 32 bits in
> the CR. If you have "BFA00 BFA01 BFA10 BFA11", that gives the bit
> numbers of all four bits in the selected CR field. So the "& ~3" does
> all you need. It is quite pretty :-)
>
>
> Segher
^ permalink raw reply
* Re: [PATCH 1/2] powerpc/vdso64: link vdso64 with linker
From: Nick Desaulniers @ 2021-04-22 22:44 UTC (permalink / raw)
To: Christophe Leroy
Cc: Christophe Leroy, Joe Lawrence, Kees Cook, Fangrui Song, LKML,
Nicholas Piggin, clang-built-linux, Paul Mackerras, linuxppc-dev
In-Reply-To: <3d837a36-a186-6789-7924-eaa97f056b68@csgroup.eu>
On Wed, Sep 2, 2020 at 11:02 AM Christophe Leroy
<christophe.leroy@csgroup.eu> wrote:
>
>
>
> Le 02/09/2020 à 19:41, Nick Desaulniers a écrit :
> > On Wed, Sep 2, 2020 at 5:14 AM Michael Ellerman <mpe@ellerman.id.au> wrote:
> >>
> >> Nick Desaulniers <ndesaulniers@google.com> writes:
> >>> Fixes: commit f2af201002a8 ("powerpc/build: vdso linker warning for orphan sections")
> >>
> >> I think I'll just revert that for v5.9 ?
> >
> > SGTM; you'll probably still want these changes with some modifications
> > at some point; vdso32 did have at least one orphaned section, and will
> > be important for hermetic builds. Seeing crashes in supported
> > versions of the tools ties our hands at the moment.
> >
>
> Keeping the tool problem aside with binutils 2.26, do you have a way to
> really link an elf32ppc object when building vdso32 for PPC64 ?
Sorry, I'm doing a bug scrub and found
https://github.com/ClangBuiltLinux/linux/issues/774 still open (and my
reply to this thread still in Drafts; never sent). With my patches
rebased:
$ file arch/powerpc/kernel/vdso32/vdso32.so
arch/powerpc/kernel/vdso32/vdso32.so: ELF 32-bit MSB shared object,
PowerPC or cisco 4500, version 1 (SYSV), dynamically linked, stripped
Are you still using 2.26?
I'm not able to repro Nathan's reported issue from
https://lore.kernel.org/lkml/20200902052123.GA2687902@ubuntu-n2-xlarge-x86/,
so I'm curious if I should resend the rebased patches as v2?
--
Thanks,
~Nick Desaulniers
^ permalink raw reply
* Re: [PATCH kernel] powerpc/makefile: Do not redefine $(CPP) for preprocessor
From: Daniel Axtens @ 2021-04-22 22:58 UTC (permalink / raw)
To: Alexey Kardashevskiy, linuxppc-dev; +Cc: Alexey Kardashevskiy
In-Reply-To: <20210422092737.895392-1-aik@ozlabs.ru>
Hi Alexey,
> The $(CPP) (do only preprocessing) macro is already defined in Makefile.
> However POWERPC redefines it and adds $(KBUILD_CFLAGS) which results
> in flags duplication. Which is not a big deal by itself except for
> the flags which depend on other flags and the compiler checks them
> as it parses the command line.
>
> Specifically, scripts/Makefile.build:304 generates ksyms for .S files.
> If clang+llvm+sanitizer are enabled, this results in
> -fno-lto -flto -fsanitize=cfi-mfcall .... -fno-lto -flto -fsanitize=cfi-mfcall
Checkpatch doesn't like this line:
WARNING:COMMIT_LOG_LONG_LINE: Possible unwrapped commit description (prefer a maximum 75 chars per line)
#14:
-fno-lto -flto -fsanitize=cfi-mfcall .... -fno-lto -flto -fsanitize=cfi-mfcall
However, it doesn't make sense to wrap the line so we should just ignore
checkpatch here.
> in the clang command line and triggers error:
>
> clang-13: error: invalid argument '-fsanitize=cfi-mfcall' only allowed with '-flto'
>
> This removes unnecessary CPP redifinition.
>
> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> ---
> arch/powerpc/Makefile | 1 -
> 1 file changed, 1 deletion(-)
>
> diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
> index c9d2c7825cd6..3a2f2001c62b 100644
> --- a/arch/powerpc/Makefile
> +++ b/arch/powerpc/Makefile
> @@ -214,7 +214,6 @@ KBUILD_CPPFLAGS += -I $(srctree)/arch/$(ARCH) $(asinstr)
> KBUILD_AFLAGS += $(AFLAGS-y)
> KBUILD_CFLAGS += $(call cc-option,-msoft-float)
> KBUILD_CFLAGS += -pipe $(CFLAGS-y)
> -CPP = $(CC) -E $(KBUILD_CFLAGS)
I was trying to check the history to see why powerpc has its own
definition. It seems to date back at least as far as merging the two
powerpc platforms into one, maybe it was helpful then. I agree it
doesn't seem to be needed now.
Snowpatch claims that this breaks the build, but I haven't been able to
reproduce the issue in either pmac32 or ppc64 defconfig. I have sent it
off to a fork of mpe's linux-ci repo to see if any of those builds hit
any issues: https://github.com/daxtens/linux-ci/actions
Assuming that doesn't break, this patch looks good to me:
Reviewed-by: Daniel Axtens <dja@axtens.net>
Kind regards,
Daniel
^ permalink raw reply
* Re: [PATCH] powerpc/powernv/pci: remove dead code from !CONFIG_EEH
From: Daniel Axtens @ 2021-04-22 23:09 UTC (permalink / raw)
To: Nick Desaulniers, Michael Ellerman
Cc: Alexey Kardashevskiy, Nick Desaulniers, linux-kernel,
Nathan Chancellor, Oliver O'Halloran, Joe Perches,
Paul Mackerras, linuxppc-dev
In-Reply-To: <20210422195405.4053917-1-ndesaulniers@google.com>
Hi Nick,
> While looking at -Wundef warnings, the #if CONFIG_EEH stood out as a
> possible candidate to convert to #ifdef CONFIG_EEH, but it seems that
> based on Kconfig dependencies it's not possible to build this file
> without CONFIG_EEH enabled.
This seemed odd to me, but I think you're right:
arch/powerpc/platforms/Kconfig contains:
config EEH
bool
depends on (PPC_POWERNV || PPC_PSERIES) && PCI
default y
It's not configurable from e.g. make menuconfig because there's no prompt.
You can attempt to explicitly disable it with e.g. `scripts/config -d EEH`
but then something like `make oldconfig` will silently re-enable it for
you.
It's been forced on since commit e49f7a9997c6 ("powerpc/pseries: Rivet
CONFIG_EEH for pSeries platform") in 2012 which fixed it for
pseries. That moved out from pseries to pseries + powernv later on.
There are other cleanups in the same vein that could be made, from the
Makefile (which has files only built with CONFIG_EEH) through to other
source files. It looks like there's one `#ifdef CONFIG_EEH` in
arch/powerpc/platforms/powernv/pci-ioda.c that could be pulled out, for
example.
I think it's probably worth trying to rip out all of those in one patch?
Kind regards,
Daniel
^ permalink raw reply
* Re: [PATCH 1/2] powerpc/sstep: Add emulation support for ‘setb’ instruction
From: Segher Boessenkool @ 2021-04-22 23:26 UTC (permalink / raw)
To: Gabriel Paubert
Cc: Sathvika Vasireddy, naveen.n.rao, linuxppc-dev, Daniel Axtens
In-Reply-To: <20210422221618.GA30594@lt-gp.iram.es>
Hi!
On Fri, Apr 23, 2021 at 12:16:18AM +0200, Gabriel Paubert wrote:
> On Thu, Apr 22, 2021 at 02:13:34PM -0500, Segher Boessenkool wrote:
> > On Fri, Apr 16, 2021 at 05:44:52PM +1000, Daniel Axtens wrote:
> > > Sathvika Vasireddy <sathvika@linux.vnet.ibm.com> writes:
> > > > + if ((regs->ccr) & (1 << (31 - ra)))
> > > > + op->val = -1;
> > > > + else if ((regs->ccr) & (1 << (30 - ra)))
> > > > + op->val = 1;
> > > > + else
> > > > + op->val = 0;
> >
> > It imo is clearer if written
> >
> > if ((regs->ccr << ra) & 0x80000000)
> > op->val = -1;
> > else if ((regs->ccr << ra) & 0x40000000)
> > op->val = 1;
> > else
> > op->val = 0;
> >
> > but I guess not everyone agrees :-)
>
> But this can be made jump free :-):
>
> int tmp = regs->ccr << ra;
> op->val = (tmp >> 31) | ((tmp >> 30) & 1);
The compiler will do so automatically (or think of some better way to
get the same result); in source code, what matters most is readability,
or clarity in general (also clarity to the compiler).
(Right shifts of negative numbers are implementation-defined in C,
fwiw -- but work like you expect in GCC).
> (IIRC the srawi instruction sign-extends its result to 64 bits).
If you consider it to work on 32-bit inputs, yeah, that is a simple way
to express it.
> > > CR field: 7 6 5 4 3 2 1 0
> > > bit: 0123 0123 0123 0123 0123 0123 0123 0123
> > > normal bit #: 0.....................................31
> > > ibm bit #: 31.....................................0
> >
> > The bit numbers in CR fields are *always* numbered left-to-right. I
> > have never seen anyone use LE for it, anyway.
> >
> > Also, even people who write LE have the bigger end on the left normally
> > (they just write some things right-to-left, and other things
> > left-to-right).
>
> Around 1985, I had a documentation for the the National's 32032
> (little-endian) processor family, and all the instruction encodings were
> presented with the LSB on the left and MSB on the right.
Ouch! Did they write "regular" numbers with the least significant digit
on the left as well?
> BTW on these processors, the immediate operands and the offsets (1, 2 or
> 4 bytes) for the addressing modes were encoded in big-endian byte order,
> but I digress. Consistency is overrated ;-)
Inconsistency is the spice of life, yeah :-)
Segher
^ permalink raw reply
* Re: [PATCH] powerpc/powernv/pci: remove dead code from !CONFIG_EEH
From: Oliver O'Halloran @ 2021-04-23 1:13 UTC (permalink / raw)
To: Daniel Axtens
Cc: Alexey Kardashevskiy, Nick Desaulniers, Linux Kernel Mailing List,
Nathan Chancellor, Paul Mackerras, Joe Perches, linuxppc-dev
In-Reply-To: <87lf99zzl3.fsf@dja-thinkpad.axtens.net>
On Fri, Apr 23, 2021 at 9:09 AM Daniel Axtens <dja@axtens.net> wrote:
>
> Hi Nick,
>
> > While looking at -Wundef warnings, the #if CONFIG_EEH stood out as a
> > possible candidate to convert to #ifdef CONFIG_EEH, but it seems that
> > based on Kconfig dependencies it's not possible to build this file
> > without CONFIG_EEH enabled.
>
> This seemed odd to me, but I think you're right:
>
> arch/powerpc/platforms/Kconfig contains:
>
> config EEH
> bool
> depends on (PPC_POWERNV || PPC_PSERIES) && PCI
> default y
>
> It's not configurable from e.g. make menuconfig because there's no prompt.
> You can attempt to explicitly disable it with e.g. `scripts/config -d EEH`
> but then something like `make oldconfig` will silently re-enable it for
> you.
>
> It's been forced on since commit e49f7a9997c6 ("powerpc/pseries: Rivet
> CONFIG_EEH for pSeries platform") in 2012 which fixed it for
> pseries. That moved out from pseries to pseries + powernv later on.
>
> There are other cleanups in the same vein that could be made, from the
> Makefile (which has files only built with CONFIG_EEH) through to other
> source files. It looks like there's one `#ifdef CONFIG_EEH` in
> arch/powerpc/platforms/powernv/pci-ioda.c that could be pulled out, for
> example.
>
> I think it's probably worth trying to rip out all of those in one patch?
The change in commit e49f7a9997c6 ("powerpc/pseries: Rivet CONFIG_EEH
for pSeries platform") never should have been made.
There's no inherent reason why EEH needs to be enabled and forcing it
on is (IMO) a large part of why EEH support is the byzantine
clusterfuck that it is. One of the things I was working towards was
allowing pseries and powernv to be built with !CONFIG_EEH since that
would help define a clearer boundary between what is "eeh support" and
what is required to support PCI on the platform. Pseries is
particularly bad for this since PAPR says the RTAS calls needed to do
a PCI bus reset are part of the EEH extension, but there's non-EEH
reasons why you might want to use those RTAS calls. The PHB reset that
we do when entering a kdump kernel is a good example since that uses
the same RTAS calls, but it has nothing to do with the EEH recovery
machinery enabled by CONFIG_EEH.
I was looking into that largely because people were considering using
OPAL for microwatt platforms. Breaking the assumption that
powernv==EEH support is one of the few bits of work required to enable
that, but even if you don't go down that road I think everyone would
be better off if you kept a degree of separation between the two.
^ permalink raw reply
* Re: [PATCH V2 net] ibmvnic: Continue with reset if set link down failed
From: Rick Lindsley @ 2021-04-23 2:26 UTC (permalink / raw)
To: Michal Suchánek, Lijun Pan
Cc: netdev, Lijun Pan, Tom Falcon, Paul Mackerras, Dany Madden,
Jakub Kicinski, Sukadev Bhattiprolu, linuxppc-dev, David Miller
In-Reply-To: <20210422172135.GY6564@kitsune.suse.cz>
On 4/22/21 10:21 AM, Michal Suchánek wrote:
> Merging do_reset and do_hard_reset might be a good code cleanup which is
> out of the scope of this fix.
I agree, on both points. Accepting the patch, and improving the reset
path are not in conflict with each other.
My position is that improving the reset path is certainly on the table,
but not with this bug or this fix. Within the context of this discovered
problem, the issue is well understood, the fix is small and addresses the
immediate problem, and it has not generated new bugs under subsequent
testing. For those reasons, the submitted patch has my support.
Rick
^ permalink raw reply
* Re: [PATCH 1/2] audit: add support for the openat2 syscall
From: Richard Guy Briggs @ 2021-04-23 2:34 UTC (permalink / raw)
To: Christian Brauner
Cc: linux-s390, linux-ia64, linux-parisc, x86, LKML, sparclinux,
Aleksa Sarai, Linux-Audit Mailing List, Alexander Viro,
linux-alpha, linux-fsdevel, Eric Paris, linuxppc-dev
In-Reply-To: <20210318120801.GK3141668@madcap2.tricolour.ca>
On 2021-03-18 08:08, Richard Guy Briggs wrote:
> On 2021-03-18 11:48, Christian Brauner wrote:
> > [+Cc Aleksa, the author of openat2()]
>
> Ah! Thanks for pulling in Aleksa. I thought I caught everyone...
>
> > and a comment below. :)
>
> Same...
>
> > On Wed, Mar 17, 2021 at 09:47:17PM -0400, Richard Guy Briggs wrote:
> > > The openat2(2) syscall was added in kernel v5.6 with commit fddb5d430ad9
> > > ("open: introduce openat2(2) syscall")
> > >
> > > Add the openat2(2) syscall to the audit syscall classifier.
> > >
> > > See the github issue
> > > https://github.com/linux-audit/audit-kernel/issues/67
> > >
> > > Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
> > > ---
> > > arch/alpha/kernel/audit.c | 2 ++
> > > arch/ia64/kernel/audit.c | 2 ++
> > > arch/parisc/kernel/audit.c | 2 ++
> > > arch/parisc/kernel/compat_audit.c | 2 ++
> > > arch/powerpc/kernel/audit.c | 2 ++
> > > arch/powerpc/kernel/compat_audit.c | 2 ++
> > > arch/s390/kernel/audit.c | 2 ++
> > > arch/s390/kernel/compat_audit.c | 2 ++
> > > arch/sparc/kernel/audit.c | 2 ++
> > > arch/sparc/kernel/compat_audit.c | 2 ++
> > > arch/x86/ia32/audit.c | 2 ++
> > > arch/x86/kernel/audit_64.c | 2 ++
> > > kernel/auditsc.c | 3 +++
> > > lib/audit.c | 4 ++++
> > > lib/compat_audit.c | 4 ++++
> > > 15 files changed, 35 insertions(+)
> > >
> > > diff --git a/arch/alpha/kernel/audit.c b/arch/alpha/kernel/audit.c
> > > index 96a9d18ff4c4..06a911b685d1 100644
> > > --- a/arch/alpha/kernel/audit.c
> > > +++ b/arch/alpha/kernel/audit.c
> > > @@ -42,6 +42,8 @@ int audit_classify_syscall(int abi, unsigned syscall)
> > > return 3;
> > > case __NR_execve:
> > > return 5;
> > > + case __NR_openat2:
> > > + return 6;
> > > default:
> > > return 0;
> > > }
> > > diff --git a/arch/ia64/kernel/audit.c b/arch/ia64/kernel/audit.c
> > > index 5192ca899fe6..5eaa888c8fd3 100644
> > > --- a/arch/ia64/kernel/audit.c
> > > +++ b/arch/ia64/kernel/audit.c
> > > @@ -43,6 +43,8 @@ int audit_classify_syscall(int abi, unsigned syscall)
> > > return 3;
> > > case __NR_execve:
> > > return 5;
> > > + case __NR_openat2:
> > > + return 6;
> > > default:
> > > return 0;
> > > }
> > > diff --git a/arch/parisc/kernel/audit.c b/arch/parisc/kernel/audit.c
> > > index 9eb47b2225d2..fc721a7727ba 100644
> > > --- a/arch/parisc/kernel/audit.c
> > > +++ b/arch/parisc/kernel/audit.c
> > > @@ -52,6 +52,8 @@ int audit_classify_syscall(int abi, unsigned syscall)
> > > return 3;
> > > case __NR_execve:
> > > return 5;
> > > + case __NR_openat2:
> > > + return 6;
> > > default:
> > > return 0;
> > > }
> > > diff --git a/arch/parisc/kernel/compat_audit.c b/arch/parisc/kernel/compat_audit.c
> > > index 20c39c9d86a9..fc6d35918c44 100644
> > > --- a/arch/parisc/kernel/compat_audit.c
> > > +++ b/arch/parisc/kernel/compat_audit.c
> > > @@ -35,6 +35,8 @@ int parisc32_classify_syscall(unsigned syscall)
> > > return 3;
> > > case __NR_execve:
> > > return 5;
> > > + case __NR_openat2:
> > > + return 6;
> > > default:
> > > return 1;
> > > }
> > > diff --git a/arch/powerpc/kernel/audit.c b/arch/powerpc/kernel/audit.c
> > > index a2dddd7f3d09..8f32700b0baa 100644
> > > --- a/arch/powerpc/kernel/audit.c
> > > +++ b/arch/powerpc/kernel/audit.c
> > > @@ -54,6 +54,8 @@ int audit_classify_syscall(int abi, unsigned syscall)
> > > return 4;
> > > case __NR_execve:
> > > return 5;
> > > + case __NR_openat2:
> > > + return 6;
> > > default:
> > > return 0;
> > > }
> > > diff --git a/arch/powerpc/kernel/compat_audit.c b/arch/powerpc/kernel/compat_audit.c
> > > index 55c6ccda0a85..ebe45534b1c9 100644
> > > --- a/arch/powerpc/kernel/compat_audit.c
> > > +++ b/arch/powerpc/kernel/compat_audit.c
> > > @@ -38,6 +38,8 @@ int ppc32_classify_syscall(unsigned syscall)
> > > return 4;
> > > case __NR_execve:
> > > return 5;
> > > + case __NR_openat2:
> > > + return 6;
> > > default:
> > > return 1;
> > > }
> > > diff --git a/arch/s390/kernel/audit.c b/arch/s390/kernel/audit.c
> > > index d395c6c9944c..d964cb94cfaf 100644
> > > --- a/arch/s390/kernel/audit.c
> > > +++ b/arch/s390/kernel/audit.c
> > > @@ -54,6 +54,8 @@ int audit_classify_syscall(int abi, unsigned syscall)
> > > return 4;
> > > case __NR_execve:
> > > return 5;
> > > + case __NR_openat2:
> > > + return 6;
> > > default:
> > > return 0;
> > > }
> > > diff --git a/arch/s390/kernel/compat_audit.c b/arch/s390/kernel/compat_audit.c
> > > index 444fb1f66944..f7b32933ce0e 100644
> > > --- a/arch/s390/kernel/compat_audit.c
> > > +++ b/arch/s390/kernel/compat_audit.c
> > > @@ -39,6 +39,8 @@ int s390_classify_syscall(unsigned syscall)
> > > return 4;
> > > case __NR_execve:
> > > return 5;
> > > + case __NR_openat2:
> > > + return 6;
> > > default:
> > > return 1;
> > > }
> > > diff --git a/arch/sparc/kernel/audit.c b/arch/sparc/kernel/audit.c
> > > index a6e91bf34d48..b6dcca9c6520 100644
> > > --- a/arch/sparc/kernel/audit.c
> > > +++ b/arch/sparc/kernel/audit.c
> > > @@ -55,6 +55,8 @@ int audit_classify_syscall(int abi, unsigned int syscall)
> > > return 4;
> > > case __NR_execve:
> > > return 5;
> > > + case __NR_openat2:
> > > + return 6;
> > > default:
> > > return 0;
> > > }
> > > diff --git a/arch/sparc/kernel/compat_audit.c b/arch/sparc/kernel/compat_audit.c
> > > index 10eeb4f15b20..d2652a1083ad 100644
> > > --- a/arch/sparc/kernel/compat_audit.c
> > > +++ b/arch/sparc/kernel/compat_audit.c
> > > @@ -39,6 +39,8 @@ int sparc32_classify_syscall(unsigned int syscall)
> > > return 4;
> > > case __NR_execve:
> > > return 5;
> > > + case __NR_openat2:
> > > + return 6;
> > > default:
> > > return 1;
> > > }
> > > diff --git a/arch/x86/ia32/audit.c b/arch/x86/ia32/audit.c
> > > index 6efe6cb3768a..57a02ade5503 100644
> > > --- a/arch/x86/ia32/audit.c
> > > +++ b/arch/x86/ia32/audit.c
> > > @@ -39,6 +39,8 @@ int ia32_classify_syscall(unsigned syscall)
> > > case __NR_execve:
> > > case __NR_execveat:
> > > return 5;
> > > + case __NR_openat2:
> > > + return 6;
> > > default:
> > > return 1;
> > > }
> > > diff --git a/arch/x86/kernel/audit_64.c b/arch/x86/kernel/audit_64.c
> > > index 83d9cad4e68b..39de1e021258 100644
> > > --- a/arch/x86/kernel/audit_64.c
> > > +++ b/arch/x86/kernel/audit_64.c
> > > @@ -53,6 +53,8 @@ int audit_classify_syscall(int abi, unsigned syscall)
> > > case __NR_execve:
> > > case __NR_execveat:
> > > return 5;
> > > + case __NR_openat2:
> > > + return 6;
> > > default:
> > > return 0;
> > > }
> > > diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> > > index 8bb9ac84d2fb..f5616e70d129 100644
> > > --- a/kernel/auditsc.c
> > > +++ b/kernel/auditsc.c
> > > @@ -76,6 +76,7 @@
> > > #include <linux/fsnotify_backend.h>
> > > #include <uapi/linux/limits.h>
> > > #include <uapi/linux/netfilter/nf_tables.h>
> > > +#include <uapi/linux/openat2.h>
> > >
> > > #include "audit.h"
> > >
> > > @@ -195,6 +196,8 @@ static int audit_match_perm(struct audit_context *ctx, int mask)
> > > return ((mask & AUDIT_PERM_WRITE) && ctx->argv[0] == SYS_BIND);
> > > case 5: /* execve */
> > > return mask & AUDIT_PERM_EXEC;
> > > + case 6: /* openat2 */
> > > + return mask & ACC_MODE((u32)((struct open_how *)ctx->argv[2])->flags);
> >
> > That looks a bit dodgy. Maybe sm like the below would be a bit better?
>
> Ah, ok, fair enough, since original flags use a u32 and this was picked
> as u64 for alignment. It was just occurring to me last night that I
> might have the dubious honour of being the first usage of 0%llo format
> specifier in the kernel... ;-)
> > diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> > index 47fb48f42c93..531e882a5096 100644
> > --- a/kernel/auditsc.c
> > +++ b/kernel/auditsc.c
> > @@ -159,6 +159,7 @@ static const struct audit_nfcfgop_tab audit_nfcfgs[] = {
> >
> > static int audit_match_perm(struct audit_context *ctx, int mask)
> > {
> > + struct open_how *openat2;
> > unsigned n;
> > if (unlikely(!ctx))
> > return 0;
> > @@ -195,6 +196,12 @@ static int audit_match_perm(struct audit_context *ctx, int mask)
> > return ((mask & AUDIT_PERM_WRITE) && ctx->argv[0] == SYS_BIND);
> > case 5: /* execve */
> > return mask & AUDIT_PERM_EXEC;
> > + case 6: /* openat2 */
> > + openat2 = ctx->argv[2];
> > + if (upper_32_bits(openat2->flags))
> > + pr_warn("Some sensible warning about unknown flags");
> > +
> > + return mask & ACC_MODE(lower_32_bits(openat2->flags));
> > default:
> > return 0;
> > }
> >
> > (Ideally we'd probably notice at build-time that we've got flags
> > exceeding 32bits. Could probably easily been done by exposing an all
> > flags macro somewhere and then we can place a BUILD_BUG_ON() or sm into
> > such places.)
open_how arguments are translated to open_flags which is limited to 32 bits.
This code is shared with the other open functions that are limited to 32 bits
in open_flags. openat2 was created to avoid the limitations of openat, so at
some point it isn't unreasonable that flags exceed 32 bits, but open_flags
would have to be modified at that point to accommodate.
This value is handed in from userspace, and could be handed in without being
defined in the kernel, so those values need to be properly checked regardless
of the flags defined in the kernel.
The openat2 syscall claims to check all flags but no check is done on the top
32 bits.
build_open_flags() assigns how->flags to an int, effectively dropping the top
32 bits, before being checked against ~VALID_OPEN_FLAGS. This happens after
audit mode filtering, but has the same result.
Audit mode filtering using ACC_MODE() already masks out all but the lowest two
bits with O_ACCMODE, so there is no danger of overflowing a u32.
tomoyo_check_open_permission() assigns ACC_MODE() to u8 without a check.
All FMODE_* flags are clamped at u32.
6 bits remain at top and 4 bits just above O_ACCMODE, so there is no immediate
danger of overflow and if any additional mode bits are needed they are
available.
000377777703 used
037777777777 available
10 bits remaining
So, I don't think a check at this point in the code is useful, but do agree
that there should be some changes and checks added in sys_openat2 and
build_open_flags().
Also noticed: It looks like fddb5d430ad9f left in VALID_UPGRADE_FLAGS for
how->upgrade_mask that was removed. This may be used at a later date, but at
this point is dead code.
> > Christian
>
> - RGB
- RGB
--
Richard Guy Briggs <rgb@redhat.com>
Sr. S/W Engineer, Kernel Security, Base Operating Systems
Remote, Ottawa, Red Hat Canada
IRC: rgb, SunRaycer
Voice: +1.647.777.2635, Internal: (81) 32635
^ permalink raw reply
* Re: [PATCH v5 16/16] of: Add plumbing for restricted DMA pool
From: Claire Chang @ 2021-04-23 2:52 UTC (permalink / raw)
To: Joerg Roedel, Will Deacon, Frank Rowand, Konrad Rzeszutek Wilk,
boris.ostrovsky, jgross, Christoph Hellwig, Marek Szyprowski
Cc: heikki.krogerus, thomas.hellstrom, peterz, joonas.lahtinen,
dri-devel, chris, grant.likely, paulus, mingo, jxgao, sstabellini,
Saravana Kannan, xypron.glpk, Rafael J . Wysocki,
Bartosz Golaszewski, bskeggs, linux-pci, xen-devel,
Thierry Reding, intel-gfx, matthew.auld, linux-devicetree, daniel,
airlied, maarten.lankhorst, linuxppc-dev, jani.nikula,
Nicolas Boichat, rodrigo.vivi, bhelgaas, Dan Williams,
Andy Shevchenko, nouveau, Greg KH, Randy Dunlap, lkml,
Tomasz Figa, list@263.net:IOMMU DRIVERS, Jim Quinlan,
Robin Murphy, bauerman
In-Reply-To: <20210422081508.3942748-17-tientzu@chromium.org>
On Thu, Apr 22, 2021 at 4:17 PM Claire Chang <tientzu@chromium.org> wrote:
>
> If a device is not behind an IOMMU, we look up the device node and set
> up the restricted DMA when the restricted-dma-pool is presented.
>
> Signed-off-by: Claire Chang <tientzu@chromium.org>
> ---
> drivers/of/address.c | 25 +++++++++++++++++++++++++
> drivers/of/device.c | 3 +++
> drivers/of/of_private.h | 5 +++++
> 3 files changed, 33 insertions(+)
>
> diff --git a/drivers/of/address.c b/drivers/of/address.c
> index 54f221dde267..fff3adfe4986 100644
> --- a/drivers/of/address.c
> +++ b/drivers/of/address.c
> @@ -8,6 +8,7 @@
> #include <linux/logic_pio.h>
> #include <linux/module.h>
> #include <linux/of_address.h>
> +#include <linux/of_reserved_mem.h>
> #include <linux/pci.h>
> #include <linux/pci_regs.h>
> #include <linux/sizes.h>
> @@ -1109,6 +1110,30 @@ bool of_dma_is_coherent(struct device_node *np)
> }
> EXPORT_SYMBOL_GPL(of_dma_is_coherent);
>
> +int of_dma_set_restricted_buffer(struct device *dev)
> +{
> + struct device_node *node;
> + int count, i;
> +
> + if (!dev->of_node)
> + return 0;
> +
> + count = of_property_count_elems_of_size(dev->of_node, "memory-region",
> + sizeof(phandle));
> + for (i = 0; i < count; i++) {
> + node = of_parse_phandle(dev->of_node, "memory-region", i);
> + /* There might be multiple memory regions, but only one
> + * restriced-dma-pool region is allowed.
> + */
> + if (of_device_is_compatible(node, "restricted-dma-pool") &&
> + of_device_is_available(node))
> + return of_reserved_mem_device_init_by_idx(
> + dev, dev->of_node, i);
> + }
> +
> + return 0;
> +}
> +
> /**
> * of_mmio_is_nonposted - Check if device uses non-posted MMIO
> * @np: device node
> diff --git a/drivers/of/device.c b/drivers/of/device.c
> index c5a9473a5fb1..d8d865223e51 100644
> --- a/drivers/of/device.c
> +++ b/drivers/of/device.c
> @@ -165,6 +165,9 @@ int of_dma_configure_id(struct device *dev, struct device_node *np,
>
> arch_setup_dma_ops(dev, dma_start, size, iommu, coherent);
>
> + if (!iommu)
> + return of_dma_set_restricted_buffer(dev);
> +
> return 0;
> }
> EXPORT_SYMBOL_GPL(of_dma_configure_id);
> diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
> index d717efbd637d..e9237f5eff48 100644
> --- a/drivers/of/of_private.h
> +++ b/drivers/of/of_private.h
> @@ -163,12 +163,17 @@ struct bus_dma_region;
> #if defined(CONFIG_OF_ADDRESS) && defined(CONFIG_HAS_DMA)
> int of_dma_get_range(struct device_node *np,
> const struct bus_dma_region **map);
> +int of_dma_set_restricted_buffer(struct device *dev);
> #else
> static inline int of_dma_get_range(struct device_node *np,
> const struct bus_dma_region **map)
> {
> return -ENODEV;
> }
> +static inline int of_dma_get_restricted_buffer(struct device *dev)
This one should be of_dma_set_restricted_buffer. Sorry for the typo.
> +{
> + return -ENODEV;
> +}
> #endif
>
> #endif /* _LINUX_OF_PRIVATE_H */
> --
> 2.31.1.368.gbe11c130af-goog
>
^ permalink raw reply
* Re: [PATCH kernel] powerpc/makefile: Do not redefine $(CPP) for preprocessor
From: Alexey Kardashevskiy @ 2021-04-23 3:06 UTC (permalink / raw)
To: Daniel Axtens, linuxppc-dev
In-Reply-To: <87mttqylho.fsf@dja-thinkpad.axtens.net>
On 23/04/2021 08:58, Daniel Axtens wrote:
> Hi Alexey,
>
>> The $(CPP) (do only preprocessing) macro is already defined in Makefile.
>> However POWERPC redefines it and adds $(KBUILD_CFLAGS) which results
>> in flags duplication. Which is not a big deal by itself except for
>> the flags which depend on other flags and the compiler checks them
>> as it parses the command line.
>>
>> Specifically, scripts/Makefile.build:304 generates ksyms for .S files.
>> If clang+llvm+sanitizer are enabled, this results in
>> -fno-lto -flto -fsanitize=cfi-mfcall .... -fno-lto -flto -fsanitize=cfi-mfcall
>
> Checkpatch doesn't like this line:
> WARNING:COMMIT_LOG_LONG_LINE: Possible unwrapped commit description (prefer a maximum 75 chars per line)
> #14:
> -fno-lto -flto -fsanitize=cfi-mfcall .... -fno-lto -flto -fsanitize=cfi-mfcall
> However, it doesn't make sense to wrap the line so we should just ignore
> checkpatch here.
>
>> in the clang command line and triggers error:
>>
>> clang-13: error: invalid argument '-fsanitize=cfi-mfcall' only allowed with '-flto'
>>
>> This removes unnecessary CPP redifinition.
>>
>> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
>> ---
>> arch/powerpc/Makefile | 1 -
>> 1 file changed, 1 deletion(-)
>>
>> diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
>> index c9d2c7825cd6..3a2f2001c62b 100644
>> --- a/arch/powerpc/Makefile
>> +++ b/arch/powerpc/Makefile
>> @@ -214,7 +214,6 @@ KBUILD_CPPFLAGS += -I $(srctree)/arch/$(ARCH) $(asinstr)
>> KBUILD_AFLAGS += $(AFLAGS-y)
>> KBUILD_CFLAGS += $(call cc-option,-msoft-float)
>> KBUILD_CFLAGS += -pipe $(CFLAGS-y)
>> -CPP = $(CC) -E $(KBUILD_CFLAGS)
>
> I was trying to check the history to see why powerpc has its own
> definition. It seems to date back at least as far as merging the two
> powerpc platforms into one, maybe it was helpful then. I agree it
> doesn't seem to be needed now.
>
> Snowpatch claims that this breaks the build, but I haven't been able to
> reproduce the issue in either pmac32 or ppc64 defconfig. I have sent it
> off to a fork of mpe's linux-ci repo to see if any of those builds hit
> any issues: https://github.com/daxtens/linux-ci/actions
To be precise, you need LLVM + LTO + byte code (-emit-llvm-bc), I am not
even sure what is the point of having -flto without -emit-llvm-bc.
No flags duplication:
[fstn1-p1 1]$ /mnt/sdb/pbuild/llvm-no-lto/bin/clang-13 -emit-llvm-bc
-fno-lto -flto -fvisibility=hidden -fsanitize=cfi-mfcall
/mnt/sdb/pbuild/llvm-bugs/1/a.c
/usr/bin/ld: warning: cannot find entry symbol mit-llvm-bc; defaulting
to 00000000100003e0
/usr/bin/ld:
/usr/lib/powerpc64le-linux-gnu/crt1.o:(.data.rel.ro.local+0x8):
undefined reference to `main'
clang-13: error: linker command failed with exit code 1 (use -v to see
invocation)
=> command line is fine, the file is not (but it is for debugging this
problem).
Now I am adding the second -fno-lto:
[fstn1-p1 1]$ /mnt/sdb/pbuild/llvm-no-lto/bin/clang-13 -emit-llvm-bc
-fno-lto -flto -fvisibility=hidden -fsanitize=cfi-mfcall -fno-lto
/mnt/sdb/pbuild/llvm-bugs/1/a.c
clang-13: error: invalid argument '-fsanitize=cfi-mfcall' only allowed
with '-flto'
=> failed.
> Assuming that doesn't break, this patch looks good to me:
> Reviewed-by: Daniel Axtens <dja@axtens.net>
>
> Kind regards,
> Daniel
>
--
Alexey
^ permalink raw reply
* [PATCH 0/4] Fix queued spinlocks and a bit more
From: Nicholas Piggin @ 2021-04-23 3:11 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Naveen N . Rao, Nicholas Piggin
Patch 1 is the important fix. 2 might fix something, although I haven't
provoked a crash yet.
Patch 3 is a small cleanup, and patch 4 I think is the right thing to do
but these could wait for later.
Thanks,
Nick
Nicholas Piggin (4):
powerpc/pseries: Fix hcall tracing recursion in pv queued spinlocks
powerpc/pseries: Don't trace hcall tracing wrapper
powerpc/pseries: use notrace hcall variant for H_CEDE idle
powerpc/pseries: warn if recursing into the hcall tracing code
arch/powerpc/include/asm/hvcall.h | 3 +++
arch/powerpc/include/asm/paravirt.h | 22 +++++++++++++++++---
arch/powerpc/include/asm/plpar_wrappers.h | 6 +++++-
arch/powerpc/platforms/pseries/hvCall.S | 10 +++++++++
arch/powerpc/platforms/pseries/lpar.c | 25 ++++++++---------------
5 files changed, 46 insertions(+), 20 deletions(-)
--
2.23.0
^ permalink raw reply
* [PATCH 1/4] powerpc/pseries: Fix hcall tracing recursion in pv queued spinlocks
From: Nicholas Piggin @ 2021-04-23 3:11 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Naveen N . Rao, Nicholas Piggin
In-Reply-To: <20210423031108.1046067-1-npiggin@gmail.com>
The paravit queued spinlock slow path adds itself to the queue then
calls pv_wait to wait for the lock to become free. This is implemented
by calling H_CONFER to donate cycles.
When hcall tracing is enabled, this H_CONFER call can lead to a spin
lock being taken in the tracing code, which will result in the lock to
be taken again, which will also go to the slow path because it queues
behind itself and so won't ever make progress.
An example trace of a deadlock:
__pv_queued_spin_lock_slowpath
trace_clock_global
ring_buffer_lock_reserve
trace_event_buffer_lock_reserve
trace_event_buffer_reserve
trace_event_raw_event_hcall_exit
__trace_hcall_exit
plpar_hcall_norets_trace
__pv_queued_spin_lock_slowpath
trace_clock_global
ring_buffer_lock_reserve
trace_event_buffer_lock_reserve
trace_event_buffer_reserve
trace_event_raw_event_rcu_dyntick
rcu_irq_exit
irq_exit
__do_irq
call_do_irq
do_IRQ
hardware_interrupt_common_virt
Fix this by introducing plpar_hcall_norets_notrace(), and using that to
make SPLPAR virtual processor dispatching hcalls by the paravirt
spinlock code.
Fixes: 20c0e8269e9d ("powerpc/pseries: Implement paravirt qspinlocks for SPLPAR")
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/include/asm/hvcall.h | 3 +++
arch/powerpc/include/asm/paravirt.h | 22 +++++++++++++++++++---
arch/powerpc/platforms/pseries/hvCall.S | 10 ++++++++++
arch/powerpc/platforms/pseries/lpar.c | 4 ++--
4 files changed, 34 insertions(+), 5 deletions(-)
diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
index ed6086d57b22..0c92b01a3c3c 100644
--- a/arch/powerpc/include/asm/hvcall.h
+++ b/arch/powerpc/include/asm/hvcall.h
@@ -446,6 +446,9 @@
*/
long plpar_hcall_norets(unsigned long opcode, ...);
+/* Variant which does not do hcall tracing */
+long plpar_hcall_norets_notrace(unsigned long opcode, ...);
+
/**
* plpar_hcall: - Make a pseries hypervisor call
* @opcode: The hypervisor call to make.
diff --git a/arch/powerpc/include/asm/paravirt.h b/arch/powerpc/include/asm/paravirt.h
index 5d1726bb28e7..3c13c2ec70a9 100644
--- a/arch/powerpc/include/asm/paravirt.h
+++ b/arch/powerpc/include/asm/paravirt.h
@@ -30,17 +30,33 @@ static inline u32 yield_count_of(int cpu)
static inline void yield_to_preempted(int cpu, u32 yield_count)
{
- plpar_hcall_norets(H_CONFER, get_hard_smp_processor_id(cpu), yield_count);
+ /*
+ * Spinlock code yields and prods, so don't trace the hcalls because
+ * tracing code takes spinlocks which could recurse.
+ *
+ * These calls are made while the lock is not held, the lock slowpath
+ * yields if it can not acquire the lock, and unlock slow path might
+ * prod if a waiter has yielded). So this did not seem to be a problem
+ * for simple spin locks because technically it didn't recuse on the
+ * lock. However the queued spin lock contended path is more strictly
+ * ordered: the H_CONFER hcall is made after the task has queued itself
+ * on the lock, so then recursing on the lock will queue up behind that
+ * (or worse: queued spinlocks uses tricks that assume a context never
+ * waits on more than one spinlock, so that may cause random
+ * corruption).
+ */
+ plpar_hcall_norets_notrace(H_CONFER,
+ get_hard_smp_processor_id(cpu), yield_count);
}
static inline void prod_cpu(int cpu)
{
- plpar_hcall_norets(H_PROD, get_hard_smp_processor_id(cpu));
+ plpar_hcall_norets_notrace(H_PROD, get_hard_smp_processor_id(cpu));
}
static inline void yield_to_any(void)
{
- plpar_hcall_norets(H_CONFER, -1, 0);
+ plpar_hcall_norets_notrace(H_CONFER, -1, 0);
}
#else
static inline bool is_shared_processor(void)
diff --git a/arch/powerpc/platforms/pseries/hvCall.S b/arch/powerpc/platforms/pseries/hvCall.S
index 2136e42833af..8a2b8d64265b 100644
--- a/arch/powerpc/platforms/pseries/hvCall.S
+++ b/arch/powerpc/platforms/pseries/hvCall.S
@@ -102,6 +102,16 @@ END_FTR_SECTION(0, 1); \
#define HCALL_BRANCH(LABEL)
#endif
+_GLOBAL_TOC(plpar_hcall_norets_notrace)
+ HMT_MEDIUM
+
+ mfcr r0
+ stw r0,8(r1)
+ HVSC /* invoke the hypervisor */
+ lwz r0,8(r1)
+ mtcrf 0xff,r0
+ blr /* return r3 = status */
+
_GLOBAL_TOC(plpar_hcall_norets)
HMT_MEDIUM
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index 3805519a6469..6011b7b80946 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -1828,8 +1828,8 @@ void hcall_tracepoint_unregfunc(void)
/*
* Since the tracing code might execute hcalls we need to guard against
- * recursion. One example of this are spinlocks calling H_YIELD on
- * shared processor partitions.
+ * recursion. H_CONFER from spin locks must be treated separately though
+ * and use _notrace plpar_hcall variants, see yield_to_preempted().
*/
static DEFINE_PER_CPU(unsigned int, hcall_trace_depth);
--
2.23.0
^ permalink raw reply related
* [PATCH 2/4] powerpc/pseries: Don't trace hcall tracing wrapper
From: Nicholas Piggin @ 2021-04-23 3:11 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Naveen N . Rao, Nicholas Piggin
In-Reply-To: <20210423031108.1046067-1-npiggin@gmail.com>
This doesn't seem very useful to trace before the recursion check, even
if the ftrace code has any recursion checks of its own. Be on the safe
side and don't trace the hcall trace wrappers.
Reported-by: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/platforms/pseries/lpar.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index 6011b7b80946..0641779e5cde 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -1834,7 +1834,7 @@ void hcall_tracepoint_unregfunc(void)
static DEFINE_PER_CPU(unsigned int, hcall_trace_depth);
-void __trace_hcall_entry(unsigned long opcode, unsigned long *args)
+notrace void __trace_hcall_entry(unsigned long opcode, unsigned long *args)
{
unsigned long flags;
unsigned int *depth;
@@ -1862,7 +1862,7 @@ void __trace_hcall_entry(unsigned long opcode, unsigned long *args)
local_irq_restore(flags);
}
-void __trace_hcall_exit(long opcode, long retval, unsigned long *retbuf)
+notrace void __trace_hcall_exit(long opcode, long retval, unsigned long *retbuf)
{
unsigned long flags;
unsigned int *depth;
--
2.23.0
^ permalink raw reply related
* [PATCH 3/4] powerpc/pseries: use notrace hcall variant for H_CEDE idle
From: Nicholas Piggin @ 2021-04-23 3:11 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Naveen N . Rao, Nicholas Piggin
In-Reply-To: <20210423031108.1046067-1-npiggin@gmail.com>
Rather than special-case H_CEDE in the hcall trace wrappers, make the
idle H_CEDE call use plpar_hcall_norets_notrace().
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/include/asm/plpar_wrappers.h | 6 +++++-
arch/powerpc/platforms/pseries/lpar.c | 10 ----------
2 files changed, 5 insertions(+), 11 deletions(-)
diff --git a/arch/powerpc/include/asm/plpar_wrappers.h b/arch/powerpc/include/asm/plpar_wrappers.h
index ece84a430701..83e0f701ebc6 100644
--- a/arch/powerpc/include/asm/plpar_wrappers.h
+++ b/arch/powerpc/include/asm/plpar_wrappers.h
@@ -28,7 +28,11 @@ static inline void set_cede_latency_hint(u8 latency_hint)
static inline long cede_processor(void)
{
- return plpar_hcall_norets(H_CEDE);
+ /*
+ * We cannot call tracepoints inside RCU idle regions which
+ * means we must not trace H_CEDE.
+ */
+ return plpar_hcall_norets_notrace(H_CEDE);
}
static inline long extended_cede_processor(unsigned long latency_hint)
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index 0641779e5cde..835e7f661a05 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -1839,13 +1839,6 @@ notrace void __trace_hcall_entry(unsigned long opcode, unsigned long *args)
unsigned long flags;
unsigned int *depth;
- /*
- * We cannot call tracepoints inside RCU idle regions which
- * means we must not trace H_CEDE.
- */
- if (opcode == H_CEDE)
- return;
-
local_irq_save(flags);
depth = this_cpu_ptr(&hcall_trace_depth);
@@ -1867,9 +1860,6 @@ notrace void __trace_hcall_exit(long opcode, long retval, unsigned long *retbuf)
unsigned long flags;
unsigned int *depth;
- if (opcode == H_CEDE)
- return;
-
local_irq_save(flags);
depth = this_cpu_ptr(&hcall_trace_depth);
--
2.23.0
^ permalink raw reply related
* [PATCH 4/4] powerpc/pseries: warn if recursing into the hcall tracing code
From: Nicholas Piggin @ 2021-04-23 3:11 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Naveen N . Rao, Nicholas Piggin
In-Reply-To: <20210423031108.1046067-1-npiggin@gmail.com>
---
arch/powerpc/platforms/pseries/lpar.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index 835e7f661a05..a961a7ebeab3 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -1828,8 +1828,11 @@ void hcall_tracepoint_unregfunc(void)
/*
* Since the tracing code might execute hcalls we need to guard against
- * recursion. H_CONFER from spin locks must be treated separately though
- * and use _notrace plpar_hcall variants, see yield_to_preempted().
+ * recursion, but this always seems risky -- __trace_hcall_entry might be
+ * ftraced, for example. So warn in this case.
+ *
+ * H_CONFER from spin locks must be treated separately though and use _notrace
+ * plpar_hcall variants, see yield_to_preempted().
*/
static DEFINE_PER_CPU(unsigned int, hcall_trace_depth);
@@ -1843,7 +1846,7 @@ notrace void __trace_hcall_entry(unsigned long opcode, unsigned long *args)
depth = this_cpu_ptr(&hcall_trace_depth);
- if (*depth)
+ if (WARN_ON_ONCE(*depth))
goto out;
(*depth)++;
@@ -1864,7 +1867,7 @@ notrace void __trace_hcall_exit(long opcode, long retval, unsigned long *retbuf)
depth = this_cpu_ptr(&hcall_trace_depth);
- if (*depth)
+ if (*depth) /* Don't warning again on the way out */
goto out;
(*depth)++;
--
2.23.0
^ permalink raw reply related
* [powerpc:next] BUILD SUCCESS ee6b25fa7c037e42cc5f3b5c024b2a779edab6dd
From: kernel test robot @ 2021-04-23 3:56 UTC (permalink / raw)
To: Michael Ellerman; +Cc: linuxppc-dev
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git next
branch HEAD: ee6b25fa7c037e42cc5f3b5c024b2a779edab6dd powerpc/44x: fix spelling mistake in Kconfig "varients" -> "variants"
elapsed time: 725m
configs tested: 148
configs skipped: 3
The following configs have been built successfully.
More configs may be tested in the coming days.
gcc tested configs:
arm defconfig
arm64 allyesconfig
arm64 defconfig
arm allyesconfig
arm allmodconfig
x86_64 allyesconfig
riscv allmodconfig
riscv allyesconfig
i386 allyesconfig
mips jazz_defconfig
mips malta_qemu_32r6_defconfig
sh apsh4ad0a_defconfig
arm mvebu_v7_defconfig
arm lpc32xx_defconfig
arc nsimosci_defconfig
arm spitz_defconfig
xtensa audio_kc705_defconfig
powerpc acadia_defconfig
powerpc ep88xc_defconfig
arc axs103_smp_defconfig
powerpc linkstation_defconfig
arm s5pv210_defconfig
sparc sparc32_defconfig
sh ul2_defconfig
mips tb0287_defconfig
powerpc ebony_defconfig
powerpc canyonlands_defconfig
powerpc ppa8548_defconfig
arm eseries_pxa_defconfig
parisc alldefconfig
powerpc mgcoge_defconfig
mips omega2p_defconfig
arm exynos_defconfig
powerpc obs600_defconfig
sh edosk7760_defconfig
powerpc stx_gp3_defconfig
sh se7724_defconfig
arm pcm027_defconfig
arm magician_defconfig
ia64 zx1_defconfig
mips maltasmvp_defconfig
arm sama5_defconfig
mips cu1000-neo_defconfig
arm u8500_defconfig
sh se7343_defconfig
mips ip32_defconfig
sh kfr2r09_defconfig
sh sh7763rdp_defconfig
csky alldefconfig
powerpc kmeter1_defconfig
powerpc iss476-smp_defconfig
powerpc maple_defconfig
sh se7751_defconfig
m68k mac_defconfig
mips sb1250_swarm_defconfig
powerpc walnut_defconfig
powerpc rainier_defconfig
arm stm32_defconfig
powerpc mpc83xx_defconfig
arm trizeps4_defconfig
powerpc ps3_defconfig
arm vt8500_v6_v7_defconfig
nios2 3c120_defconfig
arm gemini_defconfig
arm dove_defconfig
arm neponset_defconfig
um x86_64_defconfig
ia64 allmodconfig
ia64 defconfig
ia64 allyesconfig
m68k allmodconfig
m68k defconfig
m68k allyesconfig
nios2 defconfig
arc allyesconfig
nds32 allnoconfig
nds32 defconfig
nios2 allyesconfig
csky defconfig
alpha defconfig
alpha allyesconfig
xtensa allyesconfig
h8300 allyesconfig
arc defconfig
sh allmodconfig
parisc defconfig
s390 allyesconfig
s390 allmodconfig
parisc allyesconfig
s390 defconfig
sparc allyesconfig
sparc defconfig
i386 defconfig
mips allyesconfig
mips allmodconfig
powerpc allyesconfig
powerpc allmodconfig
powerpc allnoconfig
x86_64 randconfig-a004-20210421
x86_64 randconfig-a002-20210421
x86_64 randconfig-a001-20210421
x86_64 randconfig-a005-20210421
x86_64 randconfig-a006-20210421
x86_64 randconfig-a003-20210421
i386 randconfig-a005-20210421
i386 randconfig-a002-20210421
i386 randconfig-a001-20210421
i386 randconfig-a006-20210421
i386 randconfig-a004-20210421
i386 randconfig-a003-20210421
i386 randconfig-a012-20210421
i386 randconfig-a014-20210421
i386 randconfig-a011-20210421
i386 randconfig-a013-20210421
i386 randconfig-a015-20210421
i386 randconfig-a016-20210421
i386 randconfig-a014-20210422
i386 randconfig-a012-20210422
i386 randconfig-a011-20210422
i386 randconfig-a013-20210422
i386 randconfig-a015-20210422
i386 randconfig-a016-20210422
riscv nommu_k210_defconfig
riscv nommu_virt_defconfig
riscv allnoconfig
riscv defconfig
riscv rv32_defconfig
um allmodconfig
um allnoconfig
um allyesconfig
um defconfig
x86_64 rhel-8.3-kselftests
x86_64 defconfig
x86_64 rhel-8.3
x86_64 rhel-8.3-kbuiltin
x86_64 kexec
clang tested configs:
x86_64 randconfig-a015-20210421
x86_64 randconfig-a016-20210421
x86_64 randconfig-a011-20210421
x86_64 randconfig-a014-20210421
x86_64 randconfig-a013-20210421
x86_64 randconfig-a012-20210421
x86_64 randconfig-a002-20210422
x86_64 randconfig-a004-20210422
x86_64 randconfig-a001-20210422
x86_64 randconfig-a005-20210422
x86_64 randconfig-a006-20210422
x86_64 randconfig-a003-20210422
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
^ permalink raw reply
* Re: [PATCH 7/7] swiotlb: don't override the command line in swiotlb_adjust_size
From: Tom Lendacky @ 2021-04-23 5:23 UTC (permalink / raw)
To: Christoph Hellwig, Konrad Rzeszutek Wilk
Cc: Juergen Gross, Thomas Bogendoerfer, linux-mips, iommu,
Stefano Stabellini, xen-devel, Boris Ostrovsky, linuxppc-dev
In-Reply-To: <20210422071921.1428607-8-hch@lst.de>
On 4/22/21 2:19 AM, Christoph Hellwig wrote:
> When the user specified an explicit swiotlb size on the command line,
> the achitecture code should not override it.
>
> Fixes: 2cbc2776efe4 ("swiotlb: remove swiotlb_nr_tbl")
> Reported-by: Tom Lendacky <thomas.lendacky@amd.com>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
I tested this patchset and I'm not able to get the override via the
command line or via the SEV adjustment function. Looking at the code,
swiotlb_default_size is initialized, so the call to swiotlb_adjust_size()
always returns without setting the new size.
Thanks,
Tom
> ---
> kernel/dma/swiotlb.c | 6 +++++-
> 1 file changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c
> index 87d06ddf4753f3..aef02a3825b494 100644
> --- a/kernel/dma/swiotlb.c
> +++ b/kernel/dma/swiotlb.c
> @@ -106,7 +106,9 @@ void swiotlb_set_max_segment(unsigned int val)
>
> unsigned long swiotlb_size_or_default(void)
> {
> - return swiotlb_default_size;
> + if (swiotlb_default_size)
> + return swiotlb_default_size;
> + return IO_TLB_DEFAULT_SIZE;
> }
>
> void __init swiotlb_adjust_size(unsigned long size)
> @@ -116,6 +118,8 @@ void __init swiotlb_adjust_size(unsigned long size)
> * architectures such as those supporting memory encryption to
> * adjust/expand SWIOTLB size for their use.
> */
> + if (swiotlb_default_size)
> + return;
> swiotlb_default_size = ALIGN(size, IO_TLB_SEGSIZE << IO_TLB_SHIFT);
> pr_info("SWIOTLB bounce buffer size adjusted to %luMB",
> swiotlb_default_size >> 20);
>
^ permalink raw reply
* Re: [PATCH kernel] powerpc/makefile: Do not redefine $(CPP) for preprocessor
From: Christophe Leroy @ 2021-04-23 5:27 UTC (permalink / raw)
To: Daniel Axtens, Alexey Kardashevskiy, linuxppc-dev
In-Reply-To: <87mttqylho.fsf@dja-thinkpad.axtens.net>
Le 23/04/2021 à 00:58, Daniel Axtens a écrit :
>> diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
>> index c9d2c7825cd6..3a2f2001c62b 100644
>> --- a/arch/powerpc/Makefile
>> +++ b/arch/powerpc/Makefile
>> @@ -214,7 +214,6 @@ KBUILD_CPPFLAGS += -I $(srctree)/arch/$(ARCH) $(asinstr)
>> KBUILD_AFLAGS += $(AFLAGS-y)
>> KBUILD_CFLAGS += $(call cc-option,-msoft-float)
>> KBUILD_CFLAGS += -pipe $(CFLAGS-y)
>> -CPP = $(CC) -E $(KBUILD_CFLAGS)
>
> I was trying to check the history to see why powerpc has its own
> definition. It seems to date back at least as far as merging the two
> powerpc platforms into one, maybe it was helpful then. I agree it
> doesn't seem to be needed now.
>
I digged a bit deaper. It has been there since the introduction of arch/ppc/ in Linux 1.3.45
At the time, there was the exact same CPP definition in arch/mips/Makefile
The CPP definition in mips disappeared is Linux 2.1.44pre3.
Since that version, ppc has been the only one with such CPP re-definition.
> Snowpatch claims that this breaks the build, but I haven't been able to
> reproduce the issue in either pmac32 or ppc64 defconfig. I have sent it
> off to a fork of mpe's linux-ci repo to see if any of those builds hit
> any issues: https://github.com/daxtens/linux-ci/actions
>
By the way, I find snowpatch quite useless these days. It seems to delete the reports a few minutes
after the test. We are less than one day after the patch was submitted and the report of the build
failures are already gone.
Christophe
^ permalink raw reply
* [PATCH 1/2] ASoC: imx-akcodec: Add imx-akcodec machine driver
From: Shengjiu Wang @ 2021-04-23 5:51 UTC (permalink / raw)
To: lgirdwood, broonie, perex, tiwai, timur, nicoleotsuka, Xiubo.Lee,
festevam, shawnguo, s.hauer, kernel, linux-imx, linux-kernel,
alsa-devel, linuxppc-dev, linux-arm-kernel, robh+dt, devicetree
Add machine driver for i.MX boards that have
AK4458/AK5558/AK4497/AK5552 DAC/ADC attached to
SAI interface.
Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
Signed-off-by: Mihai Serban <mihai.serban@nxp.com>
Signed-off-by: Cosmin-Gabriel Samoila <cosmin.samoila@nxp.com>
Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
Signed-off-by: Adrian Alonso <adrian.alonso@nxp.com>
---
sound/soc/fsl/Kconfig | 12 +
sound/soc/fsl/Makefile | 2 +
sound/soc/fsl/imx-akcodec.c | 868 ++++++++++++++++++++++++++++++++++++
3 files changed, 882 insertions(+)
create mode 100644 sound/soc/fsl/imx-akcodec.c
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 0917d65d6921..5720ad36494f 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -350,6 +350,18 @@ config SND_SOC_IMX_RPMSG
Say Y if you want to add support for SoC audio on an i.MX board with
a rpmsg devices.
+config SND_SOC_IMX_AKCODEC
+ tristate "SoC Audio support for i.MX boards with AKCODEC"
+ depends on OF && I2C
+ select SND_SOC_AK4458
+ select SND_SOC_AK5558
+ select SND_SOC_IMX_PCM_DMA
+ select SND_SOC_FSL_SAI
+ help
+ SoC Audio support for i.MX boards with AK4458/AK4497/AK5558/AK5552
+ Say Y if you want to add support for SoC audio on an i.MX board with
+ an AK4458/AK4497/AK5558/AK5552 DAC/ADC.
+
endif # SND_IMX_SOC
endmenu
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index f146ce464acd..ee7caed0c758 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -71,6 +71,7 @@ snd-soc-imx-spdif-objs := imx-spdif.o
snd-soc-imx-audmix-objs := imx-audmix.o
snd-soc-imx-hdmi-objs := imx-hdmi.o
snd-soc-imx-rpmsg-objs := imx-rpmsg.o
+snd-soc-imx-akcodec-objs := imx-akcodec.o
obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
obj-$(CONFIG_SND_SOC_IMX_ES8328) += snd-soc-imx-es8328.o
@@ -79,3 +80,4 @@ obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o
obj-$(CONFIG_SND_SOC_IMX_AUDMIX) += snd-soc-imx-audmix.o
obj-$(CONFIG_SND_SOC_IMX_HDMI) += snd-soc-imx-hdmi.o
obj-$(CONFIG_SND_SOC_IMX_RPMSG) += snd-soc-imx-rpmsg.o
+obj-$(CONFIG_SND_SOC_IMX_AKCODEC) += snd-soc-imx-akcodec.o
diff --git a/sound/soc/fsl/imx-akcodec.c b/sound/soc/fsl/imx-akcodec.c
new file mode 100644
index 000000000000..606365f79a54
--- /dev/null
+++ b/sound/soc/fsl/imx-akcodec.c
@@ -0,0 +1,868 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright 2017-2021 NXP
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of_device.h>
+#include <linux/i2c.h>
+#include <linux/of_gpio.h>
+#include <linux/clk.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#include <sound/pcm.h>
+#include <sound/soc-dapm.h>
+
+#include "fsl_sai.h"
+
+#define MAX_CODECS 2
+
+enum codec_type {
+ CODEC_AK5558 = 1,
+ CODEC_AK4458,
+ CODEC_AK4497,
+ CODEC_AK5552,
+};
+
+/*
+ * Mapping LRCK fs and frame width, table 3 & 4 in datasheet
+ * @rmin: min rate
+ * @rmax: max rate
+ * @wmin: min frame ratio
+ * @wmax: max frame ratio
+ */
+struct imx_akcodec_fs_mul {
+ unsigned int rmin;
+ unsigned int rmax;
+ unsigned int wmin;
+ unsigned int wmax;
+};
+
+/*
+ * Mapping TDM mode and frame width
+ */
+struct imx_akcodec_tdm_fs_mul {
+ unsigned int min;
+ unsigned int max;
+ unsigned int mul;
+};
+
+/*
+ * struct imx_akcodec_plat_data - specific info for codecs
+ *
+ * @fs_mul: ratio of mclk/fs for normal mode
+ * @tdm_fs_mul: ratio of mclk/fs for tdm mode
+ * @support_rates: supported sample rate
+ * @support_tdm_rates: supported sample rate for tdm mode
+ * @support_channels: supported channels
+ * @support_tdm_channels: supported channels for tdm mode
+ * @num_fs_mul: ARRAY_SIZE of fs_mul
+ * @num_tdm_fs_mul: ARRAY_SIZE of tdm_fs_mul
+ * @num_rates: ARRAY_SIZE of support_rates
+ * @num_tdm_rates: ARRAY_SIZE of support_tdm_rates
+ * @num_channels: ARRAY_SIZE of support_channels
+ * @num_tdm_channels: ARRAY_SIZE of support_tdm_channels
+ * @num_codecs: codec number, maximum is MAX_CODECS
+ * @playback_only: only playback supported
+ * @capture_only: only capture supported
+ * @one2one_ratio: if mclk/bclk = 1 or not
+ * @tdm_is_support: if this codec support tdm
+ * @type: codec type
+ * @dai_name: codec dai name
+ */
+struct imx_akcodec_plat_data {
+ struct imx_akcodec_fs_mul *fs_mul;
+ struct imx_akcodec_tdm_fs_mul *tdm_fs_mul;
+ const u32 *support_rates;
+ const u32 *support_tdm_rates;
+ const u32 *support_channels;
+ const u32 *support_tdm_channels;
+ unsigned int num_fs_mul;
+ unsigned int num_tdm_fs_mul;
+ unsigned int num_rates;
+ unsigned int num_tdm_rates;
+ unsigned int num_channels;
+ unsigned int num_tdm_channels;
+ unsigned int num_codecs;
+ unsigned int playback_only;
+ unsigned int capture_only;
+ bool one2one_ratio;
+ bool tdm_is_support;
+ enum codec_type type;
+ const char *dai_name;
+};
+
+/*
+ * struct imx_akcodec_data - platform device data
+ *
+ * @card: card instance
+ * @codec_conf: pointer of codec conf
+ * @plat_data: pointer of imx_akcodec_plat_data
+ * @dai_link: snd_soc_dai_link
+ * @codecs: codec dai link component
+ * @dapm_routes: pointer of dapm_routes
+ * @asrc_pdev: pointer of asrc_pdev
+ * @num_codec_conf: number of codec conf
+ * @num_dapm_routes: number of dapm_routes
+ * @slots: slots value
+ * @slot_width: slot width value
+ * @tdm_mode: tdm mode enabled or not
+ * @asrc_rate: asrc rates
+ * @asrc_format: asrc format
+ */
+struct imx_akcodec_data {
+ struct snd_soc_card card;
+ struct snd_soc_codec_conf *codec_conf;
+ const struct imx_akcodec_plat_data *plat_data;
+ struct snd_soc_dai_link dai_link[3];
+ struct snd_soc_dai_link_component codecs[MAX_CODECS];
+ struct snd_soc_dapm_route *dapm_routes;
+ struct platform_device *asrc_pdev;
+ int num_codec_conf;
+ int num_dapm_routes;
+ unsigned int slots;
+ unsigned int slot_width;
+ bool tdm_mode;
+ u32 asrc_rate;
+ u32 asrc_format;
+};
+
+struct imx_akcodec_fs_mul ak4458_fs_mul[] = {
+ /* Normal, < 32kHz */
+ { .rmin = 8000, .rmax = 24000, .wmin = 1024, .wmax = 1024, },
+ /* Normal, 32kHz */
+ { .rmin = 32000, .rmax = 32000, .wmin = 256, .wmax = 1024, },
+ /* Normal */
+ { .rmin = 44100, .rmax = 48000, .wmin = 256, .wmax = 768, },
+ /* Double */
+ { .rmin = 88200, .rmax = 96000, .wmin = 256, .wmax = 512, },
+ /* Quad */
+ { .rmin = 176400, .rmax = 192000, .wmin = 128, .wmax = 256, },
+ /* Oct */
+ { .rmin = 352800, .rmax = 384000, .wmin = 32, .wmax = 128, },
+ /* Hex */
+ { .rmin = 705600, .rmax = 768000, .wmin = 16, .wmax = 64, },
+};
+
+struct imx_akcodec_tdm_fs_mul ak4458_tdm_fs_mul[] = {
+ /*
+ * Table 13 - Audio Interface Format
+ * For TDM mode, MCLK should is set to
+ * obtained from 2 * slots * slot_width
+ */
+ { .min = 128, .max = 128, .mul = 256 }, /* TDM128 */
+ { .min = 256, .max = 256, .mul = 512 }, /* TDM256 */
+ { .min = 512, .max = 512, .mul = 1024 }, /* TDM512 */
+};
+
+struct imx_akcodec_fs_mul ak4497_fs_mul[] = {
+ /**
+ * Table 7 - mapping multiplier and speed mode
+ * Tables 8 & 9 - mapping speed mode and LRCK fs
+ */
+ { .rmin = 8000, .rmax = 32000, .wmin = 1024, .wmax = 1024, }, /* Normal, <= 32kHz */
+ { .rmin = 44100, .rmax = 48000, .wmin = 512, .wmax = 512, }, /* Normal */
+ { .rmin = 88200, .rmax = 96000, .wmin = 256, .wmax = 256, }, /* Double */
+ { .rmin = 176400, .rmax = 192000, .wmin = 128, .wmax = 128, }, /* Quad */
+ { .rmin = 352800, .rmax = 384000, .wmin = 128, .wmax = 128, }, /* Oct */
+ { .rmin = 705600, .rmax = 768000, .wmin = 64, .wmax = 64, }, /* Hex */
+};
+
+/*
+ * Auto MCLK selection based on LRCK for Normal Mode
+ * (Table 4 from datasheet)
+ */
+struct imx_akcodec_fs_mul ak5558_fs_mul[] = {
+ { .rmin = 8000, .rmax = 32000, .wmin = 1024, .wmax = 1024, },
+ { .rmin = 44100, .rmax = 48000, .wmin = 512, .wmax = 512, },
+ { .rmin = 88200, .rmax = 96000, .wmin = 256, .wmax = 256, },
+ { .rmin = 176400, .rmax = 192000, .wmin = 128, .wmax = 128, },
+ { .rmin = 352800, .rmax = 384000, .wmin = 64, .wmax = 64, },
+ { .rmin = 705600, .rmax = 768000, .wmin = 32, .wmax = 32, },
+};
+
+/*
+ * MCLK and BCLK selection based on TDM mode
+ * because of SAI we also add the restriction: MCLK >= 2 * BCLK
+ * (Table 9 from datasheet)
+ */
+struct imx_akcodec_tdm_fs_mul ak5558_tdm_fs_mul[] = {
+ { .min = 128, .max = 128, .mul = 256 },
+ { .min = 256, .max = 256, .mul = 512 },
+ { .min = 512, .max = 512, .mul = 1024 },
+};
+
+static const u32 akcodec_rates[] = {
+ 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200,
+ 96000, 176400, 192000, 352800, 384000, 705600, 768000,
+};
+
+static const u32 akcodec_tdm_rates[] = {
+ 8000, 16000, 32000, 48000, 96000,
+};
+
+static const u32 ak4458_channels[] = {
+ 1, 2, 4, 6, 8, 10, 12, 14, 16,
+};
+
+static const u32 ak4458_tdm_channels[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 16,
+};
+
+static const u32 ak5558_channels[] = {
+ 1, 2, 4, 6, 8,
+};
+
+static const u32 ak5558_tdm_channels[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8,
+};
+
+static const struct imx_akcodec_plat_data imx8mq_ak4458 = {
+ .fs_mul = ak4458_fs_mul,
+ .num_fs_mul = ARRAY_SIZE(ak4458_fs_mul),
+ .tdm_fs_mul = ak4458_tdm_fs_mul,
+ .num_tdm_fs_mul = ARRAY_SIZE(ak4458_tdm_fs_mul),
+ .support_rates = akcodec_rates,
+ .num_rates = ARRAY_SIZE(akcodec_rates),
+ .support_tdm_rates = akcodec_tdm_rates,
+ .num_tdm_rates = ARRAY_SIZE(akcodec_tdm_rates),
+ .support_channels = ak4458_channels,
+ .num_channels = ARRAY_SIZE(ak4458_channels),
+ .support_tdm_channels = ak4458_tdm_channels,
+ .num_tdm_channels = ARRAY_SIZE(ak4458_tdm_channels),
+ .one2one_ratio = false,
+ .dai_name = "ak4458-aif",
+ .num_codecs = MAX_CODECS,
+ .tdm_is_support = true,
+ .playback_only = 1,
+ .capture_only = 0,
+ .type = CODEC_AK4458,
+};
+
+static const struct imx_akcodec_plat_data imx_ak4458 = {
+ .fs_mul = ak4458_fs_mul,
+ .num_fs_mul = ARRAY_SIZE(ak4458_fs_mul),
+ .tdm_fs_mul = ak4458_tdm_fs_mul,
+ .num_tdm_fs_mul = ARRAY_SIZE(ak4458_tdm_fs_mul),
+ .support_rates = akcodec_rates,
+ .num_rates = ARRAY_SIZE(akcodec_rates),
+ .support_tdm_rates = akcodec_tdm_rates,
+ .num_tdm_rates = ARRAY_SIZE(akcodec_tdm_rates),
+ .support_channels = ak4458_channels,
+ .num_channels = ARRAY_SIZE(ak4458_channels),
+ .support_tdm_channels = ak4458_tdm_channels,
+ .num_tdm_channels = ARRAY_SIZE(ak4458_tdm_channels),
+ .one2one_ratio = true,
+ .dai_name = "ak4458-aif",
+ .num_codecs = MAX_CODECS,
+ .tdm_is_support = true,
+ .playback_only = 1,
+ .capture_only = 0,
+ .type = CODEC_AK4458,
+};
+
+static const struct imx_akcodec_plat_data imx8mq_ak4497 = {
+ .fs_mul = ak4497_fs_mul,
+ .num_fs_mul = ARRAY_SIZE(ak4497_fs_mul),
+ .support_rates = akcodec_rates,
+ .num_rates = ARRAY_SIZE(akcodec_rates),
+ .support_channels = ak4458_channels,
+ .num_channels = ARRAY_SIZE(ak4458_channels),
+ .one2one_ratio = false,
+ .dai_name = "ak4497-aif",
+ .num_codecs = 1,
+ .tdm_is_support = false,
+ .playback_only = 1,
+ .capture_only = 0,
+ .type = CODEC_AK4497,
+};
+
+static const struct imx_akcodec_plat_data imx_ak4497 = {
+ .fs_mul = ak4497_fs_mul,
+ .num_fs_mul = ARRAY_SIZE(ak4497_fs_mul),
+ .support_rates = akcodec_rates,
+ .num_rates = ARRAY_SIZE(akcodec_rates),
+ .support_channels = ak4458_channels,
+ .num_channels = ARRAY_SIZE(ak4458_channels),
+ .one2one_ratio = true,
+ .dai_name = "ak4497-aif",
+ .num_codecs = 1,
+ .tdm_is_support = false,
+ .playback_only = 1,
+ .capture_only = 0,
+ .type = CODEC_AK4497,
+};
+
+static const struct imx_akcodec_plat_data imx8mq_ak5558 = {
+ .fs_mul = ak5558_fs_mul,
+ .num_fs_mul = ARRAY_SIZE(ak5558_fs_mul),
+ .tdm_fs_mul = ak5558_tdm_fs_mul,
+ .num_tdm_fs_mul = ARRAY_SIZE(ak5558_tdm_fs_mul),
+ .support_rates = akcodec_rates,
+ .num_rates = ARRAY_SIZE(akcodec_rates),
+ .support_tdm_rates = akcodec_tdm_rates,
+ .num_tdm_rates = ARRAY_SIZE(akcodec_tdm_rates),
+ .support_channels = ak5558_channels,
+ .num_channels = ARRAY_SIZE(ak5558_channels),
+ .support_tdm_channels = ak5558_tdm_channels,
+ .num_tdm_channels = ARRAY_SIZE(ak5558_tdm_channels),
+ .one2one_ratio = false,
+ .dai_name = "ak5558-aif",
+ .num_codecs = 1,
+ .tdm_is_support = true,
+ .playback_only = 0,
+ .capture_only = 1,
+ .type = CODEC_AK5558,
+};
+
+static const struct imx_akcodec_plat_data imx_ak5558 = {
+ .fs_mul = ak5558_fs_mul,
+ .num_fs_mul = ARRAY_SIZE(ak5558_fs_mul),
+ .tdm_fs_mul = ak5558_tdm_fs_mul,
+ .num_tdm_fs_mul = ARRAY_SIZE(ak5558_tdm_fs_mul),
+ .support_rates = akcodec_rates,
+ .num_rates = ARRAY_SIZE(akcodec_rates),
+ .support_tdm_rates = akcodec_tdm_rates,
+ .num_tdm_rates = ARRAY_SIZE(akcodec_tdm_rates),
+ .support_channels = ak5558_channels,
+ .num_channels = ARRAY_SIZE(ak5558_channels),
+ .support_tdm_channels = ak5558_tdm_channels,
+ .num_tdm_channels = ARRAY_SIZE(ak5558_tdm_channels),
+ .one2one_ratio = true,
+ .dai_name = "ak5558-aif",
+ .num_codecs = 1,
+ .tdm_is_support = true,
+ .playback_only = 0,
+ .capture_only = 1,
+ .type = CODEC_AK5558,
+};
+
+static bool format_is_dsd(struct snd_pcm_hw_params *params)
+{
+ snd_pcm_format_t format = params_format(params);
+
+ switch (format) {
+ case SNDRV_PCM_FORMAT_DSD_U8:
+ case SNDRV_PCM_FORMAT_DSD_U16_LE:
+ case SNDRV_PCM_FORMAT_DSD_U16_BE:
+ case SNDRV_PCM_FORMAT_DSD_U32_LE:
+ case SNDRV_PCM_FORMAT_DSD_U32_BE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static struct snd_soc_dapm_widget imx_akcodec_dapm_widgets[] = {
+ SND_SOC_DAPM_LINE("Line Out", NULL),
+ SND_SOC_DAPM_LINE("Line In", NULL),
+};
+
+static unsigned long akcodec_get_mclk_rate(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct imx_akcodec_data *data = snd_soc_card_get_drvdata(rtd->card);
+ const struct imx_akcodec_plat_data *plat_data = data->plat_data;
+ unsigned int width = data->slots * data->slot_width;
+ unsigned int rate = params_rate(params);
+ int i;
+
+ if (data->tdm_mode) {
+ for (i = 0; i < plat_data->num_tdm_fs_mul; i++) {
+ /* min = max = slots * slots_width */
+ if (width != plat_data->tdm_fs_mul[i].min)
+ continue;
+ return rate * plat_data->tdm_fs_mul[i].mul;
+ }
+ } else {
+ for (i = 0; i < plat_data->num_fs_mul; i++) {
+ if (rate >= plat_data->fs_mul[i].rmin &&
+ rate <= plat_data->fs_mul[i].rmax) {
+ width = max(width, plat_data->fs_mul[i].wmin);
+ width = min(width, plat_data->fs_mul[i].wmax);
+
+ /* Adjust SAI bclk:mclk ratio */
+ width *= plat_data->one2one_ratio ? 1 : 2;
+
+ return rate * width;
+ }
+ }
+ }
+
+ /* Let DAI manage clk frequency by default */
+ return 0;
+}
+
+static int imx_aif_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_card *card = rtd->card;
+ struct imx_akcodec_data *data = snd_soc_card_get_drvdata(card);
+ unsigned int fmt = SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ bool is_dsd = format_is_dsd(params);
+ struct device *dev = card->dev;
+ unsigned long mclk_freq;
+ int ret, i;
+
+ if (is_dsd) {
+ data->slots = 1;
+ data->slot_width = params_width(params);
+ fmt |= SND_SOC_DAIFMT_PDM;
+ } else if (data->tdm_mode) {
+ data->slots = 8;
+ data->slot_width = 32;
+ fmt |= SND_SOC_DAIFMT_DSP_B;
+ } else {
+ data->slots = 2;
+ data->slot_width = params_physical_width(params);
+ fmt |= SND_SOC_DAIFMT_I2S;
+ }
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+ if (ret) {
+ dev_err(dev, "failed to set cpu dai fmt: %d\n", ret);
+ return ret;
+ }
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai,
+ BIT(data->slots) - 1,
+ BIT(data->slots) - 1,
+ data->slots, data->slot_width);
+ if (ret) {
+ dev_err(dev, "failed to set cpu dai tdm slot: %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < rtd->num_codecs; i++) {
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, i);
+
+ ret = snd_soc_dai_set_fmt(codec_dai, fmt);
+ if (ret) {
+ dev_err(dev, "failed to set codec dai[%d] fmt: %d\n", i, ret);
+ return ret;
+ }
+ ret = snd_soc_dai_set_tdm_slot(codec_dai,
+ BIT(data->slots) - 1,
+ BIT(data->slots) - 1,
+ data->slots, data->slot_width);
+ if (ret) {
+ dev_err(dev, "failed to set codec dai[%d] tdm slot: %d\n", i, ret);
+ return ret;
+ }
+ }
+
+ /* Set MCLK freq */
+ mclk_freq = akcodec_get_mclk_rate(substream, params);
+ /* Use the maximum freq from DSD512 (512*44100 = 22579200) */
+ if (is_dsd)
+ mclk_freq = 22579200;
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, FSL_SAI_CLK_MAST1, mclk_freq,
+ SND_SOC_CLOCK_OUT);
+ if (ret < 0)
+ dev_err(dev, "failed to set cpui dai mclk1 rate (%lu): %d\n",
+ mclk_freq, ret);
+ return ret;
+}
+
+static int ak5558_hw_rule_rate(struct snd_pcm_hw_params *p, struct snd_pcm_hw_rule *r)
+{
+ struct imx_akcodec_data *data = r->private;
+ struct snd_interval t = { .min = 8000, .max = 8000, };
+ unsigned long mclk_freq;
+ unsigned int fs;
+ int i;
+
+ fs = hw_param_interval(p, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min;
+ fs *= data->tdm_mode ? 8 : 2;
+
+ /* Identify maximum supported rate */
+ for (i = 0; i < ARRAY_SIZE(akcodec_rates); i++) {
+ mclk_freq = fs * akcodec_rates[i];
+ /* Adjust SAI bclk:mclk ratio */
+ mclk_freq *= data->plat_data->one2one_ratio ? 1 : 2;
+
+ /* Skip rates for which MCLK is beyond supported value */
+ if (mclk_freq > 36864000)
+ continue;
+
+ if (t.max < akcodec_rates[i])
+ t.max = akcodec_rates[i];
+ }
+
+ return snd_interval_refine(hw_param_interval(p, r->var), &t);
+}
+
+static int imx_aif_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct imx_akcodec_data *data = snd_soc_card_get_drvdata(card);
+ static struct snd_pcm_hw_constraint_list constraint_rates;
+ static struct snd_pcm_hw_constraint_list constraint_channels;
+ int ret = 0;
+
+ if (data->tdm_mode) {
+ constraint_channels.list = data->plat_data->support_tdm_channels;
+ constraint_channels.count = data->plat_data->num_tdm_channels;
+ constraint_rates.list = data->plat_data->support_tdm_rates;
+ constraint_rates.count = data->plat_data->num_tdm_rates;
+ } else {
+ constraint_channels.list = data->plat_data->support_channels;
+ constraint_channels.count = data->plat_data->num_channels;
+ constraint_rates.list = data->plat_data->support_rates;
+ constraint_rates.count = data->plat_data->num_rates;
+ }
+
+ ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ &constraint_channels);
+ if (ret)
+ return ret;
+
+ ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ &constraint_rates);
+ if (ret)
+ return ret;
+
+ if (data->plat_data->type == CODEC_AK5558)
+ ret = snd_pcm_hw_rule_add(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ ak5558_hw_rule_rate, data,
+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
+
+ return ret;
+}
+
+static int imx_aif_hw_params_be(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_card *card = rtd->card;
+ struct device *dev = card->dev;
+ struct imx_akcodec_data *data = snd_soc_card_get_drvdata(card);
+ unsigned int slots, slot_width;
+ unsigned long mclk_freq;
+ unsigned int fmt;
+ int ret;
+
+ /* In order to support odd channels, force tdm mode for FE-BE case */
+ if (data->plat_data->tdm_is_support) {
+ fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ /* support TDM256 (8 slots * 32 bits/per slot) */
+ slots = 8;
+ slot_width = 32;
+ } else {
+ fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ slots = 2;
+ slot_width = 32;
+ }
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+ if (ret) {
+ dev_err(dev, "failed to set cpu dai fmt: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_fmt(codec_dai, fmt);
+ if (ret) {
+ dev_err(dev, "failed to set codec dai fmt: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, BIT(slots) - 1, BIT(slots) - 1,
+ slots, slot_width);
+ if (ret) {
+ dev_err(dev, "failed to set cpu dai tdm slot: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, BIT(slots) - 1, BIT(slots) - 1,
+ slots, slot_width);
+ if (ret) {
+ dev_err(dev, "failed to set codec dai fmt: %d\n", ret);
+ return ret;
+ }
+
+ mclk_freq = akcodec_get_mclk_rate(substream, params);
+ ret = snd_soc_dai_set_sysclk(cpu_dai, FSL_SAI_CLK_MAST1, mclk_freq,
+ SND_SOC_CLOCK_OUT);
+ if (ret < 0)
+ dev_err(dev, "failed to set cpu_dai mclk1 rate %lu\n",
+ mclk_freq);
+
+ return ret;
+}
+
+static struct snd_soc_ops imx_aif_ops = {
+ .hw_params = imx_aif_hw_params,
+ .startup = imx_aif_startup,
+};
+
+static struct snd_soc_ops imx_aif_ops_be = {
+ .hw_params = imx_aif_hw_params_be,
+};
+
+static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct imx_akcodec_data *data = snd_soc_card_get_drvdata(card);
+ struct snd_interval *rate;
+ struct snd_mask *mask;
+
+ if (!data->asrc_pdev)
+ return -EINVAL;
+
+ rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ rate->max = data->asrc_rate;
+ rate->min = data->asrc_rate;
+
+ mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+ snd_mask_none(mask);
+ snd_mask_set(mask, data->asrc_format);
+
+ return 0;
+}
+
+static int imx_akcodec_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dai_link_component *dlc;
+ struct device_node *codec_np[MAX_CODECS];
+ struct device_node *cpu_np = NULL;
+ struct imx_akcodec_data *data;
+ struct device_node *asrc_np = NULL;
+ char tmp[MAX_CODECS][8];
+ int ret, i;
+ u32 width;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->plat_data = of_device_get_match_data(&pdev->dev);
+
+ dlc = devm_kzalloc(&pdev->dev, 9 * sizeof(*dlc), GFP_KERNEL);
+ if (!dlc)
+ return -ENOMEM;
+
+ cpu_np = of_parse_phandle(pdev->dev.of_node, "audio-cpu", 0);
+ if (!cpu_np) {
+ dev_err(&pdev->dev, "audio dai phandle missing or invalid\n");
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ /* Parse codec node */
+ for (i = 0; i < data->plat_data->num_codecs; i++) {
+ codec_np[i] = of_parse_phandle(pdev->dev.of_node, "audio-codec", i);
+ if (!codec_np[i]) {
+ dev_err(&pdev->dev, "audio codec phandle missing or invalid\n");
+ ret = -EINVAL;
+ goto fail;
+ }
+ }
+
+ asrc_np = of_parse_phandle(pdev->dev.of_node, "audio-asrc", 0);
+ if (asrc_np)
+ data->asrc_pdev = of_find_device_by_node(asrc_np);
+
+ if (of_find_property(pdev->dev.of_node, "fsl,tdm", NULL) &&
+ data->plat_data->tdm_is_support)
+ data->tdm_mode = true;
+
+ data->num_codec_conf = data->plat_data->num_codecs;
+ data->codec_conf = devm_kzalloc(&pdev->dev,
+ data->num_codec_conf * sizeof(struct snd_soc_codec_conf),
+ GFP_KERNEL);
+ if (!data->codec_conf) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ data->num_dapm_routes = data->plat_data->num_codecs + 1;
+ data->dapm_routes = devm_kcalloc(&pdev->dev, data->num_dapm_routes,
+ sizeof(struct snd_soc_dapm_route),
+ GFP_KERNEL);
+ if (!data->dapm_routes) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ data->dai_link[0].name = "akcodec";
+ data->dai_link[0].stream_name = "Audio";
+ data->dai_link[0].cpus = &dlc[0];
+ data->dai_link[0].platforms = &dlc[1];
+ data->dai_link[0].codecs = data->codecs;
+ data->dai_link[0].num_cpus = 1;
+ data->dai_link[0].num_platforms = 1;
+ data->dai_link[0].num_codecs = data->plat_data->num_codecs;
+ data->dai_link[0].cpus->of_node = cpu_np;
+ data->dai_link[0].platforms->of_node = cpu_np;
+
+ for (i = 0; i < data->plat_data->num_codecs; i++) {
+ sprintf(tmp[i], "%d", i);
+ data->codec_conf[i].name_prefix = tmp[i];
+ data->codec_conf[i].dlc.of_node = codec_np[i];
+ data->codecs[i].of_node = codec_np[i];
+ data->codecs[i].dai_name = data->plat_data->dai_name;
+
+ if (data->plat_data->playback_only) {
+ data->dapm_routes[i].sink =
+ devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s %s",
+ tmp[i], "Playback");
+ data->dapm_routes[i].source = "CPU-Playback";
+ } else {
+ data->dapm_routes[i].source =
+ devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s %s",
+ tmp[i], "Capture");
+ data->dapm_routes[i].sink = "CPU-Capture";
+ }
+ }
+
+ if (data->plat_data->playback_only) {
+ data->dapm_routes[i].sink = "CPU-Playback";
+ data->dapm_routes[i].source = "ASRC-Playback";
+ } else {
+ data->dapm_routes[i].sink = "ASRC-Capture";
+ data->dapm_routes[i].source = "CPU-Capture";
+ }
+
+ data->dai_link[0].ops = &imx_aif_ops;
+ data->dai_link[0].ignore_pmdown_time = 1;
+ data->dai_link[0].playback_only = data->plat_data->playback_only;
+ data->dai_link[0].capture_only = data->plat_data->capture_only;
+
+ data->card.codec_conf = data->codec_conf;
+ data->card.num_configs = data->num_codec_conf;
+ data->card.dai_link = &data->dai_link[0];
+ data->card.num_links = 1;
+ data->card.dev = &pdev->dev;
+ data->card.owner = THIS_MODULE;
+ data->card.dapm_widgets = imx_akcodec_dapm_widgets;
+ data->card.num_dapm_widgets = ARRAY_SIZE(imx_akcodec_dapm_widgets);
+
+ /*if there is no asrc controller, we only enable one device*/
+ if (data->asrc_pdev) {
+ data->dai_link[1].name = "HiFi-ASRC-FE";
+ data->dai_link[1].stream_name = "HiFi-ASRC-FE";
+ data->dai_link[1].dynamic = 1;
+ data->dai_link[1].ignore_pmdown_time = 1;
+ data->dai_link[1].dpcm_playback = data->plat_data->playback_only;
+ data->dai_link[1].dpcm_capture = data->plat_data->capture_only;
+ data->dai_link[1].dpcm_merged_chan = 1;
+
+ data->dai_link[1].cpus = &dlc[2];
+ data->dai_link[1].platforms = &dlc[3];
+ data->dai_link[1].codecs = &dlc[4];
+ data->dai_link[1].num_cpus = 1;
+ data->dai_link[1].num_platforms = 1;
+ data->dai_link[1].num_codecs = 1;
+ data->dai_link[1].cpus->of_node = asrc_np;
+ data->dai_link[1].platforms->of_node = asrc_np;
+ data->dai_link[1].codecs->name = "snd-soc-dummy";
+ data->dai_link[1].codecs->dai_name = "snd-soc-dummy-dai";
+
+ data->dai_link[2].cpus = &dlc[5];
+ data->dai_link[2].platforms = &dlc[6];
+ data->dai_link[2].codecs = data->codecs;
+ data->dai_link[2].num_cpus = 1;
+ data->dai_link[2].num_platforms = 1;
+ data->dai_link[2].num_codecs = data->plat_data->num_codecs;
+
+ data->dai_link[2].name = "HiFi-ASRC-BE";
+ data->dai_link[2].stream_name = "HiFi-ASRC-BE";
+ data->dai_link[2].cpus->of_node = cpu_np;
+ data->dai_link[2].platforms->name = "snd-soc-dummy";
+ data->dai_link[2].ops = &imx_aif_ops_be;
+ data->dai_link[2].be_hw_params_fixup = be_hw_params_fixup;
+ data->dai_link[2].no_pcm = 1;
+ data->dai_link[2].ignore_pmdown_time = 1;
+ data->dai_link[2].dpcm_playback = data->plat_data->playback_only;
+ data->dai_link[2].dpcm_capture = data->plat_data->capture_only;
+
+ data->card.dapm_routes = data->dapm_routes;
+ data->card.num_dapm_routes = data->num_dapm_routes;
+ data->card.num_links = 3;
+
+ ret = of_property_read_u32(asrc_np, "fsl,asrc-rate",
+ &data->asrc_rate);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to get output rate\n");
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ ret = of_property_read_u32(asrc_np, "fsl,asrc-format",
+ &data->asrc_format);
+ if (ret) {
+ /* Fallback to old binding; translate to asrc_format */
+ ret = of_property_read_u32(asrc_np, "fsl,asrc-width",
+ &width);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "failed to decide output format\n");
+ goto fail;
+ }
+
+ if (width == 24)
+ data->asrc_format = SNDRV_PCM_FORMAT_S24_LE;
+ else
+ data->asrc_format = SNDRV_PCM_FORMAT_S16_LE;
+ }
+ }
+
+ ret = snd_soc_of_parse_card_name(&data->card, "model");
+ if (ret)
+ goto fail;
+
+ snd_soc_card_set_drvdata(&data->card, data);
+ ret = devm_snd_soc_register_card(&pdev->dev, &data->card);
+ if (ret) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+ goto fail;
+ }
+
+ ret = 0;
+fail:
+ if (cpu_np)
+ of_node_put(cpu_np);
+
+ for (i = 0; i < data->plat_data->num_codecs; i++)
+ if (codec_np[i])
+ of_node_put(codec_np[i]);
+
+ return ret;
+}
+
+static const struct of_device_id imx_akcodec_dt_ids[] = {
+ { .compatible = "fsl,imx8mq-audio-ak4458", .data = &imx8mq_ak4458, },
+ { .compatible = "fsl,imx8mq-audio-ak4497", .data = &imx8mq_ak4497, },
+ { .compatible = "fsl,imx8mq-audio-ak5558", .data = &imx8mq_ak5558, },
+ { .compatible = "fsl,imx-audio-ak4458", .data = &imx_ak4458, },
+ { .compatible = "fsl,imx-audio-ak4497", .data = &imx_ak4497, },
+ { .compatible = "fsl,imx-audio-ak5558", .data = &imx_ak5558, },
+ { .compatible = "fsl,imx-audio-ak5552", .data = &imx_ak5558, },
+ { },
+};
+MODULE_DEVICE_TABLE(of, imx_akcodec_dt_ids);
+
+static struct platform_driver imx_akcodec_driver = {
+ .driver = {
+ .name = "imx-akcodec",
+ .pm = &snd_soc_pm_ops,
+ .of_match_table = imx_akcodec_dt_ids,
+ },
+ .probe = imx_akcodec_probe,
+};
+module_platform_driver(imx_akcodec_driver);
+
+MODULE_DESCRIPTION("Freescale i.MX AK CODEC ASoC machine driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:imx-akcodec");
--
2.17.1
^ permalink raw reply related
* [PATCH 2/2] ASoC: dt-bindings: imx-akcodec: Add binding doc for akcodec machine driver
From: Shengjiu Wang @ 2021-04-23 5:51 UTC (permalink / raw)
To: lgirdwood, broonie, perex, tiwai, timur, nicoleotsuka, Xiubo.Lee,
festevam, shawnguo, s.hauer, kernel, linux-imx, linux-kernel,
alsa-devel, linuxppc-dev, linux-arm-kernel, robh+dt, devicetree
In-Reply-To: <1619157107-3734-1-git-send-email-shengjiu.wang@nxp.com>
Imx-akcodec is a new added machine driver for supporting
ak4458/ak5558/ak5552/ak4497 codec on i.MX platforms.
Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
---
.../bindings/sound/imx-audio-akcodec.yaml | 60 +++++++++++++++++++
1 file changed, 60 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/imx-audio-akcodec.yaml
diff --git a/Documentation/devicetree/bindings/sound/imx-audio-akcodec.yaml b/Documentation/devicetree/bindings/sound/imx-audio-akcodec.yaml
new file mode 100644
index 000000000000..7419bf7224e9
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/imx-audio-akcodec.yaml
@@ -0,0 +1,60 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/imx-audio-akcodec.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP i.MX audio complex with AK4458/AK5558/AK5552/AK4497 codec
+
+maintainers:
+ - Shengjiu Wang <shengjiu.wang@nxp.com>
+
+properties:
+ compatible:
+ enum:
+ - fsl,imx8mq-audio-ak4458
+ - fsl,imx8mq-audio-ak4497
+ - fsl,imx8mq-audio-ak5558
+ - fsl,imx-audio-ak4497
+ - fsl,imx-audio-ak4458
+ - fsl,imx-audio-ak5558
+ - fsl,imx-audio-ak5552
+
+ model:
+ $ref: /schemas/types.yaml#/definitions/string
+ description: User specified audio sound card name
+
+ audio-cpu:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: The phandle of a CPU DAI controller
+
+ audio-codec:
+ description: The phandle of Codec DAI controllers, there are two
+ controllers maximum.
+
+ audio-asrc:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: The phandle of ASRC. It can be absent if there's no
+ need to add ASRC support via DPCM.
+
+ fsl,tdm:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description: |
+ This is a boolean property. If present, the TDM mode is enabled.
+
+required:
+ - compatible
+ - model
+ - audio-cpu
+ - audio-codec
+
+additionalProperties: false
+
+examples:
+ - |
+ sound-ak4458 {
+ compatible = "fsl,imx-audio-ak4458";
+ model = "ak4458-audio";
+ audio-cpu = <&sai1>;
+ audio-codec = <&ak4458_1>, <&ak4458_2>;
+ };
--
2.17.1
^ permalink raw reply related
* Re: [PATCH v5 01/16] swiotlb: Fix the type of index
From: Christoph Hellwig @ 2021-04-23 7:11 UTC (permalink / raw)
To: Claire Chang
Cc: heikki.krogerus, thomas.hellstrom, peterz, joonas.lahtinen,
dri-devel, lkml, grant.likely, paulus, Will Deacon, mingo,
Marek Szyprowski, sstabellini, Saravana Kannan, xypron.glpk,
Joerg Roedel, Rafael J . Wysocki, Christoph Hellwig,
Bartosz Golaszewski, bskeggs, linux-pci, xen-devel,
Thierry Reding, intel-gfx, matthew.auld, linux-devicetree, jxgao,
daniel, Konrad Rzeszutek Wilk, maarten.lankhorst, airlied,
Dan Williams, linuxppc-dev, jani.nikula, Nicolas Boichat,
rodrigo.vivi, bhelgaas, boris.ostrovsky, Andy Shevchenko, jgross,
chris, nouveau, Greg KH, Randy Dunlap, Frank Rowand, tfiga,
list@263.net:IOMMU DRIVERS, Jim Quinlan, Robin Murphy, bauerman
In-Reply-To: <20210422081508.3942748-2-tientzu@chromium.org>
On Thu, Apr 22, 2021 at 04:14:53PM +0800, Claire Chang wrote:
> Fix the type of index from unsigned int to int since find_slots() might
> return -1.
>
> Fixes: 0774983bc923 ("swiotlb: refactor swiotlb_tbl_map_single")
> Signed-off-by: Claire Chang <tientzu@chromium.org>
Looks good:
Reviewed-by: Christoph Hellwig <hch@lst.de>
it really should go into 5.12. I'm not sure if Konrad is going to
be able to queue this up due to his vacation, so I'm tempted to just
queue it up in the dma-mapping tree.
^ permalink raw reply
* Re: [PATCH v3 01/11] powerpc/pseries/iommu: Replace hard-coded page shift
From: Alexey Kardashevskiy @ 2021-04-23 7:27 UTC (permalink / raw)
To: Leonardo Bras, Michael Ellerman, Benjamin Herrenschmidt,
Paul Mackerras, Joel Stanley, Christophe Leroy, Nicolin Chen,
Niklas Schnelle
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <20210422070721.463912-2-leobras.c@gmail.com>
On 22/04/2021 17:07, Leonardo Bras wrote:
> Some functions assume IOMMU page size can only be 4K (pageshift == 12).
> Update them to accept any page size passed, so we can use 64K pages.
>
> In the process, some defines like TCE_SHIFT were made obsolete, and then
> removed.
>
> IODA3 Revision 3.0_prd1 (OpenPowerFoundation), Figures 3.4 and 3.5 show
> a RPN of 52-bit, and considers a 12-bit pageshift, so there should be
> no need of using TCE_RPN_MASK, which masks out any bit after 40 in rpn.
> It's usage removed from tce_build_pSeries(), tce_build_pSeriesLP(), and
> tce_buildmulti_pSeriesLP().
After rereading the patch, I wonder why we had this TCE_RPN_MASK at all
but what is certain is that this has nothing to do with IODA3 as these
TCEs are guest phys addresses in pseries and IODA3 is bare metal. Except...
> Most places had a tbl struct, so using tbl->it_page_shift was simple.
> tce_free_pSeriesLP() was a special case, since callers not always have a
> tbl struct, so adding a tceshift parameter seems the right thing to do.
>
> Signed-off-by: Leonardo Bras <leobras.c@gmail.com>
> Reviewed-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> ---
> arch/powerpc/include/asm/tce.h | 8 ------
> arch/powerpc/platforms/pseries/iommu.c | 39 +++++++++++++++-----------
> 2 files changed, 23 insertions(+), 24 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/tce.h b/arch/powerpc/include/asm/tce.h
> index db5fc2f2262d..0c34d2756d92 100644
> --- a/arch/powerpc/include/asm/tce.h
> +++ b/arch/powerpc/include/asm/tce.h
> @@ -19,15 +19,7 @@
> #define TCE_VB 0
> #define TCE_PCI 1
>
> -/* TCE page size is 4096 bytes (1 << 12) */
> -
> -#define TCE_SHIFT 12
> -#define TCE_PAGE_SIZE (1 << TCE_SHIFT)
> -
> #define TCE_ENTRY_SIZE 8 /* each TCE is 64 bits */
> -
> -#define TCE_RPN_MASK 0xfffffffffful /* 40-bit RPN (4K pages) */
> -#define TCE_RPN_SHIFT 12
> #define TCE_VALID 0x800 /* TCE valid */
> #define TCE_ALLIO 0x400 /* TCE valid for all lpars */
> #define TCE_PCI_WRITE 0x2 /* write from PCI allowed */
> diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
> index 67c9953a6503..796ab356341c 100644
> --- a/arch/powerpc/platforms/pseries/iommu.c
> +++ b/arch/powerpc/platforms/pseries/iommu.c
> @@ -107,6 +107,8 @@ static int tce_build_pSeries(struct iommu_table *tbl, long index,
> u64 proto_tce;
> __be64 *tcep;
> u64 rpn;
> + const unsigned long tceshift = tbl->it_page_shift;
> + const unsigned long pagesize = IOMMU_PAGE_SIZE(tbl);
(nit: only used once)
>
> proto_tce = TCE_PCI_READ; // Read allowed
>
> @@ -117,10 +119,10 @@ static int tce_build_pSeries(struct iommu_table *tbl, long index,
... this pseries which is not pseriesLP, i.e. no LPAR == bare metal
pseries such as ancient power5 or cellbe (I guess) and for those
TCE_RPN_MASK may actually make sense, keep it.
The rest of the patch looks good. Thanks,
>
> while (npages--) {
> /* can't move this out since we might cross MEMBLOCK boundary */
> - rpn = __pa(uaddr) >> TCE_SHIFT;
> - *tcep = cpu_to_be64(proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT);
> + rpn = __pa(uaddr) >> tceshift;
> + *tcep = cpu_to_be64(proto_tce | rpn << tceshift);
>
> - uaddr += TCE_PAGE_SIZE;
> + uaddr += pagesize;
> tcep++;
> }
> return 0;
> @@ -146,7 +148,7 @@ static unsigned long tce_get_pseries(struct iommu_table *tbl, long index)
> return be64_to_cpu(*tcep);
> }
>
> -static void tce_free_pSeriesLP(unsigned long liobn, long, long);
> +static void tce_free_pSeriesLP(unsigned long liobn, long, long, long);
> static void tce_freemulti_pSeriesLP(struct iommu_table*, long, long);
>
> static int tce_build_pSeriesLP(unsigned long liobn, long tcenum, long tceshift,
> @@ -166,12 +168,12 @@ static int tce_build_pSeriesLP(unsigned long liobn, long tcenum, long tceshift,
> proto_tce |= TCE_PCI_WRITE;
>
> while (npages--) {
> - tce = proto_tce | (rpn & TCE_RPN_MASK) << tceshift;
> + tce = proto_tce | rpn << tceshift;
> rc = plpar_tce_put((u64)liobn, (u64)tcenum << tceshift, tce);
>
> if (unlikely(rc == H_NOT_ENOUGH_RESOURCES)) {
> ret = (int)rc;
> - tce_free_pSeriesLP(liobn, tcenum_start,
> + tce_free_pSeriesLP(liobn, tcenum_start, tceshift,
> (npages_start - (npages + 1)));
> break;
> }
> @@ -205,10 +207,11 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
> long tcenum_start = tcenum, npages_start = npages;
> int ret = 0;
> unsigned long flags;
> + const unsigned long tceshift = tbl->it_page_shift;
>
> if ((npages == 1) || !firmware_has_feature(FW_FEATURE_PUT_TCE_IND)) {
> return tce_build_pSeriesLP(tbl->it_index, tcenum,
> - tbl->it_page_shift, npages, uaddr,
> + tceshift, npages, uaddr,
> direction, attrs);
> }
>
> @@ -225,13 +228,13 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
> if (!tcep) {
> local_irq_restore(flags);
> return tce_build_pSeriesLP(tbl->it_index, tcenum,
> - tbl->it_page_shift,
> + tceshift,
> npages, uaddr, direction, attrs);
> }
> __this_cpu_write(tce_page, tcep);
> }
>
> - rpn = __pa(uaddr) >> TCE_SHIFT;
> + rpn = __pa(uaddr) >> tceshift;
> proto_tce = TCE_PCI_READ;
> if (direction != DMA_TO_DEVICE)
> proto_tce |= TCE_PCI_WRITE;
> @@ -245,12 +248,12 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
> limit = min_t(long, npages, 4096/TCE_ENTRY_SIZE);
>
> for (l = 0; l < limit; l++) {
> - tcep[l] = cpu_to_be64(proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT);
> + tcep[l] = cpu_to_be64(proto_tce | rpn << tceshift);
> rpn++;
> }
>
> rc = plpar_tce_put_indirect((u64)tbl->it_index,
> - (u64)tcenum << 12,
> + (u64)tcenum << tceshift,
> (u64)__pa(tcep),
> limit);
>
> @@ -277,12 +280,13 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
> return ret;
> }
>
> -static void tce_free_pSeriesLP(unsigned long liobn, long tcenum, long npages)
> +static void tce_free_pSeriesLP(unsigned long liobn, long tcenum, long tceshift,
> + long npages)
> {
> u64 rc;
>
> while (npages--) {
> - rc = plpar_tce_put((u64)liobn, (u64)tcenum << 12, 0);
> + rc = plpar_tce_put((u64)liobn, (u64)tcenum << tceshift, 0);
>
> if (rc && printk_ratelimit()) {
> printk("tce_free_pSeriesLP: plpar_tce_put failed. rc=%lld\n", rc);
> @@ -301,9 +305,11 @@ static void tce_freemulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long n
> u64 rc;
>
> if (!firmware_has_feature(FW_FEATURE_STUFF_TCE))
> - return tce_free_pSeriesLP(tbl->it_index, tcenum, npages);
> + return tce_free_pSeriesLP(tbl->it_index, tcenum,
> + tbl->it_page_shift, npages);
>
> - rc = plpar_tce_stuff((u64)tbl->it_index, (u64)tcenum << 12, 0, npages);
> + rc = plpar_tce_stuff((u64)tbl->it_index,
> + (u64)tcenum << tbl->it_page_shift, 0, npages);
>
> if (rc && printk_ratelimit()) {
> printk("tce_freemulti_pSeriesLP: plpar_tce_stuff failed\n");
> @@ -319,7 +325,8 @@ static unsigned long tce_get_pSeriesLP(struct iommu_table *tbl, long tcenum)
> u64 rc;
> unsigned long tce_ret;
>
> - rc = plpar_tce_get((u64)tbl->it_index, (u64)tcenum << 12, &tce_ret);
> + rc = plpar_tce_get((u64)tbl->it_index,
> + (u64)tcenum << tbl->it_page_shift, &tce_ret);
>
> if (rc && printk_ratelimit()) {
> printk("tce_get_pSeriesLP: plpar_tce_get failed. rc=%lld\n", rc);
>
--
Alexey
^ permalink raw reply
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