* [PATCH v3 bpf-next 06/12] selftests/bpf: add CO-RE relocs nesting tests
From: Andrii Nakryiko @ 2019-08-01 6:47 UTC (permalink / raw)
To: bpf, netdev, ast, daniel, yhs, songliubraving
Cc: andrii.nakryiko, kernel-team, Andrii Nakryiko
In-Reply-To: <20190801064803.2519675-1-andriin@fb.com>
Add a bunch of test validating correct handling of nested
structs/unions.
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Acked-by: Song Liu <songliubraving@fb.com>
---
.../selftests/bpf/prog_tests/core_reloc.c | 39 +++
.../bpf/progs/btf__core_reloc_nesting.c | 3 +
.../btf__core_reloc_nesting___anon_embed.c | 3 +
...f__core_reloc_nesting___dup_compat_types.c | 5 +
...core_reloc_nesting___err_array_container.c | 3 +
...tf__core_reloc_nesting___err_array_field.c | 3 +
...e_reloc_nesting___err_dup_incompat_types.c | 4 +
...re_reloc_nesting___err_missing_container.c | 3 +
...__core_reloc_nesting___err_missing_field.c | 3 +
..._reloc_nesting___err_nonstruct_container.c | 3 +
...e_reloc_nesting___err_partial_match_dups.c | 4 +
.../btf__core_reloc_nesting___err_too_deep.c | 3 +
.../btf__core_reloc_nesting___extra_nesting.c | 3 +
..._core_reloc_nesting___struct_union_mixup.c | 3 +
.../selftests/bpf/progs/core_reloc_types.h | 293 ++++++++++++++++++
.../bpf/progs/test_core_reloc_nesting.c | 46 +++
16 files changed, 421 insertions(+)
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_nesting.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___anon_embed.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___dup_compat_types.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_array_container.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_array_field.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_dup_incompat_types.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_missing_container.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_missing_field.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_nonstruct_container.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_partial_match_dups.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_too_deep.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___extra_nesting.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___struct_union_mixup.c
create mode 100644 tools/testing/selftests/bpf/progs/test_core_reloc_nesting.c
diff --git a/tools/testing/selftests/bpf/prog_tests/core_reloc.c b/tools/testing/selftests/bpf/prog_tests/core_reloc.c
index c147271deee6..226c5af28d6b 100644
--- a/tools/testing/selftests/bpf/prog_tests/core_reloc.c
+++ b/tools/testing/selftests/bpf/prog_tests/core_reloc.c
@@ -28,6 +28,29 @@
.fails = true, \
}
+#define NESTING_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
+ .a = { .a = { .a = 42 } }, \
+ .b = { .b = { .b = 0xc001 } }, \
+}
+
+#define NESTING_CASE_COMMON(name) \
+ .case_name = #name, \
+ .bpf_obj_file = "test_core_reloc_nesting.o", \
+ .btf_src_file = "btf__core_reloc_" #name ".o"
+
+#define NESTING_CASE(name) { \
+ NESTING_CASE_COMMON(name), \
+ .input = NESTING_DATA(core_reloc_##name), \
+ .input_len = sizeof(struct core_reloc_##name), \
+ .output = NESTING_DATA(core_reloc_nesting), \
+ .output_len = sizeof(struct core_reloc_nesting) \
+}
+
+#define NESTING_ERR_CASE(name) { \
+ NESTING_CASE_COMMON(name), \
+ .fails = true, \
+}
+
struct core_reloc_test_case {
const char *case_name;
const char *bpf_obj_file;
@@ -57,6 +80,22 @@ static struct core_reloc_test_case test_cases[] = {
FLAVORS_CASE(flavors),
FLAVORS_ERR_CASE(flavors__err_wrong_name),
+
+ /* various struct/enum nesting and resolution scenarios */
+ NESTING_CASE(nesting),
+ NESTING_CASE(nesting___anon_embed),
+ NESTING_CASE(nesting___struct_union_mixup),
+ NESTING_CASE(nesting___extra_nesting),
+ NESTING_CASE(nesting___dup_compat_types),
+
+ NESTING_ERR_CASE(nesting___err_missing_field),
+ NESTING_ERR_CASE(nesting___err_array_field),
+ NESTING_ERR_CASE(nesting___err_missing_container),
+ NESTING_ERR_CASE(nesting___err_nonstruct_container),
+ NESTING_ERR_CASE(nesting___err_array_container),
+ NESTING_ERR_CASE(nesting___err_dup_incompat_types),
+ NESTING_ERR_CASE(nesting___err_partial_match_dups),
+ NESTING_ERR_CASE(nesting___err_too_deep),
};
struct data {
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting.c
new file mode 100644
index 000000000000..4480fcc0f183
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_nesting x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___anon_embed.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___anon_embed.c
new file mode 100644
index 000000000000..13e108f76ece
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___anon_embed.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_nesting___anon_embed x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___dup_compat_types.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___dup_compat_types.c
new file mode 100644
index 000000000000..76b54fda5fbb
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___dup_compat_types.c
@@ -0,0 +1,5 @@
+#include "core_reloc_types.h"
+
+void f1(struct core_reloc_nesting___dup_compat_types x) {}
+void f2(struct core_reloc_nesting___dup_compat_types__2 x) {}
+void f3(struct core_reloc_nesting___dup_compat_types__3 x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_array_container.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_array_container.c
new file mode 100644
index 000000000000..975fb95db810
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_array_container.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_nesting___err_array_container x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_array_field.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_array_field.c
new file mode 100644
index 000000000000..ad66c67e7980
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_array_field.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_nesting___err_array_field x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_dup_incompat_types.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_dup_incompat_types.c
new file mode 100644
index 000000000000..35c5f8da6812
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_dup_incompat_types.c
@@ -0,0 +1,4 @@
+#include "core_reloc_types.h"
+
+void f1(struct core_reloc_nesting___err_dup_incompat_types__1 x) {}
+void f2(struct core_reloc_nesting___err_dup_incompat_types__2 x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_missing_container.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_missing_container.c
new file mode 100644
index 000000000000..142e332041db
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_missing_container.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_nesting___err_missing_container x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_missing_field.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_missing_field.c
new file mode 100644
index 000000000000..efcae167fab9
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_missing_field.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_nesting___err_missing_field x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_nonstruct_container.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_nonstruct_container.c
new file mode 100644
index 000000000000..97aaaedd8ada
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_nonstruct_container.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_nesting___err_nonstruct_container x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_partial_match_dups.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_partial_match_dups.c
new file mode 100644
index 000000000000..ffde35086e90
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_partial_match_dups.c
@@ -0,0 +1,4 @@
+#include "core_reloc_types.h"
+
+void f1(struct core_reloc_nesting___err_partial_match_dups__a x) {}
+void f2(struct core_reloc_nesting___err_partial_match_dups__b x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_too_deep.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_too_deep.c
new file mode 100644
index 000000000000..39a2fadd8e95
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___err_too_deep.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_nesting___err_too_deep x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___extra_nesting.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___extra_nesting.c
new file mode 100644
index 000000000000..a09d9dfb20df
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___extra_nesting.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_nesting___extra_nesting x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___struct_union_mixup.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___struct_union_mixup.c
new file mode 100644
index 000000000000..3d8a1a74012f
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_nesting___struct_union_mixup.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_nesting___struct_union_mixup x) {}
diff --git a/tools/testing/selftests/bpf/progs/core_reloc_types.h b/tools/testing/selftests/bpf/progs/core_reloc_types.h
index 33b0c6a61912..340ee2bcd463 100644
--- a/tools/testing/selftests/bpf/progs/core_reloc_types.h
+++ b/tools/testing/selftests/bpf/progs/core_reloc_types.h
@@ -13,3 +13,296 @@ struct core_reloc_flavors__err_wrong_name {
int b;
int c;
};
+
+/*
+ * NESTING
+ */
+/* original set up, used to record relocations in BPF program */
+struct core_reloc_nesting_substruct {
+ int a;
+};
+
+union core_reloc_nesting_subunion {
+ int b;
+};
+
+struct core_reloc_nesting {
+ union {
+ struct core_reloc_nesting_substruct a;
+ } a;
+ struct {
+ union core_reloc_nesting_subunion b;
+ } b;
+};
+
+/* inlined anonymous struct/union instead of named structs in original */
+struct core_reloc_nesting___anon_embed {
+ int __just_for_padding;
+ union {
+ struct {
+ int a;
+ } a;
+ } a;
+ struct {
+ union {
+ int b;
+ } b;
+ } b;
+};
+
+/* different mix of nested structs/unions than in original */
+struct core_reloc_nesting___struct_union_mixup {
+ int __a;
+ struct {
+ int __a;
+ union {
+ char __a;
+ int a;
+ } a;
+ } a;
+ int __b;
+ union {
+ int __b;
+ union {
+ char __b;
+ int b;
+ } b;
+ } b;
+};
+
+/* extra anon structs/unions, but still valid a.a.a and b.b.b accessors */
+struct core_reloc_nesting___extra_nesting {
+ int __padding;
+ struct {
+ struct {
+ struct {
+ struct {
+ union {
+ int a;
+ } a;
+ };
+ };
+ } a;
+ int __some_more;
+ struct {
+ union {
+ union {
+ union {
+ struct {
+ int b;
+ };
+ } b;
+ };
+ } b;
+ };
+ };
+};
+
+/* three flavors of same struct with different structure but same layout for
+ * a.a.a and b.b.b, thus successfully resolved and relocatable */
+struct core_reloc_nesting___dup_compat_types {
+ char __just_for_padding;
+ /* 3 more bytes of padding */
+ struct {
+ struct {
+ int a; /* offset 4 */
+ } a;
+ } a;
+ long long __more_padding;
+ struct {
+ struct {
+ int b; /* offset 16 */
+ } b;
+ } b;
+};
+
+struct core_reloc_nesting___dup_compat_types__2 {
+ int __aligned_padding;
+ struct {
+ int __trickier_noop[0];
+ struct {
+ char __some_more_noops[0];
+ int a; /* offset 4 */
+ } a;
+ } a;
+ int __more_padding;
+ struct {
+ struct {
+ struct {
+ int __critical_padding;
+ int b; /* offset 16 */
+ } b;
+ int __does_not_matter;
+ };
+ } b;
+ int __more_irrelevant_stuff;
+};
+
+struct core_reloc_nesting___dup_compat_types__3 {
+ char __correct_padding[4];
+ struct {
+ struct {
+ int a; /* offset 4 */
+ } a;
+ } a;
+ /* 8 byte padding due to next struct's alignment */
+ struct {
+ struct {
+ int b;
+ } b;
+ } b __attribute__((aligned(16)));
+};
+
+/* b.b.b field is missing */
+struct core_reloc_nesting___err_missing_field {
+ struct {
+ struct {
+ int a;
+ } a;
+ } a;
+ struct {
+ struct {
+ int x;
+ } b;
+ } b;
+};
+
+/* b.b.b field is an array of integers instead of plain int */
+struct core_reloc_nesting___err_array_field {
+ struct {
+ struct {
+ int a;
+ } a;
+ } a;
+ struct {
+ struct {
+ int b[1];
+ } b;
+ } b;
+};
+
+/* middle b container is missing */
+struct core_reloc_nesting___err_missing_container {
+ struct {
+ struct {
+ int a;
+ } a;
+ } a;
+ struct {
+ int x;
+ } b;
+};
+
+/* middle b container is referenced through pointer instead of being embedded */
+struct core_reloc_nesting___err_nonstruct_container {
+ struct {
+ struct {
+ int a;
+ } a;
+ } a;
+ struct {
+ struct {
+ int b;
+ } *b;
+ } b;
+};
+
+/* middle b container is an array of structs instead of plain struct */
+struct core_reloc_nesting___err_array_container {
+ struct {
+ struct {
+ int a;
+ } a;
+ } a;
+ struct {
+ struct {
+ int b;
+ } b[1];
+ } b;
+};
+
+/* two flavors of same struct with incompatible layout for b.b.b */
+struct core_reloc_nesting___err_dup_incompat_types__1 {
+ struct {
+ struct {
+ int a; /* offset 0 */
+ } a;
+ } a;
+ struct {
+ struct {
+ int b; /* offset 4 */
+ } b;
+ } b;
+};
+
+struct core_reloc_nesting___err_dup_incompat_types__2 {
+ struct {
+ struct {
+ int a; /* offset 0 */
+ } a;
+ } a;
+ int __extra_padding;
+ struct {
+ struct {
+ int b; /* offset 8 (!) */
+ } b;
+ } b;
+};
+
+/* two flavors of same struct having one of a.a.a and b.b.b, but not both */
+struct core_reloc_nesting___err_partial_match_dups__a {
+ struct {
+ struct {
+ int a;
+ } a;
+ } a;
+};
+
+struct core_reloc_nesting___err_partial_match_dups__b {
+ struct {
+ struct {
+ int b;
+ } b;
+ } b;
+};
+
+struct core_reloc_nesting___err_too_deep {
+ struct {
+ struct {
+ int a;
+ } a;
+ } a;
+ /* 65 levels of nestedness for b.b.b */
+ struct {
+ struct {
+ struct { struct { struct { struct { struct {
+ struct { struct { struct { struct { struct {
+ struct { struct { struct { struct { struct {
+ struct { struct { struct { struct { struct {
+ struct { struct { struct { struct { struct {
+ struct { struct { struct { struct { struct {
+ struct { struct { struct { struct { struct {
+ struct { struct { struct { struct { struct {
+ struct { struct { struct { struct { struct {
+ struct { struct { struct { struct { struct {
+ struct { struct { struct { struct { struct {
+ struct { struct { struct { struct { struct {
+ /* this one is one too much */
+ struct {
+ int b;
+ };
+ }; }; }; }; };
+ }; }; }; }; };
+ }; }; }; }; };
+ }; }; }; }; };
+ }; }; }; }; };
+ }; }; }; }; };
+ }; }; }; }; };
+ }; }; }; }; };
+ }; }; }; }; };
+ }; }; }; }; };
+ }; }; }; }; };
+ }; }; }; }; };
+ } b;
+ } b;
+};
diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_nesting.c b/tools/testing/selftests/bpf/progs/test_core_reloc_nesting.c
new file mode 100644
index 000000000000..3ca30cec2b39
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/test_core_reloc_nesting.c
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2019 Facebook
+
+#include <linux/bpf.h>
+#include <stdint.h>
+#include "bpf_helpers.h"
+
+char _license[] SEC("license") = "GPL";
+
+static volatile struct data {
+ char in[256];
+ char out[256];
+} data;
+
+struct core_reloc_nesting_substruct {
+ int a;
+};
+
+union core_reloc_nesting_subunion {
+ int b;
+};
+
+/* int a.a.a and b.b.b accesses */
+struct core_reloc_nesting {
+ union {
+ struct core_reloc_nesting_substruct a;
+ } a;
+ struct {
+ union core_reloc_nesting_subunion b;
+ } b;
+};
+
+SEC("raw_tracepoint/sys_enter")
+int test_core_nesting(void *ctx)
+{
+ struct core_reloc_nesting *in = (void *)&data.in;
+ struct core_reloc_nesting *out = (void *)&data.out;
+
+ if (BPF_CORE_READ(&out->a.a.a, &in->a.a.a))
+ return 1;
+ if (BPF_CORE_READ(&out->b.b.b, &in->b.b.b))
+ return 1;
+
+ return 0;
+}
+
--
2.17.1
^ permalink raw reply related
* [PATCH v3 bpf-next 09/12] selftests/bpf: add CO-RE relocs modifiers/typedef tests
From: Andrii Nakryiko @ 2019-08-01 6:48 UTC (permalink / raw)
To: bpf, netdev, ast, daniel, yhs, songliubraving
Cc: andrii.nakryiko, kernel-team, Andrii Nakryiko
In-Reply-To: <20190801064803.2519675-1-andriin@fb.com>
Add tests validating correct handling of various combinations of
typedefs and const/volatile/restrict modifiers.
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Acked-by: Song Liu <songliubraving@fb.com>
---
.../selftests/bpf/prog_tests/core_reloc.c | 27 +++++++
.../bpf/progs/btf__core_reloc_mods.c | 3 +
.../progs/btf__core_reloc_mods___mod_swap.c | 3 +
.../progs/btf__core_reloc_mods___typedefs.c | 3 +
.../selftests/bpf/progs/core_reloc_types.h | 72 +++++++++++++++++++
.../bpf/progs/test_core_reloc_mods.c | 62 ++++++++++++++++
6 files changed, 170 insertions(+)
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_mods.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_mods___mod_swap.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_mods___typedefs.c
create mode 100644 tools/testing/selftests/bpf/progs/test_core_reloc_mods.c
diff --git a/tools/testing/selftests/bpf/prog_tests/core_reloc.c b/tools/testing/selftests/bpf/prog_tests/core_reloc.c
index dd2bab1b2e7d..adb8480d14dc 100644
--- a/tools/testing/selftests/bpf/prog_tests/core_reloc.c
+++ b/tools/testing/selftests/bpf/prog_tests/core_reloc.c
@@ -107,6 +107,28 @@
.fails = true, \
}
+#define MODS_CASE(name) { \
+ .case_name = #name, \
+ .bpf_obj_file = "test_core_reloc_mods.o", \
+ .btf_src_file = "btf__core_reloc_" #name ".o", \
+ .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) { \
+ .a = 1, \
+ .b = 2, \
+ .c = (void *)3, \
+ .d = (void *)4, \
+ .e = { [2] = 5 }, \
+ .f = { [1] = 6 }, \
+ .g = { .x = 7 }, \
+ .h = { .y = 8 }, \
+ }, \
+ .input_len = sizeof(struct core_reloc_##name), \
+ .output = STRUCT_TO_CHAR_PTR(core_reloc_mods_output) { \
+ .a = 1, .b = 2, .c = 3, .d = 4, \
+ .e = 5, .f = 6, .g = 7, .h = 8, \
+ }, \
+ .output_len = sizeof(struct core_reloc_mods_output), \
+}
+
struct core_reloc_test_case {
const char *case_name;
const char *bpf_obj_file;
@@ -173,6 +195,11 @@ static struct core_reloc_test_case test_cases[] = {
PRIMITIVES_ERR_CASE(primitives___err_non_enum),
PRIMITIVES_ERR_CASE(primitives___err_non_int),
PRIMITIVES_ERR_CASE(primitives___err_non_ptr),
+
+ /* const/volatile/restrict and typedefs scenarios */
+ MODS_CASE(mods),
+ MODS_CASE(mods___mod_swap),
+ MODS_CASE(mods___typedefs),
};
struct data {
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_mods.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_mods.c
new file mode 100644
index 000000000000..124197a2e813
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_mods.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_mods x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_mods___mod_swap.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_mods___mod_swap.c
new file mode 100644
index 000000000000..f8a6592ca75f
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_mods___mod_swap.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_mods___mod_swap x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_mods___typedefs.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_mods___typedefs.c
new file mode 100644
index 000000000000..5c0d73687247
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_mods___typedefs.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_mods___typedefs x) {}
diff --git a/tools/testing/selftests/bpf/progs/core_reloc_types.h b/tools/testing/selftests/bpf/progs/core_reloc_types.h
index 7526a5f5755b..3401e8342e57 100644
--- a/tools/testing/selftests/bpf/progs/core_reloc_types.h
+++ b/tools/testing/selftests/bpf/progs/core_reloc_types.h
@@ -454,3 +454,75 @@ struct core_reloc_primitives___err_non_ptr {
int d; /* int instead of ptr */
int (*f)(const char *);
};
+
+/*
+ * MODS
+ */
+struct core_reloc_mods_output {
+ int a, b, c, d, e, f, g, h;
+};
+
+typedef const int int_t;
+typedef const char *char_ptr_t;
+typedef const int arr_t[7];
+
+struct core_reloc_mods_substruct {
+ int x;
+ int y;
+};
+
+typedef struct {
+ int x;
+ int y;
+} core_reloc_mods_substruct_t;
+
+struct core_reloc_mods {
+ int a;
+ int_t b;
+ char *c;
+ char_ptr_t d;
+ int e[3];
+ arr_t f;
+ struct core_reloc_mods_substruct g;
+ core_reloc_mods_substruct_t h;
+};
+
+/* a/b, c/d, e/f, and g/h pairs are swapped */
+struct core_reloc_mods___mod_swap {
+ int b;
+ int_t a;
+ char *d;
+ char_ptr_t c;
+ int f[3];
+ arr_t e;
+ struct {
+ int y;
+ int x;
+ } h;
+ core_reloc_mods_substruct_t g;
+};
+
+typedef int int1_t;
+typedef int1_t int2_t;
+typedef int2_t int3_t;
+
+typedef int arr1_t[5];
+typedef arr1_t arr2_t;
+typedef arr2_t arr3_t;
+typedef arr3_t arr4_t;
+
+typedef const char * const volatile restrict fancy_char_ptr_t;
+
+typedef core_reloc_mods_substruct_t core_reloc_mods_substruct_tt;
+
+/* we need more typedefs */
+struct core_reloc_mods___typedefs {
+ core_reloc_mods_substruct_tt g;
+ core_reloc_mods_substruct_tt h;
+ arr4_t f;
+ arr4_t e;
+ fancy_char_ptr_t d;
+ fancy_char_ptr_t c;
+ int3_t b;
+ int3_t a;
+};
diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_mods.c b/tools/testing/selftests/bpf/progs/test_core_reloc_mods.c
new file mode 100644
index 000000000000..f98b942c062b
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/test_core_reloc_mods.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2019 Facebook
+
+#include <linux/bpf.h>
+#include <stdint.h>
+#include "bpf_helpers.h"
+
+char _license[] SEC("license") = "GPL";
+
+static volatile struct data {
+ char in[256];
+ char out[256];
+} data;
+
+struct core_reloc_mods_output {
+ int a, b, c, d, e, f, g, h;
+};
+
+typedef const int int_t;
+typedef const char *char_ptr_t;
+typedef const int arr_t[7];
+
+struct core_reloc_mods_substruct {
+ int x;
+ int y;
+};
+
+typedef struct {
+ int x;
+ int y;
+} core_reloc_mods_substruct_t;
+
+struct core_reloc_mods {
+ int a;
+ int_t b;
+ char *c;
+ char_ptr_t d;
+ int e[3];
+ arr_t f;
+ struct core_reloc_mods_substruct g;
+ core_reloc_mods_substruct_t h;
+};
+
+SEC("raw_tracepoint/sys_enter")
+int test_core_mods(void *ctx)
+{
+ struct core_reloc_mods *in = (void *)&data.in;
+ struct core_reloc_mods_output *out = (void *)&data.out;
+
+ if (BPF_CORE_READ(&out->a, &in->a) ||
+ BPF_CORE_READ(&out->b, &in->b) ||
+ BPF_CORE_READ(&out->c, &in->c) ||
+ BPF_CORE_READ(&out->d, &in->d) ||
+ BPF_CORE_READ(&out->e, &in->e[2]) ||
+ BPF_CORE_READ(&out->f, &in->f[1]) ||
+ BPF_CORE_READ(&out->g, &in->g.x) ||
+ BPF_CORE_READ(&out->h, &in->h.y))
+ return 1;
+
+ return 0;
+}
+
--
2.17.1
^ permalink raw reply related
* [PATCH v3 bpf-next 08/12] selftests/bpf: add CO-RE relocs enum/ptr/func_proto tests
From: Andrii Nakryiko @ 2019-08-01 6:47 UTC (permalink / raw)
To: bpf, netdev, ast, daniel, yhs, songliubraving
Cc: andrii.nakryiko, kernel-team, Andrii Nakryiko
In-Reply-To: <20190801064803.2519675-1-andriin@fb.com>
Test CO-RE relocation handling of ints, enums, pointers, func protos, etc.
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Acked-by: Song Liu <songliubraving@fb.com>
---
.../selftests/bpf/prog_tests/core_reloc.c | 36 ++++++++++
.../bpf/progs/btf__core_reloc_primitives.c | 3 +
...f__core_reloc_primitives___diff_enum_def.c | 3 +
..._core_reloc_primitives___diff_func_proto.c | 3 +
...f__core_reloc_primitives___diff_ptr_type.c | 3 +
...tf__core_reloc_primitives___err_non_enum.c | 3 +
...btf__core_reloc_primitives___err_non_int.c | 3 +
...btf__core_reloc_primitives___err_non_ptr.c | 3 +
.../selftests/bpf/progs/core_reloc_types.h | 67 +++++++++++++++++++
.../bpf/progs/test_core_reloc_primitives.c | 43 ++++++++++++
10 files changed, 167 insertions(+)
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_primitives.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_primitives___diff_enum_def.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_primitives___diff_func_proto.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_primitives___diff_ptr_type.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_primitives___err_non_enum.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_primitives___err_non_int.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_primitives___err_non_ptr.c
create mode 100644 tools/testing/selftests/bpf/progs/test_core_reloc_primitives.c
diff --git a/tools/testing/selftests/bpf/prog_tests/core_reloc.c b/tools/testing/selftests/bpf/prog_tests/core_reloc.c
index 13e1aaeb1c99..dd2bab1b2e7d 100644
--- a/tools/testing/selftests/bpf/prog_tests/core_reloc.c
+++ b/tools/testing/selftests/bpf/prog_tests/core_reloc.c
@@ -81,6 +81,32 @@
.fails = true, \
}
+#define PRIMITIVES_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
+ .a = 1, \
+ .b = 2, \
+ .c = 3, \
+ .d = (void *)4, \
+ .f = (void *)5, \
+}
+
+#define PRIMITIVES_CASE_COMMON(name) \
+ .case_name = #name, \
+ .bpf_obj_file = "test_core_reloc_primitives.o", \
+ .btf_src_file = "btf__core_reloc_" #name ".o"
+
+#define PRIMITIVES_CASE(name) { \
+ PRIMITIVES_CASE_COMMON(name), \
+ .input = PRIMITIVES_DATA(core_reloc_##name), \
+ .input_len = sizeof(struct core_reloc_##name), \
+ .output = PRIMITIVES_DATA(core_reloc_primitives), \
+ .output_len = sizeof(struct core_reloc_primitives), \
+}
+
+#define PRIMITIVES_ERR_CASE(name) { \
+ PRIMITIVES_CASE_COMMON(name), \
+ .fails = true, \
+}
+
struct core_reloc_test_case {
const char *case_name;
const char *bpf_obj_file;
@@ -137,6 +163,16 @@ static struct core_reloc_test_case test_cases[] = {
ARRAYS_ERR_CASE(arrays___err_non_array),
ARRAYS_ERR_CASE(arrays___err_wrong_val_type1),
ARRAYS_ERR_CASE(arrays___err_wrong_val_type2),
+
+ /* enum/ptr/int handling scenarios */
+ PRIMITIVES_CASE(primitives),
+ PRIMITIVES_CASE(primitives___diff_enum_def),
+ PRIMITIVES_CASE(primitives___diff_func_proto),
+ PRIMITIVES_CASE(primitives___diff_ptr_type),
+
+ PRIMITIVES_ERR_CASE(primitives___err_non_enum),
+ PRIMITIVES_ERR_CASE(primitives___err_non_int),
+ PRIMITIVES_ERR_CASE(primitives___err_non_ptr),
};
struct data {
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_primitives.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_primitives.c
new file mode 100644
index 000000000000..96b90e39242a
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_primitives.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_primitives x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_primitives___diff_enum_def.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_primitives___diff_enum_def.c
new file mode 100644
index 000000000000..6e87233a3ed0
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_primitives___diff_enum_def.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_primitives___diff_enum_def x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_primitives___diff_func_proto.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_primitives___diff_func_proto.c
new file mode 100644
index 000000000000..d9f48e80b9d9
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_primitives___diff_func_proto.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_primitives___diff_func_proto x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_primitives___diff_ptr_type.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_primitives___diff_ptr_type.c
new file mode 100644
index 000000000000..c718f75f8f3b
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_primitives___diff_ptr_type.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_primitives___diff_ptr_type x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_primitives___err_non_enum.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_primitives___err_non_enum.c
new file mode 100644
index 000000000000..b8a120830891
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_primitives___err_non_enum.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_primitives___err_non_enum x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_primitives___err_non_int.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_primitives___err_non_int.c
new file mode 100644
index 000000000000..ad8b3c9aa76f
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_primitives___err_non_int.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_primitives___err_non_int x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_primitives___err_non_ptr.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_primitives___err_non_ptr.c
new file mode 100644
index 000000000000..e20bc1d42d0a
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_primitives___err_non_ptr.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_primitives___err_non_ptr x) {}
diff --git a/tools/testing/selftests/bpf/progs/core_reloc_types.h b/tools/testing/selftests/bpf/progs/core_reloc_types.h
index 45de7986ea2e..7526a5f5755b 100644
--- a/tools/testing/selftests/bpf/progs/core_reloc_types.h
+++ b/tools/testing/selftests/bpf/progs/core_reloc_types.h
@@ -387,3 +387,70 @@ struct core_reloc_arrays___err_wrong_val_type2 {
int c[3]; /* value is not a struct */
struct core_reloc_arrays_substruct d[1][2];
};
+
+/*
+ * PRIMITIVES
+ */
+enum core_reloc_primitives_enum {
+ A = 0,
+ B = 1,
+};
+
+struct core_reloc_primitives {
+ char a;
+ int b;
+ enum core_reloc_primitives_enum c;
+ void *d;
+ int (*f)(const char *);
+};
+
+struct core_reloc_primitives___diff_enum_def {
+ char a;
+ int b;
+ void *d;
+ int (*f)(const char *);
+ enum {
+ X = 100,
+ Y = 200,
+ } c; /* inline enum def with differing set of values */
+};
+
+struct core_reloc_primitives___diff_func_proto {
+ void (*f)(int); /* incompatible function prototype */
+ void *d;
+ enum core_reloc_primitives_enum c;
+ int b;
+ char a;
+};
+
+struct core_reloc_primitives___diff_ptr_type {
+ const char * const d; /* different pointee type + modifiers */
+ char a;
+ int b;
+ enum core_reloc_primitives_enum c;
+ int (*f)(const char *);
+};
+
+struct core_reloc_primitives___err_non_enum {
+ char a[1];
+ int b;
+ int c; /* int instead of enum */
+ void *d;
+ int (*f)(const char *);
+};
+
+struct core_reloc_primitives___err_non_int {
+ char a[1];
+ int *b; /* ptr instead of int */
+ enum core_reloc_primitives_enum c;
+ void *d;
+ int (*f)(const char *);
+};
+
+struct core_reloc_primitives___err_non_ptr {
+ char a[1];
+ int b;
+ enum core_reloc_primitives_enum c;
+ int d; /* int instead of ptr */
+ int (*f)(const char *);
+};
diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_primitives.c b/tools/testing/selftests/bpf/progs/test_core_reloc_primitives.c
new file mode 100644
index 000000000000..add52f23ab35
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/test_core_reloc_primitives.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2019 Facebook
+
+#include <linux/bpf.h>
+#include <stdint.h>
+#include "bpf_helpers.h"
+
+char _license[] SEC("license") = "GPL";
+
+static volatile struct data {
+ char in[256];
+ char out[256];
+} data;
+
+enum core_reloc_primitives_enum {
+ A = 0,
+ B = 1,
+};
+
+struct core_reloc_primitives {
+ char a;
+ int b;
+ enum core_reloc_primitives_enum c;
+ void *d;
+ int (*f)(const char *);
+};
+
+SEC("raw_tracepoint/sys_enter")
+int test_core_primitives(void *ctx)
+{
+ struct core_reloc_primitives *in = (void *)&data.in;
+ struct core_reloc_primitives *out = (void *)&data.out;
+
+ if (BPF_CORE_READ(&out->a, &in->a) ||
+ BPF_CORE_READ(&out->b, &in->b) ||
+ BPF_CORE_READ(&out->c, &in->c) ||
+ BPF_CORE_READ(&out->d, &in->d) ||
+ BPF_CORE_READ(&out->f, &in->f))
+ return 1;
+
+ return 0;
+}
+
--
2.17.1
^ permalink raw reply related
* [PATCH v3 bpf-next 11/12] selftests/bpf: add CO-RE relocs ints tests
From: Andrii Nakryiko @ 2019-08-01 6:48 UTC (permalink / raw)
To: bpf, netdev, ast, daniel, yhs, songliubraving
Cc: andrii.nakryiko, kernel-team, Andrii Nakryiko
In-Reply-To: <20190801064803.2519675-1-andriin@fb.com>
Add various tests validating handling compatible/incompatible integer
types.
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Acked-by: Song Liu <songliubraving@fb.com>
---
.../selftests/bpf/prog_tests/core_reloc.c | 40 +++++++
.../bpf/progs/btf__core_reloc_ints.c | 3 +
.../bpf/progs/btf__core_reloc_ints___bool.c | 3 +
.../btf__core_reloc_ints___err_bitfield.c | 3 +
.../btf__core_reloc_ints___err_wrong_sz_16.c | 3 +
.../btf__core_reloc_ints___err_wrong_sz_32.c | 3 +
.../btf__core_reloc_ints___err_wrong_sz_64.c | 3 +
.../btf__core_reloc_ints___err_wrong_sz_8.c | 3 +
.../btf__core_reloc_ints___reverse_sign.c | 3 +
.../selftests/bpf/progs/core_reloc_types.h | 101 ++++++++++++++++++
.../bpf/progs/test_core_reloc_ints.c | 44 ++++++++
11 files changed, 209 insertions(+)
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_ints.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_ints___bool.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_ints___err_bitfield.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_ints___err_wrong_sz_16.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_ints___err_wrong_sz_32.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_ints___err_wrong_sz_64.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_ints___err_wrong_sz_8.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_ints___reverse_sign.c
create mode 100644 tools/testing/selftests/bpf/progs/test_core_reloc_ints.c
diff --git a/tools/testing/selftests/bpf/prog_tests/core_reloc.c b/tools/testing/selftests/bpf/prog_tests/core_reloc.c
index ad663978be15..46abb4df5b1c 100644
--- a/tools/testing/selftests/bpf/prog_tests/core_reloc.c
+++ b/tools/testing/selftests/bpf/prog_tests/core_reloc.c
@@ -145,6 +145,35 @@
.output_len = sizeof(struct core_reloc_ptr_as_arr), \
}
+#define INTS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
+ .u8_field = 1, \
+ .s8_field = 2, \
+ .u16_field = 3, \
+ .s16_field = 4, \
+ .u32_field = 5, \
+ .s32_field = 6, \
+ .u64_field = 7, \
+ .s64_field = 8, \
+}
+
+#define INTS_CASE_COMMON(name) \
+ .case_name = #name, \
+ .bpf_obj_file = "test_core_reloc_ints.o", \
+ .btf_src_file = "btf__core_reloc_" #name ".o"
+
+#define INTS_CASE(name) { \
+ INTS_CASE_COMMON(name), \
+ .input = INTS_DATA(core_reloc_##name), \
+ .input_len = sizeof(struct core_reloc_##name), \
+ .output = INTS_DATA(core_reloc_ints), \
+ .output_len = sizeof(struct core_reloc_ints), \
+}
+
+#define INTS_ERR_CASE(name) { \
+ INTS_CASE_COMMON(name), \
+ .fails = true, \
+}
+
struct core_reloc_test_case {
const char *case_name;
const char *bpf_obj_file;
@@ -220,6 +249,17 @@ static struct core_reloc_test_case test_cases[] = {
/* handling "ptr is an array" semantics */
PTR_AS_ARR_CASE(ptr_as_arr),
PTR_AS_ARR_CASE(ptr_as_arr___diff_sz),
+
+ /* int signedness/sizing/bitfield handling */
+ INTS_CASE(ints),
+ INTS_CASE(ints___bool),
+ INTS_CASE(ints___reverse_sign),
+
+ INTS_ERR_CASE(ints___err_bitfield),
+ INTS_ERR_CASE(ints___err_wrong_sz_8),
+ INTS_ERR_CASE(ints___err_wrong_sz_16),
+ INTS_ERR_CASE(ints___err_wrong_sz_32),
+ INTS_ERR_CASE(ints___err_wrong_sz_64),
};
struct data {
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_ints.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_ints.c
new file mode 100644
index 000000000000..7d0f041042c5
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_ints.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_ints x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_ints___bool.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_ints___bool.c
new file mode 100644
index 000000000000..f9359450186e
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_ints___bool.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_ints___bool x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_ints___err_bitfield.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_ints___err_bitfield.c
new file mode 100644
index 000000000000..50369e8320a0
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_ints___err_bitfield.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_ints___err_bitfield x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_ints___err_wrong_sz_16.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_ints___err_wrong_sz_16.c
new file mode 100644
index 000000000000..823bac13d641
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_ints___err_wrong_sz_16.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_ints___err_wrong_sz_16 x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_ints___err_wrong_sz_32.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_ints___err_wrong_sz_32.c
new file mode 100644
index 000000000000..b44f3be18535
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_ints___err_wrong_sz_32.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_ints___err_wrong_sz_32 x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_ints___err_wrong_sz_64.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_ints___err_wrong_sz_64.c
new file mode 100644
index 000000000000..9a3dd2099c0f
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_ints___err_wrong_sz_64.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_ints___err_wrong_sz_64 x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_ints___err_wrong_sz_8.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_ints___err_wrong_sz_8.c
new file mode 100644
index 000000000000..9f11ef5f6e88
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_ints___err_wrong_sz_8.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_ints___err_wrong_sz_8 x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_ints___reverse_sign.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_ints___reverse_sign.c
new file mode 100644
index 000000000000..aafb1c5819d7
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_ints___reverse_sign.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_ints___reverse_sign x) {}
diff --git a/tools/testing/selftests/bpf/progs/core_reloc_types.h b/tools/testing/selftests/bpf/progs/core_reloc_types.h
index c17c9279deae..5f3ebd4f6dc3 100644
--- a/tools/testing/selftests/bpf/progs/core_reloc_types.h
+++ b/tools/testing/selftests/bpf/progs/core_reloc_types.h
@@ -1,3 +1,6 @@
+#include <stdint.h>
+#include <stdbool.h>
+
/*
* FLAVORS
*/
@@ -539,3 +542,101 @@ struct core_reloc_ptr_as_arr___diff_sz {
char __some_more_padding;
int a;
};
+
+/*
+ * INTS
+ */
+struct core_reloc_ints {
+ uint8_t u8_field;
+ int8_t s8_field;
+ uint16_t u16_field;
+ int16_t s16_field;
+ uint32_t u32_field;
+ int32_t s32_field;
+ uint64_t u64_field;
+ int64_t s64_field;
+};
+
+/* signed/unsigned types swap */
+struct core_reloc_ints___reverse_sign {
+ int8_t u8_field;
+ uint8_t s8_field;
+ int16_t u16_field;
+ uint16_t s16_field;
+ int32_t u32_field;
+ uint32_t s32_field;
+ int64_t u64_field;
+ uint64_t s64_field;
+};
+
+struct core_reloc_ints___bool {
+ bool u8_field; /* bool instead of uint8 */
+ int8_t s8_field;
+ uint16_t u16_field;
+ int16_t s16_field;
+ uint32_t u32_field;
+ int32_t s32_field;
+ uint64_t u64_field;
+ int64_t s64_field;
+};
+
+struct core_reloc_ints___err_bitfield {
+ uint8_t u8_field;
+ int8_t s8_field;
+ uint16_t u16_field;
+ int16_t s16_field;
+ uint32_t u32_field: 32; /* bitfields are not supported */
+ int32_t s32_field;
+ uint64_t u64_field;
+ int64_t s64_field;
+};
+
+struct core_reloc_ints___err_wrong_sz_8 {
+ uint16_t u8_field; /* not 8-bit anymore */
+ int16_t s8_field; /* not 8-bit anymore */
+
+ uint16_t u16_field;
+ int16_t s16_field;
+ uint32_t u32_field;
+ int32_t s32_field;
+ uint64_t u64_field;
+ int64_t s64_field;
+};
+
+struct core_reloc_ints___err_wrong_sz_16 {
+ uint8_t u8_field;
+ int8_t s8_field;
+
+ uint32_t u16_field; /* not 16-bit anymore */
+ int32_t s16_field; /* not 16-bit anymore */
+
+ uint32_t u32_field;
+ int32_t s32_field;
+ uint64_t u64_field;
+ int64_t s64_field;
+};
+
+struct core_reloc_ints___err_wrong_sz_32 {
+ uint8_t u8_field;
+ int8_t s8_field;
+ uint16_t u16_field;
+ int16_t s16_field;
+
+ uint64_t u32_field; /* not 32-bit anymore */
+ int64_t s32_field; /* not 32-bit anymore */
+
+ uint64_t u64_field;
+ int64_t s64_field;
+};
+
+struct core_reloc_ints___err_wrong_sz_64 {
+ uint8_t u8_field;
+ int8_t s8_field;
+ uint16_t u16_field;
+ int16_t s16_field;
+ uint32_t u32_field;
+ int32_t s32_field;
+
+ uint32_t u64_field; /* not 64-bit anymore */
+ int32_t s64_field; /* not 64-bit anymore */
+};
diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_ints.c b/tools/testing/selftests/bpf/progs/test_core_reloc_ints.c
new file mode 100644
index 000000000000..d99233c8008a
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/test_core_reloc_ints.c
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2019 Facebook
+
+#include <linux/bpf.h>
+#include <stdint.h>
+#include "bpf_helpers.h"
+
+char _license[] SEC("license") = "GPL";
+
+static volatile struct data {
+ char in[256];
+ char out[256];
+} data;
+
+struct core_reloc_ints {
+ uint8_t u8_field;
+ int8_t s8_field;
+ uint16_t u16_field;
+ int16_t s16_field;
+ uint32_t u32_field;
+ int32_t s32_field;
+ uint64_t u64_field;
+ int64_t s64_field;
+};
+
+SEC("raw_tracepoint/sys_enter")
+int test_core_ints(void *ctx)
+{
+ struct core_reloc_ints *in = (void *)&data.in;
+ struct core_reloc_ints *out = (void *)&data.out;
+
+ if (BPF_CORE_READ(&out->u8_field, &in->u8_field) ||
+ BPF_CORE_READ(&out->s8_field, &in->s8_field) ||
+ BPF_CORE_READ(&out->u16_field, &in->u16_field) ||
+ BPF_CORE_READ(&out->s16_field, &in->s16_field) ||
+ BPF_CORE_READ(&out->u32_field, &in->u32_field) ||
+ BPF_CORE_READ(&out->s32_field, &in->s32_field) ||
+ BPF_CORE_READ(&out->u64_field, &in->u64_field) ||
+ BPF_CORE_READ(&out->s64_field, &in->s64_field))
+ return 1;
+
+ return 0;
+}
+
--
2.17.1
^ permalink raw reply related
* [PATCH v3 bpf-next 10/12] selftests/bpf: add CO-RE relocs ptr-as-array tests
From: Andrii Nakryiko @ 2019-08-01 6:48 UTC (permalink / raw)
To: bpf, netdev, ast, daniel, yhs, songliubraving
Cc: andrii.nakryiko, kernel-team, Andrii Nakryiko
In-Reply-To: <20190801064803.2519675-1-andriin@fb.com>
Add test validating correct relocation handling for cases where pointer
to something is used as an array. E.g.:
int *ptr = ...;
int x = ptr[42];
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Acked-by: Song Liu <songliubraving@fb.com>
---
.../selftests/bpf/prog_tests/core_reloc.c | 20 +++++++++++++
.../bpf/progs/btf__core_reloc_ptr_as_arr.c | 3 ++
.../btf__core_reloc_ptr_as_arr___diff_sz.c | 3 ++
.../selftests/bpf/progs/core_reloc_types.h | 13 ++++++++
.../bpf/progs/test_core_reloc_ptr_as_arr.c | 30 +++++++++++++++++++
5 files changed, 69 insertions(+)
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_ptr_as_arr.c
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_ptr_as_arr___diff_sz.c
create mode 100644 tools/testing/selftests/bpf/progs/test_core_reloc_ptr_as_arr.c
diff --git a/tools/testing/selftests/bpf/prog_tests/core_reloc.c b/tools/testing/selftests/bpf/prog_tests/core_reloc.c
index adb8480d14dc..ad663978be15 100644
--- a/tools/testing/selftests/bpf/prog_tests/core_reloc.c
+++ b/tools/testing/selftests/bpf/prog_tests/core_reloc.c
@@ -129,6 +129,22 @@
.output_len = sizeof(struct core_reloc_mods_output), \
}
+#define PTR_AS_ARR_CASE(name) { \
+ .case_name = #name, \
+ .bpf_obj_file = "test_core_reloc_ptr_as_arr.o", \
+ .btf_src_file = "btf__core_reloc_" #name ".o", \
+ .input = (const char *)&(struct core_reloc_##name []){ \
+ { .a = 1 }, \
+ { .a = 2 }, \
+ { .a = 3 }, \
+ }, \
+ .input_len = 3 * sizeof(struct core_reloc_##name), \
+ .output = STRUCT_TO_CHAR_PTR(core_reloc_ptr_as_arr) { \
+ .a = 3, \
+ }, \
+ .output_len = sizeof(struct core_reloc_ptr_as_arr), \
+}
+
struct core_reloc_test_case {
const char *case_name;
const char *bpf_obj_file;
@@ -200,6 +216,10 @@ static struct core_reloc_test_case test_cases[] = {
MODS_CASE(mods),
MODS_CASE(mods___mod_swap),
MODS_CASE(mods___typedefs),
+
+ /* handling "ptr is an array" semantics */
+ PTR_AS_ARR_CASE(ptr_as_arr),
+ PTR_AS_ARR_CASE(ptr_as_arr___diff_sz),
};
struct data {
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_ptr_as_arr.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_ptr_as_arr.c
new file mode 100644
index 000000000000..8da52432ba17
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_ptr_as_arr.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_ptr_as_arr x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_ptr_as_arr___diff_sz.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_ptr_as_arr___diff_sz.c
new file mode 100644
index 000000000000..003acfc9a3e7
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_ptr_as_arr___diff_sz.c
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_ptr_as_arr___diff_sz x) {}
diff --git a/tools/testing/selftests/bpf/progs/core_reloc_types.h b/tools/testing/selftests/bpf/progs/core_reloc_types.h
index 3401e8342e57..c17c9279deae 100644
--- a/tools/testing/selftests/bpf/progs/core_reloc_types.h
+++ b/tools/testing/selftests/bpf/progs/core_reloc_types.h
@@ -526,3 +526,16 @@ struct core_reloc_mods___typedefs {
int3_t b;
int3_t a;
};
+
+/*
+ * PTR_AS_ARR
+ */
+struct core_reloc_ptr_as_arr {
+ int a;
+};
+
+struct core_reloc_ptr_as_arr___diff_sz {
+ int :32; /* padding */
+ char __some_more_padding;
+ int a;
+};
diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_ptr_as_arr.c b/tools/testing/selftests/bpf/progs/test_core_reloc_ptr_as_arr.c
new file mode 100644
index 000000000000..526b7ddc7ea1
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/test_core_reloc_ptr_as_arr.c
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2019 Facebook
+
+#include <linux/bpf.h>
+#include <stdint.h>
+#include "bpf_helpers.h"
+
+char _license[] SEC("license") = "GPL";
+
+static volatile struct data {
+ char in[256];
+ char out[256];
+} data;
+
+struct core_reloc_ptr_as_arr {
+ int a;
+};
+
+SEC("raw_tracepoint/sys_enter")
+int test_core_ptr_as_arr(void *ctx)
+{
+ struct core_reloc_ptr_as_arr *in = (void *)&data.in;
+ struct core_reloc_ptr_as_arr *out = (void *)&data.out;
+
+ if (BPF_CORE_READ(&out->a, &in[2].a))
+ return 1;
+
+ return 0;
+}
+
--
2.17.1
^ permalink raw reply related
* [PATCH v3 bpf-next 12/12] selftests/bpf: add CO-RE relocs misc tests
From: Andrii Nakryiko @ 2019-08-01 6:48 UTC (permalink / raw)
To: bpf, netdev, ast, daniel, yhs, songliubraving
Cc: andrii.nakryiko, kernel-team, Andrii Nakryiko
In-Reply-To: <20190801064803.2519675-1-andriin@fb.com>
Add tests validating few edge-cases of capturing offset relocations.
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
---
.../selftests/bpf/prog_tests/core_reloc.c | 19 ++++++
.../bpf/progs/btf__core_reloc_misc.c | 4 ++
.../selftests/bpf/progs/core_reloc_types.h | 25 ++++++++
.../bpf/progs/test_core_reloc_misc.c | 58 +++++++++++++++++++
4 files changed, 106 insertions(+)
create mode 100644 tools/testing/selftests/bpf/progs/btf__core_reloc_misc.c
create mode 100644 tools/testing/selftests/bpf/progs/test_core_reloc_misc.c
diff --git a/tools/testing/selftests/bpf/prog_tests/core_reloc.c b/tools/testing/selftests/bpf/prog_tests/core_reloc.c
index 46abb4df5b1c..a50ad439ea90 100644
--- a/tools/testing/selftests/bpf/prog_tests/core_reloc.c
+++ b/tools/testing/selftests/bpf/prog_tests/core_reloc.c
@@ -260,6 +260,25 @@ static struct core_reloc_test_case test_cases[] = {
INTS_ERR_CASE(ints___err_wrong_sz_16),
INTS_ERR_CASE(ints___err_wrong_sz_32),
INTS_ERR_CASE(ints___err_wrong_sz_64),
+
+ /* validate edge cases of capturing relocations */
+ {
+ .case_name = "misc",
+ .bpf_obj_file = "test_core_reloc_misc.o",
+ .btf_src_file = "btf__core_reloc_misc.o",
+ .input = (const char *)&(struct core_reloc_misc_extensible[]){
+ { .a = 1 },
+ { .a = 2 }, /* not read */
+ { .a = 3 },
+ },
+ .input_len = 4 * sizeof(int),
+ .output = STRUCT_TO_CHAR_PTR(core_reloc_misc_output) {
+ .a = 1,
+ .b = 1,
+ .c = 0, /* BUG in clang, should be 3 */
+ },
+ .output_len = sizeof(struct core_reloc_misc_output),
+ },
};
struct data {
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_misc.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_misc.c
new file mode 100644
index 000000000000..e379831d31a8
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btf__core_reloc_misc.c
@@ -0,0 +1,4 @@
+#include "core_reloc_types.h"
+
+void f1(struct core_reloc_misc___a x) {}
+void f2(struct core_reloc_misc___b x) {}
diff --git a/tools/testing/selftests/bpf/progs/core_reloc_types.h b/tools/testing/selftests/bpf/progs/core_reloc_types.h
index 5f3ebd4f6dc3..10a252b6da55 100644
--- a/tools/testing/selftests/bpf/progs/core_reloc_types.h
+++ b/tools/testing/selftests/bpf/progs/core_reloc_types.h
@@ -640,3 +640,28 @@ struct core_reloc_ints___err_wrong_sz_64 {
uint32_t u64_field; /* not 64-bit anymore */
int32_t s64_field; /* not 64-bit anymore */
};
+
+/*
+ * MISC
+ */
+struct core_reloc_misc_output {
+ int a, b, c;
+};
+
+struct core_reloc_misc___a {
+ int a1;
+ int a2;
+};
+
+struct core_reloc_misc___b {
+ int b1;
+ int b2;
+};
+
+/* this one extends core_reloc_misc_extensible struct from BPF prog */
+struct core_reloc_misc_extensible {
+ int a;
+ int b;
+ int c;
+ int d;
+};
diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_misc.c b/tools/testing/selftests/bpf/progs/test_core_reloc_misc.c
new file mode 100644
index 000000000000..bfd295f23d5f
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/test_core_reloc_misc.c
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2019 Facebook
+
+#include <linux/bpf.h>
+#include <stdint.h>
+#include "bpf_helpers.h"
+
+char _license[] SEC("license") = "GPL";
+
+static volatile struct data {
+ char in[256];
+ char out[256];
+} data;
+
+struct core_reloc_misc_output {
+ int a, b, c;
+};
+
+struct core_reloc_misc___a {
+ int a1;
+ int a2;
+};
+
+struct core_reloc_misc___b {
+ int b1;
+ int b2;
+};
+
+/* fixed two first members, can be extended with new fields */
+struct core_reloc_misc_extensible {
+ int a;
+ int b;
+};
+
+SEC("raw_tracepoint/sys_enter")
+int test_core_misc(void *ctx)
+{
+ struct core_reloc_misc___a *in_a = (void *)&data.in;
+ struct core_reloc_misc___b *in_b = (void *)&data.in;
+ struct core_reloc_misc_extensible *in_ext = (void *)&data.in;
+ struct core_reloc_misc_output *out = (void *)&data.out;
+
+ /* record two different relocations with the same accessor string */
+ if (BPF_CORE_READ(&out->a, &in_a->a1) || /* accessor: 0:0 */
+ BPF_CORE_READ(&out->b, &in_b->b1)) /* accessor: 0:0 */
+ return 1;
+
+ /* Validate relocations capture array-only accesses for structs with
+ * fixed header, but with potentially extendable tail. This will read
+ * first 4 bytes of 2nd element of in_ext array of potentially
+ * variably sized struct core_reloc_misc_extensible. */
+ /* BUG in Clang, isn't captured right now */
+ if (BPF_CORE_READ(&out->c, &in_ext[2])) /* accessor: 2 */
+ return 1;
+
+ return 0;
+}
+
--
2.17.1
^ permalink raw reply related
* Re: [Intel-wired-lan] [PATCH bpf-next v4 03/11] libbpf: add flags to umem config
From: Andrii Nakryiko @ 2019-08-01 6:59 UTC (permalink / raw)
To: Björn Töpel
Cc: Kevin Laatz, Netdev, Alexei Starovoitov, Daniel Borkmann,
Björn Töpel, Karlsson, Magnus, Jakub Kicinski,
Jonathan Lemon, Saeed Mahameed, Maxim Mikityanskiy,
Stephen Hemminger, Bruce Richardson, ciara.loftus,
intel-wired-lan, bpf
In-Reply-To: <CAJ+HfNifxfgycmZFz8eBZq=FZXAgNQezNqUiy3Q1z4JBrUEkew@mail.gmail.com>
On Wed, Jul 31, 2019 at 8:21 AM Björn Töpel <bjorn.topel@gmail.com> wrote:
>
> On Tue, 30 Jul 2019 at 19:43, Kevin Laatz <kevin.laatz@intel.com> wrote:
> >
> > This patch adds a 'flags' field to the umem_config and umem_reg structs.
> > This will allow for more options to be added for configuring umems.
> >
> > The first use for the flags field is to add a flag for unaligned chunks
> > mode. These flags can either be user-provided or filled with a default.
> >
> > Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
> > Signed-off-by: Ciara Loftus <ciara.loftus@intel.com>
> >
> > ---
> > v2:
> > - Removed the headroom check from this patch. It has moved to the
> > previous patch.
> >
> > v4:
> > - modified chunk flag define
> > ---
[...]
> > diff --git a/tools/lib/bpf/xsk.h b/tools/lib/bpf/xsk.h
> > index 833a6e60d065..44a03d8c34b9 100644
> > --- a/tools/lib/bpf/xsk.h
> > +++ b/tools/lib/bpf/xsk.h
> > @@ -170,12 +170,14 @@ LIBBPF_API int xsk_socket__fd(const struct xsk_socket *xsk);
> > #define XSK_UMEM__DEFAULT_FRAME_SHIFT 12 /* 4096 bytes */
> > #define XSK_UMEM__DEFAULT_FRAME_SIZE (1 << XSK_UMEM__DEFAULT_FRAME_SHIFT)
> > #define XSK_UMEM__DEFAULT_FRAME_HEADROOM 0
> > +#define XSK_UMEM__DEFAULT_FLAGS 0
> >
> > struct xsk_umem_config {
> > __u32 fill_size;
> > __u32 comp_size;
> > __u32 frame_size;
> > __u32 frame_headroom;
> > + __u32 flags;
>
> And the flags addition here, unfortunately, requires symbol versioning
> of xsk_umem__create(). That'll be the first in libbpf! :-)
xsk_umem_config is passed by pointer to xsk_umem__create(), so this
doesn't break ABI, does it?
>
>
> Björn
>
> > };
> >
> > /* Flags for the libbpf_flags field. */
> > --
> > 2.17.1
> >
> > _______________________________________________
> > Intel-wired-lan mailing list
> > Intel-wired-lan@osuosl.org
> > https://lists.osuosl.org/mailman/listinfo/intel-wired-lan
^ permalink raw reply
* Re: [PATCH -next] iwlwifi: dbg: work around clang bug by marking debug strings static
From: Johannes Berg @ 2019-08-01 7:11 UTC (permalink / raw)
To: Michael Ellerman, Nick Desaulniers, kvalo, Luca Coelho
Cc: Arnd Bergmann, Nathan Chancellor, Emmanuel Grumbach,
Intel Linux Wireless, David S. Miller, Shahar S Matityahu,
Sara Sharon, linux-wireless, netdev, linux-kernel,
clang-built-linux
In-Reply-To: <874l31r88y.fsf@concordia.ellerman.id.au>
> Luca, you said this was already fixed in your internal tree, and the fix
> would appear soon in next, but I don't see anything in linux-next?
Luca is still on vacation, but I just sent out a version of the patch we
had applied internally.
Also turns out it wasn't actually _fixed_, just _moved_, so those
internal patches wouldn't have helped anyway.
johannes
^ permalink raw reply
* Re: [PATCH net] mvpp2: fix panic on module removal
From: Antoine Tenart @ 2019-08-01 7:18 UTC (permalink / raw)
To: Matteo Croce
Cc: netdev, Miquel Raynal, linux-kernel, Lorenzo Bianconi,
Antoine Tenart, Maxime Chevallier, David S. Miller
In-Reply-To: <20190731183116.4791-1-mcroce@redhat.com>
Hi Matteo,
On Wed, Jul 31, 2019 at 08:31:16PM +0200, Matteo Croce wrote:
>
> diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
> index c51f1d5b550b..5002d51fc9d6 100644
> --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
> +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
> @@ -5760,7 +5760,6 @@ static int mvpp2_remove(struct platform_device *pdev)
> mvpp2_dbgfs_cleanup(priv);
>
> flush_workqueue(priv->stats_queue);
> - destroy_workqueue(priv->stats_queue);
>
> fwnode_for_each_available_child_node(fwnode, port_fwnode) {
> if (priv->port_list[i]) {
> @@ -5770,6 +5769,8 @@ static int mvpp2_remove(struct platform_device *pdev)
> i++;
> }
Shouldn't you also move flush_workqueue() here?
> + destroy_workqueue(priv->stats_queue);
> +
> for (i = 0; i < MVPP2_BM_POOLS_NUM; i++) {
> struct mvpp2_bm_pool *bm_pool = &priv->bm_pools[i];
Thanks!
Antoine
--
Antoine Ténart, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* [PATCH bpf] libbpf: set BTF FD for prog only when there is supported .BTF.ext data
From: Andrii Nakryiko @ 2019-08-01 7:24 UTC (permalink / raw)
To: bpf, netdev, ast, daniel, rdna
Cc: andrii.nakryiko, kernel-team, Andrii Nakryiko
5d01ab7bac46 ("libbpf: fix erroneous multi-closing of BTF FD")
introduced backwards-compatibility issue, manifesting itself as -E2BIG
error returned on program load due to unknown non-zero btf_fd attribute
value for BPF_PROG_LOAD sys_bpf() sub-command.
This patch fixes bug by ensuring that we only ever associate BTF FD with
program if there is a BTF.ext data that was successfully loaded into
kernel, which automatically means kernel supports func_info/line_info
and associated BTF FD for progs (checked and ensured also by BTF
sanitization code).
Fixes: 5d01ab7bac46 ("libbpf: fix erroneous multi-closing of BTF FD")
Reported-by: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
---
tools/lib/bpf/libbpf.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 2e84fa5b8479..2b57d7ea7836 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -2472,7 +2472,11 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
load_attr.license = license;
load_attr.kern_version = kern_version;
load_attr.prog_ifindex = prog->prog_ifindex;
- btf_fd = bpf_object__btf_fd(prog->obj);
+ /* if .BTF.ext was loaded, kernel supports associated BTF for prog */
+ if (prog->obj->btf_ext)
+ btf_fd = bpf_object__btf_fd(prog->obj);
+ else
+ btf_fd = -1;
load_attr.prog_btf_fd = btf_fd >= 0 ? btf_fd : 0;
load_attr.func_info = prog->func_info;
load_attr.func_info_rec_size = prog->func_info_rec_size;
--
2.17.1
^ permalink raw reply related
* [PATCH v1 0/2] add NPCM7xx EMC 10/100 Ethernet driver
From: Avi Fishman @ 2019-08-01 7:26 UTC (permalink / raw)
To: venture, yuenn, benjaminfair, davem, robh+dt, mark.rutland,
gregkh
Cc: avifishman70, tmaimon77, tali.perry1, openbmc, netdev, devicetree,
linux-kernel, tglx
EMC Ethernet Media Access Controller supports 10/100 Mbps and RMII.
This driver has been working on Nuvoton BMC NPCM7xx.
Avi Fishman (2):
dt-binding: net: document NPCM7xx EMC 10/100 DT bindings
net: npcm: add NPCM7xx EMC 10/100 Ethernet driver
.../bindings/net/nuvoton,npcm7xx-emc.txt | 38 +
drivers/net/ethernet/nuvoton/Kconfig | 21 +-
drivers/net/ethernet/nuvoton/Makefile | 2 +
drivers/net/ethernet/nuvoton/npcm7xx_emc.c | 2073 +++++++++++++++++
4 files changed, 2131 insertions(+), 3 deletions(-)
create mode 100644 Documentation/devicetree/bindings/net/nuvoton,npcm7xx-emc.txt
create mode 100644 drivers/net/ethernet/nuvoton/npcm7xx_emc.c
--
2.18.0
^ permalink raw reply
* [PATCH v1 1/2] dt-binding: net: document NPCM7xx EMC 10/100 DT bindings
From: Avi Fishman @ 2019-08-01 7:26 UTC (permalink / raw)
To: venture, yuenn, benjaminfair, davem, robh+dt, mark.rutland,
gregkh
Cc: avifishman70, tmaimon77, tali.perry1, openbmc, netdev, devicetree,
linux-kernel, tglx
In-Reply-To: <20190801072611.27935-1-avifishman70@gmail.com>
Added device tree binding documentation for
Nuvoton NPCM7xx Ethernet MAC Controller (EMC) 10/100 RMII
Signed-off-by: Avi Fishman <avifishman70@gmail.com>
---
.../bindings/net/nuvoton,npcm7xx-emc.txt | 38 +++++++++++++++++++
1 file changed, 38 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/nuvoton,npcm7xx-emc.txt
diff --git a/Documentation/devicetree/bindings/net/nuvoton,npcm7xx-emc.txt b/Documentation/devicetree/bindings/net/nuvoton,npcm7xx-emc.txt
new file mode 100644
index 000000000000..a7ac3ca66de9
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/nuvoton,npcm7xx-emc.txt
@@ -0,0 +1,38 @@
+Nuvoton NPCM7XX 10/100 Ethernet MAC Controller (EMC)
+
+The NPCM7XX provides one or two Ethernet MAC RMII Controllers
+for WAN/LAN applications
+
+Required properties:
+- device_type : Should be "network"
+- compatible : "nuvoton,npcm750-emc" for Poleg NPCM7XX.
+- reg : Offset and length of the register set for the device.
+- interrupts : Contain the emc interrupts with flags for falling edge.
+ first interrupt dedicated to Txirq
+ second interrupt dedicated to Rxirq
+- phy-mode : Should be "rmii" (see ethernet.txt in the same directory)
+- clocks : phandle of emc reference clock.
+- resets : phandle to the reset control for this device.
+- use-ncsi : Use the NC-SI stack instead of an MDIO PHY
+
+Example:
+
+emc0: eth@f0825000 {
+ device_type = "network";
+ compatible = "nuvoton,npcm750-emc";
+ reg = <0xf0825000 0x1000>;
+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+ phy-mode = "rmii";
+ clocks = <&clk NPCM7XX_CLK_AHB>;
+
+ #use-ncsi; /* add this to support ncsi */
+
+ clock-names = "clk_emc";
+ resets = <&rstc 6>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&r1_pins
+ &r1err_pins
+ &r1md_pins>;
+ status = "okay";
+};
--
2.18.0
^ permalink raw reply related
* [PATCH v1 2/2] net: npcm: add NPCM7xx EMC 10/100 Ethernet driver
From: Avi Fishman @ 2019-08-01 7:26 UTC (permalink / raw)
To: venture, yuenn, benjaminfair, davem, robh+dt, mark.rutland,
gregkh
Cc: avifishman70, tmaimon77, tali.perry1, openbmc, netdev, devicetree,
linux-kernel, tglx
In-Reply-To: <20190801072611.27935-1-avifishman70@gmail.com>
EMC Ethernet Media Access Controller supports 10/100 Mbps and
RMII.
This driver has been working on Nuvoton BMC NPCM7xx.
Signed-off-by: Avi Fishman <avifishman70@gmail.com>
---
drivers/net/ethernet/nuvoton/Kconfig | 21 +-
drivers/net/ethernet/nuvoton/Makefile | 2 +
drivers/net/ethernet/nuvoton/npcm7xx_emc.c | 2073 ++++++++++++++++++++
3 files changed, 2093 insertions(+), 3 deletions(-)
create mode 100644 drivers/net/ethernet/nuvoton/npcm7xx_emc.c
diff --git a/drivers/net/ethernet/nuvoton/Kconfig b/drivers/net/ethernet/nuvoton/Kconfig
index 325e26c549f8..3820dd3bc4b7 100644
--- a/drivers/net/ethernet/nuvoton/Kconfig
+++ b/drivers/net/ethernet/nuvoton/Kconfig
@@ -6,8 +6,8 @@
config NET_VENDOR_NUVOTON
bool "Nuvoton devices"
default y
- depends on ARM && ARCH_W90X900
- ---help---
+ depends on ARM && (ARCH_W90X900 || ARCH_NPCM7XX)
+ help
If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
@@ -22,8 +22,23 @@ config W90P910_ETH
depends on ARM && ARCH_W90X900
select PHYLIB
select MII
- ---help---
+ help
Say Y here if you want to use built-in Ethernet ports
on w90p910 processor.
+config NPCM7XX_EMC_ETH
+ bool "Nuvoton NPCM7XX Ethernet EMC"
+ depends on ARM && ARCH_NPCM7XX
+ select PHYLIB
+ select MII
+ help
+ Say Y here if you want to use built-in Ethernet MAC
+ on NPCM750 MCU.
+
+config NPCM7XX_EMC_ETH_DEBUG
+ bool "Nuvoton NPCM7XX Ethernet EMC debug"
+ depends on NPCM7XX_EMC_ETH
+ help
+ Say Y here if you want debug info via /proc/driver/npcm7xx_emc.x
+
endif # NET_VENDOR_NUVOTON
diff --git a/drivers/net/ethernet/nuvoton/Makefile b/drivers/net/ethernet/nuvoton/Makefile
index 66f6e728d54b..e32be694e987 100644
--- a/drivers/net/ethernet/nuvoton/Makefile
+++ b/drivers/net/ethernet/nuvoton/Makefile
@@ -3,4 +3,6 @@
# Makefile for the Nuvoton network device drivers.
#
+#Eternet 10/100 EMC
obj-$(CONFIG_W90P910_ETH) += w90p910_ether.o
+obj-$(CONFIG_NPCM7XX_EMC_ETH) += npcm7xx_emc.o
diff --git a/drivers/net/ethernet/nuvoton/npcm7xx_emc.c b/drivers/net/ethernet/nuvoton/npcm7xx_emc.c
new file mode 100644
index 000000000000..de56c7192b76
--- /dev/null
+++ b/drivers/net/ethernet/nuvoton/npcm7xx_emc.c
@@ -0,0 +1,2073 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2014-2019 Nuvoton Technology corporation.
+
+#ifdef CONFIG_NPCM7XX_EMC_ETH_DEBUG
+#define DEBUG
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ethtool.h>
+#include <linux/platform_device.h>
+#include <linux/gfp.h>
+#include <linux/kthread.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/ctype.h>
+#include <linux/debugfs.h>
+#include <linux/reset.h>
+
+#include <linux/clk.h>
+
+#include <linux/of.h>
+#include <linux/of_net.h>
+#include <linux/of_device.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#include <linux/if_ether.h>
+
+#include <net/ip.h>
+#include <net/ncsi.h>
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *npcm7xx_fs_dir;
+#endif
+
+#define MFSEL1_OFFSET 0x00C
+#define MFSEL3_OFFSET 0x064
+#define INTCR_OFFSET 0x03C
+
+#define IPSRST1_OFFSET 0x020
+
+#define DRV_MODULE_NAME "npcm7xx-emc"
+#define DRV_MODULE_VERSION "3.90"
+
+/* Ethernet MAC Registers */
+#define REG_CAMCMR 0x00
+#define REG_CAMEN 0x04
+#define REG_CAMM_BASE 0x08
+#define REG_CAML_BASE 0x0c
+#define REG_TXDLSA 0x88
+#define REG_RXDLSA 0x8C
+#define REG_MCMDR 0x90
+#define REG_MIID 0x94
+#define REG_MIIDA 0x98
+#define REG_FFTCR 0x9C
+#define REG_TSDR 0xa0
+#define REG_RSDR 0xa4
+#define REG_DMARFC 0xa8
+#define REG_MIEN 0xac
+#define REG_MISTA 0xb0
+#define REG_MGSTA 0xb4
+#define REG_MPCNT 0xb8
+#define REG_MRPC 0xbc
+#define REG_MRPCC 0xc0
+#define REG_MREPC 0xc4
+#define REG_DMARFS 0xc8
+#define REG_CTXDSA 0xcc
+#define REG_CTXBSA 0xd0
+#define REG_CRXDSA 0xd4
+#define REG_CRXBSA 0xd8
+
+/* EMC Diagnostic Registers */
+#define REG_RXFSM 0x200
+#define REG_TXFSM 0x204
+#define REG_FSM0 0x208
+#define REG_FSM1 0x20c
+#define REG_DCR 0x210
+#define REG_DMMIR 0x214
+#define REG_BISTR 0x300
+
+/* mac controller bit */
+#define MCMDR_RXON BIT(0)
+#define MCMDR_ALP BIT(1)
+#define MCMDR_ACP BIT(3)
+#define MCMDR_SPCRC BIT(5)
+#define MCMDR_TXON BIT(8)
+#define MCMDR_NDEF BIT(9)
+#define MCMDR_FDUP BIT(18)
+#define MCMDR_ENMDC BIT(19)
+#define MCMDR_OPMOD BIT(20)
+#define SWR BIT(24)
+
+/* cam command regiser */
+#define CAMCMR_AUP BIT(0)
+#define CAMCMR_AMP BIT(1)
+#define CAMCMR_ABP BIT(2)
+#define CAMCMR_CCAM BIT(3)
+#define CAMCMR_ECMP BIT(4)
+
+/* cam enable regiser */
+#define CAM0EN BIT(0)
+
+/* mac mii controller bit */
+#define PHYAD BIT(8)
+#define PHYWR BIT(16)
+#define PHYBUSY BIT(17)
+#define PHYPRESP BIT(18)
+#define MDCON BIT(19)
+#define CAM_ENTRY_SIZE 0x08
+
+/* rx and tx status */
+#define TXDS_TXCP BIT(19)
+#define RXDS_CRCE BIT(17)
+#define RXDS_PTLE BIT(19)
+#define RXDS_RXGD BIT(20)
+#define RXDS_ALIE BIT(21)
+#define RXDS_RP BIT(22)
+
+/* mac interrupt status*/
+#define MISTA_RXINTR BIT(0)
+#define MISTA_CRCE BIT(1)
+#define MISTA_RXOV BIT(2)
+#define MISTA_PTLE BIT(3)
+#define MISTA_RXGD BIT(4)
+#define MISTA_ALIE BIT(5)
+#define MISTA_RP BIT(6)
+#define MISTA_MMP BIT(7)
+#define MISTA_DFOI BIT(8)
+#define MISTA_DENI BIT(9)
+#define MISTA_RDU BIT(10)
+#define MISTA_RXBERR BIT(11)
+#define MISTA_CFR BIT(14)
+#define MISTA_TXINTR BIT(16)
+#define MISTA_TXEMP BIT(17)
+#define MISTA_TXCP BIT(18)
+#define MISTA_EXDEF BIT(19)
+#define MISTA_NCS BIT(20)
+#define MISTA_TXABT BIT(21)
+#define MISTA_LC BIT(22)
+#define MISTA_TDU BIT(23)
+#define MISTA_TXBERR BIT(24)
+
+/* Transmit/Receive Start Demand Register */
+#define ENSTART BIT(0)
+
+#define ENRXINTR BIT(0)
+#define ENCRCE BIT(1)
+#define EMRXOV BIT(2)
+#define ENPTLE BIT(3)
+#define ENRXGD BIT(4)
+#define ENALIE BIT(5)
+#define ENRP BIT(6)
+#define ENMMP BIT(7)
+#define ENDFO BIT(8)
+#define ENDENI BIT(9)
+#define ENRDU BIT(10)
+#define ENRXBERR BIT(11)
+#define ENCFR BIT(14)
+#define ENTXINTR BIT(16)
+#define ENTXEMP BIT(17)
+#define ENTXCP BIT(18)
+#define ENTXDEF BIT(19)
+#define ENNCS BIT(20)
+#define ENTXABT BIT(21)
+#define ENLC BIT(22)
+#define ENTDU BIT(23)
+#define ENTXBERR BIT(24)
+
+/* rx and tx owner bit */
+#define RX_OWN_DMA BIT(31)
+#define TX_OWN_DMA BIT(31)
+
+/* tx frame desc controller bit */
+#define MACTXINTEN BIT(2)
+#define CRCMODE BIT(1)
+#define PADDINGMODE BIT(0)
+
+/* fftcr controller bit */
+#define RXTHD (0x03 << 0)
+#define TXTHD (0x02 << 8)
+#define BLENGTH (0x02 << 20)
+
+/* global setting for driver */
+#define RX_QUEUE_LEN 128
+#define TX_QUEUE_LEN 64
+#define MAX_RBUFF_SZ 0x600
+#define MAX_TBUFF_SZ 0x600
+#define TX_TIMEOUT 50
+#define DELAY 1000
+#define CAM0 0x0
+#define RX_POLL_SIZE 16
+
+#ifdef CONFIG_VLAN_8021Q
+#define IS_VLAN 1
+#else
+#define IS_VLAN 0
+#endif
+
+#define MAX_PACKET_SIZE (1514 + (IS_VLAN * 4))
+#define MAX_PACKET_SIZE_W_CRC (MAX_PACKET_SIZE + 4) /* 1518 */
+
+#define MHZ (1000 * 1000)
+#define MII_TIMEOUT 100
+
+struct plat_npcm7xx_emc_data {
+ char *phy_bus_name;
+ int phy_addr;
+ unsigned char mac_addr[ETH_ALEN];
+};
+
+struct npcm7xx_rxbd {
+ __le32 sl;
+ __le32 buffer;
+ __le32 reserved;
+ __le32 next;
+};
+
+struct npcm7xx_txbd {
+ __le32 mode; /* Ownership bit and some other bits */
+ __le32 buffer; /* Transmit Buffer Starting Address */
+ __le32 sl; /* Transmit Byte Count and status bits */
+ __le32 next; /* Next Tx Descriptor Starting Address */
+};
+
+struct npcm7xx_ether {
+ struct sk_buff *rx_skb[RX_QUEUE_LEN];
+ struct sk_buff *tx_skb[TX_QUEUE_LEN];
+ spinlock_t lock; /* lock sk */
+ struct npcm7xx_rxbd *rdesc;
+ struct npcm7xx_txbd *tdesc;
+ dma_addr_t rdesc_phys;
+ dma_addr_t tdesc_phys;
+ struct net_device_stats stats;
+ struct platform_device *pdev;
+ struct net_device *netdev;
+ struct resource *res;
+ unsigned int msg_enable;
+ struct mii_bus *mii_bus;
+ struct phy_device *phy_dev;
+ struct napi_struct napi;
+ struct ncsi_dev *ncsidev;
+ bool use_ncsi;
+ void __iomem *reg;
+ int rxirq;
+ int txirq;
+ unsigned int cur_tx;
+ unsigned int cur_rx;
+ unsigned int finish_tx;
+ unsigned int pending_tx;
+ __le32 start_tx_ptr;
+ __le32 start_rx_ptr;
+ unsigned int rx_berr;
+ unsigned int rx_err;
+ unsigned int rdu;
+ unsigned int rxov;
+ __le32 camcmr;
+ unsigned int rx_stuck;
+ int link;
+ int speed;
+ int duplex;
+ int need_reset;
+ char *dump_buf;
+ struct reset_control *reset;
+
+ /* Scratch page to use when rx skb alloc fails */
+ void *rx_scratch;
+ dma_addr_t rx_scratch_dma;
+
+ /* debug counters */
+ unsigned int max_waiting_rx;
+ unsigned int rx_count_pool;
+ unsigned int count_xmit;
+ unsigned int rx_int_count;
+ unsigned int rx_err_count;
+ unsigned int tx_int_count;
+ unsigned int tx_tdu;
+ unsigned int tx_tdu_i;
+ unsigned int tx_cp_i;
+ unsigned int count_finish;
+
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *dbgfs_dir;
+ struct dentry *dbgfs_status;
+ struct dentry *dbgfs_dma_cap;
+#endif
+};
+
+#if defined CONFIG_NPCM7XX_EMC_ETH_DEBUG || defined CONFIG_DEBUG_FS
+#define REG_PRINT(reg_name) {t = scnprintf(next, size, "%-10s = %08X\n", \
+ #reg_name, readl(ether->reg + (reg_name))); size -= t; next += t; }
+#define DUMP_PRINT(f, x...) {t = scnprintf(next, size, f, ## x); size -= t; \
+ next += t; }
+
+static int npcm7xx_info_dump(char *buf, int count, struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ struct npcm7xx_txbd *txbd;
+ struct npcm7xx_rxbd *rxbd;
+ unsigned long flags;
+ unsigned int i, cur, txd_offset, rxd_offset;
+ char *next = buf;
+ unsigned int size = count;
+ int t;
+ int is_locked = spin_is_locked(ðer->lock);
+
+ if (!is_locked)
+ spin_lock_irqsave(ðer->lock, flags);
+
+ /* ------basic driver information ---- */
+ DUMP_PRINT("NPCM7XX EMC %s driver version: %s\n", netdev->name,
+ DRV_MODULE_VERSION);
+
+ REG_PRINT(REG_CAMCMR);
+ REG_PRINT(REG_CAMEN);
+ REG_PRINT(REG_CAMM_BASE);
+ REG_PRINT(REG_CAML_BASE);
+ REG_PRINT(REG_TXDLSA);
+ REG_PRINT(REG_RXDLSA);
+ REG_PRINT(REG_MCMDR);
+ REG_PRINT(REG_MIID);
+ REG_PRINT(REG_MIIDA);
+ REG_PRINT(REG_FFTCR);
+ REG_PRINT(REG_TSDR);
+ REG_PRINT(REG_RSDR);
+ REG_PRINT(REG_DMARFC);
+ REG_PRINT(REG_MIEN);
+ REG_PRINT(REG_MISTA);
+ REG_PRINT(REG_MGSTA);
+ REG_PRINT(REG_MPCNT);
+ writel(0x7FFF, (ether->reg + REG_MPCNT));
+ REG_PRINT(REG_MRPC);
+ REG_PRINT(REG_MRPCC);
+ REG_PRINT(REG_MREPC);
+ REG_PRINT(REG_DMARFS);
+ REG_PRINT(REG_CTXDSA);
+ REG_PRINT(REG_CTXBSA);
+ REG_PRINT(REG_CRXDSA);
+ REG_PRINT(REG_CRXBSA);
+ REG_PRINT(REG_RXFSM);
+ REG_PRINT(REG_TXFSM);
+ REG_PRINT(REG_FSM0);
+ REG_PRINT(REG_FSM1);
+ REG_PRINT(REG_DCR);
+ REG_PRINT(REG_DMMIR);
+ REG_PRINT(REG_BISTR);
+ DUMP_PRINT("\n");
+
+ DUMP_PRINT("netif_queue %s\n\n", netif_queue_stopped(netdev) ?
+ "Stopped" : "Running");
+ if (ether->rdesc)
+ DUMP_PRINT("napi is %s\n\n", test_bit(NAPI_STATE_SCHED,
+ ðer->napi.state) ?
+ "scheduled" :
+ "not scheduled");
+
+ txd_offset = (readl((ether->reg + REG_CTXDSA)) -
+ readl((ether->reg + REG_TXDLSA))) /
+ sizeof(struct npcm7xx_txbd);
+ DUMP_PRINT("TXD offset %6d\n", txd_offset);
+ DUMP_PRINT("cur_tx %6d\n", ether->cur_tx);
+ DUMP_PRINT("finish_tx %6d\n", ether->finish_tx);
+ DUMP_PRINT("pending_tx %6d\n", ether->pending_tx);
+ /* debug counters */
+ DUMP_PRINT("tx_tdu %6d\n", ether->tx_tdu);
+ ether->tx_tdu = 0;
+ DUMP_PRINT("tx_tdu_i %6d\n", ether->tx_tdu_i);
+ ether->tx_tdu_i = 0;
+ DUMP_PRINT("tx_cp_i %6d\n", ether->tx_cp_i);
+ ether->tx_cp_i = 0;
+ DUMP_PRINT("tx_int_count %6d\n", ether->tx_int_count);
+ ether->tx_int_count = 0;
+ DUMP_PRINT("count_xmit tx %6d\n", ether->count_xmit);
+ ether->count_xmit = 0;
+ DUMP_PRINT("count_finish %6d\n", ether->count_finish);
+ ether->count_finish = 0;
+ DUMP_PRINT("\n");
+
+ rxd_offset = (readl((ether->reg + REG_CRXDSA)) -
+ readl((ether->reg + REG_RXDLSA)))
+ / sizeof(struct npcm7xx_txbd);
+ DUMP_PRINT("RXD offset %6d\n", rxd_offset);
+ DUMP_PRINT("cur_rx %6d\n", ether->cur_rx);
+ DUMP_PRINT("rx_err %6d\n", ether->rx_err);
+ ether->rx_err = 0;
+ DUMP_PRINT("rx_berr %6d\n", ether->rx_berr);
+ ether->rx_berr = 0;
+ DUMP_PRINT("rx_stuck %6d\n", ether->rx_stuck);
+ ether->rx_stuck = 0;
+ DUMP_PRINT("rdu %6d\n", ether->rdu);
+ ether->rdu = 0;
+ DUMP_PRINT("rxov rx %6d\n", ether->rxov);
+ ether->rxov = 0;
+ /* debug counters */
+ DUMP_PRINT("rx_int_count %6d\n", ether->rx_int_count);
+ ether->rx_int_count = 0;
+ DUMP_PRINT("rx_err_count %6d\n", ether->rx_err_count);
+ ether->rx_err_count = 0;
+ DUMP_PRINT("rx_count_pool %6d\n", ether->rx_count_pool);
+ ether->rx_count_pool = 0;
+ DUMP_PRINT("max_waiting_rx %5d\n", ether->max_waiting_rx);
+ ether->max_waiting_rx = 0;
+ DUMP_PRINT("\n");
+ DUMP_PRINT("need_reset %5d\n", ether->need_reset);
+
+ if (ether->tdesc && ether->rdesc) {
+ cur = ether->finish_tx - 2;
+ for (i = 0; i < 3; i++) {
+ cur = (cur + 1) % TX_QUEUE_LEN;
+ txbd = (ether->tdesc + cur);
+ DUMP_PRINT("finish %3d txbd mode %08X buffer %08X sl %08X next %08X tx_skb %p\n",
+ cur, txbd->mode, txbd->buffer,
+ txbd->sl, txbd->next, ether->tx_skb[cur]);
+ }
+ DUMP_PRINT("\n");
+
+ cur = txd_offset - 2;
+ for (i = 0; i < 3; i++) {
+ cur = (cur + 1) % TX_QUEUE_LEN;
+ txbd = (ether->tdesc + cur);
+ DUMP_PRINT("txd_of %3d txbd mode %08X buffer %08X sl %08X next %08X\n",
+ cur, txbd->mode, txbd->buffer,
+ txbd->sl, txbd->next);
+ }
+ DUMP_PRINT("\n");
+
+ cur = ether->cur_tx - 63;
+ for (i = 0; i < 64; i++) {
+ cur = (cur + 1) % TX_QUEUE_LEN;
+ txbd = (ether->tdesc + cur);
+ DUMP_PRINT("cur_tx %3d txbd mode %08X buffer %08X sl %08X next %08X\n",
+ cur, txbd->mode, txbd->buffer,
+ txbd->sl, txbd->next);
+ }
+ DUMP_PRINT("\n");
+
+ cur = ether->cur_rx - 63;
+ for (i = 0; i < 64; i++) {
+ cur = (cur + 1) % RX_QUEUE_LEN;
+ rxbd = (ether->rdesc + cur);
+ DUMP_PRINT("cur_rx %3d rxbd sl %08X buffer %08X sl %08X next %08X\n",
+ cur, rxbd->sl, rxbd->buffer,
+ rxbd->reserved, rxbd->next);
+ }
+ DUMP_PRINT("\n");
+
+ cur = rxd_offset - 2;
+ for (i = 0; i < 3; i++) {
+ cur = (cur + 1) % RX_QUEUE_LEN;
+ rxbd = (ether->rdesc + cur);
+ DUMP_PRINT("rxd_of %3d rxbd sl %08X buffer %08X sl %08X next %08X\n",
+ cur, rxbd->sl, rxbd->buffer,
+ rxbd->reserved, rxbd->next);
+ }
+ DUMP_PRINT("\n");
+ }
+
+ if (!is_locked)
+ spin_unlock_irqrestore(ðer->lock, flags);
+
+ return count - size;
+}
+#endif
+
+#ifdef CONFIG_NPCM7XX_EMC_ETH_DEBUG
+static void npcm7xx_info_print(struct net_device *netdev)
+{
+ char *emc_dump_buf;
+ int count;
+ struct npcm7xx_ether *ether;
+ struct platform_device *pdev;
+ char c;
+ char *tmp_buf;
+ const size_t print_size = 5 * PAGE_SIZE;
+
+ ether = netdev_priv(netdev);
+ pdev = ether->pdev;
+
+ emc_dump_buf = kmalloc(print_size, GFP_KERNEL);
+ if (!emc_dump_buf)
+ return;
+
+ tmp_buf = emc_dump_buf;
+ count = npcm7xx_info_dump(emc_dump_buf, print_size, netdev);
+ while (count > 512) {
+ c = tmp_buf[512];
+ tmp_buf[512] = 0;
+ dev_info(&pdev->dev, "%s", tmp_buf);
+ tmp_buf += 512;
+ tmp_buf[0] = c;
+ count -= 512;
+
+ dev_info(&pdev->dev, "%s", tmp_buf);
+ kfree(emc_dump_buf);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/seq_file.h>
+
+static int npcm7xx_debug_show(struct seq_file *sf, void *v)
+{
+ struct net_device *netdev = (struct net_device *)sf->private;
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ const size_t print_size = 5 * PAGE_SIZE;
+
+ if (!ether->dump_buf) {
+ ether->dump_buf = kmalloc(print_size, GFP_KERNEL);
+ if (!ether->dump_buf)
+ return -1;
+ npcm7xx_info_dump(ether->dump_buf, print_size, netdev);
+ }
+
+ seq_printf(sf, "%s", ether->dump_buf);
+ if (sf->count < sf->size) {
+ kfree(ether->dump_buf);
+ ether->dump_buf = NULL;
+ }
+
+ return 0;
+}
+
+static int npcm7xx_debug_show_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, npcm7xx_debug_show, inode->i_private);
+}
+
+static const struct file_operations npcm7xx_debug_show_fops = {
+ .open = npcm7xx_debug_show_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int npcm7xx_debug_reset(struct seq_file *sf, void *v)
+{
+ struct net_device *netdev = (struct net_device *)sf->private;
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ unsigned long flags;
+
+ seq_puts(sf, "Ask to reset the module\n");
+ spin_lock_irqsave(ðer->lock, flags);
+ writel(0, (ether->reg + REG_MIEN));
+ spin_unlock_irqrestore(ðer->lock, flags);
+ ether->need_reset = 1;
+ napi_schedule(ðer->napi);
+
+ return 0;
+}
+
+static int npcm7xx_debug_reset_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, npcm7xx_debug_reset, inode->i_private);
+}
+
+static const struct file_operations npcm7xx_debug_reset_fops = {
+ .owner = THIS_MODULE,
+ .open = npcm7xx_debug_reset_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int npcm7xx_debug_fs(struct npcm7xx_ether *ether)
+{
+ /* Create debugfs main directory if it doesn't exist yet */
+ if (!npcm7xx_fs_dir) {
+ npcm7xx_fs_dir = debugfs_create_dir(DRV_MODULE_NAME, NULL);
+
+ if (!npcm7xx_fs_dir || IS_ERR(npcm7xx_fs_dir)) {
+ dev_err(ðer->pdev->dev,
+ "ERROR %s, debugfs create directory failed\n",
+ DRV_MODULE_NAME);
+ return -ENOMEM;
+ }
+ }
+
+ /* Create per netdev entries */
+ ether->dbgfs_dir = debugfs_create_dir(ether->netdev->name,
+ npcm7xx_fs_dir);
+ if (!ether->dbgfs_dir || IS_ERR(ether->dbgfs_dir)) {
+ dev_err(ðer->pdev->dev,
+ "ERROR failed to create %s directory\n",
+ ether->netdev->name);
+ return -ENOMEM;
+ }
+
+ /* Entry to report DMA RX/TX rings */
+ ether->dbgfs_status =
+ debugfs_create_file("status", 0444,
+ ether->dbgfs_dir, ether->netdev,
+ &npcm7xx_debug_show_fops);
+
+ if (!ether->dbgfs_status || IS_ERR(ether->dbgfs_status)) {
+ dev_err(ðer->pdev->dev,
+ "ERROR creating \'status\' debugfs file\n");
+ debugfs_remove_recursive(ether->dbgfs_dir);
+
+ return -ENOMEM;
+ }
+
+ /* Entry to report the DMA HW features */
+ ether->dbgfs_dma_cap = debugfs_create_file("do_reset", 0444,
+ ether->dbgfs_dir,
+ ether->netdev,
+ &npcm7xx_debug_reset_fops);
+
+ if (!ether->dbgfs_dma_cap || IS_ERR(ether->dbgfs_dma_cap)) {
+ dev_err(ðer->pdev->dev,
+ "ERROR creating stmmac \'do_reset\' debugfs file\n");
+ debugfs_remove_recursive(ether->dbgfs_dir);
+
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+#endif
+
+static void npcm7xx_opmode(struct net_device *netdev, int speed, int duplex)
+{
+ __le32 val;
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+
+ val = readl((ether->reg + REG_MCMDR));
+ if (speed == 100)
+ val |= MCMDR_OPMOD;
+ else
+ val &= ~MCMDR_OPMOD;
+
+ if (duplex == DUPLEX_FULL)
+ val |= MCMDR_FDUP;
+ else
+ val &= ~MCMDR_FDUP;
+
+ writel(val, (ether->reg + REG_MCMDR));
+}
+
+static void adjust_link(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ struct phy_device *phydev = ether->phy_dev;
+ bool status_change = false;
+
+ if (phydev->link) {
+ if (ether->speed != phydev->speed ||
+ ether->duplex != phydev->duplex) {
+ ether->speed = phydev->speed;
+ ether->duplex = phydev->duplex;
+ status_change = true;
+ }
+ } else {
+ ether->speed = 0;
+ ether->duplex = -1;
+ }
+
+ if (phydev->link != ether->link) {
+ ether->link = phydev->link;
+ status_change = true;
+ }
+
+ if (status_change)
+ npcm7xx_opmode(netdev, ether->speed, ether->duplex);
+}
+
+static void npcm7xx_write_cam(struct net_device *netdev,
+ unsigned int x, unsigned char *pval)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ __le32 msw, lsw;
+
+ msw = (pval[0] << 24) | (pval[1] << 16) | (pval[2] << 8) | pval[3];
+
+ lsw = (pval[4] << 24) | (pval[5] << 16);
+
+ writel(lsw, (ether->reg + REG_CAML_BASE) + x * CAM_ENTRY_SIZE);
+ writel(msw, (ether->reg + REG_CAMM_BASE) + x * CAM_ENTRY_SIZE);
+ dev_dbg(ðer->pdev->dev,
+ "REG_CAML_BASE = 0x%08X REG_CAMM_BASE = 0x%08X", lsw, msw);
+}
+
+static struct sk_buff *get_new_skb(struct net_device *netdev, u32 i)
+{
+ __le32 buffer;
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ struct sk_buff *skb = netdev_alloc_skb(netdev,
+ roundup(MAX_PACKET_SIZE_W_CRC, 4));
+
+ if (unlikely(!skb)) {
+ if (net_ratelimit())
+ netdev_warn(netdev, "failed to allocate rx skb\n");
+ buffer = ether->rx_scratch_dma;
+ } else {
+ /* Do not unmark the following skb_reserve() Receive Buffer
+ * Starting Address must be aligned to 4 bytes and the following
+ * line if unmarked will make it align to 2 and this likely will
+ * hult the RX and crash the linux
+ * skb_reserve(skb, NET_IP_ALIGN);
+ */
+ skb->dev = netdev;
+ buffer = dma_map_single(&netdev->dev,
+ skb->data,
+ roundup(MAX_PACKET_SIZE_W_CRC, 4),
+ DMA_FROM_DEVICE);
+ if (unlikely(dma_mapping_error(&netdev->dev, buffer))) {
+ if (net_ratelimit())
+ netdev_err(netdev, "failed to map rx page\n");
+ dev_kfree_skb_any(skb);
+ buffer = ether->rx_scratch_dma;
+ skb = NULL;
+ }
+ }
+ ether->rx_skb[i] = skb;
+ ether->rdesc[i].buffer = buffer;
+
+ return skb;
+}
+
+/* This API must call with Tx/Rx stopped */
+static void npcm7xx_free_desc(struct net_device *netdev,
+ bool free_also_descriptors)
+{
+ struct sk_buff *skb;
+ u32 i;
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ struct platform_device *pdev = ether->pdev;
+
+ for (i = 0; i < TX_QUEUE_LEN; i++) {
+ skb = ether->tx_skb[i];
+ if (skb) {
+ dma_unmap_single(&netdev->dev,
+ (dma_addr_t)(ether->tdesc[i].buffer),
+ skb->len, DMA_TO_DEVICE);
+ dev_kfree_skb_any(skb);
+ ether->tx_skb[i] = NULL;
+ }
+ }
+
+ for (i = 0; i < RX_QUEUE_LEN; i++) {
+ skb = ether->rx_skb[i];
+ if (skb) {
+ dma_unmap_single(&netdev->dev,
+ (dma_addr_t)(ether->rdesc[i].buffer),
+ roundup(MAX_PACKET_SIZE_W_CRC, 4),
+ DMA_FROM_DEVICE);
+ dev_kfree_skb_any(skb);
+ ether->rx_skb[i] = NULL;
+ }
+ }
+
+ if (free_also_descriptors) {
+ if (ether->tdesc)
+ dma_free_coherent(&pdev->dev,
+ sizeof(struct npcm7xx_txbd) *
+ TX_QUEUE_LEN,
+ ether->tdesc, ether->tdesc_phys);
+ ether->tdesc = NULL;
+
+ if (ether->rdesc)
+ dma_free_coherent(&pdev->dev,
+ sizeof(struct npcm7xx_rxbd) *
+ RX_QUEUE_LEN,
+ ether->rdesc, ether->rdesc_phys);
+ ether->rdesc = NULL;
+
+ /* Free scratch packet buffer */
+ if (ether->rx_scratch)
+ dma_free_coherent(&pdev->dev,
+ roundup(MAX_PACKET_SIZE_W_CRC, 4),
+ ether->rx_scratch,
+ ether->rx_scratch_dma);
+ ether->rx_scratch = NULL;
+ }
+}
+
+static int npcm7xx_init_desc(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether;
+ struct npcm7xx_txbd *tdesc;
+ struct npcm7xx_rxbd *rdesc;
+ struct platform_device *pdev;
+ unsigned int i;
+
+ ether = netdev_priv(netdev);
+ pdev = ether->pdev;
+
+ if (!ether->tdesc) {
+ ether->tdesc = (struct npcm7xx_txbd *)
+ dma_alloc_coherent(&pdev->dev,
+ sizeof(struct npcm7xx_txbd) *
+ TX_QUEUE_LEN,
+ ðer->tdesc_phys,
+ GFP_KERNEL);
+
+ if (!ether->tdesc) {
+ dev_err(&pdev->dev,
+ "Failed to allocate memory for tx desc\n");
+ npcm7xx_free_desc(netdev, true);
+ return -ENOMEM;
+ }
+ }
+
+ if (!ether->rdesc) {
+ ether->rdesc = (struct npcm7xx_rxbd *)
+ dma_alloc_coherent(&pdev->dev,
+ sizeof(struct npcm7xx_rxbd) *
+ RX_QUEUE_LEN,
+ ðer->rdesc_phys,
+ GFP_KERNEL);
+
+ if (!ether->rdesc) {
+ dev_err(&pdev->dev,
+ "Failed to allocate memory for rx desc\n");
+ npcm7xx_free_desc(netdev, true);
+ return -ENOMEM;
+ }
+ }
+
+ for (i = 0; i < TX_QUEUE_LEN; i++) {
+ unsigned int offset;
+
+ tdesc = (ether->tdesc + i);
+
+ if (i == TX_QUEUE_LEN - 1)
+ offset = 0;
+ else
+ offset = sizeof(struct npcm7xx_txbd) * (i + 1);
+
+ tdesc->next = ether->tdesc_phys + offset;
+ tdesc->buffer = (__le32)NULL;
+ tdesc->sl = 0;
+ tdesc->mode = 0;
+ }
+
+ ether->start_tx_ptr = ether->tdesc_phys;
+
+ /* Allocate scratch packet buffer */
+ if (!ether->rx_scratch) {
+ ether->rx_scratch =
+ dma_alloc_coherent(&pdev->dev,
+ roundup(MAX_PACKET_SIZE_W_CRC, 4),
+ ðer->rx_scratch_dma, GFP_KERNEL);
+ if (!ether->rx_scratch) {
+ dev_err(&pdev->dev,
+ "Failed to allocate memory for rx_scratch\n");
+ npcm7xx_free_desc(netdev, true);
+ return -ENOMEM;
+ }
+ }
+
+ for (i = 0; i < RX_QUEUE_LEN; i++) {
+ unsigned int offset;
+
+ rdesc = (ether->rdesc + i);
+
+ if (i == RX_QUEUE_LEN - 1)
+ offset = 0;
+ else
+ offset = sizeof(struct npcm7xx_rxbd) * (i + 1);
+
+ rdesc->next = ether->rdesc_phys + offset;
+ rdesc->sl = RX_OWN_DMA;
+
+ if (!get_new_skb(netdev, i)) {
+ dev_err(&pdev->dev, "get_new_skb() failed\n");
+ npcm7xx_free_desc(netdev, true);
+ return -ENOMEM;
+ }
+ }
+
+ ether->start_rx_ptr = ether->rdesc_phys;
+ for (i = 0; i < TX_QUEUE_LEN; i++)
+ ether->tx_skb[i] = NULL;
+
+ return 0;
+}
+
+static void npcm7xx_set_fifo_threshold(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ __le32 val;
+
+ val = RXTHD | TXTHD | BLENGTH;
+ writel(val, (ether->reg + REG_FFTCR));
+}
+
+static void npcm7xx_return_default_idle(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ __le32 val;
+ __le32 saved_bits;
+
+ val = readl((ether->reg + REG_MCMDR));
+ saved_bits = val & (MCMDR_FDUP | MCMDR_OPMOD);
+ val |= SWR;
+ writel(val, (ether->reg + REG_MCMDR));
+
+ /* During the EMC reset the AHB will read 0 from all registers,
+ * so in order to see if the reset finished we can't count on
+ * (ether->reg + REG_MCMDR).SWR to become 0, instead we read another
+ * register that its reset value is not 0,
+ * we choose (ether->reg + REG_FFTCR).
+ */
+ do {
+ val = readl((ether->reg + REG_FFTCR));
+ } while (val == 0);
+
+ /* Now we can verify if (ether->reg + REG_MCMDR).SWR became
+ * 0 (probably it will be 0 on the first read).
+ */
+ do {
+ val = readl((ether->reg + REG_MCMDR));
+ } while (val & SWR);
+
+ /* restore values */
+ writel(saved_bits, (ether->reg + REG_MCMDR));
+}
+
+static void npcm7xx_enable_mac_interrupt(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ __le32 val;
+
+ val = ENRXINTR | /* Start of RX interrupts */
+ ENCRCE |
+ EMRXOV |
+ (ENPTLE * !IS_VLAN) | /* If we don't support VLAN we want interrupt on long packets */
+ ENRXGD |
+ ENALIE |
+ ENRP |
+ ENMMP |
+ ENDFO |
+ /* ENDENI | */ /* We don't need interrupt on DMA Early Notification */
+ ENRDU | /* We don't need interrupt on Receive Descriptor Unavailable Interrupt */
+ ENRXBERR |
+ /* ENCFR | */
+ ENTXINTR | /* Start of TX interrupts */
+ ENTXEMP |
+ ENTXCP |
+ ENTXDEF |
+ ENNCS |
+ ENTXABT |
+ ENLC |
+ /* ENTDU | */ /* We don't need interrupt on Transmit Descriptor Unavailable at start of operation */
+ ENTXBERR;
+ writel(val, (ether->reg + REG_MIEN));
+}
+
+static void npcm7xx_get_and_clear_int(struct net_device *netdev,
+ __le32 *val, __le32 mask)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+
+ *val = readl((ether->reg + REG_MISTA)) & mask;
+ writel(*val, (ether->reg + REG_MISTA));
+}
+
+static void npcm7xx_set_global_maccmd(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ __le32 val;
+
+ val = readl((ether->reg + REG_MCMDR));
+
+ val |= MCMDR_SPCRC | MCMDR_ENMDC | MCMDR_ACP | MCMDR_NDEF;
+ if (IS_VLAN) {
+ /* we set ALP accept long packets since VLAN packets
+ * are 4 bytes longer than 1518
+ */
+ val |= MCMDR_ALP;
+ /* limit receive length to 1522 bytes due to VLAN */
+ writel(MAX_PACKET_SIZE_W_CRC, (ether->reg + REG_DMARFC));
+ }
+ writel(val, (ether->reg + REG_MCMDR));
+}
+
+static void npcm7xx_enable_cam(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ __le32 val;
+
+ npcm7xx_write_cam(netdev, CAM0, netdev->dev_addr);
+
+ val = readl((ether->reg + REG_CAMEN));
+ val |= CAM0EN;
+ writel(val, (ether->reg + REG_CAMEN));
+}
+
+static void npcm7xx_set_curdest(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+
+ writel(ether->start_rx_ptr, (ether->reg + REG_RXDLSA));
+ writel(ether->start_tx_ptr, (ether->reg + REG_TXDLSA));
+}
+
+static void npcm7xx_ether_set_rx_mode(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether;
+ __le32 rx_mode;
+
+ ether = netdev_priv(netdev);
+
+ dev_dbg(ðer->pdev->dev, "%s CAMCMR_AUP\n",
+ (netdev->flags & IFF_PROMISC) ? "Set" : "Clear");
+ if (netdev->flags & IFF_PROMISC)
+ rx_mode = CAMCMR_AUP | CAMCMR_AMP | CAMCMR_ABP | CAMCMR_ECMP;
+ else if ((netdev->flags & IFF_ALLMULTI) || !netdev_mc_empty(netdev))
+ rx_mode = CAMCMR_AMP | CAMCMR_ABP | CAMCMR_ECMP;
+ else
+ rx_mode = CAMCMR_ECMP | CAMCMR_ABP;
+ writel(rx_mode, (ether->reg + REG_CAMCMR));
+ ether->camcmr = rx_mode;
+}
+
+static void npcm7xx_reset_mac(struct net_device *netdev, int need_free)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+
+ netif_tx_lock(netdev);
+
+ /* disable RX and TX */
+ writel(readl((ether->reg + REG_MCMDR)) & ~(MCMDR_TXON | MCMDR_RXON),
+ (ether->reg + REG_MCMDR));
+
+ npcm7xx_return_default_idle(netdev);
+ npcm7xx_set_fifo_threshold(netdev);
+
+ if (need_free)
+ npcm7xx_free_desc(netdev, false);
+
+ npcm7xx_init_desc(netdev);
+
+ ether->cur_tx = 0x0;
+ ether->finish_tx = 0x0;
+ ether->pending_tx = 0x0;
+ ether->cur_rx = 0x0;
+ ether->tx_tdu = 0;
+ ether->tx_tdu_i = 0;
+ ether->tx_cp_i = 0;
+
+ npcm7xx_set_curdest(netdev);
+ npcm7xx_enable_cam(netdev);
+ npcm7xx_ether_set_rx_mode(netdev);
+ npcm7xx_enable_mac_interrupt(netdev);
+ npcm7xx_set_global_maccmd(netdev);
+
+ /* enable RX and TX */
+ writel(readl((ether->reg + REG_MCMDR)) | MCMDR_TXON | MCMDR_RXON,
+ (ether->reg + REG_MCMDR));
+
+ /* trigger RX */
+ writel(ENSTART, (ether->reg + REG_RSDR));
+
+ ether->need_reset = 0;
+
+ netif_wake_queue(netdev);
+ netif_tx_unlock(netdev);
+}
+
+static int npcm7xx_mdio_write(struct mii_bus *bus, int phy_id, int regnum,
+ u16 value)
+{
+ struct npcm7xx_ether *ether = bus->priv;
+ unsigned long timeout = jiffies + msecs_to_jiffies(MII_TIMEOUT * 100);
+
+ writel(value, (ether->reg + REG_MIID));
+ writel((phy_id << 0x08) | regnum | PHYBUSY | PHYWR,
+ (ether->reg + REG_MIIDA));
+
+ /* Wait for completion */
+ while (readl((ether->reg + REG_MIIDA)) & PHYBUSY) {
+ if (time_after(jiffies, timeout)) {
+ dev_dbg(ðer->pdev->dev,
+ "mdio read timed out\n ether->reg = 0x%x phy_id=0x%x REG_MIIDA=0x%x\n",
+ (unsigned int)ether->reg, phy_id,
+ readl((ether->reg + REG_MIIDA)));
+ return -ETIMEDOUT;
+ }
+ cpu_relax();
+ }
+
+ return 0;
+}
+
+static int npcm7xx_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
+{
+ struct npcm7xx_ether *ether = bus->priv;
+ unsigned long timeout = jiffies + msecs_to_jiffies(MII_TIMEOUT * 100);
+
+ writel((phy_id << 0x08) | regnum | PHYBUSY, (ether->reg + REG_MIIDA));
+
+ /* Wait for completion */
+ while (readl((ether->reg + REG_MIIDA)) & PHYBUSY) {
+ if (time_after(jiffies, timeout)) {
+ dev_dbg(ðer->pdev->dev,
+ "mdio read timed out\n ether->reg = 0x%x phy_id=0x%x REG_MIIDA=0x%x\n",
+ (unsigned int)ether->reg, phy_id
+ , readl((ether->reg + REG_MIIDA)));
+ return -ETIMEDOUT;
+ }
+ cpu_relax();
+ }
+
+ return readl((ether->reg + REG_MIID));
+}
+
+static int npcm7xx_mdio_reset(struct mii_bus *bus)
+{
+ /* reset EMAC engine?? */
+ return 0;
+}
+
+static int npcm7xx_set_mac_address(struct net_device *netdev, void *addr)
+{
+ struct sockaddr *address = addr;
+
+ if (!is_valid_ether_addr((u8 *)address->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(netdev->dev_addr, address->sa_data, netdev->addr_len);
+ npcm7xx_write_cam(netdev, CAM0, netdev->dev_addr);
+
+ return 0;
+}
+
+static int npcm7xx_ether_close(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+
+ npcm7xx_return_default_idle(netdev);
+
+ if (ether->phy_dev)
+ phy_stop(ether->phy_dev);
+ else if (ether->use_ncsi)
+ ncsi_stop_dev(ether->ncsidev);
+
+ msleep(20);
+
+ free_irq(ether->txirq, netdev);
+ free_irq(ether->rxirq, netdev);
+
+ netif_stop_queue(netdev);
+ napi_disable(ðer->napi);
+
+ npcm7xx_free_desc(netdev, true);
+
+ kfree(ether->dump_buf);
+ ether->dump_buf = NULL;
+
+ return 0;
+}
+
+static struct net_device_stats *npcm7xx_ether_stats(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether;
+
+ ether = netdev_priv(netdev);
+ return ðer->stats;
+}
+
+static int npcm7xx_clean_tx(struct net_device *netdev, bool from_xmit)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ struct npcm7xx_txbd *txbd;
+ struct sk_buff *s;
+ dma_addr_t cur_entry, entry;
+ __le32 sl;
+
+ if (ether->pending_tx == 0)
+ return (0);
+
+ cur_entry = readl((ether->reg + REG_CTXDSA));
+
+ /* Release old used buffers */
+ entry = ether->tdesc_phys + sizeof(struct npcm7xx_txbd) *
+ (ether->finish_tx);
+
+ while (entry != cur_entry) {
+ txbd = (ether->tdesc + ether->finish_tx);
+ s = ether->tx_skb[ether->finish_tx];
+ if (!s)
+ break;
+
+ ether->count_finish++;
+
+ dma_unmap_single(&netdev->dev, txbd->buffer, s->len,
+ DMA_TO_DEVICE);
+ consume_skb(s);
+ ether->tx_skb[ether->finish_tx] = NULL;
+
+ if (++ether->finish_tx >= TX_QUEUE_LEN)
+ ether->finish_tx = 0;
+ ether->pending_tx--;
+
+ sl = txbd->sl;
+ if (sl & TXDS_TXCP) {
+ ether->stats.tx_packets++;
+ ether->stats.tx_bytes += (sl & 0xFFFF);
+ } else {
+ ether->stats.tx_errors++;
+ }
+
+ entry = ether->tdesc_phys + sizeof(struct npcm7xx_txbd) *
+ (ether->finish_tx);
+ }
+
+ if (!from_xmit && unlikely(netif_queue_stopped(netdev) &&
+ (TX_QUEUE_LEN - ether->pending_tx) > 1)) {
+ netif_tx_lock(netdev);
+ if (netif_queue_stopped(netdev) &&
+ (TX_QUEUE_LEN - ether->pending_tx) > 1) {
+ netif_wake_queue(netdev);
+ }
+ netif_tx_unlock(netdev);
+ }
+
+ return(0);
+}
+
+static int npcm7xx_ether_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ struct npcm7xx_txbd *txbd;
+ unsigned long flags;
+
+ ether->count_xmit++;
+
+ /* Insert new buffer */
+ txbd = (ether->tdesc + ether->cur_tx);
+ txbd->buffer = dma_map_single(&netdev->dev, skb->data, skb->len,
+ DMA_TO_DEVICE);
+ ether->tx_skb[ether->cur_tx] = skb;
+ if (skb->len > MAX_PACKET_SIZE)
+ dev_err(ðer->pdev->dev,
+ "skb->len (= %d) > MAX_PACKET_SIZE (= %d)\n",
+ skb->len, MAX_PACKET_SIZE);
+
+ txbd->sl = skb->len > MAX_PACKET_SIZE ? MAX_PACKET_SIZE : skb->len;
+ dma_wmb();
+
+ txbd->mode = TX_OWN_DMA | PADDINGMODE | CRCMODE;
+
+ /* make sure that data is in memory before we trigger TX */
+ wmb();
+
+ /* trigger TX */
+ writel(ENSTART, (ether->reg + REG_TSDR));
+
+ if (++ether->cur_tx >= TX_QUEUE_LEN)
+ ether->cur_tx = 0;
+
+ spin_lock_irqsave(ðer->lock, flags);
+ ether->pending_tx++;
+
+ /* sometimes we miss the tx interrupt due to HW issue, so NAPI will not
+ * clean the pending tx, so we clean it also here
+ */
+ npcm7xx_clean_tx(netdev, true);
+
+ if (ether->pending_tx >= TX_QUEUE_LEN - 1) {
+ __le32 reg_mien;
+ unsigned int index_to_wake = ether->cur_tx +
+ ((TX_QUEUE_LEN * 3) / 4);
+
+ if (index_to_wake >= TX_QUEUE_LEN)
+ index_to_wake -= TX_QUEUE_LEN;
+
+ txbd = (ether->tdesc + index_to_wake);
+ txbd->mode = TX_OWN_DMA | PADDINGMODE | CRCMODE | MACTXINTEN;
+
+ /* make sure that data is in memory before we trigger TX */
+ wmb();
+
+ /* Clear TDU interrupt */
+ writel(MISTA_TDU, (ether->reg + REG_MISTA));
+
+ /* due to HW issue somtimes, we miss the TX interrupt we just
+ * set (MACTXINTEN), so we also set TDU for Transmit
+ * Descriptor Unavailable interrupt
+ */
+ reg_mien = readl((ether->reg + REG_MIEN));
+ if (reg_mien != 0)
+ /* Enable TDU interrupt */
+ writel(reg_mien | ENTDU, (ether->reg + REG_MIEN));
+
+ ether->tx_tdu++;
+ netif_stop_queue(netdev);
+ }
+
+ spin_unlock_irqrestore(ðer->lock, flags);
+
+ return 0;
+}
+
+static irqreturn_t npcm7xx_tx_interrupt(int irq, void *dev_id)
+{
+ struct npcm7xx_ether *ether;
+ struct platform_device *pdev;
+ struct net_device *netdev;
+ __le32 status;
+ unsigned long flags;
+
+ netdev = dev_id;
+ ether = netdev_priv(netdev);
+ pdev = ether->pdev;
+
+ npcm7xx_get_and_clear_int(netdev, &status, 0xFFFF0000);
+
+ ether->tx_int_count++;
+
+ if (status & MISTA_EXDEF)
+ dev_err(&pdev->dev, "emc defer exceed interrupt status=0x%08X\n"
+ , status);
+ else if (status & MISTA_TXBERR) {
+ dev_err(&pdev->dev, "emc bus error interrupt status=0x%08X\n",
+ status);
+#ifdef CONFIG_NPCM7XX_EMC_ETH_DEBUG
+ npcm7xx_info_print(netdev);
+#endif
+ spin_lock_irqsave(ðer->lock, flags);
+ writel(0, (ether->reg + REG_MIEN)); /* disable any interrupt */
+ spin_unlock_irqrestore(ðer->lock, flags);
+ ether->need_reset = 1;
+ } else if (status & ~(MISTA_TXINTR | MISTA_TXCP | MISTA_TDU))
+ dev_err(&pdev->dev, "emc other error interrupt status=0x%08X\n",
+ status);
+
+ /* if we got MISTA_TXCP | MISTA_TDU remove those interrupt and call napi */
+ if (status & (MISTA_TXCP | MISTA_TDU) &
+ readl((ether->reg + REG_MIEN))) {
+ __le32 reg_mien;
+
+ spin_lock_irqsave(ðer->lock, flags);
+ reg_mien = readl((ether->reg + REG_MIEN));
+ if (reg_mien & ENTDU)
+ /* Disable TDU interrupt */
+ writel(reg_mien & (~ENTDU), (ether->reg + REG_MIEN));
+
+ spin_unlock_irqrestore(ðer->lock, flags);
+
+ if (status & MISTA_TXCP)
+ ether->tx_cp_i++;
+ if (status & MISTA_TDU)
+ ether->tx_tdu_i++;
+ } else {
+ dev_dbg(&pdev->dev, "status=0x%08X\n", status);
+ }
+
+ napi_schedule(ðer->napi);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t npcm7xx_rx_interrupt(int irq, void *dev_id)
+{
+ struct net_device *netdev = (struct net_device *)dev_id;
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ struct platform_device *pdev = ether->pdev;
+ __le32 status;
+ unsigned long flags;
+ unsigned int any_err = 0;
+ __le32 rxfsm;
+
+ npcm7xx_get_and_clear_int(netdev, &status, 0xFFFF);
+ ether->rx_int_count++;
+
+ if (unlikely(status & MISTA_RXBERR)) {
+ ether->rx_berr++;
+ dev_err(&pdev->dev, "emc rx bus error status=0x%08X\n", status);
+#ifdef CONFIG_NPCM7XX_EMC_ETH_DEBUG
+ npcm7xx_info_print(netdev);
+#endif
+ spin_lock_irqsave(ðer->lock, flags);
+ writel(0, (ether->reg + REG_MIEN)); /* disable any interrupt */
+ spin_unlock_irqrestore(ðer->lock, flags);
+ ether->need_reset = 1;
+ napi_schedule(ðer->napi);
+ return IRQ_HANDLED;
+ }
+
+ if (unlikely(status & (MISTA_RXOV | MISTA_RDU))) {
+ /* filter out all received packets until we have
+ * enough available buffer descriptors
+ */
+ writel(0, (ether->reg + REG_CAMCMR));
+ any_err = 1;
+ if (status & (MISTA_RXOV))
+ ether->rxov++;
+ if (status & (MISTA_RDU))
+ ether->rdu++;
+
+ /* workaround Errata 1.36: EMC Hangs on receiving 253-256
+ * byte packet
+ */
+ rxfsm = readl((ether->reg + REG_RXFSM));
+
+ if ((rxfsm & 0xFFFFF000) == 0x08044000) {
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ rxfsm = readl((ether->reg + REG_RXFSM));
+ if ((rxfsm & 0xFFFFF000) != 0x08044000)
+ break;
+ }
+ if (i == 32) {
+ ether->rx_stuck++;
+ spin_lock_irqsave(ðer->lock, flags);
+#ifdef CONFIG_NPCM7XX_EMC_ETH_DEBUG
+ npcm7xx_info_print(netdev);
+#endif
+ writel(0, (ether->reg + REG_MIEN));
+ spin_unlock_irqrestore(ðer->lock, flags);
+ ether->need_reset = 1;
+ napi_schedule(ðer->napi);
+ dev_err(&pdev->dev,
+ "stuck on REG_RXFSM = 0x%08X status=%08X doing reset!\n",
+ rxfsm, status);
+ return IRQ_HANDLED;
+ }
+ }
+ }
+
+ /* echo MISTA status on unexpected flags although we don't do anithing
+ * with them
+ */
+ if (unlikely(status &
+ (/* MISTA_RXINTR | */ /* Receive - all RX interrupt set this */
+ MISTA_CRCE | /* CRC Error */
+ /* MISTA_RXOV | */ /* Receive FIFO Overflow - we alread handled it */
+ (!IS_VLAN * MISTA_PTLE) | /* Packet Too Long is needed if VLAN is not supported */
+ /* MISTA_RXGD | */ /* Receive Good - this is the common good case */
+ MISTA_ALIE | /* Alignment Error */
+ MISTA_RP | /* Runt Packet */
+ MISTA_MMP | /* More Missed Packet */
+ MISTA_DFOI | /* Maximum Frame Length */
+ /* MISTA_DENI | */ /* DMA Early Notification - every packet get this */
+ /* MISTA_RDU | */ /* Receive Descriptor Unavailable */
+ /* MISTA_RXBERR | */ /* Receive Bus Error Interrupt - we alread handled it */
+ /* MISTA_CFR | */ /* Control Frame Receive - not an error */
+ 0))) {
+ dev_dbg(&pdev->dev, "emc rx MISTA status=0x%08X\n", status);
+ any_err = 1;
+ ether->rx_err++;
+ }
+
+ if (!any_err && ((status & MISTA_RXGD) == 0))
+ dev_err(&pdev->dev, "emc rx MISTA status=0x%08X\n", status);
+
+ spin_lock_irqsave(ðer->lock, flags);
+ writel(readl((ether->reg + REG_MIEN)) & ~ENRXGD,
+ (ether->reg + REG_MIEN));
+ spin_unlock_irqrestore(ðer->lock, flags);
+ napi_schedule(ðer->napi);
+
+ return IRQ_HANDLED;
+}
+
+static int npcm7xx_poll(struct napi_struct *napi, int budget)
+{
+ struct npcm7xx_ether *ether =
+ container_of(napi, struct npcm7xx_ether, napi);
+ struct npcm7xx_rxbd *rxbd;
+ struct net_device *netdev = ether->netdev;
+ struct platform_device *pdev = ether->pdev;
+ struct sk_buff *s;
+ unsigned int length;
+ __le32 status;
+ unsigned long flags;
+ int rx_cnt = 0;
+ int complete = 0;
+ unsigned int rx_offset = (readl((ether->reg + REG_CRXDSA)) -
+ ether->start_rx_ptr) /
+ sizeof(struct npcm7xx_txbd);
+ unsigned int local_count = (rx_offset >= ether->cur_rx) ?
+ rx_offset - ether->cur_rx : rx_offset +
+ RX_QUEUE_LEN - ether->cur_rx;
+
+ if (local_count > ether->max_waiting_rx)
+ ether->max_waiting_rx = local_count;
+
+ if (local_count > (4 * RX_POLL_SIZE))
+ /* we are porbably in a storm of short packets and we don't
+ * want to get into RDU since short packets in RDU cause
+ * many RXOV which may cause EMC halt, so we filter out all
+ * coming packets
+ */
+ writel(0, (ether->reg + REG_CAMCMR));
+
+ if (local_count <= budget)
+ /* we can restore accepting of packets */
+ writel(ether->camcmr, (ether->reg + REG_CAMCMR));
+
+ spin_lock_irqsave(ðer->lock, flags);
+ npcm7xx_clean_tx(netdev, false);
+ spin_unlock_irqrestore(ðer->lock, flags);
+
+ rxbd = (ether->rdesc + ether->cur_rx);
+
+ while (rx_cnt < budget) {
+ status = rxbd->sl;
+ if ((status & RX_OWN_DMA) == RX_OWN_DMA) {
+ complete = 1;
+ break;
+ }
+ /* for debug puposes we save the previous value */
+ rxbd->reserved = status;
+ s = ether->rx_skb[ether->cur_rx];
+ length = status & 0xFFFF;
+
+ /* If VLAN is not supporte RXDS_PTLE (packet too long) is also
+ * an error
+ */
+ if (likely((status & (RXDS_RXGD | RXDS_CRCE | RXDS_ALIE |
+ RXDS_RP | (IS_VLAN ? 0 : RXDS_PTLE))) ==
+ RXDS_RXGD) && likely(length <= MAX_PACKET_SIZE)) {
+ dma_unmap_single(&netdev->dev, (dma_addr_t)rxbd->buffer,
+ roundup(MAX_PACKET_SIZE_W_CRC, 4),
+ DMA_FROM_DEVICE);
+
+ skb_put(s, length);
+ s->protocol = eth_type_trans(s, netdev);
+ netif_receive_skb(s);
+ ether->stats.rx_packets++;
+ ether->stats.rx_bytes += length;
+ rx_cnt++;
+ ether->rx_count_pool++;
+
+ /* now we allocate new skb instead if the used one. */
+ if (!get_new_skb(netdev, ether->cur_rx))
+ ether->stats.rx_dropped++;
+ } else {
+ ether->rx_err_count++;
+ ether->stats.rx_errors++;
+ dev_dbg(&pdev->dev, "rx_errors = %lu status = 0x%08X\n",
+ ether->stats.rx_errors, status);
+
+ if (status & RXDS_RP) {
+ ether->stats.rx_length_errors++;
+ dev_dbg(&pdev->dev, "rx_length_errors = %lu\n",
+ ether->stats.rx_length_errors);
+ } else if (status & RXDS_CRCE) {
+ ether->stats.rx_crc_errors++;
+ dev_dbg(&pdev->dev, "rx_crc_errors = %lu\n",
+ ether->stats.rx_crc_errors);
+ } else if (status & RXDS_ALIE) {
+ ether->stats.rx_frame_errors++;
+ dev_dbg(&pdev->dev, "rx_frame_errors = %lu\n",
+ ether->stats.rx_frame_errors);
+ } else if (((!IS_VLAN) && (status & RXDS_PTLE)) ||
+ length > MAX_PACKET_SIZE) {
+ ether->stats.rx_length_errors++;
+ dev_dbg(&pdev->dev, "rx_length_errors = %lu\n",
+ ether->stats.rx_length_errors);
+ }
+ }
+
+ /* make sure other values are set before we set owner */
+ wmb();
+
+ rxbd->sl = RX_OWN_DMA;
+ /* make sure that data is in memory before we trigger RX */
+ wmb();
+
+ if (++ether->cur_rx >= RX_QUEUE_LEN)
+ ether->cur_rx = 0;
+
+ rxbd = (ether->rdesc + ether->cur_rx);
+ }
+
+ if (complete) {
+ napi_complete(napi);
+
+ if (ether->need_reset) {
+ dev_dbg(&pdev->dev, "Reset\n");
+ npcm7xx_reset_mac(netdev, 1);
+ }
+
+ spin_lock_irqsave(ðer->lock, flags);
+ writel(readl((ether->reg + REG_MIEN)) | ENRXGD, (ether->reg +
+ REG_MIEN));
+ spin_unlock_irqrestore(ðer->lock, flags);
+ } else {
+ rx_offset = (readl((ether->reg + REG_CRXDSA)) -
+ ether->start_rx_ptr) / sizeof(struct npcm7xx_txbd);
+ local_count = (rx_offset >= ether->cur_rx) ? rx_offset -
+ ether->cur_rx : rx_offset + RX_QUEUE_LEN -
+ ether->cur_rx;
+
+ if (local_count > ether->max_waiting_rx)
+ ether->max_waiting_rx = local_count;
+
+ if (local_count > (3 * RX_POLL_SIZE))
+ /* we are porbably in a storm of short packets and
+ * we don't want to get into RDU since short packets in
+ * RDU cause many RXOV which may cause
+ * EMC halt, so we filter out all coming packets
+ */
+ writel(0, (ether->reg + REG_CAMCMR));
+ if (local_count <= RX_POLL_SIZE)
+ /* we can restore accepting of packets */
+ writel(ether->camcmr, (ether->reg + REG_CAMCMR));
+ }
+
+ /* trigger RX */
+ writel(ENSTART, (ether->reg + REG_RSDR));
+ return rx_cnt;
+}
+
+static int npcm7xx_ether_open(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether;
+ struct platform_device *pdev;
+
+ ether = netdev_priv(netdev);
+ pdev = ether->pdev;
+
+ if (ether->use_ncsi) {
+ ether->speed = 100;
+ ether->duplex = DUPLEX_FULL;
+ npcm7xx_opmode(netdev, 100, DUPLEX_FULL);
+ }
+ npcm7xx_reset_mac(netdev, 0);
+
+ if (request_irq(ether->txirq, npcm7xx_tx_interrupt, 0x0, pdev->name,
+ netdev)) {
+ dev_err(&pdev->dev, "register irq tx failed\n");
+ npcm7xx_ether_close(netdev);
+ return -EAGAIN;
+ }
+
+ if (request_irq(ether->rxirq, npcm7xx_rx_interrupt, 0x0, pdev->name,
+ netdev)) {
+ dev_err(&pdev->dev, "register irq rx failed\n");
+ npcm7xx_ether_close(netdev);
+ return -EAGAIN;
+ }
+
+ if (ether->phy_dev)
+ phy_start(ether->phy_dev);
+ else if (ether->use_ncsi)
+ netif_carrier_on(netdev);
+
+ netif_start_queue(netdev);
+ napi_enable(ðer->napi);
+
+ /* trigger RX */
+ writel(ENSTART, (ether->reg + REG_RSDR));
+
+ /* Start the NCSI device */
+ if (ether->use_ncsi) {
+ int err = ncsi_start_dev(ether->ncsidev);
+
+ if (err) {
+ npcm7xx_ether_close(netdev);
+ return err;
+ }
+ }
+
+ dev_info(&pdev->dev, "%s is OPENED\n", netdev->name);
+
+ return 0;
+}
+
+static int npcm7xx_ether_ioctl(struct net_device *netdev,
+ struct ifreq *ifr, int cmd)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ struct phy_device *phydev = ether->phy_dev;
+
+ if (!netif_running(netdev))
+ return -EINVAL;
+
+ if (!phydev)
+ return -ENODEV;
+
+ return phy_mii_ioctl(phydev, ifr, cmd);
+}
+
+static void npcm7xx_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *info)
+{
+ strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
+ strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
+ strlcpy(info->bus_info, "N/A", sizeof(info->bus_info));
+}
+
+static int npcm7xx_get_settings(struct net_device *netdev,
+ struct ethtool_link_ksettings *cmd)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ struct phy_device *phydev = ether->phy_dev;
+
+ if (!phydev)
+ return -ENODEV;
+
+ dev_info(ðer->pdev->dev, "\n\nnpcm7xx_get_settings\n");
+ phy_ethtool_ksettings_get(phydev, cmd);
+
+ return 0;
+}
+
+static int npcm7xx_set_settings(struct net_device *netdev,
+ const struct ethtool_link_ksettings *cmd)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ struct phy_device *phydev = ether->phy_dev;
+ int ret;
+
+ if (!phydev)
+ return -ENODEV;
+
+ dev_info(ðer->pdev->dev, "\n\nnpcm7xx_set_settings\n");
+ ret = phy_ethtool_ksettings_set(phydev, cmd);
+
+ return ret;
+}
+
+static u32 npcm7xx_get_msglevel(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+
+ return ether->msg_enable;
+}
+
+static void npcm7xx_set_msglevel(struct net_device *netdev, u32 level)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+
+ ether->msg_enable = level;
+}
+
+static const struct ethtool_ops npcm7xx_ether_ethtool_ops = {
+ .get_link_ksettings = npcm7xx_get_settings,
+ .set_link_ksettings = npcm7xx_set_settings,
+ .get_drvinfo = npcm7xx_get_drvinfo,
+ .get_msglevel = npcm7xx_get_msglevel,
+ .set_msglevel = npcm7xx_set_msglevel,
+ .get_link = ethtool_op_get_link,
+};
+
+static const struct net_device_ops npcm7xx_ether_netdev_ops = {
+ .ndo_open = npcm7xx_ether_open,
+ .ndo_stop = npcm7xx_ether_close,
+ .ndo_start_xmit = npcm7xx_ether_start_xmit,
+ .ndo_get_stats = npcm7xx_ether_stats,
+ .ndo_set_rx_mode = npcm7xx_ether_set_rx_mode,
+ .ndo_set_mac_address = npcm7xx_set_mac_address,
+ .ndo_do_ioctl = npcm7xx_ether_ioctl,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_change_mtu = eth_change_mtu,
+};
+
+static void get_mac_address(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ struct platform_device *pdev = ether->pdev;
+ struct device_node *np = ether->pdev->dev.of_node;
+ const u8 *mac_address = NULL;
+
+ mac_address = of_get_mac_address(np);
+
+ if (mac_address != 0)
+ ether_addr_copy(netdev->dev_addr, mac_address);
+
+ if (is_valid_ether_addr(netdev->dev_addr)) {
+ dev_info(&pdev->dev, "%s: device MAC address : %pM\n",
+ pdev->name, netdev->dev_addr);
+ } else {
+ eth_hw_addr_random(netdev);
+ dev_info(&pdev->dev,
+ "%s: device MAC address (random generator) %pM\n",
+ netdev->name, netdev->dev_addr);
+ }
+}
+
+static int npcm7xx_mii_setup(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ struct platform_device *pdev;
+ struct phy_device *phydev = NULL;
+ int i, err = 0;
+
+ pdev = ether->pdev;
+
+ ether->mii_bus = mdiobus_alloc();
+ if (!ether->mii_bus) {
+ err = -ENOMEM;
+ dev_err(&pdev->dev, "mdiobus_alloc() failed\n");
+ goto out0;
+ }
+
+ ether->mii_bus->name = "npcm7xx_rmii";
+ ether->mii_bus->read = &npcm7xx_mdio_read;
+ ether->mii_bus->write = &npcm7xx_mdio_write;
+ ether->mii_bus->reset = &npcm7xx_mdio_reset;
+ snprintf(ether->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+ ether->pdev->name, ether->pdev->id);
+ dev_dbg(&pdev->dev, "%s ether->mii_bus->id=%s\n", __func__,
+ ether->mii_bus->id);
+ ether->mii_bus->priv = ether;
+ ether->mii_bus->parent = ðer->pdev->dev;
+
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ ether->mii_bus->irq[i] = PHY_POLL;
+
+ platform_set_drvdata(ether->pdev, ether->mii_bus);
+
+ /* Enable MDIO Clock */
+ writel(readl((ether->reg + REG_MCMDR)) | MCMDR_ENMDC,
+ (ether->reg + REG_MCMDR));
+
+ if (mdiobus_register(ether->mii_bus)) {
+ dev_err(&pdev->dev, "mdiobus_register() failed\n");
+ goto out2;
+ }
+
+ phydev = phy_find_first(ether->mii_bus);
+ if (!phydev) {
+ dev_err(&pdev->dev, "phy_find_first() failed\n");
+ goto out3;
+ }
+
+ dev_info(&pdev->dev, " name = %s ETH-Phy-Id = 0x%x\n",
+ phydev_name(phydev), phydev->phy_id);
+
+ phydev = phy_connect(netdev, phydev_name(phydev),
+ &adjust_link,
+ PHY_INTERFACE_MODE_RMII);
+
+ dev_info(&pdev->dev, " ETH-Phy-Id = 0x%x name = %s\n",
+ phydev->phy_id, phydev->drv->name);
+
+ if (IS_ERR(phydev)) {
+ err = PTR_ERR(phydev);
+ dev_err(&pdev->dev, "phy_connect() failed - %d\n", err);
+ goto out3;
+ }
+
+ phydev->supported &= PHY_BASIC_FEATURES;
+ phydev->advertising = phydev->supported;
+ ether->phy_dev = phydev;
+
+ return 0;
+
+out3:
+ mdiobus_unregister(ether->mii_bus);
+out2:
+ kfree(ether->mii_bus->irq);
+ mdiobus_free(ether->mii_bus);
+out0:
+
+ return err;
+}
+
+static const struct of_device_id emc_dt_id[] = {
+ { .compatible = "nuvoton,npcm750-emc", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, emc_dt_id);
+
+static void npcm7xx_ncsi_handler(struct ncsi_dev *nd)
+{
+ if (unlikely(nd->state != ncsi_dev_state_functional))
+ return;
+
+ netdev_info(nd->dev, "NCSI interface %s\n",
+ nd->link_up ? "up" : "down");
+}
+
+static int npcm7xx_ether_probe(struct platform_device *pdev)
+{
+ struct npcm7xx_ether *ether;
+ struct net_device *netdev;
+ int error;
+
+ struct clk *emc_clk = NULL;
+ struct device_node *np = pdev->dev.of_node;
+
+ pdev->id = of_alias_get_id(np, "ethernet");
+ if (pdev->id < 0)
+ pdev->id = 0;
+
+ emc_clk = devm_clk_get(&pdev->dev, NULL);
+
+ if (IS_ERR(emc_clk))
+ return PTR_ERR(emc_clk);
+
+ /* Enable Clock */
+ clk_prepare_enable(emc_clk);
+
+ error = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (error)
+ return -ENODEV;
+
+ netdev = alloc_etherdev(sizeof(struct npcm7xx_ether));
+ if (!netdev)
+ return -ENOMEM;
+
+ ether = netdev_priv(netdev);
+
+ ether->reset = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(ether->reset))
+ return PTR_ERR(ether->reset);
+
+ /* Reset EMC module */
+ reset_control_assert(ether->reset);
+ udelay(5);
+ reset_control_deassert(ether->reset);
+
+ ether->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!ether->res) {
+ dev_err(&pdev->dev, "failed to get I/O memory\n");
+ error = -ENXIO;
+ goto failed_free;
+ }
+
+ if (!request_mem_region(ether->res->start,
+ resource_size(ether->res), pdev->name)) {
+ dev_err(&pdev->dev, "failed to request I/O memory\n");
+ error = -EBUSY;
+ goto failed_free;
+ }
+
+ ether->reg = ioremap(ether->res->start, resource_size(ether->res));
+ dev_dbg(&pdev->dev, "%s ether->reg = 0x%x\n", __func__,
+ (unsigned int)ether->reg);
+
+ if (!ether->reg) {
+ dev_err(&pdev->dev, "failed to remap I/O memory\n");
+ error = -ENXIO;
+ goto failed_free_mem;
+ }
+
+ ether->txirq = platform_get_irq(pdev, 0);
+ if (ether->txirq < 0) {
+ dev_err(&pdev->dev, "failed to get ether tx irq\n");
+ error = -ENXIO;
+ goto failed_free_io;
+ }
+
+ ether->rxirq = platform_get_irq(pdev, 1);
+ if (ether->rxirq < 0) {
+ dev_err(&pdev->dev, "failed to get ether rx irq\n");
+ error = -ENXIO;
+ goto failed_free_io;
+ }
+
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+ platform_set_drvdata(pdev, netdev);
+ ether->netdev = netdev;
+
+ ether->pdev = pdev;
+ ether->msg_enable = NETIF_MSG_LINK;
+
+ netdev->netdev_ops = &npcm7xx_ether_netdev_ops;
+ netdev->ethtool_ops = &npcm7xx_ether_ethtool_ops;
+
+ netdev->tx_queue_len = TX_QUEUE_LEN;
+ netdev->dma = 0x0;
+ netdev->watchdog_timeo = TX_TIMEOUT;
+
+ get_mac_address(netdev);
+
+ ether->speed = 100;
+ ether->duplex = DUPLEX_FULL;
+
+ spin_lock_init(ðer->lock);
+
+ netif_napi_add(netdev, ðer->napi, npcm7xx_poll, RX_POLL_SIZE);
+
+ if (pdev->dev.of_node &&
+ of_get_property(pdev->dev.of_node, "use-ncsi", NULL)) {
+ if (!IS_ENABLED(CONFIG_NET_NCSI)) {
+ dev_err(&pdev->dev, "CONFIG_NET_NCSI not enabled\n");
+ error = -ENODEV;
+ goto failed_free_napi;
+ }
+ dev_info(&pdev->dev, "Using NCSI interface\n");
+ ether->use_ncsi = true;
+ ether->ncsidev = ncsi_register_dev(netdev,
+ npcm7xx_ncsi_handler);
+ if (!ether->ncsidev) {
+ error = -ENODEV;
+ goto failed_free_napi;
+ }
+ } else {
+ ether->use_ncsi = false;
+ error = npcm7xx_mii_setup(netdev);
+ if (error < 0) {
+ dev_err(&pdev->dev, "npcm7xx_mii_setup err\n");
+ goto failed_free_napi;
+ }
+ }
+
+ error = register_netdev(netdev);
+ if (error != 0) {
+ dev_err(&pdev->dev, "register_netdev() failed\n");
+ error = -ENODEV;
+ goto failed_free_napi;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ npcm7xx_debug_fs(ether);
+#endif
+
+ return 0;
+
+failed_free_napi:
+ netif_napi_del(ðer->napi);
+ platform_set_drvdata(pdev, NULL);
+failed_free_io:
+ iounmap(ether->reg);
+failed_free_mem:
+ release_mem_region(ether->res->start, resource_size(ether->res));
+failed_free:
+ free_netdev(netdev);
+
+ return error;
+}
+
+static int npcm7xx_ether_remove(struct platform_device *pdev)
+{
+ struct net_device *netdev = platform_get_drvdata(pdev);
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+
+#ifdef CONFIG_DEBUG_FS
+ debugfs_remove_recursive(ether->dbgfs_dir);
+#endif
+
+ unregister_netdev(netdev);
+
+ free_irq(ether->txirq, netdev);
+ free_irq(ether->rxirq, netdev);
+
+ if (ether->phy_dev)
+ phy_disconnect(ether->phy_dev);
+
+ mdiobus_unregister(ether->mii_bus);
+ kfree(ether->mii_bus->irq);
+ mdiobus_free(ether->mii_bus);
+
+ platform_set_drvdata(pdev, NULL);
+
+ free_netdev(netdev);
+ return 0;
+}
+
+static struct platform_driver npcm7xx_ether_driver = {
+ .probe = npcm7xx_ether_probe,
+ .remove = npcm7xx_ether_remove,
+ .driver = {
+ .name = DRV_MODULE_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(emc_dt_id),
+ },
+};
+
+module_platform_driver(npcm7xx_ether_driver);
+
+MODULE_AUTHOR("Nuvoton Technology Corp.");
+MODULE_DESCRIPTION("NPCM750 EMC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:npcm750-emc");
+MODULE_VERSION(DRV_MODULE_VERSION);
--
2.18.0
^ permalink raw reply related
* Re: [PATCH 00/14] ARM: move lpc32xx and dove to multiplatform
From: Arnd Bergmann @ 2019-08-01 7:33 UTC (permalink / raw)
To: Russell King - ARM Linux admin
Cc: soc, Linux ARM, Vladimir Zapolskiy, Sylvain Lemieux,
Gregory Clement, Linus Walleij, Jason Cooper, Andrew Lunn,
Sebastian Hesselbarth, David S. Miller, Greg Kroah-Hartman,
Alan Stern, Guenter Roeck, open list:GPIO SUBSYSTEM, Networking,
linux-serial, USB list, LINUXWATCHDOG
In-Reply-To: <20190731225303.GC1330@shell.armlinux.org.uk>
On Thu, Aug 1, 2019 at 12:53 AM Russell King - ARM Linux admin
<linux@armlinux.org.uk> wrote:
>
> On Wed, Jul 31, 2019 at 09:56:42PM +0200, Arnd Bergmann wrote:
> > For dove, the patches are basically what I had proposed back in
> > 2015 when all other ARMv6/ARMv7 machines became part of a single
> > kernel build. I don't know what the state is mach-dove support is,
> > compared to the DT based support in mach-mvebu for the same
> > hardware. If they are functionally the same, we could also just
> > remove mach-dove rather than applying my patches.
>
> Well, the good news is that I'm down to a small board support file
> for the Dove Cubox now - but the bad news is, that there's still a
> board support file necessary to support everything the Dove SoC has
> to offer.
>
> Even for a DT based Dove Cubox, I'm still using mach-dove, but it
> may be possible to drop most of mach-dove now. Without spending a
> lot of time digging through it, it's impossible to really know.
Ok, so we won't remove it then, but I'd like to merge my patches to
at least get away from the special case of requiring a separate kernel
image for it.
Can you try if applying patches 12 and 14 from my series causes
problems for you? (it may be easier to apply the entire set
or pull from [1] to avoid rebase conflicts).
Arnd
[1] kernel.org:/pub/scm/linux/kernel/git/arnd/playground.git mach-cleanup-5.4
^ permalink raw reply
* Re: [Intel-wired-lan] [PATCH bpf-next v4 03/11] libbpf: add flags to umem config
From: Björn Töpel @ 2019-08-01 7:34 UTC (permalink / raw)
To: Andrii Nakryiko
Cc: Kevin Laatz, Netdev, Alexei Starovoitov, Daniel Borkmann,
Björn Töpel, Karlsson, Magnus, Jakub Kicinski,
Jonathan Lemon, Saeed Mahameed, Maxim Mikityanskiy,
Stephen Hemminger, Bruce Richardson, ciara.loftus,
intel-wired-lan, bpf
In-Reply-To: <CAEf4BzbTbX-Teth+4-yiorO-oHp+JhGfW2e08iBoCsBA4JCbMQ@mail.gmail.com>
On Thu, 1 Aug 2019 at 08:59, Andrii Nakryiko <andrii.nakryiko@gmail.com> wrote:
>
> On Wed, Jul 31, 2019 at 8:21 AM Björn Töpel <bjorn.topel@gmail.com> wrote:
> >
> > On Tue, 30 Jul 2019 at 19:43, Kevin Laatz <kevin.laatz@intel.com> wrote:
> > >
> > > This patch adds a 'flags' field to the umem_config and umem_reg structs.
> > > This will allow for more options to be added for configuring umems.
> > >
> > > The first use for the flags field is to add a flag for unaligned chunks
> > > mode. These flags can either be user-provided or filled with a default.
> > >
> > > Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
> > > Signed-off-by: Ciara Loftus <ciara.loftus@intel.com>
> > >
> > > ---
> > > v2:
> > > - Removed the headroom check from this patch. It has moved to the
> > > previous patch.
> > >
> > > v4:
> > > - modified chunk flag define
> > > ---
>
> [...]
>
> > > diff --git a/tools/lib/bpf/xsk.h b/tools/lib/bpf/xsk.h
> > > index 833a6e60d065..44a03d8c34b9 100644
> > > --- a/tools/lib/bpf/xsk.h
> > > +++ b/tools/lib/bpf/xsk.h
> > > @@ -170,12 +170,14 @@ LIBBPF_API int xsk_socket__fd(const struct xsk_socket *xsk);
> > > #define XSK_UMEM__DEFAULT_FRAME_SHIFT 12 /* 4096 bytes */
> > > #define XSK_UMEM__DEFAULT_FRAME_SIZE (1 << XSK_UMEM__DEFAULT_FRAME_SHIFT)
> > > #define XSK_UMEM__DEFAULT_FRAME_HEADROOM 0
> > > +#define XSK_UMEM__DEFAULT_FLAGS 0
> > >
> > > struct xsk_umem_config {
> > > __u32 fill_size;
> > > __u32 comp_size;
> > > __u32 frame_size;
> > > __u32 frame_headroom;
> > > + __u32 flags;
> >
> > And the flags addition here, unfortunately, requires symbol versioning
> > of xsk_umem__create(). That'll be the first in libbpf! :-)
>
> xsk_umem_config is passed by pointer to xsk_umem__create(), so this
> doesn't break ABI, does it?
>
Old application, dynamically linked to new libbpf.so will crash,
right? Old application passes old version of xsk_umem_config, and new
library accesses (non-existing) flag struct member.
Björn
> >
> >
> > Björn
> >
> > > };
> > >
> > > /* Flags for the libbpf_flags field. */
> > > --
> > > 2.17.1
> > >
> > > _______________________________________________
> > > Intel-wired-lan mailing list
> > > Intel-wired-lan@osuosl.org
> > > https://lists.osuosl.org/mailman/listinfo/intel-wired-lan
^ permalink raw reply
* Re: next-20190723: bpf/seccomp - systemd/journald issue?
From: Sedat Dilek @ 2019-08-01 7:39 UTC (permalink / raw)
To: Yonghong Song, Josh Poimboeuf
Cc: Alexei Starovoitov, Daniel Borkmann, Martin Lau, Song Liu,
netdev@vger.kernel.org, bpf@vger.kernel.org, Clang-Built-Linux ML,
Kees Cook, Nick Desaulniers, Nathan Chancellor
In-Reply-To: <c2524c96-d71c-d7db-22ec-12da905dc180@fb.com>
Hi,
just want to let you know that I did a git bisect with Linux v5.3-rc2
(where the problem also exists) and the result (details see [1]):
e55a73251da335873a6e87d68fb17e5aabb8978e is the first bad commit
commit e55a73251da335873a6e87d68fb17e5aabb8978e
Author: Josh Poimboeuf <jpoimboe@redhat.com>
Date: Thu Jun 27 20:50:47 2019 -0500
bpf: Fix ORC unwinding in non-JIT BPF code
Objtool previously ignored ___bpf_prog_run() because it didn't understand
the jump table. This resulted in the ORC unwinder not being able to unwind
through non-JIT BPF code.
Now that objtool knows how to read jump tables, remove the whitelist and
annotate the jump table so objtool can recognize it.
Also add an additional "const" to the jump table definition to clarify that
the text pointers are constant. Otherwise GCC sets the section writable
flag and the assembler spits out warnings.
Fixes: d15d356887e7 ("perf/x86: Make perf callchains work without
CONFIG_FRAME_POINTER")
Reported-by: Song Liu <songliubraving@fb.com>
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Kairui Song <kasong@redhat.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lkml.kernel.org/r/881939122b88f32be4c374d248c09d7527a87e35.1561685471.git.jpoimboe@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
:040000 040000 4735e9d14fa416c1c361ec3923440a3d586a627d
31de80b85c7b0292e47a719ecb6b1a451de2f8ef M kernel
Maybe you want to look at this, too.
The object files are attached in [2].
Thanks,
- Sedat -
[0] https://github.com/ClangBuiltLinux/linux/issues/619
[1] https://github.com/ClangBuiltLinux/linux/issues/619#issuecomment-517152467
[2] https://github.com/ClangBuiltLinux/linux/issues/619#issuecomment-517159635
^ permalink raw reply
* Re: [PATCH] net/mlx5e: always initialize frag->last_in_page
From: Tariq Toukan @ 2019-08-01 7:46 UTC (permalink / raw)
To: Qian Cai, davem@davemloft.net
Cc: Saeed Mahameed, Tariq Toukan, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <1564599773-9474-1-git-send-email-cai@lca.pw>
On 7/31/2019 10:02 PM, Qian Cai wrote:
> The commit 069d11465a80 ("net/mlx5e: RX, Enhance legacy Receive Queue
> memory scheme") introduced an undefined behaviour below due to
> "frag->last_in_page" is only initialized in
> mlx5e_init_frags_partition() when,
>
> if (next_frag.offset + frag_info[f].frag_stride > PAGE_SIZE)
>
> or after bailed out the loop,
>
> for (i = 0; i < mlx5_wq_cyc_get_size(&rq->wqe.wq); i++)
>
> As the result, there could be some "frag" have uninitialized
> value of "last_in_page".
>
> Later, get_frag() obtains those "frag" and check "rag->last_in_page" in
> mlx5e_put_rx_frag() and triggers the error during boot. Fix it by always
> initializing "frag->last_in_page" to "false" in
> mlx5e_init_frags_partition().
>
> UBSAN: Undefined behaviour in
> drivers/net/ethernet/mellanox/mlx5/core/en_rx.c:325:12
> load of value 170 is not a valid value for type 'bool' (aka '_Bool')
> Call trace:
> dump_backtrace+0x0/0x264
> show_stack+0x20/0x2c
> dump_stack+0xb0/0x104
> __ubsan_handle_load_invalid_value+0x104/0x128
> mlx5e_handle_rx_cqe+0x8e8/0x12cc [mlx5_core]
> mlx5e_poll_rx_cq+0xca8/0x1a94 [mlx5_core]
> mlx5e_napi_poll+0x17c/0xa30 [mlx5_core]
> net_rx_action+0x248/0x940
> __do_softirq+0x350/0x7b8
> irq_exit+0x200/0x26c
> __handle_domain_irq+0xc8/0x128
> gic_handle_irq+0x138/0x228
> el1_irq+0xb8/0x140
> arch_cpu_idle+0x1a4/0x348
> do_idle+0x114/0x1b0
> cpu_startup_entry+0x24/0x28
> rest_init+0x1ac/0x1dc
> arch_call_rest_init+0x10/0x18
> start_kernel+0x4d4/0x57c
>
> Fixes: 069d11465a80 ("net/mlx5e: RX, Enhance legacy Receive Queue memory scheme")
> Signed-off-by: Qian Cai <cai@lca.pw>
> ---
> drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
> index 47eea6b3a1c3..96f5110a9b43 100644
> --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
> +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
> @@ -336,6 +336,7 @@ static void mlx5e_init_frags_partition(struct mlx5e_rq *rq)
>
> next_frag.di = &rq->wqe.di[0];
> next_frag.offset = 0;
> + next_frag.last_in_page = false;
> prev = NULL;
>
> for (i = 0; i < mlx5_wq_cyc_get_size(&rq->wqe.wq); i++) {
>
Thanks Qian.
Please zero-init the whole struct instead:
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 1f433a06e637..55f4f5cc1d8f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -312,11 +312,10 @@ static inline u64 mlx5e_get_mpwqe_offset(struct
mlx5e_rq *rq, u16 wqe_ix)
static void mlx5e_init_frags_partition(struct mlx5e_rq *rq)
{
- struct mlx5e_wqe_frag_info next_frag, *prev;
+ struct mlx5e_wqe_frag_info next_frag = {}, *prev;
int i;
next_frag.di = &rq->wqe.di[0];
- next_frag.offset = 0;
prev = NULL;
for (i = 0; i < mlx5_wq_cyc_get_size(&rq->wqe.wq); i++) {
Thanks,
Tariq
^ permalink raw reply related
* Re: [PATCH] can: flexcan: free error skb if enqueueing failed
From: Martin Hundebøll @ 2019-08-01 7:59 UTC (permalink / raw)
To: Wolfgang Grandegger, Marc Kleine-Budde, linux-can
Cc: David S . Miller, netdev, Sean Nyekjaer
In-Reply-To: <20190715185308.104333-1-martin@geanix.com>
On 15/07/2019 20.53, Martin Hundebøll wrote:
> If the call to can_rx_offload_queue_sorted() fails, the passed skb isn't
> consumed, so the caller must do so.
>
> Fixes: 30164759db1b ("can: flexcan: make use of rx-offload's irq_offload_fifo")
> Signed-off-by: Martin Hundebøll <martin@geanix.com>
Ping.
^ permalink raw reply
* Re: [PATCH V2 7/9] vhost: do not use RCU to synchronize MMU notifier with worker
From: Jason Wang @ 2019-08-01 8:06 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: kvm, virtualization, netdev, linux-kernel, linux-mm, jgg,
Paul E. McKenney
In-Reply-To: <20190731132438-mutt-send-email-mst@kernel.org>
On 2019/8/1 上午2:29, Michael S. Tsirkin wrote:
> On Wed, Jul 31, 2019 at 04:46:53AM -0400, Jason Wang wrote:
>> We used to use RCU to synchronize MMU notifier with worker. This leads
>> calling synchronize_rcu() in invalidate_range_start(). But on a busy
>> system, there would be many factors that may slow down the
>> synchronize_rcu() which makes it unsuitable to be called in MMU
>> notifier.
>>
>> A solution is SRCU but its overhead is obvious with the expensive full
>> memory barrier. Another choice is to use seqlock, but it doesn't
>> provide a synchronization method between readers and writers. The last
>> choice is to use vq mutex, but it need to deal with the worst case
>> that MMU notifier must be blocked and wait for the finish of swap in.
>>
>> So this patch switches use a counter to track whether or not the map
>> was used. The counter was increased when vq try to start or finish
>> uses the map. This means, when it was even, we're sure there's no
>> readers and MMU notifier is synchronized. When it was odd, it means
>> there's a reader we need to wait it to be even again then we are
>> synchronized. To avoid full memory barrier, store_release +
>> load_acquire on the counter is used.
>
> Unfortunately this needs a lot of review and testing, so this can't make
> rc2, and I don't think this is the kind of patch I can merge after rc3.
> Subtle memory barrier tricks like this can introduce new bugs while they
> are fixing old ones.
I admit the patch is tricky. Some questions:
- Do we must address the case of e.g swap in? If not, a simple
vhost_work_flush() instead of synchronize_rcu() may work.
- Having some hard thought, I think we can use seqlock, it looks
to me smp_wmb() is in write_segcount_begin() is sufficient, we don't
care vq->map read before smp_wmb(), and for the other we all have
good data devendency so smp_wmb() in the write_seqbegin_end() is
sufficient.
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index db2c81cb1e90..6d9501303258 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -363,39 +363,29 @@ static bool vhost_map_range_overlap(struct vhost_uaddr *uaddr,
static void inline vhost_vq_access_map_begin(struct vhost_virtqueue *vq)
{
- int ref = READ_ONCE(vq->ref);
-
- smp_store_release(&vq->ref, ref + 1);
- /* Make sure ref counter is visible before accessing the map */
- smp_load_acquire(&vq->ref);
+ write_seqcount_begin(&vq->seq);
}
static void inline vhost_vq_access_map_end(struct vhost_virtqueue *vq)
{
- int ref = READ_ONCE(vq->ref);
-
- /* Make sure vq access is done before increasing ref counter */
- smp_store_release(&vq->ref, ref + 1);
+ write_seqcount_end(&vq->seq);
}
static void inline vhost_vq_sync_access(struct vhost_virtqueue *vq)
{
- int ref;
+ unsigned int ret;
/* Make sure map change was done before checking ref counter */
smp_mb();
-
- ref = READ_ONCE(vq->ref);
- if (ref & 0x1) {
- /* When ref change, we are sure no reader can see
+ ret = raw_read_seqcount(&vq->seq);
+ if (ret & 0x1) {
+ /* When seq changes, we are sure no reader can see
* previous map */
- while (READ_ONCE(vq->ref) == ref) {
- set_current_state(TASK_RUNNING);
+ while (raw_read_seqcount(&vq->seq) == ret)
schedule();
- }
}
- /* Make sure ref counter was checked before any other
- * operations that was dene on map. */
+ /* Make sure seq was checked before any other operations that
+ * was dene on map. */
smp_mb();
}
@@ -691,7 +681,7 @@ void vhost_dev_init(struct vhost_dev *dev,
vq->indirect = NULL;
vq->heads = NULL;
vq->dev = dev;
- vq->ref = 0;
+ seqcount_init(&vq->seq);
mutex_init(&vq->mutex);
spin_lock_init(&vq->mmu_lock);
vhost_vq_reset(dev, vq);
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
index 3d10da0ae511..1a705e181a84 100644
--- a/drivers/vhost/vhost.h
+++ b/drivers/vhost/vhost.h
@@ -125,7 +125,7 @@ struct vhost_virtqueue {
*/
struct vhost_uaddr uaddrs[VHOST_NUM_ADDRS];
#endif
- int ref;
+ seqcount_t seq;
const struct vhost_umem_node *meta_iotlb[VHOST_NUM_ADDRS];
struct file *kick;
--
2.18.1
>
>
>
>
>
>>
>> Consider the read critical section is pretty small the synchronization
>> should be done very fast.
>>
>> Note the patch lead about 3% PPS dropping.
>
> Sorry what do you mean by this last sentence? This degrades performance
> compared to what?
Compare to without this patch.
>
>>
>> Reported-by: Michael S. Tsirkin <mst@redhat.com>
>> Fixes: 7f466032dc9e ("vhost: access vq metadata through kernel virtual address")
>> Signed-off-by: Jason Wang <jasowang@redhat.com>
>> ---
>> drivers/vhost/vhost.c | 145 ++++++++++++++++++++++++++----------------
>> drivers/vhost/vhost.h | 7 +-
>> 2 files changed, 94 insertions(+), 58 deletions(-)
>>
>> diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
>> index cfc11f9ed9c9..db2c81cb1e90 100644
>> --- a/drivers/vhost/vhost.c
>> +++ b/drivers/vhost/vhost.c
>> @@ -324,17 +324,16 @@ static void vhost_uninit_vq_maps(struct vhost_virtqueue *vq)
>>
>> spin_lock(&vq->mmu_lock);
>> for (i = 0; i < VHOST_NUM_ADDRS; i++) {
>> - map[i] = rcu_dereference_protected(vq->maps[i],
>> - lockdep_is_held(&vq->mmu_lock));
>> + map[i] = vq->maps[i];
>> if (map[i]) {
>> vhost_set_map_dirty(vq, map[i], i);
>> - rcu_assign_pointer(vq->maps[i], NULL);
>> + vq->maps[i] = NULL;
>> }
>> }
>> spin_unlock(&vq->mmu_lock);
>>
>> - /* No need for synchronize_rcu() or kfree_rcu() since we are
>> - * serialized with memory accessors (e.g vq mutex held).
>> + /* No need for synchronization since we are serialized with
>> + * memory accessors (e.g vq mutex held).
>> */
>>
>> for (i = 0; i < VHOST_NUM_ADDRS; i++)
>> @@ -362,6 +361,44 @@ static bool vhost_map_range_overlap(struct vhost_uaddr *uaddr,
>> return !(end < uaddr->uaddr || start > uaddr->uaddr - 1 + uaddr->size);
>> }
>>
>> +static void inline vhost_vq_access_map_begin(struct vhost_virtqueue *vq)
>> +{
>> + int ref = READ_ONCE(vq->ref);
>> +
>> + smp_store_release(&vq->ref, ref + 1);
>> + /* Make sure ref counter is visible before accessing the map */
>> + smp_load_acquire(&vq->ref);
>
> The map access is after this sequence, correct?
Yes.
>
> Just going by the rules in Documentation/memory-barriers.txt,
> I think that this pair will not order following accesses with ref store.
>
> Documentation/memory-barriers.txt says:
>
>
> + In addition, a RELEASE+ACQUIRE
> + pair is -not- guaranteed to act as a full memory barrier.
>
>
>
> The guarantee that is made is this:
> after
> an ACQUIRE on a given variable, all memory accesses preceding any prior
> RELEASE on that same variable are guaranteed to be visible.
Yes, but it's not clear about the order of ACQUIRE the same location
of previous RELEASE. And it only has a example like:
"
*A = a;
RELEASE M
ACQUIRE N
*B = b;
could occur as:
ACQUIRE N, STORE *B, STORE *A, RELEASE M
"
But it doesn't explain what happen when
*A = a
RELEASE M
ACQUIRE M
*B = b;
And tools/memory-model/Documentation said
"
First, when a lock-acquire reads from a lock-release, the LKMM
requires that every instruction po-before the lock-release must
execute before any instruction po-after the lock-acquire.
"
Is this a hint that I was correct?
>
>
> And if we also had the reverse rule we'd end up with a full barrier,
> won't we?
>
> Cc Paul in case I missed something here. And if I'm right,
> maybe we should call this out, adding
>
> "The opposite is not true: a prior RELEASE is not
> guaranteed to be visible before memory accesses following
> the subsequent ACQUIRE".
That kinds of violates the RELEASE?
"
This also acts as a one-way permeable barrier. It guarantees that all
memory operations before the RELEASE operation will appear to happen
before the RELEASE operation with respect to the other components of the
"
>
>
>
>> +}
>> +
>> +static void inline vhost_vq_access_map_end(struct vhost_virtqueue *vq)
>> +{
>> + int ref = READ_ONCE(vq->ref);
>> +
>> + /* Make sure vq access is done before increasing ref counter */
>> + smp_store_release(&vq->ref, ref + 1);
>> +}
>> +
>> +static void inline vhost_vq_sync_access(struct vhost_virtqueue *vq)
>> +{
>> + int ref;
>> +
>> + /* Make sure map change was done before checking ref counter */
>> + smp_mb();
>> +
>> + ref = READ_ONCE(vq->ref);
>> + if (ref & 0x1) {
>
> Please document the even/odd trick here too, not just in the commit log.
>
Ok.
>> + /* When ref change,
>
> changes
>
>> we are sure no reader can see
>> + * previous map */
>> + while (READ_ONCE(vq->ref) == ref) {
>
>
> what is the below line in aid of?
>
>> + set_current_state(TASK_RUNNING);
>> + schedule();
>
> if (need_resched())
> schedule();
>
> ?
Yes, better.
>
>> + }
>
> On an interruptible kernel, there's a risk here is that
> a task got preempted with an odd ref.
> So I suspect we'll have to disable preemption when we
> make ref odd.
I'm not sure I get, if the odd is not the original value we read,
we're sure it won't read the new map here I believe.
>
>
>> + }
>> + /* Make sure ref counter was checked before any other
>> + * operations that was dene on map. */
>
> was dene -> were done?
>
Yes.
>> + smp_mb();
>> +}
>> +
>> static void vhost_invalidate_vq_start(struct vhost_virtqueue *vq,
>> int index,
>> unsigned long start,
>> @@ -376,16 +413,15 @@ static void vhost_invalidate_vq_start(struct vhost_virtqueue *vq,
>> spin_lock(&vq->mmu_lock);
>> ++vq->invalidate_count;
>>
>> - map = rcu_dereference_protected(vq->maps[index],
>> - lockdep_is_held(&vq->mmu_lock));
>> + map = vq->maps[index];
>> if (map) {
>> vhost_set_map_dirty(vq, map, index);
>> - rcu_assign_pointer(vq->maps[index], NULL);
>> + vq->maps[index] = NULL;
>> }
>> spin_unlock(&vq->mmu_lock);
>>
>> if (map) {
>> - synchronize_rcu();
>> + vhost_vq_sync_access(vq);
>> vhost_map_unprefetch(map);
>> }
>> }
>> @@ -457,7 +493,7 @@ static void vhost_init_maps(struct vhost_dev *dev)
>> for (i = 0; i < dev->nvqs; ++i) {
>> vq = dev->vqs[i];
>> for (j = 0; j < VHOST_NUM_ADDRS; j++)
>> - RCU_INIT_POINTER(vq->maps[j], NULL);
>> + vq->maps[j] = NULL;
>> }
>> }
>> #endif
>> @@ -655,6 +691,7 @@ void vhost_dev_init(struct vhost_dev *dev,
>> vq->indirect = NULL;
>> vq->heads = NULL;
>> vq->dev = dev;
>> + vq->ref = 0;
>> mutex_init(&vq->mutex);
>> spin_lock_init(&vq->mmu_lock);
>> vhost_vq_reset(dev, vq);
>> @@ -921,7 +958,7 @@ static int vhost_map_prefetch(struct vhost_virtqueue *vq,
>> map->npages = npages;
>> map->pages = pages;
>>
>> - rcu_assign_pointer(vq->maps[index], map);
>> + vq->maps[index] = map;
>> /* No need for a synchronize_rcu(). This function should be
>> * called by dev->worker so we are serialized with all
>> * readers.
>> @@ -1216,18 +1253,18 @@ static inline int vhost_put_avail_event(struct vhost_virtqueue *vq)
>> struct vring_used *used;
>>
>> if (!vq->iotlb) {
>> - rcu_read_lock();
>> + vhost_vq_access_map_begin(vq);
>>
>> - map = rcu_dereference(vq->maps[VHOST_ADDR_USED]);
>> + map = vq->maps[VHOST_ADDR_USED];
>> if (likely(map)) {
>> used = map->addr;
>> *((__virtio16 *)&used->ring[vq->num]) =
>> cpu_to_vhost16(vq, vq->avail_idx);
>> - rcu_read_unlock();
>> + vhost_vq_access_map_end(vq);
>> return 0;
>> }
>>
>> - rcu_read_unlock();
>> + vhost_vq_access_map_end(vq);
>> }
>> #endif
>>
>> @@ -1245,18 +1282,18 @@ static inline int vhost_put_used(struct vhost_virtqueue *vq,
>> size_t size;
>>
>> if (!vq->iotlb) {
>> - rcu_read_lock();
>> + vhost_vq_access_map_begin(vq);
>>
>> - map = rcu_dereference(vq->maps[VHOST_ADDR_USED]);
>> + map = vq->maps[VHOST_ADDR_USED];
>> if (likely(map)) {
>> used = map->addr;
>> size = count * sizeof(*head);
>> memcpy(used->ring + idx, head, size);
>> - rcu_read_unlock();
>> + vhost_vq_access_map_end(vq);
>> return 0;
>> }
>>
>> - rcu_read_unlock();
>> + vhost_vq_access_map_end(vq);
>> }
>> #endif
>>
>> @@ -1272,17 +1309,17 @@ static inline int vhost_put_used_flags(struct vhost_virtqueue *vq)
>> struct vring_used *used;
>>
>> if (!vq->iotlb) {
>> - rcu_read_lock();
>> + vhost_vq_access_map_begin(vq);
>>
>> - map = rcu_dereference(vq->maps[VHOST_ADDR_USED]);
>> + map = vq->maps[VHOST_ADDR_USED];
>> if (likely(map)) {
>> used = map->addr;
>> used->flags = cpu_to_vhost16(vq, vq->used_flags);
>> - rcu_read_unlock();
>> + vhost_vq_access_map_end(vq);
>> return 0;
>> }
>>
>> - rcu_read_unlock();
>> + vhost_vq_access_map_end(vq);
>> }
>> #endif
>>
>> @@ -1298,17 +1335,17 @@ static inline int vhost_put_used_idx(struct vhost_virtqueue *vq)
>> struct vring_used *used;
>>
>> if (!vq->iotlb) {
>> - rcu_read_lock();
>> + vhost_vq_access_map_begin(vq);
>>
>> - map = rcu_dereference(vq->maps[VHOST_ADDR_USED]);
>> + map = vq->maps[VHOST_ADDR_USED];
>> if (likely(map)) {
>> used = map->addr;
>> used->idx = cpu_to_vhost16(vq, vq->last_used_idx);
>> - rcu_read_unlock();
>> + vhost_vq_access_map_end(vq);
>> return 0;
>> }
>>
>> - rcu_read_unlock();
>> + vhost_vq_access_map_end(vq);
>> }
>> #endif
>>
>> @@ -1362,17 +1399,17 @@ static inline int vhost_get_avail_idx(struct vhost_virtqueue *vq,
>> struct vring_avail *avail;
>>
>> if (!vq->iotlb) {
>> - rcu_read_lock();
>> + vhost_vq_access_map_begin(vq);
>>
>> - map = rcu_dereference(vq->maps[VHOST_ADDR_AVAIL]);
>> + map = vq->maps[VHOST_ADDR_AVAIL];
>> if (likely(map)) {
>> avail = map->addr;
>> *idx = avail->idx;
>> - rcu_read_unlock();
>> + vhost_vq_access_map_end(vq);
>> return 0;
>> }
>>
>> - rcu_read_unlock();
>> + vhost_vq_access_map_end(vq);
>> }
>> #endif
>>
>> @@ -1387,17 +1424,17 @@ static inline int vhost_get_avail_head(struct vhost_virtqueue *vq,
>> struct vring_avail *avail;
>>
>> if (!vq->iotlb) {
>> - rcu_read_lock();
>> + vhost_vq_access_map_begin(vq);
>>
>> - map = rcu_dereference(vq->maps[VHOST_ADDR_AVAIL]);
>> + map = vq->maps[VHOST_ADDR_AVAIL];
>> if (likely(map)) {
>> avail = map->addr;
>> *head = avail->ring[idx & (vq->num - 1)];
>> - rcu_read_unlock();
>> + vhost_vq_access_map_end(vq);
>> return 0;
>> }
>>
>> - rcu_read_unlock();
>> + vhost_vq_access_map_end(vq);
>> }
>> #endif
>>
>> @@ -1413,17 +1450,17 @@ static inline int vhost_get_avail_flags(struct vhost_virtqueue *vq,
>> struct vring_avail *avail;
>>
>> if (!vq->iotlb) {
>> - rcu_read_lock();
>> + vhost_vq_access_map_begin(vq);
>>
>> - map = rcu_dereference(vq->maps[VHOST_ADDR_AVAIL]);
>> + map = vq->maps[VHOST_ADDR_AVAIL];
>> if (likely(map)) {
>> avail = map->addr;
>> *flags = avail->flags;
>> - rcu_read_unlock();
>> + vhost_vq_access_map_end(vq);
>> return 0;
>> }
>>
>> - rcu_read_unlock();
>> + vhost_vq_access_map_end(vq);
>> }
>> #endif
>>
>> @@ -1438,15 +1475,15 @@ static inline int vhost_get_used_event(struct vhost_virtqueue *vq,
>> struct vring_avail *avail;
>>
>> if (!vq->iotlb) {
>> - rcu_read_lock();
>> - map = rcu_dereference(vq->maps[VHOST_ADDR_AVAIL]);
>> + vhost_vq_access_map_begin(vq);
>> + map = vq->maps[VHOST_ADDR_AVAIL];
>> if (likely(map)) {
>> avail = map->addr;
>> *event = (__virtio16)avail->ring[vq->num];
>> - rcu_read_unlock();
>> + vhost_vq_access_map_end(vq);
>> return 0;
>> }
>> - rcu_read_unlock();
>> + vhost_vq_access_map_end(vq);
>> }
>> #endif
>>
>> @@ -1461,17 +1498,17 @@ static inline int vhost_get_used_idx(struct vhost_virtqueue *vq,
>> struct vring_used *used;
>>
>> if (!vq->iotlb) {
>> - rcu_read_lock();
>> + vhost_vq_access_map_begin(vq);
>>
>> - map = rcu_dereference(vq->maps[VHOST_ADDR_USED]);
>> + map = vq->maps[VHOST_ADDR_USED];
>> if (likely(map)) {
>> used = map->addr;
>> *idx = used->idx;
>> - rcu_read_unlock();
>> + vhost_vq_access_map_end(vq);
>> return 0;
>> }
>>
>> - rcu_read_unlock();
>> + vhost_vq_access_map_end(vq);
>> }
>> #endif
>>
>> @@ -1486,17 +1523,17 @@ static inline int vhost_get_desc(struct vhost_virtqueue *vq,
>> struct vring_desc *d;
>>
>> if (!vq->iotlb) {
>> - rcu_read_lock();
>> + vhost_vq_access_map_begin(vq);
>>
>> - map = rcu_dereference(vq->maps[VHOST_ADDR_DESC]);
>> + map = vq->maps[VHOST_ADDR_DESC];
>> if (likely(map)) {
>> d = map->addr;
>> *desc = *(d + idx);
>> - rcu_read_unlock();
>> + vhost_vq_access_map_end(vq);
>> return 0;
>> }
>>
>> - rcu_read_unlock();
>> + vhost_vq_access_map_end(vq);
>> }
>> #endif
>>
>> @@ -1843,13 +1880,11 @@ static bool iotlb_access_ok(struct vhost_virtqueue *vq,
>> #if VHOST_ARCH_CAN_ACCEL_UACCESS
>> static void vhost_vq_map_prefetch(struct vhost_virtqueue *vq)
>> {
>> - struct vhost_map __rcu *map;
>> + struct vhost_map *map;
>> int i;
>>
>> for (i = 0; i < VHOST_NUM_ADDRS; i++) {
>> - rcu_read_lock();
>> - map = rcu_dereference(vq->maps[i]);
>> - rcu_read_unlock();
>> + map = vq->maps[i];
>> if (unlikely(!map))
>> vhost_map_prefetch(vq, i);
>> }
>> diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
>> index a9a2a93857d2..f9e9558a529d 100644
>> --- a/drivers/vhost/vhost.h
>> +++ b/drivers/vhost/vhost.h
>> @@ -115,16 +115,17 @@ struct vhost_virtqueue {
>> #if VHOST_ARCH_CAN_ACCEL_UACCESS
>> /* Read by memory accessors, modified by meta data
>> * prefetching, MMU notifier and vring ioctl().
>> - * Synchonrized through mmu_lock (writers) and RCU (writers
>> - * and readers).
>> + * Synchonrized through mmu_lock (writers) and ref counters,
>> + * see vhost_vq_access_map_begin()/vhost_vq_access_map_end().
>> */
>> - struct vhost_map __rcu *maps[VHOST_NUM_ADDRS];
>> + struct vhost_map *maps[VHOST_NUM_ADDRS];
>> /* Read by MMU notifier, modified by vring ioctl(),
>> * synchronized through MMU notifier
>> * registering/unregistering.
>> */
>> struct vhost_uaddr uaddrs[VHOST_NUM_ADDRS];
>> #endif
>> + int ref;
>
> Is it important that this is signed? If not I'd do unsigned here:
> even though kernel does compile with 2s complement sign overflow,
> it seems cleaner not to depend on that.
Not a must, let me fix.
Thanks
>
>> const struct vhost_umem_node *meta_iotlb[VHOST_NUM_ADDRS];
>>
>> struct file *kick;
>> --
>> 2.18.1
^ permalink raw reply related
* [v2,0/2] tools: bpftool: add net attach/detach command to attach XDP prog
From: Daniel T. Lee @ 2019-08-01 8:11 UTC (permalink / raw)
To: Daniel Borkmann, Alexei Starovoitov; +Cc: netdev
Currently, bpftool net only supports dumping progs attached on the
interface. To attach XDP prog on interface, user must use other tool
(eg. iproute2). By this patch, with `bpftool net attach/detach`, user
can attach/detach XDP prog on interface.
$ ./bpftool prog
...
208: xdp name xdp_prog1 tag ad822e38b629553f gpl
loaded_at 2019-07-28T18:03:11+0900 uid 0
...
$ ./bpftool net attach id 208 xdpdrv enp6s0np1
$ ./bpftool net
xdp:
enp6s0np1(5) driver id 208
...
$ ./bpftool net detach xdpdrv enp6s0np1
$ ./bpftool net
xdp:
...
While this patch only contains support for XDP, through `net
attach/detach`, bpftool can further support other prog attach types.
XDP attach/detach tested on Mellanox ConnectX-4 and Netronome Agilio.
---
Changes in v2:
- command 'load/unload' changed to 'attach/detach' for the consistency
Daniel T. Lee (2):
tools: bpftool: add net attach command to attach XDP on interface
tools: bpftool: add net detach command to detach XDP on interface
tools/bpf/bpftool/net.c | 160 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 159 insertions(+), 1 deletion(-)
--
2.20.1
^ permalink raw reply
* [v2,1/2] tools: bpftool: add net attach command to attach XDP on interface
From: Daniel T. Lee @ 2019-08-01 8:11 UTC (permalink / raw)
To: Daniel Borkmann, Alexei Starovoitov; +Cc: netdev
In-Reply-To: <20190801081133.13200-1-danieltimlee@gmail.com>
By this commit, using `bpftool net attach`, user can attach XDP prog on
interface. New type of enum 'net_attach_type' has been made, as stated at
cover-letter, the meaning of 'attach' is, prog will be attached on interface.
BPF prog will be attached through libbpf 'bpf_set_link_xdp_fd'.
Signed-off-by: Daniel T. Lee <danieltimlee@gmail.com>
---
Changes in v2:
- command 'load' changed to 'attach' for the consistency
- 'NET_ATTACH_TYPE_XDP_DRIVE' changed to 'NET_ATTACH_TYPE_XDP_DRIVER'
tools/bpf/bpftool/net.c | 107 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 106 insertions(+), 1 deletion(-)
diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
index 67e99c56bc88..f3b57660b303 100644
--- a/tools/bpf/bpftool/net.c
+++ b/tools/bpf/bpftool/net.c
@@ -55,6 +55,35 @@ struct bpf_attach_info {
__u32 flow_dissector_id;
};
+enum net_attach_type {
+ NET_ATTACH_TYPE_XDP,
+ NET_ATTACH_TYPE_XDP_GENERIC,
+ NET_ATTACH_TYPE_XDP_DRIVER,
+ NET_ATTACH_TYPE_XDP_OFFLOAD,
+ __MAX_NET_ATTACH_TYPE
+};
+
+static const char * const attach_type_strings[] = {
+ [NET_ATTACH_TYPE_XDP] = "xdp",
+ [NET_ATTACH_TYPE_XDP_GENERIC] = "xdpgeneric",
+ [NET_ATTACH_TYPE_XDP_DRIVER] = "xdpdrv",
+ [NET_ATTACH_TYPE_XDP_OFFLOAD] = "xdpoffload",
+ [__MAX_NET_ATTACH_TYPE] = NULL,
+};
+
+static enum net_attach_type parse_attach_type(const char *str)
+{
+ enum net_attach_type type;
+
+ for (type = 0; type < __MAX_NET_ATTACH_TYPE; type++) {
+ if (attach_type_strings[type] &&
+ is_prefix(str, attach_type_strings[type]))
+ return type;
+ }
+
+ return __MAX_NET_ATTACH_TYPE;
+}
+
static int dump_link_nlmsg(void *cookie, void *msg, struct nlattr **tb)
{
struct bpf_netdev_t *netinfo = cookie;
@@ -223,6 +252,77 @@ static int query_flow_dissector(struct bpf_attach_info *attach_info)
return 0;
}
+static int parse_attach_args(int argc, char **argv, int *progfd,
+ enum net_attach_type *attach_type, int *ifindex)
+{
+ if (!REQ_ARGS(3))
+ return -EINVAL;
+
+ *progfd = prog_parse_fd(&argc, &argv);
+ if (*progfd < 0)
+ return *progfd;
+
+ *attach_type = parse_attach_type(*argv);
+ if (*attach_type == __MAX_NET_ATTACH_TYPE) {
+ p_err("invalid net attach/detach type");
+ return -EINVAL;
+ }
+
+ NEXT_ARG();
+ if (!REQ_ARGS(1))
+ return -EINVAL;
+
+ *ifindex = if_nametoindex(*argv);
+ if (!*ifindex) {
+ p_err("Invalid ifname");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int do_attach_detach_xdp(int *progfd, enum net_attach_type *attach_type,
+ int *ifindex)
+{
+ __u32 flags;
+ int err;
+
+ flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
+ if (*attach_type == NET_ATTACH_TYPE_XDP_GENERIC)
+ flags |= XDP_FLAGS_SKB_MODE;
+ if (*attach_type == NET_ATTACH_TYPE_XDP_DRIVER)
+ flags |= XDP_FLAGS_DRV_MODE;
+ if (*attach_type == NET_ATTACH_TYPE_XDP_OFFLOAD)
+ flags |= XDP_FLAGS_HW_MODE;
+
+ err = bpf_set_link_xdp_fd(*ifindex, *progfd, flags);
+
+ return err;
+}
+
+static int do_attach(int argc, char **argv)
+{
+ enum net_attach_type attach_type;
+ int err, progfd, ifindex;
+
+ err = parse_attach_args(argc, argv, &progfd, &attach_type, &ifindex);
+ if (err)
+ return err;
+
+ if (is_prefix("xdp", attach_type_strings[attach_type]))
+ err = do_attach_detach_xdp(&progfd, &attach_type, &ifindex);
+
+ if (err < 0) {
+ p_err("link set %s failed", attach_type_strings[attach_type]);
+ return -1;
+ }
+
+ if (json_output)
+ jsonw_null(json_wtr);
+
+ return 0;
+}
+
static int do_show(int argc, char **argv)
{
struct bpf_attach_info attach_info = {};
@@ -305,13 +405,17 @@ static int do_help(int argc, char **argv)
fprintf(stderr,
"Usage: %s %s { show | list } [dev <devname>]\n"
+ " %s %s attach PROG LOAD_TYPE <devname>\n"
" %s %s help\n"
+ "\n"
+ " " HELP_SPEC_PROGRAM "\n"
+ " LOAD_TYPE := { xdp | xdpgeneric | xdpdrv | xdpoffload }\n"
"Note: Only xdp and tc attachments are supported now.\n"
" For progs attached to cgroups, use \"bpftool cgroup\"\n"
" to dump program attachments. For program types\n"
" sk_{filter,skb,msg,reuseport} and lwt/seg6, please\n"
" consult iproute2.\n",
- bin_name, argv[-2], bin_name, argv[-2]);
+ bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]);
return 0;
}
@@ -319,6 +423,7 @@ static int do_help(int argc, char **argv)
static const struct cmd cmds[] = {
{ "show", do_show },
{ "list", do_show },
+ { "attach", do_attach },
{ "help", do_help },
{ 0 }
};
--
2.20.1
^ permalink raw reply related
* [v2,2/2] tools: bpftool: add net detach command to detach XDP on interface
From: Daniel T. Lee @ 2019-08-01 8:11 UTC (permalink / raw)
To: Daniel Borkmann, Alexei Starovoitov; +Cc: netdev
In-Reply-To: <20190801081133.13200-1-danieltimlee@gmail.com>
By this commit, using `bpftool net detach`, the attached XDP prog can
be detached. Detaching the BPF prog will be done through libbpf
'bpf_set_link_xdp_fd' with the progfd set to -1.
Signed-off-by: Daniel T. Lee <danieltimlee@gmail.com>
---
Changes in v2:
- command 'unload' changed to 'detach' for the consistency
tools/bpf/bpftool/net.c | 55 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 54 insertions(+), 1 deletion(-)
diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
index f3b57660b303..2ae9a613b05c 100644
--- a/tools/bpf/bpftool/net.c
+++ b/tools/bpf/bpftool/net.c
@@ -281,6 +281,31 @@ static int parse_attach_args(int argc, char **argv, int *progfd,
return 0;
}
+static int parse_detach_args(int argc, char **argv,
+ enum net_attach_type *attach_type, int *ifindex)
+{
+ if (!REQ_ARGS(2))
+ return -EINVAL;
+
+ *attach_type = parse_attach_type(*argv);
+ if (*attach_type == __MAX_NET_ATTACH_TYPE) {
+ p_err("invalid net attach/detach type");
+ return -EINVAL;
+ }
+
+ NEXT_ARG();
+ if (!REQ_ARGS(1))
+ return -EINVAL;
+
+ *ifindex = if_nametoindex(*argv);
+ if (!*ifindex) {
+ p_err("Invalid ifname");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int do_attach_detach_xdp(int *progfd, enum net_attach_type *attach_type,
int *ifindex)
{
@@ -323,6 +348,31 @@ static int do_attach(int argc, char **argv)
return 0;
}
+static int do_detach(int argc, char **argv)
+{
+ enum net_attach_type attach_type;
+ int err, progfd, ifindex;
+
+ err = parse_detach_args(argc, argv, &attach_type, &ifindex);
+ if (err)
+ return err;
+
+ /* to detach xdp prog */
+ progfd = -1;
+ if (is_prefix("xdp", attach_type_strings[attach_type]))
+ err = do_attach_detach_xdp(&progfd, &attach_type, &ifindex);
+
+ if (err < 0) {
+ p_err("link set %s failed", attach_type_strings[attach_type]);
+ return -1;
+ }
+
+ if (json_output)
+ jsonw_null(json_wtr);
+
+ return 0;
+}
+
static int do_show(int argc, char **argv)
{
struct bpf_attach_info attach_info = {};
@@ -406,6 +456,7 @@ static int do_help(int argc, char **argv)
fprintf(stderr,
"Usage: %s %s { show | list } [dev <devname>]\n"
" %s %s attach PROG LOAD_TYPE <devname>\n"
+ " %s %s detach LOAD_TYPE <devname>\n"
" %s %s help\n"
"\n"
" " HELP_SPEC_PROGRAM "\n"
@@ -415,7 +466,8 @@ static int do_help(int argc, char **argv)
" to dump program attachments. For program types\n"
" sk_{filter,skb,msg,reuseport} and lwt/seg6, please\n"
" consult iproute2.\n",
- bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]);
+ bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
+ bin_name, argv[-2]);
return 0;
}
@@ -424,6 +476,7 @@ static const struct cmd cmds[] = {
{ "show", do_show },
{ "list", do_show },
{ "attach", do_attach },
+ { "detach", do_detach },
{ "help", do_help },
{ 0 }
};
--
2.20.1
^ permalink raw reply related
* Re: [PATCH 03/12] block: bio_release_pages: use flags arg instead of bool
From: Christoph Hellwig @ 2019-08-01 8:20 UTC (permalink / raw)
To: Jerome Glisse
Cc: Christoph Hellwig, Christoph Hellwig, john.hubbard, Andrew Morton,
Alexander Viro, Anna Schumaker, David S . Miller,
Dominique Martinet, Eric Van Hensbergen, Jason Gunthorpe,
Jason Wang, Jens Axboe, Latchesar Ionkov, Michael S . Tsirkin,
Miklos Szeredi, Trond Myklebust, Matthew Wilcox, linux-mm, LKML,
ceph-devel, kvm, linux-block, linux-cifs, linux-fsdevel,
linux-nfs, linux-rdma, netdev, samba-technical, v9fs-developer,
virtualization, John Hubbard, Minwoo Im
In-Reply-To: <20190730155702.GB10366@redhat.com>
On Tue, Jul 30, 2019 at 11:57:02AM -0400, Jerome Glisse wrote:
> Other user can also add page that are not coming from GUP but need to
> have a reference see __blkdev_direct_IO()
Except for the zero page case I mentioned in my last mail explicitly,
and the KVEC/PIPE type iov vecs from the original mail what other
pages do you see to get added?
^ permalink raw reply
* [PATCH net] ipv4/route: do not check saddr dev if iif is LOOPBACK_IFINDEX
From: Hangbin Liu @ 2019-08-01 8:29 UTC (permalink / raw)
To: netdev
Cc: Stefano Brivio, Marcelo Ricardo Leitner, David Ahern,
David S . Miller, Hangbin Liu
Jianlin reported a bug that for IPv4, ip route get from src_addr would fail
if src_addr is not an address on local system.
\# ip route get 1.1.1.1 from 2.2.2.2
RTNETLINK answers: Invalid argument
While IPv6 would get the default route
\# ip -6 route get 1111::1 from 2222::2
1111::1 from 2222::2 via fe80:52:0:4982::1fe dev eth0 proto ra src \
2620::2cf:e2ff:fe40:37 metric 1024 hoplimit 64 pref medium
Fix it by disabling the __ip_dev_find() check if iif is LOOPBACK_IFINDEX.
Reported-by: Jianlin Shi <jishi@redhat.com>
Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
---
net/ipv4/route.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 517300d587a7..1be78e8f9e3c 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -2512,7 +2512,8 @@ struct rtable *ip_route_output_key_hash_rcu(struct net *net, struct flowi4 *fl4,
goto make_route;
}
- if (!(fl4->flowi4_flags & FLOWI_FLAG_ANYSRC)) {
+ if (!(fl4->flowi4_flags & FLOWI_FLAG_ANYSRC) &&
+ fl4->flowi4_iif != LOOPBACK_IFINDEX) {
/* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
if (!__ip_dev_find(net, fl4->saddr, false))
goto out;
--
2.19.2
^ permalink raw reply related
* [PATCH net] ibmveth: use net_err_ratelimited when set_multicast_list
From: Hangbin Liu @ 2019-08-01 9:03 UTC (permalink / raw)
To: netdev; +Cc: Thomas Falcon, David S . Miller, Hangbin Liu
When setting lots of multicast list on ibmveth, e.g. add 3000 membership on a
multicast group, the following error message flushes our log file
8507 [ 901.478251] ibmveth 30000003 env3: h_multicast_ctrl rc=4 when adding an entry to the filter table
...
1718386 [ 5636.808658] ibmveth 30000003 env3: h_multicast_ctrl rc=4 when adding an entry to the filter table
We got 1.5 million lines of messages in 1.3h. Let's replace netdev_err() by
net_err_ratelimited() to avoid this issue. I don't use netdev_err_once() in
case h_multicast_ctrl() return different lpar_rc types.
Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
---
drivers/net/ethernet/ibm/ibmveth.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index d654c234aaf7..3b9406a4ca92 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -1446,9 +1446,11 @@ static void ibmveth_set_multicast_list(struct net_device *netdev)
IbmVethMcastAddFilter,
mcast_addr);
if (lpar_rc != H_SUCCESS) {
- netdev_err(netdev, "h_multicast_ctrl rc=%ld "
- "when adding an entry to the filter "
- "table\n", lpar_rc);
+ net_err_ratelimited("%s %s%s: h_multicast_ctrl rc=%ld when adding an entry to the filter table\n",
+ ibmveth_driver_name,
+ netdev_name(netdev),
+ netdev_reg_state(netdev),
+ lpar_rc);
}
}
--
2.19.2
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox