* Re: [PATCH v2 net-next 4/4] bpftool: implement cgroup bpf operations
From: Quentin Monnet @ 2017-12-08 10:34 UTC (permalink / raw)
To: Roman Gushchin, netdev
Cc: linux-kernel, kernel-team, ast, daniel, jakub.kicinski, kafai,
David Ahern
In-Reply-To: <20171207183909.16240-5-guro@fb.com>
2017-12-07 18:39 UTC+0000 ~ Roman Gushchin <guro@fb.com>
> This patch adds basic cgroup bpf operations to bpftool:
> cgroup list, attach and detach commands.
>
> Usage is described in the corresponding man pages,
> and examples are provided.
>
> Syntax:
> $ bpftool cgroup list CGROUP
> $ bpftool cgroup attach CGROUP ATTACH_TYPE PROG [ATTACH_FLAGS]
> $ bpftool cgroup detach CGROUP ATTACH_TYPE PROG
>
> Signed-off-by: Roman Gushchin <guro@fb.com>
> Cc: Alexei Starovoitov <ast@kernel.org>
> Cc: Daniel Borkmann <daniel@iogearbox.net>
> Cc: Jakub Kicinski <jakub.kicinski@netronome.com>
> Cc: Martin KaFai Lau <kafai@fb.com>
> Cc: Quentin Monnet <quentin.monnet@netronome.com>
> Cc: David Ahern <dsahern@gmail.com>
> ---
> tools/bpf/bpftool/Documentation/bpftool-cgroup.rst | 92 +++++++
> tools/bpf/bpftool/Documentation/bpftool-map.rst | 2 +-
> tools/bpf/bpftool/Documentation/bpftool-prog.rst | 2 +-
> tools/bpf/bpftool/Documentation/bpftool.rst | 6 +-
> tools/bpf/bpftool/cgroup.c | 305 +++++++++++++++++++++
> tools/bpf/bpftool/main.c | 3 +-
> tools/bpf/bpftool/main.h | 1 +
> 7 files changed, 406 insertions(+), 5 deletions(-)
> create mode 100644 tools/bpf/bpftool/Documentation/bpftool-cgroup.rst
> create mode 100644 tools/bpf/bpftool/cgroup.c
>
> diff --git a/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst b/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst
> new file mode 100644
> index 000000000000..61ded613aee1
> --- /dev/null
> +++ b/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst
> @@ -0,0 +1,92 @@
> +================
> +bpftool-cgroup
> +================
> +-------------------------------------------------------------------------------
> +tool for inspection and simple manipulation of eBPF progs
> +-------------------------------------------------------------------------------
> +
> +:Manual section: 8
> +
> +SYNOPSIS
> +========
> +
> + **bpftool** [*OPTIONS*] **cgroup** *COMMAND*
> +
> + *OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] | { **-f** | **--bpffs** } }
> +
> + *COMMANDS* :=
> + { **list** | **attach** | **detach** | **help** }
> +
> +MAP COMMANDS
> +=============
> +
> +| **bpftool** **cgroup list** *CGROUP*
> +| **bpftool** **cgroup attach** *CGROUP* *ATTACH_TYPE* *PROG* [*ATTACH_FLAGS*]
> +| **bpftool** **cgroup detach** *CGROUP* *ATTACH_TYPE* *PROG*
> +| **bpftool** **cgroup help**
> +|
> +| *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* }
Could you please give the different possible values for ATTACH_TYPE and
ATTACH_FLAGS, and provide some documentation for the flags?
> +
> +DESCRIPTION
> +===========
> + **bpftool cgroup list** *CGROUP*
> + List all programs attached to the cgroup *CGROUP*.
> +
> + Output will start with program ID followed by attach type,
> + attach flags and program name.
> +
> + **bpftool cgroup attach** *CGROUP* *ATTACH_TYPE* *PROG* [*ATTACH_FLAGS*]
> + Attach program *PROG* to the cgroup *CGROUP* with attach type
> + *ATTACH_TYPE* and optional *ATTACH_FLAGS*.
> +
> + **bpftool cgroup detach** *CGROUP* *ATTACH_TYPE* *PROG*
> + Detach *PROG* from the cgroup *CGROUP* and attach type
> + *ATTACH_TYPE*.
> +
> + **bpftool prog help**
> + Print short help message.
[…]
> diff --git a/tools/bpf/bpftool/cgroup.c b/tools/bpf/bpftool/cgroup.c
> new file mode 100644
> index 000000000000..88d67f74313f
> --- /dev/null
> +++ b/tools/bpf/bpftool/cgroup.c
> @@ -0,0 +1,305 @@
> +/*
> + * Copyright (C) 2017 Facebook
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version
> + * 2 of the License, or (at your option) any later version.
> + *
> + * Author: Roman Gushchin <guro@fb.com>
> + */
> +
[…]
> +static int do_detach(int argc, char **argv)
> +{
> + int prog_fd, cgroup_fd;
> + enum bpf_attach_type attach_type;
> + int ret = -1;
> +
> + if (argc < 4) {
> + p_err("too few parameters for cgroup detach\n");
> + goto exit;
> + }
> +
> + cgroup_fd = open(argv[0], O_RDONLY);
> + if (cgroup_fd < 0) {
> + p_err("can't open cgroup %s\n", argv[1]);
> + goto exit;
> + }
> +
> + attach_type = parse_attach_type(argv[1]);
> + if (attach_type == __MAX_BPF_ATTACH_TYPE) {
> + p_err("invalid attach type");
> + goto exit_cgroup;
> + }
> +
> + argc -= 2;
> + argv = &argv[2];
> + prog_fd = prog_parse_fd(&argc, &argv);
> + if (prog_fd < 0)
> + goto exit_cgroup;
> +
> + if (bpf_prog_detach2(prog_fd, cgroup_fd, attach_type)) {
> + p_err("failed to attach program");
Failed to *detach* instead of “attach”.
> + goto exit_prog;
> + }
> +
> + if (json_output)
> + jsonw_null(json_wtr);
> +
> + ret = 0;
> +
> +exit_prog:
> + close(prog_fd);
> +exit_cgroup:
> + close(cgroup_fd);
> +exit:
> + return ret;
> +}
[…]
Very nice work on this v2, thanks a lot!
Quentin
^ permalink raw reply
* Re: [PATCH v2 net-next 3/4] bpftool: implement prog load command
From: Quentin Monnet @ 2017-12-08 10:33 UTC (permalink / raw)
To: Roman Gushchin, netdev
Cc: linux-kernel, kernel-team, ast, daniel, jakub.kicinski, kafai,
David Ahern
In-Reply-To: <20171207183909.16240-4-guro@fb.com>
2017-12-07 18:39 UTC+0000 ~ Roman Gushchin <guro@fb.com>
> Add the prog load command to load a bpf program from a specified
> binary file and pin it to bpffs.
>
> Usage description and examples are given in the corresponding man
> page.
>
> Syntax:
> $ bpftool prog load SOURCE_FILE FILE
>
> FILE is a non-existing file on bpffs.
>
> Signed-off-by: Roman Gushchin <guro@fb.com>
> Cc: Alexei Starovoitov <ast@kernel.org>
> Cc: Daniel Borkmann <daniel@iogearbox.net>
> Cc: Jakub Kicinski <jakub.kicinski@netronome.com>
> Cc: Martin KaFai Lau <kafai@fb.com>
> Cc: Quentin Monnet <quentin.monnet@netronome.com>
> Cc: David Ahern <dsahern@gmail.com>
> ---
> tools/bpf/bpftool/Documentation/bpftool-prog.rst | 10 +++-
> tools/bpf/bpftool/Documentation/bpftool.rst | 2 +-
> tools/bpf/bpftool/common.c | 71 +++++++++++++-----------
> tools/bpf/bpftool/main.h | 1 +
> tools/bpf/bpftool/prog.c | 31 ++++++++++-
> 5 files changed, 81 insertions(+), 34 deletions(-)
>
> diff --git a/tools/bpf/bpftool/Documentation/bpftool-prog.rst b/tools/bpf/bpftool/Documentation/bpftool-prog.rst
> index 36e8d1c3c40d..827b415f8ab6 100644
> --- a/tools/bpf/bpftool/Documentation/bpftool-prog.rst
> +++ b/tools/bpf/bpftool/Documentation/bpftool-prog.rst
> @@ -15,7 +15,7 @@ SYNOPSIS
> *OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] | { **-f** | **--bpffs** } }
>
> *COMMANDS* :=
> - { **show** | **dump xlated** | **dump jited** | **pin** | **help** }
> + { **show** | **dump xlated** | **dump jited** | **pin** | **load** | **help** }
>
> MAP COMMANDS
> =============
> @@ -24,6 +24,7 @@ MAP COMMANDS
> | **bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes**}]
> | **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes**}]
> | **bpftool** **prog pin** *PROG* *FILE*
> +| **bpftool** **prog load** *SRC* *FILE*
> | **bpftool** **prog help**
> |
> | *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* }
> @@ -57,6 +58,11 @@ DESCRIPTION
>
> Note: *FILE* must be located in *bpffs* mount.
>
> + **bpftool prog load** *SRC* *FILE*
> + Load bpf program from binary *SRC* and pin as *FILE*.
> +
> + Note: *FILE* must be located in *bpffs* mount.
> +
> **bpftool prog help**
> Print short help message.
>
> @@ -126,8 +132,10 @@ EXAMPLES
> |
> | **# mount -t bpf none /sys/fs/bpf/**
> | **# bpftool prog pin id 10 /sys/fs/bpf/prog**
> +| **# bpftool prog load ./my_prog.o /sys/fs/bpf/prog2**
> | **# ls -l /sys/fs/bpf/**
> | -rw------- 1 root root 0 Jul 22 01:43 prog
> +| -rw------- 1 root root 0 Dec 07 17:23 prog2
Nit: would you mind using a date closer to the first one? Just from a
reader's point of view it might look strange to see the files apparently
created with two successive commands having such a difference between
their creation times.
>
> **# bpftool prog dum jited pinned /sys/fs/bpf/prog opcodes**
>
> diff --git a/tools/bpf/bpftool/Documentation/bpftool.rst b/tools/bpf/bpftool/Documentation/bpftool.rst
> index 926c03d5a8da..f547a0c0aa34 100644
> --- a/tools/bpf/bpftool/Documentation/bpftool.rst
> +++ b/tools/bpf/bpftool/Documentation/bpftool.rst
> @@ -26,7 +26,7 @@ SYNOPSIS
> | **pin** | **help** }
>
> *PROG-COMMANDS* := { **show** | **dump jited** | **dump xlated** | **pin**
> - | **help** }
> + | **load** | **help** }
>
> DESCRIPTION
> ===========
[…]
> diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
> index ad619b96c276..bac5d81e2ff0 100644
> --- a/tools/bpf/bpftool/prog.c
> +++ b/tools/bpf/bpftool/prog.c
> @@ -45,6 +45,7 @@
> #include <sys/stat.h>
>
> #include <bpf.h>
> +#include <libbpf.h>
>
> #include "main.h"
> #include "disasm.h"
> @@ -635,6 +636,32 @@ static int do_pin(int argc, char **argv)
> return err;
> }
>
> +static int do_load(int argc, char **argv)
> +{
> + struct bpf_object *obj;
> + int prog_fd;
> +
> + if (argc != 2) {
> + usage();
> + return -1;
> + }
No need to return here, usage() exits from the program.
> +
> + if (bpf_prog_load(argv[0], BPF_PROG_TYPE_UNSPEC, &obj, &prog_fd)) {
> + p_err("failed to load program\n");
> + return -1;
> + }
> +
> + if (do_pin_fd(prog_fd, argv[1])) {
> + p_err("failed to pin program\n");
> + return -1;
> + }
> +
> + if (json_output)
> + jsonw_null(json_wtr);
> +
> + return 0;
> +}
> +
> static int do_help(int argc, char **argv)
> {
> if (json_output) {
> @@ -647,13 +674,14 @@ static int do_help(int argc, char **argv)
> " %s %s dump xlated PROG [{ file FILE | opcodes }]\n"
> " %s %s dump jited PROG [{ file FILE | opcodes }]\n"
> " %s %s pin PROG FILE\n"
> + " %s %s load SRC FILE\n"
> " %s %s help\n"
> "\n"
> " " HELP_SPEC_PROGRAM "\n"
> " " HELP_SPEC_OPTIONS "\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], bin_name, argv[-2]);
>
> return 0;
> }
> @@ -663,6 +691,7 @@ static const struct cmd cmds[] = {
> { "help", do_help },
> { "dump", do_dump },
> { "pin", do_pin },
> + { "load", do_load },
> { 0 }
> };
>
>
^ permalink raw reply
* Re: [PATCH v2 net-next 1/4] libbpf: add ability to guess program type based on section name
From: Quentin Monnet @ 2017-12-08 10:33 UTC (permalink / raw)
To: Roman Gushchin, netdev
Cc: linux-kernel, kernel-team, ast, daniel, jakub.kicinski, kafai,
David Ahern
In-Reply-To: <20171207183909.16240-2-guro@fb.com>
2017-12-07 18:39 UTC+0000 ~ Roman Gushchin <guro@fb.com>
> The bpf_prog_load() function will guess program type if it's not
> specified explicitly. This functionality will be used to implement
> loading of different programs without asking a user to specify
> the program type. In first order it will be used by bpftool.
>
> Signed-off-by: Roman Gushchin <guro@fb.com>
> Cc: Alexei Starovoitov <ast@kernel.org>
> Cc: Daniel Borkmann <daniel@iogearbox.net>
> Cc: Jakub Kicinski <jakub.kicinski@netronome.com>
> Cc: Martin KaFai Lau <kafai@fb.com>
> Cc: Quentin Monnet <quentin.monnet@netronome.com>
> Cc: David Ahern <dsahern@gmail.com>
> ---
> tools/lib/bpf/libbpf.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 51 insertions(+)
>
> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index 5aa45f89da93..205b7822fa0a 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -1721,6 +1721,45 @@ BPF_PROG_TYPE_FNS(tracepoint, BPF_PROG_TYPE_TRACEPOINT);
> BPF_PROG_TYPE_FNS(xdp, BPF_PROG_TYPE_XDP);
> BPF_PROG_TYPE_FNS(perf_event, BPF_PROG_TYPE_PERF_EVENT);
>
> +#define BPF_PROG_SEC(string, type) { string, sizeof(string), type }
> +static const struct {
> + const char *sec;
> + size_t len;
> + enum bpf_prog_type prog_type;
> +} section_names[] = {
> + BPF_PROG_SEC("socket", BPF_PROG_TYPE_SOCKET_FILTER),
> + BPF_PROG_SEC("kprobe/", BPF_PROG_TYPE_KPROBE),
> + BPF_PROG_SEC("kretprobe/", BPF_PROG_TYPE_KPROBE),
> + BPF_PROG_SEC("tracepoint/", BPF_PROG_TYPE_TRACEPOINT),
> + BPF_PROG_SEC("xdp", BPF_PROG_TYPE_XDP),
> + BPF_PROG_SEC("perf_event", BPF_PROG_TYPE_PERF_EVENT),
> + BPF_PROG_SEC("cgroup/skb", BPF_PROG_TYPE_CGROUP_SKB),
> + BPF_PROG_SEC("cgroup/sock", BPF_PROG_TYPE_CGROUP_SOCK),
> + BPF_PROG_SEC("cgroup/dev", BPF_PROG_TYPE_CGROUP_DEVICE),
> + BPF_PROG_SEC("sockops", BPF_PROG_TYPE_SOCK_OPS),
> + BPF_PROG_SEC("sk_skb", BPF_PROG_TYPE_SK_SKB),
> +};
> +#undef BPF_PROG_SEC
> +
> +static enum bpf_prog_type bpf_program__guess_type(struct bpf_program *prog)
> +{
> + int i;
> +
> + if (!prog->section_name)
> + goto err;
> +
> + for (i = 0; i < ARRAY_SIZE(section_names); i++)
> + if (strncmp(prog->section_name, section_names[i].sec,
> + section_names[i].len) == 0)
> + return section_names[i].prog_type;
> +
> +err:
> + pr_warning("failed to guess program type based on section name %s\n",
> + prog->section_name);
> +
> + return BPF_PROG_TYPE_UNSPEC;
> +}
> +
> int bpf_map__fd(struct bpf_map *map)
> {
> return map ? map->fd : -EINVAL;
> @@ -1832,6 +1871,18 @@ int bpf_prog_load(const char *file, enum bpf_prog_type type,
> return -ENOENT;
> }
>
> + /*
> + * If type is not specified, try to guess it based on
> + * section name.
> + */
> + if (type == BPF_PROG_TYPE_UNSPEC) {
> + type = bpf_program__guess_type(prog);
> + if (type == BPF_PROG_TYPE_UNSPEC) {
> + bpf_object__close(obj);
> + return -EINVAL;
> + }
> + }
> +
> bpf_program__set_type(prog, type);
> err = bpf_object__load(obj);
> if (err) {
>
Looks good to me, nice to avoid the hard-coded string lengths :). Thanks
for the changes!
Quentin
^ permalink raw reply
* Re: [PATCH net 1/3] hv_netvsc: Correct the max receive buffer size
From: Dan Carpenter @ 2017-12-08 10:33 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: devel, haiyangz, sthemmin, netdev
In-Reply-To: <20171208001055.24670-2-sthemmin@microsoft.com>
On Thu, Dec 07, 2017 at 04:10:53PM -0800, Stephen Hemminger wrote:
> From: Haiyang Zhang <haiyangz@microsoft.com>
>
> It should be 31 MB on recent host versions.
>
> Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
> Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
This is very vague. What does "recent" mean in this context? There are
also some unrelated white space changes here which make the patch harder
to read.
This patch kind of makes the bug fixed by patch 2 even worse because
before the receive buffer was capped at around 16MB and now we can set
the receive buffer to 31MB. It might make sense to fold the two
patches together.
Is patch 2 a memory corruption bug? The changelog doesn't really say
what the user visible effects of the bug are. Basically if you make the
buffer too small then it's a performance issue but if you make it too
large what happens? It's not clear to me.
regards,
dan carpenter
^ permalink raw reply
* Re: [PATCH v3 24/33] nds32: Device tree support
From: Mark Rutland @ 2017-12-08 10:27 UTC (permalink / raw)
To: Greentime Hu
Cc: greentime, linux-kernel, arnd, linux-arch, tglx, jason,
marc.zyngier, robh+dt, netdev, deanbo422, devicetree, viro,
dhowells, will.deacon, daniel.lezcano, linux-serial,
geert.uytterhoeven, linus.walleij, greg, Vincent Chen
In-Reply-To: <c1083b6f603aeeb13c72c501214e82549404fa5c.1512723245.git.green.hu@gmail.com>
On Fri, Dec 08, 2017 at 05:12:07PM +0800, Greentime Hu wrote:
> + timer0: timer@98400000 {
> + compatible = "andestech,atftmr010";
> + reg = <0x98400000 0x1000>;
> + interrupts = <19>;
> + clocks = <&clk_pll>;
> + clock-names = "apb_pclk";
> + cycle-count-offset = <0x20>;
> + };
Looking through the series, I can't find a binding or driver for this
timer, either.
Does timekeeping work with this series, or are additional patches
necessary?
Thanks,
Mark.
^ permalink raw reply
* Re: [PATCH v3 24/33] nds32: Device tree support
From: Mark Rutland @ 2017-12-08 10:23 UTC (permalink / raw)
To: Greentime Hu
Cc: greentime, linux-kernel, arnd, linux-arch, tglx, jason,
marc.zyngier, robh+dt, netdev, deanbo422, devicetree, viro,
dhowells, will.deacon, daniel.lezcano, linux-serial,
geert.uytterhoeven, linus.walleij, greg, Vincent Chen
In-Reply-To: <c1083b6f603aeeb13c72c501214e82549404fa5c.1512723245.git.green.hu@gmail.com>
On Fri, Dec 08, 2017 at 05:12:07PM +0800, Greentime Hu wrote:
> + timer0: timer@f0400000 {
> + compatible = "andestech,atcpit100";
> + reg = <0xf0400000 0x1000>;
> + interrupts = <2>;
> + clocks = <&clk_pll>;
> + clock-names = "apb_pclk";
> + cycle-count-offset = <0x38>;
> + cycle-count-down;
> + };
The cover leter mentioned the atcpit100 driver had been removed, but the
node is still here, and the vdso code seems to look for this node.
This binding needs documentation.
Thanks,
Mark.
^ permalink raw reply
* Re: [PATCH v3 17/33] nds32: VDSO support
From: Mark Rutland @ 2017-12-08 10:21 UTC (permalink / raw)
To: Greentime Hu
Cc: greentime, linux-kernel, arnd, linux-arch, tglx, jason,
marc.zyngier, robh+dt, netdev, deanbo422, devicetree, viro,
dhowells, will.deacon, daniel.lezcano, linux-serial,
geert.uytterhoeven, linus.walleij, greg, Vincent Chen
In-Reply-To: <921ccfa97c4c13f12c7b22b9554f52dcce51f87e.1512723245.git.green.hu@gmail.com>
On Fri, Dec 08, 2017 at 05:12:00PM +0800, Greentime Hu wrote:
> From: Greentime Hu <greentime@andestech.com>
>
> This patch adds VDSO support. The VDSO code is currently used for
> sys_rt_sigreturn() and optimised gettimeofday() (using the SoC timer counter).
[...]
> +static int grab_timer_node_info(void)
> +{
> + struct device_node *timer_node;
> +
> + timer_node = of_find_node_by_name(NULL, "timer");
Please use a compatible string, rather than matching the timer by name.
It's plausible that you have multiple nodes called "timer" in the DT,
under different parent nodes, and this might not be the device you
think it is. I see your dt in patch 24 has two timer nodes.
It would be best if your clocksource driver exposed some stuct that you
looked at here, so that you're guaranteed to user the same device.
> + of_property_read_u32(timer_node, "cycle-count-offset",
> + &vdso_data->cycle_count_offset);
> + vdso_data->cycle_count_down =
> + of_property_read_bool(timer_node, "cycle-count-down");
... and then you'd only need to parse these in one place, too.
IIUC these are proeprties for the atcpit device, which has no
documentation or driver in this series.
So I'm rather confused as to what's going on here.
> + return of_address_to_resource(timer_node, 0, &timer_res);
> +}
> +int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
> +{
> + /*Map timer to user space */
> + vdso_base += PAGE_SIZE;
> + prot = __pgprot(_PAGE_V | _PAGE_M_UR_KR | _PAGE_D |
> + _PAGE_G | _PAGE_C_DEV);
> + ret = io_remap_pfn_range(vma, vdso_base, timer_res.start >> PAGE_SHIFT,
> + PAGE_SIZE, prot);
> + if (ret)
> + goto up_fail;
Maybe this is fine, but it looks a bit suspicious.
Is it safe to map IO memory to a userspace process like this?
In general that isn't safe, since userspace could access other registers
(if those exist), perform accesses that change the state of hardware, or
make unsupported access types (e.g. unaligned, atomic) that result in
errors the kernel can't handle.
Does none of that apply here?
Thanks,
Mark.
^ permalink raw reply
* Re: [PATCH nf-next RFC,v2 6/6] netfilter: nft_flow_offload: add ndo hooks for hardware offload
From: Florian Westphal @ 2017-12-08 10:18 UTC (permalink / raw)
To: Pablo Neira Ayuso
Cc: netfilter-devel, netdev, f.fainelli, simon.horman, ronye, jiri,
nbd, john, kubakici, fw
In-Reply-To: <20171207124501.24325-7-pablo@netfilter.org>
Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> The software flow table garbage collector skips entries that resides in
> the hardware, so the hardware will be responsible for releasing this
> flow table entry too via flow_offload_dead(). In the next garbage
> collector run, this removes the entries both in the software and
> hardware flow table from user context.
>
> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
> ---
> @Florian: I still owe you one here, you mentioned about inmediate schedule
> of the workqueue thread, and I need to revisit this, the quick patch I made
> is hitting splats when calling queue_delayed_work() from packet path, this
> may be my fault though.
OK. IIRC I had suggested to just use schedule_work() instead.
In most cases (assuming system is busy) the workqueue will already be
pending anyway.
> diff --git a/net/netfilter/nf_flow_table.c b/net/netfilter/nf_flow_table.c
> index ff27dad268c3..c578c3aec0e0 100644
> --- a/net/netfilter/nf_flow_table.c
> +++ b/net/netfilter/nf_flow_table.c
> @@ -212,6 +212,21 @@ int nf_flow_table_iterate(struct nf_flowtable *flow_table,
> }
> EXPORT_SYMBOL_GPL(nf_flow_table_iterate);
>
> +static void flow_offload_hw_del(struct flow_offload *flow)
> +{
> + struct net_device *indev;
> + int ret, ifindex;
> +
> + rtnl_lock();
> + ifindex = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.iifidx;
> + indev = __dev_get_by_index(&init_net, ifindex);
I think this should pass struct net * as arg to flow_offload_hw_del.
> + if (WARN_ON(!indev))
> + return;
> +
> + ret = indev->netdev_ops->ndo_flow_offload(FLOW_OFFLOAD_DEL, flow);
> + rtnl_unlock();
> +}
Please no rtnl lock unless absolutely needed.
Seems this could even avoid the mutex completely by using
dev_get_by_index + dev_put.
> +static int do_flow_offload(struct flow_offload *flow)
> +{
> + struct net_device *indev;
> + int ret, ifindex;
> +
> + rtnl_lock();
> + ifindex = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.iifidx;
> + indev = __dev_get_by_index(&init_net, ifindex);
likewise.
> +#define FLOW_HW_WORK_TIMEOUT msecs_to_jiffies(100)
> +
> +static struct delayed_work nft_flow_offload_dwork;
I would go with struct work and no delay at all.
^ permalink raw reply
* [PATCH iproute v2] tc: util: Don't call NEXT_ARG_FWD() in __parse_action_control()
From: Michal Privoznik @ 2017-12-08 10:18 UTC (permalink / raw)
To: netdev; +Cc: jiri, stephen
Not all callers want parse_action_control*() to advance the
arguments. For instance act_parse_police() does the argument
advancing itself.
Fixes: e67aba559581 ("tc: actions: add helpers to parse and print control actions")
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
---
Technically, even though this implements different approach, it is v2 of:
http://www.spinics.net/lists/netdev/msg468479.html
tc/m_bpf.c | 1 +
tc/m_connmark.c | 1 +
tc/m_csum.c | 1 +
tc/m_gact.c | 10 +++++-----
tc/m_ife.c | 1 +
tc/m_mirred.c | 4 +++-
tc/m_nat.c | 1 +
tc/m_pedit.c | 1 +
tc/m_sample.c | 1 +
tc/m_skbedit.c | 1 +
tc/m_skbmod.c | 1 +
tc/m_tunnel_key.c | 1 +
tc/m_vlan.c | 1 +
tc/tc_util.c | 1 -
14 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/tc/m_bpf.c b/tc/m_bpf.c
index 1c1f71cd..576f69cc 100644
--- a/tc/m_bpf.c
+++ b/tc/m_bpf.c
@@ -129,6 +129,7 @@ opt_bpf:
parse_action_control_dflt(&argc, &argv, &parm.action,
false, TC_ACT_PIPE);
+ NEXT_ARG_FWD();
if (argc) {
if (matches(*argv, "index") == 0) {
diff --git a/tc/m_connmark.c b/tc/m_connmark.c
index 37d71854..47c7a8c2 100644
--- a/tc/m_connmark.c
+++ b/tc/m_connmark.c
@@ -82,6 +82,7 @@ parse_connmark(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
}
parse_action_control_dflt(&argc, &argv, &sel.action, false, TC_ACT_PIPE);
+ NEXT_ARG_FWD();
if (argc) {
if (matches(*argv, "index") == 0) {
diff --git a/tc/m_csum.c b/tc/m_csum.c
index 7b156734..e1352c08 100644
--- a/tc/m_csum.c
+++ b/tc/m_csum.c
@@ -124,6 +124,7 @@ parse_csum(struct action_util *a, int *argc_p,
}
parse_action_control_dflt(&argc, &argv, &sel.action, false, TC_ACT_OK);
+ NEXT_ARG_FWD();
if (argc) {
if (matches(*argv, "index") == 0) {
diff --git a/tc/m_gact.c b/tc/m_gact.c
index e7d91dab..b30b0420 100644
--- a/tc/m_gact.c
+++ b/tc/m_gact.c
@@ -87,14 +87,13 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p,
if (argc < 0)
return -1;
-
- if (matches(*argv, "gact") == 0) {
- argc--;
- argv++;
- } else if (parse_action_control(&argc, &argv, &p.action, false) == -1) {
+ if (matches(*argv, "gact") != 0 &&
+ parse_action_control(&argc, &argv, &p.action, false) == -1) {
usage(); /* does not return */
}
+ NEXT_ARG_FWD();
+
#ifdef CONFIG_GACT_PROB
if (argc > 0) {
if (matches(*argv, "random") == 0) {
@@ -114,6 +113,7 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p,
if (parse_action_control(&argc, &argv,
&pp.paction, false) == -1)
usage();
+ NEXT_ARG_FWD();
if (get_u16(&pp.pval, *argv, 10)) {
fprintf(stderr,
"Illegal probability val 0x%x\n",
diff --git a/tc/m_ife.c b/tc/m_ife.c
index 205efc9f..4647f6a6 100644
--- a/tc/m_ife.c
+++ b/tc/m_ife.c
@@ -159,6 +159,7 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p,
parse_action_control_dflt(&argc, &argv, &p.action, false, TC_ACT_PIPE);
+ NEXT_ARG_FWD();
if (argc) {
if (matches(*argv, "index") == 0) {
NEXT_ARG();
diff --git a/tc/m_mirred.c b/tc/m_mirred.c
index 3870d3a4..aa7ce6d9 100644
--- a/tc/m_mirred.c
+++ b/tc/m_mirred.c
@@ -202,8 +202,10 @@ parse_direction(struct action_util *a, int *argc_p, char ***argv_p,
}
- if (p.eaction == TCA_EGRESS_MIRROR || p.eaction == TCA_INGRESS_MIRROR)
+ if (p.eaction == TCA_EGRESS_MIRROR || p.eaction == TCA_INGRESS_MIRROR) {
parse_action_control(&argc, &argv, &p.action, false);
+ NEXT_ARG_FWD();
+ }
if (argc) {
if (iok && matches(*argv, "index") == 0) {
diff --git a/tc/m_nat.c b/tc/m_nat.c
index 1e4ff51f..f5de4d4c 100644
--- a/tc/m_nat.c
+++ b/tc/m_nat.c
@@ -116,6 +116,7 @@ parse_nat(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct
parse_action_control_dflt(&argc, &argv, &sel.action, false, TC_ACT_OK);
+ NEXT_ARG_FWD();
if (argc) {
if (matches(*argv, "index") == 0) {
NEXT_ARG();
diff --git a/tc/m_pedit.c b/tc/m_pedit.c
index 26549eee..dc57f14a 100644
--- a/tc/m_pedit.c
+++ b/tc/m_pedit.c
@@ -672,6 +672,7 @@ int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
parse_action_control_dflt(&argc, &argv, &sel.sel.action, false, TC_ACT_OK);
+ NEXT_ARG_FWD();
if (argc) {
if (matches(*argv, "index") == 0) {
NEXT_ARG();
diff --git a/tc/m_sample.c b/tc/m_sample.c
index ff5ee6bd..31774c0e 100644
--- a/tc/m_sample.c
+++ b/tc/m_sample.c
@@ -100,6 +100,7 @@ static int parse_sample(struct action_util *a, int *argc_p, char ***argv_p,
parse_action_control_dflt(&argc, &argv, &p.action, false, TC_ACT_PIPE);
+ NEXT_ARG_FWD();
if (argc) {
if (matches(*argv, "index") == 0) {
NEXT_ARG();
diff --git a/tc/m_skbedit.c b/tc/m_skbedit.c
index aa374fcb..c41a7bb0 100644
--- a/tc/m_skbedit.c
+++ b/tc/m_skbedit.c
@@ -123,6 +123,7 @@ parse_skbedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
parse_action_control_dflt(&argc, &argv, &sel.action,
false, TC_ACT_PIPE);
+ NEXT_ARG_FWD();
if (argc) {
if (matches(*argv, "index") == 0) {
NEXT_ARG();
diff --git a/tc/m_skbmod.c b/tc/m_skbmod.c
index 561b73fb..bc268dfd 100644
--- a/tc/m_skbmod.c
+++ b/tc/m_skbmod.c
@@ -124,6 +124,7 @@ static int parse_skbmod(struct action_util *a, int *argc_p, char ***argv_p,
parse_action_control_dflt(&argc, &argv, &p.action, false, TC_ACT_PIPE);
+ NEXT_ARG_FWD();
if (argc) {
if (matches(*argv, "index") == 0) {
NEXT_ARG();
diff --git a/tc/m_tunnel_key.c b/tc/m_tunnel_key.c
index 1cdd0356..2dc91879 100644
--- a/tc/m_tunnel_key.c
+++ b/tc/m_tunnel_key.c
@@ -175,6 +175,7 @@ static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p,
parse_action_control_dflt(&argc, &argv, &parm.action,
false, TC_ACT_PIPE);
+ NEXT_ARG_FWD();
if (argc) {
if (matches(*argv, "index") == 0) {
NEXT_ARG();
diff --git a/tc/m_vlan.c b/tc/m_vlan.c
index 161759fd..edae0d1e 100644
--- a/tc/m_vlan.c
+++ b/tc/m_vlan.c
@@ -131,6 +131,7 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p,
parse_action_control_dflt(&argc, &argv, &parm.action,
false, TC_ACT_PIPE);
+ NEXT_ARG_FWD();
if (argc) {
if (matches(*argv, "index") == 0) {
NEXT_ARG();
diff --git a/tc/tc_util.c b/tc/tc_util.c
index 18879056..ee9a70aa 100644
--- a/tc/tc_util.c
+++ b/tc/tc_util.c
@@ -586,7 +586,6 @@ static int __parse_action_control(int *argc_p, char ***argv_p, int *result_p,
}
result |= jump_cnt;
}
- NEXT_ARG_FWD();
*argc_p = argc;
*argv_p = argv;
*result_p = result;
--
2.13.6
^ permalink raw reply related
* From Precious
From: preciouskazim1@myself.com @ 2017-12-08 10:12 UTC (permalink / raw)
Hello dear,
My name is Precious, I saw your profile and I became interested in
you, I would also like to know more about you, please contact me with
this email address so that I can give you a so that you know who I am,
because I have something very important to tell you.
Precious.
^ permalink raw reply
* Re: [PATCH nf-next RFC,v2 4/6] netfilter: flow table support for IPv4
From: Florian Westphal @ 2017-12-08 10:04 UTC (permalink / raw)
To: Pablo Neira Ayuso
Cc: netfilter-devel, netdev, f.fainelli, simon.horman, ronye, jiri,
nbd, john, kubakici, fw
In-Reply-To: <20171207124501.24325-5-pablo@netfilter.org>
Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> This patch adds the IPv4 flow table type, that implements the datapath
> flow table to forward IPv4 traffic. Rationale is:
>
> 1) Look up for the packet in the flow table, from the ingress hook.
> 2) If there's a hit, decrement ttl and pass it on to the neighbour layer
> for transmission.
> 3) If there's a miss, packet is passed up to the classic forwarding
> path.
Is there a plan to also handle zone IDs in future?
I't going to be messy for sure since we'd need to tell HW how to do
the zone mapping. Perhaps only support a builtin list, e.g.
vlan id == zone...?
Don't yet see how it could be done in a generic way as the mappings can
be arbitrarily complex.
Right now afaics one could install one flow table per zone and map
this in nft, but then we still miss the part that tells the hardware
how the zone identifier was derived.
> +static bool ip_has_options(unsigned int thoff)
> +{
> + return thoff > sizeof(struct iphdr);
I'd use
thoff != sizeof(...)
to catch case where ihl is < struct iphdr.
> +nf_flow_offload_hook(void *priv, struct sk_buff *skb,
> + const struct nf_hook_state *state)
> +{
> + struct flow_offload_tuple_rhash *tuplehash;
> + struct nf_flowtable *flow_table = priv;
> + struct flow_offload_tuple tuple = {};
> + union nf_inet_addr nexthop;
> + struct flow_offload *flow;
> + struct net_device *outdev;
> + struct iphdr *iph;
> +
> + if (nf_flow_tuple_ip(skb, &tuple) < 0)
> + return NF_ACCEPT;
> +
> + tuplehash = flow_offload_lookup(flow_table, &tuple);
> + if (tuplehash == NULL)
> + return NF_ACCEPT;
> +
> + outdev = dev_get_by_index_rcu(&init_net, tuplehash->tuple.oifidx);
state->net ?
^ permalink raw reply
* Re: [PATCH net 2/4] net: aquantia: Fix hardware DMA stream overload on large MRRS
From: Igor Russkikh @ 2017-12-08 9:56 UTC (permalink / raw)
To: David Miller
Cc: netdev, darcari, pavel.belous, Nadezhda.Krupnina, simon.edelhaus
In-Reply-To: <20171207.142331.906125407031062563.davem@davemloft.net>
Hi David!
>> +#define pci_reg_control6_adr 0x1014u
>> +
> CPP macros, especially those which define register numbers or bit
> valus, should never use lowercase. They should always use uppercase
> names.
>
> This is a coding style convention we use in the entire kernel which
> makes it easy to visually see whether something is a bonafide C
> symbol or a CPP macro.
Totally agree on that. I honestly not aware of the history why it was done in lowercase.
I'm now preparing a set of commits for new hardware revisions support, I can queue this task there as well.
Or, if you prefer, I may add this low to uppercase conversion patch into this patchset and resubmit.
BR, Igor
^ permalink raw reply
* Re: [PATCH v4.1] phylib: Add device reset GPIO support
From: Geert Uytterhoeven @ 2017-12-08 9:53 UTC (permalink / raw)
To: Sergei Shtylyov
Cc: Geert Uytterhoeven, David S . Miller, Andrew Lunn,
Florian Fainelli, Simon Horman, Magnus Damm, Rob Herring,
Mark Rutland, Nicolas Ferre, Richard Leitner,
netdev@vger.kernel.org, devicetree@vger.kernel.org, Linux-Renesas,
linux-kernel@vger.kernel.org
In-Reply-To: <69fe9a6d-4039-6f80-b80d-7dc0de31e5bf@cogentembedded.com>
Hi Sergei,
On Thu, Dec 7, 2017 at 6:20 PM, Sergei Shtylyov
<sergei.shtylyov@cogentembedded.com> wrote:
> On 12/04/2017 03:35 PM, Geert Uytterhoeven wrote:
>> From: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
>> The PHY devices sometimes do have their reset signal (maybe even power
>> supply?) tied to some GPIO and sometimes it also does happen that a boot
>> loader does not leave it deasserted. So far this issue has been attacked
>> from (as I believe) a wrong angle: by teaching the MAC driver to
>> manipulate
>> the GPIO in question; that solution, when applied to the device trees, led
>> to adding the PHY reset GPIO properties to the MAC device node, with one
>> exception: Cadence MACB driver which could handle the "reset-gpios" prop
>> in a PHY device subnode. I believe that the correct approach is to teach
>> the 'phylib' to get the MDIO device reset GPIO from the device tree node
>> corresponding to this device -- which this patch is doing...
>>
>> Note that I had to modify the AT803x PHY driver as it would stop working
>> otherwise -- it made use of the reset GPIO for its own purposes...
>>
>> Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
>> Acked-by: Rob Herring <robh@kernel.org>
>> [geert: Propagate actual errors from fwnode_get_named_gpiod()]
>> [geert: Avoid destroying initial setup]
>> [geert: Consolidate GPIO descriptor acquiring code]
>> Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
>
> [...]
>>
>> diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
>> index 2df7b62c1a36811e..8f8b7747c54bc478 100644
>> --- a/drivers/net/phy/mdio_bus.c
>> +++ b/drivers/net/phy/mdio_bus.c
>
> [...]
>>
>> @@ -48,9 +49,26 @@
>> int mdiobus_register_device(struct mdio_device *mdiodev)
>> {
>> + struct gpio_desc *gpiod = NULL;
>> +
>> if (mdiodev->bus->mdio_map[mdiodev->addr])
>> return -EBUSY;
>> + /* Deassert the optional reset signal */
>
>
> Umm, but why deassert it here for such a short time?
That's a consequence of moving it from drivers/of/of_mdio.c to here.
Not that it was deasserted that much longer in drivers/of/of_mdio.c, though...
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH v5 2/2] sock: Move the socket inuse to namespace.
From: Tonghao Zhang @ 2017-12-08 9:52 UTC (permalink / raw)
To: Eric Dumazet
Cc: David Miller, Cong Wang, Eric Dumazet, Willem de Bruijn,
Linux Kernel Network Developers
In-Reply-To: <1512711658.25033.23.camel@gmail.com>
On Fri, Dec 8, 2017 at 1:40 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> On Fri, 2017-12-08 at 13:28 +0800, Tonghao Zhang wrote:
>> On Fri, Dec 8, 2017 at 1:20 AM, Eric Dumazet <eric.dumazet@gmail.com>
>> wrote:
>> > On Thu, 2017-12-07 at 08:45 -0800, Tonghao Zhang wrote:
>> > > In some case, we want to know how many sockets are in use in
>> > > different _net_ namespaces. It's a key resource metric.
>> > >
>> >
>> > ...
>> >
>> > > +static void sock_inuse_add(struct net *net, int val)
>> > > +{
>> > > + if (net->core.prot_inuse)
>> > > + this_cpu_add(*net->core.sock_inuse, val);
>> > > +}
>> >
>> > This is very confusing.
>> >
>> > Why testing net->core.prot_inuse for NULL is needed at all ?
>> >
>> > Why not testing net->core.sock_inuse instead ?
>> >
>>
>> Hi Eric and Cong, oh it's a typo. it's net->core.sock_inuse there.
>> Why
>> we should check the net->core.sock_inuse
>> Now show you the code:
>>
>> cleanup_net will call all of the network namespace exit methods,
>> rcu_barrier, and then remove the _net_ namespace.
>>
>> cleanup_net:
>> list_for_each_entry_reverse(ops, &pernet_list, list)
>> ops_exit_list(ops, &net_exit_list);
>>
>> rcu_barrier(); /* for netlink sock, the ‘deferred_put_nlk_sk’
>> will
>> be called. But sock_inuse has been released. */
>
>
> Thats would be a bug.
>
> Please find another way, but we want ultimately to check that before
> net->core.sock_inuse is freed, folding the inuse count on all cpus is
> 0, to make sure we do not have a bug somewhere.
Yes, I am aware of this issue even we will destroy the network namespace.
By the way, we can counter the socket-inuse in sock_alloc or sock_release.
In this way, we have to hold the network namespace again(via
get_net()) while sock
may hold it.
what do you think of this idea?
> We should not have to test if net->core.sock_inuse is NULL or not from
> sock_inuse_add(). Pointer must be there all the time.
>
> The freeing should only happen once we are sure sock_inuse_add() can
> not be called anymore.
>
>>
>>
>> /* Finally it is safe to free my network namespace structure */
>> list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) {}
>>
>>
>>
>> Release the netlink sock created in kernel(not hold the _net_
>> namespace):
>>
>> netlink_release
>> call_rcu(&nlk->rcu, deferred_put_nlk_sk);
>>
>> deferred_put_nlk_sk
>> sk_free(sk);
>>
>>
>> I may add a comment for sock_inuse_add in v6.
>
>
^ permalink raw reply
* Re: [PATCH net 3/4] net: aquantia: Improve and fix statistics on device
From: Igor Russkikh @ 2017-12-08 9:43 UTC (permalink / raw)
To: Andrew Lunn
Cc: David S . Miller, netdev, David Arcari, Pavel Belous,
Nadezhda Krupnina, Simon Edelhaus
In-Reply-To: <20171207190830.GB7240@lunn.ch>
Hi Andrew,
>> 1) Device hardware provides only 32bit counters. Using these directly
>> causes byte counters to overflow soon. A separate nic level structure
>> with 64 bit counters is now used to collect incrementally all the stats
>> and report these counters to ethtool stats and ndev stats.
>>
>> 2) ndev stats were filled from ring counters. These sometimes incorrectly
>> calculate byte and packet amounts when using LRO/LSO and jumboframes.
>> Fill ndev counters from hardware makes them precise.
>>
>> 3) Fill in multicast counter in ndev stats from hardware counter
>>
>> 4) Improve link state and statistics check interval callback: reduce normal
>> timeout from 2 secs to 1 sec. If link is down, reduce it to 500msec. This
>> speeds up link detection.
>>
>> 5) Reset driver level statistics to zero on initialization
>>
>> 6) Fix typo in ethtool statistics names
> Hi Igor
>
> This list suggests there should actually be 6 patches, not one.
>
1,2 and 3 are tightly linked and are difficult to separate.
4, 5 and 6 are small, agree I can split them.
BR, Igor
^ permalink raw reply
* [PATCH v3 29/33] dt-bindings: nds32 CPU Bindings
From: Greentime Hu @ 2017-12-08 9:12 UTC (permalink / raw)
To: greentime, linux-kernel, arnd, linux-arch, tglx, jason,
marc.zyngier, robh+dt, netdev, deanbo422, devicetree, viro,
dhowells, will.deacon, daniel.lezcano, linux-serial,
geert.uytterhoeven, linus.walleij, mark.rutland, greg
Cc: green.hu, Vincent Chen, Rick Chen, Zong Li
In-Reply-To: <cover.1512723245.git.green.hu@gmail.com>
From: Greentime Hu <greentime@andestech.com>
This patch adds nds32 CPU binding documents.
Signed-off-by: Vincent Chen <vincentc@andestech.com>
Signed-off-by: Rick Chen <rick@andestech.com>
Signed-off-by: Zong Li <zong@andestech.com>
Signed-off-by: Greentime Hu <greentime@andestech.com>
---
Documentation/devicetree/bindings/nds32/cpus.txt | 37 ++++++++++++++++++++++
1 file changed, 37 insertions(+)
create mode 100644 Documentation/devicetree/bindings/nds32/cpus.txt
diff --git a/Documentation/devicetree/bindings/nds32/cpus.txt b/Documentation/devicetree/bindings/nds32/cpus.txt
new file mode 100644
index 0000000..9a52937
--- /dev/null
+++ b/Documentation/devicetree/bindings/nds32/cpus.txt
@@ -0,0 +1,37 @@
+* Andestech Processor Binding
+
+This binding specifies what properties must be available in the device tree
+representation of a Andestech Processor Core, which is the root node in the
+tree.
+
+Required properties:
+
+ - compatible:
+ Usage: required
+ Value type: <string>
+ Definition: should be one of:
+ "andestech,n13"
+ "andestech,n15"
+ "andestech,d15"
+ "andestech,n10"
+ "andestech,d10"
+ "andestech,nds32v3"
+ - device_type
+ Usage: required
+ Value type: <string>
+ Definition: must be "cpu"
+ - reg: Contains CPU index.
+ - clock-frequency: Contains the clock frequency for CPU, in Hz.
+
+* Examples
+
+/ {
+ cpus {
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "andestech,n13", "andestech,nds32v3";
+ reg = <0x0>;
+ clock-frequency = <60000000>
+ };
+ };
+};
--
1.7.9.5
^ permalink raw reply related
* [PATCH v3 26/33] nds32: defconfig
From: Greentime Hu @ 2017-12-08 9:12 UTC (permalink / raw)
To: greentime, linux-kernel, arnd, linux-arch, tglx, jason,
marc.zyngier, robh+dt, netdev, deanbo422, devicetree, viro,
dhowells, will.deacon, daniel.lezcano, linux-serial,
geert.uytterhoeven, linus.walleij, mark.rutland, greg
Cc: green.hu, Vincent Chen
In-Reply-To: <cover.1512723245.git.green.hu@gmail.com>
From: Greentime Hu <greentime@andestech.com>
This patch adds nds32 defconfig.
Signed-off-by: Vincent Chen <vincentc@andestech.com>
Signed-off-by: Greentime Hu <greentime@andestech.com>
---
arch/nds32/configs/defconfig | 108 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 108 insertions(+)
create mode 100644 arch/nds32/configs/defconfig
diff --git a/arch/nds32/configs/defconfig b/arch/nds32/configs/defconfig
new file mode 100644
index 0000000..069ebe6
--- /dev/null
+++ b/arch/nds32/configs/defconfig
@@ -0,0 +1,108 @@
+CONFIG_CROSS_COMPILE="nds32le-linux-"
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_USER_NS=y
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_PROFILING=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_CACHE_L2 is not set
+CONFIG_VMSPLIT_3G_OPT=y
+CONFIG_PREEMPT=y
+# CONFIG_COMPACTION is not set
+CONFIG_HZ_100=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_BLK_DEV is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NET_CADENCE is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+CONFIG_FTMAC100=y
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_SERIO is not set
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=3
+CONFIG_SERIAL_8250_RUNTIME_UARTS=3
+CONFIG_SERIAL_OF_PLATFORM=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_RC_CORE is not set
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_ITE is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_CLKSRC_ATCPIT100=y
+CONFIG_GENERIC_PHY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_FUSE_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_NFS_USE_LEGACY_DNS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF4=y
+CONFIG_GDB_SCRIPTS=y
+CONFIG_READABLE_ASM=y
+CONFIG_HEADERS_CHECK=y
+CONFIG_DEBUG_SECTION_MISMATCH=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_PANIC_ON_OOPS=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_STACKTRACE=y
+CONFIG_RCU_CPU_STALL_TIMEOUT=300
+# CONFIG_CRYPTO_HW is not set
--
1.7.9.5
^ permalink raw reply related
* [PATCH v3 20/33] nds32: Debugging support
From: Greentime Hu @ 2017-12-08 9:12 UTC (permalink / raw)
To: greentime, linux-kernel, arnd, linux-arch, tglx, jason,
marc.zyngier, robh+dt, netdev, deanbo422, devicetree, viro,
dhowells, will.deacon, daniel.lezcano, linux-serial,
geert.uytterhoeven, linus.walleij, mark.rutland, greg
Cc: green.hu, Vincent Chen
In-Reply-To: <cover.1512723245.git.green.hu@gmail.com>
From: Greentime Hu <greentime@andestech.com>
This patch adds ptrace support.
Signed-off-by: Vincent Chen <vincentc@andestech.com>
Signed-off-by: Greentime Hu <greentime@andestech.com>
---
arch/nds32/include/uapi/asm/ptrace.h | 38 ++++
arch/nds32/kernel/ptrace.c | 325 ++++++++++++++++++++++++++++++++++
2 files changed, 363 insertions(+)
create mode 100644 arch/nds32/include/uapi/asm/ptrace.h
create mode 100644 arch/nds32/kernel/ptrace.c
diff --git a/arch/nds32/include/uapi/asm/ptrace.h b/arch/nds32/include/uapi/asm/ptrace.h
new file mode 100644
index 0000000..76fe2ae
--- /dev/null
+++ b/arch/nds32/include/uapi/asm/ptrace.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UAPI_ASM_NDS32_PTRACE_H
+#define __UAPI_ASM_NDS32_PTRACE_H
+
+#ifndef __ASSEMBLY__
+
+/*
+ * User structures for general purpose register.
+ */
+struct user_pt_regs {
+ long uregs[26];
+ long fp;
+ long gp;
+ long lp;
+ long sp;
+ long ipc;
+ long lb;
+ long le;
+ long lc;
+ long syscallno;
+};
+#endif
+#endif
diff --git a/arch/nds32/kernel/ptrace.c b/arch/nds32/kernel/ptrace.c
new file mode 100644
index 0000000..d91b3b8
--- /dev/null
+++ b/arch/nds32/kernel/ptrace.c
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/security.h>
+#include <linux/init.h>
+#include <linux/uaccess.h>
+#include <linux/regset.h>
+#include <linux/tracehook.h>
+#include <linux/elf.h>
+#include <linux/sched/task_stack.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+
+enum nds32_regset {
+ REGSET_GPR,
+};
+
+static int gpr_get(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user * ubuf)
+{
+ struct user_pt_regs *uregs = &task_pt_regs(target)->user_regs;
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, -1);
+}
+
+static int gpr_set(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user * ubuf)
+{
+ int err;
+ struct user_pt_regs newregs = task_pt_regs(target)->user_regs;
+
+ err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newregs, 0, -1);
+ if (err)
+ return err;
+
+ task_pt_regs(target)->user_regs = newregs;
+ return 0;
+}
+
+static const struct user_regset nds32_regsets[] = {
+ [REGSET_GPR] = {
+ .core_note_type = NT_PRSTATUS,
+ .n = sizeof(struct user_pt_regs) / sizeof(u32),
+ .size = sizeof(u32),
+ .align = sizeof(u32),
+ .get = gpr_get,
+ .set = gpr_set}
+};
+
+static const struct user_regset_view nds32_user_view = {
+ .name = "nds32",.e_machine = EM_NDS32,
+ .regsets = nds32_regsets,.n = ARRAY_SIZE(nds32_regsets)
+};
+
+const struct user_regset_view *task_user_regset_view(struct task_struct *task)
+{
+ return &nds32_user_view;
+}
+
+/* get_user_reg()
+ *
+ * This routine will get a word off of the processes privileged stack.
+ * the offset is how far from the base addr as stored in the THREAD.
+ * this routine assumes that all the privileged stacks are in our
+ * data space.
+ */
+static inline unsigned int get_user_reg(struct task_struct *task, int offset)
+{
+ return task_pt_regs(task)->uregs[offset];
+}
+
+/* put_user_reg()
+ *
+ * this routine will put a word on the processes privileged stack.
+ * the offset is how far from the base addr as stored in the THREAD.
+ * this routine assumes that all the privileged stacks are in our
+ * data space.
+ */
+static inline int put_user_reg(struct task_struct *task, int offset, long data)
+{
+ struct pt_regs newregs, *regs = task_pt_regs(task);
+ int ret = -EINVAL;
+
+ newregs = *regs;
+ newregs.uregs[offset] = data;
+
+ if (valid_user_regs(&newregs)) {
+ regs->uregs[offset] = data;
+ ret = 0;
+ }
+
+ return ret;
+}
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure the single step bit is not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+ user_disable_single_step(child);
+}
+
+static void fill_sigtrap_info(struct task_struct *tsk,
+ struct pt_regs *regs,
+ int error_code, int si_code, struct siginfo *info)
+{
+ tsk->thread.trap_no = ENTRY_DEBUG_RELATED;
+ tsk->thread.error_code = error_code;
+
+ memset(info, 0, sizeof(*info));
+ info->si_signo = SIGTRAP;
+ info->si_code = si_code;
+ info->si_addr = (void __user *)instruction_pointer(regs);
+}
+
+void user_single_step_siginfo(struct task_struct *tsk,
+ struct pt_regs *regs, struct siginfo *info)
+{
+ fill_sigtrap_info(tsk, regs, 0, TRAP_BRKPT, info);
+}
+
+/*
+ * Handle hitting a breakpoint.
+ */
+void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
+ int error_code, int si_code)
+{
+ struct siginfo info;
+
+ fill_sigtrap_info(tsk, regs, error_code, TRAP_BRKPT, &info);
+ /* Send us the fake SIGTRAP */
+ force_sig_info(SIGTRAP, &info, tsk);
+}
+
+/* ptrace_read_user()
+ *
+ * Read the word at offset "off" into the "struct user". We
+ * actually access the pt_regs stored on the kernel stack.
+ */
+static int
+ptrace_read_user(struct task_struct *tsk, unsigned long off,
+ unsigned long __user * ret)
+{
+ unsigned long tmp = 0;
+
+ if (off < sizeof(struct pt_regs)) {
+ if (off & 3)
+ return -EIO;
+ tmp = get_user_reg(tsk, off >> 2);
+ return put_user(tmp, ret);
+ } else
+ return -EIO;
+}
+
+/* ptrace_write_user()
+ *
+ * Write the word at offset "off" into "struct user". We
+ * actually access the pt_regs stored on the kernel stack.
+ */
+static int
+ptrace_write_user(struct task_struct *tsk, unsigned long off, unsigned long val)
+{
+ if (off < sizeof(struct pt_regs)) {
+ if (off & 3)
+ return -EIO;
+ return put_user_reg(tsk, off >> 2, val);
+ } else
+ return -EIO;
+}
+
+/* ptrace_getregs()
+ *
+ * Get all user integer registers.
+ */
+static int ptrace_getregs(struct task_struct *tsk, void __user * uregs)
+{
+ struct pt_regs *regs = task_pt_regs(tsk);
+
+ return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0;
+}
+
+/* ptrace_setregs()
+ *
+ * Set all user integer registers.
+ */
+static int ptrace_setregs(struct task_struct *tsk, void __user * uregs)
+{
+ struct pt_regs newregs;
+ int ret;
+
+ ret = -EFAULT;
+ if (copy_from_user(&newregs, uregs, sizeof(struct pt_regs)) == 0) {
+ struct pt_regs *regs = task_pt_regs(tsk);
+
+ ret = -EINVAL;
+ if (valid_user_regs(&newregs)) {
+ *regs = newregs;
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
+/* ptrace_getfpregs()
+ *
+ * Get the child FPU state.
+ */
+static int ptrace_getfpregs(struct task_struct *tsk, void __user * ufpregs)
+{
+ return -EFAULT;
+}
+
+/*
+ * Set the child FPU state.
+ */
+static int ptrace_setfpregs(struct task_struct *tsk, void __user * ufpregs)
+{
+ return -EFAULT;
+}
+
+/* do_ptrace()
+ *
+ * Provide ptrace defined service.
+ */
+long arch_ptrace(struct task_struct *child, long request, unsigned long addr,
+ unsigned long data)
+{
+ int ret;
+
+ switch (request) {
+ case PTRACE_PEEKUSR:
+ ret =
+ ptrace_read_user(child, addr, (unsigned long __user *)data);
+ break;
+
+ case PTRACE_POKEUSR:
+ ret = ptrace_write_user(child, addr, data);
+ break;
+
+ case PTRACE_GETREGS:
+ ret = ptrace_getregs(child, (void __user *)data);
+ break;
+
+ case PTRACE_SETREGS:
+ ret = ptrace_setregs(child, (void __user *)data);
+ break;
+
+ case PTRACE_GETFPREGS:
+ ret = ptrace_getfpregs(child, (void __user *)data);
+ break;
+
+ case PTRACE_SETFPREGS:
+ ret = ptrace_setfpregs(child, (void __user *)data);
+ break;
+
+ default:
+ ret = ptrace_request(child, request, addr, data);
+ break;
+ }
+
+ return ret;
+}
+
+void user_enable_single_step(struct task_struct *child)
+{
+ struct pt_regs *regs;
+ regs = task_pt_regs(child);
+ regs->ipsw |= PSW_mskHSS;
+ set_tsk_thread_flag(child, TIF_SINGLESTEP);
+}
+
+void user_disable_single_step(struct task_struct *child)
+{
+ struct pt_regs *regs;
+ regs = task_pt_regs(child);
+ regs->ipsw &= ~PSW_mskHSS;
+ clear_tsk_thread_flag(child, TIF_SINGLESTEP);
+}
+
+/* sys_trace()
+ *
+ * syscall trace handler.
+ */
+
+asmlinkage int syscall_trace_enter(int syscall, struct pt_regs *regs)
+{
+ if (test_thread_flag(TIF_SYSCALL_TRACE)) {
+ if (tracehook_report_syscall_entry(regs))
+ return -1;
+ }
+ return syscall;
+}
+
+asmlinkage void syscall_trace_leave(struct pt_regs *regs)
+{
+ int step = test_thread_flag(TIF_SINGLESTEP);
+ if (step || test_thread_flag(TIF_SYSCALL_TRACE))
+ tracehook_report_syscall_exit(regs, step);
+
+}
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH 4/7 v2] net: ethernet: i825xx: Fix platform_get_irq's error checking
From: arvindY @ 2017-12-08 9:38 UTC (permalink / raw)
To: Sergei Shtylyov, David Miller
Cc: f.fainelli, netdev, michal.simek, linux-kernel, opendmb, mkl,
linux-arm-kernel, wg
In-Reply-To: <d0b7e1cc-4190-437a-6461-35cee6edc203@cogentembedded.com>
Hi David,
On Wednesday 06 December 2017 05:49 PM, Sergei Shtylyov wrote:
> On 12/05/2017 06:49 PM, David Miller wrote:
>
>>>> From: Arvind Yadav <arvind.yadav.cs@gmail.com>
>>>> Date: Mon, 4 Dec 2017 23:18:20 +0530
>>>>
>>>>> @@ -120,9 +120,10 @@ static int sni_82596_probe(struct
>>>>> platform_device
>>>>> *dev)
>>>>> netdevice->dev_addr[5] = readb(eth_addr + 0x06);
>>>>> iounmap(eth_addr);
>>>>> - if (!netdevice->irq) {
>>>>> + if (netdevice->irq <= 0) {
>>>>> printk(KERN_ERR "%s: IRQ not found for i82596 at 0x%lx\n",
>>>>> __FILE__, netdevice->base_addr);
>>>>> + retval = netdevice->irq ? netdevice->irq : -ENODEV;
>>>>> goto probe_failed;
>>>>> }
>>>> Ok, thinking about this some more...
>>>>
>>>> It is impossible to use platform_get_irq() without every single call
>>>> site having this funny:
>>>>
>>>> ret = val ? val : -ENODEV;
>>>>
>>>> sequence.
>>>>
>>>> This is unnecessary duplication and it is also error prone, so I
>>>> really think this logic belongs in platform_get_irq() itself. It can
>>>> convert '0' to -ENODEV and that way we need no special logic in the
>>>> callers at all.
>>> platform_get_irq() will return 0 only for sparc, If sparc initialize
>>> platform
>>> data irq[PROMINTR_MAX] as zero. Otherwise platform_get_irq() will
>>> never return
>>> 0. It will return either IRQ number or error (as negative number). But
>>> I am getting
>>> review comment by reviewer/maintainer in other subsystem to add check
>>> for
>>> zero. So I have done same changes here. Please correct me if i am
>>> wrong.
>>
>> If you make the change that I suggest, you instead can check for
>
> I assume such change is needed only for the SPARC-specific section
> of platform_get_irq()?
>
>> '-ENODEV' to mean no IRQ.
>
> No specific error check is needed, just irq < 0 check should be
> enough...
> Also, looking at platform_get_irq(), -ENXIO should be returned in this
> case.
>
> MBR, Sergei
Is it ok. If We will add a check for only < 0.
Regards
Arvind
^ permalink raw reply
* [PATCH v3 09/33] nds32: Cache and TLB routines
From: Greentime Hu @ 2017-12-08 9:11 UTC (permalink / raw)
To: greentime, linux-kernel, arnd, linux-arch, tglx, jason,
marc.zyngier, robh+dt, netdev, deanbo422, devicetree, viro,
dhowells, will.deacon, daniel.lezcano, linux-serial,
geert.uytterhoeven, linus.walleij, mark.rutland, greg
Cc: green.hu, Vincent Chen
In-Reply-To: <cover.1512723245.git.green.hu@gmail.com>
From: Greentime Hu <greentime@andestech.com>
This patch contains cache and TLB maintenance functions.
Signed-off-by: Vincent Chen <vincentc@andestech.com>
Signed-off-by: Greentime Hu <greentime@andestech.com>
---
arch/nds32/include/asm/cache.h | 25 ++
arch/nds32/include/asm/cache_info.h | 26 ++
arch/nds32/include/asm/cacheflush.h | 57 ++++
arch/nds32/include/asm/mmu_context.h | 81 +++++
arch/nds32/include/asm/proc-fns.h | 57 ++++
arch/nds32/include/asm/tlb.h | 41 +++
arch/nds32/include/asm/tlbflush.h | 60 ++++
arch/nds32/include/uapi/asm/cachectl.h | 19 ++
arch/nds32/kernel/cacheinfo.c | 62 ++++
arch/nds32/mm/cacheflush.c | 331 ++++++++++++++++++++
arch/nds32/mm/proc.c | 527 ++++++++++++++++++++++++++++++++
arch/nds32/mm/tlb.c | 63 ++++
12 files changed, 1349 insertions(+)
create mode 100644 arch/nds32/include/asm/cache.h
create mode 100644 arch/nds32/include/asm/cache_info.h
create mode 100644 arch/nds32/include/asm/cacheflush.h
create mode 100644 arch/nds32/include/asm/mmu_context.h
create mode 100644 arch/nds32/include/asm/proc-fns.h
create mode 100644 arch/nds32/include/asm/tlb.h
create mode 100644 arch/nds32/include/asm/tlbflush.h
create mode 100644 arch/nds32/include/uapi/asm/cachectl.h
create mode 100644 arch/nds32/kernel/cacheinfo.c
create mode 100644 arch/nds32/mm/cacheflush.c
create mode 100644 arch/nds32/mm/proc.c
create mode 100644 arch/nds32/mm/tlb.c
diff --git a/arch/nds32/include/asm/cache.h b/arch/nds32/include/asm/cache.h
new file mode 100644
index 0000000..36ec549
--- /dev/null
+++ b/arch/nds32/include/asm/cache.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __NDS32_CACHE_H__
+#define __NDS32_CACHE_H__
+
+#define L1_CACHE_BYTES 32
+#define L1_CACHE_SHIFT 5
+
+#define ARCH_DMA_MINALIGN L1_CACHE_BYTES
+
+#endif /* __NDS32_CACHE_H__ */
diff --git a/arch/nds32/include/asm/cache_info.h b/arch/nds32/include/asm/cache_info.h
new file mode 100644
index 0000000..2b17b7d
--- /dev/null
+++ b/arch/nds32/include/asm/cache_info.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+struct cache_info {
+ unsigned char ways;
+ unsigned char line_size;
+ unsigned short sets;
+ unsigned short size;
+#if defined(CONFIG_CPU_CACHE_ALIASING)
+ unsigned short aliasing_num;
+ unsigned int aliasing_mask;
+#endif
+};
diff --git a/arch/nds32/include/asm/cacheflush.h b/arch/nds32/include/asm/cacheflush.h
new file mode 100644
index 0000000..5b95a6c
--- /dev/null
+++ b/arch/nds32/include/asm/cacheflush.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __NDS32_CACHEFLUSH_H__
+#define __NDS32_CACHEFLUSH_H__
+
+#include <linux/mm.h>
+
+#define PG_dcache_dirty PG_arch_1
+
+#ifdef CONFIG_CPU_CACHE_ALIASING
+void flush_cache_mm(struct mm_struct *mm);
+void flush_cache_dup_mm(struct mm_struct *mm);
+void flush_cache_range(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end);
+void flush_cache_page(struct vm_area_struct *vma,
+ unsigned long addr, unsigned long pfn);
+void flush_cache_kmaps(void);
+void flush_cache_vmap(unsigned long start, unsigned long end);
+void flush_cache_vunmap(unsigned long start, unsigned long end);
+
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
+void flush_dcache_page(struct page *page);
+void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long vaddr, void *dst, void *src, int len);
+void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long vaddr, void *dst, void *src, int len);
+
+#define ARCH_HAS_FLUSH_ANON_PAGE
+void flush_anon_page(struct vm_area_struct *vma,
+ struct page *page, unsigned long vaddr);
+
+#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
+void flush_kernel_dcache_page(struct page *page);
+void flush_icache_range(unsigned long start, unsigned long end);
+void flush_icache_page(struct vm_area_struct *vma, struct page *page);
+#define flush_dcache_mmap_lock(mapping) spin_lock_irq(&(mapping)->tree_lock)
+#define flush_dcache_mmap_unlock(mapping) spin_unlock_irq(&(mapping)->tree_lock)
+
+#else
+#include <asm-generic/cacheflush.h>
+#endif
+
+#endif /* __NDS32_CACHEFLUSH_H__ */
diff --git a/arch/nds32/include/asm/mmu_context.h b/arch/nds32/include/asm/mmu_context.h
new file mode 100644
index 0000000..4a59b5d
--- /dev/null
+++ b/arch/nds32/include/asm/mmu_context.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ASM_NDS32_MMU_CONTEXT_H
+#define __ASM_NDS32_MMU_CONTEXT_H
+
+#include <linux/spinlock.h>
+#include <asm/tlbflush.h>
+#include <asm/proc-fns.h>
+#include <asm-generic/mm_hooks.h>
+
+static inline int
+init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+ mm->context.id = 0;
+ return 0;
+}
+
+#define destroy_context(mm) do { } while(0)
+
+#define CID_BITS 9
+extern spinlock_t cid_lock;
+extern unsigned int cpu_last_cid;
+
+static inline void __new_context(struct mm_struct *mm)
+{
+ unsigned int cid;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cid_lock, flags);
+ cid = cpu_last_cid;
+ cpu_last_cid += 1 << TLB_MISC_offCID;
+ if (cpu_last_cid == 0)
+ cpu_last_cid = 1 << TLB_MISC_offCID << CID_BITS;
+
+ if ((cid & TLB_MISC_mskCID) == 0)
+ flush_tlb_all();
+ spin_unlock_irqrestore(&cid_lock, flags);
+
+ mm->context.id = cid;
+}
+
+static inline void check_context(struct mm_struct *mm)
+{
+ if (unlikely
+ ((mm->context.id ^ cpu_last_cid) >> TLB_MISC_offCID >> CID_BITS))
+ __new_context(mm);
+}
+
+static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+{
+}
+
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
+ struct task_struct *tsk)
+{
+ unsigned int cpu = smp_processor_id();
+
+ if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next) {
+ check_context(next);
+ cpu_switch_mm(next);
+ }
+}
+
+#define deactivate_mm(tsk,mm) do { } while (0)
+#define activate_mm(prev,next) switch_mm(prev, next, NULL)
+
+#endif
diff --git a/arch/nds32/include/asm/proc-fns.h b/arch/nds32/include/asm/proc-fns.h
new file mode 100644
index 0000000..b1a56d2
--- /dev/null
+++ b/arch/nds32/include/asm/proc-fns.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __NDS32_PROCFNS_H__
+#define __NDS32_PROCFNS_H__
+
+#ifdef __KERNEL__
+#include <asm/page.h>
+
+struct mm_struct;
+struct vm_area_struct;
+extern void cpu_proc_init(void);
+extern void cpu_proc_fin(void);
+extern void cpu_do_idle(void);
+extern void cpu_reset(unsigned long reset);
+extern void cpu_switch_mm(struct mm_struct *mm);
+
+extern void cpu_dcache_inval_all(void);
+extern void cpu_dcache_wbinval_all(void);
+extern void cpu_dcache_inval_page(unsigned long page);
+extern void cpu_dcache_wb_page(unsigned long page);
+extern void cpu_dcache_wbinval_page(unsigned long page);
+extern void cpu_dcache_inval_range(unsigned long start, unsigned long end);
+extern void cpu_dcache_wb_range(unsigned long start, unsigned long end);
+extern void cpu_dcache_wbinval_range(unsigned long start, unsigned long end);
+
+extern void cpu_icache_inval_all(void);
+extern void cpu_icache_inval_page(unsigned long page);
+extern void cpu_icache_inval_range(unsigned long start, unsigned long end);
+
+extern void cpu_cache_wbinval_page(unsigned long page, int flushi);
+extern void cpu_cache_wbinval_range(unsigned long start,
+ unsigned long end, int flushi);
+extern void cpu_cache_wbinval_range_check(struct vm_area_struct *vma,
+ unsigned long start,
+ unsigned long end, bool flushi,
+ bool wbd);
+
+extern void cpu_dma_wb_range(unsigned long start, unsigned long end);
+extern void cpu_dma_inval_range(unsigned long start, unsigned long end);
+extern void cpu_dma_wbinval_range(unsigned long start, unsigned long end);
+
+#endif /* __KERNEL__ */
+#endif /* __NDS32_PROCFNS_H__ */
diff --git a/arch/nds32/include/asm/tlb.h b/arch/nds32/include/asm/tlb.h
new file mode 100644
index 0000000..c599827
--- /dev/null
+++ b/arch/nds32/include/asm/tlb.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ASMNDS32_TLB_H
+#define __ASMNDS32_TLB_H
+
+#define tlb_start_vma(tlb,vma) \
+ do { \
+ if (!tlb->fullmm) \
+ flush_cache_range(vma, vma->vm_start, vma->vm_end); \
+ } while (0)
+
+#define tlb_end_vma(tlb,vma) \
+ do { \
+ if(!tlb->fullmm) \
+ flush_tlb_range(vma, vma->vm_start, vma->vm_end); \
+ } while (0)
+
+#define __tlb_remove_tlb_entry(tlb, pte, addr) do { } while (0)
+
+#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
+
+#include <asm-generic/tlb.h>
+
+#define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, pte)
+#define __pmd_free_tlb(tlb, pmd, addr) pmd_free((tln)->mm, pmd)
+
+#endif
diff --git a/arch/nds32/include/asm/tlbflush.h b/arch/nds32/include/asm/tlbflush.h
new file mode 100644
index 0000000..680aeb3
--- /dev/null
+++ b/arch/nds32/include/asm/tlbflush.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _ASMNDS32_TLBFLUSH_H
+#define _ASMNDS32_TLBFLUSH_H
+
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <nds32_intrinsic.h>
+
+static inline void local_flush_tlb_all(void)
+{
+ __nds32__tlbop_flua();
+ __nds32__isb();
+}
+
+static inline void local_flush_tlb_mm(struct mm_struct *mm)
+{
+ __nds32__tlbop_flua();
+ __nds32__isb();
+}
+
+static inline void local_flush_tlb_kernel_range(unsigned long start,
+ unsigned long end)
+{
+ while (start < end) {
+ __nds32__tlbop_inv(start);
+ __nds32__isb();
+ start += PAGE_SIZE;
+ }
+}
+
+void local_flush_tlb_range(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end);
+void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long addr);
+
+#define flush_tlb_all local_flush_tlb_all
+#define flush_tlb_mm local_flush_tlb_mm
+#define flush_tlb_range local_flush_tlb_range
+#define flush_tlb_page local_flush_tlb_page
+#define flush_tlb_kernel_range local_flush_tlb_kernel_range
+
+void update_mmu_cache(struct vm_area_struct *vma,
+ unsigned long address, pte_t * pte);
+void tlb_migrate_finish(struct mm_struct *mm);
+
+#endif
diff --git a/arch/nds32/include/uapi/asm/cachectl.h b/arch/nds32/include/uapi/asm/cachectl.h
new file mode 100644
index 0000000..a56a37d
--- /dev/null
+++ b/arch/nds32/include/uapi/asm/cachectl.h
@@ -0,0 +1,19 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1994, 1995, 1996 by Ralf Baechle
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ */
+#ifndef _ASM_CACHECTL
+#define _ASM_CACHECTL
+
+/*
+ * Options for cacheflush system call
+ */
+#define ICACHE 0 /* flush instruction cache */
+#define DCACHE 1 /* writeback and flush data cache */
+#define BCACHE 2 /* flush instruction cache + writeback and flush data cache */
+
+#endif /* _ASM_CACHECTL */
diff --git a/arch/nds32/kernel/cacheinfo.c b/arch/nds32/kernel/cacheinfo.c
new file mode 100644
index 0000000..edc0fda
--- /dev/null
+++ b/arch/nds32/kernel/cacheinfo.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/bitops.h>
+#include <linux/cacheinfo.h>
+#include <linux/cpu.h>
+
+static void ci_leaf_init(struct cacheinfo *this_leaf,
+ enum cache_type type, unsigned int level)
+{
+ char cache_type = (type & CACHE_TYPE_INST ? ICACHE : DCACHE);
+
+ this_leaf->level = level;
+ this_leaf->type = type;
+ this_leaf->coherency_line_size = CACHE_LINE_SIZE(cache_type);
+ this_leaf->number_of_sets = CACHE_SET(cache_type);;
+ this_leaf->ways_of_associativity = CACHE_WAY(cache_type);
+ this_leaf->size = this_leaf->number_of_sets *
+ this_leaf->coherency_line_size * this_leaf->ways_of_associativity;
+#if defined(CONFIG_CPU_DCACHE_WRITETHROUGH)
+ this_leaf->attributes = CACHE_WRITE_THROUGH;
+#else
+ this_leaf->attributes = CACHE_WRITE_BACK;
+#endif
+}
+
+int init_cache_level(unsigned int cpu)
+{
+ struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+
+ /* Only 1 level and I/D cache seperate. */
+ this_cpu_ci->num_levels = 1;
+ this_cpu_ci->num_leaves = 2;
+ return 0;
+}
+
+int populate_cache_leaves(unsigned int cpu)
+{
+ unsigned int level, idx;
+ struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+ struct cacheinfo *this_leaf = this_cpu_ci->info_list;
+
+ for (idx = 0, level = 1; level <= this_cpu_ci->num_levels &&
+ idx < this_cpu_ci->num_leaves; idx++, level++) {
+ ci_leaf_init(this_leaf++, CACHE_TYPE_DATA, level);
+ ci_leaf_init(this_leaf++, CACHE_TYPE_INST, level);
+ }
+ return 0;
+}
diff --git a/arch/nds32/mm/cacheflush.c b/arch/nds32/mm/cacheflush.c
new file mode 100644
index 0000000..69a85f7
--- /dev/null
+++ b/arch/nds32/mm/cacheflush.c
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include <linux/module.h>
+#include <asm/cacheflush.h>
+#include <asm/proc-fns.h>
+#include <asm/shmparam.h>
+#include <asm/cache_info.h>
+
+extern struct cache_info L1_cache_info[2];
+
+#ifndef CONFIG_CPU_CACHE_ALIASING
+void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr,
+ pte_t * pte)
+{
+ struct page *page;
+ unsigned long pfn = pte_pfn(*pte);
+
+ if (!pfn_valid(pfn))
+ return;
+
+ if (vma->vm_mm == current->active_mm) {
+
+ __nds32__mtsr_dsb(addr, NDS32_SR_TLB_VPN);
+ __nds32__tlbop_rwr(*pte);
+ __nds32__isb();
+ }
+ page = pfn_to_page(pfn);
+
+ if ((test_and_clear_bit(PG_dcache_dirty, &page->flags)) ||
+ (vma->vm_flags & VM_EXEC)) {
+
+ if (!PageHighMem(page)) {
+ cpu_cache_wbinval_page((unsigned long)
+ page_address(page),
+ vma->vm_flags & VM_EXEC);
+ } else {
+ unsigned long kaddr = (unsigned long)kmap_atomic(page);
+ cpu_cache_wbinval_page(kaddr, vma->vm_flags & VM_EXEC);
+ kunmap_atomic((void *)kaddr);
+ }
+ }
+}
+#else
+extern pte_t va_present(struct mm_struct *mm, unsigned long addr);
+
+static inline unsigned long aliasing(unsigned long addr, unsigned long page)
+{
+ return ((addr & PAGE_MASK) ^ page) & (SHMLBA - 1);
+}
+
+static inline unsigned long kremap0(unsigned long uaddr, unsigned long pa)
+{
+ unsigned long kaddr, pte;
+
+#define BASE_ADDR0 0xffffc000
+ kaddr = BASE_ADDR0 | (uaddr & L1_cache_info[DCACHE].aliasing_mask);
+ pte = (pa | PAGE_KERNEL);
+ __nds32__mtsr_dsb(kaddr, NDS32_SR_TLB_VPN);
+ __nds32__tlbop_rwlk(pte);
+ __nds32__isb();
+ return kaddr;
+}
+
+static inline void kunmap01(unsigned long kaddr)
+{
+ __nds32__tlbop_unlk(kaddr);
+ __nds32__tlbop_inv(kaddr);
+ __nds32__isb();
+}
+
+static inline unsigned long kremap1(unsigned long uaddr, unsigned long pa)
+{
+ unsigned long kaddr, pte;
+
+#define BASE_ADDR1 0xffff8000
+ kaddr = BASE_ADDR1 | (uaddr & L1_cache_info[DCACHE].aliasing_mask);
+ pte = (pa | PAGE_KERNEL);
+ __nds32__mtsr_dsb(kaddr, NDS32_SR_TLB_VPN);
+ __nds32__tlbop_rwlk(pte);
+ __nds32__isb();
+ return kaddr;
+}
+
+void flush_cache_mm(struct mm_struct *mm)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ cpu_dcache_wbinval_all();
+ cpu_icache_inval_all();
+ local_irq_restore(flags);
+}
+
+void flush_cache_dup_mm(struct mm_struct *mm)
+{
+}
+
+void flush_cache_range(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)
+{
+ unsigned long flags;
+
+ if ((end - start) > 8 * PAGE_SIZE) {
+ cpu_dcache_wbinval_all();
+ if (vma->vm_flags & VM_EXEC)
+ cpu_icache_inval_all();
+ return;
+ }
+ local_irq_save(flags);
+ while (start < end) {
+ if (va_present(vma->vm_mm, start))
+ cpu_cache_wbinval_page(start, vma->vm_flags & VM_EXEC);
+ start += PAGE_SIZE;
+ }
+ local_irq_restore(flags);
+ return;
+}
+
+void flush_cache_page(struct vm_area_struct *vma,
+ unsigned long addr, unsigned long pfn)
+{
+ unsigned long vto, flags;
+
+ local_irq_save(flags);
+ vto = kremap0(addr, pfn << PAGE_SHIFT);
+ cpu_cache_wbinval_page(vto, vma->vm_flags & VM_EXEC);
+ kunmap01(vto);
+ local_irq_restore(flags);
+}
+
+void flush_cache_vmap(unsigned long start, unsigned long end)
+{
+ cpu_dcache_wbinval_all();
+ cpu_icache_inval_all();
+}
+
+void flush_cache_vunmap(unsigned long start, unsigned long end)
+{
+ cpu_dcache_wbinval_all();
+ cpu_icache_inval_all();
+}
+
+void copy_user_highpage(struct page *to, struct page *from,
+ unsigned long vaddr, struct vm_area_struct *vma)
+{
+ unsigned long vto, vfrom, flags, kto, kfrom, pfrom, pto;
+ kto = ((unsigned long)page_address(to) & PAGE_MASK);
+ kfrom = ((unsigned long)page_address(from) & PAGE_MASK);
+ pto = page_to_phys(to);
+ pfrom = page_to_phys(from);
+
+ if (aliasing(vaddr, (unsigned long)kfrom))
+ cpu_dcache_wb_page((unsigned long)kfrom);
+ if (aliasing(vaddr, (unsigned long)kto))
+ cpu_dcache_inval_page((unsigned long)kto);
+ local_irq_save(flags);
+ vto = kremap0(vaddr, pto);
+ vfrom = kremap1(vaddr, pfrom);
+ copy_page((void *)vto, (void *)vfrom);
+ kunmap01(vfrom);
+ kunmap01(vto);
+ local_irq_restore(flags);
+}
+
+EXPORT_SYMBOL(copy_user_highpage);
+
+void clear_user_highpage(struct page *page, unsigned long vaddr)
+{
+ unsigned long vto, flags, kto;
+
+ kto = ((unsigned long)page_address(page) & PAGE_MASK);
+
+ local_irq_save(flags);
+ if (aliasing(kto, vaddr) && kto != 0) {
+ cpu_dcache_inval_page(kto);
+ cpu_icache_inval_page(kto);
+ }
+ vto = kremap0(vaddr, page_to_phys(page));
+ clear_page((void *)vto);
+ kunmap01(vto);
+ local_irq_restore(flags);
+}
+
+EXPORT_SYMBOL(clear_user_highpage);
+
+void flush_dcache_page(struct page *page)
+{
+ struct address_space *mapping;
+
+ mapping = page_mapping(page);
+ if (mapping && !mapping_mapped(mapping))
+ set_bit(PG_dcache_dirty, &page->flags);
+ else {
+ int i, pc;
+ unsigned long vto, kaddr, flags;
+ kaddr = (unsigned long)page_address(page);
+ cpu_dcache_wbinval_page(kaddr);
+ pc = CACHE_SET(DCACHE) * CACHE_LINE_SIZE(DCACHE) / PAGE_SIZE;
+ local_irq_save(flags);
+ for (i = 0; i < pc; i++) {
+ vto =
+ kremap0(kaddr + i * PAGE_SIZE, page_to_phys(page));
+ cpu_dcache_wbinval_page(vto);
+ kunmap01(vto);
+ }
+ local_irq_restore(flags);
+ }
+}
+
+void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long vaddr, void *dst, void *src, int len)
+{
+ unsigned long line_size, start, end, vto, flags;
+
+ local_irq_save(flags);
+ vto = kremap0(vaddr, page_to_phys(page));
+ dst = (void *)(vto | (vaddr & (PAGE_SIZE - 1)));
+ memcpy(dst, src, len);
+ if (vma->vm_flags & VM_EXEC) {
+ line_size = L1_cache_info[DCACHE].line_size;
+ start = (unsigned long)dst & ~(line_size - 1);
+ end =
+ ((unsigned long)dst + len + line_size - 1) & ~(line_size -
+ 1);
+ cpu_cache_wbinval_range(start, end, 1);
+ }
+ kunmap01(vto);
+ local_irq_restore(flags);
+}
+
+void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long vaddr, void *dst, void *src, int len)
+{
+ unsigned long vto, flags;
+
+ local_irq_save(flags);
+ vto = kremap0(vaddr, page_to_phys(page));
+ src = (void *)(vto | (vaddr & (PAGE_SIZE - 1)));
+ memcpy(dst, src, len);
+ kunmap01(vto);
+ local_irq_restore(flags);
+}
+
+void flush_anon_page(struct vm_area_struct *vma,
+ struct page *page, unsigned long vaddr)
+{
+ unsigned long flags;
+ if (!PageAnon(page))
+ return;
+
+ if (vma->vm_mm != current->active_mm)
+ return;
+
+ local_irq_save(flags);
+ if (vma->vm_flags & VM_EXEC)
+ cpu_icache_inval_page(vaddr & PAGE_MASK);
+ cpu_dcache_wbinval_page((unsigned long)page_address(page));
+ local_irq_restore(flags);
+}
+
+void flush_kernel_dcache_page(struct page *page)
+{
+ unsigned long flags;
+ local_irq_save(flags);
+ cpu_dcache_wbinval_page((unsigned long)page_address(page));
+ local_irq_restore(flags);
+}
+
+void flush_icache_range(unsigned long start, unsigned long end)
+{
+ unsigned long line_size, flags;
+ line_size = L1_cache_info[DCACHE].line_size;
+ start = start & ~(line_size - 1);
+ end = (end + line_size - 1) & ~(line_size - 1);
+ local_irq_save(flags);
+ cpu_cache_wbinval_range(start, end, 1);
+ local_irq_restore(flags);
+}
+
+void flush_icache_page(struct vm_area_struct *vma, struct page *page)
+{
+ unsigned long flags;
+ local_irq_save(flags);
+ cpu_cache_wbinval_page((unsigned long)page_address(page),
+ vma->vm_flags & VM_EXEC);
+ local_irq_restore(flags);
+}
+
+void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr,
+ pte_t * pte)
+{
+ struct page *page;
+ unsigned long flags;
+ unsigned long pfn = pte_pfn(*pte);
+
+ if (!pfn_valid(pfn))
+ return;
+
+ if (vma->vm_mm == current->active_mm) {
+ __nds32__mtsr_dsb(addr, NDS32_SR_TLB_VPN);
+ __nds32__tlbop_rwr(*pte);
+ __nds32__isb();
+ }
+
+ page = pfn_to_page(pfn);
+ if (test_and_clear_bit(PG_dcache_dirty, &page->flags) ||
+ (vma->vm_flags & VM_EXEC)) {
+ local_irq_save(flags);
+ cpu_dcache_wbinval_page((unsigned long)page_address(page));
+ local_irq_restore(flags);
+ }
+}
+#endif
diff --git a/arch/nds32/mm/proc.c b/arch/nds32/mm/proc.c
new file mode 100644
index 0000000..b78c25a
--- /dev/null
+++ b/arch/nds32/mm/proc.c
@@ -0,0 +1,527 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm/nds32.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
+#include <asm/l2_cache.h>
+#include <nds32_intrinsic.h>
+
+#include <asm/cache_info.h>
+extern struct cache_info L1_cache_info[2];
+
+int va_kernel_present(unsigned long addr)
+{
+ pmd_t *pmd;
+ pte_t *ptep, pte;
+
+ pmd = pmd_offset(pgd_offset_k(addr), addr);
+ if (!pmd_none(*pmd)) {
+ ptep = pte_offset_map(pmd, addr);
+ pte = *ptep;
+ if (pte_present(pte))
+ return pte;
+ }
+ return 0;
+}
+
+pte_t va_present(struct mm_struct * mm, unsigned long addr)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *ptep, pte;
+
+ pgd = pgd_offset(mm, addr);
+ if (!pgd_none(*pgd)) {
+ pud = pud_offset(pgd, addr);
+ if (!pud_none(*pud)) {
+ pmd = pmd_offset(pud, addr);
+ if (!pmd_none(*pmd)) {
+ ptep = pte_offset_map(pmd, addr);
+ pte = *ptep;
+ if (pte_present(pte))
+ return pte;
+ }
+ }
+ }
+ return 0;
+
+}
+
+int va_readable(struct pt_regs *regs, unsigned long addr)
+{
+ struct mm_struct *mm = current->mm;
+ pte_t pte;
+ int ret = 0;
+
+ if (user_mode(regs)) {
+ /* user mode */
+ pte = va_present(mm, addr);
+ if (!pte && pte_read(pte))
+ ret = 1;
+ } else {
+ /* superuser mode is always readable, so we can only
+ * check it is present or not*/
+ return (! !va_kernel_present(addr));
+ }
+ return ret;
+}
+
+int va_writable(struct pt_regs *regs, unsigned long addr)
+{
+ struct mm_struct *mm = current->mm;
+ pte_t pte;
+ int ret = 0;
+
+ if (user_mode(regs)) {
+ /* user mode */
+ pte = va_present(mm, addr);
+ if (!pte && pte_write(pte))
+ ret = 1;
+ } else {
+ /* superuser mode */
+ pte = va_kernel_present(addr);
+ if (!pte && pte_kernel_write(pte))
+ ret = 1;
+ }
+ return ret;
+}
+
+/*
+ * All
+ */
+void cpu_icache_inval_all(void)
+{
+ unsigned long end, line_size;
+
+ line_size = L1_cache_info[ICACHE].line_size;
+ end =
+ line_size * L1_cache_info[ICACHE].ways * L1_cache_info[ICACHE].sets;
+
+ do {
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL"::"r" (end));
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL"::"r" (end));
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL"::"r" (end));
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL"::"r" (end));
+ } while (end > 0);
+}
+
+void cpu_dcache_inval_all(void)
+{
+ __nds32__cctl_l1d_invalall();
+ __nds32__msync_all();
+}
+
+void cpu_dcache_wb_all(void)
+{
+#ifdef CONFIG_CACHE_L2
+ if (atl2c_base)
+ __nds32__cctl_l1d_wball_alvl();
+ else
+ __nds32__cctl_l1d_wball_one_lvl();
+#else
+ __nds32__cctl_l1d_wball_one_lvl();
+#endif
+ __nds32__msync_all();
+}
+
+void cpu_dcache_wbinval_all(void)
+{
+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ unsigned long flags;
+ local_irq_save(flags);
+#endif
+ cpu_dcache_wb_all();
+ cpu_dcache_inval_all();
+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ local_irq_restore(flags);
+#endif
+}
+
+/*
+ * Page
+ */
+void cpu_icache_inval_page(unsigned long start)
+{
+ unsigned long line_size, end;
+
+ line_size = L1_cache_info[ICACHE].line_size;
+ end = start + PAGE_SIZE;
+
+ do {
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (end));
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (end));
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (end));
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (end));
+ } while (end != start);
+}
+
+void cpu_dcache_inval_page(unsigned long start)
+{
+ unsigned long line_size, end;
+
+ line_size = L1_cache_info[DCACHE].line_size;
+ end = start + PAGE_SIZE;
+
+ do {
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end));
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end));
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end));
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end));
+ } while (end != start);
+ __nds32__msync_all();
+}
+
+void cpu_dcache_wb_page(unsigned long start)
+{
+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ unsigned long line_size, end;
+
+ line_size = L1_cache_info[DCACHE].line_size;
+ end = start + PAGE_SIZE;
+
+ do {
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end));
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end));
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end));
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end));
+ } while (end != start);
+ __nds32__msync_all();
+#endif
+}
+
+void cpu_dcache_wbinval_page(unsigned long start)
+{
+ unsigned long line_size, end;
+
+ line_size = L1_cache_info[DCACHE].line_size;
+ end = start + PAGE_SIZE;
+
+ do {
+ end -= line_size;
+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end));
+#endif
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end));
+ end -= line_size;
+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end));
+#endif
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end));
+ end -= line_size;
+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end));
+#endif
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end));
+ end -= line_size;
+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end));
+#endif
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end));
+ } while (end != start);
+ __nds32__msync_all();
+}
+
+void cpu_cache_wbinval_page(unsigned long page, int flushi)
+{
+ cpu_dcache_wbinval_page(page);
+ if (flushi)
+ cpu_icache_inval_page(page);
+}
+
+/*
+ * Range
+ */
+void cpu_icache_inval_range(unsigned long start, unsigned long end)
+{
+ unsigned long line_size;
+
+ line_size = L1_cache_info[ICACHE].line_size;
+
+ while (end > start) {
+ __asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (start));
+ start += line_size;
+ }
+}
+
+void cpu_dcache_inval_range(unsigned long start, unsigned long end)
+{
+ unsigned long line_size;
+
+ line_size = L1_cache_info[DCACHE].line_size;
+
+ while (end > start) {
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (start));
+ start += line_size;
+ }
+ __nds32__msync_all();
+}
+
+void cpu_dcache_wb_range(unsigned long start, unsigned long end)
+{
+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ unsigned long line_size;
+
+ line_size = L1_cache_info[DCACHE].line_size;
+
+ while (end > start) {
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (start));
+ start += line_size;
+ }
+ __nds32__msync_all();
+#endif
+}
+
+void cpu_dcache_wbinval_range(unsigned long start, unsigned long end)
+{
+ unsigned long line_size;
+
+ line_size = L1_cache_info[DCACHE].line_size;
+
+ while (end > start) {
+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (start));
+#endif
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (start));
+ start += line_size;
+ }
+ __nds32__msync_all();
+}
+
+void cpu_cache_wbinval_range(unsigned long start, unsigned long end, int flushi)
+{
+ unsigned long line_size, align_start, align_end;
+
+ line_size = L1_cache_info[DCACHE].line_size;
+ align_start = start & ~(line_size - 1);
+ align_end = (end + line_size - 1) & ~(line_size - 1);
+ cpu_dcache_wbinval_range(align_start, align_end);
+
+ if (flushi) {
+ line_size = L1_cache_info[ICACHE].line_size;
+ align_start = start & ~(line_size - 1);
+ align_end = (end + line_size - 1) & ~(line_size - 1);
+ cpu_icache_inval_range(align_start, align_end);
+ }
+}
+
+void cpu_cache_wbinval_range_check(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end,
+ bool flushi, bool wbd)
+{
+ unsigned long line_size, t_start, t_end;
+
+ if (!flushi && !wbd)
+ return;
+ line_size = L1_cache_info[DCACHE].line_size;
+ start = start & ~(line_size - 1);
+ end = (end + line_size - 1) & ~(line_size - 1);
+
+ if ((end - start) > (8 * PAGE_SIZE)) {
+ if (wbd)
+ cpu_dcache_wbinval_all();
+ if (flushi)
+ cpu_icache_inval_all();
+ __nds32__msync_all();
+ return;
+ }
+
+ t_start = (start + PAGE_SIZE) & PAGE_MASK;
+ t_end = ((end - 1) & PAGE_MASK);
+
+ if ((start & PAGE_MASK) == t_end) {
+ if (va_present(vma->vm_mm, start)) {
+ if (wbd)
+ cpu_dcache_wbinval_range(start, end);
+ if (flushi)
+ cpu_icache_inval_range(start, end);
+ }
+ __nds32__msync_all();
+ return;
+ }
+
+ if (va_present(vma->vm_mm, start)) {
+ if (wbd)
+ cpu_dcache_wbinval_range(start, t_start);
+ if (flushi)
+ cpu_icache_inval_range(start, t_start);
+ }
+
+ if (va_present(vma->vm_mm, end - 1)) {
+ if (wbd)
+ cpu_dcache_wbinval_range(t_end, end);
+ if (flushi)
+ cpu_icache_inval_range(t_end, end);
+ }
+
+ while (t_start < t_end) {
+ if (va_present(vma->vm_mm, t_start)) {
+ if (wbd)
+ cpu_dcache_wbinval_page(t_start);
+ if (flushi)
+ cpu_icache_inval_page(t_start);
+ }
+ t_start += PAGE_SIZE;
+ }
+ __nds32__msync_all();
+}
+static inline void cpu_l2cache_op(unsigned long start, unsigned long end, unsigned long op)
+{
+#ifdef CONFIG_CACHE_L2
+ if (atl2c_base) {
+ unsigned long p_start = __pa(start);
+ unsigned long p_end = __pa(end);
+ unsigned long cmd;
+ unsigned long line_size;
+ /* TODO Can Use PAGE Mode to optimize if range large than PAGE_SIZE */
+ line_size = L2_CACHE_LINE_SIZE();
+ p_start = p_start & (~(line_size - 1));
+ p_end = (p_end + line_size - 1) & (~(line_size - 1));
+ cmd =
+ (p_start & ~(line_size - 1)) | op |
+ CCTL_SINGLE_CMD;
+ do {
+ L2_CMD_RDY();
+ L2C_W_REG(L2_CCTL_CMD_OFF, cmd);
+ cmd += line_size;
+ p_start += line_size;
+ } while (p_end > p_start);
+ cmd = CCTL_CMD_L2_SYNC;
+ L2_CMD_RDY();
+ L2C_W_REG(L2_CCTL_CMD_OFF, cmd);
+ L2_CMD_RDY();
+ }
+#endif
+}
+/*
+ * DMA
+ */
+void cpu_dma_wb_range(unsigned long start, unsigned long end)
+{
+ unsigned long line_size;
+ unsigned long flags;
+ line_size = L1_cache_info[DCACHE].line_size;
+ start = start & (~(line_size - 1));
+ end = (end + line_size - 1) & (~(line_size - 1));
+ if (unlikely(start == end))
+ return;
+
+ local_irq_save(flags);
+ cpu_dcache_wb_range(start, end);
+ cpu_l2cache_op(start, end, CCTL_CMD_L2_PA_WB);
+ __nds32__msync_all();
+ local_irq_restore(flags);
+}
+
+void cpu_dma_inval_range(unsigned long start, unsigned long end)
+{
+ unsigned long line_size;
+ unsigned long old_start = start;
+ unsigned long old_end = end;
+ unsigned long flags;
+ line_size = L1_cache_info[DCACHE].line_size;
+ start = start & (~(line_size - 1));
+ end = (end + line_size - 1) & (~(line_size - 1));
+ if (unlikely(start == end))
+ return;
+ local_irq_save(flags);
+ if (start != old_start) {
+ cpu_dcache_wbinval_range(start, start + line_size);
+ cpu_l2cache_op(start, start + line_size, CCTL_CMD_L2_PA_WBINVAL);
+ }
+ if (end != old_end) {
+ cpu_dcache_wbinval_range(end - line_size, end);
+ cpu_l2cache_op(end - line_size, end, CCTL_CMD_L2_PA_WBINVAL);
+ }
+ cpu_dcache_inval_range(start, end);
+ cpu_l2cache_op(start, end, CCTL_CMD_L2_PA_INVAL);
+ __nds32__msync_all();
+ local_irq_restore(flags);
+
+}
+
+void cpu_dma_wbinval_range(unsigned long start, unsigned long end)
+{
+ unsigned long line_size;
+ unsigned long flags;
+ line_size = L1_cache_info[DCACHE].line_size;
+ start = start & (~(line_size - 1));
+ end = (end + line_size - 1) & (~(line_size - 1));
+ if (unlikely(start == end))
+ return;
+
+ local_irq_save(flags);
+ cpu_dcache_wbinval_range(start, end);
+ cpu_l2cache_op(start, end, CCTL_CMD_L2_PA_WBINVAL);
+ __nds32__msync_all();
+ local_irq_restore(flags);
+}
+
+void cpu_proc_init(void)
+{
+}
+
+void cpu_proc_fin(void)
+{
+}
+
+void cpu_do_idle(void)
+{
+ __nds32__standby_no_wake_grant();
+}
+
+void cpu_reset(unsigned long reset)
+{
+ u32 tmp;
+ GIE_DISABLE();
+ tmp = __nds32__mfsr(NDS32_SR_CACHE_CTL);
+ tmp &= ~(CACHE_CTL_mskIC_EN | CACHE_CTL_mskDC_EN);
+ __nds32__mtsr_isb(tmp, NDS32_SR_CACHE_CTL);
+ cpu_dcache_wbinval_all();
+ cpu_icache_inval_all();
+
+ __asm__ __volatile__("jr.toff %0\n\t"::"r"(reset));
+}
+
+void cpu_switch_mm(struct mm_struct *mm)
+{
+ unsigned long cid;
+ cid = __nds32__mfsr(NDS32_SR_TLB_MISC);
+ cid = (cid & ~TLB_MISC_mskCID) | mm->context.id;
+ __nds32__mtsr_dsb(cid, NDS32_SR_TLB_MISC);
+ __nds32__mtsr_isb(__pa(mm->pgd), NDS32_SR_L1_PPTB);
+}
diff --git a/arch/nds32/mm/tlb.c b/arch/nds32/mm/tlb.c
new file mode 100644
index 0000000..b397b9f
--- /dev/null
+++ b/arch/nds32/mm/tlb.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/spinlock_types.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <asm/nds32.h>
+#include <nds32_intrinsic.h>
+
+unsigned int cpu_last_cid = { TLB_MISC_mskCID + (2 << TLB_MISC_offCID) };
+
+DEFINE_SPINLOCK(cid_lock);
+
+void local_flush_tlb_range(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)
+{
+ unsigned long flags, ocid, ncid;
+
+ if ((end - start) > 0x400000) {
+ __nds32__tlbop_flua();
+ __nds32__isb();
+ return;
+ }
+
+ spin_lock_irqsave(&cid_lock, flags);
+ ocid = __nds32__mfsr(NDS32_SR_TLB_MISC);
+ ncid = (ocid & ~TLB_MISC_mskCID) | vma->vm_mm->context.id;
+ __nds32__mtsr_dsb(ncid, NDS32_SR_TLB_MISC);
+ while (start < end) {
+ __nds32__tlbop_inv(start);
+ __nds32__isb();
+ start += PAGE_SIZE;
+ }
+ __nds32__mtsr_dsb(ocid, NDS32_SR_TLB_MISC);
+ spin_unlock_irqrestore(&cid_lock, flags);
+}
+
+void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
+{
+ unsigned long flags, ocid, ncid;
+
+ spin_lock_irqsave(&cid_lock, flags);
+ ocid = __nds32__mfsr(NDS32_SR_TLB_MISC);
+ ncid = (ocid & ~TLB_MISC_mskCID) | vma->vm_mm->context.id;
+ __nds32__mtsr_dsb(ncid, NDS32_SR_TLB_MISC);
+ __nds32__tlbop_inv(addr);
+ __nds32__isb();
+ __nds32__mtsr_dsb(ocid, NDS32_SR_TLB_MISC);
+ spin_unlock_irqrestore(&cid_lock, flags);
+}
--
1.7.9.5
^ permalink raw reply related
* [PATCH v3 08/33] nds32: MMU fault handling and page table management
From: Greentime Hu @ 2017-12-08 9:11 UTC (permalink / raw)
To: greentime, linux-kernel, arnd, linux-arch, tglx, jason,
marc.zyngier, robh+dt, netdev, deanbo422, devicetree, viro,
dhowells, will.deacon, daniel.lezcano, linux-serial,
geert.uytterhoeven, linus.walleij, mark.rutland, greg
Cc: green.hu, Vincent Chen
In-Reply-To: <cover.1512723245.git.green.hu@gmail.com>
From: Greentime Hu <greentime@andestech.com>
This patch includes page fault handler, mmap and fixup implementations.
Signed-off-by: Vincent Chen <vincentc@andestech.com>
Signed-off-by: Greentime Hu <greentime@andestech.com>
---
arch/nds32/lib/copy_page.S | 50 ++++++
arch/nds32/mm/extable.c | 29 +++
arch/nds32/mm/fault.c | 424 ++++++++++++++++++++++++++++++++++++++++++++
arch/nds32/mm/mmap.c | 86 +++++++++
4 files changed, 589 insertions(+)
create mode 100644 arch/nds32/lib/copy_page.S
create mode 100644 arch/nds32/mm/extable.c
create mode 100644 arch/nds32/mm/fault.c
create mode 100644 arch/nds32/mm/mmap.c
diff --git a/arch/nds32/lib/copy_page.S b/arch/nds32/lib/copy_page.S
new file mode 100644
index 0000000..a55a5cc
--- /dev/null
+++ b/arch/nds32/lib/copy_page.S
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+#include <asm/page.h>
+
+ .text
+ENTRY(copy_page)
+ pushm $r2, $r10
+ movi $r2, PAGE_SIZE >> 5
+.Lcopy_loop:
+ lmw.bim $r3, [$r1], $r10
+ smw.bim $r3, [$r0], $r10
+ subi45 $r2, #1
+ bnez38 $r2, .Lcopy_loop
+ popm $r2, $r10
+ ret
+ENDPROC(copy_page)
+
+ENTRY(clear_page)
+ pushm $r1, $r9
+ movi $r1, PAGE_SIZE >> 5
+ movi55 $r2, #0
+ movi55 $r3, #0
+ movi55 $r4, #0
+ movi55 $r5, #0
+ movi55 $r6, #0
+ movi55 $r7, #0
+ movi55 $r8, #0
+ movi55 $r9, #0
+.Lclear_loop:
+ smw.bim $r2, [$r0], $r9
+ subi45 $r1, #1
+ bnez38 $r1, .Lclear_loop
+ popm $r1, $r9
+ ret
+ENDPROC(clear_page)
diff --git a/arch/nds32/mm/extable.c b/arch/nds32/mm/extable.c
new file mode 100644
index 0000000..bce62d7
--- /dev/null
+++ b/arch/nds32/mm/extable.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/extable.h>
+#include <asm/uaccess.h>
+
+int fixup_exception(struct pt_regs *regs)
+{
+ const struct exception_table_entry *fixup;
+
+ fixup = search_exception_tables(instruction_pointer(regs));
+ if (fixup)
+ regs->ipc = fixup->fixup;
+
+ return fixup != NULL;
+}
diff --git a/arch/nds32/mm/fault.c b/arch/nds32/mm/fault.c
new file mode 100644
index 0000000..00fa3df
--- /dev/null
+++ b/arch/nds32/mm/fault.c
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/extable.h>
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/ptrace.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/hardirq.h>
+#include <linux/uaccess.h>
+
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+#include <asm/uaccess.h>
+
+extern void die(const char *str, struct pt_regs *regs, long err);
+
+/*
+ * This is useful to dump out the page tables associated with
+ * 'addr' in mm 'mm'.
+ */
+void show_pte(struct mm_struct *mm, unsigned long addr)
+{
+ pgd_t *pgd;
+ if (!mm)
+ mm = &init_mm;
+
+ pr_alert("pgd = %p\n", mm->pgd);
+ pgd = pgd_offset(mm, addr);
+ pr_alert("[%08lx] *pgd=%08lx", addr, pgd_val(*pgd));
+
+ do {
+ pmd_t *pmd;
+
+ if (pgd_none(*pgd))
+ break;
+
+ if (pgd_bad(*pgd)) {
+ pr_alert("(bad)");
+ break;
+ }
+
+ pmd = pmd_offset(pgd, addr);
+#if PTRS_PER_PMD != 1
+ pr_alert(", *pmd=%08lx", pmd_val(*pmd));
+#endif
+
+ if (pmd_none(*pmd))
+ break;
+
+ if (pmd_bad(*pmd)) {
+ pr_alert("(bad)");
+ break;
+ }
+
+ if (IS_ENABLED(CONFIG_HIGHMEM))
+ {
+ pte_t *pte;
+ /* We must not map this if we have highmem enabled */
+ pte = pte_offset_map(pmd, addr);
+ pr_alert(", *pte=%08lx", pte_val(*pte));
+ pte_unmap(pte);
+ }
+ } while (0);
+
+ pr_alert("\n");
+}
+
+void do_page_fault(unsigned long entry, unsigned long addr,
+ unsigned int error_code, struct pt_regs *regs)
+{
+ struct task_struct *tsk;
+ struct mm_struct *mm;
+ struct vm_area_struct *vma;
+ siginfo_t info;
+ int fault;
+ unsigned int mask = VM_READ | VM_WRITE | VM_EXEC;
+ unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
+
+ error_code = error_code & (ITYPE_mskINST | ITYPE_mskETYPE);
+ tsk = current;
+ mm = tsk->mm;
+ info.si_code = SEGV_MAPERR;
+ /*
+ * We fault-in kernel-space virtual memory on-demand. The
+ * 'reference' page table is init_mm.pgd.
+ *
+ * NOTE! We MUST NOT take any locks for this case. We may
+ * be in an interrupt or a critical region, and should
+ * only copy the information from the master page table,
+ * nothing more.
+ */
+ if (addr >= TASK_SIZE) {
+ if (user_mode(regs))
+ goto bad_area_nosemaphore;
+
+ if (addr >= TASK_SIZE && addr < VMALLOC_END
+ && (entry == ENTRY_PTE_NOT_PRESENT))
+ goto vmalloc_fault;
+ else
+ goto no_context;
+ }
+
+ /* Send a signal to the task for handling the unalignment access. */
+ if (entry == ENTRY_GENERAL_EXCPETION
+ && error_code == ETYPE_ALIGNMENT_CHECK) {
+ if (user_mode(regs))
+ goto bad_area_nosemaphore;
+ else
+ goto no_context;
+ }
+
+ /*
+ * If we're in an interrupt or have no user
+ * context, we must not take the fault..
+ */
+ if (unlikely(faulthandler_disabled() || !mm))
+ goto no_context;
+
+ /*
+ * As per x86, we may deadlock here. However, since the kernel only
+ * validly references user space from well defined areas of the code,
+ * we can bug out early if this is from code which shouldn't.
+ */
+ if (unlikely(!down_read_trylock(&mm->mmap_sem))) {
+ if (!user_mode(regs) &&
+ !search_exception_tables(instruction_pointer(regs)))
+ goto no_context;
+retry:
+ down_read(&mm->mmap_sem);
+ } else {
+ /*
+ * The above down_read_trylock() might have succeeded in which
+ * case, we'll have missed the might_sleep() from down_read().
+ */
+ might_sleep();
+ if (IS_ENABLED(CONFIG_DEBUG_VM)) {
+ if (!user_mode(regs) &&
+ !search_exception_tables(instruction_pointer(regs)))
+ goto no_context;
+ }
+ }
+
+ vma = find_vma(mm, addr);
+
+ if (unlikely(!vma))
+ goto bad_area;
+
+ if (vma->vm_start <= addr)
+ goto good_area;
+
+ if (unlikely(!(vma->vm_flags & VM_GROWSDOWN)))
+ goto bad_area;
+
+ if (unlikely(expand_stack(vma, addr)))
+ goto bad_area;
+
+ /*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
+ */
+
+good_area:
+ info.si_code = SEGV_ACCERR;
+
+ /* first do some preliminary protection checks */
+ if (entry == ENTRY_PTE_NOT_PRESENT) {
+ if (error_code & ITYPE_mskINST)
+ mask = VM_EXEC;
+ else {
+ mask = VM_READ | VM_WRITE;
+ if (vma->vm_flags & VM_WRITE)
+ flags |= FAULT_FLAG_WRITE;
+ }
+ } else if (entry == ENTRY_TLB_MISC) {
+ switch (error_code & ITYPE_mskETYPE) {
+ case RD_PROT:
+ mask = VM_READ;
+ break;
+ case WRT_PROT:
+ mask = VM_WRITE;
+ flags |= FAULT_FLAG_WRITE;
+ break;
+ case NOEXEC:
+ mask = VM_EXEC;
+ break;
+ case PAGE_MODIFY:
+ mask = VM_WRITE;
+ flags |= FAULT_FLAG_WRITE;
+ break;
+ case ACC_BIT:
+ BUG();
+ default:
+ break;
+ }
+
+ }
+ if (!(vma->vm_flags & mask))
+ goto bad_area;
+
+ /*
+ * If for any reason at all we couldn't handle the fault,
+ * make sure we exit gracefully rather than endlessly redo
+ * the fault.
+ */
+
+ fault = handle_mm_fault(vma, addr, flags);
+
+ /*
+ * If we need to retry but a fatal signal is pending, handle the
+ * signal first. We do not need to release the mmap_sem because it
+ * would already be released in __lock_page_or_retry in mm/filemap.c.
+ */
+ if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) {
+ if (!user_mode(regs))
+ goto no_context;
+ return;
+ }
+
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM)
+ goto out_of_memory;
+ else if (fault & VM_FAULT_SIGBUS)
+ goto do_sigbus;
+ else
+ goto bad_area;
+ }
+
+ /*
+ * Major/minor page fault accounting is only done on the initial
+ * attempt. If we go through a retry, it is extremely likely that the
+ * page will be found in page cache at that point.
+ */
+ if (flags & FAULT_FLAG_ALLOW_RETRY) {
+ if (fault & VM_FAULT_MAJOR)
+ tsk->maj_flt++;
+ else
+ tsk->min_flt++;
+ if (fault & VM_FAULT_RETRY) {
+ flags &= ~FAULT_FLAG_ALLOW_RETRY;
+ flags |= FAULT_FLAG_TRIED;
+
+ /* No need to up_read(&mm->mmap_sem) as we would
+ * have already released it in __lock_page_or_retry
+ * in mm/filemap.c.
+ */
+ goto retry;
+ }
+ }
+
+ up_read(&mm->mmap_sem);
+ return;
+
+ /*
+ * Something tried to access memory that isn't in our memory map..
+ * Fix it, but check if it's kernel or user first..
+ */
+bad_area:
+ up_read(&mm->mmap_sem);
+
+bad_area_nosemaphore:
+
+ /* User mode accesses just cause a SIGSEGV */
+
+ if (user_mode(regs)) {
+ tsk->thread.address = addr;
+ tsk->thread.error_code = error_code;
+ tsk->thread.trap_no = entry;
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ /* info.si_code has been set above */
+ info.si_addr = (void *)addr;
+ force_sig_info(SIGSEGV, &info, tsk);
+ return;
+ }
+
+no_context:
+
+ /* Are we prepared to handle this kernel fault?
+ *
+ * (The kernel has valid exception-points in the source
+ * when it acesses user-memory. When it fails in one
+ * of those points, we find it in a table and do a jump
+ * to some fixup code that loads an appropriate error
+ * code)
+ */
+
+ {
+ const struct exception_table_entry *entry;
+
+ if ((entry =
+ search_exception_tables(instruction_pointer(regs))) !=
+ NULL) {
+ /* Adjust the instruction pointer in the stackframe */
+ instruction_pointer(regs) = entry->fixup;
+ return;
+ }
+ }
+
+ /*
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ */
+
+ bust_spinlocks(1);
+ pr_alert("Unable to handle kernel %s at virtual address %08lx\n",
+ (addr < PAGE_SIZE) ? "NULL pointer dereference" :
+ "paging request", addr);
+
+ show_pte(mm, addr);
+ die("Oops", regs, error_code);
+ bust_spinlocks(0);
+ do_exit(SIGKILL);
+
+ return;
+
+ /*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+
+out_of_memory:
+ up_read(&mm->mmap_sem);
+ if (!user_mode(regs))
+ goto no_context;
+ pagefault_out_of_memory();
+ return;
+
+do_sigbus:
+ up_read(&mm->mmap_sem);
+
+ /* Kernel mode? Handle exceptions or die */
+ if (!user_mode(regs))
+ goto no_context;
+
+ /*
+ * Send a sigbus
+ */
+ tsk->thread.address = addr;
+ tsk->thread.error_code = error_code;
+ tsk->thread.trap_no = entry;
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = BUS_ADRERR;
+ info.si_addr = (void *)addr;
+ force_sig_info(SIGBUS, &info, tsk);
+
+ return;
+
+vmalloc_fault:
+ {
+ /*
+ * Synchronize this task's top level page-table
+ * with the 'reference' page table.
+ *
+ * Use current_pgd instead of tsk->active_mm->pgd
+ * since the latter might be unavailable if this
+ * code is executed in a misfortunately run irq
+ * (like inside schedule() between switch_mm and
+ * switch_to...).
+ */
+
+ unsigned int index = pgd_index(addr);
+ pgd_t *pgd, *pgd_k;
+ pud_t *pud, *pud_k;
+ pmd_t *pmd, *pmd_k;
+ pte_t *pte_k;
+
+ pgd = (pgd_t *) __va(__nds32__mfsr(NDS32_SR_L1_PPTB)) + index;
+ pgd_k = init_mm.pgd + index;
+
+ if (!pgd_present(*pgd_k))
+ goto no_context;
+
+ pud = pud_offset(pgd, addr);
+ pud_k = pud_offset(pgd_k, addr);
+ if (!pud_present(*pud_k))
+ goto no_context;
+
+ pmd = pmd_offset(pud, addr);
+ pmd_k = pmd_offset(pud_k, addr);
+ if (!pmd_present(*pmd_k))
+ goto no_context;
+
+ if (!pmd_present(*pmd))
+ set_pmd(pmd, *pmd_k);
+ else
+ BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k));
+
+ /*
+ * Since the vmalloc area is global, we don't
+ * need to copy individual PTE's, it is enough to
+ * copy the pgd pointer into the pte page of the
+ * root task. If that is there, we'll find our pte if
+ * it exists.
+ */
+
+ /* Make sure the actual PTE exists as well to
+ * catch kernel vmalloc-area accesses to non-mapped
+ * addres. If we don't do this, this will just
+ * silently loop forever.
+ */
+
+ pte_k = pte_offset_kernel(pmd_k, addr);
+ if (!pte_present(*pte_k))
+ goto no_context;
+
+ return;
+ }
+}
diff --git a/arch/nds32/mm/mmap.c b/arch/nds32/mm/mmap.c
new file mode 100644
index 0000000..9d019235
--- /dev/null
+++ b/arch/nds32/mm/mmap.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/sched.h>
+#include <linux/mman.h>
+#include <linux/shm.h>
+
+#define COLOUR_ALIGN(addr,pgoff) \
+ ((((addr)+SHMLBA-1)&~(SHMLBA-1)) + \
+ (((pgoff)<<PAGE_SHIFT) & (SHMLBA-1)))
+
+/*
+ * We need to ensure that shared mappings are correctly aligned to
+ * avoid aliasing issues with VIPT caches. We need to ensure that
+ * a specific page of an object is always mapped at a multiple of
+ * SHMLBA bytes.
+ *
+ * We unconditionally provide this function for all cases, however
+ * in the VIVT case, we optimise out the alignment rules.
+ */
+unsigned long
+arch_get_unmapped_area(struct file *filp, unsigned long addr,
+ unsigned long len, unsigned long pgoff,
+ unsigned long flags)
+{
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma;
+ int do_align = 0;
+ struct vm_unmapped_area_info info;
+ int aliasing = 0;
+ if(IS_ENABLED(CONFIG_CPU_CACHE_ALIASING))
+ aliasing = 1;
+
+ /*
+ * We only need to do colour alignment if either the I or D
+ * caches alias.
+ */
+ if (aliasing)
+ do_align = filp || (flags & MAP_SHARED);
+
+ /*
+ * We enforce the MAP_FIXED case.
+ */
+ if (flags & MAP_FIXED) {
+ if (aliasing && flags & MAP_SHARED &&
+ (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))
+ return -EINVAL;
+ return addr;
+ }
+
+ if (len > TASK_SIZE)
+ return -ENOMEM;
+
+ if (addr) {
+ if (do_align)
+ addr = COLOUR_ALIGN(addr, pgoff);
+ else
+ addr = PAGE_ALIGN(addr);
+
+ vma = find_vma(mm, addr);
+ if (TASK_SIZE - len >= addr &&
+ (!vma || addr + len <= vma->vm_start))
+ return addr;
+ }
+
+ info.flags = 0;
+ info.length = len;
+ info.low_limit = mm->mmap_base;
+ info.high_limit = TASK_SIZE;
+ info.align_mask = do_align ? (PAGE_MASK & (SHMLBA - 1)) : 0;
+ info.align_offset = pgoff << PAGE_SHIFT;
+ return vm_unmapped_area(&info);
+}
--
1.7.9.5
^ permalink raw reply related
* [PATCH v3 01/33] asm-generic/io.h: move ioremap_nocache/ioremap_uc/ioremap_wc/ioremap_wt out of ifndef CONFIG_MMU
From: Greentime Hu @ 2017-12-08 9:11 UTC (permalink / raw)
To: greentime, linux-kernel, arnd, linux-arch, tglx, jason,
marc.zyngier, robh+dt, netdev, deanbo422, devicetree, viro,
dhowells, will.deacon, daniel.lezcano, linux-serial,
geert.uytterhoeven, linus.walleij, mark.rutland, greg
Cc: green.hu, Vincent Chen
In-Reply-To: <cover.1512723245.git.green.hu@gmail.com>
From: Greentime Hu <greentime@andestech.com>
It allows some architectures to use this generic macro instead of
defining theirs.
Signed-off-by: Vincent Chen <vincentc@andestech.com>
Signed-off-by: Greentime Hu <greentime@andestech.com>
---
include/asm-generic/io.h | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
index b4531e3..7c6a39e 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -852,7 +852,16 @@ static inline void __iomem *__ioremap(phys_addr_t offset, size_t size,
}
#endif
+#ifndef iounmap
+#define iounmap iounmap
+
+static inline void iounmap(void __iomem *addr)
+{
+}
+#endif
+#endif /* CONFIG_MMU */
#ifndef ioremap_nocache
+void __iomem *ioremap(phys_addr_t phys_addr, size_t size);
#define ioremap_nocache ioremap_nocache
static inline void __iomem *ioremap_nocache(phys_addr_t offset, size_t size)
{
@@ -884,15 +893,6 @@ static inline void __iomem *ioremap_wt(phys_addr_t offset, size_t size)
}
#endif
-#ifndef iounmap
-#define iounmap iounmap
-
-static inline void iounmap(void __iomem *addr)
-{
-}
-#endif
-#endif /* CONFIG_MMU */
-
#ifdef CONFIG_HAS_IOPORT_MAP
#ifndef CONFIG_GENERIC_IOMAP
#ifndef ioport_map
--
1.7.9.5
^ permalink raw reply related
* [PATCH net] net: mvpp2: fix the RSS table entry offset
From: Antoine Tenart @ 2017-12-08 9:24 UTC (permalink / raw)
To: davem
Cc: Antoine Tenart, gregory.clement, thomas.petazzoni, miquel.raynal,
nadavh, mw, stefanc, ymarkman, netdev, linux-kernel
The macro used to access or set an RSS table entry was using an offset
of 8, while it should use an offset of 0. This lead to wrongly configure
the RSS table, not accessing the right entries.
Fixes: 1d7d15d79fb4 ("net: mvpp2: initialize the RSS tables")
Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
---
drivers/net/ethernet/marvell/mvpp2.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index fed2b2f909fc..634b2f41cc9e 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -85,7 +85,7 @@
/* RSS Registers */
#define MVPP22_RSS_INDEX 0x1500
-#define MVPP22_RSS_INDEX_TABLE_ENTRY(idx) ((idx) << 8)
+#define MVPP22_RSS_INDEX_TABLE_ENTRY(idx) (idx)
#define MVPP22_RSS_INDEX_TABLE(idx) ((idx) << 8)
#define MVPP22_RSS_INDEX_QUEUE(idx) ((idx) << 16)
#define MVPP22_RSS_TABLE_ENTRY 0x1508
--
2.14.3
^ permalink raw reply related
* [PATCH v3 33/33] net: faraday add nds32 support.
From: Greentime Hu @ 2017-12-08 9:12 UTC (permalink / raw)
To: greentime, linux-kernel, arnd, linux-arch, tglx, jason,
marc.zyngier, robh+dt, netdev, deanbo422, devicetree, viro,
dhowells, will.deacon, daniel.lezcano, linux-serial,
geert.uytterhoeven, linus.walleij, mark.rutland, greg
Cc: green.hu
In-Reply-To: <cover.1512723245.git.green.hu@gmail.com>
From: Greentime Hu <greentime@andestech.com>
This patch is used to support nds32 architecture to use these faraday
mac IP.
Signed-off-by: Greentime Hu <greentime@andestech.com>
---
drivers/net/ethernet/faraday/Kconfig | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/faraday/Kconfig b/drivers/net/ethernet/faraday/Kconfig
index 040c7f1..1bdaffc 100644
--- a/drivers/net/ethernet/faraday/Kconfig
+++ b/drivers/net/ethernet/faraday/Kconfig
@@ -5,7 +5,7 @@
config NET_VENDOR_FARADAY
bool "Faraday devices"
default y
- depends on ARM
+ depends on ARM || NDS32 || COMPILE_TEST
---help---
If you have a network (Ethernet) card belonging to this class, say Y.
@@ -18,7 +18,7 @@ if NET_VENDOR_FARADAY
config FTMAC100
tristate "Faraday FTMAC100 10/100 Ethernet support"
- depends on ARM
+ depends on ARM || NDS32 || COMPILE_TEST
select MII
---help---
This driver supports the FTMAC100 10/100 Ethernet controller
@@ -27,7 +27,7 @@ config FTMAC100
config FTGMAC100
tristate "Faraday FTGMAC100 Gigabit Ethernet support"
- depends on ARM
+ depends on ARM || NDS32 || COMPILE_TEST
select PHYLIB
---help---
This driver supports the FTGMAC100 Gigabit Ethernet controller
--
1.7.9.5
^ permalink raw reply related
* [PATCH v3 32/33] irqchip: Andestech Internal Vector Interrupt Controller driver
From: Greentime Hu @ 2017-12-08 9:12 UTC (permalink / raw)
To: greentime-MUIXKm3Oiri1Z/+hSey0Gg,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, arnd-r2nGTMty4D4,
linux-arch-u79uwXL29TY76Z2rM5mHXA, tglx-hfZtesqFncYOwBW4kG4KsQ,
jason-NLaQJdtUoK4Be96aLqz0jA, marc.zyngier-5wv7dgnIgG8,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, netdev-u79uwXL29TY76Z2rM5mHXA,
deanbo422-Re5JQEeQqe8AvxtiuMwx3w,
devicetree-u79uwXL29TY76Z2rM5mHXA,
viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn,
dhowells-H+wXaHxf7aLQT0dZR+AlfA, will.deacon-5wv7dgnIgG8,
daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A,
linux-serial-u79uwXL29TY76Z2rM5mHXA,
geert.uytterhoeven-Re5JQEeQqe8AvxtiuMwx3w,
linus.walleij-QSEj5FYQhm4dnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
greg-U8xfFu+wG4EAvxtiuMwx3w
Cc: green.hu-Re5JQEeQqe8AvxtiuMwx3w, Rick Chen
In-Reply-To: <cover.1512723245.git.green.hu-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
From: Greentime Hu <greentime-MUIXKm3Oiri1Z/+hSey0Gg@public.gmane.org>
This patch adds the Andestech Internal Vector Interrupt Controller
driver. You can find the spec here. Ch4.9 of AndeStar SPA V3 Manual.
http://www.andestech.com/product.php?cls=9
Signed-off-by: Rick Chen <rick-MUIXKm3Oiri1Z/+hSey0Gg@public.gmane.org>
Signed-off-by: Greentime Hu <greentime-MUIXKm3Oiri1Z/+hSey0Gg@public.gmane.org>
---
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-ativic32.c | 120 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 121 insertions(+)
create mode 100644 drivers/irqchip/irq-ativic32.c
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index b842dfd..201ca9f 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -80,3 +80,4 @@ obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o
obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o
obj-$(CONFIG_QCOM_IRQ_COMBINER) += qcom-irq-combiner.o
obj-$(CONFIG_IRQ_UNIPHIER_AIDET) += irq-uniphier-aidet.o
+obj-$(CONFIG_NDS32) += irq-ativic32.o
diff --git a/drivers/irqchip/irq-ativic32.c b/drivers/irqchip/irq-ativic32.c
new file mode 100644
index 0000000..709b65c
--- /dev/null
+++ b/drivers/irqchip/irq-ativic32.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip.h>
+#include <nds32_intrinsic.h>
+
+static void ativic32_ack_irq(struct irq_data *data)
+{
+ __nds32__mtsr_dsb(BIT(data->hwirq), NDS32_SR_INT_PEND2);
+}
+
+static void ativic32_mask_irq(struct irq_data *data)
+{
+ unsigned long int_mask2 = __nds32__mfsr(NDS32_SR_INT_MASK2);
+ __nds32__mtsr_dsb(int_mask2 & (~(BIT(data->hwirq))), NDS32_SR_INT_MASK2);
+}
+
+static void ativic32_unmask_irq(struct irq_data *data)
+{
+ unsigned long int_mask2 = __nds32__mfsr(NDS32_SR_INT_MASK2);
+ __nds32__mtsr_dsb(int_mask2 | (BIT(data->hwirq)), NDS32_SR_INT_MASK2);
+}
+
+static struct irq_chip ativic32_chip = {
+ .name = "ativic32",
+ .irq_ack = ativic32_ack_irq,
+ .irq_mask = ativic32_mask_irq,
+ .irq_unmask = ativic32_unmask_irq,
+};
+
+static unsigned int __initdata nivic_map[6] = { 6, 2, 10, 16, 24, 32 };
+
+static struct irq_domain *root_domain;
+static int ativic32_irq_domain_map(struct irq_domain *id, unsigned int virq,
+ irq_hw_number_t hw)
+{
+
+ unsigned long int_trigger_type;
+ u32 type;
+ struct irq_data *irq_data;
+ int_trigger_type = __nds32__mfsr(NDS32_SR_INT_TRIGGER);
+ irq_data = irq_get_irq_data(virq);
+ if (!irq_data)
+ return -EINVAL;
+
+ if (int_trigger_type & (BIT(hw))) {
+ irq_set_chip_and_handler(virq, &ativic32_chip, handle_edge_irq);
+ type = IRQ_TYPE_EDGE_RISING;
+ } else {
+ irq_set_chip_and_handler(virq, &ativic32_chip, handle_level_irq);
+ type = IRQ_TYPE_LEVEL_HIGH;
+ }
+
+ irqd_set_trigger_type(irq_data, type);
+ return 0;
+}
+
+static struct irq_domain_ops ativic32_ops = {
+ .map = ativic32_irq_domain_map,
+ .xlate = irq_domain_xlate_onecell
+};
+
+static irq_hw_number_t get_intr_src(void)
+{
+ return ((__nds32__mfsr(NDS32_SR_ITYPE) & ITYPE_mskVECTOR) >> ITYPE_offVECTOR)
+ - NDS32_VECTOR_offINTERRUPT;
+}
+
+asmlinkage void asm_do_IRQ(struct pt_regs *regs)
+{
+ irq_hw_number_t hwirq = get_intr_src();
+ handle_domain_irq(root_domain, hwirq, regs);
+}
+
+int __init ativic32_init_irq(struct device_node *node, struct device_node *parent)
+{
+ unsigned long int_vec_base, nivic, nr_ints;
+
+ if (WARN(parent, "non-root ativic32 are not supported"))
+ return -EINVAL;
+
+ int_vec_base = __nds32__mfsr(NDS32_SR_IVB);
+
+ if (((int_vec_base & IVB_mskIVIC_VER) >> IVB_offIVIC_VER) == 0)
+ panic("Unable to use atcivic32 for this cpu.\n");
+
+ nivic = (int_vec_base & IVB_mskNIVIC) >> IVB_offNIVIC;
+ if (nivic >= ARRAY_SIZE(nivic_map))
+ panic("The number of input for ativic32 is not supported.\n");
+
+ nr_ints = nivic_map[nivic];
+
+ root_domain = irq_domain_add_linear(node, nr_ints,
+ &ativic32_ops, NULL);
+
+ if (!root_domain)
+ panic("%s: unable to create IRQ domain\n", node->full_name);
+
+ return 0;
+}
+IRQCHIP_DECLARE(ativic32, "andestech,ativic32", ativic32_init_irq);
--
1.7.9.5
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox