Re: [net-next 0/2] BPF, kprobes: Add current_in_cgroup helper
On Sat, Aug 06, 2016 at 09:32:05PM -0700, Alexei Starovoitov wrote: > On Sat, Aug 06, 2016 at 09:06:53PM -0700, Sargun Dhillon wrote: > > This patchset includes a helper and an example to determine whether the > > kprobe > > is currently executing in the context of a specific cgroup based on a cgroup > > bpf map / array. > > description is too short to understand how this new helper is going to be > used. > depending on kprobe current is not always valid. Anything not in in_interrupt() should have a current, right? > what are you trying to achieve? This is primarily to help troubleshoot containers (Docker, and now systemd). A lot of the time we want to determine what's going on in a given container (opening files, connecting to systems, etc...). There's not really a great way to restrict to containers except by manually walking datastructures to check for the right cgroup. This seems like a better alternative. > This looks like an alternative to lsm patches submitted earlier? No. But I would like to use this helper in the LSM patches I'm working on. For now, with those patches, and this helper, I can create a map sized 1, and add the cgroup I care about to it. Given I can add as many bpf programs to an LSM hook I want, I can use this mechanism to "attach BPF programs to cgroups" -- I put that in quotes because you're not really attaching it to a cgroup, but just burning some instructions on checking it. In my mind it seems better than making cgroup-attachment a first-class part of the checmate work since I still want to make globally available hooks possible. > btw net-next is closed and no new features accepted at the moment. Sorry, I didn't realize that. I'd still love to get feedback. >
Re: [net-next 0/2] BPF, kprobes: Add current_in_cgroup helper
On Sat, Aug 06, 2016 at 09:06:53PM -0700, Sargun Dhillon wrote: > This patchset includes a helper and an example to determine whether the > kprobe > is currently executing in the context of a specific cgroup based on a cgroup > bpf map / array. description is too short to understand how this new helper is going to be used. depending on kprobe current is not always valid. what are you trying to achieve? This looks like an alternative to lsm patches submitted earlier? btw net-next is closed and no new features accepted at the moment.
[net-next 2/2] samples/bpf: Add example using current_in_cgroup
This is a simple trace example that shows programs connecting, but only if they're in a chosen cgroup. Signed-off-by: Sargun DhillonCc: Alexei Starovoitov Cc: Daniel Borkmann --- samples/bpf/Makefile | 4 ++ samples/bpf/bpf_helpers.h | 2 + samples/bpf/trace_current_in_cgroup_kern.c | 44 samples/bpf/trace_current_in_cgroup_user.c | 66 ++ 4 files changed, 116 insertions(+) create mode 100644 samples/bpf/trace_current_in_cgroup_kern.c create mode 100644 samples/bpf/trace_current_in_cgroup_user.c diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 90ebf7d..61b0534 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -24,6 +24,7 @@ hostprogs-y += test_overhead hostprogs-y += test_cgrp2_array_pin hostprogs-y += xdp1 hostprogs-y += xdp2 +hostprogs-y += trace_current_in_cgroup test_verifier-objs := test_verifier.o libbpf.o test_maps-objs := test_maps.o libbpf.o @@ -49,6 +50,7 @@ test_cgrp2_array_pin-objs := libbpf.o test_cgrp2_array_pin.o xdp1-objs := bpf_load.o libbpf.o xdp1_user.o # reuse xdp1 source intentionally xdp2-objs := bpf_load.o libbpf.o xdp1_user.o +trace_current_in_cgroup-objs := bpf_load.o libbpf.o trace_current_in_cgroup_user.o # Tell kbuild to always build the programs always := $(hostprogs-y) @@ -74,6 +76,7 @@ always += parse_varlen.o parse_simple.o parse_ldabs.o always += test_cgrp2_tc_kern.o always += xdp1_kern.o always += xdp2_kern.o +always += trace_current_in_cgroup_kern.o HOSTCFLAGS += -I$(objtree)/usr/include @@ -97,6 +100,7 @@ HOSTLOADLIBES_map_perf_test += -lelf -lrt HOSTLOADLIBES_test_overhead += -lelf -lrt HOSTLOADLIBES_xdp1 += -lelf HOSTLOADLIBES_xdp2 += -lelf +HOSTLOADLIBES_trace_current_in_cgroup += -lelf # Allows pointing LLC/CLANG to a LLVM backend with bpf support, redefine on cmdline: # make samples/bpf/ LLC=~/git/llvm/build/bin/llc CLANG=~/git/llvm/build/bin/clang diff --git a/samples/bpf/bpf_helpers.h b/samples/bpf/bpf_helpers.h index 217c8d5..080403c 100644 --- a/samples/bpf/bpf_helpers.h +++ b/samples/bpf/bpf_helpers.h @@ -43,6 +43,8 @@ static int (*bpf_get_stackid)(void *ctx, void *map, int flags) = (void *) BPF_FUNC_get_stackid; static int (*bpf_probe_write_user)(void *dst, void *src, int size) = (void *) BPF_FUNC_probe_write_user; +static int (*bpf_current_in_cgroup)(void *map, int index) = + (void *) BPF_FUNC_current_in_cgroup; /* llvm builtin functions that eBPF C program may use to * emit BPF_LD_ABS and BPF_LD_IND instructions diff --git a/samples/bpf/trace_current_in_cgroup_kern.c b/samples/bpf/trace_current_in_cgroup_kern.c new file mode 100644 index 000..7aafb86 --- /dev/null +++ b/samples/bpf/trace_current_in_cgroup_kern.c @@ -0,0 +1,44 @@ +/* Copyright (c) 2016 Sargun Dhillon + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + */ + +#include +#include +#include +#include "bpf_helpers.h" +#include + +struct bpf_map_def SEC("maps") test_current_in_cgroup_map = { + .type = BPF_MAP_TYPE_CGROUP_ARRAY, + .key_size = sizeof(u32), + .value_size = sizeof(u32), + .max_entries = 1, +}; + +SEC("kprobe/sys_connect") +int bpf_prog1(struct pt_regs *ctx) +{ + struct sockaddr_in addr = {}; + void *sockaddr_arg = (void *)PT_REGS_PARM2(ctx); + int sockaddr_len = (int)PT_REGS_PARM3(ctx); + char fmt[] = "Connection on port %d\n"; + + if (!bpf_current_in_cgroup(_current_in_cgroup_map, 0)) + return 0; + if (sockaddr_len > sizeof(addr)) + return 0; + if (bpf_probe_read(, sizeof(addr), sockaddr_arg) != 0) + return 0; + if (addr.sin_family != AF_INET) + return 0; + + bpf_trace_printk(fmt, sizeof(fmt), be16_to_cpu(addr.sin_port)); + + return 1; +} + +char _license[] SEC("license") = "GPL"; +u32 _version SEC("version") = LINUX_VERSION_CODE; diff --git a/samples/bpf/trace_current_in_cgroup_user.c b/samples/bpf/trace_current_in_cgroup_user.c new file mode 100644 index 000..be717bb --- /dev/null +++ b/samples/bpf/trace_current_in_cgroup_user.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include "libbpf.h" +#include "bpf_load.h" +#include +#include +#include +#include +#include +#include +#include + +static void usage(char **argv) +{ + printf("Usage: %s [...]\n", argv[0]); + printf("-f Full path of the cgroup2\n"); + printf("-h Display this help\n"); +} + +int main(int argc, char **argv) +{ + char filename[256]; + const char *cg2 = NULL; + int ret, opt, cg2_fd; + int array_index = 0; + + while ((opt = getopt(argc, argv, "f:")) != -1) {
[net-next 0/2] BPF, kprobes: Add current_in_cgroup helper
This patchset includes a helper and an example to determine whether the kprobe is currently executing in the context of a specific cgroup based on a cgroup bpf map / array. Sargun Dhillon (2): bpf: Add bpf_current_in_cgroup helper samples/bpf: Add example using current_in_cgroup include/linux/bpf.h| 24 +++ include/uapi/linux/bpf.h | 11 + kernel/bpf/arraymap.c | 2 +- kernel/bpf/verifier.c | 4 +- kernel/trace/bpf_trace.c | 34 +++ net/core/filter.c | 11 ++--- samples/bpf/Makefile | 4 ++ samples/bpf/bpf_helpers.h | 2 + samples/bpf/trace_current_in_cgroup_kern.c | 44 samples/bpf/trace_current_in_cgroup_user.c | 66 ++ 10 files changed, 193 insertions(+), 9 deletions(-) create mode 100644 samples/bpf/trace_current_in_cgroup_kern.c create mode 100644 samples/bpf/trace_current_in_cgroup_user.c -- 2.7.4
[net-next 1/2] bpf: Add bpf_current_in_cgroup helper
This adds a kprobe helper that's similar to the skb_in_cgroup helper. It checks whether the probe is currently executing in the context of the cgroup at the given index a CGROUP_ARRAY. Signed-off-by: Sargun DhillonCc: Alexei Starovoitov Cc: Daniel Borkmann --- include/linux/bpf.h | 24 include/uapi/linux/bpf.h | 11 +++ kernel/bpf/arraymap.c| 2 +- kernel/bpf/verifier.c| 4 +++- kernel/trace/bpf_trace.c | 34 ++ net/core/filter.c| 11 --- 6 files changed, 77 insertions(+), 9 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 1113423..9adf712 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -319,4 +319,28 @@ extern const struct bpf_func_proto bpf_get_stackid_proto; void bpf_user_rnd_init_once(void); u64 bpf_user_rnd_u32(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); +#ifdef CONFIG_CGROUPS +/* Helper to fetch a cgroup pointer based on index. + * @map: a cgroup arraymap + * @idx: index of the item you want to fetch + * + * Returns pointer on success, + * Error code if item not found, or out-of-bounds access + */ +static inline struct cgroup *fetch_arraymap_ptr(struct bpf_map *map, int idx) +{ + struct cgroup *cgrp; + struct bpf_array *array = container_of(map, struct bpf_array, map); + + if (unlikely(idx >= array->map.max_entries)) + return ERR_PTR(-E2BIG); + + cgrp = READ_ONCE(array->ptrs[idx]); + if (unlikely(!cgrp)) + return ERR_PTR(-EAGAIN); + + return cgrp; +} +#endif /* CONFIG_CGROUPS */ + #endif /* _LINUX_BPF_H */ diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index da218fe..23a5b99 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -375,6 +375,17 @@ enum bpf_func_id { */ BPF_FUNC_probe_write_user, + /** +* bpf_current_in_cgroup(map, index) - Check cgroup2 membership of skb +* @map: pointer to bpf_map in BPF_MAP_TYPE_CGROUP_ARRAY type +* @index: index of the cgroup in the bpf_map +* Return: +* == 0 current failed the cgroup2 descendant test +* == 1 current succeeded the cgroup2 descendant test +*< 0 error +*/ + BPF_FUNC_current_in_cgroup, + __BPF_FUNC_MAX_ID, }; diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index 633a650..a2ac051 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -538,7 +538,7 @@ static int __init register_perf_event_array_map(void) } late_initcall(register_perf_event_array_map); -#ifdef CONFIG_SOCK_CGROUP_DATA +#ifdef CONFIG_CGROUPS static void *cgroup_fd_array_get_ptr(struct bpf_map *map, struct file *map_file /* not used */, int fd) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index f72f23b..e16559b 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -1052,7 +1052,8 @@ static int check_map_func_compatibility(struct bpf_map *map, int func_id) goto error; break; case BPF_MAP_TYPE_CGROUP_ARRAY: - if (func_id != BPF_FUNC_skb_in_cgroup) + if (func_id != BPF_FUNC_skb_in_cgroup && + func_id != BPF_FUNC_current_in_cgroup) goto error; break; default: @@ -1074,6 +1075,7 @@ static int check_map_func_compatibility(struct bpf_map *map, int func_id) if (map->map_type != BPF_MAP_TYPE_STACK_TRACE) goto error; break; + case BPF_FUNC_current_in_cgroup: case BPF_FUNC_skb_in_cgroup: if (map->map_type != BPF_MAP_TYPE_CGROUP_ARRAY) goto error; diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index b20438f..f2a6bc5 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -376,6 +376,36 @@ static const struct bpf_func_proto bpf_get_current_task_proto = { .ret_type = RET_INTEGER, }; +#ifdef CONFIG_CGROUPS +static u64 bpf_current_in_cgroup(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5) +{ + struct bpf_map *map = (struct bpf_map *)(long)r1; + struct css_set *cset; + struct cgroup *cgrp; + u32 idx = (u32)r2; + + if (unlikely(in_interrupt())) + return -EINVAL; + + cgrp = fetch_arraymap_ptr(map, idx); + + if (unlikely(IS_ERR(cgrp))) + return PTR_ERR(cgrp); + + cset = task_css_set(current); + + return cgroup_is_descendant(cset->dfl_cgrp, cgrp); +} + +static const struct bpf_func_proto bpf_current_in_cgroup_proto = { + .func = bpf_current_in_cgroup, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_CONST_MAP_PTR, + .arg2_type =
[PATCH v2 04/14] net: ethernet: ti: cpsw: remove clk var from priv
There is no need to hold link to clk, it's used only once while probe. Signed-off-by: Ivan Khoronzhuk--- drivers/net/ethernet/ti/cpsw.c | 10 -- 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 30e1ddb..70a9570 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -379,7 +379,6 @@ struct cpsw_priv { u32 coal_intvl; u32 bus_freq_mhz; int rx_packet_max; - struct clk *clk; u8 mac_addr[ETH_ALEN]; struct cpsw_slave *slaves; struct cpdma_ctlr *dma; @@ -2179,8 +2178,6 @@ static int cpsw_probe_dual_emac(struct platform_device *pdev, memcpy(ndev->dev_addr, priv_sl2->mac_addr, ETH_ALEN); priv_sl2->slaves = priv->slaves; - priv_sl2->clk = priv->clk; - priv_sl2->coal_intvl = 0; priv_sl2->bus_freq_mhz = priv->bus_freq_mhz; @@ -2258,6 +2255,7 @@ MODULE_DEVICE_TABLE(of, cpsw_of_mtable); static int cpsw_probe(struct platform_device *pdev) { + struct clk *clk; struct cpsw_platform_data *data; struct net_device *ndev; struct cpsw_priv*priv; @@ -2336,14 +2334,14 @@ static int cpsw_probe(struct platform_device *pdev) priv->slaves[0].ndev = ndev; priv->emac_port = 0; - priv->clk = devm_clk_get(>dev, "fck"); - if (IS_ERR(priv->clk)) { + clk = devm_clk_get(>dev, "fck"); + if (IS_ERR(clk)) { dev_err(priv->dev, "fck is not found\n"); ret = -ENODEV; goto clean_runtime_disable_ret; } priv->coal_intvl = 0; - priv->bus_freq_mhz = clk_get_rate(priv->clk) / 100; + priv->bus_freq_mhz = clk_get_rate(clk) / 100; ss_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ss_regs = devm_ioremap_resource(>dev, ss_res); -- 1.9.1
[PATCH v2 01/14] net: ethernet: ti: cpsw: simplify submit routine
As second net dev is created only in case of dual_emac mode, port number can be figured out in simpler way. Also no need to pass redundant ndev struct. Signed-off-by: Ivan Khoronzhuk--- drivers/net/ethernet/ti/cpsw.c | 18 +- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index c51f346..8972bf6 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -1065,19 +1065,11 @@ static int cpsw_common_res_usage_state(struct cpsw_priv *priv) return usage_count; } -static inline int cpsw_tx_packet_submit(struct net_device *ndev, - struct cpsw_priv *priv, struct sk_buff *skb) +static inline int cpsw_tx_packet_submit(struct cpsw_priv *priv, + struct sk_buff *skb) { - if (!priv->data.dual_emac) - return cpdma_chan_submit(priv->txch, skb, skb->data, - skb->len, 0); - - if (ndev == cpsw_get_slave_ndev(priv, 0)) - return cpdma_chan_submit(priv->txch, skb, skb->data, - skb->len, 1); - else - return cpdma_chan_submit(priv->txch, skb, skb->data, - skb->len, 2); + return cpdma_chan_submit(priv->txch, skb, skb->data, skb->len, +priv->emac_port + priv->data.dual_emac); } static inline void cpsw_add_dual_emac_def_ale_entries( @@ -1406,7 +1398,7 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb, skb_tx_timestamp(skb); - ret = cpsw_tx_packet_submit(ndev, priv, skb); + ret = cpsw_tx_packet_submit(priv, skb); if (unlikely(ret != 0)) { cpsw_err(priv, tx_err, "desc submit failed\n"); goto fail; -- 1.9.1
[PATCH v2 05/14] net: ethernet: ti: cpsw: don't check slave num in runtime
No need to check const slave num in runtime for every packet, and ndev for slaves w/o ndev is anyway NULL. So remove redundant check. Signed-off-by: Ivan Khoronzhuk--- drivers/net/ethernet/ti/cpsw.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 70a9570..19aa4bb 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -498,8 +498,7 @@ static const struct cpsw_stats cpsw_gstrings_stats[] = { (func)(slave++, ##arg); \ } while (0) #define cpsw_get_slave_ndev(priv, __slave_no__) \ - ((__slave_no__ < priv->data.slaves) ? \ - priv->slaves[__slave_no__].ndev : NULL) + priv->slaves[__slave_no__].ndev #define cpsw_get_slave_priv(priv, __slave_no__) \ (((__slave_no__ < priv->data.slaves) && \ (priv->slaves[__slave_no__].ndev)) ?\ -- 1.9.1
[PATCH v2 13/14] net: ethernet: ti: cpsw: move napi struct to cpsw_common
The napi structs are common for both net devices in dual_emac mode, In order to not hold duplicate links to them, move to cpsw_common. Signed-off-by: Ivan Khoronzhuk--- drivers/net/ethernet/ti/cpsw.c | 50 +++--- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 395531d..e0a1b80 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -367,6 +367,8 @@ static inline void slave_write(struct cpsw_slave *slave, u32 val, u32 offset) struct cpsw_common { struct device *dev; struct cpsw_platform_data data; + struct napi_struct napi_rx; + struct napi_struct napi_tx; struct cpsw_ss_regs __iomem *regs; struct cpsw_wr_regs __iomem *wr_regs; u8 __iomem *hw_stats; @@ -383,8 +385,6 @@ struct cpsw_common { struct cpsw_priv { struct net_device *ndev; - struct napi_struct napi_rx; - struct napi_struct napi_tx; struct device *dev; u32 msg_enable; u32 version; @@ -489,7 +489,7 @@ static const struct cpsw_stats cpsw_gstrings_stats[] = { #define CPSW_STATS_LEN ARRAY_SIZE(cpsw_gstrings_stats) #define ndev_to_cpsw(ndev) (((struct cpsw_priv *)netdev_priv(ndev))->cpsw) -#define napi_to_priv(napi) container_of(napi, struct cpsw_priv, napi) +#define napi_to_cpsw(napi) container_of(napi, struct cpsw_common, napi) #define for_each_slave(priv, func, arg...) \ do {\ struct cpsw_slave *slave; \ @@ -755,8 +755,7 @@ requeue: static irqreturn_t cpsw_tx_interrupt(int irq, void *dev_id) { - struct cpsw_priv *priv = dev_id; - struct cpsw_common *cpsw = priv->cpsw; + struct cpsw_common *cpsw = dev_id; writel(0, >wr_regs->tx_en); cpdma_ctlr_eoi(cpsw->dma, CPDMA_EOI_TX); @@ -766,14 +765,13 @@ static irqreturn_t cpsw_tx_interrupt(int irq, void *dev_id) cpsw->tx_irq_disabled = true; } - napi_schedule(>napi_tx); + napi_schedule(>napi_tx); return IRQ_HANDLED; } static irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id) { - struct cpsw_priv *priv = dev_id; - struct cpsw_common *cpsw = priv->cpsw; + struct cpsw_common *cpsw = dev_id; cpdma_ctlr_eoi(cpsw->dma, CPDMA_EOI_RX); writel(0, >wr_regs->rx_en); @@ -783,15 +781,14 @@ static irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id) cpsw->rx_irq_disabled = true; } - napi_schedule(>napi_rx); + napi_schedule(>napi_rx); return IRQ_HANDLED; } static int cpsw_tx_poll(struct napi_struct *napi_tx, int budget) { - struct cpsw_priv*priv = napi_to_priv(napi_tx); + struct cpsw_common *cpsw = napi_to_cpsw(napi_tx); int num_tx; - struct cpsw_common *cpsw = priv->cpsw; num_tx = cpdma_chan_process(cpsw->txch, budget); if (num_tx < budget) { @@ -811,9 +808,8 @@ static int cpsw_tx_poll(struct napi_struct *napi_tx, int budget) static int cpsw_rx_poll(struct napi_struct *napi_rx, int budget) { - struct cpsw_priv*priv = napi_to_priv(napi_rx); + struct cpsw_common *cpsw = napi_to_cpsw(napi_rx); int num_rx; - struct cpsw_common *cpsw = priv->cpsw; num_rx = cpdma_chan_process(cpsw->rxch, budget); if (num_rx < budget) { @@ -1292,7 +1288,6 @@ static int cpsw_ndo_open(struct net_device *ndev) ALE_ALL_PORTS, ALE_ALL_PORTS, 0, 0); if (!cpsw_common_res_usage_state(cpsw)) { - struct cpsw_priv *priv_sl0 = cpsw_get_slave_priv(cpsw, 0); int buf_num; /* setup tx dma to fixed prio and zero offset */ @@ -1308,8 +1303,8 @@ static int cpsw_ndo_open(struct net_device *ndev) /* Enable internal fifo flow control */ writel(0x7, >regs->flow_control); - napi_enable(_sl0->napi_rx); - napi_enable(_sl0->napi_tx); + napi_enable(>napi_rx); + napi_enable(>napi_tx); if (cpsw->tx_irq_disabled) { cpsw->tx_irq_disabled = false; @@ -1384,8 +1379,8 @@ static int cpsw_ndo_stop(struct net_device *ndev) if (cpsw_common_res_usage_state(cpsw) <= 1) { struct cpsw_priv *priv_sl0 = cpsw_get_slave_priv(cpsw, 0); - napi_disable(_sl0->napi_rx); - napi_disable(_sl0->napi_tx); + napi_disable(>napi_rx); +
[PATCH v2 08/14] net: ethernet: ti: cpsw: move links on h/w registers to cpsw_common
The pointers on h/w registers are common for every cpsw_private instance, so no need to hold them for every ndev. Signed-off-by: Ivan Khoronzhuk--- drivers/net/ethernet/ti/cpsw.c | 97 +++--- 1 file changed, 53 insertions(+), 44 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index a813bac..6fc22df 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -365,6 +365,10 @@ static inline void slave_write(struct cpsw_slave *slave, u32 val, u32 offset) struct cpsw_common { struct device *dev; + struct cpsw_ss_regs __iomem *regs; + struct cpsw_wr_regs __iomem *wr_regs; + u8 __iomem *hw_stats; + struct cpsw_host_regs __iomem *host_port_regs; }; struct cpsw_priv { @@ -373,10 +377,6 @@ struct cpsw_priv { struct napi_struct napi_tx; struct device *dev; struct cpsw_platform_data data; - struct cpsw_ss_regs __iomem *regs; - struct cpsw_wr_regs __iomem *wr_regs; - u8 __iomem *hw_stats; - struct cpsw_host_regs __iomem *host_port_regs; u32 msg_enable; u32 version; u32 coal_intvl; @@ -658,8 +658,10 @@ static void cpsw_ndo_set_rx_mode(struct net_device *ndev) static void cpsw_intr_enable(struct cpsw_priv *priv) { - __raw_writel(0xFF, >wr_regs->tx_en); - __raw_writel(0xFF, >wr_regs->rx_en); + struct cpsw_common *cpsw = priv->cpsw; + + __raw_writel(0xFF, >wr_regs->tx_en); + __raw_writel(0xFF, >wr_regs->rx_en); cpdma_ctlr_int_ctrl(priv->dma, true); return; @@ -667,8 +669,10 @@ static void cpsw_intr_enable(struct cpsw_priv *priv) static void cpsw_intr_disable(struct cpsw_priv *priv) { - __raw_writel(0, >wr_regs->tx_en); - __raw_writel(0, >wr_regs->rx_en); + struct cpsw_common *cpsw = priv->cpsw; + + __raw_writel(0, >wr_regs->tx_en); + __raw_writel(0, >wr_regs->rx_en); cpdma_ctlr_int_ctrl(priv->dma, false); return; @@ -752,8 +756,9 @@ requeue: static irqreturn_t cpsw_tx_interrupt(int irq, void *dev_id) { struct cpsw_priv *priv = dev_id; + struct cpsw_common *cpsw = priv->cpsw; - writel(0, >wr_regs->tx_en); + writel(0, >wr_regs->tx_en); cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX); if (priv->quirk_irq) { @@ -768,9 +773,10 @@ static irqreturn_t cpsw_tx_interrupt(int irq, void *dev_id) static irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id) { struct cpsw_priv *priv = dev_id; + struct cpsw_common *cpsw = priv->cpsw; cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX); - writel(0, >wr_regs->rx_en); + writel(0, >wr_regs->rx_en); if (priv->quirk_irq) { disable_irq_nosync(priv->irqs_table[0]); @@ -785,11 +791,12 @@ static int cpsw_tx_poll(struct napi_struct *napi_tx, int budget) { struct cpsw_priv*priv = napi_to_priv(napi_tx); int num_tx; + struct cpsw_common *cpsw = priv->cpsw; num_tx = cpdma_chan_process(priv->txch, budget); if (num_tx < budget) { napi_complete(napi_tx); - writel(0xff, >wr_regs->tx_en); + writel(0xff, >wr_regs->tx_en); if (priv->quirk_irq && priv->tx_irq_disabled) { priv->tx_irq_disabled = false; enable_irq(priv->irqs_table[1]); @@ -804,11 +811,12 @@ static int cpsw_rx_poll(struct napi_struct *napi_rx, int budget) { struct cpsw_priv*priv = napi_to_priv(napi_rx); int num_rx; + struct cpsw_common *cpsw = priv->cpsw; num_rx = cpdma_chan_process(priv->rxch, budget); if (num_rx < budget) { napi_complete(napi_rx); - writel(0xff, >wr_regs->rx_en); + writel(0xff, >wr_regs->rx_en); if (priv->quirk_irq && priv->rx_irq_disabled) { priv->rx_irq_disabled = false; enable_irq(priv->irqs_table[0]); @@ -929,10 +937,11 @@ static int cpsw_set_coalesce(struct net_device *ndev, u32 prescale = 0; u32 addnl_dvdr = 1; u32 coal_intvl = 0; + struct cpsw_common *cpsw = priv->cpsw; coal_intvl = coal->rx_coalesce_usecs; - int_ctrl = readl(>wr_regs->int_control); + int_ctrl = readl(>wr_regs->int_control); prescale = priv->bus_freq_mhz * 4; if (!coal->rx_coalesce_usecs) { @@ -961,15 +970,15 @@ static int cpsw_set_coalesce(struct net_device *ndev, } num_interrupts = (1000 * addnl_dvdr) / coal_intvl; - writel(num_interrupts, >wr_regs->rx_imax); -
[PATCH v2 02/14] net: ethernet: ti: cpsw: remove redundant check in napi poll
No need to check number of handled packets, when in most cases (> 99%) it's not 0. It can be 0 only in rare cases, even in this case it's not bad to print just 0. Signed-off-by: Ivan Khoronzhuk--- drivers/net/ethernet/ti/cpsw.c | 8 ++-- 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 8972bf6..85ee9f5 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -793,9 +793,7 @@ static int cpsw_tx_poll(struct napi_struct *napi_tx, int budget) } } - if (num_tx) - cpsw_dbg(priv, intr, "poll %d tx pkts\n", num_tx); - + cpsw_dbg(priv, intr, "poll %d tx pkts\n", num_tx); return num_tx; } @@ -814,9 +812,7 @@ static int cpsw_rx_poll(struct napi_struct *napi_rx, int budget) } } - if (num_rx) - cpsw_dbg(priv, intr, "poll %d rx pkts\n", num_rx); - + cpsw_dbg(priv, intr, "poll %d rx pkts\n", num_rx); return num_rx; } -- 1.9.1
[PATCH v2 00/14] net: ethernet: ti: cpsw: split driver data and per ndev data
In dual_emac mode the driver can handle 2 network devices. Each of them can use its own private data and common data/resources. This patchset splits common driver data/resources and private per net device data. It leads to: - reduce memory usage - increase code readability - allows add a bunch of simplification - create prerequisites to add multi-channel support, when channels are shared between net devices Doesn't have bad impact on performance. v1: https://lkml.org/lkml/2016/8/4/616 Since v1: - added several patch improvements - avoided variable reordering in structures - removed static variable for common function - split big patch on several patches: net: ethernet: ti: cpsw: remove priv from cpsw_get_slave_port() parameters list net: ethernet: ti: cpsw: remove clk var from priv net: ethernet: ti: cpsw: don't check slave num in runtime net: ethernet: ti: cpsw: create common struct to hold shared driver data net: ethernet: ti: cpsw: replace pdev on dev net: ethernet: ti: cpsw: move links on h/w registers to cpsw_common net: ethernet: ti: cpsw: move cpdma resources to cpsw_common net; ethernet: ti: cpsw: move irq stuff under cpsw_common net: ethernet: ti: cpsw: move data platform data and slaves info to cpsw_common net: ethernet: ti: cpsw: fix int dbg message net: ethernet: ti: cpsw: move napi struct to cpsw_common net: ethernet: ti: cpsw: move ale, cpts and drivers params under Based on net-next/master Ivan Khoronzhuk (14): net: ethernet: ti: cpsw: simplify submit routine net: ethernet: ti: cpsw: remove redundant check in napi poll net: ethernet: ti: cpsw: remove priv from cpsw_get_slave_port() parameters list net: ethernet: ti: cpsw: remove clk var from priv net: ethernet: ti: cpsw: don't check slave num in runtime net: ethernet: ti: cpsw: create common struct to hold shared driver data net: ethernet: ti: cpsw: replace pdev on dev net: ethernet: ti: cpsw: move links on h/w registers to cpsw_common net: ethernet: ti: cpsw: move cpdma resources to cpsw_common net; ethernet: ti: cpsw: move irq stuff under cpsw_common net: ethernet: ti: cpsw: move data platform data and slaves info to cpsw_common net: ethernet: ti: cpsw: fix int dbg message net: ethernet: ti: cpsw: move napi struct to cpsw_common net: ethernet: ti: cpsw: move ale, cpts and drivers params under cpsw_common drivers/net/ethernet/ti/cpsw.c | 879 + 1 file changed, 447 insertions(+), 432 deletions(-) -- 1.9.1
[PATCH v2 10/14] net; ethernet: ti: cpsw: move irq stuff under cpsw_common
The irq data are common per net device. So no need to hold these data per net dev, move it under cpsw_common. Also delete irq_num var, as after optimization it's not needed. Correct number of irqs to 2, as anyway, driver is using only 2, at least for now. Signed-off-by: Ivan Khoronzhuk--- drivers/net/ethernet/ti/cpsw.c | 65 +++--- 1 file changed, 29 insertions(+), 36 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index d3af373..4080487 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -143,6 +143,7 @@ do { \ #define cpsw_slave_index(priv) \ ((priv->data.dual_emac) ? priv->emac_port : \ priv->data.active_slave) +#define IRQ_NUM2 static int debug_level; module_param(debug_level, int, 0); @@ -371,6 +372,10 @@ struct cpsw_common { struct cpsw_host_regs __iomem *host_port_regs; struct cpdma_ctlr *dma; struct cpdma_chan *txch, *rxch; + boolquirk_irq; + boolrx_irq_disabled; + booltx_irq_disabled; + u32 irqs_table[IRQ_NUM]; }; struct cpsw_priv { @@ -389,12 +394,6 @@ struct cpsw_priv { struct cpsw_ale *ale; boolrx_pause; booltx_pause; - boolquirk_irq; - boolrx_irq_disabled; - booltx_irq_disabled; - /* snapshot of IRQ numbers */ - u32 irqs_table[4]; - u32 num_irqs; struct cpts *cpts; u32 emac_port; struct cpsw_common *cpsw; @@ -758,9 +757,9 @@ static irqreturn_t cpsw_tx_interrupt(int irq, void *dev_id) writel(0, >wr_regs->tx_en); cpdma_ctlr_eoi(cpsw->dma, CPDMA_EOI_TX); - if (priv->quirk_irq) { - disable_irq_nosync(priv->irqs_table[1]); - priv->tx_irq_disabled = true; + if (cpsw->quirk_irq) { + disable_irq_nosync(cpsw->irqs_table[1]); + cpsw->tx_irq_disabled = true; } napi_schedule(>napi_tx); @@ -775,9 +774,9 @@ static irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id) cpdma_ctlr_eoi(cpsw->dma, CPDMA_EOI_RX); writel(0, >wr_regs->rx_en); - if (priv->quirk_irq) { - disable_irq_nosync(priv->irqs_table[0]); - priv->rx_irq_disabled = true; + if (cpsw->quirk_irq) { + disable_irq_nosync(cpsw->irqs_table[0]); + cpsw->rx_irq_disabled = true; } napi_schedule(>napi_rx); @@ -794,9 +793,9 @@ static int cpsw_tx_poll(struct napi_struct *napi_tx, int budget) if (num_tx < budget) { napi_complete(napi_tx); writel(0xff, >wr_regs->tx_en); - if (priv->quirk_irq && priv->tx_irq_disabled) { - priv->tx_irq_disabled = false; - enable_irq(priv->irqs_table[1]); + if (cpsw->quirk_irq && cpsw->tx_irq_disabled) { + cpsw->tx_irq_disabled = false; + enable_irq(cpsw->irqs_table[1]); } } @@ -814,9 +813,9 @@ static int cpsw_rx_poll(struct napi_struct *napi_rx, int budget) if (num_rx < budget) { napi_complete(napi_rx); writel(0xff, >wr_regs->rx_en); - if (priv->quirk_irq && priv->rx_irq_disabled) { - priv->rx_irq_disabled = false; - enable_irq(priv->irqs_table[0]); + if (cpsw->quirk_irq && cpsw->rx_irq_disabled) { + cpsw->rx_irq_disabled = false; + enable_irq(cpsw->irqs_table[0]); } } @@ -1303,14 +1302,14 @@ static int cpsw_ndo_open(struct net_device *ndev) napi_enable(_sl0->napi_rx); napi_enable(_sl0->napi_tx); - if (priv_sl0->tx_irq_disabled) { - priv_sl0->tx_irq_disabled = false; - enable_irq(priv->irqs_table[1]); + if (cpsw->tx_irq_disabled) { + cpsw->tx_irq_disabled = false; + enable_irq(cpsw->irqs_table[1]); } - if (priv_sl0->rx_irq_disabled) { - priv_sl0->rx_irq_disabled = false; - enable_irq(priv->irqs_table[0]); + if (cpsw->rx_irq_disabled) { + cpsw->rx_irq_disabled = false; + enable_irq(cpsw->irqs_table[0]); } buf_num = cpdma_chan_get_rx_buf_num(cpsw->dma); @@ -1659,8
[PATCH v2 03/14] net: ethernet: ti: cpsw: remove priv from cpsw_get_slave_port() parameters list
There is no need in priv here. Signed-off-by: Ivan Khoronzhuk--- drivers/net/ethernet/ti/cpsw.c | 10 +- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 85ee9f5..30e1ddb 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -525,7 +525,7 @@ static const struct cpsw_stats cpsw_gstrings_stats[] = { if (priv->data.dual_emac) { \ struct cpsw_slave *slave = priv->slaves + \ priv->emac_port;\ - int slave_port = cpsw_get_slave_port(priv, \ + int slave_port = cpsw_get_slave_port( \ slave->slave_num); \ cpsw_ale_add_mcast(priv->ale, addr, \ 1 << slave_port | ALE_PORT_HOST,\ @@ -537,7 +537,7 @@ static const struct cpsw_stats cpsw_gstrings_stats[] = { } \ } while (0) -static inline int cpsw_get_slave_port(struct cpsw_priv *priv, u32 slave_num) +static inline int cpsw_get_slave_port(u32 slave_num) { return slave_num + 1; } @@ -849,7 +849,7 @@ static void _cpsw_adjust_link(struct cpsw_slave *slave, if (!phy) return; - slave_port = cpsw_get_slave_port(priv, slave->slave_num); + slave_port = cpsw_get_slave_port(slave->slave_num); if (phy->link) { mac_control = priv->data.mac_control; @@ -1120,7 +1120,7 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv) slave->mac_control = 0; /* no link yet */ - slave_port = cpsw_get_slave_port(priv, slave->slave_num); + slave_port = cpsw_get_slave_port(slave->slave_num); if (priv->data.dual_emac) cpsw_add_dual_emac_def_ale_entries(priv, slave, slave_port); @@ -1222,7 +1222,7 @@ static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv) { u32 slave_port; - slave_port = cpsw_get_slave_port(priv, slave->slave_num); + slave_port = cpsw_get_slave_port(slave->slave_num); if (!slave->phy) return; -- 1.9.1
[PATCH v2 07/14] net: ethernet: ti: cpsw: replace pdev on dev
No need to hold pdev link when only dev is needed. This allows to simplify a bunch of cpsw->pdev->dev now and farther. Signed-off-by: Ivan Khoronzhuk--- drivers/net/ethernet/ti/cpsw.c | 65 ++ 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index ac875b3..a813bac 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -364,7 +364,7 @@ static inline void slave_write(struct cpsw_slave *slave, u32 val, u32 offset) } struct cpsw_common { - struct platform_device *pdev; + struct device *dev; }; struct cpsw_priv { @@ -1159,7 +1159,7 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv) phy_start(slave->phy); /* Configure GMII_SEL register */ - cpsw_phy_sel(>pdev->dev, slave->phy->interface, slave->slave_num); + cpsw_phy_sel(cpsw->dev, slave->phy->interface, slave->slave_num); } static inline void cpsw_add_default_vlan(struct cpsw_priv *priv) @@ -1245,9 +1245,9 @@ static int cpsw_ndo_open(struct net_device *ndev) int i, ret; u32 reg; - ret = pm_runtime_get_sync(>pdev->dev); + ret = pm_runtime_get_sync(cpsw->dev); if (ret < 0) { - pm_runtime_put_noidle(>pdev->dev); + pm_runtime_put_noidle(cpsw->dev); return ret; } @@ -1324,7 +1324,7 @@ static int cpsw_ndo_open(struct net_device *ndev) */ cpsw_info(priv, ifup, "submitted %d rx descriptors\n", i); - if (cpts_register(>pdev->dev, priv->cpts, + if (cpts_register(cpsw->dev, priv->cpts, priv->data.cpts_clock_mult, priv->data.cpts_clock_shift)) dev_err(priv->dev, "error registering cpts device\n"); @@ -1349,7 +1349,7 @@ static int cpsw_ndo_open(struct net_device *ndev) err_cleanup: cpdma_ctlr_stop(priv->dma); for_each_slave(priv, cpsw_slave_stop, priv); - pm_runtime_put_sync(>pdev->dev); + pm_runtime_put_sync(cpsw->dev); netif_carrier_off(priv->ndev); return ret; } @@ -1374,7 +1374,7 @@ static int cpsw_ndo_stop(struct net_device *ndev) cpsw_ale_stop(priv->ale); } for_each_slave(priv, cpsw_slave_stop, priv); - pm_runtime_put_sync(>pdev->dev); + pm_runtime_put_sync(cpsw->dev); if (priv->data.dual_emac) priv->slaves[priv->emac_port].open_stat = false; return 0; @@ -1614,9 +1614,9 @@ static int cpsw_ndo_set_mac_address(struct net_device *ndev, void *p) if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; - ret = pm_runtime_get_sync(>pdev->dev); + ret = pm_runtime_get_sync(cpsw->dev); if (ret < 0) { - pm_runtime_put_noidle(>pdev->dev); + pm_runtime_put_noidle(cpsw->dev); return ret; } @@ -1634,7 +1634,7 @@ static int cpsw_ndo_set_mac_address(struct net_device *ndev, void *p) memcpy(ndev->dev_addr, priv->mac_addr, ETH_ALEN); for_each_slave(priv, cpsw_set_slave_mac, priv); - pm_runtime_put(>pdev->dev); + pm_runtime_put(cpsw->dev); return 0; } @@ -1706,9 +1706,9 @@ static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev, if (vid == priv->data.default_vlan) return 0; - ret = pm_runtime_get_sync(>pdev->dev); + ret = pm_runtime_get_sync(cpsw->dev); if (ret < 0) { - pm_runtime_put_noidle(>pdev->dev); + pm_runtime_put_noidle(cpsw->dev); return ret; } @@ -1728,7 +1728,7 @@ static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev, dev_info(priv->dev, "Adding vlanid %d to vlan filter\n", vid); ret = cpsw_add_vlan_ale_entry(priv, vid); - pm_runtime_put(>pdev->dev); + pm_runtime_put(cpsw->dev); return ret; } @@ -1742,9 +1742,9 @@ static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev, if (vid == priv->data.default_vlan) return 0; - ret = pm_runtime_get_sync(>pdev->dev); + ret = pm_runtime_get_sync(cpsw->dev); if (ret < 0) { - pm_runtime_put_noidle(>pdev->dev); + pm_runtime_put_noidle(cpsw->dev); return ret; } @@ -1769,7 +1769,7 @@ static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev, ret = cpsw_ale_del_mcast(priv->ale, priv->ndev->broadcast, 0, ALE_VLAN, vid); - pm_runtime_put(>pdev->dev); + pm_runtime_put(cpsw->dev); return ret; } @@ -1813,10 +1813,11 @@ static void cpsw_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo
Re: [PATCH net] bridge: Fix problems around fdb entries pointing to the bridge device
On Thu, 04 Aug 2016 11:27:25 -0700 Roopa Prabhuwrote: > On 8/4/16, 1:15 AM, Toshiaki Makita wrote: > > On 2016/08/04 16:24, Roopa Prabhu wrote: > >> On 8/3/16, 7:11 PM, Toshiaki Makita wrote: > >>> Adding fdb entries pointing to the bridge device uses fdb_insert(), > >>> which lacks various checks and does not respect added_by_user flag. > >>> > >>> As a result, some inconsistent behavior can happen: > >>> * Adding temporary entries succeeds but results in permanent entries. > >> IIRC this is not specific to fdb entries on the bridge device. all temp > >> fdb entries via iproute2 result in permanent entries. thats why 'dynamic' > >> was added. > > Sorry for confusing you, I meant "temp" (i.e., "static") of bridge fdb > > command. > > "temp", "dynamic" and "use" should not result in "permanent". > > > >>> * Same goes for "dynamic" and "use". > >> This patch seems to not allow dynamic and use entries > >> on the bridge device. I don't see a strong use-case to > >> allow them, but any reason you want to add the restriction now ? > > Because dynamic fdb entries pointing the bridge device cannot be > > created. So it is prohibited. I cannot find other appropriate behavior > > about this. > > Or are you suggesting local entries with aging supported or something > > like that? > no, i am ok with prohibiting it, just was wondering if this is necessary. > > > > >>> * Changing mac address of the bridge device causes deletion of > >>> user-added entries. > >> unless I am missing something, this does not seem to be related to the > >> external fdb entry on the bridge device. > > Yes this is related to manually-added fdb entries on the bridge device. > > When manual addition of fdb pointing the bridge device was introduced, > > we should have set added_by_user on adding the entry and modify > > br_fdb_change_mac_address() to respect the flag, but both were not done. > > > >>> * Replacing existing entries looks successful from userspace but actually > >>> not, regardless of NLM_F_EXCL flag. > >> curious about this one. I will try it, but if you have an example that > >> will help. > > Before: > > # bridge fdb add 12:34:56:78:90:ab dev enp3s0 master > > # bridge fdb add 12:34:56:78:90:ab dev br0; echo $? > > 0 > > # bridge fdb show > > ... > > 12:34:56:78:90:ab dev enp3s0 master br0 permanent > > > > # bridge fdb replace 12:34:56:78:90:ab dev br0; echo $? > > 0 > > # bridge fdb show > > ... > > 12:34:56:78:90:ab dev enp3s0 master br0 permanent > > > > After: > > # bridge fdb add 12:34:56:78:90:ab dev enp3s0 master > > # bridge fdb add 12:34:56:78:90:ab dev br0; echo $? > > RTNETLINK answers: File exists > > 255 > > > > # bridge fdb replace 12:34:56:78:90:ab dev br0; echo $? > > 0 > > # bridge fdb show > > ... > > 12:34:56:78:90:ab dev br0 master br0 permanent > > > ok, thanks for the example. > > Acked-by: Roopa Prabhu It should be possible to manually add fdb entries with any combination of valid flags. That is it should be possible to add temporary as well as permanent entries. There are people that use this facility to do long and short ageing temporary entries.
Re: [PATCH iproute v2 2/5] ila: Support for configuring ila to use netfilter hook
I have no problem with this series in general and wanted to put it in before closing the lid on 4.7 version, BUT. This patch generates warnings when built on Debian Strech with gcc-5 ipila.c: In function ‘ila_parse_opt.constprop’: ipila.c:205:2: warning: ‘locator_match’ may be used uninitialized in this function [-Wmaybe-uninitialized] addattr64(n, 1024, ILA_ATTR_LOCATOR_MATCH, locator_match); if (matches(*argv, "add") == 0) > + return do_add(argc-1, argv+1); > + if (matches(*argv, "delete") == 0) > + return do_del(argc-1, argv+1); > + if (matches(*argv, "list") == 0) > + return do_list(argc-1, argv+1); > + if (matches(*argv, "help") == 0) > + usage(); > + > + fprintf(stderr, "Command \"%s\" is unknown, try \"ip ila help\".\n", > + *argv); > + exit(-1); > +} > + You also added a blank line at end of file. Please fix this and resubmit the series.
Re: [PATCH v2 12/14] net: ethernet: ti: cpsw: fix int dbg message
On Sat, 2016-08-06 at 13:48 +0300, Ivan Khoronzhuk wrote: > While poll handlers there is no possibility to figure out > which network device is handling packets, as cpdma channels > are common for both network devices in dual_emac mode. Currently, > the messages are printed only for one device, in fact, there is two. > So, better to print integrated num_tx value for both devices if > any of them is allowed to. [] > diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c [] > @@ -378,6 +378,7 @@ struct cpsw_common { > boolrx_irq_disabled; > booltx_irq_disabled; > u32 irqs_table[IRQ_NUM]; > + int intr_dbg_msg; Looks like this should be bool and should be placed after tx_irq_disabled [] > @@ -1848,8 +1853,35 @@ static u32 cpsw_get_msglevel(struct net_device *ndev) > > static void cpsw_set_msglevel(struct net_device *ndev, u32 value) > { > + int i; > + struct cpsw_priv *sl_priv; > struct cpsw_priv *priv = netdev_priv(ndev); > + struct cpsw_common *cpsw = priv->cpsw; > + > priv->msg_enable = value; > + > + /* There is no possibility to at napi poll level > + * to know which netdev is handled, so enable > + * common dbg msg print if any interface is enabled to to? too? > + */ > + cpsw->intr_dbg_msg = 0; > + if (!cpsw->data.dual_emac) { > + if (netif_msg_intr(priv)) > + cpsw->intr_dbg_msg = 1; > + return; > + } > + > + for (i = 0; i < cpsw->data.slaves; i++) { > + ndev = netdev_priv(cpsw->slaves[i].ndev); > + if (!ndev) > + continue; > + > + sl_priv = netdev_priv(ndev); > + if (netif_msg_intr(sl_priv)) { > + cpsw->intr_dbg_msg = 1; > + break; > + } > + } > } > > static int cpsw_get_ts_info(struct net_device *ndev,
[PATCH v2 09/14] net: ethernet: ti: cpsw: move cpdma resources to cpsw_common
Every net device private struct holds links to shared cpdma resources. No need to save and every time synchronize these resources per net dev. So, move it to common driver struct. Signed-off-by: Ivan Khoronzhuk--- drivers/net/ethernet/ti/cpsw.c | 97 +- 1 file changed, 48 insertions(+), 49 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 6fc22df..d3af373 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -369,6 +369,8 @@ struct cpsw_common { struct cpsw_wr_regs __iomem *wr_regs; u8 __iomem *hw_stats; struct cpsw_host_regs __iomem *host_port_regs; + struct cpdma_ctlr *dma; + struct cpdma_chan *txch, *rxch; }; struct cpsw_priv { @@ -384,8 +386,6 @@ struct cpsw_priv { int rx_packet_max; u8 mac_addr[ETH_ALEN]; struct cpsw_slave *slaves; - struct cpdma_ctlr *dma; - struct cpdma_chan *txch, *rxch; struct cpsw_ale *ale; boolrx_pause; booltx_pause; @@ -656,25 +656,21 @@ static void cpsw_ndo_set_rx_mode(struct net_device *ndev) } } -static void cpsw_intr_enable(struct cpsw_priv *priv) +static void cpsw_intr_enable(struct cpsw_common *cpsw) { - struct cpsw_common *cpsw = priv->cpsw; - __raw_writel(0xFF, >wr_regs->tx_en); __raw_writel(0xFF, >wr_regs->rx_en); - cpdma_ctlr_int_ctrl(priv->dma, true); + cpdma_ctlr_int_ctrl(cpsw->dma, true); return; } -static void cpsw_intr_disable(struct cpsw_priv *priv) +static void cpsw_intr_disable(struct cpsw_common *cpsw) { - struct cpsw_common *cpsw = priv->cpsw; - __raw_writel(0, >wr_regs->tx_en); __raw_writel(0, >wr_regs->rx_en); - cpdma_ctlr_int_ctrl(priv->dma, false); + cpdma_ctlr_int_ctrl(cpsw->dma, false); return; } @@ -702,6 +698,7 @@ static void cpsw_rx_handler(void *token, int len, int status) struct net_device *ndev = skb->dev; struct cpsw_priv*priv = netdev_priv(ndev); int ret = 0; + struct cpsw_common *cpsw = priv->cpsw; cpsw_dual_emac_src_port_detect(status, priv, ndev, skb); @@ -747,8 +744,8 @@ static void cpsw_rx_handler(void *token, int len, int status) } requeue: - ret = cpdma_chan_submit(priv->rxch, new_skb, new_skb->data, - skb_tailroom(new_skb), 0); + ret = cpdma_chan_submit(cpsw->rxch, new_skb, new_skb->data, + skb_tailroom(new_skb), 0); if (WARN_ON(ret < 0)) dev_kfree_skb_any(new_skb); } @@ -759,7 +756,7 @@ static irqreturn_t cpsw_tx_interrupt(int irq, void *dev_id) struct cpsw_common *cpsw = priv->cpsw; writel(0, >wr_regs->tx_en); - cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX); + cpdma_ctlr_eoi(cpsw->dma, CPDMA_EOI_TX); if (priv->quirk_irq) { disable_irq_nosync(priv->irqs_table[1]); @@ -775,7 +772,7 @@ static irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id) struct cpsw_priv *priv = dev_id; struct cpsw_common *cpsw = priv->cpsw; - cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX); + cpdma_ctlr_eoi(cpsw->dma, CPDMA_EOI_RX); writel(0, >wr_regs->rx_en); if (priv->quirk_irq) { @@ -793,7 +790,7 @@ static int cpsw_tx_poll(struct napi_struct *napi_tx, int budget) int num_tx; struct cpsw_common *cpsw = priv->cpsw; - num_tx = cpdma_chan_process(priv->txch, budget); + num_tx = cpdma_chan_process(cpsw->txch, budget); if (num_tx < budget) { napi_complete(napi_tx); writel(0xff, >wr_regs->tx_en); @@ -813,7 +810,7 @@ static int cpsw_rx_poll(struct napi_struct *napi_rx, int budget) int num_rx; struct cpsw_common *cpsw = priv->cpsw; - num_rx = cpdma_chan_process(priv->rxch, budget); + num_rx = cpdma_chan_process(cpsw->rxch, budget); if (num_rx < budget) { napi_complete(napi_rx); writel(0xff, >wr_regs->rx_en); @@ -1024,17 +1021,16 @@ static void cpsw_get_strings(struct net_device *ndev, u32 stringset, u8 *data) static void cpsw_get_ethtool_stats(struct net_device *ndev, struct ethtool_stats *stats, u64 *data) { - struct cpsw_priv *priv = netdev_priv(ndev); struct cpdma_chan_stats rx_stats; struct cpdma_chan_stats tx_stats; u32 val; u8 *p; int i; - struct cpsw_common *cpsw = priv->cpsw; + struct cpsw_common *cpsw = ndev_to_cpsw(ndev); /*
[PATCH v2 11/14] net: ethernet: ti: cpsw: move data platform data and slaves info to cpsw_common
These data are common per net dev. No need to hold it in every priv instance, so move them under cpsw_common. Signed-off-by: Ivan Khoronzhuk--- drivers/net/ethernet/ti/cpsw.c | 271 + 1 file changed, 140 insertions(+), 131 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 4080487..29ff489 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -140,9 +140,9 @@ do { \ #define CPSW_CMINTMAX_INTVL(1000 / CPSW_CMINTMIN_CNT) #define CPSW_CMINTMIN_INTVL((1000 / CPSW_CMINTMAX_CNT) + 1) -#define cpsw_slave_index(priv) \ - ((priv->data.dual_emac) ? priv->emac_port : \ - priv->data.active_slave) +#define cpsw_slave_index(cpsw, priv) \ + ((cpsw->data.dual_emac) ? priv->emac_port : \ + cpsw->data.active_slave) #define IRQ_NUM2 static int debug_level; @@ -366,10 +366,12 @@ static inline void slave_write(struct cpsw_slave *slave, u32 val, u32 offset) struct cpsw_common { struct device *dev; + struct cpsw_platform_data data; struct cpsw_ss_regs __iomem *regs; struct cpsw_wr_regs __iomem *wr_regs; u8 __iomem *hw_stats; struct cpsw_host_regs __iomem *host_port_regs; + struct cpsw_slave *slaves; struct cpdma_ctlr *dma; struct cpdma_chan *txch, *rxch; boolquirk_irq; @@ -383,14 +385,12 @@ struct cpsw_priv { struct napi_struct napi_rx; struct napi_struct napi_tx; struct device *dev; - struct cpsw_platform_data data; u32 msg_enable; u32 version; u32 coal_intvl; u32 bus_freq_mhz; int rx_packet_max; u8 mac_addr[ETH_ALEN]; - struct cpsw_slave *slaves; struct cpsw_ale *ale; boolrx_pause; booltx_pause; @@ -492,40 +492,41 @@ static const struct cpsw_stats cpsw_gstrings_stats[] = { #define for_each_slave(priv, func, arg...) \ do {\ struct cpsw_slave *slave; \ + struct cpsw_common *cpsw = (priv)->cpsw;\ int n; \ - if (priv->data.dual_emac) \ - (func)((priv)->slaves + priv->emac_port, ##arg);\ + if (cpsw->data.dual_emac) \ + (func)((cpsw)->slaves + priv->emac_port, ##arg);\ else\ - for (n = (priv)->data.slaves, \ - slave = (priv)->slaves; \ + for (n = cpsw->data.slaves, \ + slave = cpsw->slaves; \ n; n--) \ (func)(slave++, ##arg); \ } while (0) -#define cpsw_get_slave_ndev(priv, __slave_no__) \ - priv->slaves[__slave_no__].ndev -#define cpsw_get_slave_priv(priv, __slave_no__) \ - (((__slave_no__ < priv->data.slaves) && \ - (priv->slaves[__slave_no__].ndev)) ?\ - netdev_priv(priv->slaves[__slave_no__].ndev) : NULL)\ - -#define cpsw_dual_emac_src_port_detect(status, priv, ndev, skb) \ +#define cpsw_get_slave_ndev(cpsw, __slave_no__) \ + cpsw->slaves[__slave_no__].ndev +#define cpsw_get_slave_priv(cpsw, __slave_no__) \ + (((__slave_no__ < cpsw->data.slaves) && \ + (cpsw->slaves[__slave_no__].ndev)) ?\ + netdev_priv(cpsw->slaves[__slave_no__].ndev) : NULL)\ + +#define cpsw_dual_emac_src_port_detect(cpsw, status, priv, ndev, skb) \ do {\ - if (!priv->data.dual_emac) \ + if (!cpsw->data.dual_emac)
[PATCH net 1/2] net: vxlan: lwt: Use source ip address during route lookup.
LWT user can specify destination as well as source ip address for given tunnel endpoint. But vxlan is ignoring given source ip address. Following patch uses both ip address to route the tunnel packet. This consistent with other LWT implementations, like GENEVE and GRE. Fixes: ee122c79d42 ("vxlan: Flow based tunneling"). Signed-off-by: Pravin B Shelar--- drivers/net/vxlan.c | 30 ++ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index da4e3d6..b812234 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1811,7 +1811,7 @@ static struct rtable *vxlan_get_route(struct vxlan_dev *vxlan, fl4.flowi4_mark = skb->mark; fl4.flowi4_proto = IPPROTO_UDP; fl4.daddr = daddr; - fl4.saddr = vxlan->cfg.saddr.sin.sin_addr.s_addr; + fl4.saddr = *saddr; rt = ip_route_output_key(vxlan->net, ); if (!IS_ERR(rt)) { @@ -1847,7 +1847,7 @@ static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan, memset(, 0, sizeof(fl6)); fl6.flowi6_oif = oif; fl6.daddr = *daddr; - fl6.saddr = vxlan->cfg.saddr.sin6.sin6_addr; + fl6.saddr = *saddr; fl6.flowlabel = ip6_make_flowinfo(RT_TOS(tos), label); fl6.flowi6_mark = skb->mark; fl6.flowi6_proto = IPPROTO_UDP; @@ -1920,7 +1920,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, struct rtable *rt = NULL; const struct iphdr *old_iph; union vxlan_addr *dst; - union vxlan_addr remote_ip; + union vxlan_addr remote_ip, local_ip; + union vxlan_addr *src; struct vxlan_metadata _md; struct vxlan_metadata *md = &_md; __be16 src_port = 0, dst_port; @@ -1938,6 +1939,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, dst_port = rdst->remote_port ? rdst->remote_port : vxlan->cfg.dst_port; vni = rdst->remote_vni; dst = >remote_ip; + src = >cfg.saddr; dst_cache = >dst_cache; } else { if (!info) { @@ -1948,11 +1950,15 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, dst_port = info->key.tp_dst ? : vxlan->cfg.dst_port; vni = vxlan_tun_id_to_vni(info->key.tun_id); remote_ip.sa.sa_family = ip_tunnel_info_af(info); - if (remote_ip.sa.sa_family == AF_INET) + if (remote_ip.sa.sa_family == AF_INET) { remote_ip.sin.sin_addr.s_addr = info->key.u.ipv4.dst; - else + local_ip.sin.sin_addr.s_addr = info->key.u.ipv4.src; + } else { remote_ip.sin6.sin6_addr = info->key.u.ipv6.dst; + local_ip.sin6.sin6_addr = info->key.u.ipv6.src; + } dst = _ip; + src = _ip; dst_cache = >dst_cache; } @@ -1992,15 +1998,14 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, } if (dst->sa.sa_family == AF_INET) { - __be32 saddr; - if (!vxlan->vn4_sock) goto drop; sk = vxlan->vn4_sock->sock->sk; rt = vxlan_get_route(vxlan, skb, rdst ? rdst->remote_ifindex : 0, tos, -dst->sin.sin_addr.s_addr, , +dst->sin.sin_addr.s_addr, +>sin.sin_addr.s_addr, dst_cache, info); if (IS_ERR(rt)) { netdev_dbg(dev, "no route to %pI4\n", @@ -2043,13 +2048,12 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, if (err < 0) goto xmit_tx_error; - udp_tunnel_xmit_skb(rt, sk, skb, saddr, + udp_tunnel_xmit_skb(rt, sk, skb, src->sin.sin_addr.s_addr, dst->sin.sin_addr.s_addr, tos, ttl, df, src_port, dst_port, xnet, !udp_sum); #if IS_ENABLED(CONFIG_IPV6) } else { struct dst_entry *ndst; - struct in6_addr saddr; u32 rt6i_flags; if (!vxlan->vn6_sock) @@ -2058,7 +2062,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, ndst = vxlan6_get_route(vxlan, skb, rdst ? rdst->remote_ifindex : 0, tos, - label, >sin6.sin6_addr, , + label, >sin6.sin6_addr, + >sin6.sin6_addr, dst_cache, info); if (IS_ERR(ndst)) {
[PATCH v2 12/14] net: ethernet: ti: cpsw: fix int dbg message
While poll handlers there is no possibility to figure out which network device is handling packets, as cpdma channels are common for both network devices in dual_emac mode. Currently, the messages are printed only for one device, in fact, there is two. So, better to print integrated num_tx value for both devices if any of them is allowed to. Signed-off-by: Ivan Khoronzhuk--- drivers/net/ethernet/ti/cpsw.c | 36 ++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 29ff489..395531d 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -378,6 +378,7 @@ struct cpsw_common { boolrx_irq_disabled; booltx_irq_disabled; u32 irqs_table[IRQ_NUM]; + int intr_dbg_msg; }; struct cpsw_priv { @@ -802,7 +803,9 @@ static int cpsw_tx_poll(struct napi_struct *napi_tx, int budget) } } - cpsw_dbg(priv, intr, "poll %d tx pkts\n", num_tx); + if (cpsw->intr_dbg_msg && net_ratelimit()) + dev_dbg(cpsw->dev, "poll %d tx pkts\n", num_tx); + return num_tx; } @@ -822,7 +825,9 @@ static int cpsw_rx_poll(struct napi_struct *napi_rx, int budget) } } - cpsw_dbg(priv, intr, "poll %d rx pkts\n", num_rx); + if (cpsw->intr_dbg_msg && net_ratelimit()) + dev_dbg(cpsw->dev, "poll %d tx pkts\n", num_rx); + return num_rx; } @@ -1848,8 +1853,35 @@ static u32 cpsw_get_msglevel(struct net_device *ndev) static void cpsw_set_msglevel(struct net_device *ndev, u32 value) { + int i; + struct cpsw_priv *sl_priv; struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; + priv->msg_enable = value; + + /* There is no possibility to at napi poll level +* to know which netdev is handled, so enable +* common dbg msg print if any interface is enabled to +*/ + cpsw->intr_dbg_msg = 0; + if (!cpsw->data.dual_emac) { + if (netif_msg_intr(priv)) + cpsw->intr_dbg_msg = 1; + return; + } + + for (i = 0; i < cpsw->data.slaves; i++) { + ndev = netdev_priv(cpsw->slaves[i].ndev); + if (!ndev) + continue; + + sl_priv = netdev_priv(ndev); + if (netif_msg_intr(sl_priv)) { + cpsw->intr_dbg_msg = 1; + break; + } + } } static int cpsw_get_ts_info(struct net_device *ndev, -- 1.9.1
[PATCH net 2/2] net: vxlan: lwt: Fix vxlan local traffic.
vxlan driver has bypass for local vxlan traffic, but that depends on information about all VNIs on local system in vxlan driver. This is not available in case of LWT. Therefore following patch disable encap bypass for LWT vxlan traffic. Fixes: ee122c79d42 ("vxlan: Flow based tunneling"). Reported-by: Jakub LibosvarSigned-off-by: Pravin B Shelar --- drivers/net/vxlan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index b812234..c0dda6f 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -2022,7 +2022,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, } /* Bypass encapsulation if the destination is local */ - if (rt->rt_flags & RTCF_LOCAL && + if (!info && rt->rt_flags & RTCF_LOCAL && !(rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))) { struct vxlan_dev *dst_vxlan; @@ -2082,7 +2082,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, /* Bypass encapsulation if the destination is local */ rt6i_flags = ((struct rt6_info *)ndst)->rt6i_flags; - if (rt6i_flags & RTF_LOCAL && + if (!info && rt6i_flags & RTF_LOCAL && !(rt6i_flags & (RTCF_BROADCAST | RTCF_MULTICAST))) { struct vxlan_dev *dst_vxlan; -- 1.9.1
[PATCH v2 06/14] net: ethernet: ti: cpsw: create common struct to hold shared driver data
This patch simply create holder for common data and as a start moves pdev var to it. Signed-off-by: Ivan Khoronzhuk--- drivers/net/ethernet/ti/cpsw.c | 62 ++ 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 19aa4bb..ac875b3 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -363,8 +363,11 @@ static inline void slave_write(struct cpsw_slave *slave, u32 val, u32 offset) __raw_writel(val, slave->regs + offset); } -struct cpsw_priv { +struct cpsw_common { struct platform_device *pdev; +}; + +struct cpsw_priv { struct net_device *ndev; struct napi_struct napi_rx; struct napi_struct napi_tx; @@ -394,6 +397,7 @@ struct cpsw_priv { u32 num_irqs; struct cpts *cpts; u32 emac_port; + struct cpsw_common *cpsw; }; struct cpsw_stats { @@ -484,6 +488,7 @@ static const struct cpsw_stats cpsw_gstrings_stats[] = { #define CPSW_STATS_LEN ARRAY_SIZE(cpsw_gstrings_stats) +#define ndev_to_cpsw(ndev) (((struct cpsw_priv *)netdev_priv(ndev))->cpsw) #define napi_to_priv(napi) container_of(napi, struct cpsw_priv, napi) #define for_each_slave(priv, func, arg...) \ do {\ @@ -1095,6 +1100,7 @@ static void soft_reset_slave(struct cpsw_slave *slave) static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv) { u32 slave_port; + struct cpsw_common *cpsw = priv->cpsw; soft_reset_slave(slave); @@ -1153,7 +1159,7 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv) phy_start(slave->phy); /* Configure GMII_SEL register */ - cpsw_phy_sel(>pdev->dev, slave->phy->interface, slave->slave_num); + cpsw_phy_sel(>pdev->dev, slave->phy->interface, slave->slave_num); } static inline void cpsw_add_default_vlan(struct cpsw_priv *priv) @@ -1235,12 +1241,13 @@ static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv) static int cpsw_ndo_open(struct net_device *ndev) { struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; int i, ret; u32 reg; - ret = pm_runtime_get_sync(>pdev->dev); + ret = pm_runtime_get_sync(>pdev->dev); if (ret < 0) { - pm_runtime_put_noidle(>pdev->dev); + pm_runtime_put_noidle(>pdev->dev); return ret; } @@ -1317,7 +1324,7 @@ static int cpsw_ndo_open(struct net_device *ndev) */ cpsw_info(priv, ifup, "submitted %d rx descriptors\n", i); - if (cpts_register(>pdev->dev, priv->cpts, + if (cpts_register(>pdev->dev, priv->cpts, priv->data.cpts_clock_mult, priv->data.cpts_clock_shift)) dev_err(priv->dev, "error registering cpts device\n"); @@ -1342,7 +1349,7 @@ static int cpsw_ndo_open(struct net_device *ndev) err_cleanup: cpdma_ctlr_stop(priv->dma); for_each_slave(priv, cpsw_slave_stop, priv); - pm_runtime_put_sync(>pdev->dev); + pm_runtime_put_sync(>pdev->dev); netif_carrier_off(priv->ndev); return ret; } @@ -1350,6 +1357,7 @@ err_cleanup: static int cpsw_ndo_stop(struct net_device *ndev) { struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; cpsw_info(priv, ifdown, "shutting down cpsw device\n"); netif_stop_queue(priv->ndev); @@ -1366,7 +1374,7 @@ static int cpsw_ndo_stop(struct net_device *ndev) cpsw_ale_stop(priv->ale); } for_each_slave(priv, cpsw_slave_stop, priv); - pm_runtime_put_sync(>pdev->dev); + pm_runtime_put_sync(>pdev->dev); if (priv->data.dual_emac) priv->slaves[priv->emac_port].open_stat = false; return 0; @@ -1598,6 +1606,7 @@ static int cpsw_ndo_set_mac_address(struct net_device *ndev, void *p) { struct cpsw_priv *priv = netdev_priv(ndev); struct sockaddr *addr = (struct sockaddr *)p; + struct cpsw_common *cpsw = priv->cpsw; int flags = 0; u16 vid = 0; int ret; @@ -1605,9 +1614,9 @@ static int cpsw_ndo_set_mac_address(struct net_device *ndev, void *p) if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; - ret = pm_runtime_get_sync(>pdev->dev); + ret = pm_runtime_get_sync(>pdev->dev); if (ret < 0) { - pm_runtime_put_noidle(>pdev->dev); + pm_runtime_put_noidle(>pdev->dev); return ret; } @@ -1625,7 +1634,7 @@ static int cpsw_ndo_set_mac_address(struct
[PATCH v2 14/14] net: ethernet: ti: cpsw: move ale, cpts and drivers params under cpsw_common
The ale, cpts, version, limit, freq, interrupt pacing parameters are common per net device that uses the same h/w. So, move them to common driver structure. Signed-off-by: Ivan Khoronzhuk--- drivers/net/ethernet/ti/cpsw.c | 237 ++--- 1 file changed, 106 insertions(+), 131 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index e0a1b80..bd0ea71 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -373,13 +373,19 @@ struct cpsw_common { struct cpsw_wr_regs __iomem *wr_regs; u8 __iomem *hw_stats; struct cpsw_host_regs __iomem *host_port_regs; + u32 version; + u32 coal_intvl; + u32 bus_freq_mhz; + int rx_packet_max; struct cpsw_slave *slaves; struct cpdma_ctlr *dma; struct cpdma_chan *txch, *rxch; + struct cpsw_ale *ale; boolquirk_irq; boolrx_irq_disabled; booltx_irq_disabled; u32 irqs_table[IRQ_NUM]; + struct cpts *cpts; int intr_dbg_msg; }; @@ -387,15 +393,9 @@ struct cpsw_priv { struct net_device *ndev; struct device *dev; u32 msg_enable; - u32 version; - u32 coal_intvl; - u32 bus_freq_mhz; - int rx_packet_max; u8 mac_addr[ETH_ALEN]; - struct cpsw_ale *ale; boolrx_pause; booltx_pause; - struct cpts *cpts; u32 emac_port; struct cpsw_common *cpsw; }; @@ -505,22 +505,16 @@ static const struct cpsw_stats cpsw_gstrings_stats[] = { } while (0) #define cpsw_get_slave_ndev(cpsw, __slave_no__) \ cpsw->slaves[__slave_no__].ndev -#define cpsw_get_slave_priv(cpsw, __slave_no__) \ - (((__slave_no__ < cpsw->data.slaves) && \ - (cpsw->slaves[__slave_no__].ndev)) ?\ - netdev_priv(cpsw->slaves[__slave_no__].ndev) : NULL)\ -#define cpsw_dual_emac_src_port_detect(cpsw, status, priv, ndev, skb) \ +#define cpsw_dual_emac_src_port_detect(cpsw, status, ndev, skb) \ do {\ if (!cpsw->data.dual_emac) \ break; \ if (CPDMA_RX_SOURCE_PORT(status) == 1) {\ ndev = cpsw_get_slave_ndev(cpsw, 0);\ - priv = netdev_priv(ndev); \ skb->dev = ndev;\ } else if (CPDMA_RX_SOURCE_PORT(status) == 2) { \ ndev = cpsw_get_slave_ndev(cpsw, 1);\ - priv = netdev_priv(ndev); \ skb->dev = ndev;\ } \ } while (0) @@ -531,11 +525,11 @@ static const struct cpsw_stats cpsw_gstrings_stats[] = { priv->emac_port;\ int slave_port = cpsw_get_slave_port( \ slave->slave_num); \ - cpsw_ale_add_mcast(priv->ale, addr, \ + cpsw_ale_add_mcast(cpsw->ale, addr, \ 1 << slave_port | ALE_PORT_HOST,\ ALE_VLAN, slave->port_vlan, 0); \ } else {\ - cpsw_ale_add_mcast(priv->ale, addr, \ + cpsw_ale_add_mcast(cpsw->ale, addr, \ ALE_ALL_PORTS, \ 0, 0, 0); \ } \ @@ -548,9 +542,8 @@ static inline int cpsw_get_slave_port(u32 slave_num) static void cpsw_set_promiscious(struct net_device *ndev, bool enable) { - struct cpsw_priv *priv = netdev_priv(ndev); - struct