* [PATCH net-next v2 1/2] bpf: add helper for retrieving current numa node id
From: Daniel Borkmann @ 2016-10-21 10:46 UTC (permalink / raw)
To: davem; +Cc: alexei.starovoitov, edumazet, netdev, Daniel Borkmann
In-Reply-To: <cover.1477043972.git.daniel@iogearbox.net>
Use case is mainly for soreuseport to select sockets for the local
numa node, but since generic, lets also add this for other networking
and tracing program types.
Suggested-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Alexei Starovoitov <ast@kernel.org>
---
include/linux/bpf.h | 1 +
include/uapi/linux/bpf.h | 6 ++++++
kernel/bpf/core.c | 1 +
kernel/bpf/helpers.c | 12 ++++++++++++
kernel/trace/bpf_trace.c | 2 ++
net/core/filter.c | 2 ++
6 files changed, 24 insertions(+)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index c201017..edcd96d 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -319,6 +319,7 @@ static inline struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog)
extern const struct bpf_func_proto bpf_get_prandom_u32_proto;
extern const struct bpf_func_proto bpf_get_smp_processor_id_proto;
+extern const struct bpf_func_proto bpf_get_numa_node_id_proto;
extern const struct bpf_func_proto bpf_tail_call_proto;
extern const struct bpf_func_proto bpf_ktime_get_ns_proto;
extern const struct bpf_func_proto bpf_get_current_pid_tgid_proto;
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index f09c70b..374ef58 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -426,6 +426,12 @@ enum bpf_func_id {
*/
BPF_FUNC_set_hash_invalid,
+ /**
+ * bpf_get_numa_node_id()
+ * Returns the id of the current NUMA node.
+ */
+ BPF_FUNC_get_numa_node_id,
+
__BPF_FUNC_MAX_ID,
};
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index aa6d981..82a0414 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -1043,6 +1043,7 @@ void bpf_user_rnd_init_once(void)
const struct bpf_func_proto bpf_get_prandom_u32_proto __weak;
const struct bpf_func_proto bpf_get_smp_processor_id_proto __weak;
+const struct bpf_func_proto bpf_get_numa_node_id_proto __weak;
const struct bpf_func_proto bpf_ktime_get_ns_proto __weak;
const struct bpf_func_proto bpf_get_current_pid_tgid_proto __weak;
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index 3991840..045cbe6 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -13,6 +13,7 @@
#include <linux/rcupdate.h>
#include <linux/random.h>
#include <linux/smp.h>
+#include <linux/topology.h>
#include <linux/ktime.h>
#include <linux/sched.h>
#include <linux/uidgid.h>
@@ -92,6 +93,17 @@
.ret_type = RET_INTEGER,
};
+BPF_CALL_0(bpf_get_numa_node_id)
+{
+ return numa_node_id();
+}
+
+const struct bpf_func_proto bpf_get_numa_node_id_proto = {
+ .func = bpf_get_numa_node_id,
+ .gpl_only = false,
+ .ret_type = RET_INTEGER,
+};
+
BPF_CALL_0(bpf_ktime_get_ns)
{
/* NMI safe access to clock monotonic */
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 5dcb992..fa77311 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -422,6 +422,8 @@ static const struct bpf_func_proto *tracing_func_proto(enum bpf_func_id func_id)
return bpf_get_trace_printk_proto();
case BPF_FUNC_get_smp_processor_id:
return &bpf_get_smp_processor_id_proto;
+ case BPF_FUNC_get_numa_node_id:
+ return &bpf_get_numa_node_id_proto;
case BPF_FUNC_perf_event_read:
return &bpf_perf_event_read_proto;
case BPF_FUNC_probe_write_user:
diff --git a/net/core/filter.c b/net/core/filter.c
index 00351cd..cd9e2ba 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -2492,6 +2492,8 @@ static unsigned long bpf_xdp_copy(void *dst_buff, const void *src_buff,
return &bpf_get_prandom_u32_proto;
case BPF_FUNC_get_smp_processor_id:
return &bpf_get_raw_smp_processor_id_proto;
+ case BPF_FUNC_get_numa_node_id:
+ return &bpf_get_numa_node_id_proto;
case BPF_FUNC_tail_call:
return &bpf_tail_call_proto;
case BPF_FUNC_ktime_get_ns:
--
1.9.3
^ permalink raw reply related
* [PATCH net-next v2 0/2] Add BPF numa id helper
From: Daniel Borkmann @ 2016-10-21 10:46 UTC (permalink / raw)
To: davem; +Cc: alexei.starovoitov, edumazet, netdev, Daniel Borkmann
This patch set adds a helper for retrieving current numa node
id and a test case for SO_REUSEPORT.
Thanks!
v1 -> v2:
- Missed __weak definition when bpf syscall is not enabled, sorry.
- Rest as is.
Daniel Borkmann (2):
bpf: add helper for retrieving current numa node id
reuseport, bpf: add test case for bpf_get_numa_node_id
include/linux/bpf.h | 1 +
include/uapi/linux/bpf.h | 6 +
kernel/bpf/core.c | 1 +
kernel/bpf/helpers.c | 12 ++
kernel/trace/bpf_trace.c | 2 +
net/core/filter.c | 2 +
tools/testing/selftests/net/.gitignore | 1 +
tools/testing/selftests/net/Makefile | 11 +-
tools/testing/selftests/net/reuseport_bpf_numa.c | 255 +++++++++++++++++++++++
9 files changed, 287 insertions(+), 4 deletions(-)
create mode 100644 tools/testing/selftests/net/reuseport_bpf_numa.c
--
1.9.3
^ permalink raw reply
* [PATCH net-next v2 2/2] reuseport, bpf: add test case for bpf_get_numa_node_id
From: Daniel Borkmann @ 2016-10-21 10:46 UTC (permalink / raw)
To: davem; +Cc: alexei.starovoitov, edumazet, netdev, Daniel Borkmann
In-Reply-To: <cover.1477043972.git.daniel@iogearbox.net>
The test case is very similar to reuseport_bpf_cpu, only that here
we select socket members based on current numa node id.
# numactl -H
available: 2 nodes (0-1)
node 0 cpus: 0 1 2 3 4 5 12 13 14 15 16 17
node 0 size: 128867 MB
node 0 free: 120080 MB
node 1 cpus: 6 7 8 9 10 11 18 19 20 21 22 23
node 1 size: 96765 MB
node 1 free: 87504 MB
node distances:
node 0 1
0: 10 20
1: 20 10
# ./reuseport_bpf_numa
---- IPv4 UDP ----
send node 0, receive socket 0
send node 1, receive socket 1
send node 1, receive socket 1
send node 0, receive socket 0
---- IPv6 UDP ----
send node 0, receive socket 0
send node 1, receive socket 1
send node 1, receive socket 1
send node 0, receive socket 0
---- IPv4 TCP ----
send node 0, receive socket 0
send node 1, receive socket 1
send node 1, receive socket 1
send node 0, receive socket 0
---- IPv6 TCP ----
send node 0, receive socket 0
send node 1, receive socket 1
send node 1, receive socket 1
send node 0, receive socket 0
SUCCESS
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Alexei Starovoitov <ast@kernel.org>
---
tools/testing/selftests/net/.gitignore | 1 +
tools/testing/selftests/net/Makefile | 11 +-
tools/testing/selftests/net/reuseport_bpf_numa.c | 255 +++++++++++++++++++++++
3 files changed, 263 insertions(+), 4 deletions(-)
create mode 100644 tools/testing/selftests/net/reuseport_bpf_numa.c
diff --git a/tools/testing/selftests/net/.gitignore b/tools/testing/selftests/net/.gitignore
index 0840684..afe109e 100644
--- a/tools/testing/selftests/net/.gitignore
+++ b/tools/testing/selftests/net/.gitignore
@@ -3,4 +3,5 @@ psock_fanout
psock_tpacket
reuseport_bpf
reuseport_bpf_cpu
+reuseport_bpf_numa
reuseport_dualstack
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index 0e53407..e24e4c8 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -1,14 +1,17 @@
# Makefile for net selftests
-CFLAGS = -Wall -O2 -g
-
+CFLAGS = -Wall -Wl,--no-as-needed -O2 -g
CFLAGS += -I../../../../usr/include/
-NET_PROGS = socket psock_fanout psock_tpacket reuseport_bpf reuseport_bpf_cpu reuseport_dualstack
+NET_PROGS = socket
+NET_PROGS += psock_fanout psock_tpacket
+NET_PROGS += reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa
+NET_PROGS += reuseport_dualstack
all: $(NET_PROGS)
+reuseport_bpf_numa: LDFLAGS += -lnuma
%: %.c
- $(CC) $(CFLAGS) -o $@ $^
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
TEST_PROGS := run_netsocktests run_afpackettests test_bpf.sh
TEST_FILES := $(NET_PROGS)
diff --git a/tools/testing/selftests/net/reuseport_bpf_numa.c b/tools/testing/selftests/net/reuseport_bpf_numa.c
new file mode 100644
index 0000000..6f20bc9
--- /dev/null
+++ b/tools/testing/selftests/net/reuseport_bpf_numa.c
@@ -0,0 +1,255 @@
+/*
+ * Test functionality of BPF filters with SO_REUSEPORT. Same test as
+ * in reuseport_bpf_cpu, only as one socket per NUMA node.
+ */
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <error.h>
+#include <linux/filter.h>
+#include <linux/bpf.h>
+#include <linux/in.h>
+#include <linux/unistd.h>
+#include <sched.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <numa.h>
+
+static const int PORT = 8888;
+
+static void build_rcv_group(int *rcv_fd, size_t len, int family, int proto)
+{
+ struct sockaddr_storage addr;
+ struct sockaddr_in *addr4;
+ struct sockaddr_in6 *addr6;
+ size_t i;
+ int opt;
+
+ switch (family) {
+ case AF_INET:
+ addr4 = (struct sockaddr_in *)&addr;
+ addr4->sin_family = AF_INET;
+ addr4->sin_addr.s_addr = htonl(INADDR_ANY);
+ addr4->sin_port = htons(PORT);
+ break;
+ case AF_INET6:
+ addr6 = (struct sockaddr_in6 *)&addr;
+ addr6->sin6_family = AF_INET6;
+ addr6->sin6_addr = in6addr_any;
+ addr6->sin6_port = htons(PORT);
+ break;
+ default:
+ error(1, 0, "Unsupported family %d", family);
+ }
+
+ for (i = 0; i < len; ++i) {
+ rcv_fd[i] = socket(family, proto, 0);
+ if (rcv_fd[i] < 0)
+ error(1, errno, "failed to create receive socket");
+
+ opt = 1;
+ if (setsockopt(rcv_fd[i], SOL_SOCKET, SO_REUSEPORT, &opt,
+ sizeof(opt)))
+ error(1, errno, "failed to set SO_REUSEPORT");
+
+ if (bind(rcv_fd[i], (struct sockaddr *)&addr, sizeof(addr)))
+ error(1, errno, "failed to bind receive socket");
+
+ if (proto == SOCK_STREAM && listen(rcv_fd[i], len * 10))
+ error(1, errno, "failed to listen on receive port");
+ }
+}
+
+static void attach_bpf(int fd)
+{
+ static char bpf_log_buf[65536];
+ static const char bpf_license[] = "";
+
+ int bpf_fd;
+ const struct bpf_insn prog[] = {
+ /* R0 = bpf_get_numa_node_id() */
+ { BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_numa_node_id },
+ /* return R0 */
+ { BPF_JMP | BPF_EXIT, 0, 0, 0, 0 }
+ };
+ union bpf_attr attr;
+
+ memset(&attr, 0, sizeof(attr));
+ attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
+ attr.insn_cnt = sizeof(prog) / sizeof(prog[0]);
+ attr.insns = (unsigned long) &prog;
+ attr.license = (unsigned long) &bpf_license;
+ attr.log_buf = (unsigned long) &bpf_log_buf;
+ attr.log_size = sizeof(bpf_log_buf);
+ attr.log_level = 1;
+
+ bpf_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
+ if (bpf_fd < 0)
+ error(1, errno, "ebpf error. log:\n%s\n", bpf_log_buf);
+
+ if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_REUSEPORT_EBPF, &bpf_fd,
+ sizeof(bpf_fd)))
+ error(1, errno, "failed to set SO_ATTACH_REUSEPORT_EBPF");
+
+ close(bpf_fd);
+}
+
+static void send_from_node(int node_id, int family, int proto)
+{
+ struct sockaddr_storage saddr, daddr;
+ struct sockaddr_in *saddr4, *daddr4;
+ struct sockaddr_in6 *saddr6, *daddr6;
+ int fd;
+
+ switch (family) {
+ case AF_INET:
+ saddr4 = (struct sockaddr_in *)&saddr;
+ saddr4->sin_family = AF_INET;
+ saddr4->sin_addr.s_addr = htonl(INADDR_ANY);
+ saddr4->sin_port = 0;
+
+ daddr4 = (struct sockaddr_in *)&daddr;
+ daddr4->sin_family = AF_INET;
+ daddr4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ daddr4->sin_port = htons(PORT);
+ break;
+ case AF_INET6:
+ saddr6 = (struct sockaddr_in6 *)&saddr;
+ saddr6->sin6_family = AF_INET6;
+ saddr6->sin6_addr = in6addr_any;
+ saddr6->sin6_port = 0;
+
+ daddr6 = (struct sockaddr_in6 *)&daddr;
+ daddr6->sin6_family = AF_INET6;
+ daddr6->sin6_addr = in6addr_loopback;
+ daddr6->sin6_port = htons(PORT);
+ break;
+ default:
+ error(1, 0, "Unsupported family %d", family);
+ }
+
+ if (numa_run_on_node(node_id) < 0)
+ error(1, errno, "failed to pin to node");
+
+ fd = socket(family, proto, 0);
+ if (fd < 0)
+ error(1, errno, "failed to create send socket");
+
+ if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)))
+ error(1, errno, "failed to bind send socket");
+
+ if (connect(fd, (struct sockaddr *)&daddr, sizeof(daddr)))
+ error(1, errno, "failed to connect send socket");
+
+ if (send(fd, "a", 1, 0) < 0)
+ error(1, errno, "failed to send message");
+
+ close(fd);
+}
+
+static
+void receive_on_node(int *rcv_fd, int len, int epfd, int node_id, int proto)
+{
+ struct epoll_event ev;
+ int i, fd;
+ char buf[8];
+
+ i = epoll_wait(epfd, &ev, 1, -1);
+ if (i < 0)
+ error(1, errno, "epoll_wait failed");
+
+ if (proto == SOCK_STREAM) {
+ fd = accept(ev.data.fd, NULL, NULL);
+ if (fd < 0)
+ error(1, errno, "failed to accept");
+ i = recv(fd, buf, sizeof(buf), 0);
+ close(fd);
+ } else {
+ i = recv(ev.data.fd, buf, sizeof(buf), 0);
+ }
+
+ if (i < 0)
+ error(1, errno, "failed to recv");
+
+ for (i = 0; i < len; ++i)
+ if (ev.data.fd == rcv_fd[i])
+ break;
+ if (i == len)
+ error(1, 0, "failed to find socket");
+ fprintf(stderr, "send node %d, receive socket %d\n", node_id, i);
+ if (node_id != i)
+ error(1, 0, "node id/receive socket mismatch");
+}
+
+static void test(int *rcv_fd, int len, int family, int proto)
+{
+ struct epoll_event ev;
+ int epfd, node;
+
+ build_rcv_group(rcv_fd, len, family, proto);
+ attach_bpf(rcv_fd[0]);
+
+ epfd = epoll_create(1);
+ if (epfd < 0)
+ error(1, errno, "failed to create epoll");
+ for (node = 0; node < len; ++node) {
+ ev.events = EPOLLIN;
+ ev.data.fd = rcv_fd[node];
+ if (epoll_ctl(epfd, EPOLL_CTL_ADD, rcv_fd[node], &ev))
+ error(1, errno, "failed to register sock epoll");
+ }
+
+ /* Forward iterate */
+ for (node = 0; node < len; ++node) {
+ send_from_node(node, family, proto);
+ receive_on_node(rcv_fd, len, epfd, node, proto);
+ }
+
+ /* Reverse iterate */
+ for (node = len - 1; node >= 0; --node) {
+ send_from_node(node, family, proto);
+ receive_on_node(rcv_fd, len, epfd, node, proto);
+ }
+
+ close(epfd);
+ for (node = 0; node < len; ++node)
+ close(rcv_fd[node]);
+}
+
+int main(void)
+{
+ int *rcv_fd, nodes;
+
+ if (numa_available() < 0)
+ error(1, errno, "no numa api support");
+
+ nodes = numa_max_node() + 1;
+
+ rcv_fd = calloc(nodes, sizeof(int));
+ if (!rcv_fd)
+ error(1, 0, "failed to allocate array");
+
+ fprintf(stderr, "---- IPv4 UDP ----\n");
+ test(rcv_fd, nodes, AF_INET, SOCK_DGRAM);
+
+ fprintf(stderr, "---- IPv6 UDP ----\n");
+ test(rcv_fd, nodes, AF_INET6, SOCK_DGRAM);
+
+ fprintf(stderr, "---- IPv4 TCP ----\n");
+ test(rcv_fd, nodes, AF_INET, SOCK_STREAM);
+
+ fprintf(stderr, "---- IPv6 TCP ----\n");
+ test(rcv_fd, nodes, AF_INET6, SOCK_STREAM);
+
+ free(rcv_fd);
+
+ fprintf(stderr, "SUCCESS\n");
+ return 0;
+}
--
1.9.3
^ permalink raw reply related
* [PATCH net-next 0/9] alx: add multi queue support
From: Tobias Regnery @ 2016-10-21 10:49 UTC (permalink / raw)
To: jcliburn, chris.snook, netdev; +Cc: davem, Tobias Regnery
This patchset lays the groundwork for multi queue support in the alx driver
and enables multi queue support for the tx path by default. The hardware
supports up to 4 tx queues.
The rx path is a little bit harder because apparently (based on the limited
information from the downstream driver) the hardware supports up to 8 rss
queues but only has one hardware descriptor ring on the rx side. So the rx
path will be part of another patchset.
This work is based on the downstream driver at github.com/qca/alx
I had a hard time splitting these changes up into reasonable parts because
this is my first bigger kernel patchset, so please be patient if this is not
the right approach.
Tobias Regnery (9):
alx: refactor descriptor allocation
alx: extend data structures for multi queue support
alx: add ability to allocate and free alx_napi structures
alx: switch to per queue data structures
alx: prepare interrupt functions for multiple queues
alx: prepare resource allocation for multi queue support
alx: prepare tx path for multi queue support
alx: enable msi-x interrupts by default
alx: enable multiple tx queues
drivers/net/ethernet/atheros/alx/alx.h | 36 ++-
drivers/net/ethernet/atheros/alx/main.c | 554 ++++++++++++++++++++++----------
2 files changed, 420 insertions(+), 170 deletions(-)
--
2.7.4
^ permalink raw reply
* Re: [PATCH net-next 1/1] driver: tun: Forbid to set IFF_TUN and IFF_TAP at the same time
From: Sergei Shtylyov @ 2016-10-21 10:50 UTC (permalink / raw)
To: fgao, davem, jasowang, edumazet, pabeni, netdev; +Cc: gfree.wind
In-Reply-To: <1477030452-1765-1-git-send-email-fgao@ikuai8.com>
Hello.
On 10/21/2016 9:14 AM, fgao@ikuai8.com wrote:
> From: Gao Feng <fgao@ikuai8.com>
>
> Current tun driver permits the ifr_flags is set with IFF_TUN and
> IFF_TAP at the same time. But actually there is only IFF_TUN flag
> works. And it does not make sense these two flags are set, so add
> this check.
>
> Signed-off-by: Gao Feng <fgao@ikuai8.com>
> ---
> drivers/net/tun.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
> index 8093e39..c1f89c1 100644
> --- a/drivers/net/tun.c
> +++ b/drivers/net/tun.c
> @@ -1752,6 +1752,10 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
> if (err < 0)
> return err;
>
> + if ((ifr->ifr_flags & (IFF_TUN | IFF_TAP)) == (IFF_TUN | IFF_TAP)) {
> + return -EINVAL;
> + }
{} not needed here.
MBR, Sergei
^ permalink raw reply
* [PATCH net-next 1/9] alx: refactor descriptor allocation
From: Tobias Regnery @ 2016-10-21 10:49 UTC (permalink / raw)
To: jcliburn, chris.snook, netdev; +Cc: davem, Tobias Regnery
In-Reply-To: <cover.1477044917.git.tobias.regnery@gmail.com>
Split the allocation of descriptor memory and the buffer allocation into a
tx and rx function. This is in preparation for multiple queues where we
need to iterate over the new functions.
Signed-off-by: Tobias Regnery <tobias.regnery@gmail.com>
---
drivers/net/ethernet/atheros/alx/main.c | 97 ++++++++++++++++++---------------
1 file changed, 53 insertions(+), 44 deletions(-)
diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c
index eccbacd96201..b7e67dd3d995 100644
--- a/drivers/net/ethernet/atheros/alx/main.c
+++ b/drivers/net/ethernet/atheros/alx/main.c
@@ -573,19 +573,41 @@ static int alx_set_mac_address(struct net_device *netdev, void *data)
return 0;
}
-static int alx_alloc_descriptors(struct alx_priv *alx)
+static int alx_alloc_tx_ring(struct alx_priv *alx, struct alx_tx_queue *txq,
+ int offset)
{
- alx->txq.bufs = kcalloc(alx->tx_ringsz,
- sizeof(struct alx_buffer),
- GFP_KERNEL);
- if (!alx->txq.bufs)
+ txq->bufs = kcalloc(alx->tx_ringsz, sizeof(struct alx_buffer), GFP_KERNEL);
+ if (!txq->bufs)
return -ENOMEM;
- alx->rxq.bufs = kcalloc(alx->rx_ringsz,
- sizeof(struct alx_buffer),
- GFP_KERNEL);
- if (!alx->rxq.bufs)
- goto out_free;
+ txq->tpd = alx->descmem.virt + offset;
+ txq->tpd_dma = alx->descmem.dma + offset;
+ offset += sizeof(struct alx_txd) * alx->tx_ringsz;
+
+ return offset;
+}
+
+static int alx_alloc_rx_ring(struct alx_priv *alx, struct alx_rx_queue *rxq,
+ int offset)
+{
+ rxq->bufs = kcalloc(alx->rx_ringsz, sizeof(struct alx_buffer), GFP_KERNEL);
+ if (!rxq->bufs)
+ return -ENOMEM;
+
+ rxq->rrd = (void *)((u8 *)alx->descmem.virt + offset);
+ rxq->rrd_dma = alx->descmem.dma + offset;
+ offset += sizeof(struct alx_rrd) * alx->rx_ringsz;
+
+ rxq->rfd = (void *)((u8 *)alx->descmem.virt + offset);
+ rxq->rfd_dma = alx->descmem.dma + offset;
+ offset += sizeof(struct alx_rfd) * alx->rx_ringsz;
+
+ return offset;
+}
+
+static int alx_alloc_rings(struct alx_priv *alx)
+{
+ int offset = 0;
/* physical tx/rx ring descriptors
*
@@ -601,45 +623,23 @@ static int alx_alloc_descriptors(struct alx_priv *alx)
&alx->descmem.dma,
GFP_KERNEL);
if (!alx->descmem.virt)
- goto out_free;
-
- alx->txq.tpd = alx->descmem.virt;
- alx->txq.tpd_dma = alx->descmem.dma;
+ return -ENOMEM;
- /* alignment requirement for next block */
+ /* alignment requirements */
BUILD_BUG_ON(sizeof(struct alx_txd) % 8);
-
- alx->rxq.rrd =
- (void *)((u8 *)alx->descmem.virt +
- sizeof(struct alx_txd) * alx->tx_ringsz);
- alx->rxq.rrd_dma = alx->descmem.dma +
- sizeof(struct alx_txd) * alx->tx_ringsz;
-
- /* alignment requirement for next block */
BUILD_BUG_ON(sizeof(struct alx_rrd) % 8);
- alx->rxq.rfd =
- (void *)((u8 *)alx->descmem.virt +
- sizeof(struct alx_txd) * alx->tx_ringsz +
- sizeof(struct alx_rrd) * alx->rx_ringsz);
- alx->rxq.rfd_dma = alx->descmem.dma +
- sizeof(struct alx_txd) * alx->tx_ringsz +
- sizeof(struct alx_rrd) * alx->rx_ringsz;
-
- return 0;
-out_free:
- kfree(alx->txq.bufs);
- kfree(alx->rxq.bufs);
- return -ENOMEM;
-}
-
-static int alx_alloc_rings(struct alx_priv *alx)
-{
- int err;
+ offset = alx_alloc_tx_ring(alx, &alx->txq, offset);
+ if (offset < 0) {
+ netdev_err(alx->dev, "Allocation of tx buffer failed!\n");
+ goto out_free;
+ }
- err = alx_alloc_descriptors(alx);
- if (err)
- return err;
+ offset = alx_alloc_rx_ring(alx, &alx->rxq, offset);
+ if (offset < 0) {
+ netdev_err(alx->dev, "Allocation of rx buffer failed!\n");
+ goto out_free;
+ }
alx->int_mask &= ~ALX_ISR_ALL_QUEUES;
alx->int_mask |= ALX_ISR_TX_Q0 | ALX_ISR_RX_Q0;
@@ -647,7 +647,16 @@ static int alx_alloc_rings(struct alx_priv *alx)
netif_napi_add(alx->dev, &alx->napi, alx_poll, 64);
alx_reinit_rings(alx);
+
return 0;
+out_free:
+ kfree(alx->txq.bufs);
+ kfree(alx->rxq.bufs);
+ dma_free_coherent(&alx->hw.pdev->dev,
+ alx->descmem.size,
+ alx->descmem.virt,
+ alx->descmem.dma);
+ return -ENOMEM;
}
static void alx_free_rings(struct alx_priv *alx)
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 2/9] alx: extend data structures for multi queue support
From: Tobias Regnery @ 2016-10-21 10:49 UTC (permalink / raw)
To: jcliburn, chris.snook, netdev; +Cc: davem, Tobias Regnery
In-Reply-To: <cover.1477044917.git.tobias.regnery@gmail.com>
Extend the driver data structures to be able to handle multiple queues.
Based on the downstream driver at github.com/qca/alx
Signed-off-by: Tobias Regnery <tobias.regnery@gmail.com>
---
drivers/net/ethernet/atheros/alx/alx.h | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/drivers/net/ethernet/atheros/alx/alx.h b/drivers/net/ethernet/atheros/alx/alx.h
index 6cac919272ea..0859053525de 100644
--- a/drivers/net/ethernet/atheros/alx/alx.h
+++ b/drivers/net/ethernet/atheros/alx/alx.h
@@ -50,6 +50,10 @@ struct alx_buffer {
};
struct alx_rx_queue {
+ struct net_device *netdev;
+ struct device *dev;
+ struct alx_napi *np;
+
struct alx_rrd *rrd;
dma_addr_t rrd_dma;
@@ -58,16 +62,26 @@ struct alx_rx_queue {
struct alx_buffer *bufs;
+ u16 count;
u16 write_idx, read_idx;
u16 rrd_read_idx;
+ u16 queue_idx;
};
#define ALX_RX_ALLOC_THRESH 32
struct alx_tx_queue {
+ struct net_device *netdev;
+ struct device *dev;
+
struct alx_txd *tpd;
dma_addr_t tpd_dma;
+
struct alx_buffer *bufs;
+
+ u16 count;
u16 write_idx, read_idx;
+ u16 queue_idx;
+ u16 p_reg, c_reg;
};
#define ALX_DEFAULT_TX_WORK 128
@@ -76,6 +90,18 @@ enum alx_device_quirks {
ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG = BIT(0),
};
+struct alx_napi {
+ struct napi_struct napi;
+ struct alx_priv *alx;
+ struct alx_rx_queue *rxq;
+ struct alx_tx_queue *txq;
+ int vec_idx;
+ u32 vec_mask;
+ char irq_lbl[IFNAMSIZ + 8];
+};
+
+#define ALX_MAX_NAPIS 8
+
#define ALX_FLAG_USING_MSIX BIT(0)
#define ALX_FLAG_USING_MSI BIT(1)
@@ -96,6 +122,11 @@ struct alx_priv {
unsigned int size;
} descmem;
+ struct alx_napi *qnapi[ALX_MAX_NAPIS];
+ int num_txq;
+ int num_rxq;
+ int num_napi;
+
/* protect int_mask updates */
spinlock_t irq_lock;
u32 int_mask;
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 3/9] alx: add ability to allocate and free alx_napi structures
From: Tobias Regnery @ 2016-10-21 10:49 UTC (permalink / raw)
To: jcliburn, chris.snook, netdev; +Cc: davem, Tobias Regnery
In-Reply-To: <cover.1477044917.git.tobias.regnery@gmail.com>
Add new functions to allocate and free the alx_napi structures and use them
in __alx_open and __alx_stop. We only allocate one of these structures for
now, as the rest of the driver is not yet ready for multiple queues.
We switch over the setup of the interrupt mask and the call to netif_napi_add
to the new function because we must adjust these later on a per queue basis.
Based on the downstream driver at github.com/qca/alx
Signed-off-by: Tobias Regnery <tobias.regnery@gmail.com>
---
drivers/net/ethernet/atheros/alx/main.c | 99 ++++++++++++++++++++++++++-------
1 file changed, 78 insertions(+), 21 deletions(-)
diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c
index b7e67dd3d995..77b225535600 100644
--- a/drivers/net/ethernet/atheros/alx/main.c
+++ b/drivers/net/ethernet/atheros/alx/main.c
@@ -632,45 +632,96 @@ static int alx_alloc_rings(struct alx_priv *alx)
offset = alx_alloc_tx_ring(alx, &alx->txq, offset);
if (offset < 0) {
netdev_err(alx->dev, "Allocation of tx buffer failed!\n");
- goto out_free;
+ return -ENOMEM;
}
offset = alx_alloc_rx_ring(alx, &alx->rxq, offset);
if (offset < 0) {
netdev_err(alx->dev, "Allocation of rx buffer failed!\n");
- goto out_free;
+ return -ENOMEM;
}
- alx->int_mask &= ~ALX_ISR_ALL_QUEUES;
- alx->int_mask |= ALX_ISR_TX_Q0 | ALX_ISR_RX_Q0;
-
- netif_napi_add(alx->dev, &alx->napi, alx_poll, 64);
-
alx_reinit_rings(alx);
return 0;
-out_free:
- kfree(alx->txq.bufs);
- kfree(alx->rxq.bufs);
- dma_free_coherent(&alx->hw.pdev->dev,
- alx->descmem.size,
- alx->descmem.virt,
- alx->descmem.dma);
- return -ENOMEM;
}
static void alx_free_rings(struct alx_priv *alx)
{
- netif_napi_del(&alx->napi);
alx_free_buffers(alx);
kfree(alx->txq.bufs);
kfree(alx->rxq.bufs);
- dma_free_coherent(&alx->hw.pdev->dev,
- alx->descmem.size,
- alx->descmem.virt,
- alx->descmem.dma);
+ if (!alx->descmem.virt)
+ dma_free_coherent(&alx->hw.pdev->dev,
+ alx->descmem.size,
+ alx->descmem.virt,
+ alx->descmem.dma);
+}
+
+static void alx_free_napis(struct alx_priv *alx)
+{
+ struct alx_napi *np;
+
+ np = alx->qnapi[0];
+ if (!np)
+ return;
+
+ netif_napi_del(&alx->napi);
+ kfree(np->txq);
+ kfree(np->rxq);
+ kfree(np);
+ alx->qnapi[0] = NULL;
+}
+
+static int alx_alloc_napis(struct alx_priv *alx)
+{
+ struct alx_napi *np;
+ struct alx_rx_queue *rxq;
+ struct alx_tx_queue *txq;
+
+ alx->int_mask &= ~ALX_ISR_ALL_QUEUES;
+ alx->int_mask |= ALX_ISR_TX_Q0 | ALX_ISR_RX_Q0;
+
+ /* allocate alx_napi structures */
+ np = kzalloc(sizeof(struct alx_napi), GFP_KERNEL);
+ if (!np)
+ goto err_out;
+
+ np->alx = alx;
+ netif_napi_add(alx->dev, &alx->napi, alx_poll, 64);
+ alx->qnapi[0] = np;
+
+ /* allocate tx queues */
+ np = alx->qnapi[0];
+ txq = kzalloc(sizeof(*txq), GFP_KERNEL);
+ if (!txq)
+ goto err_out;
+
+ np->txq = txq;
+ txq->count = alx->tx_ringsz;
+ txq->netdev = alx->dev;
+ txq->dev = &alx->hw.pdev->dev;
+
+ /* allocate rx queues */
+ np = alx->qnapi[0];
+ rxq = kzalloc(sizeof(*rxq), GFP_KERNEL);
+ if (!rxq)
+ goto err_out;
+
+ np->rxq = rxq;
+ rxq->np = alx->qnapi[0];
+ rxq->count = alx->rx_ringsz;
+ rxq->netdev = alx->dev;
+ rxq->dev = &alx->hw.pdev->dev;
+
+ return 0;
+
+err_out:
+ netdev_err(alx->dev, "error allocating internal structures\n");
+ alx_free_napis(alx);
+ return -ENOMEM;
}
static void alx_config_vector_mapping(struct alx_priv *alx)
@@ -1031,10 +1082,14 @@ static int __alx_open(struct alx_priv *alx, bool resume)
if (!resume)
netif_carrier_off(alx->dev);
- err = alx_alloc_rings(alx);
+ err = alx_alloc_napis(alx);
if (err)
goto out_disable_adv_intr;
+ err = alx_alloc_rings(alx);
+ if (err)
+ goto out_free_rings;
+
alx_configure(alx);
err = alx_request_irq(alx);
@@ -1054,6 +1109,7 @@ static int __alx_open(struct alx_priv *alx, bool resume)
out_free_rings:
alx_free_rings(alx);
+ alx_free_napis(alx);
out_disable_adv_intr:
alx_disable_advanced_intr(alx);
return err;
@@ -1064,6 +1120,7 @@ static void __alx_stop(struct alx_priv *alx)
alx_halt(alx);
alx_free_irq(alx);
alx_free_rings(alx);
+ alx_free_napis(alx);
}
static const char *alx_speed_desc(struct alx_hw *hw)
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 4/9] alx: switch to per queue data structures
From: Tobias Regnery @ 2016-10-21 10:49 UTC (permalink / raw)
To: jcliburn, chris.snook, netdev; +Cc: davem, Tobias Regnery
In-Reply-To: <cover.1477044917.git.tobias.regnery@gmail.com>
Remove the tx and rx queue structures from the alx_priv structure and switch
everything over to the queue pointers in the alx_napi structure.
Based on the downstream driver at github.com/qca/alx
Signed-off-by: Tobias Regnery <tobias.regnery@gmail.com>
---
drivers/net/ethernet/atheros/alx/alx.h | 5 -
drivers/net/ethernet/atheros/alx/main.c | 183 ++++++++++++++++----------------
2 files changed, 93 insertions(+), 95 deletions(-)
diff --git a/drivers/net/ethernet/atheros/alx/alx.h b/drivers/net/ethernet/atheros/alx/alx.h
index 0859053525de..d4a409139ea2 100644
--- a/drivers/net/ethernet/atheros/alx/alx.h
+++ b/drivers/net/ethernet/atheros/alx/alx.h
@@ -113,7 +113,6 @@ struct alx_priv {
/* msi-x vectors */
int num_vec;
struct msix_entry *msix_entries;
- char irq_lbl[IFNAMSIZ + 8];
/* all descriptor memory */
struct {
@@ -135,10 +134,6 @@ struct alx_priv {
unsigned int rx_ringsz;
unsigned int rxbuf_size;
- struct napi_struct napi;
- struct alx_tx_queue txq;
- struct alx_rx_queue rxq;
-
struct work_struct link_check_wk;
struct work_struct reset_wk;
diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c
index 77b225535600..5d058e075752 100644
--- a/drivers/net/ethernet/atheros/alx/main.c
+++ b/drivers/net/ethernet/atheros/alx/main.c
@@ -55,12 +55,12 @@ static bool msix = false;
module_param(msix, bool, 0);
MODULE_PARM_DESC(msix, "Enable msi-x interrupt support");
-static void alx_free_txbuf(struct alx_priv *alx, int entry)
+static void alx_free_txbuf(struct alx_tx_queue *txq, int entry)
{
- struct alx_buffer *txb = &alx->txq.bufs[entry];
+ struct alx_buffer *txb = &txq->bufs[entry];
if (dma_unmap_len(txb, size)) {
- dma_unmap_single(&alx->hw.pdev->dev,
+ dma_unmap_single(txq->dev,
dma_unmap_addr(txb, dma),
dma_unmap_len(txb, size),
DMA_TO_DEVICE);
@@ -75,7 +75,7 @@ static void alx_free_txbuf(struct alx_priv *alx, int entry)
static int alx_refill_rx_ring(struct alx_priv *alx, gfp_t gfp)
{
- struct alx_rx_queue *rxq = &alx->rxq;
+ struct alx_rx_queue *rxq = alx->qnapi[0]->rxq;
struct sk_buff *skb;
struct alx_buffer *cur_buf;
dma_addr_t dma;
@@ -143,22 +143,22 @@ static int alx_refill_rx_ring(struct alx_priv *alx, gfp_t gfp)
return count;
}
-static inline int alx_tpd_avail(struct alx_priv *alx)
+static inline int alx_tpd_avail(struct alx_tx_queue *txq)
{
- struct alx_tx_queue *txq = &alx->txq;
-
if (txq->write_idx >= txq->read_idx)
- return alx->tx_ringsz + txq->read_idx - txq->write_idx - 1;
+ return txq->count + txq->read_idx - txq->write_idx - 1;
return txq->read_idx - txq->write_idx - 1;
}
-static bool alx_clean_tx_irq(struct alx_priv *alx)
+static bool alx_clean_tx_irq(struct alx_tx_queue *txq)
{
- struct alx_tx_queue *txq = &alx->txq;
+ struct alx_priv *alx;
u16 hw_read_idx, sw_read_idx;
unsigned int total_bytes = 0, total_packets = 0;
int budget = ALX_DEFAULT_TX_WORK;
+ alx = netdev_priv(txq->netdev);
+
sw_read_idx = txq->read_idx;
hw_read_idx = alx_read_mem16(&alx->hw, ALX_TPD_PRI0_CIDX);
@@ -173,19 +173,19 @@ static bool alx_clean_tx_irq(struct alx_priv *alx)
budget--;
}
- alx_free_txbuf(alx, sw_read_idx);
+ alx_free_txbuf(txq, sw_read_idx);
- if (++sw_read_idx == alx->tx_ringsz)
+ if (++sw_read_idx == txq->count)
sw_read_idx = 0;
}
txq->read_idx = sw_read_idx;
- netdev_completed_queue(alx->dev, total_packets, total_bytes);
+ netdev_completed_queue(txq->netdev, total_packets, total_bytes);
}
- if (netif_queue_stopped(alx->dev) && netif_carrier_ok(alx->dev) &&
- alx_tpd_avail(alx) > alx->tx_ringsz/4)
- netif_wake_queue(alx->dev);
+ if (netif_queue_stopped(txq->netdev) && netif_carrier_ok(txq->netdev) &&
+ alx_tpd_avail(txq) > txq->count / 4)
+ netif_wake_queue(txq->netdev);
return sw_read_idx == hw_read_idx;
}
@@ -200,15 +200,17 @@ static void alx_schedule_reset(struct alx_priv *alx)
schedule_work(&alx->reset_wk);
}
-static int alx_clean_rx_irq(struct alx_priv *alx, int budget)
+static int alx_clean_rx_irq(struct alx_rx_queue *rxq, int budget)
{
- struct alx_rx_queue *rxq = &alx->rxq;
+ struct alx_priv *alx;
struct alx_rrd *rrd;
struct alx_buffer *rxb;
struct sk_buff *skb;
u16 length, rfd_cleaned = 0;
int work = 0;
+ alx = netdev_priv(rxq->netdev);
+
while (work < budget) {
rrd = &rxq->rrd[rxq->rrd_read_idx];
if (!(rrd->word3 & cpu_to_le32(1 << RRD_UPDATED_SHIFT)))
@@ -224,7 +226,7 @@ static int alx_clean_rx_irq(struct alx_priv *alx, int budget)
}
rxb = &rxq->bufs[rxq->read_idx];
- dma_unmap_single(&alx->hw.pdev->dev,
+ dma_unmap_single(rxq->dev,
dma_unmap_addr(rxb, dma),
dma_unmap_len(rxb, size),
DMA_FROM_DEVICE);
@@ -242,7 +244,7 @@ static int alx_clean_rx_irq(struct alx_priv *alx, int budget)
length = ALX_GET_FIELD(le32_to_cpu(rrd->word3),
RRD_PKTLEN) - ETH_FCS_LEN;
skb_put(skb, length);
- skb->protocol = eth_type_trans(skb, alx->dev);
+ skb->protocol = eth_type_trans(skb, rxq->netdev);
skb_checksum_none_assert(skb);
if (alx->dev->features & NETIF_F_RXCSUM &&
@@ -259,13 +261,13 @@ static int alx_clean_rx_irq(struct alx_priv *alx, int budget)
}
}
- napi_gro_receive(&alx->napi, skb);
+ napi_gro_receive(&rxq->np->napi, skb);
work++;
next_pkt:
- if (++rxq->read_idx == alx->rx_ringsz)
+ if (++rxq->read_idx == rxq->count)
rxq->read_idx = 0;
- if (++rxq->rrd_read_idx == alx->rx_ringsz)
+ if (++rxq->rrd_read_idx == rxq->count)
rxq->rrd_read_idx = 0;
if (++rfd_cleaned > ALX_RX_ALLOC_THRESH)
@@ -280,19 +282,20 @@ static int alx_clean_rx_irq(struct alx_priv *alx, int budget)
static int alx_poll(struct napi_struct *napi, int budget)
{
- struct alx_priv *alx = container_of(napi, struct alx_priv, napi);
+ struct alx_napi *np = container_of(napi, struct alx_napi, napi);
+ struct alx_priv *alx = np->alx;
struct alx_hw *hw = &alx->hw;
unsigned long flags;
bool tx_complete;
int work;
- tx_complete = alx_clean_tx_irq(alx);
- work = alx_clean_rx_irq(alx, budget);
+ tx_complete = alx_clean_tx_irq(np->txq);
+ work = alx_clean_rx_irq(np->rxq, budget);
if (!tx_complete || work == budget)
return budget;
- napi_complete(&alx->napi);
+ napi_complete(&np->napi);
/* enable interrupt */
if (alx->flags & ALX_FLAG_USING_MSIX) {
@@ -350,7 +353,7 @@ static irqreturn_t alx_intr_handle(struct alx_priv *alx, u32 intr)
goto out;
if (intr & (ALX_ISR_TX_Q0 | ALX_ISR_RX_Q0)) {
- napi_schedule(&alx->napi);
+ napi_schedule(&alx->qnapi[0]->napi);
/* mask rx/tx interrupt, enable them when napi complete */
alx->int_mask &= ~ALX_ISR_ALL_QUEUES;
alx_write_mem32(hw, ALX_IMR, alx->int_mask);
@@ -365,15 +368,15 @@ static irqreturn_t alx_intr_handle(struct alx_priv *alx, u32 intr)
static irqreturn_t alx_intr_msix_ring(int irq, void *data)
{
- struct alx_priv *alx = data;
- struct alx_hw *hw = &alx->hw;
+ struct alx_napi *np = data;
+ struct alx_hw *hw = &np->alx->hw;
/* mask interrupt to ACK chip */
alx_mask_msix(hw, 1, true);
/* clear interrupt status */
alx_write_mem32(hw, ALX_ISR, (ALX_ISR_TX_Q0 | ALX_ISR_RX_Q0));
- napi_schedule(&alx->napi);
+ napi_schedule(&np->napi);
return IRQ_HANDLED;
}
@@ -428,59 +431,58 @@ static void alx_init_ring_ptrs(struct alx_priv *alx)
{
struct alx_hw *hw = &alx->hw;
u32 addr_hi = ((u64)alx->descmem.dma) >> 32;
+ struct alx_napi *np = alx->qnapi[0];
- alx->rxq.read_idx = 0;
- alx->rxq.write_idx = 0;
- alx->rxq.rrd_read_idx = 0;
+ np->rxq->read_idx = 0;
+ np->rxq->write_idx = 0;
+ np->rxq->rrd_read_idx = 0;
alx_write_mem32(hw, ALX_RX_BASE_ADDR_HI, addr_hi);
- alx_write_mem32(hw, ALX_RRD_ADDR_LO, alx->rxq.rrd_dma);
+ alx_write_mem32(hw, ALX_RRD_ADDR_LO, np->rxq->rrd_dma);
alx_write_mem32(hw, ALX_RRD_RING_SZ, alx->rx_ringsz);
- alx_write_mem32(hw, ALX_RFD_ADDR_LO, alx->rxq.rfd_dma);
+ alx_write_mem32(hw, ALX_RFD_ADDR_LO, np->rxq->rfd_dma);
alx_write_mem32(hw, ALX_RFD_RING_SZ, alx->rx_ringsz);
alx_write_mem32(hw, ALX_RFD_BUF_SZ, alx->rxbuf_size);
- alx->txq.read_idx = 0;
- alx->txq.write_idx = 0;
+ np->txq->read_idx = 0;
+ np->txq->write_idx = 0;
alx_write_mem32(hw, ALX_TX_BASE_ADDR_HI, addr_hi);
- alx_write_mem32(hw, ALX_TPD_PRI0_ADDR_LO, alx->txq.tpd_dma);
+ alx_write_mem32(hw, ALX_TPD_PRI0_ADDR_LO, np->txq->tpd_dma);
alx_write_mem32(hw, ALX_TPD_RING_SZ, alx->tx_ringsz);
/* load these pointers into the chip */
alx_write_mem32(hw, ALX_SRAM9, ALX_SRAM_LOAD_PTR);
}
-static void alx_free_txring_buf(struct alx_priv *alx)
+static void alx_free_txring_buf(struct alx_tx_queue *txq)
{
- struct alx_tx_queue *txq = &alx->txq;
int i;
if (!txq->bufs)
return;
- for (i = 0; i < alx->tx_ringsz; i++)
- alx_free_txbuf(alx, i);
+ for (i = 0; i < txq->count; i++)
+ alx_free_txbuf(txq, i);
- memset(txq->bufs, 0, alx->tx_ringsz * sizeof(struct alx_buffer));
- memset(txq->tpd, 0, alx->tx_ringsz * sizeof(struct alx_txd));
+ memset(txq->bufs, 0, txq->count * sizeof(struct alx_buffer));
+ memset(txq->tpd, 0, txq->count * sizeof(struct alx_txd));
txq->write_idx = 0;
txq->read_idx = 0;
- netdev_reset_queue(alx->dev);
+ netdev_reset_queue(txq->netdev);
}
-static void alx_free_rxring_buf(struct alx_priv *alx)
+static void alx_free_rxring_buf(struct alx_rx_queue *rxq)
{
- struct alx_rx_queue *rxq = &alx->rxq;
struct alx_buffer *cur_buf;
u16 i;
if (rxq == NULL)
return;
- for (i = 0; i < alx->rx_ringsz; i++) {
+ for (i = 0; i < rxq->count; i++) {
cur_buf = rxq->bufs + i;
if (cur_buf->skb) {
- dma_unmap_single(&alx->hw.pdev->dev,
+ dma_unmap_single(rxq->dev,
dma_unmap_addr(cur_buf, dma),
dma_unmap_len(cur_buf, size),
DMA_FROM_DEVICE);
@@ -498,8 +500,8 @@ static void alx_free_rxring_buf(struct alx_priv *alx)
static void alx_free_buffers(struct alx_priv *alx)
{
- alx_free_txring_buf(alx);
- alx_free_rxring_buf(alx);
+ alx_free_txring_buf(alx->qnapi[0]->txq);
+ alx_free_rxring_buf(alx->qnapi[0]->rxq);
}
static int alx_reinit_rings(struct alx_priv *alx)
@@ -576,13 +578,13 @@ static int alx_set_mac_address(struct net_device *netdev, void *data)
static int alx_alloc_tx_ring(struct alx_priv *alx, struct alx_tx_queue *txq,
int offset)
{
- txq->bufs = kcalloc(alx->tx_ringsz, sizeof(struct alx_buffer), GFP_KERNEL);
+ txq->bufs = kcalloc(txq->count, sizeof(struct alx_buffer), GFP_KERNEL);
if (!txq->bufs)
return -ENOMEM;
txq->tpd = alx->descmem.virt + offset;
txq->tpd_dma = alx->descmem.dma + offset;
- offset += sizeof(struct alx_txd) * alx->tx_ringsz;
+ offset += sizeof(struct alx_txd) * txq->count;
return offset;
}
@@ -590,17 +592,17 @@ static int alx_alloc_tx_ring(struct alx_priv *alx, struct alx_tx_queue *txq,
static int alx_alloc_rx_ring(struct alx_priv *alx, struct alx_rx_queue *rxq,
int offset)
{
- rxq->bufs = kcalloc(alx->rx_ringsz, sizeof(struct alx_buffer), GFP_KERNEL);
+ rxq->bufs = kcalloc(rxq->count, sizeof(struct alx_buffer), GFP_KERNEL);
if (!rxq->bufs)
return -ENOMEM;
rxq->rrd = (void *)((u8 *)alx->descmem.virt + offset);
rxq->rrd_dma = alx->descmem.dma + offset;
- offset += sizeof(struct alx_rrd) * alx->rx_ringsz;
+ offset += sizeof(struct alx_rrd) * rxq->count;
rxq->rfd = (void *)((u8 *)alx->descmem.virt + offset);
rxq->rfd_dma = alx->descmem.dma + offset;
- offset += sizeof(struct alx_rfd) * alx->rx_ringsz;
+ offset += sizeof(struct alx_rfd) * rxq->count;
return offset;
}
@@ -629,13 +631,13 @@ static int alx_alloc_rings(struct alx_priv *alx)
BUILD_BUG_ON(sizeof(struct alx_txd) % 8);
BUILD_BUG_ON(sizeof(struct alx_rrd) % 8);
- offset = alx_alloc_tx_ring(alx, &alx->txq, offset);
+ offset = alx_alloc_tx_ring(alx, alx->qnapi[0]->txq, offset);
if (offset < 0) {
netdev_err(alx->dev, "Allocation of tx buffer failed!\n");
return -ENOMEM;
}
- offset = alx_alloc_rx_ring(alx, &alx->rxq, offset);
+ offset = alx_alloc_rx_ring(alx, alx->qnapi[0]->rxq, offset);
if (offset < 0) {
netdev_err(alx->dev, "Allocation of rx buffer failed!\n");
return -ENOMEM;
@@ -648,10 +650,11 @@ static int alx_alloc_rings(struct alx_priv *alx)
static void alx_free_rings(struct alx_priv *alx)
{
+
alx_free_buffers(alx);
- kfree(alx->txq.bufs);
- kfree(alx->rxq.bufs);
+ kfree(alx->qnapi[0]->txq->bufs);
+ kfree(alx->qnapi[0]->rxq->bufs);
if (!alx->descmem.virt)
dma_free_coherent(&alx->hw.pdev->dev,
@@ -668,7 +671,7 @@ static void alx_free_napis(struct alx_priv *alx)
if (!np)
return;
- netif_napi_del(&alx->napi);
+ netif_napi_del(&np->napi);
kfree(np->txq);
kfree(np->rxq);
kfree(np);
@@ -690,7 +693,7 @@ static int alx_alloc_napis(struct alx_priv *alx)
goto err_out;
np->alx = alx;
- netif_napi_add(alx->dev, &alx->napi, alx_poll, 64);
+ netif_napi_add(alx->dev, &np->napi, alx_poll, 64);
alx->qnapi[0] = np;
/* allocate tx queues */
@@ -768,6 +771,7 @@ static int alx_request_msix(struct alx_priv *alx)
{
struct net_device *netdev = alx->dev;
int i, err, vector = 0, free_vector = 0;
+ struct alx_napi *np = alx->qnapi[0];
err = request_irq(alx->msix_entries[0].vector, alx_intr_msix_misc,
0, netdev->name, alx);
@@ -775,10 +779,10 @@ static int alx_request_msix(struct alx_priv *alx)
goto out_err;
vector++;
- sprintf(alx->irq_lbl, "%s-TxRx-0", netdev->name);
+ sprintf(np->irq_lbl, "%s-TxRx-0", netdev->name);
err = request_irq(alx->msix_entries[vector].vector,
- alx_intr_msix_ring, 0, alx->irq_lbl, alx);
+ alx_intr_msix_ring, 0, np->irq_lbl, np);
if (err)
goto out_free;
@@ -789,7 +793,7 @@ static int alx_request_msix(struct alx_priv *alx)
vector--;
for (i = 0; i < vector; i++)
- free_irq(alx->msix_entries[free_vector++].vector, alx);
+ free_irq(alx->msix_entries[free_vector++].vector, alx->qnapi[0]);
out_err:
return err;
@@ -905,12 +909,12 @@ static int alx_request_irq(struct alx_priv *alx)
static void alx_free_irq(struct alx_priv *alx)
{
struct pci_dev *pdev = alx->hw.pdev;
- int i;
+ int i, vector = 0;
if (alx->flags & ALX_FLAG_USING_MSIX) {
/* we have only 2 vectors without multi queue support */
- for (i = 0; i < 2; i++)
- free_irq(alx->msix_entries[i].vector, alx);
+ free_irq(alx->msix_entries[vector++].vector, alx);
+ free_irq(alx->msix_entries[vector++].vector, alx->qnapi[0]);
} else {
free_irq(pdev->irq, alx);
}
@@ -999,7 +1003,7 @@ static void alx_netif_stop(struct alx_priv *alx)
if (netif_carrier_ok(alx->dev)) {
netif_carrier_off(alx->dev);
netif_tx_disable(alx->dev);
- napi_disable(&alx->napi);
+ napi_disable(&alx->qnapi[0]->napi);
}
}
@@ -1069,7 +1073,7 @@ static int alx_change_mtu(struct net_device *netdev, int mtu)
static void alx_netif_start(struct alx_priv *alx)
{
netif_tx_wake_all_queues(alx->dev);
- napi_enable(&alx->napi);
+ napi_enable(&alx->qnapi[0]->napi);
netif_carrier_on(alx->dev);
}
@@ -1303,9 +1307,8 @@ static int alx_tso(struct sk_buff *skb, struct alx_txd *first)
return 1;
}
-static int alx_map_tx_skb(struct alx_priv *alx, struct sk_buff *skb)
+static int alx_map_tx_skb(struct alx_tx_queue *txq, struct sk_buff *skb)
{
- struct alx_tx_queue *txq = &alx->txq;
struct alx_txd *tpd, *first_tpd;
dma_addr_t dma;
int maplen, f, first_idx = txq->write_idx;
@@ -1314,7 +1317,7 @@ static int alx_map_tx_skb(struct alx_priv *alx, struct sk_buff *skb)
tpd = first_tpd;
if (tpd->word1 & (1 << TPD_LSO_V2_SHIFT)) {
- if (++txq->write_idx == alx->tx_ringsz)
+ if (++txq->write_idx == txq->count)
txq->write_idx = 0;
tpd = &txq->tpd[txq->write_idx];
@@ -1324,9 +1327,9 @@ static int alx_map_tx_skb(struct alx_priv *alx, struct sk_buff *skb)
}
maplen = skb_headlen(skb);
- dma = dma_map_single(&alx->hw.pdev->dev, skb->data, maplen,
+ dma = dma_map_single(txq->dev, skb->data, maplen,
DMA_TO_DEVICE);
- if (dma_mapping_error(&alx->hw.pdev->dev, dma))
+ if (dma_mapping_error(txq->dev, dma))
goto err_dma;
dma_unmap_len_set(&txq->bufs[txq->write_idx], size, maplen);
@@ -1340,16 +1343,16 @@ static int alx_map_tx_skb(struct alx_priv *alx, struct sk_buff *skb)
frag = &skb_shinfo(skb)->frags[f];
- if (++txq->write_idx == alx->tx_ringsz)
+ if (++txq->write_idx == txq->count)
txq->write_idx = 0;
tpd = &txq->tpd[txq->write_idx];
tpd->word1 = first_tpd->word1;
maplen = skb_frag_size(frag);
- dma = skb_frag_dma_map(&alx->hw.pdev->dev, frag, 0,
+ dma = skb_frag_dma_map(txq->dev, frag, 0,
maplen, DMA_TO_DEVICE);
- if (dma_mapping_error(&alx->hw.pdev->dev, dma))
+ if (dma_mapping_error(txq->dev, dma))
goto err_dma;
dma_unmap_len_set(&txq->bufs[txq->write_idx], size, maplen);
dma_unmap_addr_set(&txq->bufs[txq->write_idx], dma, dma);
@@ -1362,7 +1365,7 @@ static int alx_map_tx_skb(struct alx_priv *alx, struct sk_buff *skb)
tpd->word1 |= cpu_to_le32(1 << TPD_EOP_SHIFT);
txq->bufs[txq->write_idx].skb = skb;
- if (++txq->write_idx == alx->tx_ringsz)
+ if (++txq->write_idx == txq->count)
txq->write_idx = 0;
return 0;
@@ -1370,8 +1373,8 @@ static int alx_map_tx_skb(struct alx_priv *alx, struct sk_buff *skb)
err_dma:
f = first_idx;
while (f != txq->write_idx) {
- alx_free_txbuf(alx, f);
- if (++f == alx->tx_ringsz)
+ alx_free_txbuf(txq, f);
+ if (++f == txq->count)
f = 0;
}
return -ENOMEM;
@@ -1381,12 +1384,12 @@ static netdev_tx_t alx_start_xmit(struct sk_buff *skb,
struct net_device *netdev)
{
struct alx_priv *alx = netdev_priv(netdev);
- struct alx_tx_queue *txq = &alx->txq;
+ struct alx_tx_queue *txq = alx->qnapi[0]->txq;
struct alx_txd *first;
int tso;
- if (alx_tpd_avail(alx) < alx_tpd_req(skb)) {
- netif_stop_queue(alx->dev);
+ if (alx_tpd_avail(txq) < alx_tpd_req(skb)) {
+ netif_stop_queue(txq->netdev);
goto drop;
}
@@ -1399,17 +1402,17 @@ static netdev_tx_t alx_start_xmit(struct sk_buff *skb,
else if (!tso && alx_tx_csum(skb, first))
goto drop;
- if (alx_map_tx_skb(alx, skb) < 0)
+ if (alx_map_tx_skb(txq, skb) < 0)
goto drop;
- netdev_sent_queue(alx->dev, skb->len);
+ netdev_sent_queue(txq->netdev, skb->len);
/* flush updates before updating hardware */
wmb();
alx_write_mem16(&alx->hw, ALX_TPD_PRI0_PIDX, txq->write_idx);
- if (alx_tpd_avail(alx) < alx->tx_ringsz/8)
- netif_stop_queue(alx->dev);
+ if (alx_tpd_avail(txq) < txq->count / 8)
+ netif_stop_queue(txq->netdev);
return NETDEV_TX_OK;
@@ -1478,7 +1481,7 @@ static void alx_poll_controller(struct net_device *netdev)
if (alx->flags & ALX_FLAG_USING_MSIX) {
alx_intr_msix_misc(0, alx);
- alx_intr_msix_ring(0, alx);
+ alx_intr_msix_ring(0, alx->qnapi[0]);
} else if (alx->flags & ALX_FLAG_USING_MSI)
alx_intr_msi(0, alx);
else
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 5/9] alx: prepare interrupt functions for multiple queues
From: Tobias Regnery @ 2016-10-21 10:49 UTC (permalink / raw)
To: jcliburn, chris.snook, netdev; +Cc: davem, Tobias Regnery
In-Reply-To: <cover.1477044917.git.tobias.regnery@gmail.com>
Extend the interrupt bringup code and the interrupt handler for msi-x
interrupts in order to handle multiple queues.
We must change the poll function because with multiple queues it is possible
that an alx_napi structure has only a tx or only a rx queue pointer.
Based on the downstream driver at github.com/qca/alx
Signed-off-by: Tobias Regnery <tobias.regnery@gmail.com>
---
drivers/net/ethernet/atheros/alx/main.c | 132 +++++++++++++++++++++++++-------
1 file changed, 105 insertions(+), 27 deletions(-)
diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c
index 5d058e075752..624419968df5 100644
--- a/drivers/net/ethernet/atheros/alx/main.c
+++ b/drivers/net/ethernet/atheros/alx/main.c
@@ -286,11 +286,13 @@ static int alx_poll(struct napi_struct *napi, int budget)
struct alx_priv *alx = np->alx;
struct alx_hw *hw = &alx->hw;
unsigned long flags;
- bool tx_complete;
- int work;
+ bool tx_complete = true;
+ int work = 0;
- tx_complete = alx_clean_tx_irq(np->txq);
- work = alx_clean_rx_irq(np->rxq, budget);
+ if (np->txq)
+ tx_complete = alx_clean_tx_irq(np->txq);
+ if (np->rxq)
+ work = alx_clean_rx_irq(np->rxq, budget);
if (!tx_complete || work == budget)
return budget;
@@ -299,7 +301,7 @@ static int alx_poll(struct napi_struct *napi, int budget)
/* enable interrupt */
if (alx->flags & ALX_FLAG_USING_MSIX) {
- alx_mask_msix(hw, 1, false);
+ alx_mask_msix(hw, np->vec_idx, false);
} else {
spin_lock_irqsave(&alx->irq_lock, flags);
alx->int_mask |= ALX_ISR_TX_Q0 | ALX_ISR_RX_Q0;
@@ -372,9 +374,9 @@ static irqreturn_t alx_intr_msix_ring(int irq, void *data)
struct alx_hw *hw = &np->alx->hw;
/* mask interrupt to ACK chip */
- alx_mask_msix(hw, 1, true);
+ alx_mask_msix(hw, np->vec_idx, true);
/* clear interrupt status */
- alx_write_mem32(hw, ALX_ISR, (ALX_ISR_TX_Q0 | ALX_ISR_RX_Q0));
+ alx_write_mem32(hw, ALX_ISR, np->vec_mask);
napi_schedule(&np->napi);
@@ -678,6 +680,13 @@ static void alx_free_napis(struct alx_priv *alx)
alx->qnapi[0] = NULL;
}
+static const u32 tx_vect_mask[] = {ALX_ISR_TX_Q0, ALX_ISR_TX_Q1,
+ ALX_ISR_TX_Q2, ALX_ISR_TX_Q3};
+static const u32 rx_vect_mask[] = {ALX_ISR_RX_Q0, ALX_ISR_RX_Q1,
+ ALX_ISR_RX_Q2, ALX_ISR_RX_Q3,
+ ALX_ISR_RX_Q4, ALX_ISR_RX_Q5,
+ ALX_ISR_RX_Q6, ALX_ISR_RX_Q7};
+
static int alx_alloc_napis(struct alx_priv *alx)
{
struct alx_napi *np;
@@ -685,7 +694,6 @@ static int alx_alloc_napis(struct alx_priv *alx)
struct alx_tx_queue *txq;
alx->int_mask &= ~ALX_ISR_ALL_QUEUES;
- alx->int_mask |= ALX_ISR_TX_Q0 | ALX_ISR_RX_Q0;
/* allocate alx_napi structures */
np = kzalloc(sizeof(struct alx_napi), GFP_KERNEL);
@@ -703,9 +711,12 @@ static int alx_alloc_napis(struct alx_priv *alx)
goto err_out;
np->txq = txq;
+ txq->queue_idx = 0;
txq->count = alx->tx_ringsz;
txq->netdev = alx->dev;
txq->dev = &alx->hw.pdev->dev;
+ np->vec_mask |= tx_vect_mask[0];
+ alx->int_mask |= tx_vect_mask[0];
/* allocate rx queues */
np = alx->qnapi[0];
@@ -715,9 +726,12 @@ static int alx_alloc_napis(struct alx_priv *alx)
np->rxq = rxq;
rxq->np = alx->qnapi[0];
+ rxq->queue_idx = 0;
rxq->count = alx->rx_ringsz;
rxq->netdev = alx->dev;
rxq->dev = &alx->hw.pdev->dev;
+ np->vec_mask |= rx_vect_mask[0];
+ alx->int_mask |= rx_vect_mask[0];
return 0;
@@ -727,24 +741,43 @@ static int alx_alloc_napis(struct alx_priv *alx)
return -ENOMEM;
}
+static const int txq_vec_mapping_shift[] = {
+ 0, ALX_MSI_MAP_TBL1_TXQ0_SHIFT,
+ 0, ALX_MSI_MAP_TBL1_TXQ1_SHIFT,
+ 1, ALX_MSI_MAP_TBL2_TXQ2_SHIFT,
+ 1, ALX_MSI_MAP_TBL2_TXQ3_SHIFT,
+};
+
static void alx_config_vector_mapping(struct alx_priv *alx)
{
struct alx_hw *hw = &alx->hw;
- u32 tbl = 0;
+ u32 tbl[2] = {0, 0};
+ int i, vector, idx, shift;
if (alx->flags & ALX_FLAG_USING_MSIX) {
- tbl |= 1 << ALX_MSI_MAP_TBL1_TXQ0_SHIFT;
- tbl |= 1 << ALX_MSI_MAP_TBL1_RXQ0_SHIFT;
+ /* tx mappings */
+ for (i = 0, vector = 1; i < alx->num_txq; i++, vector++) {
+ idx = txq_vec_mapping_shift[i * 2];
+ shift = txq_vec_mapping_shift[i * 2 + 1];
+ tbl[idx] |= vector << shift;
+ }
+
+ /* rx mapping */
+ tbl[0] |= 1 << ALX_MSI_MAP_TBL1_RXQ0_SHIFT;
}
- alx_write_mem32(hw, ALX_MSI_MAP_TBL1, tbl);
- alx_write_mem32(hw, ALX_MSI_MAP_TBL2, 0);
+ alx_write_mem32(hw, ALX_MSI_MAP_TBL1, tbl[0]);
+ alx_write_mem32(hw, ALX_MSI_MAP_TBL2, tbl[1]);
alx_write_mem32(hw, ALX_MSI_ID_MAP, 0);
}
static bool alx_enable_msix(struct alx_priv *alx)
{
- int i, err, num_vec = 2;
+ int i, err, num_vec, num_txq, num_rxq;
+
+ num_txq = 1;
+ num_rxq = 1;
+ num_vec = max_t(int, num_txq, num_rxq) + 1;
alx->msix_entries = kcalloc(num_vec, sizeof(struct msix_entry),
GFP_KERNEL);
@@ -764,6 +797,10 @@ static bool alx_enable_msix(struct alx_priv *alx)
}
alx->num_vec = num_vec;
+ alx->num_napi = num_vec - 1;
+ alx->num_txq = num_txq;
+ alx->num_rxq = num_rxq;
+
return true;
}
@@ -771,21 +808,35 @@ static int alx_request_msix(struct alx_priv *alx)
{
struct net_device *netdev = alx->dev;
int i, err, vector = 0, free_vector = 0;
- struct alx_napi *np = alx->qnapi[0];
err = request_irq(alx->msix_entries[0].vector, alx_intr_msix_misc,
0, netdev->name, alx);
if (err)
goto out_err;
- vector++;
- sprintf(np->irq_lbl, "%s-TxRx-0", netdev->name);
-
- err = request_irq(alx->msix_entries[vector].vector,
- alx_intr_msix_ring, 0, np->irq_lbl, np);
+ for (i = 0; i < alx->num_napi; i++) {
+ struct alx_napi *np = alx->qnapi[i];
+
+ vector++;
+
+ if (np->txq && np->rxq)
+ sprintf(np->irq_lbl, "%s-TxRx-%u", netdev->name,
+ np->txq->queue_idx);
+ else if (np->txq)
+ sprintf(np->irq_lbl, "%s-tx-%u", netdev->name,
+ np->txq->queue_idx);
+ else if (np->rxq)
+ sprintf(np->irq_lbl, "%s-rx-%u", netdev->name,
+ np->rxq->queue_idx);
+ else
+ sprintf(np->irq_lbl, "%s-unused", netdev->name);
+
+ np->vec_idx = vector;
+ err = request_irq(alx->msix_entries[vector].vector,
+ alx_intr_msix_ring, 0, np->irq_lbl, np);
if (err)
goto out_free;
-
+ }
return 0;
out_free:
@@ -793,7 +844,8 @@ static int alx_request_msix(struct alx_priv *alx)
vector--;
for (i = 0; i < vector; i++)
- free_irq(alx->msix_entries[free_vector++].vector, alx->qnapi[0]);
+ free_irq(alx->msix_entries[free_vector++].vector,
+ alx->qnapi[i]);
out_err:
return err;
@@ -808,6 +860,9 @@ static void alx_init_intr(struct alx_priv *alx, bool msix)
if (!(alx->flags & ALX_FLAG_USING_MSIX)) {
alx->num_vec = 1;
+ alx->num_napi = 1;
+ alx->num_txq = 1;
+ alx->num_rxq = 1;
if (!pci_enable_msi(alx->hw.pdev))
alx->flags |= ALX_FLAG_USING_MSI;
@@ -863,6 +918,25 @@ static void alx_irq_disable(struct alx_priv *alx)
}
}
+static int alx_realloc_resources(struct alx_priv *alx)
+{
+ int err;
+
+ alx_free_rings(alx);
+ alx_free_napis(alx);
+ alx_disable_advanced_intr(alx);
+
+ err = alx_alloc_napis(alx);
+ if (err)
+ return err;
+
+ err = alx_alloc_rings(alx);
+ if (err)
+ return err;
+
+ return 0;
+}
+
static int alx_request_irq(struct alx_priv *alx)
{
struct pci_dev *pdev = alx->hw.pdev;
@@ -879,8 +953,9 @@ static int alx_request_irq(struct alx_priv *alx)
goto out;
/* msix request failed, realloc resources */
- alx_disable_advanced_intr(alx);
- alx_init_intr(alx, false);
+ err = alx_realloc_resources(alx);
+ if (err)
+ goto out;
}
if (alx->flags & ALX_FLAG_USING_MSI) {
@@ -912,9 +987,10 @@ static void alx_free_irq(struct alx_priv *alx)
int i, vector = 0;
if (alx->flags & ALX_FLAG_USING_MSIX) {
- /* we have only 2 vectors without multi queue support */
free_irq(alx->msix_entries[vector++].vector, alx);
- free_irq(alx->msix_entries[vector++].vector, alx->qnapi[0]);
+ for (i = 0; i < alx->num_napi; i++)
+ free_irq(alx->msix_entries[vector++].vector,
+ alx->qnapi[i]);
} else {
free_irq(pdev->irq, alx);
}
@@ -1478,10 +1554,12 @@ static int alx_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
static void alx_poll_controller(struct net_device *netdev)
{
struct alx_priv *alx = netdev_priv(netdev);
+ int i;
if (alx->flags & ALX_FLAG_USING_MSIX) {
alx_intr_msix_misc(0, alx);
- alx_intr_msix_ring(0, alx->qnapi[0]);
+ for (i = 0; i < alx->num_txq; i++)
+ alx_intr_msix_ring(0, alx->qnapi[i]);
} else if (alx->flags & ALX_FLAG_USING_MSI)
alx_intr_msi(0, alx);
else
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 6/9] alx: prepare resource allocation for multi queue support
From: Tobias Regnery @ 2016-10-21 10:49 UTC (permalink / raw)
To: jcliburn, chris.snook, netdev; +Cc: davem, Tobias Regnery
In-Reply-To: <cover.1477044917.git.tobias.regnery@gmail.com>
Allocate, initialise and free alx_tx_queue structs based on the number of
alx_napi structures. Also increase the size of the descriptor memory based
on the number of tx queues in use.
Based on the downstream driver at github.com/qca/alx
Signed-off-by: Tobias Regnery <tobias.regnery@gmail.com>
---
drivers/net/ethernet/atheros/alx/main.c | 149 +++++++++++++++++++++-----------
1 file changed, 97 insertions(+), 52 deletions(-)
diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c
index 624419968df5..19812bdf3e53 100644
--- a/drivers/net/ethernet/atheros/alx/main.c
+++ b/drivers/net/ethernet/atheros/alx/main.c
@@ -429,28 +429,45 @@ static irqreturn_t alx_intr_legacy(int irq, void *data)
return alx_intr_handle(alx, intr);
}
+static const u16 txring_header_reg[] = {ALX_TPD_PRI0_ADDR_LO,
+ ALX_TPD_PRI1_ADDR_LO,
+ ALX_TPD_PRI2_ADDR_LO,
+ ALX_TPD_PRI3_ADDR_LO};
+
static void alx_init_ring_ptrs(struct alx_priv *alx)
{
struct alx_hw *hw = &alx->hw;
u32 addr_hi = ((u64)alx->descmem.dma) >> 32;
- struct alx_napi *np = alx->qnapi[0];
+ struct alx_napi *np;
+ int i;
+
+ for (i = 0; i < alx->num_napi; i++) {
+ np = alx->qnapi[i];
+ if (np->txq) {
+ np->txq->read_idx = 0;
+ np->txq->write_idx = 0;
+ alx_write_mem32(hw,
+ txring_header_reg[np->txq->queue_idx],
+ np->txq->tpd_dma);
+ }
+
+ if (np->rxq) {
+ np->rxq->read_idx = 0;
+ np->rxq->write_idx = 0;
+ np->rxq->rrd_read_idx = 0;
+ alx_write_mem32(hw, ALX_RRD_ADDR_LO, np->rxq->rrd_dma);
+ alx_write_mem32(hw, ALX_RFD_ADDR_LO, np->rxq->rfd_dma);
+ }
+ }
+
+ alx_write_mem32(hw, ALX_TX_BASE_ADDR_HI, addr_hi);
+ alx_write_mem32(hw, ALX_TPD_RING_SZ, alx->tx_ringsz);
- np->rxq->read_idx = 0;
- np->rxq->write_idx = 0;
- np->rxq->rrd_read_idx = 0;
alx_write_mem32(hw, ALX_RX_BASE_ADDR_HI, addr_hi);
- alx_write_mem32(hw, ALX_RRD_ADDR_LO, np->rxq->rrd_dma);
alx_write_mem32(hw, ALX_RRD_RING_SZ, alx->rx_ringsz);
- alx_write_mem32(hw, ALX_RFD_ADDR_LO, np->rxq->rfd_dma);
alx_write_mem32(hw, ALX_RFD_RING_SZ, alx->rx_ringsz);
alx_write_mem32(hw, ALX_RFD_BUF_SZ, alx->rxbuf_size);
- np->txq->read_idx = 0;
- np->txq->write_idx = 0;
- alx_write_mem32(hw, ALX_TX_BASE_ADDR_HI, addr_hi);
- alx_write_mem32(hw, ALX_TPD_PRI0_ADDR_LO, np->txq->tpd_dma);
- alx_write_mem32(hw, ALX_TPD_RING_SZ, alx->tx_ringsz);
-
/* load these pointers into the chip */
alx_write_mem32(hw, ALX_SRAM9, ALX_SRAM_LOAD_PTR);
}
@@ -478,7 +495,7 @@ static void alx_free_rxring_buf(struct alx_rx_queue *rxq)
struct alx_buffer *cur_buf;
u16 i;
- if (rxq == NULL)
+ if (!rxq->bufs)
return;
for (i = 0; i < rxq->count; i++) {
@@ -502,8 +519,14 @@ static void alx_free_rxring_buf(struct alx_rx_queue *rxq)
static void alx_free_buffers(struct alx_priv *alx)
{
- alx_free_txring_buf(alx->qnapi[0]->txq);
- alx_free_rxring_buf(alx->qnapi[0]->rxq);
+ int i;
+
+ for (i = 0; i < alx->num_txq; i++)
+ if (alx->qnapi[i] && alx->qnapi[i]->txq)
+ alx_free_txring_buf(alx->qnapi[i]->txq);
+
+ if (alx->qnapi[0] && alx->qnapi[0]->rxq)
+ alx_free_rxring_buf(alx->qnapi[0]->rxq);
}
static int alx_reinit_rings(struct alx_priv *alx)
@@ -611,7 +634,7 @@ static int alx_alloc_rx_ring(struct alx_priv *alx, struct alx_rx_queue *rxq,
static int alx_alloc_rings(struct alx_priv *alx)
{
- int offset = 0;
+ int i, offset = 0;
/* physical tx/rx ring descriptors
*
@@ -619,7 +642,8 @@ static int alx_alloc_rings(struct alx_priv *alx)
* 4G boundary (hardware has a single register for high 32 bits
* of addresses only)
*/
- alx->descmem.size = sizeof(struct alx_txd) * alx->tx_ringsz +
+ alx->descmem.size = sizeof(struct alx_txd) * alx->tx_ringsz *
+ alx->num_txq +
sizeof(struct alx_rrd) * alx->rx_ringsz +
sizeof(struct alx_rfd) * alx->rx_ringsz;
alx->descmem.virt = dma_zalloc_coherent(&alx->hw.pdev->dev,
@@ -633,10 +657,12 @@ static int alx_alloc_rings(struct alx_priv *alx)
BUILD_BUG_ON(sizeof(struct alx_txd) % 8);
BUILD_BUG_ON(sizeof(struct alx_rrd) % 8);
- offset = alx_alloc_tx_ring(alx, alx->qnapi[0]->txq, offset);
- if (offset < 0) {
- netdev_err(alx->dev, "Allocation of tx buffer failed!\n");
- return -ENOMEM;
+ for (i = 0; i < alx->num_txq; i++) {
+ offset = alx_alloc_tx_ring(alx, alx->qnapi[i]->txq, offset);
+ if (offset < 0) {
+ netdev_err(alx->dev, "Allocation of tx buffer failed!\n");
+ return -ENOMEM;
+ }
}
offset = alx_alloc_rx_ring(alx, alx->qnapi[0]->rxq, offset);
@@ -652,11 +678,16 @@ static int alx_alloc_rings(struct alx_priv *alx)
static void alx_free_rings(struct alx_priv *alx)
{
+ int i;
alx_free_buffers(alx);
- kfree(alx->qnapi[0]->txq->bufs);
- kfree(alx->qnapi[0]->rxq->bufs);
+ for (i = 0; i < alx->num_txq; i++)
+ if (alx->qnapi[i] && alx->qnapi[i]->txq)
+ kfree(alx->qnapi[i]->txq->bufs);
+
+ if (alx->qnapi[0] && alx->qnapi[0]->rxq)
+ kfree(alx->qnapi[0]->rxq->bufs);
if (!alx->descmem.virt)
dma_free_coherent(&alx->hw.pdev->dev,
@@ -668,16 +699,19 @@ static void alx_free_rings(struct alx_priv *alx)
static void alx_free_napis(struct alx_priv *alx)
{
struct alx_napi *np;
+ int i;
- np = alx->qnapi[0];
- if (!np)
- return;
-
- netif_napi_del(&np->napi);
- kfree(np->txq);
- kfree(np->rxq);
- kfree(np);
- alx->qnapi[0] = NULL;
+ for (i = 0; i < alx->num_napi; i++) {
+ np = alx->qnapi[i];
+ if (!np)
+ continue;
+
+ netif_napi_del(&np->napi);
+ kfree(np->txq);
+ kfree(np->rxq);
+ kfree(np);
+ alx->qnapi[i] = NULL;
+ }
}
static const u32 tx_vect_mask[] = {ALX_ISR_TX_Q0, ALX_ISR_TX_Q1,
@@ -692,31 +726,36 @@ static int alx_alloc_napis(struct alx_priv *alx)
struct alx_napi *np;
struct alx_rx_queue *rxq;
struct alx_tx_queue *txq;
+ int i;
alx->int_mask &= ~ALX_ISR_ALL_QUEUES;
/* allocate alx_napi structures */
- np = kzalloc(sizeof(struct alx_napi), GFP_KERNEL);
- if (!np)
- goto err_out;
+ for (i = 0; i < alx->num_napi; i++) {
+ np = kzalloc(sizeof(struct alx_napi), GFP_KERNEL);
+ if (!np)
+ goto err_out;
- np->alx = alx;
- netif_napi_add(alx->dev, &np->napi, alx_poll, 64);
- alx->qnapi[0] = np;
+ np->alx = alx;
+ netif_napi_add(alx->dev, &np->napi, alx_poll, 64);
+ alx->qnapi[i] = np;
+ }
/* allocate tx queues */
- np = alx->qnapi[0];
- txq = kzalloc(sizeof(*txq), GFP_KERNEL);
- if (!txq)
- goto err_out;
-
- np->txq = txq;
- txq->queue_idx = 0;
- txq->count = alx->tx_ringsz;
- txq->netdev = alx->dev;
- txq->dev = &alx->hw.pdev->dev;
- np->vec_mask |= tx_vect_mask[0];
- alx->int_mask |= tx_vect_mask[0];
+ for (i = 0; i < alx->num_txq; i++) {
+ np = alx->qnapi[i];
+ txq = kzalloc(sizeof(*txq), GFP_KERNEL);
+ if (!txq)
+ goto err_out;
+
+ np->txq = txq;
+ txq->queue_idx = i;
+ txq->count = alx->tx_ringsz;
+ txq->netdev = alx->dev;
+ txq->dev = &alx->hw.pdev->dev;
+ np->vec_mask |= tx_vect_mask[i];
+ alx->int_mask |= tx_vect_mask[i];
+ }
/* allocate rx queues */
np = alx->qnapi[0];
@@ -1075,11 +1114,14 @@ static netdev_features_t alx_fix_features(struct net_device *netdev,
static void alx_netif_stop(struct alx_priv *alx)
{
+ int i;
+
netif_trans_update(alx->dev);
if (netif_carrier_ok(alx->dev)) {
netif_carrier_off(alx->dev);
netif_tx_disable(alx->dev);
- napi_disable(&alx->qnapi[0]->napi);
+ for (i = 0; i < alx->num_napi; i++)
+ napi_disable(&alx->qnapi[i]->napi);
}
}
@@ -1148,8 +1190,11 @@ static int alx_change_mtu(struct net_device *netdev, int mtu)
static void alx_netif_start(struct alx_priv *alx)
{
+ int i;
+
netif_tx_wake_all_queues(alx->dev);
- napi_enable(&alx->qnapi[0]->napi);
+ for (i = 0; i < alx->num_napi; i++)
+ napi_enable(&alx->qnapi[i]->napi);
netif_carrier_on(alx->dev);
}
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 7/9] alx: prepare tx path for multi queue support
From: Tobias Regnery @ 2016-10-21 10:49 UTC (permalink / raw)
To: jcliburn, chris.snook, netdev; +Cc: davem, Tobias Regnery
In-Reply-To: <cover.1477044917.git.tobias.regnery@gmail.com>
This patch prepares the tx path to send data on multiple tx queues. It
introduces per queue register adresses and uses them in the alx_tx_queue
structs.
There are new helper functions for the queue mapping in the tx path.
Based on the downstream driver at github.com/qca/alx
Signed-off-by: Tobias Regnery <tobias.regnery@gmail.com>
---
drivers/net/ethernet/atheros/alx/main.c | 58 +++++++++++++++++++++++++--------
1 file changed, 45 insertions(+), 13 deletions(-)
diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c
index 19812bdf3e53..39f6247cbbd0 100644
--- a/drivers/net/ethernet/atheros/alx/main.c
+++ b/drivers/net/ethernet/atheros/alx/main.c
@@ -143,6 +143,22 @@ static int alx_refill_rx_ring(struct alx_priv *alx, gfp_t gfp)
return count;
}
+static struct alx_tx_queue *alx_tx_queue_mapping(struct alx_priv *alx,
+ struct sk_buff *skb)
+{
+ unsigned int r_idx = skb->queue_mapping;
+
+ if (r_idx >= alx->num_txq)
+ r_idx = r_idx % alx->num_txq;
+
+ return alx->qnapi[r_idx]->txq;
+}
+
+static struct netdev_queue *alx_get_tx_queue(const struct alx_tx_queue *txq)
+{
+ return netdev_get_tx_queue(txq->netdev, txq->queue_idx);
+}
+
static inline int alx_tpd_avail(struct alx_tx_queue *txq)
{
if (txq->write_idx >= txq->read_idx)
@@ -153,14 +169,16 @@ static inline int alx_tpd_avail(struct alx_tx_queue *txq)
static bool alx_clean_tx_irq(struct alx_tx_queue *txq)
{
struct alx_priv *alx;
+ struct netdev_queue *tx_queue;
u16 hw_read_idx, sw_read_idx;
unsigned int total_bytes = 0, total_packets = 0;
int budget = ALX_DEFAULT_TX_WORK;
alx = netdev_priv(txq->netdev);
+ tx_queue = alx_get_tx_queue(txq);
sw_read_idx = txq->read_idx;
- hw_read_idx = alx_read_mem16(&alx->hw, ALX_TPD_PRI0_CIDX);
+ hw_read_idx = alx_read_mem16(&alx->hw, txq->c_reg);
if (sw_read_idx != hw_read_idx) {
while (sw_read_idx != hw_read_idx && budget > 0) {
@@ -180,12 +198,12 @@ static bool alx_clean_tx_irq(struct alx_tx_queue *txq)
}
txq->read_idx = sw_read_idx;
- netdev_completed_queue(txq->netdev, total_packets, total_bytes);
+ netdev_tx_completed_queue(tx_queue, total_packets, total_bytes);
}
- if (netif_queue_stopped(txq->netdev) && netif_carrier_ok(txq->netdev) &&
+ if (netif_tx_queue_stopped(tx_queue) && netif_carrier_ok(alx->dev) &&
alx_tpd_avail(txq) > txq->count / 4)
- netif_wake_queue(txq->netdev);
+ netif_tx_wake_queue(tx_queue);
return sw_read_idx == hw_read_idx;
}
@@ -487,7 +505,7 @@ static void alx_free_txring_buf(struct alx_tx_queue *txq)
txq->write_idx = 0;
txq->read_idx = 0;
- netdev_reset_queue(txq->netdev);
+ netdev_tx_reset_queue(alx_get_tx_queue(txq));
}
static void alx_free_rxring_buf(struct alx_rx_queue *rxq)
@@ -714,6 +732,10 @@ static void alx_free_napis(struct alx_priv *alx)
}
}
+static const u16 tx_pidx_reg[] = {ALX_TPD_PRI0_PIDX, ALX_TPD_PRI1_PIDX,
+ ALX_TPD_PRI2_PIDX, ALX_TPD_PRI3_PIDX};
+static const u16 tx_cidx_reg[] = {ALX_TPD_PRI0_CIDX, ALX_TPD_PRI1_CIDX,
+ ALX_TPD_PRI2_CIDX, ALX_TPD_PRI3_CIDX};
static const u32 tx_vect_mask[] = {ALX_ISR_TX_Q0, ALX_ISR_TX_Q1,
ALX_ISR_TX_Q2, ALX_ISR_TX_Q3};
static const u32 rx_vect_mask[] = {ALX_ISR_RX_Q0, ALX_ISR_RX_Q1,
@@ -749,6 +771,8 @@ static int alx_alloc_napis(struct alx_priv *alx)
goto err_out;
np->txq = txq;
+ txq->p_reg = tx_pidx_reg[i];
+ txq->c_reg = tx_cidx_reg[i];
txq->queue_idx = i;
txq->count = alx->tx_ringsz;
txq->netdev = alx->dev;
@@ -1501,16 +1525,17 @@ static int alx_map_tx_skb(struct alx_tx_queue *txq, struct sk_buff *skb)
return -ENOMEM;
}
-static netdev_tx_t alx_start_xmit(struct sk_buff *skb,
- struct net_device *netdev)
+static netdev_tx_t alx_start_xmit_ring(struct sk_buff *skb,
+ struct alx_tx_queue *txq)
{
- struct alx_priv *alx = netdev_priv(netdev);
- struct alx_tx_queue *txq = alx->qnapi[0]->txq;
+ struct alx_priv *alx;
struct alx_txd *first;
int tso;
+ alx = netdev_priv(txq->netdev);
+
if (alx_tpd_avail(txq) < alx_tpd_req(skb)) {
- netif_stop_queue(txq->netdev);
+ netif_tx_stop_queue(alx_get_tx_queue(txq));
goto drop;
}
@@ -1526,14 +1551,14 @@ static netdev_tx_t alx_start_xmit(struct sk_buff *skb,
if (alx_map_tx_skb(txq, skb) < 0)
goto drop;
- netdev_sent_queue(txq->netdev, skb->len);
+ netdev_tx_sent_queue(alx_get_tx_queue(txq), skb->len);
/* flush updates before updating hardware */
wmb();
- alx_write_mem16(&alx->hw, ALX_TPD_PRI0_PIDX, txq->write_idx);
+ alx_write_mem16(&alx->hw, txq->p_reg, txq->write_idx);
if (alx_tpd_avail(txq) < txq->count / 8)
- netif_stop_queue(txq->netdev);
+ netif_tx_stop_queue(alx_get_tx_queue(txq));
return NETDEV_TX_OK;
@@ -1542,6 +1567,13 @@ static netdev_tx_t alx_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
}
+static netdev_tx_t alx_start_xmit(struct sk_buff *skb,
+ struct net_device *netdev)
+{
+ struct alx_priv *alx = netdev_priv(netdev);
+ return alx_start_xmit_ring(skb, alx_tx_queue_mapping(alx, skb));
+}
+
static void alx_tx_timeout(struct net_device *dev)
{
struct alx_priv *alx = netdev_priv(dev);
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 8/9] alx: enable msi-x interrupts by default
From: Tobias Regnery @ 2016-10-21 10:49 UTC (permalink / raw)
To: jcliburn, chris.snook, netdev; +Cc: davem, Tobias Regnery
In-Reply-To: <cover.1477044917.git.tobias.regnery@gmail.com>
Remove the module parameter to enable msi-x support and enable msi-x
interrupts unconditionally by default. This is a preparatory step to enable
multi queue support by default, because this is only working with msi-x
interrupts.
Signed-off-by: Tobias Regnery <tobias.regnery@gmail.com>
---
drivers/net/ethernet/atheros/alx/main.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c
index 39f6247cbbd0..3b832090ad2e 100644
--- a/drivers/net/ethernet/atheros/alx/main.c
+++ b/drivers/net/ethernet/atheros/alx/main.c
@@ -51,10 +51,6 @@
const char alx_drv_name[] = "alx";
-static bool msix = false;
-module_param(msix, bool, 0);
-MODULE_PARM_DESC(msix, "Enable msi-x interrupt support");
-
static void alx_free_txbuf(struct alx_tx_queue *txq, int entry)
{
struct alx_buffer *txb = &txq->bufs[entry];
@@ -1226,7 +1222,7 @@ static int __alx_open(struct alx_priv *alx, bool resume)
{
int err;
- alx_init_intr(alx, msix);
+ alx_init_intr(alx, true);
if (!resume)
netif_carrier_off(alx->dev);
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 9/9] alx: enable multiple tx queues
From: Tobias Regnery @ 2016-10-21 10:49 UTC (permalink / raw)
To: jcliburn, chris.snook, netdev; +Cc: davem, Tobias Regnery
In-Reply-To: <cover.1477044917.git.tobias.regnery@gmail.com>
Enable multiple tx queues by default based on the number of online cpus. The
hardware supports up to four tx queues.
Based on the downstream driver at github.com/qca/alx
Signed-off-by: Tobias Regnery <tobias.regnery@gmail.com>
---
drivers/net/ethernet/atheros/alx/main.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c
index 3b832090ad2e..df5bfa4480d7 100644
--- a/drivers/net/ethernet/atheros/alx/main.c
+++ b/drivers/net/ethernet/atheros/alx/main.c
@@ -834,7 +834,7 @@ static bool alx_enable_msix(struct alx_priv *alx)
{
int i, err, num_vec, num_txq, num_rxq;
- num_txq = 1;
+ num_txq = min_t(int, num_online_cpus(), ALX_MAX_TX_QUEUES);
num_rxq = 1;
num_vec = max_t(int, num_txq, num_rxq) + 1;
@@ -1241,6 +1241,9 @@ static int __alx_open(struct alx_priv *alx, bool resume)
if (err)
goto out_free_rings;
+ netif_set_real_num_tx_queues(alx->dev, alx->num_txq);
+ netif_set_real_num_rx_queues(alx->dev, alx->num_rxq);
+
/* clear old interrupts */
alx_write_mem32(&alx->hw, ALX_ISR, ~(u32)ALX_ISR_DIS);
@@ -1749,7 +1752,8 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out_pci_release;
}
- netdev = alloc_etherdev(sizeof(*alx));
+ netdev = alloc_etherdev_mqs(sizeof(*alx),
+ ALX_MAX_TX_QUEUES, 1);
if (!netdev) {
err = -ENOMEM;
goto out_pci_release;
--
2.7.4
^ permalink raw reply related
* Re: commit-3ac72b7b63d5 breaks networking on iMX28
From: Fabio Estevam @ 2016-10-21 10:55 UTC (permalink / raw)
To: Henri Roosen; +Cc: Eric Nelson, Fugang Duan, netdev@vger.kernel.org
In-Reply-To: <bc6aa851-3f52-2274-47dc-4933662648a1@ginzinger.com>
Hi Henri,
2016-10-21 7:19 GMT-02:00 Henri Roosen <henri.roosen@ginzinger.com>:
> Hi,
>
> Unfortunately commit-3ac72b7b63d5 "net: fec: align IP header in
> hardware" breaks networking on an iMX28 system.
>
> The commit seems valid for iMX6, where it is tested okay and solves the
> unaligned accesses.
>
> On iMX28 I still see unaligned accesses and networking is broken. Can
> anyone confirm this?
Does this fix the problem?
diff --git a/drivers/net/ethernet/freescale/fec_main.c
b/drivers/net/ethernet/freescale/fec_main.c
index 4ce8179..d1cefe1 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1430,14 +1430,15 @@ fec_enet_rx_queue(struct net_device *ndev, int
budget, u16 queue_id)
skb_put(skb, pkt_len - 4);
data = skb->data;
+ if (!is_copybreak && need_swap)
+ swap_buffer(data, pkt_len);
+
+
#if !defined(CONFIG_M5272)
if (fep->quirks & FEC_QUIRK_HAS_RACC)
data = skb_pull_inline(skb, 2);
#endif
- if (!is_copybreak && need_swap)
- swap_buffer(data, pkt_len);
-
/* Extract the enhanced buffer descriptor */
ebdp = NULL;
if (fep->bufdesc_ex)
^ permalink raw reply related
* [PATCH v2 net-next 1/1] driver: tun: Forbid to set IFF_TUN and IFF_TAP at the same time
From: fgao @ 2016-10-21 11:02 UTC (permalink / raw)
To: davem, jasowang, edumazet, pabeni, netdev; +Cc: gfree.wind, Gao Feng
From: Gao Feng <fgao@ikuai8.com>
Current tun driver permits the ifr_flags is set with IFF_TUN and
IFF_TAP at the same time. But actually there is only IFF_TUN flag
works. And it does not make sense these two flags are set, so add
this check.
Signed-off-by: Gao Feng <fgao@ikuai8.com>
---
v2: Remove useless {}
v1: Initial patch
drivers/net/tun.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 8093e39..faaa189 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1752,6 +1752,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
if (err < 0)
return err;
+ if ((ifr->ifr_flags & (IFF_TUN | IFF_TAP)) == (IFF_TUN | IFF_TAP))
+ return -EINVAL;
+
/* Set dev type */
if (ifr->ifr_flags & IFF_TUN) {
/* TUN device */
--
1.9.1
^ permalink raw reply related
* Re: [PATCH net-next v2 2/2] reuseport, bpf: add test case for bpf_get_numa_node_id
From: Jiri Pirko @ 2016-10-21 11:08 UTC (permalink / raw)
To: Daniel Borkmann; +Cc: davem, alexei.starovoitov, edumazet, netdev
In-Reply-To: <a3bb5be5fdab7b8415adcad984442181196609a7.1477043973.git.daniel@iogearbox.net>
Fri, Oct 21, 2016 at 12:46:34PM CEST, daniel@iogearbox.net wrote:
>The test case is very similar to reuseport_bpf_cpu, only that here
>we select socket members based on current numa node id.
>
> # numactl -H
> available: 2 nodes (0-1)
> node 0 cpus: 0 1 2 3 4 5 12 13 14 15 16 17
> node 0 size: 128867 MB
> node 0 free: 120080 MB
> node 1 cpus: 6 7 8 9 10 11 18 19 20 21 22 23
> node 1 size: 96765 MB
> node 1 free: 87504 MB
> node distances:
> node 0 1
> 0: 10 20
> 1: 20 10
>
> # ./reuseport_bpf_numa
> ---- IPv4 UDP ----
> send node 0, receive socket 0
> send node 1, receive socket 1
> send node 1, receive socket 1
> send node 0, receive socket 0
> ---- IPv6 UDP ----
> send node 0, receive socket 0
> send node 1, receive socket 1
> send node 1, receive socket 1
> send node 0, receive socket 0
> ---- IPv4 TCP ----
> send node 0, receive socket 0
> send node 1, receive socket 1
> send node 1, receive socket 1
> send node 0, receive socket 0
> ---- IPv6 TCP ----
> send node 0, receive socket 0
> send node 1, receive socket 1
> send node 1, receive socket 1
> send node 0, receive socket 0
> SUCCESS
>
>Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
>Acked-by: Alexei Starovoitov <ast@kernel.org>
>---
> tools/testing/selftests/net/.gitignore | 1 +
> tools/testing/selftests/net/Makefile | 11 +-
> tools/testing/selftests/net/reuseport_bpf_numa.c | 255 +++++++++++++++++++++++
> 3 files changed, 263 insertions(+), 4 deletions(-)
> create mode 100644 tools/testing/selftests/net/reuseport_bpf_numa.c
>
>diff --git a/tools/testing/selftests/net/.gitignore b/tools/testing/selftests/net/.gitignore
>index 0840684..afe109e 100644
>--- a/tools/testing/selftests/net/.gitignore
>+++ b/tools/testing/selftests/net/.gitignore
>@@ -3,4 +3,5 @@ psock_fanout
> psock_tpacket
> reuseport_bpf
> reuseport_bpf_cpu
>+reuseport_bpf_numa
> reuseport_dualstack
>diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
>index 0e53407..e24e4c8 100644
>--- a/tools/testing/selftests/net/Makefile
>+++ b/tools/testing/selftests/net/Makefile
>@@ -1,14 +1,17 @@
> # Makefile for net selftests
>
>-CFLAGS = -Wall -O2 -g
>-
>+CFLAGS = -Wall -Wl,--no-as-needed -O2 -g
^ why the extra space?
> CFLAGS += -I../../../../usr/include/
>
>-NET_PROGS = socket psock_fanout psock_tpacket reuseport_bpf reuseport_bpf_cpu reuseport_dualstack
>+NET_PROGS = socket
^ yet again. Sorry for nitpicking :)
>+NET_PROGS += psock_fanout psock_tpacket
>+NET_PROGS += reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa
>+NET_PROGS += reuseport_dualstack
>
> all: $(NET_PROGS)
>+reuseport_bpf_numa: LDFLAGS += -lnuma
> %: %.c
>- $(CC) $(CFLAGS) -o $@ $^
>+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
>
> TEST_PROGS := run_netsocktests run_afpackettests test_bpf.sh
> TEST_FILES := $(NET_PROGS)
>diff --git a/tools/testing/selftests/net/reuseport_bpf_numa.c b/tools/testing/selftests/net/reuseport_bpf_numa.c
>new file mode 100644
>index 0000000..6f20bc9
>--- /dev/null
>+++ b/tools/testing/selftests/net/reuseport_bpf_numa.c
>@@ -0,0 +1,255 @@
>+/*
>+ * Test functionality of BPF filters with SO_REUSEPORT. Same test as
>+ * in reuseport_bpf_cpu, only as one socket per NUMA node.
>+ */
>+
>+#define _GNU_SOURCE
>+
>+#include <arpa/inet.h>
>+#include <errno.h>
>+#include <error.h>
>+#include <linux/filter.h>
>+#include <linux/bpf.h>
>+#include <linux/in.h>
>+#include <linux/unistd.h>
>+#include <sched.h>
>+#include <stdio.h>
>+#include <stdlib.h>
>+#include <string.h>
>+#include <sys/epoll.h>
>+#include <sys/types.h>
>+#include <sys/socket.h>
>+#include <unistd.h>
>+#include <numa.h>
>+
>+static const int PORT = 8888;
>+
>+static void build_rcv_group(int *rcv_fd, size_t len, int family, int proto)
>+{
>+ struct sockaddr_storage addr;
>+ struct sockaddr_in *addr4;
>+ struct sockaddr_in6 *addr6;
>+ size_t i;
>+ int opt;
>+
>+ switch (family) {
>+ case AF_INET:
>+ addr4 = (struct sockaddr_in *)&addr;
>+ addr4->sin_family = AF_INET;
>+ addr4->sin_addr.s_addr = htonl(INADDR_ANY);
>+ addr4->sin_port = htons(PORT);
>+ break;
>+ case AF_INET6:
>+ addr6 = (struct sockaddr_in6 *)&addr;
>+ addr6->sin6_family = AF_INET6;
>+ addr6->sin6_addr = in6addr_any;
>+ addr6->sin6_port = htons(PORT);
>+ break;
>+ default:
>+ error(1, 0, "Unsupported family %d", family);
>+ }
>+
>+ for (i = 0; i < len; ++i) {
>+ rcv_fd[i] = socket(family, proto, 0);
>+ if (rcv_fd[i] < 0)
>+ error(1, errno, "failed to create receive socket");
>+
>+ opt = 1;
>+ if (setsockopt(rcv_fd[i], SOL_SOCKET, SO_REUSEPORT, &opt,
>+ sizeof(opt)))
>+ error(1, errno, "failed to set SO_REUSEPORT");
>+
>+ if (bind(rcv_fd[i], (struct sockaddr *)&addr, sizeof(addr)))
>+ error(1, errno, "failed to bind receive socket");
>+
>+ if (proto == SOCK_STREAM && listen(rcv_fd[i], len * 10))
>+ error(1, errno, "failed to listen on receive port");
>+ }
>+}
>+
>+static void attach_bpf(int fd)
>+{
>+ static char bpf_log_buf[65536];
>+ static const char bpf_license[] = "";
>+
>+ int bpf_fd;
>+ const struct bpf_insn prog[] = {
>+ /* R0 = bpf_get_numa_node_id() */
>+ { BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_numa_node_id },
>+ /* return R0 */
>+ { BPF_JMP | BPF_EXIT, 0, 0, 0, 0 }
>+ };
>+ union bpf_attr attr;
>+
>+ memset(&attr, 0, sizeof(attr));
>+ attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
>+ attr.insn_cnt = sizeof(prog) / sizeof(prog[0]);
>+ attr.insns = (unsigned long) &prog;
>+ attr.license = (unsigned long) &bpf_license;
>+ attr.log_buf = (unsigned long) &bpf_log_buf;
>+ attr.log_size = sizeof(bpf_log_buf);
>+ attr.log_level = 1;
>+
>+ bpf_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
>+ if (bpf_fd < 0)
>+ error(1, errno, "ebpf error. log:\n%s\n", bpf_log_buf);
>+
>+ if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_REUSEPORT_EBPF, &bpf_fd,
>+ sizeof(bpf_fd)))
>+ error(1, errno, "failed to set SO_ATTACH_REUSEPORT_EBPF");
>+
>+ close(bpf_fd);
>+}
>+
>+static void send_from_node(int node_id, int family, int proto)
>+{
>+ struct sockaddr_storage saddr, daddr;
>+ struct sockaddr_in *saddr4, *daddr4;
>+ struct sockaddr_in6 *saddr6, *daddr6;
>+ int fd;
>+
>+ switch (family) {
>+ case AF_INET:
>+ saddr4 = (struct sockaddr_in *)&saddr;
>+ saddr4->sin_family = AF_INET;
>+ saddr4->sin_addr.s_addr = htonl(INADDR_ANY);
>+ saddr4->sin_port = 0;
>+
>+ daddr4 = (struct sockaddr_in *)&daddr;
>+ daddr4->sin_family = AF_INET;
>+ daddr4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
>+ daddr4->sin_port = htons(PORT);
>+ break;
>+ case AF_INET6:
>+ saddr6 = (struct sockaddr_in6 *)&saddr;
>+ saddr6->sin6_family = AF_INET6;
>+ saddr6->sin6_addr = in6addr_any;
>+ saddr6->sin6_port = 0;
>+
>+ daddr6 = (struct sockaddr_in6 *)&daddr;
>+ daddr6->sin6_family = AF_INET6;
>+ daddr6->sin6_addr = in6addr_loopback;
>+ daddr6->sin6_port = htons(PORT);
>+ break;
>+ default:
>+ error(1, 0, "Unsupported family %d", family);
>+ }
>+
>+ if (numa_run_on_node(node_id) < 0)
>+ error(1, errno, "failed to pin to node");
>+
>+ fd = socket(family, proto, 0);
>+ if (fd < 0)
>+ error(1, errno, "failed to create send socket");
>+
>+ if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)))
>+ error(1, errno, "failed to bind send socket");
>+
>+ if (connect(fd, (struct sockaddr *)&daddr, sizeof(daddr)))
>+ error(1, errno, "failed to connect send socket");
>+
>+ if (send(fd, "a", 1, 0) < 0)
>+ error(1, errno, "failed to send message");
>+
>+ close(fd);
>+}
>+
>+static
>+void receive_on_node(int *rcv_fd, int len, int epfd, int node_id, int proto)
>+{
>+ struct epoll_event ev;
>+ int i, fd;
>+ char buf[8];
>+
>+ i = epoll_wait(epfd, &ev, 1, -1);
>+ if (i < 0)
>+ error(1, errno, "epoll_wait failed");
>+
>+ if (proto == SOCK_STREAM) {
>+ fd = accept(ev.data.fd, NULL, NULL);
>+ if (fd < 0)
>+ error(1, errno, "failed to accept");
>+ i = recv(fd, buf, sizeof(buf), 0);
>+ close(fd);
>+ } else {
>+ i = recv(ev.data.fd, buf, sizeof(buf), 0);
>+ }
>+
>+ if (i < 0)
>+ error(1, errno, "failed to recv");
>+
>+ for (i = 0; i < len; ++i)
>+ if (ev.data.fd == rcv_fd[i])
>+ break;
>+ if (i == len)
>+ error(1, 0, "failed to find socket");
>+ fprintf(stderr, "send node %d, receive socket %d\n", node_id, i);
>+ if (node_id != i)
>+ error(1, 0, "node id/receive socket mismatch");
>+}
>+
>+static void test(int *rcv_fd, int len, int family, int proto)
>+{
>+ struct epoll_event ev;
>+ int epfd, node;
>+
>+ build_rcv_group(rcv_fd, len, family, proto);
>+ attach_bpf(rcv_fd[0]);
>+
>+ epfd = epoll_create(1);
>+ if (epfd < 0)
>+ error(1, errno, "failed to create epoll");
>+ for (node = 0; node < len; ++node) {
>+ ev.events = EPOLLIN;
>+ ev.data.fd = rcv_fd[node];
>+ if (epoll_ctl(epfd, EPOLL_CTL_ADD, rcv_fd[node], &ev))
>+ error(1, errno, "failed to register sock epoll");
>+ }
>+
>+ /* Forward iterate */
>+ for (node = 0; node < len; ++node) {
>+ send_from_node(node, family, proto);
>+ receive_on_node(rcv_fd, len, epfd, node, proto);
>+ }
>+
>+ /* Reverse iterate */
>+ for (node = len - 1; node >= 0; --node) {
>+ send_from_node(node, family, proto);
>+ receive_on_node(rcv_fd, len, epfd, node, proto);
>+ }
>+
>+ close(epfd);
>+ for (node = 0; node < len; ++node)
>+ close(rcv_fd[node]);
>+}
>+
>+int main(void)
>+{
>+ int *rcv_fd, nodes;
>+
>+ if (numa_available() < 0)
>+ error(1, errno, "no numa api support");
>+
>+ nodes = numa_max_node() + 1;
>+
>+ rcv_fd = calloc(nodes, sizeof(int));
>+ if (!rcv_fd)
>+ error(1, 0, "failed to allocate array");
>+
>+ fprintf(stderr, "---- IPv4 UDP ----\n");
>+ test(rcv_fd, nodes, AF_INET, SOCK_DGRAM);
>+
>+ fprintf(stderr, "---- IPv6 UDP ----\n");
>+ test(rcv_fd, nodes, AF_INET6, SOCK_DGRAM);
>+
>+ fprintf(stderr, "---- IPv4 TCP ----\n");
>+ test(rcv_fd, nodes, AF_INET, SOCK_STREAM);
>+
>+ fprintf(stderr, "---- IPv6 TCP ----\n");
>+ test(rcv_fd, nodes, AF_INET6, SOCK_STREAM);
>+
>+ free(rcv_fd);
>+
>+ fprintf(stderr, "SUCCESS\n");
>+ return 0;
>+}
>--
>1.9.3
>
^ permalink raw reply
* Re: commit-3ac72b7b63d5 breaks networking on iMX28
From: Henri Roosen @ 2016-10-21 11:09 UTC (permalink / raw)
To: Fabio Estevam; +Cc: Eric Nelson, Fugang Duan, netdev@vger.kernel.org
In-Reply-To: <CAOMZO5ADSSUkTwi3WDHHGX-i-Jm+YbrVzES0BDtGsR1kFTxO+Q@mail.gmail.com>
Hi Fabio,
On 10/21/2016 12:55 PM, Fabio Estevam wrote:
> Hi Henri,
>
> 2016-10-21 7:19 GMT-02:00 Henri Roosen <henri.roosen@ginzinger.com>:
>> Hi,
>>
>> Unfortunately commit-3ac72b7b63d5 "net: fec: align IP header in
>> hardware" breaks networking on an iMX28 system.
>>
>> The commit seems valid for iMX6, where it is tested okay and solves the
>> unaligned accesses.
>>
>> On iMX28 I still see unaligned accesses and networking is broken. Can
>> anyone confirm this?
>
> Does this fix the problem?
Yes, this fixes the problem.
Note: only tested on iMX28.
Thanks,
Henri
>
> diff --git a/drivers/net/ethernet/freescale/fec_main.c
> b/drivers/net/ethernet/freescale/fec_main.c
> index 4ce8179..d1cefe1 100644
> --- a/drivers/net/ethernet/freescale/fec_main.c
> +++ b/drivers/net/ethernet/freescale/fec_main.c
> @@ -1430,14 +1430,15 @@ fec_enet_rx_queue(struct net_device *ndev, int
> budget, u16 queue_id)
> skb_put(skb, pkt_len - 4);
> data = skb->data;
>
> + if (!is_copybreak && need_swap)
> + swap_buffer(data, pkt_len);
> +
> +
> #if !defined(CONFIG_M5272)
> if (fep->quirks & FEC_QUIRK_HAS_RACC)
> data = skb_pull_inline(skb, 2);
> #endif
>
> - if (!is_copybreak && need_swap)
> - swap_buffer(data, pkt_len);
> -
> /* Extract the enhanced buffer descriptor */
> ebdp = NULL;
> if (fep->bufdesc_ex)
>
________________________________
Ginzinger electronic systems GmbH
Gewerbegebiet Pirath 16
4952 Weng im Innkreis
www.ginzinger.com
Firmenbuchnummer: FN 364958d
Firmenbuchgericht: Ried im Innkreis
UID-Nr.: ATU66521089
________________________________
Kommende Events:
08.-11. November 2016: Besuchen Sie uns auf der electronica in München -> Halle B1 Stand 538
16. November 2016: Nachmittagsseminar mit unserem Partner Irlbacher zum Thema „Glas als innovatives Material für moderne HMI’s“
17. November 2016: Juristisches Seminar in Linz: Einsatz von Open Source-Software in der Industrie
06. Dezember 2016: Nachmittagsseminar mit unserem Partner sequality software engineering zum Thema Usability
>> Weitere Informationen zu diesen Veranstaltungen und Neuigkeiten aus der Elektronikbranche finden Sie auf www.ginzinger.com/techtalk
^ permalink raw reply
* Re: [PATCH net-next] hv_netvsc: fix a race between netvsc_send() and netvsc_init_buf()
From: Vitaly Kuznetsov @ 2016-10-21 11:15 UTC (permalink / raw)
To: David Miller; +Cc: sthemmin, netdev, haiyangz, linux-kernel, devel
In-Reply-To: <20161020.140300.122827393647670926.davem@davemloft.net>
David Miller <davem@davemloft.net> writes:
> From: Vitaly Kuznetsov <vkuznets@redhat.com>
> Date: Thu, 20 Oct 2016 10:51:04 +0200
>
>> Stephen Hemminger <sthemmin@microsoft.com> writes:
>>
>>> Do we need ACCESS_ONCE() here to avoid check/use issues?
>>>
>>
>> I think we don't: this is the only place in the function where we read
>> the variable so we'll get normal read. We're not trying to syncronize
>> with netvsc_init_buf() as that would require locking, if we read stale
>> NULL value after it was already updated on a different CPU we're fine,
>> we'll just return -EAGAIN.
>
> The concern is if we race with netvsc_destroy_buf() and this pointer
> becomes NULL after the test you are adding.
Thanks, this is interesting.
We may reach to netvsc_destroy_buf() by 3 pathes:
1) cleanup path in netvsc_init_buf(). It is never called with
send_section_map being not NULL so it seems we're safe.
2) from netvsc_remove() when the device is being removed. As far as I
understand we can't be on the transmit path after we call
unregister_netdev() so we're safe.
3) from netvsc_change_mtu() and netvsc_set_channels(). These pathes are
specific to netvsc driver as basically we need to remove the device and
add it back to change mtu/number of channels. The underligning 'struct
net_device' stays but the rest is being removed and added back. On both
pathes we first call netvsc_close() which does netif_tx_disable() and as
far as I understand (I may be wrong) this guarantees that we won't be in
netvsc_send().
So *I think* that we can't ever free send_section_map while in
netvsc_send() and we can't even get to netvsc_send() after it is freed
but I may have missed something.
--
Vitaly
^ permalink raw reply
* Re: Need help with mdiobus_register and phy
From: Timur Tabi @ 2016-10-21 11:19 UTC (permalink / raw)
To: Zefir Kurtisi, Andrew Lunn; +Cc: Florian Fainelli, netdev
In-Reply-To: <e4b86886-737a-0a1c-c95a-34b6b6373755@neratec.com>
Zefir Kurtisi wrote:
>> >Now the interesting (and new for me) part is: if I remove the at803x driver from
>> >the system and use the generic phy instead, the problem does not happen (or at
>> >least not while running for one full day). [...]
>> >
> Update: the failure also happened with genphy after running for another day.
I haven't had a chance to try to reproduce this failure, but to me this
sounds like you have a problem with gianfar or your board, and not the
at803x driver.
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the
Code Aurora Forum, hosted by The Linux Foundation.
^ permalink raw reply
* [PATCH net] macsec: Fix header length if SCI is added if explicitily disabled
From: Tobias Brunner @ 2016-10-21 11:11 UTC (permalink / raw)
To: David S. Miller, Sabrina Dubroca; +Cc: netdev
Even if sending SCIs is explicitly disabled, the code that creates the
Security Tag might still decide to add it (e.g. if multiple RX SCs are
defined on the MACsec interface).
But because the header length so far only depended on the configuration
option the SCI might not actually have ended up in the packet, while the
SC flag in the TCI field of the Security Tag was still set, resulting
in invalid MACsec frames.
Signed-off-by: Tobias Brunner <tobias@strongswan.org>
---
drivers/net/macsec.c | 22 ++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index 3ea47f28e143..246679f24a44 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -397,6 +397,14 @@ static struct macsec_cb *macsec_skb_cb(struct sk_buff *skb)
#define DEFAULT_ENCRYPT false
#define DEFAULT_ENCODING_SA 0
+static bool send_sci(const struct macsec_secy *secy)
+{
+ const struct macsec_tx_sc *tx_sc = &secy->tx_sc;
+
+ return tx_sc->send_sci ||
+ (secy->n_rx_sc > 1 && !tx_sc->end_station && !tx_sc->scb);
+}
+
static sci_t make_sci(u8 *addr, __be16 port)
{
sci_t sci;
@@ -440,12 +448,12 @@ static void macsec_fill_sectag(struct macsec_eth_header *h,
const struct macsec_secy *secy, u32 pn)
{
const struct macsec_tx_sc *tx_sc = &secy->tx_sc;
+ bool sci_present = send_sci(secy);
- memset(&h->tci_an, 0, macsec_sectag_len(tx_sc->send_sci));
+ memset(&h->tci_an, 0, macsec_sectag_len(sci_present));
h->eth.h_proto = htons(ETH_P_MACSEC);
- if (tx_sc->send_sci ||
- (secy->n_rx_sc > 1 && !tx_sc->end_station && !tx_sc->scb)) {
+ if (sci_present) {
h->tci_an |= MACSEC_TCI_SC;
memcpy(&h->secure_channel_id, &secy->sci,
sizeof(h->secure_channel_id));
@@ -650,6 +658,7 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb,
struct macsec_tx_sc *tx_sc;
struct macsec_tx_sa *tx_sa;
struct macsec_dev *macsec = macsec_priv(dev);
+ bool sci_present;
u32 pn;
secy = &macsec->secy;
@@ -687,7 +696,8 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb,
unprotected_len = skb->len;
eth = eth_hdr(skb);
- hh = (struct macsec_eth_header *)skb_push(skb, macsec_extra_len(tx_sc->send_sci));
+ sci_present = send_sci(secy);
+ hh = (struct macsec_eth_header *)skb_push(skb, macsec_extra_len(sci_present));
memmove(hh, eth, 2 * ETH_ALEN);
pn = tx_sa_update_pn(tx_sa, secy);
@@ -726,10 +736,10 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb,
skb_to_sgvec(skb, sg, 0, skb->len);
if (tx_sc->encrypt) {
- int len = skb->len - macsec_hdr_len(tx_sc->send_sci) -
+ int len = skb->len - macsec_hdr_len(sci_present) -
secy->icv_len;
aead_request_set_crypt(req, sg, sg, len, iv);
- aead_request_set_ad(req, macsec_hdr_len(tx_sc->send_sci));
+ aead_request_set_ad(req, macsec_hdr_len(sci_present));
} else {
aead_request_set_crypt(req, sg, sg, 0, iv);
aead_request_set_ad(req, skb->len - secy->icv_len);
--
1.9.1
^ permalink raw reply related
* Re: [PATCH net-next v2 2/2] reuseport, bpf: add test case for bpf_get_numa_node_id
From: Daniel Borkmann @ 2016-10-21 11:22 UTC (permalink / raw)
To: Jiri Pirko; +Cc: davem, alexei.starovoitov, edumazet, netdev
In-Reply-To: <20161021110801.GA2140@nanopsycho>
On 10/21/2016 01:08 PM, Jiri Pirko wrote:
> Fri, Oct 21, 2016 at 12:46:34PM CEST, daniel@iogearbox.net wrote:
>> The test case is very similar to reuseport_bpf_cpu, only that here
>> we select socket members based on current numa node id.
>>
>> # numactl -H
>> available: 2 nodes (0-1)
>> node 0 cpus: 0 1 2 3 4 5 12 13 14 15 16 17
>> node 0 size: 128867 MB
>> node 0 free: 120080 MB
>> node 1 cpus: 6 7 8 9 10 11 18 19 20 21 22 23
>> node 1 size: 96765 MB
>> node 1 free: 87504 MB
>> node distances:
>> node 0 1
>> 0: 10 20
>> 1: 20 10
>>
>> # ./reuseport_bpf_numa
>> ---- IPv4 UDP ----
>> send node 0, receive socket 0
>> send node 1, receive socket 1
>> send node 1, receive socket 1
>> send node 0, receive socket 0
>> ---- IPv6 UDP ----
>> send node 0, receive socket 0
>> send node 1, receive socket 1
>> send node 1, receive socket 1
>> send node 0, receive socket 0
>> ---- IPv4 TCP ----
>> send node 0, receive socket 0
>> send node 1, receive socket 1
>> send node 1, receive socket 1
>> send node 0, receive socket 0
>> ---- IPv6 TCP ----
>> send node 0, receive socket 0
>> send node 1, receive socket 1
>> send node 1, receive socket 1
>> send node 0, receive socket 0
>> SUCCESS
>>
>> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
>> Acked-by: Alexei Starovoitov <ast@kernel.org>
>> ---
>> tools/testing/selftests/net/.gitignore | 1 +
>> tools/testing/selftests/net/Makefile | 11 +-
>> tools/testing/selftests/net/reuseport_bpf_numa.c | 255 +++++++++++++++++++++++
>> 3 files changed, 263 insertions(+), 4 deletions(-)
>> create mode 100644 tools/testing/selftests/net/reuseport_bpf_numa.c
>>
>> diff --git a/tools/testing/selftests/net/.gitignore b/tools/testing/selftests/net/.gitignore
>> index 0840684..afe109e 100644
>> --- a/tools/testing/selftests/net/.gitignore
>> +++ b/tools/testing/selftests/net/.gitignore
>> @@ -3,4 +3,5 @@ psock_fanout
>> psock_tpacket
>> reuseport_bpf
>> reuseport_bpf_cpu
>> +reuseport_bpf_numa
>> reuseport_dualstack
>> diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
>> index 0e53407..e24e4c8 100644
>> --- a/tools/testing/selftests/net/Makefile
>> +++ b/tools/testing/selftests/net/Makefile
>> @@ -1,14 +1,17 @@
>> # Makefile for net selftests
>>
>> -CFLAGS = -Wall -O2 -g
>> -
>> +CFLAGS = -Wall -Wl,--no-as-needed -O2 -g
>
> ^ why the extra space?
>
>> CFLAGS += -I../../../../usr/include/
>>
>> -NET_PROGS = socket psock_fanout psock_tpacket reuseport_bpf reuseport_bpf_cpu reuseport_dualstack
>> +NET_PROGS = socket
>
> ^ yet again. Sorry for nitpicking :)
No strong opinion; did this so it aligns with the next lines:
CFLAGS = -Wall -Wl,--no-as-needed -O2 -g
CFLAGS += -I../../../../usr/include/
NET_PROGS = socket
NET_PROGS += psock_fanout psock_tpacket
NET_PROGS += reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa
NET_PROGS += reuseport_dualstack
^ permalink raw reply
* Re: [PATCH v2 net-next 1/1] driver: tun: Forbid to set IFF_TUN and IFF_TAP at the same time
From: Eric Dumazet @ 2016-10-21 11:28 UTC (permalink / raw)
To: fgao; +Cc: davem, jasowang, edumazet, pabeni, netdev, gfree.wind
In-Reply-To: <1477047735-26003-1-git-send-email-fgao@ikuai8.com>
On Fri, 2016-10-21 at 19:02 +0800, fgao@ikuai8.com wrote:
> From: Gao Feng <fgao@ikuai8.com>
>
> Current tun driver permits the ifr_flags is set with IFF_TUN and
> IFF_TAP at the same time. But actually there is only IFF_TUN flag
> works. And it does not make sense these two flags are set, so add
> this check.
>
> Signed-off-by: Gao Feng <fgao@ikuai8.com>
> ---
> v2: Remove useless {}
> v1: Initial patch
>
> drivers/net/tun.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
> index 8093e39..faaa189 100644
> --- a/drivers/net/tun.c
> +++ b/drivers/net/tun.c
> @@ -1752,6 +1752,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
> if (err < 0)
> return err;
>
> + if ((ifr->ifr_flags & (IFF_TUN | IFF_TAP)) == (IFF_TUN | IFF_TAP))
> + return -EINVAL;
> +
> /* Set dev type */
> if (ifr->ifr_flags & IFF_TUN) {
> /* TUN device */
This might break some applications.
It might be too late to add this check without a grace period.
^ permalink raw reply
* Re: [PATCH net-next v2 1/2] bpf: add helper for retrieving current numa node id
From: Eric Dumazet @ 2016-10-21 11:29 UTC (permalink / raw)
To: Daniel Borkmann; +Cc: davem, alexei.starovoitov, edumazet, netdev
In-Reply-To: <46dd208fee014c0837d750ffa13e625c6f4ee53c.1477043972.git.daniel@iogearbox.net>
On Fri, 2016-10-21 at 12:46 +0200, Daniel Borkmann wrote:
> Use case is mainly for soreuseport to select sockets for the local
> numa node, but since generic, lets also add this for other networking
> and tracing program types.
>
> Suggested-by: Eric Dumazet <edumazet@google.com>
> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
> Acked-by: Alexei Starovoitov <ast@kernel.org>
> ---
Acked-by: Eric Dumazet <edumazet@google.com>
Thanks Daniel !
^ permalink raw reply
* Re: [PATCH v2 net-next 1/1] driver: tun: Forbid to set IFF_TUN and IFF_TAP at the same time
From: Gao Feng @ 2016-10-21 11:32 UTC (permalink / raw)
To: Eric Dumazet
Cc: David S. Miller, jasowang, edumazet, pabeni,
Linux Kernel Network Developers
In-Reply-To: <1477049287.7065.51.camel@edumazet-glaptop3.roam.corp.google.com>
Hi Eric,
On Fri, Oct 21, 2016 at 7:28 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> On Fri, 2016-10-21 at 19:02 +0800, fgao@ikuai8.com wrote:
>> From: Gao Feng <fgao@ikuai8.com>
>>
>> Current tun driver permits the ifr_flags is set with IFF_TUN and
>> IFF_TAP at the same time. But actually there is only IFF_TUN flag
>> works. And it does not make sense these two flags are set, so add
>> this check.
>>
>> Signed-off-by: Gao Feng <fgao@ikuai8.com>
>> ---
>> v2: Remove useless {}
>> v1: Initial patch
>>
>> drivers/net/tun.c | 3 +++
>> 1 file changed, 3 insertions(+)
>>
>> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
>> index 8093e39..faaa189 100644
>> --- a/drivers/net/tun.c
>> +++ b/drivers/net/tun.c
>> @@ -1752,6 +1752,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
>> if (err < 0)
>> return err;
>>
>> + if ((ifr->ifr_flags & (IFF_TUN | IFF_TAP)) == (IFF_TUN | IFF_TAP))
>> + return -EINVAL;
>> +
>> /* Set dev type */
>> if (ifr->ifr_flags & IFF_TUN) {
>> /* TUN device */
>
>
> This might break some applications.
Yes. I consider about this case.
But I think there should be very least applications which set these
two flags at the same time.
>
> It might be too late to add this check without a grace period.
>
>
>
Yes, It needs some discussions.
Regards
Feng
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox