Re: regression (4.10) - interface remove uevents not generated
On Sat, Mar 11, 2017 at 11:24:34PM +0200, Mantas Mikulėnas wrote: > On 2017-03-11 21:50, Andrei Vagin wrote: > > Hi Mantas, > > > > Thank you for the report. Could you try out the attached patch? > > Thanks, I tested it on current master but it doesn't seem to help; there > still aren't any uevents for removed interfaces. I reproduced the issue on my host and the correct patch is attached to this message. Thanks! > > -- > Mantas Mikulėnas > >From 456e28813d40f2076d4b9346fe8633c83b7a19d8 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sat, 11 Mar 2017 15:18:25 -0800 Subject: [PATCH] net: check net->count to check whether a netns is alive or not The previous idea was to check whether a net namespace is in net_exit_list or not. It doesn't work, because net->exit_list is used in __register_pernet_operations and __unregister_pernet_operations where all namespaces are added to a temporary list to make cleanup in error cases, so list_empty(&net->exit_list) always returns false. Fixes: 002d8a1a6c11 ("net: skip genenerating uevents for network namespaces that are exiting") Signed-off-by: Andrei Vagin --- net/core/net-sysfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index b0c04cf..1004418 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -952,7 +952,7 @@ net_rx_queue_update_kobjects(struct net_device *dev, int old_num, int new_num) while (--i >= new_num) { struct kobject *kobj = &dev->_rx[i].kobj; - if (!list_empty(&dev_net(dev)->exit_list)) + if (!atomic_read(&dev_net(dev)->count)) kobj->uevent_suppress = 1; if (dev->sysfs_rx_queue_group) sysfs_remove_group(kobj, dev->sysfs_rx_queue_group); @@ -1370,7 +1370,7 @@ netdev_queue_update_kobjects(struct net_device *dev, int old_num, int new_num) while (--i >= new_num) { struct netdev_queue *queue = dev->_tx + i; - if (!list_empty(&dev_net(dev)->exit_list)) + if (!atomic_read(&dev_net(dev)->count)) queue->kobj.uevent_suppress = 1; #ifdef CONFIG_BQL sysfs_remove_group(&queue->kobj, &dql_group); @@ -1557,7 +1557,7 @@ void netdev_unregister_kobject(struct net_device *ndev) { struct device *dev = &(ndev->dev); - if (!list_empty(&dev_net(ndev)->exit_list)) + if (!atomic_read(&dev_net(ndev)->count)) dev_set_uevent_suppress(dev, 1); kobject_get(&dev->kobj); -- 2.9.3
Re: [PATCH 2/5] rds: ib: replace spin_lock_irq with spin_lock_irqsave
On 3/11/17 6:33 PM, Yanjun Zhu wrote: Sorry. I have no test case to show some issue. But from Linux Kernel Development Second Edition by Robert Love. Yes I know the book and what the API does :D Use spin_lock_irq is dangerous since spin_unlock_irq unconditionally enables interrupts. We can assume the following scenario: --->the interrupt is disabled. spin_lock_irq(lock_ptr); <---this will disable interrupt again list_del(&ic->ib_node); spin_unlock_irq(lock_ptr); <---this will enable interrupt >the interrupt is enabled. our code change the state of interrupt. This will make potential risk. But spin_lock_irqsave/spin_unlock_irqrestore will not make potential risk. ic is well protected for any possible race and hence I asked if you had any test case. Please re-post the series again with the subject patch dropper for Dave to pick it up. Regards, Santosh
[net-next:master 38/46] drivers/net/ethernet/synopsys/dwc-xlgmac-hw.c:1548:36: error: 'IEEE_8021QAZ_MAX_TCS' undeclared
tree: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git master head: 01461abe62df44844efc5a57f9a365270a7c0299 commit: 65e0ace2c5cdd7aa898fea17d6e7bdc909394bf9 [38/46] net: dwc-xlgmac: Initial driver for DesignWare Enterprise Ethernet config: i386-randconfig-x0-03121309 (attached as .config) compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901 reproduce: git checkout 65e0ace2c5cdd7aa898fea17d6e7bdc909394bf9 # save the attached .config to linux build tree make ARCH=i386 All error/warnings (new ones prefixed by >>): In file included from include/linux/list.h:8:0, from include/linux/preempt.h:10, from include/linux/spinlock.h:50, from include/linux/phy.h:20, from drivers/net/ethernet/synopsys/dwc-xlgmac-hw.c:20: drivers/net/ethernet/synopsys/dwc-xlgmac-hw.c: In function 'xlgmac_config_queue_mapping': >> drivers/net/ethernet/synopsys/dwc-xlgmac-hw.c:1548:36: error: >> 'IEEE_8021QAZ_MAX_TCS' undeclared (first use in this function) prio_queues = min_t(unsigned int, IEEE_8021QAZ_MAX_TCS, ^ include/linux/kernel.h:753:13: note: in definition of macro '__min' t1 min1 = (x); \ ^ >> drivers/net/ethernet/synopsys/dwc-xlgmac-hw.c:1548:16: note: in expansion of >> macro 'min_t' prio_queues = min_t(unsigned int, IEEE_8021QAZ_MAX_TCS, ^ drivers/net/ethernet/synopsys/dwc-xlgmac-hw.c:1548:36: note: each undeclared identifier is reported only once for each function it appears in prio_queues = min_t(unsigned int, IEEE_8021QAZ_MAX_TCS, ^ include/linux/kernel.h:753:13: note: in definition of macro '__min' t1 min1 = (x); \ ^ >> drivers/net/ethernet/synopsys/dwc-xlgmac-hw.c:1548:16: note: in expansion of >> macro 'min_t' prio_queues = min_t(unsigned int, IEEE_8021QAZ_MAX_TCS, ^ vim +/IEEE_8021QAZ_MAX_TCS +1548 drivers/net/ethernet/synopsys/dwc-xlgmac-hw.c 1542MTL_Q_TQOMR)); 1543 queue++; 1544 } 1545 } 1546 1547 /* Map the 8 VLAN priority values to available MTL Rx queues */ > 1548 prio_queues = min_t(unsigned int, IEEE_8021QAZ_MAX_TCS, 1549 pdata->rx_q_count); 1550 ppq = IEEE_8021QAZ_MAX_TCS / prio_queues; 1551 ppq_extra = IEEE_8021QAZ_MAX_TCS % prio_queues; --- 0-DAY kernel test infrastructureOpen Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation .config.gz Description: application/gzip
Proposal...
Personal Business proposal for you,contact me via my personal E-mail for more detail's: ms_teresa_a...@outlook.com
Re: [PATCH 2/5] rds: ib: replace spin_lock_irq with spin_lock_irqsave
Sorry. I have no test case to show some issue. But from Linux Kernel Development Second Edition by Robert Love. Use spin_lock_irq is dangerous since spin_unlock_irq unconditionally enables interrupts. We can assume the following scenario: --->the interrupt is disabled. spin_lock_irq(lock_ptr); <---this will disable interrupt again list_del(&ic->ib_node); spin_unlock_irq(lock_ptr); <---this will enable interrupt >the interrupt is enabled. our code change the state of interrupt. This will make potential risk. But spin_lock_irqsave/spin_unlock_irqrestore will not make potential risk. Zhu Yanjun On 2017/3/10 0:50, Santosh Shilimkar wrote: On 3/8/2017 11:26 PM, Zhu Yanjun wrote: It is difficult to make sure the state of the interrupt when this function is called. As such, it is safer to use spin_lock_irqsave than spin_lock_irq. There is no reason to hold irqs and as such the code path is safe from irq context. I don't see need of this change unless you have test case which showed some issue. Regards, Santosh
Re: [PATCH net-next v2 00/17] net: dsa: mv88e6xxx: rework ATU support
Le 03/11/17 à 13:12, Vivien Didelot a écrit : > The purpose of this patch series is to rework the code related to the > Address Translation Unit (ATU), and bring support for it to the 88E6390 > family of switch chips. > > All Global (1) ATU related code have been reworked and moved to its own > file. Some port related bits used for ATU configuration (such as the > Learn2All and MessagePort feature) have also been taken care of. > > The ports' mode and egress flooding mode have been refactored to fix the > egress of frames with unknown unicast or multicast destination address, > and write all these bits regardless the port mode (Normal, DSA, etc.) > > Finally remove the eth_addr_greater which was only used by mv88e6xxx. Just some general note on the way the driver seems to be going there seems to be a multiplication of new ops being introduced, and most of them seem to default to the mv88e6xxx (generic) ones. Should you do something like: if (!ops->foo) ops->foo = mv88e6xxx_foo Such that you reduce the possibility for a specific switch model to lack such an operation? > > Changes in v2: > - add Reviewed-by tags > - split mv88e6xxx_g1_atu_set_age_time and mv88e6xxx_atu_setup addition > - remove DSA_TAG_PROTO_TRAILER check > - split Message Port and Learn2All addition > - remove unused MV88E6XXX_FLAG_G1_ATU_FID flag > - add dsa_is_normal_port helper > > Vivien Didelot (17): > net: dsa: mv88e6xxx: add port mask helper > net: dsa: mv88e6xxx: move ATU ageing time setter > net: dsa: mv88e6xxx: add ATU setup helper > net: dsa: mv88e6xxx: setup message ports > net: dsa: mv88e6xxx: enable ATU Learn2All > net: dsa: mv88e6xxx: rework ATU Load/Purge > net: dsa: mv88e6xxx: rework ATU GetNext > net: dsa: mv88e6xxx: rework ATU Flush > net: dsa: mv88e6xxx: rework ATU Remove > net: dsa: mv88e6xxx: rename new FID helper > net: dsa: mv88e6xxx: rename the port vector member > net: dsa: add dsa_is_normal_port helper > net: dsa: mv88e6xxx: rework port mode setup > net: dsa: mv88e6xxx: fix port egress flooding mode > net: dsa: mv88e6xxx: add port ATU learn limit op > net: dsa: mv88e6xxx: add port priority override op > etherdevice: remove unused eth_addr_greater > > drivers/net/dsa/mv88e6xxx/Makefile | 1 + > drivers/net/dsa/mv88e6xxx/chip.c| 667 > +++- > drivers/net/dsa/mv88e6xxx/global1.h | 11 + > drivers/net/dsa/mv88e6xxx/global1_atu.c | 300 ++ > drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 44 ++- > drivers/net/dsa/mv88e6xxx/port.c| 78 +++- > drivers/net/dsa/mv88e6xxx/port.h| 16 +- > include/linux/etherdevice.h | 15 - > include/net/dsa.h | 5 + > 9 files changed, 638 insertions(+), 499 deletions(-) > create mode 100644 drivers/net/dsa/mv88e6xxx/global1_atu.c > -- Florian
Re: [PATCH net-next v2 12/17] net: dsa: add dsa_is_normal_port helper
Le 03/11/17 à 13:12, Vivien Didelot a écrit : > Introduce a dsa_is_normal_port helper to check if a given port is a > normal user port as opposed to a CPU port or DSA link. net/dsa/dsa2.c uses the "user" terminology should we use something like that here? > > Signed-off-by: Vivien Didelot > --- > include/net/dsa.h | 5 + > 1 file changed, 5 insertions(+) > > diff --git a/include/net/dsa.h b/include/net/dsa.h > index 4e13e695f025..bf0e42c2a6f7 100644 > --- a/include/net/dsa.h > +++ b/include/net/dsa.h > @@ -248,6 +248,11 @@ static inline bool dsa_is_dsa_port(struct dsa_switch > *ds, int p) > return !!((ds->dsa_port_mask) & (1 << p)); > } > > +static inline bool dsa_is_normal_port(struct dsa_switch *ds, int p) > +{ > + return !dsa_is_cpu_port(ds, p) && !dsa_is_dsa_port(ds, p); > +} > + > static inline bool dsa_is_port_initialized(struct dsa_switch *ds, int p) > { > return ds->enabled_port_mask & (1 << p) && ds->ports[p].netdev; > -- Florian
[Patch net-next] atm: remove an unnecessary loop
From: Francois Romieu Andrey reported this kernel warning: WARNING: CPU: 0 PID: 4114 at kernel/sched/core.c:7737 __might_sleep+0x149/0x1a0 do not call blocking ops when !TASK_RUNNING; state=1 set at [] prepare_to_wait+0x182/0x530 The deeply nested alloc_skb is a problem. Diagnosis: nesting is wrong. It makes zero sense. Fix it and the implicit task state change problem automagically goes away. alloc_skb() does not need to be in the "while" loop. alloc_skb() does not need to be in the {prepare_to_wait/add_wait_queue ... finish_wait/remove_wait_queue} block. I claim that: - alloc_tx() should only perform the "wait_for_decent_tx_drain" part - alloc_skb() ought to be done directly in vcc_sendmsg - alloc_skb() failure can be handled gracefully in vcc_sendmsg - alloc_skb() may use a (m->msg_flags & MSG_DONTWAIT) dependent GFP_{KERNEL / ATOMIC} flag Reported-by: Andrey Konovalov Reviewed-and-Tested-by: Chas Williams <3ch...@gmail.com> Signed-off-by: Chas Williams <3ch...@gmail.com> --- net/atm/common.c | 22 +- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/net/atm/common.c b/net/atm/common.c index 9613381..f06422f 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -62,21 +62,16 @@ static void vcc_remove_socket(struct sock *sk) write_unlock_irq(&vcc_sklist_lock); } -static struct sk_buff *alloc_tx(struct atm_vcc *vcc, unsigned int size) +static bool vcc_tx_ready(struct atm_vcc *vcc, unsigned int size) { - struct sk_buff *skb; struct sock *sk = sk_atm(vcc); if (sk_wmem_alloc_get(sk) && !atm_may_send(vcc, size)) { pr_debug("Sorry: wmem_alloc = %d, size = %d, sndbuf = %d\n", sk_wmem_alloc_get(sk), size, sk->sk_sndbuf); - return NULL; + return false; } - while (!(skb = alloc_skb(size, GFP_KERNEL))) - schedule(); - pr_debug("%d += %d\n", sk_wmem_alloc_get(sk), skb->truesize); - atomic_add(skb->truesize, &sk->sk_wmem_alloc); - return skb; + return true; } static void vcc_sock_destruct(struct sock *sk) @@ -606,7 +601,7 @@ int vcc_sendmsg(struct socket *sock, struct msghdr *m, size_t size) eff = (size+3) & ~3; /* align to word boundary */ prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); error = 0; - while (!(skb = alloc_tx(vcc, eff))) { + while (!vcc_tx_ready(vcc, eff)) { if (m->msg_flags & MSG_DONTWAIT) { error = -EAGAIN; break; @@ -628,6 +623,15 @@ int vcc_sendmsg(struct socket *sock, struct msghdr *m, size_t size) finish_wait(sk_sleep(sk), &wait); if (error) goto out; + + skb = alloc_skb(eff, GFP_KERNEL); + if (!skb) { + error = -ENOMEM; + goto out; + } + pr_debug("%d += %d\n", sk_wmem_alloc_get(sk), skb->truesize); + atomic_add(skb->truesize, &sk->sk_wmem_alloc); + skb->dev = NULL; /* for paths shared with net_device interfaces */ ATM_SKB(skb)->atm_options = vcc->atm_options; if (!copy_from_iter_full(skb_put(skb, size), size, &m->msg_iter)) { -- 2.7.4
Proposal...
Personal Business proposal for you,contact me via my personal E-mail for more detail's: ms_teresa_a...@outlook.com
Re: [PATCH net-next v2 03/17] net: dsa: mv88e6xxx: add ATU setup helper
On Sat, Mar 11, 2017 at 04:12:49PM -0500, Vivien Didelot wrote: > Move the configuration of the default ageing time in a new > mv88e6xxx_atu_setup function. > > That function will be extended later to contain all ATU related > configuration bits. > > Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Andrew
Re: [PATCH net-next v2 17/17] etherdevice: remove unused eth_addr_greater
On Sat, Mar 11, 2017 at 04:13:03PM -0500, Vivien Didelot wrote: > eth_addr_greater() was introduced for the mv88e6xxx driver, but is not > used anymore. There is no other user, thus remove this function. > > Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Andrew
Re: [PATCH net-next v2 12/17] net: dsa: add dsa_is_normal_port helper
On Sat, Mar 11, 2017 at 04:12:58PM -0500, Vivien Didelot wrote: > Introduce a dsa_is_normal_port helper to check if a given port is a > normal user port as opposed to a CPU port or DSA link. > > Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Andrew
Re: [PATCH net-next 04/14] net: dsa: mv88e6xxx: rework ATU Load/Purge
> > I really wished you had moved the code, unmodified, into > > global1_atu.c. Then made lots of easy to review small changes. I > > cannot just look at this patch and know it is correct. What i need to > > compare against is not in this patch. So it is a lot harder to review. > > I've addressed all of your comments in this patchset except this one. Hi Vivien This time, i'm not going to push the issue further. But next time i will. The point is, we have working code. You don't just throw that away. You make lots of small changes to that working code to morph it into the code you want. These small changes are all very quick and easy to review, because they are all small and obvious. At each stage we have working code. If somehow it does break, it is easy to bisect it down to one small change. The actual likelyhood of breaking it is small, because the changes are all small and obviously correct. It does result in more patches, more to review, but it is much easier to review, because it should be obviously correct. The overall lines of code at the end is the same. So overall there is no harm is having lots of small patches. > A patch file cannot guarantee that a chunk of code moved around has not > been altered in the process. This will just generate more diff for no > value, that needs to be updated afterwards anyway. I don't need a guarantee. I would trust you have moved it, without editing it. Generating more diff is not a problem. The number of diffs is not important at all. What is important is lots of small, easy to review, obviously correct patches. > Plus you already complained in the first iteration I sent about > modifying lines that I previously added. I took care of logically > splitting the new ATU Load/Purge, GetNext, Flush and Remove operations > into incremental unmodified chunks in this series. Unfortunately, you are splitting in the wrong dimension. None of this is obviously correct. But it easily code of been. Andrew
Re: [PATCH] Enable tx timestamping on loopback and dummy
2 and 3 were recommendations by the checkpatch.pl script; as suggested, I've broken them down from the timestamping code and resubmitted as two separate patches (on separate emails though). > On 11 Mar 2017, at 23:17, Oliver Hartkopp wrote: > > Hi Ezequiel, > >> On 03/11/2017 03:42 PM, Ezequiel Lara Gomez wrote: >> Also, cleanup some warnings from timestamping code. > > in fact you're doing three different things here: > > 1. introduce tx timestamping > 2. silently change an include: -> > 3. fix some whitespace and empty line issues > > You'd better provide one patch for 1 & 2 and explain why 2 is needed. > > Regards, > Oliver > >> >> This enables testing of SO_TIMESTAMPING options by targetting localhost >> addresses. >> >> Tested on qemu using txtimestamping.c from the kernel selftests. >> >> Signed-off-by: Ezequiel Lara Gomez >> --- >> drivers/net/dummy.c| 1 + >> drivers/net/loopback.c | 14 +++--- >> 2 files changed, 8 insertions(+), 7 deletions(-) >> >> diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c >> index 2c80611..32fdc00 100644 >> --- a/drivers/net/dummy.c >> +++ b/drivers/net/dummy.c >> @@ -125,6 +125,7 @@ static netdev_tx_t dummy_xmit(struct sk_buff *skb, >> struct net_device *dev) >>dstats->tx_bytes += skb->len; >>u64_stats_update_end(&dstats->syncp); >> >> +skb_tx_timestamp(skb); >>dev_kfree_skb(skb); >>return NETDEV_TX_OK; >> } >> diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c >> index b23b719..8bcf479 100644 >> --- a/drivers/net/loopback.c >> +++ b/drivers/net/loopback.c >> @@ -13,7 +13,7 @@ >> * >> *Alan Cox:Fixed oddments for NET3.014 >> *Alan Cox:Rejig for NET3.029 snap #3 >> - *Alan Cox:Fixed NET3.029 bugs and sped up >> + *Alan Cox:Fixed NET3.029 bugs and sped up >> *Larry McVoy:Tiny tweak to double performance >> *Alan Cox:Backed out LMV's tweak - the linux mm >> *can't take it... >> @@ -41,7 +41,7 @@ >> #include >> >> #include >> -#include >> +#include >> >> #include >> #include >> @@ -74,6 +74,7 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb, >>struct pcpu_lstats *lb_stats; >>int len; >> >> +skb_tx_timestamp(skb); >>skb_orphan(skb); >> >>/* Before queueing this packet to netif_rx(), >> @@ -149,8 +150,8 @@ static void loopback_dev_free(struct net_device *dev) >> } >> >> static const struct net_device_ops loopback_ops = { >> -.ndo_init = loopback_dev_init, >> -.ndo_start_xmit= loopback_xmit, >> +.ndo_init= loopback_dev_init, >> +.ndo_start_xmit = loopback_xmit, >>.ndo_get_stats64 = loopback_get_stats64, >>.ndo_set_mac_address = eth_mac_addr, >> }; >> @@ -170,7 +171,7 @@ static void loopback_setup(struct net_device *dev) >>dev->priv_flags|= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE; >>netif_keep_dst(dev); >>dev->hw_features= NETIF_F_GSO_SOFTWARE; >> -dev->features= NETIF_F_SG | NETIF_F_FRAGLIST >> +dev->features= NETIF_F_SG | NETIF_F_FRAGLIST >>| NETIF_F_GSO_SOFTWARE >>| NETIF_F_HW_CSUM >>| NETIF_F_RXCSUM >> @@ -206,7 +207,6 @@ static __net_init int loopback_net_init(struct net *net) >>net->loopback_dev = dev; >>return 0; >> >> - >> out_free_netdev: >>free_netdev(dev); >> out: >> @@ -217,5 +217,5 @@ static __net_init int loopback_net_init(struct net *net) >> >> /* Registered in net/core/dev.c */ >> struct pernet_operations __net_initdata loopback_net_ops = { >> - .init = loopback_net_init, >> +.init = loopback_net_init, >> }; >> > Amazon Data Services Ireland Limited registered office: One Burlington Plaza, Burlington Road, Dublin 4, Ireland. Registered in Ireland. Registration number 390566.
Re: [PATCH] Enable tx timestamping on loopback and dummy
Hi Ezequiel, On 03/11/2017 03:42 PM, Ezequiel Lara Gomez wrote: Also, cleanup some warnings from timestamping code. in fact you're doing three different things here: 1. introduce tx timestamping 2. silently change an include: -> 3. fix some whitespace and empty line issues You'd better provide one patch for 1 & 2 and explain why 2 is needed. Regards, Oliver This enables testing of SO_TIMESTAMPING options by targetting localhost addresses. Tested on qemu using txtimestamping.c from the kernel selftests. Signed-off-by: Ezequiel Lara Gomez --- drivers/net/dummy.c| 1 + drivers/net/loopback.c | 14 +++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 2c80611..32fdc00 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -125,6 +125,7 @@ static netdev_tx_t dummy_xmit(struct sk_buff *skb, struct net_device *dev) dstats->tx_bytes += skb->len; u64_stats_update_end(&dstats->syncp); + skb_tx_timestamp(skb); dev_kfree_skb(skb); return NETDEV_TX_OK; } diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index b23b719..8bcf479 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -13,7 +13,7 @@ * * Alan Cox: Fixed oddments for NET3.014 * Alan Cox: Rejig for NET3.029 snap #3 - * Alan Cox: Fixed NET3.029 bugs and sped up + * Alan Cox: Fixed NET3.029 bugs and sped up * Larry McVoy : Tiny tweak to double performance * Alan Cox: Backed out LMV's tweak - the linux mm * can't take it... @@ -41,7 +41,7 @@ #include #include -#include +#include #include #include @@ -74,6 +74,7 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb, struct pcpu_lstats *lb_stats; int len; + skb_tx_timestamp(skb); skb_orphan(skb); /* Before queueing this packet to netif_rx(), @@ -149,8 +150,8 @@ static void loopback_dev_free(struct net_device *dev) } static const struct net_device_ops loopback_ops = { - .ndo_init = loopback_dev_init, - .ndo_start_xmit= loopback_xmit, + .ndo_init= loopback_dev_init, + .ndo_start_xmit = loopback_xmit, .ndo_get_stats64 = loopback_get_stats64, .ndo_set_mac_address = eth_mac_addr, }; @@ -170,7 +171,7 @@ static void loopback_setup(struct net_device *dev) dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE; netif_keep_dst(dev); dev->hw_features = NETIF_F_GSO_SOFTWARE; - dev->features= NETIF_F_SG | NETIF_F_FRAGLIST + dev->features= NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE | NETIF_F_HW_CSUM | NETIF_F_RXCSUM @@ -206,7 +207,6 @@ static __net_init int loopback_net_init(struct net *net) net->loopback_dev = dev; return 0; - out_free_netdev: free_netdev(dev); out: @@ -217,5 +217,5 @@ static __net_init int loopback_net_init(struct net *net) /* Registered in net/core/dev.c */ struct pernet_operations __net_initdata loopback_net_ops = { - .init = loopback_net_init, + .init = loopback_net_init, };
Proposal...
Personal Business proposal for you,contact me via my personal E-mail for more detail's: ms_teresa_a...@outlook.com
[no subject]
-- Hi, I appreciate your beauty! can we get to know each other better if you don't mind? My name is karl, Can you please tell me a little about yourself so that we can get to know each other better? Best Regards Karl.
Re: [PATCH net-next v5 0/7] gtp: misc improvements
Hi Andreas, > Andreas Schultz (7): > gtp: switch from struct socket to struct sock for the GTP sockets > gtp: make GTP sockets in gtp_newlink optional > gtp: merge gtp_get_net and gtp_genl_find_dev > gtp: consolidate gtp socket rx path > gtp: unify genl_find_pdp and prepare for per socket lookup > gtp: consolidate pdp context destruction into helper > gtp: add socket to pdp context I agree with the conceptual and architectural direction that you're taking the code, and I also think your current patchset is good to go ahead, so feel free to add my "Acked-By: Harald Welte ". However, the usual disclaimer: I've been out of kernel networking land for a long time, so my review skills are clearly not the best anymore. I'm happy for any input others can give from that point of view. There are some minor typos in the commit logs, but at the rate my typos increase over the years, I am the last one to complain about wasting time on fixing these ;) Regards, Harald -- - Harald Weltehttp://laforge.gnumonks.org/ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6)
Re: regression (4.10) - interface remove uevents not generated
On 2017-03-11 21:50, Andrei Vagin wrote: > Hi Mantas, > > Thank you for the report. Could you try out the attached patch? Thanks, I tested it on current master but it doesn't seem to help; there still aren't any uevents for removed interfaces. -- Mantas Mikulėnas
[PATCH net-next v2 02/17] net: dsa: mv88e6xxx: move ATU ageing time setter
Move the ATU ageing time setter code in a new global1_atu.c file, which will be extended in future patches to contains all consequent Global (1) ATU support code. Signed-off-by: Vivien Didelot --- drivers/net/dsa/mv88e6xxx/Makefile | 1 + drivers/net/dsa/mv88e6xxx/chip.c| 31 ++-- drivers/net/dsa/mv88e6xxx/global1.h | 3 +++ drivers/net/dsa/mv88e6xxx/global1_atu.c | 43 + 4 files changed, 49 insertions(+), 29 deletions(-) create mode 100644 drivers/net/dsa/mv88e6xxx/global1_atu.c diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile index c36be318de1a..31d37a90cec7 100644 --- a/drivers/net/dsa/mv88e6xxx/Makefile +++ b/drivers/net/dsa/mv88e6xxx/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_NET_DSA_MV88E6XXX) += mv88e6xxx.o mv88e6xxx-objs := chip.o mv88e6xxx-objs += global1.o +mv88e6xxx-objs += global1_atu.o mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_GLOBAL2) += global2.o mv88e6xxx-objs += port.o diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 03dc886ed3d6..b228b8491afc 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2697,33 +2697,6 @@ static int mv88e6xxx_g1_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr) return 0; } -static int mv88e6xxx_g1_set_age_time(struct mv88e6xxx_chip *chip, -unsigned int msecs) -{ - const unsigned int coeff = chip->info->age_time_coeff; - const unsigned int min = 0x01 * coeff; - const unsigned int max = 0xff * coeff; - u8 age_time; - u16 val; - int err; - - if (msecs < min || msecs > max) - return -ERANGE; - - /* Round to nearest multiple of coeff */ - age_time = (msecs + coeff / 2) / coeff; - - err = mv88e6xxx_g1_read(chip, GLOBAL_ATU_CONTROL, &val); - if (err) - return err; - - /* AgeTime is 11:4 bits */ - val &= ~0xff0; - val |= age_time << 4; - - return mv88e6xxx_g1_write(chip, GLOBAL_ATU_CONTROL, val); -} - static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds, unsigned int ageing_time) { @@ -2731,7 +2704,7 @@ static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds, int err; mutex_lock(&chip->reg_lock); - err = mv88e6xxx_g1_set_age_time(chip, ageing_time); + err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time); mutex_unlock(&chip->reg_lock); return err; @@ -2783,7 +2756,7 @@ static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip) if (err) return err; - err = mv88e6xxx_g1_set_age_time(chip, 30); + err = mv88e6xxx_g1_atu_set_age_time(chip, 30); if (err) return err; diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h index 1aec7382c02d..b8d0fb519bab 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.h +++ b/drivers/net/dsa/mv88e6xxx/global1.h @@ -38,4 +38,7 @@ int mv88e6095_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port); int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port); int mv88e6390_g1_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip); +int mv88e6xxx_g1_atu_set_age_time(struct mv88e6xxx_chip *chip, + unsigned int msecs); + #endif /* _MV88E6XXX_GLOBAL1_H */ diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c new file mode 100644 index ..4d0ada9efc6d --- /dev/null +++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c @@ -0,0 +1,43 @@ +/* + * Marvell 88E6xxx Address Translation Unit (ATU) support + * + * Copyright (c) 2008 Marvell Semiconductor + * Copyright (c) 2017 Savoir-faire Linux, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include "mv88e6xxx.h" +#include "global1.h" + +/* Offset 0x0A: ATU Control Register */ + +int mv88e6xxx_g1_atu_set_age_time(struct mv88e6xxx_chip *chip, + unsigned int msecs) +{ + const unsigned int coeff = chip->info->age_time_coeff; + const unsigned int min = 0x01 * coeff; + const unsigned int max = 0xff * coeff; + u8 age_time; + u16 val; + int err; + + if (msecs < min || msecs > max) + return -ERANGE; + + /* Round to nearest multiple of coeff */ + age_time = (msecs + coeff / 2) / coeff; + + err = mv88e6xxx_g1_read(chip, GLOBAL_ATU_CONTROL, &val); + if (err) + return err; + + /* AgeTime is 11:4 bits */ + val &= ~0xff0; + val |= age_time << 4; + + return mv88e6xxx_g1_write(chip, GLOBAL_ATU_CONTROL, val); +} -- 2.12.0
[PATCH net-next v2 06/17] net: dsa: mv88e6xxx: rework ATU Load/Purge
All Marvell switch chips have an ATU accessed using the same Global (1) register layout. Only the handling of the FID differs as more bits were necessary to support more and more databases. Add and use a fresh documented implementation of the ATU Load/Purge. The static mv88e6xxx_g1_atu_{fid_write,op_wait,op,data_write,mac_write} functions won't need to be exposed in the end so for the moment keep their counterparts _mv88e6xxx_atu_{wait,cmd,data_write,mac_write} as is, since they are still used by other ATU operations. Signed-off-by: Vivien Didelot --- drivers/net/dsa/mv88e6xxx/chip.c| 22 +-- drivers/net/dsa/mv88e6xxx/global1.h | 2 + drivers/net/dsa/mv88e6xxx/global1_atu.c | 108 3 files changed, 111 insertions(+), 21 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 1ee0c05f624e..95dbf581b54a 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2045,26 +2045,6 @@ static int _mv88e6xxx_atu_mac_read(struct mv88e6xxx_chip *chip, return 0; } -static int _mv88e6xxx_atu_load(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_atu_entry *entry) -{ - int ret; - - ret = _mv88e6xxx_atu_wait(chip); - if (ret < 0) - return ret; - - ret = _mv88e6xxx_atu_mac_write(chip, entry->mac); - if (ret < 0) - return ret; - - ret = _mv88e6xxx_atu_data_write(chip, entry); - if (ret < 0) - return ret; - - return _mv88e6xxx_atu_cmd(chip, entry->fid, GLOBAL_ATU_OP_LOAD_DB); -} - static int _mv88e6xxx_atu_getnext(struct mv88e6xxx_chip *chip, u16 fid, struct mv88e6xxx_atu_entry *entry); @@ -2132,7 +2112,7 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port, entry.state = state; } - return _mv88e6xxx_atu_load(chip, &entry); + return mv88e6xxx_g1_atu_loadpurge(chip, vlan.fid, &entry); } static int mv88e6xxx_port_fdb_prepare(struct dsa_switch *ds, int port, diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h index 18322d05225a..2c03f2e04639 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.h +++ b/drivers/net/dsa/mv88e6xxx/global1.h @@ -41,5 +41,7 @@ int mv88e6390_g1_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip); int mv88e6xxx_g1_atu_set_learn2all(struct mv88e6xxx_chip *chip, bool learn2all); int mv88e6xxx_g1_atu_set_age_time(struct mv88e6xxx_chip *chip, unsigned int msecs); +int mv88e6xxx_g1_atu_loadpurge(struct mv88e6xxx_chip *chip, u16 fid, + struct mv88e6xxx_atu_entry *entry); #endif /* _MV88E6XXX_GLOBAL1_H */ diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c index 843a21e05f7b..09190559178b 100644 --- a/drivers/net/dsa/mv88e6xxx/global1_atu.c +++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c @@ -13,6 +13,13 @@ #include "mv88e6xxx.h" #include "global1.h" +/* Offset 0x01: ATU FID Register */ + +static int mv88e6xxx_g1_atu_fid_write(struct mv88e6xxx_chip *chip, u16 fid) +{ + return mv88e6xxx_g1_write(chip, GLOBAL_ATU_FID, fid & 0xfff); +} + /* Offset 0x0A: ATU Control Register */ int mv88e6xxx_g1_atu_set_learn2all(struct mv88e6xxx_chip *chip, bool learn2all) @@ -58,3 +65,104 @@ int mv88e6xxx_g1_atu_set_age_time(struct mv88e6xxx_chip *chip, return mv88e6xxx_g1_write(chip, GLOBAL_ATU_CONTROL, val); } + +/* Offset 0x0B: ATU Operation Register */ + +static int mv88e6xxx_g1_atu_op_wait(struct mv88e6xxx_chip *chip) +{ + return mv88e6xxx_g1_wait(chip, GLOBAL_ATU_OP, GLOBAL_ATU_OP_BUSY); +} + +static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip *chip, u16 fid, u16 op) +{ + u16 val; + int err; + + /* FID bits are dispatched all around gradually as more are supported */ + if (mv88e6xxx_num_databases(chip) > 256) { + err = mv88e6xxx_g1_atu_fid_write(chip, fid); + if (err) + return err; + } else { + if (mv88e6xxx_num_databases(chip) > 16) { + /* ATU DBNum[7:4] are located in ATU Control 15:12 */ + err = mv88e6xxx_g1_read(chip, GLOBAL_ATU_CONTROL, &val); + if (err) + return err; + + val = (val & 0x0fff) | ((fid << 8) & 0xf000); + err = mv88e6xxx_g1_write(chip, GLOBAL_ATU_CONTROL, val); + if (err) + return err; + } + + /* ATU DBNum[3:0] are located in ATU Operation 3:0 */ + op |= fid & 0xf; + } + + err = mv88e6xxx_g1_write(chip, GLOBAL_ATU_OP, op); + if (err) + return err; + + return mv88e6xxx_g1_atu_op_wait(chip); +} + +/* Offset 0x0C: ATU Data R
[PATCH net-next v2 03/17] net: dsa: mv88e6xxx: add ATU setup helper
Move the configuration of the default ageing time in a new mv88e6xxx_atu_setup function. That function will be extended later to contain all ATU related configuration bits. Signed-off-by: Vivien Didelot --- drivers/net/dsa/mv88e6xxx/chip.c | 13 + 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index b228b8491afc..0ad8200f3321 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1306,6 +1306,11 @@ static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port, netdev_err(ds->ports[port].netdev, "failed to update state\n"); } +static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip) +{ + return mv88e6xxx_g1_atu_set_age_time(chip, 30); +} + static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port) { struct mv88e6xxx_chip *chip = ds->priv; @@ -2756,10 +2761,6 @@ static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip) if (err) return err; - err = mv88e6xxx_g1_atu_set_age_time(chip, 30); - if (err) - return err; - /* Clear all ATU entries */ err = _mv88e6xxx_atu_flush(chip, 0, true); if (err) @@ -2845,6 +2846,10 @@ static int mv88e6xxx_setup(struct dsa_switch *ds) goto unlock; } + err = mv88e6xxx_atu_setup(chip); + if (err) + goto unlock; + /* Some generations have the configuration of sending reserved * management frames to the CPU in global2, others in * global1. Hence it does not fit the two setup functions -- 2.12.0
[PATCH net-next v2 13/17] net: dsa: mv88e6xxx: rework port mode setup
A switch port mode is defined by the association of its egress mode, its frame mode and if supported or required, the ether type value. Pack all this in a mv88e6xxx_set_port_mode function and provide helpers for the Normal Network mode, the DSA mode, and the Ether Type DSA mode, as well as an helper to setup a port's mode depending on its nature. Define PORT_ETH_TYPE_DEFAULT for the 0x9100 reset value of port E Type. Signed-off-by: Vivien Didelot --- drivers/net/dsa/mv88e6xxx/chip.c | 120 +++--- drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 1 + 2 files changed, 67 insertions(+), 54 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index e9533d4919bc..5f5023215ce1 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2199,69 +2199,82 @@ static int mv88e6xxx_serdes_power_on(struct mv88e6xxx_chip *chip) return err; } +static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port, + enum mv88e6xxx_frame_mode frame, u16 egress, + u16 etype) +{ + int err; + + if (!chip->info->ops->port_set_frame_mode) + return -EOPNOTSUPP; + + err = mv88e6xxx_port_set_egress_mode(chip, port, egress); + if (err) + return err; + + err = chip->info->ops->port_set_frame_mode(chip, port, frame); + if (err) + return err; + + if (chip->info->ops->port_set_ether_type) + return chip->info->ops->port_set_ether_type(chip, port, etype); + + return 0; +} + +static int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port) +{ + return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL, + PORT_CONTROL_EGRESS_UNMODIFIED, + PORT_ETH_TYPE_DEFAULT); +} + +static int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port) +{ + return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA, + PORT_CONTROL_EGRESS_UNMODIFIED, + PORT_ETH_TYPE_DEFAULT); +} + +static int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port) +{ + return mv88e6xxx_set_port_mode(chip, port, + MV88E6XXX_FRAME_MODE_ETHERTYPE, + PORT_CONTROL_EGRESS_ADD_TAG, ETH_P_EDSA); +} + +static int mv88e6xxx_setup_port_mode(struct mv88e6xxx_chip *chip, int port) +{ + if (dsa_is_dsa_port(chip->ds, port)) + return mv88e6xxx_set_port_mode_dsa(chip, port); + + if (dsa_is_normal_port(chip->ds, port)) + return mv88e6xxx_set_port_mode_normal(chip, port); + + /* Setup CPU port mode depending on its supported tag format */ + if (chip->info->tag_protocol == DSA_TAG_PROTO_DSA) + return mv88e6xxx_set_port_mode_dsa(chip, port); + + if (chip->info->tag_protocol == DSA_TAG_PROTO_EDSA) + return mv88e6xxx_set_port_mode_edsa(chip, port); + + return -EINVAL; +} + static int mv88e6xxx_setup_port_dsa(struct mv88e6xxx_chip *chip, int port, int upstream_port) { - int err; - - err = chip->info->ops->port_set_frame_mode( - chip, port, MV88E6XXX_FRAME_MODE_DSA); - if (err) - return err; - return chip->info->ops->port_set_egress_unknowns( chip, port, port == upstream_port); } static int mv88e6xxx_setup_port_cpu(struct mv88e6xxx_chip *chip, int port) { - int err; - - switch (chip->info->tag_protocol) { - case DSA_TAG_PROTO_EDSA: - err = chip->info->ops->port_set_frame_mode( - chip, port, MV88E6XXX_FRAME_MODE_ETHERTYPE); - if (err) - return err; - - err = mv88e6xxx_port_set_egress_mode( - chip, port, PORT_CONTROL_EGRESS_ADD_TAG); - if (err) - return err; - - if (chip->info->ops->port_set_ether_type) - err = chip->info->ops->port_set_ether_type( - chip, port, ETH_P_EDSA); - break; - - case DSA_TAG_PROTO_DSA: - err = chip->info->ops->port_set_frame_mode( - chip, port, MV88E6XXX_FRAME_MODE_DSA); - if (err) - return err; - - err = mv88e6xxx_port_set_egress_mode( - chip, port, PORT_CONTROL_EGRESS_UNMODIFIED); - break; - default: - err = -EINVAL; - } - - if (err) - return err; - return chip->info->ops->port_set_egress_unknowns(chip, port, true); } static int mv88e6xxx_setup_port_normal(struct mv88e6xxx_chi
[PATCH net-next v2 17/17] etherdevice: remove unused eth_addr_greater
eth_addr_greater() was introduced for the mv88e6xxx driver, but is not used anymore. There is no other user, thus remove this function. Signed-off-by: Vivien Didelot --- include/linux/etherdevice.h | 15 --- 1 file changed, 15 deletions(-) diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index c62b709b1ce0..2d9f80848d4b 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h @@ -447,21 +447,6 @@ static inline void eth_addr_dec(u8 *addr) } /** - * ether_addr_greater - Compare two Ethernet addresses - * @addr1: Pointer to a six-byte array containing the Ethernet address - * @addr2: Pointer other six-byte array containing the Ethernet address - * - * Compare two Ethernet addresses, returns true addr1 is greater than addr2 - */ -static inline bool ether_addr_greater(const u8 *addr1, const u8 *addr2) -{ - u64 u1 = ether_addr_to_u64(addr1); - u64 u2 = ether_addr_to_u64(addr2); - - return u1 > u2; -} - -/** * is_etherdev_addr - Tell if given Ethernet address belongs to the device. * @dev: Pointer to a device structure * @addr: Pointer to a six-byte array containing the Ethernet address -- 2.12.0
[PATCH net-next v2 10/17] net: dsa: mv88e6xxx: rename new FID helper
Rename the _mv88e6xxx_fid_new helper to mv88e6xxx_atu_new to get rid of the old underscore prefix naming convention and be consistent with the rest of the chip-wide ATU API. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn --- drivers/net/dsa/mv88e6xxx/chip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index a11e5354f14f..df31c2c57e09 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1556,7 +1556,7 @@ static int _mv88e6xxx_stu_loadpurge(struct mv88e6xxx_chip *chip, return _mv88e6xxx_vtu_cmd(chip, GLOBAL_VTU_OP_STU_LOAD_PURGE); } -static int _mv88e6xxx_fid_new(struct mv88e6xxx_chip *chip, u16 *fid) +static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid) { DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID); struct mv88e6xxx_vtu_entry vlan; @@ -1610,7 +1610,7 @@ static int _mv88e6xxx_vtu_new(struct mv88e6xxx_chip *chip, u16 vid, }; int i, err; - err = _mv88e6xxx_fid_new(chip, &vlan.fid); + err = mv88e6xxx_atu_new(chip, &vlan.fid); if (err) return err; -- 2.12.0
[PATCH net-next v2 01/17] net: dsa: mv88e6xxx: add port mask helper
Add a mv88e6xxx_port_mask() helper to get the bitmask of ports in a switch chip, that will be used in several features. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn --- drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 5 + drivers/net/dsa/mv88e6xxx/port.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h index 6033f2f6260a..166b513ff751 100644 --- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h @@ -944,6 +944,11 @@ static inline unsigned int mv88e6xxx_num_ports(struct mv88e6xxx_chip *chip) return chip->info->num_ports; } +static inline u16 mv88e6xxx_port_mask(struct mv88e6xxx_chip *chip) +{ + return GENMASK(mv88e6xxx_num_ports(chip) - 1, 0); +} + int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val); int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val); int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 8875784c4718..9bb0f2134cba 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -539,7 +539,7 @@ int mv88e6351_port_set_egress_unknowns(struct mv88e6xxx_chip *chip, int port, int mv88e6xxx_port_set_vlan_map(struct mv88e6xxx_chip *chip, int port, u16 map) { - const u16 mask = GENMASK(mv88e6xxx_num_ports(chip) - 1, 0); + const u16 mask = mv88e6xxx_port_mask(chip); u16 reg; int err; -- 2.12.0
[PATCH net-next v2 11/17] net: dsa: mv88e6xxx: rename the port vector member
Not all Marvell switch chips support port trunking, which is embedded in the port vector data for ATU operations. Rename the portv_trunkid member of the mv88e6xxx_atu_entry structure to portvec to be more concise and consistent with the different chips. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn --- drivers/net/dsa/mv88e6xxx/chip.c| 8 drivers/net/dsa/mv88e6xxx/global1_atu.c | 8 drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index df31c2c57e09..e9533d4919bc 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1928,11 +1928,11 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port, /* Purge the ATU entry only if no port is using it anymore */ if (state == GLOBAL_ATU_DATA_STATE_UNUSED) { - entry.portv_trunkid &= ~BIT(port); - if (!entry.portv_trunkid) + entry.portvec &= ~BIT(port); + if (!entry.portvec) entry.state = GLOBAL_ATU_DATA_STATE_UNUSED; } else { - entry.portv_trunkid |= BIT(port); + entry.portvec |= BIT(port); entry.state = state; } @@ -1995,7 +1995,7 @@ static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip, if (addr.state == GLOBAL_ATU_DATA_STATE_UNUSED) break; - if (addr.trunk || (addr.portv_trunkid & BIT(port)) == 0) + if (addr.trunk || (addr.portvec & BIT(port)) == 0) continue; if (obj->id == SWITCHDEV_OBJ_ID_PORT_FDB) { diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c index d753e3eb1359..120b7f41a735 100644 --- a/drivers/net/dsa/mv88e6xxx/global1_atu.c +++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c @@ -124,7 +124,7 @@ static int mv88e6xxx_g1_atu_data_read(struct mv88e6xxx_chip *chip, if (val & GLOBAL_ATU_DATA_TRUNK) entry->trunk = true; - entry->portv_trunkid = (val >> 4) & mv88e6xxx_port_mask(chip); + entry->portvec = (val >> 4) & mv88e6xxx_port_mask(chip); } return 0; @@ -139,7 +139,7 @@ static int mv88e6xxx_g1_atu_data_write(struct mv88e6xxx_chip *chip, if (entry->trunk) data |= GLOBAL_ATU_DATA_TRUNK; - data |= (entry->portv_trunkid & mv88e6xxx_port_mask(chip)) << 4; + data |= (entry->portvec & mv88e6xxx_port_mask(chip)) << 4; } return mv88e6xxx_g1_write(chip, GLOBAL_ATU_DATA, data); @@ -284,8 +284,8 @@ static int mv88e6xxx_g1_atu_move(struct mv88e6xxx_chip *chip, u16 fid, shift = bitmap_weight(&mask, 16); entry.state = 0xf, /* Full EntryState means Move */ - entry.portv_trunkid = from_port & mask; - entry.portv_trunkid |= (to_port & mask) << shift; + entry.portvec = from_port & mask; + entry.portvec |= (to_port & mask) << shift; return mv88e6xxx_g1_atu_flushmove(chip, fid, &entry, all); } diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h index 1fca6fae2f83..69acb4c40fdc 100644 --- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h @@ -713,7 +713,7 @@ struct mv88e6xxx_info { struct mv88e6xxx_atu_entry { u8 state; booltrunk; - u16 portv_trunkid; + u16 portvec; u8 mac[ETH_ALEN]; }; -- 2.12.0
[PATCH net-next v2 16/17] net: dsa: mv88e6xxx: add port priority override op
Add a new operation to disable the DA, SA and VTU priority override. Setting such limit is not likely to be used soon, so provide a port_disable_pri_override operation directly. This can be changed later for port_set_pri_override when we'll need it. Also remove the now obsolete mv88e6xxx_6320_family helper. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn --- drivers/net/dsa/mv88e6xxx/chip.c | 39 +++ drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 1 + drivers/net/dsa/mv88e6xxx/port.c | 7 +++ drivers/net/dsa/mv88e6xxx/port.h | 1 + 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 06fe86309e27..3354f99df378 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -687,11 +687,6 @@ static bool mv88e6xxx_6165_family(struct mv88e6xxx_chip *chip) return chip->info->family == MV88E6XXX_FAMILY_6165; } -static bool mv88e6xxx_6320_family(struct mv88e6xxx_chip *chip) -{ - return chip->info->family == MV88E6XXX_FAMILY_6320; -} - static bool mv88e6xxx_6341_family(struct mv88e6xxx_chip *chip) { return chip->info->family == MV88E6XXX_FAMILY_6341; @@ -2407,14 +2402,8 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) return err; } - if (mv88e6xxx_6352_family(chip) || mv88e6xxx_6351_family(chip) || - mv88e6xxx_6165_family(chip) || mv88e6xxx_6097_family(chip) || - mv88e6xxx_6320_family(chip) || mv88e6xxx_6341_family(chip)) { - /* Priority Override: disable DA, SA and VTU priority -* override. -*/ - err = mv88e6xxx_port_write(chip, port, PORT_PRI_OVERRIDE, - 0x); + if (chip->info->ops->port_disable_pri_override) { + err = chip->info->ops->port_disable_pri_override(chip, port); if (err) return err; } @@ -2840,6 +2829,7 @@ static const struct mv88e6xxx_ops mv88e6085_ops = { .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, .port_pause_config = mv88e6097_port_pause_config, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, + .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .stats_snapshot = mv88e6xxx_g1_stats_snapshot, .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, @@ -2890,6 +2880,7 @@ static const struct mv88e6xxx_ops mv88e6097_ops = { .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, .port_pause_config = mv88e6097_port_pause_config, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, + .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .stats_snapshot = mv88e6xxx_g1_stats_snapshot, .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, @@ -2912,6 +2903,7 @@ static const struct mv88e6xxx_ops mv88e6123_ops = { .port_set_frame_mode = mv88e6085_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, + .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .stats_snapshot = mv88e6xxx_g1_stats_snapshot, .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, @@ -2968,6 +2960,7 @@ static const struct mv88e6xxx_ops mv88e6161_ops = { .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, .port_pause_config = mv88e6097_port_pause_config, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, + .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .stats_snapshot = mv88e6xxx_g1_stats_snapshot, .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, @@ -2988,6 +2981,7 @@ static const struct mv88e6xxx_ops mv88e6165_ops = { .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_speed = mv88e6185_port_set_speed, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, + .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .stats_snapshot = mv88e6xxx_g1_stats_snapshot, .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, @@ -3016,6 +3010,7 @@ static const struct mv88e6xxx_ops mv88e6171_ops = { .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, .port_pause_config = mv88e6097_port_pause_config, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, + .port_disable_pri_ove
[PATCH net-next v2 04/17] net: dsa: mv88e6xxx: setup message ports
All interconnectable Marvell switch chips have an ATU Learn2All feature which allows newly learnt addresses to be spanned on ports marked as "Message Port". This commit configures the DSA ports as Message Port. Note that this has no effect until the Learn2All feature is enabled. Signed-off-by: Vivien Didelot --- drivers/net/dsa/mv88e6xxx/chip.c | 12 drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 1 + drivers/net/dsa/mv88e6xxx/port.c | 18 ++ drivers/net/dsa/mv88e6xxx/port.h | 2 ++ 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 0ad8200f3321..5c1b5825fe6c 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2504,6 +2504,13 @@ static int mv88e6xxx_setup_port_normal(struct mv88e6xxx_chip *chip, int port) return chip->info->ops->port_set_egress_unknowns(chip, port, false); } +static int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port) +{ + bool message = dsa_is_dsa_port(chip->ds, port); + + return mv88e6xxx_port_set_message_port(chip, port, message); +} + static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) { struct dsa_switch *ds = chip->ds; @@ -2658,10 +2665,7 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) return err; } - /* Port Control 1: disable trunking, disable sending -* learning messages to this port. -*/ - err = mv88e6xxx_port_write(chip, port, PORT_CONTROL_1, 0x); + err = mv88e6xxx_setup_message_port(chip, port); if (err) return err; diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h index 166b513ff751..45205519b9fe 100644 --- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h @@ -144,6 +144,7 @@ #define PORT_CONTROL_STATE_LEARNING0x02 #define PORT_CONTROL_STATE_FORWARDING 0x03 #define PORT_CONTROL_1 0x05 +#define PORT_CONTROL_1_MESSAGE_PORTBIT(15) #define PORT_CONTROL_1_FID_11_4_MASK (0xff << 0) #define PORT_BASE_VLAN 0x06 #define PORT_BASE_VLAN_FID_3_0_MASK(0xf << 12) diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 9bb0f2134cba..40fe48188056 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -535,6 +535,24 @@ int mv88e6351_port_set_egress_unknowns(struct mv88e6xxx_chip *chip, int port, /* Offset 0x05: Port Control 1 */ +int mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip *chip, int port, + bool message_port) +{ + u16 val; + int err; + + err = mv88e6xxx_port_read(chip, port, PORT_CONTROL_1, &val); + if (err) + return err; + + if (message_port) + val |= PORT_CONTROL_1_MESSAGE_PORT; + else + val &= ~PORT_CONTROL_1_MESSAGE_PORT; + + return mv88e6xxx_port_write(chip, port, PORT_CONTROL_1, val); +} + /* Offset 0x06: Port Based VLAN Map */ int mv88e6xxx_port_set_vlan_map(struct mv88e6xxx_chip *chip, int port, u16 map) diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index c83cbb3f4491..4328d6f29d4d 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -64,6 +64,8 @@ int mv88e6351_port_set_egress_unknowns(struct mv88e6xxx_chip *chip, int port, bool on); int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port, u16 etype); +int mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip *chip, int port, + bool message_port); int mv88e6165_port_jumbo_config(struct mv88e6xxx_chip *chip, int port); int mv88e6095_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port); int mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port); -- 2.12.0
[PATCH net-next v2 09/17] net: dsa: mv88e6xxx: rework ATU Remove
Add a fresh documented implementation of the ATU Move operation, and use it to replace the current ATU Remove operation. Note that not all Marvell switch chip support the ATU Move operation. For those supporting it, the number of bits used to mask the destination port may vary. 6352 and such use 4-bit, while 6390 use 5-bit. Thus add a new atu_move_port_mask member in the info structure to describe the presence and variant of ATU Move operation. Note that the ATU Move operation is not documented in the 6185 datasheet but the chip does support the operation. All remaining _mv88e6xxx_atu_* functions are now unused as well as the MV88E6XXX_FLAG_G1_ATU_FID flag, thus remove them. Signed-off-by: Vivien Didelot --- drivers/net/dsa/mv88e6xxx/chip.c| 140 +++- drivers/net/dsa/mv88e6xxx/global1.h | 2 + drivers/net/dsa/mv88e6xxx/global1_atu.c | 29 +++ drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 18 ++-- 4 files changed, 67 insertions(+), 122 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 8b8c3cb167c1..a11e5354f14f 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1066,11 +1066,6 @@ static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port, mutex_unlock(&chip->reg_lock); } -static int _mv88e6xxx_atu_wait(struct mv88e6xxx_chip *chip) -{ - return mv88e6xxx_g1_wait(chip, GLOBAL_ATU_OP, GLOBAL_ATU_OP_BUSY); -} - static int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) { @@ -1130,111 +1125,6 @@ static int mv88e6xxx_set_eee(struct dsa_switch *ds, int port, return err; } -static int _mv88e6xxx_atu_cmd(struct mv88e6xxx_chip *chip, u16 fid, u16 cmd) -{ - u16 val; - int err; - - if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G1_ATU_FID)) { - err = mv88e6xxx_g1_write(chip, GLOBAL_ATU_FID, fid); - if (err) - return err; - } else if (mv88e6xxx_num_databases(chip) == 256) { - /* ATU DBNum[7:4] are located in ATU Control 15:12 */ - err = mv88e6xxx_g1_read(chip, GLOBAL_ATU_CONTROL, &val); - if (err) - return err; - - err = mv88e6xxx_g1_write(chip, GLOBAL_ATU_CONTROL, -(val & 0xfff) | ((fid << 8) & 0xf000)); - if (err) - return err; - - /* ATU DBNum[3:0] are located in ATU Operation 3:0 */ - cmd |= fid & 0xf; - } - - err = mv88e6xxx_g1_write(chip, GLOBAL_ATU_OP, cmd); - if (err) - return err; - - return _mv88e6xxx_atu_wait(chip); -} - -static int _mv88e6xxx_atu_data_write(struct mv88e6xxx_chip *chip, -struct mv88e6xxx_atu_entry *entry) -{ - u16 data = entry->state & GLOBAL_ATU_DATA_STATE_MASK; - - if (entry->state != GLOBAL_ATU_DATA_STATE_UNUSED) { - unsigned int mask, shift; - - if (entry->trunk) { - data |= GLOBAL_ATU_DATA_TRUNK; - mask = GLOBAL_ATU_DATA_TRUNK_ID_MASK; - shift = GLOBAL_ATU_DATA_TRUNK_ID_SHIFT; - } else { - mask = GLOBAL_ATU_DATA_PORT_VECTOR_MASK; - shift = GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT; - } - - data |= (entry->portv_trunkid << shift) & mask; - } - - return mv88e6xxx_g1_write(chip, GLOBAL_ATU_DATA, data); -} - -static int _mv88e6xxx_atu_flush_move(struct mv88e6xxx_chip *chip, -struct mv88e6xxx_atu_entry *entry, -bool static_too) -{ - int op; - int err; - - err = _mv88e6xxx_atu_wait(chip); - if (err) - return err; - - err = _mv88e6xxx_atu_data_write(chip, entry); - if (err) - return err; - - if (entry->fid) { - op = static_too ? GLOBAL_ATU_OP_FLUSH_MOVE_ALL_DB : - GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC_DB; - } else { - op = static_too ? GLOBAL_ATU_OP_FLUSH_MOVE_ALL : - GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC; - } - - return _mv88e6xxx_atu_cmd(chip, entry->fid, op); -} - -static int _mv88e6xxx_atu_move(struct mv88e6xxx_chip *chip, u16 fid, - int from_port, int to_port, bool static_too) -{ - struct mv88e6xxx_atu_entry entry = { - .trunk = false, - .fid = fid, - }; - - /* EntryState bits must be 0xF */ - entry.state = GLOBAL_ATU_DATA_STATE_MASK; - - /* ToPort and FromPort are respectively in PortVec bits 7:4 and 3:0 */ - entry.portv_trunkid = (to_port & 0x0f) << 4; - entry.portv_trunkid |= from_port & 0x0f; - - return _mv88e6xxx_atu_flush_mo
[PATCH net-next v2 00/17] net: dsa: mv88e6xxx: rework ATU support
The purpose of this patch series is to rework the code related to the Address Translation Unit (ATU), and bring support for it to the 88E6390 family of switch chips. All Global (1) ATU related code have been reworked and moved to its own file. Some port related bits used for ATU configuration (such as the Learn2All and MessagePort feature) have also been taken care of. The ports' mode and egress flooding mode have been refactored to fix the egress of frames with unknown unicast or multicast destination address, and write all these bits regardless the port mode (Normal, DSA, etc.) Finally remove the eth_addr_greater which was only used by mv88e6xxx. Changes in v2: - add Reviewed-by tags - split mv88e6xxx_g1_atu_set_age_time and mv88e6xxx_atu_setup addition - remove DSA_TAG_PROTO_TRAILER check - split Message Port and Learn2All addition - remove unused MV88E6XXX_FLAG_G1_ATU_FID flag - add dsa_is_normal_port helper Vivien Didelot (17): net: dsa: mv88e6xxx: add port mask helper net: dsa: mv88e6xxx: move ATU ageing time setter net: dsa: mv88e6xxx: add ATU setup helper net: dsa: mv88e6xxx: setup message ports net: dsa: mv88e6xxx: enable ATU Learn2All net: dsa: mv88e6xxx: rework ATU Load/Purge net: dsa: mv88e6xxx: rework ATU GetNext net: dsa: mv88e6xxx: rework ATU Flush net: dsa: mv88e6xxx: rework ATU Remove net: dsa: mv88e6xxx: rename new FID helper net: dsa: mv88e6xxx: rename the port vector member net: dsa: add dsa_is_normal_port helper net: dsa: mv88e6xxx: rework port mode setup net: dsa: mv88e6xxx: fix port egress flooding mode net: dsa: mv88e6xxx: add port ATU learn limit op net: dsa: mv88e6xxx: add port priority override op etherdevice: remove unused eth_addr_greater drivers/net/dsa/mv88e6xxx/Makefile | 1 + drivers/net/dsa/mv88e6xxx/chip.c| 667 +++- drivers/net/dsa/mv88e6xxx/global1.h | 11 + drivers/net/dsa/mv88e6xxx/global1_atu.c | 300 ++ drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 44 ++- drivers/net/dsa/mv88e6xxx/port.c| 78 +++- drivers/net/dsa/mv88e6xxx/port.h| 16 +- include/linux/etherdevice.h | 15 - include/net/dsa.h | 5 + 9 files changed, 638 insertions(+), 499 deletions(-) create mode 100644 drivers/net/dsa/mv88e6xxx/global1_atu.c -- 2.12.0
[PATCH net-next v2 07/17] net: dsa: mv88e6xxx: rework ATU GetNext
Add and use a fresh documented implementation of the ATU GetNext. Since it is not necessary to write the MAC address to iterate from, only do it once directly in the ATU GetNext operation, if the provided ATU entry structure is not valid. This makes the user code simpler. Also, there is no need to loop when getting a single ATU entry. So remove the mv88e6xxx_atu_get helper and add a simpler snippet in mv88e6xxx_port_db_load_purge to lookup a given MAC address. The _mv88e6xxx_atu_mac_{read,write} are not used anymore thus remove them. _mv88e6xxx_atu_data_{read,write} are still used so keep them. Signed-off-by: Vivien Didelot --- drivers/net/dsa/mv88e6xxx/chip.c| 140 drivers/net/dsa/mv88e6xxx/global1.h | 2 + drivers/net/dsa/mv88e6xxx/global1_atu.c | 66 +++ 3 files changed, 84 insertions(+), 124 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 95dbf581b54a..2d1ec0d79fb6 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2012,76 +2012,6 @@ static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, return err; } -static int _mv88e6xxx_atu_mac_write(struct mv88e6xxx_chip *chip, - const unsigned char *addr) -{ - int i, err; - - for (i = 0; i < 3; i++) { - err = mv88e6xxx_g1_write(chip, GLOBAL_ATU_MAC_01 + i, -(addr[i * 2] << 8) | addr[i * 2 + 1]); - if (err) - return err; - } - - return 0; -} - -static int _mv88e6xxx_atu_mac_read(struct mv88e6xxx_chip *chip, - unsigned char *addr) -{ - u16 val; - int i, err; - - for (i = 0; i < 3; i++) { - err = mv88e6xxx_g1_read(chip, GLOBAL_ATU_MAC_01 + i, &val); - if (err) - return err; - - addr[i * 2] = val >> 8; - addr[i * 2 + 1] = val & 0xff; - } - - return 0; -} - -static int _mv88e6xxx_atu_getnext(struct mv88e6xxx_chip *chip, u16 fid, - struct mv88e6xxx_atu_entry *entry); - -static int mv88e6xxx_atu_get(struct mv88e6xxx_chip *chip, int fid, -const u8 *addr, struct mv88e6xxx_atu_entry *entry) -{ - struct mv88e6xxx_atu_entry next; - int err; - - memcpy(next.mac, addr, ETH_ALEN); - eth_addr_dec(next.mac); - - err = _mv88e6xxx_atu_mac_write(chip, next.mac); - if (err) - return err; - - do { - err = _mv88e6xxx_atu_getnext(chip, fid, &next); - if (err) - return err; - - if (next.state == GLOBAL_ATU_DATA_STATE_UNUSED) - break; - - if (ether_addr_equal(next.mac, addr)) { - *entry = next; - return 0; - } - } while (ether_addr_greater(addr, next.mac)); - - memset(entry, 0, sizeof(*entry)); - entry->fid = fid; - ether_addr_copy(entry->mac, addr); - - return 0; -} - static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port, const unsigned char *addr, u16 vid, u8 state) @@ -2098,10 +2028,21 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port, if (err) return err; - err = mv88e6xxx_atu_get(chip, vlan.fid, addr, &entry); + entry.state = GLOBAL_ATU_DATA_STATE_UNUSED; + ether_addr_copy(entry.mac, addr); + eth_addr_dec(entry.mac); + + err = mv88e6xxx_g1_atu_getnext(chip, vlan.fid, &entry); if (err) return err; + /* Initialize a fresh ATU entry if it isn't found */ + if (entry.state == GLOBAL_ATU_DATA_STATE_UNUSED || + !ether_addr_equal(entry.mac, addr)) { + memset(&entry, 0, sizeof(entry)); + ether_addr_copy(entry.mac, addr); + } + /* Purge the ATU entry only if no port is using it anymore */ if (state == GLOBAL_ATU_DATA_STATE_UNUSED) { entry.portv_trunkid &= ~BIT(port); @@ -2152,68 +2093,19 @@ static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, return err; } -static int _mv88e6xxx_atu_getnext(struct mv88e6xxx_chip *chip, u16 fid, - struct mv88e6xxx_atu_entry *entry) -{ - struct mv88e6xxx_atu_entry next = { 0 }; - u16 val; - int err; - - next.fid = fid; - - err = _mv88e6xxx_atu_wait(chip); - if (err) - return err; - - err = _mv88e6xxx_atu_cmd(chip, fid, GLOBAL_ATU_OP_GET_NEXT_DB); - if (err) - return err; - - err = _mv88e6xxx_atu_mac_read(chip, next.mac); - if (err) - return err
[PATCH net-next v2 12/17] net: dsa: add dsa_is_normal_port helper
Introduce a dsa_is_normal_port helper to check if a given port is a normal user port as opposed to a CPU port or DSA link. Signed-off-by: Vivien Didelot --- include/net/dsa.h | 5 + 1 file changed, 5 insertions(+) diff --git a/include/net/dsa.h b/include/net/dsa.h index 4e13e695f025..bf0e42c2a6f7 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -248,6 +248,11 @@ static inline bool dsa_is_dsa_port(struct dsa_switch *ds, int p) return !!((ds->dsa_port_mask) & (1 << p)); } +static inline bool dsa_is_normal_port(struct dsa_switch *ds, int p) +{ + return !dsa_is_cpu_port(ds, p) && !dsa_is_dsa_port(ds, p); +} + static inline bool dsa_is_port_initialized(struct dsa_switch *ds, int p) { return ds->enabled_port_mask & (1 << p) && ds->ports[p].netdev; -- 2.12.0
[PATCH net-next v2 15/17] net: dsa: mv88e6xxx: add port ATU learn limit op
Add a new operation to disable the limiting of learnt MAC addresses. Setting such limit is not likely to be used soon, so provide a port_disable_learn_limit operation directly. This can be changed later for port_set_learn_limit when we'll need it. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn --- drivers/net/dsa/mv88e6xxx/chip.c | 36 +-- drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 1 + drivers/net/dsa/mv88e6xxx/port.c | 7 +++ drivers/net/dsa/mv88e6xxx/port.h | 3 +++ 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 0844df1b25e9..06fe86309e27 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2401,15 +2401,15 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) return err; } + if (chip->info->ops->port_disable_learn_limit) { + err = chip->info->ops->port_disable_learn_limit(chip, port); + if (err) + return err; + } + if (mv88e6xxx_6352_family(chip) || mv88e6xxx_6351_family(chip) || mv88e6xxx_6165_family(chip) || mv88e6xxx_6097_family(chip) || mv88e6xxx_6320_family(chip) || mv88e6xxx_6341_family(chip)) { - /* Port ATU control: disable limiting the number of -* address database entries that this port is allowed -* to use. -*/ - err = mv88e6xxx_port_write(chip, port, PORT_ATU_CONTROL, - 0x); /* Priority Override: disable DA, SA and VTU priority * override. */ @@ -2839,6 +2839,7 @@ static const struct mv88e6xxx_ops mv88e6085_ops = { .port_set_ether_type = mv88e6351_port_set_ether_type, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, .port_pause_config = mv88e6097_port_pause_config, + .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .stats_snapshot = mv88e6xxx_g1_stats_snapshot, .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, @@ -2888,6 +2889,7 @@ static const struct mv88e6xxx_ops mv88e6097_ops = { .port_jumbo_config = mv88e6165_port_jumbo_config, .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, .port_pause_config = mv88e6097_port_pause_config, + .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .stats_snapshot = mv88e6xxx_g1_stats_snapshot, .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, @@ -2909,6 +2911,7 @@ static const struct mv88e6xxx_ops mv88e6123_ops = { .port_set_speed = mv88e6185_port_set_speed, .port_set_frame_mode = mv88e6085_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, + .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .stats_snapshot = mv88e6xxx_g1_stats_snapshot, .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, @@ -2964,6 +2967,7 @@ static const struct mv88e6xxx_ops mv88e6161_ops = { .port_jumbo_config = mv88e6165_port_jumbo_config, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, .port_pause_config = mv88e6097_port_pause_config, + .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .stats_snapshot = mv88e6xxx_g1_stats_snapshot, .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, @@ -2983,6 +2987,7 @@ static const struct mv88e6xxx_ops mv88e6165_ops = { .port_set_link = mv88e6xxx_port_set_link, .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_speed = mv88e6185_port_set_speed, + .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .stats_snapshot = mv88e6xxx_g1_stats_snapshot, .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, @@ -3010,6 +3015,7 @@ static const struct mv88e6xxx_ops mv88e6171_ops = { .port_jumbo_config = mv88e6165_port_jumbo_config, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, .port_pause_config = mv88e6097_port_pause_config, + .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .stats_snapshot = mv88e6320_g1_stats_snapshot, .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, @@ -3039,6 +3045,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = { .port_jumbo_config = mv88e6165_port_jumbo_config, .port_egress_rate_limiting =
[PATCH net-next v2 05/17] net: dsa: mv88e6xxx: enable ATU Learn2All
The ATU Learn2All feature allows newly learnt addresses to be spanned on ports marked as "Message Port", currently all DSA ports. This commit enables this feature which is necessary and quite convenient for multi-chip switch fabrics. Signed-off-by: Vivien Didelot --- drivers/net/dsa/mv88e6xxx/chip.c| 15 ++- drivers/net/dsa/mv88e6xxx/global1.h | 1 + drivers/net/dsa/mv88e6xxx/global1_atu.c | 17 + 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 5c1b5825fe6c..1ee0c05f624e 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1308,6 +1308,12 @@ static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port, static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip) { + int err; + + err = mv88e6xxx_g1_atu_set_learn2all(chip, true); + if (err) + return err; + return mv88e6xxx_g1_atu_set_age_time(chip, 30); } @@ -2756,15 +2762,6 @@ static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip) if (err < 0) return err; - /* Set the default address aging time to 5 minutes, and -* enable address learn messages to be sent to all message -* ports. -*/ - err = mv88e6xxx_g1_write(chip, GLOBAL_ATU_CONTROL, -GLOBAL_ATU_CONTROL_LEARN2ALL); - if (err) - return err; - /* Clear all ATU entries */ err = _mv88e6xxx_atu_flush(chip, 0, true); if (err) diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h index b8d0fb519bab..18322d05225a 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.h +++ b/drivers/net/dsa/mv88e6xxx/global1.h @@ -38,6 +38,7 @@ int mv88e6095_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port); int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port); int mv88e6390_g1_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip); +int mv88e6xxx_g1_atu_set_learn2all(struct mv88e6xxx_chip *chip, bool learn2all); int mv88e6xxx_g1_atu_set_age_time(struct mv88e6xxx_chip *chip, unsigned int msecs); diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c index 4d0ada9efc6d..843a21e05f7b 100644 --- a/drivers/net/dsa/mv88e6xxx/global1_atu.c +++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c @@ -15,6 +15,23 @@ /* Offset 0x0A: ATU Control Register */ +int mv88e6xxx_g1_atu_set_learn2all(struct mv88e6xxx_chip *chip, bool learn2all) +{ + u16 val; + int err; + + err = mv88e6xxx_g1_read(chip, GLOBAL_ATU_CONTROL, &val); + if (err) + return err; + + if (learn2all) + val |= GLOBAL_ATU_CONTROL_LEARN2ALL; + else + val &= ~GLOBAL_ATU_CONTROL_LEARN2ALL; + + return mv88e6xxx_g1_write(chip, GLOBAL_ATU_CONTROL, val); +} + int mv88e6xxx_g1_atu_set_age_time(struct mv88e6xxx_chip *chip, unsigned int msecs) { -- 2.12.0
[PATCH net-next v2 08/17] net: dsa: mv88e6xxx: rework ATU Flush
Add a fresh documented implementation of the ATU Flush/Move operation. Use it to replace the current ATU Flush operation. _mv88e6xxx_atu_flush_move is still used by the Move operation so keep it until the Move operation is refactored in a next commit. Signed-off-by: Vivien Didelot --- drivers/net/dsa/mv88e6xxx/chip.c| 22 +--- drivers/net/dsa/mv88e6xxx/global1.h | 1 + drivers/net/dsa/mv88e6xxx/global1_atu.c | 37 + 3 files changed, 43 insertions(+), 17 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 2d1ec0d79fb6..8b8c3cb167c1 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1210,17 +1210,6 @@ static int _mv88e6xxx_atu_flush_move(struct mv88e6xxx_chip *chip, return _mv88e6xxx_atu_cmd(chip, entry->fid, op); } -static int _mv88e6xxx_atu_flush(struct mv88e6xxx_chip *chip, - u16 fid, bool static_too) -{ - struct mv88e6xxx_atu_entry entry = { - .fid = fid, - .state = 0, /* EntryState bits must be 0 */ - }; - - return _mv88e6xxx_atu_flush_move(chip, &entry, static_too); -} - static int _mv88e6xxx_atu_move(struct mv88e6xxx_chip *chip, u16 fid, int from_port, int to_port, bool static_too) { @@ -1310,6 +1299,10 @@ static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip) { int err; + err = mv88e6xxx_g1_atu_flush(chip, 0, true); + if (err) + return err; + err = mv88e6xxx_g1_atu_set_learn2all(chip, true); if (err) return err; @@ -1714,7 +1707,7 @@ static int _mv88e6xxx_fid_new(struct mv88e6xxx_chip *chip, u16 *fid) return -ENOSPC; /* Clear the database */ - return _mv88e6xxx_atu_flush(chip, *fid, true); + return mv88e6xxx_g1_atu_flush(chip, *fid, true); } static int _mv88e6xxx_vtu_new(struct mv88e6xxx_chip *chip, u16 vid, @@ -2634,11 +2627,6 @@ static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip) if (err < 0) return err; - /* Clear all ATU entries */ - err = _mv88e6xxx_atu_flush(chip, 0, true); - if (err) - return err; - /* Configure the IP ToS mapping registers. */ err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_0, 0x); if (err) diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h index 8dd8ecc9f064..187acfc8ed37 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.h +++ b/drivers/net/dsa/mv88e6xxx/global1.h @@ -45,5 +45,6 @@ int mv88e6xxx_g1_atu_getnext(struct mv88e6xxx_chip *chip, u16 fid, struct mv88e6xxx_atu_entry *entry); int mv88e6xxx_g1_atu_loadpurge(struct mv88e6xxx_chip *chip, u16 fid, struct mv88e6xxx_atu_entry *entry); +int mv88e6xxx_g1_atu_flush(struct mv88e6xxx_chip *chip, u16 fid, bool all); #endif /* _MV88E6XXX_GLOBAL1_H */ diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c index 94e940522849..7ec9b22feaee 100644 --- a/drivers/net/dsa/mv88e6xxx/global1_atu.c +++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c @@ -232,3 +232,40 @@ int mv88e6xxx_g1_atu_loadpurge(struct mv88e6xxx_chip *chip, u16 fid, return mv88e6xxx_g1_atu_op(chip, fid, GLOBAL_ATU_OP_LOAD_DB); } + +static int mv88e6xxx_g1_atu_flushmove(struct mv88e6xxx_chip *chip, u16 fid, + struct mv88e6xxx_atu_entry *entry, + bool all) +{ + u16 op; + int err; + + err = mv88e6xxx_g1_atu_op_wait(chip); + if (err) + return err; + + err = mv88e6xxx_g1_atu_data_write(chip, entry); + if (err) + return err; + + /* Flush/Move all or non-static entries from all or a given database */ + if (all && fid) + op = GLOBAL_ATU_OP_FLUSH_MOVE_ALL_DB; + else if (fid) + op = GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC_DB; + else if (all) + op = GLOBAL_ATU_OP_FLUSH_MOVE_ALL; + else + op = GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC; + + return mv88e6xxx_g1_atu_op(chip, fid, op); +} + +int mv88e6xxx_g1_atu_flush(struct mv88e6xxx_chip *chip, u16 fid, bool all) +{ + struct mv88e6xxx_atu_entry entry = { + .state = 0, /* Null EntryState means Flush */ + }; + + return mv88e6xxx_g1_atu_flushmove(chip, fid, &entry, all); +} -- 2.12.0
[PATCH net-next v2 14/17] net: dsa: mv88e6xxx: fix port egress flooding mode
The Marvell switch ports can be configured to allow or prevent egress of frames with an unknown unicast or multicast destination address. Some switch chips such as 88E6095 and 88E6185 have two disjoint bits in Port Control Register (0x04) bit 2 "Forward Unknown" (for unicast) and Port Control 2 Register (0x08) bit 6 "Default Forward" (for multicast). Other chips such as 88E6085, 88E6123, 88E6352, and 88E6390 have a 2-bit value in Port Control Register (0x04) bits 3:2 "EgressFloods". The current code does not fully implement the disjoint bits variant and assigns incorrect ones to some chip models. Fix that with two implementation references (6185 and 6352 that I currently have) of a port_set_egress_floods operation (as named in datasheets). Old chips such as 88E6060 don't have egress flooding mode, so don't error out if the operation is not provided. Signed-off-by: Vivien Didelot --- drivers/net/dsa/mv88e6xxx/chip.c | 111 +- drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 15 +++-- drivers/net/dsa/mv88e6xxx/port.c | 44 ++ drivers/net/dsa/mv88e6xxx/port.h | 10 ++- 4 files changed, 84 insertions(+), 96 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 5f5023215ce1..0844df1b25e9 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2261,23 +2261,6 @@ static int mv88e6xxx_setup_port_mode(struct mv88e6xxx_chip *chip, int port) return -EINVAL; } -static int mv88e6xxx_setup_port_dsa(struct mv88e6xxx_chip *chip, int port, - int upstream_port) -{ - return chip->info->ops->port_set_egress_unknowns( - chip, port, port == upstream_port); -} - -static int mv88e6xxx_setup_port_cpu(struct mv88e6xxx_chip *chip, int port) -{ - return chip->info->ops->port_set_egress_unknowns(chip, port, true); -} - -static int mv88e6xxx_setup_port_normal(struct mv88e6xxx_chip *chip, int port) -{ - return chip->info->ops->port_set_egress_unknowns(chip, port, false); -} - static int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port) { bool message = dsa_is_dsa_port(chip->ds, port); @@ -2285,6 +2268,18 @@ static int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port) return mv88e6xxx_port_set_message_port(chip, port, message); } +static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port) +{ + bool flood = port == dsa_upstream_port(chip->ds); + + /* Upstream ports flood frames with unknown unicast or multicast DA */ + if (chip->info->ops->port_set_egress_floods) + return chip->info->ops->port_set_egress_floods(chip, port, + flood, flood); + + return 0; +} + static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) { struct dsa_switch *ds = chip->ds; @@ -2327,21 +2322,14 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) if (err) return err; - if (dsa_is_cpu_port(ds, port)) { - err = mv88e6xxx_setup_port_cpu(chip, port); - } else if (dsa_is_dsa_port(ds, port)) { - err = mv88e6xxx_setup_port_dsa(chip, port, - dsa_upstream_port(ds)); - } else { - err = mv88e6xxx_setup_port_normal(chip, port); - } - if (err) - return err; - err = mv88e6xxx_setup_port_mode(chip, port); if (err) return err; + err = mv88e6xxx_setup_egress_floods(chip, port); + if (err) + return err; + /* If this port is connected to a SerDes, make sure the SerDes is not * powered down. */ @@ -2847,7 +2835,7 @@ static const struct mv88e6xxx_ops mv88e6085_ops = { .port_set_speed = mv88e6185_port_set_speed, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, - .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns, + .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_ether_type = mv88e6351_port_set_ether_type, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, .port_pause_config = mv88e6097_port_pause_config, @@ -2873,7 +2861,7 @@ static const struct mv88e6xxx_ops mv88e6095_ops = { .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_speed = mv88e6185_port_set_speed, .port_set_frame_mode = mv88e6085_port_set_frame_mode, - .port_set_egress_unknowns = mv88e6095_port_set_egress_unknowns, + .port_set_egress_floods = mv88e6185_port_set_egress_floods, .port_set_upstream_port = mv88e6095_port_set_upstream_port, .stats_snapshot = mv88e6xxx_g1_stats_snapshot, .stats_get_sset_count = mv88e6095_stats_get_sset_co
[PATCH v2] net: tun: use new api ethtool_{get|set}_link_ksettings
The ethtool api {get|set}_settings is deprecated. We move this driver to new api {get|set}_link_ksettings. Signed-off-by: Philippe Reynes --- Changelog: v2: - Finaly, I've found the hardware and do basic test ;) thanks Michael S. Tsirkin and Eric Dumazet for the feedback drivers/net/tun.c | 24 +++- 1 files changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index dc1b1dd..c418f0a 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -2430,18 +2430,16 @@ static void tun_chr_show_fdinfo(struct seq_file *m, struct file *f) /* ethtool interface */ -static int tun_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - cmd->supported = 0; - cmd->advertising= 0; - ethtool_cmd_speed_set(cmd, SPEED_10); - cmd->duplex = DUPLEX_FULL; - cmd->port = PORT_TP; - cmd->phy_address= 0; - cmd->transceiver= XCVR_INTERNAL; - cmd->autoneg= AUTONEG_DISABLE; - cmd->maxtxpkt = 0; - cmd->maxrxpkt = 0; +static int tun_get_link_ksettings(struct net_device *dev, + struct ethtool_link_ksettings *cmd) +{ + ethtool_link_ksettings_zero_link_mode(cmd, supported); + ethtool_link_ksettings_zero_link_mode(cmd, advertising); + cmd->base.speed = SPEED_10; + cmd->base.duplex= DUPLEX_FULL; + cmd->base.port = PORT_TP; + cmd->base.phy_address = 0; + cmd->base.autoneg = AUTONEG_DISABLE; return 0; } @@ -2504,7 +2502,6 @@ static int tun_set_coalesce(struct net_device *dev, } static const struct ethtool_ops tun_ethtool_ops = { - .get_settings = tun_get_settings, .get_drvinfo= tun_get_drvinfo, .get_msglevel = tun_get_msglevel, .set_msglevel = tun_set_msglevel, @@ -2512,6 +2509,7 @@ static int tun_set_coalesce(struct net_device *dev, .get_ts_info= ethtool_op_get_ts_info, .get_coalesce = tun_get_coalesce, .set_coalesce = tun_set_coalesce, + .get_link_ksettings = tun_get_link_ksettings, }; static int tun_queue_resize(struct tun_struct *tun) -- 1.7.4.4
Re: [PATCH net-next 04/14] net: dsa: mv88e6xxx: rework ATU Load/Purge
Hi Andrew, Andrew Lunn writes: > On Thu, Mar 09, 2017 at 06:33:14PM -0500, Vivien Didelot wrote: >> All Marvell switch chips have an ATU accessed using the same Global (1) >> register layout. Only the handling of the FID differs as more bits were >> necessary to support more and more databases. >> >> Add and use a fresh documented implementation of the ATU Load/Purge. > > This is not really the Linux way of doing something. You don't throw > something away and replace it. You incrementally modify what you have > into something better. > > I really wished you had moved the code, unmodified, into > global1_atu.c. Then made lots of easy to review small changes. I > cannot just look at this patch and know it is correct. What i need to > compare against is not in this patch. So it is a lot harder to review. I've addressed all of your comments in this patchset except this one. A patch file cannot guarantee that a chunk of code moved around has not been altered in the process. This will just generate more diff for no value, that needs to be updated afterwards anyway. Plus you already complained in the first iteration I sent about modifying lines that I previously added. I took care of logically splitting the new ATU Load/Purge, GetNext, Flush and Remove operations into incremental unmodified chunks in this series. I have updated the commit messages to detail the addition of the static helpers and their counterparts, but I will resend this patch as is. Thanks, Vivien
[PATCH] Cleanup some warning from timestamping code.
--- drivers/net/loopback.c | 13 ++--- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index b23b719..122cc2d 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -13,7 +13,7 @@ * * Alan Cox: Fixed oddments for NET3.014 * Alan Cox: Rejig for NET3.029 snap #3 - * Alan Cox: Fixed NET3.029 bugs and sped up + * Alan Cox: Fixed NET3.029 bugs and sped up * Larry McVoy : Tiny tweak to double performance * Alan Cox: Backed out LMV's tweak - the linux mm * can't take it... @@ -41,7 +41,7 @@ #include #include -#include +#include #include #include @@ -149,8 +149,8 @@ static void loopback_dev_free(struct net_device *dev) } static const struct net_device_ops loopback_ops = { - .ndo_init = loopback_dev_init, - .ndo_start_xmit= loopback_xmit, + .ndo_init= loopback_dev_init, + .ndo_start_xmit = loopback_xmit, .ndo_get_stats64 = loopback_get_stats64, .ndo_set_mac_address = eth_mac_addr, }; @@ -170,7 +170,7 @@ static void loopback_setup(struct net_device *dev) dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE; netif_keep_dst(dev); dev->hw_features= NETIF_F_GSO_SOFTWARE; - dev->features = NETIF_F_SG | NETIF_F_FRAGLIST + dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE | NETIF_F_HW_CSUM | NETIF_F_RXCSUM @@ -206,7 +206,6 @@ static __net_init int loopback_net_init(struct net *net) net->loopback_dev = dev; return 0; - out_free_netdev: free_netdev(dev); out: @@ -217,5 +216,5 @@ static __net_init int loopback_net_init(struct net *net) /* Registered in net/core/dev.c */ struct pernet_operations __net_initdata loopback_net_ops = { - .init = loopback_net_init, + .init = loopback_net_init, }; -- 1.9.1 Amazon Data Services Ireland Limited registered office: One Burlington Plaza, Burlington Road, Dublin 4, Ireland. Registered in Ireland. Registration number 390566.
[PATCH] Enable tx timestamping on loopback and dummy
This enables testing of SO_TIMESTAMPING options by targetting localhost addresses. Tested on qemu using txtimestamping.c from the kernel selftests. --- drivers/net/dummy.c| 1 + drivers/net/loopback.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 2c80611..32fdc00 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -125,6 +125,7 @@ static netdev_tx_t dummy_xmit(struct sk_buff *skb, struct net_device *dev) dstats->tx_bytes += skb->len; u64_stats_update_end(&dstats->syncp); + skb_tx_timestamp(skb); dev_kfree_skb(skb); return NETDEV_TX_OK; } diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 122cc2d..8bcf479 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -74,6 +74,7 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb, struct pcpu_lstats *lb_stats; int len; + skb_tx_timestamp(skb); skb_orphan(skb); /* Before queueing this packet to netif_rx(), -- 1.9.1 Amazon Data Services Ireland Limited registered office: One Burlington Plaza, Burlington Road, Dublin 4, Ireland. Registered in Ireland. Registration number 390566.
Re: regression (4.10) - interface remove uevents not generated
Hi Mantas, Thank you for the report. Could you try out the attached patch? On Sat, Mar 11, 2017 at 05:10:22PM +0200, Mantas Mikulėnas wrote: > Hello, > > It seems that commit 002d8a1a6c11b9b2a8ac615095589111dd52749b ("net: > skip genenerating uevents for network namespaces that are exiting") > broke 'remove' uevents for *all* network interfaces, even for those in > the main/default namespace. > > Other than breaking some of my udev rules, this also causes problems for > NetworkManager, which apparently relies on those uevents to update its > interface information cache. (I ended up reverting that commit locally > just so I could connect to VPNs again.) > > This problem is present in both v4.10.1 and current master > (v4.11-rc1-290-g434fd6353b4c). > > -- > Mantas Mikulėnas diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 3c4bbec..20c48cf 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -34,6 +34,7 @@ EXPORT_SYMBOL_GPL(net_namespace_list); struct net init_net = { .dev_base_head = LIST_HEAD_INIT(init_net.dev_base_head), + .exit_list = LIST_HEAD_INIT(init_net.exit_list), }; EXPORT_SYMBOL(init_net); @@ -286,6 +287,7 @@ static __net_init int setup_net(struct net *net, struct user_namespace *user_ns) net->user_ns = user_ns; idr_init(&net->netns_ids); spin_lock_init(&net->nsid_lock); + INIT_LIST_HEAD(&net->exit_list); list_for_each_entry(ops, &pernet_list, list) { error = ops_init(ops, net);
Proposal...
Personal Business proposal for you,contact me via my personal E-mail for more detail's: ms_teresa_a...@outlook.com
Re: [PATCH] Enable tx timestamping on loopback and dummy
On Sat, Mar 11, 2017 at 9:42 AM, Ezequiel Lara Gomez wrote: > Also, cleanup some warnings from timestamping code. Can you please submit the styling fixes as a separate patch? Thanks, Soheil
[PATCH net] bpf: improve read-only handling
Improve bpf_{prog,jit_binary}_{un,}lock_ro() by throwing a one-time warning in case of an error when the image couldn't be set read-only, and also mark struct bpf_prog as locked when bpf_prog_lock_ro() was called. Reason for the latter is that bpf_prog_unlock_ro() is called from various places including error paths, and we shouldn't mess with page attributes when really not needed. For bpf_jit_binary_unlock_ro() this is not needed as jited flag implicitly indicates this, thus for archs with ARCH_HAS_SET_MEMORY we're guaranteed to have a previously locked image. Overall, this should also help us to identify any further potential issues with set_memory_*() helpers. Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov --- ( My preference is on -net, so we can potentially find and fix any remaining unexpected issue with set_memory_*(). Thanks! ) include/linux/filter.h | 16 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/include/linux/filter.h b/include/linux/filter.h index 0c167fd..fbf7b39 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -409,6 +409,7 @@ struct bpf_prog { u16 pages; /* Number of allocated pages */ kmemcheck_bitfield_begin(meta); u16 jited:1,/* Is our filter JIT'ed? */ + locked:1, /* Program image locked? */ gpl_compatible:1, /* Is filter GPL compatible? */ cb_access:1,/* Is control block accessed? */ dst_needed:1, /* Do we need dst entry? */ @@ -554,22 +555,29 @@ static inline bool bpf_prog_was_classic(const struct bpf_prog *prog) #ifdef CONFIG_ARCH_HAS_SET_MEMORY static inline void bpf_prog_lock_ro(struct bpf_prog *fp) { - set_memory_ro((unsigned long)fp, fp->pages); + fp->locked = 1; + WARN_ON_ONCE(set_memory_ro((unsigned long)fp, fp->pages)); } static inline void bpf_prog_unlock_ro(struct bpf_prog *fp) { - set_memory_rw((unsigned long)fp, fp->pages); + if (fp->locked) { + WARN_ON_ONCE(set_memory_rw((unsigned long)fp, fp->pages)); + /* In case set_memory_rw() fails, we want to be the first +* to crash here instead of some random place later on. +*/ + fp->locked = 0; + } } static inline void bpf_jit_binary_lock_ro(struct bpf_binary_header *hdr) { - set_memory_ro((unsigned long)hdr, hdr->pages); + WARN_ON_ONCE(set_memory_ro((unsigned long)hdr, hdr->pages)); } static inline void bpf_jit_binary_unlock_ro(struct bpf_binary_header *hdr) { - set_memory_rw((unsigned long)hdr, hdr->pages); + WARN_ON_ONCE(set_memory_rw((unsigned long)hdr, hdr->pages)); } #else static inline void bpf_prog_lock_ro(struct bpf_prog *fp) -- 1.9.3
regression (4.10) - interface remove uevents not generated
Hello, It seems that commit 002d8a1a6c11b9b2a8ac615095589111dd52749b ("net: skip genenerating uevents for network namespaces that are exiting") broke 'remove' uevents for *all* network interfaces, even for those in the main/default namespace. Other than breaking some of my udev rules, this also causes problems for NetworkManager, which apparently relies on those uevents to update its interface information cache. (I ended up reverting that commit locally just so I could connect to VPNs again.) This problem is present in both v4.10.1 and current master (v4.11-rc1-290-g434fd6353b4c). -- Mantas Mikulėnas
[PATCH] Enable tx timestamping on loopback and dummy
Also, cleanup some warnings from timestamping code. This enables testing of SO_TIMESTAMPING options by targetting localhost addresses. Tested on qemu using txtimestamping.c from the kernel selftests. Signed-off-by: Ezequiel Lara Gomez --- drivers/net/dummy.c| 1 + drivers/net/loopback.c | 14 +++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 2c80611..32fdc00 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -125,6 +125,7 @@ static netdev_tx_t dummy_xmit(struct sk_buff *skb, struct net_device *dev) dstats->tx_bytes += skb->len; u64_stats_update_end(&dstats->syncp); + skb_tx_timestamp(skb); dev_kfree_skb(skb); return NETDEV_TX_OK; } diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index b23b719..8bcf479 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -13,7 +13,7 @@ * * Alan Cox: Fixed oddments for NET3.014 * Alan Cox: Rejig for NET3.029 snap #3 - * Alan Cox: Fixed NET3.029 bugs and sped up + * Alan Cox: Fixed NET3.029 bugs and sped up * Larry McVoy : Tiny tweak to double performance * Alan Cox: Backed out LMV's tweak - the linux mm * can't take it... @@ -41,7 +41,7 @@ #include #include -#include +#include #include #include @@ -74,6 +74,7 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb, struct pcpu_lstats *lb_stats; int len; + skb_tx_timestamp(skb); skb_orphan(skb); /* Before queueing this packet to netif_rx(), @@ -149,8 +150,8 @@ static void loopback_dev_free(struct net_device *dev) } static const struct net_device_ops loopback_ops = { - .ndo_init = loopback_dev_init, - .ndo_start_xmit= loopback_xmit, + .ndo_init= loopback_dev_init, + .ndo_start_xmit = loopback_xmit, .ndo_get_stats64 = loopback_get_stats64, .ndo_set_mac_address = eth_mac_addr, }; @@ -170,7 +171,7 @@ static void loopback_setup(struct net_device *dev) dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE; netif_keep_dst(dev); dev->hw_features= NETIF_F_GSO_SOFTWARE; - dev->features = NETIF_F_SG | NETIF_F_FRAGLIST + dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE | NETIF_F_HW_CSUM | NETIF_F_RXCSUM @@ -206,7 +207,6 @@ static __net_init int loopback_net_init(struct net *net) net->loopback_dev = dev; return 0; - out_free_netdev: free_netdev(dev); out: @@ -217,5 +217,5 @@ static __net_init int loopback_net_init(struct net *net) /* Registered in net/core/dev.c */ struct pernet_operations __net_initdata loopback_net_ops = { - .init = loopback_net_init, + .init = loopback_net_init, }; -- 1.9.1 Amazon Data Services Ireland Limited registered office: One Burlington Plaza, Burlington Road, Dublin 4, Ireland. Registered in Ireland. Registration number 390566.
ANNOUNCE: Netdev Conference: What you have been missing
As announced last time, we are making more frequent announcements on peo...@netdevconf.org You can subscribe via mailman here: https://lists.netdevconf.org/cgi-bin/mailman/listinfo/people We urge people to subscribe to that list to get more up to date information and conference discussions. We will still be sending weekly summaries and announcements on the netdev list. If you have already registered for the conference we will very likely have registered you already. Register early so we can plan better (and so you can save some $$). https://onlineregistrations.ca/netdev21/ - hotel (unfortunately space is running out here. If you cant get in and need help from us, please send email to i...@netdevconf.org): https://www.netdevconf.org/2.1/hotel.html And here's a summary of whats new since last posting on netdev: 1) New sponsors a) Mojatatu - Gold sponsor https://netdevconf.org/2.1/news.html?sponsor-mojatatu b) Verizon - Platinum https://netdevconf.org/2.1/news.html?news-verizon-sponsor Accepted sessions: 2) New sessions a) Talk: XDP in practice: integrating XDP in our DDoS mitigation pipeline from Gilberto Bertin https://netdevconf.org/2.1/news.html?news-bertin b)Workshop: Network Performance Workshop chaired by Alex Duyck https://netdevconf.org/2.1/news.html?news-duyck c) Talk: Netfilter's connection tracking subsystem by Florian Westphal https://netdevconf.org/2.1/news.html?news-netfilters-talk d) Talk: IOT Without Things: Building virtual 6LoWPAN Mesh Networks by Alexander Aring https://netdevconf.org/2.1/news.html?news-aring-talk e) Talk: Kernel HTTP/TCP/IP stack for HTTP DDoS mitigation by Alexander Krizhanovsky https://netdevconf.org/2.1/news.html?news-krizhanovsky-talk A lot more exciting announcements coming. cheers, jamal
Re: [PATCH net] selftests/bpf: fix broken build
On 03/11/2017 07:05 AM, Alexei Starovoitov wrote: Recent merge of 'linux-kselftest-4.11-rc1' tree broke bpf test build. None of the tests were building and test_verifier.c had tons of compiler errors. Fix it and add #ifdef CAP_IS_SUPPORTED to support old versions of libcap. Tested on centos 6.8 and 7 Signed-off-by: Alexei Starovoitov Fix looks correct to me and makes the test suite work again. Acked-by: Daniel Borkmann Tested-by: Daniel Borkmann
Re: [PATCH] netfilter: Force fake conntrack entry to be at least 8 bytes aligned
Steven Rostedt (VMware) wrote: > Since the nfct and nfctinfo have been combined, the nf_conn structure > must be at least 8 bytes aligned, as the 3 LSB bits are used for the > nfctinfo. But there's a fake nf_conn structure to denote untracked > connections, which is created by a PER_CPU construct. This does not > guarantee that it will be 8 bytes aligned and can break the logic in > determining the correct nfctinfo. > > I triggered this on a 32bit machine with the following error: [..] Ugh. Originally I had planned to also submit followup changes to get rid of the untracked objects but that part got delayed. > By using DEFINE/DECLARE_PER_CPU_ALIGNED we can enforce at least 8 byte > alignment as all cache line sizes are at least 8 bytes or more. Thanks for fixing this! Acked-by: Florian Westphal
[patch net-next 6/9] mlxsw: spectrum: Add periodic ACL rule activity update
From: Arkadi Sharshevsky Introduce periodic task for dumping the activity status for the ACL rule TCAM entries. This is done in order to emulate last use statistics. Signed-off-by: Arkadi Sharshevsky Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko --- drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c | 74 +- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c index 1888092..d2f6cbb 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c @@ -50,11 +50,17 @@ #include "spectrum_acl_flex_keys.h" struct mlxsw_sp_acl { + struct mlxsw_sp *mlxsw_sp; struct mlxsw_afk *afk; struct mlxsw_afa *afa; const struct mlxsw_sp_acl_ops *ops; struct rhashtable ruleset_ht; struct list_head rules; + struct { + struct delayed_work dw; + unsigned long interval; /* ms */ +#define MLXSW_SP_ACL_RULE_ACTIVITY_UPDATE_PERIOD_MS 1000 + } rule_activity_update; unsigned long priv[0]; /* priv has to be always the last item */ }; @@ -85,6 +91,7 @@ struct mlxsw_sp_acl_rule { unsigned long cookie; /* HT key */ struct mlxsw_sp_acl_ruleset *ruleset; struct mlxsw_sp_acl_rule_info *rulei; + u64 last_used; unsigned long priv[0]; /* priv has to be always the last item */ }; @@ -459,6 +466,64 @@ mlxsw_sp_acl_rule_rulei(struct mlxsw_sp_acl_rule *rule) return rule->rulei; } +static int mlxsw_sp_acl_rule_activity_update(struct mlxsw_sp *mlxsw_sp, +struct mlxsw_sp_acl_rule *rule) +{ + struct mlxsw_sp_acl_ruleset *ruleset = rule->ruleset; + const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops; + bool active; + int err; + + err = ops->rule_activity_get(mlxsw_sp, rule->priv, &active); + if (err) + return err; + if (active) + rule->last_used = jiffies; + return 0; +} + +static int mlxsw_sp_acl_rules_activity_update(struct mlxsw_sp_acl *acl) +{ + struct mlxsw_sp_acl_rule *rule; + int err; + + /* Protect internal structures from changes */ + rtnl_lock(); + list_for_each_entry(rule, &acl->rules, list) { + err = mlxsw_sp_acl_rule_activity_update(acl->mlxsw_sp, + rule); + if (err) + goto err_rule_update; + } + rtnl_unlock(); + return 0; + +err_rule_update: + rtnl_unlock(); + return err; +} + +static void mlxsw_sp_acl_rule_activity_work_schedule(struct mlxsw_sp_acl *acl) +{ + unsigned long interval = acl->rule_activity_update.interval; + + mlxsw_core_schedule_dw(&acl->rule_activity_update.dw, + msecs_to_jiffies(interval)); +} + +static void mlxsw_sp_acl_rul_activity_update_work(struct work_struct *work) +{ + struct mlxsw_sp_acl *acl = container_of(work, struct mlxsw_sp_acl, + rule_activity_update.dw.work); + int err; + + err = mlxsw_sp_acl_rules_activity_update(acl); + if (err) + dev_err(acl->mlxsw_sp->bus_info->dev, "Could not update acl activity"); + + mlxsw_sp_acl_rule_activity_work_schedule(acl); +} + #define MLXSW_SP_KDVL_ACT_EXT_SIZE 1 static int mlxsw_sp_act_kvdl_set_add(void *priv, u32 *p_kvdl_index, @@ -551,7 +616,7 @@ int mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp) if (!acl) return -ENOMEM; mlxsw_sp->acl = acl; - + acl->mlxsw_sp = mlxsw_sp; acl->afk = mlxsw_afk_create(MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_FLEX_KEYS), mlxsw_sp_afk_blocks, @@ -580,6 +645,12 @@ int mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp) goto err_acl_ops_init; acl->ops = acl_ops; + + /* Create the delayed work for the rule activity_update */ + INIT_DELAYED_WORK(&acl->rule_activity_update.dw, + mlxsw_sp_acl_rul_activity_update_work); + acl->rule_activity_update.interval = MLXSW_SP_ACL_RULE_ACTIVITY_UPDATE_PERIOD_MS; + mlxsw_core_schedule_dw(&acl->rule_activity_update.dw, 0); return 0; err_acl_ops_init: @@ -598,6 +669,7 @@ void mlxsw_sp_acl_fini(struct mlxsw_sp *mlxsw_sp) struct mlxsw_sp_acl *acl = mlxsw_sp->acl; const struct mlxsw_sp_acl_ops *acl_ops = acl->ops; + cancel_delayed_work_sync(&mlxsw_sp->acl->rule_activity_update.dw); acl_ops->fini(mlxsw_sp, acl->priv); WARN_ON(!list_empty(&acl->rules)); rhashtable_destroy(&acl->ruleset_ht); -- 2.7.4
[patch net-next 9/9] mlxsw: spectrum: Add support for TC flower offload statistics
From: Arkadi Sharshevsky Add support for TC flower offload statistics including number of packets, bytes and last use timestamp. Currently the statistics are gathered on a per-rule basis. Signed-off-by: Arkadi Sharshvesky Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 3 ++ drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 2 + drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c | 28 + .../net/ethernet/mellanox/mlxsw/spectrum_flower.c | 49 ++ 4 files changed, 82 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index af43048..475499b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -1434,6 +1434,9 @@ static int mlxsw_sp_setup_tc(struct net_device *dev, u32 handle, mlxsw_sp_flower_destroy(mlxsw_sp_port, ingress, tc->cls_flower); return 0; + case TC_CLSFLOWER_STATS: + return mlxsw_sp_flower_stats(mlxsw_sp_port, ingress, +tc->cls_flower); default: return -EOPNOTSUPP; } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index b4f32a6..5502232 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -688,6 +688,8 @@ int mlxsw_sp_flower_replace(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress, __be16 protocol, struct tc_cls_flower_offload *f); void mlxsw_sp_flower_destroy(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress, struct tc_cls_flower_offload *f); +int mlxsw_sp_flower_stats(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress, + struct tc_cls_flower_offload *f); int mlxsw_sp_flow_counter_get(struct mlxsw_sp *mlxsw_sp, unsigned int counter_index, u64 *packets, u64 *bytes); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c index 87d0111..4d6920d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c @@ -92,6 +92,8 @@ struct mlxsw_sp_acl_rule { struct mlxsw_sp_acl_ruleset *ruleset; struct mlxsw_sp_acl_rule_info *rulei; u64 last_used; + u64 last_packets; + u64 last_bytes; unsigned long priv[0]; /* priv has to be always the last item */ }; @@ -559,6 +561,32 @@ static void mlxsw_sp_acl_rul_activity_update_work(struct work_struct *work) mlxsw_sp_acl_rule_activity_work_schedule(acl); } +int mlxsw_sp_acl_rule_get_stats(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_acl_rule *rule, + u64 *packets, u64 *bytes, u64 *last_use) + +{ + struct mlxsw_sp_acl_rule_info *rulei; + u64 current_packets; + u64 current_bytes; + int err; + + rulei = mlxsw_sp_acl_rule_rulei(rule); + err = mlxsw_sp_flow_counter_get(mlxsw_sp, rulei->counter_index, + ¤t_packets, ¤t_bytes); + if (err) + return err; + + *packets = current_packets - rule->last_packets; + *bytes = current_bytes - rule->last_bytes; + *last_use = rule->last_used; + + rule->last_bytes = current_bytes; + rule->last_packets = current_packets; + + return 0; +} + #define MLXSW_SP_KDVL_ACT_EXT_SIZE 1 static int mlxsw_sp_act_kvdl_set_add(void *priv, u32 *p_kvdl_index, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c index f2ed0b3..28bc989 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c @@ -56,6 +56,11 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp, if (tc_no_actions(exts)) return 0; + /* Count action is inserted first */ + err = mlxsw_sp_acl_rulei_act_count(mlxsw_sp, rulei); + if (err) + return err; + tcf_exts_to_list(exts, &actions); list_for_each_entry(a, &actions, list) { if (is_tcf_gact_shot(a)) { @@ -346,3 +351,47 @@ void mlxsw_sp_flower_destroy(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress, mlxsw_sp_acl_ruleset_put(mlxsw_sp, ruleset); } + +int mlxsw_sp_flower_stats(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress, + struct tc_cls_flower_offload *f) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct mlxsw_sp_acl_ruleset *rul
[patch net-next 4/9] mlxsw: spectrum_acl_tcam: Add support for retrieving TCAM entry activity
From: Arkadi Sharshevsky Add support for retrieving TCAM entry activity. In order to support ACL rule activity corresponding TCAM entry should be queried. Signed-off-by: Arkadi Sharshevsky Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko --- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 2 ++ .../ethernet/mellanox/mlxsw/spectrum_acl_tcam.c| 42 ++ 2 files changed, 44 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index b0500b8..26718b1 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -607,6 +607,8 @@ struct mlxsw_sp_acl_profile_ops { void *ruleset_priv, void *rule_priv, struct mlxsw_sp_acl_rule_info *rulei); void (*rule_del)(struct mlxsw_sp *mlxsw_sp, void *rule_priv); + int (*rule_activity_get)(struct mlxsw_sp *mlxsw_sp, void *rule_priv, +bool *activity); }; struct mlxsw_sp_acl_ops { diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c index 6858439..3a24289 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c @@ -561,6 +561,24 @@ mlxsw_sp_acl_tcam_region_entry_remove(struct mlxsw_sp *mlxsw_sp, mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl); } +static int +mlxsw_sp_acl_tcam_region_entry_activity_get(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_acl_tcam_region *region, + unsigned int offset, + bool *activity) +{ + char ptce2_pl[MLXSW_REG_PTCE2_LEN]; + int err; + + mlxsw_reg_ptce2_pack(ptce2_pl, true, MLXSW_REG_PTCE2_OP_QUERY_CLEAR_ON_READ, +region->tcam_region_info, offset); + err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl); + if (err) + return err; + *activity = mlxsw_reg_ptce2_a_get(ptce2_pl); + return 0; +} + #define MLXSW_SP_ACL_TCAM_CATCHALL_PRIO (~0U) static int @@ -940,6 +958,19 @@ static void mlxsw_sp_acl_tcam_entry_del(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_acl_tcam_chunk_put(mlxsw_sp, chunk); } +static int +mlxsw_sp_acl_tcam_entry_activity_get(struct mlxsw_sp *mlxsw_sp, +struct mlxsw_sp_acl_tcam_entry *entry, +bool *activity) +{ + struct mlxsw_sp_acl_tcam_chunk *chunk = entry->chunk; + struct mlxsw_sp_acl_tcam_region *region = chunk->region; + + return mlxsw_sp_acl_tcam_region_entry_activity_get(mlxsw_sp, region, + entry->parman_item.index, + activity); +} + static const enum mlxsw_afk_element mlxsw_sp_acl_tcam_pattern_ipv4[] = { MLXSW_AFK_ELEMENT_SRC_SYS_PORT, MLXSW_AFK_ELEMENT_DMAC, @@ -1048,6 +1079,16 @@ mlxsw_sp_acl_tcam_flower_rule_del(struct mlxsw_sp *mlxsw_sp, void *rule_priv) mlxsw_sp_acl_tcam_entry_del(mlxsw_sp, &rule->entry); } +static int +mlxsw_sp_acl_tcam_flower_rule_activity_get(struct mlxsw_sp *mlxsw_sp, + void *rule_priv, bool *activity) +{ + struct mlxsw_sp_acl_tcam_flower_rule *rule = rule_priv; + + return mlxsw_sp_acl_tcam_entry_activity_get(mlxsw_sp, &rule->entry, + activity); +} + static const struct mlxsw_sp_acl_profile_ops mlxsw_sp_acl_tcam_flower_ops = { .ruleset_priv_size = sizeof(struct mlxsw_sp_acl_tcam_flower_ruleset), .ruleset_add= mlxsw_sp_acl_tcam_flower_ruleset_add, @@ -1057,6 +1098,7 @@ static const struct mlxsw_sp_acl_profile_ops mlxsw_sp_acl_tcam_flower_ops = { .rule_priv_size = sizeof(struct mlxsw_sp_acl_tcam_flower_rule), .rule_add = mlxsw_sp_acl_tcam_flower_rule_add, .rule_del = mlxsw_sp_acl_tcam_flower_rule_del, + .rule_activity_get = mlxsw_sp_acl_tcam_flower_rule_activity_get, }; static const struct mlxsw_sp_acl_profile_ops * -- 2.7.4
[patch net-next 5/9] mlxsw: spectrum: Add support for direct rule access
From: Arkadi Sharshevsky Currently the ACL rules can be accessed only by hashing. In order to dump the activity the rules are also placed in a list. Signed-off-by: Arkadi Sharshevsky Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko --- drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c index 3c5ea7e..1888092 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c @@ -54,6 +54,7 @@ struct mlxsw_sp_acl { struct mlxsw_afa *afa; const struct mlxsw_sp_acl_ops *ops; struct rhashtable ruleset_ht; + struct list_head rules; unsigned long priv[0]; /* priv has to be always the last item */ }; @@ -80,6 +81,7 @@ struct mlxsw_sp_acl_ruleset { struct mlxsw_sp_acl_rule { struct rhash_head ht_node; /* Member of rule HT */ + struct list_head list; unsigned long cookie; /* HT key */ struct mlxsw_sp_acl_ruleset *ruleset; struct mlxsw_sp_acl_rule_info *rulei; @@ -422,6 +424,7 @@ int mlxsw_sp_acl_rule_add(struct mlxsw_sp *mlxsw_sp, if (err) goto err_rhashtable_insert; + list_add_tail(&rule->list, &mlxsw_sp->acl->rules); return 0; err_rhashtable_insert: @@ -435,6 +438,7 @@ void mlxsw_sp_acl_rule_del(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_ruleset *ruleset = rule->ruleset; const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops; + list_del(&rule->list); rhashtable_remove_fast(&ruleset->rule_ht, &rule->ht_node, mlxsw_sp_acl_rule_ht_params); ops->rule_del(mlxsw_sp, rule->priv); @@ -570,6 +574,7 @@ int mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp) if (err) goto err_rhashtable_init; + INIT_LIST_HEAD(&acl->rules); err = acl_ops->init(mlxsw_sp, acl->priv); if (err) goto err_acl_ops_init; @@ -594,6 +599,7 @@ void mlxsw_sp_acl_fini(struct mlxsw_sp *mlxsw_sp) const struct mlxsw_sp_acl_ops *acl_ops = acl->ops; acl_ops->fini(mlxsw_sp, acl->priv); + WARN_ON(!list_empty(&acl->rules)); rhashtable_destroy(&acl->ruleset_ht); mlxsw_afa_destroy(acl->afa); mlxsw_afk_destroy(acl->afk); -- 2.7.4
[patch net-next 8/9] mlxsw: spectrum: Add support for counters on TCAM entries
From: Arkadi Sharshevsky Add support for packets and byte statistics on TCAM entries. The counters are allocated from the generic flow counters pool. Signed-off-by: Arkadi Sharshevsky Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko --- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 7 + drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c | 35 ++ 2 files changed, 42 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 26718b1..b4f32a6 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -588,6 +588,8 @@ struct mlxsw_sp_acl_rule_info { unsigned int priority; struct mlxsw_afk_element_values values; struct mlxsw_afa_block *act_block; + unsigned int counter_index; + bool counter_valid; }; enum mlxsw_sp_acl_profile { @@ -652,6 +654,8 @@ int mlxsw_sp_acl_rulei_act_fwd(struct mlxsw_sp *mlxsw_sp, int mlxsw_sp_acl_rulei_act_vlan(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_rule_info *rulei, u32 action, u16 vid, u16 proto, u8 prio); +int mlxsw_sp_acl_rulei_act_count(struct mlxsw_sp *mlxsw_sp, +struct mlxsw_sp_acl_rule_info *rulei); struct mlxsw_sp_acl_rule; @@ -671,6 +675,9 @@ mlxsw_sp_acl_rule_lookup(struct mlxsw_sp *mlxsw_sp, unsigned long cookie); struct mlxsw_sp_acl_rule_info * mlxsw_sp_acl_rule_rulei(struct mlxsw_sp_acl_rule *rule); +int mlxsw_sp_acl_rule_get_stats(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_acl_rule *rule, + u64 *packets, u64 *bytes, u64 *last_use); int mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_acl_fini(struct mlxsw_sp *mlxsw_sp); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c index d2f6cbb..87d0111 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c @@ -247,6 +247,27 @@ void mlxsw_sp_acl_ruleset_put(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_acl_ruleset_ref_dec(mlxsw_sp, ruleset); } +static int +mlxsw_sp_acl_rulei_counter_alloc(struct mlxsw_sp *mlxsw_sp, +struct mlxsw_sp_acl_rule_info *rulei) +{ + int err; + + err = mlxsw_sp_flow_counter_alloc(mlxsw_sp, &rulei->counter_index); + if (err) + return err; + rulei->counter_valid = true; + return 0; +} + +static void +mlxsw_sp_acl_rulei_counter_free(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_acl_rule_info *rulei) +{ + rulei->counter_valid = false; + mlxsw_sp_flow_counter_free(mlxsw_sp, rulei->counter_index); +} + struct mlxsw_sp_acl_rule_info * mlxsw_sp_acl_rulei_create(struct mlxsw_sp_acl *acl) { @@ -373,6 +394,13 @@ int mlxsw_sp_acl_rulei_act_vlan(struct mlxsw_sp *mlxsw_sp, } } +int mlxsw_sp_acl_rulei_act_count(struct mlxsw_sp *mlxsw_sp, +struct mlxsw_sp_acl_rule_info *rulei) +{ + return mlxsw_afa_block_append_counter(rulei->act_block, + rulei->counter_index); +} + struct mlxsw_sp_acl_rule * mlxsw_sp_acl_rule_create(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_ruleset *ruleset, @@ -396,8 +424,14 @@ mlxsw_sp_acl_rule_create(struct mlxsw_sp *mlxsw_sp, err = PTR_ERR(rule->rulei); goto err_rulei_create; } + + err = mlxsw_sp_acl_rulei_counter_alloc(mlxsw_sp, rule->rulei); + if (err) + goto err_counter_alloc; return rule; +err_counter_alloc: + mlxsw_sp_acl_rulei_destroy(rule->rulei); err_rulei_create: kfree(rule); err_alloc: @@ -410,6 +444,7 @@ void mlxsw_sp_acl_rule_destroy(struct mlxsw_sp *mlxsw_sp, { struct mlxsw_sp_acl_ruleset *ruleset = rule->ruleset; + mlxsw_sp_acl_rulei_counter_free(mlxsw_sp, rule->rulei); mlxsw_sp_acl_rulei_destroy(rule->rulei); kfree(rule); mlxsw_sp_acl_ruleset_ref_dec(mlxsw_sp, ruleset); -- 2.7.4
[patch net-next 7/9] mlxsw: spectrum: Add support for Policing and Counting action block
From: Arkadi Sharshevsky Add support for Policing and Counting action block. This action block will be used to bind counter to TCAM entries. Signed-off-by: Arkadi Sharshevsky Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko --- .../mellanox/mlxsw/core_acl_flex_actions.c | 51 ++ .../mellanox/mlxsw/core_acl_flex_actions.h | 2 + 2 files changed, 53 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c index fe3c6ea1..a984c36 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c @@ -760,3 +760,54 @@ int mlxsw_afa_block_append_fwd(struct mlxsw_afa_block *block, return err; } EXPORT_SYMBOL(mlxsw_afa_block_append_fwd); + +/* Policing and Counting Action + * + * Policing and Counting action is used for binding policer and counter + * to ACL rules. + */ + +#define MLXSW_AFA_POLCNT_CODE 0x08 +#define MLXSW_AFA_POLCNT_SIZE 1 + +enum mlxsw_afa_polcnt_counter_set_type { + /* No count */ + MLXSW_AFA_POLCNT_COUNTER_SET_TYPE_NO_COUNT = 0x00, + /* Count packets and bytes */ + MLXSW_AFA_POLCNT_COUNTER_SET_TYPE_PACKETS_BYTES = 0x03, + /* Count only packets */ + MLXSW_AFA_POLCNT_COUNTER_SET_TYPE_PACKETS = 0x05, +}; + +/* afa_polcnt_counter_set_type + * Counter set type for flow counters. + */ +MLXSW_ITEM32(afa, polcnt, counter_set_type, 0x04, 24, 8); + +/* afa_polcnt_counter_index + * Counter index for flow counters. + */ +MLXSW_ITEM32(afa, polcnt, counter_index, 0x04, 0, 24); + +static inline void +mlxsw_afa_polcnt_pack(char *payload, + enum mlxsw_afa_polcnt_counter_set_type set_type, + u32 counter_index) +{ + mlxsw_afa_polcnt_counter_set_type_set(payload, set_type); + mlxsw_afa_polcnt_counter_index_set(payload, counter_index); +} + +int mlxsw_afa_block_append_counter(struct mlxsw_afa_block *block, + u32 counter_index) +{ + char *act = mlxsw_afa_block_append_action(block, + MLXSW_AFA_POLCNT_CODE, + MLXSW_AFA_POLCNT_SIZE); + if (!act) + return -ENOBUFS; + mlxsw_afa_polcnt_pack(act, MLXSW_AFA_POLCNT_COUNTER_SET_TYPE_PACKETS_BYTES, + counter_index); + return 0; +} +EXPORT_SYMBOL(mlxsw_afa_block_append_counter); diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h index 6e103ac..a03362c 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h @@ -64,5 +64,7 @@ int mlxsw_afa_block_append_fwd(struct mlxsw_afa_block *block, u8 local_port, bool in_port); int mlxsw_afa_block_append_vlan_modify(struct mlxsw_afa_block *block, u16 vid, u8 pcp, u8 et); +int mlxsw_afa_block_append_counter(struct mlxsw_afa_block *block, + u32 counter_index); #endif -- 2.7.4
[patch net-next 3/9] mlxsw: spectrum: Add support for generic flow counter allocation
From: Arkadi Sharshevsky Add support for allocating generic flow counter. Generic flow counter can count packets or packets and bytes and can be assigned to different hardware processes. First use will be for counting packets and bytes of ACL rules, and will be introduced in the following patches. Signed-off-by: Arkadi Sharshevsky Reviewed-by: Ido schimmel Signed-off-by: Jiri Pirko --- drivers/net/ethernet/mellanox/mlxsw/resources.h| 2 + drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 54 ++ drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 7 +++ drivers/net/ethernet/mellanox/mlxsw/spectrum_cnt.c | 23 - drivers/net/ethernet/mellanox/mlxsw/spectrum_cnt.h | 3 +- 5 files changed, 86 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/resources.h b/drivers/net/ethernet/mellanox/mlxsw/resources.h index 15b8086..905a8e2 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/resources.h +++ b/drivers/net/ethernet/mellanox/mlxsw/resources.h @@ -45,6 +45,7 @@ enum mlxsw_res_id { MLXSW_RES_ID_MAX_TRAP_GROUPS, MLXSW_RES_ID_COUNTER_POOL_SIZE, MLXSW_RES_ID_MAX_SPAN, + MLXSW_RES_ID_COUNTER_SIZE_PACKETS_BYTES, MLXSW_RES_ID_MAX_SYSTEM_PORT, MLXSW_RES_ID_MAX_LAG, MLXSW_RES_ID_MAX_LAG_MEMBERS, @@ -78,6 +79,7 @@ static u16 mlxsw_res_ids[] = { [MLXSW_RES_ID_MAX_TRAP_GROUPS] = 0x2201, [MLXSW_RES_ID_COUNTER_POOL_SIZE] = 0x2410, [MLXSW_RES_ID_MAX_SPAN] = 0x2420, + [MLXSW_RES_ID_COUNTER_SIZE_PACKETS_BYTES] = 0x2443, [MLXSW_RES_ID_MAX_SYSTEM_PORT] = 0x2502, [MLXSW_RES_ID_MAX_LAG] = 0x2520, [MLXSW_RES_ID_MAX_LAG_MEMBERS] = 0x2521, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index b8237f9..af43048 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -139,6 +139,60 @@ MLXSW_ITEM32(tx, hdr, fid, 0x08, 0, 16); */ MLXSW_ITEM32(tx, hdr, type, 0x0C, 0, 4); +int mlxsw_sp_flow_counter_get(struct mlxsw_sp *mlxsw_sp, + unsigned int counter_index, u64 *packets, + u64 *bytes) +{ + char mgpc_pl[MLXSW_REG_MGPC_LEN]; + int err; + + mlxsw_reg_mgpc_pack(mgpc_pl, counter_index, MLXSW_REG_MGPC_OPCODE_NOP, + MLXSW_REG_MGPC_COUNTER_SET_TYPE_PACKETS_BYTES); + err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(mgpc), mgpc_pl); + if (err) + return err; + *packets = mlxsw_reg_mgpc_packet_counter_get(mgpc_pl); + *bytes = mlxsw_reg_mgpc_byte_counter_get(mgpc_pl); + return 0; +} + +static int mlxsw_sp_flow_counter_clear(struct mlxsw_sp *mlxsw_sp, + unsigned int counter_index) +{ + char mgpc_pl[MLXSW_REG_MGPC_LEN]; + + mlxsw_reg_mgpc_pack(mgpc_pl, counter_index, MLXSW_REG_MGPC_OPCODE_CLEAR, + MLXSW_REG_MGPC_COUNTER_SET_TYPE_PACKETS_BYTES); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mgpc), mgpc_pl); +} + +int mlxsw_sp_flow_counter_alloc(struct mlxsw_sp *mlxsw_sp, + unsigned int *p_counter_index) +{ + int err; + + err = mlxsw_sp_counter_alloc(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_FLOW, +p_counter_index); + if (err) + return err; + err = mlxsw_sp_flow_counter_clear(mlxsw_sp, *p_counter_index); + if (err) + goto err_counter_clear; + return 0; + +err_counter_clear: + mlxsw_sp_counter_free(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_FLOW, + *p_counter_index); + return err; +} + +void mlxsw_sp_flow_counter_free(struct mlxsw_sp *mlxsw_sp, + unsigned int counter_index) +{ +mlxsw_sp_counter_free(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_FLOW, + counter_index); +} + static void mlxsw_sp_txhdr_construct(struct sk_buff *skb, const struct mlxsw_tx_info *tx_info) { diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index dd59a9b..b0500b8 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -679,5 +679,12 @@ int mlxsw_sp_flower_replace(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress, __be16 protocol, struct tc_cls_flower_offload *f); void mlxsw_sp_flower_destroy(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress, struct tc_cls_flower_offload *f); +int mlxsw_sp_flow_counter_get(struct mlxsw_sp *mlxsw_sp, + unsigned int counter_index, u64 *packets, + u64 *bytes); +int mlxsw_sp_flow_counter_alloc(struct mlxsw_sp *mlxsw_sp, +
[patch net-next 1/9] mlxsw: spectrum: Add support for counter allocator
From: Arkadi Sharshevsky Add implementation for counter allocator. The ASIC has special memory pool for various counting purposes. Counter memory is distributed between equal size banks. The static sub-pool configuration should specify the following parameters for each sub-pool: - Number of required banks. - Maximum entry size. Each module can add dedicated sub-pool or use existing one. Signed-off-by: Arkadi Sharshevsky Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko --- drivers/net/ethernet/mellanox/mlxsw/Makefile | 3 +- drivers/net/ethernet/mellanox/mlxsw/resources.h| 2 + drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 10 ++ drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 2 + drivers/net/ethernet/mellanox/mlxsw/spectrum_cnt.c | 177 + drivers/net/ethernet/mellanox/mlxsw/spectrum_cnt.h | 54 +++ 6 files changed, 247 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/mellanox/mlxsw/spectrum_cnt.c create mode 100644 drivers/net/ethernet/mellanox/mlxsw/spectrum_cnt.h diff --git a/drivers/net/ethernet/mellanox/mlxsw/Makefile b/drivers/net/ethernet/mellanox/mlxsw/Makefile index 6b6c30d..95fcacf 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/Makefile +++ b/drivers/net/ethernet/mellanox/mlxsw/Makefile @@ -15,7 +15,8 @@ obj-$(CONFIG_MLXSW_SPECTRUM) += mlxsw_spectrum.o mlxsw_spectrum-objs:= spectrum.o spectrum_buffers.o \ spectrum_switchdev.o spectrum_router.o \ spectrum_kvdl.o spectrum_acl_tcam.o \ - spectrum_acl.o spectrum_flower.o + spectrum_acl.o spectrum_flower.o \ + spectrum_cnt.o mlxsw_spectrum-$(CONFIG_MLXSW_SPECTRUM_DCB)+= spectrum_dcb.o obj-$(CONFIG_MLXSW_MINIMAL)+= mlxsw_minimal.o mlxsw_minimal-objs := minimal.o diff --git a/drivers/net/ethernet/mellanox/mlxsw/resources.h b/drivers/net/ethernet/mellanox/mlxsw/resources.h index bce8c2e..15b8086 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/resources.h +++ b/drivers/net/ethernet/mellanox/mlxsw/resources.h @@ -43,6 +43,7 @@ enum mlxsw_res_id { MLXSW_RES_ID_KVD_SINGLE_MIN_SIZE, MLXSW_RES_ID_KVD_DOUBLE_MIN_SIZE, MLXSW_RES_ID_MAX_TRAP_GROUPS, + MLXSW_RES_ID_COUNTER_POOL_SIZE, MLXSW_RES_ID_MAX_SPAN, MLXSW_RES_ID_MAX_SYSTEM_PORT, MLXSW_RES_ID_MAX_LAG, @@ -75,6 +76,7 @@ static u16 mlxsw_res_ids[] = { [MLXSW_RES_ID_KVD_SINGLE_MIN_SIZE] = 0x1002, [MLXSW_RES_ID_KVD_DOUBLE_MIN_SIZE] = 0x1003, [MLXSW_RES_ID_MAX_TRAP_GROUPS] = 0x2201, + [MLXSW_RES_ID_COUNTER_POOL_SIZE] = 0x2410, [MLXSW_RES_ID_MAX_SPAN] = 0x2420, [MLXSW_RES_ID_MAX_SYSTEM_PORT] = 0x2502, [MLXSW_RES_ID_MAX_LAG] = 0x2520, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 2104ee4..b8237f9 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -66,6 +66,7 @@ #include "port.h" #include "trap.h" #include "txheader.h" +#include "spectrum_cnt.h" static const char mlxsw_sp_driver_name[] = "mlxsw_spectrum"; static const char mlxsw_sp_driver_version[] = "1.0"; @@ -3224,6 +3225,12 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, goto err_acl_init; } + err = mlxsw_sp_counter_pool_init(mlxsw_sp); + if (err) { + dev_err(mlxsw_sp->bus_info->dev, "Failed to init counter pool\n"); + goto err_counter_pool_init; + } + err = mlxsw_sp_ports_create(mlxsw_sp); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Failed to create ports\n"); @@ -3233,6 +3240,8 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, return 0; err_ports_create: + mlxsw_sp_counter_pool_fini(mlxsw_sp); +err_counter_pool_init: mlxsw_sp_acl_fini(mlxsw_sp); err_acl_init: mlxsw_sp_span_fini(mlxsw_sp); @@ -3255,6 +3264,7 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core) struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); mlxsw_sp_ports_remove(mlxsw_sp); + mlxsw_sp_counter_pool_fini(mlxsw_sp); mlxsw_sp_acl_fini(mlxsw_sp); mlxsw_sp_span_fini(mlxsw_sp); mlxsw_sp_router_fini(mlxsw_sp); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 3bc1b09..dd59a9b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -246,6 +246,7 @@ struct mlxsw_sp_router { }; struct mlxsw_sp_acl; +struct mlxsw_sp_counter_pool; struct mlxsw_sp { struct { @@ -281,6 +282,7 @@ struct mlxsw_sp { DECLARE_BITMAP(usage, MLXSW_SP_KVD_LINEAR_SIZE); } kvdl; + struct mlxsw_sp_count
[patch net-next 2/9] mlxsw: reg: Add Monitoring General Purpose Counter Set register
From: Arkadi Sharshevsky The MGPC register retrieves generic flow counter value. It will be used to query ACL counters. Signed-off-by: Arkadi Sharshevsky Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 65 +++ 1 file changed, 65 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index eb94a5a..393743c 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -5506,6 +5506,70 @@ static inline void mlxsw_reg_mpsc_pack(char *payload, u8 local_port, bool e, mlxsw_reg_mpsc_rate_set(payload, rate); } +/* MGPC - Monitoring General Purpose Counter Set Register + * The MGPC register retrieves and sets the General Purpose Counter Set. + */ +#define MLXSW_REG_MGPC_ID 0x9081 +#define MLXSW_REG_MGPC_LEN 0x18 + +MLXSW_REG_DEFINE(mgpc, MLXSW_REG_MGPC_ID, MLXSW_REG_MGPC_LEN); + +enum mlxsw_reg_mgpc_counter_set_type { + /* No count */ + MLXSW_REG_MGPC_COUNTER_SET_TYPE_NO_COUT = 0x00, + /* Count packets and bytes */ + MLXSW_REG_MGPC_COUNTER_SET_TYPE_PACKETS_BYTES = 0x03, + /* Count only packets */ + MLXSW_REG_MGPC_COUNTER_SET_TYPE_PACKETS = 0x05, +}; + +/* reg_mgpc_counter_set_type + * Counter set type. + * Access: OP + */ +MLXSW_ITEM32(reg, mgpc, counter_set_type, 0x00, 24, 8); + +/* reg_mgpc_counter_index + * Counter index. + * Access: Index + */ +MLXSW_ITEM32(reg, mgpc, counter_index, 0x00, 0, 24); + +enum mlxsw_reg_mgpc_opcode { + /* Nop */ + MLXSW_REG_MGPC_OPCODE_NOP = 0x00, + /* Clear counters */ + MLXSW_REG_MGPC_OPCODE_CLEAR = 0x08, +}; + +/* reg_mgpc_opcode + * Opcode. + * Access: OP + */ +MLXSW_ITEM32(reg, mgpc, opcode, 0x04, 28, 4); + +/* reg_mgpc_byte_counter + * Byte counter value. + * Access: RW + */ +MLXSW_ITEM64(reg, mgpc, byte_counter, 0x08, 0, 64); + +/* reg_mgpc_packet_counter + * Packet counter value. + * Access: RW + */ +MLXSW_ITEM64(reg, mgpc, packet_counter, 0x10, 0, 64); + +static inline void mlxsw_reg_mgpc_pack(char *payload, u32 counter_index, + enum mlxsw_reg_mgpc_opcode opcode, + enum mlxsw_reg_mgpc_counter_set_type set_type) +{ + MLXSW_REG_ZERO(mgpc, payload); + mlxsw_reg_mgpc_counter_index_set(payload, counter_index); + mlxsw_reg_mgpc_counter_set_type_set(payload, set_type); + mlxsw_reg_mgpc_opcode_set(payload, opcode); +} + /* SBPR - Shared Buffer Pools Register * --- * The SBPR configures and retrieves the shared buffer pools and configuration. @@ -5979,6 +6043,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { MLXSW_REG(mpar), MLXSW_REG(mlcr), MLXSW_REG(mpsc), + MLXSW_REG(mgpc), MLXSW_REG(sbpr), MLXSW_REG(sbcm), MLXSW_REG(sbpm), -- 2.7.4
[patch net-next 0/9] mlxsw: Add support for TC flower offload statistics
From: Jiri Pirko Arkadi says: This patchset adds support for retrieving TC flower statistics for offloaded rules, which includes packets count, bytes count and last used time stamp. Currently The statistics are gathered on a per-rule basis. This patchset also includes generic allocator for counters. Arkadi Sharshevsky (9): mlxsw: spectrum: Add support for counter allocator mlxsw: reg: Add Monitoring General Purpose Counter Set register mlxsw: spectrum: Add support for generic flow counter allocation mlxsw: spectrum_acl_tcam: Add support for retrieving TCAM entry activity mlxsw: spectrum: Add support for direct rule access mlxsw: spectrum: Add periodic ACL rule activity update mlxsw: spectrum: Add support for Policing and Counting action block mlxsw: spectrum: Add support for counters on TCAM entries mlxsw: spectrum: Add support for TC flower offload statistics drivers/net/ethernet/mellanox/mlxsw/Makefile | 3 +- .../mellanox/mlxsw/core_acl_flex_actions.c | 51 ++ .../mellanox/mlxsw/core_acl_flex_actions.h | 2 + drivers/net/ethernet/mellanox/mlxsw/reg.h | 65 +++ drivers/net/ethernet/mellanox/mlxsw/resources.h| 4 + drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 67 +++ drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 20 +++ drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c | 143 ++- .../ethernet/mellanox/mlxsw/spectrum_acl_tcam.c| 42 + drivers/net/ethernet/mellanox/mlxsw/spectrum_cnt.c | 198 + drivers/net/ethernet/mellanox/mlxsw/spectrum_cnt.h | 53 ++ .../net/ethernet/mellanox/mlxsw/spectrum_flower.c | 49 + 12 files changed, 695 insertions(+), 2 deletions(-) create mode 100644 drivers/net/ethernet/mellanox/mlxsw/spectrum_cnt.c create mode 100644 drivers/net/ethernet/mellanox/mlxsw/spectrum_cnt.h -- 2.7.4