* Re: nfp bpf offload add/replace
From: Jakub Kicinski @ 2017-09-07 13:44 UTC (permalink / raw)
To: Jiri Pirko; +Cc: netdev, mlxsw, Daniel Borkmann, Simon Horman
In-Reply-To: <20170907091033.GD1967@nanopsycho>
On Thu, 7 Sep 2017 11:10:33 +0200, Jiri Pirko wrote:
> Hi Kuba.
>
> I'm looking into cls_bpf code and nfp_net_bpf_offload function in your
> driver. Why do you need TC_CLSBPF_ADD? Seems like TC_CLSBPF_REPLACE
> should be enough. It would make the cls_bpf code easier.
>
> Note that other cls just have replace/destroy (u32 too, as drivers
> handle NEW/REPLACE in one switch-case - will patch this).
Could we clarify what the REPLACE is actually supposed to do? :)
In the flower code and the REPLACE looks a lot like ADD on the
surface... If change is called it will invoke REPLACE with the new
filter and then if there was an old filter, it will do DELETE. Is my
understanding correct?
If so I found this model of operation somehow confusing. Plus the
management of flows may get slightly tricky if there is a possibility of
"replacing" a flow with an identical one. Flower may make calls like
these:
add flower vlan_id 100 action ...
# REPLACE vid 100 ...
change ... flower vlan_id 100 action ...
# REPLACE vid 100 ...
# DELETE vid 100 ...
Doesn't this force driver/HW to implement refcounting on the rules?
On why I need the replace - BPF unlike other classifiers usually
installs a single program, I think offloading multiple TC filters is
questionable (people will use tailcalls instead most likely). I want to
be able to implement atomic replace of that single program (i.e. not ADD
followed by DELETE) because that simplifies the driver quite a bit.
^ permalink raw reply
* Re:
From: Quick Loan @ 2017-09-07 13:34 UTC (permalink / raw)
Hello dear I am an International loan lender, I give out loans at 1% interest
rate, email me at:(rich_ken2016@usa.com)
^ permalink raw reply
* Re: [PATCH 0/2] net: Fix crashes due to activity during suspend
From: Florian Fainelli @ 2017-09-07 13:09 UTC (permalink / raw)
To: Geert Uytterhoeven, andrew
Cc: marc_gonzalez, slash.tmp, Geert Uytterhoeven, David S . Miller,
Steve Glendinning, Lukas Wunner, Rafael J . Wysocki,
netdev@vger.kernel.org, Linux PM list, Linux-Renesas,
linux-kernel@vger.kernel.org
In-Reply-To: <5a1b6f23-6fce-1a68-f9c3-ca0d709979e7@gmail.com>
On 08/23/2017 10:13 AM, Florian Fainelli wrote:
> On 08/23/2017 04:45 AM, Geert Uytterhoeven wrote:
>> Hi Florian,
>>
>> On Tue, Aug 22, 2017 at 8:49 PM, Florian Fainelli <f.fainelli@gmail.com> wrote:
>>> On 08/22/2017 11:37 AM, Geert Uytterhoeven wrote:
>>>> If an Ethernet device is used while the device is suspended, the system may
>>>> crash.
>>>>
>>>> E.g. on sh73a0/kzm9g and r8a73a4/ape6evm, the external Ethernet chip is
>>>> driven by a PM controlled clock. If the Ethernet registers are accessed
>>>> while the clock is not running, the system will crash with an imprecise
>>>> external abort.
>>>>
>>>> This patch series fixes two of such crashes:
>>>> 1. The first patch prevents the PHY polling state machine from accessing
>>>> PHY registers while a device is suspended,
>>>> 2. The second patch prevents the net core from trying to transmit packets
>>>> when an smsc911x device is suspended.
>>>>
>>>> Both crashes can be reproduced on sh73a0/kzm9g and r8a73a4/ape6evm during
>>>> s2ram (rarely), or by using pm_test (more likely to trigger):
>>>>
>>>> # echo 0 > /sys/module/printk/parameters/console_suspend
>>>> # echo platform > /sys/power/pm_test
>>>> # echo mem > /sys/power/state
>>>>
>>>> With this series applied, my test systems survive a loop of 100 test
>>>> suspends.
>>>
>>> It seems to me like part, if not the entire problem is that smsc91xx's
>>> suspend and resume functions are way too simplistic and absolutely do
>>> not manage the PHY during suspend/resume, the PHY state machine is not
>>> even stopped, so of course, this will cause bus errors if you access
>>> those registers.
>>>
>>> You are addressing this as part of patch 2, but this seems to me like
>>> this is still a bit incomplete and you'd need at least phy_stop() and/or
>>> phy_suspend() (does a power down of the PHY) and phy_start() and/or
>>> phy_resume() calls to complete the PHY state machine shutdown during
>>> suspend.
>>>
>>> Have you tried that?
>>
>> Unfortunately that doesn't help.
>> In state PHY_HALTED, the PHY state machine still calls the .adjust_link()
>> callback while the device is suspended.
>
> Humm that is correct yes.
>
>>
>> Do you have a clue? This is too far beyond my phy-foo...
>
> I was initially contemplating a revert of
> 7ad813f208533cebfcc32d3d7474dc1677d1b09a ("net: phy: Correctly process
> PHY_HALTED in phy_stop_machine()") but this is not the root of the
> problem. The problem really is that phy_stop() does not wait for the PHY
> state machine to be stopped so you cannot rely on that and past the
> function return be offered any guarantees that adjust_link is not called.
>
> We seem to be getting away with that in most drivers because when we see
> phydev->link = 0, we either do nothing or actually turn of the HW block.
>
> How about we export phy_stop_machine() to drivers which would provide a
> synchronization point that would ensure that no HW accesses are done
> past this point?
>
> I am absolutely not clear on the implications of using a freezable
> workqueue with respect to the PHY state machine and how devices are
> going to wind-up being powered down or not...
Geert, as you may have notice a revert of the change was sent so 4.13
should be fine, but ultimately I would like to put the non-reverted code
back in after we add a few safeguards:
- David Daney reported he could crash the kernel by calling just
phy_disconnect() with no prior phy_stop() which is not "legal" but
should not crash either
- and you reported the bus errors on smsc911x when we call adjust_link
during suspend, and due to a lack of hard synchronization so phy_stop()
here does not give you enough guarantees to let you turn off power to
the smsc911x block
If that seems accurate then we can work on something that should be
working again (famous last words).
Thanks
--
Florian
^ permalink raw reply
* Re: [RFC net-next 0/5] TSN: Add qdisc-based config interfaces for traffic shapers
From: Richard Cochran @ 2017-09-07 12:40 UTC (permalink / raw)
To: Henrik Austad
Cc: Vinicius Costa Gomes, netdev, jhs, xiyou.wangcong, jiri,
intel-wired-lan, andre.guedes, ivan.briano,
jesus.sanchez-palencia, boon.leong.ong
In-Reply-To: <20170907053411.GA6580@sisyphus.home.austad.us>
On Thu, Sep 07, 2017 at 07:34:11AM +0200, Henrik Austad wrote:
> Also, does this mean that when you create the qdisc, you have locked the
> bandwidth for the scheduler? Meaning, if I later want to add another
> stream that requires more bandwidth, I have to close all active streams,
> reconfigure the qdisc and then restart?
No, just allocate enough bandwidth to accomodate all of the expected
streams. The streams can start and stop at will.
> So my understanding of all of this is that you configure the *total*
> bandwith for each class when you load the qdisc and then let userspace
> handle the rest. Is this correct?
Nothing wrong with that.
> In my view, it would be nice if the qdisc had some notion about streams so
> that you could create a stream, feed frames to it and let the driver pace
> them out. (The fewer you queue, the shorter the delay). This will also
> allow you to enforce per-stream bandwidth restrictions. I don't see how you
> can do this here unless you want to do this in userspace.
>
> Do you have any plans for adding support for multiplexing streams? If you
> have multiple streams, how do you enforce that one stream does not eat into
> the bandwidth of another stream? AFAIK, this is something the network must
> enforce, but I see no option of doing som here.
Please, lets keep this simple. Today we have exactly zero user space
applications using this kind of bandwidth reservation. The case of
wanting the kernel to police individual stream usage does not exist,
and probably never will.
For serious TSN use cases, the bandwidth needed by each system and
indeed the entire network will be engineered, and we can reasonably
expect applications to cooperate in this regard.
Thanks,
Richard
^ permalink raw reply
* Re: [PATCH] iwlwifi: mvm: only send LEDS_CMD when the FW supports it
From: Kalle Valo @ 2017-09-07 12:39 UTC (permalink / raw)
To: torvalds, Luca Coelho
Cc: linux-wireless, johannes, linux-kernel, akpm, netdev, davem,
emmanuel.grumbach, Luca Coelho
In-Reply-To: <20170907075152.4522-1-luca@coelho.fi>
Luca Coelho <luca@coelho.fi> writes:
> From: Luca Coelho <luciano.coelho@intel.com>
>
> The LEDS_CMD command is only supported in some newer FW versions
> (e.g. iwlwifi-8000C-31.ucode), so we can't send it to older versions
> (such as iwlwifi-8000C-27.ucode).
>
> To fix this, check for a new bit in the FW capabilities TLV that tells
> when the command is supported.
>
> Note that the current version of -31.ucode in linux-firmware.git
> (31.532993.0) does not have this capability bit set, so the LED won't
> work, even though this version should support it. But we will update
> this firmware soon, so it won't be a problem anymore.
>
> Fixes: 7089ae634c50 ("iwlwifi: mvm: use firmware LED command where applicable")
> Reported-by: Linus Torvalds <torvalds@linux-foundation.org>
> Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Linus, do you want to apply this directly or should we take it via the
normal route (wireless-drivers -> net)? If your prefer the latter when
I'm planning to submit this to Dave in a day or two and expecting it to
get to your tree in about a week, depending of course what is Dave's
schedule.
--
Kalle Valo
^ permalink raw reply
* [V2 PATCH net-next 2/2] xdp: catch invalid XDP_REDIRECT API usage
From: Jesper Dangaard Brouer @ 2017-09-07 12:33 UTC (permalink / raw)
To: netdev, David S. Miller
Cc: Daniel Borkmann, John Fastabend, Andy Gospodarek,
Jesper Dangaard Brouer
In-Reply-To: <150478756604.28665.6915020425359475729.stgit@firesoul>
Catch different invalid XDP_REDIRECT and bpf_redirect_map API usage.
It is fairly easy to create a dangling redirect_info->map pointer,
which (until John or Daniel fix this) can crash the kernel.
The intended usage of the BPF helper bpf_redirect_map(), is to return
XDP_REDIRECT action after invoking it, but there is nothing stopping
the bpf_prog to return anything else. When XDP_REDIRECT isn't
returned, then a dangling ->map pointer is left behind, as
xdp_do_redirect() isn't called.
This also happens for drivers not implementing XDP_REDIRECT, as they
are not aware of this new XDP_REDIRECT return code, they leave the map
pointer dangling.
The simply solution to check for a dangling ->map pointer after each
driver napi->poll() invocation, see xdp_do_map_check().
This patch also add a check for a dangling ->map_to_flush pointer.
This should be considered a driver bug, as the driver contract is that
a pair of xdp_do_redirect and xdp_do_flush_map MUST be called in the
same cpu context.
Note, we need to check after each drivers napi->poll call, as:
1. DevA poll call bpf_redirect_map() but not xdp_do_redirect()
2. DevB bpf_prog uses bpf_redirect() and call xdp_do_redirect()
which now use map from DevA
Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
---
include/linux/filter.h | 1 +
net/core/dev.c | 3 +++
net/core/filter.c | 25 +++++++++++++++++++++++++
3 files changed, 29 insertions(+)
diff --git a/include/linux/filter.h b/include/linux/filter.h
index d29e58fde364..0c48941e0022 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -724,6 +724,7 @@ int xdp_do_redirect(struct net_device *dev,
struct xdp_buff *xdp,
struct bpf_prog *prog);
void xdp_do_flush_map(void);
+void xdp_do_map_check(struct napi_struct *napi);
void bpf_warn_invalid_xdp_action(u32 act);
void bpf_warn_invalid_xdp_redirect(u32 ifindex);
diff --git a/net/core/dev.c b/net/core/dev.c
index 6f845e4fec17..7eac642b469f 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5320,6 +5320,7 @@ static void busy_poll_stop(struct napi_struct *napi, void *have_poll_lock)
*/
rc = napi->poll(napi, BUSY_POLL_BUDGET);
trace_napi_poll(napi, rc, BUSY_POLL_BUDGET);
+ xdp_do_map_check(napi);
netpoll_poll_unlock(have_poll_lock);
if (rc == BUSY_POLL_BUDGET)
__napi_schedule(napi);
@@ -5367,6 +5368,7 @@ void napi_busy_loop(unsigned int napi_id,
}
work = napi_poll(napi, BUSY_POLL_BUDGET);
trace_napi_poll(napi, work, BUSY_POLL_BUDGET);
+ xdp_do_map_check(napi);
count:
if (work > 0)
__NET_ADD_STATS(dev_net(napi->dev),
@@ -5529,6 +5531,7 @@ static int napi_poll(struct napi_struct *n, struct list_head *repoll)
if (test_bit(NAPI_STATE_SCHED, &n->state)) {
work = n->poll(n, weight);
trace_napi_poll(n, work, weight);
+ xdp_do_map_check(n);
}
WARN_ON_ONCE(work > weight);
diff --git a/net/core/filter.c b/net/core/filter.c
index 3767470cab6c..f0e1135eeb9d 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -2500,6 +2500,31 @@ void xdp_do_flush_map(void)
}
EXPORT_SYMBOL_GPL(xdp_do_flush_map);
+void xdp_do_map_check(struct napi_struct *napi)
+{
+ struct redirect_info *ri = this_cpu_ptr(&redirect_info);
+
+ /* XDP drivers (and XDP-generic) must invoke xdp_do_redirect()
+ * when bpf_prog use helper bpf_redirect_map(), else the map
+ * pointer can be left dangling. Catch this invalid API
+ * usage, instead of potentially crashing.
+ */
+ if (ri->map) {
+ ri->map = NULL;
+ net_err_ratelimited("%s: caught invalid XDP bpf_redirect_map\n",
+ napi->dev->name);
+ trace_xdp_exception(napi->dev, NULL, XDP_REDIRECT);
+ }
+ if (ri->map_to_flush) { /* Driver bug */
+ net_err_ratelimited("%s: XDP driver miss xdp_do_flush_map\n",
+ napi->dev->name);
+ trace_xdp_exception(napi->dev, NULL, XDP_REDIRECT);
+ /* Flush map, else pkts can be stuck on XDP TXq */
+ xdp_do_flush_map();
+ }
+}
+EXPORT_SYMBOL_GPL(xdp_do_map_check);
+
static int xdp_do_redirect_map(struct net_device *dev, struct xdp_buff *xdp,
struct bpf_prog *xdp_prog)
{
^ permalink raw reply related
* [V2 PATCH net-next 1/2] xdp: implement xdp_redirect_map for generic XDP
From: Jesper Dangaard Brouer @ 2017-09-07 12:33 UTC (permalink / raw)
To: netdev, David S. Miller
Cc: Daniel Borkmann, John Fastabend, Andy Gospodarek,
Jesper Dangaard Brouer
In-Reply-To: <150478756604.28665.6915020425359475729.stgit@firesoul>
Using bpf_redirect_map is allowed for generic XDP programs, but the
appropriate map lookup was never performed in xdp_do_generic_redirect().
Instead the map-index is directly used as the ifindex. For the
xdp_redirect_map sample in SKB-mode '-S', this resulted in trying
sending on ifindex 0 which isn't valid, resulting in getting SKB
packets dropped. Thus, the reported performance numbers are wrong in
commit 24251c264798 ("samples/bpf: add option for native and skb mode
for redirect apps") for the 'xdp_redirect_map -S' case.
It might seem innocent this was lacking, but it can actually crash the
kernel. The potential crash is caused by not consuming redirect_info->map.
The bpf_redirect_map helper will set this_cpu_ptr(&redirect_info)->map
pointer, which will survive even after unloading the xdp bpf_prog and
deallocating the devmap data-structure. This leaves a dead map
pointer around. The kernel will crash when loading the xdp_redirect
sample (in native XDP mode) as it doesn't reset map (via bpf_redirect)
and returns XDP_REDIRECT, which will cause it to dereference the map
pointer.
Fixes: 6103aa96ec07 ("net: implement XDP_REDIRECT for xdp generic")
Fixes: 24251c264798 ("samples/bpf: add option for native and skb mode for redirect apps")
Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
---
include/trace/events/xdp.h | 4 ++--
net/core/filter.c | 14 +++++++++++---
2 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/include/trace/events/xdp.h b/include/trace/events/xdp.h
index 862575ac8da9..4e16c43fba10 100644
--- a/include/trace/events/xdp.h
+++ b/include/trace/events/xdp.h
@@ -138,11 +138,11 @@ DEFINE_EVENT_PRINT(xdp_redirect_template, xdp_redirect_map_err,
#define _trace_xdp_redirect_map(dev, xdp, fwd, map, idx) \
trace_xdp_redirect_map(dev, xdp, fwd ? fwd->ifindex : 0, \
- 0, map, idx);
+ 0, map, idx)
#define _trace_xdp_redirect_map_err(dev, xdp, fwd, map, idx, err) \
trace_xdp_redirect_map_err(dev, xdp, fwd ? fwd->ifindex : 0, \
- err, map, idx);
+ err, map, idx)
#endif /* _TRACE_XDP_H */
diff --git a/net/core/filter.c b/net/core/filter.c
index 5912c738a7b2..3767470cab6c 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -2566,13 +2566,19 @@ int xdp_do_generic_redirect(struct net_device *dev, struct sk_buff *skb,
struct bpf_prog *xdp_prog)
{
struct redirect_info *ri = this_cpu_ptr(&redirect_info);
+ struct bpf_map *map = ri->map;
u32 index = ri->ifindex;
struct net_device *fwd;
unsigned int len;
int err = 0;
- fwd = dev_get_by_index_rcu(dev_net(dev), index);
ri->ifindex = 0;
+ ri->map = NULL;
+
+ if (map)
+ fwd = __dev_map_lookup_elem(map, index);
+ else
+ fwd = dev_get_by_index_rcu(dev_net(dev), index);
if (unlikely(!fwd)) {
err = -EINVAL;
goto err;
@@ -2590,10 +2596,12 @@ int xdp_do_generic_redirect(struct net_device *dev, struct sk_buff *skb,
}
skb->dev = fwd;
- _trace_xdp_redirect(dev, xdp_prog, index);
+ map ? _trace_xdp_redirect_map(dev, xdp_prog, fwd, map, index)
+ : _trace_xdp_redirect(dev, xdp_prog, index);
return 0;
err:
- _trace_xdp_redirect_err(dev, xdp_prog, index, err);
+ map ? _trace_xdp_redirect_map_err(dev, xdp_prog, fwd, map, index, err)
+ : _trace_xdp_redirect_err(dev, xdp_prog, index, err);
return err;
}
EXPORT_SYMBOL_GPL(xdp_do_generic_redirect);
^ permalink raw reply related
* [V2 PATCH net-next 0/2] Fixes for XDP_REDIRECT map
From: Jesper Dangaard Brouer @ 2017-09-07 12:33 UTC (permalink / raw)
To: netdev, David S. Miller
Cc: Daniel Borkmann, John Fastabend, Andy Gospodarek,
Jesper Dangaard Brouer
This my V2 of catching XDP_REDIRECT and bpf_redirect_map() API usage
that can potentially crash the kernel. Addressed Daniels feedback in
patch01, and added patch02 which catch and cleanup dangling map
pointers.
I know John and Daniel are working on a more long-term solution, of
recording the bpf_prog pointer together with the map pointer. I just
wanted to propose these fixes as a stop-gap to the potential crashes.
---
Jesper Dangaard Brouer (2):
xdp: implement xdp_redirect_map for generic XDP
xdp: catch invalid XDP_REDIRECT API usage
include/linux/filter.h | 1 +
include/trace/events/xdp.h | 4 ++--
net/core/dev.c | 3 +++
net/core/filter.c | 39 ++++++++++++++++++++++++++++++++++++---
4 files changed, 42 insertions(+), 5 deletions(-)
^ permalink raw reply
* Re: [PATCH 1/3] security: bpf: Add eBPF LSM hooks to security module
From: Stephen Smalley @ 2017-09-07 12:32 UTC (permalink / raw)
To: Chenbo Feng
Cc: netdev, Chenbo Feng, linux-security-module, SELinux,
Alexei Starovoitov, Lorenzo Colitti
In-Reply-To: <CAMOXUJ=r1AEO_6Pg7-tio9UPn2YCJKOrLS=xbn7U4SE_mBYyJQ@mail.gmail.com>
On Tue, 2017-09-05 at 15:24 -0700, Chenbo Feng via Selinux wrote:
> On Fri, Sep 1, 2017 at 5:50 AM, Stephen Smalley <sds@tycho.nsa.gov>
> wrote:
> > On Thu, 2017-08-31 at 13:56 -0700, Chenbo Feng wrote:
> > > From: Chenbo Feng <fengc@google.com>
> > >
> > > Introduce 5 LSM hooks to provide finer granularity controls on
> > > eBPF
> > > related operations including create eBPF maps, modify and read
> > > eBPF
> > > maps
> > > content and load eBPF programs to the kernel. Hooks use the new
> > > security
> > > pointer inside the eBPF map struct to store the owner's security
> > > information and the different security modules can perform
> > > different
> > > checks based on the information stored inside the security field.
> > >
> > > Signed-off-by: Chenbo Feng <fengc@google.com>
> > > ---
> > > include/linux/lsm_hooks.h | 41
> > > +++++++++++++++++++++++++++++++++++++++++
> > > include/linux/security.h | 36
> > > ++++++++++++++++++++++++++++++++++++
> > > security/security.c | 28 ++++++++++++++++++++++++++++
> > > 3 files changed, 105 insertions(+)
> > >
> > > diff --git a/include/linux/lsm_hooks.h
> > > b/include/linux/lsm_hooks.h
> > > index ce02f76a6188..3aaf9a08a983 100644
> > > --- a/include/linux/lsm_hooks.h
> > > +++ b/include/linux/lsm_hooks.h
> > > @@ -1353,6 +1353,32 @@
> > > * @inode we wish to get the security context of.
> > > * @ctx is a pointer in which to place the allocated security
> > > context.
> > > * @ctxlen points to the place to put the length of @ctx.
> > > + *
> > > + * Security hooks for using the eBPF maps and programs
> > > functionalities through
> > > + * eBPF syscalls.
> > > + *
> > > + * @bpf_map_create:
> > > + * Check permissions prior to creating a new bpf map.
> > > + * Return 0 if the permission is granted.
> > > + *
> > > + * @bpf_map_modify:
> > > + * Check permission prior to insert, update and delete map
> > > content.
> > > + * @map pointer to the struct bpf_map that contains map
> > > information.
> > > + * Return 0 if the permission is granted.
> > > + *
> > > + * @bpf_map_read:
> > > + * Check permission prior to read a bpf map content.
> > > + * @map pointer to the struct bpf_map that contains map
> > > information.
> > > + * Return 0 if the permission is granted.
> > > + *
> > > + * @bpf_prog_load:
> > > + * Check permission prior to load eBPF program.
> > > + * Return 0 if the permission is granted.
> > > + *
> > > + * @bpf_post_create:
> > > + * Initialize the bpf object security field inside struct
> > > bpf_maps and
> > > + * it is used for future security checks.
> > > + *
> > > */
> > > union security_list_options {
> > > int (*binder_set_context_mgr)(struct task_struct *mgr);
> > > @@ -1685,6 +1711,14 @@ union security_list_options {
> > > struct audit_context *actx);
> > > void (*audit_rule_free)(void *lsmrule);
> > > #endif /* CONFIG_AUDIT */
> > > +
> > > +#ifdef CONFIG_BPF_SYSCALL
> > > + int (*bpf_map_create)(void);
> > > + int (*bpf_map_read)(struct bpf_map *map);
> > > + int (*bpf_map_modify)(struct bpf_map *map);
> > > + int (*bpf_prog_load)(void);
> > > + int (*bpf_post_create)(struct bpf_map *map);
> > > +#endif /* CONFIG_BPF_SYSCALL */
> > > };
> > >
> > > struct security_hook_heads {
> > > @@ -1905,6 +1939,13 @@ struct security_hook_heads {
> > > struct list_head audit_rule_match;
> > > struct list_head audit_rule_free;
> > > #endif /* CONFIG_AUDIT */
> > > +#ifdef CONFIG_BPF_SYSCALL
> > > + struct list_head bpf_map_create;
> > > + struct list_head bpf_map_read;
> > > + struct list_head bpf_map_modify;
> > > + struct list_head bpf_prog_load;
> > > + struct list_head bpf_post_create;
> > > +#endif /* CONFIG_BPF_SYSCALL */
> > > } __randomize_layout;
> > >
> > > /*
> > > diff --git a/include/linux/security.h b/include/linux/security.h
> > > index 458e24bea2d4..0656a4f74d14 100644
> > > --- a/include/linux/security.h
> > > +++ b/include/linux/security.h
> > > @@ -31,6 +31,7 @@
> > > #include <linux/string.h>
> > > #include <linux/mm.h>
> > > #include <linux/fs.h>
> > > +#include <linux/bpf.h>
> > >
> > > struct linux_binprm;
> > > struct cred;
> > > @@ -1735,6 +1736,41 @@ static inline void
> > > securityfs_remove(struct
> > > dentry *dentry)
> > >
> > > #endif
> > >
> > > +#ifdef CONFIG_BPF_SYSCALL
> > > +#ifdef CONFIG_SECURITY
> > > +int security_map_create(void);
> > > +int security_map_modify(struct bpf_map *map);
> > > +int security_map_read(struct bpf_map *map);
> > > +int security_prog_load(void);
> > > +int security_post_create(struct bpf_map *map);
> > > +#else
> > > +static inline int security_map_create(void)
> > > +{
> > > + return 0;
> > > +}
> > > +
> > > +static inline int security_map_read(struct bpf_map *map)
> > > +{
> > > + return 0;
> > > +}
> > > +
> > > +static inline int security_map_modify(struct bpf_map *map)
> > > +{
> > > + return 0;
> > > +}
> > > +
> > > +static inline int security_prog_load(void)
> > > +{
> > > + return 0;
> > > +}
> > > +
> > > +static inline int security_post_create(struct bpf_map *map)
> > > +{
> > > + return 0;
> > > +}
> > > +#endif /* CONFIG_SECURITY */
> > > +#endif /* CONFIG_BPF_SYSCALL */
> >
> > These should be named consistently with the ones in lsm_hooks.h and
> > should unambiguously indicate that these are hooks for bpf
> > objects/operations, i.e. security_bpf_map_create(),
> > security_bpf_map_read(), etc.
> >
>
> Thanks for pointing out, will fix this.
> > Do you need this level of granularity?
> >
>
> The cover letter of this patch series described a possible use cases
> of
> these lsm hooks and this level of granularity would be ideal to reach
> that
> goal. We can also implement two hooks such as bpf_obj_create and
> bpf_obj_use to restrict the creation and using when get the bpf fd
> from
> kernel. But that will be less powerful and flexible.
> > Could you coalesce the map_create() and post_map_create() hooks
> > into
> > one hook and just unwind the create in that case?
> >
>
> Okay, I will take a look on how to fix this.
Also, what you called security_post_create() would normally be called
something like security_bpf_alloc_security(), and would have a
corresponding security_bpf_free_security() hook too. However, whether
or not you still need this security field and hook at all is unclear to
me, given the direction the discussion has gone.
> > Why do you label bpf maps but not bpf progs? Should we be
> > controlling
> > the ability to attach/detach a bpf prog (partly controlled by
> > CAP_NET_ADMIN, but also somewhat broad in scope and doesn't allow
> > control based on who created the prog)?
> >
> > Should there be a top-level security_bpf_use() hook and permission
> > check that limits ability to use bpf() at all?
> >
>
> This could be useful but having additional lsm hooks check when
> reading
> and write to eBPF maps may cause performance issue. Instead maybe we
> could have a hook for creating eBPF object and retrieve object fd to
> restrict
> the access.
> > > +
> > > #ifdef CONFIG_SECURITY
> > >
> > > static inline char *alloc_secdata(void)
> > > diff --git a/security/security.c b/security/security.c
> > > index 55b5997e4b72..02272f93a89e 100644
> > > --- a/security/security.c
> > > +++ b/security/security.c
> > > @@ -12,6 +12,7 @@
> > > * (at your option) any later version.
> > > */
> > >
> > > +#include <linux/bpf.h>
> > > #include <linux/capability.h>
> > > #include <linux/dcache.h>
> > > #include <linux/module.h>
> > > @@ -1708,3 +1709,30 @@ int security_audit_rule_match(u32 secid,
> > > u32
> > > field, u32 op, void *lsmrule,
> > > actx);
> > > }
> > > #endif /* CONFIG_AUDIT */
> > > +
> > > +#ifdef CONFIG_BPF_SYSCALL
> > > +int security_map_create(void)
> > > +{
> > > + return call_int_hook(bpf_map_create, 0);
> > > +}
> > > +
> > > +int security_map_modify(struct bpf_map *map)
> > > +{
> > > + return call_int_hook(bpf_map_modify, 0, map);
> > > +}
> > > +
> > > +int security_map_read(struct bpf_map *map)
> > > +{
> > > + return call_int_hook(bpf_map_read, 0, map);
> > > +}
> > > +
> > > +int security_prog_load(void)
> > > +{
> > > + return call_int_hook(bpf_prog_load, 0);
> > > +}
> > > +
> > > +int security_post_create(struct bpf_map *map)
> > > +{
> > > + return call_int_hook(bpf_post_create, 0, map);
> > > +}
> > > +#endif /* CONFIG_BPF_SYSCALL */
^ permalink raw reply
* Re: [PATCH] ath10: mark PM functions as __maybe_unused
From: Kalle Valo @ 2017-09-07 11:36 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Colin Ian King, bartosz.markowski@tieto.com, Govind Singh,
Ryan Hsu, Srinivas Kandagatla, Rajkumar Manoharan,
Ashok Raj Nagarajan, Ben Greear, ath10k@lists.infradead.org,
linux-wireless@vger.kernel.org, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <20170906125904.2588620-1-arnd@arndb.de>
Arnd Bergmann <arnd@arndb.de> writes:
> When CONFIG_PM_SLEEP is disabled, we get a compile-time
> warning:
>
> drivers/net/wireless/ath/ath10k/pci.c:3417:12: error: 'ath10k_pci_pm_resume' defined but not used [-Werror=unused-function]
> static int ath10k_pci_pm_resume(struct device *dev)
> ^~~~~~~~~~~~~~~~~~~~
> drivers/net/wireless/ath/ath10k/pci.c:3401:12: error: 'ath10k_pci_pm_suspend' defined but not used [-Werror=unused-function]
> static int ath10k_pci_pm_suspend(struct device *dev)
>
> Rather than fixing the #ifdef, this just marks both functions
> as __maybe_unused, which is a more robust way to do this.
>
> Fixes: 32faa3f0ee50 ("ath10k: add the PCI PM core suspend/resume ops")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Thanks. But the title should have "ath10k:", I'll fix that.
--
Kalle Valo
^ permalink raw reply
* [PATCH] drivers: net: Display proper debug level up to 6
From: Mathieu Malaterre @ 2017-09-07 11:24 UTC (permalink / raw)
Cc: Mathieu Malaterre, David S. Miller, Philippe Reynes,
Johannes Berg, Jarod Wilson, netdev, linux-kernel
This will make it explicit some messages are of the form:
dm9000_dbg(db, 5, ...
Signed-off-by: Mathieu Malaterre <malat@debian.org>
---
drivers/net/ethernet/davicom/dm9000.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c
index 16fe776ddbe5..50222b7b81f3 100644
--- a/drivers/net/ethernet/davicom/dm9000.c
+++ b/drivers/net/ethernet/davicom/dm9000.c
@@ -65,7 +65,7 @@ MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");
*/
static int debug;
module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "dm9000 debug level (0-4)");
+MODULE_PARM_DESC(debug, "dm9000 debug level (0-6)");
/* DM9000 register address locking.
*
--
2.11.0
^ permalink raw reply related
* Re: [PATCH] netfilter: xt_hashlimit: avoid 64-bit division
From: Arnd Bergmann @ 2017-09-07 11:16 UTC (permalink / raw)
To: Pablo Neira Ayuso
Cc: Vishwanath Pai, Jozsef Kadlecsik, Florian Westphal,
David S. Miller, Josh Hunt, netfilter-devel, coreteam, Networking,
Linux Kernel Mailing List
In-Reply-To: <20170907101931.GB2049@salvia>
On Thu, Sep 7, 2017 at 12:19 PM, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> On Wed, Sep 06, 2017 at 10:48:22PM +0200, Arnd Bergmann wrote:
>> On Wed, Sep 6, 2017 at 10:22 PM, Vishwanath Pai <vpai@akamai.com> wrote:
>> > On 09/06/2017 03:57 PM, Arnd Bergmann wrote:
>> >> 64-bit division is expensive on 32-bit architectures, and
>> >> requires a special function call to avoid a link error like:
>> >>
>> >> net/netfilter/xt_hashlimit.o: In function `hashlimit_mt_common':
>> >> xt_hashlimit.c:(.text+0x1328): undefined reference to `__aeabi_uldivmod'
>> >>
>> >> In the case of hashlimit_mt_common, we don't actually need a
>> >> 64-bit operation, we can simply rewrite the function slightly
>> >> to make that clear to the compiler.
>> >>
>> >> Fixes: bea74641e378 ("netfilter: xt_hashlimit: add rate match mode")
>> >> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
>> >> ---
>> >> net/netfilter/xt_hashlimit.c | 5 ++++-
>> >> 1 file changed, 4 insertions(+), 1 deletion(-)
>> >>
>> >> diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
>> >> index 10d48234f5f4..50b53d86eef5 100644
>> >> --- a/net/netfilter/xt_hashlimit.c
>> >> +++ b/net/netfilter/xt_hashlimit.c
>> >> @@ -531,7 +531,10 @@ static u64 user2rate_bytes(u64 user)
>> >> {
>> >> u64 r;
>> >>
>> >> - r = user ? 0xFFFFFFFFULL / user : 0xFFFFFFFFULL;
>> >> + if (user > 0xFFFFFFFFULL)
>> >> + return 0;
>> >> +
>> >> + r = user ? 0xFFFFFFFFULL / (u32)user : 0xFFFFFFFFULL;
>> >> r = (r - 1) << 4;
>> >> return r;
>> >> }
>> >>
>> >
>> > I have submitted another patch to fix this:
>> > https://patchwork.ozlabs.org/patch/809881/
>> >
>> > We have seen this problem before, I was careful not to introduce this
>> > again in the new patch but clearly I overlooked this particular line :(
>> >
>> > In the other cases we fixed it by replacing division with div64_u64().
>>
>> div64_u64() seems needlessly expensive here since the dividend
>> is known to be a 32-bit number. I guess the function is not called
>> frequently though, so it doesn't matter much.
>
> This is called from the packet path, only for the first packet for
> each new destination IP entry in the hashtable, still from the
> datapath. So if we can take something faster (for 32 bit arches) that
> is correct, I think it's sensible to take.
>
> Let me know in any case.
I think my version should be slightly better then, unless someone
finds something wrong with it.
Arnd
^ permalink raw reply
* [RFC, iproute2 PATCH v2] tc/mqprio: Offload mode and shaper options in mqprio
From: Amritha Nambiar @ 2017-09-07 11:03 UTC (permalink / raw)
To: stephen, netdev; +Cc: alexander.h.duyck, amritha.nambiar
Adds new mqprio options for 'mode' and 'shaper'. The mode
option can take values for offload modes such as 'dcb' (default),
'channel' with the 'hw' option set to 1. The 'shaper' option is
to support HW shapers ('dcb' default) and takes the value
'bw_rlimit' for bandwidth rate limiting. The parameters to the
bw_rlimit shaper are minimum and maximum bandwidth rates.
New HW shapers in future can be supported through the shaper
attribute.
# tc qdisc add dev eth0 root mqprio num_tc 2 map 0 0 0 0 1 1 1 1\
queues 4@0 4@4 hw 1 mode channel shaper bw_rlimit\
min_rate 1Gbit 2Gbit max_rate 4Gbit 5Gbit
# tc qdisc show dev eth0
qdisc mqprio 804a: root tc 2 map 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0
queues:(0:3) (4:7)
mode:channel
shaper:bw_rlimit min_rate:1Gbit 2Gbit max_rate:4Gbit 5Gbit
Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
---
include/linux/pkt_sched.h | 32 ++++++++
tc/q_mqprio.c | 191 +++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 216 insertions(+), 7 deletions(-)
diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
index 099bf55..e95b5c9 100644
--- a/include/linux/pkt_sched.h
+++ b/include/linux/pkt_sched.h
@@ -625,6 +625,22 @@ enum {
#define TC_MQPRIO_HW_OFFLOAD_MAX (__TC_MQPRIO_HW_OFFLOAD_MAX - 1)
+enum {
+ TC_MQPRIO_MODE_DCB,
+ TC_MQPRIO_MODE_CHANNEL,
+ __TC_MQPRIO_MODE_MAX
+};
+
+#define __TC_MQPRIO_MODE_MAX (__TC_MQPRIO_MODE_MAX - 1)
+
+enum {
+ TC_MQPRIO_SHAPER_DCB,
+ TC_MQPRIO_SHAPER_BW_RATE, /* Add new shapers below */
+ __TC_MQPRIO_SHAPER_MAX
+};
+
+#define __TC_MQPRIO_SHAPER_MAX (__TC_MQPRIO_SHAPER_MAX - 1)
+
struct tc_mqprio_qopt {
__u8 num_tc;
__u8 prio_tc_map[TC_QOPT_BITMASK + 1];
@@ -633,6 +649,22 @@ struct tc_mqprio_qopt {
__u16 offset[TC_QOPT_MAX_QUEUE];
};
+#define TC_MQPRIO_F_MODE 0x1
+#define TC_MQPRIO_F_SHAPER 0x2
+#define TC_MQPRIO_F_MIN_RATE 0x4
+#define TC_MQPRIO_F_MAX_RATE 0x8
+
+enum {
+ TCA_MQPRIO_UNSPEC,
+ TCA_MQPRIO_MODE,
+ TCA_MQPRIO_SHAPER,
+ TCA_MQPRIO_MIN_RATE64,
+ TCA_MQPRIO_MAX_RATE64,
+ __TCA_MQPRIO_MAX,
+};
+
+#define TCA_MQPRIO_MAX (__TCA_MQPRIO_MAX - 1)
+
/* SFB */
enum {
diff --git a/tc/q_mqprio.c b/tc/q_mqprio.c
index d6718fb..5fec63d 100644
--- a/tc/q_mqprio.c
+++ b/tc/q_mqprio.c
@@ -27,6 +27,10 @@ static void explain(void)
fprintf(stderr, "Usage: ... mqprio [num_tc NUMBER] [map P0 P1 ...]\n");
fprintf(stderr, " [queues count1@offset1 count2@offset2 ...] ");
fprintf(stderr, "[hw 1|0]\n");
+ fprintf(stderr, " [mode dcb|channel]\n");
+ fprintf(stderr, " [shaper bw_rlimit SHAPER_PARAMS]\n"
+ "Where: SHAPER_PARAMS := { min_rate MIN_RATE1 MIN_RATE2 ...|\n"
+ " max_rate MAX_RATE1 MAX_RATE2 ... }\n");
}
static int mqprio_parse_opt(struct qdisc_util *qu, int argc,
@@ -40,6 +44,12 @@ static int mqprio_parse_opt(struct qdisc_util *qu, int argc,
.count = { },
.offset = { },
};
+ __u64 min_rate64[TC_QOPT_MAX_QUEUE] = {0};
+ __u64 max_rate64[TC_QOPT_MAX_QUEUE] = {0};
+ __u16 shaper = TC_MQPRIO_SHAPER_DCB;
+ __u16 mode = TC_MQPRIO_MODE_DCB;
+ struct rtattr *tail;
+ __u32 flags = 0;
while (argc > 0) {
idx = 0;
@@ -92,6 +102,68 @@ static int mqprio_parse_opt(struct qdisc_util *qu, int argc,
return -1;
}
idx++;
+ } else if (opt.hw && strcmp(*argv, "mode") == 0) {
+ NEXT_ARG();
+ if (matches(*argv, "dcb") == 0) {
+ mode = TC_MQPRIO_MODE_DCB;
+ } else if (matches(*argv, "channel") == 0) {
+ mode = TC_MQPRIO_MODE_CHANNEL;
+ } else {
+ fprintf(stderr, "Illegal mode (%s)\n",
+ *argv);
+ return -1;
+ }
+ if (mode != TC_MQPRIO_MODE_DCB)
+ flags |= TC_MQPRIO_F_MODE;
+ idx++;
+ } else if (opt.hw && strcmp(*argv, "shaper") == 0) {
+ NEXT_ARG();
+ if (matches(*argv, "dcb") == 0) {
+ shaper = TC_MQPRIO_SHAPER_DCB;
+ } else if (matches(*argv, "bw_rlimit") == 0) {
+ shaper = TC_MQPRIO_SHAPER_BW_RATE;
+ if (!NEXT_ARG_OK()) {
+ fprintf(stderr, "Incomplete shaper arguments\n");
+ return -1;
+ }
+ } else {
+ fprintf(stderr, "Illegal shaper (%s)\n",
+ *argv);
+ return -1;
+ }
+ if (shaper != TC_MQPRIO_SHAPER_DCB)
+ flags |= TC_MQPRIO_F_SHAPER;
+ idx++;
+ } else if ((shaper == TC_MQPRIO_SHAPER_BW_RATE) &&
+ strcmp(*argv, "min_rate") == 0) {
+ while (idx < TC_QOPT_MAX_QUEUE && NEXT_ARG_OK()) {
+ NEXT_ARG();
+ if (get_rate64(&min_rate64[idx], *argv)) {
+ PREV_ARG();
+ break;
+ }
+ idx++;
+ }
+ if ((idx < opt.num_tc) && !NEXT_ARG_OK()) {
+ fprintf(stderr, "Incomplete arguments, min_rate values expected\n");
+ return -1;
+ }
+ flags |= TC_MQPRIO_F_MIN_RATE;
+ } else if ((shaper == TC_MQPRIO_SHAPER_BW_RATE) &&
+ strcmp(*argv, "max_rate") == 0) {
+ while (idx < TC_QOPT_MAX_QUEUE && NEXT_ARG_OK()) {
+ NEXT_ARG();
+ if (get_rate64(&max_rate64[idx], *argv)) {
+ PREV_ARG();
+ break;
+ }
+ idx++;
+ }
+ if ((idx < opt.num_tc) && !NEXT_ARG_OK()) {
+ fprintf(stderr, "Incomplete arguments, max_rate values expected\n");
+ return -1;
+ }
+ flags |= TC_MQPRIO_F_MAX_RATE;
} else if (strcmp(*argv, "help") == 0) {
explain();
return -1;
@@ -102,27 +174,132 @@ static int mqprio_parse_opt(struct qdisc_util *qu, int argc,
argc--; argv++;
}
+ tail = NLMSG_TAIL(n);
addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt));
+
+ if (flags & TC_MQPRIO_F_MODE)
+ addattr_l(n, 1024, TCA_MQPRIO_MODE,
+ &mode, sizeof(mode));
+ if (flags & TC_MQPRIO_F_SHAPER)
+ addattr_l(n, 1024, TCA_MQPRIO_SHAPER,
+ &shaper, sizeof(shaper));
+
+ if (flags & TC_MQPRIO_F_MIN_RATE) {
+ struct rtattr *start;
+
+ start = addattr_nest(n, 1024,
+ TCA_MQPRIO_MIN_RATE64 | NLA_F_NESTED);
+
+ for (idx = 0; idx < TC_QOPT_MAX_QUEUE; idx++)
+ addattr_l(n, 1024, TCA_MQPRIO_MIN_RATE64,
+ &min_rate64[idx], sizeof(min_rate64[idx]));
+
+ addattr_nest_end(n, start);
+ }
+
+ if (flags & TC_MQPRIO_F_MAX_RATE) {
+ struct rtattr *start;
+
+ start = addattr_nest(n, 1024,
+ TCA_MQPRIO_MAX_RATE64 | NLA_F_NESTED);
+
+ for (idx = 0; idx < TC_QOPT_MAX_QUEUE; idx++)
+ addattr_l(n, 1024, TCA_MQPRIO_MAX_RATE64,
+ &max_rate64[idx], sizeof(max_rate64[idx]));
+
+ addattr_nest_end(n, start);
+ }
+
+ tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
+
return 0;
}
static int mqprio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
{
int i;
- struct tc_mqprio_qopt *qopt;
+ struct tc_mqprio_qopt qopt;
+ __u64 min_rate64[TC_QOPT_MAX_QUEUE] = {0};
+ __u64 max_rate64[TC_QOPT_MAX_QUEUE] = {0};
+ int len = RTA_PAYLOAD(opt) - RTA_ALIGN(sizeof(qopt));
+
+ SPRINT_BUF(b1);
if (opt == NULL)
return 0;
- qopt = RTA_DATA(opt);
+ if (len < 0) {
+ fprintf(stderr, "options size error\n");
+ return -1;
+ }
+
+ memcpy(&qopt, RTA_DATA(opt), RTA_ALIGN(sizeof(qopt)));
- fprintf(f, " tc %u map ", qopt->num_tc);
+ fprintf(f, " tc %u map ", qopt.num_tc);
for (i = 0; i <= TC_PRIO_MAX; i++)
- fprintf(f, "%u ", qopt->prio_tc_map[i]);
+ fprintf(f, "%u ", qopt.prio_tc_map[i]);
fprintf(f, "\n queues:");
- for (i = 0; i < qopt->num_tc; i++)
- fprintf(f, "(%u:%u) ", qopt->offset[i],
- qopt->offset[i] + qopt->count[i] - 1);
+ for (i = 0; i < qopt.num_tc; i++)
+ fprintf(f, "(%u:%u) ", qopt.offset[i],
+ qopt.offset[i] + qopt.count[i] - 1);
+
+ if (len > 0) {
+ struct rtattr *tb[TCA_MQPRIO_MAX + 1];
+
+ parse_rtattr(tb, TCA_MQPRIO_MAX,
+ RTA_DATA(opt) + RTA_ALIGN(sizeof(qopt)),
+ len);
+
+ if (tb[TCA_MQPRIO_MODE]) {
+ __u16 *mode = RTA_DATA(tb[TCA_MQPRIO_MODE]);
+
+ if (*mode == TC_MQPRIO_MODE_CHANNEL)
+ fprintf(f, "\n mode:channel");
+ } else {
+ fprintf(f, "\n mode:dcb");
+ }
+
+ if (tb[TCA_MQPRIO_SHAPER]) {
+ __u16 *shaper = RTA_DATA(tb[TCA_MQPRIO_SHAPER]);
+
+ if (*shaper == TC_MQPRIO_SHAPER_BW_RATE)
+ fprintf(f, "\n shaper:bw_rlimit");
+ } else {
+ fprintf(f, "\n shaper:dcb");
+ }
+
+ if (tb[TCA_MQPRIO_MIN_RATE64]) {
+ struct rtattr *r;
+ int rem = RTA_PAYLOAD(tb[TCA_MQPRIO_MIN_RATE64]);
+ __u64 *min = min_rate64;
+
+ for (r = RTA_DATA(tb[TCA_MQPRIO_MIN_RATE64]);
+ RTA_OK(r, rem); r = RTA_NEXT(r, rem)) {
+ if (r->rta_type != TCA_MQPRIO_MIN_RATE64)
+ return -1;
+ *(min++) = rta_getattr_u64(r);
+ }
+ fprintf(f, " min_rate:");
+ for (i = 0; i < qopt.num_tc; i++)
+ fprintf(f, "%s ", sprint_rate(min_rate64[i], b1));
+ }
+
+ if (tb[TCA_MQPRIO_MAX_RATE64]) {
+ struct rtattr *r;
+ int rem = RTA_PAYLOAD(tb[TCA_MQPRIO_MAX_RATE64]);
+ __u64 *max = max_rate64;
+
+ for (r = RTA_DATA(tb[TCA_MQPRIO_MAX_RATE64]);
+ RTA_OK(r, rem); r = RTA_NEXT(r, rem)) {
+ if (r->rta_type != TCA_MQPRIO_MAX_RATE64)
+ return -1;
+ *(max++) = rta_getattr_u64(r);
+ }
+ fprintf(f, " max_rate:");
+ for (i = 0; i < qopt.num_tc; i++)
+ fprintf(f, "%s ", sprint_rate(max_rate64[i], b1));
+ }
+ }
return 0;
}
^ permalink raw reply related
* [RFC PATCH v3 6/6] i40e: Add support setting TC max bandwidth rates
From: Amritha Nambiar @ 2017-09-07 11:00 UTC (permalink / raw)
To: intel-wired-lan, jeffrey.t.kirsher
Cc: alexander.h.duyck, netdev, amritha.nambiar
In-Reply-To: <150478158684.24662.17975701233699487888.stgit@anamdev.jf.intel.com>
This patch enables setting up maximum Tx rates for the traffic
classes in i40e. The maximum rate is offloaded to the hardware through
the mqprio framework by specifying the mode option as 'channel' and
shaper option as 'bw_rlimit' and is configured for the VSI. Configuring
minimum Tx rate limit is not supported in the device. The minimum
usable value for Tx rate is 50Mbps.
Example:
# tc qdisc add dev eth0 root mqprio num_tc 2 map 0 0 0 0 1 1 1 1\
queues 4@0 4@4 hw 1 mode channel shaper bw_rlimit\
max_rate 4Gbit 5Gbit
To dump the bandwidth rates:
# tc qdisc show dev eth0
qdisc mqprio 804a: root tc 2 map 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0
queues:(0:3) (4:7)
mode:channel
shaper:bw_rlimit max_rate:4Gbit 5Gbit
Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
---
drivers/net/ethernet/intel/i40e/i40e.h | 2 +
drivers/net/ethernet/intel/i40e/i40e_main.c | 101 +++++++++++++++++++++++++--
2 files changed, 94 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
index 2ee0197..02cae34 100644
--- a/drivers/net/ethernet/intel/i40e/i40e.h
+++ b/drivers/net/ethernet/intel/i40e/i40e.h
@@ -359,6 +359,8 @@ struct i40e_channel {
u8 enabled_tc;
struct i40e_aqc_vsi_properties_data info;
+ u64 max_tx_rate;
+
/* track this channel belongs to which VSI */
struct i40e_vsi *parent_vsi;
};
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 7f13bc7..14a177b 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -5202,9 +5202,16 @@ static int i40e_vsi_configure_bw_alloc(struct i40e_vsi *vsi, u8 enabled_tc,
i40e_status ret;
int i;
- if ((vsi->back->flags & I40E_FLAG_TC_MQPRIO) ||
- !vsi->mqprio_qopt.qopt.hw)
+ if (vsi->back->flags & I40E_FLAG_TC_MQPRIO)
return 0;
+ if (!vsi->mqprio_qopt.qopt.hw) {
+ ret = i40e_set_bw_limit(vsi, vsi->seid, 0);
+ if (ret)
+ dev_info(&vsi->back->pdev->dev,
+ "Failed to reset tx rate for vsi->seid %u\n",
+ vsi->seid);
+ return ret;
+ }
bw_data.tc_valid_bits = enabled_tc;
for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
bw_data.tc_bw_credits[i] = bw_share[i];
@@ -5511,6 +5518,13 @@ static void i40e_remove_queue_channels(struct i40e_vsi *vsi)
rx_ring->ch = NULL;
}
+ /* Reset BW configured for this VSI via mqprio */
+ ret = i40e_set_bw_limit(vsi, ch->seid, 0);
+ if (ret)
+ dev_info(&vsi->back->pdev->dev,
+ "Failed to reset tx rate for ch->seid %u\n",
+ ch->seid);
+
/* delete VSI from FW */
ret = i40e_aq_delete_element(&vsi->back->hw, ch->seid,
NULL);
@@ -6053,6 +6067,17 @@ int i40e_create_queue_channel(struct i40e_vsi *vsi,
"Setup channel (id:%u) utilizing num_queues %d\n",
ch->seid, ch->num_queue_pairs);
+ /* configure VSI for BW limit */
+ if (ch->max_tx_rate) {
+ if (i40e_set_bw_limit(vsi, ch->seid, ch->max_tx_rate))
+ return -EINVAL;
+
+ dev_dbg(&pf->pdev->dev,
+ "Set tx rate of %llu Mbps (count of 50Mbps %llu) for vsi->seid %u\n",
+ ch->max_tx_rate,
+ ch->max_tx_rate / I40E_BW_CREDIT_DIVISOR, ch->seid);
+ }
+
/* in case of VF, this will be main SRIOV VSI */
ch->parent_vsi = vsi;
@@ -6088,6 +6113,12 @@ static int i40e_configure_queue_channels(struct i40e_vsi *vsi)
ch->base_queue =
vsi->tc_config.tc_info[i].qoffset;
+ /* Bandwidth limit through tc interface is in bytes/s,
+ * change to Mbit/s
+ */
+ ch->max_tx_rate =
+ vsi->mqprio_qopt.max_rate[i] / (1000000 / 8);
+
list_add_tail(&ch->list, &vsi->ch_list);
ret = i40e_create_queue_channel(vsi, ch);
@@ -6514,6 +6545,7 @@ void i40e_down(struct i40e_vsi *vsi)
static int i40e_validate_mqprio_qopt(struct i40e_vsi *vsi,
struct tc_mqprio_qopt_offload *mqprio_qopt)
{
+ u64 sum_max_rate = 0;
int i;
if ((mqprio_qopt->qopt.offset[0] != 0) ||
@@ -6523,8 +6555,13 @@ static int i40e_validate_mqprio_qopt(struct i40e_vsi *vsi,
for (i = 0; ; i++) {
if (!mqprio_qopt->qopt.count[i])
return -EINVAL;
- if (mqprio_qopt->min_rate[i] || mqprio_qopt->max_rate[i])
+ if (mqprio_qopt->min_rate[i]) {
+ dev_err(&vsi->back->pdev->dev,
+ "Invalid min tx rate (greater than 0) specified\n");
return -EINVAL;
+ }
+ sum_max_rate += (mqprio_qopt->max_rate[i] / (1000000 / 8));
+
if (i >= mqprio_qopt->qopt.num_tc - 1)
break;
if (mqprio_qopt->qopt.offset[i + 1] !=
@@ -6535,6 +6572,11 @@ static int i40e_validate_mqprio_qopt(struct i40e_vsi *vsi,
(mqprio_qopt->qopt.offset[i] + mqprio_qopt->qopt.count[i])) {
return -EINVAL;
}
+ if (sum_max_rate > i40e_get_link_speed(vsi)) {
+ dev_err(&vsi->back->pdev->dev,
+ "Invalid max tx rate specified\n");
+ return -EINVAL;
+ }
return 0;
}
@@ -6661,6 +6703,21 @@ static int i40e_setup_tc(struct net_device *netdev, void *type_data)
}
if (pf->flags & I40E_FLAG_TC_MQPRIO) {
+ if (vsi->mqprio_qopt.max_rate[0]) {
+ u64 max_tx_rate = vsi->mqprio_qopt.max_rate[0] /
+ (1000000 / 8);
+ ret = i40e_set_bw_limit(vsi, vsi->seid, max_tx_rate);
+ if (!ret) {
+ dev_dbg(&vsi->back->pdev->dev,
+ "Set tx rate of %llu Mbps (count of 50Mbps %llu) for vsi->seid %u\n",
+ max_tx_rate,
+ max_tx_rate / I40E_BW_CREDIT_DIVISOR,
+ vsi->seid);
+ } else {
+ need_reset = true;
+ goto exit;
+ }
+ }
ret = i40e_configure_queue_channels(vsi);
if (ret) {
netdev_info(netdev,
@@ -8114,6 +8171,18 @@ static int i40e_rebuild_channels(struct i40e_vsi *vsi)
vsi->uplink_seid);
return ret;
}
+ if (ch->max_tx_rate) {
+ if (i40e_set_bw_limit(vsi, ch->seid,
+ ch->max_tx_rate))
+ return -EINVAL;
+
+ dev_dbg(&vsi->back->pdev->dev,
+ "Set tx rate of %llu Mbps (count of 50Mbps %llu) for vsi->seid %u\n",
+ ch->max_tx_rate,
+ ch->max_tx_rate /
+ I40E_BW_CREDIT_DIVISOR,
+ ch->seid);
+ }
}
return 0;
}
@@ -8254,6 +8323,7 @@ static int i40e_reset(struct i40e_pf *pf)
**/
static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
{
+ struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
struct i40e_hw *hw = &pf->hw;
u8 set_fc_aq_fail = 0;
i40e_status ret;
@@ -8336,7 +8406,7 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
* If there were VEBs but the reconstitution failed, we'll try
* try to recover minimal use by getting the basic PF VSI working.
*/
- if (pf->vsi[pf->lan_vsi]->uplink_seid != pf->mac_seid) {
+ if (vsi->uplink_seid != pf->mac_seid) {
dev_dbg(&pf->pdev->dev, "attempting to rebuild switch\n");
/* find the one VEB connected to the MAC, and find orphans */
for (v = 0; v < I40E_MAX_VEB; v++) {
@@ -8360,8 +8430,7 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
dev_info(&pf->pdev->dev,
"rebuild of switch failed: %d, will try to set up simple PF connection\n",
ret);
- pf->vsi[pf->lan_vsi]->uplink_seid
- = pf->mac_seid;
+ vsi->uplink_seid = pf->mac_seid;
break;
} else if (pf->veb[v]->uplink_seid == 0) {
dev_info(&pf->pdev->dev,
@@ -8372,10 +8441,10 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
}
}
- if (pf->vsi[pf->lan_vsi]->uplink_seid == pf->mac_seid) {
+ if (vsi->uplink_seid == pf->mac_seid) {
dev_dbg(&pf->pdev->dev, "attempting to rebuild PF VSI\n");
/* no VEB, so rebuild only the Main VSI */
- ret = i40e_add_vsi(pf->vsi[pf->lan_vsi]);
+ ret = i40e_add_vsi(vsi);
if (ret) {
dev_info(&pf->pdev->dev,
"rebuild of Main VSI failed: %d\n", ret);
@@ -8383,10 +8452,24 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
}
}
+ if (vsi->mqprio_qopt.max_rate[0]) {
+ u64 max_tx_rate = vsi->mqprio_qopt.max_rate[0] / (1000000 / 8);
+
+ ret = i40e_set_bw_limit(vsi, vsi->seid, max_tx_rate);
+ if (!ret)
+ dev_dbg(&vsi->back->pdev->dev,
+ "Set tx rate of %llu Mbps (count of 50Mbps %llu) for vsi->seid %u\n",
+ max_tx_rate,
+ max_tx_rate / I40E_BW_CREDIT_DIVISOR,
+ vsi->seid);
+ else
+ goto end_unlock;
+ }
+
/* PF Main VSI is rebuild by now, go ahead and rebuild channel VSIs
* for this main VSI if they exist
*/
- ret = i40e_rebuild_channels(pf->vsi[pf->lan_vsi]);
+ ret = i40e_rebuild_channels(vsi);
if (ret)
goto end_unlock;
^ permalink raw reply related
* [RFC PATCH v3 5/6] i40e: Refactor VF BW rate limiting
From: Amritha Nambiar @ 2017-09-07 11:00 UTC (permalink / raw)
To: intel-wired-lan, jeffrey.t.kirsher
Cc: alexander.h.duyck, netdev, amritha.nambiar
In-Reply-To: <150478158684.24662.17975701233699487888.stgit@anamdev.jf.intel.com>
This patch refactors the BW rate limiting for Tx traffic
on the VF to be reused in the next patch for rate limiting Tx
traffic for the VSIs on the PF as well.
v3: Minor fixes, clean up log messages based on Shannon's comments.
Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
---
drivers/net/ethernet/intel/i40e/i40e.h | 5 ++
drivers/net/ethernet/intel/i40e/i40e_main.c | 64 ++++++++++++++++++++
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 45 +-------------
3 files changed, 71 insertions(+), 43 deletions(-)
diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
index ddb7292..2ee0197 100644
--- a/drivers/net/ethernet/intel/i40e/i40e.h
+++ b/drivers/net/ethernet/intel/i40e/i40e.h
@@ -128,6 +128,10 @@
/* default to trying for four seconds */
#define I40E_TRY_LINK_TIMEOUT (4 * HZ)
+/* BW rate limiting */
+#define I40E_BW_CREDIT_DIVISOR 50 /* 50Mbps per BW credit */
+#define I40E_MAX_BW_INACTIVE_ACCUM 4 /* accumulate 4 credits max */
+
/* driver state flags */
enum i40e_state_t {
__I40E_TESTING,
@@ -1042,4 +1046,5 @@ static inline bool i40e_enabled_xdp_vsi(struct i40e_vsi *vsi)
}
int i40e_create_queue_channel(struct i40e_vsi *vsi, struct i40e_channel *ch);
+int i40e_set_bw_limit(struct i40e_vsi *vsi, u16 seid, u64 max_tx_rate);
#endif /* _I40E_H_ */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index a953c2e..7f13bc7 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -5406,6 +5406,70 @@ static int i40e_vsi_config_tc(struct i40e_vsi *vsi, u8 enabled_tc)
}
/**
+ * i40e_get_link_speed - Returns link speed for the interface
+ * @vsi: VSI to be configured
+ *
+ **/
+int i40e_get_link_speed(struct i40e_vsi *vsi)
+{
+ struct i40e_pf *pf = vsi->back;
+
+ switch (pf->hw.phy.link_info.link_speed) {
+ case I40E_LINK_SPEED_40GB:
+ return 40000;
+ case I40E_LINK_SPEED_25GB:
+ return 25000;
+ case I40E_LINK_SPEED_20GB:
+ return 20000;
+ case I40E_LINK_SPEED_10GB:
+ return 10000;
+ case I40E_LINK_SPEED_1GB:
+ return 1000;
+ default:
+ return -EINVAL;
+ }
+}
+
+/**
+ * i40e_set_bw_limit - setup BW limit for Tx traffic based on max_tx_rate
+ * @vsi: VSI to be configured
+ * @seid: seid of the channel/VSI
+ * @max_tx_rate: max TX rate to be configured as BW limit
+ *
+ * Helper function to set BW limit for a given VSI
+ **/
+int i40e_set_bw_limit(struct i40e_vsi *vsi, u16 seid, u64 max_tx_rate)
+{
+ struct i40e_pf *pf = vsi->back;
+ int speed = 0;
+ int ret = 0;
+
+ speed = i40e_get_link_speed(vsi);
+ if (max_tx_rate > speed) {
+ dev_err(&pf->pdev->dev,
+ "Invalid max tx rate %llu specified for VSI seid %d.",
+ max_tx_rate, seid);
+ return -EINVAL;
+ }
+ if (max_tx_rate && max_tx_rate < 50) {
+ dev_warn(&pf->pdev->dev,
+ "Setting max tx rate to minimum usable value of 50Mbps.\n");
+ max_tx_rate = 50;
+ }
+
+ /* Tx rate credits are in values of 50Mbps, 0 is disabled */
+ ret = i40e_aq_config_vsi_bw_limit(&pf->hw, seid,
+ max_tx_rate / I40E_BW_CREDIT_DIVISOR,
+ I40E_MAX_BW_INACTIVE_ACCUM, NULL);
+ if (ret)
+ dev_err(&pf->pdev->dev,
+ "Failed set tx rate (%llu Mbps) for vsi->seid %u, err %s aq_err %s\n",
+ max_tx_rate, seid, i40e_stat_str(&pf->hw, ret),
+ i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
+ return ret;
+}
+
+/**
* i40e_remove_queue_channels - Remove queue channels for the TCs
* @vsi: VSI to be configured
*
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
index ac88d96..06b2548 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
@@ -3115,8 +3115,6 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, int vf_id,
return ret;
}
-#define I40E_BW_CREDIT_DIVISOR 50 /* 50Mbps per BW credit */
-#define I40E_MAX_BW_INACTIVE_ACCUM 4 /* device can accumulate 4 credits max */
/**
* i40e_ndo_set_vf_bw
* @netdev: network interface device structure
@@ -3132,7 +3130,6 @@ int i40e_ndo_set_vf_bw(struct net_device *netdev, int vf_id, int min_tx_rate,
struct i40e_pf *pf = np->vsi->back;
struct i40e_vsi *vsi;
struct i40e_vf *vf;
- int speed = 0;
int ret = 0;
/* validate the request */
@@ -3157,48 +3154,10 @@ int i40e_ndo_set_vf_bw(struct net_device *netdev, int vf_id, int min_tx_rate,
goto error;
}
- switch (pf->hw.phy.link_info.link_speed) {
- case I40E_LINK_SPEED_40GB:
- speed = 40000;
- break;
- case I40E_LINK_SPEED_25GB:
- speed = 25000;
- break;
- case I40E_LINK_SPEED_20GB:
- speed = 20000;
- break;
- case I40E_LINK_SPEED_10GB:
- speed = 10000;
- break;
- case I40E_LINK_SPEED_1GB:
- speed = 1000;
- break;
- default:
- break;
- }
-
- if (max_tx_rate > speed) {
- dev_err(&pf->pdev->dev, "Invalid max tx rate %d specified for VF %d.\n",
- max_tx_rate, vf->vf_id);
- ret = -EINVAL;
+ ret = i40e_set_bw_limit(vsi, vsi->seid, max_tx_rate);
+ if (ret)
goto error;
- }
- if ((max_tx_rate < 50) && (max_tx_rate > 0)) {
- dev_warn(&pf->pdev->dev, "Setting max Tx rate to minimum usable value of 50Mbps.\n");
- max_tx_rate = 50;
- }
-
- /* Tx rate credits are in values of 50Mbps, 0 is disabled*/
- ret = i40e_aq_config_vsi_bw_limit(&pf->hw, vsi->seid,
- max_tx_rate / I40E_BW_CREDIT_DIVISOR,
- I40E_MAX_BW_INACTIVE_ACCUM, NULL);
- if (ret) {
- dev_err(&pf->pdev->dev, "Unable to set max tx rate, error code %d.\n",
- ret);
- ret = -EIO;
- goto error;
- }
vf->tx_rate = max_tx_rate;
error:
return ret;
^ permalink raw reply related
* [RFC PATCH v3 4/6] i40e: Enable 'channel' mode in mqprio for TC configs
From: Amritha Nambiar @ 2017-09-07 11:00 UTC (permalink / raw)
To: intel-wired-lan, jeffrey.t.kirsher
Cc: alexander.h.duyck, netdev, amritha.nambiar
In-Reply-To: <150478158684.24662.17975701233699487888.stgit@anamdev.jf.intel.com>
The i40e driver is modified to enable the new mqprio hardware
offload mode and factor the TCs and queue configuration by
creating channel VSIs. In this mode, the priority to traffic
class mapping and the user specified queue ranges are used
to configure the traffic classes by setting the mode option to
'channel'.
Example:
# tc qdisc add dev eth0 root mqprio num_tc 4\
map 0 0 0 0 1 2 2 3 queues 2@0 2@2 1@4 1@5\
hw 1 mode channel
# tc qdisc show dev eth0
qdisc mqprio 8038: root tc 4 map 0 0 0 0 1 2 2 3 0 0 0 0 0 0 0 0
queues:(0:1) (2:3) (4:4) (5:5)
mode:channel
shaper:dcb
The HW channels created are removed and all the queue configuration
is set to default when the qdisc is detached from the root of the
device.
# tc qdisc del dev eth0 root
This patch also disables setting up channels via ethtool (ethtool -L)
when the TCs are configured using mqprio scheduler.
The patch also limits setting ethtool Rx flow hash indirection
(ethtool -X eth0 equal N) to max queues configured via mqprio.
The Rx flow hash indirection input through ethtool should be
validated so that it is within in the queue range configured via
tc/mqprio. The bound checking is achieved by reporting the current
rss size to the kernel when queues are configured via mqprio.
Example:
# tc qdisc add dev eth0 root mqprio num_tc 4\
map 0 0 0 1 0 2 3 0 queues 2@0 4@2 8@6 11@14\
hw 1 mode channel
# ethtool -X eth0 equal 12
Cannot set RX flow hash configuration: Invalid argument
v3: Changes to incorporate new mqprio mode option. Minor clean
up of setup_tc error handling based on Shannon's comments.
v2: Clean up __i40e_setup_tc() and i40e_setup_tc() to work
with Jiri's changes to the ndo_setup_tc interface which
now takes a type and the type_data for the offload.
No need to disable ATR in MQPRIO mode.
Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
---
drivers/net/ethernet/intel/i40e/i40e.h | 3
drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 8
drivers/net/ethernet/intel/i40e/i40e_main.c | 457 ++++++++++++++++++------
3 files changed, 362 insertions(+), 106 deletions(-)
diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
index 2401931..ddb7292 100644
--- a/drivers/net/ethernet/intel/i40e/i40e.h
+++ b/drivers/net/ethernet/intel/i40e/i40e.h
@@ -54,6 +54,7 @@
#include <linux/clocksource.h>
#include <linux/net_tstamp.h>
#include <linux/ptp_clock_kernel.h>
+#include <net/pkt_cls.h>
#include "i40e_type.h"
#include "i40e_prototype.h"
#include "i40e_client.h"
@@ -700,6 +701,7 @@ struct i40e_vsi {
enum i40e_vsi_type type; /* VSI type, e.g., LAN, FCoE, etc */
s16 vf_id; /* Virtual function ID for SRIOV VSIs */
+ struct tc_mqprio_qopt_offload mqprio_qopt; /* queue parameters */
struct i40e_tc_configuration tc_config;
struct i40e_aqc_vsi_properties_data info;
@@ -725,6 +727,7 @@ struct i40e_vsi {
u16 cnt_q_avail; /* num of queues available for channel usage */
u16 orig_rss_size;
u16 current_rss_size;
+ bool reconfig_rss;
u16 next_base_queue; /* next queue to be used for channel setup */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
index b531aa3..3fa90a6 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
@@ -2652,7 +2652,7 @@ static int i40e_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
switch (cmd->cmd) {
case ETHTOOL_GRXRINGS:
- cmd->data = vsi->num_queue_pairs;
+ cmd->data = vsi->rss_size;
ret = 0;
break;
case ETHTOOL_GRXFH:
@@ -3897,6 +3897,12 @@ static int i40e_set_channels(struct net_device *dev,
if (vsi->type != I40E_VSI_MAIN)
return -EINVAL;
+ /* We do not support setting channels via ethtool when TCs are
+ * configured through mqprio
+ */
+ if (pf->flags & I40E_FLAG_TC_MQPRIO)
+ return -EINVAL;
+
/* verify they are not requesting separate vectors */
if (!count || ch->rx_count || ch->tx_count)
return -EINVAL;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index a5b164d..a953c2e 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -1589,6 +1589,170 @@ static int i40e_set_mac(struct net_device *netdev, void *p)
}
/**
+ * i40e_config_rss_aq - Prepare for RSS using AQ commands
+ * @vsi: vsi structure
+ * @seed: RSS hash seed
+ **/
+static int i40e_config_rss_aq(struct i40e_vsi *vsi, const u8 *seed,
+ u8 *lut, u16 lut_size)
+{
+ struct i40e_pf *pf = vsi->back;
+ struct i40e_hw *hw = &pf->hw;
+ int ret = 0;
+
+ if (seed) {
+ struct i40e_aqc_get_set_rss_key_data *seed_dw =
+ (struct i40e_aqc_get_set_rss_key_data *)seed;
+ ret = i40e_aq_set_rss_key(hw, vsi->id, seed_dw);
+ if (ret) {
+ dev_info(&pf->pdev->dev,
+ "Cannot set RSS key, err %s aq_err %s\n",
+ i40e_stat_str(hw, ret),
+ i40e_aq_str(hw, hw->aq.asq_last_status));
+ return ret;
+ }
+ }
+ if (lut) {
+ bool pf_lut = vsi->type == I40E_VSI_MAIN ? true : false;
+
+ ret = i40e_aq_set_rss_lut(hw, vsi->id, pf_lut, lut, lut_size);
+ if (ret) {
+ dev_info(&pf->pdev->dev,
+ "Cannot set RSS lut, err %s aq_err %s\n",
+ i40e_stat_str(hw, ret),
+ i40e_aq_str(hw, hw->aq.asq_last_status));
+ return ret;
+ }
+ }
+ return ret;
+}
+
+/**
+ * i40e_vsi_config_rss - Prepare for VSI(VMDq) RSS if used
+ * @vsi: VSI structure
+ **/
+static int i40e_vsi_config_rss(struct i40e_vsi *vsi)
+{
+ u8 seed[I40E_HKEY_ARRAY_SIZE];
+ struct i40e_pf *pf = vsi->back;
+ u8 *lut;
+ int ret;
+
+ if (!(pf->hw_features & I40E_HW_RSS_AQ_CAPABLE))
+ return 0;
+ if (!vsi->rss_size)
+ vsi->rss_size = min_t(int, pf->alloc_rss_size,
+ vsi->num_queue_pairs);
+ if (!vsi->rss_size)
+ return -EINVAL;
+ lut = kzalloc(vsi->rss_table_size, GFP_KERNEL);
+ if (!lut)
+ return -ENOMEM;
+
+ /* Use the user configured hash keys and lookup table if there is one,
+ * otherwise use default
+ */
+ if (vsi->rss_lut_user)
+ memcpy(lut, vsi->rss_lut_user, vsi->rss_table_size);
+ else
+ i40e_fill_rss_lut(pf, lut, vsi->rss_table_size, vsi->rss_size);
+ if (vsi->rss_hkey_user)
+ memcpy(seed, vsi->rss_hkey_user, I40E_HKEY_ARRAY_SIZE);
+ else
+ netdev_rss_key_fill((void *)seed, I40E_HKEY_ARRAY_SIZE);
+ ret = i40e_config_rss_aq(vsi, seed, lut, vsi->rss_table_size);
+ kfree(lut);
+ return ret;
+}
+
+/**
+ * i40e_vsi_setup_queue_map_mqprio - Prepares mqprio based tc_config
+ * @vsi: the VSI being configured,
+ * @ctxt: VSI context structure
+ * @enabled_tc: number of traffic classes to enable
+ *
+ * Prepares VSI tc_config to have queue configurations based on MQPRIO options.
+ **/
+static int i40e_vsi_setup_queue_map_mqprio(struct i40e_vsi *vsi,
+ struct i40e_vsi_context *ctxt,
+ u8 enabled_tc)
+{
+ u16 qcount = 0, max_qcount, qmap, sections = 0;
+ int i, override_q, pow, num_qps, ret;
+ u8 netdev_tc = 0, offset = 0;
+
+ if (vsi->type != I40E_VSI_MAIN)
+ return -EINVAL;
+ sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID;
+ sections |= I40E_AQ_VSI_PROP_SCHED_VALID;
+ vsi->tc_config.numtc = vsi->mqprio_qopt.qopt.num_tc;
+ vsi->tc_config.enabled_tc = enabled_tc ? enabled_tc : 1;
+ num_qps = vsi->mqprio_qopt.qopt.count[0];
+
+ /* find the next higher power-of-2 of num queue pairs */
+ pow = ilog2(num_qps);
+ if (!is_power_of_2(num_qps))
+ pow++;
+ qmap = (offset << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) |
+ (pow << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT);
+
+ /* Setup queue offset/count for all TCs for given VSI */
+ max_qcount = vsi->mqprio_qopt.qopt.count[0];
+ for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+ /* See if the given TC is enabled for the given VSI */
+ if (vsi->tc_config.enabled_tc & BIT(i)) {
+ offset = vsi->mqprio_qopt.qopt.offset[i];
+ qcount = vsi->mqprio_qopt.qopt.count[i];
+ if (qcount > max_qcount)
+ max_qcount = qcount;
+ vsi->tc_config.tc_info[i].qoffset = offset;
+ vsi->tc_config.tc_info[i].qcount = qcount;
+ vsi->tc_config.tc_info[i].netdev_tc = netdev_tc++;
+ } else {
+ /* TC is not enabled so set the offset to
+ * default queue and allocate one queue
+ * for the given TC.
+ */
+ vsi->tc_config.tc_info[i].qoffset = 0;
+ vsi->tc_config.tc_info[i].qcount = 1;
+ vsi->tc_config.tc_info[i].netdev_tc = 0;
+ }
+ }
+
+ /* Set actual Tx/Rx queue pairs */
+ vsi->num_queue_pairs = offset + qcount;
+
+ /* Setup queue TC[0].qmap for given VSI context */
+ ctxt->info.tc_mapping[0] = cpu_to_le16(qmap);
+ ctxt->info.mapping_flags |= cpu_to_le16(I40E_AQ_VSI_QUE_MAP_CONTIG);
+ ctxt->info.queue_mapping[0] = cpu_to_le16(vsi->base_queue);
+ ctxt->info.valid_sections |= cpu_to_le16(sections);
+
+ /* Reconfigure RSS for main VSI with max queue count */
+ vsi->rss_size = max_qcount;
+ ret = i40e_vsi_config_rss(vsi);
+ if (ret) {
+ dev_info(&vsi->back->pdev->dev,
+ "Failed to reconfig rss for num_queues (%u)\n",
+ max_qcount);
+ return ret;
+ }
+ vsi->reconfig_rss = true;
+ dev_dbg(&vsi->back->pdev->dev,
+ "Reconfigured rss with num_queues (%u)\n", max_qcount);
+
+ /* Find queue count available for channel VSIs and starting offset
+ * for channel VSIs
+ */
+ override_q = vsi->mqprio_qopt.qopt.count[0];
+ if (override_q && (override_q < vsi->num_queue_pairs)) {
+ vsi->cnt_q_avail = vsi->num_queue_pairs - override_q;
+ vsi->next_base_queue = override_q;
+ }
+ return 0;
+}
+
+/**
* i40e_vsi_setup_queue_map - Setup a VSI queue map based on enabled_tc
* @vsi: the VSI being setup
* @ctxt: VSI context structure
@@ -1626,7 +1790,7 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi,
numtc = 1;
}
} else {
- /* At least TC0 is enabled in case of non-DCB case */
+ /* At least TC0 is enabled in non-DCB, non-MQPRIO case */
numtc = 1;
}
@@ -3163,6 +3327,7 @@ static void i40e_vsi_config_dcb_rings(struct i40e_vsi *vsi)
rx_ring->dcb_tc = 0;
tx_ring->dcb_tc = 0;
}
+ return;
}
for (n = 0; n < I40E_MAX_TRAFFIC_CLASS; n++) {
@@ -4880,6 +5045,24 @@ static u8 i40e_dcb_get_enabled_tc(struct i40e_dcbx_config *dcbcfg)
}
/**
+ * i40e_mqprio_get_enabled_tc - Get enabled traffic classes
+ * @pf: PF being queried
+ *
+ * Query the current MQPRIO configuration and return the number of
+ * traffic classes enabled.
+ **/
+static u8 i40e_mqprio_get_enabled_tc(struct i40e_pf *pf)
+{
+ struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
+ u8 num_tc = vsi->mqprio_qopt.qopt.num_tc;
+ u8 enabled_tc = 1, i;
+
+ for (i = 1; i < num_tc; i++)
+ enabled_tc |= BIT(i);
+ return enabled_tc;
+}
+
+/**
* i40e_pf_get_num_tc - Get enabled traffic classes for PF
* @pf: PF being queried
*
@@ -4892,7 +5075,10 @@ static u8 i40e_pf_get_num_tc(struct i40e_pf *pf)
u8 num_tc = 0;
struct i40e_dcbx_config *dcbcfg = &hw->local_dcbx_config;
- /* If DCB is not enabled then always in single TC */
+ if (pf->flags & I40E_FLAG_TC_MQPRIO)
+ return pf->vsi[pf->lan_vsi]->mqprio_qopt.qopt.num_tc;
+
+ /* If neither MQPRIO nor DCB is enabled, then always use single TC */
if (!(pf->flags & I40E_FLAG_DCB_ENABLED))
return 1;
@@ -4921,7 +5107,12 @@ static u8 i40e_pf_get_num_tc(struct i40e_pf *pf)
**/
static u8 i40e_pf_get_tc_map(struct i40e_pf *pf)
{
- /* If DCB is not enabled for this PF then just return default TC */
+ if (pf->flags & I40E_FLAG_TC_MQPRIO)
+ return i40e_mqprio_get_enabled_tc(pf);
+
+ /* If neither MQPRIO nor DCB is enabled for this PF then just return
+ * default TC
+ */
if (!(pf->flags & I40E_FLAG_DCB_ENABLED))
return I40E_DEFAULT_TRAFFIC_CLASS;
@@ -5011,6 +5202,9 @@ static int i40e_vsi_configure_bw_alloc(struct i40e_vsi *vsi, u8 enabled_tc,
i40e_status ret;
int i;
+ if ((vsi->back->flags & I40E_FLAG_TC_MQPRIO) ||
+ !vsi->mqprio_qopt.qopt.hw)
+ return 0;
bw_data.tc_valid_bits = enabled_tc;
for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
bw_data.tc_bw_credits[i] = bw_share[i];
@@ -5073,6 +5267,9 @@ static void i40e_vsi_config_netdev_tc(struct i40e_vsi *vsi, u8 enabled_tc)
vsi->tc_config.tc_info[i].qoffset);
}
+ if (pf->flags & I40E_FLAG_TC_MQPRIO)
+ return;
+
/* Assign UP2TC map for the VSI */
for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) {
/* Get the actual TC# for the UP */
@@ -5123,7 +5320,8 @@ static int i40e_vsi_config_tc(struct i40e_vsi *vsi, u8 enabled_tc)
int i;
/* Check if enabled_tc is same as existing or new TCs */
- if (vsi->tc_config.enabled_tc == enabled_tc)
+ if (vsi->tc_config.enabled_tc == enabled_tc &&
+ vsi->mqprio_qopt.mode != TC_MQPRIO_MODE_CHANNEL)
return ret;
/* Enable ETS TCs with equal BW Share for now across all VSIs */
@@ -5146,15 +5344,37 @@ static int i40e_vsi_config_tc(struct i40e_vsi *vsi, u8 enabled_tc)
ctxt.vf_num = 0;
ctxt.uplink_seid = vsi->uplink_seid;
ctxt.info = vsi->info;
- i40e_vsi_setup_queue_map(vsi, &ctxt, enabled_tc, false);
+ if (vsi->back->flags & I40E_FLAG_TC_MQPRIO) {
+ ret = i40e_vsi_setup_queue_map_mqprio(vsi, &ctxt, enabled_tc);
+ if (ret)
+ goto out;
+ } else {
+ i40e_vsi_setup_queue_map(vsi, &ctxt, enabled_tc, false);
+ }
+ /* On destroying the qdisc, reset vsi->rss_size, as number of enabled
+ * queues changed.
+ */
+ if (!vsi->mqprio_qopt.qopt.hw && vsi->reconfig_rss) {
+ vsi->rss_size = min_t(int, vsi->back->alloc_rss_size,
+ vsi->num_queue_pairs);
+ ret = i40e_vsi_config_rss(vsi);
+ if (ret) {
+ dev_info(&vsi->back->pdev->dev,
+ "Failed to reconfig rss for num_queues\n");
+ return ret;
+ }
+ vsi->reconfig_rss = false;
+ }
if (vsi->back->flags & I40E_FLAG_IWARP_ENABLED) {
ctxt.info.valid_sections |=
cpu_to_le16(I40E_AQ_VSI_PROP_QUEUE_OPT_VALID);
ctxt.info.queueing_opt_flags |= I40E_AQ_VSI_QUE_OPT_TCP_ENA;
}
- /* Update the VSI after updating the VSI queue-mapping information */
+ /* Update the VSI after updating the VSI queue-mapping
+ * information
+ */
ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL);
if (ret) {
dev_info(&vsi->back->pdev->dev,
@@ -6223,53 +6443,156 @@ void i40e_down(struct i40e_vsi *vsi)
}
/**
+ * i40e_validate_mqprio_qopt- validate queue mapping info
+ * @vsi: the VSI being configured
+ * @mqprio_qopt: queue parametrs
+ **/
+static int i40e_validate_mqprio_qopt(struct i40e_vsi *vsi,
+ struct tc_mqprio_qopt_offload *mqprio_qopt)
+{
+ int i;
+
+ if ((mqprio_qopt->qopt.offset[0] != 0) ||
+ (mqprio_qopt->qopt.num_tc < 1) ||
+ (mqprio_qopt->qopt.num_tc > I40E_MAX_TRAFFIC_CLASS))
+ return -EINVAL;
+ for (i = 0; ; i++) {
+ if (!mqprio_qopt->qopt.count[i])
+ return -EINVAL;
+ if (mqprio_qopt->min_rate[i] || mqprio_qopt->max_rate[i])
+ return -EINVAL;
+ if (i >= mqprio_qopt->qopt.num_tc - 1)
+ break;
+ if (mqprio_qopt->qopt.offset[i + 1] !=
+ (mqprio_qopt->qopt.offset[i] + mqprio_qopt->qopt.count[i]))
+ return -EINVAL;
+ }
+ if (vsi->num_queue_pairs <
+ (mqprio_qopt->qopt.offset[i] + mqprio_qopt->qopt.count[i])) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/**
+ * i40e_vsi_set_default_tc_config - set default values for tc configuration
+ * @vsi: the VSI being configured
+ **/
+static void i40e_vsi_set_default_tc_config(struct i40e_vsi *vsi)
+{
+ u16 qcount;
+ int i;
+
+ /* Only TC0 is enabled */
+ vsi->tc_config.numtc = 1;
+ vsi->tc_config.enabled_tc = 1;
+ qcount = min_t(int, vsi->alloc_queue_pairs,
+ i40e_pf_get_max_q_per_tc(vsi->back));
+ for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+ /* For the TC that is not enabled set the offset to to default
+ * queue and allocate one queue for the given TC.
+ */
+ vsi->tc_config.tc_info[i].qoffset = 0;
+ if (i == 0)
+ vsi->tc_config.tc_info[i].qcount = qcount;
+ else
+ vsi->tc_config.tc_info[i].qcount = 1;
+ vsi->tc_config.tc_info[i].netdev_tc = 0;
+ }
+}
+
+/**
* i40e_setup_tc - configure multiple traffic classes
* @netdev: net device to configure
- * @tc: number of traffic classes to enable
+ * @type_data: tc offload data
**/
-static int i40e_setup_tc(struct net_device *netdev, u8 tc)
+static int i40e_setup_tc(struct net_device *netdev, void *type_data)
{
+ struct tc_mqprio_qopt_offload *mqprio_qopt = type_data;
struct i40e_netdev_priv *np = netdev_priv(netdev);
struct i40e_vsi *vsi = np->vsi;
struct i40e_pf *pf = vsi->back;
- u8 enabled_tc = 0;
+ u8 enabled_tc = 0, num_tc, hw;
+ bool need_reset = false;
int ret = -EINVAL;
+ u16 mode;
int i;
- /* Check if DCB enabled to continue */
- if (!(pf->flags & I40E_FLAG_DCB_ENABLED)) {
- netdev_info(netdev, "DCB is not enabled for adapter\n");
- goto exit;
+ num_tc = mqprio_qopt->qopt.num_tc;
+ hw = mqprio_qopt->qopt.hw;
+ mode = mqprio_qopt->mode;
+ if (!hw) {
+ pf->flags &= ~I40E_FLAG_TC_MQPRIO;
+ memcpy(&vsi->mqprio_qopt, mqprio_qopt, sizeof(*mqprio_qopt));
+ goto config_tc;
}
/* Check if MFP enabled */
if (pf->flags & I40E_FLAG_MFP_ENABLED) {
- netdev_info(netdev, "Configuring TC not supported in MFP mode\n");
- goto exit;
+ netdev_info(netdev,
+ "Configuring TC not supported in MFP mode\n");
+ return ret;
}
+ switch (mode) {
+ case TC_MQPRIO_MODE_DCB:
+ pf->flags &= ~I40E_FLAG_TC_MQPRIO;
- /* Check whether tc count is within enabled limit */
- if (tc > i40e_pf_get_num_tc(pf)) {
- netdev_info(netdev, "TC count greater than enabled on link for adapter\n");
- goto exit;
+ /* Check if DCB enabled to continue */
+ if (!(pf->flags & I40E_FLAG_DCB_ENABLED)) {
+ netdev_info(netdev,
+ "DCB is not enabled for adapter\n");
+ return ret;
+ }
+
+ /* Check whether tc count is within enabled limit */
+ if (num_tc > i40e_pf_get_num_tc(pf)) {
+ netdev_info(netdev,
+ "TC count greater than enabled on link for adapter\n");
+ return ret;
+ }
+ break;
+ case TC_MQPRIO_MODE_CHANNEL:
+ if (pf->flags & I40E_FLAG_DCB_ENABLED) {
+ netdev_info(netdev,
+ "Full offload of TC Mqprio options is not supported when DCB is enabled\n");
+ return ret;
+ }
+ if (!(pf->flags & I40E_FLAG_MSIX_ENABLED))
+ return ret;
+ ret = i40e_validate_mqprio_qopt(vsi, mqprio_qopt);
+ if (ret)
+ return ret;
+ memcpy(&vsi->mqprio_qopt, mqprio_qopt,
+ sizeof(*mqprio_qopt));
+ pf->flags |= I40E_FLAG_TC_MQPRIO;
+ pf->flags &= ~I40E_FLAG_DCB_ENABLED;
+ break;
+ default:
+ return -EINVAL;
}
+config_tc:
/* Generate TC map for number of tc requested */
- for (i = 0; i < tc; i++)
+ for (i = 0; i < num_tc; i++)
enabled_tc |= BIT(i);
/* Requesting same TC configuration as already enabled */
- if (enabled_tc == vsi->tc_config.enabled_tc)
+ if (enabled_tc == vsi->tc_config.enabled_tc &&
+ mode != TC_MQPRIO_MODE_CHANNEL)
return 0;
/* Quiesce VSI queues */
i40e_quiesce_vsi(vsi);
+ if (!hw && !(pf->flags & I40E_FLAG_TC_MQPRIO))
+ i40e_remove_queue_channels(vsi);
+
/* Configure VSI for enabled TCs */
ret = i40e_vsi_config_tc(vsi, enabled_tc);
if (ret) {
netdev_info(netdev, "Failed configuring TC for VSI seid=%d\n",
vsi->seid);
+ need_reset = true;
goto exit;
}
@@ -6278,11 +6601,18 @@ static int i40e_setup_tc(struct net_device *netdev, u8 tc)
if (ret) {
netdev_info(netdev,
"Failed configuring queue channels\n");
+ need_reset = true;
goto exit;
}
}
exit:
+ /* Reset the configuration data to defaults, only TC0 is enabled */
+ if (need_reset) {
+ i40e_vsi_set_default_tc_config(vsi);
+ need_reset = false;
+ }
+
/* Unquiesce VSI */
i40e_unquiesce_vsi(vsi);
return ret;
@@ -6291,14 +6621,10 @@ static int i40e_setup_tc(struct net_device *netdev, u8 tc)
static int __i40e_setup_tc(struct net_device *netdev, enum tc_setup_type type,
void *type_data)
{
- struct tc_mqprio_qopt *mqprio = type_data;
-
if (type != TC_SETUP_MQPRIO)
return -EOPNOTSUPP;
- mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
-
- return i40e_setup_tc(netdev, mqprio->num_tc);
+ return i40e_setup_tc(netdev, type_data);
}
/**
@@ -9160,45 +9486,6 @@ static int i40e_setup_misc_vector(struct i40e_pf *pf)
}
/**
- * i40e_config_rss_aq - Prepare for RSS using AQ commands
- * @vsi: vsi structure
- * @seed: RSS hash seed
- **/
-static int i40e_config_rss_aq(struct i40e_vsi *vsi, const u8 *seed,
- u8 *lut, u16 lut_size)
-{
- struct i40e_pf *pf = vsi->back;
- struct i40e_hw *hw = &pf->hw;
- int ret = 0;
-
- if (seed) {
- struct i40e_aqc_get_set_rss_key_data *seed_dw =
- (struct i40e_aqc_get_set_rss_key_data *)seed;
- ret = i40e_aq_set_rss_key(hw, vsi->id, seed_dw);
- if (ret) {
- dev_info(&pf->pdev->dev,
- "Cannot set RSS key, err %s aq_err %s\n",
- i40e_stat_str(hw, ret),
- i40e_aq_str(hw, hw->aq.asq_last_status));
- return ret;
- }
- }
- if (lut) {
- bool pf_lut = vsi->type == I40E_VSI_MAIN ? true : false;
-
- ret = i40e_aq_set_rss_lut(hw, vsi->id, pf_lut, lut, lut_size);
- if (ret) {
- dev_info(&pf->pdev->dev,
- "Cannot set RSS lut, err %s aq_err %s\n",
- i40e_stat_str(hw, ret),
- i40e_aq_str(hw, hw->aq.asq_last_status));
- return ret;
- }
- }
- return ret;
-}
-
-/**
* i40e_get_rss_aq - Get RSS keys and lut by using AQ commands
* @vsi: Pointer to vsi structure
* @seed: Buffter to store the hash keys
@@ -9245,46 +9532,6 @@ static int i40e_get_rss_aq(struct i40e_vsi *vsi, const u8 *seed,
}
/**
- * i40e_vsi_config_rss - Prepare for VSI(VMDq) RSS if used
- * @vsi: VSI structure
- **/
-static int i40e_vsi_config_rss(struct i40e_vsi *vsi)
-{
- u8 seed[I40E_HKEY_ARRAY_SIZE];
- struct i40e_pf *pf = vsi->back;
- u8 *lut;
- int ret;
-
- if (!(pf->hw_features & I40E_HW_RSS_AQ_CAPABLE))
- return 0;
-
- if (!vsi->rss_size)
- vsi->rss_size = min_t(int, pf->alloc_rss_size,
- vsi->num_queue_pairs);
- if (!vsi->rss_size)
- return -EINVAL;
-
- lut = kzalloc(vsi->rss_table_size, GFP_KERNEL);
- if (!lut)
- return -ENOMEM;
- /* Use the user configured hash keys and lookup table if there is one,
- * otherwise use default
- */
- if (vsi->rss_lut_user)
- memcpy(lut, vsi->rss_lut_user, vsi->rss_table_size);
- else
- i40e_fill_rss_lut(pf, lut, vsi->rss_table_size, vsi->rss_size);
- if (vsi->rss_hkey_user)
- memcpy(seed, vsi->rss_hkey_user, I40E_HKEY_ARRAY_SIZE);
- else
- netdev_rss_key_fill((void *)seed, I40E_HKEY_ARRAY_SIZE);
- ret = i40e_config_rss_aq(vsi, seed, lut, vsi->rss_table_size);
- kfree(lut);
-
- return ret;
-}
-
-/**
* i40e_config_rss_reg - Configure RSS keys and lut by writing registers
* @vsi: Pointer to vsi structure
* @seed: RSS hash seed
^ permalink raw reply related
* [RFC PATCH v3 2/6] i40e: Add macro for PF reset bit
From: Amritha Nambiar @ 2017-09-07 11:00 UTC (permalink / raw)
To: intel-wired-lan, jeffrey.t.kirsher
Cc: alexander.h.duyck, netdev, amritha.nambiar
In-Reply-To: <150478158684.24662.17975701233699487888.stgit@anamdev.jf.intel.com>
Introduce a macro for the bit setting the PF reset flag and
update its usages. This makes it easier to use this flag
in functions to be introduced in future without encountering
checkpatch issues related to alignment and line over 80
characters.
Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
---
drivers/net/ethernet/intel/i40e/i40e.h | 2 ++
drivers/net/ethernet/intel/i40e/i40e_debugfs.c | 3 +--
drivers/net/ethernet/intel/i40e/i40e_main.c | 9 ++++-----
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 5 ++---
4 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
index 18c453a..d414adc 100644
--- a/drivers/net/ethernet/intel/i40e/i40e.h
+++ b/drivers/net/ethernet/intel/i40e/i40e.h
@@ -157,6 +157,8 @@ enum i40e_state_t {
__I40E_STATE_SIZE__,
};
+#define I40E_PF_RESET_FLAG BIT_ULL(__I40E_PF_RESET_REQUESTED)
+
/* VSI state flags */
enum i40e_vsi_state_t {
__I40E_VSI_DOWN,
diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
index 6f2725f..2b8bbc8 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
@@ -798,8 +798,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
*/
if (!(pf->flags & I40E_FLAG_VEB_MODE_ENABLED)) {
pf->flags |= I40E_FLAG_VEB_MODE_ENABLED;
- i40e_do_reset_safe(pf,
- BIT_ULL(__I40E_PF_RESET_REQUESTED));
+ i40e_do_reset_safe(pf, I40E_PF_RESET_FLAG);
}
vsi = i40e_vsi_setup(pf, I40E_VSI_VMDQ2, vsi_seid, 0);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 76b03f7..2fdb99f 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -5753,7 +5753,7 @@ int i40e_vsi_open(struct i40e_vsi *vsi)
err_setup_tx:
i40e_vsi_free_tx_resources(vsi);
if (vsi == pf->vsi[pf->lan_vsi])
- i40e_do_reset(pf, BIT_ULL(__I40E_PF_RESET_REQUESTED), true);
+ i40e_do_reset(pf, I40E_PF_RESET_FLAG, true);
return err;
}
@@ -5881,7 +5881,7 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags, bool lock_acquired)
wr32(&pf->hw, I40E_GLGEN_RTRIG, val);
i40e_flush(&pf->hw);
- } else if (reset_flags & BIT_ULL(__I40E_PF_RESET_REQUESTED)) {
+ } else if (reset_flags & I40E_PF_RESET_FLAG) {
/* Request a PF Reset
*
@@ -9229,7 +9229,7 @@ static int i40e_set_features(struct net_device *netdev,
need_reset = i40e_set_ntuple(pf, features);
if (need_reset)
- i40e_do_reset(pf, BIT_ULL(__I40E_PF_RESET_REQUESTED), true);
+ i40e_do_reset(pf, I40E_PF_RESET_FLAG, true);
return 0;
}
@@ -9481,8 +9481,7 @@ static int i40e_ndo_bridge_setlink(struct net_device *dev,
pf->flags |= I40E_FLAG_VEB_MODE_ENABLED;
else
pf->flags &= ~I40E_FLAG_VEB_MODE_ENABLED;
- i40e_do_reset(pf, BIT_ULL(__I40E_PF_RESET_REQUESTED),
- true);
+ i40e_do_reset(pf, I40E_PF_RESET_FLAG, true);
break;
}
}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
index 8bedc74c..ac88d96 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
@@ -1424,8 +1424,7 @@ int i40e_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
if (num_vfs) {
if (!(pf->flags & I40E_FLAG_VEB_MODE_ENABLED)) {
pf->flags |= I40E_FLAG_VEB_MODE_ENABLED;
- i40e_do_reset_safe(pf,
- BIT_ULL(__I40E_PF_RESET_REQUESTED));
+ i40e_do_reset_safe(pf, I40E_PF_RESET_FLAG);
}
return i40e_pci_sriov_enable(pdev, num_vfs);
}
@@ -1433,7 +1432,7 @@ int i40e_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
if (!pci_vfs_assigned(pf->pdev)) {
i40e_free_vfs(pf);
pf->flags &= ~I40E_FLAG_VEB_MODE_ENABLED;
- i40e_do_reset_safe(pf, BIT_ULL(__I40E_PF_RESET_REQUESTED));
+ i40e_do_reset_safe(pf, I40E_PF_RESET_FLAG);
} else {
dev_warn(&pdev->dev, "Unable to free VFs because some are assigned to VMs.\n");
return -EINVAL;
^ permalink raw reply related
* [RFC PATCH v3 3/6] i40e: Add infrastructure for queue channel support
From: Amritha Nambiar @ 2017-09-07 11:00 UTC (permalink / raw)
To: intel-wired-lan, jeffrey.t.kirsher
Cc: alexander.h.duyck, netdev, amritha.nambiar
In-Reply-To: <150478158684.24662.17975701233699487888.stgit@anamdev.jf.intel.com>
This patch sets up the infrastructure for offloading TCs and
queue configurations to the hardware by creating HW channels(VSI).
A new channel is created for each of the traffic class
configuration offloaded via mqprio framework except for the first TC
(TC0). TC0 for the main VSI is also reconfigured as per user provided
queue parameters. Queue counts that are not power-of-2 are handled by
reconfiguring RSS by reprogramming LUTs using the queue count value.
This patch also handles configuring the TX rings for the channels,
setting up the RX queue map for channel.
Also, the channels so created are removed and all the queue
configuration is set to default when the qdisc is detached from the
root of the device.
v3: Addressed Shannon's feedback removing unwanted code, variables,
atomic operations (since setup_tc is protected with rtnl_lock held
by stack) and other minor clean up.
Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
Signed-off-by: Kiran Patil <kiran.patil@intel.com>
---
drivers/net/ethernet/intel/i40e/i40e.h | 32 +
drivers/net/ethernet/intel/i40e/i40e_main.c | 718 +++++++++++++++++++++++++++
drivers/net/ethernet/intel/i40e/i40e_txrx.h | 2
3 files changed, 743 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
index d414adc..2401931 100644
--- a/drivers/net/ethernet/intel/i40e/i40e.h
+++ b/drivers/net/ethernet/intel/i40e/i40e.h
@@ -87,6 +87,7 @@
#define I40E_AQ_LEN 256
#define I40E_AQ_WORK_LIMIT 66 /* max number of VFs + a little */
#define I40E_MAX_USER_PRIORITY 8
+#define I40E_MAX_QUEUES_PER_CH 64
#define I40E_DEFAULT_TRAFFIC_CLASS BIT(0)
#define I40E_DEFAULT_MSG_ENABLE 4
#define I40E_QUEUE_WAIT_RETRY_LIMIT 10
@@ -340,6 +341,23 @@ struct i40e_flex_pit {
u8 pit_index;
};
+struct i40e_channel {
+ struct list_head list;
+ bool initialized;
+ u8 type;
+ u16 vsi_number; /* Assigned VSI number from AQ 'Add VSI' response */
+ u16 stat_counter_idx;
+ u16 base_queue;
+ u16 num_queue_pairs; /* Requested by user */
+ u16 seid;
+
+ u8 enabled_tc;
+ struct i40e_aqc_vsi_properties_data info;
+
+ /* track this channel belongs to which VSI */
+ struct i40e_vsi *parent_vsi;
+};
+
/* struct that defines the Ethernet device */
struct i40e_pf {
struct pci_dev *pdev;
@@ -456,6 +474,7 @@ struct i40e_pf {
#define I40E_FLAG_CLIENT_RESET BIT(26)
#define I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED BIT(27)
#define I40E_FLAG_SOURCE_PRUNING_DISABLED BIT(28)
+#define I40E_FLAG_TC_MQPRIO BIT(29)
struct i40e_client_instance *cinst;
bool stat_offsets_loaded;
@@ -536,6 +555,8 @@ struct i40e_pf {
u32 ioremap_len;
u32 fd_inv;
u16 phy_led_val;
+
+ u16 override_q_count;
};
/**
@@ -700,6 +721,15 @@ struct i40e_vsi {
bool current_isup; /* Sync 'link up' logging */
enum i40e_aq_link_speed current_speed; /* Sync link speed logging */
+ /* channel specific fields */
+ u16 cnt_q_avail; /* num of queues available for channel usage */
+ u16 orig_rss_size;
+ u16 current_rss_size;
+
+ u16 next_base_queue; /* next queue to be used for channel setup */
+
+ struct list_head ch_list;
+
void *priv; /* client driver data reference. */
/* VSI specific handlers */
@@ -1007,4 +1037,6 @@ static inline bool i40e_enabled_xdp_vsi(struct i40e_vsi *vsi)
{
return !!vsi->xdp_prog;
}
+
+int i40e_create_queue_channel(struct i40e_vsi *vsi, struct i40e_channel *ch);
#endif /* _I40E_H_ */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 2fdb99f..a5b164d 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -2882,7 +2882,7 @@ static void i40e_config_xps_tx_ring(struct i40e_ring *ring)
struct i40e_vsi *vsi = ring->vsi;
int cpu;
- if (!ring->q_vector || !ring->netdev)
+ if (!ring->q_vector || !ring->netdev || ring->ch)
return;
if ((vsi->tc_config.numtc <= 1) &&
@@ -2949,7 +2949,14 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
* initialization. This has to be done regardless of
* DCB as by default everything is mapped to TC0.
*/
- tx_ctx.rdylist = le16_to_cpu(vsi->info.qs_handle[ring->dcb_tc]);
+
+ if (ring->ch)
+ tx_ctx.rdylist =
+ le16_to_cpu(ring->ch->info.qs_handle[ring->dcb_tc]);
+
+ else
+ tx_ctx.rdylist = le16_to_cpu(vsi->info.qs_handle[ring->dcb_tc]);
+
tx_ctx.rdylist_act = 0;
/* clear the context in the HMC */
@@ -2971,12 +2978,23 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
}
/* Now associate this queue with this PCI function */
- if (vsi->type == I40E_VSI_VMDQ2) {
- qtx_ctl = I40E_QTX_CTL_VM_QUEUE;
- qtx_ctl |= ((vsi->id) << I40E_QTX_CTL_VFVM_INDX_SHIFT) &
- I40E_QTX_CTL_VFVM_INDX_MASK;
+ if (ring->ch) {
+ if (ring->ch->type == I40E_VSI_VMDQ2)
+ qtx_ctl = I40E_QTX_CTL_VM_QUEUE;
+ else
+ return -EINVAL;
+
+ qtx_ctl |= (ring->ch->vsi_number <<
+ I40E_QTX_CTL_VFVM_INDX_SHIFT) &
+ I40E_QTX_CTL_VFVM_INDX_MASK;
} else {
- qtx_ctl = I40E_QTX_CTL_PF_QUEUE;
+ if (vsi->type == I40E_VSI_VMDQ2) {
+ qtx_ctl = I40E_QTX_CTL_VM_QUEUE;
+ qtx_ctl |= ((vsi->id) << I40E_QTX_CTL_VFVM_INDX_SHIFT) &
+ I40E_QTX_CTL_VFVM_INDX_MASK;
+ } else {
+ qtx_ctl = I40E_QTX_CTL_PF_QUEUE;
+ }
}
qtx_ctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) &
@@ -5168,6 +5186,643 @@ static int i40e_vsi_config_tc(struct i40e_vsi *vsi, u8 enabled_tc)
}
/**
+ * i40e_remove_queue_channels - Remove queue channels for the TCs
+ * @vsi: VSI to be configured
+ *
+ * Remove queue channels for the TCs
+ **/
+static void i40e_remove_queue_channels(struct i40e_vsi *vsi)
+{
+ struct i40e_channel *ch, *ch_tmp;
+ int ret, i;
+
+ /* Reset rss size that was stored when reconfiguring rss for
+ * channel VSIs with non-power-of-2 queue count.
+ */
+ vsi->current_rss_size = 0;
+
+ /* perform cleanup for channels if they exist */
+ if (list_empty(&vsi->ch_list))
+ return;
+
+ list_for_each_entry_safe(ch, ch_tmp, &vsi->ch_list, list) {
+ struct i40e_vsi *p_vsi;
+
+ list_del(&ch->list);
+ p_vsi = ch->parent_vsi;
+ if (!p_vsi || !ch->initialized) {
+ kfree(ch);
+ continue;
+ }
+ /* Reset queue contexts */
+ for (i = 0; i < ch->num_queue_pairs; i++) {
+ struct i40e_ring *tx_ring, *rx_ring;
+ u16 pf_q;
+
+ pf_q = ch->base_queue + i;
+ tx_ring = vsi->tx_rings[pf_q];
+ tx_ring->ch = NULL;
+
+ rx_ring = vsi->rx_rings[pf_q];
+ rx_ring->ch = NULL;
+ }
+
+ /* delete VSI from FW */
+ ret = i40e_aq_delete_element(&vsi->back->hw, ch->seid,
+ NULL);
+ if (ret)
+ dev_err(&vsi->back->pdev->dev,
+ "unable to remove channel (%d) for parent VSI(%d)\n",
+ ch->seid, p_vsi->seid);
+ kfree(ch);
+ }
+ INIT_LIST_HEAD(&vsi->ch_list);
+}
+
+/**
+ * i40e_is_any_channel - channel exist or not
+ * @vsi: ptr to VSI to which channels are associated with
+ *
+ * Returns true or false if channel(s) exist for associated VSI or not
+ **/
+static bool i40e_is_any_channel(struct i40e_vsi *vsi)
+{
+ struct i40e_channel *ch, *ch_tmp;
+
+ list_for_each_entry_safe(ch, ch_tmp, &vsi->ch_list, list) {
+ if (ch->initialized)
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * i40e_get_max_queues_for_channel
+ * @vsi: ptr to VSI to which channels are associated with
+ *
+ * Helper function which returns max value among the queue counts set on the
+ * channels/TCs created.
+ **/
+static int i40e_get_max_queues_for_channel(struct i40e_vsi *vsi)
+{
+ struct i40e_channel *ch, *ch_tmp;
+ int max = 0;
+
+ list_for_each_entry_safe(ch, ch_tmp, &vsi->ch_list, list) {
+ if (!ch->initialized)
+ continue;
+ if (ch->num_queue_pairs > max)
+ max = ch->num_queue_pairs;
+ }
+
+ return max;
+}
+
+/**
+ * i40e_validate_num_queues - validate num_queues w.r.t channel
+ * @pf: ptr to PF device
+ * @num_queues: number of queues
+ * @vsi: the parent VSI
+ * @reconfig_rss: indicates should the RSS be reconfigured or not
+ *
+ * This function validates number of queues in the context of new channel
+ * which is being established and determines if RSS should be reconfigured
+ * or not for parent VSI.
+ **/
+static int i40e_validate_num_queues(struct i40e_pf *pf, int num_queues,
+ struct i40e_vsi *vsi, bool *reconfig_rss)
+{
+ int max_ch_queues;
+
+ if (!reconfig_rss)
+ return -EINVAL;
+
+ *reconfig_rss = false;
+
+ if (num_queues > I40E_MAX_QUEUES_PER_CH) {
+ dev_err(&pf->pdev->dev,
+ "Failed to create VMDq VSI. User requested num_queues (%d) > I40E_MAX_QUEUES_PER_VSI (%u)\n",
+ num_queues, I40E_MAX_QUEUES_PER_CH);
+ return -EINVAL;
+ }
+
+ if (vsi->current_rss_size) {
+ if (num_queues > vsi->current_rss_size) {
+ dev_dbg(&pf->pdev->dev,
+ "Error: num_queues (%d) > vsi's current_size(%d)\n",
+ num_queues, vsi->current_rss_size);
+ return -EINVAL;
+ } else if ((num_queues < vsi->current_rss_size) &&
+ (!is_power_of_2(num_queues))) {
+ dev_dbg(&pf->pdev->dev,
+ "Error: num_queues (%d) < vsi's current_size(%d), but not power of 2\n",
+ num_queues, vsi->current_rss_size);
+ return -EINVAL;
+ }
+ }
+
+ if (!is_power_of_2(num_queues)) {
+ /* Find the max num_queues configured for channel if channel
+ * exist.
+ * if channel exist, then enforce 'num_queues' to be more than
+ * max ever queues configured for channel.
+ */
+ max_ch_queues = i40e_get_max_queues_for_channel(vsi);
+ if (num_queues < max_ch_queues) {
+ dev_dbg(&pf->pdev->dev,
+ "Error: num_queues (%d) < max queues configured for channel(%d)\n",
+ num_queues, max_ch_queues);
+ return -EINVAL;
+ }
+ *reconfig_rss = true;
+ }
+
+ return 0;
+}
+
+/**
+ * i40e_vsi_reconfig_rss - reconfig RSS based on specified rss_size
+ * @vsi: the VSI being setup
+ * @rss_size: size of RSS, accordingly LUT gets reprogrammed
+ *
+ * This function reconfigures RSS by reprogramming LUTs using 'rss_size'
+ **/
+static int i40e_vsi_reconfig_rss(struct i40e_vsi *vsi, u16 rss_size)
+{
+ struct i40e_pf *pf = vsi->back;
+ u8 seed[I40E_HKEY_ARRAY_SIZE];
+ struct i40e_hw *hw = &pf->hw;
+ int local_rss_size;
+ u8 *lut;
+ int ret;
+
+ if (!vsi->rss_size)
+ return -EINVAL;
+
+ if (rss_size > vsi->rss_size)
+ return -EINVAL;
+
+ local_rss_size = min_t(int, vsi->rss_size, rss_size);
+ lut = kzalloc(vsi->rss_table_size, GFP_KERNEL);
+ if (!lut)
+ return -ENOMEM;
+
+ /* Ignoring user configured lut if there is one */
+ i40e_fill_rss_lut(pf, lut, vsi->rss_table_size, local_rss_size);
+
+ /* Use user configured hash key if there is one, otherwise
+ * use default.
+ */
+ if (vsi->rss_hkey_user)
+ memcpy(seed, vsi->rss_hkey_user, I40E_HKEY_ARRAY_SIZE);
+ else
+ netdev_rss_key_fill((void *)seed, I40E_HKEY_ARRAY_SIZE);
+
+ ret = i40e_config_rss(vsi, seed, lut, vsi->rss_table_size);
+ if (ret) {
+ dev_info(&pf->pdev->dev,
+ "Cannot set RSS lut, err %s aq_err %s\n",
+ i40e_stat_str(hw, ret),
+ i40e_aq_str(hw, hw->aq.asq_last_status));
+ kfree(lut);
+ return ret;
+ }
+ kfree(lut);
+
+ /* Do the update w.r.t. storing rss_size */
+ if (!vsi->orig_rss_size)
+ vsi->orig_rss_size = vsi->rss_size;
+ vsi->current_rss_size = local_rss_size;
+
+ return ret;
+}
+
+/**
+ * i40e_channel_setup_queue_map - Setup a channel queue map
+ * @pf: ptr to PF device
+ * @vsi: the VSI being setup
+ * @ctxt: VSI context structure
+ * @ch: ptr to channel structure
+ *
+ * Setup queue map for a specific channel
+ **/
+static void i40e_channel_setup_queue_map(struct i40e_pf *pf,
+ struct i40e_vsi_context *ctxt,
+ struct i40e_channel *ch)
+{
+ u16 qcount, qmap, sections = 0;
+ int pow;
+ u8 offset = 0;
+
+ sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID;
+ sections |= I40E_AQ_VSI_PROP_SCHED_VALID;
+
+ qcount = min_t(int, ch->num_queue_pairs, pf->num_lan_msix);
+ ch->num_queue_pairs = qcount;
+
+ /* find the next higher power-of-2 of num queue pairs */
+ pow = ilog2(qcount);
+ if (!is_power_of_2(qcount))
+ pow++;
+
+ qmap = (offset << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) |
+ (pow << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT);
+
+ /* Setup queue TC[0].qmap for given VSI context */
+ ctxt->info.tc_mapping[0] = cpu_to_le16(qmap);
+
+ ctxt->info.up_enable_bits = 0x1; /* TC0 enabled */
+ ctxt->info.mapping_flags |= cpu_to_le16(I40E_AQ_VSI_QUE_MAP_CONTIG);
+ ctxt->info.queue_mapping[0] = cpu_to_le16(ch->base_queue);
+ ctxt->info.valid_sections |= cpu_to_le16(sections);
+}
+
+/**
+ * i40e_add_channel - add a channel by adding VSI
+ * @pf: ptr to PF device
+ * @uplink_seid: underlying HW switching element (VEB) ID
+ * @ch: ptr to channel structure
+ *
+ * Add a channel (VSI) using add_vsi and queue_map
+ **/
+static int i40e_add_channel(struct i40e_pf *pf, u16 uplink_seid,
+ struct i40e_channel *ch)
+{
+ struct i40e_hw *hw = &pf->hw;
+ struct i40e_vsi_context ctxt;
+ u8 enabled_tc = 0x1; /* TC0 enabled */
+ int ret;
+
+ if (ch->type != I40E_VSI_VMDQ2) {
+ dev_info(&pf->pdev->dev,
+ "add new vsi failed, ch->type %d\n", ch->type);
+ return -EINVAL;
+ }
+
+ memset(&ctxt, 0, sizeof(ctxt));
+ ctxt.pf_num = hw->pf_id;
+ ctxt.vf_num = 0;
+ ctxt.uplink_seid = uplink_seid;
+ ctxt.connection_type = I40E_AQ_VSI_CONN_TYPE_NORMAL;
+ if (ch->type == I40E_VSI_VMDQ2)
+ ctxt.flags = I40E_AQ_VSI_TYPE_VMDQ2;
+
+ if (pf->flags & I40E_FLAG_VEB_MODE_ENABLED) {
+ ctxt.info.valid_sections |=
+ cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID);
+ ctxt.info.switch_id =
+ cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB);
+ }
+
+ /* Set queue map for a given VSI context */
+ i40e_channel_setup_queue_map(pf, &ctxt, ch);
+
+ /* Now time to create VSI */
+ ret = i40e_aq_add_vsi(hw, &ctxt, NULL);
+ if (ret) {
+ dev_info(&pf->pdev->dev,
+ "add new vsi failed, err %s aq_err %s\n",
+ i40e_stat_str(&pf->hw, ret),
+ i40e_aq_str(&pf->hw,
+ pf->hw.aq.asq_last_status));
+ return -ENOENT;
+ }
+
+ /* Success, update channel */
+ ch->enabled_tc = enabled_tc;
+ ch->seid = ctxt.seid;
+ ch->vsi_number = ctxt.vsi_number;
+ ch->stat_counter_idx = cpu_to_le16(ctxt.info.stat_counter_idx);
+
+ /* copy just the sections touched not the entire info
+ * since not all sections are valid as returned by
+ * update vsi params
+ */
+ ch->info.mapping_flags = ctxt.info.mapping_flags;
+ memcpy(&ch->info.queue_mapping,
+ &ctxt.info.queue_mapping, sizeof(ctxt.info.queue_mapping));
+ memcpy(&ch->info.tc_mapping, ctxt.info.tc_mapping,
+ sizeof(ctxt.info.tc_mapping));
+
+ return 0;
+}
+
+static int i40e_channel_config_bw(struct i40e_vsi *vsi, struct i40e_channel *ch,
+ u8 *bw_share)
+{
+ struct i40e_aqc_configure_vsi_tc_bw_data bw_data;
+ i40e_status ret;
+ int i;
+
+ bw_data.tc_valid_bits = ch->enabled_tc;
+ for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
+ bw_data.tc_bw_credits[i] = bw_share[i];
+
+ ret = i40e_aq_config_vsi_tc_bw(&vsi->back->hw, ch->seid,
+ &bw_data, NULL);
+ if (ret) {
+ dev_info(&vsi->back->pdev->dev,
+ "Config VSI BW allocation per TC failed, aq_err: %d for new_vsi->seid %u\n",
+ vsi->back->hw.aq.asq_last_status, ch->seid);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
+ ch->info.qs_handle[i] = bw_data.qs_handles[i];
+
+ return 0;
+}
+
+/**
+ * i40e_channel_config_tx_ring - config TX ring associated with new channel
+ * @pf: ptr to PF device
+ * @vsi: the VSI being setup
+ * @ch: ptr to channel structure
+ *
+ * Configure TX rings associated with channel (VSI) since queues are being
+ * from parent VSI.
+ **/
+static int i40e_channel_config_tx_ring(struct i40e_pf *pf,
+ struct i40e_vsi *vsi,
+ struct i40e_channel *ch)
+{
+ i40e_status ret;
+ int i;
+ u8 bw_share[I40E_MAX_TRAFFIC_CLASS] = {0};
+
+ /* Enable ETS TCs with equal BW Share for now across all VSIs */
+ for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+ if (ch->enabled_tc & BIT(i))
+ bw_share[i] = 1;
+ }
+
+ /* configure BW for new VSI */
+ ret = i40e_channel_config_bw(vsi, ch, bw_share);
+ if (ret) {
+ dev_info(&vsi->back->pdev->dev,
+ "Failed configuring TC map %d for channel (seid %u)\n",
+ ch->enabled_tc, ch->seid);
+ return ret;
+ }
+
+ for (i = 0; i < ch->num_queue_pairs; i++) {
+ struct i40e_ring *tx_ring, *rx_ring;
+ u16 pf_q;
+
+ pf_q = ch->base_queue + i;
+
+ /* Get to TX ring ptr of main VSI, for re-setup TX queue
+ * context
+ */
+ tx_ring = vsi->tx_rings[pf_q];
+ tx_ring->ch = ch;
+
+ /* Get the RX ring ptr */
+ rx_ring = vsi->rx_rings[pf_q];
+ rx_ring->ch = ch;
+ }
+
+ return 0;
+}
+
+/**
+ * i40e_setup_hw_channel - setup new channel
+ * @pf: ptr to PF device
+ * @vsi: the VSI being setup
+ * @ch: ptr to channel structure
+ * @uplink_seid: underlying HW switching element (VEB) ID
+ * @type: type of channel to be created (VMDq2/VF)
+ *
+ * Setup new channel (VSI) based on specified type (VMDq2/VF)
+ * and configures TX rings accordingly
+ **/
+static inline int i40e_setup_hw_channel(struct i40e_pf *pf,
+ struct i40e_vsi *vsi,
+ struct i40e_channel *ch,
+ u16 uplink_seid, u8 type)
+{
+ int ret;
+
+ ch->initialized = false;
+ ch->base_queue = vsi->next_base_queue;
+ ch->type = type;
+
+ /* Proceed with creation of channel (VMDq2) VSI */
+ ret = i40e_add_channel(pf, uplink_seid, ch);
+ if (ret) {
+ dev_info(&pf->pdev->dev,
+ "failed to add_channel using uplink_seid %u\n",
+ uplink_seid);
+ return ret;
+ }
+
+ /* Mark the successful creation of channel */
+ ch->initialized = true;
+
+ /* Reconfigure TX queues using QTX_CTL register */
+ ret = i40e_channel_config_tx_ring(pf, vsi, ch);
+ if (ret) {
+ dev_info(&pf->pdev->dev,
+ "failed to configure TX rings for channel %u\n",
+ ch->seid);
+ return ret;
+ }
+
+ /* update 'next_base_queue' */
+ vsi->next_base_queue = vsi->next_base_queue + ch->num_queue_pairs;
+ dev_dbg(&pf->pdev->dev,
+ "Added channel: vsi_seid %u, vsi_number %u, stat_counter_idx %u, num_queue_pairs %u, pf->next_base_queue %d\n",
+ ch->seid, ch->vsi_number, ch->stat_counter_idx,
+ ch->num_queue_pairs,
+ vsi->next_base_queue);
+ return ret;
+}
+
+/**
+ * i40e_setup_channel - setup new channel using uplink element
+ * @pf: ptr to PF device
+ * @type: type of channel to be created (VMDq2/VF)
+ * @uplink_seid: underlying HW switching element (VEB) ID
+ * @ch: ptr to channel structure
+ *
+ * Setup new channel (VSI) based on specified type (VMDq2/VF)
+ * and uplink switching element (uplink_seid)
+ **/
+static bool i40e_setup_channel(struct i40e_pf *pf, struct i40e_vsi *vsi,
+ struct i40e_channel *ch)
+{
+ u16 seid;
+ u8 vsi_type;
+ int ret;
+
+ if (vsi->type == I40E_VSI_MAIN) {
+ vsi_type = I40E_VSI_VMDQ2;
+ } else {
+ dev_err(&pf->pdev->dev, "unsupported parent vsi type(%d)\n",
+ vsi->type);
+ return false;
+ }
+
+ /* underlying switching element */
+ seid = pf->vsi[pf->lan_vsi]->uplink_seid;
+
+ /* create channel (VSI), configure TX rings */
+ ret = i40e_setup_hw_channel(pf, vsi, ch, seid, vsi_type);
+ if (ret) {
+ dev_err(&pf->pdev->dev, "failed to setup hw_channel\n");
+ return false;
+ }
+
+ return ch->initialized ? true : false;
+}
+
+/**
+ * i40e_create_queue_channel - function to create channel
+ * @vsi: VSI to be configured
+ * @ch: ptr to channel (it contains channel specific params)
+ *
+ * This function creates channel (VSI) using num_queues specified by user,
+ * reconfigs RSS if needed.
+ **/
+int i40e_create_queue_channel(struct i40e_vsi *vsi,
+ struct i40e_channel *ch)
+{
+ struct i40e_pf *pf = vsi->back;
+ bool reconfig_rss;
+ int err;
+
+ if (!ch)
+ return -EINVAL;
+
+ if (!ch->num_queue_pairs) {
+ dev_err(&pf->pdev->dev, "Invalid num_queues requested: %d\n",
+ ch->num_queue_pairs);
+ return -EINVAL;
+ }
+
+ /* validate user requested num_queues for channel */
+ err = i40e_validate_num_queues(pf, ch->num_queue_pairs, vsi,
+ &reconfig_rss);
+ if (err) {
+ dev_info(&pf->pdev->dev, "Failed to validate num_queues (%d)\n",
+ ch->num_queue_pairs);
+ return -EINVAL;
+ }
+
+ /* By default we are in VEPA mode, if this is the first VF/VMDq
+ * VSI to be added switch to VEB mode.
+ */
+ if ((!(pf->flags & I40E_FLAG_VEB_MODE_ENABLED)) ||
+ (!i40e_is_any_channel(vsi))) {
+ if (!is_power_of_2(vsi->tc_config.tc_info[0].qcount)) {
+ dev_dbg(&pf->pdev->dev,
+ "Failed to create channel. Override queues (%u) not power of 2\n",
+ vsi->tc_config.tc_info[0].qcount);
+ return -EINVAL;
+ }
+
+ if (!(pf->flags & I40E_FLAG_VEB_MODE_ENABLED)) {
+ pf->flags |= I40E_FLAG_VEB_MODE_ENABLED;
+
+ if (vsi->type == I40E_VSI_MAIN) {
+ if (pf->flags & I40E_FLAG_TC_MQPRIO)
+ i40e_do_reset(pf, I40E_PF_RESET_FLAG,
+ true);
+ else
+ i40e_do_reset_safe(pf,
+ I40E_PF_RESET_FLAG);
+ }
+ }
+ /* now onwards for main VSI, number of queues will be value
+ * of TC0's queue count
+ */
+ }
+
+ /* By this time, vsi->cnt_q_avail shall be set to non-zero and
+ * it should be more than num_queues
+ */
+ if (!vsi->cnt_q_avail || vsi->cnt_q_avail < ch->num_queue_pairs) {
+ dev_dbg(&pf->pdev->dev,
+ "Error: cnt_q_avail (%u) less than num_queues %d\n",
+ vsi->cnt_q_avail, ch->num_queue_pairs);
+ return -EINVAL;
+ }
+
+ /* reconfig_rss only if vsi type is MAIN_VSI */
+ if (reconfig_rss && (vsi->type == I40E_VSI_MAIN)) {
+ err = i40e_vsi_reconfig_rss(vsi, ch->num_queue_pairs);
+ if (err) {
+ dev_info(&pf->pdev->dev,
+ "Error: unable to reconfig rss for num_queues (%u)\n",
+ ch->num_queue_pairs);
+ return -EINVAL;
+ }
+ }
+
+ if (!i40e_setup_channel(pf, vsi, ch)) {
+ dev_info(&pf->pdev->dev, "Failed to setup channel\n");
+ return -EINVAL;
+ }
+
+ dev_info(&pf->pdev->dev,
+ "Setup channel (id:%u) utilizing num_queues %d\n",
+ ch->seid, ch->num_queue_pairs);
+
+ /* in case of VF, this will be main SRIOV VSI */
+ ch->parent_vsi = vsi;
+
+ /* and update main_vsi's count for queue_available to use */
+ vsi->cnt_q_avail -= ch->num_queue_pairs;
+
+ return 0;
+}
+
+/**
+ * i40e_configure_queue_channels - Add queue channel for the given TCs
+ * @vsi: VSI to be configured
+ *
+ * Configures queue channel mapping to the given TCs
+ **/
+static int i40e_configure_queue_channels(struct i40e_vsi *vsi)
+{
+ struct i40e_channel *ch;
+ int ret = 0, i;
+
+ /* Create app vsi with the TCs. Main VSI with TC0 is already set up */
+ for (i = 1; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+ if (vsi->tc_config.enabled_tc & BIT(i)) {
+ ch = kzalloc(sizeof(*ch), GFP_KERNEL);
+ if (!ch) {
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
+ INIT_LIST_HEAD(&ch->list);
+ ch->num_queue_pairs =
+ vsi->tc_config.tc_info[i].qcount;
+ ch->base_queue =
+ vsi->tc_config.tc_info[i].qoffset;
+
+ list_add_tail(&ch->list, &vsi->ch_list);
+
+ ret = i40e_create_queue_channel(vsi, ch);
+ if (ret) {
+ dev_err(&vsi->back->pdev->dev,
+ "Failed creating queue channel with TC%d: queues %d\n",
+ i, ch->num_queue_pairs);
+ goto err_free;
+ }
+ }
+ }
+ return ret;
+
+err_free:
+ i40e_remove_queue_channels(vsi);
+ return ret;
+}
+
+/**
* i40e_veb_config_tc - Configure TCs for given VEB
* @veb: given VEB
* @enabled_tc: TC bitmap
@@ -5618,10 +6273,18 @@ static int i40e_setup_tc(struct net_device *netdev, u8 tc)
goto exit;
}
- /* Unquiesce VSI */
- i40e_unquiesce_vsi(vsi);
+ if (pf->flags & I40E_FLAG_TC_MQPRIO) {
+ ret = i40e_configure_queue_channels(vsi);
+ if (ret) {
+ netdev_info(netdev,
+ "Failed configuring queue channels\n");
+ goto exit;
+ }
+ }
exit:
+ /* Unquiesce VSI */
+ i40e_unquiesce_vsi(vsi);
return ret;
}
@@ -7037,6 +7700,35 @@ static void i40e_fdir_teardown(struct i40e_pf *pf)
}
/**
+ * i40e_rebuild_channels - Rebuilds channel VSIs if they existed before reset
+ * @vsi: PF main vsi
+ *
+ * Rebuilds channel VSIs if they existed before reset
+ **/
+static int i40e_rebuild_channels(struct i40e_vsi *vsi)
+{
+ struct i40e_channel *ch, *ch_tmp;
+ i40e_status ret;
+
+ if (list_empty(&vsi->ch_list))
+ return 0;
+
+ list_for_each_entry_safe(ch, ch_tmp, &vsi->ch_list, list) {
+ if (!ch->initialized)
+ break;
+ /* Proceed with creation of channel (VMDq2) VSI */
+ ret = i40e_add_channel(vsi->back, vsi->uplink_seid, ch);
+ if (ret) {
+ dev_info(&vsi->back->pdev->dev,
+ "failed to rebuild channels using uplink_seid %u\n",
+ vsi->uplink_seid);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+/**
* i40e_prep_for_reset - prep for the core to reset
* @pf: board private structure
* @lock_acquired: indicates whether or not the lock has been acquired
@@ -7301,6 +7993,13 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
}
}
+ /* PF Main VSI is rebuild by now, go ahead and rebuild channel VSIs
+ * for this main VSI if they exist
+ */
+ ret = i40e_rebuild_channels(pf->vsi[pf->lan_vsi]);
+ if (ret)
+ goto end_unlock;
+
/* Reconfigure hardware for allowing smaller MSS in the case
* of TSO, so that we avoid the MDD being fired and causing
* a reset in the case of small MSS+TSO.
@@ -11614,6 +12313,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev_info(&pdev->dev, "setup_pf_switch failed: %d\n", err);
goto err_vsis;
}
+ INIT_LIST_HEAD(&pf->vsi[pf->lan_vsi]->ch_list);
/* Make sure flow control is set according to current settings */
err = i40e_set_fc(hw, &set_fc_aq_fail, true);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
index a4e3e66..81624dd 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
@@ -424,6 +424,8 @@ struct i40e_ring {
* i40e_clean_rx_ring_irq() is called
* for this ring.
*/
+
+ struct i40e_channel *ch;
} ____cacheline_internodealigned_in_smp;
static inline bool ring_uses_build_skb(struct i40e_ring *ring)
^ permalink raw reply related
* [RFC PATCH v3 1/6] mqprio: Introduce new hardware offload mode and shaper in mqprio
From: Amritha Nambiar @ 2017-09-07 11:00 UTC (permalink / raw)
To: intel-wired-lan, jeffrey.t.kirsher
Cc: alexander.h.duyck, netdev, amritha.nambiar
In-Reply-To: <150478158684.24662.17975701233699487888.stgit@anamdev.jf.intel.com>
The offload types currently supported in mqprio are 0 (no offload) and
1 (offload only TCs) by setting these values for the 'hw' option. If
offloads are supported by setting the 'hw' option to 1, the default
offload mode is 'dcb' where only the TC values are offloaded to the
device. This patch introduces a new hardware offload mode called
'channel' with 'hw' set to 1 in mqprio which makes full use of the
mqprio options, the TCs, the queue configurations and the QoS parameters
for the TCs. This is achieved through a new netlink attribute for the
'mode' option which takes values such as 'dcb' (default) and 'channel'.
The 'channel' mode also supports QoS attributes for traffic class such as
minimum and maximum values for bandwidth rate limits.
This patch enables configuring additional HW shaper attributes associated
with a traffic class. Currently the shaper for bandwidth rate limiting is
supported which takes options such as minimum and maximum bandwidth rates
and are offloaded to the hardware in the 'channel' mode. The min and max
limits for bandwidth rates are provided by the user along with the the TCs
and the queue configurations when creating the mqprio qdisc. The interface
can be extended to support new HW shapers in future through the 'shaper'
attribute.
Introduces a new datastructure 'tc_mqprio_qopt_offload' for offloading
mqprio queue options and use this to be shared between the kernel and
device driver. This contains a copy of the exisiting datastructure
for mqprio queue options. This new datastructure can be extended when
adding new attributes for traffic class such as mode, shaper, shaper
parameters (bandwidth rate limits). The existing datastructure for mqprio
queue options will be shared between the kernel and userspace.
Example:
# tc qdisc add dev eth0 root mqprio num_tc 2 map 0 0 0 0 1 1 1 1\
queues 4@0 4@4 hw 1 mode channel shaper bw_rlimit\
min_rate 1Gbit 2Gbit max_rate 4Gbit 5Gbit
To dump the bandwidth rates:
# tc qdisc show dev eth0
qdisc mqprio 804a: root tc 2 map 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0
queues:(0:3) (4:7)
mode:channel
shaper:bw_rlimit min_rate:1Gbit 2Gbit max_rate:4Gbit 5Gbit
v3 : Removed supporting new offloads through value 2 for 'hw' option,
introduced new netlink based options for offload mode and HW shaper.
v2 : Jiri's changes accepted upstream removes the struct
tc_to_netdev. Clean up the full offload related changes added to
mqprio_init() and mqprio_destroy() to rebase on these changes.
Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
---
include/net/pkt_cls.h | 9 ++
include/uapi/linux/pkt_sched.h | 32 +++++++
net/sched/sch_mqprio.c | 183 ++++++++++++++++++++++++++++++++++++++--
3 files changed, 215 insertions(+), 9 deletions(-)
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index e80edd8..456017a 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -546,6 +546,15 @@ struct tc_cls_bpf_offload {
u32 gen_flags;
};
+struct tc_mqprio_qopt_offload {
+ /* struct tc_mqprio_qopt must always be the first element */
+ struct tc_mqprio_qopt qopt;
+ u16 mode;
+ u16 shaper;
+ u32 flags;
+ u64 min_rate[TC_QOPT_MAX_QUEUE];
+ u64 max_rate[TC_QOPT_MAX_QUEUE];
+};
/* This structure holds cookie structure that is passed from user
* to the kernel for actions and classifiers
diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h
index 099bf55..e95b5c9 100644
--- a/include/uapi/linux/pkt_sched.h
+++ b/include/uapi/linux/pkt_sched.h
@@ -625,6 +625,22 @@ enum {
#define TC_MQPRIO_HW_OFFLOAD_MAX (__TC_MQPRIO_HW_OFFLOAD_MAX - 1)
+enum {
+ TC_MQPRIO_MODE_DCB,
+ TC_MQPRIO_MODE_CHANNEL,
+ __TC_MQPRIO_MODE_MAX
+};
+
+#define __TC_MQPRIO_MODE_MAX (__TC_MQPRIO_MODE_MAX - 1)
+
+enum {
+ TC_MQPRIO_SHAPER_DCB,
+ TC_MQPRIO_SHAPER_BW_RATE, /* Add new shapers below */
+ __TC_MQPRIO_SHAPER_MAX
+};
+
+#define __TC_MQPRIO_SHAPER_MAX (__TC_MQPRIO_SHAPER_MAX - 1)
+
struct tc_mqprio_qopt {
__u8 num_tc;
__u8 prio_tc_map[TC_QOPT_BITMASK + 1];
@@ -633,6 +649,22 @@ struct tc_mqprio_qopt {
__u16 offset[TC_QOPT_MAX_QUEUE];
};
+#define TC_MQPRIO_F_MODE 0x1
+#define TC_MQPRIO_F_SHAPER 0x2
+#define TC_MQPRIO_F_MIN_RATE 0x4
+#define TC_MQPRIO_F_MAX_RATE 0x8
+
+enum {
+ TCA_MQPRIO_UNSPEC,
+ TCA_MQPRIO_MODE,
+ TCA_MQPRIO_SHAPER,
+ TCA_MQPRIO_MIN_RATE64,
+ TCA_MQPRIO_MAX_RATE64,
+ __TCA_MQPRIO_MAX,
+};
+
+#define TCA_MQPRIO_MAX (__TCA_MQPRIO_MAX - 1)
+
/* SFB */
enum {
diff --git a/net/sched/sch_mqprio.c b/net/sched/sch_mqprio.c
index 6bcdfe6..e5e7724 100644
--- a/net/sched/sch_mqprio.c
+++ b/net/sched/sch_mqprio.c
@@ -18,10 +18,16 @@
#include <net/netlink.h>
#include <net/pkt_sched.h>
#include <net/sch_generic.h>
+#include <net/pkt_cls.h>
struct mqprio_sched {
struct Qdisc **qdiscs;
+ u16 mode;
+ u16 shaper;
int hw_offload;
+ u32 flags;
+ u64 min_rate[TC_QOPT_MAX_QUEUE];
+ u64 max_rate[TC_QOPT_MAX_QUEUE];
};
static void mqprio_destroy(struct Qdisc *sch)
@@ -39,9 +45,17 @@ static void mqprio_destroy(struct Qdisc *sch)
}
if (priv->hw_offload && dev->netdev_ops->ndo_setup_tc) {
- struct tc_mqprio_qopt mqprio = {};
+ struct tc_mqprio_qopt_offload mqprio = { { 0 } };
- dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_MQPRIO, &mqprio);
+ switch (priv->mode) {
+ case TC_MQPRIO_MODE_DCB:
+ case TC_MQPRIO_MODE_CHANNEL:
+ dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_MQPRIO,
+ &mqprio);
+ break;
+ default:
+ return;
+ }
} else {
netdev_set_num_tc(dev, 0);
}
@@ -97,6 +111,26 @@ static int mqprio_parse_opt(struct net_device *dev, struct tc_mqprio_qopt *qopt)
return 0;
}
+static const struct nla_policy mqprio_policy[TCA_MQPRIO_MAX + 1] = {
+ [TCA_MQPRIO_MODE] = { .len = sizeof(u16) },
+ [TCA_MQPRIO_SHAPER] = { .len = sizeof(u16) },
+ [TCA_MQPRIO_MIN_RATE64] = { .type = NLA_NESTED },
+ [TCA_MQPRIO_MAX_RATE64] = { .type = NLA_NESTED },
+};
+
+static int parse_attr(struct nlattr *tb[], int maxtype, struct nlattr *nla,
+ const struct nla_policy *policy, int len)
+{
+ int nested_len = nla_len(nla) - NLA_ALIGN(len);
+
+ if (nested_len >= nla_attr_size(0))
+ return nla_parse(tb, maxtype, nla_data(nla) + NLA_ALIGN(len),
+ nested_len, policy, NULL);
+
+ memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
+ return 0;
+}
+
static int mqprio_init(struct Qdisc *sch, struct nlattr *opt)
{
struct net_device *dev = qdisc_dev(sch);
@@ -105,6 +139,10 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt)
struct Qdisc *qdisc;
int i, err = -EOPNOTSUPP;
struct tc_mqprio_qopt *qopt = NULL;
+ struct nlattr *tb[TCA_MQPRIO_MAX + 1];
+ struct nlattr *attr;
+ int rem;
+ int len = nla_len(opt) - NLA_ALIGN(sizeof(*qopt));
BUILD_BUG_ON(TC_MAX_QUEUE != TC_QOPT_MAX_QUEUE);
BUILD_BUG_ON(TC_BITMASK != TC_QOPT_BITMASK);
@@ -122,6 +160,58 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt)
if (mqprio_parse_opt(dev, qopt))
return -EINVAL;
+ if (len > 0) {
+ err = parse_attr(tb, TCA_MQPRIO_MAX, opt, mqprio_policy,
+ sizeof(*qopt));
+ if (err < 0)
+ return err;
+
+ if (!qopt->hw)
+ return -EINVAL;
+
+ if (tb[TCA_MQPRIO_MODE]) {
+ priv->flags |= TC_MQPRIO_F_MODE;
+ priv->mode = *(u16 *)nla_data(tb[TCA_MQPRIO_MODE]);
+ }
+
+ if (tb[TCA_MQPRIO_SHAPER]) {
+ priv->flags |= TC_MQPRIO_F_SHAPER;
+ priv->shaper = *(u16 *)nla_data(tb[TCA_MQPRIO_SHAPER]);
+ }
+
+ if (tb[TCA_MQPRIO_MIN_RATE64]) {
+ if (priv->shaper != TC_MQPRIO_SHAPER_BW_RATE)
+ return -EINVAL;
+ i = 0;
+ nla_for_each_nested(attr, tb[TCA_MQPRIO_MIN_RATE64],
+ rem) {
+ if (nla_type(attr) != TCA_MQPRIO_MIN_RATE64)
+ return -EINVAL;
+ if (i >= qopt->num_tc)
+ break;
+ priv->min_rate[i] = *(u64 *)nla_data(attr);
+ i++;
+ }
+ priv->flags |= TC_MQPRIO_F_MIN_RATE;
+ }
+
+ if (tb[TCA_MQPRIO_MAX_RATE64]) {
+ if (priv->shaper != TC_MQPRIO_SHAPER_BW_RATE)
+ return -EINVAL;
+ i = 0;
+ nla_for_each_nested(attr, tb[TCA_MQPRIO_MAX_RATE64],
+ rem) {
+ if (nla_type(attr) != TCA_MQPRIO_MAX_RATE64)
+ return -EINVAL;
+ if (i >= qopt->num_tc)
+ break;
+ priv->max_rate[i] = *(u64 *)nla_data(attr);
+ i++;
+ }
+ priv->flags |= TC_MQPRIO_F_MAX_RATE;
+ }
+ }
+
/* pre-allocate qdisc, attachment can't fail */
priv->qdiscs = kcalloc(dev->num_tx_queues, sizeof(priv->qdiscs[0]),
GFP_KERNEL);
@@ -146,14 +236,36 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt)
* supplied and verified mapping
*/
if (qopt->hw) {
- struct tc_mqprio_qopt mqprio = *qopt;
+ struct tc_mqprio_qopt_offload mqprio = {.qopt = *qopt};
- err = dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_MQPRIO,
+ switch (priv->mode) {
+ case TC_MQPRIO_MODE_DCB:
+ if (priv->shaper != TC_MQPRIO_SHAPER_DCB)
+ return -EINVAL;
+ break;
+ case TC_MQPRIO_MODE_CHANNEL:
+ mqprio.flags = priv->flags;
+ if (priv->flags & TC_MQPRIO_F_MODE)
+ mqprio.mode = priv->mode;
+ if (priv->flags & TC_MQPRIO_F_SHAPER)
+ mqprio.shaper = priv->shaper;
+ if (priv->flags & TC_MQPRIO_F_MIN_RATE)
+ for (i = 0; i < mqprio.qopt.num_tc; i++)
+ mqprio.min_rate[i] = priv->min_rate[i];
+ if (priv->flags & TC_MQPRIO_F_MAX_RATE)
+ for (i = 0; i < mqprio.qopt.num_tc; i++)
+ mqprio.max_rate[i] = priv->max_rate[i];
+ break;
+ default:
+ return -EINVAL;
+ }
+ err = dev->netdev_ops->ndo_setup_tc(dev,
+ TC_SETUP_MQPRIO,
&mqprio);
if (err)
return err;
- priv->hw_offload = mqprio.hw;
+ priv->hw_offload = mqprio.qopt.hw;
} else {
netdev_set_num_tc(dev, qopt->num_tc);
for (i = 0; i < qopt->num_tc; i++)
@@ -223,11 +335,51 @@ static int mqprio_graft(struct Qdisc *sch, unsigned long cl, struct Qdisc *new,
return 0;
}
+static int dump_rates(struct mqprio_sched *priv,
+ struct tc_mqprio_qopt *opt, struct sk_buff *skb)
+{
+ struct nlattr *nest;
+ int i;
+
+ if (priv->flags & TC_MQPRIO_F_MIN_RATE) {
+ nest = nla_nest_start(skb, TCA_MQPRIO_MIN_RATE64);
+ if (!nest)
+ goto nla_put_failure;
+
+ for (i = 0; i < opt->num_tc; i++) {
+ if (nla_put(skb, TCA_MQPRIO_MIN_RATE64,
+ sizeof(priv->min_rate[i]),
+ &priv->min_rate[i]))
+ goto nla_put_failure;
+ }
+ nla_nest_end(skb, nest);
+ }
+
+ if (priv->flags & TC_MQPRIO_F_MAX_RATE) {
+ nest = nla_nest_start(skb, TCA_MQPRIO_MAX_RATE64);
+ if (!nest)
+ goto nla_put_failure;
+
+ for (i = 0; i < opt->num_tc; i++) {
+ if (nla_put(skb, TCA_MQPRIO_MAX_RATE64,
+ sizeof(priv->max_rate[i]),
+ &priv->max_rate[i]))
+ goto nla_put_failure;
+ }
+ nla_nest_end(skb, nest);
+ }
+ return 0;
+
+nla_put_failure:
+ nla_nest_cancel(skb, nest);
+ return -1;
+}
+
static int mqprio_dump(struct Qdisc *sch, struct sk_buff *skb)
{
struct net_device *dev = qdisc_dev(sch);
struct mqprio_sched *priv = qdisc_priv(sch);
- unsigned char *b = skb_tail_pointer(skb);
+ struct nlattr *nla = (struct nlattr *)skb_tail_pointer(skb);
struct tc_mqprio_qopt opt = { 0 };
struct Qdisc *qdisc;
unsigned int i;
@@ -258,12 +410,25 @@ static int mqprio_dump(struct Qdisc *sch, struct sk_buff *skb)
opt.offset[i] = dev->tc_to_txq[i].offset;
}
- if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt))
+ if (nla_put(skb, TCA_OPTIONS, NLA_ALIGN(sizeof(opt)), &opt))
+ goto nla_put_failure;
+
+ if ((priv->flags & TC_MQPRIO_F_MODE) &&
+ nla_put_u16(skb, TCA_MQPRIO_MODE, priv->mode))
+ goto nla_put_failure;
+
+ if ((priv->flags & TC_MQPRIO_F_SHAPER) &&
+ nla_put_u16(skb, TCA_MQPRIO_SHAPER, priv->shaper))
+ goto nla_put_failure;
+
+ if ((priv->flags & TC_MQPRIO_F_MIN_RATE ||
+ priv->flags & TC_MQPRIO_F_MAX_RATE) &&
+ (dump_rates(priv, &opt, skb) != 0))
goto nla_put_failure;
- return skb->len;
+ return nla_nest_end(skb, nla);
nla_put_failure:
- nlmsg_trim(skb, b);
+ nlmsg_trim(skb, nla);
return -1;
}
^ permalink raw reply related
* [RFC PATCH v3 0/6] Configuring traffic classes via new hardware offload mechanism in tc/mqprio
From: Amritha Nambiar @ 2017-09-07 11:00 UTC (permalink / raw)
To: intel-wired-lan, jeffrey.t.kirsher
Cc: alexander.h.duyck, netdev, amritha.nambiar
The following series introduces a new hardware offload mode in
tc/mqprio where the TCs, the queue configurations and
bandwidth rate limits are offloaded to the hardware. The existing
mqprio framework is extended to configure the queue counts and
layout and also added support for rate limiting. This is achieved
through new netlink attributes for the 'mode' option which takes
values such as 'dcb' (default) and 'channel' and a 'shaper' option
for QoS attributes such as bandwidth rate limits in hw mode 1.
Legacy devices can fall back to the existing setup supporting hw mode
1 without these additional options where only the TCs are offloaded
and then the 'mode' and 'shaper' options defaults to DCB support.
The i40e driver enables the new mqprio hardware offload mechanism
factoring the TCs, queue configuration and bandwidth rates by
creating HW channel VSIs.
In this new mode, the priority to traffic class mapping and the
user specified queue ranges are used to configure the traffic
class when the 'mode' option is set to 'channel'. This is achieved by
creating HW channels(VSI). A new channel is created for each of the
traffic class configuration offloaded via mqprio framework except for
the first TC (TC0) which is for the main VSI. TC0 for the main VSI is
also reconfigured as per user provided queue parameters. Finally,
bandwidth rate limits are set on these traffic classes through the
shaper attribute by sending these rates in addition to the number of
TCs and the queue configurations.
Example:
# tc qdisc add dev eth0 root mqprio num_tc 2 map 0 0 0 0 1 1 1 1\
queues 4@0 4@4 hw 1 mode channel shaper bw_rlimit\
min_rate 1Gbit 2Gbit max_rate 4Gbit 5Gbit
To dump the bandwidth rates:
# tc qdisc show dev eth0
qdisc mqprio 804a: root tc 2 map 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0
queues:(0:3) (4:7)
mode:channel
shaper:bw_rlimit min_rate:1Gbit 2Gbit max_rate:4Gbit 5Gbit
---
Amritha Nambiar (6):
mqprio: Introduce new hardware offload mode and shaper in mqprio
i40e: Add macro for PF reset bit
i40e: Add infrastructure for queue channel support
i40e: Enable 'channel' mode in mqprio for TC configs
i40e: Refactor VF BW rate limiting
i40e: Add support setting TC max bandwidth rates
drivers/net/ethernet/intel/i40e/i40e.h | 44 +
drivers/net/ethernet/intel/i40e/i40e_debugfs.c | 3
drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 8
drivers/net/ethernet/intel/i40e/i40e_main.c | 1463 +++++++++++++++++---
drivers/net/ethernet/intel/i40e/i40e_txrx.h | 2
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 50 -
include/net/pkt_cls.h | 9
include/uapi/linux/pkt_sched.h | 32
net/sched/sch_mqprio.c | 183 ++-
9 files changed, 1551 insertions(+), 243 deletions(-)
^ permalink raw reply
* Re: [PATCH] netfilter: xt_hashlimit: avoid 64-bit division
From: Pablo Neira Ayuso @ 2017-09-07 10:19 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Vishwanath Pai, Jozsef Kadlecsik, Florian Westphal,
David S. Miller, Josh Hunt, netfilter-devel, coreteam, Networking,
Linux Kernel Mailing List
In-Reply-To: <CAK8P3a1GxBjWqnK+fdKmzOhXyFK1XbCFWau8md3OjnLjUZOeDg@mail.gmail.com>
On Wed, Sep 06, 2017 at 10:48:22PM +0200, Arnd Bergmann wrote:
> On Wed, Sep 6, 2017 at 10:22 PM, Vishwanath Pai <vpai@akamai.com> wrote:
> > On 09/06/2017 03:57 PM, Arnd Bergmann wrote:
> >> 64-bit division is expensive on 32-bit architectures, and
> >> requires a special function call to avoid a link error like:
> >>
> >> net/netfilter/xt_hashlimit.o: In function `hashlimit_mt_common':
> >> xt_hashlimit.c:(.text+0x1328): undefined reference to `__aeabi_uldivmod'
> >>
> >> In the case of hashlimit_mt_common, we don't actually need a
> >> 64-bit operation, we can simply rewrite the function slightly
> >> to make that clear to the compiler.
> >>
> >> Fixes: bea74641e378 ("netfilter: xt_hashlimit: add rate match mode")
> >> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> >> ---
> >> net/netfilter/xt_hashlimit.c | 5 ++++-
> >> 1 file changed, 4 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
> >> index 10d48234f5f4..50b53d86eef5 100644
> >> --- a/net/netfilter/xt_hashlimit.c
> >> +++ b/net/netfilter/xt_hashlimit.c
> >> @@ -531,7 +531,10 @@ static u64 user2rate_bytes(u64 user)
> >> {
> >> u64 r;
> >>
> >> - r = user ? 0xFFFFFFFFULL / user : 0xFFFFFFFFULL;
> >> + if (user > 0xFFFFFFFFULL)
> >> + return 0;
> >> +
> >> + r = user ? 0xFFFFFFFFULL / (u32)user : 0xFFFFFFFFULL;
> >> r = (r - 1) << 4;
> >> return r;
> >> }
> >>
> >
> > I have submitted another patch to fix this:
> > https://patchwork.ozlabs.org/patch/809881/
> >
> > We have seen this problem before, I was careful not to introduce this
> > again in the new patch but clearly I overlooked this particular line :(
> >
> > In the other cases we fixed it by replacing division with div64_u64().
>
> div64_u64() seems needlessly expensive here since the dividend
> is known to be a 32-bit number. I guess the function is not called
> frequently though, so it doesn't matter much.
This is called from the packet path, only for the first packet for
each new destination IP entry in the hashtable, still from the
datapath. So if we can take something faster (for 32 bit arches) that
is correct, I think it's sensible to take.
Let me know in any case.
^ permalink raw reply
* Can you help to analyze this panic issue when using VPN?
From: Songchuan @ 2017-09-07 10:18 UTC (permalink / raw)
To: netdev@vger.kernel.org
Cc: weiwan@google.com, davem@davemloft.net, Wanghao (R), sunjilong,
Liwei (Sirius), sangguanlin, Xuhui (hunter, Device company ),
Eric Dumazet
In-Reply-To: <CANn89iLWa7bL+WdWzdQXLhFGpORf3ZmyRoi3Pp2XLKS3O4skNw@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 7184 bytes --]
HI, ALL
Did you ever encount the issue, panic will occur when using VPN by probably, the stack is a following:
<0>[18581.550354s][pid:678,cpu5,hisi_rxdata]Call trace:
<4>[18581.550354s][pid:678,cpu5,hisi_rxdata][<ffffffc000e50004>] ipv6_rcv+0x100/0x50c
<4>[18581.550384s][pid:678,cpu5,hisi_rxdata][<ffffffc000d5ced8>] __netif_receive_skb_core+0x2ac/0xa04
<4>[18581.550384s][pid:678,cpu5,hisi_rxdata][<ffffffc000d5eeb8>] __netif_receive_skb+0x2c/0x84
<4>[18581.550384s][pid:678,cpu5,hisi_rxdata][<ffffffc000d5fb20>] process_backlog+0xa4/0x164
<4>[18581.550415s][pid:678,cpu5,hisi_rxdata][<ffffffc000d60cf0>] net_rx_action+0x1e8/0x358
<4>[18581.550415s][pid:678,cpu5,hisi_rxdata][<ffffffc0000a4d28>] __do_softirq+0xcc/0x3a4
<4>[18581.550415s][pid:678,cpu5,hisi_rxdata][<ffffffc0000a50ac>] do_softirq+0x5c/0x60
<4>[18581.550415s][pid:678,cpu5,hisi_rxdata][<ffffffc000d5cb0c>] netif_rx_ni+0x124/0x12c
<4>[18581.550445s][pid:678,cpu5,hisi_rxdata][<ffffffc000bd0564>] hmac_rxdata_thread+0x88/0x8c
<4>[18581.550445s][pid:678,cpu5,hisi_rxdata][<ffffffc0000bf3d8>] kthread+0xdc/0xf0
<0>[18581.550445s][pid:678,cpu5,hisi_rxdata]Code: f9402e60 f27ff800 54001380 f940a000 (f9400000)
<4>[18581.550476s][pid:678,cpu5,hisi_rxdata]---[ end trace 244e1ff5a3cd0017 ]---
<0>[18581.550476s][pid:678,cpu5,hisi_rxdata]Kernel panic - not syncing: Fatal exception in interrupt
We also use the kasan version to reproduce this issue, the message like this:
4>[ 1730.083587s][pid:1928,cpu3,HeapTaskDaemon]Disabling lock debugging due to kernel taint
<3>[ 1730.083618s][pid:1928,cpu3,HeapTaskDaemon]INFO: Allocated in dst_alloc+0x80/0x2a0 age=1315 cpu=3 pid=343
<3>[ 1730.083679s][pid:1928,cpu3,HeapTaskDaemon] alloc_debug_processing+0x198/0x1a0
<3>[ 1730.083709s][pid:1928,cpu3,HeapTaskDaemon] __slab_alloc.isra.63.constprop.65+0x6ec/0x738
<3>[ 1730.083740s][pid:1928,cpu3,HeapTaskDaemon] kmem_cache_alloc+0x154/0x250
<3>[ 1730.083770s][pid:1928,cpu3,HeapTaskDaemon] dst_alloc+0x80/0x2a0
<3>[ 1730.083801s][pid:1928,cpu3,HeapTaskDaemon] rt_dst_alloc+0x70/0x80
<3>[ 1730.083831s][pid:1928,cpu3,HeapTaskDaemon] ip_route_input_noref+0x2dc/0xdd4
<3>[ 1730.083862s][pid:1928,cpu3,HeapTaskDaemon] ip_rcv_finish+0x348/0x52c
<3>[ 1730.083892s][pid:1928,cpu3,HeapTaskDaemon] ip_rcv+0x548/0x708
<3>[ 1730.083923s][pid:1928,cpu3,HeapTaskDaemon] __netif_receive_skb_core+0x52c/0xf28
<3>[ 1730.083953s][pid:1928,cpu3,HeapTaskDaemon] __netif_receive_skb+0x40/0xcc
<3>[ 1730.083984s][pid:1928,cpu3,HeapTaskDaemon] process_backlog+0x114/0x244
<3>[ 1730.084014s][pid:1928,cpu3,HeapTaskDaemon] net_rx_action+0x3e4/0x64c
<3>[ 1730.084075s][pid:1928,cpu3,HeapTaskDaemon] __do_softirq+0x110/0x574
<3>[ 1730.084106s][pid:1928,cpu3,HeapTaskDaemon] irq_exit+0xc0/0xf4
<3>[ 1730.084136s][pid:1928,cpu3,HeapTaskDaemon] handle_IPI+0x3d4/0x3f0
<3>[ 1730.084167s][pid:1928,cpu3,HeapTaskDaemon] gic_handle_irq+0x88/0x8c
<3>[ 1730.084197s][pid:1928,cpu3,HeapTaskDaemon]INFO: Freed in dst_destroy+0x134/0x1c4 age=2758 cpu=4 pid=30
<3>[ 1730.084228s][pid:1928,cpu3,HeapTaskDaemon] free_debug_processing+0x2ec/0x360
<3>[ 1730.084259s][pid:1928,cpu3,HeapTaskDaemon] __slab_free+0x308/0x448
<3>[ 1730.084289s][pid:1928,cpu3,HeapTaskDaemon] kmem_cache_free+0x274/0x28c
<3>[ 1730.084320s][pid:1928,cpu3,HeapTaskDaemon] dst_destroy+0x134/0x1c4
<3>[ 1730.084350s][pid:1928,cpu3,HeapTaskDaemon] free_fib_info_rcu+0x248/0x310
<3>[ 1730.084381s][pid:1928,cpu3,HeapTaskDaemon] rcu_process_callbacks+0x6f0/0x9cc
<3>[ 1730.084411s][pid:1928,cpu3,HeapTaskDaemon] __do_softirq+0x110/0x574
<3>[ 1730.084442s][pid:1928,cpu3,HeapTaskDaemon] run_ksoftirqd+0x4c/0x60
<3>[ 1730.084472s][pid:1928,cpu3,HeapTaskDaemon] smpboot_thread_fn+0x298/0x404
<3>[ 1730.084533s][pid:1928,cpu3,HeapTaskDaemon] kthread+0x190/0x1ac
<3>[ 1730.084564s][pid:1928,cpu3,HeapTaskDaemon] ret_from_fork+0x10/0x50
<3>[ 1730.084594s][pid:1928,cpu3,HeapTaskDaemon]INFO: Slab 0xffffffbdc033bc00 objects=16 used=14 fp=0xffffffc00caf1c00 flags=0x8100
<3>[ 1730.084594s][pid:1928,cpu3,HeapTaskDaemon]INFO: Object 0xffffffc00caf1a00 @offset=6656 fp=0x (null)
<3>[ 1730.085083s][pid:1928,cpu3,HeapTaskDaemon]Padding ffffffc00caf1bf8: 00 00 00 00 00 00 00 00 ........
<4>[ 1730.085113s][pid:1928,cpu3,HeapTaskDaemon]CPU: 3 PID: 1928 Comm: HeapTaskDaemon Tainted: G B W 4.1.18-kasan-g6e99722-dirty #1
<4>[ 1730.085144s][pid:1928,cpu3,HeapTaskDaemon]TGID: 1911 Comm: ndroid.settings
<4>[ 1730.085174s][pid:1928,cpu3,HeapTaskDaemon]Hardware name: hi6250 (DT)
<0>[ 1730.085205s][pid:1928,cpu3,HeapTaskDaemon]Call trace:
<4>[ 1730.085235s][pid:1928,cpu3,HeapTaskDaemon][<ffffffc00008d548>] dump_backtrace+0x0/0x1f4
<4>[ 1730.085266s][pid:1928,cpu3,HeapTaskDaemon][<ffffffc00008d75c>] show_stack+0x20/0x28
<4>[ 1730.085296s][pid:1928,cpu3,HeapTaskDaemon][<ffffffc0016bbd20>] dump_stack+0x84/0xa8
<4>[ 1730.085327s][pid:1928,cpu3,HeapTaskDaemon][<ffffffc00025fbe8>] print_trailer+0x11c/0x1b0
<4>[ 1730.085357s][pid:1928,cpu3,HeapTaskDaemon][<ffffffc00026443c>] object_err+0x4c/0x5c
<4>[ 1730.085388s][pid:1928,cpu3,HeapTaskDaemon][<ffffffc0002667dc>] kasan_report+0x240/0x574
<4>[ 1730.085418s][pid:1928,cpu3,HeapTaskDaemon][<ffffffc000265708>] __asan_loadN+0x18c/0x1f0
<4>[ 1730.085449s][pid:1928,cpu3,HeapTaskDaemon][<ffffffc0015ae338>] ipv6_rcv+0x244/0xb50
<4>[ 1730.085479s][pid:1928,cpu3,HeapTaskDaemon][<ffffffc00141e9f4>] __netif_receive_skb_core+0x52c/0xf28
<4>[ 1730.085510s][pid:1928,cpu3,HeapTaskDaemon][<ffffffc001421e04>] __netif_receive_skb+0x40/0xcc
<4>[ 1730.085540s][pid:1928,cpu3,HeapTaskDaemon][<ffffffc001423530>] process_backlog+0x114/0x244
<4>[ 1730.085571s][pid:1928,cpu3,HeapTaskDaemon][<ffffffc001425738>] net_rx_action+0x3e4/0x64c
<4>[ 1730.085601s][pid:1928,cpu3,HeapTaskDaemon][<ffffffc0000b3a48>] __do_softirq+0x110/0x574
<4>[ 1730.085632s][pid:1928,cpu3,HeapTaskDaemon][<ffffffc0000b41f8>] irq_exit+0xc0/0xf4
<4>[ 1730.085662s][pid:1928,cpu3,HeapTaskDaemon][<ffffffc0000936c4>] handle_IPI+0x3d4/0x3f0
<4>[ 1730.085693s][pid:1928,cpu3,HeapTaskDaemon][<ffffffc000081830>] gic_handle_irq+0x88/0x8c
The dump on vpn using and kasan is attached, Can you help to analyze this panic issue, thanks.
-----邮件原件-----
发件人: Eric Dumazet [mailto:edumazet@google.com]
发送时间: 2017年9月7日 17:06
收件人: Songchuan
抄送: weiwan@google.com; davem@davemloft.net; Wanghao (R); sunjilong; Liwei (Sirius); sangguanlin; Xuhui (hunter, Device company )
主题: Re: Can you help to analyze this panic issue when using VPN?
On Wed, Sep 6, 2017 at 11:43 PM, Songchuan <songchuan@huawei.com> wrote:
> Did you ever encount the issue?
>
You will have to send a mail in plain text, no HTML, otherwise it wont reach netdev@ mailing list.
We wont reply to you until you get this right, because we do not want part of the thread being not visible to most of the people/experts.
Thanks.
[-- Attachment #2: stack_using_vpn_ramoops-0 --]
[-- Type: application/octet-stream, Size: 219136 bytes --]
[-- Attachment #3: dump_kasan_scan_ramoops.bin --]
[-- Type: application/octet-stream, Size: 218453 bytes --]
^ permalink raw reply
* [PATCH net v4 1/3] dt-bindings: add SFF vendor prefix
From: Baruch Siach @ 2017-09-07 9:25 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Andrew Lunn, Florian Fainelli,
David S. Miller, Russell King
Cc: netdev, devicetree, Sergei Shtylyov, Antoine Tenart, Baruch Siach
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Baruch Siach <baruch@tkos.co.il>
---
v4: No change
v3: Add Rob's ack
v2: New patch in this series
---
Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 4e72012928b4..12b5808b82f2 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -289,6 +289,7 @@ schindler Schindler
seagate Seagate Technology PLC
semtech Semtech Corporation
sensirion Sensirion AG
+sff Small Form Factor Committee
sgx SGX Sensortech
sharp Sharp Corporation
si-en Si-En Technology Ltd.
--
2.14.1
^ permalink raw reply related
* [PATCH net v4 3/3] net: phy: sfp: rename dt properties to match the binding
From: Baruch Siach @ 2017-09-07 9:25 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Andrew Lunn, Florian Fainelli,
David S. Miller, Russell King
Cc: netdev-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA,
Sergei Shtylyov, Antoine Tenart, Baruch Siach
In-Reply-To: <b98ac3e8cde5c99489e8dcee9a1d5b8a19face8d.1504776350.git.baruch-NswTu9S1W3P6gbPvEgmw2w@public.gmane.org>
Make the Rx rate select control gpio property name match the documented
binding. This would make the addition of 'rate-select1-gpios' for SFP+
support more natural.
Also, make the MOD-DEF0 gpio property name match the documentation.
Signed-off-by: Baruch Siach <baruch-NswTu9S1W3P6gbPvEgmw2w@public.gmane.org>
---
v4: Rename also MOD-DEF0
v3: No change
v2: New patch in this series
---
drivers/net/phy/sfp.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
index fb2cf4342f48..baee371bf767 100644
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -58,11 +58,11 @@ enum {
};
static const char *gpio_of_names[] = {
- "moddef0",
+ "mod-def0",
"los",
"tx-fault",
"tx-disable",
- "rate-select",
+ "rate-select0",
};
static const enum gpiod_flags gpio_flags[] = {
--
2.14.1
--
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 net v4 2/3] dt-binding: net: sfp binding documentation
From: Baruch Siach @ 2017-09-07 9:25 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Andrew Lunn, Florian Fainelli,
David S. Miller, Russell King
Cc: netdev-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA,
Sergei Shtylyov, Antoine Tenart, Baruch Siach
In-Reply-To: <b98ac3e8cde5c99489e8dcee9a1d5b8a19face8d.1504776350.git.baruch-NswTu9S1W3P6gbPvEgmw2w@public.gmane.org>
Add device-tree binding documentation SFP transceivers. Support for SFP
transceivers has been recently introduced (drivers/net/phy/sfp.c).
Signed-off-by: Baruch Siach <baruch-NswTu9S1W3P6gbPvEgmw2w@public.gmane.org>
---
v4:
Remove redundant 'single' from the gpio specifier
Rename 'moddef0-gpios' property to 'mod-def0-gpios'
Remove 'phy-mode' property from the example; SFP determines the mode
v3:
Mention gpios phandle and specifier
Mention the polarity of each gpio
Fix example property names
v2:
Rename -gpio properties to -gpios
Rename the rate-select-gpio property to rate-select0-gpios
Add the rate-select1-gpios property
Add examples
---
Documentation/devicetree/bindings/net/sff,sfp.txt | 76 +++++++++++++++++++++++
1 file changed, 76 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/sff,sfp.txt
diff --git a/Documentation/devicetree/bindings/net/sff,sfp.txt b/Documentation/devicetree/bindings/net/sff,sfp.txt
new file mode 100644
index 000000000000..60e970ce10ee
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/sff,sfp.txt
@@ -0,0 +1,76 @@
+Small Form Factor (SFF) Committee Small Form-factor Pluggable (SFP)
+Transceiver
+
+Required properties:
+
+- compatible : must be "sff,sfp"
+
+Optional Properties:
+
+- i2c-bus : phandle of an I2C bus controller for the SFP two wire serial
+ interface
+
+- mod-def0-gpios : GPIO phandle and a specifier of the MOD-DEF0 (AKA Mod_ABS)
+ module presence input gpio signal, active (module absent) high
+
+- los-gpios : GPIO phandle and a specifier of the Receiver Loss of Signal
+ Indication input gpio signal, active (signal lost) high
+
+- tx-fault-gpios : GPIO phandle and a specifier of the Module Transmitter
+ Fault input gpio signal, active (fault condition) high
+
+- tx-disable-gpios : GPIO phandle and a specifier of the Transmitter Disable
+ output gpio signal, active (Tx disable) high
+
+- rate-select0-gpios : GPIO phandle and a specifier of the Rx Signaling Rate
+ Select (AKA RS0) output gpio signal, low: low Rx rate, high: high Rx rate
+
+- rate-select1-gpios : GPIO phandle and a specifier of the Tx Signaling Rate
+ Select (AKA RS1) output gpio signal (SFP+ only), low: low Tx rate, high:
+ high Tx rate
+
+Example #1: Direct serdes to SFP connection
+
+sfp_eth3: sfp-eth3 {
+ compatible = "sff,sfp";
+ i2c-bus = <&sfp_1g_i2c>;
+ los-gpios = <&cpm_gpio2 22 GPIO_ACTIVE_HIGH>;
+ mod-def0-gpios = <&cpm_gpio2 21 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&cpm_sfp_1g_pins &cps_sfp_1g_pins>;
+ tx-disable-gpios = <&cps_gpio1 24 GPIO_ACTIVE_HIGH>;
+ tx-fault-gpios = <&cpm_gpio2 19 GPIO_ACTIVE_HIGH>;
+};
+
+&cps_emac3 {
+ phy-names = "comphy";
+ phys = <&cps_comphy5 0>;
+ sfp = <&sfp_eth3>;
+};
+
+Example #2: Serdes to PHY to SFP connection
+
+sfp_eth0: sfp-eth0 {
+ compatible = "sff,sfp";
+ i2c-bus = <&sfpp0_i2c>;
+ los-gpios = <&cps_gpio1 28 GPIO_ACTIVE_HIGH>;
+ mod-def0-gpios = <&cps_gpio1 27 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&cps_sfpp0_pins>;
+ tx-disable-gpios = <&cps_gpio1 29 GPIO_ACTIVE_HIGH>;
+ tx-fault-gpios = <&cps_gpio1 26 GPIO_ACTIVE_HIGH>;
+};
+
+p0_phy: ethernet-phy@0 {
+ compatible = "ethernet-phy-ieee802.3-c45";
+ pinctrl-names = "default";
+ pinctrl-0 = <&cpm_phy0_pins &cps_phy0_pins>;
+ reg = <0>;
+ interrupt = <&cpm_gpio2 18 IRQ_TYPE_EDGE_FALLING>;
+ sfp = <&sfp_eth0>;
+};
+
+&cpm_eth0 {
+ phy = <&p0_phy>;
+ phy-mode = "10gbase-kr";
+};
--
2.14.1
--
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
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