* [PATCH 2/2] ARM: imx: Add speed grading check for imx6ul
From: Bai Ping @ 2016-11-30 3:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480475098-2037-1-git-send-email-ping.bai@nxp.com>
On i.MX6UL, it has two type of part, the difference
is the max ARM frequency that can run at(528MHz/700MHz).
The part can be identified by part marking for speed grading
fuse. This patch add speed grading check to disable the unsupported
OPP dynamically.
Signed-off-by: Bai Ping <ping.bai@nxp.com>
---
arch/arm/mach-imx/mach-imx6ul.c | 78 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 77 insertions(+), 1 deletion(-)
diff --git a/arch/arm/mach-imx/mach-imx6ul.c b/arch/arm/mach-imx/mach-imx6ul.c
index 6cb8a22..bf86530 100644
--- a/arch/arm/mach-imx/mach-imx6ul.c
+++ b/arch/arm/mach-imx/mach-imx6ul.c
@@ -9,14 +9,17 @@
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <linux/micrel_phy.h>
+#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/phy.h>
+#include <linux/pm_opp.h>
#include <linux/regmap.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include "common.h"
#include "cpuidle.h"
+#include "hardware.h"
static void __init imx6ul_enet_clk_init(void)
{
@@ -57,6 +60,76 @@ static inline void imx6ul_enet_init(void)
imx6ul_enet_phy_init();
}
+#define OCOTP_CFG3 0x440
+#define OCOTP_CFG3_SPEED_SHIFT 16
+#define OCOTP_CFG3_SPEED_696MHZ 0x2
+
+static void __init imx6ul_opp_check_speed_grading(struct device *cpu_dev)
+{
+ struct device_node *np;
+ void __iomem *base;
+ u32 val;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-ocotp");
+ if (!np) {
+ pr_warn("failed to find ocotp node\n");
+ return;
+ }
+
+ base = of_iomap(np, 0);
+ if (!base) {
+ pr_warn("failed to map ocotp\n");
+ goto put_node;
+ }
+
+ /*
+ * Speed GRADING[1:0] defines the max speed of ARM:
+ * 2b'00: Reserved;
+ * 2b'01: 528000000Hz;
+ * 2b'10: 700000000Hz;
+ * 2b'11: Reserved;
+ * We need to set the max speed of ARM according to fuse map.
+ */
+ val = readl_relaxed(base + OCOTP_CFG3);
+ val >>= OCOTP_CFG3_SPEED_SHIFT;
+ val &= 0x3;
+
+ if (val != OCOTP_CFG3_SPEED_696MHZ) {
+ if (dev_pm_opp_disable(cpu_dev, 696000000))
+ pr_warn("Failed to disable 696MHz OPP\n");
+ }
+ iounmap(base);
+
+put_node:
+ of_node_put(np);
+}
+
+static void __init imx6ul_opp_init(void)
+{
+ struct device_node *np;
+ struct device *cpu_dev = get_cpu_device(0);
+
+ if (!cpu_dev) {
+ pr_warn("failed to get cpu0 device\n");
+ return;
+ }
+ np = of_node_get(cpu_dev->of_node);
+ if (!np) {
+ pr_warn("failed to find cpu0 node\n");
+ return;
+ }
+
+ if (dev_pm_opp_of_add_table(cpu_dev)) {
+ pr_warn("failed to init OPP table\n");
+ goto put_node;
+ }
+
+ imx6ul_opp_check_speed_grading(cpu_dev);
+
+put_node:
+ of_node_put(np);
+}
+
static void __init imx6ul_init_machine(void)
{
struct device *parent;
@@ -83,8 +156,11 @@ static void __init imx6ul_init_late(void)
{
imx6sx_cpuidle_init();
- if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ))
+ if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ)) {
+ if (cpu_is_imx6ul())
+ imx6ul_opp_init();
platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0);
+ }
}
static const char * const imx6ul_dt_compat[] __initconst = {
--
1.9.1
^ permalink raw reply related
* [PATCH 1/2] ARM: dts: imx: Add 696MHz setpoint for imx6ul
From: Bai Ping @ 2016-11-30 3:04 UTC (permalink / raw)
To: linux-arm-kernel
Add 696MHz setpoint support for i.MX6UL.
Signed-off-by: Bai Ping <ping.bai@nxp.com>
---
arch/arm/boot/dts/imx6ul.dtsi | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm/boot/dts/imx6ul.dtsi b/arch/arm/boot/dts/imx6ul.dtsi
index 612827d..3ade04e 100644
--- a/arch/arm/boot/dts/imx6ul.dtsi
+++ b/arch/arm/boot/dts/imx6ul.dtsi
@@ -60,12 +60,14 @@
clock-latency = <61036>; /* two CLK32 periods */
operating-points = <
/* kHz uV */
+ 696000 1275000
528000 1175000
396000 1025000
198000 950000
>;
fsl,soc-operating-points = <
/* KHz uV */
+ 696000 1275000
528000 1175000
396000 1175000
198000 1175000
--
1.9.1
^ permalink raw reply related
* [PATCH v2 1/6] mm: hugetlb: rename some allocation functions
From: Huang Shijie @ 2016-11-30 3:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <d28b825d-1026-1e91-fa4e-395df3e1be86@suse.cz>
On Tue, Nov 29, 2016 at 11:44:23AM +0100, Vlastimil Babka wrote:
> On 11/29/2016 09:53 AM, Huang Shijie wrote:
> > On Mon, Nov 28, 2016 at 02:29:03PM +0100, Vlastimil Babka wrote:
> > > On 11/14/2016 08:07 AM, Huang Shijie wrote:
> > > > static inline bool gigantic_page_supported(void) { return true; }
> > > > #else
> > > > +static inline struct page *alloc_gigantic_page(int nid, unsigned int order)
> > > > +{
> > > > + return NULL;
> > > > +}
> > >
> > > This hunk is not explained by the description. Could belong to a later
> > > patch?
> > >
> >
> > Okay, I can create an extra patch to add the description for the
> > alloc_gigantic_page().
>
> Not sure about extra patch, just move it to an existing later patch that
> relies on it?
The whole patch set has been merged to Andrew's tree, so an extra patch
is better. :)
Thanks
Huang Shijie
^ permalink raw reply
* [PATCH V2 fix 5/6] mm: hugetlb: add a new function to allocate a new gigantic page
From: Huang Shijie @ 2016-11-30 3:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <777f7e0c-c04b-77c3-b866-0787bad32aa8@suse.cz>
On Tue, Nov 29, 2016 at 11:50:37AM +0100, Vlastimil Babka wrote:
> > > > + if (!vma) {
> > > > + if (nid == NUMA_NO_NODE) {
> > > > + if (!init_nodemask_of_mempolicy(nodes_allowed)) {
> > > > + NODEMASK_FREE(nodes_allowed);
> > > > + nodes_allowed = &node_states[N_MEMORY];
> > > > + }
> > > > + } else if (nodes_allowed) {
> > The check is here.
>
> It's below a possible usage of nodes_allowed as an argument of
> init_nodemask_of_mempolicy(mask). Which does
Sorry, I missed that.
>
> if (!(mask && current->mempolicy))
> return false;
>
> which itself looks like an error at first sight :)
Yes. I agree.
>
> > Do we really need to re-arrange the code here for the explicit check? :)
>
> We don't need it *now* to be correct, but I still find it fragile. Also it
> mixes up the semantic of NULL as a conscious "default" value, and NULL as
> a side-effect of memory allocation failure. Nothing good can come from that
> in the long term :)
Okay, I think we do have the need to do the NULL check for
@nodes_allowed. :)
Thanks
Huang Shijie
^ permalink raw reply
* [RESEND PATCH] pinctrl: mt8173: set GPIO16 to usb iddig mode
From: Chunfeng Yun @ 2016-11-30 2:21 UTC (permalink / raw)
To: linux-arm-kernel
the default mode of GPIO16 pin is gpio, when set EINT16 to
IRQ_TYPE_LEVEL_HIGH, no interrupt is triggered, it can be
fixed when set its default mode as usb iddig.
Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
drivers/pinctrl/mediatek/pinctrl-mtk-mt8173.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-mt8173.h b/drivers/pinctrl/mediatek/pinctrl-mtk-mt8173.h
index 13e5b68..9b018fd 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-mt8173.h
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-mt8173.h
@@ -201,7 +201,7 @@
MTK_PIN(
PINCTRL_PIN(16, "IDDIG"),
NULL, "mt8173",
- MTK_EINT_FUNCTION(0, 16),
+ MTK_EINT_FUNCTION(1, 16),
MTK_FUNCTION(0, "GPIO16"),
MTK_FUNCTION(1, "IDDIG"),
MTK_FUNCTION(2, "CMFLASH"),
--
1.7.9.5
^ permalink raw reply related
* [PATCH 3/3] ARM: dts: sunxi: enable SDIO Wi-Fi on Orange Pi Zero
From: Alexey Kardashevskiy @ 2016-11-30 2:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161129131922.JFbeipav@smtp2o.mail.yandex.net>
On 29/11/16 21:19, Icenowy Zheng wrote:
>
> 2016?11?29? 15:16? Alexey Kardashevskiy <aik@ozlabs.ru>???
>>
>>
>>
>> On Wed, Nov 23, 2016 at 6:59 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
>>>
>>> Hi,
>>>
>>> On Tue, Nov 22, 2016 at 12:24:21AM +0800, Icenowy Zheng wrote:
>>> > There's a Allwinner's XR819 SDIO Wi-Fi module soldered on the board of
>>> > Orange Pi Zero, which used a dedicated regulator to power.
>>> >
>>> > Add the device tree node of the regulator, the enable gpio (with
>>> > mmc-pwrseq) and the sdio controller.
>>> >
>>> > There's a out-of-tree driver tested to work with this device tree.
>>
>>
>> btw could you please give a pointer where to find a XR819 driver for
> relatively recent kernel (4.8 may be, just not 3.4)? Thanks.
>
> https://github.com/Icenowy/xradio
Thanks!
I tried, cannot make it work though.
This compiles:
CONFIG_XRADIO=y
CONFIG_XRADIO_SDIO=y
CONFIG_XRADIO_NON_POWER_OF_TWO_BLOCKSIZES=y
# CONFIG_XRADIO_USE_GPIO_IRQ is not set
# CONFIG_XRADIO_5GHZ_SUPPORT is not set
# CONFIG_XRADIO_WAPI_SUPPORT is not set
CONFIG_XRADIO_USE_EXTENSIONS=y
But produces:
[ 0.964793] [XRADIO] Driver Label:L34M.01.08.0002
[ 0.969659] [XRADIO] Allocated hw_priv @ df684dc0
[ 3.038167] [SBUS_ERR] sdio probe timeout!
[ 3.046283] [XRADIO_ERR] sbus_sdio_init failed
If I enable CONFIG_XRADIO_USE_GPIO_IRQ (which Kconfig suggest to enable -
do I really need it?), it does not compile:
drivers/built-in.o: In function `sdio_irq_subscribe':
sunxi_sid.c:(.text+0x12dfe8): undefined reference to `xradio_request_gpio_irq'
sunxi_sid.c:(.text+0x12e06c): undefined reference to `xradio_free_gpio_irq'
sunxi_sid.c:(.text+0x12e080): undefined reference to `sunxi_mci_check_r1_ready'
drivers/built-in.o: In function `sdio_irq_unsubscribe':
sunxi_sid.c:(.text+0x12e3b0): undefined reference to `xradio_free_gpio_irq'
Makefile:962: recipe for target 'vmlinux' failed
make: *** [vmlinux] Error 1
I am using recent upstream kernel and
https://patchwork.kernel.org/patch/9439759/
https://patchwork.kernel.org/patch/9439761/
and I added missing emac.
Basically, here is my current tree with all sun8xi support
https://github.com/aik/linux/commits/pizero
and I just did
git -C drivers/net/ethernet clone https://github.com/Icenowy/xradio
and compiled it into vmlinux (no modules).
What am I missing? Sorry I am a newbie with ARM. Thanks.
--
Alexey
^ permalink raw reply
* [PATCH V7 2/3] ACPI: Add support for ResourceSource/IRQ domain mapping
From: Hanjun Guo @ 2016-11-30 2:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAJZ5v0gpYqH9psHz4YQp=c5_M9NyZ4qppLFF5NK0XRHbm5nbbQ@mail.gmail.com>
On 2016/11/30 0:26, Rafael J. Wysocki wrote:
> On Tue, Nov 29, 2016 at 4:20 PM, Agustin Vega-Frias
> <agustinv@codeaurora.org> wrote:
>> Hi Rafael,
>>
>>
>> On 2016-11-29 07:43, Rafael J. Wysocki wrote:
>>> On Tue, Nov 29, 2016 at 1:11 PM, Lorenzo Pieralisi
>>> <lorenzo.pieralisi@arm.com> wrote:
>>>> Hi Agustin,
>>>>
>>>> On Mon, Nov 28, 2016 at 05:40:24PM -0500, Agustin Vega-Frias wrote:
>>>>> Hi Rafael,
>>>>>
>>>>> Can you chime in on Lorenzo's feedback and the discussion below?
>>>>> It would be great if you can comment on the reason ACPI does things
>>>>> in a certain way.
>>>>>
>>>>> Hi Lorenzo,
>>>>>
>>>>> On 2016-11-25 06:40, Lorenzo Pieralisi wrote:
>>>>>> Hi Agustin,
>>>>>>
>>>>>> On Thu, Nov 24, 2016 at 04:15:48PM +0000, Lorenzo Pieralisi wrote:
>>>>>>
>>>>>> [...]
>>>>>>
>>>>>>>> @@ -448,6 +449,7 @@ bool acpi_dev_resource_interrupt(struct
>>>>>>>> acpi_resource *ares, int index,
>>>>>>>> {
>>>>>>>> struct acpi_resource_irq *irq;
>>>>>>>> struct acpi_resource_extended_irq *ext_irq;
>>>>>>>> + struct fwnode_handle *src;
>>>>>>>>
>>>>>>>> switch (ares->type) {
>>>>>>>> case ACPI_RESOURCE_TYPE_IRQ:
>>>>>>>> @@ -460,7 +462,7 @@ bool acpi_dev_resource_interrupt(struct
>>>>>>>> acpi_resource *ares, int index,
>>>>>>>> acpi_dev_irqresource_disabled(res, 0);
>>>>>>>> return false;
>>>>>>>> }
>>>>>>>> - acpi_dev_get_irqresource(res, irq->interrupts[index],
>>>>>>>> + acpi_dev_get_irqresource(res, irq->interrupts[index],
>>>>>>>> NULL,
>>>>>>>> irq->triggering, irq->polarity,
>>>>>>>> irq->sharable, true);
>>>>>>>> break;
>>>>>>>> @@ -470,7 +472,8 @@ bool acpi_dev_resource_interrupt(struct
>>>>>>>> acpi_resource *ares, int index,
>>>>>>>> acpi_dev_irqresource_disabled(res, 0);
>>>>>>>> return false;
>>>>>>>> }
>>>>>>>> - acpi_dev_get_irqresource(res, ext_irq->interrupts[index],
>>>>>>>> + src =
>>>>>>>> acpi_get_irq_source_fwhandle(&ext_irq->resource_source);
>>>>>>> Is there a reason why we need to do the domain look-up here ?
>>>>> Because we need to pass the resource down to acpi_dev_get_irqresource
>>>>> which does the mapping through acpi_register_irq/acpi_register_gsi.
>>>>>
>>>>>>> I would like to understand if, by reshuffling the code (and by
>>>>>>> returning
>>>>>>> the resource_source to the calling code - somehow), it would be
>>>>>>> possible
>>>>>>> to just mirror what the OF code does in of_irq_get(), namely:
>>>>>>>
>>>>>>> (1) parse the irq entry -> of_irq_parse_one()
>>>>>>> (2) look the domain up -> irq_find_host()
>>>>>>> (3) create the mapping -> irq_create_of_mapping()
>>>>>>>
>>>>>>> You wrote the code already, I think it is just a matter of shuffling
>>>>>>> it around (well, minus returning the resource_source to the caller
>>>>>>> which is phandle equivalent in DT).
>>>>> This is one area in which DT and ACPI are fundamentally different. In DT
>>>>> once the flattened blob is expanded the data is fixed. In ACPI the data
>>>>> returned by a method can change. In reality most methods like CRS return
>>>>> constants, but given that per-spec they are methods the interpreter has
>>>>> to be involved, which makes it an expensive operation. I believe that is
>>>>> the reason the resource parsing code in ACPI attempts all mappings
>>>>> during
>>>>> the bus scan. Rafael can you comment on this?
>>>>>
>>>>> One way to do what you suggest would be to defer IRQ mapping by, e.g.,
>>>>> populating res->start with the HW IRQ number and res->end with the
>>>>> fwnode.
>>>>> That way we can avoid having to walk the resource buffer when a mapping
>>>>> is needed. I don't think that approach would deviate much more from
>>>>> the spec from what the current ahead-of-time mapping does, but it would
>>>>> require more changes in the core code. An alternative would be to do
>>>>> that only for resources that fail to map.
>>>>>
>>>>>>> You abstracted away (2) and (3) behind acpi_register_irq(), that
>>>>>>> on anything than does not use ACPI_GENERIC_GSI is just glue code
>>>>>>> to acpi_register_gsi().
>>>>>>>
>>>>>>> Also, it is not a question on this patch but I ask it here because it
>>>>>>> is related. On ACPI you are doing the reverse of what is done in
>>>>>>> DT in platform_get_irq():
>>>>>>>
>>>>>>> - get the resources already parsed -> platform_get_resource()
>>>>>>> - if they are disabled -> acpi_irq_get()
>>>>>>>
>>>>>>> and I think the ordering is tied to my question above because
>>>>>>> you carry out the domain look up in acpi_dev_resource_interrupt()
>>>>>>> so that if for any reason it fails the corresponding resource
>>>>>>> is disabled so that we try to get it again through acpi_irq_get().
>>>>>>>
>>>>>>> I suspect you did it this way to make sure:
>>>>>>>
>>>>>>> a) keep the current ACPI IRQ parsing interface changes to a mininum
>>>>>>> b) avoid changing the behaviour on x86/ia64; in particular, calling
>>>>>>> acpi_register_gsi() for the _same_ mapping (an IRQ that was already
>>>>>>> registered at device creation resource parsing) multiple times can
>>>>>>> trigger issues on x86/ia64
>>>>> You are correct about my reasons. I wanted to keep ACPI core code
>>>>> changes
>>>>> to a minimum, and I also needed to work within the current
>>>>> implementation
>>>>> which uses the pre-converted IRQ resources.
>>>>>
>>>>>>> I think that's a reasonable approach but I wanted to get these
>>>>>>> clarifications, I do not think you are far from getting this
>>>>>>> done but since it is a significant change I think it is worth
>>>>>>> discussing the points I raised above because I think the DT code
>>>>>>> sequence in of_irq_get() (1-2-3 above) is cleaner from an IRQ
>>>>>>> layer perspective (instead of having the domain look-up buried
>>>>>>> inside the ACPI IRQ resource parsing API).
>>>>>> I had another look and to achieve the above one way of doing that is to
>>>>>> implement acpi_irq_get() only for ACPI_GENERIC_GSI and stub it out for
>>>>>> !ACPI_GENERIC_GSI (ie return an error code so that on !ACPI_GENERIC_GSI
>>>>>> we would fall back to current solution for ACPI). Within acpi_irq_get()
>>>>>> you can easily carry out the same steps (1->2->3) above in ACPI
>>>>>> you have
>>>>>> the code already there I think it is easy to change the
>>>>>> acpi_irq_get_cb() interface to return a filled in struct irq_fwspec and
>>>>>> the interface would become identical to of_irq_get() that is an
>>>>>> advantage to maintain it from an IRQ maintainership perspective I
>>>>>> think,
>>>>>> that's my opinion.
>>>>> I think I get what you mean. I'll take a stab at implementing
>>>>> acpi_irq_get()
>>>>> in the way you suggest.
>>>>>
>>>>>> There is still a nagging snag though. When platform devices are
>>>>>> created, core ACPI code parse the resources through:
>>>>>>
>>>>>> acpi_dev_get_resources()
>>>>>>
>>>>>> and we _have_ to have way to avoid initializing IRQ resources that
>>>>>> have a dependency (ie there is a resource_source pointer that is valid
>>>>>> in their descriptors) that's easy to do if we think that's the right
>>>>>> thing to do and can hardly break current code (which ignores the
>>>>>> resource_source altogether).
>>>>> I'd rather keep the core code as-is with regard to the ahead-of-time
>>>>> conversion. Whether a resource source is available at the time of
>>>>> the bus
>>>>> scan should be transparent to the code in drivers/acpi/resource.c, and
>>>>> we need the initialization as a disabled resource to signal the need
>>>>> to retry anyway.
>>>>
>>>> Yes, exactly that's the nub. Your current code works, I am trying to
>>>> make it more modular and similar to the DT/irqdomain IRQ look-up path,
>>>> which has its advantages.
>>>>
>>>> There are two options IMHO:
>>>>
>>>> - always disable the resource if it has a resource_source dependency and
>>>> defer
>>>> its parsing to acpi_irq_get() (where you can easily implement steps
>>>> 1-2-3 above).
>>>> What I wanted to say is that, by disabling the resource if it has a
>>>> resource_source dependency you can't break x86/ia64 (it is ignored at
>>>> present - hopefully there is nothing that we are not aware of behind
>>>> that choice). On x86/ia64 acpi_irq_get() would be an empty stub.
>>>> This way you would keep the irqdomain look-up out of the ACPI resource
>>>> parsing API, correct ?
>>>> - keep code as-is
>>>>
>>>> Your point on _CRS being _current_ resource setting is perfectly valid
>>>> so platform_get_resource() in platform_get_irq() must always take
>>>> precedence over acpi_irq_get() (which should just apply to disabled
>>>> resources), I am not sure that doing it the other way around is safe.
>>>>
>>>>> Rafael, do you have any other suggestions/feedback on how to go about
>>>>> doing this?
>>>>
>>>> Yes, comments very appreciated, these changes are not trivial and need
>>>> agreement.
>>>
>>> So I need more time.
>>
>> Please wait for V8 which will address some issues raised by Lorenzo.
>>
>>> But basically, _CRS can't really change on the fly AFAICS. I'm not
>>> even sure it is valid for it to change at all after the first
>>> evaluation if _SRS/_PRS are not present.
>>
>> That's good to know and it opens more possibilities.
> Actually, to me it follows from the very purpose of _CRS that, as long
> as the device is enabled, it should be expected to return the same
> data every time it is evaluated, unless _SRS is invoked in the
> meantime. Otherwise, it would be possible for the device's resources
> to change unexpectedly under a driver using it.
Agreed, here is the hotplug case:
For hotplug cases, _CRS is updated before the device is enabled. for example
for a memory hot add, BIOS will update the _CRS to collect memory address
ranges before notify OS, but once the BIOS notified OS to add the memory in
(BIOS will enable the device to set the _STA to functional), _CRS can't be updated.
Thanks
Hanjun
^ permalink raw reply
* [PATCH net-next v3 0/4] Fix OdroidC2 Gigabit Tx link issue
From: Florian Fainelli @ 2016-11-30 1:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161129.201331.2207317476589573523.davem@davemloft.net>
On 11/29/2016 05:13 PM, David Miller wrote:
> From: Florian Fainelli <f.fainelli@gmail.com>
> Date: Tue, 29 Nov 2016 16:43:20 -0800
>
>> On 11/29/2016 04:38 PM, David Miller wrote:
>>> From: Jerome Brunet <jbrunet@baylibre.com>
>>> Date: Mon, 28 Nov 2016 10:46:45 +0100
>>>
>>>> This patchset fixes an issue with the OdroidC2 board (DWMAC + RTL8211F).
>>>> The platform seems to enter LPI on the Rx path too often while performing
>>>> relatively high TX transfer. This eventually break the link (both Tx and
>>>> Rx), and require to bring the interface down and up again to get the Rx
>>>> path working again.
>>>>
>>>> The root cause of this issue is not fully understood yet but disabling EEE
>>>> advertisement on the PHY prevent this feature to be negotiated.
>>>> With this change, the link is stable and reliable, with the expected
>>>> throughput performance.
>>>>
>>>> The patchset adds options in the generic phy driver to disable EEE
>>>> advertisement, through device tree. The way it is done is very similar
>>>> to the handling of the max-speed property.
>>>
>>> Patches 1-3 applied to net-next, thanks.
>>
>> Meh, there was a v4 submitted shortly after, and I objected to the whole
>> idea of using that kind of Device Tree properties to disable EEE, we can
>> send reverts though..
>
> Sorry, I lost this in all the discussion, I can revert.
Yeah, I can understand why, these freaking PHYs tend to generate a lot
of noise and discussion...
>
> Just send me a revert of the entire merge commit
> a152c91889556df17ca6d8ea134fb2cb4ac9f893 with a short
> description of why and I'll apply it.
OK, I will talk with Jerome first to make sure that we are in agreement
with the solution to deploy to fix the OdroidC2 problem first.
Thanks!
--
Florian
^ permalink raw reply
* [PATCH net-next v3 0/4] Fix OdroidC2 Gigabit Tx link issue
From: David Miller @ 2016-11-30 1:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <e14a3b0c-dc34-be14-48b3-518a0ad0c080@gmail.com>
From: Florian Fainelli <f.fainelli@gmail.com>
Date: Tue, 29 Nov 2016 16:43:20 -0800
> On 11/29/2016 04:38 PM, David Miller wrote:
>> From: Jerome Brunet <jbrunet@baylibre.com>
>> Date: Mon, 28 Nov 2016 10:46:45 +0100
>>
>>> This patchset fixes an issue with the OdroidC2 board (DWMAC + RTL8211F).
>>> The platform seems to enter LPI on the Rx path too often while performing
>>> relatively high TX transfer. This eventually break the link (both Tx and
>>> Rx), and require to bring the interface down and up again to get the Rx
>>> path working again.
>>>
>>> The root cause of this issue is not fully understood yet but disabling EEE
>>> advertisement on the PHY prevent this feature to be negotiated.
>>> With this change, the link is stable and reliable, with the expected
>>> throughput performance.
>>>
>>> The patchset adds options in the generic phy driver to disable EEE
>>> advertisement, through device tree. The way it is done is very similar
>>> to the handling of the max-speed property.
>>
>> Patches 1-3 applied to net-next, thanks.
>
> Meh, there was a v4 submitted shortly after, and I objected to the whole
> idea of using that kind of Device Tree properties to disable EEE, we can
> send reverts though..
Sorry, I lost this in all the discussion, I can revert.
Just send me a revert of the entire merge commit
a152c91889556df17ca6d8ea134fb2cb4ac9f893 with a short
description of why and I'll apply it.
Thanks.
^ permalink raw reply
* [PATCH v3 3/3] fpga manager: Add cyclone-ps-spi driver for Altera FPGAs
From: Joshua Clayton @ 2016-11-30 1:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1480467185.git.stillcompiling@gmail.com>
cyclone-ps-spi loads FPGA firmware over spi, using the "passive serial"
interface on Altera Cyclone FPGAS.
This is one of the simpler ways to set up an FPGA at runtime.
The signal interface is close to unidirectional spi with lsb first.
Signed-off-by: Joshua Clayton <stillcompiling@gmail.com>
---
drivers/fpga/Kconfig | 7 ++
drivers/fpga/Makefile | 1 +
drivers/fpga/cyclone-ps-spi.c | 176 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 184 insertions(+)
create mode 100644 drivers/fpga/cyclone-ps-spi.c
diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index cd84934..2462707 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -13,6 +13,13 @@ config FPGA
if FPGA
+config FPGA_MGR_CYCLONE_PS_SPI
+ tristate "Altera Cyclone FPGA Passive Serial over SPI"
+ depends on SPI
+ help
+ FPGA manager driver support for Altera Cyclone using the
+ passive serial interface over SPI
+
config FPGA_MGR_SOCFPGA
tristate "Altera SOCFPGA FPGA Manager"
depends on ARCH_SOCFPGA
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index 8d83fc6..8f93930 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -6,5 +6,6 @@
obj-$(CONFIG_FPGA) += fpga-mgr.o
# FPGA Manager Drivers
+obj-$(CONFIG_FPGA_MGR_CYCLONE_PS_SPI) += cyclone-ps-spi.o
obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o
obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o
diff --git a/drivers/fpga/cyclone-ps-spi.c b/drivers/fpga/cyclone-ps-spi.c
new file mode 100644
index 0000000..57a520d
--- /dev/null
+++ b/drivers/fpga/cyclone-ps-spi.c
@@ -0,0 +1,176 @@
+/**
+ * Copyright (c) 2015 United Western Technologies, Corporation
+ *
+ * Joshua Clayton <stillcompiling@gmail.com>
+ *
+ * Manage Altera fpga firmware that is loaded over spi.
+ * Firmware must be in binary "rbf" format.
+ * Works on Cyclone V. Should work on cyclone series.
+ * May work on other Altera fpgas.
+ *
+ */
+
+#include <linux/bitrev.h>
+#include <linux/delay.h>
+#include <linux/fpga/fpga-mgr.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/sizes.h>
+
+#define FPGA_RESET_TIME 50 /* time in usecs to trigger FPGA config */
+#define FPGA_MIN_DELAY 50 /* min usecs to wait for config status */
+#define FPGA_MAX_DELAY 1000 /* max usecs to wait for config status */
+
+struct cyclonespi_conf {
+ struct gpio_desc *config;
+ struct gpio_desc *status;
+ struct spi_device *spi;
+};
+
+static const struct of_device_id of_ef_match[] = {
+ { .compatible = "altr,cyclone-ps-spi-fpga-mgr", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, of_ef_match);
+
+static enum fpga_mgr_states cyclonespi_state(struct fpga_manager *mgr)
+{
+ return mgr->state;
+}
+
+static int cyclonespi_write_init(struct fpga_manager *mgr, u32 flags,
+ const char *buf, size_t count)
+{
+ struct cyclonespi_conf *conf = (struct cyclonespi_conf *)mgr->priv;
+ int i;
+
+ if (flags & FPGA_MGR_PARTIAL_RECONFIG) {
+ dev_err(&mgr->dev, "Partial reconfiguration not supported.\n");
+ return -EINVAL;
+ }
+
+ gpiod_set_value(conf->config, 0);
+ usleep_range(FPGA_RESET_TIME, FPGA_RESET_TIME + 20);
+ if (gpiod_get_value(conf->status) == 1) {
+ dev_err(&mgr->dev, "Status pin should be low.\n");
+ return -EIO;
+ }
+
+ gpiod_set_value(conf->config, 1);
+ for (i = 0; i < (FPGA_MAX_DELAY / FPGA_MIN_DELAY); i++) {
+ usleep_range(FPGA_MIN_DELAY, FPGA_MIN_DELAY + 20);
+ if (gpiod_get_value(conf->status))
+ return 0;
+ }
+
+ dev_err(&mgr->dev, "Status pin not ready.\n");
+ return -EIO;
+}
+
+static void rev_buf(void *buf, size_t len)
+{
+ u32 *fw32 = (u32 *)buf;
+ const u32 *fw_end = (u32 *)(buf + len);
+
+ /* set buffer to lsb first */
+ while (fw32 < fw_end) {
+ *fw32 = bitrev8x4(*fw32);
+ fw32++;
+ }
+}
+
+static int cyclonespi_write(struct fpga_manager *mgr, const char *buf,
+ size_t count)
+{
+ struct cyclonespi_conf *conf = (struct cyclonespi_conf *)mgr->priv;
+ const char *fw_data = buf;
+ const char *fw_data_end = fw_data + count;
+
+ while (fw_data < fw_data_end) {
+ int ret;
+ size_t stride = min(fw_data_end - fw_data, SZ_4K);
+
+ rev_buf((void *)fw_data, stride);
+ ret = spi_write(conf->spi, fw_data, stride);
+ if (ret) {
+ dev_err(&mgr->dev, "spi error in firmware write: %d\n",
+ ret);
+ return ret;
+ }
+ fw_data += stride;
+ }
+
+ return 0;
+}
+
+static int cyclonespi_write_complete(struct fpga_manager *mgr, u32 flags)
+{
+ struct cyclonespi_conf *conf = (struct cyclonespi_conf *)mgr->priv;
+
+ if (gpiod_get_value(conf->status) == 0) {
+ dev_err(&mgr->dev, "Error during configuration.\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static const struct fpga_manager_ops cyclonespi_ops = {
+ .state = cyclonespi_state,
+ .write_init = cyclonespi_write_init,
+ .write = cyclonespi_write,
+ .write_complete = cyclonespi_write_complete,
+};
+
+static int cyclonespi_probe(struct spi_device *spi)
+{
+ struct cyclonespi_conf *conf = devm_kzalloc(&spi->dev, sizeof(*conf),
+ GFP_KERNEL);
+
+ if (!conf)
+ return -ENOMEM;
+
+ conf->spi = spi;
+ conf->config = devm_gpiod_get(&spi->dev, "config", GPIOD_OUT_LOW);
+ if (IS_ERR(conf->config)) {
+ dev_err(&spi->dev, "Failed to get config gpio: %ld\n",
+ PTR_ERR(conf->config));
+ return PTR_ERR(conf->config);
+ }
+
+ conf->status = devm_gpiod_get(&spi->dev, "status", GPIOD_IN);
+ if (IS_ERR(conf->status)) {
+ dev_err(&spi->dev, "Failed to get status gpio: %ld\n",
+ PTR_ERR(conf->status));
+ return PTR_ERR(conf->status);
+ }
+
+ return fpga_mgr_register(&spi->dev,
+ "Altera Cyclone PS SPI FPGA Manager",
+ &cyclonespi_ops, conf);
+}
+
+static int cyclonespi_remove(struct spi_device *spi)
+{
+ fpga_mgr_unregister(&spi->dev);
+
+ return 0;
+}
+
+static struct spi_driver cyclonespi_driver = {
+ .driver = {
+ .name = "cyclone-ps-spi",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(of_ef_match),
+ },
+ .probe = cyclonespi_probe,
+ .remove = cyclonespi_remove,
+};
+
+module_spi_driver(cyclonespi_driver)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Joshua Clayton <stillcompiling@gmail.com>");
+MODULE_DESCRIPTION("Module to load Altera FPGA firmware over spi");
--
2.9.3
^ permalink raw reply related
* [PATCH v3 2/3] doc: dt: add cyclone-spi binding document
From: Joshua Clayton @ 2016-11-30 1:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1480467185.git.stillcompiling@gmail.com>
Describe a cyclonei-ps-spi devicetree entry, required features
Signed-off-by: Joshua Clayton <stillcompiling@gmail.com>
---
.../bindings/fpga/cyclone-ps-spi-fpga-mgr.txt | 23 ++++++++++++++++++++++
1 file changed, 23 insertions(+)
create mode 100644 Documentation/devicetree/bindings/fpga/cyclone-ps-spi-fpga-mgr.txt
diff --git a/Documentation/devicetree/bindings/fpga/cyclone-ps-spi-fpga-mgr.txt b/Documentation/devicetree/bindings/fpga/cyclone-ps-spi-fpga-mgr.txt
new file mode 100644
index 0000000..c942281
--- /dev/null
+++ b/Documentation/devicetree/bindings/fpga/cyclone-ps-spi-fpga-mgr.txt
@@ -0,0 +1,23 @@
+Altera Cyclone Passive Serial SPI FPGA Manager
+
+Altera Cyclone FPGAs support a method of loading the bitstream over what is
+referred to as "passive serial".
+The passive serial link is not technically spi, and might require extra
+circuits in order to play nicely with other spi slaves on the same bus.
+
+See https://www.altera.com/literature/hb/cyc/cyc_c51013.pdf
+
+Required properties:
+- compatible : should contain "altr,cyclone-ps-spi-fpga-mgr"
+- reg : spi slave id of the fpga
+- config-gpio : config pin (referred to as nCONFIG in the cyclone manual)
+- status-gpio : status pin (referred to as nSTATUS in the cyclone manual)
+
+Example:
+ fpga_spi: evi-fpga-spi at 0 {
+ compatible = "altr,cyclone-ps-spi-fpga-mgr";
+ spi-max-frequency = <20000000>;
+ reg = <0>;
+ config-gpio = <&gpio4 9 GPIO_ACTIVE_HIGH>;
+ status-gpio = <&gpio4 11 GPIO_ACTIVE_HIGH>;
+ };
--
2.9.3
^ permalink raw reply related
* [PATCH v3 1/3] lib: add bitrev8x4()
From: Joshua Clayton @ 2016-11-30 1:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1480467185.git.stillcompiling@gmail.com>
Add a function to reverse bytes within a 32 bit word.
This function is more efficient than using the 8 bit version when
iterating over an array
Signed-off-by: Joshua Clayton <stillcompiling@gmail.com>
---
arch/arm/include/asm/bitrev.h | 5 +++++
include/linux/bitrev.h | 26 ++++++++++++++++++++++++++
2 files changed, 31 insertions(+)
diff --git a/arch/arm/include/asm/bitrev.h b/arch/arm/include/asm/bitrev.h
index ec291c3..6d2e9ca 100644
--- a/arch/arm/include/asm/bitrev.h
+++ b/arch/arm/include/asm/bitrev.h
@@ -17,4 +17,9 @@ static __always_inline __attribute_const__ u8 __arch_bitrev8(u8 x)
return __arch_bitrev32((u32)x) >> 24;
}
+static __always_inline __attribute_const__ u32 __arch_bitrev8x4(u32 x)
+{
+ __asm__ ("rbit %0, %1; rev %0, %0" : "=r" (x) : "r" (x));
+}
+
#endif
diff --git a/include/linux/bitrev.h b/include/linux/bitrev.h
index fb790b8..b1cfa1a 100644
--- a/include/linux/bitrev.h
+++ b/include/linux/bitrev.h
@@ -9,6 +9,7 @@
#define __bitrev32 __arch_bitrev32
#define __bitrev16 __arch_bitrev16
#define __bitrev8 __arch_bitrev8
+#define __bitrev8x4 __arch_bitrev8x4
#else
extern u8 const byte_rev_table[256];
@@ -27,6 +28,14 @@ static inline u32 __bitrev32(u32 x)
return (__bitrev16(x & 0xffff) << 16) | __bitrev16(x >> 16);
}
+static inline u32 __bitrev8x4(u32 x)
+{
+ return(__bitrev8(x & 0xff) |
+ (__bitrev8((x >> 8) & 0xff) << 8) |
+ (__bitrev8((x >> 16) & 0xff) << 16) |
+ (__bitrev8((x >> 24) & 0xff) << 24));
+}
+
#endif /* CONFIG_HAVE_ARCH_BITREVERSE */
#define __constant_bitrev32(x) \
@@ -50,6 +59,15 @@ static inline u32 __bitrev32(u32 x)
__x; \
})
+#define __constant_bitrev8x4(x) \
+({ \
+ u32 __x = x; \
+ __x = ((__x & (u32)0xF0F0F0F0UL) >> 4) | ((__x & (u32)0x0F0F0F0FUL) << 4); \
+ __x = ((__x & (u32)0xCCCCCCCCUL) >> 2) | ((__x & (u32)0x33333333UL) << 2); \
+ __x = ((__x & (u32)0xAAAAAAAAUL) >> 1) | ((__x & (u32)0x55555555UL) << 1); \
+ __x; \
+})
+
#define __constant_bitrev8(x) \
({ \
u8 __x = x; \
@@ -75,6 +93,14 @@ static inline u32 __bitrev32(u32 x)
__bitrev16(__x); \
})
+#define bitrev8x4(x) \
+({ \
+ u32 __x = x; \
+ __builtin_constant_p(__x) ? \
+ __constant_bitrev8x4(__x) : \
+ __bitrev8x4(__x); \
+})
+
#define bitrev8(x) \
({ \
u8 __x = x; \
--
2.9.3
^ permalink raw reply related
* [PATCH v3 0/3] Altera Cyclone Passive Serial SPI FPGA Manager
From: Joshua Clayton @ 2016-11-30 1:11 UTC (permalink / raw)
To: linux-arm-kernel
This series adds an FPGA manager for Altera cyclone FPGAs
that can program them using an spi port and a couple of gpios, using
Alteras passive serial protocol.
Changes from v2:
- Merged patch 3 and 4 as suggested in review by Moritz Fischer
- Changed FPGA_MIN_DELAY from 250 to 50 ms is the time advertized by
Altera. This now works, as we don't assume it is done
Changes from v1:
- Changed the name from cyclone-spi-fpga-mgr to cyclone-ps-spi-fpga-mgr
This name change was requested by Alan Tull, to be specific about which
programming method is being employed on the fpga.
- Changed the name of the reset-gpio to config-gpio to closer match the
way the pins are described in the Altera manual
- Moved MODULE_LICENCE, _AUTHOR, and _DESCRIPTION to the bottom
- Added a bitrev8x4() function to the bitrev headers and implemented ARM
const, runtime, and ARM specific faster versions (This may end up
needing to be a standalone patch)
- Moved the bitswapping into cyclonespi_write(), as requested.
This falls short of my desired generic lsb first spi support, but is a step
in that direction.
- Fixed whitespace problems introduced during refactoring
- Replaced magic number for initial delay with a descriptive macro
- Poll the fpga to see when it is ready rather than a fixed 1 ms sleep
Joshua Clayton (3):
lib: add bitrev8x4()
doc: dt: add cyclone-spi binding document
fpga manager: Add cyclone-ps-spi driver for Altera FPGAs
.../bindings/fpga/cyclone-ps-spi-fpga-mgr.txt | 23 +++
arch/arm/include/asm/bitrev.h | 5 +
drivers/fpga/Kconfig | 7 +
drivers/fpga/Makefile | 1 +
drivers/fpga/cyclone-ps-spi.c | 176 +++++++++++++++++++++
include/linux/bitrev.h | 26 +++
6 files changed, 238 insertions(+)
create mode 100644 Documentation/devicetree/bindings/fpga/cyclone-ps-spi-fpga-mgr.txt
create mode 100644 drivers/fpga/cyclone-ps-spi.c
--
2.9.3
^ permalink raw reply
* [alsa-devel] [PATCH v2] clkdev: add devm_of_clk_get()
From: Kuninori Morimoto @ 2016-11-30 1:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161129210556.GC6095@codeaurora.org>
Hi Stephen
Thank you for your feedback.
> > > > sound_soc {
> > > > clocks = <&xxx>, <&xxx>;
> > > > clock-names = "cpu", "codec";
> > > > ...
> > > > cpu {
> > > > ...
> > > > };
> > > > codec {
> > > > ...
> > > > };
> > > > };
(snip)
> The problem is that it encourages the use of of_clk_get() when
> clk_get() is more desirable. Ideally of_clk_get() is never used
> when a device exists. In this case, it seems like we need to
> support it though, hence the suggestion of having a
> devm_get_clk_from_child() API, that explicitly reads as "get a
> clock from a child node of this device". The distinction is
> important, because of_clk_get() should rarely be used.
I understand your point, but I think devm_get_clk_from_child()
needs new DT setings, and it can't keep compatibility, or
it makes driver complex.
I think it is nice to have. but, I want to keep current style.
Thus, I will try to use current of_clk_get() as-is, and
call clk_free() somehow in this driver.
^ permalink raw reply
* [PATCH net v2 1/1] net: macb: fix the RX queue reset in macb_rx()
From: David Miller @ 2016-11-30 1:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <80ebb550eb6155e3b882cab1fb8d78a7385f8227.1480339901.git.cyrille.pitchen@atmel.com>
From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
Date: Mon, 28 Nov 2016 14:40:55 +0100
> On macb only (not gem), when a RX queue corruption was detected from
> macb_rx(), the RX queue was reset: during this process the RX ring
> buffer descriptor was initialized by macb_init_rx_ring() but we forgot
> to also set bp->rx_tail to 0.
>
> Indeed, when processing the received frames, bp->rx_tail provides the
> macb driver with the index in the RX ring buffer of the next buffer to
> process. So when the whole ring buffer is reset we must also reset
> bp->rx_tail so the driver is synchronized again with the hardware.
>
> Since macb_init_rx_ring() is called from many locations, currently from
> macb_rx() and macb_init_rings(), we'd rather add the "bp->rx_tail = 0;"
> line inside macb_init_rx_ring() than add the very same line after each
> call of this function.
>
> Without this fix, the rx queue is not reset properly to recover from
> queue corruption and connection drop may occur.
>
> Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
> Fixes: 9ba723b081a2 ("net: macb: remove BUG_ON() and reset the queue to handle RX errors")
> Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Applied and queued up for -stable, thanks.
^ permalink raw reply
* [PATCH net-next v3 0/4] Fix OdroidC2 Gigabit Tx link issue
From: Florian Fainelli @ 2016-11-30 0:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161129.193853.827524417068912706.davem@davemloft.net>
On 11/29/2016 04:38 PM, David Miller wrote:
> From: Jerome Brunet <jbrunet@baylibre.com>
> Date: Mon, 28 Nov 2016 10:46:45 +0100
>
>> This patchset fixes an issue with the OdroidC2 board (DWMAC + RTL8211F).
>> The platform seems to enter LPI on the Rx path too often while performing
>> relatively high TX transfer. This eventually break the link (both Tx and
>> Rx), and require to bring the interface down and up again to get the Rx
>> path working again.
>>
>> The root cause of this issue is not fully understood yet but disabling EEE
>> advertisement on the PHY prevent this feature to be negotiated.
>> With this change, the link is stable and reliable, with the expected
>> throughput performance.
>>
>> The patchset adds options in the generic phy driver to disable EEE
>> advertisement, through device tree. The way it is done is very similar
>> to the handling of the max-speed property.
>
> Patches 1-3 applied to net-next, thanks.
Meh, there was a v4 submitted shortly after, and I objected to the whole
idea of using that kind of Device Tree properties to disable EEE, we can
send reverts though..
--
Florian
^ permalink raw reply
* [PATCH net-next v3 0/4] Fix OdroidC2 Gigabit Tx link issue
From: David Miller @ 2016-11-30 0:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480326409-25419-1-git-send-email-jbrunet@baylibre.com>
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Mon, 28 Nov 2016 10:46:45 +0100
> This patchset fixes an issue with the OdroidC2 board (DWMAC + RTL8211F).
> The platform seems to enter LPI on the Rx path too often while performing
> relatively high TX transfer. This eventually break the link (both Tx and
> Rx), and require to bring the interface down and up again to get the Rx
> path working again.
>
> The root cause of this issue is not fully understood yet but disabling EEE
> advertisement on the PHY prevent this feature to be negotiated.
> With this change, the link is stable and reliable, with the expected
> throughput performance.
>
> The patchset adds options in the generic phy driver to disable EEE
> advertisement, through device tree. The way it is done is very similar
> to the handling of the max-speed property.
Patches 1-3 applied to net-next, thanks.
^ permalink raw reply
* [PATCH V3 0/8] IOMMU probe deferral support
From: Sricharan @ 2016-11-30 0:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161128181339.GA32078@red-moon>
Hi Lorenzo,
>-----Original Message-----
>From: linux-arm-kernel [mailto:linux-arm-kernel-bounces at lists.infradead.org] On Behalf Of Lorenzo Pieralisi
>Sent: Monday, November 28, 2016 11:44 PM
>To: Sricharan <sricharan@codeaurora.org>
>Cc: linux-arm-msm at vger.kernel.org; joro at 8bytes.org; will.deacon at arm.com; tfiga at chromium.org; iommu at lists.linux-
>foundation.org; srinivas.kandagatla at linaro.org; laurent.pinchart at ideasonboard.com; 'Robin Murphy' <robin.murphy@arm.com>;
>linux-arm-kernel at lists.infradead.org; m.szyprowski at samsung.com
>Subject: Re: [PATCH V3 0/8] IOMMU probe deferral support
>
>On Mon, Nov 28, 2016 at 11:12:08PM +0530, Sricharan wrote:
>
>[...]
>
>> >Cool. We're rather hoping that the ACPI stuff is good to go for 4.10
>> >now, so it's probably worth pulling the rest of that in (beyond the one
>> >patch I picked) to make sure the of_dma_configure/acpi_dma_configure
>> >paths don't inadvertently diverge.
>> >
>>
>> I rebased and was testing your branch with Lorenzo's series. One thing
>> i am still trying to get right is the acpi_dma_configure call. With your
>> series dma_configure calls pci_dma/of_dma configure, so i am just adding
>> acpi_dma_configure call there for non-pci ACPI devices as well. I see that
>> acpi_dma_configure right now is called from acpi_bind_one and
>> iort_add_smmu_platform_device, both go through the really_probe function
>> path, so moving acpi_dma_configure from the above the two functions
>> to dma_configure. I remember we discussed this on another thread, so
>> hopefully it is correct. I do not have an platform to test the ACPI though.
>> I will take some testing help on V4 for this.
>
>I am happy to test it for you please just send me a pointer at your v4
>code.
>
I posted the v4 and CCed you there. So i am little skeptical about the acpi
changes that i have posted. I was checking for a function equivalent
in acpi as of_match_node in DT, to figure out if the iommu_spec.np that
the master device is pointing to is there in the iommu_of_table and based
on that we can decide if to defer the probe. I was seeing iort_scan_node
was its equivalent. But if that is not correct, then last patch has to be reworked.
Anyways will be good to know your feedback on this.
Regards,
Sricharan
^ permalink raw reply
* [PATCH 10/10] drivers: acpi: Handle IOMMU lookup failure with deferred probing or error
From: Sricharan R @ 2016-11-30 0:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480465344-11862-1-git-send-email-sricharan@codeaurora.org>
This is an equivalent to the DT's handling of the iommu master's probe
with deferred probing when the corrsponding iommu is not probed yet.
The lack of a registered IOMMU can be caused by the lack of a driver for
the IOMMU, the IOMMU device probe not having been performed yet, having
been deferred, or having failed.
The first case occurs when the firmware describes the bus master and
IOMMU topology correctly but no device driver exists for the IOMMU yet
or the device driver has not been compiled in. Return NULL, the caller
will configure the device without an IOMMU.
The second and third cases are handled by deferring the probe of the bus
master device which will eventually get reprobed after the IOMMU.
The last case is currently handled by deferring the probe of the bus
master device as well. A mechanism to either configure the bus master
device without an IOMMU or to fail the bus master device probe depending
on whether the IOMMU is optional or mandatory would be a good
enhancement.
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
drivers/acpi/arm64/iort.c | 17 ++++++++++++++++-
drivers/acpi/scan.c | 7 +++++--
drivers/pci/probe.c | 2 +-
include/acpi/acpi_bus.h | 2 +-
include/linux/acpi.h | 7 +++++--
5 files changed, 28 insertions(+), 7 deletions(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 47bace8..18ad4d9 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -537,8 +537,9 @@ static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
return NULL;
ops = iommu_get_instance(iort_fwnode);
+ /* This means that the iommu driver is still not probed */
if (!ops)
- return NULL;
+ return ERR_PTR(-EPROBE_DEFER);
ret = arm_smmu_iort_xlate(dev, streamid, iort_fwnode, ops);
}
@@ -590,12 +591,26 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
while (parent) {
ops = iort_iommu_xlate(dev, parent, streamid);
+ if (IS_ERR_OR_NULL(ops))
+ return ops;
parent = iort_node_get_id(node, &streamid,
IORT_IOMMU_TYPE, i++);
}
}
+ /*
+ * If we have reason to believe the IOMMU driver missed the initial
+ * add_device callback for dev, replay it to get things in order.
+ */
+ if (!IS_ERR_OR_NULL(ops) && ops->add_device &&
+ dev->bus && !dev->iommu_group) {
+ int err = ops->add_device(dev);
+
+ if (err)
+ ops = ERR_PTR(err);
+ }
+
return ops;
}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 80698d3..c80e51e 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1376,7 +1376,7 @@ enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
* @dev: The pointer to the device
* @attr: device dma attributes
*/
-void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr)
+int acpi_dma_configure(struct device *dev, enum dev_dma_attr attr)
{
const struct iommu_ops *iommu;
@@ -1395,13 +1395,16 @@ void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr)
dev->dma_mask = &dev->coherent_dma_mask;
iommu = iort_iommu_configure(dev);
-
+ if (IS_ERR(iommu))
+ return PTR_ERR(iommu);
/*
* Assume dma valid range starts at 0 and covers the whole
* coherent_dma_mask.
*/
arch_setup_dma_ops(dev, 0, dev->coherent_dma_mask + 1, iommu,
attr == DEV_DMA_COHERENT);
+
+ return 0;
}
EXPORT_SYMBOL_GPL(acpi_dma_configure);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 6316cae..e32c7e5 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1739,7 +1739,7 @@ int pci_dma_configure(struct device *dev)
if (attr == DEV_DMA_NOT_SUPPORTED)
dev_warn(dev, "DMA not supported.\n");
else
- acpi_dma_configure(dev, attr);
+ ret = acpi_dma_configure(dev, attr);
}
pci_put_host_bridge_device(bridge);
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 4242c31..9aa762f 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -573,7 +573,7 @@ struct acpi_pci_root {
bool acpi_dma_supported(struct acpi_device *adev);
enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev);
-void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr);
+int acpi_dma_configure(struct device *dev, enum dev_dma_attr attr);
void acpi_dma_deconfigure(struct device *dev);
struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 8d15fc5..0e8d33f 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -765,8 +765,11 @@ static inline enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
return DEV_DMA_NOT_SUPPORTED;
}
-static inline void acpi_dma_configure(struct device *dev,
- enum dev_dma_attr attr) { }
+static inline int acpi_dma_configure(struct device *dev,
+ enum dev_dma_attr attr)
+{
+ return 0;
+}
static inline void acpi_dma_deconfigure(struct device *dev) { }
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related
* [PATCH 09/10] drivers: acpi: Configure acpi devices dma operation at probe time
From: Sricharan R @ 2016-11-30 0:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480465344-11862-1-git-send-email-sricharan@codeaurora.org>
With all the DT based devices getting their dma ops configured
during probe time to have the right iommu setup, let us do the
same for acpi based devices as well.
Configuring DMA ops at probe time will allow deferring device probe when
the IOMMU isn't available yet. The dma_configure for the device is now called
from the generic device_attach callback just before the bus/driver probe
is called. This way, configuring the DMA ops for the device would be called
at the same place for all bus_types, hence the deferred probing mechanism
should work for all buses as well.
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
drivers/acpi/glue.c | 6 ------
drivers/base/dma-mapping.c | 12 ++++++++++++
2 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index f8d6564..458445f 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -168,7 +168,6 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
struct list_head *physnode_list;
unsigned int node_id;
int retval = -EINVAL;
- enum dev_dma_attr attr;
if (has_acpi_companion(dev)) {
if (acpi_dev) {
@@ -225,10 +224,6 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
if (!has_acpi_companion(dev))
ACPI_COMPANION_SET(dev, acpi_dev);
- attr = acpi_get_dma_attr(acpi_dev);
- if (attr != DEV_DMA_NOT_SUPPORTED)
- acpi_dma_configure(dev, attr);
-
acpi_physnode_link_name(physical_node_name, node_id);
retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
physical_node_name);
@@ -250,7 +245,6 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
return 0;
err:
- acpi_dma_deconfigure(dev);
ACPI_COMPANION_SET(dev, NULL);
put_device(dev);
put_device(&acpi_dev->dev);
diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c
index 576fdfb..2ec4dae 100644
--- a/drivers/base/dma-mapping.c
+++ b/drivers/base/dma-mapping.c
@@ -347,17 +347,29 @@ void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags)
* Common configuration to enable DMA API use for a device
*/
#include <linux/pci.h>
+#include <linux/acpi.h>
int dma_configure(struct device *dev)
{
+ struct acpi_device *adev;
+ enum dev_dma_attr attr;
+
if (dev_is_pci(dev))
return pci_dma_configure(dev);
else if (dev->of_node)
return of_dma_configure(dev, dev->of_node);
+ else if (has_acpi_companion(dev)) {
+ adev = to_acpi_device_node(dev->fwnode);
+ attr = acpi_get_dma_attr(adev);
+ if (attr != DEV_DMA_NOT_SUPPORTED)
+ return acpi_dma_configure(dev, attr);
+ }
+
return 0;
}
void dma_deconfigure(struct device *dev)
{
of_dma_deconfigure(dev);
+ acpi_dma_deconfigure(dev);
}
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related
* [PATCH 08/10] iommu/arm-smmu: Clean up early-probing workarounds
From: Sricharan R @ 2016-11-30 0:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480465344-11862-1-git-send-email-sricharan@codeaurora.org>
From: Robin Murphy <robin.murphy@arm.com>
Now that the appropriate ordering is enforced via profe-deferral of
masters in core code, rip it all out and bask in the simplicity.
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
[sricharan: Rebased on top of ACPI IORT SMMU series]
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
[v4] Removed arm_smmu_acpi_init function and let the
module_platform_driver to take care of the driver
registration.
drivers/iommu/arm-smmu-v3.c | 35 ++--------------------------
drivers/iommu/arm-smmu.c | 56 ++++++++-------------------------------------
2 files changed, 11 insertions(+), 80 deletions(-)
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index d22c428..257a6a3 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -2729,40 +2729,9 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
.probe = arm_smmu_device_probe,
.remove = arm_smmu_device_remove,
};
+module_platform_driver(arm_smmu_driver);
-static int __init arm_smmu_init(void)
-{
- static bool registered;
- int ret = 0;
-
- if (!registered) {
- ret = platform_driver_register(&arm_smmu_driver);
- registered = !ret;
- }
- return ret;
-}
-
-static void __exit arm_smmu_exit(void)
-{
- return platform_driver_unregister(&arm_smmu_driver);
-}
-
-subsys_initcall(arm_smmu_init);
-module_exit(arm_smmu_exit);
-
-static int __init arm_smmu_of_init(struct device_node *np)
-{
- int ret = arm_smmu_init();
-
- if (ret)
- return ret;
-
- if (!of_platform_device_create(np, NULL, platform_bus_type.dev_root))
- return -ENODEV;
-
- return 0;
-}
-IOMMU_OF_DECLARE(arm_smmuv3, "arm,smmu-v3", arm_smmu_of_init);
+IOMMU_OF_DECLARE(arm_smmuv3, "arm,smmu-v3", NULL);
#ifdef CONFIG_ACPI
static int __init acpi_smmu_v3_init(struct acpi_table_header *table)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 8e66b16..eaa8f44 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -2127,57 +2127,19 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
.probe = arm_smmu_device_probe,
.remove = arm_smmu_device_remove,
};
-
-static int __init arm_smmu_init(void)
-{
- static bool registered;
- int ret = 0;
-
- if (!registered) {
- ret = platform_driver_register(&arm_smmu_driver);
- registered = !ret;
- }
- return ret;
-}
-
-static void __exit arm_smmu_exit(void)
-{
- return platform_driver_unregister(&arm_smmu_driver);
-}
-
-subsys_initcall(arm_smmu_init);
-module_exit(arm_smmu_exit);
-
-static int __init arm_smmu_of_init(struct device_node *np)
-{
- int ret = arm_smmu_init();
-
- if (ret)
- return ret;
-
- if (!of_platform_device_create(np, NULL, platform_bus_type.dev_root))
- return -ENODEV;
-
- return 0;
-}
-IOMMU_OF_DECLARE(arm_smmuv1, "arm,smmu-v1", arm_smmu_of_init);
-IOMMU_OF_DECLARE(arm_smmuv2, "arm,smmu-v2", arm_smmu_of_init);
-IOMMU_OF_DECLARE(arm_mmu400, "arm,mmu-400", arm_smmu_of_init);
-IOMMU_OF_DECLARE(arm_mmu401, "arm,mmu-401", arm_smmu_of_init);
-IOMMU_OF_DECLARE(arm_mmu500, "arm,mmu-500", arm_smmu_of_init);
-IOMMU_OF_DECLARE(cavium_smmuv2, "cavium,smmu-v2", arm_smmu_of_init);
+module_platform_driver(arm_smmu_driver);
#ifdef CONFIG_ACPI
-static int __init arm_smmu_acpi_init(struct acpi_table_header *table)
-{
- if (iort_node_match(ACPI_IORT_NODE_SMMU))
- return arm_smmu_init();
-
- return 0;
-}
-IORT_ACPI_DECLARE(arm_smmu, ACPI_SIG_IORT, arm_smmu_acpi_init);
+IORT_ACPI_DECLARE(arm_smmu, ACPI_SIG_IORT, NULL);
#endif
+IOMMU_OF_DECLARE(arm_smmuv1, "arm,smmu-v1", NULL);
+IOMMU_OF_DECLARE(arm_smmuv2, "arm,smmu-v2", NULL);
+IOMMU_OF_DECLARE(arm_mmu400, "arm,mmu-400", NULL);
+IOMMU_OF_DECLARE(arm_mmu401, "arm,mmu-401", NULL);
+IOMMU_OF_DECLARE(arm_mmu500, "arm,mmu-500", NULL);
+IOMMU_OF_DECLARE(cavium_smmuv2, "cavium,smmu-v2", NULL);
+
MODULE_DESCRIPTION("IOMMU API for ARM architected SMMU implementations");
MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>");
MODULE_LICENSE("GPL v2");
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related
* [PATCH 07/10] arm64: dma-mapping: Remove the notifier trick to handle early setting of dma_ops
From: Sricharan R @ 2016-11-30 0:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480465344-11862-1-git-send-email-sricharan@codeaurora.org>
With arch_setup_dma_ops now being called late during device's probe after the
device's iommu is probed, the notifier trick required to handle the early
setup of dma_ops before the iommu group gets created is not required.
So removing the notifier's here.
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
[rm: clean up even more]
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---
arch/arm64/mm/dma-mapping.c | 132 ++++----------------------------------------
1 file changed, 12 insertions(+), 120 deletions(-)
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index aa6c8f8..401f79a 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -800,140 +800,32 @@ static void __iommu_unmap_sg_attrs(struct device *dev,
.mapping_error = iommu_dma_mapping_error,
};
-/*
- * TODO: Right now __iommu_setup_dma_ops() gets called too early to do
- * everything it needs to - the device is only partially created and the
- * IOMMU driver hasn't seen it yet, so it can't have a group. Thus we
- * need this delayed attachment dance. Once IOMMU probe ordering is sorted
- * to move the arch_setup_dma_ops() call later, all the notifier bits below
- * become unnecessary, and will go away.
- */
-struct iommu_dma_notifier_data {
- struct list_head list;
- struct device *dev;
- const struct iommu_ops *ops;
- u64 dma_base;
- u64 size;
-};
-static LIST_HEAD(iommu_dma_masters);
-static DEFINE_MUTEX(iommu_dma_notifier_lock);
-
-static bool do_iommu_attach(struct device *dev, const struct iommu_ops *ops,
- u64 dma_base, u64 size)
-{
- struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
-
- /*
- * If the IOMMU driver has the DMA domain support that we require,
- * then the IOMMU core will have already configured a group for this
- * device, and allocated the default domain for that group.
- */
- if (!domain || iommu_dma_init_domain(domain, dma_base, size, dev)) {
- pr_warn("Failed to set up IOMMU for device %s; retaining platform DMA ops\n",
- dev_name(dev));
- return false;
- }
-
- dev->archdata.dma_ops = &iommu_dma_ops;
- return true;
-}
-
-static void queue_iommu_attach(struct device *dev, const struct iommu_ops *ops,
- u64 dma_base, u64 size)
-{
- struct iommu_dma_notifier_data *iommudata;
-
- iommudata = kzalloc(sizeof(*iommudata), GFP_KERNEL);
- if (!iommudata)
- return;
-
- iommudata->dev = dev;
- iommudata->ops = ops;
- iommudata->dma_base = dma_base;
- iommudata->size = size;
-
- mutex_lock(&iommu_dma_notifier_lock);
- list_add(&iommudata->list, &iommu_dma_masters);
- mutex_unlock(&iommu_dma_notifier_lock);
-}
-
-static int __iommu_attach_notifier(struct notifier_block *nb,
- unsigned long action, void *data)
-{
- struct iommu_dma_notifier_data *master, *tmp;
-
- if (action != BUS_NOTIFY_BIND_DRIVER)
- return 0;
-
- mutex_lock(&iommu_dma_notifier_lock);
- list_for_each_entry_safe(master, tmp, &iommu_dma_masters, list) {
- if (data == master->dev && do_iommu_attach(master->dev,
- master->ops, master->dma_base, master->size)) {
- list_del(&master->list);
- kfree(master);
- break;
- }
- }
- mutex_unlock(&iommu_dma_notifier_lock);
- return 0;
-}
-
-static int __init register_iommu_dma_ops_notifier(struct bus_type *bus)
-{
- struct notifier_block *nb = kzalloc(sizeof(*nb), GFP_KERNEL);
- int ret;
-
- if (!nb)
- return -ENOMEM;
-
- nb->notifier_call = __iommu_attach_notifier;
-
- ret = bus_register_notifier(bus, nb);
- if (ret) {
- pr_warn("Failed to register DMA domain notifier; IOMMU DMA ops unavailable on bus '%s'\n",
- bus->name);
- kfree(nb);
- }
- return ret;
-}
-
static int __init __iommu_dma_init(void)
{
- int ret;
-
- ret = iommu_dma_init();
- if (!ret)
- ret = register_iommu_dma_ops_notifier(&platform_bus_type);
- if (!ret)
- ret = register_iommu_dma_ops_notifier(&amba_bustype);
-#ifdef CONFIG_PCI
- if (!ret)
- ret = register_iommu_dma_ops_notifier(&pci_bus_type);
-#endif
- return ret;
+ return iommu_dma_init();
}
arch_initcall(__iommu_dma_init);
static void __iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
const struct iommu_ops *ops)
{
- struct iommu_group *group;
+ struct iommu_domain *domain;
if (!ops)
return;
+
/*
- * TODO: As a concession to the future, we're ready to handle being
- * called both early and late (i.e. after bus_add_device). Once all
- * the platform bus code is reworked to call us late and the notifier
- * junk above goes away, move the body of do_iommu_attach here.
+ * The IOMMU core code allocates the default DMA domain, which the
+ * underlying IOMMU driver needs to support via the dma-iommu layer.
*/
- group = iommu_group_get(dev);
- if (group) {
- do_iommu_attach(dev, ops, dma_base, size);
- iommu_group_put(group);
- } else {
- queue_iommu_attach(dev, ops, dma_base, size);
+ domain = iommu_get_domain_for_dev(dev);
+ if (!domain || iommu_dma_init_domain(domain, dma_base, size, dev)) {
+ pr_warn("Failed to set up IOMMU for device %s; retaining platform DMA ops\n",
+ dev_name(dev));
+ return;
}
+
+ dev->archdata.dma_ops = &iommu_dma_ops;
}
void arch_teardown_dma_ops(struct device *dev)
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related
* [PATCH 06/10] iommu: of: Handle IOMMU lookup failure with deferred probing or error
From: Sricharan R @ 2016-11-30 0:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480465344-11862-1-git-send-email-sricharan@codeaurora.org>
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Failures to look up an IOMMU when parsing the DT iommus property need to
be handled separately from the .of_xlate() failures to support deferred
probing.
The lack of a registered IOMMU can be caused by the lack of a driver for
the IOMMU, the IOMMU device probe not having been performed yet, having
been deferred, or having failed.
The first case occurs when the device tree describes the bus master and
IOMMU topology correctly but no device driver exists for the IOMMU yet
or the device driver has not been compiled in. Return NULL, the caller
will configure the device without an IOMMU.
The second and third cases are handled by deferring the probe of the bus
master device which will eventually get reprobed after the IOMMU.
The last case is currently handled by deferring the probe of the bus
master device as well. A mechanism to either configure the bus master
device without an IOMMU or to fail the bus master device probe depending
on whether the IOMMU is optional or mandatory would be a good
enhancement.
Signed-off-by: Laurent Pichart <laurent.pinchart+renesas@ideasonboard.com>
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
[rm: massive PCI hacks]
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---
drivers/base/dma-mapping.c | 4 ++--
drivers/iommu/dma-iommu.c | 1 +
drivers/iommu/of_iommu.c | 5 +++--
drivers/of/device.c | 9 +++++++--
drivers/pci/probe.c | 6 ++++--
include/linux/of_device.h | 9 ++++++---
include/linux/pci.h | 4 ++--
7 files changed, 25 insertions(+), 13 deletions(-)
diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c
index b2a5629..576fdfb 100644
--- a/drivers/base/dma-mapping.c
+++ b/drivers/base/dma-mapping.c
@@ -351,9 +351,9 @@ void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags)
int dma_configure(struct device *dev)
{
if (dev_is_pci(dev))
- pci_dma_configure(dev);
+ return pci_dma_configure(dev);
else if (dev->of_node)
- of_dma_configure(dev, dev->of_node);
+ return of_dma_configure(dev, dev->of_node);
return 0;
}
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index c5ab866..d2a7a46 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -148,6 +148,7 @@ int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base,
base_pfn = max_t(unsigned long, 1, base >> order);
end_pfn = (base + size - 1) >> order;
+ dev_info(dev, "0x%llx 0x%llx, 0x%llx 0x%llx, 0x%llx 0x%llx\n", base, size, domain->geometry.aperture_start, domain->geometry.aperture_end, *dev->dma_mask, dev->coherent_dma_mask);
/* Check the domain allows at least some access to the device... */
if (domain->geometry.force_aperture) {
if (base > domain->geometry.aperture_end ||
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index 349bd1d..9529d6c 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -23,6 +23,7 @@
#include <linux/of.h>
#include <linux/of_iommu.h>
#include <linux/of_pci.h>
+#include <linux/pci.h>
#include <linux/slab.h>
static const struct of_device_id __iommu_of_table_sentinel
@@ -223,7 +224,7 @@ const struct iommu_ops *of_iommu_configure(struct device *dev,
ops = ERR_PTR(err);
}
- return IS_ERR(ops) ? NULL : ops;
+ return ops;
}
static int __init of_iommu_init(void)
@@ -234,7 +235,7 @@ static int __init of_iommu_init(void)
for_each_matching_node_and_match(np, matches, &match) {
const of_iommu_init_fn init_fn = match->data;
- if (init_fn(np))
+ if (init_fn && init_fn(np))
pr_err("Failed to initialise IOMMU %s\n",
of_node_full_name(np));
}
diff --git a/drivers/of/device.c b/drivers/of/device.c
index 1c843e2..d58595c 100644
--- a/drivers/of/device.c
+++ b/drivers/of/device.c
@@ -82,7 +82,7 @@ int of_device_add(struct platform_device *ofdev)
* can use a platform bus notifier and handle BUS_NOTIFY_ADD_DEVICE events
* to fix up DMA configuration.
*/
-void of_dma_configure(struct device *dev, struct device_node *np)
+int of_dma_configure(struct device *dev, struct device_node *np)
{
u64 dma_addr, paddr, size;
int ret;
@@ -107,7 +107,7 @@ void of_dma_configure(struct device *dev, struct device_node *np)
ret = of_dma_get_range(np, &dma_addr, &paddr, &size);
if (ret < 0) {
dma_addr = offset = 0;
- size = dev->coherent_dma_mask + 1;
+ size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1);
} else {
offset = PFN_DOWN(paddr - dma_addr);
dev_dbg(dev, "dma_pfn_offset(%#08lx)\n", offset);
@@ -129,10 +129,15 @@ void of_dma_configure(struct device *dev, struct device_node *np)
coherent ? " " : " not ");
iommu = of_iommu_configure(dev, np);
+ if (IS_ERR(iommu))
+ return PTR_ERR(iommu);
+
dev_dbg(dev, "device is%sbehind an iommu\n",
iommu ? " " : " not ");
arch_setup_dma_ops(dev, dma_addr, size, iommu, coherent);
+
+ return 0;
}
EXPORT_SYMBOL_GPL(of_dma_configure);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 04af770..6316cae 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1724,13 +1724,14 @@ static void pci_set_msi_domain(struct pci_dev *dev)
* Function to update PCI devices's DMA configuration using the same
* info from the OF node or ACPI node of host bridge's parent (if any).
*/
-void pci_dma_configure(struct device *dev)
+int pci_dma_configure(struct device *dev)
{
struct device *bridge = pci_get_host_bridge_device(to_pci_dev(dev));
+ int ret = 0;
if (IS_ENABLED(CONFIG_OF) &&
bridge->parent && bridge->parent->of_node) {
- of_dma_configure(dev, bridge->parent->of_node);
+ ret = of_dma_configure(dev, bridge->parent->of_node);
} else if (has_acpi_companion(bridge)) {
struct acpi_device *adev = to_acpi_device_node(bridge->fwnode);
enum dev_dma_attr attr = acpi_get_dma_attr(adev);
@@ -1742,6 +1743,7 @@ void pci_dma_configure(struct device *dev)
}
pci_put_host_bridge_device(bridge);
+ return ret;
}
void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
diff --git a/include/linux/of_device.h b/include/linux/of_device.h
index d20a31a..6dca65c 100644
--- a/include/linux/of_device.h
+++ b/include/linux/of_device.h
@@ -55,7 +55,7 @@ static inline struct device_node *of_cpu_device_node_get(int cpu)
return of_node_get(cpu_dev->of_node);
}
-void of_dma_configure(struct device *dev, struct device_node *np);
+int of_dma_configure(struct device *dev, struct device_node *np);
void of_dma_deconfigure(struct device *dev);
#else /* CONFIG_OF */
@@ -99,8 +99,11 @@ static inline struct device_node *of_cpu_device_node_get(int cpu)
{
return NULL;
}
-static inline void of_dma_configure(struct device *dev, struct device_node *np)
-{}
+
+static inline int of_dma_configure(struct device *dev, struct device_node *np)
+{
+ return 0;
+}
static inline void of_dma_deconfigure(struct device *dev)
{}
#endif /* CONFIG_OF */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index d04f651..989ca44 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -870,7 +870,7 @@ struct resource *pci_find_parent_resource(const struct pci_dev *dev,
#define dev_is_pf(d) ((dev_is_pci(d) ? to_pci_dev(d)->is_physfn : false))
#define dev_num_vf(d) ((dev_is_pci(d) ? pci_num_vf(to_pci_dev(d)) : 0))
-void pci_dma_configure(struct device *dev);
+int pci_dma_configure(struct device *dev);
/* Generic PCI functions exported to card drivers */
@@ -1604,7 +1604,7 @@ static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus,
#define dev_is_pf(d) (false)
#define dev_num_vf(d) (0)
-static inline void pci_dma_configure(struct device *dev) { }
+static inline int pci_dma_configure(struct device *dev) { return 0; }
#endif /* CONFIG_PCI */
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related
* [PATCH 05/10] drivers: platform: Configure dma operations at probe time
From: Sricharan R @ 2016-11-30 0:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480465344-11862-1-git-send-email-sricharan@codeaurora.org>
Configuring DMA ops at probe time will allow deferring device probe when
the IOMMU isn't available yet. The dma_configure for the device is now called
from the generic device_attach callback just before the bus/driver probe
is called. This way, configuring the DMA ops for the device would be called
at the same place for all bus_types, hence the deferred probing mechanism
should work for all buses as well.
pci_bus_add_devices (platform/amba)(_device_create/driver_register)
| |
pci_bus_add_device (device_add/driver_register)
| |
device_attach device_initial_probe
| |
__device_attach_driver __device_attach_driver
|
driver_probe_device
|
really_probe
|
dma_configure
Similarly on the device/driver_unregister path __device_release_driver is
called which inturn calls dma_deconfigure.
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
[rm: PCI hacks]
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---
drivers/base/dd.c | 10 ++++++++++
drivers/base/dma-mapping.c | 20 ++++++++++++++++++++
drivers/of/platform.c | 5 +----
drivers/pci/probe.c | 15 +++++++--------
include/linux/dma-mapping.h | 3 +++
include/linux/pci.h | 5 +++++
6 files changed, 46 insertions(+), 12 deletions(-)
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index d76cd97..6c0a885 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -19,6 +19,7 @@
#include <linux/device.h>
#include <linux/delay.h>
+#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/wait.h>
@@ -351,6 +352,10 @@ static int really_probe(struct device *dev, struct device_driver *drv)
if (ret)
goto pinctrl_bind_failed;
+ ret = dma_configure(dev);
+ if (ret)
+ goto dma_failed;
+
if (driver_sysfs_add(dev)) {
printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
__func__, dev_name(dev));
@@ -412,6 +417,8 @@ static int really_probe(struct device *dev, struct device_driver *drv)
goto done;
probe_failed:
+ dma_deconfigure(dev);
+dma_failed:
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_DRIVER_NOT_BOUND, dev);
@@ -796,6 +803,9 @@ static void __device_release_driver(struct device *dev)
dev->bus->remove(dev);
else if (drv->remove)
drv->remove(dev);
+
+ dma_deconfigure(dev);
+
devres_release_all(dev);
dev->driver = NULL;
dev_set_drvdata(dev, NULL);
diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c
index 8f8b68c..b2a5629 100644
--- a/drivers/base/dma-mapping.c
+++ b/drivers/base/dma-mapping.c
@@ -10,6 +10,7 @@
#include <linux/dma-mapping.h>
#include <linux/export.h>
#include <linux/gfp.h>
+#include <linux/of_device.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
@@ -341,3 +342,22 @@ void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags)
vunmap(cpu_addr);
}
#endif
+
+/*
+ * Common configuration to enable DMA API use for a device
+ */
+#include <linux/pci.h>
+
+int dma_configure(struct device *dev)
+{
+ if (dev_is_pci(dev))
+ pci_dma_configure(dev);
+ else if (dev->of_node)
+ of_dma_configure(dev, dev->of_node);
+ return 0;
+}
+
+void dma_deconfigure(struct device *dev)
+{
+ of_dma_deconfigure(dev);
+}
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index fdb6f8e..b0a2f9e 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
+#include <linux/of_iommu.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
@@ -183,11 +184,9 @@ static struct platform_device *of_platform_device_create_pdata(
dev->dev.bus = &platform_bus_type;
dev->dev.platform_data = platform_data;
- of_dma_configure(&dev->dev, dev->dev.of_node);
of_msi_configure(&dev->dev, dev->dev.of_node);
if (of_device_add(dev) != 0) {
- of_dma_deconfigure(&dev->dev);
platform_device_put(dev);
goto err_clear_flag;
}
@@ -245,7 +244,6 @@ static struct amba_device *of_amba_device_create(struct device_node *node,
dev_set_name(&dev->dev, "%s", bus_id);
else
of_device_make_bus_id(&dev->dev);
- of_dma_configure(&dev->dev, dev->dev.of_node);
/* Allow the HW Peripheral ID to be overridden */
prop = of_get_property(node, "arm,primecell-periphid", NULL);
@@ -539,7 +537,6 @@ static int of_platform_device_destroy(struct device *dev, void *data)
amba_device_unregister(to_amba_device(dev));
#endif
- of_dma_deconfigure(dev);
of_node_clear_flag(dev->of_node, OF_POPULATED);
of_node_clear_flag(dev->of_node, OF_POPULATED_BUS);
return 0;
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index c29e07a..04af770 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1719,26 +1719,26 @@ static void pci_set_msi_domain(struct pci_dev *dev)
/**
* pci_dma_configure - Setup DMA configuration
- * @dev: ptr to pci_dev struct of the PCI device
+ * @dev: ptr to device struct of the PCI device
*
* Function to update PCI devices's DMA configuration using the same
* info from the OF node or ACPI node of host bridge's parent (if any).
*/
-static void pci_dma_configure(struct pci_dev *dev)
+void pci_dma_configure(struct device *dev)
{
- struct device *bridge = pci_get_host_bridge_device(dev);
+ struct device *bridge = pci_get_host_bridge_device(to_pci_dev(dev));
if (IS_ENABLED(CONFIG_OF) &&
- bridge->parent && bridge->parent->of_node) {
- of_dma_configure(&dev->dev, bridge->parent->of_node);
+ bridge->parent && bridge->parent->of_node) {
+ of_dma_configure(dev, bridge->parent->of_node);
} else if (has_acpi_companion(bridge)) {
struct acpi_device *adev = to_acpi_device_node(bridge->fwnode);
enum dev_dma_attr attr = acpi_get_dma_attr(adev);
if (attr == DEV_DMA_NOT_SUPPORTED)
- dev_warn(&dev->dev, "DMA not supported.\n");
+ dev_warn(dev, "DMA not supported.\n");
else
- acpi_dma_configure(&dev->dev, attr);
+ acpi_dma_configure(dev, attr);
}
pci_put_host_bridge_device(bridge);
@@ -1757,7 +1757,6 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
dev->dev.dma_mask = &dev->dma_mask;
dev->dev.dma_parms = &dev->dma_parms;
dev->dev.coherent_dma_mask = 0xffffffffull;
- pci_dma_configure(dev);
pci_set_dma_max_seg_size(dev, 65536);
pci_set_dma_seg_boundary(dev, 0xffffffff);
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index 08528af..6f3e6ca 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -702,6 +702,9 @@ void *dma_mark_declared_memory_occupied(struct device *dev,
}
#endif /* CONFIG_HAVE_GENERIC_DMA_COHERENT */
+int dma_configure(struct device *dev);
+void dma_deconfigure(struct device *dev);
+
/*
* Managed DMA API
*/
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 0e49f70..d04f651 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -870,6 +870,8 @@ struct resource *pci_find_parent_resource(const struct pci_dev *dev,
#define dev_is_pf(d) ((dev_is_pci(d) ? to_pci_dev(d)->is_physfn : false))
#define dev_num_vf(d) ((dev_is_pci(d) ? pci_num_vf(to_pci_dev(d)) : 0))
+void pci_dma_configure(struct device *dev);
+
/* Generic PCI functions exported to card drivers */
enum pci_lost_interrupt_reason {
@@ -1601,6 +1603,9 @@ static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus,
#define dev_is_pci(d) (false)
#define dev_is_pf(d) (false)
#define dev_num_vf(d) (0)
+
+static inline void pci_dma_configure(struct device *dev) { }
+
#endif /* CONFIG_PCI */
/* Include architecture-dependent settings and functions */
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related
* [PATCH 04/10] of: dma: Make of_dma_deconfigure() public
From: Sricharan R @ 2016-11-30 0:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480465344-11862-1-git-send-email-sricharan@codeaurora.org>
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
As part of moving DMA initializing to probe time the
of_dma_deconfigure() function will need to be called from different
source files. Make it public and move it to drivers/of/device.c where
the of_dma_configure() function is.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
drivers/of/device.c | 12 ++++++++++++
drivers/of/platform.c | 5 -----
include/linux/of_device.h | 3 +++
3 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/drivers/of/device.c b/drivers/of/device.c
index d9898d9..1c843e2 100644
--- a/drivers/of/device.c
+++ b/drivers/of/device.c
@@ -136,6 +136,18 @@ void of_dma_configure(struct device *dev, struct device_node *np)
}
EXPORT_SYMBOL_GPL(of_dma_configure);
+/**
+ * of_dma_deconfigure - Clean up DMA configuration
+ * @dev: Device for which to clean up DMA configuration
+ *
+ * Clean up all configuration performed by of_dma_configure_ops() and free all
+ * resources that have been allocated.
+ */
+void of_dma_deconfigure(struct device *dev)
+{
+ arch_teardown_dma_ops(dev);
+}
+
int of_device_register(struct platform_device *pdev)
{
device_initialize(&pdev->dev);
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index e4bf07d..fdb6f8e 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -155,11 +155,6 @@ struct platform_device *of_device_alloc(struct device_node *np,
}
EXPORT_SYMBOL(of_device_alloc);
-static void of_dma_deconfigure(struct device *dev)
-{
- arch_teardown_dma_ops(dev);
-}
-
/**
* of_platform_device_create_pdata - Alloc, initialize and register an of_device
* @np: pointer to node to create device for
diff --git a/include/linux/of_device.h b/include/linux/of_device.h
index cc7dd687..d20a31a 100644
--- a/include/linux/of_device.h
+++ b/include/linux/of_device.h
@@ -56,6 +56,7 @@ static inline struct device_node *of_cpu_device_node_get(int cpu)
}
void of_dma_configure(struct device *dev, struct device_node *np);
+void of_dma_deconfigure(struct device *dev);
#else /* CONFIG_OF */
static inline int of_driver_match_device(struct device *dev,
@@ -100,6 +101,8 @@ static inline struct device_node *of_cpu_device_node_get(int cpu)
}
static inline void of_dma_configure(struct device *dev, struct device_node *np)
{}
+static inline void of_dma_deconfigure(struct device *dev)
+{}
#endif /* CONFIG_OF */
#endif /* _LINUX_OF_DEVICE_H */
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox