* [PATCH net-next 3/5] net: stmmac: dwmac4: Enable RX Jumbo frame support
From: Jose Abreu @ 2019-09-06 7:41 UTC (permalink / raw)
To: netdev
Cc: Jose Abreu, Joao Pinto, Alexandre Torgue, linux-kernel,
Maxime Coquelin, Giuseppe Cavallaro, David S. Miller,
linux-arm-kernel
In-Reply-To: <cover.1567755423.git.joabreu@synopsys.com>
We are already doing it by default in the TX path so we can also enable
Jumbo Frame support in the RX path independently of MTU value.
Signed-off-by: Jose Abreu <joabreu@synopsys.com>
---
Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Cc: Alexandre Torgue <alexandre.torgue@st.com>
Cc: Jose Abreu <joabreu@synopsys.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com>
Cc: netdev@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
drivers/net/ethernet/stmicro/stmmac/dwmac4.h | 3 ++-
drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c | 6 ------
2 files changed, 2 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
index 2ed11a581d80..03301ffc0391 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
@@ -352,7 +352,8 @@ enum power_event {
/* Default operating mode of the MAC */
#define GMAC_CORE_INIT (GMAC_CONFIG_JD | GMAC_CONFIG_PS | \
- GMAC_CONFIG_BE | GMAC_CONFIG_DCRS)
+ GMAC_CONFIG_BE | GMAC_CONFIG_DCRS | \
+ GMAC_CONFIG_JE)
/* To dump the core regs excluding the Address Registers */
#define GMAC_REG_NUM 132
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index fc9954e4a772..596311a80d1c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -25,15 +25,9 @@ static void dwmac4_core_init(struct mac_device_info *hw,
{
void __iomem *ioaddr = hw->pcsr;
u32 value = readl(ioaddr + GMAC_CONFIG);
- int mtu = dev->mtu;
value |= GMAC_CORE_INIT;
- if (mtu > 1500)
- value |= GMAC_CONFIG_2K;
- if (mtu > 2000)
- value |= GMAC_CONFIG_JE;
-
if (hw->ps) {
value |= GMAC_CONFIG_TE;
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH net-next 2/5] net: stmmac: selftests: Set RX tail pointer in Flow Control test
From: Jose Abreu @ 2019-09-06 7:41 UTC (permalink / raw)
To: netdev
Cc: Jose Abreu, Joao Pinto, Alexandre Torgue, linux-kernel,
Maxime Coquelin, Giuseppe Cavallaro, David S. Miller,
linux-arm-kernel
In-Reply-To: <cover.1567755423.git.joabreu@synopsys.com>
We need to set the RX tail pointer so that RX engine starts working
again after finishing the Flow Control test.
Signed-off-by: Jose Abreu <joabreu@synopsys.com>
---
Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Cc: Alexandre Torgue <alexandre.torgue@st.com>
Cc: Jose Abreu <joabreu@synopsys.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com>
Cc: netdev@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c
index dce34c081a1e..2943943bec43 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c
@@ -722,8 +722,14 @@ static int stmmac_test_flowctrl(struct stmmac_priv *priv)
for (i = 0; i < rx_cnt; i++) {
struct stmmac_channel *ch = &priv->channel[i];
+ u32 tail;
+ tail = priv->rx_queue[i].dma_rx_phy +
+ (DMA_RX_SIZE * sizeof(struct dma_desc));
+
+ stmmac_set_rx_tail_ptr(priv, priv->ioaddr, tail, i);
stmmac_start_rx(priv, priv->ioaddr, i);
+
local_bh_disable();
napi_reschedule(&ch->rx_napi);
local_bh_enable();
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH net-next 1/5] net: stmmac: selftests: Add missing checks for support of SA
From: Jose Abreu @ 2019-09-06 7:41 UTC (permalink / raw)
To: netdev
Cc: Jose Abreu, Joao Pinto, Alexandre Torgue, linux-kernel,
Maxime Coquelin, Giuseppe Cavallaro, David S. Miller,
linux-arm-kernel
In-Reply-To: <cover.1567755423.git.joabreu@synopsys.com>
Add checks for support of Source Address Insertion/Replacement before
running the test.
Signed-off-by: Jose Abreu <joabreu@synopsys.com>
---
Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Cc: Alexandre Torgue <alexandre.torgue@st.com>
Cc: Jose Abreu <joabreu@synopsys.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com>
Cc: netdev@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c
index 305d24935cf4..dce34c081a1e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c
@@ -1057,6 +1057,9 @@ static int stmmac_test_desc_sai(struct stmmac_priv *priv)
struct stmmac_packet_attrs attr = { };
int ret;
+ if (!priv->dma_cap.vlins)
+ return -EOPNOTSUPP;
+
attr.remove_sa = true;
attr.sarc = true;
attr.src = src;
@@ -1076,6 +1079,9 @@ static int stmmac_test_desc_sar(struct stmmac_priv *priv)
struct stmmac_packet_attrs attr = { };
int ret;
+ if (!priv->dma_cap.vlins)
+ return -EOPNOTSUPP;
+
attr.sarc = true;
attr.src = src;
attr.dst = priv->dev->dev_addr;
@@ -1094,6 +1100,9 @@ static int stmmac_test_reg_sai(struct stmmac_priv *priv)
struct stmmac_packet_attrs attr = { };
int ret;
+ if (!priv->dma_cap.vlins)
+ return -EOPNOTSUPP;
+
attr.remove_sa = true;
attr.sarc = true;
attr.src = src;
@@ -1114,6 +1123,9 @@ static int stmmac_test_reg_sar(struct stmmac_priv *priv)
struct stmmac_packet_attrs attr = { };
int ret;
+ if (!priv->dma_cap.vlins)
+ return -EOPNOTSUPP;
+
attr.sarc = true;
attr.src = src;
attr.dst = priv->dev->dev_addr;
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH] bus: ti-sysc: Fix handling of invalid clocks
From: Keerthy @ 2019-09-06 7:49 UTC (permalink / raw)
To: Tony Lindgren, linux-omap
Cc: Nishanth Menon, Tero Kristo, Dave Gerlach, Greg Kroah-Hartman,
linux-kernel, Andrew F . Davis, Peter Ujfalusi, Faiz Abbas,
linux-arm-kernel, Roger Quadros
In-Reply-To: <20190905215356.8168-1-tony@atomide.com>
On 06/09/19 3:23 AM, Tony Lindgren wrote:
> We can currently get "Unable to handle kernel paging request at
> virtual address" for invalid clocks with dts node but no driver:
>
> (__clk_get_hw) from [<c0138ebc>] (ti_sysc_find_one_clockdomain+0x18/0x34)
> (ti_sysc_find_one_clockdomain) from [<c0138f0c>] (ti_sysc_clkdm_init+0x34/0xdc)
> (ti_sysc_clkdm_init) from [<c0584660>] (sysc_probe+0xa50/0x10e8)
> (sysc_probe) from [<c065c6ac>] (platform_drv_probe+0x58/0xa8)
>
> Let's add IS_ERR checks to ti_sysc_clkdm_init() as And let's start treating
> clk_get() with -ENOENT as a proper error. If the clock name is specified
> in device tree we must succeed with clk_get() to continue. For modules with
> no clock names specified in device tree we will just ignore the clocks.
Tested for DS0 and RTC+DDR modes on AM437x
FWIW
Tested-by: Keerthy <j-keerthy@ti.com>
>
> Fixes: 2b2f7def058a ("bus: ti-sysc: Add support for missing clockdomain handling")
> Signed-off-by: Tony Lindgren <tony@atomide.com>
> ---
> arch/arm/mach-omap2/pdata-quirks.c | 4 ++--
> drivers/bus/ti-sysc.c | 5 +----
> 2 files changed, 3 insertions(+), 6 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c
> --- a/arch/arm/mach-omap2/pdata-quirks.c
> +++ b/arch/arm/mach-omap2/pdata-quirks.c
> @@ -491,11 +491,11 @@ static int ti_sysc_clkdm_init(struct device *dev,
> struct clk *fck, struct clk *ick,
> struct ti_sysc_cookie *cookie)
> {
> - if (fck)
> + if (!IS_ERR(fck))
> cookie->clkdm = ti_sysc_find_one_clockdomain(fck);
> if (cookie->clkdm)
> return 0;
> - if (ick)
> + if (!IS_ERR(ick))
> cookie->clkdm = ti_sysc_find_one_clockdomain(ick);
> if (cookie->clkdm)
> return 0;
> diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
> --- a/drivers/bus/ti-sysc.c
> +++ b/drivers/bus/ti-sysc.c
> @@ -280,9 +280,6 @@ static int sysc_get_one_clock(struct sysc *ddata, const char *name)
>
> ddata->clocks[index] = devm_clk_get(ddata->dev, name);
> if (IS_ERR(ddata->clocks[index])) {
> - if (PTR_ERR(ddata->clocks[index]) == -ENOENT)
> - return 0;
> -
> dev_err(ddata->dev, "clock get error for %s: %li\n",
> name, PTR_ERR(ddata->clocks[index]));
>
> @@ -357,7 +354,7 @@ static int sysc_get_clocks(struct sysc *ddata)
> continue;
>
> error = sysc_get_one_clock(ddata, name);
> - if (error && error != -ENOENT)
> + if (error)
> return error;
> }
>
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 1/1] KVM: inject data abort if instruction cannot be decoded
From: Christoffer Dall @ 2019-09-06 7:58 UTC (permalink / raw)
To: Heinrich Schuchardt
Cc: Peter Maydell, Daniel P. Berrangé, Marc Zyngier,
lkml - Kernel Mailing List, Stefan Hajnoczi, kvmarm,
arm-mail-list
In-Reply-To: <27e7edd6-1c4f-c970-3395-ecb4f176f858@gmx.de>
On Thu, Sep 05, 2019 at 03:25:47PM +0200, Heinrich Schuchardt wrote:
> On 9/5/19 11:22 AM, Christoffer Dall wrote:
> > On Thu, Sep 05, 2019 at 09:56:44AM +0100, Peter Maydell wrote:
> > > On Thu, 5 Sep 2019 at 09:52, Marc Zyngier <maz@kernel.org> wrote:
> > > >
> > > > On Thu, 05 Sep 2019 09:16:54 +0100,
> > > > Peter Maydell <peter.maydell@linaro.org> wrote:
> > > > > This is true, but the problem is that barfing out to userspace
> > > > > makes it harder to debug the guest because it means that
> > > > > the VM is immediately destroyed, whereas AIUI if we
> > > > > inject some kind of exception then (assuming you're set up
> > > > > to do kernel-debug via gdbstub) you can actually examine
> > > > > the offending guest code with a debugger because at least
> > > > > your VM is still around to inspect...
> > > >
> > > > To Christoffer's point, I find the benefit a bit dubious. Yes, you get
> > > > an exception, but the instruction that caused it may be completely
> > > > legal (store with post-increment, for example), leading to an even
> > > > more puzzled developer (that exception should never have been
> > > > delivered the first place).
> > >
> > > Right, but the combination of "host kernel prints a message
> > > about an unsupported load/store insn" and "within-guest debug
> > > dump/stack trace/etc" is much more useful than just having
> > > "host kernel prints message" and "QEMU exits"; and it requires
> > > about 3 lines of code change...
> > >
> > > > I'm far more in favour of dumping the state of the access in the run
> > > > structure (much like we do for a MMIO access) and let userspace do
> > > > something about it (such as dumping information on the console or
> > > > breaking). It could even inject an exception *if* the user has asked
> > > > for it.
> > >
> > > ...whereas this requires agreement on a kernel-userspace API,
> > > larger changes in the kernel, somebody to implement the userspace
> > > side of things, and the user to update both the kernel and QEMU.
> > > It's hard for me to see that the benefit here over the 3-line
> > > approach really outweighs the extra effort needed. In practice
> > > saying "we should do this" is saying "we're going to do nothing",
> > > based on the historical record.
> > >
> >
> > How about something like the following (completely untested, liable for
> > ABI discussions etc. etc., but for illustration purposes).
> >
> > I think it raises the question (and likely many other) of whether we can
> > break the existing 'ABI' and change behavior for missing ISV
> > retrospectively for legacy user space when the issue has occurred?
> >
> > Someone might have written code that reacts to the -ENOSYS, so I've
> > taken the conservative approach for this for the time being.
> >
> >
> > diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
> > index 8a37c8e89777..19a92c49039c 100644
> > --- a/arch/arm/include/asm/kvm_host.h
> > +++ b/arch/arm/include/asm/kvm_host.h
> > @@ -76,6 +76,14 @@ struct kvm_arch {
> >
> > /* Mandated version of PSCI */
> > u32 psci_version;
> > +
> > + /*
> > + * If we encounter a data abort without valid instruction syndrome
> > + * information, report this to user space. User space can (and
> > + * should) opt in to this feature if KVM_CAP_ARM_NISV_TO_USER is
> > + * supported.
> > + */
> > + bool return_nisv_io_abort_to_user;
> > };
> >
> > #define KVM_NR_MEM_OBJS 40
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index f656169db8c3..019bc560edc1 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -83,6 +83,14 @@ struct kvm_arch {
> >
> > /* Mandated version of PSCI */
> > u32 psci_version;
> > +
> > + /*
> > + * If we encounter a data abort without valid instruction syndrome
> > + * information, report this to user space. User space can (and
> > + * should) opt in to this feature if KVM_CAP_ARM_NISV_TO_USER is
> > + * supported.
> > + */
> > + bool return_nisv_io_abort_to_user;
>
> How about 32bit ARM?
>
What about it? Not sure I understand the comment.
> > };
> >
> > #define KVM_NR_MEM_OBJS 40
> > diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> > index 5e3f12d5359e..a4dd004d0db9 100644
> > --- a/include/uapi/linux/kvm.h
> > +++ b/include/uapi/linux/kvm.h
> > @@ -235,6 +235,7 @@ struct kvm_hyperv_exit {
> > #define KVM_EXIT_S390_STSI 25
> > #define KVM_EXIT_IOAPIC_EOI 26
> > #define KVM_EXIT_HYPERV 27
> > +#define KVM_EXIT_ARM_NISV 28
> >
> > /* For KVM_EXIT_INTERNAL_ERROR */
> > /* Emulate instruction failed. */
> > @@ -996,6 +997,7 @@ struct kvm_ppc_resize_hpt {
> > #define KVM_CAP_ARM_PTRAUTH_ADDRESS 171
> > #define KVM_CAP_ARM_PTRAUTH_GENERIC 172
> > #define KVM_CAP_PMU_EVENT_FILTER 173
> > +#define KVM_CAP_ARM_NISV_TO_USER 174
> >
> > #ifdef KVM_CAP_IRQ_ROUTING
> >
> > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > index 35a069815baf..2ce94bd9d4a9 100644
> > --- a/virt/kvm/arm/arm.c
> > +++ b/virt/kvm/arm/arm.c
> > @@ -98,6 +98,26 @@ int kvm_arch_check_processor_compat(void)
> > return 0;
> > }
> >
> > +int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
> > + struct kvm_enable_cap *cap)
>
> This overrides the weak implementation in virt/kvm/kvm_main.c. OK.
>
Yes.
> > +{
> > + int r;
> > +
> > + if (cap->flags)
> > + return -EINVAL;
> > +
> > + switch (cap->cap) {
> > + case KVM_CAP_ARM_NISV_TO_USER:
> > + r = 0;
> > + kvm->arch.return_nisv_io_abort_to_user = true;
> > + break;
> > + default:
> > + r = -EINVAL;
> > + break;
> > + }
> > +
> > + return r;
> > +}
> >
> > /**
> > * kvm_arch_init_vm - initializes a VM data structure
> > @@ -196,6 +216,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
> > case KVM_CAP_MP_STATE:
> > case KVM_CAP_IMMEDIATE_EXIT:
> > case KVM_CAP_VCPU_EVENTS:
> > + case KVM_CAP_ARM_NISV_TO_USER:
> > r = 1;
> > break;
> > case KVM_CAP_ARM_SET_DEVICE_ADDR:
> > @@ -673,6 +694,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
> > ret = kvm_handle_mmio_return(vcpu, vcpu->run);
> > if (ret)
> > return ret;
> > + } else if (run->exit_reason == KVM_EXIT_ARM_NISV) {
> > + kvm_inject_undefined(vcpu);
>
> So QEMU can try to enable the feature via IOCTL. And here you would
> raise the 'undefined instruction' exception which QEMU will have to
> handle in the loop calling KVM either by trying to make sense of the
> instruction or by passing it on to the guest.
>
> Conceptually this looks good to me and meets the requirements of my
> application.
>
> Thanks a lot for your suggestion.
>
I will change the undef to an external abort as I think that's more in
line with the architecture, and document this, test and send out as a
proper patch.
Thanks,
Christoffer
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 1/1] KVM: inject data abort if instruction cannot be decoded
From: Christoffer Dall @ 2019-09-06 8:00 UTC (permalink / raw)
To: Marc Zyngier
Cc: Peter Maydell, Daniel P. Berrangé, Heinrich Schuchardt,
lkml - Kernel Mailing List, Stefan Hajnoczi, kvmarm,
arm-mail-list
In-Reply-To: <4b6662bd-56e4-3c10-3b65-7c90828a22f9@kernel.org>
On Thu, Sep 05, 2019 at 02:09:18PM +0100, Marc Zyngier wrote:
> On 05/09/2019 10:22, Christoffer Dall wrote:
> > On Thu, Sep 05, 2019 at 09:56:44AM +0100, Peter Maydell wrote:
> >> On Thu, 5 Sep 2019 at 09:52, Marc Zyngier <maz@kernel.org> wrote:
> >>>
> >>> On Thu, 05 Sep 2019 09:16:54 +0100,
> >>> Peter Maydell <peter.maydell@linaro.org> wrote:
> >>>> This is true, but the problem is that barfing out to userspace
> >>>> makes it harder to debug the guest because it means that
> >>>> the VM is immediately destroyed, whereas AIUI if we
> >>>> inject some kind of exception then (assuming you're set up
> >>>> to do kernel-debug via gdbstub) you can actually examine
> >>>> the offending guest code with a debugger because at least
> >>>> your VM is still around to inspect...
> >>>
> >>> To Christoffer's point, I find the benefit a bit dubious. Yes, you get
> >>> an exception, but the instruction that caused it may be completely
> >>> legal (store with post-increment, for example), leading to an even
> >>> more puzzled developer (that exception should never have been
> >>> delivered the first place).
> >>
> >> Right, but the combination of "host kernel prints a message
> >> about an unsupported load/store insn" and "within-guest debug
> >> dump/stack trace/etc" is much more useful than just having
> >> "host kernel prints message" and "QEMU exits"; and it requires
> >> about 3 lines of code change...
> >>
> >>> I'm far more in favour of dumping the state of the access in the run
> >>> structure (much like we do for a MMIO access) and let userspace do
> >>> something about it (such as dumping information on the console or
> >>> breaking). It could even inject an exception *if* the user has asked
> >>> for it.
> >>
> >> ...whereas this requires agreement on a kernel-userspace API,
> >> larger changes in the kernel, somebody to implement the userspace
> >> side of things, and the user to update both the kernel and QEMU.
> >> It's hard for me to see that the benefit here over the 3-line
> >> approach really outweighs the extra effort needed. In practice
> >> saying "we should do this" is saying "we're going to do nothing",
> >> based on the historical record.
> >>
> >
> > How about something like the following (completely untested, liable for
> > ABI discussions etc. etc., but for illustration purposes).
> >
> > I think it raises the question (and likely many other) of whether we can
> > break the existing 'ABI' and change behavior for missing ISV
> > retrospectively for legacy user space when the issue has occurred?
> >
> > Someone might have written code that reacts to the -ENOSYS, so I've
> > taken the conservative approach for this for the time being.
> >
> >
> > diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
> > index 8a37c8e89777..19a92c49039c 100644
> > --- a/arch/arm/include/asm/kvm_host.h
> > +++ b/arch/arm/include/asm/kvm_host.h
> > @@ -76,6 +76,14 @@ struct kvm_arch {
> >
> > /* Mandated version of PSCI */
> > u32 psci_version;
> > +
> > + /*
> > + * If we encounter a data abort without valid instruction syndrome
> > + * information, report this to user space. User space can (and
> > + * should) opt in to this feature if KVM_CAP_ARM_NISV_TO_USER is
> > + * supported.
> > + */
> > + bool return_nisv_io_abort_to_user;
> > };
> >
> > #define KVM_NR_MEM_OBJS 40
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index f656169db8c3..019bc560edc1 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -83,6 +83,14 @@ struct kvm_arch {
> >
> > /* Mandated version of PSCI */
> > u32 psci_version;
> > +
> > + /*
> > + * If we encounter a data abort without valid instruction syndrome
> > + * information, report this to user space. User space can (and
> > + * should) opt in to this feature if KVM_CAP_ARM_NISV_TO_USER is
> > + * supported.
> > + */
> > + bool return_nisv_io_abort_to_user;
> > };
> >
> > #define KVM_NR_MEM_OBJS 40
> > diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> > index 5e3f12d5359e..a4dd004d0db9 100644
> > --- a/include/uapi/linux/kvm.h
> > +++ b/include/uapi/linux/kvm.h
> > @@ -235,6 +235,7 @@ struct kvm_hyperv_exit {
> > #define KVM_EXIT_S390_STSI 25
> > #define KVM_EXIT_IOAPIC_EOI 26
> > #define KVM_EXIT_HYPERV 27
> > +#define KVM_EXIT_ARM_NISV 28
> >
> > /* For KVM_EXIT_INTERNAL_ERROR */
> > /* Emulate instruction failed. */
> > @@ -996,6 +997,7 @@ struct kvm_ppc_resize_hpt {
> > #define KVM_CAP_ARM_PTRAUTH_ADDRESS 171
> > #define KVM_CAP_ARM_PTRAUTH_GENERIC 172
> > #define KVM_CAP_PMU_EVENT_FILTER 173
> > +#define KVM_CAP_ARM_NISV_TO_USER 174
> >
> > #ifdef KVM_CAP_IRQ_ROUTING
> >
> > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > index 35a069815baf..2ce94bd9d4a9 100644
> > --- a/virt/kvm/arm/arm.c
> > +++ b/virt/kvm/arm/arm.c
> > @@ -98,6 +98,26 @@ int kvm_arch_check_processor_compat(void)
> > return 0;
> > }
> >
> > +int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
> > + struct kvm_enable_cap *cap)
> > +{
> > + int r;
> > +
> > + if (cap->flags)
> > + return -EINVAL;
> > +
> > + switch (cap->cap) {
> > + case KVM_CAP_ARM_NISV_TO_USER:
> > + r = 0;
> > + kvm->arch.return_nisv_io_abort_to_user = true;
> > + break;
> > + default:
> > + r = -EINVAL;
> > + break;
> > + }
> > +
> > + return r;
> > +}
> >
> > /**
> > * kvm_arch_init_vm - initializes a VM data structure
> > @@ -196,6 +216,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
> > case KVM_CAP_MP_STATE:
> > case KVM_CAP_IMMEDIATE_EXIT:
> > case KVM_CAP_VCPU_EVENTS:
> > + case KVM_CAP_ARM_NISV_TO_USER:
> > r = 1;
> > break;
> > case KVM_CAP_ARM_SET_DEVICE_ADDR:
> > @@ -673,6 +694,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
> > ret = kvm_handle_mmio_return(vcpu, vcpu->run);
> > if (ret)
> > return ret;
> > + } else if (run->exit_reason == KVM_EXIT_ARM_NISV) {
> > + kvm_inject_undefined(vcpu);
>
> Just to make sure I understand: Is the expectation here that userspace
> could clear the exit reason if it managed to handle the exit? And
> otherwise we'd inject an UNDEF on reentry?
>
Yes, but I think we should change that to an external abort. I'll test
something and send a proper patch with more clear documentation.
> > }
> >
> > if (run->immediate_exit)
> > diff --git a/virt/kvm/arm/mmio.c b/virt/kvm/arm/mmio.c
> > index 6af5c91337f2..62e6ef47a6de 100644
> > --- a/virt/kvm/arm/mmio.c
> > +++ b/virt/kvm/arm/mmio.c
> > @@ -167,8 +167,15 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
> > if (ret)
> > return ret;
> > } else {
> > - kvm_err("load/store instruction decoding not implemented\n");
> > - return -ENOSYS;
> > + if (vcpu->kvm->arch.return_nisv_io_abort_to_user) {
> > + run->exit_reason = KVM_EXIT_ARM_NISV;
> > + run->mmio.phys_addr = fault_ipa;
>
> We could also record whether that's a read or a write (WnR should still
> be valid). Actually, we could store a sanitized version of the ESR.
>
Ah yes, I'll incorporate that.
> > + vcpu->stat.mmio_exit_user++;
> > + return 0;
> > + } else {
> > + kvm_info("encountered data abort without syndrome info\n");
>
> My only issue with this is that the previous message has been sort of
> documented...
Well, my main gripe with the current code is that the error message is
massively misleading because it explains one possible case, which is
very "kernel part of a KVM VM centric" and is actually not the common
scenario that people encounter.
Let me work on the particular wording of the error message and see if I
can achieve something self-documenting.
Thanks,
Christoffer
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [v2] ACPI: support for NXP i2c controller
From: Biwen Li @ 2019-09-06 7:53 UTC (permalink / raw)
To: andy.shevchenko, rafael, leoyang.li, meenakshi.aggarwal,
udit.kumar, wsa, rjw
Cc: Biwen Li, s.hauer, linux-kernel, linux-acpi, linux-i2c,
chuanhua.han, shawnguo, linux-arm-kernel
From: Chuanhua Han <chuanhua.han@nxp.com>
Enable NXP i2c controller to boot with ACPI
Signed-off-by: Meenakshi Aggarwal <meenakshi.aggarwal@nxp.com>
Signed-off-by: Udit Kumar <udit.kumar@nxp.com>
Signed-off-by: Chuanhua Han <chuanhua.han@nxp.com>
Signed-off-by: Biwen Li <biwen.li@nxp.com>
---
Change in v2:
- Simplify code
- Adjust header file order
- Not use ACPI_PTR()
drivers/acpi/acpi_apd.c | 7 +++++++
drivers/i2c/busses/i2c-imx.c | 17 +++++++++++++----
2 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c
index 7cd0c9ac71ea..71511ae2dfcd 100644
--- a/drivers/acpi/acpi_apd.c
+++ b/drivers/acpi/acpi_apd.c
@@ -160,11 +160,17 @@ static const struct apd_device_desc hip08_i2c_desc = {
.setup = acpi_apd_setup,
.fixed_clk_rate = 250000000,
};
+
static const struct apd_device_desc thunderx2_i2c_desc = {
.setup = acpi_apd_setup,
.fixed_clk_rate = 125000000,
};
+static const struct apd_device_desc nxp_i2c_desc = {
+ .setup = acpi_apd_setup,
+ .fixed_clk_rate = 350000000,
+};
+
static const struct apd_device_desc hip08_spi_desc = {
.setup = acpi_apd_setup,
.fixed_clk_rate = 250000000,
@@ -238,6 +244,7 @@ static const struct acpi_device_id acpi_apd_device_ids[] = {
{ "HISI02A1", APD_ADDR(hip07_i2c_desc) },
{ "HISI02A2", APD_ADDR(hip08_i2c_desc) },
{ "HISI0173", APD_ADDR(hip08_spi_desc) },
+ { "NXP0001", APD_ADDR(nxp_i2c_desc) },
#endif
{ }
};
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 15f6cde6452f..a3b61336fe55 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -20,6 +20,7 @@
*
*/
+#include <linux/acpi.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/delay.h>
@@ -255,6 +256,12 @@ static const struct of_device_id i2c_imx_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, i2c_imx_dt_ids);
+static const struct acpi_device_id i2c_imx_acpi_ids[] = {
+ {"NXP0001", .driver_data = (kernel_ulong_t)&vf610_i2c_hwdata},
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, i2c_imx_acpi_ids);
+
static inline int is_imx1_i2c(struct imx_i2c_struct *i2c_imx)
{
return i2c_imx->hwdata->devtype == IMX1_I2C;
@@ -1048,14 +1055,13 @@ static const struct i2c_algorithm i2c_imx_algo = {
static int i2c_imx_probe(struct platform_device *pdev)
{
- const struct of_device_id *of_id = of_match_device(i2c_imx_dt_ids,
- &pdev->dev);
struct imx_i2c_struct *i2c_imx;
struct resource *res;
struct imxi2c_platform_data *pdata = dev_get_platdata(&pdev->dev);
void __iomem *base;
int irq, ret;
dma_addr_t phy_addr;
+ const struct imx_i2c_hwdata *match;
dev_dbg(&pdev->dev, "<%s>\n", __func__);
@@ -1075,8 +1081,9 @@ static int i2c_imx_probe(struct platform_device *pdev)
if (!i2c_imx)
return -ENOMEM;
- if (of_id)
- i2c_imx->hwdata = of_id->data;
+ match = device_get_match_data(&pdev->dev);
+ if (match)
+ i2c_imx->hwdata = match;
else
i2c_imx->hwdata = (struct imx_i2c_hwdata *)
platform_get_device_id(pdev)->driver_data;
@@ -1089,6 +1096,7 @@ static int i2c_imx_probe(struct platform_device *pdev)
i2c_imx->adapter.nr = pdev->id;
i2c_imx->adapter.dev.of_node = pdev->dev.of_node;
i2c_imx->base = base;
+ ACPI_COMPANION_SET(&i2c_imx->adapter.dev, ACPI_COMPANION(&pdev->dev));
/* Get I2C clock */
i2c_imx->clk = devm_clk_get(&pdev->dev, NULL);
@@ -1247,6 +1255,7 @@ static struct platform_driver i2c_imx_driver = {
.name = DRIVER_NAME,
.pm = &i2c_imx_pm_ops,
.of_match_table = i2c_imx_dt_ids,
+ .acpi_match_table = i2c_imx_acpi_ids,
},
.id_table = imx_i2c_devtype,
};
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 1/2] perf/imx_ddr: add enhanced AXI ID filter support
From: Joakim Zhang @ 2019-09-06 8:26 UTC (permalink / raw)
To: will@kernel.org, mark.rutland@arm.com, robin.murphy@arm.com,
Frank Li
Cc: dl-linux-imx, linux-arm-kernel@lists.infradead.org, Joakim Zhang
With DDR_CAP_AXI_ID_FILTER quirk, indicating HW supports AXI ID filter
which only can get bursts of reading/writing DDR, i.e. DDR read/write
request.
This patch add DDR_CAP_AXI_ID_ENHANCED_FILTER quirk, indicating HW
supports AXI ID filter which can get bytes of reading/writing DDR. This
feature is more meaningful due to we always care more about bandwidth.
Need select both above two qiurks together when HW support enhanced AXI
ID filter.
Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
---
drivers/perf/fsl_imx8_ddr_perf.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/drivers/perf/fsl_imx8_ddr_perf.c b/drivers/perf/fsl_imx8_ddr_perf.c
index ce7345745b42..5f70dbfa9607 100644
--- a/drivers/perf/fsl_imx8_ddr_perf.c
+++ b/drivers/perf/fsl_imx8_ddr_perf.c
@@ -45,7 +45,8 @@
static DEFINE_IDA(ddr_ida);
/* DDR Perf hardware feature */
-#define DDR_CAP_AXI_ID_FILTER 0x1 /* support AXI ID filter */
+#define DDR_CAP_AXI_ID_FILTER BIT(1) /* support AXI ID filter */
+#define DDR_CAP_AXI_ID_FILTER_ENHANCED BIT(2) /* support enhanced AXI ID filter */
struct fsl_ddr_devtype_data {
unsigned int quirks; /* quirks needed for different DDR Perf core */
@@ -209,7 +210,15 @@ static void ddr_perf_free_counter(struct ddr_pmu *pmu, int counter)
static u32 ddr_perf_read_counter(struct ddr_pmu *pmu, int counter)
{
- return readl_relaxed(pmu->base + COUNTER_READ + counter * 4);
+ if ((pmu->devtype_data->quirks & DDR_CAP_AXI_ID_FILTER) &&
+ (pmu->devtype_data->quirks & DDR_CAP_AXI_ID_FILTER_ENHANCED)) {
+ if ((pmu->events[counter]->attr.config == 0x41) ||
+ (pmu->events[counter]->attr.config == 0x42))
+ return readl_relaxed(pmu->base + COUNTER_DPCR1 + counter * 4);
+ else
+ return readl_relaxed(pmu->base + COUNTER_READ + counter * 4);
+ } else
+ return readl_relaxed(pmu->base + COUNTER_READ + counter * 4);
}
static bool ddr_perf_is_filtered(struct perf_event *event)
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 2/2] doc/perf: add DDR_CAP_AXI_ID_FILTER_ENHANCED quirk explanation
From: Joakim Zhang @ 2019-09-06 8:26 UTC (permalink / raw)
To: will@kernel.org, mark.rutland@arm.com, robin.murphy@arm.com,
Frank Li
Cc: dl-linux-imx, linux-arm-kernel@lists.infradead.org, Joakim Zhang
In-Reply-To: <20190906082356.25485-1-qiangqing.zhang@nxp.com>
Add DDR_CAP_AXI_ID_FILTER_ENHANCED quirk explanation.
Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
---
Documentation/admin-guide/perf/imx-ddr.rst | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/Documentation/admin-guide/perf/imx-ddr.rst b/Documentation/admin-guide/perf/imx-ddr.rst
index 45943c7325e3..0f2170974701 100644
--- a/Documentation/admin-guide/perf/imx-ddr.rst
+++ b/Documentation/admin-guide/perf/imx-ddr.rst
@@ -51,3 +51,10 @@ in the driver.
e.g.::
perf stat -a -e imx8_ddr0/axid-read,axi_id=0x12/ cmd, which will monitor ARID=0x12
+* With DDR_CAP_AXI_ID_FILTER_ENHANCED quirk.
+ This is the extension of DDR_CAP_AXI_ID_FILTER quirk which is only support getting
+ bursts from DDR reading or writing, i.e. only can get DDR read or write requests.
+ You can select both DDR_CAP_AXI_ID_FILTER and DDR_CAP_AXI_ID_FILTER_ENHANCED
+ quirks together to get bytes of reading or writing DDR if HW supports this
+ enhanced filter. It is meaningful as user always care more about each master's
+ bandwidth.
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH 1/1] PCI: iproc: Invalidate PAXB address mapping before programming it
From: Andrew Murray @ 2019-09-06 8:38 UTC (permalink / raw)
To: Abhishek Shah
Cc: Lorenzo Pieralisi, Scott Branden, Ray Jui, linux-kernel,
bcm-kernel-feedback-list, linux-pci, Bjorn Helgaas,
linux-arm-kernel
In-Reply-To: <20190906035813.24046-1-abhishek.shah@broadcom.com>
On Fri, Sep 06, 2019 at 09:28:13AM +0530, Abhishek Shah wrote:
> Invalidate PAXB inbound/outbound address mapping each time before
> programming it. This is helpful for the cases where we need to
> reprogram inbound/outbound address mapping without resetting PAXB.
> kexec kernel is one such example.
Why is this approach better than resetting the PAXB (I assume that's
the PCI controller IP)? Wouldn't resetting the PAXB address this issue,
and ensure that no other configuration is left behind?
Or is this related to earlier boot stages loading firmware for the emulated
downstream endpoints (ep_is_internal)?
Finally, in the case where ep_is_internal do you need to disable anything
prior to invalidating the mappings?
>
> Signed-off-by: Abhishek Shah <abhishek.shah@broadcom.com>
> Reviewed-by: Ray Jui <ray.jui@broadcom.com>
> Reviewed-by: Vikram Mysore Prakash <vikram.prakash@broadcom.com>
> ---
> drivers/pci/controller/pcie-iproc.c | 28 ++++++++++++++++++++++++++++
> 1 file changed, 28 insertions(+)
>
> diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c
> index e3ca46497470..99a9521ba7ab 100644
> --- a/drivers/pci/controller/pcie-iproc.c
> +++ b/drivers/pci/controller/pcie-iproc.c
> @@ -1245,6 +1245,32 @@ static int iproc_pcie_map_dma_ranges(struct iproc_pcie *pcie)
> return ret;
> }
>
> +static void iproc_pcie_invalidate_mapping(struct iproc_pcie *pcie)
> +{
> + struct iproc_pcie_ib *ib = &pcie->ib;
> + struct iproc_pcie_ob *ob = &pcie->ob;
> + int idx;
> +
> + if (pcie->ep_is_internal)
> + return;
> +
> + if (pcie->need_ob_cfg) {
> + /* iterate through all OARR mapping regions */
> + for (idx = ob->nr_windows - 1; idx >= 0; idx--) {
> + iproc_pcie_write_reg(pcie,
> + MAP_REG(IPROC_PCIE_OARR0, idx), 0);
> + }
> + }
> +
> + if (pcie->need_ib_cfg) {
> + /* iterate through all IARR mapping regions */
> + for (idx = 0; idx < ib->nr_regions; idx++) {
> + iproc_pcie_write_reg(pcie,
> + MAP_REG(IPROC_PCIE_IARR0, idx), 0);
> + }
> + }
> +}
> +
> static int iproce_pcie_get_msi(struct iproc_pcie *pcie,
> struct device_node *msi_node,
> u64 *msi_addr)
> @@ -1517,6 +1543,8 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
> iproc_pcie_perst_ctrl(pcie, true);
> iproc_pcie_perst_ctrl(pcie, false);
>
> + iproc_pcie_invalidate_mapping(pcie);
> +
> if (pcie->need_ob_cfg) {
> ret = iproc_pcie_map_ranges(pcie, res);
> if (ret) {
The code changes look good to me.
Thanks,
Andrew Murray
> --
> 2.17.1
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 3/4] gpio: of: Switch to EXPORT_SYMBOL_GPL()
From: Geert Uytterhoeven @ 2019-09-06 8:45 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski
Cc: devicetree, Geert Uytterhoeven, linux-kernel, linux-gpio,
Rob Herring, Frank Rowand, linux-arm-kernel
In-Reply-To: <20190906084539.21838-1-geert+renesas@glider.be>
All exported functions provide genuine Linux-specific functionality.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
drivers/gpio/gpiolib-of.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index fad3aad667558325..7aea6d0f3ace9b82 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -274,7 +274,7 @@ int of_get_named_gpio_flags(struct device_node *np, const char *list_name,
else
return desc_to_gpio(desc);
}
-EXPORT_SYMBOL(of_get_named_gpio_flags);
+EXPORT_SYMBOL_GPL(of_get_named_gpio_flags);
/**
* gpiod_get_from_of_node() - obtain a GPIO from an OF node
@@ -343,7 +343,7 @@ struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
return desc;
}
-EXPORT_SYMBOL(gpiod_get_from_of_node);
+EXPORT_SYMBOL_GPL(gpiod_get_from_of_node);
/*
* The SPI GPIO bindings happened before we managed to establish that GPIO
@@ -719,7 +719,7 @@ int of_mm_gpiochip_add_data(struct device_node *np,
pr_err("%pOF: GPIO chip registration failed with status %d\n", np, ret);
return ret;
}
-EXPORT_SYMBOL(of_mm_gpiochip_add_data);
+EXPORT_SYMBOL_GPL(of_mm_gpiochip_add_data);
/**
* of_mm_gpiochip_remove - Remove memory mapped GPIO chip (bank)
@@ -736,7 +736,7 @@ void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc)
iounmap(mm_gc->regs);
kfree(gc->label);
}
-EXPORT_SYMBOL(of_mm_gpiochip_remove);
+EXPORT_SYMBOL_GPL(of_mm_gpiochip_remove);
static void of_gpiochip_init_valid_mask(struct gpio_chip *chip)
{
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 1/4] gpio: of: Make of_get_named_gpiod_flags() private
From: Geert Uytterhoeven @ 2019-09-06 8:45 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski
Cc: devicetree, Geert Uytterhoeven, linux-kernel, linux-gpio,
Rob Herring, Frank Rowand, linux-arm-kernel
In-Reply-To: <20190906084539.21838-1-geert+renesas@glider.be>
Since commit f626d6dfb7098525 ("gpio: of: Break out OF-only code"),
there are no more users of of_get_named_gpiod_flags() outside
gpiolib-of.c.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
drivers/gpio/gpiolib-of.c | 2 +-
drivers/gpio/gpiolib-of.h | 7 -------
2 files changed, 1 insertion(+), 8 deletions(-)
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index b034abe59f287bff..4c6b366cb7bd5cd0 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -223,7 +223,7 @@ static void of_gpio_flags_quirks(struct device_node *np,
* value on the error condition. If @flags is not NULL the function also fills
* in flags for the GPIO.
*/
-struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
+static struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
const char *propname, int index, enum of_gpio_flags *flags)
{
struct of_phandle_args gpiospec;
diff --git a/drivers/gpio/gpiolib-of.h b/drivers/gpio/gpiolib-of.h
index 454d1658ee2d45fb..9768831b1fe2f25b 100644
--- a/drivers/gpio/gpiolib-of.h
+++ b/drivers/gpio/gpiolib-of.h
@@ -11,8 +11,6 @@ struct gpio_desc *of_find_gpio(struct device *dev,
const char *con_id,
unsigned int idx,
unsigned long *lookupflags);
-struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
- const char *list_name, int index, enum of_gpio_flags *flags);
int of_gpiochip_add(struct gpio_chip *gc);
void of_gpiochip_remove(struct gpio_chip *gc);
int of_gpio_get_count(struct device *dev, const char *con_id);
@@ -25,11 +23,6 @@ static inline struct gpio_desc *of_find_gpio(struct device *dev,
{
return ERR_PTR(-ENOENT);
}
-static inline struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
- const char *list_name, int index, enum of_gpio_flags *flags)
-{
- return ERR_PTR(-ENOENT);
-}
static inline int of_gpiochip_add(struct gpio_chip *gc) { return 0; }
static inline void of_gpiochip_remove(struct gpio_chip *gc) { }
static inline int of_gpio_get_count(struct device *dev, const char *con_id)
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 0/4] gpio: API boundary cleanups
From: Geert Uytterhoeven @ 2019-09-06 8:45 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski
Cc: devicetree, Geert Uytterhoeven, linux-kernel, linux-gpio,
Rob Herring, Frank Rowand, linux-arm-kernel
Hi Linus, Bartosz,
This patch series contains various API boundary cleanups for gpiolib:
- The first two patches make two functions private,
- The last two patches switch the remaining gpiolib exported functions
from EXPORT_SYMBOL() to EXPORT_SYMBOL_GPL().
After this there is only a single GPIO driver function exported with
EXPORT_SYMBOL();
drivers/gpio/gpio-htc-egpio.c:EXPORT_SYMBOL(htc_egpio_get_wakeup_irq);
I believe this symbol was never used upstream, and may be a relic of the
original out-of-tree code the htc-egpio was based on. I don't know if
there (still) exist out-of-tree users of the symbol.
Thanks for your comments!
Geert Uytterhoeven (4):
gpio: of: Make of_get_named_gpiod_flags() private
gpio: of: Make of_gpio_simple_xlate() private
gpio: of: Switch to EXPORT_SYMBOL_GPL()
gpio: devres: Switch to EXPORT_SYMBOL_GPL()
drivers/gpio/gpiolib-devres.c | 28 ++++++++++++++--------------
drivers/gpio/gpiolib-of.c | 16 ++++++++--------
drivers/gpio/gpiolib-of.h | 7 -------
include/linux/of_gpio.h | 11 -----------
4 files changed, 22 insertions(+), 40 deletions(-)
--
2.17.1
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 4/4] gpio: devres: Switch to EXPORT_SYMBOL_GPL()
From: Geert Uytterhoeven @ 2019-09-06 8:45 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski
Cc: devicetree, Geert Uytterhoeven, linux-kernel, linux-gpio,
Rob Herring, Frank Rowand, linux-arm-kernel
In-Reply-To: <20190906084539.21838-1-geert+renesas@glider.be>
Change all exported symbols for managed GPIO functions from
EXPORT_SYMBOL() to EXPORT_SYMBOL_GPL(), like is used for their
non-managed counterparts.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
The only exception was gpiod_get_from_of_node(), as everything in
drivers/gpio/gpiolib-of.c used EXPORT_SYMBOL(), until the previous
patch.
---
drivers/gpio/gpiolib-devres.c | 28 ++++++++++++++--------------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/drivers/gpio/gpiolib-devres.c b/drivers/gpio/gpiolib-devres.c
index 0acc2cc6e868fdef..98e3c20d9730e66a 100644
--- a/drivers/gpio/gpiolib-devres.c
+++ b/drivers/gpio/gpiolib-devres.c
@@ -59,7 +59,7 @@ struct gpio_desc *__must_check devm_gpiod_get(struct device *dev,
{
return devm_gpiod_get_index(dev, con_id, 0, flags);
}
-EXPORT_SYMBOL(devm_gpiod_get);
+EXPORT_SYMBOL_GPL(devm_gpiod_get);
/**
* devm_gpiod_get_optional - Resource-managed gpiod_get_optional()
@@ -77,7 +77,7 @@ struct gpio_desc *__must_check devm_gpiod_get_optional(struct device *dev,
{
return devm_gpiod_get_index_optional(dev, con_id, 0, flags);
}
-EXPORT_SYMBOL(devm_gpiod_get_optional);
+EXPORT_SYMBOL_GPL(devm_gpiod_get_optional);
/**
* devm_gpiod_get_index - Resource-managed gpiod_get_index()
@@ -127,7 +127,7 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
return desc;
}
-EXPORT_SYMBOL(devm_gpiod_get_index);
+EXPORT_SYMBOL_GPL(devm_gpiod_get_index);
/**
* devm_gpiod_get_from_of_node() - obtain a GPIO from an OF node
@@ -182,7 +182,7 @@ struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
return desc;
}
-EXPORT_SYMBOL(devm_gpiod_get_from_of_node);
+EXPORT_SYMBOL_GPL(devm_gpiod_get_from_of_node);
/**
* devm_fwnode_get_index_gpiod_from_child - get a GPIO descriptor from a
@@ -239,7 +239,7 @@ struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev,
return desc;
}
-EXPORT_SYMBOL(devm_fwnode_get_index_gpiod_from_child);
+EXPORT_SYMBOL_GPL(devm_fwnode_get_index_gpiod_from_child);
/**
* devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional()
@@ -268,7 +268,7 @@ struct gpio_desc *__must_check devm_gpiod_get_index_optional(struct device *dev,
return desc;
}
-EXPORT_SYMBOL(devm_gpiod_get_index_optional);
+EXPORT_SYMBOL_GPL(devm_gpiod_get_index_optional);
/**
* devm_gpiod_get_array - Resource-managed gpiod_get_array()
@@ -303,7 +303,7 @@ struct gpio_descs *__must_check devm_gpiod_get_array(struct device *dev,
return descs;
}
-EXPORT_SYMBOL(devm_gpiod_get_array);
+EXPORT_SYMBOL_GPL(devm_gpiod_get_array);
/**
* devm_gpiod_get_array_optional - Resource-managed gpiod_get_array_optional()
@@ -328,7 +328,7 @@ devm_gpiod_get_array_optional(struct device *dev, const char *con_id,
return descs;
}
-EXPORT_SYMBOL(devm_gpiod_get_array_optional);
+EXPORT_SYMBOL_GPL(devm_gpiod_get_array_optional);
/**
* devm_gpiod_put - Resource-managed gpiod_put()
@@ -344,7 +344,7 @@ void devm_gpiod_put(struct device *dev, struct gpio_desc *desc)
WARN_ON(devres_release(dev, devm_gpiod_release, devm_gpiod_match,
&desc));
}
-EXPORT_SYMBOL(devm_gpiod_put);
+EXPORT_SYMBOL_GPL(devm_gpiod_put);
/**
* devm_gpiod_unhinge - Remove resource management from a gpio descriptor
@@ -374,7 +374,7 @@ void devm_gpiod_unhinge(struct device *dev, struct gpio_desc *desc)
/* Anything else we should warn about */
WARN_ON(ret);
}
-EXPORT_SYMBOL(devm_gpiod_unhinge);
+EXPORT_SYMBOL_GPL(devm_gpiod_unhinge);
/**
* devm_gpiod_put_array - Resource-managed gpiod_put_array()
@@ -390,7 +390,7 @@ void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs)
WARN_ON(devres_release(dev, devm_gpiod_release_array,
devm_gpiod_match_array, &descs));
}
-EXPORT_SYMBOL(devm_gpiod_put_array);
+EXPORT_SYMBOL_GPL(devm_gpiod_put_array);
@@ -444,7 +444,7 @@ int devm_gpio_request(struct device *dev, unsigned gpio, const char *label)
return 0;
}
-EXPORT_SYMBOL(devm_gpio_request);
+EXPORT_SYMBOL_GPL(devm_gpio_request);
/**
* devm_gpio_request_one - request a single GPIO with initial setup
@@ -474,7 +474,7 @@ int devm_gpio_request_one(struct device *dev, unsigned gpio,
return 0;
}
-EXPORT_SYMBOL(devm_gpio_request_one);
+EXPORT_SYMBOL_GPL(devm_gpio_request_one);
/**
* devm_gpio_free - free a GPIO
@@ -492,4 +492,4 @@ void devm_gpio_free(struct device *dev, unsigned int gpio)
WARN_ON(devres_release(dev, devm_gpio_release, devm_gpio_match,
&gpio));
}
-EXPORT_SYMBOL(devm_gpio_free);
+EXPORT_SYMBOL_GPL(devm_gpio_free);
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 2/4] gpio: of: Make of_gpio_simple_xlate() private
From: Geert Uytterhoeven @ 2019-09-06 8:45 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski
Cc: devicetree, Geert Uytterhoeven, linux-kernel, linux-gpio,
Rob Herring, Frank Rowand, linux-arm-kernel
In-Reply-To: <20190906084539.21838-1-geert+renesas@glider.be>
Since commit 9a95e8d25a140ba9 ("gpio: remove etraxfs driver"), there are
no more users of of_gpio_simple_xlate() outside gpiolib-of.c.
All GPIO drivers that need it now rely on of_gpiochip_add() setting it
up as the default translate function.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
drivers/gpio/gpiolib-of.c | 6 +++---
include/linux/of_gpio.h | 11 -----------
2 files changed, 3 insertions(+), 14 deletions(-)
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 4c6b366cb7bd5cd0..fad3aad667558325 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -637,8 +637,9 @@ static int of_gpiochip_scan_gpios(struct gpio_chip *chip)
* GPIO chips. This function performs only one sanity check: whether GPIO
* is less than ngpios (that is specified in the gpio_chip).
*/
-int of_gpio_simple_xlate(struct gpio_chip *gc,
- const struct of_phandle_args *gpiospec, u32 *flags)
+static int of_gpio_simple_xlate(struct gpio_chip *gc,
+ const struct of_phandle_args *gpiospec,
+ u32 *flags)
{
/*
* We're discouraging gpio_cells < 2, since that way you'll have to
@@ -662,7 +663,6 @@ int of_gpio_simple_xlate(struct gpio_chip *gc,
return gpiospec->args[0];
}
-EXPORT_SYMBOL(of_gpio_simple_xlate);
/**
* of_mm_gpiochip_add_data - Add memory mapped GPIO chip (bank)
diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h
index f9737dea9d1f945a..16967390a3fe3b12 100644
--- a/include/linux/of_gpio.h
+++ b/include/linux/of_gpio.h
@@ -61,10 +61,6 @@ static inline int of_mm_gpiochip_add(struct device_node *np,
}
extern void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc);
-extern int of_gpio_simple_xlate(struct gpio_chip *gc,
- const struct of_phandle_args *gpiospec,
- u32 *flags);
-
#else /* CONFIG_OF_GPIO */
/* Drivers may not strictly depend on the GPIO support, so let them link. */
@@ -77,13 +73,6 @@ static inline int of_get_named_gpio_flags(struct device_node *np,
return -ENOSYS;
}
-static inline int of_gpio_simple_xlate(struct gpio_chip *gc,
- const struct of_phandle_args *gpiospec,
- u32 *flags)
-{
- return -ENOSYS;
-}
-
#endif /* CONFIG_OF_GPIO */
/**
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [GIT PULL 2/4] DaVinci defconfig updates for v5.4
From: Arnd Bergmann @ 2019-09-06 8:46 UTC (permalink / raw)
To: Peter Ujfalusi
Cc: Bartosz Golaszewski, ARM-SoC Maintainers, Sekhar Nori,
Linux ARM Mailing List
In-Reply-To: <52d010f7-29e4-4a64-6f78-731c49766535@ti.com>
On Fri, Sep 6, 2019 at 8:31 AM Peter Ujfalusi <peter.ujfalusi@ti.com> wrote:
> On 04/09/2019 17.51, Arnd Bergmann wrote:
> > On Wed, Aug 28, 2019 at 5:18 PM Sekhar Nori <nsekhar@ti.com> wrote:
> >
> > -# CONFIG_IOSCHED_DEADLINE is not set
> > -# CONFIG_IOSCHED_CFQ is not set
> > -CONFIG_PREEMPT=y
> > -CONFIG_SND_SOC_TLV320AIC3X=m
> > -CONFIG_SND_SOC_DAVINCI_MCASP=m
> > -CONFIG_LEDS_TRIGGERS=y
> > -CONFIG_TI_EDMA=y
>
> EDMA is kind of needed on daVinci, no?
> aic3x and McASP can be good if you want audio support on the boards...
That was my thought as well, but after looking closer I found
that they are enabled implicitly. However, I really prefer not having
to take a closer look when I get a pull request, hence the request
to split up these patches into obvious ones that explain
what is going on.
Arnd
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* RE: [PATCH v2] pinctrl: at91-pio4: implement .get_multiple and .set_multiple
From: David Laight @ 2019-09-06 9:05 UTC (permalink / raw)
To: 'Alexandre Belloni', Linus Walleij
Cc: linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org,
Ludovic Desroches, Claudiu.Beznea@microchip.com,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <20190905144849.24882-1-alexandre.belloni@bootlin.com>
From: Alexandre Belloni
> Implement .get_multiple and .set_multiple to allow reading or setting
> multiple pins simultaneously. Pins in the same bank will all be switched at
> the same time, improving synchronization and performances.
Actually it won't 'improve synchronisation', instead it will lead to
random synchronisation errors and potential metastability if one
pin is used as a clock and another as data, or if the code is reading
a free-flowing counter.
It will improve performance though.
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v2] pinctrl: at91-pio4: implement .get_multiple and .set_multiple
From: Alexandre Belloni @ 2019-09-06 9:12 UTC (permalink / raw)
To: David Laight
Cc: Linus Walleij, linux-kernel@vger.kernel.org,
linux-gpio@vger.kernel.org, Ludovic Desroches,
Claudiu.Beznea@microchip.com,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <2261eadf98584d13a490f2abd8777d4a@AcuMS.aculab.com>
On 06/09/2019 09:05:36+0000, David Laight wrote:
> From: Alexandre Belloni
> > Implement .get_multiple and .set_multiple to allow reading or setting
> > multiple pins simultaneously. Pins in the same bank will all be switched at
> > the same time, improving synchronization and performances.
>
> Actually it won't 'improve synchronisation', instead it will lead to
> random synchronisation errors and potential metastability if one
> pin is used as a clock and another as data, or if the code is reading
> a free-flowing counter.
>
It does improve gpio switching synchronisation when they are in the same
bank as it will remove the 250ns delay. Of course, if you need this
delay between clk and data, then the consumer driver should ensure the
delay is present.
> It will improve performance though.
>
> David
>
> -
> Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
> Registration No: 1397386 (Wales)
>
--
Alexandre Belloni, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [RFC PATCH V2 4/6] platform: mtk-isp: Add Mediatek DIP driver
From: Frederic Chen @ 2019-09-06 9:16 UTC (permalink / raw)
To: Tomasz Figa
Cc: yuzhao@chromium.org, linux-mediatek@lists.infradead.org,
zwisler@chromium.org, matthias.bgg@gmail.com, mchehab@kernel.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <CAAFQd5B7WM-uExpo-qpEyDMNXLQkvqO=qBDrkpNvERr+iXVhtw@mail.gmail.com>
Hi Tomasz,
Thank you for your comments.
On Fri, 2019-08-30 at 16:14 +0900, Tomasz Figa wrote:
> Hi Frederic,
>
> On Tue, Aug 27, 2019 at 12:16 PM Frederic Chen
> <frederic.chen@mediatek.com> wrote:
> >
> > Dear Tomasz,
> >
> > I appreciate your comment. I will collaborate more closely with Jungo
> > to solve the common issues in DIP and Pass 1(CAM) drivers.
> >
>
> Thank you!
>
> Also thanks for replying to all the comments, it's very helpful.
> Please check my replies inline. I've snipped out the parts that I
> don't have further comments on.
>
> >
> > On Wed, 2019-07-31 at 15:10 +0800, Tomasz Figa wrote:
> > > Hi Frederic,
> > >
> > > On Mon, Jul 08, 2019 at 07:04:58PM +0800, frederic.chen@mediatek.com wrote:
>
> [snip]
>
> > >
> > > > + dev_buf->vbb.vb2_buf.timestamp =
> > > > + in_buf->vbb.vb2_buf.timestamp;
> > > > +
> > > > + vb2_buffer_done(&dev_buf->vbb.vb2_buf, vbf_state);
> > > > +
> > > > + node = mtk_dip_vbq_to_node(dev_buf->vbb.vb2_buf.vb2_queue);
> > > > + spin_lock(&node->buf_list_lock);
> > > > + list_del(&dev_buf->list);
> > > > + spin_unlock(&node->buf_list_lock);
> > > > +
> > > > + dev_dbg(&pipe->dip_dev->pdev->dev,
> > > > + "%s:%s: return buf, idx(%d), state(%d)\n",
> > > > + pipe->desc->name, node->desc->name,
> > > > + dev_buf->vbb.vb2_buf.index, vbf_state);
> > > > + }
> > >
> > > This looks almost the same as what's being done inside
> > > mtk_dip_hw_streamoff(). Could we just call this function from the loop
> > > there?
> >
> > I would like to call the function from mtk_dip_hw_streamoff(). The only
> > difference is mtk_dip_pipe_job_finish() also remove the buffer from the
> > node's internal list.
> >
>
> Would anything wrong happen if we also remove the buffer from the
> node's internal list in mtk_dip_hw_streamoff()?
>
> Actually, do we need that internal node list? If we have a list of
> requests and each request stores its buffer, wouldn't that be enough?
>
We use the buffer list in the following cases:
1. media_pipeline_start() failed when streaming on video device
2. Video device stream off
If the some video device is streamed on ,but the entire pipe has not
started streaming (for example, MDP 0 is streamed on, but RAW input has
not been streamed on), we use the list to return the buffers.
Should we handle this cases? or we expect that the user will request
buffers again to ensure all buffers are removed from the video device in
this error case.
> [snip]
>
> > >
> > > > +
> > > > + width = ALIGN(width, 4);
> > > > + stride = DIV_ROUND_UP(width * 3, 2);
> > > > + stride = DIV_ROUND_UP(stride * pixel_byte, 8);
> > > > +
> > > > + if (pix_fmt == V4L2_PIX_FMT_MTISP_F10)
> > > > + stride = ALIGN(stride, 4);
> > > > + else
> > > > + stride = ALIGN(stride, 8);
> > >
> > > Could you explain all the calculations done above?
> >
> > If the buffer comes from mtk-cam-p1, the stride setting must be the same
> > as p1. I would like to re-implement the codes following p1's design in
> > v4 patch as following:
> >
> > static u32
> > mtk_dip_pass1_cal_pack_stride(u32 width, u32 pix_fmt) {
> > unsigned int bpl;
> > unsigned int pixel_bits =
> > get_pixel_byte_by_fmt(mp->pixelformat);
> >
> > /* Bayer encoding format, P1 HW needs 2 bytes alignment */
> > bpl = ALIGN(DIV_ROUND_UP(width * pixel_bits, 8), 2);
> >
> > /* The setting also needs 4 bytes alignment for DIP HW */
> > return ALIGN(bpl, 4);;
>
> If we need 4 bytes alignment, wouldn't the bytes per line value end up
> different from P1 anyway? Perhaps we can just remove the ALIGN(..., 2)
> above and keep this one? It should be the userspace responsibility
> anyway to choose a format compatible with both consumer and producer.
>
> By the way, double semicolon in the line above. :)
>
I would like to remove the ALIGN(..., 2).
> > }
> >
> >
> > static __u32
> > mtk_dip_pass1_cal_main_stride(u32 width, u32 pix_fmt)
> > {
> > unsigned int bpl, ppl;
> > unsigned int pixel_bits =
> > get_pixel_byte_by_fmt(mp->pixelformat);
> >
> > /*
> > * The FULL-G encoding format
> > * 1 G component per pixel
> > * 1 R component per 4 pixel
> > * 1 B component per 4 pixel
> > * Total 4G/1R/1B in 4 pixel (pixel per line:ppl)
> > */
> > ppl = DIV_ROUND_UP(width * 6, 4);
> > bpl = DIV_ROUND_UP(ppl * pixel_bits, 8);
> >
> > /* 4 bytes alignment for 10 bit & others are 8 bytes */
> > if (pixel_bits == 10)
> > bpl = ALIGN(bpl, 4);
> > else
> > bpl = ALIGN(bpl, 8);
> > }
>
> Spurious }.
>
> >
> > return bpl;
> > }
> >
>
> Looks good to me, thanks!
>
> >
> > >
> > > > +
> > > > + return stride;
> > > > +}
> > > > +
> > > > +static int is_stride_need_to_align(u32 format, u32 *need_aligned_fmts,
> > > > + int length)
> > > > +{
> > > > + int i;
> > > > +
> > > > + for (i = 0; i < length; i++) {
> > > > + if (format == need_aligned_fmts[i])
> > > > + return true;
> > > > + }
> > > > +
> > > > + return false;
> > > > +}
> > > > +
> > > > +/* Stride that is accepted by MDP HW */
> > > > +static u32 dip_mdp_fmt_get_stride(struct v4l2_pix_format_mplane *mfmt,
> > > > + const struct mtk_dip_dev_format *fmt,
> > > > + unsigned int plane)
> > > > +{
> > > > + enum mdp_color c = fmt->mdp_color;
> > > > + u32 bytesperline = (mfmt->width * fmt->row_depth[plane]) / 8;
> > > > + u32 stride = (bytesperline * MDP_COLOR_BITS_PER_PIXEL(c))
> > > > + / fmt->row_depth[0];
> > > > +
> > > > + if (plane == 0)
> > > > + return stride;
> > > > +
> > > > + if (plane < MDP_COLOR_GET_PLANE_COUNT(c)) {
> > > > + if (MDP_COLOR_IS_BLOCK_MODE(c))
> > > > + stride = stride / 2;
> > > > + return stride;
> > > > + }
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > +/* Stride that is accepted by MDP HW of format with contiguous planes */
> > > > +static u32
> > > > +dip_mdp_fmt_get_stride_contig(const struct mtk_dip_dev_format *fmt,
> > > > + u32 pix_stride,
> > > > + unsigned int plane)
> > > > +{
> > > > + enum mdp_color c = fmt->mdp_color;
> > > > + u32 stride = pix_stride;
> > > > +
> > > > + if (plane == 0)
> > > > + return stride;
> > > > +
> > > > + if (plane < MDP_COLOR_GET_PLANE_COUNT(c)) {
> > > > + stride = stride >> MDP_COLOR_GET_H_SUBSAMPLE(c);
> > > > + if (MDP_COLOR_IS_UV_COPLANE(c) && !MDP_COLOR_IS_BLOCK_MODE(c))
> > > > + stride = stride * 2;
> > > > + return stride;
> > > > + }
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > +/* Plane size that is accepted by MDP HW */
> > > > +static u32
> > > > +dip_mdp_fmt_get_plane_size(const struct mtk_dip_dev_format *fmt,
> > > > + u32 stride, u32 height,
> > > > + unsigned int plane)
> > > > +{
> > > > + enum mdp_color c = fmt->mdp_color;
> > > > + u32 bytesperline;
> > > > +
> > > > + bytesperline = (stride * fmt->row_depth[0])
> > > > + / MDP_COLOR_BITS_PER_PIXEL(c);
> > >
> > > Hmm, stride and bytesperline should be exactly the same thing. Could you
> > > explain what's happening here?
> >
> > The stride here is specific for MDP hardware (which uses the same MDP
> > stride setting for NV12 and NV12M):
> >
> > bytesperline = width * row_depth / 8
> > MDP stride = width * MDP_COLOR_BITS_PER_PIXEL /8
> >
> > Therfore,
> >
> > bytesperline = MDP stride * row_depth / MDP_COLOR_BITS_PER_PIXEL
> > MDP stride = bytesperline * MDP_COLOR_BITS_PER_PIXEL/ row_depth
> >
>
> I'm sorry I'm still confused. Is there an intermediate buffer between
> DIP and MDP that has stride of |MDP stride| and then MDP writes to the
> final buffer that has the stride of |bytesperline|?
>
No, there is no intermediate buffer between DIP and MDP that has stride
of |MDP stride|. DIP connects to MDP in hardware level, so MDP writes
the buffer with |MDP stride|.
As I know, V4L2's bytesperline means bytes per line of the first
plane(*), but mdp hw needs y, u, v stride (it is different from V4L2).
Therefore we calculate the |MDP stride| here.
*:
https://linuxtv.org/downloads/v4l-dvb-apis/uapi/v4l/pixfmt-v4l2.html#c.v4l2_pix_format
"When the image format is planar the bytesperline value applies to the
first plane and is divided by the same factor as the width field for the
other planes."
> [snip]
>
> > >
> > > > + u32 sizeimage;
> > > > +
> > > > + if (bpl < min_bpl)
> > > > + bpl = min_bpl;
> > > > +
> > > > + sizeimage = (bpl * mfmt_to_fill->height * dev_fmt->depth[i])
> > > > + / dev_fmt->row_depth[i];
> > >
> > > Shouldn't this be bpl * fmt->height?
> >
> > Row_depth is the bits of the pixel.
> > Depth means the bytes per pixel of the image format.
> >
> > For example,
> > Image: 640 * 480
> > YV12: row_depth = 8, depth = 12
>
> YV12 has 3 planes of 8 bits per pixel. Not sure where does this 12 come from.
>
Let me elaborate more about the 12 depth.
depth: pixel bit number
For 420,
y = w * h
u = (w/2) * (h/2)
v = (w/2) * (h/2)
Therefore,
y = 8,
u = 8/2/2 = 2
v = 8/2/2 = 2
depth (y + u + v) = 8 + 2 + 2 = 12
> > Bytes per line = width * row_depth / 8 = 640 * 8/ 8 = 640
> > Image size = Bytes per line * height * (depth/ row_depth)
> > = 640 * 480 * 1.5
> >
>
> I think we might be having some terminology issue here. "row" is
> normally the same as "line", which consists of |width| pixels +
> padding, which is |bytesperline| bytes in total.
>
> Perhaps you want to store a bits_per_pixel[] and vertical and
> horizontal subsampling arrays for all planes of the formats in the
> format descriptor.
>
> By the way, have you considered using the V4L2 format helpers [1]?
>
> [1] https://elixir.bootlin.com/linux/v5.3-rc6/source/drivers/media/v4l2-core/v4l2-common.c#L561
Would it be possible to keep row_depth and depth? It is already used in
MDP drivers.
https://elixir.bootlin.com/linux/v5.3-rc6/source/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
>
> > >
> > > > + dev_dbg(&pipe->dip_dev->pdev->dev,
> > > > + "Non-contiguous-mp-buf(%s),total-plane-size(%d),dma_port(%d)\n",
> > > > + buf_name,
> > > > + total_plane_size,
> > > > + b->usage);
> > > > + return 0;
> > > > + }
> > > > +
> > > > + for (; i < MDP_COLOR_GET_PLANE_COUNT(b->format.colorformat); ++i) {
> > >
> > > I don't see these MDP_ macros defined anywhere. Please don't use macros
> > > defined from other drivers. We can embed this information in the
> > > mtk_dip_dev_format struct. One would normally call it num_cplanes (color
> > > planes).
> > >
> > > However, I would just make this driver support M formats only and forget
> > > about formats with only memory planes count != color planes count.
> >
> > Since the non-M formats are still used by 8183's user lib now, may I add
> > num_cplanes and support the both formats?
> >
>
> Okay, let's keep them for now.
>
> [snip]
>
> > > > +
> > > > + /* Tuning buffer */
> > > > + dev_buf_tuning =
> > > > + pipe_job_info->buf_map[MTK_DIP_VIDEO_NODE_ID_TUNING_OUT];
> > > > + if (dev_buf_tuning) {
> > > > + dev_dbg(&pdev->dev,
> > > > + "Tuning buf queued: scp_daddr(%pad),isp_daddr(%pad)\n",
> > > > + &dev_buf_tuning->scp_daddr[0],
> > > > + &dev_buf_tuning->isp_daddr[0]);
> > > > + dip_param->tuning_data.pa =
> > > > + (uint32_t)dev_buf_tuning->scp_daddr[0];
> > > > + dip_param->tuning_data.present = true;
> > > > + dip_param->tuning_data.iova =
> > > > + (uint32_t)dev_buf_tuning->isp_daddr[0];
> > >
> > > Why are these casts needed?
> >
> > This structure is shared between CPU and scp and the pa and iova is
> > defined as 32bits fields.
> >
> > struct tuning_addr {
> > u32 present;
> > u32 pa; /* Used by CM4 access */
> > u32 iova; /* Used by IOMMU HW access */
> > } __attribute__ ((__packed__));
> >
>
> I see, thanks.
>
> [snip]
>
> > >
> > > > +#define DIP_COMPOSING_MAX_NUM 3
> > > > +#define DIP_MAX_ERR_COUNT 188U
> > > > +#define DIP_FLUSHING_WQ_TIMEOUT (16U * DIP_MAX_ERR_COUNT)
> > >
> > > Any rationale behind this particular numbers? Please add comments explaining
> > > them.
> >
> > I would like to adjust the time out value to 1000 / 30 *
> > (DIP_COMPOSING_MAX_NUM) * 3.
> >
> > To wait 3 times of expected frame time (@30fps) in the worst case (max
> > number of jobs in SCP).
> >
>
> With high system load it could be still possible to hit this. Since it
> should normally be impossible to hit this timeout on a system working
> correctly, how about just making this something really long like 1
> second?
>
I got it. I would like to use 1 second instead.
> [snip]
>
> > >
> > > > +
> > > > + dev_dbg(&dip_dev->pdev->dev,
> > > > + "%s: wakeup frame_no(%d),num(%d)\n",
> > > > + __func__, req->img_fparam.frameparam.frame_no,
> > > > + atomic_read(&dip_hw->num_composing));
> > > > +
> > > > + buf = req->working_buf;
> > > > + mtk_dip_wbuf_to_ipi_img_addr(&req->img_fparam.frameparam.subfrm_data,
> > > > + &buf->buffer);
> > > > + memset(buf->buffer.vaddr, 0, DIP_SUB_FRM_SZ);
> > > > + mtk_dip_wbuf_to_ipi_img_sw_addr(&req->img_fparam.frameparam.config_data,
> > > > + &buf->config_data);
> > > > + memset(buf->config_data.vaddr, 0, DIP_COMP_SZ);
> > > > +
> > > > + if (!req->img_fparam.frameparam.tuning_data.present) {
> > > > + /*
> > > > + * When user enqueued without tuning buffer,
> > > > + * it would use driver internal buffer.
> > > > + */
> > > > + dev_dbg(&dip_dev->pdev->dev,
> > > > + "%s: frame_no(%d) has no tuning_data\n",
> > > > + __func__, req->img_fparam.frameparam.frame_no);
> > > > +
> > > > + mtk_dip_wbuf_to_ipi_tuning_addr
> > > > + (&req->img_fparam.frameparam.tuning_data,
> > > > + &buf->tuning_buf);
> > > > + memset(buf->tuning_buf.vaddr, 0, DIP_TUNING_SZ);
> > > > + }
> > > > +
> > > > + req->img_fparam.frameparam.state = FRAME_STATE_COMPOSING;
> > > > + mtk_dip_wbuf_to_ipi_img_sw_addr(&req->img_fparam.frameparam.self_data,
> > > > + &buf->frameparam);
> > > > + memcpy(buf->frameparam.vaddr, &req->img_fparam.frameparam,
> > > > + sizeof(req->img_fparam.frameparam));
> > >
> > > Is img_fparam really used at this stage? I can only see ipi_param passed to
> > > the IPI.
> >
> > The content of img_fparam is passed to SCP.
> >
> > The dip frame information is saved in req->img_fparam.frameparam (in
> > mtk_dip_pipe_ipi_params_config()).
> >
> > The content of req->img_fparam.frameparam is copied to
> > buf->frameparam.vaddr.
> >
> > Since we set ipi_param.frm_param.pa to the buf->frameparam.scp_daddr in
> > mtk_dip_wbuf_to_ipi_img_sw_addr(), the content of img_fparam is pass to
> > SCP through ipi_param.
>
> Okay, I see. Thanks,
>
> [snip]
>
> > >
> > > > + } else {
> > > > + for (i = 0; i < *num_planes; i++) {
> > > > + if (sizes[i] < fmt->fmt.pix_mp.plane_fmt[i].sizeimage) {
> > > > + dev_dbg(&pipe->dip_dev->pdev->dev,
> > > > + "%s:%s:%s: invalid buf: %u < %u\n",
> > > > + __func__, pipe->desc->name,
> > > > + node->desc->name, sizes[0], size);
> > > > + return -EINVAL;
> > > > + }
> > > > + sizes[i] = fmt->fmt.pix_mp.plane_fmt[i].sizeimage;
> > >
> > > For VIDIOC_CREATEBUFS we also need to handle the case when *num_planes > 0
> > > and then we need to honor the values already present in sizes[]. (Note that
> > > the code above overrides *num_planes to 1, so we lose the information. The
> > > code needs to be restructured to handle that.)
> >
> > We overrides *num_planes when *num_planes is 0. Is the modification I
> > need to do to keep the original value of size[]?
>
> Yes.
>
> >
> > if (!*num_planes) {
> > *num_planes = 1;
> > sizes[0] = fmt->fmt.pix_mp.plane_fmt[0].sizeimage;
> > }
> >
>
> [snip]
>
> > >
> > > > + dev_dbg(&pipe->dip_dev->pdev->dev,
> > > > + "%s:%s:%s cnt_nodes_not_streaming(%d), is_pipe_streamon(%d)\n",
> > > > + __func__, pipe->desc->name, node->desc->name, count,
> > > > + is_pipe_streamon);
> > > > +
> > > > + if (count && is_pipe_streamon) {
> > >
> > > For v4l2_subdev_call() shouldn't this be !count && is_pipe_streamon?
> >
> > Do you mean that pipe->subdev's stop stream should be called after all
> > video device are stream off, not the first video device's stream off?
> >
>
> Partially. See the comment below. We should stop the subdev when the
> first video node stops streaming, but the media pipeline only when all
> the nodes stopped.
I got it.
>
> > >
> > > > + ret = v4l2_subdev_call(&pipe->subdev, video, s_stream, 0);
> > > > + if (ret)
> > > > + dev_err(&pipe->dip_dev->pdev->dev,
> > > > + "%s:%s: sub dev s_stream(0) failed(%d)\n",
> > > > + pipe->desc->name, node->desc->name, ret);
> > > > + media_pipeline_stop(&node->vdev.entity);
> > >
> > > We should do this one when the last node stops streaming to solve the
> > > enable state locking issue as described in my comment to _start_streaming().
> >
> > I will do this when the last node stops streaming.
> >
>
> Ack.
>
> > >
> > > > + }
> > > > +
> > > > + mtk_dip_return_all_buffers(pipe, node, VB2_BUF_STATE_ERROR);
> > > > +}
> > > > +
> > > > +static int mtk_dip_videoc_querycap(struct file *file, void *fh,
> > > > + struct v4l2_capability *cap)
> > > > +{
> > > > + struct mtk_dip_pipe *pipe = video_drvdata(file);
> > > > +
> > > > + strlcpy(cap->driver, pipe->desc->name,
> > > > + sizeof(cap->driver));
> > > > + strlcpy(cap->card, pipe->desc->name,
> > > > + sizeof(cap->card));
> > > > + snprintf(cap->bus_info, sizeof(cap->bus_info),
> > > > + "platform:%s", dev_name(pipe->dip_dev->mdev.dev));
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > +static int mtk_dip_videoc_try_fmt(struct file *file, void *fh,
> > > > + struct v4l2_format *f)
> > >
> > > I don't see this function returning any error codes. Please make it void.
> >
> > mtk_dip_videoc_try_fmt() is used as vidioc_try_fmt_vid_out_mplane op.
> > Using void seems to make it incompatible with
> > vidioc_try_fmt_vid_out_mplane.
> >
> > .vidioc_try_fmt_vid_out_mplane = mtk_dip_videoc_try_fmt,
> >
> > int (*vidioc_try_fmt_vid_out_mplane)(struct file *file, void *fh,
> > struct v4l2_format *f);
> >
>
> Oops, sorry, I'm not sure why I suggested that.
>
> [snip]
>
> > > > + /* Initialize subdev */
> > > > + v4l2_subdev_init(&pipe->subdev, &mtk_dip_subdev_ops);
> > > > +
> > > > + pipe->subdev.entity.function =
> > > > + MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
> > > > + pipe->subdev.entity.ops = &mtk_dip_media_ops;
> > > > + pipe->subdev.flags =
> > > > + V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
> > > > + pipe->subdev.ctrl_handler = NULL;
> > > > + pipe->subdev.internal_ops = &mtk_dip_subdev_internal_ops;
> > > > +
> > > > + for (i = 0; i < pipe->num_nodes; i++)
> > > > + pipe->subdev_pads[i].flags =
> > > > + V4L2_TYPE_IS_OUTPUT(pipe->nodes[i].desc->buf_type) ?
> > > > + MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
> > >
> > > Isn't this the other way around?
> >
> > I checked the document of MEDIA_PAD_FL_SINK and MEDIA_PAD_FL_SOURCE. It
> > seems that the codes match the description.
> >
> > RAW Ouput video device: MEDIA_PAD_FL_SOURCE --> DIP sub dev:
> > MEDIA_PAD_FL_SINK
> > DIP sub dev: MEDIA_PAD_FL_SOURCE --> MDP Capture video device:
> > MEDIA_PAD_FL_SINK
> >
> > MEDIA_PAD_FL_SINK: Input pad, relative to the entity. Input pads sink
> > data and are targets of links.
> > MEDIA_PAD_FL_SOURCE: Output pad, relative to the entity. Output pads
> > source data and are origins of links.
> >
>
> Ah, that's right, sorry for the noise.
>
> [snip]
>
> > > > + {
> > > > + .format = V4L2_PIX_FMT_NV12M,
> > > > + .mdp_color = MDP_COLOR_NV12,
> > > > + .colorspace = V4L2_COLORSPACE_BT2020,
> > > > + .depth = { 8, 4 },
> > > > + .row_depth = { 8, 8 },
> > >
> > > What is depth and what is row_depth? They both seem to not match NV12, which
> > > should have 16 bits per sample in the CbCr plane.
> >
> > Fow_depth is the bits of the pixel.
>
> Bits of a YCbCr plane pixel is 16 for NV12.
>
> > Depth means the bytes per pixel of the image foramt.
> >
> > For example,
> > Image: 640 * 480
> > YV12: row_depth = 8, depth = 12
> > Bytes per line = width * row_depth / 8 = 640 * 8/ 8 = 640
> > Image size = Bytes per line * height * (depth/ row_depth)
> > = 640 * 480 * 1.5
> >
> > Image: 640 * 480
> > Bytes per line(Y) = width * row_depth/ 8 = 640
> > Bytes per line(CbCr) = width * row_depth/ 8 = 640
> >
> > Image size(Y) = Bytes per line * height * (depth/ row_depth)
> > = 640 * 480 * 8/8 = 640 * 480 * 1
> >
> > Image size(CbCr) = Bytes per line * height * (depth/ row_depth)
> > = 640 * 480 * 4/8 = 640 * 480 * 0.5
> >
>
> I'd suggest either using the V4L2 format helpers, as suggested in
> another comment above with a link OR adopting the typical convention
> of having the .depth mean the pixel value size, i.e. 16-bit for CbCr
> plane of NV12 and then use subsampling factors to calculate the plane
> bytesperline and sizeimage.
>
> [snip]
>
> > > > +static const struct mtk_dip_video_device_desc
> > > > +reprocess_output_queues_setting[MTK_DIP_VIDEO_NODE_ID_OUT_TOTAL_NUM] = {
> > > > + {
> > > > + .id = MTK_DIP_VIDEO_NODE_ID_RAW_OUT,
> > > > + .name = "Raw Input",
> > > > + .cap = V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_STREAMING,
> > > > + .buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
> > > > + .smem_alloc = 0,
> > > > + .flags = MEDIA_LNK_FL_ENABLED,
> > > > + .fmts = in_fmts,
> > > > + .num_fmts = ARRAY_SIZE(in_fmts),
> > > > + .default_fmt_idx = 5,
> > > > + .default_width = MTK_DIP_OUTPUT_MAX_WIDTH,
> > > > + .default_height = MTK_DIP_OUTPUT_MAX_HEIGHT,
> > > > + .dma_port = 0,
> > > > + .frmsizeenum = &in_frmsizeenum,
> > > > + .ops = &mtk_dip_v4l2_video_out_ioctl_ops,
> > > > + .description = "Source image to be process",
> > > > +
> > > > + },
> > > > + {
> > > > + .id = MTK_DIP_VIDEO_NODE_ID_TUNING_OUT,
> > > > + .name = "Tuning",
> > > > + .cap = V4L2_CAP_META_OUTPUT | V4L2_CAP_STREAMING,
> > > > + .buf_type = V4L2_BUF_TYPE_META_OUTPUT,
> > > > + .smem_alloc = 1,
> > > > + .flags = 0,
> > > > + .fmts = fw_param_fmts,
> > > > + .num_fmts = 1,
> > > > + .default_fmt_idx = 0,
> > > > + .dma_port = 0,
> > > > + .frmsizeenum = &in_frmsizeenum,
> > > > + .ops = &mtk_dip_v4l2_meta_out_ioctl_ops,
> > > > + .description = "Tuning data for image enhancement",
> > > > + },
> > > > +};
> > >
> > > The entries here seem to be almost the same to output_queues_setting[], the
> > > only difference seems to be default_fmt_idx and description.
> > >
> > > What's the difference between the capture and reprocess pipes?
> >
> > The reprocess pipe is completely the same as capture one except the
> > default format of the input.
> >
>
> Does the default format really matter here? The userspace should set
> its own desired format anyway. Then we could just unify the settings
> of both pipes.
>
I would like to remove the reprocess_output_queues_setting.
> [snip]
>
> > >
> > > > +
> > > > + return num;
> > > > +}
> > > > +
> > > > +static int __maybe_unused mtk_dip_suspend(struct device *dev)
> > > > +{
> > > > + struct mtk_dip_dev *dip_dev = dev_get_drvdata(dev);
> > > > + int ret, num;
> > > > +
> > > > + if (pm_runtime_suspended(dev)) {
> > > > + dev_dbg(dev, "%s: pm_runtime_suspended is true, no action\n",
> > > > + __func__);
> > > > + return 0;
> > > > + }
> > > > +
> > > > + ret = wait_event_timeout(dip_dev->dip_hw.flushing_hw_wq,
> > > > + !(num = mtk_dip_get_scp_job_num(dip_dev)),
> > > > + msecs_to_jiffies(200));
> > >
> > > Is 200 milliseconds a reasonable timeout here, i.e. for any potential use
> > > case it would always take less than 200 ms to wait for all the tasks running
> > > in the ISP?
> >
> > I would like to adjust the time out value to 1000 / 30 *
> > (DIP_COMPOSING_MAX_NUM) * 3.
> >
> > To wait 3 times of expected frame time (@30fps) in worst case (max
> > number of jobs in SCP).
> >
>
> As I suggested in another comment above, the worst case for the
> hardware might be still better than the scheduling latency we could
> get for a heavy loaded system. While that wouldn't really apply here,
> because nothing else happening in parallel when the system is
> suspending, we could just stick to some really long time out anyway,
> e.g. 1 second. We shouldn't hit it anyway - it's just a safety guard
> to prevent the system hanging if something goes really bad.
>
I got it. I will use 1 second as timeout setting.
> Best regards,
> Tomasz
Sincerely,
Frederic Chen
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH] drm/stm: ltdc: add pinctrl for DPI encoder mode
From: Yannick Fertré @ 2019-09-06 9:21 UTC (permalink / raw)
To: Yannick Fertre, Philippe Cornu, Benjamin Gaignard, Vincent Abriou,
David Airlie, Daniel Vetter, Maxime Coquelin, Alexandre Torgue,
dri-devel, linux-stm32, linux-arm-kernel, linux-kernel
The implementation of functions encoder_enable and encoder_disable
make possible to control the pinctrl according to the encoder type.
The pinctrl must be activated only if the encoder type is DPI.
This helps to move the DPI-related pinctrl configuration from
all the panel or bridge to the LTDC dt node.
Reviewed-by: Philippe Cornu <philippe.cornu@st.com>
Signed-off-by: Yannick Fertré <yannick.fertre@st.com>
---
drivers/gpu/drm/stm/ltdc.c | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c
index 3ab4fbf..1c4fde0 100644
--- a/drivers/gpu/drm/stm/ltdc.c
+++ b/drivers/gpu/drm/stm/ltdc.c
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_graph.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
@@ -1040,6 +1041,36 @@ static const struct drm_encoder_funcs ltdc_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
+static void ltdc_encoder_disable(struct drm_encoder *encoder)
+{
+ struct drm_device *ddev = encoder->dev;
+
+ DRM_DEBUG_DRIVER("\n");
+
+ /* Set to sleep state the pinctrl whatever type of encoder */
+ pinctrl_pm_select_sleep_state(ddev->dev);
+}
+
+static void ltdc_encoder_enable(struct drm_encoder *encoder)
+{
+ struct drm_device *ddev = encoder->dev;
+
+ DRM_DEBUG_DRIVER("\n");
+
+ /*
+ * Set to default state the pinctrl only with DPI type.
+ * Others types like DSI, don't need pinctrl due to
+ * internal bridge (the signals do not come out of the chipset).
+ */
+ if (encoder->encoder_type == DRM_MODE_ENCODER_DPI)
+ pinctrl_pm_select_default_state(ddev->dev);
+}
+
+static const struct drm_encoder_helper_funcs ltdc_encoder_helper_funcs = {
+ .disable = ltdc_encoder_disable,
+ .enable = ltdc_encoder_enable,
+};
+
static int ltdc_encoder_init(struct drm_device *ddev, struct drm_bridge *bridge)
{
struct drm_encoder *encoder;
@@ -1055,6 +1086,8 @@ static int ltdc_encoder_init(struct drm_device *ddev, struct drm_bridge *bridge)
drm_encoder_init(ddev, encoder, <dc_encoder_funcs,
DRM_MODE_ENCODER_DPI, NULL);
+ drm_encoder_helper_add(encoder, <dc_encoder_helper_funcs);
+
ret = drm_bridge_attach(encoder, bridge, NULL);
if (ret) {
drm_encoder_cleanup(encoder);
@@ -1280,6 +1313,8 @@ int ltdc_load(struct drm_device *ddev)
clk_disable_unprepare(ldev->pixel_clk);
+ pinctrl_pm_select_sleep_state(ddev->dev);
+
pm_runtime_enable(ddev->dev);
return 0;
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH 1/1] PCI: iproc: Invalidate PAXB address mapping before programming it
From: Abhishek Shah @ 2019-09-06 9:25 UTC (permalink / raw)
To: Andrew Murray
Cc: Lorenzo Pieralisi, Scott Branden, Ray Jui, open list,
BCM Kernel Feedback, linux-pci, Bjorn Helgaas, linux-arm-kernel
In-Reply-To: <20190906083816.GD9720@e119886-lin.cambridge.arm.com>
Hi Andrew,
Thanks for the review. Please see my response inline:
On Fri, Sep 6, 2019 at 2:08 PM Andrew Murray <andrew.murray@arm.com> wrote:
>
> On Fri, Sep 06, 2019 at 09:28:13AM +0530, Abhishek Shah wrote:
> > Invalidate PAXB inbound/outbound address mapping each time before
> > programming it. This is helpful for the cases where we need to
> > reprogram inbound/outbound address mapping without resetting PAXB.
> > kexec kernel is one such example.
>
> Why is this approach better than resetting the PAXB (I assume that's
> the PCI controller IP)? Wouldn't resetting the PAXB address this issue,
> and ensure that no other configuration is left behind?
>
We normally reset PAXB in the firmware(ATF). But for cases like kexec
kernel boot,
we do not execute any firmware code and directly boot into kernel.
We could have done PAXB reset in the driver itself as you have suggested here.
But note that this detail could vary for each SoC, because these
registers are not part
of PAXB register space itself, rather exists in a register space responsible for
controlling power to various wrappers in PCIe IP. Normally, this kind
of SoC specific
details are handled in firmware itself, we don't bring them to driver level.
> Or is this related to earlier boot stages loading firmware for the emulated
> downstream endpoints (ep_is_internal)?
>
> Finally, in the case where ep_is_internal do you need to disable anything
> prior to invalidating the mappings?
>
No, ep_is_internal is indicator for PAXC IP. It does not have
mappings as in PAXB.
Regards,
Abhishek
> >
> > Signed-off-by: Abhishek Shah <abhishek.shah@broadcom.com>
> > Reviewed-by: Ray Jui <ray.jui@broadcom.com>
> > Reviewed-by: Vikram Mysore Prakash <vikram.prakash@broadcom.com>
> > ---
> > drivers/pci/controller/pcie-iproc.c | 28 ++++++++++++++++++++++++++++
> > 1 file changed, 28 insertions(+)
> >
> > diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c
> > index e3ca46497470..99a9521ba7ab 100644
> > --- a/drivers/pci/controller/pcie-iproc.c
> > +++ b/drivers/pci/controller/pcie-iproc.c
> > @@ -1245,6 +1245,32 @@ static int iproc_pcie_map_dma_ranges(struct iproc_pcie *pcie)
> > return ret;
> > }
> >
> > +static void iproc_pcie_invalidate_mapping(struct iproc_pcie *pcie)
> > +{
> > + struct iproc_pcie_ib *ib = &pcie->ib;
> > + struct iproc_pcie_ob *ob = &pcie->ob;
> > + int idx;
> > +
> > + if (pcie->ep_is_internal)
> > + return;
> > +
> > + if (pcie->need_ob_cfg) {
> > + /* iterate through all OARR mapping regions */
> > + for (idx = ob->nr_windows - 1; idx >= 0; idx--) {
> > + iproc_pcie_write_reg(pcie,
> > + MAP_REG(IPROC_PCIE_OARR0, idx), 0);
> > + }
> > + }
> > +
> > + if (pcie->need_ib_cfg) {
> > + /* iterate through all IARR mapping regions */
> > + for (idx = 0; idx < ib->nr_regions; idx++) {
> > + iproc_pcie_write_reg(pcie,
> > + MAP_REG(IPROC_PCIE_IARR0, idx), 0);
> > + }
> > + }
> > +}
> > +
> > static int iproce_pcie_get_msi(struct iproc_pcie *pcie,
> > struct device_node *msi_node,
> > u64 *msi_addr)
> > @@ -1517,6 +1543,8 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
> > iproc_pcie_perst_ctrl(pcie, true);
> > iproc_pcie_perst_ctrl(pcie, false);
> >
> > + iproc_pcie_invalidate_mapping(pcie);
> > +
> > if (pcie->need_ob_cfg) {
> > ret = iproc_pcie_map_ranges(pcie, res);
> > if (ret) {
>
> The code changes look good to me.
>
> Thanks,
>
> Andrew Murray
>
> > --
> > 2.17.1
> >
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 2/2] nvmem: imx: scu: support write
From: Srinivas Kandagatla @ 2019-09-06 9:37 UTC (permalink / raw)
To: Peng Fan, shawnguo@kernel.org, s.hauer@pengutronix.de
Cc: Aisheng Dong, linux-kernel@vger.kernel.org, dl-linux-imx,
kernel@pengutronix.de, festevam@gmail.com,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <AM0PR04MB448144701DB63A3C9F05B3E488BA0@AM0PR04MB4481.eurprd04.prod.outlook.com>
On 06/09/2019 07:57, Peng Fan wrote:
>> Subject: [PATCH 2/2] nvmem: imx: scu: support write
>
> Ping..
>
Thanks for your patience!
I normally do not take patches after rc5 for nvmem.
These will be applied after rc1 is released!
Thanks,
srini
> Thanks,
> Peng.
>
>>
>> From: Peng Fan <peng.fan@nxp.com>
>>
>> The fuse programming from non-secure world is blocked, so we could only use
>> Arm Trusted Firmware SIP call to let ATF program fuse.
>>
>> Because there is ECC region that could only be programmed once, so add a
>> heler in_ecc to check the ecc region.
>>
>> Signed-off-by: Peng Fan <peng.fan@nxp.com>
>> ---
>>
>> The ATF patch will soon be posted to ATF community.
>>
>> drivers/nvmem/imx-ocotp-scu.c | 73
>> ++++++++++++++++++++++++++++++++++++++++++-
>> 1 file changed, 72 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/nvmem/imx-ocotp-scu.c b/drivers/nvmem/imx-ocotp-scu.c
>> index 2f339d7432e6..0f064f2e74a8 100644
>> --- a/drivers/nvmem/imx-ocotp-scu.c
>> +++ b/drivers/nvmem/imx-ocotp-scu.c
>> @@ -7,6 +7,7 @@
>> * Peng Fan <peng.fan@nxp.com>
>> */
>>
>> +#include <linux/arm-smccc.h>
>> #include <linux/firmware/imx/sci.h>
>> #include <linux/module.h>
>> #include <linux/nvmem-provider.h>
>> @@ -14,6 +15,9 @@
>> #include <linux/platform_device.h>
>> #include <linux/slab.h>
>>
>> +#define IMX_SIP_OTP 0xC200000A
>> +#define IMX_SIP_OTP_WRITE 0x2
>> +
>> enum ocotp_devtype {
>> IMX8QXP,
>> };
>> @@ -45,6 +49,8 @@ struct imx_sc_msg_misc_fuse_read {
>> u32 word;
>> } __packed;
>>
>> +static DEFINE_MUTEX(scu_ocotp_mutex);
>> +
>> static struct ocotp_devtype_data imx8qxp_data = {
>> .devtype = IMX8QXP,
>> .nregs = 800,
>> @@ -73,6 +79,23 @@ static bool in_hole(void *context, u32 index)
>> return false;
>> }
>>
>> +static bool in_ecc(void *context, u32 index) {
>> + struct ocotp_priv *priv = context;
>> + const struct ocotp_devtype_data *data = priv->data;
>> + int i;
>> +
>> + for (i = 0; i < data->num_region; i++) {
>> + if (data->region[i].flag & ECC_REGION) {
>> + if ((index >= data->region[i].start) &&
>> + (index <= data->region[i].end))
>> + return true;
>> + }
>> + }
>> +
>> + return false;
>> +}
>> +
>> static int imx_sc_misc_otp_fuse_read(struct imx_sc_ipc *ipc, u32 word,
>> u32 *val)
>> {
>> @@ -116,6 +139,8 @@ static int imx_scu_ocotp_read(void *context,
>> unsigned int offset,
>> if (!p)
>> return -ENOMEM;
>>
>> + mutex_lock(&scu_ocotp_mutex);
>> +
>> buf = p;
>>
>> for (i = index; i < (index + count); i++) { @@ -126,6 +151,7 @@ static int
>> imx_scu_ocotp_read(void *context, unsigned int offset,
>>
>> ret = imx_sc_misc_otp_fuse_read(priv->nvmem_ipc, i, buf);
>> if (ret) {
>> + mutex_unlock(&scu_ocotp_mutex);
>> kfree(p);
>> return ret;
>> }
>> @@ -134,18 +160,63 @@ static int imx_scu_ocotp_read(void *context,
>> unsigned int offset,
>>
>> memcpy(val, (u8 *)p + offset % 4, bytes);
>>
>> + mutex_unlock(&scu_ocotp_mutex);
>> +
>> kfree(p);
>>
>> return 0;
>> }
>>
>> +static int imx_scu_ocotp_write(void *context, unsigned int offset,
>> + void *val, size_t bytes)
>> +{
>> + struct ocotp_priv *priv = context;
>> + struct arm_smccc_res res;
>> + u32 *buf = val;
>> + u32 tmp;
>> + u32 index;
>> + int ret;
>> +
>> + /* allow only writing one complete OTP word at a time */
>> + if ((bytes != 4) || (offset % 4))
>> + return -EINVAL;
>> +
>> + index = offset >> 2;
>> +
>> + if (in_hole(context, index))
>> + return -EINVAL;
>> +
>> + if (in_ecc(context, index)) {
>> + pr_warn("ECC region, only program once\n");
>> + mutex_lock(&scu_ocotp_mutex);
>> + ret = imx_sc_misc_otp_fuse_read(priv->nvmem_ipc, index, &tmp);
>> + mutex_unlock(&scu_ocotp_mutex);
>> + if (ret)
>> + return ret;
>> + if (tmp) {
>> + pr_warn("ECC region, already has value: %x\n", tmp);
>> + return -EIO;
>> + }
>> + }
>> +
>> + mutex_lock(&scu_ocotp_mutex);
>> +
>> + arm_smccc_smc(IMX_SIP_OTP, IMX_SIP_OTP_WRITE, index, *buf,
>> + 0, 0, 0, 0, &res);
>> +
>> + mutex_unlock(&scu_ocotp_mutex);
>> +
>> + return res.a0;
>> +}
>> +
>> static struct nvmem_config imx_scu_ocotp_nvmem_config = {
>> .name = "imx-scu-ocotp",
>> - .read_only = true,
>> + .read_only = false,
>> .word_size = 4,
>> .stride = 1,
>> .owner = THIS_MODULE,
>> .reg_read = imx_scu_ocotp_read,
>> + .reg_write = imx_scu_ocotp_write,
>> };
>>
>> static const struct of_device_id imx_scu_ocotp_dt_ids[] = {
>> --
>> 2.16.4
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* RE: [PATCH v2] pinctrl: at91-pio4: implement .get_multiple and .set_multiple
From: David Laight @ 2019-09-06 9:46 UTC (permalink / raw)
To: 'Alexandre Belloni'
Cc: Linus Walleij, linux-kernel@vger.kernel.org,
linux-gpio@vger.kernel.org, Ludovic Desroches,
Claudiu.Beznea@microchip.com,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <20190906091212.GF21254@piout.net>
From: Alexandre Belloni
> Sent: 06 September 2019 10:12
> On 06/09/2019 09:05:36+0000, David Laight wrote:
> > From: Alexandre Belloni
> > > Implement .get_multiple and .set_multiple to allow reading or setting
> > > multiple pins simultaneously. Pins in the same bank will all be switched at
> > > the same time, improving synchronization and performances.
> >
> > Actually it won't 'improve synchronisation', instead it will lead to
> > random synchronisation errors and potential metastability if one
> > pin is used as a clock and another as data, or if the code is reading
> > a free-flowing counter.
> >
>
> It does improve gpio switching synchronisation when they are in the same
> bank as it will remove the 250ns delay. Of course, if you need this
> delay between clk and data, then the consumer driver should ensure the
> delay is present.
With multiple requests the output pin changes will always be in the
same order and will be separated by (say) 250ns.
This is a guaranteed synchronisation.
If you change multiple pins with the same 'iowrite()' then the pins
will change at approximately the same time.
But the actual order will depend on internal device delays (which
may depend on the actual silicon and temperature).
You then have to take account of varying track lengths and the
target devices input stage properties before knowing which change
arrives first.
The delays might be sub-nanosecond, but they matter if you are
talking about synchronisation.
IIRC both SMBus and I2C now quote 0ns setup time.
Changing both clock and data with the same IOW isn't enough to
guarantee this.
(In practise the I2C setup time required by a device is probably
slightly negative (In order to support 0ns inputs) so a very small
-ve setup will (mostly) work.)
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 1/1] PCI: iproc: Invalidate PAXB address mapping before programming it
From: Andrew Murray @ 2019-09-06 10:01 UTC (permalink / raw)
To: Abhishek Shah
Cc: Lorenzo Pieralisi, Scott Branden, Ray Jui, open list,
BCM Kernel Feedback, linux-pci, Bjorn Helgaas, linux-arm-kernel
In-Reply-To: <CAKUFe6ZuRGJSmLdXqTWJzX-nE_Vh4yEQF_-rf+BWFrD_r4BRaQ@mail.gmail.com>
On Fri, Sep 06, 2019 at 02:55:19PM +0530, Abhishek Shah wrote:
> Hi Andrew,
>
> Thanks for the review. Please see my response inline:
>
> On Fri, Sep 6, 2019 at 2:08 PM Andrew Murray <andrew.murray@arm.com> wrote:
> >
> > On Fri, Sep 06, 2019 at 09:28:13AM +0530, Abhishek Shah wrote:
> > > Invalidate PAXB inbound/outbound address mapping each time before
> > > programming it. This is helpful for the cases where we need to
> > > reprogram inbound/outbound address mapping without resetting PAXB.
> > > kexec kernel is one such example.
> >
> > Why is this approach better than resetting the PAXB (I assume that's
> > the PCI controller IP)? Wouldn't resetting the PAXB address this issue,
> > and ensure that no other configuration is left behind?
> >
> We normally reset PAXB in the firmware(ATF). But for cases like kexec
> kernel boot,
> we do not execute any firmware code and directly boot into kernel.
>
> We could have done PAXB reset in the driver itself as you have suggested here.
> But note that this detail could vary for each SoC, because these
> registers are not part
> of PAXB register space itself, rather exists in a register space responsible for
> controlling power to various wrappers in PCIe IP. Normally, this kind
> of SoC specific
> details are handled in firmware itself, we don't bring them to driver level.
OK understood.
>
> > Or is this related to earlier boot stages loading firmware for the emulated
> > downstream endpoints (ep_is_internal)?
> >
> > Finally, in the case where ep_is_internal do you need to disable anything
> > prior to invalidating the mappings?
> >
> No, ep_is_internal is indicator for PAXC IP. It does not have
> mappings as in PAXB.
I think I meant !ep_is_internal. I.e. is there possibility of inbound traffic
prior to invalidating the mappings. I'd assume not, but that's an assumption.
Either way:
Reviewed-by: Andrew Murray <andrew.murray@arm.com>
>
>
> Regards,
> Abhishek
> > >
> > > Signed-off-by: Abhishek Shah <abhishek.shah@broadcom.com>
> > > Reviewed-by: Ray Jui <ray.jui@broadcom.com>
> > > Reviewed-by: Vikram Mysore Prakash <vikram.prakash@broadcom.com>
> > > ---
> > > drivers/pci/controller/pcie-iproc.c | 28 ++++++++++++++++++++++++++++
> > > 1 file changed, 28 insertions(+)
> > >
> > > diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c
> > > index e3ca46497470..99a9521ba7ab 100644
> > > --- a/drivers/pci/controller/pcie-iproc.c
> > > +++ b/drivers/pci/controller/pcie-iproc.c
> > > @@ -1245,6 +1245,32 @@ static int iproc_pcie_map_dma_ranges(struct iproc_pcie *pcie)
> > > return ret;
> > > }
> > >
> > > +static void iproc_pcie_invalidate_mapping(struct iproc_pcie *pcie)
> > > +{
> > > + struct iproc_pcie_ib *ib = &pcie->ib;
> > > + struct iproc_pcie_ob *ob = &pcie->ob;
> > > + int idx;
> > > +
> > > + if (pcie->ep_is_internal)
> > > + return;
> > > +
> > > + if (pcie->need_ob_cfg) {
> > > + /* iterate through all OARR mapping regions */
> > > + for (idx = ob->nr_windows - 1; idx >= 0; idx--) {
> > > + iproc_pcie_write_reg(pcie,
> > > + MAP_REG(IPROC_PCIE_OARR0, idx), 0);
> > > + }
> > > + }
> > > +
> > > + if (pcie->need_ib_cfg) {
> > > + /* iterate through all IARR mapping regions */
> > > + for (idx = 0; idx < ib->nr_regions; idx++) {
> > > + iproc_pcie_write_reg(pcie,
> > > + MAP_REG(IPROC_PCIE_IARR0, idx), 0);
> > > + }
> > > + }
> > > +}
> > > +
> > > static int iproce_pcie_get_msi(struct iproc_pcie *pcie,
> > > struct device_node *msi_node,
> > > u64 *msi_addr)
> > > @@ -1517,6 +1543,8 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
> > > iproc_pcie_perst_ctrl(pcie, true);
> > > iproc_pcie_perst_ctrl(pcie, false);
> > >
> > > + iproc_pcie_invalidate_mapping(pcie);
> > > +
> > > if (pcie->need_ob_cfg) {
> > > ret = iproc_pcie_map_ranges(pcie, res);
> > > if (ret) {
> >
> > The code changes look good to me.
> >
> > Thanks,
> >
> > Andrew Murray
> >
> > > --
> > > 2.17.1
> > >
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v5 0/3] PM / AVS: SVS: Introduce SVS engine
From: Roger Lu @ 2019-09-06 10:05 UTC (permalink / raw)
To: Kevin Hilman, Rob Herring, Nicolas Boichat, Stephen Boyd
Cc: Mark Rutland, Nishanth Menon, Angus Lin, devicetree, linux-pm,
Roger Lu, linux-kernel, HenryC Chen, yt.lee, Fan Chen,
linux-mediatek, Matthias Brugger, linux-arm-kernel
1. SVS driver use OPP adjust event in [1] to update OPP table voltage part.
2. SVS dts node refers to CPU opp table [2] and GPU opp table [3].
3. SVS dts node refers to thermal efuse [4] and PMIC regulator [5].
[1] https://patchwork.kernel.org/patch/11092245/
[2] https://patchwork.kernel.org/patch/10934123/
[3] https://patchwork.kernel.org/patch/11132381/
[4] https://patchwork.kernel.org/patch/11093655/
[5] https://patchwork.kernel.org/patch/11110493/
Roger Lu (3):
dt-bindings: soc: add mtk svs dt-bindings
arm64: dts: mt8183: add svs device information
PM / AVS: SVS: Introduce SVS engine
.../devicetree/bindings/power/mtk-svs.txt | 88 +
arch/arm64/boot/dts/mediatek/mt8183-evb.dts | 16 +
arch/arm64/boot/dts/mediatek/mt8183.dtsi | 38 +
drivers/power/avs/Kconfig | 10 +
drivers/power/avs/Makefile | 1 +
drivers/power/avs/mtk_svs.c | 2075 +++++++++++++++++
include/linux/power/mtk_svs.h | 23 +
7 files changed, 2251 insertions(+)
create mode 100644 Documentation/devicetree/bindings/power/mtk-svs.txt
create mode 100644 drivers/power/avs/mtk_svs.c
create mode 100644 include/linux/power/mtk_svs.h
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ 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