* [PATCH v3 4/4] arm64: dts: allwinner: a64: add SRAM controller device tree node
From: Chen-Yu Tsai @ 2018-06-14 15:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180614153548.9644-1-wens@csie.org>
From: Icenowy Zheng <icenowy@aosc.io>
Allwinner A64 has a SRAM controller, and in the device tree currently
we have a syscon node to enable EMAC driver to access the EMAC clock
register. As SRAM controller driver can now export regmap for this
register, replace the syscon node to the SRAM controller device node,
and let EMAC driver to acquire its EMAC clock regmap.
Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
[wens at csie.org: Updated compatible string]
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
index 1b2ef28c42bd..87968dafe1dc 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
@@ -169,9 +169,24 @@
ranges;
syscon: syscon at 1c00000 {
- compatible = "allwinner,sun50i-a64-system-controller",
- "syscon";
+ compatible = "allwinner,sun50i-a64-system-control";
reg = <0x01c00000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ sram_c: sram at 18000 {
+ compatible = "mmio-sram";
+ reg = <0x00018000 0x28000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x00018000 0x28000>;
+
+ de2_sram: sram-section at 0 {
+ compatible = "allwinner,sun50i-a64-sram-c";
+ reg = <0x0000 0x28000>;
+ };
+ };
};
dma: dma-controller at 1c02000 {
--
2.17.1
^ permalink raw reply related
* [PATCH v3 3/4] soc: sunxi: sram: Add updated compatible string for A64 system control
From: Chen-Yu Tsai @ 2018-06-14 15:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180614153548.9644-1-wens@csie.org>
The SRAM mapping controls on Allwinner SoCs is located in a block called
"System Controls". This block also has registers for identifying the SoC,
reading the state of an external boot-related pin, and on some newer SoCs,
glue layer controls for the EMAC Ethernet controller.
The A64 variant compatible is renamed to "allwinner,a64-system-control"
to reflect this. The old A64 compatible is deprecated. So far we haven't
seen any actual use of it.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
drivers/soc/sunxi/sunxi_sram.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c
index eec7fc6e9f66..7fec1b160dbb 100644
--- a/drivers/soc/sunxi/sunxi_sram.c
+++ b/drivers/soc/sunxi/sunxi_sram.c
@@ -359,6 +359,10 @@ static const struct of_device_id sunxi_sram_dt_match[] = {
.compatible = "allwinner,sun50i-a64-sram-controller",
.data = &sun50i_a64_sramc_variant,
},
+ {
+ .compatible = "allwinner,sun50i-a64-system-control",
+ .data = &sun50i_a64_sramc_variant,
+ },
{ },
};
MODULE_DEVICE_TABLE(of, sunxi_sram_dt_match);
--
2.17.1
^ permalink raw reply related
* [PATCH v3 2/4] dt-bindings: sram: Rename A64 SRAM controller compatible
From: Chen-Yu Tsai @ 2018-06-14 15:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180614153548.9644-1-wens@csie.org>
The SRAM mapping controls on Allwinner SoCs is located in a block called
"System Controls". This block also has registers for identifying the SoC,
reading the state of an external boot-related pin, and on some newer SoCs,
glue layer controls for the EMAC Ethernet controller.
The A64 variant compatible is renamed to "allwinner,a64-system-control"
to reflect this. The old A64 compatible is deprecated. So far we haven't
seen any actual use of it.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
Documentation/devicetree/bindings/sram/sunxi-sram.txt | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/sram/sunxi-sram.txt b/Documentation/devicetree/bindings/sram/sunxi-sram.txt
index d087f04a4d7f..9ef40e2e0a48 100644
--- a/Documentation/devicetree/bindings/sram/sunxi-sram.txt
+++ b/Documentation/devicetree/bindings/sram/sunxi-sram.txt
@@ -11,7 +11,8 @@ Controller Node
Required properties:
- compatible : should be:
- "allwinner,sun4i-a10-sram-controller"
- - "allwinner,sun50i-a64-sram-controller"
+ - "allwinner,sun50i-a64-sram-controller" (deprecated)
+ - "allwinner,sun50i-a64-system-control"
- reg : sram controller register offset + length
SRAM nodes
--
2.17.1
^ permalink raw reply related
* [PATCH v3 1/4] soc: sunxi: export a regmap for EMAC clock reg on A64
From: Chen-Yu Tsai @ 2018-06-14 15:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180614153548.9644-1-wens@csie.org>
From: Icenowy Zheng <icenowy@aosc.io>
The A64 SRAM controller memory zone has a EMAC clock register, which is
needed by the Ethernet MAC driver (dwmac-sun8i).
Export a regmap for this register on A64.
Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
[wens at csie.org: export whole address range with only EMAC register
accessible and drop regmap name]
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Acked-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
drivers/soc/sunxi/sunxi_sram.c | 57 ++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c
index 882be5ed7e84..eec7fc6e9f66 100644
--- a/drivers/soc/sunxi/sunxi_sram.c
+++ b/drivers/soc/sunxi/sunxi_sram.c
@@ -17,6 +17,7 @@
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/soc/sunxi/sunxi_sram.h>
@@ -281,13 +282,51 @@ int sunxi_sram_release(struct device *dev)
}
EXPORT_SYMBOL(sunxi_sram_release);
+struct sunxi_sramc_variant {
+ bool has_emac_clock;
+};
+
+static const struct sunxi_sramc_variant sun4i_a10_sramc_variant = {
+ /* Nothing special */
+};
+
+static const struct sunxi_sramc_variant sun50i_a64_sramc_variant = {
+ .has_emac_clock = true,
+};
+
+#define SUNXI_SRAM_EMAC_CLOCK_REG 0x30
+static bool sunxi_sram_regmap_accessible_reg(struct device *dev,
+ unsigned int reg)
+{
+ if (reg == SUNXI_SRAM_EMAC_CLOCK_REG)
+ return true;
+ return false;
+}
+
+static struct regmap_config sunxi_sram_emac_clock_regmap = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ /* last defined register */
+ .max_register = SUNXI_SRAM_EMAC_CLOCK_REG,
+ /* other devices have no business accessing other registers */
+ .readable_reg = sunxi_sram_regmap_accessible_reg,
+ .writeable_reg = sunxi_sram_regmap_accessible_reg,
+};
+
static int sunxi_sram_probe(struct platform_device *pdev)
{
struct resource *res;
struct dentry *d;
+ struct regmap *emac_clock;
+ const struct sunxi_sramc_variant *variant;
sram_dev = &pdev->dev;
+ variant = of_device_get_match_data(&pdev->dev);
+ if (!variant)
+ return -EINVAL;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
@@ -300,12 +339,26 @@ static int sunxi_sram_probe(struct platform_device *pdev)
if (!d)
return -ENOMEM;
+ if (variant->has_emac_clock) {
+ emac_clock = devm_regmap_init_mmio(&pdev->dev, base,
+ &sunxi_sram_emac_clock_regmap);
+
+ if (IS_ERR(emac_clock))
+ return PTR_ERR(emac_clock);
+ }
+
return 0;
}
static const struct of_device_id sunxi_sram_dt_match[] = {
- { .compatible = "allwinner,sun4i-a10-sram-controller" },
- { .compatible = "allwinner,sun50i-a64-sram-controller" },
+ {
+ .compatible = "allwinner,sun4i-a10-sram-controller",
+ .data = &sun4i_a10_sramc_variant,
+ },
+ {
+ .compatible = "allwinner,sun50i-a64-sram-controller",
+ .data = &sun50i_a64_sramc_variant,
+ },
{ },
};
MODULE_DEVICE_TABLE(of, sunxi_sram_dt_match);
--
2.17.1
^ permalink raw reply related
* [PATCH v3 0/4] allwinner: a64: add SRAM controller / system control
From: Chen-Yu Tsai @ 2018-06-14 15:35 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
This series is the remaining A64 syscon changes from the R40 DWMAC
series. The series aligns how the A64 system control exports a regmap
for the sun8i DWMAC driver to access with what we've done for the R40.
Originally the A64 used the generic syscon for this bit of hardware.
But this block also contains mapping bits for the onboard SRAM, used
by various peripherals, and other vendor specific bits we may use in
the future. It is by no means generic. And we already have a device
tree binding and driver for the SRAM part.
The first patch make the SRAM control device export a regmap, exposing
a single EMAC control register, for the DWMAC driver to consume.
The second and third patches rename the A64 compatible string to read
"system control", which is what the block is named in the user manual.
The last patch fixes up the device node, and also adds the lone mappable
SRAM block, which is needed by the Display Engine.
Changes since v2:
- changed the compatible string from "*-sram-controller" to
"*-system-control"
ChenYu
Chen-Yu Tsai (2):
dt-bindings: sram: Rename A64 SRAM controller compatible
soc: sunxi: sram: Add updated compatible string for A64 system control
Icenowy Zheng (2):
soc: sunxi: export a regmap for EMAC clock reg on A64
arm64: dts: allwinner: a64: add SRAM controller device tree node
.../devicetree/bindings/sram/sunxi-sram.txt | 3 +-
arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 19 +++++-
drivers/soc/sunxi/sunxi_sram.c | 61 ++++++++++++++++++-
3 files changed, 78 insertions(+), 5 deletions(-)
--
2.17.1
^ permalink raw reply
* [RFC V2 3/3] perf: qcom: Add Falkor CPU PMU IMPLEMENTATION DEFINED event support
From: Agustin Vega-Frias @ 2018-06-14 15:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180613130232.GA27675@arm.com>
Hi,
On 2018-06-13 09:02, Will Deacon wrote:
> On Wed, Jun 13, 2018 at 01:59:58PM +0100, Marc Zyngier wrote:
>> On 13/06/18 11:35, Will Deacon wrote:
[...]
>> > Great :( We need to make sure we disable EL0 access during boot then, but
>> > that means we need to prove for the existence of this thing in head.S
>> > (since the PMU driver might not get loaded).
Unfortunately it appears the only check we can do for this is through
the MIDR or PMPIDRx. I'm investigating whether we can detect this
through
some other mechanism, but it that doesn't exists would the MIDR.PMPIDRx
check be acceptable?
>> >
>> > Also, what's the kvm story here so that we don't accidentally open up a
>> > VM-VM side-channel via these registers? How do the EL1 trapping controls
>> > work?
Traps for these registers are as follows:
Architecture traps:
- HCR_EL2.TIDCP enables a trap when accessing IMP DEF registers. kvm
will set
this bit for all guests and access from EL1/EL0 will cause a trap to
EL2.
- MDCR_EL2.TPM enables a trap when accessing the PM registers from
EL1/EL0,
causing accesses to trap to EL2.
- MDCR_EL2.TPM enables a trap when accessing the PM registers from
EL1/EL0,
causing accesses to trap to EL2.
IMP DEF traps:
- IMP DEF register PMACTLR_EL0.UEN controls EL0 access to all IMP DEF
registers related to performance monitoring:
0->disables EL0 access (default), 1->enables EL0 access
- IMP DEF HACR_EL2.TCPUPMRBB enables a trap when accessing the RBB
registers
from EL1/EL0, causing accesses to trap to EL2.
- IMP DEF HACR_EL2.TCPUPMPCCPT enables a trap when accessing the PCC
registers
from EL1/EL0, causing accesses to trap to EL2.
- IMP DEF HACR_EL2.TCPUPMRESRRLDR enables a trap when accessing the
PMRESRx_EL0
registers from EL1/EL0, causing accesses to trap to EL2.
>>
>> We'd trap the IMPDEF register access and inject an UNDEF (assuming
>> that
>> the IMPDEF trapping works correctly). I have strictly no plan to
>> support
>> this in a guest.
>
> Ah, so we could actually configure that in el2_setup and solve the host
> problem if we're entered at EL2. Agustin -- does that work, and what do
> we
> need to do if the host is entered at EL1?
>
Yes, that works, I understand there is no desire to support this under
virtualization.
As for the question about the EL1 host, all of our firmware
configurations
boot the host OS at EL2. Is that sufficient guarantee or can you suggest
an alternative mechanism to ensure security?
Thanks,
Agust?n
--
Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm
Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a
Linux Foundation Collaborative Project.
^ permalink raw reply
* [RFC PATCH 6/8] dts: coresight: Clean up the device tree graph bindings
From: Matt Sealey @ 2018-06-14 15:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAL_Jsq+0kExVY33kdDoR6bAxbr2VzRUzW2j0k+2wmv4CSNVnpQ@mail.gmail.com>
Hi Rob,
To take this in a somewhat different direction...
> > No, the above comment is about using "unit" ( if it is a standard
> > property for specifying something specific to hardware) instead of
> > "coresight,hwid". I would prefer to stick to the DT graph bindings,
> > because :
>
> "unit" is not a standard property and I don't like it either.
Fair enough.
> If you have "in-ports" and "out-ports" nodes, then that gives you
> direction and you can use reg for the "hardware port".
>
> in-ports {
> port at 0 {
> reg = <0>;
> endpoint {...};
> };
> port at 1 {
> reg = <1>;
> endpoint {...};
> };
> };
> out-ports {
> port at 0 {
> reg = <0>;
> endpoint {...};
> };
> };
>
> I'll need to check, but dtc may need an update to not warn about this.
If the requirement that unit-address and the low #address-cells of reg
now being forced by a validation tool is screwing us over here, we can't
really change the tool; that's a IEEE 1275-1994 requirement we'd be
hacking around.
Here's a thought - why don't we define the ports in each component in a
separate graph? Describing the ATB topology as a bus with a graph structure
and then having the components simply reference the port nodes would make
it much easier to design.
Part of the problem is trying to describe an ATB bus via a component on
an APB bus. You lose all the niceties of describing a bus with bus
subcomponents. Lets take the ATB bus outside.. by describing the ingress
and egress of the component you have no idea where in the graph you are
at the point of entry (you could start parsing at a funnel, which means
travelling around looking for other units that match other compatibles).
If the CoreSight subsystem could have a graph pre-made of the full
topology, then the components can point to how they wrap parts of
that topology. You can also do away with ridiculous non-programmable
funnels and replicator nodes, since the trace graph would encapsulate
that information without having to instantiate a stub driver for it.
That doesn't solve 'unit' or 'unit-address' or 'reg' or anything but
it would keep us in graph bindings and abstract the ATB topology from
the components. Other fun stuff; describing bridge components and bus
widths within the graph could give abilities to describe bandwidths
over each trace path.
In any case, what happens when you have to decide what your funnel
port priorities are, you'll have to define a new property for that,
and it won't be 'reg'.
Trying not to add anything to the graph bindings is one thing but
trying to shoehorn it in either by doing that or inventing wholly
device-specific properties are just as bad.
Perhaps we can use the path at unit-address:arguments <-- parameters here to
add extra information about the port. 'my-args' would pull it out in Forth,
I don't know how FDT code deals with it (but there should be something,
since we use it for console definition in /chosen). They're entirely
specific to the node in question, but not used in path matching.
Why can't we decide on a graph-binding update that allows specifying
something simple as a demultiplexer output in a way the driver can
understand and map to the hardware?
> If DT bindings can be reused for ACPI, that's fine
However in my opinion not the preferred way to do it..
> any DT bindings to be accepted simply because they match ACPI
> bindings.
I'm sure ACPI has capability of a much classier way of describing
things, but I have some fear that it's just OF bindings stuffed in
a _DSD.. DT and ACPI have the responsibility of shouldering the
burden of describing hardware. Any attempts to try and make some
commonality to promote brevity of Linux code is totally out of scope..
You can always abstract whatever definition into whatever the Linux
drivers need at the time. That's kind of the point. Locking in to
'how it's currently coded' is stifling when realizing the first
attempt didn't actually adequately do what it was intended.
Ta,
Matt
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
^ permalink raw reply
* [PATCH v3 4/6] thermal: tsens: Add support for SDM845
From: Amit Kucheria @ 2018-06-14 14:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAL_JsqLPKktGFH4X9gDgCFq70Uo6NvFx9-a0sR7fQU35NwZe1g@mail.gmail.com>
Hi Rob,
Thanks for the review.
On Thu, Jun 14, 2018 at 5:21 PM Rob Herring <robh+dt@kernel.org> wrote:
>
> On Thu, Jun 14, 2018 at 4:43 AM, Amit Kucheria <amit.kucheria@linaro.org> wrote:
> > SDM845 uses the TSENS v2 IP block
> >
> > Signed-off-by: Amit Kucheria <amit.kucheria@linaro.org>
> > ---
> > Documentation/devicetree/bindings/thermal/qcom-tsens.txt | 1 +
> > arch/arm64/boot/dts/qcom/msm8996.dtsi | 2 +-
> > drivers/thermal/qcom/tsens-v2.c | 9 ++++++++-
> > drivers/thermal/qcom/tsens.c | 3 +++
> > drivers/thermal/qcom/tsens.h | 5 ++++-
> > 5 files changed, 17 insertions(+), 3 deletions(-)
> >
> > diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
> > index 06195e8..84da3db 100644
> > --- a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
> > +++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
> > @@ -5,6 +5,7 @@ Required properties:
> > - "qcom,msm8916-tsens" : For 8916 Family of SoCs
> > - "qcom,msm8974-tsens" : For 8974 Family of SoCs
> > - "qcom,msm8996-tsens" : For 8996 Family of SoCs
> > + - "qcom,tsens-v2" : For any SoC with v2 version of the tsens IP
>
> Stick with "qcom,sdm845-tsens". Though perhaps it should be
> '"qcom,sdm845-tsens", "qcom,msm8996-tsens"' if there is compatibility.
There are lots of (30+) SoC families that use v2 of the tsens IP. So
we're talking about potentially 100s of platforms using the IP. This
could become very unwieldy to deal with very quickly.
The core functionality in tsens v2 remains the same (e.g. reading the
temperature) and any differences could potentially be addressed with
more specific DTs or preferably dynamically detected by probing the
minor version of the HW version register.
> > - reg: Address range of the thermal registers
> > - #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description.
> > diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi
> > index 6c8a857..28d4c08 100644
> > --- a/arch/arm64/boot/dts/qcom/msm8996.dtsi
> > +++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi
> > @@ -460,7 +460,7 @@
> > };
> >
> > tsens0: thermal-sensor at 4a8000 {
> > - compatible = "qcom,msm8996-tsens";
> > + compatible = "qcom,msm8996-tsens", "qcom,tsens-v2";
>
> There's no point to adding this now because you already have to
> support "qcom,msm8996-tsens".
Of course.
>
> > reg = <0x4a9000 0x1000>, /* TM */
> > <0x4a8000 0x1000>; /* SROT */
> > #qcom,sensors = <13>;
> > diff --git a/drivers/thermal/qcom/tsens-v2.c b/drivers/thermal/qcom/tsens-v2.c
> > index c981a40..abc8f13 100644
> > --- a/drivers/thermal/qcom/tsens-v2.c
> > +++ b/drivers/thermal/qcom/tsens-v2.c
> > @@ -69,8 +69,15 @@ static const struct tsens_ops ops_v2 = {
> > .get_temp = get_temp_tsens_v2,
> > };
> >
> > +const struct tsens_data data_tsens_v2 = {
> > + .ops = &ops_v2,
> > +};
> > +
> > +/* Kept around for backward compatibility with old msm8996.dtsi.
> > + * New platforms should use data_tsens_v2 if possible and define
> > + * the #qcom,sensors property in DT.
>
> Hum, I think this should just be implied by the compatible as it was.
> If this was the *only* difference, then a property would be okay, but
> as soon as you find some other difference you need yet another
> property and have to do a DT update on all platforms.
Perhaps I was needless wordy, but the only reason to keep data_8996
around is the num_sensors bit below. Now that Bjorn's patch
6d7c70d1cd65 ("thermal: qcom: tsens: Allow number of sensors to come
from DT") has landed, that should be the default way to specify the
number of sensors connected to each IP block.
We want future DTs to simply use the qcom,tsens-v2 property instead of
saying that they're all compatible with 8996. That will more truly
reflect the HW (tsens v2) and the qcom,msm8996-tsens binding probably
shouldn't have been added in the first place.
> > + */
> > const struct tsens_data data_8996 = {
> > .num_sensors = 13,
> > .ops = &ops_v2,
> > };
> > -
> > diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
> > index 3440166c..a2c9bfa 100644
> > --- a/drivers/thermal/qcom/tsens.c
> > +++ b/drivers/thermal/qcom/tsens.c
> > @@ -72,6 +72,9 @@ static const struct of_device_id tsens_table[] = {
> > }, {
> > .compatible = "qcom,msm8996-tsens",
> > .data = &data_8996,
> > + }, {
> > + .compatible = "qcom,tsens-v2",
> > + .data = &data_tsens_v2,
>
> Why different data if 8996 is compatible with v2?
See above.
> > },
> > {}
> > };
> > diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
> > index dc56e1e..69212cb 100644
> > --- a/drivers/thermal/qcom/tsens.h
> > +++ b/drivers/thermal/qcom/tsens.h
> > @@ -87,6 +87,9 @@ void compute_intercept_slope(struct tsens_device *, u32 *, u32 *, u32);
> > int init_common(struct tsens_device *);
> > int get_temp_common(struct tsens_device *, int, int *);
> >
> > -extern const struct tsens_data data_8916, data_8974, data_8960, data_8996;
> > +/* TSENS v1 targets */
> > +extern const struct tsens_data data_8916, data_8974, data_8960;
> > +/* TSENS v2 targets */
> > +extern const struct tsens_data data_8996, data_tsens_v2;
> >
> > #endif /* __QCOM_TSENS_H__ */
> > --
> > 2.7.4
> >
^ permalink raw reply
* [linux-sunxi] [PATCH v2 00/27] Add support for R40 HDMI pipeline
From: Jernej Škrabec @ 2018-06-14 14:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAMty3ZC-Edg5XJQpqEuwLbSFzmam3zP3zUPak4K7ypyT2+arAg@mail.gmail.com>
Dne ?etrtek, 14. junij 2018 ob 09:12:41 CEST je Jagan Teki napisal(a):
> On Wed, Jun 13, 2018 at 1:30 AM, Jernej Skrabec <jernej.skrabec@siol.net>
wrote:
> > This series adds support for R40 HDMI pipeline. It is a bit special
> > than other already supported pipelines because it has additional unit
> > called TCON TOP responsible for relationship configuration between
> > mixers, TCONs and HDMI. Additionally, it has additional gates for DSI
> > and TV TCONs, TV encoder clock settings and pin muxing between LCD
> > and TV encoders.
> >
> > However, it seems that TCON TOP will become a norm, since newer
> > Allwinner SoCs like H6 also have this unit.
> >
> > I tested different possible configurations:
> > - mixer0 <> TCON-TV0 <> HDMI
> > - mixer0 <> TCON-TV1 <> HDMI
> > - mixer1 <> TCON-TV0 <> HDMI
> > - mixer1 <> TCON-TV1 <> HDMI
> >
> > Please review.
> >
> > Best regards,
> > Jernej
> >
> > Changes from v1:
> > - Split DT bindings patch and updated description
> > - Split HDMI PHY patch
> > - Move header file from TCON TOP patch to dt bindings patch
> > - Added Rob reviewed-by tag
> > - Used clk_hw_register_gate() instead of custom gate registration code
> > - Reworked TCON TOP to be part of of-graph. Because of that, a lot of
> >
> > new patches were added.
> >
> > - Droped mixer index quirk patch
> > - Reworked TCON support for TCON TOP
> > - Updated commit messages
> >
> > Jernej Skrabec (27):
> > clk: sunxi-ng: r40: Add minimal rate for video PLLs
> > clk: sunxi-ng: r40: Allow setting parent rate to display related
> >
> > clocks
> >
> > clk: sunxi-ng: r40: Export video PLLs
> > dt-bindings: display: sunxi-drm: Add TCON TOP description
> > drm/sun4i: Add TCON TOP driver
> > drm/sun4i: Fix releasing node when enumerating enpoints
> > drm/sun4i: Split out code for enumerating endpoints in output port
> > drm/sun4i: Add support for traversing graph with TCON TOP
> > drm/sun4i: Don't skip TCONs if they don't have channel 0
> > dt-bindings: display: sun4i-drm: Add R40 TV TCON description
> > drm/sun4i: tcon: Add support for tcon-top gate
> > drm/sun4i: tcon: Generalize engine search algorithm
> > drm/sun4i: Don't check for LVDS and RGB when TCON has only ch1
> > drm/sun4i: Don't check for panel or bridge on TV TCONs
> > drm/sun4i: Add support for R40 TV TCON
> > dt-bindings: display: sun4i-drm: Add R40 mixer compatibles
> > drm/sun4i: Add support for R40 mixers
> > dt-bindings: display: sun4i-drm: Add description of A64 HDMI PHY
> > drm/sun4i: Enable DW HDMI PHY clock
> > drm/sun4i: Don't change clock bits in DW HDMI PHY driver
> > drm/sun4i: DW HDMI PHY: Add support for second PLL
> > drm/sun4i: Add support for second clock parent to DW HDMI PHY clk
> >
> > driver
> >
> > drm/sun4i: Add support for A64 HDMI PHY
> > drm: of: Export drm_crtc_port_mask()
> > drm/sun4i: DW HDMI: Expand algorithm for possible crtcs
> > ARM: dts: sun8i: r40: Add HDMI pipeline
> > ARM: dts: sun8i: r40: Enable HDMI output on BananaPi M2 Ultra
>
> Tested whole series on top of linux-next.
>
> Tested-by: Jagan Teki <jagan@amarulasolutions.com>
Thanks!
^ permalink raw reply
* [PATCH] pinctrl: mt7622: fix a kernel panic when pio don't work as EINT controller
From: Linus Walleij @ 2018-06-14 14:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <6615b85997509d659358d33eab2d280e235b8659.1528966092.git.sean.wang@mediatek.com>
On Thu, Jun 14, 2018 at 10:55 AM, <sean.wang@mediatek.com> wrote:
> From: Sean Wang <sean.wang@mediatek.com>
>
> The function, external interrupt controller, is made as an optional to
> mt7622 pinctrl. But if we don't want pio behaves as an external interrupt
> controller, it would lead to hw->eint not be created properly and then
> will cause 'kernel NULL pointer' issue when gpiochip try to call .to_irq
> or .set_config. To fix it, check hw->eint before accessing the member.
>
> [ 1.339494] Unable to handle kernel NULL pointer dereference at virtual
> address 00000010
> [ 1.347857] Mem abort info:
> [ 1.350742] ESR = 0x96000005
> [ 1.353905] Exception class = DABT (current EL), IL = 32 bits
> [ 1.360024] SET = 0, FnV = 0
> [ 1.363185] EA = 0, S1PTW = 0
> [ 1.366431] Data abort info:
> [ 1.369405] ISV = 0, ISS = 0x00000005
> [ 1.373363] CM = 0, WnR = 0
> [ 1.376437] [0000000000000010] user address but active_mm is swapper
> [ 1.383005] Internal error: Oops: 96000005 [#1] PREEMPT SMP
> [ 1.388748] Modules linked in:
> [ 1.391897] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.16.0-rc1+ #344
> [ 1.398625] Hardware name: MediaTek MT7622 RFB1 board (DT)
> [ 1.404279] pstate: 80000005 (Nzcv daif -PAN -UAO)
> [ 1.409221] pc : mtk_eint_find_irq+0x8/0x24
> [ 1.413532] lr : mtk_gpio_to_irq+0x20/0x28
> [ 1.417749] sp : ffffff800801baf0
> [ 1.421161] x29: ffffff800801baf0 x28: ffffff8008792f40
> [ 1.426637] x27: ffffff800886b000 x26: ffffff8008615620
> [ 1.432113] x25: ffffffc00e4dbdc8 x24: ffffff80087b8000
> [ 1.437589] x23: ffffffc00325a000 x22: ffffffc00325a010
> [ 1.443066] x21: ffffffc0033dec18 x20: 00000000ffffffea
> [ 1.448542] x19: ffffffc00e4db800 x18: 0000000000000130
> [ 1.454018] x17: 000000000000000e x16: 0000000000000007
> [ 1.459494] x15: ffffff80085ee000 x14: 0000000000000001
> [ 1.464970] x13: 0000000000000001 x12: 0000000000000010
> [ 1.470446] x11: 0101010101010101 x10: 0000000000000880
> [ 1.475922] x9 : ffffff800801b990 x8 : ffffffc0030688e0
> [ 1.481399] x7 : ffffff80080c0660 x6 : ffffffc00e4dbbb0
> [ 1.486875] x5 : 0000000000000000 x4 : 0000000000000000
> [ 1.492351] x3 : ffffff80082a92f4 x2 : 00000000fffffffa
> [ 1.497826] x1 : 0000000000000051 x0 : 0000000000000000
> [ 1.503305] Process swapper/0 (pid: 1, stack limit = 0x0000000054e053bd)
> [ 1.510210] Call trace:
> [ 1.512727] mtk_eint_find_irq+0x8/0x24
> [ 1.516677] mtk_gpio_to_irq+0x20/0x28
> [ 1.520539] gpiod_to_irq+0x48/0x60
> [ 1.524135] mmc_gpiod_request_cd_irq+0x3c/0xc4
> [ 1.528804] mmc_start_host+0x6c/0x8c
> [ 1.532575] mmc_add_host+0x58/0x7c
> [ 1.536168] msdc_drv_probe+0x4fc/0x67c
> [ 1.540121] platform_drv_probe+0x58/0xa4
> [ 1.544251] driver_probe_device+0x204/0x44c
> [ 1.548649] __driver_attach+0x84/0xf8
> [ 1.552512] bus_for_each_dev+0x68/0xa0
> [ 1.556461] driver_attach+0x20/0x28
> [ 1.560142] bus_add_driver+0xec/0x240
> [ 1.564002] driver_register+0x98/0xe4
> [ 1.567863] __platform_driver_register+0x48/0x50
> [ 1.572711] mt_msdc_driver_init+0x18/0x20
> [ 1.576932] do_one_initcall+0x98/0x130
> [ 1.580886] kernel_init_freeable+0x13c/0x1d4
> [ 1.585375] kernel_init+0x10/0xf8
> [ 1.588879] ret_from_fork+0x10/0x18
> [ 1.592564] Code: a8c67bfd d65f03c0 a9bf7bfd 910003fd (f9400800)
> [ 1.598849] ---[ end trace 4bbcb7bc30e98492 ]---
> [ 1.603677] Kernel panic - not syncing: Attempted to kill init!
> exitcode=0x0000000b
> [ 1.603677]
>
> cc: Kevin Hilman <khilman@baylibre.com>
> Cc: stable at vger.kernel.org
> Fixes: e6dabd38d8e7 ("pinctrl: mediatek: add EINT support to MT7622 SoC")
> Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Patch applied for fixes.
Yours,
Linus Walleij
^ permalink raw reply
* [PATCH v3 4/6] thermal: tsens: Add support for SDM845
From: Rob Herring @ 2018-06-14 14:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <0cdd0957cf80c2f9921928755722a427c7309964.1528972165.git.amit.kucheria@linaro.org>
On Thu, Jun 14, 2018 at 4:43 AM, Amit Kucheria <amit.kucheria@linaro.org> wrote:
> SDM845 uses the TSENS v2 IP block
>
> Signed-off-by: Amit Kucheria <amit.kucheria@linaro.org>
> ---
> Documentation/devicetree/bindings/thermal/qcom-tsens.txt | 1 +
> arch/arm64/boot/dts/qcom/msm8996.dtsi | 2 +-
> drivers/thermal/qcom/tsens-v2.c | 9 ++++++++-
> drivers/thermal/qcom/tsens.c | 3 +++
> drivers/thermal/qcom/tsens.h | 5 ++++-
> 5 files changed, 17 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
> index 06195e8..84da3db 100644
> --- a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
> +++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
> @@ -5,6 +5,7 @@ Required properties:
> - "qcom,msm8916-tsens" : For 8916 Family of SoCs
> - "qcom,msm8974-tsens" : For 8974 Family of SoCs
> - "qcom,msm8996-tsens" : For 8996 Family of SoCs
> + - "qcom,tsens-v2" : For any SoC with v2 version of the tsens IP
Stick with "qcom,sdm845-tsens". Though perhaps it should be
'"qcom,sdm845-tsens", "qcom,msm8996-tsens"' if there is compatibility.
>
> - reg: Address range of the thermal registers
> - #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description.
> diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi
> index 6c8a857..28d4c08 100644
> --- a/arch/arm64/boot/dts/qcom/msm8996.dtsi
> +++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi
> @@ -460,7 +460,7 @@
> };
>
> tsens0: thermal-sensor at 4a8000 {
> - compatible = "qcom,msm8996-tsens";
> + compatible = "qcom,msm8996-tsens", "qcom,tsens-v2";
There's no point to adding this now because you already have to
support "qcom,msm8996-tsens".
> reg = <0x4a9000 0x1000>, /* TM */
> <0x4a8000 0x1000>; /* SROT */
> #qcom,sensors = <13>;
> diff --git a/drivers/thermal/qcom/tsens-v2.c b/drivers/thermal/qcom/tsens-v2.c
> index c981a40..abc8f13 100644
> --- a/drivers/thermal/qcom/tsens-v2.c
> +++ b/drivers/thermal/qcom/tsens-v2.c
> @@ -69,8 +69,15 @@ static const struct tsens_ops ops_v2 = {
> .get_temp = get_temp_tsens_v2,
> };
>
> +const struct tsens_data data_tsens_v2 = {
> + .ops = &ops_v2,
> +};
> +
> +/* Kept around for backward compatibility with old msm8996.dtsi.
> + * New platforms should use data_tsens_v2 if possible and define
> + * the #qcom,sensors property in DT.
Hum, I think this should just be implied by the compatible as it was.
If this was the *only* difference, then a property would be okay, but
as soon as you find some other difference you need yet another
property and have to do a DT update on all platforms.
> + */
> const struct tsens_data data_8996 = {
> .num_sensors = 13,
> .ops = &ops_v2,
> };
> -
> diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
> index 3440166c..a2c9bfa 100644
> --- a/drivers/thermal/qcom/tsens.c
> +++ b/drivers/thermal/qcom/tsens.c
> @@ -72,6 +72,9 @@ static const struct of_device_id tsens_table[] = {
> }, {
> .compatible = "qcom,msm8996-tsens",
> .data = &data_8996,
> + }, {
> + .compatible = "qcom,tsens-v2",
> + .data = &data_tsens_v2,
Why different data if 8996 is compatible with v2?
> },
> {}
> };
> diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
> index dc56e1e..69212cb 100644
> --- a/drivers/thermal/qcom/tsens.h
> +++ b/drivers/thermal/qcom/tsens.h
> @@ -87,6 +87,9 @@ void compute_intercept_slope(struct tsens_device *, u32 *, u32 *, u32);
> int init_common(struct tsens_device *);
> int get_temp_common(struct tsens_device *, int, int *);
>
> -extern const struct tsens_data data_8916, data_8974, data_8960, data_8996;
> +/* TSENS v1 targets */
> +extern const struct tsens_data data_8916, data_8974, data_8960;
> +/* TSENS v2 targets */
> +extern const struct tsens_data data_8996, data_tsens_v2;
>
> #endif /* __QCOM_TSENS_H__ */
> --
> 2.7.4
>
^ permalink raw reply
* [PATCH] gpio: uniphier: set legitimate irq trigger type in .to_irq hook
From: Linus Walleij @ 2018-06-14 14:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528954065-25563-1-git-send-email-yamada.masahiro@socionext.com>
On Thu, Jun 14, 2018 at 7:27 AM, Masahiro Yamada
<yamada.masahiro@socionext.com> wrote:
> If a GPIO chip is a part of a hierarchy IRQ domain, there is no
> way to specify the trigger type when gpio(d)_to_irq() allocates an
> interrupt on-the-fly.
>
> Currently, uniphier_gpio_to_irq() sets IRQ_TYPE_NONE, but it causes
> an error in the .alloc() hook of the parent domain.
> (drivers/irq/irq-uniphier-aidet.c)
>
> Even if we change irq-uniphier-aidet.c to accept the NONE type,
> GIC complains about it since commit 83a86fbb5b56 ("irqchip/gic:
> Loudly complain about the use of IRQ_TYPE_NONE").
>
> Instead, use IRQ_TYPE_LEVEL_HIGH as a temporary value when an irq
> is allocated. irq_set_irq_type() will override it when the irq is
> really requested.
>
> Fixes: dbe776c2ca54 ("gpio: uniphier: add UniPhier GPIO controller driver")
> Reported-by: Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>
> Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
> Tested-by: Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>
Patch applied for fixes!
Yours,
Linus Walleij
^ permalink raw reply
* [PATCH v3 6/7] mmc: sunxi: Add runtime_pm support
From: Marc Zyngier @ 2018-06-14 14:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4514368de4ef7b4224be455f2d9e6090b464e819.1523888566.git-series.maxime.ripard@bootlin.com>
Hi Maxime,
On 16/04/18 15:23, Maxime Ripard wrote:
> So far, even if our card was not in use, we didn't shut down our MMC
> controller, which meant that it was still active and clocking the bus.
>
> While this obviously means that we could save some power there, it also
> creates issues when it comes to EMC control since we'll have a perfect peak
> at the card clock rate.
>
> Let's implement runtime_pm with autosuspend so that we will shut down the
> controller when it's not been in use for quite some time.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
> ---
> drivers/mmc/host/sunxi-mmc.c | 48 +++++++++++++++++++++++++++++++++++++-
> 1 file changed, 48 insertions(+)
>
> diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c
> index 0165da0d022a..0253deb153a4 100644
> --- a/drivers/mmc/host/sunxi-mmc.c
> +++ b/drivers/mmc/host/sunxi-mmc.c
> @@ -35,6 +35,7 @@
> #include <linux/of_gpio.h>
> #include <linux/of_platform.h>
> #include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> #include <linux/regulator/consumer.h>
> #include <linux/reset.h>
> #include <linux/scatterlist.h>
> @@ -969,6 +970,9 @@ static void sunxi_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
> unsigned long flags;
> u32 imask;
>
> + if (enable)
> + pm_runtime_get_noresume(host->dev);
> +
> spin_lock_irqsave(&host->lock, flags);
>
> imask = mmc_readl(host, REG_IMASK);
> @@ -981,6 +985,9 @@ static void sunxi_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
> }
> mmc_writel(host, REG_IMASK, imask);
> spin_unlock_irqrestore(&host->lock, flags);
> +
> + if (!enable)
> + pm_runtime_put_noidle(host->mmc->parent);
> }
>
> static void sunxi_mmc_hw_reset(struct mmc_host *mmc)
> @@ -1394,6 +1401,11 @@ static int sunxi_mmc_probe(struct platform_device *pdev)
> if (ret)
> goto error_free_dma;
>
> + pm_runtime_set_active(&pdev->dev);
> + pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
> + pm_runtime_use_autosuspend(&pdev->dev);
> + pm_runtime_enable(&pdev->dev);
> +
> ret = mmc_add_host(mmc);
> if (ret)
> goto error_free_dma;
> @@ -1414,6 +1426,7 @@ static int sunxi_mmc_remove(struct platform_device *pdev)
> struct sunxi_mmc_host *host = mmc_priv(mmc);
>
> mmc_remove_host(mmc);
> + pm_runtime_force_suspend(&pdev->dev);
> disable_irq(host->irq);
> sunxi_mmc_disable(host);
> dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
> @@ -1422,10 +1435,45 @@ static int sunxi_mmc_remove(struct platform_device *pdev)
> return 0;
> }
>
> +static int sunxi_mmc_runtime_resume(struct device *dev)
> +{
> + struct mmc_host *mmc = dev_get_drvdata(dev);
> + struct sunxi_mmc_host *host = mmc_priv(mmc);
> + int ret;
> +
> + ret = sunxi_mmc_enable(host);
> + if (ret)
> + return ret;
> +
> + sunxi_mmc_init_host(host);
> + sunxi_mmc_set_bus_width(host, mmc->ios.bus_width);
> + sunxi_mmc_set_clk(host, &mmc->ios);
> +
> + return 0;
> +}
> +
> +static int sunxi_mmc_runtime_suspend(struct device *dev)
> +{
> + struct mmc_host *mmc = dev_get_drvdata(dev);
> + struct sunxi_mmc_host *host = mmc_priv(mmc);
> +
> + sunxi_mmc_reset_host(host);
> + sunxi_mmc_disable(host);
> +
> + return 0;
> +}
> +
> +static const struct dev_pm_ops sunxi_mmc_pm_ops = {
> + SET_RUNTIME_PM_OPS(sunxi_mmc_runtime_suspend,
> + sunxi_mmc_runtime_resume,
> + NULL)
> +};
> +
> static struct platform_driver sunxi_mmc_driver = {
> .driver = {
> .name = "sunxi-mmc",
> .of_match_table = of_match_ptr(sunxi_mmc_of_match),
> + .pm = &sunxi_mmc_pm_ops,
> },
> .probe = sunxi_mmc_probe,
> .remove = sunxi_mmc_remove,
>
This patch has the unfortunate impact of killing my A20 system
(cubietruck), as of 9a8e1e8cc2c02c57c4e941651a8481a633506c91:
[...]
[ 3.286649] NET: Registered protocol family 10
[ 3.291898] mmcblk0: p1
[ 3.295297] mmc1: queuing unknown CIS tuple 0x80 (2 bytes)
[ 3.302773] mmc1: queuing unknown CIS tuple 0x80 (3 bytes)
[ 3.305787] Segment Routing with IPv6
[ 3.312225] mip6: Mobile IPv6
[ 3.316166] sit: IPv6, IPv4 and MPLS over IPv4 tunneling driver
[ 3.316246] mmc1: queuing unknown CIS tuple 0x80 (3 bytes)
[ 3.323721] ip6_gre: GRE over IPv6 tunneling driver
[ 3.333954] NET: Registered protocol family 17
[ 3.338837] 9pnet: Installing 9P2000 support
[ 3.343379] NET: Registered protocol family 37
[ 3.347885] Key type dns_resolver registered
[ 3.352214] mmc1: queuing unknown CIS tuple 0x80 (7 bytes)
[ 3.352217] openvswitch: Open vSwitch switching datapath
[ 3.352620] mpls_gso: MPLS GSO support
[ 3.367001] ThumbEE CPU extension supported.
and that's where it stops. No message, just a hard lockup (I suppose
that both the CPUs are trying to access some device that is now not
clocked).
With a working kernel, I see SATA and the wifi SDIO being probed.
Happy to help testing stuff if you have any idea.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply
* [PATCH 4.9 19/30] serial: sh-sci: Stop using printk format %pCr
From: Greg Kroah-Hartman @ 2018-06-14 14:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180614132600.255515394@linuxfoundation.org>
4.9-stable review patch. If anyone has any objections, please let me know.
------------------
From: Geert Uytterhoeven <geert+renesas@glider.be>
commit d63c16f8e1ab761775275adcf54f4bef7c330295 upstream.
Printk format "%pCr" will be removed soon, as clk_get_rate() must not be
called in atomic context.
Replace it by open-coding the operation. This is safe here, as the code
runs in task context.
Link: http://lkml.kernel.org/r/1527845302-12159-4-git-send-email-geert+renesas at glider.be
To: Jia-Ju Bai <baijiaju1990@gmail.com>
To: Jonathan Corbet <corbet@lwn.net>
To: Michael Turquette <mturquette@baylibre.com>
To: Stephen Boyd <sboyd@kernel.org>
To: Zhang Rui <rui.zhang@intel.com>
To: Eduardo Valentin <edubezval@gmail.com>
To: Eric Anholt <eric@anholt.net>
To: Stefan Wahren <stefan.wahren@i2se.com>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
Cc: Petr Mladek <pmladek@suse.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: linux-doc at vger.kernel.org
Cc: linux-clk at vger.kernel.org
Cc: linux-pm at vger.kernel.org
Cc: linux-serial at vger.kernel.org
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-renesas-soc at vger.kernel.org
Cc: linux-kernel at vger.kernel.org
Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Cc: stable at vger.kernel.org # 4.5+
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/tty/serial/sh-sci.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -2626,8 +2626,8 @@ found:
dev_dbg(dev, "failed to get %s (%ld)\n", clk_names[i],
PTR_ERR(clk));
else
- dev_dbg(dev, "clk %s is %pC rate %pCr\n", clk_names[i],
- clk, clk);
+ dev_dbg(dev, "clk %s is %pC rate %lu\n", clk_names[i],
+ clk, clk_get_rate(clk));
sci_port->clks[i] = IS_ERR(clk) ? NULL : clk;
}
return 0;
^ permalink raw reply
* [PATCH 4.14 18/36] serial: sh-sci: Stop using printk format %pCr
From: Greg Kroah-Hartman @ 2018-06-14 14:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180614132157.333004166@linuxfoundation.org>
4.14-stable review patch. If anyone has any objections, please let me know.
------------------
From: Geert Uytterhoeven <geert+renesas@glider.be>
commit d63c16f8e1ab761775275adcf54f4bef7c330295 upstream.
Printk format "%pCr" will be removed soon, as clk_get_rate() must not be
called in atomic context.
Replace it by open-coding the operation. This is safe here, as the code
runs in task context.
Link: http://lkml.kernel.org/r/1527845302-12159-4-git-send-email-geert+renesas at glider.be
To: Jia-Ju Bai <baijiaju1990@gmail.com>
To: Jonathan Corbet <corbet@lwn.net>
To: Michael Turquette <mturquette@baylibre.com>
To: Stephen Boyd <sboyd@kernel.org>
To: Zhang Rui <rui.zhang@intel.com>
To: Eduardo Valentin <edubezval@gmail.com>
To: Eric Anholt <eric@anholt.net>
To: Stefan Wahren <stefan.wahren@i2se.com>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
Cc: Petr Mladek <pmladek@suse.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: linux-doc at vger.kernel.org
Cc: linux-clk at vger.kernel.org
Cc: linux-pm at vger.kernel.org
Cc: linux-serial at vger.kernel.org
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-renesas-soc at vger.kernel.org
Cc: linux-kernel at vger.kernel.org
Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Cc: stable at vger.kernel.org # 4.5+
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/tty/serial/sh-sci.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -2669,8 +2669,8 @@ found:
dev_dbg(dev, "failed to get %s (%ld)\n", clk_names[i],
PTR_ERR(clk));
else
- dev_dbg(dev, "clk %s is %pC rate %pCr\n", clk_names[i],
- clk, clk);
+ dev_dbg(dev, "clk %s is %pC rate %lu\n", clk_names[i],
+ clk, clk_get_rate(clk));
sci_port->clks[i] = IS_ERR(clk) ? NULL : clk;
}
return 0;
^ permalink raw reply
* [PATCH 4.16 25/43] serial: sh-sci: Stop using printk format %pCr
From: Greg Kroah-Hartman @ 2018-06-14 14:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180614132135.111973468@linuxfoundation.org>
4.16-stable review patch. If anyone has any objections, please let me know.
------------------
From: Geert Uytterhoeven <geert+renesas@glider.be>
commit d63c16f8e1ab761775275adcf54f4bef7c330295 upstream.
Printk format "%pCr" will be removed soon, as clk_get_rate() must not be
called in atomic context.
Replace it by open-coding the operation. This is safe here, as the code
runs in task context.
Link: http://lkml.kernel.org/r/1527845302-12159-4-git-send-email-geert+renesas at glider.be
To: Jia-Ju Bai <baijiaju1990@gmail.com>
To: Jonathan Corbet <corbet@lwn.net>
To: Michael Turquette <mturquette@baylibre.com>
To: Stephen Boyd <sboyd@kernel.org>
To: Zhang Rui <rui.zhang@intel.com>
To: Eduardo Valentin <edubezval@gmail.com>
To: Eric Anholt <eric@anholt.net>
To: Stefan Wahren <stefan.wahren@i2se.com>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
Cc: Petr Mladek <pmladek@suse.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: linux-doc at vger.kernel.org
Cc: linux-clk at vger.kernel.org
Cc: linux-pm at vger.kernel.org
Cc: linux-serial at vger.kernel.org
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-renesas-soc at vger.kernel.org
Cc: linux-kernel at vger.kernel.org
Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Cc: stable at vger.kernel.org # 4.5+
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/tty/serial/sh-sci.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -2691,8 +2691,8 @@ found:
dev_dbg(dev, "failed to get %s (%ld)\n", clk_names[i],
PTR_ERR(clk));
else
- dev_dbg(dev, "clk %s is %pC rate %pCr\n", clk_names[i],
- clk, clk);
+ dev_dbg(dev, "clk %s is %pC rate %lu\n", clk_names[i],
+ clk, clk_get_rate(clk));
sci_port->clks[i] = IS_ERR(clk) ? NULL : clk;
}
return 0;
^ permalink raw reply
* [PATCH 4.17 25/45] serial: sh-sci: Stop using printk format %pCr
From: Greg Kroah-Hartman @ 2018-06-14 14:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180614132126.797006529@linuxfoundation.org>
4.17-stable review patch. If anyone has any objections, please let me know.
------------------
From: Geert Uytterhoeven <geert+renesas@glider.be>
commit d63c16f8e1ab761775275adcf54f4bef7c330295 upstream.
Printk format "%pCr" will be removed soon, as clk_get_rate() must not be
called in atomic context.
Replace it by open-coding the operation. This is safe here, as the code
runs in task context.
Link: http://lkml.kernel.org/r/1527845302-12159-4-git-send-email-geert+renesas at glider.be
To: Jia-Ju Bai <baijiaju1990@gmail.com>
To: Jonathan Corbet <corbet@lwn.net>
To: Michael Turquette <mturquette@baylibre.com>
To: Stephen Boyd <sboyd@kernel.org>
To: Zhang Rui <rui.zhang@intel.com>
To: Eduardo Valentin <edubezval@gmail.com>
To: Eric Anholt <eric@anholt.net>
To: Stefan Wahren <stefan.wahren@i2se.com>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
Cc: Petr Mladek <pmladek@suse.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: linux-doc at vger.kernel.org
Cc: linux-clk at vger.kernel.org
Cc: linux-pm at vger.kernel.org
Cc: linux-serial at vger.kernel.org
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-renesas-soc at vger.kernel.org
Cc: linux-kernel at vger.kernel.org
Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Cc: stable at vger.kernel.org # 4.5+
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/tty/serial/sh-sci.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -2704,8 +2704,8 @@ found:
dev_dbg(dev, "failed to get %s (%ld)\n", clk_names[i],
PTR_ERR(clk));
else
- dev_dbg(dev, "clk %s is %pC rate %pCr\n", clk_names[i],
- clk, clk);
+ dev_dbg(dev, "clk %s is %pC rate %lu\n", clk_names[i],
+ clk, clk_get_rate(clk));
sci_port->clks[i] = IS_ERR(clk) ? NULL : clk;
}
return 0;
^ permalink raw reply
* [PATCH v4 7/7] tty: serial: imx: split all dma setup operations out of 'port.lock' protector
From: Robin Gong @ 2018-06-14 14:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528984982-5074-1-git-send-email-yibin.gong@nxp.com>
After sdma driver change to virt-dma, all bds will be allocated
dynamically with 'port.lock' acquired instead of statically allocated
before. That means the lock sequence is 'port.lock' -> 'fs_reclaim_acquire'
.But in case uart rx/tx dma callback coming after other kernel code which
have already acquired 'fs_reclaim_acquire' lock, which means the above lock
sequence reverted as 'fs_reclaim_acquire' -> 'port.lock'(acquired in uart
dma callback), thus, lockdep warning comes as beow. Actually don't need to
spinlock all DMA operations in UART driver with 'port.lock', because dma
driver can wipe off race condition by commone virt-dma lock . Split all dma
operations out of the code areas which protected by 'port.lock'.
[ 46.155406] =====================================================
[ 46.161503] WARNING: HARDIRQ-safe -> HARDIRQ-unsafe lock order detected
[ 46.168122] 4.17.0-rc6-00008-g7caafa3-dirty #48 Not tainted
[ 46.173696] -----------------------------------------------------
[ 46.179795] mxc_uart_stress/419 [HC0[0]:SC0[0]:HE0:SE1] is trying to acquire:
[ 46.186934] fa7c1440 (fs_reclaim){+.+.}, at: fs_reclaim_acquire.part.3+0x0/0x48
[ 46.194270]
[ 46.194270] and this task is already holding:
[ 46.200106] 09a17fda (&port_lock_key){-.-.}, at: uart_write+0x84/0x190
[ 46.206658] which would create a new lock dependency:
[ 46.211710] (&port_lock_key){-.-.} -> (fs_reclaim){+.+.}
[ 46.217132]
[ 46.217132] but this new dependency connects a HARDIRQ-irq-safe lock:
[ 46.225051] (&port_lock_key){-.-.}
[ 46.225062]
[ 46.225062] ... which became HARDIRQ-irq-safe at:
[ 46.234740] lock_acquire+0x70/0x90
[ 46.238326] _raw_spin_lock_irqsave+0x40/0x54
[ 46.242777] imx_uart_console_write+0x1bc/0x1e0
[ 46.247402] console_unlock+0x320/0x5f0
[ 46.251329] vprintk_emit+0x22c/0x3fc
[ 46.255082] vprintk_default+0x28/0x30
[ 46.258923] vprintk_func+0x78/0xcc
[ 46.262503] printk+0x34/0x54
[ 46.265566] crng_fast_load+0xf8/0x138
[ 46.269407] add_interrupt_randomness+0x21c/0x24c
[ 46.274204] handle_irq_event_percpu+0x40/0x84
[ 46.278739] handle_irq_event+0x40/0x64
[ 46.282667] handle_fasteoi_irq+0xbc/0x178
[ 46.286854] generic_handle_irq+0x28/0x3c
[ 46.290954] __handle_domain_irq+0x6c/0xe8
[ 46.295148] gic_handle_irq+0x64/0xc4
[ 46.298904] __irq_svc+0x70/0x98
[ 46.302225] _raw_spin_unlock_irq+0x30/0x34
[ 46.306505] finish_task_switch+0xc0/0x27c
[ 46.310693] __schedule+0x2c0/0x79c
[ 46.314272] schedule_idle+0x40/0x84
[ 46.317941] do_idle+0x178/0x2b4
[ 46.321259] cpu_startup_entry+0x20/0x24
[ 46.325278] rest_init+0x214/0x264
[ 46.328775] start_kernel+0x39c/0x424
[ 46.332527] (null)
[ 46.334891]
[ 46.334891] to a HARDIRQ-irq-unsafe lock:
[ 46.340379] (fs_reclaim){+.+.}
[ 46.340391]
[ 46.340391] ... which became HARDIRQ-irq-unsafe at:
[ 46.349885] ...
[ 46.349895] lock_acquire+0x70/0x90
[ 46.355225] fs_reclaim_acquire.part.3+0x38/0x48
[ 46.359933] fs_reclaim_acquire+0x1c/0x20
[ 46.364036] kmem_cache_alloc+0x2c/0x174
[ 46.368051] alloc_worker.constprop.10+0x1c/0x58
[ 46.372759] init_rescuer.part.4+0x18/0xa4
[ 46.376952] workqueue_init+0xc0/0x210
[ 46.380793] kernel_init_freeable+0x58/0x1d8
[ 46.385156] kernel_init+0x10/0x11c
[ 46.388736] ret_from_fork+0x14/0x20
[ 46.392399] (null)
[ 46.394762]
[ 46.394762] other info that might help us debug this:
[ 46.394762]
[ 46.402769] Possible interrupt unsafe locking scenario:
[ 46.402769]
[ 46.409560] CPU0 CPU1
[ 46.414092] ---- ----
[ 46.418622] lock(fs_reclaim);
[ 46.421772] local_irq_disable();
[ 46.427693] lock(&port_lock_key);
[ 46.433707] lock(fs_reclaim);
[ 46.439372] <Interrupt>
[ 46.441993] lock(&port_lock_key);
[ 46.445661]
[ 46.445661] *** DEADLOCK ***
[ 46.445661]
Signed-off-by: Robin Gong <yibin.gong@nxp.com>
---
drivers/tty/serial/imx.c | 97 ++++++++++++++++++++++++++----------------------
1 file changed, 53 insertions(+), 44 deletions(-)
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index b83bc2c..f2a2966 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -223,6 +223,7 @@ struct imx_port {
dma_cookie_t rx_cookie;
unsigned int tx_bytes;
unsigned int dma_tx_nents;
+ struct work_struct tsk_dma_tx;
unsigned int saved_reg[10];
bool context_saved;
};
@@ -491,8 +492,6 @@ static void imx_uart_enable_ms(struct uart_port *port)
mctrl_gpio_enable_ms(sport->gpios);
}
-static void imx_uart_dma_tx(struct imx_port *sport);
-
/* called with port.lock taken and irqs off */
static inline void imx_uart_transmit_buffer(struct imx_port *sport)
{
@@ -524,7 +523,7 @@ static inline void imx_uart_transmit_buffer(struct imx_port *sport)
imx_uart_writel(sport, ucr1, UCR1);
} else {
imx_uart_writel(sport, ucr1, UCR1);
- imx_uart_dma_tx(sport);
+ schedule_work(&sport->tsk_dma_tx);
}
return;
@@ -574,7 +573,7 @@ static void imx_uart_dma_tx_callback(void *data)
uart_write_wakeup(&sport->port);
if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port))
- imx_uart_dma_tx(sport);
+ schedule_work(&sport->tsk_dma_tx);
else if (sport->port.rs485.flags & SER_RS485_ENABLED) {
u32 ucr4 = imx_uart_readl(sport, UCR4);
ucr4 |= UCR4_TCEN;
@@ -584,19 +583,21 @@ static void imx_uart_dma_tx_callback(void *data)
spin_unlock_irqrestore(&sport->port.lock, flags);
}
-/* called with port.lock taken and irqs off */
-static void imx_uart_dma_tx(struct imx_port *sport)
+static void dma_tx_work(struct work_struct *w)
{
+ struct imx_port *sport = container_of(w, struct imx_port, tsk_dma_tx);
struct circ_buf *xmit = &sport->port.state->xmit;
struct scatterlist *sgl = sport->tx_sgl;
struct dma_async_tx_descriptor *desc;
struct dma_chan *chan = sport->dma_chan_tx;
struct device *dev = sport->port.dev;
+ unsigned long flags;
u32 ucr1, ucr4;
int ret;
+ spin_lock_irqsave(&sport->port.lock, flags);
if (sport->dma_is_txing)
- return;
+ goto work_out;
ucr4 = imx_uart_readl(sport, UCR4);
ucr4 &= ~UCR4_TCEN;
@@ -604,45 +605,51 @@ static void imx_uart_dma_tx(struct imx_port *sport)
sport->tx_bytes = uart_circ_chars_pending(xmit);
- if (xmit->tail < xmit->head) {
- sport->dma_tx_nents = 1;
- sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes);
- } else {
- sport->dma_tx_nents = 2;
- sg_init_table(sgl, 2);
- sg_set_buf(sgl, xmit->buf + xmit->tail,
- UART_XMIT_SIZE - xmit->tail);
- sg_set_buf(sgl + 1, xmit->buf, xmit->head);
- }
+ if (sport->tx_bytes > 0) {
+ if (xmit->tail < xmit->head) {
+ sport->dma_tx_nents = 1;
+ sg_init_one(sgl, xmit->buf + xmit->tail,
+ sport->tx_bytes);
+ } else {
+ sport->dma_tx_nents = 2;
+ sg_init_table(sgl, 2);
+ sg_set_buf(sgl, xmit->buf + xmit->tail,
+ UART_XMIT_SIZE - xmit->tail);
+ sg_set_buf(sgl + 1, xmit->buf, xmit->head);
+ }
+ spin_unlock_irqrestore(&sport->port.lock, flags);
- ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
- if (ret == 0) {
- dev_err(dev, "DMA mapping error for TX.\n");
- return;
- }
- desc = dmaengine_prep_slave_sg(chan, sgl, sport->dma_tx_nents,
+ ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
+ if (ret == 0) {
+ dev_err(dev, "DMA mapping error for TX.\n");
+ return;
+ }
+ desc = dmaengine_prep_slave_sg(chan, sgl, sport->dma_tx_nents,
DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
- if (!desc) {
- dma_unmap_sg(dev, sgl, sport->dma_tx_nents,
- DMA_TO_DEVICE);
- dev_err(dev, "We cannot prepare for the TX slave dma!\n");
- return;
- }
- desc->callback = imx_uart_dma_tx_callback;
- desc->callback_param = sport;
+ if (!desc) {
+ dma_unmap_sg(dev, sgl, sport->dma_tx_nents,
+ DMA_TO_DEVICE);
+ dev_err(dev, "We cannot prepare for the TX slave dma!\n");
+ return;
+ }
+ desc->callback = imx_uart_dma_tx_callback;
+ desc->callback_param = sport;
- dev_dbg(dev, "TX: prepare to send %lu bytes by DMA.\n",
- uart_circ_chars_pending(xmit));
+ dev_dbg(dev, "TX: prepare to send %lu bytes by DMA.\n",
+ uart_circ_chars_pending(xmit));
- ucr1 = imx_uart_readl(sport, UCR1);
- ucr1 |= UCR1_TXDMAEN;
- imx_uart_writel(sport, ucr1, UCR1);
+ ucr1 = imx_uart_readl(sport, UCR1);
+ ucr1 |= UCR1_TXDMAEN;
+ imx_uart_writel(sport, ucr1, UCR1);
- /* fire it */
- sport->dma_is_txing = 1;
- dmaengine_submit(desc);
- dma_async_issue_pending(chan);
- return;
+ /* fire it */
+ sport->dma_is_txing = 1;
+ dmaengine_submit(desc);
+ dma_async_issue_pending(chan);
+ return;
+ }
+work_out:
+ spin_unlock_irqrestore(&sport->port.lock, flags);
}
/* called with port.lock taken and irqs off */
@@ -696,7 +703,7 @@ static void imx_uart_start_tx(struct uart_port *port)
if (!uart_circ_empty(&port->state->xmit) &&
!uart_tx_stopped(port))
- imx_uart_dma_tx(sport);
+ schedule_work(&sport->tsk_dma_tx);
return;
}
}
@@ -1405,7 +1412,9 @@ static int imx_uart_startup(struct uart_port *port)
*/
imx_uart_enable_ms(&sport->port);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
if (dma_is_inited) {
+ INIT_WORK(&sport->tsk_dma_tx, dma_tx_work);
imx_uart_enable_dma(sport);
imx_uart_start_rx_dma(sport);
} else {
@@ -1418,8 +1427,6 @@ static int imx_uart_startup(struct uart_port *port)
imx_uart_writel(sport, ucr2, UCR2);
}
- spin_unlock_irqrestore(&sport->port.lock, flags);
-
return 0;
}
@@ -1435,6 +1442,8 @@ static void imx_uart_shutdown(struct uart_port *port)
dmaengine_terminate_sync(sport->dma_chan_tx);
dmaengine_terminate_sync(sport->dma_chan_rx);
+ cancel_work_sync(&sport->tsk_dma_tx);
+
spin_lock_irqsave(&sport->port.lock, flags);
imx_uart_stop_tx(port);
imx_uart_stop_rx(port);
--
2.7.4
^ permalink raw reply related
* [PATCH v4 6/7] dmaengine: imx-sdma: add sdma_transfer_init to decrease code overlap
From: Robin Gong @ 2018-06-14 14:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528984982-5074-1-git-send-email-yibin.gong@nxp.com>
There are lot of codes overlap between prep_sg and prep_cyclic function.
Add sdma_transfer_init() function to elimated the code overlap.
Signed-off-by: Robin Gong <yibin.gong@nxp.com>
---
drivers/dma/imx-sdma.c | 83 ++++++++++++++++++++++----------------------------
1 file changed, 37 insertions(+), 46 deletions(-)
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index f56226f..e0783a2 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -1255,6 +1255,40 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
clk_disable(sdma->clk_ahb);
}
+static struct sdma_desc *sdma_transfer_init(struct sdma_channel *sdmac,
+ enum dma_transfer_direction direction, u32 bds)
+{
+ struct sdma_desc *desc;
+
+ desc = kzalloc((sizeof(*desc)), GFP_KERNEL);
+ if (!desc)
+ goto err_out;
+
+ sdmac->status = DMA_IN_PROGRESS;
+ sdmac->direction = direction;
+ sdmac->flags = 0;
+
+ desc->chn_count = 0;
+ desc->chn_real_count = 0;
+ desc->buf_tail = 0;
+ desc->buf_ptail = 0;
+ desc->sdmac = sdmac;
+ desc->num_bd = bds;
+
+ if (sdma_alloc_bd(desc))
+ goto err_desc_out;
+
+ if (sdma_load_context(sdmac))
+ goto err_desc_out;
+
+ return desc;
+
+err_desc_out:
+ kfree(desc);
+err_out:
+ return NULL;
+}
+
static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
struct dma_chan *chan, struct scatterlist *sgl,
unsigned int sg_len, enum dma_transfer_direction direction,
@@ -1267,36 +1301,13 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
struct scatterlist *sg;
struct sdma_desc *desc;
- if (sdmac->status == DMA_IN_PROGRESS)
- return NULL;
- sdmac->status = DMA_IN_PROGRESS;
-
- sdmac->flags = 0;
-
- desc = kzalloc((sizeof(*desc)), GFP_KERNEL);
+ desc = sdma_transfer_init(sdmac, direction, sg_len);
if (!desc)
goto err_out;
- desc->buf_tail = 0;
- desc->buf_ptail = 0;
- desc->sdmac = sdmac;
- desc->num_bd = sg_len;
- desc->chn_real_count = 0;
-
- if (sdma_alloc_bd(desc)) {
- kfree(desc);
- goto err_out;
- }
-
dev_dbg(sdma->dev, "setting up %d entries for channel %d.\n",
sg_len, channel);
- sdmac->direction = direction;
- ret = sdma_load_context(sdmac);
- if (ret)
- goto err_bd_out;
-
- desc->chn_count = 0;
for_each_sg(sgl, sg, sg_len, i) {
struct sdma_buffer_descriptor *bd = &desc->bd[i];
int param;
@@ -1372,38 +1383,18 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
struct sdma_engine *sdma = sdmac->sdma;
int num_periods = buf_len / period_len;
int channel = sdmac->channel;
- int ret, i = 0, buf = 0;
+ int i = 0, buf = 0;
struct sdma_desc *desc;
dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel);
- if (sdmac->status == DMA_IN_PROGRESS)
- return NULL;
-
- sdmac->status = DMA_IN_PROGRESS;
-
- desc = kzalloc((sizeof(*desc)), GFP_KERNEL);
+ desc = sdma_transfer_init(sdmac, direction, num_periods);
if (!desc)
goto err_out;
- desc->buf_tail = 0;
- desc->buf_ptail = 0;
- desc->sdmac = sdmac;
- desc->num_bd = num_periods;
- desc->chn_real_count = 0;
desc->period_len = period_len;
sdmac->flags |= IMX_DMA_SG_LOOP;
- sdmac->direction = direction;
-
- if (sdma_alloc_bd(desc)) {
- kfree(desc);
- goto err_bd_out;
- }
-
- ret = sdma_load_context(sdmac);
- if (ret)
- goto err_bd_out;
if (period_len > 0xffff) {
dev_err(sdma->dev, "SDMA channel %d: maximum period size exceeded: %zu > %d\n",
--
2.7.4
^ permalink raw reply related
* [PATCH v4 5/7] dmaengine: imx-sdma: remove the maximum limitation for bd numbers
From: Robin Gong @ 2018-06-14 14:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528984982-5074-1-git-send-email-yibin.gong@nxp.com>
No this limitation now after virtual dma used since bd is allocated
dynamically instead of static.
Signed-off-by: Robin Gong <yibin.gong@nxp.com>
---
drivers/dma/imx-sdma.c | 14 --------------
1 file changed, 14 deletions(-)
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 27b76eb..f56226f 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -292,7 +292,6 @@ struct sdma_context_data {
u32 scratch7;
} __attribute__ ((packed));
-#define NUM_BD (int)(PAGE_SIZE / sizeof(struct sdma_buffer_descriptor))
struct sdma_engine;
@@ -1297,13 +1296,6 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
if (ret)
goto err_bd_out;
- if (sg_len > NUM_BD) {
- dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n",
- channel, sg_len, NUM_BD);
- ret = -EINVAL;
- goto err_bd_out;
- }
-
desc->chn_count = 0;
for_each_sg(sgl, sg, sg_len, i) {
struct sdma_buffer_descriptor *bd = &desc->bd[i];
@@ -1413,12 +1405,6 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
if (ret)
goto err_bd_out;
- if (num_periods > NUM_BD) {
- dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n",
- channel, num_periods, NUM_BD);
- goto err_bd_out;
- }
-
if (period_len > 0xffff) {
dev_err(sdma->dev, "SDMA channel %d: maximum period size exceeded: %zu > %d\n",
channel, period_len, 0xffff);
--
2.7.4
^ permalink raw reply related
* [PATCH v4 4/7] dmaengine: imx-sdma: remove useless 'lock' and 'enabled' in 'struct sdma_channel'
From: Robin Gong @ 2018-06-14 14:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528984982-5074-1-git-send-email-yibin.gong@nxp.com>
Since 'sdmac->vc.lock' and 'sdmac->desc' can be used as 'lock' and
'enabled' in 'struct sdma_channel sdmac', remove them.
Signed-off-by: Robin Gong <yibin.gong@nxp.com>
---
drivers/dma/imx-sdma.c | 23 -----------------------
1 file changed, 23 deletions(-)
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 719bf9f..27b76eb 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -349,10 +349,8 @@ struct sdma_channel {
unsigned long event_mask[2];
unsigned long watermark_level;
u32 shp_addr, per_addr;
- spinlock_t lock;
enum dma_status status;
struct imx_dma_data data;
- bool enabled;
};
#define IMX_DMA_SG_LOOP BIT(0)
@@ -613,14 +611,7 @@ static int sdma_config_ownership(struct sdma_channel *sdmac,
static void sdma_enable_channel(struct sdma_engine *sdma, int channel)
{
- unsigned long flags;
- struct sdma_channel *sdmac = &sdma->channel[channel];
-
writel(BIT(channel), sdma->regs + SDMA_H_START);
-
- spin_lock_irqsave(&sdmac->lock, flags);
- sdmac->enabled = true;
- spin_unlock_irqrestore(&sdmac->lock, flags);
}
/*
@@ -738,14 +729,6 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
struct sdma_buffer_descriptor *bd;
int error = 0;
enum dma_status old_status = sdmac->status;
- unsigned long flags;
-
- spin_lock_irqsave(&sdmac->lock, flags);
- if (!sdmac->enabled) {
- spin_unlock_irqrestore(&sdmac->lock, flags);
- return;
- }
- spin_unlock_irqrestore(&sdmac->lock, flags);
/*
* loop mode. Iterate over descriptors, re-setup them and
@@ -1007,15 +990,10 @@ static int sdma_disable_channel(struct dma_chan *chan)
struct sdma_channel *sdmac = to_sdma_chan(chan);
struct sdma_engine *sdma = sdmac->sdma;
int channel = sdmac->channel;
- unsigned long flags;
writel_relaxed(BIT(channel), sdma->regs + SDMA_H_STATSTOP);
sdmac->status = DMA_ERROR;
- spin_lock_irqsave(&sdmac->lock, flags);
- sdmac->enabled = false;
- spin_unlock_irqrestore(&sdmac->lock, flags);
-
return 0;
}
@@ -1929,7 +1907,6 @@ static int sdma_probe(struct platform_device *pdev)
struct sdma_channel *sdmac = &sdma->channel[i];
sdmac->sdma = sdma;
- spin_lock_init(&sdmac->lock);
sdmac->channel = i;
sdmac->vc.desc_free = sdma_desc_free;
--
2.7.4
^ permalink raw reply related
* [PATCH v4 3/7] dmaengine: imx-sdma: add virt-dma support
From: Robin Gong @ 2018-06-14 14:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528984982-5074-1-git-send-email-yibin.gong@nxp.com>
The legacy sdma driver has below limitations or drawbacks:
1. Hardcode the max BDs number as "PAGE_SIZE / sizeof(*)", and alloc
one page size for one channel regardless of only few BDs needed
most time. But in few cases, the max PAGE_SIZE maybe not enough.
2. One SDMA channel can't stop immediatley once channel disabled which
means SDMA interrupt may come in after this channel terminated.There
are some patches for this corner case such as commit "2746e2c389f9",
but not cover non-cyclic.
The common virt-dma overcomes the above limitations. It can alloc bd
dynamically and free bd once this tx transfer done. No memory wasted or
maximum limititation here, only depends on how many memory can be requested
from kernel. For No.2, such issue can be workaround by checking if there
is available descript("sdmac->desc") now once the unwanted interrupt
coming. At last the common virt-dma is easier for sdma driver maintain.
Signed-off-by: Robin Gong <yibin.gong@nxp.com>
---
drivers/dma/Kconfig | 1 +
drivers/dma/imx-sdma.c | 261 ++++++++++++++++++++++++++++++++-----------------
2 files changed, 170 insertions(+), 92 deletions(-)
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 6d61cd0..78715a2 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -257,6 +257,7 @@ config IMX_SDMA
tristate "i.MX SDMA support"
depends on ARCH_MXC
select DMA_ENGINE
+ select DMA_VIRTUAL_CHANNELS
help
Support the i.MX SDMA engine. This engine is integrated into
Freescale i.MX25/31/35/51/53/6 chips.
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 556d087..719bf9f 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -48,6 +48,7 @@
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include "dmaengine.h"
+#include "virt-dma.h"
/* SDMA registers */
#define SDMA_H_C0PTR 0x000
@@ -308,6 +309,7 @@ struct sdma_engine;
* @bd pointer of alloced bd
*/
struct sdma_desc {
+ struct virt_dma_desc vd;
unsigned int num_bd;
dma_addr_t bd_phys;
unsigned int buf_tail;
@@ -331,8 +333,8 @@ struct sdma_desc {
* @word_size peripheral access size
*/
struct sdma_channel {
+ struct virt_dma_chan vc;
struct sdma_desc *desc;
- struct sdma_desc _desc;
struct sdma_engine *sdma;
unsigned int channel;
enum dma_transfer_direction direction;
@@ -347,11 +349,8 @@ struct sdma_channel {
unsigned long event_mask[2];
unsigned long watermark_level;
u32 shp_addr, per_addr;
- struct dma_chan chan;
spinlock_t lock;
- struct dma_async_tx_descriptor txdesc;
enum dma_status status;
- struct tasklet_struct tasklet;
struct imx_dma_data data;
bool enabled;
};
@@ -705,6 +704,35 @@ static void sdma_event_disable(struct sdma_channel *sdmac, unsigned int event)
writel_relaxed(val, sdma->regs + chnenbl);
}
+static struct sdma_desc *to_sdma_desc(struct dma_async_tx_descriptor *t)
+{
+ return container_of(t, struct sdma_desc, vd.tx);
+}
+
+static void sdma_start_desc(struct sdma_channel *sdmac)
+{
+ struct virt_dma_desc *vd = vchan_next_desc(&sdmac->vc);
+ struct sdma_desc *desc;
+ struct sdma_engine *sdma = sdmac->sdma;
+ int channel = sdmac->channel;
+
+ if (!vd) {
+ sdmac->desc = NULL;
+ return;
+ }
+ sdmac->desc = desc = to_sdma_desc(&vd->tx);
+ /*
+ * Do not delete the node in desc_issued list in cyclic mode, otherwise
+ * the desc alloced will never be freed in vchan_dma_desc_free_list
+ */
+ if (!(sdmac->flags & IMX_DMA_SG_LOOP))
+ list_del(&vd->node);
+
+ sdma->channel_control[channel].base_bd_ptr = desc->bd_phys;
+ sdma->channel_control[channel].current_bd_ptr = desc->bd_phys;
+ sdma_enable_channel(sdma, sdmac->channel);
+}
+
static void sdma_update_channel_loop(struct sdma_channel *sdmac)
{
struct sdma_buffer_descriptor *bd;
@@ -723,7 +751,7 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
* loop mode. Iterate over descriptors, re-setup them and
* call callback function.
*/
- while (1) {
+ while (sdmac->desc) {
struct sdma_desc *desc = sdmac->desc;
bd = &desc->bd[desc->buf_tail];
@@ -754,15 +782,16 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
* SDMA transaction status by the time the client tasklet is
* executed.
*/
-
- dmaengine_desc_get_callback_invoke(&sdmac->txdesc, NULL);
+ spin_unlock(&sdmac->vc.lock);
+ dmaengine_desc_get_callback_invoke(&desc->vd.tx, NULL);
+ spin_lock(&sdmac->vc.lock);
if (error)
sdmac->status = old_status;
}
}
-static void mxc_sdma_handle_channel_normal(unsigned long data)
+static void mxc_sdma_handle_channel_normal(struct sdma_channel *data)
{
struct sdma_channel *sdmac = (struct sdma_channel *) data;
struct sdma_buffer_descriptor *bd;
@@ -785,10 +814,6 @@ static void mxc_sdma_handle_channel_normal(unsigned long data)
sdmac->status = DMA_ERROR;
else
sdmac->status = DMA_COMPLETE;
-
- dma_cookie_complete(&sdmac->txdesc);
-
- dmaengine_desc_get_callback_invoke(&sdmac->txdesc, NULL);
}
static irqreturn_t sdma_int_handler(int irq, void *dev_id)
@@ -804,12 +829,21 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id)
while (stat) {
int channel = fls(stat) - 1;
struct sdma_channel *sdmac = &sdma->channel[channel];
+ struct sdma_desc *desc;
+
+ spin_lock(&sdmac->vc.lock);
+ desc = sdmac->desc;
+ if (desc) {
+ if (sdmac->flags & IMX_DMA_SG_LOOP) {
+ sdma_update_channel_loop(sdmac);
+ } else {
+ mxc_sdma_handle_channel_normal(sdmac);
+ vchan_cookie_complete(&desc->vd);
+ sdma_start_desc(sdmac);
+ }
+ }
- if (sdmac->flags & IMX_DMA_SG_LOOP)
- sdma_update_channel_loop(sdmac);
- else
- tasklet_schedule(&sdmac->tasklet);
-
+ spin_unlock(&sdmac->vc.lock);
__clear_bit(channel, &stat);
}
@@ -965,7 +999,7 @@ static int sdma_load_context(struct sdma_channel *sdmac)
static struct sdma_channel *to_sdma_chan(struct dma_chan *chan)
{
- return container_of(chan, struct sdma_channel, chan);
+ return container_of(chan, struct sdma_channel, vc.chan);
}
static int sdma_disable_channel(struct dma_chan *chan)
@@ -987,7 +1021,16 @@ static int sdma_disable_channel(struct dma_chan *chan)
static int sdma_disable_channel_with_delay(struct dma_chan *chan)
{
+ struct sdma_channel *sdmac = to_sdma_chan(chan);
+ unsigned long flags;
+ LIST_HEAD(head);
+
sdma_disable_channel(chan);
+ spin_lock_irqsave(&sdmac->vc.lock, flags);
+ vchan_get_all_descriptors(&sdmac->vc, &head);
+ sdmac->desc = NULL;
+ spin_unlock_irqrestore(&sdmac->vc.lock, flags);
+ vchan_dma_desc_free_list(&sdmac->vc, &head);
/*
* According to NXP R&D team a delay of one BD SDMA cost time
@@ -1116,46 +1159,56 @@ static int sdma_set_channel_priority(struct sdma_channel *sdmac,
return 0;
}
-static int sdma_request_channel(struct sdma_channel *sdmac)
+static int sdma_request_channel0(struct sdma_engine *sdma)
{
- struct sdma_engine *sdma = sdmac->sdma;
- struct sdma_desc *desc;
- int channel = sdmac->channel;
int ret = -EBUSY;
- sdmac->desc = &sdmac->_desc;
- desc = sdmac->desc;
-
- desc->bd = dma_zalloc_coherent(NULL, PAGE_SIZE, &desc->bd_phys,
+ sdma->bd0 = dma_zalloc_coherent(NULL, PAGE_SIZE, &sdma->bd0_phys,
GFP_KERNEL);
- if (!desc->bd) {
+ if (!sdma->bd0) {
ret = -ENOMEM;
goto out;
}
- sdma->channel_control[channel].base_bd_ptr = desc->bd_phys;
- sdma->channel_control[channel].current_bd_ptr = desc->bd_phys;
+ sdma->channel_control[0].base_bd_ptr = sdma->bd0_phys;
+ sdma->channel_control[0].current_bd_ptr = sdma->bd0_phys;
- sdma_set_channel_priority(sdmac, MXC_SDMA_DEFAULT_PRIORITY);
+ sdma_set_channel_priority(&sdma->channel[0], MXC_SDMA_DEFAULT_PRIORITY);
return 0;
out:
return ret;
}
-static dma_cookie_t sdma_tx_submit(struct dma_async_tx_descriptor *tx)
+
+static int sdma_alloc_bd(struct sdma_desc *desc)
{
- unsigned long flags;
- struct sdma_channel *sdmac = to_sdma_chan(tx->chan);
- dma_cookie_t cookie;
+ u32 bd_size = desc->num_bd * sizeof(struct sdma_buffer_descriptor);
+ int ret = 0;
- spin_lock_irqsave(&sdmac->lock, flags);
+ desc->bd = dma_zalloc_coherent(NULL, bd_size, &desc->bd_phys,
+ GFP_ATOMIC);
+ if (!desc->bd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+out:
+ return ret;
+}
- cookie = dma_cookie_assign(tx);
+static void sdma_free_bd(struct sdma_desc *desc)
+{
+ u32 bd_size = desc->num_bd * sizeof(struct sdma_buffer_descriptor);
- spin_unlock_irqrestore(&sdmac->lock, flags);
+ dma_free_coherent(NULL, bd_size, desc->bd, desc->bd_phys);
+}
- return cookie;
+static void sdma_desc_free(struct virt_dma_desc *vd)
+{
+ struct sdma_desc *desc = container_of(vd, struct sdma_desc, vd);
+
+ sdma_free_bd(desc);
+ kfree(desc);
}
static int sdma_alloc_chan_resources(struct dma_chan *chan)
@@ -1191,19 +1244,10 @@ static int sdma_alloc_chan_resources(struct dma_chan *chan)
if (ret)
goto disable_clk_ipg;
- ret = sdma_request_channel(sdmac);
- if (ret)
- goto disable_clk_ahb;
-
ret = sdma_set_channel_priority(sdmac, prio);
if (ret)
goto disable_clk_ahb;
- dma_async_tx_descriptor_init(&sdmac->txdesc, chan);
- sdmac->txdesc.tx_submit = sdma_tx_submit;
- /* txd.flags will be overwritten in prep funcs */
- sdmac->txdesc.flags = DMA_CTRL_ACK;
-
return 0;
disable_clk_ahb:
@@ -1217,9 +1261,8 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
{
struct sdma_channel *sdmac = to_sdma_chan(chan);
struct sdma_engine *sdma = sdmac->sdma;
- struct sdma_desc *desc = sdmac->desc;
- sdma_disable_channel(chan);
+ sdma_disable_channel_with_delay(chan);
if (sdmac->event_id0)
sdma_event_disable(sdmac, sdmac->event_id0);
@@ -1231,8 +1274,6 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
sdma_set_channel_priority(sdmac, 0);
- dma_free_coherent(NULL, PAGE_SIZE, desc->bd, desc->bd_phys);
-
clk_disable(sdma->clk_ipg);
clk_disable(sdma->clk_ahb);
}
@@ -1247,7 +1288,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
int ret, i, count;
int channel = sdmac->channel;
struct scatterlist *sg;
- struct sdma_desc *desc = sdmac->desc;
+ struct sdma_desc *desc;
if (sdmac->status == DMA_IN_PROGRESS)
return NULL;
@@ -1255,23 +1296,34 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
sdmac->flags = 0;
+ desc = kzalloc((sizeof(*desc)), GFP_KERNEL);
+ if (!desc)
+ goto err_out;
+
desc->buf_tail = 0;
desc->buf_ptail = 0;
+ desc->sdmac = sdmac;
+ desc->num_bd = sg_len;
desc->chn_real_count = 0;
+ if (sdma_alloc_bd(desc)) {
+ kfree(desc);
+ goto err_out;
+ }
+
dev_dbg(sdma->dev, "setting up %d entries for channel %d.\n",
sg_len, channel);
sdmac->direction = direction;
ret = sdma_load_context(sdmac);
if (ret)
- goto err_out;
+ goto err_bd_out;
if (sg_len > NUM_BD) {
dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n",
channel, sg_len, NUM_BD);
ret = -EINVAL;
- goto err_out;
+ goto err_bd_out;
}
desc->chn_count = 0;
@@ -1287,7 +1339,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
dev_err(sdma->dev, "SDMA channel %d: maximum bytes for sg entry exceeded: %d > %d\n",
channel, count, 0xffff);
ret = -EINVAL;
- goto err_out;
+ goto err_bd_out;
}
bd->mode.count = count;
@@ -1295,25 +1347,25 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES) {
ret = -EINVAL;
- goto err_out;
+ goto err_bd_out;
}
switch (sdmac->word_size) {
case DMA_SLAVE_BUSWIDTH_4_BYTES:
bd->mode.command = 0;
if (count & 3 || sg->dma_address & 3)
- return NULL;
+ goto err_bd_out;
break;
case DMA_SLAVE_BUSWIDTH_2_BYTES:
bd->mode.command = 2;
if (count & 1 || sg->dma_address & 1)
- return NULL;
+ goto err_bd_out;
break;
case DMA_SLAVE_BUSWIDTH_1_BYTE:
bd->mode.command = 1;
break;
default:
- return NULL;
+ goto err_bd_out;
}
param = BD_DONE | BD_EXTD | BD_CONT;
@@ -1332,10 +1384,10 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
bd->mode.status = param;
}
- desc->num_bd = sg_len;
- sdma->channel_control[channel].current_bd_ptr = desc->bd_phys;
-
- return &sdmac->txdesc;
+ return vchan_tx_prep(&sdmac->vc, &desc->vd, flags);
+err_bd_out:
+ sdma_free_bd(desc);
+ kfree(desc);
err_out:
sdmac->status = DMA_ERROR;
return NULL;
@@ -1351,7 +1403,7 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
int num_periods = buf_len / period_len;
int channel = sdmac->channel;
int ret, i = 0, buf = 0;
- struct sdma_desc *desc = sdmac->desc;
+ struct sdma_desc *desc;
dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel);
@@ -1360,27 +1412,39 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
sdmac->status = DMA_IN_PROGRESS;
+ desc = kzalloc((sizeof(*desc)), GFP_KERNEL);
+ if (!desc)
+ goto err_out;
+
desc->buf_tail = 0;
desc->buf_ptail = 0;
+ desc->sdmac = sdmac;
+ desc->num_bd = num_periods;
desc->chn_real_count = 0;
desc->period_len = period_len;
sdmac->flags |= IMX_DMA_SG_LOOP;
sdmac->direction = direction;
+
+ if (sdma_alloc_bd(desc)) {
+ kfree(desc);
+ goto err_bd_out;
+ }
+
ret = sdma_load_context(sdmac);
if (ret)
- goto err_out;
+ goto err_bd_out;
if (num_periods > NUM_BD) {
dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n",
channel, num_periods, NUM_BD);
- goto err_out;
+ goto err_bd_out;
}
if (period_len > 0xffff) {
dev_err(sdma->dev, "SDMA channel %d: maximum period size exceeded: %zu > %d\n",
channel, period_len, 0xffff);
- goto err_out;
+ goto err_bd_out;
}
while (buf < buf_len) {
@@ -1392,7 +1456,7 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
bd->mode.count = period_len;
if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES)
- goto err_out;
+ goto err_bd_out;
if (sdmac->word_size == DMA_SLAVE_BUSWIDTH_4_BYTES)
bd->mode.command = 0;
else
@@ -1415,10 +1479,10 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
i++;
}
- desc->num_bd = num_periods;
- sdma->channel_control[channel].current_bd_ptr = desc->bd_phys;
-
- return &sdmac->txdesc;
+ return vchan_tx_prep(&sdmac->vc, &desc->vd, flags);
+err_bd_out:
+ sdma_free_bd(desc);
+ kfree(desc);
err_out:
sdmac->status = DMA_ERROR;
return NULL;
@@ -1457,14 +1521,31 @@ static enum dma_status sdma_tx_status(struct dma_chan *chan,
struct dma_tx_state *txstate)
{
struct sdma_channel *sdmac = to_sdma_chan(chan);
- struct sdma_desc *desc = sdmac->desc;
+ struct sdma_desc *desc;
u32 residue;
+ struct virt_dma_desc *vd;
+ enum dma_status ret;
+ unsigned long flags;
- if (sdmac->flags & IMX_DMA_SG_LOOP)
- residue = (desc->num_bd - desc->buf_ptail) *
- desc->period_len - desc->chn_real_count;
- else
- residue = desc->chn_count - desc->chn_real_count;
+ ret = dma_cookie_status(chan, cookie, txstate);
+ if (ret == DMA_COMPLETE || !txstate)
+ return ret;
+
+ spin_lock_irqsave(&sdmac->vc.lock, flags);
+ vd = vchan_find_desc(&sdmac->vc, cookie);
+ if (vd) {
+ desc = to_sdma_desc(&vd->tx);
+ if (sdmac->flags & IMX_DMA_SG_LOOP)
+ residue = (desc->num_bd - desc->buf_ptail) *
+ desc->period_len - desc->chn_real_count;
+ else
+ residue = desc->chn_count - desc->chn_real_count;
+ } else if (sdmac->desc && sdmac->desc->vd.tx.cookie == cookie) {
+ residue = sdmac->desc->chn_count - sdmac->desc->chn_real_count;
+ } else {
+ residue = 0;
+ }
+ spin_unlock_irqrestore(&sdmac->vc.lock, flags);
dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie,
residue);
@@ -1475,10 +1556,12 @@ static enum dma_status sdma_tx_status(struct dma_chan *chan,
static void sdma_issue_pending(struct dma_chan *chan)
{
struct sdma_channel *sdmac = to_sdma_chan(chan);
- struct sdma_engine *sdma = sdmac->sdma;
+ unsigned long flags;
- if (sdmac->status == DMA_IN_PROGRESS)
- sdma_enable_channel(sdma, sdmac->channel);
+ spin_lock_irqsave(&sdmac->vc.lock, flags);
+ if (vchan_issue_pending(&sdmac->vc) && !sdmac->desc)
+ sdma_start_desc(sdmac);
+ spin_unlock_irqrestore(&sdmac->vc.lock, flags);
}
#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 34
@@ -1684,12 +1767,10 @@ static int sdma_init(struct sdma_engine *sdma)
for (i = 0; i < MAX_DMA_CHANNELS; i++)
writel_relaxed(0, sdma->regs + SDMA_CHNPRI_0 + i * 4);
- ret = sdma_request_channel(&sdma->channel[0]);
+ ret = sdma_request_channel0(sdma);
if (ret)
goto err_dma_alloc;
- sdma->bd0 = sdma->channel[0].desc->bd;
-
sdma_config_ownership(&sdma->channel[0], false, true, false);
/* Set Command Channel (Channel Zero) */
@@ -1850,20 +1931,15 @@ static int sdma_probe(struct platform_device *pdev)
sdmac->sdma = sdma;
spin_lock_init(&sdmac->lock);
- sdmac->chan.device = &sdma->dma_device;
- dma_cookie_init(&sdmac->chan);
sdmac->channel = i;
-
- tasklet_init(&sdmac->tasklet, mxc_sdma_handle_channel_normal,
- (unsigned long) sdmac);
+ sdmac->vc.desc_free = sdma_desc_free;
/*
* Add the channel to the DMAC list. Do not add channel 0 though
* because we need it internally in the SDMA driver. This also means
* that channel 0 in dmaengine counting matches sdma channel 1.
*/
if (i)
- list_add_tail(&sdmac->chan.device_node,
- &sdma->dma_device.channels);
+ vchan_init(&sdmac->vc, &sdma->dma_device);
}
ret = sdma_init(sdma);
@@ -1968,7 +2044,8 @@ static int sdma_remove(struct platform_device *pdev)
for (i = 0; i < MAX_DMA_CHANNELS; i++) {
struct sdma_channel *sdmac = &sdma->channel[i];
- tasklet_kill(&sdmac->tasklet);
+ tasklet_kill(&sdmac->vc.task);
+ sdma_free_chan_resources(&sdmac->vc.chan);
}
platform_set_drvdata(pdev, NULL);
--
2.7.4
^ permalink raw reply related
* [PATCH v4 2/7] dmaengine: imx-sdma: factor out a struct sdma_desc from struct sdma_channel
From: Robin Gong @ 2018-06-14 14:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528984982-5074-1-git-send-email-yibin.gong@nxp.com>
From: Sascha Hauer <s.hauer@pengutronix.de>
This is a preparation step to make the adding of virt-dma easier.
We create a struct sdma_desc, move some fields from struct sdma_channel
there and add a pointer from the former to the latter. For now we
allocate the data statically in struct sdma_channel, but with
virt-dma support it will be dynamically allocated.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Robin Gong <yibin.gong@nxp.com>
---
drivers/dma/imx-sdma.c | 137 ++++++++++++++++++++++++++++++-------------------
1 file changed, 83 insertions(+), 54 deletions(-)
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index ccd03c3..556d087 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -296,6 +296,30 @@ struct sdma_context_data {
struct sdma_engine;
/**
+ * struct sdma_desc - descriptor structor for one transfer
+ * @vd descriptor for virt dma
+ * @num_bd max NUM_BD. number of descriptors currently handling
+ * @buf_tail ID of the buffer that was processed
+ * @buf_ptail ID of the previous buffer that was processed
+ * @period_len period length, used in cyclic.
+ * @chn_real_count the real count updated from bd->mode.count
+ * @chn_count the transfer count setuped
+ * @sdmac sdma_channel pointer
+ * @bd pointer of alloced bd
+ */
+struct sdma_desc {
+ unsigned int num_bd;
+ dma_addr_t bd_phys;
+ unsigned int buf_tail;
+ unsigned int buf_ptail;
+ unsigned int period_len;
+ unsigned int chn_real_count;
+ unsigned int chn_count;
+ struct sdma_channel *sdmac;
+ struct sdma_buffer_descriptor *bd;
+};
+
+/**
* struct sdma_channel - housekeeping for a SDMA channel
*
* @sdma pointer to the SDMA engine for this channel
@@ -305,11 +329,10 @@ struct sdma_engine;
* @event_id0 aka dma request line
* @event_id1 for channels that use 2 events
* @word_size peripheral access size
- * @buf_tail ID of the buffer that was processed
- * @buf_ptail ID of the previous buffer that was processed
- * @num_bd max NUM_BD. number of descriptors currently handling
*/
struct sdma_channel {
+ struct sdma_desc *desc;
+ struct sdma_desc _desc;
struct sdma_engine *sdma;
unsigned int channel;
enum dma_transfer_direction direction;
@@ -317,12 +340,6 @@ struct sdma_channel {
unsigned int event_id0;
unsigned int event_id1;
enum dma_slave_buswidth word_size;
- unsigned int buf_tail;
- unsigned int buf_ptail;
- unsigned int num_bd;
- unsigned int period_len;
- struct sdma_buffer_descriptor *bd;
- dma_addr_t bd_phys;
unsigned int pc_from_device, pc_to_device;
unsigned int device_to_device;
unsigned long flags;
@@ -332,10 +349,8 @@ struct sdma_channel {
u32 shp_addr, per_addr;
struct dma_chan chan;
spinlock_t lock;
- struct dma_async_tx_descriptor desc;
+ struct dma_async_tx_descriptor txdesc;
enum dma_status status;
- unsigned int chn_count;
- unsigned int chn_real_count;
struct tasklet_struct tasklet;
struct imx_dma_data data;
bool enabled;
@@ -398,6 +413,8 @@ struct sdma_engine {
u32 spba_start_addr;
u32 spba_end_addr;
unsigned int irq;
+ dma_addr_t bd0_phys;
+ struct sdma_buffer_descriptor *bd0;
};
static struct sdma_driver_data sdma_imx31 = {
@@ -632,7 +649,7 @@ static int sdma_run_channel0(struct sdma_engine *sdma)
static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size,
u32 address)
{
- struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
+ struct sdma_buffer_descriptor *bd0 = sdma->bd0;
void *buf_virt;
dma_addr_t buf_phys;
int ret;
@@ -707,7 +724,9 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
* call callback function.
*/
while (1) {
- bd = &sdmac->bd[sdmac->buf_tail];
+ struct sdma_desc *desc = sdmac->desc;
+
+ bd = &desc->bd[desc->buf_tail];
if (bd->mode.status & BD_DONE)
break;
@@ -723,11 +742,11 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
* the number of bytes present in the current buffer descriptor.
*/
- sdmac->chn_real_count = bd->mode.count;
+ desc->chn_real_count = bd->mode.count;
bd->mode.status |= BD_DONE;
- bd->mode.count = sdmac->period_len;
- sdmac->buf_ptail = sdmac->buf_tail;
- sdmac->buf_tail = (sdmac->buf_tail + 1) % sdmac->num_bd;
+ bd->mode.count = desc->period_len;
+ desc->buf_ptail = desc->buf_tail;
+ desc->buf_tail = (desc->buf_tail + 1) % desc->num_bd;
/*
* The callback is called from the interrupt context in order
@@ -736,7 +755,7 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
* executed.
*/
- dmaengine_desc_get_callback_invoke(&sdmac->desc, NULL);
+ dmaengine_desc_get_callback_invoke(&sdmac->txdesc, NULL);
if (error)
sdmac->status = old_status;
@@ -749,17 +768,17 @@ static void mxc_sdma_handle_channel_normal(unsigned long data)
struct sdma_buffer_descriptor *bd;
int i, error = 0;
- sdmac->chn_real_count = 0;
+ sdmac->desc->chn_real_count = 0;
/*
* non loop mode. Iterate over all descriptors, collect
* errors and call callback function
*/
- for (i = 0; i < sdmac->num_bd; i++) {
- bd = &sdmac->bd[i];
+ for (i = 0; i < sdmac->desc->num_bd; i++) {
+ bd = &sdmac->desc->bd[i];
if (bd->mode.status & (BD_DONE | BD_RROR))
error = -EIO;
- sdmac->chn_real_count += bd->mode.count;
+ sdmac->desc->chn_real_count += bd->mode.count;
}
if (error)
@@ -767,9 +786,9 @@ static void mxc_sdma_handle_channel_normal(unsigned long data)
else
sdmac->status = DMA_COMPLETE;
- dma_cookie_complete(&sdmac->desc);
+ dma_cookie_complete(&sdmac->txdesc);
- dmaengine_desc_get_callback_invoke(&sdmac->desc, NULL);
+ dmaengine_desc_get_callback_invoke(&sdmac->txdesc, NULL);
}
static irqreturn_t sdma_int_handler(int irq, void *dev_id)
@@ -897,7 +916,7 @@ static int sdma_load_context(struct sdma_channel *sdmac)
int channel = sdmac->channel;
int load_address;
struct sdma_context_data *context = sdma->context;
- struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
+ struct sdma_buffer_descriptor *bd0 = sdma->bd0;
int ret;
unsigned long flags;
@@ -1100,18 +1119,22 @@ static int sdma_set_channel_priority(struct sdma_channel *sdmac,
static int sdma_request_channel(struct sdma_channel *sdmac)
{
struct sdma_engine *sdma = sdmac->sdma;
+ struct sdma_desc *desc;
int channel = sdmac->channel;
int ret = -EBUSY;
- sdmac->bd = dma_zalloc_coherent(NULL, PAGE_SIZE, &sdmac->bd_phys,
+ sdmac->desc = &sdmac->_desc;
+ desc = sdmac->desc;
+
+ desc->bd = dma_zalloc_coherent(NULL, PAGE_SIZE, &desc->bd_phys,
GFP_KERNEL);
- if (!sdmac->bd) {
+ if (!desc->bd) {
ret = -ENOMEM;
goto out;
}
- sdma->channel_control[channel].base_bd_ptr = sdmac->bd_phys;
- sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
+ sdma->channel_control[channel].base_bd_ptr = desc->bd_phys;
+ sdma->channel_control[channel].current_bd_ptr = desc->bd_phys;
sdma_set_channel_priority(sdmac, MXC_SDMA_DEFAULT_PRIORITY);
return 0;
@@ -1176,10 +1199,10 @@ static int sdma_alloc_chan_resources(struct dma_chan *chan)
if (ret)
goto disable_clk_ahb;
- dma_async_tx_descriptor_init(&sdmac->desc, chan);
- sdmac->desc.tx_submit = sdma_tx_submit;
+ dma_async_tx_descriptor_init(&sdmac->txdesc, chan);
+ sdmac->txdesc.tx_submit = sdma_tx_submit;
/* txd.flags will be overwritten in prep funcs */
- sdmac->desc.flags = DMA_CTRL_ACK;
+ sdmac->txdesc.flags = DMA_CTRL_ACK;
return 0;
@@ -1194,6 +1217,7 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
{
struct sdma_channel *sdmac = to_sdma_chan(chan);
struct sdma_engine *sdma = sdmac->sdma;
+ struct sdma_desc *desc = sdmac->desc;
sdma_disable_channel(chan);
@@ -1207,7 +1231,7 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
sdma_set_channel_priority(sdmac, 0);
- dma_free_coherent(NULL, PAGE_SIZE, sdmac->bd, sdmac->bd_phys);
+ dma_free_coherent(NULL, PAGE_SIZE, desc->bd, desc->bd_phys);
clk_disable(sdma->clk_ipg);
clk_disable(sdma->clk_ahb);
@@ -1223,6 +1247,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
int ret, i, count;
int channel = sdmac->channel;
struct scatterlist *sg;
+ struct sdma_desc *desc = sdmac->desc;
if (sdmac->status == DMA_IN_PROGRESS)
return NULL;
@@ -1230,9 +1255,9 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
sdmac->flags = 0;
- sdmac->buf_tail = 0;
- sdmac->buf_ptail = 0;
- sdmac->chn_real_count = 0;
+ desc->buf_tail = 0;
+ desc->buf_ptail = 0;
+ desc->chn_real_count = 0;
dev_dbg(sdma->dev, "setting up %d entries for channel %d.\n",
sg_len, channel);
@@ -1249,9 +1274,9 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
goto err_out;
}
- sdmac->chn_count = 0;
+ desc->chn_count = 0;
for_each_sg(sgl, sg, sg_len, i) {
- struct sdma_buffer_descriptor *bd = &sdmac->bd[i];
+ struct sdma_buffer_descriptor *bd = &desc->bd[i];
int param;
bd->buffer_addr = sg->dma_address;
@@ -1266,7 +1291,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
}
bd->mode.count = count;
- sdmac->chn_count += count;
+ desc->chn_count += count;
if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES) {
ret = -EINVAL;
@@ -1307,10 +1332,10 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
bd->mode.status = param;
}
- sdmac->num_bd = sg_len;
- sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
+ desc->num_bd = sg_len;
+ sdma->channel_control[channel].current_bd_ptr = desc->bd_phys;
- return &sdmac->desc;
+ return &sdmac->txdesc;
err_out:
sdmac->status = DMA_ERROR;
return NULL;
@@ -1326,6 +1351,7 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
int num_periods = buf_len / period_len;
int channel = sdmac->channel;
int ret, i = 0, buf = 0;
+ struct sdma_desc *desc = sdmac->desc;
dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel);
@@ -1334,10 +1360,10 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
sdmac->status = DMA_IN_PROGRESS;
- sdmac->buf_tail = 0;
- sdmac->buf_ptail = 0;
- sdmac->chn_real_count = 0;
- sdmac->period_len = period_len;
+ desc->buf_tail = 0;
+ desc->buf_ptail = 0;
+ desc->chn_real_count = 0;
+ desc->period_len = period_len;
sdmac->flags |= IMX_DMA_SG_LOOP;
sdmac->direction = direction;
@@ -1358,7 +1384,7 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
}
while (buf < buf_len) {
- struct sdma_buffer_descriptor *bd = &sdmac->bd[i];
+ struct sdma_buffer_descriptor *bd = &desc->bd[i];
int param;
bd->buffer_addr = dma_addr;
@@ -1389,10 +1415,10 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
i++;
}
- sdmac->num_bd = num_periods;
- sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
+ desc->num_bd = num_periods;
+ sdma->channel_control[channel].current_bd_ptr = desc->bd_phys;
- return &sdmac->desc;
+ return &sdmac->txdesc;
err_out:
sdmac->status = DMA_ERROR;
return NULL;
@@ -1431,13 +1457,14 @@ static enum dma_status sdma_tx_status(struct dma_chan *chan,
struct dma_tx_state *txstate)
{
struct sdma_channel *sdmac = to_sdma_chan(chan);
+ struct sdma_desc *desc = sdmac->desc;
u32 residue;
if (sdmac->flags & IMX_DMA_SG_LOOP)
- residue = (sdmac->num_bd - sdmac->buf_ptail) *
- sdmac->period_len - sdmac->chn_real_count;
+ residue = (desc->num_bd - desc->buf_ptail) *
+ desc->period_len - desc->chn_real_count;
else
- residue = sdmac->chn_count - sdmac->chn_real_count;
+ residue = desc->chn_count - desc->chn_real_count;
dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie,
residue);
@@ -1661,6 +1688,8 @@ static int sdma_init(struct sdma_engine *sdma)
if (ret)
goto err_dma_alloc;
+ sdma->bd0 = sdma->channel[0].desc->bd;
+
sdma_config_ownership(&sdma->channel[0], false, true, false);
/* Set Command Channel (Channel Zero) */
--
2.7.4
^ permalink raw reply related
* [PATCH v4 1/7] tty: serial: imx: correct dma cookie status
From: Robin Gong @ 2018-06-14 14:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528984982-5074-1-git-send-email-yibin.gong@nxp.com>
Correct to check the right rx dma cookie status in spit of it
works because only one cookie is running in the current sdma.
But it will not once sdma driver support multi cookies
running based on virt-dma.
Signed-off-by: Robin Gong <yibin.gong@nxp.com>
---
drivers/tty/serial/imx.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index c2fc6be..b83bc2c 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -1051,7 +1051,7 @@ static void imx_uart_dma_rx_callback(void *data)
unsigned int r_bytes;
unsigned int bd_size;
- status = dmaengine_tx_status(chan, (dma_cookie_t)0, &state);
+ status = dmaengine_tx_status(chan, sport->rx_cookie, &state);
if (status == DMA_ERROR) {
imx_uart_clear_rx_errors(sport);
--
2.7.4
^ permalink raw reply related
* [PATCH v4 0/7] add virt-dma support for imx-sdma
From: Robin Gong @ 2018-06-14 14:02 UTC (permalink / raw)
To: linux-arm-kernel
The legacy sdma driver has below limitations or drawbacks:
1. Hardcode the max BDs number as "PAGE_SIZE / sizeof(*)", and alloc
one page size for one channel regardless of only few BDs needed
most time. But in few cases, the max PAGE_SIZE maybe not enough.
2. One SDMA channel can't stop immediatley once channel disabled which
means SDMA interrupt may come in after this channel terminated.There
are some patches for this corner case such as commit "2746e2c389f9",
but not cover non-cyclic.
The common virt-dma overcomes the above limitations. It can alloc bd
dynamically and free bd once this tx transfer done. No memory wasted or
maximum limititation here, only depends on how many memory can be requested
from kernel. For No.2, such issue can be workaround by checking if there
is available descript("sdmac->desc") now once the unwanted interrupt
coming. At last the common virt-dma is easier for sdma driver maintain.
Change from v3:
1. add two uart patches which impacted by this patchset.
2. unlock 'vc.lock' before cyclic dma callback and lock again after
it because some driver such as uart will call dmaengine_tx_status
which will acquire 'vc.lock' again and dead lock comes out.
3. remove 'Revert commit' stuff since that patch is not wrong and
combine two patch into one patch as Sascha's comment.
Change from v2:
1. include Sascha's patch to make the main patch easier to review.
Thanks Sacha.
2. remove useless 'desc'/'chan' in struct sdma_channe.
Change from v1:
1. split v1 patch into 5 patches.
2. remove some unnecessary condition check.
3. remove unnecessary 'pending' list.
Robin Gong (6):
tty: serial: imx: correct dma cookie status
dmaengine: imx-sdma: add virt-dma support
dmaengine: imx-sdma: remove useless 'lock' and 'enabled' in 'struct
sdma_channel'
dmaengine: imx-sdma: remove the maximum limitation for bd numbers
dmaengine: imx-sdma: add sdma_transfer_init to decrease code overlap
tty: serial: imx: split all dma setup operations out of 'port.lock'
protector
Sascha Hauer (1):
dmaengine: imx-sdma: factor out a struct sdma_desc from struct
sdma_channel
drivers/dma/Kconfig | 1 +
drivers/dma/imx-sdma.c | 394 +++++++++++++++++++++++++++--------------------
drivers/tty/serial/imx.c | 99 ++++++------
3 files changed, 282 insertions(+), 212 deletions(-)
--
2.7.4
^ 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