* Re: [PATCH] of: overlay: fix memory leak of ovcs on error exit path
From: Frank Rowand @ 2017-11-30 15:01 UTC (permalink / raw)
To: Colin Ian King, Pantelis Antoniou, Rob Herring, devicetree
Cc: kernel-janitors, linux-kernel
In-Reply-To: <75d7d1c8-8a19-1a4c-0796-7cf69fdebe6d@gmail.com>
On 11/30/17 08:37, Frank Rowand wrote:
> Hi Colin, Rob,
>
> On 11/30/17 07:18, Colin Ian King wrote:
>> On 30/11/17 12:14, Frank Rowand wrote:
>>> On 11/29/17 14:17, Colin King wrote:
>>>> From: Colin Ian King <colin.king@canonical.com>
>>>>
>>>> Currently if the call to of_resolve_phandles fails then then ovcs
>>>> is not kfree'd on the error exit path. Rather than try and make
>>>> the clean up exit path more convoluted, fix this by just kfree'ing
>>>> ovcs at the point of error detection and exit via the same exit
>>>> path.
>>>>
>>>> Detected by CoverityScan, CID#1462296 ("Resource Leak")
>>>>
>>>> Fixes: f948d6d8b792 ("of: overlay: avoid race condition between applying multiple overlays")
>>>> Signed-off-by: Colin Ian King <colin.king@canonical.com>
>>>> ---
>>>> drivers/of/overlay.c | 4 +++-
>>>> 1 file changed, 3 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
>>>> index 53bc9e3f0b98..6c8efe7d8cbb 100644
>>>> --- a/drivers/of/overlay.c
>>>> +++ b/drivers/of/overlay.c
>>>> @@ -708,8 +708,10 @@ int of_overlay_apply(struct device_node *tree, int *ovcs_id)
>>>> of_overlay_mutex_lock();
>>>>
>>>> ret = of_resolve_phandles(tree);
>>>> - if (ret)
>>>> + if (ret) {
>>>> + kfree(ovcs);
>>>> goto err_overlay_unlock;
>>>> + }
>>>>
>>>> mutex_lock(&of_mutex);
>>>>
>>>>
>>>
>>> False coverity warning. ovcs is freed in free_overlay_changeset().
>>>
>>
>> The error exit path is via err_overlay_unlock:
>>
>> err_overlay_unlock:
>> of_overlay_mutex_unlock();
>>
>> out:
>> pr_debug("%s() err=%d\n", __func__, ret);
>>
>> return ret;
>>
>> ..so there is no call to free_overlay_changeset there.
>>
>> Colin
>>
>
> OK, I was looking at 4.15-rc1. You must be looking at a later version where
> "[PATCH 1/2] of: overlay: Fix cleanup order in of_overlay_apply()" has been
> applied. Thanks for providing the extra details about the exit path so I
> could see that.
>
> Rob, I think that the fix for cleanup order was not the best way to fix that
> problem. A better method would have been to move "mutex_lock(&of_mutex);"
> up 5 lines, to just before calling of_reserve_phandles().
It is getting late (midnight my time), so I really should revisit this all
tomorrow. My last comment ("move ... up 5 lines") is probably wrong.
I'll look at this after some sleep.
> The problem
> found by coverity was caused by the "Fix cleanup order" patch.
>
> I can create that alternate fix if you would like, but I am traveling
> right now and don't want to submit a patch without boot testing, so
> there will be a slight delay.
>
> -Frank
^ permalink raw reply
* Re: [RFC PATCH 0/3] pinctrl: sunxi: Add DT-based generic pinctrl driver
From: Linus Walleij @ 2017-11-30 15:20 UTC (permalink / raw)
To: Andre Przywara, Rob Herring
Cc: Maxime Ripard, Chen-Yu Tsai, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
Mark Rutland,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Linux ARM, Arnd Bergmann, Icenowy Zheng,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
In-Reply-To: <54ecfdf7-cf4a-3eae-2661-47fa668a6066-5wv7dgnIgG8@public.gmane.org>
On Fri, Nov 24, 2017 at 1:05 PM, Andre Przywara <andre.przywara-5wv7dgnIgG8@public.gmane.org> wrote:
> On 24/11/17 10:28, Linus Walleij wrote:
>> The DT maintainers have been pretty clear on that they don't like
>> using the the DT as a generic fit-all information dump. They
>> prefer to look up hardware data from per-soc compatible strings.
(...)
> I am just a bit worried that with Allwinner recently playing the SKU
> game we end up with tons of tables for only slightly different SoCs (see
> the H3 and H5, for instance). And with single image kernels we pile up
> quite some *data* in each kernel, which is of little interest for
> everyone else.
So what you are saying is that you want to use the DTS for
data dumping and what I'm saying is that the DT maintainers
do not like that stance.
They will have to speak on the issue directly before we continue
I think.
I have been getting a *LOT* of pushback to putting large amounts
of data and configuration in the DTS recently, so IIUC that is something
they simply don't like, probably for good reasons.
C.f:
https://www.spinics.net/lists/dri-devel/msg150321.html
> Also my understanding is that the actual Allwinner pin controller IP
> (register map) is very much the same across all SoCs. Mostly the only
> difference is the mapping between pins and mux functions, which we
> express in the DT already anyway (in the subnodes). And this is really a
> poster book example of what DT should be doing: express the specific
> mappings of a particular implementation. I don't see why this would need
> to be per-board only, if we can pull this up to the SoC level.
It's not me you need to sell this point.
You need to sell it to the DT maintainers.
Yours,
Linus Walleij
^ permalink raw reply
* Re: [PATCH v3 4/4] DTS: Pandora: fix panel compatibility string
From: Tony Lindgren @ 2017-11-30 15:24 UTC (permalink / raw)
To: H. Nikolaus Schaller
Cc: Tomi Valkeinen, Thierry Reding, David Airlie, Rob Herring,
Mark Rutland, Benoît Cousson, Russell King,
Bartlomiej Zolnierkiewicz, Laurent Pinchart, Julia Lawall,
Sean Paul, dri-devel, DTML, Linux Kernel Mailing List, linux-omap,
Linux ARM, linux-fbdev, Discussions about the Letux Kernel
In-Reply-To: <4EE1E298-6461-48FF-977C-958DD16AD83A@goldelico.com>
* H. Nikolaus Schaller <hns@goldelico.com> [171128 18:35]:
> Hi,
>
> > Am 28.11.2017 um 17:18 schrieb Tony Lindgren <tony@atomide.com>:
> >
> > * H. Nikolaus Schaller <hns@goldelico.com> [171128 16:17]:
> >> Hi Tony,
> >>
> >>> Am 28.11.2017 um 17:04 schrieb Tony Lindgren <tony@atomide.com>:
> >>>
> >>> * H. Nikolaus Schaller <hns@goldelico.com> [171128 15:52]:
> >>>> We can remove the unnecessary "omapdss," prefix because
> >>>> the omapdrm driver takes care of it when matching with
> >>>> the driver table.
> >>>
> >>> So is this needed as a fix or is this another clean-up?
> >>>
> >>> So is this is really needed as a fix?
> >>
> >> Hm. How do you differentiate between "fix" and "cleanup"?
> >> Maybe it is more a wording than a content issue...
> >>
> >> For me it is a "fix" because it is semantically wrong to have
> >> a prefix where it is not needed. And "fixing" it changes the
> >> compiler output by 8 bytes.
> >
> > How about let's call it a "typo fix" then? :)
>
> Well, it is not really a typo.
Well what if the stable people pick it into earlier stable series
based on the word fix in the subject? That has happened before.
I suggest you update the dts patches to use wording like
"update compatible to use new naming" or something similar.
Regards,
Tony
^ permalink raw reply
* Re: [PATCH] of: overlay: fix memory leak of ovcs on error exit path
From: Rob Herring @ 2017-11-30 15:26 UTC (permalink / raw)
To: Frank Rowand
Cc: Colin Ian King, Pantelis Antoniou, devicetree@vger.kernel.org,
kernel-janitors, linux-kernel@vger.kernel.org
In-Reply-To: <788fe2e4-03b2-6f9d-f5dd-5bdf0c48892f@gmail.com>
On Thu, Nov 30, 2017 at 9:01 AM, Frank Rowand <frowand.list@gmail.com> wrote:
> On 11/30/17 08:37, Frank Rowand wrote:
>> Hi Colin, Rob,
>>
>> On 11/30/17 07:18, Colin Ian King wrote:
>>> On 30/11/17 12:14, Frank Rowand wrote:
>>>> On 11/29/17 14:17, Colin King wrote:
>>>>> From: Colin Ian King <colin.king@canonical.com>
>>>>>
>>>>> Currently if the call to of_resolve_phandles fails then then ovcs
>>>>> is not kfree'd on the error exit path. Rather than try and make
>>>>> the clean up exit path more convoluted, fix this by just kfree'ing
>>>>> ovcs at the point of error detection and exit via the same exit
>>>>> path.
>>>>>
>>>>> Detected by CoverityScan, CID#1462296 ("Resource Leak")
>>>>>
>>>>> Fixes: f948d6d8b792 ("of: overlay: avoid race condition between applying multiple overlays")
>>>>> Signed-off-by: Colin Ian King <colin.king@canonical.com>
>>>>> ---
>>>>> drivers/of/overlay.c | 4 +++-
>>>>> 1 file changed, 3 insertions(+), 1 deletion(-)
>>>>>
>>>>> diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
>>>>> index 53bc9e3f0b98..6c8efe7d8cbb 100644
>>>>> --- a/drivers/of/overlay.c
>>>>> +++ b/drivers/of/overlay.c
>>>>> @@ -708,8 +708,10 @@ int of_overlay_apply(struct device_node *tree, int *ovcs_id)
>>>>> of_overlay_mutex_lock();
>>>>>
>>>>> ret = of_resolve_phandles(tree);
>>>>> - if (ret)
>>>>> + if (ret) {
>>>>> + kfree(ovcs);
>>>>> goto err_overlay_unlock;
>>>>> + }
>>>>>
>>>>> mutex_lock(&of_mutex);
>>>>>
>>>>>
>>>>
>>>> False coverity warning. ovcs is freed in free_overlay_changeset().
>>>>
>>>
>>> The error exit path is via err_overlay_unlock:
>>>
>>> err_overlay_unlock:
>>> of_overlay_mutex_unlock();
>>>
>>> out:
>>> pr_debug("%s() err=%d\n", __func__, ret);
>>>
>>> return ret;
>>>
>>> ..so there is no call to free_overlay_changeset there.
>>>
>>> Colin
>>>
>>
>> OK, I was looking at 4.15-rc1. You must be looking at a later version where
>> "[PATCH 1/2] of: overlay: Fix cleanup order in of_overlay_apply()" has been
>> applied. Thanks for providing the extra details about the exit path so I
>> could see that.
>>
>> Rob, I think that the fix for cleanup order was not the best way to fix that
>> problem. A better method would have been to move "mutex_lock(&of_mutex);"
>> up 5 lines, to just before calling of_reserve_phandles().
>
> It is getting late (midnight my time), so I really should revisit this all
> tomorrow. My last comment ("move ... up 5 lines") is probably wrong.
>
> I'll look at this after some sleep.
I'm dropping "of: overlay: Fix cleanup order in of_overlay_apply()",
so someone please fix this in the original patch.
Rob
^ permalink raw reply
* Re: [PATCH v3 0/4] Fixes for omapdrm on OpenPandora and GTA04
From: Tony Lindgren @ 2017-11-30 15:27 UTC (permalink / raw)
To: Tomi Valkeinen
Cc: H. Nikolaus Schaller, Thierry Reding, David Airlie, Rob Herring,
Mark Rutland, Benoît Cousson, Russell King,
Bartlomiej Zolnierkiewicz, Laurent Pinchart, Julia Lawall,
Sean Paul, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-omap-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
letux-kernel-S0jZdbWzriLCfDggNXIi3w,
kernel-Jl6IXVxNIMRxAtABVqVhTwC/G2K4zDHf
In-Reply-To: <27b12bc8-2c3a-6caa-c800-158b75f80d3f-l0cyMroinI0@public.gmane.org>
* Tomi Valkeinen <tomi.valkeinen-l0cyMroinI0@public.gmane.org> [171130 10:56]:
> On 28/11/17 17:48, H. Nikolaus Schaller wrote:
> > Changes V3:
> > * stay compatible with old DTB files which still use "toppoly" (suggested by Tomi Valkeinen)
> > * replaced MODULE_ALIAS entries by MODULE_DEVICE_TABLE (suggested by Andrew F. Davis)
> > * removed DSI VDDS patch as it has already been accepted
> >
> > 2017-11-16 09:50:22: Changes V2:
> > * replaced patch to fix DSI VDDS for OMAP3 by equivalent patch from Laurent Pinchart
> > * keep previous compatibility option in panel driver to handle older device tree binaries
> >
> > 2017-11-08 22:09:36:
> > This patch set fixes vendor names of the panels
> > and fixes a problem on omapdrm with enabling
> > VDD_DSI for OMAP3 which is needed for displaying
> > the Red and Green channel on OMAP3530 (Pandora).
> >
> > H. Nikolaus Schaller (4):
> > omapdrm: panel: fix compatible vendor string for td028ttec1
> > omapdrm: panel: td028ttec1: replace MODULE_ALIAS by
> > MODULE_DEVICE_TABLE
> > DTS: GTA04: fix panel compatibility string
> > DTS: Pandora: fix panel compatibility string
> >
> > .../panel/{toppoly,td028ttec1.txt => tpo,td028ttec1.txt} | 4 ++--
> > arch/arm/boot/dts/omap3-gta04.dtsi | 2 +-
> > arch/arm/boot/dts/omap3-pandora-common.dtsi | 2 +-
> > drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c | 13 ++++++++++++-
> > .../fbdev/omap2/omapfb/displays/panel-tpo-td028ttec1.c | 12 +++++++++++-
> > 5 files changed, 27 insertions(+), 6 deletions(-)
> > rename Documentation/devicetree/bindings/display/panel/{toppoly,td028ttec1.txt => tpo,td028ttec1.txt} (84%)
> >
>
> Thanks. I have picked up patches 1 and 2.
>
> 3 can be applied when 1 & 2 are in. The change in 4 could be applied
> independently, but it conflicts with 3.
>
> Tony, how do you want to handle 3 and 4? I will push 1 and 2 to v4.16. I
> don't think they are real issues, so I don't see a reason to push them
> as fixes to v4.15. I think they are mostly just cleanups, and we might
> as well wait until v4.17, but that's quite far away...
In general to avoid the huge hassle of cross tree dependencies and
confusion if the dts changes are fixes, I suggest the following:
1. Nikolaus reposts the dts changes to not say word "fix" in them
and use "update to use new binding" or something similar to avoid
patches wrongly getting picked into earlier stable trees
2. Then I can ack the patches as they are just oneliners and
unlikely to conflict with anything else
Regards,
Tony
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] of: overlay: Remove else after goto
From: Rob Herring @ 2017-11-30 15:34 UTC (permalink / raw)
To: Frank Rowand
Cc: Geert Uytterhoeven, Pantelis Antoniou,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <6d0dc834-6df6-fa6c-3adc-5506f432fa7d-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On Wed, Nov 29, 2017 at 3:30 AM, Frank Rowand <frowand.list-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On 11/28/17 03:26, Geert Uytterhoeven wrote:
>> If an "if" branch is terminated by a "goto", there's no need to have an
>> "else" statement and an indented block of code.
>>
>> Remove the "else" statement to simplify the code flow for the casual
>> reviewer.
>>
>> Signed-off-by: Geert Uytterhoeven <geert+renesas-gXvu3+zWzMSzQB+pC5nmwQ@public.gmane.org>
>> ---
>> drivers/of/overlay.c | 25 ++++++++++---------------
>> 1 file changed, 10 insertions(+), 15 deletions(-)
>>
>> diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
>> index 8676411bd3e6f29f..53bc9e3f0b985415 100644
>> --- a/drivers/of/overlay.c
>> +++ b/drivers/of/overlay.c
>> @@ -580,9 +580,9 @@ static int init_overlay_changeset(struct overlay_changeset *ovcs,
>> of_node_put(fragment->overlay);
>> ret = -EINVAL;
>> goto err_free_fragments;
>> - } else {
>> - cnt++;
>> }
>> +
>> + cnt++;
>> }
>> }
>>
>> @@ -736,14 +736,12 @@ int of_overlay_apply(struct device_node *tree, int *ovcs_id)
>> devicetree_state_flags |= DTSF_APPLY_FAIL;
>> }
>> goto err_free_overlay_changeset;
>> - } else {
>> - ret = __of_changeset_apply_notify(&ovcs->cset);
>> - if (ret)
>> - pr_err("overlay changeset entry notify error %d\n",
>> - ret);
>> - /* fall through */
>> }
>>
>> + ret = __of_changeset_apply_notify(&ovcs->cset);
>> + if (ret)
>> + pr_err("overlay changeset entry notify error %d\n", ret);
>> +
>
> The fall through comment was removed. It is important to document that we
> are intentionally continuing despite the error.
I've fixed these up like this:
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index 53bc9e3f0b98..cb520169d679 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -741,6 +741,7 @@ int of_overlay_apply(struct device_node *tree, int *ovcs_id)
ret = __of_changeset_apply_notify(&ovcs->cset);
if (ret)
pr_err("overlay changeset entry notify error %d\n", ret);
+ /* notify failure is not fatal, continue */
list_add_tail(&ovcs->ovcs_list, &ovcs_list);
*ovcs_id = ovcs->id;
@@ -934,6 +935,7 @@ int of_overlay_remove(int *ovcs_id)
ret = __of_changeset_revert_notify(&ovcs->cset);
if (ret)
pr_err("overlay changeset entry notify error %d\n", ret);
+ /* notify failure is not fatal, continue */
*ovcs_id = 0;
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: [PATCH v3 4/5] pinctrl: mcp23s08: configure irq polarity using irq data
From: Marc Zyngier @ 2017-11-30 15:50 UTC (permalink / raw)
To: Linus Walleij, Sebastian Reichel
Cc: Phil Reid, Rob Herring, Mark Rutland, linux-gpio,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS
In-Reply-To: <CACRpkdbkG_83-gpGqdMA5y3cpAvSbQ2X_xT07PC3+boxPeWbPQ@mail.gmail.com>
On 30/11/17 14:21, Linus Walleij wrote:
> On Tue, Nov 21, 2017 at 4:21 PM, Sebastian Reichel <sre@kernel.org> wrote:
>
>> IMHO the explicit line-inverter is a bit over-engineered and
>> implicit line-inverter is enough, but I'm fine with both solutions.
>> I think the DT binding maintainers should comment on this though,
>> since it's pretty much a core decision about interrupt specifiers.
>
> I feel the same.
>
> I am very much back and forth on the subject.
>
> Simplicity of use vs modelling the system as it actually works.
>
> Back and forth.
>
> I honestly have just a very vague idea about this.
>
> I don't know if Marc Z as irqchip maintainer has some idea
> on how to model inverters on irq lines or if he's seen some
> solutions to it out there.
So far, I've seen two types of solutions:
- One based on a stacked irqchip driver that implements the inverter on
the irq_set_type method
- One based on per-device vendor-specific properties in DT
While the first one is clearly a big hammer, it has the advantage of not
adding new stuff to the DT spec, and accurately describe the signal path
(see the mediatek stuff for reference).
The second one is just a hack, frankly. It just has the advantage of
being trivial to implement.
I'm clearly inclined to prefer the first solution. But maybe it is time
to invent a "generic inverter" driver that could be reusable, just like
we have a generic irqchip?
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply
* Re: [PATCH 2/2] pinctrl: sunxi: Disable strict mode for H5 driver
From: Linus Walleij @ 2017-11-30 15:51 UTC (permalink / raw)
To: Andre Przywara
Cc: Maxime Ripard, Chen-Yu Tsai, Rob Herring, Chris Obbard,
Mark Rutland,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Linux ARM, linux-gpio-u79uwXL29TY76Z2rM5mHXA, linux-sunxi
In-Reply-To: <20171125120200.23294-3-andre.przywara-5wv7dgnIgG8@public.gmane.org>
On Sat, Nov 25, 2017 at 1:02 PM, Andre Przywara <andre.przywara-5wv7dgnIgG8@public.gmane.org> wrote:
> All of the H5 boards in the kernel reference the MMC0 CD pin twice in
> their DT, so strict mode will make the MMC driver fail to load.
> To keep existing DTs working, disable strict mode in the H5 driver.
>
> Signed-off-by: Andre Przywara <andre.przywara-5wv7dgnIgG8@public.gmane.org>
> Reported-by: Chris Obbard <obbardc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Patch applied with Maxime's ACK.
Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [RFC PATCH 0/3] pinctrl: sunxi: Add DT-based generic pinctrl driver
From: Andre Przywara @ 2017-11-30 15:55 UTC (permalink / raw)
To: Linus Walleij, Rob Herring
Cc: Maxime Ripard, Chen-Yu Tsai, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
Mark Rutland,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Linux ARM, Arnd Bergmann, Icenowy Zheng,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
In-Reply-To: <CACRpkdZQPspH79_nS-WgiSg6d2meXUztgocYbxO07vTgP1HehA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
Hi,
On 30/11/17 15:20, Linus Walleij wrote:
> On Fri, Nov 24, 2017 at 1:05 PM, Andre Przywara <andre.przywara-5wv7dgnIgG8@public.gmane.org> wrote:
>> On 24/11/17 10:28, Linus Walleij wrote:
>
>>> The DT maintainers have been pretty clear on that they don't like
>>> using the the DT as a generic fit-all information dump. They
>>> prefer to look up hardware data from per-soc compatible strings.
> (...)
>> I am just a bit worried that with Allwinner recently playing the SKU
>> game we end up with tons of tables for only slightly different SoCs (see
>> the H3 and H5, for instance). And with single image kernels we pile up
>> quite some *data* in each kernel, which is of little interest for
>> everyone else.
>
> So what you are saying is that you want to use the DTS for
> data dumping
Well, that's what the DT is for, right? As opposed to dump the data in
*every* kernel (Linux, U-Boot, BSD) for *every* SoC.
And, following this argument, why do we have reg and interrupt
properties if we could derive them from the compatible string as well?
Those are SoC specific and immutable by a board as well.
It seems the discussion went slightly heated and astray, but basically I
am after two things, maybe we should separate them:
1) Put the actual mux value into the DT, next to the already existing
function property. That is a small addition, but has the great effect of
avoiding to hard code this information for *each* supported SoC in
*every* kernel. Doing so just sounds like bonkers to me, sorry.
If there is really so much resistance against also *using* this
information from Linux, I would be happy to at least add the already
existing and generic "pinmux" property to the binding. This way we could
add those values to the .dtsi(s), and other OSes could use them. No need
for a driver change in Linux, then. I am not buying this molly guard
argument at all, but this way we could keep this protection in the kernel.
This would immediately allow to get an easy DT based pinctrl driver on
the road for U-Boot.
2) Add the (very few!) properties to the pinctrl root node that we need
to size and enumerate the pins. This would allow generic pinctrl driver
support, so one thing less to worry when bringing up a new SoC (variant).
So my main goal is more about the binding and the DTs.
Linux could just ignore them, though I don't see a good reason for us to
not make use of those for good.
I believe that both are not really a big issue and I don't really
understand why there is so much opposition towards it.
> and what I'm saying is that the DT maintainers
> do not like that stance.
>
> They will have to speak on the issue directly before we continue
> I think.
Fair enough.
> I have been getting a *LOT* of pushback to putting large amounts
> of data and configuration in the DTS recently, so IIUC that is something
> they simply don't like, probably for good reasons.
That's a shame, maybe it's to limit the amount of review and maintenance
needed? And it's a safe bet to have a simple binding, where nothing can
go wrong? And since we can't predict the future?
I don't know, but in this case we have quite a sample of already
existing controllers and can make an much more educated guess for a
better and compatible binding, kind of in hindsight.
> C.f:
> https://www.spinics.net/lists/dri-devel/msg150321.html
>
>> Also my understanding is that the actual Allwinner pin controller IP
>> (register map) is very much the same across all SoCs. Mostly the only
>> difference is the mapping between pins and mux functions, which we
>> express in the DT already anyway (in the subnodes). And this is really a
>> poster book example of what DT should be doing: express the specific
>> mappings of a particular implementation. I don't see why this would need
>> to be per-board only, if we can pull this up to the SoC level.
>
> It's not me you need to sell this point.
>
> You need to sell it to the DT maintainers.
Well, so far I only got some push back from Thierry, Maxime and you. My
understanding of the DT maintainers' position is to leave those details
to the subsystem maintainers.
Cheers,
Andre.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v2 2/2] ASoC: codecs: Add initial PCM1862/63/64/65 universal ADC driver
From: Andrew F. Davis @ 2017-11-30 15:56 UTC (permalink / raw)
To: Mark Brown
Cc: Liam Girdwood, Rob Herring, Mark Rutland,
alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20171130122035.wgj2jpvzx6md5gnl-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
On 11/30/2017 06:20 AM, Mark Brown wrote:
> On Wed, Nov 29, 2017 at 12:50:15PM -0600, Andrew F. Davis wrote:
>
>> + case SND_SOC_BIAS_STANDBY:
>> + pcm186x_power_on(codec);
>> + break;
>> + case SND_SOC_BIAS_OFF:
>> + pcm186x_power_off(codec);
>> + break;
>> + }
>
>> +/*
>> + * The PCM186x's page register is located on every page, allowing to program it
>> + * without having to switch pages. Take advantage of this by defining the range
>> + * such to have this register located inside the data window.
>> + */
>
> That sounds like a normal page register?
>
It is, I believe Andreas commented this for his own reference, I'll drop it.
>> +int pcm186x_probe(struct device *dev, enum pcm186x_type type, int irq,
>> + struct regmap *regmap)
>> +{
>
>> + ret = regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
>> + priv->supplies);
>> + if (ret) {
>> + dev_err(dev, "failed disable supplies: %d\n", ret);
>> + return ret;
>> + }
>
>> +static int __maybe_unused pcm186x_resume(struct device *dev)
>> +{
>> + struct pcm186x_priv *priv = dev_get_drvdata(dev);
>> + int ret;
>> +
>> + ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
>> + priv->supplies);
>> + if (ret != 0) {
>> + dev_err(dev, "failed to enable supplies: %d\n", ret);
>> + return ret;
>> + }
>
>> +const struct dev_pm_ops pcm186x_pm_ops = {
>> + SET_RUNTIME_PM_OPS(pcm186x_suspend, pcm186x_resume, NULL)
>> +};
>> +EXPORT_SYMBOL_GPL(pcm186x_pm_ops);
>
> There's no code in the driver that enables runtime PM so this isn't
> going to do anything. I'm also not clear that the power management
> handling is in general joined up - we leave the regulators disabled
> at the end of probe, relying on the bias level configuration to reenable
> them but then the runtime PM configuration also tries to enable and
> disable them. Based on what I think the intention is I'd suggest
> removing the bias level handling and then having probe enable runtime
> PM with the device flagged as active, letting runtime PM do any
> disabling if the device is idle.
>
I beleive this was meant to be be SIMPLE_DEV_PM_OPS and not
SET_RUNTIME_PM_OPS. I'll fix this all up for v3.
Just thinking, the sound core sets SND_SOC_BIAS_OFF before suspend
anyway, right? So the results would be similar just having all the PM
stuff in the bias level handling for consistency, but I'm open to
whatever is the preferred way.
> I'd also expect to see some system suspend handling.
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 2/2] pinctrl: sunxi: Disable strict mode for H5 driver
From: Andre Przywara @ 2017-11-30 16:07 UTC (permalink / raw)
To: Linus Walleij
Cc: Maxime Ripard, Chen-Yu Tsai, Rob Herring, Chris Obbard,
Mark Rutland,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Linux ARM, linux-gpio-u79uwXL29TY76Z2rM5mHXA, linux-sunxi
In-Reply-To: <CACRpkdZX5U=JoQFS+X96+F68yVSZbnCZpgNfAnvfJGxZ9moi8A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
Hi,
On 30/11/17 15:51, Linus Walleij wrote:
> On Sat, Nov 25, 2017 at 1:02 PM, Andre Przywara <andre.przywara-5wv7dgnIgG8@public.gmane.org> wrote:
>
>> All of the H5 boards in the kernel reference the MMC0 CD pin twice in
>> their DT, so strict mode will make the MMC driver fail to load.
>> To keep existing DTs working, disable strict mode in the H5 driver.
>>
>> Signed-off-by: Andre Przywara <andre.przywara-5wv7dgnIgG8@public.gmane.org>
>> Reported-by: Chris Obbard <obbardc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
>
> Patch applied with Maxime's ACK.
Thanks for that (also to Maxime and Chen-Yu) and the smooth handling!
Sorry, I just see that I didn't point this out explicitly, but this is
to fix a regression introduced in 4.15-rc1, so is this on a branch that
will be pushed for 4.15-rc, still? (Couldn't find anything quickly on
kernel.org)
Cheers,
Andre.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH 1/3] dt-bindings: net: Add DT bindings for Socionext Netsec
From: jassisinghbrar-Re5JQEeQqe8AvxtiuMwx3w @ 2017-11-30 16:12 UTC (permalink / raw)
To: netdev-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: davem-fT/PcQaiUtIeIZ0/mPfg9Q,
arnd.bergmann-QSEj5FYQhm4dnm+yROfE0A,
ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
Jassi Brar, Jassi Brar
From: Jassi Brar <jassisinghbrar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
This patch adds documentation for Device-Tree bindings for the
Socionext NetSec Controller driver.
Signed-off-by: Jassi Brar <jaswinder.singh-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
.../devicetree/bindings/net/socionext-netsec.txt | 43 ++++++++++++++++++++++
1 file changed, 43 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/socionext-netsec.txt
diff --git a/Documentation/devicetree/bindings/net/socionext-netsec.txt b/Documentation/devicetree/bindings/net/socionext-netsec.txt
new file mode 100644
index 0000000..4695969
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/socionext-netsec.txt
@@ -0,0 +1,43 @@
+* Socionext NetSec Ethernet Controller IP
+
+Required properties:
+- compatible: Should be "socionext,synquacer-netsec"
+- reg: Address and length of the control register area, followed by the
+ address and length of the EEPROM holding the MAC address and
+ microengine firmware
+- interrupts: Should contain ethernet controller interrupt
+- clocks: phandle to the PHY reference clock, and any other clocks to be
+ switched by runtime_pm
+- clock-names: Required only if more than a single clock is listed in 'clocks'.
+ The PHY reference clock must be named 'phy_refclk'
+- phy-mode: See ethernet.txt file in the same directory
+- phy-handle: phandle to select child phy
+
+Optional properties: (See ethernet.txt file in the same directory)
+- local-mac-address
+- mac-address
+- max-speed
+- max-frame-size
+
+Required properties for the child phy:
+- reg: phy address
+
+Example:
+ eth0: netsec@522D0000 {
+ compatible = "socionext,synquacer-netsec";
+ reg = <0 0x522D0000 0x0 0x10000>, <0 0x10000000 0x0 0x10000>;
+ interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk_netsec>;
+ phy-mode = "rgmii";
+ max-speed = <1000>;
+ max-frame-size = <9000>;
+ phy-handle = <ðphy0>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ethphy0: ethernet-phy@1 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <1>;
+ };
+ };
--
2.7.4
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 2/3] net: socionext: Add Synquacer NetSec driver
From: jassisinghbrar @ 2017-11-30 16:13 UTC (permalink / raw)
To: netdev, devicetree
Cc: davem, arnd.bergmann, ard.biesheuvel, robh+dt, mark.rutland,
Jassi Brar
From: Jassi Brar <jaswinder.singh@linaro.org>
This driver adds support for Socionext "netsec" IP Gigabit
Ethernet + PHY IP used in the Synquacer SC2A11 SoC.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
---
drivers/net/ethernet/Kconfig | 1 +
drivers/net/ethernet/Makefile | 1 +
drivers/net/ethernet/socionext/Kconfig | 29 +
drivers/net/ethernet/socionext/Makefile | 1 +
drivers/net/ethernet/socionext/netsec.c | 1820 +++++++++++++++++++++++++++++++
5 files changed, 1852 insertions(+)
create mode 100644 drivers/net/ethernet/socionext/Kconfig
create mode 100644 drivers/net/ethernet/socionext/Makefile
create mode 100644 drivers/net/ethernet/socionext/netsec.c
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index c604213..d50519e 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -170,6 +170,7 @@ source "drivers/net/ethernet/sis/Kconfig"
source "drivers/net/ethernet/sfc/Kconfig"
source "drivers/net/ethernet/sgi/Kconfig"
source "drivers/net/ethernet/smsc/Kconfig"
+source "drivers/net/ethernet/socionext/Kconfig"
source "drivers/net/ethernet/stmicro/Kconfig"
source "drivers/net/ethernet/sun/Kconfig"
source "drivers/net/ethernet/tehuti/Kconfig"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index 39f62733..6cf5ade 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_SFC) += sfc/
obj-$(CONFIG_SFC_FALCON) += sfc/falcon/
obj-$(CONFIG_NET_VENDOR_SGI) += sgi/
obj-$(CONFIG_NET_VENDOR_SMSC) += smsc/
+obj-$(CONFIG_NET_VENDOR_SOCIONEXT) += socionext/
obj-$(CONFIG_NET_VENDOR_STMICRO) += stmicro/
obj-$(CONFIG_NET_VENDOR_SUN) += sun/
obj-$(CONFIG_NET_VENDOR_TEHUTI) += tehuti/
diff --git a/drivers/net/ethernet/socionext/Kconfig b/drivers/net/ethernet/socionext/Kconfig
new file mode 100644
index 0000000..f50c906
--- /dev/null
+++ b/drivers/net/ethernet/socionext/Kconfig
@@ -0,0 +1,29 @@
+#
+# Socionext Network device configuration
+#
+
+config NET_VENDOR_SOCIONEXT
+ bool "Socionext devices"
+ default y
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y.
+
+ Note that the answer to this question doesn't directly affect the
+ the questions about Socionext cards. If you say Y, you will be asked
+ for your specific card in the following questions.
+
+if NET_VENDOR_SOCIONEXT
+
+config SNI_NETSEC
+ tristate "NETSEC Driver Support"
+ depends on (ARCH_SYNQUACER || COMPILE_TEST) && OF
+ select PHYLIB
+ select MII
+help
+ Enable to add support for the SocioNext NetSec Gigabit Ethernet
+ controller + PHY, as found on the Synquacer SC2A11 SoC
+
+ To compile this driver as a module, choose M here: the module will be
+ called netsec. If unsure, say N.
+
+endif # NET_VENDOR_SOCIONEXT
diff --git a/drivers/net/ethernet/socionext/Makefile b/drivers/net/ethernet/socionext/Makefile
new file mode 100644
index 0000000..9505923
--- /dev/null
+++ b/drivers/net/ethernet/socionext/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SNI_NETSEC) += netsec.o
diff --git a/drivers/net/ethernet/socionext/netsec.c b/drivers/net/ethernet/socionext/netsec.c
new file mode 100644
index 0000000..d40718c
--- /dev/null
+++ b/drivers/net/ethernet/socionext/netsec.c
@@ -0,0 +1,1820 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/types.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/acpi.h>
+#include <linux/of_mdio.h>
+#include <linux/etherdevice.h>
+#include <linux/interrupt.h>
+
+#include <net/tcp.h>
+#include <net/ip6_checksum.h>
+
+#define NETSEC_REG_SOFT_RST 0x104
+#define NETSEC_REG_COM_INIT 0x120
+
+#define NETSEC_REG_TOP_STATUS 0x200
+#define NETSEC_IRQ_RX BIT(1)
+#define NETSEC_IRQ_TX BIT(0)
+
+#define NETSEC_REG_TOP_INTEN 0x204
+#define NETSEC_REG_INTEN_SET 0x234
+#define NETSEC_REG_INTEN_CLR 0x238
+
+#define NETSEC_REG_NRM_TX_STATUS 0x400
+#define NETSEC_REG_NRM_TX_INTEN 0x404
+#define NETSEC_REG_NRM_TX_INTEN_SET 0x428
+#define NETSEC_REG_NRM_TX_INTEN_CLR 0x42c
+#define NRM_TX_ST_NTOWNR BIT(17)
+#define NRM_TX_ST_TR_ERR BIT(16)
+#define NRM_TX_ST_TXDONE BIT(15)
+#define NRM_TX_ST_TMREXP BIT(14)
+
+#define NETSEC_REG_NRM_RX_STATUS 0x440
+#define NETSEC_REG_NRM_RX_INTEN 0x444
+#define NETSEC_REG_NRM_RX_INTEN_SET 0x468
+#define NETSEC_REG_NRM_RX_INTEN_CLR 0x46c
+#define NRM_RX_ST_RC_ERR BIT(16)
+#define NRM_RX_ST_PKTCNT BIT(15)
+#define NRM_RX_ST_TMREXP BIT(14)
+
+#define NETSEC_REG_PKT_CMD_BUF 0xd0
+
+#define NETSEC_REG_CLK_EN 0x100
+
+#define NETSEC_REG_PKT_CTRL 0x140
+
+#define NETSEC_REG_DMA_TMR_CTRL 0x20c
+#define NETSEC_REG_F_TAIKI_MC_VER 0x22c
+#define NETSEC_REG_F_TAIKI_VER 0x230
+#define NETSEC_REG_DMA_HM_CTRL 0x214
+#define NETSEC_REG_DMA_MH_CTRL 0x220
+#define NETSEC_REG_ADDR_DIS_CORE 0x218
+#define NETSEC_REG_DMAC_HM_CMD_BUF 0x210
+#define NETSEC_REG_DMAC_MH_CMD_BUF 0x21c
+
+#define NETSEC_REG_NRM_TX_PKTCNT 0x410
+
+#define NETSEC_REG_NRM_TX_DONE_PKTCNT 0x414
+#define NETSEC_REG_NRM_TX_DONE_TXINT_PKTCNT 0x418
+
+#define NETSEC_REG_NRM_TX_TMR 0x41c
+
+#define NETSEC_REG_NRM_RX_PKTCNT 0x454
+#define NETSEC_REG_NRM_RX_RXINT_PKTCNT 0x458
+#define NETSEC_REG_NRM_TX_TXINT_TMR 0x420
+#define NETSEC_REG_NRM_RX_RXINT_TMR 0x460
+
+#define NETSEC_REG_NRM_RX_TMR 0x45c
+
+#define NETSEC_REG_NRM_TX_DESC_START_UP 0x434
+#define NETSEC_REG_NRM_TX_DESC_START_LW 0x408
+#define NETSEC_REG_NRM_RX_DESC_START_UP 0x474
+#define NETSEC_REG_NRM_RX_DESC_START_LW 0x448
+
+#define NETSEC_REG_NRM_TX_CONFIG 0x430
+#define NETSEC_REG_NRM_RX_CONFIG 0x470
+
+#define MAC_REG_STATUS 0x1024
+#define MAC_REG_DATA 0x11c0
+#define MAC_REG_CMD 0x11c4
+#define MAC_REG_FLOW_TH 0x11cc
+#define MAC_REG_INTF_SEL 0x11d4
+#define MAC_REG_DESC_INIT 0x11fc
+#define MAC_REG_DESC_SOFT_RST 0x1204
+#define NETSEC_REG_MODE_TRANS_COMP_STATUS 0x500
+
+#define GMAC_REG_MCR 0x0000
+#define GMAC_REG_MFFR 0x0004
+#define GMAC_REG_GAR 0x0010
+#define GMAC_REG_GDR 0x0014
+#define GMAC_REG_FCR 0x0018
+#define GMAC_REG_BMR 0x1000
+#define GMAC_REG_RDLAR 0x100c
+#define GMAC_REG_TDLAR 0x1010
+#define GMAC_REG_OMR 0x1018
+
+#define MHZ(n) ((n) * 1000 * 1000)
+
+#define NETSEC_TX_SHIFT_OWN_FIELD 31
+#define NETSEC_TX_SHIFT_LD_FIELD 30
+#define NETSEC_TX_SHIFT_DRID_FIELD 24
+#define NETSEC_TX_SHIFT_PT_FIELD 21
+#define NETSEC_TX_SHIFT_TDRID_FIELD 16
+#define NETSEC_TX_SHIFT_CC_FIELD 15
+#define NETSEC_TX_SHIFT_FS_FIELD 9
+#define NETSEC_TX_LAST 8
+#define NETSEC_TX_SHIFT_CO 7
+#define NETSEC_TX_SHIFT_SO 6
+#define NETSEC_TX_SHIFT_TRS_FIELD 4
+
+#define NETSEC_RX_PKT_OWN_FIELD 31
+#define NETSEC_RX_PKT_LD_FIELD 30
+#define NETSEC_RX_PKT_SDRID_FIELD 24
+#define NETSEC_RX_PKT_FR_FIELD 23
+#define NETSEC_RX_PKT_ER_FIELD 21
+#define NETSEC_RX_PKT_ERR_FIELD 16
+#define NETSEC_RX_PKT_TDRID_FIELD 12
+#define NETSEC_RX_PKT_FS_FIELD 9
+#define NETSEC_RX_PKT_LS_FIELD 8
+#define NETSEC_RX_PKT_CO_FIELD 6
+
+#define NETSEC_RX_PKT_ERR_MASK 3
+
+#define NETSEC_MAX_TX_PKT_LEN 1518
+#define NETSEC_MAX_TX_JUMBO_PKT_LEN 9018
+
+#define NETSEC_RING_GMAC 15
+#define NETSEC_RING_MAX 2
+
+#define NETSEC_TCP_SEG_LEN_MAX 1460
+#define NETSEC_TCP_JUMBO_SEG_LEN_MAX 8960
+
+#define NETSEC_RX_CKSUM_NOTAVAIL 0
+#define NETSEC_RX_CKSUM_OK 1
+#define NETSEC_RX_CKSUM_NG 2
+
+#define NETSEC_TOP_IRQ_REG_CODE_LOAD_END BIT(20)
+#define NETSEC_IRQ_TRANSITION_COMPLETE BIT(4)
+
+#define NETSEC_MODE_TRANS_COMP_IRQ_N2T BIT(20)
+#define NETSEC_MODE_TRANS_COMP_IRQ_T2N BIT(19)
+
+#define NETSEC_INT_PKTCNT_MAX 2047
+
+#define NETSEC_FLOW_START_TH_MAX 95
+#define NETSEC_FLOW_STOP_TH_MAX 95
+#define NETSEC_FLOW_PAUSE_TIME_MIN 5
+
+#define NETSEC_CLK_EN_REG_DOM_ALL 0x3f
+
+#define NETSEC_PKT_CTRL_REG_MODE_NRM BIT(28)
+#define NETSEC_PKT_CTRL_REG_EN_JUMBO BIT(27)
+#define NETSEC_PKT_CTRL_REG_LOG_CHKSUM_ER BIT(3)
+#define NETSEC_PKT_CTRL_REG_LOG_HD_INCOMPLETE BIT(2)
+#define NETSEC_PKT_CTRL_REG_LOG_HD_ER BIT(1)
+#define NETSEC_PKT_CTRL_REG_DRP_NO_MATCH BIT(0)
+
+#define NETSEC_CLK_EN_REG_DOM_G BIT(5)
+#define NETSEC_CLK_EN_REG_DOM_C BIT(1)
+#define NETSEC_CLK_EN_REG_DOM_D BIT(0)
+
+#define NETSEC_COM_INIT_REG_DB BIT(2)
+#define NETSEC_COM_INIT_REG_CLS BIT(1)
+#define NETSEC_COM_INIT_REG_ALL (NETSEC_COM_INIT_REG_CLS | \
+ NETSEC_COM_INIT_REG_DB)
+
+#define NETSEC_SOFT_RST_REG_RESET 0
+#define NETSEC_SOFT_RST_REG_RUN BIT(31)
+
+#define NETSEC_DMA_CTRL_REG_STOP 1
+#define MH_CTRL__MODE_TRANS BIT(20)
+
+#define NETSEC_GMAC_CMD_ST_READ 0
+#define NETSEC_GMAC_CMD_ST_WRITE BIT(28)
+#define NETSEC_GMAC_CMD_ST_BUSY BIT(31)
+
+#define NETSEC_GMAC_BMR_REG_COMMON 0x00412080
+#define NETSEC_GMAC_BMR_REG_RESET 0x00020181
+#define NETSEC_GMAC_BMR_REG_SWR 0x00000001
+
+#define NETSEC_GMAC_OMR_REG_ST BIT(13)
+#define NETSEC_GMAC_OMR_REG_SR BIT(1)
+
+#define NETSEC_GMAC_MCR_REG_IBN BIT(30)
+#define NETSEC_GMAC_MCR_REG_CST BIT(25)
+#define NETSEC_GMAC_MCR_REG_JE BIT(20)
+#define NETSEC_MCR_PS BIT(15)
+#define NETSEC_GMAC_MCR_REG_FES BIT(14)
+#define NETSEC_GMAC_MCR_REG_FULL_DUPLEX_COMMON 0x0000280c
+#define NETSEC_GMAC_MCR_REG_HALF_DUPLEX_COMMON 0x0001a00c
+
+#define NETSEC_FCR_RFE BIT(2)
+#define NETSEC_FCR_TFE BIT(1)
+
+#define NETSEC_GMAC_GAR_REG_GW BIT(1)
+#define NETSEC_GMAC_GAR_REG_GB BIT(0)
+
+#define NETSEC_GMAC_GAR_REG_SHIFT_PA 11
+#define NETSEC_GMAC_GAR_REG_SHIFT_GR 6
+#define GMAC_REG_SHIFT_CR_GAR 2
+
+#define NETSEC_GMAC_GAR_REG_CR_25_35_MHZ 2
+#define NETSEC_GMAC_GAR_REG_CR_35_60_MHZ 3
+#define NETSEC_GMAC_GAR_REG_CR_60_100_MHZ 0
+#define NETSEC_GMAC_GAR_REG_CR_100_150_MHZ 1
+#define NETSEC_GMAC_GAR_REG_CR_150_250_MHZ 4
+#define NETSEC_GMAC_GAR_REG_CR_250_300_MHZ 5
+
+#define NETSEC_GMAC_RDLAR_REG_COMMON 0x18000
+#define NETSEC_GMAC_TDLAR_REG_COMMON 0x1c000
+
+#define NETSEC_REG_NETSEC_VER_F_TAIKI 0x50000
+
+#define NETSEC_REG_DESC_RING_CONFIG_CFG_UP BIT(31)
+#define NETSEC_REG_DESC_RING_CONFIG_CH_RST BIT(30)
+#define NETSEC_REG_DESC_TMR_MODE 4
+#define NETSEC_REG_DESC_ENDIAN 0
+
+#define NETSEC_MAC_DESC_SOFT_RST_SOFT_RST 1
+#define NETSEC_MAC_DESC_INIT_REG_INIT 1
+
+#define NETSEC_EEPROM_MAC_ADDRESS 0x00
+#define NETSEC_EEPROM_HM_ME_ADDRESS_H 0x08
+#define NETSEC_EEPROM_HM_ME_ADDRESS_L 0x0C
+#define NETSEC_EEPROM_HM_ME_SIZE 0x10
+#define NETSEC_EEPROM_MH_ME_ADDRESS_H 0x14
+#define NETSEC_EEPROM_MH_ME_ADDRESS_L 0x18
+#define NETSEC_EEPROM_MH_ME_SIZE 0x1C
+#define NETSEC_EEPROM_PKT_ME_ADDRESS 0x20
+#define NETSEC_EEPROM_PKT_ME_SIZE 0x24
+
+#define DESC_NUM 128
+#define NAPI_BUDGET (DESC_NUM / 2)
+
+#define DESC_SZ sizeof(struct netsec_de)
+
+#define NETSEC_F_NETSEC_VER_MAJOR_NUM(x) ((x) & 0xffff0000)
+
+enum ring_id {
+ NETSEC_RING_TX = 0,
+ NETSEC_RING_RX
+};
+
+struct netsec_desc {
+ struct sk_buff *skb;
+ dma_addr_t dma_addr;
+ void *addr;
+ u16 len;
+};
+
+struct netsec_desc_ring {
+ phys_addr_t desc_phys;
+ struct netsec_desc *desc;
+ void *vaddr;
+ u16 pkt_cnt;
+ u16 head, tail;
+};
+
+struct netsec_priv {
+ struct netsec_desc_ring desc_ring[NETSEC_RING_MAX];
+ struct ethtool_coalesce et_coalesce;
+ spinlock_t reglock; /* protect reg access */
+ struct napi_struct napi;
+ phy_interface_t phy_interface;
+ struct net_device *ndev;
+ struct device_node *phy_np;
+ struct phy_device *phydev;
+ struct mii_bus *mii_bus;
+ void __iomem *ioaddr;
+ const void *eeprom_base;
+ struct device *dev;
+ struct clk *clk[3];
+ u32 msg_enable;
+ u32 freq;
+ int clock_count;
+ bool rx_cksum_offload_flag;
+};
+
+struct netsec_de { /* Netsec Descriptor layout */
+ u32 attr;
+ u32 data_buf_addr_up;
+ u32 data_buf_addr_lw;
+ u32 buf_len_info;
+};
+
+struct netsec_tx_pkt_ctrl {
+ u16 tcp_seg_len;
+ bool tcp_seg_offload_flag;
+ bool cksum_offload_flag;
+};
+
+struct netsec_rx_pkt_info {
+ int rx_cksum_result;
+ int err_code;
+ bool err_flag;
+};
+
+static inline void netsec_write(struct netsec_priv *priv,
+ u32 reg_addr, u32 val)
+{
+ writel(val, priv->ioaddr + reg_addr);
+}
+
+static inline u32 netsec_read(struct netsec_priv *priv, u32 reg_addr)
+{
+ return readl(priv->ioaddr + reg_addr);
+}
+
+#define DRING_TAIL(r) ((r)->tail)
+
+#define DRING_HEAD(r) ((r)->head)
+
+#define MOVE_TAIL(r) do { \
+ if (++(r)->tail == DESC_NUM) \
+ (r)->tail = 0; \
+ } while (0)
+
+#define MOVE_HEAD(r) do { \
+ if (++(r)->head == DESC_NUM) \
+ (r)->head = 0; \
+ } while (0)
+
+#define JUMP_HEAD(r, n) do { \
+ int i; \
+ for (i = 0; i < (n); i++) \
+ MOVE_HEAD(r); \
+ } while (0)
+
+static inline int available_descs(struct netsec_desc_ring *r)
+{
+ int filled;
+
+ if ((r)->head >= (r)->tail)
+ filled = (r)->head - (r)->tail;
+ else
+ filled = (r)->head + DESC_NUM - (r)->tail;
+
+ return DESC_NUM - filled;
+}
+
+/*************************************************************/
+/*********************** MDIO BUS OPS ************************/
+/*************************************************************/
+
+#define TIMEOUT_SPINS_MAC 1000
+#define TIMEOUT_SECONDARY_MS_MAC 100
+
+static u32 netsec_clk_type(u32 freq)
+{
+ if (freq < MHZ(35))
+ return NETSEC_GMAC_GAR_REG_CR_25_35_MHZ;
+ if (freq < MHZ(60))
+ return NETSEC_GMAC_GAR_REG_CR_35_60_MHZ;
+ if (freq < MHZ(100))
+ return NETSEC_GMAC_GAR_REG_CR_60_100_MHZ;
+ if (freq < MHZ(150))
+ return NETSEC_GMAC_GAR_REG_CR_100_150_MHZ;
+ if (freq < MHZ(250))
+ return NETSEC_GMAC_GAR_REG_CR_150_250_MHZ;
+
+ return NETSEC_GMAC_GAR_REG_CR_250_300_MHZ;
+}
+
+static int netsec_wait_while_busy(struct netsec_priv *priv, u32 addr, u32 mask)
+{
+ u32 timeout = TIMEOUT_SPINS_MAC;
+
+ while (--timeout && netsec_read(priv, addr) & mask)
+ cpu_relax();
+ if (timeout)
+ return 0;
+
+ timeout = TIMEOUT_SECONDARY_MS_MAC;
+ while (--timeout && netsec_read(priv, addr) & mask)
+ usleep_range(1000, 2000);
+
+ if (timeout)
+ return 0;
+
+ netdev_WARN(priv->ndev, "%s: timeout\n", __func__);
+
+ return -ETIMEDOUT;
+}
+
+static int netsec_mac_write(struct netsec_priv *priv, u32 addr, u32 value)
+{
+ netsec_write(priv, MAC_REG_DATA, value);
+ netsec_write(priv, MAC_REG_CMD, addr | NETSEC_GMAC_CMD_ST_WRITE);
+ return netsec_wait_while_busy(priv,
+ MAC_REG_CMD, NETSEC_GMAC_CMD_ST_BUSY);
+}
+
+static int netsec_mac_read(struct netsec_priv *priv, u32 addr, u32 *read)
+{
+ int ret;
+
+ netsec_write(priv, MAC_REG_CMD, addr | NETSEC_GMAC_CMD_ST_READ);
+ ret = netsec_wait_while_busy(priv,
+ MAC_REG_CMD, NETSEC_GMAC_CMD_ST_BUSY);
+ if (ret)
+ return ret;
+
+ *read = netsec_read(priv, MAC_REG_DATA);
+
+ return 0;
+}
+
+static int netsec_mac_wait_while_busy(struct netsec_priv *priv,
+ u32 addr, u32 mask)
+{
+ u32 timeout = TIMEOUT_SPINS_MAC;
+ int ret, data;
+
+ do {
+ ret = netsec_mac_read(priv, addr, &data);
+ if (ret)
+ break;
+ cpu_relax();
+ } while (--timeout && (data & mask));
+
+ if (timeout)
+ return 0;
+
+ timeout = TIMEOUT_SECONDARY_MS_MAC;
+ do {
+ usleep_range(1000, 2000);
+
+ ret = netsec_mac_read(priv, addr, &data);
+ if (ret)
+ break;
+ cpu_relax();
+ } while (--timeout && (data & mask));
+
+ if (timeout && !ret)
+ return 0;
+
+ netdev_WARN(priv->ndev, "%s: timeout\n", __func__);
+
+ return -ETIMEDOUT;
+}
+
+static int netsec_mac_update_to_phy_state(struct netsec_priv *priv)
+{
+ struct phy_device *phydev = priv->ndev->phydev;
+ u32 value = 0;
+
+ value = phydev->duplex ? NETSEC_GMAC_MCR_REG_FULL_DUPLEX_COMMON :
+ NETSEC_GMAC_MCR_REG_HALF_DUPLEX_COMMON;
+
+ if (phydev->speed != SPEED_1000)
+ value |= NETSEC_MCR_PS;
+
+ if (priv->phy_interface != PHY_INTERFACE_MODE_GMII &&
+ phydev->speed == SPEED_100)
+ value |= NETSEC_GMAC_MCR_REG_FES;
+
+ value |= NETSEC_GMAC_MCR_REG_CST | NETSEC_GMAC_MCR_REG_JE;
+
+ if (priv->phy_interface == PHY_INTERFACE_MODE_RGMII)
+ value |= NETSEC_GMAC_MCR_REG_IBN;
+
+ if (netsec_mac_write(priv, GMAC_REG_MCR, value))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int netsec_phy_write(struct mii_bus *bus,
+ int phy_addr, int reg, u16 val)
+{
+ struct netsec_priv *priv = bus->priv;
+
+ if (netsec_mac_write(priv, GMAC_REG_GDR, val))
+ return -ETIMEDOUT;
+ if (netsec_mac_write(priv, GMAC_REG_GAR,
+ phy_addr << NETSEC_GMAC_GAR_REG_SHIFT_PA |
+ reg << NETSEC_GMAC_GAR_REG_SHIFT_GR |
+ NETSEC_GMAC_GAR_REG_GW | NETSEC_GMAC_GAR_REG_GB |
+ (netsec_clk_type(priv->freq) <<
+ GMAC_REG_SHIFT_CR_GAR)))
+ return -ETIMEDOUT;
+
+ return netsec_mac_wait_while_busy(priv, GMAC_REG_GAR,
+ NETSEC_GMAC_GAR_REG_GB);
+}
+
+static int netsec_phy_read(struct mii_bus *bus, int phy_addr, int reg_addr)
+{
+ struct netsec_priv *priv = bus->priv;
+ u32 data;
+ int ret;
+
+ if (netsec_mac_write(priv, GMAC_REG_GAR, NETSEC_GMAC_GAR_REG_GB |
+ phy_addr << NETSEC_GMAC_GAR_REG_SHIFT_PA |
+ reg_addr << NETSEC_GMAC_GAR_REG_SHIFT_GR |
+ (netsec_clk_type(priv->freq) <<
+ GMAC_REG_SHIFT_CR_GAR)))
+ return -ETIMEDOUT;
+
+ ret = netsec_mac_wait_while_busy(priv, GMAC_REG_GAR,
+ NETSEC_GMAC_GAR_REG_GB);
+ if (ret)
+ return ret;
+
+ ret = netsec_mac_read(priv, GMAC_REG_GDR, &data);
+ if (ret)
+ return ret;
+
+ return data;
+}
+
+/*************************************************************/
+/*********************** ETHTOOL_OPS **************************/
+/*************************************************************/
+
+static void netsec_et_get_drvinfo(struct net_device *net_device,
+ struct ethtool_drvinfo *info)
+{
+ strlcpy(info->driver, "netsec", sizeof(info->driver));
+ strlcpy(info->bus_info, dev_name(net_device->dev.parent),
+ sizeof(info->bus_info));
+}
+
+static int netsec_et_get_coalesce(struct net_device *net_device,
+ struct ethtool_coalesce *et_coalesce)
+{
+ struct netsec_priv *priv = netdev_priv(net_device);
+
+ *et_coalesce = priv->et_coalesce;
+
+ return 0;
+}
+
+static int netsec_et_set_coalesce(struct net_device *net_device,
+ struct ethtool_coalesce *et_coalesce)
+{
+ struct netsec_priv *priv = netdev_priv(net_device);
+
+ priv->et_coalesce = *et_coalesce;
+
+ if (priv->et_coalesce.tx_coalesce_usecs < 50)
+ priv->et_coalesce.tx_coalesce_usecs = 50;
+ if (priv->et_coalesce.tx_max_coalesced_frames < 1)
+ priv->et_coalesce.tx_max_coalesced_frames = 1;
+
+ netsec_write(priv, NETSEC_REG_NRM_TX_DONE_TXINT_PKTCNT,
+ priv->et_coalesce.tx_max_coalesced_frames);
+ netsec_write(priv, NETSEC_REG_NRM_TX_TXINT_TMR,
+ priv->et_coalesce.tx_coalesce_usecs);
+ netsec_write(priv, NETSEC_REG_NRM_TX_INTEN_SET, NRM_TX_ST_TXDONE);
+ netsec_write(priv, NETSEC_REG_NRM_TX_INTEN_SET, NRM_TX_ST_TMREXP);
+
+ if (priv->et_coalesce.rx_coalesce_usecs < 50)
+ priv->et_coalesce.rx_coalesce_usecs = 50;
+ if (priv->et_coalesce.rx_max_coalesced_frames < 1)
+ priv->et_coalesce.rx_max_coalesced_frames = 1;
+
+ netsec_write(priv, NETSEC_REG_NRM_RX_RXINT_PKTCNT,
+ priv->et_coalesce.rx_max_coalesced_frames);
+ netsec_write(priv, NETSEC_REG_NRM_RX_RXINT_TMR,
+ priv->et_coalesce.rx_coalesce_usecs);
+ netsec_write(priv, NETSEC_REG_NRM_RX_INTEN_SET, NRM_RX_ST_PKTCNT);
+ netsec_write(priv, NETSEC_REG_NRM_RX_INTEN_SET, NRM_RX_ST_TMREXP);
+
+ return 0;
+}
+
+static u32 netsec_et_get_msglevel(struct net_device *dev)
+{
+ struct netsec_priv *priv = netdev_priv(dev);
+
+ return priv->msg_enable;
+}
+
+static void netsec_et_set_msglevel(struct net_device *dev, u32 datum)
+{
+ struct netsec_priv *priv = netdev_priv(dev);
+
+ priv->msg_enable = datum;
+}
+
+static const struct ethtool_ops netsec_ethtool_ops = {
+ .get_drvinfo = netsec_et_get_drvinfo,
+ .get_link_ksettings = phy_ethtool_get_link_ksettings,
+ .set_link_ksettings = phy_ethtool_set_link_ksettings,
+ .get_link = ethtool_op_get_link,
+ .get_coalesce = netsec_et_get_coalesce,
+ .set_coalesce = netsec_et_set_coalesce,
+ .get_msglevel = netsec_et_get_msglevel,
+ .set_msglevel = netsec_et_set_msglevel,
+};
+
+/*************************************************************/
+/*********************** NETDEV_OPS **************************/
+/*************************************************************/
+
+static struct sk_buff *netsec_alloc_skb(struct netsec_priv *priv,
+ struct netsec_desc *desc)
+{
+ struct sk_buff *skb;
+
+ if (device_get_dma_attr(priv->dev) == DEV_DMA_COHERENT) {
+ skb = netdev_alloc_skb_ip_align(priv->ndev, desc->len);
+ } else {
+ desc->len = L1_CACHE_ALIGN(desc->len);
+ skb = netdev_alloc_skb(priv->ndev, desc->len);
+ }
+ if (!skb)
+ return NULL;
+
+ desc->addr = skb->data;
+ desc->dma_addr = dma_map_single(priv->dev, desc->addr, desc->len,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(priv->dev, desc->dma_addr)) {
+ dev_kfree_skb_any(skb);
+ return NULL;
+ }
+ return skb;
+}
+
+static void netsec_set_rx_de(struct netsec_priv *priv,
+ struct netsec_desc_ring *dring, u16 idx,
+ const struct netsec_desc *desc,
+ struct sk_buff *skb)
+{
+ struct netsec_de *de = dring->vaddr + DESC_SZ * idx;
+ u32 attr = (1 << NETSEC_RX_PKT_OWN_FIELD) |
+ (1 << NETSEC_RX_PKT_FS_FIELD) |
+ (1 << NETSEC_RX_PKT_LS_FIELD);
+
+ if (idx == DESC_NUM - 1)
+ attr |= (1 << NETSEC_RX_PKT_LD_FIELD);
+
+ de->data_buf_addr_up = upper_32_bits(desc->dma_addr);
+ de->data_buf_addr_lw = lower_32_bits(desc->dma_addr);
+ de->buf_len_info = desc->len;
+ de->attr = attr;
+ dma_wmb();
+
+ dring->desc[idx].dma_addr = desc->dma_addr;
+ dring->desc[idx].addr = desc->addr;
+ dring->desc[idx].len = desc->len;
+ dring->desc[idx].skb = skb;
+}
+
+static struct sk_buff *netsec_get_rx_de(struct netsec_priv *priv,
+ struct netsec_desc_ring *dring,
+ u16 idx,
+ struct netsec_rx_pkt_info *rxpi,
+ struct netsec_desc *desc, u16 *len)
+{
+ struct netsec_de de = {};
+
+ memcpy(&de, dring->vaddr + DESC_SZ * idx, DESC_SZ);
+
+ *len = de.buf_len_info >> 16;
+
+ rxpi->err_flag = (de.attr >> NETSEC_RX_PKT_ER_FIELD) & 1;
+ rxpi->rx_cksum_result = (de.attr >> NETSEC_RX_PKT_CO_FIELD) & 3;
+ rxpi->err_code = (de.attr >> NETSEC_RX_PKT_ERR_FIELD) &
+ NETSEC_RX_PKT_ERR_MASK;
+ *desc = dring->desc[idx];
+ return desc->skb;
+}
+
+static struct sk_buff *netsec_get_rx_pkt_data(struct netsec_priv *priv,
+ struct netsec_rx_pkt_info *rxpi,
+ struct netsec_desc *desc,
+ u16 *len)
+{
+ struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_RX];
+ struct sk_buff *tmp_skb, *skb = NULL;
+ struct netsec_desc td;
+ int tail;
+
+ *rxpi = (struct netsec_rx_pkt_info){};
+
+ td.len = priv->ndev->mtu + 22;
+
+ tmp_skb = netsec_alloc_skb(priv, &td);
+
+ dma_rmb();
+
+ tail = DRING_TAIL(dring);
+
+ if (!tmp_skb) {
+ netsec_set_rx_de(priv, dring, tail, &dring->desc[tail],
+ dring->desc[tail].skb);
+ } else {
+ skb = netsec_get_rx_de(priv, dring, tail, rxpi, desc, len);
+ netsec_set_rx_de(priv, dring, tail, &td, tmp_skb);
+ }
+
+ MOVE_TAIL(dring);
+ dring->pkt_cnt--;
+
+ return skb;
+}
+
+static int netsec_clean_tx_dring(struct netsec_priv *priv, int budget)
+{
+ struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_TX];
+ unsigned int pkts, bytes;
+
+ dring->pkt_cnt += netsec_read(priv, NETSEC_REG_NRM_TX_DONE_PKTCNT);
+
+ if (dring->pkt_cnt < budget)
+ budget = dring->pkt_cnt;
+
+ pkts = 0;
+ bytes = 0;
+
+ while (pkts < budget) {
+ struct netsec_desc *desc;
+ struct netsec_de *entry;
+ int tail, eop;
+
+ tail = DRING_TAIL(dring);
+ MOVE_TAIL(dring);
+
+ desc = &dring->desc[tail];
+ entry = dring->vaddr + DESC_SZ * tail;
+
+ eop = (entry->attr >> NETSEC_TX_LAST) & 1;
+
+ dma_unmap_single(priv->dev, desc->dma_addr, desc->len,
+ DMA_TO_DEVICE);
+ if (eop) {
+ pkts++;
+ bytes += desc->skb->len;
+ dev_kfree_skb(desc->skb);
+ }
+ *desc = (struct netsec_desc){};
+ }
+ dring->pkt_cnt -= budget;
+
+ priv->ndev->stats.tx_packets += budget;
+ priv->ndev->stats.tx_bytes += bytes;
+
+ netdev_completed_queue(priv->ndev, budget, bytes);
+
+ return budget;
+}
+
+static int netsec_process_tx(struct netsec_priv *priv, int budget)
+{
+ struct net_device *ndev = priv->ndev;
+ int new, done = 0;
+
+ do {
+ new = netsec_clean_tx_dring(priv, budget);
+ done += new;
+ budget -= new;
+ } while (new);
+
+ if (done && netif_queue_stopped(ndev))
+ netif_wake_queue(ndev);
+
+ return done;
+}
+
+static int netsec_process_rx(struct netsec_priv *priv, int budget)
+{
+ struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_RX];
+ struct net_device *ndev = priv->ndev;
+ struct netsec_rx_pkt_info rx_info;
+ int done = 0, rx_num = 0;
+ struct netsec_desc desc;
+ struct sk_buff *skb;
+ u16 len;
+
+ while (done < budget) {
+ if (!rx_num) {
+ rx_num = netsec_read(priv, NETSEC_REG_NRM_RX_PKTCNT);
+ dring->pkt_cnt += rx_num;
+ JUMP_HEAD(dring, rx_num);
+
+ rx_num = dring->pkt_cnt;
+ if (!rx_num)
+ break;
+ }
+ done++;
+ rx_num--;
+ skb = netsec_get_rx_pkt_data(priv, &rx_info, &desc, &len);
+ if (unlikely(!skb) || rx_info.err_flag) {
+ netif_err(priv, drv, priv->ndev,
+ "%s: rx fail err(%d)\n",
+ __func__, rx_info.err_code);
+ ndev->stats.rx_dropped++;
+ continue;
+ }
+
+ dma_unmap_single(priv->dev, desc.dma_addr, desc.len,
+ DMA_FROM_DEVICE);
+ skb_put(skb, len);
+ skb->protocol = eth_type_trans(skb, priv->ndev);
+
+ if (priv->rx_cksum_offload_flag &&
+ rx_info.rx_cksum_result == NETSEC_RX_CKSUM_OK)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ if (napi_gro_receive(&priv->napi, skb) != GRO_DROP) {
+ ndev->stats.rx_packets++;
+ ndev->stats.rx_bytes += len;
+ }
+ }
+
+ return done;
+}
+
+static int netsec_napi_poll(struct napi_struct *napi, int budget)
+{
+ struct netsec_priv *priv;
+ struct net_device *ndev;
+ int tx, rx, done, todo;
+
+ priv = container_of(napi, struct netsec_priv, napi);
+ ndev = priv->ndev;
+
+ todo = budget;
+ do {
+ if (!todo)
+ break;
+
+ tx = netsec_process_tx(priv, todo);
+ todo -= tx;
+
+ if (!todo)
+ break;
+
+ rx = netsec_process_rx(priv, todo);
+ todo -= rx;
+ } while (rx || tx);
+
+ done = budget - todo;
+
+ if (done < budget && napi_complete_done(napi, done)) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->reglock, flags);
+ netsec_write(priv, NETSEC_REG_INTEN_SET,
+ NETSEC_IRQ_RX | NETSEC_IRQ_TX);
+ spin_unlock_irqrestore(&priv->reglock, flags);
+ }
+
+ return done;
+}
+
+static void netsec_set_tx_de(struct netsec_priv *priv,
+ struct netsec_desc_ring *dring,
+ const struct netsec_tx_pkt_ctrl *tx_ctrl,
+ const struct netsec_desc *desc,
+ struct sk_buff *skb)
+{
+ struct netsec_de *de;
+ int idx = DRING_HEAD(dring);
+ u32 attr;
+
+ de = dring->vaddr + (DESC_SZ * idx);
+
+ attr = (1 << NETSEC_TX_SHIFT_OWN_FIELD) |
+ (1 << NETSEC_TX_SHIFT_PT_FIELD) |
+ (NETSEC_RING_GMAC << NETSEC_TX_SHIFT_TDRID_FIELD) |
+ (1 << NETSEC_TX_SHIFT_FS_FIELD) |
+ (1 << NETSEC_TX_LAST) |
+ (tx_ctrl->cksum_offload_flag << NETSEC_TX_SHIFT_CO) |
+ (tx_ctrl->tcp_seg_offload_flag << NETSEC_TX_SHIFT_SO) |
+ (1 << NETSEC_TX_SHIFT_TRS_FIELD);
+ if (idx == DESC_NUM - 1)
+ attr |= (1 << NETSEC_TX_SHIFT_LD_FIELD);
+
+ de->data_buf_addr_up = upper_32_bits(desc->dma_addr);
+ de->data_buf_addr_lw = lower_32_bits(desc->dma_addr);
+ de->buf_len_info = (tx_ctrl->tcp_seg_len << 16) | desc->len;
+ de->attr = attr;
+ dma_wmb();
+
+ dring->desc[idx] = *desc;
+ dring->desc[idx].skb = skb;
+
+ MOVE_HEAD(dring);
+}
+
+static netdev_tx_t netsec_netdev_start_xmit(struct sk_buff *skb,
+ struct net_device *ndev)
+{
+ struct netsec_priv *priv = netdev_priv(ndev);
+ struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_TX];
+ struct netsec_tx_pkt_ctrl tx_ctrl = {};
+ struct netsec_desc tx_desc;
+ u16 tso_seg_len = 0;
+
+ /* differentiate between full/emtpy ring */
+ if (available_descs(dring) < 2) {
+ netif_err(priv, drv, priv->ndev, "%s: TxQFull!\n", __func__);
+ netif_stop_queue(priv->ndev);
+ dma_wmb();
+ return NETDEV_TX_BUSY;
+ }
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ tx_ctrl.cksum_offload_flag = true;
+
+ if (skb_is_gso(skb))
+ tso_seg_len = skb_shinfo(skb)->gso_size;
+
+ if (tso_seg_len > 0) {
+ if (skb->protocol == htons(ETH_P_IP)) {
+ ip_hdr(skb)->tot_len = 0;
+ tcp_hdr(skb)->check =
+ ~tcp_v4_check(0, ip_hdr(skb)->saddr,
+ ip_hdr(skb)->daddr, 0);
+ } else {
+ ipv6_hdr(skb)->payload_len = 0;
+ tcp_hdr(skb)->check =
+ ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+ &ipv6_hdr(skb)->daddr,
+ 0, IPPROTO_TCP, 0);
+ }
+
+ tx_ctrl.tcp_seg_offload_flag = true;
+ tx_ctrl.tcp_seg_len = tso_seg_len;
+ }
+
+ tx_desc.dma_addr = dma_map_single(priv->dev, skb->data,
+ skb_headlen(skb), DMA_TO_DEVICE);
+ if (dma_mapping_error(priv->dev, tx_desc.dma_addr)) {
+ netif_err(priv, drv, priv->ndev,
+ "%s: DMA mapping failed\n", __func__);
+ ndev->stats.tx_dropped++;
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+ tx_desc.addr = skb->data;
+ tx_desc.len = skb_headlen(skb);
+
+ skb_tx_timestamp(skb);
+ netdev_sent_queue(priv->ndev, skb->len);
+
+ netsec_set_tx_de(priv, dring, &tx_ctrl, &tx_desc, skb);
+ netsec_write(priv, NETSEC_REG_NRM_TX_PKTCNT, 1); /* submit another tx */
+
+ return NETDEV_TX_OK;
+}
+
+static void netsec_uninit_pkt_dring(struct netsec_priv *priv, int id)
+{
+ struct netsec_desc_ring *dring = &priv->desc_ring[id];
+ struct netsec_desc *desc;
+ u16 idx;
+
+ if (!dring->vaddr || !dring->desc)
+ return;
+
+ for (idx = 0; idx < DESC_NUM; idx++) {
+ desc = &dring->desc[idx];
+ if (!desc->addr)
+ continue;
+
+ dma_unmap_single(priv->dev, desc->dma_addr, desc->len,
+ id == NETSEC_RING_RX ? DMA_FROM_DEVICE :
+ DMA_TO_DEVICE);
+ dev_kfree_skb(desc->skb);
+ }
+
+ memset(dring->desc, 0, sizeof(struct netsec_desc) * DESC_NUM);
+ memset(dring->vaddr, 0, DESC_SZ * DESC_NUM);
+
+ dring->head = 0;
+ dring->tail = 0;
+ dring->pkt_cnt = 0;
+}
+
+static void netsec_free_dring(struct netsec_priv *priv, int id)
+{
+ struct netsec_desc_ring *dring = &priv->desc_ring[id];
+
+ if (dring->vaddr) {
+ dma_free_coherent(priv->dev, DESC_SZ * DESC_NUM,
+ dring->vaddr, dring->desc_phys);
+ dring->vaddr = NULL;
+ }
+
+ kfree(dring->desc);
+ dring->desc = NULL;
+}
+
+static int netsec_alloc_dring(struct netsec_priv *priv, enum ring_id id)
+{
+ struct netsec_desc_ring *dring = &priv->desc_ring[id];
+ int ret = 0;
+
+ dring->vaddr = dma_zalloc_coherent(priv->dev, DESC_SZ * DESC_NUM,
+ &dring->desc_phys, GFP_KERNEL);
+ if (!dring->vaddr) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ dring->desc = kzalloc(DESC_NUM * sizeof(*dring->desc), GFP_KERNEL);
+ if (!dring->desc) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ return 0;
+err:
+ netsec_free_dring(priv, id);
+
+ return ret;
+}
+
+static int netsec_setup_rx_dring(struct netsec_priv *priv)
+{
+ struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_RX];
+ struct netsec_desc desc;
+ struct sk_buff *skb;
+ int n;
+
+ desc.len = priv->ndev->mtu + 22;
+
+ for (n = 0; n < DESC_NUM; n++) {
+ skb = netsec_alloc_skb(priv, &desc);
+ if (!skb) {
+ netsec_uninit_pkt_dring(priv, NETSEC_RING_RX);
+ return -ENOMEM;
+ }
+ netsec_set_rx_de(priv, dring, n, &desc, skb);
+ }
+
+ return 0;
+}
+
+static int netsec_netdev_load_ucode_region(struct netsec_priv *priv, u32 reg,
+ u32 addr_h, u32 addr_l, u32 size)
+{
+ u64 base = (u64)addr_h << 32 | addr_l;
+ __le32 *ucode;
+ u32 i;
+
+ ucode = memremap(base, size * sizeof(u32), MEMREMAP_WT);
+ if (!ucode)
+ return -ENOMEM;
+
+ for (i = 0; i < size; i++)
+ netsec_write(priv, reg, le32_to_cpu(ucode[i]));
+
+ memunmap(ucode);
+ return 0;
+}
+
+static int netsec_netdev_load_microcode(struct netsec_priv *priv)
+{
+ int err;
+
+ err = netsec_netdev_load_ucode_region(
+ priv, NETSEC_REG_DMAC_HM_CMD_BUF,
+ le32_to_cpup(priv->eeprom_base + NETSEC_EEPROM_HM_ME_ADDRESS_H),
+ le32_to_cpup(priv->eeprom_base + NETSEC_EEPROM_HM_ME_ADDRESS_L),
+ le32_to_cpup(priv->eeprom_base + NETSEC_EEPROM_HM_ME_SIZE));
+ if (err)
+ return err;
+
+ err = netsec_netdev_load_ucode_region(
+ priv, NETSEC_REG_DMAC_MH_CMD_BUF,
+ le32_to_cpup(priv->eeprom_base + NETSEC_EEPROM_MH_ME_ADDRESS_H),
+ le32_to_cpup(priv->eeprom_base + NETSEC_EEPROM_MH_ME_ADDRESS_L),
+ le32_to_cpup(priv->eeprom_base + NETSEC_EEPROM_MH_ME_SIZE));
+ if (err)
+ return err;
+
+ err = netsec_netdev_load_ucode_region(
+ priv, NETSEC_REG_PKT_CMD_BUF,
+ 0,
+ le32_to_cpup(priv->eeprom_base + NETSEC_EEPROM_PKT_ME_ADDRESS),
+ le32_to_cpup(priv->eeprom_base + NETSEC_EEPROM_PKT_ME_SIZE));
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int netsec_reset_hardware(struct netsec_priv *priv)
+{
+ u32 value;
+ int err;
+
+ /* stop DMA engines */
+ if (!netsec_read(priv, NETSEC_REG_ADDR_DIS_CORE)) {
+ netsec_write(priv, NETSEC_REG_DMA_HM_CTRL,
+ NETSEC_DMA_CTRL_REG_STOP);
+ netsec_write(priv, NETSEC_REG_DMA_MH_CTRL,
+ NETSEC_DMA_CTRL_REG_STOP);
+
+ while (netsec_read(priv, NETSEC_REG_DMA_HM_CTRL) &
+ NETSEC_DMA_CTRL_REG_STOP)
+ cpu_relax();
+
+ while (netsec_read(priv, NETSEC_REG_DMA_MH_CTRL) &
+ NETSEC_DMA_CTRL_REG_STOP)
+ cpu_relax();
+ }
+
+ netsec_write(priv, NETSEC_REG_SOFT_RST, NETSEC_SOFT_RST_REG_RESET);
+ netsec_write(priv, NETSEC_REG_SOFT_RST, NETSEC_SOFT_RST_REG_RUN);
+ netsec_write(priv, NETSEC_REG_COM_INIT, NETSEC_COM_INIT_REG_ALL);
+
+ while (netsec_read(priv, NETSEC_REG_COM_INIT) != 0)
+ cpu_relax();
+
+ /* set desc_start addr */
+ netsec_write(priv, NETSEC_REG_NRM_RX_DESC_START_UP,
+ upper_32_bits(priv->desc_ring[NETSEC_RING_RX].desc_phys));
+ netsec_write(priv, NETSEC_REG_NRM_RX_DESC_START_LW,
+ lower_32_bits(priv->desc_ring[NETSEC_RING_RX].desc_phys));
+
+ netsec_write(priv, NETSEC_REG_NRM_TX_DESC_START_UP,
+ upper_32_bits(priv->desc_ring[NETSEC_RING_TX].desc_phys));
+ netsec_write(priv, NETSEC_REG_NRM_TX_DESC_START_LW,
+ lower_32_bits(priv->desc_ring[NETSEC_RING_TX].desc_phys));
+
+ /* set normal tx dring ring config */
+ netsec_write(priv, NETSEC_REG_NRM_TX_CONFIG,
+ 1 << NETSEC_REG_DESC_ENDIAN);
+ netsec_write(priv, NETSEC_REG_NRM_RX_CONFIG,
+ 1 << NETSEC_REG_DESC_ENDIAN);
+
+ err = netsec_netdev_load_microcode(priv);
+ if (err) {
+ netif_err(priv, probe, priv->ndev,
+ "%s: failed to load microcode (%d)\n", __func__, err);
+ return err;
+ }
+
+ /* start DMA engines */
+ netsec_write(priv, NETSEC_REG_DMA_TMR_CTRL, priv->freq / 1000000 - 1);
+ netsec_write(priv, NETSEC_REG_ADDR_DIS_CORE, 0);
+
+ usleep_range(1000, 2000);
+
+ if (!(netsec_read(priv, NETSEC_REG_TOP_STATUS) &
+ NETSEC_TOP_IRQ_REG_CODE_LOAD_END)) {
+ netif_err(priv, probe, priv->ndev,
+ "microengine start failed\n");
+ return -ENXIO;
+ }
+ netsec_write(priv, NETSEC_REG_TOP_STATUS,
+ NETSEC_TOP_IRQ_REG_CODE_LOAD_END);
+
+ value = NETSEC_PKT_CTRL_REG_MODE_NRM;
+ if (priv->ndev->mtu > ETH_DATA_LEN)
+ value |= NETSEC_PKT_CTRL_REG_EN_JUMBO;
+
+ /* change to normal mode */
+ netsec_write(priv, NETSEC_REG_DMA_MH_CTRL, MH_CTRL__MODE_TRANS);
+ netsec_write(priv, NETSEC_REG_PKT_CTRL, value);
+
+ while ((netsec_read(priv, NETSEC_REG_MODE_TRANS_COMP_STATUS) &
+ NETSEC_MODE_TRANS_COMP_IRQ_T2N) == 0)
+ cpu_relax();
+
+ /* clear any pending EMPTY/ERR irq status */
+ netsec_write(priv, NETSEC_REG_NRM_TX_STATUS, ~0);
+
+ /* Disable TX & RX intr */
+ netsec_write(priv, NETSEC_REG_INTEN_CLR, ~0);
+
+ return 0;
+}
+
+static int netsec_start_gmac(struct netsec_priv *priv)
+{
+ struct phy_device *phydev = priv->ndev->phydev;
+ u32 value = 0;
+ int ret;
+
+ if (phydev->speed != SPEED_1000)
+ value = (NETSEC_GMAC_MCR_REG_CST |
+ NETSEC_GMAC_MCR_REG_HALF_DUPLEX_COMMON);
+
+ if (netsec_mac_write(priv, GMAC_REG_MCR, value))
+ return -ETIMEDOUT;
+ if (netsec_mac_write(priv, GMAC_REG_BMR,
+ NETSEC_GMAC_BMR_REG_RESET))
+ return -ETIMEDOUT;
+
+ /* Wait soft reset */
+ usleep_range(1000, 5000);
+
+ ret = netsec_mac_read(priv, GMAC_REG_BMR, &value);
+ if (ret)
+ return ret;
+ if (value & NETSEC_GMAC_BMR_REG_SWR)
+ return -EAGAIN;
+
+ netsec_write(priv, MAC_REG_DESC_SOFT_RST, 1);
+ if (netsec_wait_while_busy(priv, MAC_REG_DESC_SOFT_RST, 1))
+ return -ETIMEDOUT;
+
+ netsec_write(priv, MAC_REG_DESC_INIT, 1);
+ if (netsec_wait_while_busy(priv, MAC_REG_DESC_INIT, 1))
+ return -ETIMEDOUT;
+
+ if (netsec_mac_write(priv, GMAC_REG_BMR,
+ NETSEC_GMAC_BMR_REG_COMMON))
+ return -ETIMEDOUT;
+ if (netsec_mac_write(priv, GMAC_REG_RDLAR,
+ NETSEC_GMAC_RDLAR_REG_COMMON))
+ return -ETIMEDOUT;
+ if (netsec_mac_write(priv, GMAC_REG_TDLAR,
+ NETSEC_GMAC_TDLAR_REG_COMMON))
+ return -ETIMEDOUT;
+ if (netsec_mac_write(priv, GMAC_REG_MFFR, 0x80000001))
+ return -ETIMEDOUT;
+
+ ret = netsec_mac_update_to_phy_state(priv);
+ if (ret)
+ return ret;
+
+ ret = netsec_mac_read(priv, GMAC_REG_OMR, &value);
+ if (ret)
+ return ret;
+
+ value |= NETSEC_GMAC_OMR_REG_SR;
+ value |= NETSEC_GMAC_OMR_REG_ST;
+
+ netsec_write(priv, NETSEC_REG_NRM_RX_INTEN_CLR, ~0);
+ netsec_write(priv, NETSEC_REG_NRM_TX_INTEN_CLR, ~0);
+
+ netsec_et_set_coalesce(priv->ndev, &priv->et_coalesce);
+
+ if (netsec_mac_write(priv, GMAC_REG_OMR, value))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int netsec_stop_gmac(struct netsec_priv *priv)
+{
+ u32 value;
+ int ret;
+
+ ret = netsec_mac_read(priv, GMAC_REG_OMR, &value);
+ if (ret)
+ return ret;
+ value &= ~NETSEC_GMAC_OMR_REG_SR;
+ value &= ~NETSEC_GMAC_OMR_REG_ST;
+
+ /* disable all interrupts */
+ netsec_write(priv, NETSEC_REG_NRM_RX_INTEN_CLR, ~0);
+ netsec_write(priv, NETSEC_REG_NRM_TX_INTEN_CLR, ~0);
+
+ return netsec_mac_write(priv, GMAC_REG_OMR, value);
+}
+
+static void netsec_phy_adjust_link(struct net_device *ndev)
+{
+ struct netsec_priv *priv = netdev_priv(ndev);
+
+ if (ndev->phydev->link)
+ netsec_start_gmac(priv);
+ else
+ netsec_stop_gmac(priv);
+
+ phy_print_status(ndev->phydev);
+}
+
+static irqreturn_t netsec_irq_handler(int irq, void *dev_id)
+{
+ struct netsec_priv *priv = dev_id;
+ u32 val, status = netsec_read(priv, NETSEC_REG_TOP_STATUS);
+ unsigned long flags;
+
+ /* Disable interrupts */
+ if (status & NETSEC_IRQ_TX) {
+ val = netsec_read(priv, NETSEC_REG_NRM_TX_STATUS);
+ netsec_write(priv, NETSEC_REG_NRM_TX_STATUS, val);
+ }
+ if (status & NETSEC_IRQ_RX) {
+ val = netsec_read(priv, NETSEC_REG_NRM_RX_STATUS);
+ netsec_write(priv, NETSEC_REG_NRM_RX_STATUS, val);
+ }
+
+ spin_lock_irqsave(&priv->reglock, flags);
+ netsec_write(priv, NETSEC_REG_INTEN_CLR, NETSEC_IRQ_RX | NETSEC_IRQ_TX);
+ spin_unlock_irqrestore(&priv->reglock, flags);
+
+ napi_schedule(&priv->napi);
+
+ return IRQ_HANDLED;
+}
+
+static int netsec_netdev_open(struct net_device *ndev)
+{
+ struct netsec_priv *priv = netdev_priv(ndev);
+ int ret;
+
+ pm_runtime_get_sync(priv->dev);
+
+ ret = netsec_setup_rx_dring(priv);
+ if (ret) {
+ netif_err(priv, probe, priv->ndev,
+ "%s: fail setup ring\n", __func__);
+ goto err1;
+ }
+
+ ret = request_irq(priv->ndev->irq, netsec_irq_handler,
+ IRQF_SHARED, "netsec", priv);
+ if (ret) {
+ netif_err(priv, drv, priv->ndev, "request_irq failed\n");
+ goto err2;
+ }
+
+ if (dev_of_node(priv->dev)) {
+ if (!of_phy_connect(priv->ndev, priv->phy_np,
+ netsec_phy_adjust_link, 0,
+ priv->phy_interface)) {
+ netif_err(priv, link, priv->ndev, "missing PHY\n");
+ goto err3;
+ }
+ } else {
+ ret = phy_connect_direct(priv->ndev, priv->phydev,
+ netsec_phy_adjust_link,
+ priv->phy_interface);
+ if (ret) {
+ netif_err(priv, link, priv->ndev,
+ "phy_connect_direct() failed (%d)\n", ret);
+ goto err3;
+ }
+ }
+
+ phy_start(ndev->phydev);
+
+ netsec_start_gmac(priv);
+ napi_enable(&priv->napi);
+ netif_start_queue(ndev);
+
+ /* Enable RX intr. */
+ netsec_write(priv, NETSEC_REG_INTEN_SET, NETSEC_IRQ_RX);
+
+ return 0;
+err3:
+ free_irq(priv->ndev->irq, priv);
+err2:
+ netsec_uninit_pkt_dring(priv, NETSEC_RING_RX);
+err1:
+ pm_runtime_put_sync(priv->dev);
+ return ret;
+}
+
+static int netsec_netdev_stop(struct net_device *ndev)
+{
+ struct netsec_priv *priv = netdev_priv(ndev);
+
+ netif_stop_queue(priv->ndev);
+ dma_wmb();
+
+ napi_disable(&priv->napi);
+
+ netsec_write(priv, NETSEC_REG_INTEN_CLR, ~0);
+ netsec_stop_gmac(priv);
+
+ free_irq(priv->ndev->irq, priv);
+
+ netsec_uninit_pkt_dring(priv, NETSEC_RING_TX);
+ netsec_uninit_pkt_dring(priv, NETSEC_RING_RX);
+
+ phy_stop(ndev->phydev);
+ phy_disconnect(ndev->phydev);
+
+ pm_runtime_put_sync(priv->dev);
+
+ return 0;
+}
+
+static int netsec_netdev_init(struct net_device *ndev)
+{
+ struct netsec_priv *priv = netdev_priv(ndev);
+ int ret;
+
+ ret = netsec_alloc_dring(priv, NETSEC_RING_TX);
+ if (ret)
+ return ret;
+
+ ret = netsec_alloc_dring(priv, NETSEC_RING_RX);
+ if (ret)
+ goto err1;
+
+ ret = netsec_reset_hardware(priv);
+ if (ret)
+ goto err2;
+
+ return 0;
+err2:
+ netsec_free_dring(priv, NETSEC_RING_RX);
+err1:
+ netsec_free_dring(priv, NETSEC_RING_TX);
+ return ret;
+}
+
+static void netsec_netdev_uninit(struct net_device *ndev)
+{
+ struct netsec_priv *priv = netdev_priv(ndev);
+
+ netsec_free_dring(priv, NETSEC_RING_RX);
+ netsec_free_dring(priv, NETSEC_RING_TX);
+}
+
+static int netsec_netdev_set_features(struct net_device *ndev,
+ netdev_features_t features)
+{
+ struct netsec_priv *priv = netdev_priv(ndev);
+
+ priv->rx_cksum_offload_flag = !!(features & NETIF_F_RXCSUM);
+
+ return 0;
+}
+
+static const struct net_device_ops netsec_netdev_ops = {
+ .ndo_init = netsec_netdev_init,
+ .ndo_uninit = netsec_netdev_uninit,
+ .ndo_open = netsec_netdev_open,
+ .ndo_stop = netsec_netdev_stop,
+ .ndo_start_xmit = netsec_netdev_start_xmit,
+ .ndo_set_features = netsec_netdev_set_features,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+/*************************************************************/
+/*************************************************************/
+
+static int netsec_of_probe(struct platform_device *pdev,
+ struct netsec_priv *priv)
+{
+ int clk_count, ret, i;
+
+ priv->phy_np = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
+ if (!priv->phy_np) {
+ dev_err(&pdev->dev, "missing required property 'phy-handle'\n");
+ return -EINVAL;
+ }
+
+ /* we require named clocks if there is more than one */
+ clk_count = of_property_count_strings(pdev->dev.of_node, "clock-names");
+ if (clk_count > 1) {
+ if (clk_count > ARRAY_SIZE(priv->clk)) {
+ dev_err(&pdev->dev, "too many clocks specified (%d)\n",
+ clk_count);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < clk_count; i++) {
+ const char *clk_name;
+
+ ret = of_property_read_string_index(pdev->dev.of_node,
+ "clock-names", i,
+ &clk_name);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "failed to parse 'clock-names'\n");
+ return ret;
+ }
+ priv->clk[i] = devm_clk_get(&pdev->dev, clk_name);
+ if (!strcmp(clk_name, "phy_refclk")) {
+ priv->freq = clk_get_rate(priv->clk[i]);
+ dev_dbg(&pdev->dev,
+ "found PHY refclock #%d freq %u\n",
+ i, priv->freq);
+ }
+ }
+ priv->clock_count = clk_count;
+ } else {
+ priv->clk[0] = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ dev_err(&pdev->dev,
+ "missing required property 'clocks'\n");
+ return PTR_ERR(priv->clk);
+ }
+ priv->freq = clk_get_rate(priv->clk[0]);
+ priv->clock_count = 1;
+ }
+ return 0;
+}
+
+static int netsec_acpi_probe(struct platform_device *pdev,
+ struct netsec_priv *priv, u32 *phy_addr)
+{
+ int ret;
+
+ if (!IS_ENABLED(CONFIG_ACPI))
+ return -ENODEV;
+
+ ret = device_property_read_u32(&pdev->dev, "phy-channel", phy_addr);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "missing required property 'phy-channel'\n");
+ return ret;
+ }
+
+ ret = device_property_read_u32(&pdev->dev,
+ "socionext,phy-clock-frequency",
+ &priv->freq);
+ if (ret)
+ dev_err(&pdev->dev,
+ "missing required property 'socionext,phy-clock-frequency'\n");
+ return ret;
+}
+
+static void netsec_unregister_mdio(struct netsec_priv *priv)
+{
+ struct phy_device *phydev = priv->phydev;
+
+ if (!dev_of_node(priv->dev) && phydev) {
+ phy_device_remove(phydev);
+ phy_device_free(phydev);
+ }
+
+ mdiobus_unregister(priv->mii_bus);
+}
+
+static int netsec_register_mdio(struct netsec_priv *priv, u32 phy_addr)
+{
+ struct mii_bus *bus;
+ int ret;
+
+ bus = devm_mdiobus_alloc(priv->dev);
+ if (!bus)
+ return -ENOMEM;
+
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(priv->dev));
+ bus->priv = priv;
+ bus->name = "SNI NETSEC MDIO";
+ bus->read = netsec_phy_read;
+ bus->write = netsec_phy_write;
+ bus->parent = priv->dev;
+ priv->mii_bus = bus;
+
+ if (dev_of_node(priv->dev)) {
+ ret = of_mdiobus_register(bus, dev_of_node(priv->dev));
+ if (ret) {
+ dev_err(priv->dev, "mdiobus register err(%d)\n", ret);
+ return ret;
+ }
+ } else {
+ /* Mask out all PHYs from auto probing. */
+ bus->phy_mask = ~0;
+ ret = mdiobus_register(bus);
+ if (ret) {
+ dev_err(priv->dev, "mdiobus register err(%d)\n", ret);
+ return ret;
+ }
+
+ priv->phydev = get_phy_device(priv->mii_bus, phy_addr, false);
+ if (IS_ERR(priv->phydev)) {
+ ret = PTR_ERR(priv->phydev);
+ dev_err(priv->dev, "get_phy_device err(%d)\n", ret);
+ priv->phydev = NULL;
+ return -ENODEV;
+ }
+
+ ret = phy_device_register(priv->phydev);
+ if (ret)
+ dev_err(priv->dev,
+ "phy_device_register err(%d)\n", ret);
+ }
+
+ return ret;
+}
+
+static int netsec_probe(struct platform_device *pdev)
+{
+ struct resource *mmio_res, *eeprom_res, *irq_res;
+ u8 *mac, macbuf[ETH_ALEN];
+ struct netsec_priv *priv;
+ struct net_device *ndev;
+ u32 hw_ver, phy_addr = 0;
+ int ret;
+
+ mmio_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mmio_res) {
+ dev_err(&pdev->dev, "No MMIO resource found.\n");
+ return -ENODEV;
+ }
+
+ eeprom_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!eeprom_res) {
+ dev_info(&pdev->dev, "No EEPROM resource found.\n");
+ return -ENODEV;
+ }
+
+ irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!irq_res) {
+ dev_err(&pdev->dev, "No IRQ resource found.\n");
+ return -ENODEV;
+ }
+
+ ndev = alloc_etherdev(sizeof(*priv));
+ if (!ndev)
+ return -ENOMEM;
+
+ priv = netdev_priv(ndev);
+
+ spin_lock_init(&priv->reglock);
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+ platform_set_drvdata(pdev, priv);
+ ndev->irq = irq_res->start;
+ priv->dev = &pdev->dev;
+ priv->ndev = ndev;
+
+ priv->msg_enable = NETIF_MSG_TX_ERR | NETIF_MSG_HW | NETIF_MSG_DRV |
+ NETIF_MSG_LINK | NETIF_MSG_PROBE;
+
+ priv->phy_interface = device_get_phy_mode(&pdev->dev);
+ if (priv->phy_interface < 0) {
+ dev_err(&pdev->dev, "missing required property 'phy-mode'\n");
+ ret = -ENODEV;
+ goto free_ndev;
+ }
+
+ priv->ioaddr = devm_ioremap(&pdev->dev, mmio_res->start,
+ resource_size(mmio_res));
+ if (!priv->ioaddr) {
+ dev_err(&pdev->dev, "devm_ioremap() failed\n");
+ ret = -ENXIO;
+ goto free_ndev;
+ }
+
+ priv->eeprom_base = devm_memremap(&pdev->dev, eeprom_res->start,
+ resource_size(eeprom_res),
+ MEMREMAP_WT);
+ if (!priv->eeprom_base) {
+ dev_err(&pdev->dev, "devm_memremap() failed for EEPROM\n");
+ ret = -ENXIO;
+ goto free_ndev;
+ }
+
+ mac = device_get_mac_address(&pdev->dev, macbuf, sizeof(macbuf));
+ if (mac)
+ ether_addr_copy(ndev->dev_addr, mac);
+
+ if (priv->eeprom_base &&
+ (!mac || !is_valid_ether_addr(ndev->dev_addr))) {
+ const u8 *macp = priv->eeprom_base + NETSEC_EEPROM_MAC_ADDRESS;
+
+ ndev->dev_addr[0] = macp[3];
+ ndev->dev_addr[1] = macp[2];
+ ndev->dev_addr[2] = macp[1];
+ ndev->dev_addr[3] = macp[0];
+ ndev->dev_addr[4] = macp[7];
+ ndev->dev_addr[5] = macp[6];
+ }
+
+ if (!is_valid_ether_addr(ndev->dev_addr)) {
+ dev_warn(&pdev->dev, "No MAC address found, using random\n");
+ eth_hw_addr_random(ndev);
+ }
+
+ if (dev_of_node(&pdev->dev))
+ ret = netsec_of_probe(pdev, priv);
+ else
+ ret = netsec_acpi_probe(pdev, priv, &phy_addr);
+ if (ret)
+ goto free_ndev;
+
+ if (!priv->freq) {
+ dev_err(&pdev->dev, "missing PHY reference clock frequency\n");
+ ret = -ENODEV;
+ goto free_ndev;
+ }
+
+ /* default for throughput */
+ priv->et_coalesce.rx_coalesce_usecs = 500;
+ priv->et_coalesce.rx_max_coalesced_frames = 8;
+ priv->et_coalesce.tx_coalesce_usecs = 500;
+ priv->et_coalesce.tx_max_coalesced_frames = 8;
+
+ ret = device_property_read_u32(&pdev->dev, "max-frame-size",
+ &ndev->max_mtu);
+ if (ret < 0)
+ ndev->max_mtu = ETH_DATA_LEN;
+
+ /* runtime_pm coverage just for probe, open/close also cover it */
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+
+ hw_ver = netsec_read(priv, NETSEC_REG_F_TAIKI_VER);
+ /* this driver only supports F_TAIKI style NETSEC */
+ if (NETSEC_F_NETSEC_VER_MAJOR_NUM(hw_ver) !=
+ NETSEC_F_NETSEC_VER_MAJOR_NUM(NETSEC_REG_NETSEC_VER_F_TAIKI)) {
+ ret = -ENODEV;
+ goto pm_disable;
+ }
+
+ dev_info(&pdev->dev, "hardware revision %d.%d\n",
+ hw_ver >> 16, hw_ver & 0xffff);
+
+ netif_napi_add(ndev, &priv->napi, netsec_napi_poll, NAPI_BUDGET);
+
+ ndev->netdev_ops = &netsec_netdev_ops;
+ ndev->ethtool_ops = &netsec_ethtool_ops;
+
+ ndev->features |= NETIF_F_HIGHDMA | NETIF_F_RXCSUM | NETIF_F_GSO |
+ NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+ ndev->hw_features = ndev->features;
+
+ priv->rx_cksum_offload_flag = true;
+
+ ret = netsec_register_mdio(priv, phy_addr);
+ if (ret)
+ goto unreg_napi;
+
+ if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)))
+ dev_warn(&pdev->dev, "Failed to enable 64-bit DMA\n");
+
+ ret = register_netdev(ndev);
+ if (ret) {
+ netif_err(priv, probe, ndev, "register_netdev() failed\n");
+ goto unreg_mii;
+ }
+
+ pm_runtime_put_sync(&pdev->dev);
+ return 0;
+
+unreg_mii:
+ netsec_unregister_mdio(priv);
+unreg_napi:
+ netif_napi_del(&priv->napi);
+pm_disable:
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+free_ndev:
+ free_netdev(ndev);
+ dev_err(&pdev->dev, "init failed\n");
+
+ return ret;
+}
+
+static int netsec_remove(struct platform_device *pdev)
+{
+ struct netsec_priv *priv = platform_get_drvdata(pdev);
+
+ unregister_netdev(priv->ndev);
+
+ netsec_unregister_mdio(priv);
+
+ netif_napi_del(&priv->napi);
+
+ pm_runtime_disable(&pdev->dev);
+ free_netdev(priv->ndev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int netsec_runtime_suspend(struct device *dev)
+{
+ struct netsec_priv *priv = dev_get_drvdata(dev);
+ int n;
+
+ netsec_write(priv, NETSEC_REG_CLK_EN, 0);
+
+ for (n = priv->clock_count - 1; n >= 0; n--)
+ clk_disable_unprepare(priv->clk[n]);
+
+ return 0;
+}
+
+static int netsec_runtime_resume(struct device *dev)
+{
+ struct netsec_priv *priv = dev_get_drvdata(dev);
+ int n;
+
+ /* first let the clocks back on */
+ for (n = 0; n < priv->clock_count; n++)
+ clk_prepare_enable(priv->clk[n]);
+
+ netsec_write(priv, NETSEC_REG_CLK_EN, NETSEC_CLK_EN_REG_DOM_D |
+ NETSEC_CLK_EN_REG_DOM_C |
+ NETSEC_CLK_EN_REG_DOM_G);
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops netsec_pm_ops = {
+ SET_RUNTIME_PM_OPS(netsec_runtime_suspend, netsec_runtime_resume, NULL)
+};
+
+static const struct of_device_id netsec_dt_ids[] = {
+ { .compatible = "socionext,synquacer-netsec" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, netsec_dt_ids);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id netsec_acpi_ids[] = {
+ { "SCX0001" },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, netsec_acpi_ids);
+#endif
+
+static struct platform_driver netsec_driver = {
+ .probe = netsec_probe,
+ .remove = netsec_remove,
+ .driver = {
+ .name = "netsec",
+ .pm = &netsec_pm_ops,
+ .of_match_table = netsec_dt_ids,
+ .acpi_match_table = ACPI_PTR(netsec_acpi_ids),
+ },
+};
+module_platform_driver(netsec_driver);
+
+MODULE_AUTHOR("Jassi Brar <jaswinder.singh@linaro.org>");
+MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
+MODULE_DESCRIPTION("NETSEC Ethernet driver");
+MODULE_LICENSE("GPL");
--
2.7.4
^ permalink raw reply related
* [PATCH 3/3] MAINTAINERS: Add entry for Socionext ethernet driver
From: jassisinghbrar @ 2017-11-30 16:13 UTC (permalink / raw)
To: netdev, devicetree
Cc: davem, arnd.bergmann, ard.biesheuvel, robh+dt, mark.rutland,
Jassi Brar
From: Jassi Brar <jaswinder.singh@linaro.org>
Add entry for the Socionext Netsec controller driver and DT bindings.
Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
---
MAINTAINERS | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index aa71ab52f..aed9d32 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12617,6 +12617,14 @@ F: drivers/md/raid*
F: include/linux/raid/
F: include/uapi/linux/raid/
+SOCIONEXT (SNI) NETSEC NETWORK DRIVER
+M: Jassi Brar <jaswinder.singh@linaro.org>
+L: netdev@vger.kernel.org
+S: Supported
+S: Maintained
+F: drivers/net/ethernet/socionext/netsec.c
+F: Documentation/devicetree/bindings/net/socionext-netsec.txt
+
SONIC NETWORK DRIVER
M: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
L: netdev@vger.kernel.org
--
2.7.4
^ permalink raw reply related
* Re: [PATCH v2 5/8] ARM: dts: am335x-pepper: Fix the audio CODEC's reset pin
From: Tony Lindgren @ 2017-11-30 16:18 UTC (permalink / raw)
To: Andrew F. Davis
Cc: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland,
Benoît Cousson, Shawn Guo, Sascha Hauer, alsa-devel,
devicetree, linux-kernel
In-Reply-To: <20171129171359.29382-6-afd@ti.com>
* Andrew F. Davis <afd@ti.com> [171129 17:16]:
> The correct DT property for specifying a GPIO used for reset
> is "reset-gpios", fix this here.
>
> Fixes: 4341881d0562 ("ARM: dts: Add devicetree for Gumstix Pepper board")
So it seems this and patch 8/8 are safe for me to pick separately?
Regards,
Tony
> Signed-off-by: Andrew F. Davis <afd@ti.com>
> ---
> arch/arm/boot/dts/am335x-pepper.dts | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/arm/boot/dts/am335x-pepper.dts b/arch/arm/boot/dts/am335x-pepper.dts
> index 03c7d77023c6..9fb7426070ce 100644
> --- a/arch/arm/boot/dts/am335x-pepper.dts
> +++ b/arch/arm/boot/dts/am335x-pepper.dts
> @@ -139,7 +139,7 @@
> &audio_codec {
> status = "okay";
>
> - gpio-reset = <&gpio1 16 GPIO_ACTIVE_LOW>;
> + reset-gpios = <&gpio1 16 GPIO_ACTIVE_LOW>;
> AVDD-supply = <&ldo3_reg>;
> IOVDD-supply = <&ldo3_reg>;
> DRVDD-supply = <&ldo3_reg>;
> --
> 2.15.0
>
^ permalink raw reply
* Re: [PATCH v2 2/2] ASoC: codecs: Add initial PCM1862/63/64/65 universal ADC driver
From: Mark Brown @ 2017-11-30 16:31 UTC (permalink / raw)
To: Andrew F. Davis
Cc: Mark Rutland, devicetree, alsa-devel, Liam Girdwood, linux-kernel,
Rob Herring
In-Reply-To: <d4f015ab-3b17-dab8-33ba-4144b7571554@ti.com>
[-- Attachment #1.1: Type: text/plain, Size: 1098 bytes --]
On Thu, Nov 30, 2017 at 09:56:08AM -0600, Andrew F. Davis wrote:
> On 11/30/2017 06:20 AM, Mark Brown wrote:
> > disable them. Based on what I think the intention is I'd suggest
> > removing the bias level handling and then having probe enable runtime
> > PM with the device flagged as active, letting runtime PM do any
> > disabling if the device is idle.
> I beleive this was meant to be be SIMPLE_DEV_PM_OPS and not
> SET_RUNTIME_PM_OPS. I'll fix this all up for v3.
I was wondering that.
> Just thinking, the sound core sets SND_SOC_BIAS_OFF before suspend
> anyway, right? So the results would be similar just having all the PM
> stuff in the bias level handling for consistency, but I'm open to
> whatever is the preferred way.
It doesn't matter that much, if you do it only in set_bias_level() then
unless you set idle_bias_off there will be no runtime PM which may or
may not be what you want and you'll also not give the user the ability
to control if runtime PM happens via the sysfs files but I'm not
convinced that anyone ever actually does that. Either approach is fine
really.
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply
* Re: [PATCH 3/3] MAINTAINERS: Add entry for Socionext ethernet driver
From: Joe Perches @ 2017-11-30 16:33 UTC (permalink / raw)
To: jassisinghbrar-Re5JQEeQqe8AvxtiuMwx3w,
netdev-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: davem-fT/PcQaiUtIeIZ0/mPfg9Q,
arnd.bergmann-QSEj5FYQhm4dnm+yROfE0A,
ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
Jassi Brar
In-Reply-To: <1512058416-15968-1-git-send-email-jassisinghbrar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On Thu, 2017-11-30 at 21:43 +0530, jassisinghbrar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org wrote:
> Add entry for the Socionext Netsec controller driver and DT bindings.
[]
> diff --git a/MAINTAINERS b/MAINTAINERS
[]
> @@ -12617,6 +12617,14 @@ F: drivers/md/raid*
> F: include/linux/raid/
> F: include/uapi/linux/raid/
>
> +SOCIONEXT (SNI) NETSEC NETWORK DRIVER
> +M: Jassi Brar <jaswinder.singh-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> +L: netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> +S: Supported
> +S: Maintained
One S: line per customer...
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v2 5/8] ARM: dts: am335x-pepper: Fix the audio CODEC's reset pin
From: Mark Brown @ 2017-11-30 16:33 UTC (permalink / raw)
To: Tony Lindgren
Cc: Andrew F. Davis, Liam Girdwood, Rob Herring, Mark Rutland,
Benoît Cousson, Shawn Guo, Sascha Hauer,
alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20171130161826.GP28152-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 324 bytes --]
On Thu, Nov 30, 2017 at 08:18:26AM -0800, Tony Lindgren wrote:
> So it seems this and patch 8/8 are safe for me to pick separately?
It might make sense to pull in the relevant branches from ASoC first
however IIRC the reset GPIO code currently does nothing useful anyway so
it won't have any impact on bisection. Andrew?
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH v2 5/8] ARM: dts: am335x-pepper: Fix the audio CODEC's reset pin
From: Andrew F. Davis @ 2017-11-30 16:37 UTC (permalink / raw)
To: Mark Brown, Tony Lindgren
Cc: Mark Rutland, devicetree, alsa-devel, Sascha Hauer, Liam Girdwood,
linux-kernel, Rob Herring, Benoît Cousson, Shawn Guo
In-Reply-To: <20171130163344.kudopvsljywb4hyw@sirena.org.uk>
On 11/30/2017 10:33 AM, Mark Brown wrote:
> On Thu, Nov 30, 2017 at 08:18:26AM -0800, Tony Lindgren wrote:
>
>> So it seems this and patch 8/8 are safe for me to pick separately?
>
> It might make sense to pull in the relevant branches from ASoC first
> however IIRC the reset GPIO code currently does nothing useful anyway so
> it won't have any impact on bisection. Andrew?
>
Yeah, that's right, for safety it would be nice to take these after the
ASoC code, but it shouldn't matter in practice as the reset wasn't used
right anyway.
^ permalink raw reply
* Re: [PATCH 1/2] dt-binding: can: mcp2517fd: document device tree bindings
From: Patrick Menschel @ 2017-11-30 16:44 UTC (permalink / raw)
To: kernel-TqfNSX0MhmxHKSADF0wUEw
Cc: linux-can-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <612BB6CD-5330-40B8-A854-FD065E0A3331-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 1945 bytes --]
Am 30.11.2017 um 08:24 schrieb kernel-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org:
> I understand, but the question still is: how to
> present the information in a valid way.
>
> To use gpio propperly it would require that the driver
> implements a “sub-driver” pinctrl with all the extra
> (boilerplate) code overhead.
>
> Also this would mean mixing different types of
> logical drivers into a single source - I doubt that
> would be easy to get accepted...
>
> Here again a summary of all the GPIOs that the mcp2517fd has:
> * TXCAN: dedicated GPIO with single function,
> individually conigurable as push/pull or open drain
> * INT: main interrupt line - configurable as push/pull or
> individually conigurable as push/pull or open drain
> * GPIO0: general GPIO with in/out option, but 2 special “cases”:
> tx-irq and TX-disable
> group configurable as push/pull or open drain
> * GPIO1: general GPIO with in/out potion, but 1 special “cases”:
> rx-irq
> group configurable as push/pull or open drain
> * CLKO/SOF: clock output at (1/10th, 1/5th, 1/2, 1 of the
> core frequency) or start of frame output
> possibly group configurable as push/pull or open drain
> (not explicitly specified in datasheet)
>
> How would you try to present that HW-configuration in the
> device tree instead?
> How would it impact the driver design?
>
Hi,
I'm afraid I don't know what is best practice but you may want to look
at the max310x driver which declares it's GPIOs and GPIO based
interrupts in the regular driver.
drivers/tty/serial/max310x.c
Documentation/devicetree/bindings/serial/maxim,max310x.txt
Look for "#ifdef CONFIG_GPIOLIB".
My first try would be a single dt node like the max310x uses in the dt
example.
Imho it is better to make things useful before making them complicated.
Regards,
Patrick
[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 3992 bytes --]
^ permalink raw reply
* Re: [PATCH v2 5/8] ARM: dts: am335x-pepper: Fix the audio CODEC's reset pin
From: Mark Brown @ 2017-11-30 16:53 UTC (permalink / raw)
To: Andrew F. Davis
Cc: Mark Rutland, devicetree, alsa-devel, Sascha Hauer, Tony Lindgren,
Liam Girdwood, linux-kernel, Rob Herring, Benoît Cousson,
Shawn Guo
In-Reply-To: <4b535cec-6e33-adc0-a962-f5e65d84d1ad@ti.com>
[-- Attachment #1.1: Type: text/plain, Size: 498 bytes --]
On Thu, Nov 30, 2017 at 10:37:22AM -0600, Andrew F. Davis wrote:
> On 11/30/2017 10:33 AM, Mark Brown wrote:
> > It might make sense to pull in the relevant branches from ASoC first
> > however IIRC the reset GPIO code currently does nothing useful anyway so
> > it won't have any impact on bisection. Andrew?
> Yeah, that's right, for safety it would be nice to take these after the
> ASoC code, but it shouldn't matter in practice as the reset wasn't used
> right anyway.
I'd just go for it.
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply
* Re: [RFC v2 2/2] backlight: pwm_bl: compute brightness of LED linearly to human eye.
From: Doug Anderson @ 2017-11-30 16:57 UTC (permalink / raw)
To: Daniel Thompson
Cc: Enric Balletbo i Serra, Jingoo Han, Richard Purdie,
Jacek Anaszewski, Pavel Machek, Rob Herring, Brian Norris,
Guenter Roeck, Lee Jones, Alexandru Stan,
linux-leds-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, LKML
In-Reply-To: <c6450f50-5c12-dc52-4340-b068c0b38c54-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Hi,
On Thu, Nov 30, 2017 at 3:27 AM, Daniel Thompson
<daniel.thompson-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
>
>
> On 30/11/17 00:44, Doug Anderson wrote:
>>
>> Hi,
>>
>> On Thu, Nov 16, 2017 at 6:11 AM, Enric Balletbo i Serra
>> <enric.balletbo-ZGY8ohtN/8qB+jHODAdFcQ@public.gmane.org> wrote:
>>>
>>> When you want to change the brightness using a PWM signal, one thing you
>>> need to consider is how human perceive the brightness. Human perceive the
>>> brightness change non-linearly, we have better sensitivity at low
>>> luminance than high luminance, so to achieve perceived linear dimming,
>>> the
>>> brightness must be matches to the way our eyes behave. The CIE 1931
>>> lightness formula is what actually describes how we perceive light.
>>>
>>> This patch adds support to compute the brightness levels based on a
>>> static
>>> table filled with the numbers provided by the CIE 1931 algorithm, for now
>>> it only supports PWM resolutions up to 65535 (16 bits) with 1024 steps.
>>> Lower PWM resolutions are implemented using the same curve but with less
>>> steps, e.g. For a PWM resolution of 256 (8 bits) we have 37 steps.
>>
>>
>> Your patch assumes that the input to your formula (luminance, I think)
>> scales linearly with PWM duty cycle. I don't personally know this,
>> but has anyone confirmed it's common in reality, or at least is a
>> close enough approximation of reality?
>
>
> Isn't this the loop we went round for v1?
>
> We do know that its not linear, however the graphs from a couple of example
> devices didn't look too scary and nobody has proposed a better formula.
>
> At this point the linear interpolation code in patch 1 allows people with
> especially alinear devices to express suitable brightness curves.
>
> However we also know that many DT authors choose not to create good
> brightness tables for their devices... and we'd rather they used allowed the
> kernel to choose a model than to use no model at all.
OK, cool. I didn't remember anyone actually confirming that they had
checked that this was the case, but that's probably just my bad memory
and failures at searching through history. I don't have any
objections to the idea if people are convinced it's a good enough
approximation. :)
It would be kinda nice if something could go in the commit message, like:
This method will work in any cases where linearly scaling the PWM duty
cycle causes a roughly linear scaling of the luminance of the
backlight.
:)
-Doug
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 1/2] dt-binding: can: mcp2517fd: document device tree bindings
From: kernel-TqfNSX0MhmxHKSADF0wUEw @ 2017-11-30 16:58 UTC (permalink / raw)
To: Patrick Menschel; +Cc: linux-can-u79uwXL29TY76Z2rM5mHXA, devicetree
In-Reply-To: <6aea8071-dc21-4ba7-2b2f-5af41b5755a5-1KBjaw7Xf1+zQB+pC5nmwQ@public.gmane.org>
Hi Patrick!
> On 30.11.2017, at 17:44, Patrick Menschel <menschel.p-1KBjaw7Xf1+zQB+pC5nmwQ@public.gmane.org> wrote:
>> How would you try to present that HW-configuration in the
>> device tree instead?
>> How would it impact the driver design?
>>
> Hi,
> I'm afraid I don't know what is best practice but you may want to look
> at the max310x driver which declares it's GPIOs and GPIO based
> interrupts in the regular driver.
>
> drivers/tty/serial/max310x.c
> Documentation/devicetree/bindings/serial/maxim,max310x.txt
> Look for "#ifdef CONFIG_GPIOLIB”.
This is a gpio-controller, for which this is what I would implement.
The problem comes more from the fact that the mcp2517fd is
primarily a CAN controller, which has a few GPIO pins.
So implementing a gpio-controller for those (rarely used) GPIOs
in the same driver seems a bit of an overkill.
The mcp2515 chip also supports 5 GPIO pins, but the driver
does not really make use of them, so they are left out.
The problem here is more the fact that the mcp2517fd supports
also push-pull/open-drain on some of those gpios.
And at least openDrain may be required on TXCan if used on a network
without a transceiver…
> My first try would be a single dt node like the max310x uses in the dt
> example.
> Imho it is better to make things useful before making them complicated.
The settings as they are now are the “simple” version.
implementing a separate GPIO-controller driver just to implement the same
logic we have now would make it a much bigger driver without lots of extra
benefits.
So I hope the current proposal is ok...
Martin--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v2 5/8] ARM: dts: am335x-pepper: Fix the audio CODEC's reset pin
From: Tony Lindgren @ 2017-11-30 17:00 UTC (permalink / raw)
To: Mark Brown
Cc: Andrew F. Davis, Liam Girdwood, Rob Herring, Mark Rutland,
Benoît Cousson, Shawn Guo, Sascha Hauer, alsa-devel,
devicetree, linux-kernel
In-Reply-To: <20171130165328.q5nknyvwp36xj4t2@sirena.org.uk>
* Mark Brown <broonie@kernel.org> [171130 16:56]:
> On Thu, Nov 30, 2017 at 10:37:22AM -0600, Andrew F. Davis wrote:
> > On 11/30/2017 10:33 AM, Mark Brown wrote:
>
> > > It might make sense to pull in the relevant branches from ASoC first
> > > however IIRC the reset GPIO code currently does nothing useful anyway so
> > > it won't have any impact on bisection. Andrew?
>
> > Yeah, that's right, for safety it would be nice to take these after the
> > ASoC code, but it shouldn't matter in practice as the reset wasn't used
> > right anyway.
>
> I'd just go for it.
OK will apply the two omap dts changes for v4.16.
Thanks,
Tony
^ permalink raw reply
* Re: [PATCH v2 2/2] ARM: dts: at91: disable the nxp,se97b SMBUS timeout on the TSE-850
From: Guenter Roeck @ 2017-11-30 17:16 UTC (permalink / raw)
To: Alexandre Belloni
Cc: Peter Rosin, linux-kernel, Rob Herring, Mark Rutland,
Nicolas Ferre, Russell King, Jean Delvare, Ludovic Desroches,
devicetree, linux-arm-kernel, linux-hwmon
In-Reply-To: <20171129205629.GO21126@piout.net>
On Wed, Nov 29, 2017 at 09:56:29PM +0100, Alexandre Belloni wrote:
> On 29/11/2017 at 12:53:11 -0800, Guenter Roeck wrote:
> > On Mon, Nov 27, 2017 at 05:31:01PM +0100, Peter Rosin wrote:
> > > The I2C adapter driver is sometimes slow, causing the SCL line to
> > > be stuck low for more than the stipulated SMBUS timeout of 25-35 ms.
> > > This causes the client device to give up which in turn causes silent
> > > corruption of data. So, disable the SMBUS timeout in the client device.
> > >
> > > Signed-off-by: Peter Rosin <peda@axentia.se>
> >
> > Acked-by: Guenter Roeck <linux@roeck-us.net>
> >
> > I assume this will be sent upstream through an arm tree.
> >
>
> Yes, I'm applying it right now.
>
Are you going to apply the patch for 4.15, or queue it up for 4.16 ?
I have been arguing with myself if this is a feature or a bug fix.
So far I queued the driver change up for 4.16, but I am open to
applying it to 4.15. Any thoughts ?
Guenter
> > Thanks,
> > Guenter
> >
> > > ---
> > > arch/arm/boot/dts/at91-tse850-3.dts | 1 +
> > > 1 file changed, 1 insertion(+)
> > >
> > > diff --git a/arch/arm/boot/dts/at91-tse850-3.dts b/arch/arm/boot/dts/at91-tse850-3.dts
> > > index 5f29010cdbd8..9b82cc8843e1 100644
> > > --- a/arch/arm/boot/dts/at91-tse850-3.dts
> > > +++ b/arch/arm/boot/dts/at91-tse850-3.dts
> > > @@ -221,6 +221,7 @@
> > > jc42@18 {
> > > compatible = "nxp,se97b", "jedec,jc-42.4-temp";
> > > reg = <0x18>;
> > > + smbus-timeout-disable;
> > > };
> > >
> > > dpot: mcp4651-104@28 {
> > > --
> > > 2.11.0
> > >
>
> --
> Alexandre Belloni, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com
^ 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