diff options
127 files changed, 4601 insertions, 1520 deletions
diff --git a/contrib/libarchive/libarchive/archive_string.c b/contrib/libarchive/libarchive/archive_string.c index c6ae8968d54f..4fb96a9fa178 100644 --- a/contrib/libarchive/libarchive/archive_string.c +++ b/contrib/libarchive/libarchive/archive_string.c @@ -1314,7 +1314,17 @@ create_sconv_object(const char *fc, const char *tc, else if (strcmp(fc, "CP932") == 0) sc->cd = iconv_open(tc, "SJIS"); } -#if defined(_WIN32) && !defined(__CYGWIN__) +#if defined(__FreeBSD__) && !defined(HAVE_LIBICONV) + /* + * FreeBSD's native iconv() by default returns the number of + * invalid characters in the input string, as specified by + * POSIX, but iconv_strncat_in_locale() assumes GNU iconv + * semantics. + */ + int v = 1; + + (void)iconvctl(sc->cd, ICONV_SET_ILSEQ_INVALID, &v); +#elif defined(_WIN32) && !defined(__CYGWIN__) /* * archive_mstring on Windows directly convert multi-bytes * into archive_wstring in order not to depend on locale diff --git a/lib/libc/gen/fts.3 b/lib/libc/gen/fts.3 index 199603b5f3c7..b6dbfffe8079 100644 --- a/lib/libc/gen/fts.3 +++ b/lib/libc/gen/fts.3 @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd May 21, 2026 +.Dd May 29, 2026 .Dt FTS 3 .Os .Sh NAME @@ -497,6 +497,13 @@ field to and leave the contents of the .Fa statp field undefined. +The roots and any directories encountered during traversal +.Po +.Dv FTS_D , +.Dv FTS_DC , +.Dv FTS_DP +.Pc +are still fully populated. .It Dv FTS_NOSTAT_TYPE This option is similar to .Dv FTS_NOSTAT , diff --git a/lib/libc/gen/fts.c b/lib/libc/gen/fts.c index 4aa386d777cd..e8063ecb646e 100644 --- a/lib/libc/gen/fts.c +++ b/lib/libc/gen/fts.c @@ -41,6 +41,7 @@ #include <fcntl.h> #include <fts.h> #include <stdalign.h> +#include <stdint.h> #include <stdlib.h> #include <string.h> #include <unistd.h> @@ -114,6 +115,19 @@ static const char *ufslike_filesystems[] = { 0 }; +/* + * POSIX provides nlink_t but unfortunately not NLINK_MAX. + */ +#define NLINK_MAX \ + _Generic((nlink_t)0, \ + int16_t: INT16_MAX, \ + uint16_t: UINT16_MAX, \ + int32_t: INT32_MAX, \ + uint32_t: UINT32_MAX, \ + int64_t: INT64_MAX, \ + uint64_t: UINT64_MAX, \ + default: 0) + static FTS * __fts_open(FTS *sp, char * const *argv) { @@ -736,7 +750,7 @@ fts_build(FTS *sp, int type) int cderrno, descend, oflag, saved_errno, nostat, doadjust, readdir_errno; long level; - long nlinks; /* has to be signed because -1 is a magic value */ + int64_t nlinks; /* has to be signed because -1 is a magic value */ size_t dnamlen, len, maxlen, nitems; /* Set current node pointer. */ @@ -759,16 +773,36 @@ fts_build(FTS *sp, int type) } /* - * Nlinks is the number of possible entries of type directory in the - * directory if we're cheating on stat calls, 0 if we're not doing - * any stat calls at all, -1 if we're doing stats on everything. + * In the FTS_PHYSICAL | FTS_NOSTAT case, we want to avoid calling + * fstat() unnecessarily, but we still need to call it for + * subdirectories. The current directory's link count provides an + * upper bound on the number of subdirectories we may encounter + * (including . and .. in the FTS_SEEDOT case). We initialize + * nlinks to the current directory's link count, then decrement it + * every time we encounter a directory, so when we hit zero we can + * save some time by not calling fstat() on subsequent entries. + * + * If FTS_NOSTAT is not set, or the link count is less than two + * (which should not be possible) or equal to NLINK_MAX (which + * suggests that the actual value could be higher), or the current + * filesystem is not known to provide reliable link counts, we + * initialize nlinks to -1 and fstat() everything. + * + * In the rare case where we don't need to stat anything, even + * subdirectories, we initialize nlinks to 0 regardless of the + * actual link count. + * + * Note that we ignore the FTS_NOSTAT flag in the FTS_LOGICAL + * case, although we could choose to only stat symbolic links. + * Implementing this is left as an exercise for the reader. */ if (type == BNAMES) { nlinks = 0; /* Be quiet about nostat, GCC. */ nostat = 0; } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) { - if (fts_ufslinks(sp, cur)) + if (cur->fts_nlink >= 2 && cur->fts_nlink < NLINK_MAX && + cur->fts_nlink <= INT64_MAX && fts_ufslinks(sp, cur)) nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2); else nlinks = -1; diff --git a/lib/libc/tests/gen/fts_options_test.c b/lib/libc/tests/gen/fts_options_test.c index fc3015138a49..863c0809d16e 100644 --- a/lib/libc/tests/gen/fts_options_test.c +++ b/lib/libc/tests/gen/fts_options_test.c @@ -36,6 +36,8 @@ fts_options_prepare(const struct atf_tc *tc) ATF_REQUIRE_EQ(0, mkdir("dir", 0755)); ATF_REQUIRE_EQ(0, close(creat("file", 0644))); ATF_REQUIRE_EQ(0, close(creat("dir/file", 0644))); + ATF_REQUIRE_EQ(0, mkdir("dir/sd", 0750)); + ATF_REQUIRE_EQ(0, mkdir("dir/sd/sd", 0700)); ATF_REQUIRE_EQ(0, symlink("..", "dir/up")); ATF_REQUIRE_EQ(0, symlink("dir", "dirl")); ATF_REQUIRE_EQ(0, symlink("file", "filel")); @@ -57,6 +59,10 @@ ATF_TC_BODY(fts_options_logical, tc) { FTS_DL, "dead", "dead" }, { FTS_D, "dir", "dir" }, { FTS_F, "file", "dir/file" }, + { FTS_D, "sd", "dir/sd" }, + { FTS_D, "sd", "dir/sd/sd" }, + { FTS_DP, "sd", "dir/sd/sd" }, + { FTS_DP, "sd", "dir/sd" }, { FTS_D, "up", "dir/up" }, { FTS_DL, "dead", "dir/up/dead" }, { FTS_DC, "dir", "dir/up/dir" }, @@ -67,6 +73,10 @@ ATF_TC_BODY(fts_options_logical, tc) { FTS_DP, "dir", "dir" }, { FTS_D, "dirl", "dirl" }, { FTS_F, "file", "dirl/file" }, + { FTS_D, "sd", "dirl/sd" }, + { FTS_D, "sd", "dirl/sd/sd" }, + { FTS_DP, "sd", "dirl/sd/sd" }, + { FTS_DP, "sd", "dirl/sd" }, { FTS_D, "up", "dirl/up" }, { FTS_DL, "dead", "dirl/up/dead" }, { FTS_DC, "dir", "dirl/up/dir" }, @@ -108,6 +118,10 @@ ATF_TC_BODY(fts_options_logical_nostat, tc) { FTS_DL, "dead", "dead" }, { FTS_D, "dir", "dir" }, { FTS_NSOK, "file", "dir/file" }, + { FTS_D, "sd", "dir/sd" }, + { FTS_D, "sd", "dir/sd/sd" }, + { FTS_DP, "sd", "dir/sd/sd" }, + { FTS_DP, "sd", "dir/sd" }, { FTS_D, "up", "dir/up" }, { FTS_DL, "dead", "dir/up/dead" }, { FTS_DC, "dir", "dir/up/dir" }, @@ -118,6 +132,10 @@ ATF_TC_BODY(fts_options_logical_nostat, tc) { FTS_DP, "dir", "dir" }, { FTS_D, "dirl", "dirl" }, { FTS_NSOK, "file", "dirl/file" }, + { FTS_D, "sd", "dirl/sd" }, + { FTS_D, "sd", "dirl/sd/sd" }, + { FTS_DP, "sd", "dirl/sd/sd" }, + { FTS_DP, "sd", "dirl/sd" }, { FTS_D, "up", "dirl/up" }, { FTS_DL, "dead", "dirl/up/dead" }, { FTS_DC, "dir", "dirl/up/dir" }, @@ -151,6 +169,14 @@ ATF_TC_BODY(fts_options_logical_seedot, tc) { FTS_DOT, ".", "dir/." }, { FTS_DOT, "..", "dir/.." }, { FTS_F, "file", "dir/file" }, + { FTS_D, "sd", "dir/sd" }, + { FTS_DOT, ".", "dir/sd/." }, + { FTS_DOT, "..", "dir/sd/.." }, + { FTS_D, "sd", "dir/sd/sd" }, + { FTS_DOT, ".", "dir/sd/sd/." }, + { FTS_DOT, "..", "dir/sd/sd/.." }, + { FTS_DP, "sd", "dir/sd/sd" }, + { FTS_DP, "sd", "dir/sd" }, { FTS_D, "up", "dir/up" }, { FTS_DOT, ".", "dir/up/." }, { FTS_DOT, "..", "dir/up/.." }, @@ -165,6 +191,14 @@ ATF_TC_BODY(fts_options_logical_seedot, tc) { FTS_DOT, ".", "dirl/." }, { FTS_DOT, "..", "dirl/.." }, { FTS_F, "file", "dirl/file" }, + { FTS_D, "sd", "dirl/sd" }, + { FTS_DOT, ".", "dirl/sd/." }, + { FTS_DOT, "..", "dirl/sd/.." }, + { FTS_D, "sd", "dirl/sd/sd" }, + { FTS_DOT, ".", "dirl/sd/sd/." }, + { FTS_DOT, "..", "dirl/sd/sd/.." }, + { FTS_DP, "sd", "dirl/sd/sd" }, + { FTS_DP, "sd", "dirl/sd" }, { FTS_D, "up", "dirl/up" }, { FTS_DOT, ".", "dirl/up/." }, { FTS_DOT, "..", "dirl/up/.." }, @@ -198,6 +232,10 @@ ATF_TC_BODY(fts_options_physical, tc) { FTS_SL, "dead", "dead" }, { FTS_D, "dir", "dir" }, { FTS_F, "file", "file" }, + { FTS_D, "sd", "sd" }, + { FTS_D, "sd", "sd" }, + { FTS_DP, "sd", "sd" }, + { FTS_DP, "sd", "sd" }, { FTS_SL, "up", "up" }, { FTS_DP, "dir", "dir" }, { FTS_SL, "dirl", "dirl" }, @@ -224,6 +262,10 @@ ATF_TC_BODY(fts_options_physical_nochdir, tc) { FTS_SL, "dead", "dead" }, { FTS_D, "dir", "dir" }, { FTS_F, "file", "dir/file" }, + { FTS_D, "sd", "dir/sd" }, + { FTS_D, "sd", "dir/sd/sd" }, + { FTS_DP, "sd", "dir/sd/sd" }, + { FTS_DP, "sd", "dir/sd" }, { FTS_SL, "up", "dir/up" }, { FTS_DP, "dir", "dir" }, { FTS_SL, "dirl", "dirl" }, @@ -250,10 +292,18 @@ ATF_TC_BODY(fts_options_physical_comfollow, tc) { FTS_DL, "dead", "dead" }, { FTS_D, "dir", "dir" }, { FTS_F, "file", "file" }, + { FTS_D, "sd", "sd" }, + { FTS_D, "sd", "sd" }, + { FTS_DP, "sd", "sd" }, + { FTS_DP, "sd", "sd" }, { FTS_SL, "up", "up" }, { FTS_DP, "dir", "dir" }, { FTS_D, "dirl", "dirl" }, { FTS_F, "file", "file" }, + { FTS_D, "sd", "sd" }, + { FTS_D, "sd", "sd" }, + { FTS_DP, "sd", "sd" }, + { FTS_DP, "sd", "sd" }, { FTS_SL, "up", "up" }, { FTS_DP, "dirl", "dirl" }, { FTS_F, "file", "file" }, @@ -279,10 +329,18 @@ ATF_TC_BODY(fts_options_physical_comfollowdir, tc) { FTS_DL, "dead", "dead" }, { FTS_D, "dir", "dir" }, { FTS_F, "file", "file" }, + { FTS_D, "sd", "sd" }, + { FTS_D, "sd", "sd" }, + { FTS_DP, "sd", "sd" }, + { FTS_DP, "sd", "sd" }, { FTS_SL, "up", "up" }, { FTS_DP, "dir", "dir" }, { FTS_D, "dirl", "dirl" }, { FTS_F, "file", "file" }, + { FTS_D, "sd", "sd" }, + { FTS_D, "sd", "sd" }, + { FTS_DP, "sd", "sd" }, + { FTS_DP, "sd", "sd" }, { FTS_SL, "up", "up" }, { FTS_DP, "dirl", "dirl" }, { FTS_F, "file", "file" }, @@ -308,6 +366,10 @@ ATF_TC_BODY(fts_options_physical_nostat, tc) { FTS_SL, "dead", "dead" }, { FTS_D, "dir", "dir" }, { FTS_NSOK, "file", "file" }, + { FTS_D, "sd", "sd" }, + { FTS_D, "sd", "sd" }, + { FTS_DP, "sd", "sd" }, + { FTS_DP, "sd", "sd" }, { FTS_NSOK, "up", "up" }, { FTS_DP, "dir", "dir" }, { FTS_SL, "dirl", "dirl" }, @@ -334,6 +396,10 @@ ATF_TC_BODY(fts_options_physical_nostat_type, tc) { FTS_SL, "dead", "dead" }, { FTS_D, "dir", "dir" }, { FTS_F, "file", "file" }, + { FTS_D, "sd", "sd" }, + { FTS_D, "sd", "sd" }, + { FTS_DP, "sd", "sd" }, + { FTS_DP, "sd", "sd" }, { FTS_SL, "up", "up" }, { FTS_DP, "dir", "dir" }, { FTS_SL, "dirl", "dirl" }, @@ -362,6 +428,14 @@ ATF_TC_BODY(fts_options_physical_seedot, tc) { FTS_DOT, ".", "." }, { FTS_DOT, "..", ".." }, { FTS_F, "file", "file" }, + { FTS_D, "sd", "sd" }, + { FTS_DOT, ".", "." }, + { FTS_DOT, "..", ".." }, + { FTS_D, "sd", "sd" }, + { FTS_DOT, ".", "." }, + { FTS_DOT, "..", ".." }, + { FTS_DP, "sd", "sd" }, + { FTS_DP, "sd", "sd" }, { FTS_SL, "up", "up" }, { FTS_DP, "dir", "dir" }, { FTS_SL, "dirl", "dirl" }, diff --git a/lib/libutil/login.conf.5 b/lib/libutil/login.conf.5 index d4bbc1d67780..9b136291dc1e 100644 --- a/lib/libutil/login.conf.5 +++ b/lib/libutil/login.conf.5 @@ -17,7 +17,7 @@ .\" 5. Modifications may be freely made to this file providing the above .\" conditions are met. .\" -.Dd December 15, 2025 +.Dd May 27, 2026 .Dt LOGIN.CONF 5 .Os .Sh NAME @@ -194,17 +194,18 @@ login environment. .It "cputime time CPU usage limit." .It "datasize size Maximum data size limit." .It "filesize size Maximum file size limit." +.It "kqueues number Maximum number of kernel event queues." .It "maxproc number Maximum number of processes." .It "memorylocked size Maximum locked in core memory size limit." .It "memoryuse size Maximum of core memory use size limit." .It "openfiles number Maximum number of open files per process." +.It "pipebuf size Maximum size of pipe buffers." +.It "pseudoterminals number Maximum number of pseudo-terminals." .It "sbsize size Maximum permitted socketbuffer size." -.It "vmemoryuse size Maximum permitted total VM usage per process." .It "stacksize size Maximum stack size limit." -.It "pseudoterminals number Maximum number of pseudo-terminals." .It "swapuse size Maximum swap space size limit." .It "umtxp number Maximum number of process-shared pthread locks." -.It "pipebuf size Maximum size of pipe buffers." +.It "vmemoryuse size Maximum permitted total VM usage per process." .El .Pp These resource limit entries actually specify both the maximum diff --git a/lib/libutil/login_class.c b/lib/libutil/login_class.c index 90e4e01f7c3b..8a465e2eb24e 100644 --- a/lib/libutil/login_class.c +++ b/lib/libutil/login_class.c @@ -63,9 +63,9 @@ static struct login_res { { "vmemoryuse", login_getcapsize, RLIMIT_VMEM }, { "pseudoterminals", login_getcapnum, RLIMIT_NPTS }, { "swapuse", login_getcapsize, RLIMIT_SWAP }, - { "kqueues", login_getcapsize, RLIMIT_KQUEUES }, + { "kqueues", login_getcapnum, RLIMIT_KQUEUES }, { "umtxp", login_getcapnum, RLIMIT_UMTXP }, - { "pipebuf", login_getcapnum, RLIMIT_PIPEBUF }, + { "pipebuf", login_getcapsize, RLIMIT_PIPEBUF }, { "vms", login_getcapnum, RLIMIT_VMM }, { NULL, 0, 0 } }; diff --git a/libexec/rc/rc.conf b/libexec/rc/rc.conf index 75420e42cdeb..27e8c8456b6f 100644 --- a/libexec/rc/rc.conf +++ b/libexec/rc/rc.conf @@ -736,7 +736,11 @@ newsyslog_flags="-CN" # Newsyslog flags to create marked files mixer_enable="YES" # Run the sound mixer. opensm_enable="NO" # Opensm(8) for infiniband devices defaults to off nuageinit_enable="NO" # Run nuageinit at startup -virtual_oss_enable="NO" # Run virtual_oss at startup + +virtual_oss_enable="NO" # Run virtual_oss at startup. +virtual_oss_configs="dsp" # List of configurations. +virtual_oss_default_control_device="vdsp.ctl" # Default configuration's + # control device. # rctl(8) requires kernel options RACCT and RCTL rctl_enable="YES" # Load rctl(8) rules on boot diff --git a/libexec/rc/rc.d/virtual_oss b/libexec/rc/rc.d/virtual_oss index 73a486f547a5..9861545b8bfc 100644 --- a/libexec/rc/rc.d/virtual_oss +++ b/libexec/rc/rc.d/virtual_oss @@ -22,13 +22,9 @@ status_cmd="${name}_status" required_modules="cuse" -configs= pidpath="/var/run/${name}" -default_unit=$(sysctl -n hw.snd.default_unit 2> /dev/null) - -# Default configuration's control device. -: "${virtual_oss_default_control_device:="vdsp.ctl"}" +default_unit=$(sysctl -n hw.snd.default_unit 2> /dev/null) virtual_oss_default_args="\ -S \ -C 2 \ @@ -42,12 +38,6 @@ virtual_oss_default_args="\ -l dsp.loop \ -t ${virtual_oss_default_control_device}" -# Set to NO by default. Set it to "YES" to enable virtual_oss. -: "${virtual_oss_enable:="NO"}" - -# List of configurations to use. Default is "dsp". -: "${virtual_oss_configs:="dsp"}" - # Default (dsp) virtual_oss config. : "${virtual_oss_dsp:="${virtual_oss_default_args}"}" @@ -86,10 +76,17 @@ stop_instance() if [ -z "${instance_args}" ]; then warn "no such config: ${config}" else - startmsg -n "Stopping virtual_oss config: ${config}: " - kill "$(cat "${pidpath}/${config}.pid")" - rm -f "${pidpath}/${config}.pid" - startmsg "done" + pidfile="${pidpath}/${config}.pid" + if [ ! -f "${pidfile}" ]; then + warn "not running: ${config}" + else + pid="$(cat "${pidfile}")" + startmsg -n "Stopping virtual_oss config: ${config}: " + kill "${pid}" + pwait "${pid}" + rm -f "${pidfile}" + startmsg "done" + fi fi } diff --git a/sbin/ping/tests/ping_test.sh b/sbin/ping/tests/ping_test.sh index af700615dc8d..ab45ad809a52 100644 --- a/sbin/ping/tests/ping_test.sh +++ b/sbin/ping/tests/ping_test.sh @@ -253,14 +253,22 @@ inject_reply_cleanup() ifconfig `cat tun.txt` destroy } -atf_test_case timestamp_origin +atf_test_case timestamp_origin cleanup timestamp_origin_head() { atf_set "descr" "ICMP Originate Timestamp" + atf_set "require.user" "root" + atf_set "require.config" "allow_sysctl_side_effects" } timestamp_origin_body() { require_ipv4 + # The kernel only replies to ICMP timestamp requests when + # net.inet.icmp.tstamprepl is enabled. Save the current value + # so the cleanup hook can restore it, then enable replies. + sysctl -n net.inet.icmp.tstamprepl > tstamprepl.txt + sysctl net.inet.icmp.tstamprepl=1 + # Run ping timestamp out=$(ping -Mt -c1 127.0.0.1) @@ -286,6 +294,12 @@ timestamp_origin_body() atf_fail "tso ($tso) differs from tsr ($tsr) by $diff seconds" fi } +timestamp_origin_cleanup() +{ + if [ -f tstamprepl.txt ]; then + sysctl net.inet.icmp.tstamprepl=`cat tstamprepl.txt` + fi +} atf_init_test_cases() { diff --git a/sbin/route/route_netlink.c b/sbin/route/route_netlink.c index 051662688047..0d4420767082 100644 --- a/sbin/route/route_netlink.c +++ b/sbin/route/route_netlink.c @@ -950,7 +950,8 @@ flushroutes_fib_nl(int fib, int af) struct snl_msg_info attrs = {}; print_nlmsg(&h, hdr, &attrs); } - if (r.rta_table != (uint32_t)fib || r.rtm_family != af) + if (r.rta_table != (uint32_t)fib || + (af != AF_UNSPEC && r.rtm_family != af)) continue; if ((r.rta_rtflags & RTF_GATEWAY) == 0) continue; diff --git a/share/man/man4/mac_do.4 b/share/man/man4/mac_do.4 index 8c08e072be88..7f05d5f88bf8 100644 --- a/share/man/man4/mac_do.4 +++ b/share/man/man4/mac_do.4 @@ -1,8 +1,8 @@ .\"- .\" SPDX-License-Identifier: BSD-2-Clause .\" -.\" Copyright (c) 2024 Baptiste Daroussin <bapt@FreeBSD.org> -.\" Copyright (c) 2024 The FreeBSD Foundation +.\" Copyright (c) 2024, Baptiste Daroussin <bapt@FreeBSD.org> +.\" Copyright (c) 2024, 2026, The FreeBSD Foundation .\" .\" Portions of this documentation were written by Olivier Certner .\" <olce@FreeBSD.org> at Kumacom SARL under sponsorship from the FreeBSD @@ -42,13 +42,23 @@ policy module allows unprivileged users to change process credentials according to rules configured by the administrator. It supports per-jail configuration. .Pp -Currently, the +The .Nm -policy module only produces effects to processes spawned from the +policy module only produces effects on processes spawned from specific +executables from a configurable whitelist. +By default, this whitelist only contains the .Pa /usr/bin/mdo executable, please see .Xr mdo 1 for more details on this program. +.Pp +Section +.Sx CREDENTIALS RULES +specifies the format of credentials transition rules, and section +.Sx CONFIGURATION +explains how to configure +.Nm , +including rules and authorized executables. .Sh CREDENTIALS RULES Rules specify which transitions of process credentials .Nm @@ -267,84 +277,170 @@ then converted to unsigned ones as specified in the C standard for the and .Vt gid_t types, which are both 32-bit unsigned integers. -.Sh RUNTIME CONFIGURATION -The following +.Sh CONFIGURATION +Each parameter of +.Nm +has a corresponding +.Xr sysctl 8 +knob. +.Nm +supports per-jail values for most parameters. +.Ss Sysctl Knobs +The .Xr sysctl 8 -knobs are available: +knobs presented by +.Nm +are of two types: Global ones, which influence all uses of the module, and +per-jail ones, which allow to retrieve or change the setting applicable to +a jail +.Pq or the host +from within. +They are tagged accordingly in the list below. +.Pp +The indicated default values for per-jail parameters applies to the host. +Those applying to jails are described in the +.Sx Jail Parameters +subsection below. +.Pp +The following knobs are available: .Bl -tag -width indent .It Va security.mac.do.enabled Enable the .Nm policy. -(Default: 1). -.It Va security.mac.do.rules -The list of credential rules, whose syntax is described in the -.Sx CREDENTIALS RULES -section above. -This list is specific to each jail. -Please see the -.Sx JAIL SUPPORT -section below for more details on the interaction of -.Nm -with jails. +.Pq Global. Default: 1. .It Va security.mac.do.print_parse_error Logs a message on trying to set incorrect rules via the .Va security.mac.do.rules .Xr sysctl 8 knob. +.Pq Global. Default: 1. +.It Va security.mac.do.rules +The list of credentials transition rules, whose syntax is described in the +.Sx CREDENTIALS RULES +section above. +An empty string effectively disables the policy. +.Pq Per-jail. Default: Empty. +.It Va security.mac.do.exec_paths +The list of absolute paths +.Pq relative to the current jail's root +to authorized executables, separated by colons +.Pq Ql ":" . +Only processes launched from these executables are considered by the +.Nm +policy. +An empty string effectively disables the policy. +.Po +Per-jail. Default: +.Ql "/usr/bin/mdo" . +.Pc .El -.Sh JAIL SUPPORT +.Ss Jail Parameters +Most parameters of .Nm -supports per-jail configuration of rules. +are per-jail +.Po +see the +.Sx "Sysctl Knobs" +subsection above +.Pc . +Those that are per-jail have corresponding jail parameters that can be used to +set their initial values on jail creation or modify their values in a running +jail from outside the jail. .Pp -By default, at creation, a new jail has no credentials rules, effectively -disabling +By default, as it is for the host, a new jail has .Nm -for its processes. +disabled for its processes, as if the +.Va mac.do +parameter below was explicitly set to +.Ql disable . .Pp -The following jail parameters are defined: +Each unspecified parameter other than +.Va mac.do +defaults to a copy of its value in the currently applicable configuration for +a running jail, or from the parent jail on jail creation. +.Pp +The following jail parameters are available: .Bl -tag -width indent .It Va mac.do Possible values are: +.Pp .Bl -tag -width "'disable'" -compact .It Ql new .Nm -will enforce specific credential rules in the jail. -The -.Va mac.do.rules -jail parameter must also be set in this case. +will use a specific configuration for the jail. +This case degrades to +.Ql disable +if one of the other jail parameters end up empty after applying the default +values rule +.Pq see the preamble . .It Ql disable Disables .Nm in the jail. -Strictly equivalent to jail creation's default behavior and to setting the rules -to an empty string. +This is achieved by ensuring that at least one of the +.Va mac.do.rules +and +.Va mac.do.exec_paths +jail parameters are empty. +If none of them ends up empty after applying the default values rule +.Pq see the preamble , +.Va mac.do.rules +is forced to an empty value. +An explicit +.Ql disable +is incompatible with explicit non-empty values for all other jail parameters and +will trigger an error. .It Ql inherit -The jail's credentials rules are inherited from the jail's parent +The other per-jail parameters are inherited from those applicable to the jail's +parent .Pq which may themselves have been inherited . -Modified rules propagate to all children jails configured for inheritance. +Configuration modifications immediately propagate to all descendant jails +configured for inheritance +.Po +as long as there is no intervening jail having its own specific configuration +.Pc . .El +.Pp +The default value depends on the absence or presence and value of the other jail +parameters. +As soon as one of the latter is present and not empty, the default value is +.Ql new , +else it is +.Ql disable . +Inheritance is never established implicitly, it must be explicitly requested. .It Va mac.do.rules The credentials rules for the jail. -It is always equal to the value that can be retrieved by the +See the description of the corresponding .Xr sysctl 8 knob .Va security.mac.do.rules -described in section -.Sx RUNTIME CONFIGURATION . -If set, and the jail parameter -.Va mac.do -is not so explicitly, the value of the latter will default to -.Ql disable -if empty, else to -.Ql new . +in subsection +.Sx "Sysctl Knobs" +above. +See also the preamble for the default values rule. +.It Va mac.do.exec_paths +The authorized executables. +See the description of the corresponding +.Xr sysctl 8 +knob +.Va security.mac.do.exec_paths +in subsection +.Sx "Sysctl Knobs" +above. +See also the preamble for the default values rule. .El +.Ss Consistency +Values read or set from jail parameters are always consistent with their +corresponding +.Xr sysctl 8 +knobs, effectively operating on the same internal +.Dq variable . .Pp -Each jail must have -.Xr mdo 1 -installed at path -.Pa /usr/bin/mdo , -as this path is currently not configurable. +All accesses to some parameter or some jail configuration as a whole, whether +a read or a modification, are sequentially consistent. +In other words, they appear to be atomic, and all threads see them happening in +the same order. .Sh EXAMPLES Here are several examples of single rules matching processes having a real user ID of 10001: @@ -405,6 +501,7 @@ current supplementary groups must be kept. .Sh AUTHORS .An Olivier Certner Aq Mt olce@FreeBSD.org .An Baptiste Daroussin Aq Mt bapt@FreeBSD.org +.An Kushagra Srivastava Aq Mt kushagra1403@gmail.com .Sh BUGS Currently, .Nm diff --git a/share/man/man4/pcm.4 b/share/man/man4/pcm.4 index 4e70d95d5441..9ea0f14c3930 100644 --- a/share/man/man4/pcm.4 +++ b/share/man/man4/pcm.4 @@ -197,9 +197,6 @@ The Parametric Software Equalizer (EQ) enables the use of controls (bass and treble). Commonly used for ear-candy or frequency compensation due to the vast difference in hardware quality. -EQ is disabled by default, but can be enabled with the -.Va hint.pcm.%d.eq -tunable. .Ss VCHANs Each device can optionally support more playback and recording channels than physical hardware provides by using @@ -230,12 +227,6 @@ driver. The following tunables can not be changed during runtime using .Xr sysctl 8 . .Bl -tag -width indent -.It Va hint.pcm.%d.eq -Set to 1 or 0 to explicitly enable (1) or disable (0) the equalizer. -Requires a driver reload if changed. -Enabling this will make bass and treble controls appear in mixer applications. -This tunable is undefined by default. -Equalizing is disabled by default. .It Va hint.pcm.%d.vpc Set to 1 or 0 to explicitly enable (1) or disable (0) the VPC feature. This tunable is undefined by default. @@ -416,15 +407,6 @@ When a channel is closed the channel volume will be reset to 0db. This means that any changes to the volume will be lost. Enabling this will preserve the volume, at the cost of possible confusion when applications tries to re-open the same device. -.It Va hw.snd.vpc_mixer_bypass -The recommended way to use the VPC feature is to teach applications to use the -correct -.Fn ioctl : -.Dv SNDCTL_DSP_GETPLAYVOL , SNDCTL_DSP_SETPLAYVOL , -.Dv SNDCTL_DSP_SETRECVOL , SNDCTL_DSP_SETRECVOL . -This is however not always possible. -Enable this to allow applications to use their own existing mixer logic -to control their own channel volume. .It Va hw.snd.vpc_reset Enable to restore all channel volumes back to the default value of 0db. .It Va dev.pcm.%d.bitperfect @@ -439,6 +421,17 @@ the definitive format/rate target. The recommended way to use bitperfect mode is to disable VCHANs and enable this sysctl. Default is disabled. +.It Va dev.pcm.%d.eq +Set to 1 or 0 to enable (1) or disable (0) the equalizer. +Default is disabled. +When enabled, the mixer bass and treble controls can be used, as well as the +.Va dev.pcm.%d.eq_preamp +tunable. +.It Va dev.pcm.%d.eq_preamp +Equalizer preamp (in dB). +.Va dev.pcm.%d.eq +has to be enabled, in order for this tunable to take effect. +Read the tunable's description to see the available range of values. .It Va dev.pcm.%d.[play|rec].vchans Enable (1) or disable (0) VCHANs. Default is enabled. diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile index 7044b6f1bb68..894a9971295c 100644 --- a/share/man/man9/Makefile +++ b/share/man/man9/Makefile @@ -943,6 +943,7 @@ MLINKS+=cpu_machdep.9 cpu_copy_thread.9 \ cpu_machdep.9 cpu_thread_clean.9 \ cpu_machdep.9 cpu_thread_exit.9 \ cpu_machdep.9 cpu_thread_free.9 \ + cpu_machdep.9 cpu_thread_new_kstack.9 \ cpu_machdep.9 cpu_throw.9 \ cpu_machdep.9 cpu_update_pcb.9 MLINKS+=cpuset.9 CPUSET_T_INITIALIZER.9 \ diff --git a/share/man/man9/cpu_machdep.9 b/share/man/man9/cpu_machdep.9 index 415d86a8b766..514f3f0104cc 100644 --- a/share/man/man9/cpu_machdep.9 +++ b/share/man/man9/cpu_machdep.9 @@ -8,7 +8,7 @@ .\" Technology), and Capabilities Limited under Defense Advanced Research .\" Projects Agency (DARPA) Contract No. FA8750-24-C-B047 ("DEC"). .\" -.Dd January 31, 2025 +.Dd May 27, 2026 .Dt cpu_machdep 9 .Os .Sh NAME @@ -31,6 +31,7 @@ .Nm cpu_thread_clean , .Nm cpu_thread_exit , .Nm cpu_thread_free , +.Nm cpu_thread_new_kstack , .Nm cpu_throw , .Nm cpu_update_pcb .Nd machine-dependent interfaces to handle CPU and thread state @@ -84,6 +85,8 @@ .Ft void .Fn cpu_thread_free "struct thread *td" .Ft void +.Fn cpu_thread_new_kstack "struct thread *td" +.Ft void .Fn cpu_throw "struct thread *old" "struct thread *new" .Ft void .Fn cpu_update_pcb "struct thread *td" @@ -366,19 +369,25 @@ When the process object is later reused for a new process in .Xr fork 2 , the kernel recycles that last thread object and uses it as the initial thread in the new process. -When a thread is recycled, some of the steps in the thread allocation -and free cycle are skipped as an optimization. +When a thread is recycled, a new kernel stack may be allocated if +the existing kernel stack is not suitable for the new process. .Pp .Fn cpu_thread_alloc initializes machine-dependent fields in .Fa td +when allocating a new thread object. +.Pp +.Fn cpu_thread_new_kstack +initializes kernel stack-related machine-dependent fields in +.Fa td after allocating a new kernel stack. This function typically sets the .Fa td_pcb +.Pq on architectures which store the pcb in the kernel stack and initial .Fa td_frame pointers. -.Fn cpu_thread_alloc +.Fn cpu_thread_new_kstack is called both when allocating a new thread object and when a recycled thread allocates a new kernel stack. Note that this function is @@ -386,12 +395,19 @@ Note that this function is called if a recycled thread reuses its existing kernel stack. .Pp .Fn cpu_thread_clean -releases any machine-dependent resources for the last thread in a +releases machine-dependent resources for the last thread in a process during .Xr wait 2 . -The thread is a candidate for recycling so should be reset to run as a +Since the thread is a candidate for recycling, +machine-dependent fields should be reset to run as a new thread in case it is recycled by a future .Xr fork 2 . +In particular, +if the thread reuses its existing kernel stack, +no other +.Fn cpu_thread_* +function will be invoked before the thread is reused as the main +thread of a new process. .Pp .Fn cpu_thread_exit cleans any machine-dependent state in diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index e338db372df3..8df4868f5312 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -1367,8 +1367,9 @@ hammer_time(u_int64_t modulep, u_int64_t physfree) thread0.td_kstack = (char *)physfree - kernphys + KERNSTART; thread0.td_kstack_pages = kstack_pages; - kstack0_sz = thread0.td_kstack_pages * PAGE_SIZE; + kstack0_sz = ptoa(kstack_pages); bzero(thread0.td_kstack, kstack0_sz); + cpu_thread_new_kstack(&thread0); physfree += kstack0_sz; /* @@ -1521,8 +1522,6 @@ hammer_time(u_int64_t modulep, u_int64_t physfree) * We initialize the PCB pointer early so that exception * handlers will work. */ - cpu_max_ext_state_size = sizeof(struct savefpu); - set_top_of_stack_td(&thread0); thread0.td_pcb = get_pcb_td(&thread0); /* @@ -1828,29 +1827,53 @@ wrmsr_early_safe_start(void) { struct region_descriptor efi_idt; struct gate_descriptor *gpf_descr; + int i; sidt(&wrmsr_early_safe_orig_efi_idt); efi_idt.rd_limit = 32 * sizeof(idt0[0]); efi_idt.rd_base = (uintptr_t)idt0; lidt(&efi_idt); - gpf_descr = &idt0[IDT_GP]; - gpf_descr->gd_looffset = (uintptr_t)wrmsr_early_safe_gp_handler; - gpf_descr->gd_hioffset = (uintptr_t)wrmsr_early_safe_gp_handler >> 16; - gpf_descr->gd_selector = rcs(); - gpf_descr->gd_type = SDT_SYSTGT; - gpf_descr->gd_p = 1; + /* Setup handler for all possible exceptions. */ + for (i = 0; i < 32; i++) { + gpf_descr = &idt0[i]; + gpf_descr->gd_looffset = + (uintptr_t)wrmsr_early_safe_gp_handler; + gpf_descr->gd_hioffset = + (uintptr_t)wrmsr_early_safe_gp_handler >> 16; + gpf_descr->gd_selector = rcs(); + gpf_descr->gd_type = SDT_SYSTGT; + gpf_descr->gd_p = 1; + } } void wrmsr_early_safe_end(void) { - struct gate_descriptor *gpf_descr; + int i; lidt(&wrmsr_early_safe_orig_efi_idt); - gpf_descr = &idt0[IDT_GP]; - memset_early(gpf_descr, 0, sizeof(*gpf_descr)); + for (i = 0; i < 32; i++) + memset_early(&idt0[i], 0, sizeof(idt0[0])); +} + +int +safe_read(vm_offset_t addr, char *valp) +{ + struct uio uio; + struct iovec iov; + + iov.iov_base = valp; + iov.iov_len = 1; + uio.uio_offset = addr; + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_resid = 1; + uio.uio_segflg = UIO_SYSSPACE; + uio.uio_rw = UIO_READ; + uio.uio_td = NULL; + return (uiomove_mem(UIO_MEM_KMEM, &uio)); } #ifdef KDB diff --git a/sys/amd64/amd64/mem.c b/sys/amd64/amd64/mem.c index ab1e6cde6cd5..7d1f0f42d01c 100644 --- a/sys/amd64/amd64/mem.c +++ b/sys/amd64/amd64/mem.c @@ -61,10 +61,6 @@ #include <machine/specialreg.h> #include <machine/vmparam.h> -#include <vm/vm.h> -#include <vm/pmap.h> -#include <vm/vm_extern.h> - #include <machine/memdev.h> /* @@ -72,99 +68,22 @@ */ MALLOC_DEFINE(M_MEMDESC, "memdesc", "memory range descriptors"); -/* ARGSUSED */ int memrw(struct cdev *dev, struct uio *uio, int flags) { - struct iovec *iov; - void *p, *vd; - ssize_t orig_resid; - vm_prot_t prot; - u_long v; - u_int c; - int error; - - error = 0; - orig_resid = uio->uio_resid; - while (uio->uio_resid > 0 && error == 0) { - iov = uio->uio_iov; - if (iov->iov_len == 0) { - uio->uio_iov++; - uio->uio_iovcnt--; - if (uio->uio_iovcnt < 0) - panic("memrw"); - continue; - } - v = uio->uio_offset; - c = ulmin(iov->iov_len, PAGE_SIZE - (u_int)(v & PAGE_MASK)); - - switch (dev2unit(dev)) { - case CDEV_MINOR_KMEM: - /* - * Since c is clamped to be less or equal than - * PAGE_SIZE, the uiomove() call does not - * access past the end of the direct map. - */ - if (v >= kva_layout.dmap_low && - v < kva_layout.dmap_high) { - error = uiomove((void *)v, c, uio); - break; - } - - switch (uio->uio_rw) { - case UIO_READ: - prot = VM_PROT_READ; - break; - case UIO_WRITE: - prot = VM_PROT_WRITE; - break; - } + enum uiomove_mem_req req; - if (!kernacc((void *)v, c, prot)) { - error = EFAULT; - break; - } - - /* - * If the extracted address is not accessible - * through the direct map, then we make a - * private (uncached) mapping because we can't - * depend on the existing kernel mapping - * remaining valid until the completion of - * uiomove(). - * - * XXX We cannot provide access to the - * physical page 0 mapped into KVA. - */ - v = pmap_extract(kernel_pmap, v); - if (v == 0) { - error = EFAULT; - break; - } - /* FALLTHROUGH */ - case CDEV_MINOR_MEM: - if (v < dmaplimit) { - vd = PHYS_TO_DMAP(v); - error = uiomove(vd, c, uio); - break; - } - if (v > cpu_getmaxphyaddr()) { - error = EFAULT; - break; - } - p = pmap_mapdev(v, PAGE_SIZE); - error = uiomove(p, c, uio); - pmap_unmapdev(p, PAGE_SIZE); - break; - } + switch (dev2unit(dev)) { + case CDEV_MINOR_KMEM: + req = UIO_MEM_KMEM; + break; + case CDEV_MINOR_MEM: + req = UIO_MEM_MEM; + break; + default: + __unreachable(); } - /* - * Don't return error if any byte was written. Read and write - * can return error only if no i/o was performed. - */ - if (uio->uio_resid != orig_resid) - error = 0; - return (error); + return (uiomove_mem(req, uio)); } /* diff --git a/sys/amd64/amd64/support.S b/sys/amd64/amd64/support.S index 09d4ef85b087..1d7d05843ba8 100644 --- a/sys/amd64/amd64/support.S +++ b/sys/amd64/amd64/support.S @@ -1566,20 +1566,19 @@ msr_onfault: ret ENTRY(wrmsr_early_safe) + movq %rsp,%r11 movl %edi,%ecx movl %esi,%eax sarq $32,%rsi movl %esi,%edx wrmsr xorl %eax,%eax -wrmsr_early_faulted: ret ENTRY(wrmsr_early_safe_gp_handler) - addq $8,%rsp + movq %r11,%rsp movl $EFAULT,%eax - movq $wrmsr_early_faulted,(%rsp) - iretq + ret /* * void pmap_pti_pcid_invalidate(uint64_t ucr3, uint64_t kcr3); diff --git a/sys/amd64/amd64/uio_machdep.c b/sys/amd64/amd64/uio_machdep.c index 16915bccf9f5..11e6ad2b1da9 100644 --- a/sys/amd64/amd64/uio_machdep.c +++ b/sys/amd64/amd64/uio_machdep.c @@ -44,9 +44,11 @@ #include <sys/uio.h> #include <vm/vm.h> +#include <vm/vm_extern.h> #include <vm/vm_page.h> #include <machine/vmparam.h> +#include <machine/md_var.h> /* * Implement uiomove(9) from physical memory using the direct map to @@ -141,3 +143,97 @@ out: td->td_pflags &= ~TDP_DEADLKTREAT; return (error); } + +int +uiomove_mem(enum uiomove_mem_req req, struct uio *uio) +{ + struct iovec *iov; + void *p, *vd; + ssize_t orig_resid; + vm_prot_t prot; + u_long v; + u_int c; + int error; + + error = 0; + orig_resid = uio->uio_resid; + while (uio->uio_resid > 0 && error == 0) { + iov = uio->uio_iov; + if (iov->iov_len == 0) { + uio->uio_iov++; + uio->uio_iovcnt--; + if (uio->uio_iovcnt < 0) + panic("memrw"); + continue; + } + v = uio->uio_offset; + c = ulmin(iov->iov_len, PAGE_SIZE - (u_int)(v & PAGE_MASK)); + + switch (req) { + case UIO_MEM_KMEM: + /* + * Since c is clamped to be less or equal than + * PAGE_SIZE, the uiomove() call does not + * access past the end of the direct map. + */ + if (v >= kva_layout.dmap_low && + v < kva_layout.dmap_high) { + error = uiomove((void *)v, c, uio); + break; + } + + switch (uio->uio_rw) { + case UIO_READ: + prot = VM_PROT_READ; + break; + case UIO_WRITE: + prot = VM_PROT_WRITE; + break; + } + + if (!kernacc((void *)v, c, prot)) { + error = EFAULT; + break; + } + + /* + * If the extracted address is not accessible + * through the direct map, then we make a + * private (uncached) mapping because we can't + * depend on the existing kernel mapping + * remaining valid until the completion of + * uiomove(). + * + * XXX We cannot provide access to the + * physical page 0 mapped into KVA. + */ + v = pmap_extract(kernel_pmap, v); + if (v == 0) { + error = EFAULT; + break; + } + /* FALLTHROUGH */ + case UIO_MEM_MEM: + if (v < dmaplimit) { + vd = PHYS_TO_DMAP(v); + error = uiomove(vd, c, uio); + break; + } + if (v > cpu_getmaxphyaddr()) { + error = EFAULT; + break; + } + p = pmap_mapdev(v, PAGE_SIZE); + error = uiomove(p, c, uio); + pmap_unmapdev(p, PAGE_SIZE); + break; + } + } + /* + * Don't return error if any byte was written. Read and write + * can return error only if no i/o was performed. + */ + if (uio->uio_resid != orig_resid) + error = 0; + return (error); +} diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c index 2e180003e93d..1de891680f94 100644 --- a/sys/amd64/amd64/vm_machdep.c +++ b/sys/amd64/amd64/vm_machdep.c @@ -83,13 +83,6 @@ _Static_assert(OFFSETOF_MONITORBUF == offsetof(struct pcpu, pc_monitorbuf), "OFFSETOF_MONITORBUF does not correspond with offset of pc_monitorbuf."); -void -set_top_of_stack_td(struct thread *td) -{ - td->td_md.md_stack_base = td->td_kstack + - td->td_kstack_pages * PAGE_SIZE; -} - struct savefpu * get_pcb_user_save_td(struct thread *td) { @@ -167,8 +160,6 @@ copy_thread(struct thread *td1, struct thread *td2) clear_pcb_flags(pcb2, PCB_TLSBASE); } - td2->td_frame = (struct trapframe *)td2->td_md.md_stack_base - 1; - /* * Set registers for trampoline to user mode. Leave space for the * return address on stack. These are the kernel mode register values. @@ -240,9 +231,7 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) return; } - /* Point the stack and pcb to the actual location */ - set_top_of_stack_td(td2); - td2->td_pcb = pcb2 = get_pcb_td(td2); + pcb2 = td2->td_pcb; copy_thread(td1, td2); @@ -379,18 +368,17 @@ void cpu_thread_alloc(struct thread *td) { struct pcb *pcb; - struct xstate_hdr *xhdr; - set_top_of_stack_td(td); td->td_pcb = pcb = get_pcb_td(td); - td->td_frame = (struct trapframe *)td->td_md.md_stack_base - 1; td->td_md.md_usr_fpu_save = fpu_save_area_alloc(); pcb->pcb_save = get_pcb_user_save_pcb(pcb); - if (use_xsave) { - xhdr = (struct xstate_hdr *)(pcb->pcb_save + 1); - bzero(xhdr, sizeof(*xhdr)); - xhdr->xstate_bv = xsave_mask; - } +} + +void +cpu_thread_new_kstack(struct thread *td) +{ + td->td_md.md_stack_base = td_kstack_top(td); + td->td_frame = (struct trapframe *)td->td_md.md_stack_base - 1; } void diff --git a/sys/amd64/include/md_var.h b/sys/amd64/include/md_var.h index 46a30518b212..0e8fe916490b 100644 --- a/sys/amd64/include/md_var.h +++ b/sys/amd64/include/md_var.h @@ -94,7 +94,6 @@ void gsbase_load_fault(void) __asm(__STRING(gsbase_load_fault)); void fpstate_drop(struct thread *td); void pagezero(void *addr); void setidt(int idx, alias_for_inthand_t *func, int typ, int dpl, int ist); -void set_top_of_stack_td(struct thread *td); struct savefpu *get_pcb_user_save_td(struct thread *td); struct savefpu *get_pcb_user_save_pcb(struct pcb *pcb); void pci_early_quirks(void); @@ -107,6 +106,12 @@ void wrmsr_early_safe_start(void); void wrmsr_early_safe_end(void); int wrmsr_early_safe(u_int msr, uint64_t data); +enum uiomove_mem_req { + UIO_MEM_KMEM = 101, + UIO_MEM_MEM, +}; +int uiomove_mem(enum uiomove_mem_req req, struct uio *uio); + #endif /* !_MACHINE_MD_VAR_H_ */ #endif /* __i386__ */ diff --git a/sys/amd64/include/stack.h b/sys/amd64/include/stack.h index 3c27266b775b..7d821348be0e 100644 --- a/sys/amd64/include/stack.h +++ b/sys/amd64/include/stack.h @@ -12,17 +12,15 @@ /* Get the current kernel thread stack usage. */ #define GET_STACK_USAGE(total, used) do { \ struct thread *td = curthread; \ - (total) = td->td_kstack_pages * PAGE_SIZE; \ - (used) = td->td_kstack + td->td_kstack_pages * PAGE_SIZE - \ - (char *)&td; \ + (total) = ptoa(td->td_kstack_pages); \ + (used) = td_kstack_top(td) - (char *)&td; \ } while (0) static __inline bool kstack_contains(struct thread *td, vm_offset_t va, size_t len) { return (va >= (vm_offset_t)td->td_kstack && va + len >= va && - va + len <= (vm_offset_t)td->td_kstack + td->td_kstack_pages * - PAGE_SIZE); + va + len <= (vm_offset_t)td_kstack_top(td)); } #endif /* _SYS_PROC_H_ */ diff --git a/sys/arm/allwinner/a64/sun50i_a64_acodec.c b/sys/arm/allwinner/a64/sun50i_a64_acodec.c index 12c9a86cf361..93b0328e99e0 100644 --- a/sys/arm/allwinner/a64/sun50i_a64_acodec.c +++ b/sys/arm/allwinner/a64/sun50i_a64_acodec.c @@ -339,19 +339,9 @@ static int a64codec_mixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) { struct a64codec_softc *sc; - struct mtx *mixer_lock; - uint8_t do_unlock; u_int val; sc = device_get_softc(mix_getdevinfo(m)); - mixer_lock = mixer_get_lock(m); - - if (mtx_owned(mixer_lock)) { - do_unlock = 0; - } else { - do_unlock = 1; - mtx_lock(mixer_lock); - } right = left; @@ -375,10 +365,6 @@ a64codec_mixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned ri } A64CODEC_UNLOCK(sc); - if (do_unlock) { - mtx_unlock(mixer_lock); - } - return (left | (right << 8)); } diff --git a/sys/arm/arm/machdep.c b/sys/arm/arm/machdep.c index a06e6773cd49..989adef3478d 100644 --- a/sys/arm/arm/machdep.c +++ b/sys/arm/arm/machdep.c @@ -378,8 +378,7 @@ init_proc0(void *kstack) proc_linkup0(&proc0, &thread0); thread0.td_kstack = kstack; thread0.td_kstack_pages = kstack_pages; - thread0.td_pcb = (struct pcb *)(thread0.td_kstack + - thread0.td_kstack_pages * PAGE_SIZE) - 1; + thread0.td_pcb = (struct pcb *)td_kstack_top(&thread0) - 1; thread0.td_pcb->pcb_flags = 0; thread0.td_pcb->pcb_fpflags = 0; thread0.td_pcb->pcb_vfpcpu = -1; diff --git a/sys/arm/arm/vm_machdep.c b/sys/arm/arm/vm_machdep.c index bee1c705fbbd..a8a4b6b8c7be 100644 --- a/sys/arm/arm/vm_machdep.c +++ b/sys/arm/arm/vm_machdep.c @@ -97,9 +97,6 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) if ((flags & RFPROC) == 0) return; - /* Point the pcb to the top of the stack */ - pcb2 = (struct pcb *) - (td2->td_kstack + td2->td_kstack_pages * PAGE_SIZE) - 1; #ifdef VFP /* Store actual state of VFP */ if (curthread == td1) { @@ -107,7 +104,7 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) vfp_save_state(td1, td1->td_pcb); } #endif - td2->td_pcb = pcb2; + pcb2 = td2->td_pcb; /* Clone td1's pcb */ bcopy(td1->td_pcb, pcb2, sizeof(*pcb2)); @@ -116,8 +113,7 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) mdp2 = &p2->p_md; bcopy(&td1->td_proc->p_md, mdp2, sizeof(*mdp2)); - /* Point the frame to the stack in front of pcb and copy td1's frame */ - td2->td_frame = (struct trapframe *)pcb2 - 1; + /* Copy td1's frame */ *td2->td_frame = *td1->td_frame; /* @@ -245,8 +241,12 @@ cpu_thread_exit(struct thread *td) void cpu_thread_alloc(struct thread *td) { - td->td_pcb = (struct pcb *)(td->td_kstack + td->td_kstack_pages * - PAGE_SIZE) - 1; +} + +void +cpu_thread_new_kstack(struct thread *td) +{ + td->td_pcb = (struct pcb *)td_kstack_top(td) - 1; /* * Ensure td_frame is aligned to an 8 byte boundary as it will be * placed into the stack pointer which must be 8 byte aligned in diff --git a/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c b/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c index e0c4327d8e05..6e974a1a61bb 100644 --- a/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c +++ b/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c @@ -365,6 +365,7 @@ bcm_sdhci_attach(device_t dev) return (0); fail: + bcm_dma_free(sc->sc_dma_ch); if (sc->sc_intrhand) bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand); if (sc->sc_irq_res) diff --git a/sys/arm/include/stack.h b/sys/arm/include/stack.h index e80d3dc060fd..f6bc67dbe771 100644 --- a/sys/arm/include/stack.h +++ b/sys/arm/include/stack.h @@ -68,7 +68,7 @@ void unwind_module_unloaded(struct linker_file *); /* Get the current kernel thread stack usage. */ #define GET_STACK_USAGE(total, used) do { \ struct thread *td = curthread; \ - (total) = td->td_kstack_pages * PAGE_SIZE - sizeof(struct pcb); \ + (total) = ptoa(td->td_kstack_pages) - sizeof(struct pcb); \ (used) = td->td_kstack + (total) - (char *)&td; \ } while (0) @@ -76,8 +76,7 @@ static __inline bool kstack_contains(struct thread *td, vm_offset_t va, size_t len) { return (va >= (vm_offset_t)td->td_kstack && va + len >= va && - va + len <= (vm_offset_t)td->td_kstack + td->td_kstack_pages * - PAGE_SIZE - sizeof(struct pcb)); + va + len <= (vm_offset_t)td_kstack_top(td) - sizeof(struct pcb)); } #endif /* _SYS_PROC_H_ */ diff --git a/sys/arm64/arm64/exception.S b/sys/arm64/arm64/exception.S index 5a4181348a54..5efbc4b36710 100644 --- a/sys/arm64/arm64/exception.S +++ b/sys/arm64/arm64/exception.S @@ -92,10 +92,34 @@ blr x1 1: - ldr x0, [x18, #PC_CURTHREAD] + ldr x19, [x18, #PC_CURTHREAD] + + ldr x1, [x19, #TD_MD_SCTLR] + /* + * If the upper bit in SCTLR_EL1.TCF0 is set we are either in async + * or asym modes. Either of which could set TFSRE0_EL1. + */ + tbz x1, #(SCTLR_TCF0_SHIFT + 1), 2f + /* Check for a tag fault */ + mrs x1, TFSRE0_EL1_REG + tbz x1, #TFSRE0_TF0_SHIFT, 2f + + /* + * A fault has happened, set MD_FLAG_MTE_ASYNC_FAULT. As FEAT_LSE + * is a required feature where FEAT_MTE_ASYNC could be implemented + * we can depend on it being present to set the flag. + */ + ldr w1, =MD_FLAG_MTE_ASYNC_FAULT + add x2, x19, #TD_MD_FLAGS +.arch_extension lse + stset w1, [x2] +.arch_extension nolse + +2: + mov x0, x19 bl ptrauth_exit_el0 - ldr x0, [x18, #(PC_CURTHREAD)] + mov x0, x19 bl dbg_monitor_enter /* Unmask debug and SError exceptions */ @@ -118,6 +142,14 @@ msr daifset, #(DAIF_ALL) .if \el == 0 ldr x0, [x18, #PC_CURTHREAD] + + ldr x1, [x0, #TD_MD_SCTLR] + /* See above for why we check this field */ + tbz x1, #(SCTLR_TCF0_SHIFT + 1), 1f + dsb ish + msr TFSRE0_EL1_REG, xzr +1: + mov x1, sp bl dbg_monitor_exit diff --git a/sys/arm64/arm64/exec_machdep.c b/sys/arm64/arm64/exec_machdep.c index a2e1e42249b4..d0a7302e2f7d 100644 --- a/sys/arm64/arm64/exec_machdep.c +++ b/sys/arm64/arm64/exec_machdep.c @@ -471,6 +471,7 @@ exec_setregs(struct thread *td, struct image_params *imgp, uintptr_t stack) /* Generate new pointer authentication keys */ ptrauth_exec(td); + mte_exec(td); } /* Sanity check these are the same size, they will be memcpy'd to and from */ diff --git a/sys/arm64/arm64/genassym.c b/sys/arm64/arm64/genassym.c index 22696796e69d..6c86f190282d 100644 --- a/sys/arm64/arm64/genassym.c +++ b/sys/arm64/arm64/genassym.c @@ -53,8 +53,6 @@ ASSYM(PC_CURPCB, offsetof(struct pcpu, pc_curpcb)); ASSYM(PC_CURTHREAD, offsetof(struct pcpu, pc_curthread)); ASSYM(PC_SSBD, offsetof(struct pcpu, pc_ssbd)); -/* Size of pcb, rounded to keep stack alignment */ -ASSYM(PCB_SIZE, roundup2(sizeof(struct pcb), STACKALIGNBYTES + 1)); ASSYM(PCB_SINGLE_STEP_SHIFT, PCB_SINGLE_STEP_SHIFT); ASSYM(PCB_REGS, offsetof(struct pcb, pcb_x)); ASSYM(PCB_X19, PCB_X19); @@ -76,6 +74,9 @@ ASSYM(TD_FRAME, offsetof(struct thread, td_frame)); ASSYM(TD_LOCK, offsetof(struct thread, td_lock)); ASSYM(TD_MD_CANARY, offsetof(struct thread, td_md.md_canary)); ASSYM(TD_MD_EFIRT_TMP, offsetof(struct thread, td_md.md_efirt_tmp)); +ASSYM(TD_MD_FLAGS, offsetof(struct thread, td_md.md_flags)); +ASSYM(MD_FLAG_MTE_ASYNC_FAULT, MD_FLAG_MTE_ASYNC_FAULT); +ASSYM(TD_MD_SCTLR, offsetof(struct thread, td_md.md_sctlr)); ASSYM(TF_SIZE, sizeof(struct trapframe)); ASSYM(TF_SP, offsetof(struct trapframe, tf_sp)); diff --git a/sys/arm64/arm64/locore.S b/sys/arm64/arm64/locore.S index b200aa93c281..bd61b485edf7 100644 --- a/sys/arm64/arm64/locore.S +++ b/sys/arm64/arm64/locore.S @@ -128,8 +128,7 @@ virtdone: /* Set up the stack */ adrp x25, initstack_end - add x25, x25, :lo12:initstack_end - sub sp, x25, #PCB_SIZE + add sp, x25, :lo12:initstack_end /* Zero the BSS */ ldr x15, .Lbss diff --git a/sys/arm64/arm64/machdep.c b/sys/arm64/arm64/machdep.c index d219c737c215..f35ec7ab2e2e 100644 --- a/sys/arm64/arm64/machdep.c +++ b/sys/arm64/arm64/machdep.c @@ -131,6 +131,7 @@ uintptr_t boot_canary = 0x49a2d892bc05a0b1ul; #endif static struct trapframe proc0_tf; +static struct pcb pcb0; int early_boot = 1; int cold = 1; @@ -443,14 +444,14 @@ init_proc0(void *kstack) #if defined(PERTHREAD_SSP) thread0.td_md.md_canary = boot_canary; #endif - thread0.td_pcb = (struct pcb *)(thread0.td_kstack + - thread0.td_kstack_pages * PAGE_SIZE) - 1; + thread0.td_pcb = &pcb0; thread0.td_pcb->pcb_flags = 0; thread0.td_pcb->pcb_fpflags = 0; thread0.td_pcb->pcb_fpusaved = &thread0.td_pcb->pcb_fpustate; thread0.td_pcb->pcb_vfpcpu = UINT_MAX; thread0.td_frame = &proc0_tf; ptrauth_thread0(&thread0); + mte_thread0(&thread0); pcpup->pc_curpcb = thread0.td_pcb; /* diff --git a/sys/arm64/arm64/mte.c b/sys/arm64/arm64/mte.c new file mode 100644 index 000000000000..6e902858a8b9 --- /dev/null +++ b/sys/arm64/arm64/mte.c @@ -0,0 +1,191 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2024-2026 Arm Ltd + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/libkern.h> +#include <sys/proc.h> + +#include <machine/cpu_feat.h> +#include <machine/pcb.h> +#include <machine/pte.h> +#include <machine/sysarch.h> +#include <vm/vm.h> +#include <vm/vm_page.h> + +/* Version of MTE implemented. 0 == unimplemented */ +static u_int __read_mostly mte_version = 0; + +/* + * FEAT_MTE (mte_version == 1) has userspace instructions, but no tag + * checking. May of the registers/fields need FEAT_MTE2 to be implemented + * before we can access them. + */ +#define MTE_HAS_TAG_CHECK (mte_version >= 2) + +struct thread *mte_switch(struct thread *); + +#define load_tags(addr) ({ \ + uint64_t __val; \ + asm volatile( \ + ".arch_extension memtag \n" \ + "ldgm %0, [%1] \n" \ + ".arch_extension nomemtag" : "=r" (__val) : "r" (addr)); \ + __val; \ +}) + +#define set_tags(tags, addr) do { \ + asm volatile( \ + ".arch_extension memtag \n" \ + "stgm %0, [%1] \n" \ + ".arch_extension nomemtag" : "=r" (tags) : "r" (addr)); \ +} while (0) + +/* Fetch the block size used by tag load and store instructions */ +static inline size_t +mte_block_size(void) +{ + return (sizeof(int) << GMID_BS_SIZE(READ_SPECIALREG(GMID_EL1_REG))); +} + +static void +mte_update_sctlr(struct thread *td, uint64_t sctlr) +{ + MPASS((sctlr & ~(SCTLR_ATA0 | SCTLR_TCF0_MASK)) == 0); + td->td_md.md_sctlr &= ~(SCTLR_ATA0 | SCTLR_TCF0_MASK); + td->td_md.md_sctlr |= sctlr; +} + +/** + * Clear/sync the allocation tags for a given page. This should be done on + * allocation of a page to ensure a tag check fault does not occur immediately + * after accessing newly tagged memory. + */ +void +mte_sync_tags(vm_page_t page) +{ + char *addr; + size_t block_size; + + if (!MTE_HAS_TAG_CHECK) + return; + + /* don't clear the tags on a page that's already setup for mte */ + if ((page->md.pv_flags & PV_MTE_TAGGED) != 0) + return; + + block_size = mte_block_size(); + addr = PHYS_TO_DMAP(page->phys_addr); + + for (size_t count = 0; count < PAGE_SIZE; + count += block_size, addr += block_size) + asm volatile( + ".arch_extension memtag \n" + "stgm xzr, [%0] \n" + ".arch_extension nomemtag" : : "r" (addr)); + + page->md.pv_flags |= PV_MTE_TAGGED; +} + +/** + * Copy the allocation tags from given target to destination page. This is called + * on a copy-on-write and anything that causes a pmap_copy_page call. + */ +void +mte_copy_tags(vm_page_t srcpage, vm_page_t dstpage, char *src, char *dst) +{ + size_t block_size; + uint64_t tags; + + MPASS((srcpage->md.pv_flags & PV_MTE_TAGGED) != 0); + + /* + * Copy the tags from the source page to the destination page, + * incrementing by the block count read from GMID_EL1 + */ + block_size = mte_block_size(); + for (size_t count = 0; count < PAGE_SIZE; + count += block_size, src += block_size, dst += block_size) { + tags = load_tags(src); + set_tags(tags, dst); + } + dstpage->md.pv_flags |= PV_MTE_TAGGED; +} + +void +mte_fork(struct thread *new_td, struct thread *orig_td) +{ + if (!MTE_HAS_TAG_CHECK) + return; + + mte_update_sctlr(new_td, + orig_td->td_md.md_sctlr & SCTLR_TCF0_MASK); + new_td->td_md.md_gcr = orig_td->td_md.md_gcr; +} + +void +mte_exec(struct thread *td) +{ + if (!MTE_HAS_TAG_CHECK) + return; + + mte_update_sctlr(td, SCTLR_TCF0_NONE); + td->td_md.md_gcr = GCR_RRND; +} + +void +mte_copy_thread(struct thread *new_td, struct thread *orig_td) +{ + if (!MTE_HAS_TAG_CHECK) + return; + + mte_update_sctlr(new_td, + orig_td->td_md.md_sctlr & SCTLR_TCF0_MASK); + new_td->td_md.md_gcr = orig_td->td_md.md_gcr; +} + +/* Only for kernel threads */ +void +mte_thread_alloc(struct thread *td) +{ +} + +/* Only for a kernel thread */ +void +mte_thread0(struct thread *td) +{ +} + + +struct thread * +mte_switch(struct thread *td) +{ + if (MTE_HAS_TAG_CHECK) { + WRITE_SPECIALREG(GCR_EL1_REG, td->td_md.md_gcr); + } + return (td); +} diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c index adc583812e5b..1fb9ac2011aa 100644 --- a/sys/arm64/arm64/pmap.c +++ b/sys/arm64/arm64/pmap.c @@ -146,6 +146,7 @@ #include <vm/uma.h> #include <machine/asan.h> +#include <machine/cpu.h> #include <machine/cpu_feat.h> #include <machine/elf.h> #include <machine/ifunc.h> @@ -358,6 +359,7 @@ struct pv_chunks_list __exclusive_cache_line pv_chunks[PMAP_MEMDOM]; vm_paddr_t dmap_phys_base; /* The start of the dmap region */ vm_paddr_t dmap_phys_max; /* The limit of the dmap region */ vm_offset_t dmap_max_addr; /* The virtual address limit of the dmap */ +static int dmap_attr = VM_MEMATTR_WRITE_BACK; extern pt_entry_t pagetable_l0_ttbr1[]; @@ -483,7 +485,7 @@ static void pmap_abort_ptp(pmap_t pmap, vm_offset_t va, vm_page_t mpte); static bool pmap_activate_int(struct thread *td, pmap_t pmap); static void pmap_alloc_asid(pmap_t pmap); static int pmap_change_props_locked(void *addr, vm_size_t size, - vm_prot_t prot, int mode, bool skip_unmapped); + vm_prot_t prot, int mode, int old_mode, bool skip_unmapped); static bool pmap_copy_l3c(pmap_t pmap, pt_entry_t *l3p, vm_offset_t va, pt_entry_t l3e, vm_page_t ml3, struct rwlock **lockp); static pt_entry_t *pmap_demote_l1(pmap_t pmap, pt_entry_t *l1, vm_offset_t va); @@ -1586,6 +1588,7 @@ pmap_page_init(vm_page_t m) TAILQ_INIT(&m->md.pv_list); m->md.pv_memattr = VM_MEMATTR_WRITE_BACK; + m->md.pv_flags = 0; } static void @@ -6920,6 +6923,7 @@ pmap_zero_page(vm_page_t m) void *va = VM_PAGE_TO_DMAP(m); pagezero(va); + m->md.pv_flags &= ~PV_MTE_TAGGED; } /* @@ -6951,6 +6955,15 @@ pmap_copy_page(vm_page_t msrc, vm_page_t mdst) void *src = VM_PAGE_TO_DMAP(msrc); void *dst = VM_PAGE_TO_DMAP(mdst); + /* + * On a page copy, check whether the src page is tagged. If it is, + * we must copy the tags before copying the contents of the page. + */ + if ((msrc->md.pv_flags & PV_MTE_TAGGED) != 0) + mte_copy_tags(msrc, mdst, src, dst); + else + mdst->md.pv_flags &= ~PV_MTE_TAGGED; + pagecopy(src, dst); } @@ -6967,6 +6980,9 @@ pmap_copy_pages(vm_page_t ma[], vm_offset_t a_offset, vm_page_t mb[], int cnt; while (xfersize > 0) { + KASSERT(ADDR_IS_CANONICAL(a_offset), + ("%s: Address not in canonical form: %lx", __func__, a_offset)); + a_pg_offset = a_offset & PAGE_MASK; m_a = ma[a_offset >> PAGE_SHIFT]; p_a = m_a->phys_addr; @@ -8161,7 +8177,7 @@ pmap_unmapbios(void *p, vm_size_t size) /* Ensure the attributes are as expected for the DMAP region */ PMAP_LOCK(kernel_pmap); error = pmap_change_props_locked(va, size, - PROT_READ | PROT_WRITE, VM_MEMATTR_DEFAULT, false); + PROT_READ | PROT_WRITE, VM_MEMATTR_DEFAULT, -1, false); PMAP_UNLOCK(kernel_pmap); KASSERT(error == 0, ("%s: Failed to reset DMAP attributes: %d", __func__, error)); @@ -8267,7 +8283,25 @@ pmap_change_attr(void *va, vm_size_t size, int mode) int error; PMAP_LOCK(kernel_pmap); - error = pmap_change_props_locked(va, size, PROT_NONE, mode, false); + error = pmap_change_props_locked(va, size, PROT_NONE, mode, -1, false); + PMAP_UNLOCK(kernel_pmap); + return (error); +} + +int +pmap_change_dmap_attr(int mode) +{ + int error; + + KASSERT(mode == VM_MEMATTR_WRITE_BACK || + mode == VM_MEMATTR_TAGGED, + ("%s: mode %d must be compatible with write-back", __func__, mode)); + + PMAP_LOCK(kernel_pmap); + error = pmap_change_props_locked((void *)DMAP_MIN_ADDRESS, + dmap_max_addr - DMAP_MIN_ADDRESS, PROT_NONE, mode, dmap_attr, true); + if (error == 0) + dmap_attr = mode; PMAP_UNLOCK(kernel_pmap); return (error); } @@ -8289,20 +8323,20 @@ pmap_change_prot(void *va, vm_size_t size, vm_prot_t prot) return (EINVAL); PMAP_LOCK(kernel_pmap); - error = pmap_change_props_locked(va, size, prot, -1, false); + error = pmap_change_props_locked(va, size, prot, -1, -1, false); PMAP_UNLOCK(kernel_pmap); return (error); } static int pmap_change_props_locked(void *addr, vm_size_t size, vm_prot_t prot, - int mode, bool skip_unmapped) + int mode, int old_mode, bool skip_unmapped) { vm_offset_t base, offset, tmpva, va; vm_size_t pte_size; vm_paddr_t pa; pt_entry_t pte, *ptep, *newpte; - pt_entry_t bits, mask; + pt_entry_t bits, mask, old_mode_bits, old_mode_mask; char *tmpptep; int lvl, rv; @@ -8316,8 +8350,8 @@ pmap_change_props_locked(void *addr, vm_size_t size, vm_prot_t prot, !(base >= VM_MIN_KERNEL_ADDRESS && base < VM_MAX_KERNEL_ADDRESS)) return (EINVAL); - bits = 0; - mask = 0; + bits = old_mode_bits = 0; + mask = old_mode_mask = 0; if (mode != -1) { bits = ATTR_S1_IDX(mode); mask = ATTR_S1_IDX_MASK; @@ -8326,6 +8360,10 @@ pmap_change_props_locked(void *addr, vm_size_t size, vm_prot_t prot, bits |= ATTR_S1_XN; } } + if (old_mode != -1) { + old_mode_bits = ATTR_S1_IDX(old_mode); + old_mode_mask = ATTR_S1_IDX_MASK; + } if (prot != VM_PROT_NONE) { /* Don't mark the DMAP as executable. It never is on arm64. */ if (VIRT_IN_DMAP(base)) { @@ -8353,11 +8391,14 @@ pmap_change_props_locked(void *addr, vm_size_t size, vm_prot_t prot, if (ptep == NULL && !skip_unmapped) { return (EINVAL); } else if ((ptep == NULL && skip_unmapped) || - (pmap_load(ptep) & mask) == bits) { + (pmap_load(ptep) & mask) == bits || + (pmap_load(ptep) & old_mode_mask) != old_mode_bits) { /* - * We already have the correct attribute or there - * is no memory mapped at this address and we are - * skipping unmapped memory. + * We already have one of the following meaning + * we can skip this memory region:: + * - No memory mapped at this address + * - The new attributes are already set + * - The expected attributes are incorrect */ switch (lvl) { default: @@ -8487,12 +8528,24 @@ pmap_change_props_locked(void *addr, vm_size_t size, vm_prot_t prot, pa = PTE_TO_PHYS(pte); if (!VIRT_IN_DMAP(tmpva) && PHYS_IN_DMAP(pa)) { + int dmap_mode; + + /* + * When booting on HW with MTE enabled we may + * need to swap to a tagged type for the DMAP + * to allow tags to be set through it. + */ + if (mode == VM_MEMATTR_WRITE_BACK) + dmap_mode = dmap_attr; + else + dmap_mode = mode; + /* * Keep the DMAP memory in sync. */ rv = pmap_change_props_locked( PHYS_TO_DMAP(pa), pte_size, - prot, mode, true); + prot, dmap_mode, old_mode, true); if (rv != 0) return (rv); } diff --git a/sys/arm64/arm64/swtch.S b/sys/arm64/arm64/swtch.S index b3bf88135e57..b349072c06f4 100644 --- a/sys/arm64/arm64/swtch.S +++ b/sys/arm64/arm64/swtch.S @@ -75,7 +75,7 @@ * void cpu_throw(struct thread *old, struct thread *new) */ ENTRY(cpu_throw) - /* Of old == NULL skip disabling stepping */ + /* If old == NULL skip disabling stepping */ cbz x0, 1f /* If we were single stepping, disable it */ @@ -96,8 +96,9 @@ ENTRY(cpu_throw) mov x0, x1 #endif - /* This returns the thread pointer so no need to save it */ + /* These return the thread pointer so no need to save it */ bl ptrauth_switch + bl mte_switch #ifdef PERTHREAD_SSP mov x19, x0 #endif @@ -176,8 +177,9 @@ ENTRY(cpu_switch) mov x0, x1 #endif - /* This returns the thread pointer so no need to save it */ + /* These return the thread pointer so no need to save it */ bl ptrauth_switch + bl mte_switch /* This returns the thread pcb */ bl pmap_switch /* Move the new pcb out of the way */ @@ -276,6 +278,8 @@ ENTRY(fork_trampoline) ldp x26, x27, [sp, #TF_X + 26 * 8] ldp x28, x29, [sp, #TF_X + 28 * 8] + add sp, sp, #(TF_SIZE) + /* * No need for interrupts reenabling since PSR * will be set to the desired value anyway. diff --git a/sys/arm64/arm64/vm_machdep.c b/sys/arm64/arm64/vm_machdep.c index 4cb87ca9856e..635bdcef7025 100644 --- a/sys/arm64/arm64/vm_machdep.c +++ b/sys/arm64/arm64/vm_machdep.c @@ -27,8 +27,8 @@ #include "opt_platform.h" -#include <sys/param.h> #include <sys/systm.h> +#include <sys/kernel.h> #include <sys/limits.h> #include <sys/proc.h> #include <sys/sf_buf.h> @@ -61,6 +61,8 @@ */ cpu_reset_hook_t cpu_reset_hook = psci_reset; +static uma_zone_t pcb_zone; + /* * Finish a fork operation, with process p2 nearly set up. * Copy and update the pcb, set up the stack so that the child @@ -89,25 +91,21 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) #endif } - pcb2 = (struct pcb *)(td2->td_kstack + - td2->td_kstack_pages * PAGE_SIZE) - 1; - - td2->td_pcb = pcb2; + pcb2 = td2->td_pcb; bcopy(td1->td_pcb, pcb2, sizeof(*pcb2)); /* Clear the debug register state. */ bzero(&pcb2->pcb_dbg_regs, sizeof(pcb2->pcb_dbg_regs)); ptrauth_fork(td2, td1); + mte_fork(td2, td1); - tf = STACKALIGN((struct trapframe *)pcb2 - 1); + tf = td2->td_frame; bcopy(td1->td_frame, tf, sizeof(*tf)); tf->tf_x[0] = 0; tf->tf_x[1] = 0; tf->tf_spsr = td1->td_frame->tf_spsr & (PSR_M_32 | PSR_DAIF); - td2->td_frame = tf; - /* Set the return value registers for fork() */ td2->td_pcb->pcb_x[PCB_X19] = (uintptr_t)fork_return; td2->td_pcb->pcb_x[PCB_X20] = (uintptr_t)td2; @@ -203,6 +201,7 @@ cpu_copy_thread(struct thread *td, struct thread *td0) /* Generate new pointer authentication keys. */ ptrauth_copy_thread(td, td0); + mte_copy_thread(td, td0); } /* @@ -265,17 +264,21 @@ cpu_thread_exit(struct thread *td) void cpu_thread_alloc(struct thread *td) { - - td->td_pcb = (struct pcb *)(td->td_kstack + - td->td_kstack_pages * PAGE_SIZE) - 1; - td->td_frame = (struct trapframe *)STACKALIGN( - (struct trapframe *)td->td_pcb - 1); + td->td_pcb = uma_zalloc(pcb_zone, M_WAITOK); ptrauth_thread_alloc(td); + mte_thread_alloc(td); +} + +void +cpu_thread_new_kstack(struct thread *td) +{ + td->td_frame = (struct trapframe *)td_kstack_top(td) - 1; } void cpu_thread_free(struct thread *td) { + uma_zfree(pcb_zone, td->td_pcb); } void @@ -335,3 +338,11 @@ cpu_sync_core(void) * return from ELx is a context synchronization event. */ } + +static void +pcbinit(void *dummy __unused) +{ + pcb_zone = uma_zcreate("pcb", sizeof(struct pcb), NULL, NULL, NULL, + NULL, UMA_ALIGNOF(struct pcb), 0); +} +SYSINIT(pcbinit, SI_SUB_INTRINSIC, SI_ORDER_ANY, pcbinit, NULL); diff --git a/sys/arm64/include/cpu.h b/sys/arm64/include/cpu.h index 05844ad63036..bdbc601edd26 100644 --- a/sys/arm64/include/cpu.h +++ b/sys/arm64/include/cpu.h @@ -277,6 +277,16 @@ void ptrauth_thread0(struct thread *); void ptrauth_mp_start(uint64_t); #endif +/* Memory Tagging Extension (MTE) support */ +void mte_fork(struct thread *, struct thread *); +void mte_exec(struct thread *); +void mte_copy_thread(struct thread *, struct thread *); +void mte_thread_alloc(struct thread *); +void mte_thread0(struct thread *); + +void mte_sync_tags(vm_page_t page); +void mte_copy_tags(vm_page_t, vm_page_t, char *, char *); + /* Functions to read the sanitised view of the special registers */ void update_special_regs(u_int); void update_special_reg_iss(u_int, uint64_t, uint64_t); diff --git a/sys/arm64/include/elf.h b/sys/arm64/include/elf.h index a5a90f8c7712..7940bb259256 100644 --- a/sys/arm64/include/elf.h +++ b/sys/arm64/include/elf.h @@ -96,6 +96,12 @@ __ElfType(Auxinfo); /* First __FreeBSD_version that supports Top Byte Ignore (TBI) */ #define TBI_VERSION 1500058 +/* + * The HWCAP values must be identical to Linux. Many userspace programs + * will define missing HWCAP values to the Linux version. To keep these + * working when we add the HWCAP it must be the same. + */ + /* HWCAP */ #define HWCAP_FP (1 << 0) #define HWCAP_ASIMD (1 << 1) diff --git a/sys/arm64/include/pcpu.h b/sys/arm64/include/pcpu.h index 286a40e7de3d..d04f975350d8 100644 --- a/sys/arm64/include/pcpu.h +++ b/sys/arm64/include/pcpu.h @@ -55,7 +55,6 @@ struct debug_monitor_state; #ifdef _KERNEL -struct pcb; struct pcpu; static inline struct pcpu * diff --git a/sys/arm64/include/pmap.h b/sys/arm64/include/pmap.h index 00b54a874e12..cf20827fa666 100644 --- a/sys/arm64/include/pmap.h +++ b/sys/arm64/include/pmap.h @@ -70,9 +70,13 @@ struct md_page { TAILQ_HEAD(,pv_entry) pv_list; int pv_gen; vm_memattr_t pv_memattr; - uint8_t pv_reserve[3]; + uint8_t pv_flags; + uint8_t pv_reserve[2]; }; +/* machine page flags */ +#define PV_MTE_TAGGED 0x01 /* page is tagged with MTE */ + enum pmap_stage { PM_INVALID, PM_STAGE1, @@ -148,6 +152,7 @@ void pmap_activate_vm(pmap_t); void pmap_bootstrap_dmap(vm_size_t); void pmap_bootstrap(void); int pmap_change_attr(void *va, vm_size_t size, int mode); +int pmap_change_dmap_attr(int); int pmap_change_prot(void *va, vm_size_t size, vm_prot_t prot); void pmap_kenter(vm_offset_t sva, vm_size_t size, vm_paddr_t pa, int mode); void pmap_kenter_device(vm_offset_t, vm_size_t, vm_paddr_t); diff --git a/sys/arm64/include/proc.h b/sys/arm64/include/proc.h index d5879a794269..22ceb614413d 100644 --- a/sys/arm64/include/proc.h +++ b/sys/arm64/include/proc.h @@ -69,9 +69,11 @@ struct mdthread { uint64_t md_efirt_tmp; int md_efirt_dis_pf; - int md_reserved0; + u_int md_flags; +#define MD_FLAG_MTE_ASYNC_FAULT_SHIFT 0 +#define MD_FLAG_MTE_ASYNC_FAULT (1u << 0) uint64_t md_sctlr; - uint64_t md_reserved1; + uint64_t md_gcr; /* FEAT_MTE: Tag Control Register */ }; struct mdproc { diff --git a/sys/arm64/include/stack.h b/sys/arm64/include/stack.h index 19e9e837e3ee..23e7a5af27de 100644 --- a/sys/arm64/include/stack.h +++ b/sys/arm64/include/stack.h @@ -39,11 +39,9 @@ bool unwind_frame(struct thread *, struct unwind_state *); #ifdef _SYS_PROC_H_ -#include <machine/pcb.h> - #define GET_STACK_USAGE(total, used) do { \ struct thread *td = curthread; \ - (total) = td->td_kstack_pages * PAGE_SIZE - sizeof(struct pcb); \ + (total) = ptoa(td->td_kstack_pages); \ (used) = td->td_kstack + (total) - (char *)&td; \ } while (0) @@ -51,8 +49,7 @@ static __inline bool kstack_contains(struct thread *td, vm_offset_t va, size_t len) { return (va >= (vm_offset_t)td->td_kstack && va + len >= va && - va + len <= (vm_offset_t)td->td_kstack + td->td_kstack_pages * - PAGE_SIZE - sizeof(struct pcb)); + va + len <= (vm_offset_t)td_kstack_top(td)); } #endif /* _SYS_PROC_H_ */ diff --git a/sys/arm64/rockchip/rk3328_codec.c b/sys/arm64/rockchip/rk3328_codec.c index 22e3cde9093e..a019cab27cc9 100644 --- a/sys/arm64/rockchip/rk3328_codec.c +++ b/sys/arm64/rockchip/rk3328_codec.c @@ -416,18 +416,8 @@ static int rkcodec_mixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) { struct rkcodec_softc *sc; - struct mtx *mixer_lock; - uint8_t do_unlock; sc = device_get_softc(mix_getdevinfo(m)); - mixer_lock = mixer_get_lock(m); - - if (mtx_owned(mixer_lock)) { - do_unlock = 0; - } else { - do_unlock = 1; - mtx_lock(mixer_lock); - } right = left; @@ -443,10 +433,6 @@ rkcodec_mixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned rig } RKCODEC_UNLOCK(sc); - if (do_unlock) { - mtx_unlock(mixer_lock); - } - return (left | (right << 8)); } diff --git a/sys/arm64/rockchip/rk_gpio.c b/sys/arm64/rockchip/rk_gpio.c index 8da37d516802..7c2071d2d178 100644 --- a/sys/arm64/rockchip/rk_gpio.c +++ b/sys/arm64/rockchip/rk_gpio.c @@ -227,8 +227,22 @@ rk_gpio_intr(void *arg) status &= ~(1 << pin); if (intr_isrc_dispatch(RK_GPIO_ISRC(sc, pin), tf)) { - device_printf(sc->sc_dev, "Interrupt pin=%d unhandled\n", - pin); + /* + * Pin asserted but no consumer is registered for it + * yet (or anymore). Level-triggered sources keep + * firing on every interrupt cycle, so a single stuck + * pin floods the console with thousands of these + * messages per second. Mask the pin's IRQ at the + * controller and disable further dispatches; if a + * consumer attaches later it will re-enable through + * pic_enable_intr / rk_gpio_pic_enable_intr. + */ + RK_GPIO_LOCK(sc); + rk_gpio_write_bit(sc, RK_GPIO_INTMASK, pin, 1); + rk_gpio_write_bit(sc, RK_GPIO_INTEN, pin, 0); + RK_GPIO_UNLOCK(sc); + device_printf(sc->sc_dev, + "Interrupt pin=%d unhandled โ masked\n", pin); continue; } @@ -818,10 +832,14 @@ rk_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc, return (EINVAL); } rk_gpio_write_bit(sc, RK_GPIO_DEBOUNCE, pin, 1); - rk_gpio_write_bit(sc, RK_GPIO_INTMASK, pin, 0); - rk_gpio_write_bit(sc, RK_GPIO_INTEN, pin, 1); RK_GPIO_UNLOCK(sc); + /* + * Leave the interrupt masked + disabled here. INTRNG will call + * pic_enable_intr() next to make it live. That keeps the + * masking responsibility cleanly in enable/disable rather than + * split between setup and disable. + */ return (0); } @@ -837,14 +855,86 @@ rk_pic_teardown_intr(device_t dev, struct intr_irqsrc *isrc, if (isrc->isrc_handlers == 0) { irqsrc->mode = GPIO_INTR_CONFORM; RK_GPIO_LOCK(sc); - rk_gpio_write_bit(sc, RK_GPIO_INTEN, irqsrc->irq, 0); - rk_gpio_write_bit(sc, RK_GPIO_INTMASK, irqsrc->irq, 0); + /* + * INTEN/INTMASK are already cleared by pic_disable_intr, + * which INTRNG calls before teardown of the last handler. + * We only need to undo what setup_intr configured -- here, + * the debounce filter. + */ rk_gpio_write_bit(sc, RK_GPIO_DEBOUNCE, irqsrc->irq, 0); RK_GPIO_UNLOCK(sc); } return (0); } +/* + * INTRNG calls pic_disable_intr() during teardown of the final handler + * for a source, OR when a consumer explicitly wants the source off. + * Clear INTEN so the controller will not raise this pin at all. + * + * The in-flight masking between FILTER_SCHEDULE_THREAD and ithread + * completion is handled by pic_pre_ithread() / pic_post_ithread() + * below, NOT by this method. + */ +static void +rk_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc) +{ + struct rk_gpio_softc *sc = device_get_softc(dev); + struct rk_pin_irqsrc *rkisrc = (struct rk_pin_irqsrc *)isrc; + + RK_GPIO_LOCK(sc); + rk_gpio_write_bit(sc, RK_GPIO_INTMASK, rkisrc->irq, 1); + rk_gpio_write_bit(sc, RK_GPIO_INTEN, rkisrc->irq, 0); + RK_GPIO_UNLOCK(sc); +} + +/* + * INTRNG calls pic_enable_intr() to make a source live for the first + * time (after setup_intr), or to re-enable after a prior + * pic_disable_intr(). Set INTEN and unmask so the controller starts + * delivering this pin. + */ +static void +rk_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc) +{ + struct rk_gpio_softc *sc = device_get_softc(dev); + struct rk_pin_irqsrc *rkisrc = (struct rk_pin_irqsrc *)isrc; + + RK_GPIO_LOCK(sc); + rk_gpio_write_bit(sc, RK_GPIO_INTEN, rkisrc->irq, 1); + rk_gpio_write_bit(sc, RK_GPIO_INTMASK, rkisrc->irq, 0); + RK_GPIO_UNLOCK(sc); +} + +/* + * Called by INTRNG before delivering to the ithread. Mask the source + * so it cannot re-fire during the ithread window -- without this, + * level-low IRQs (e.g. FUSB302 INT_N) re-trigger continuously and + * starve the ithread (~210 kHz storm observed via dtrace). + * Re-unmasked in pic_post_ithread() once the ithread acks the source. + */ +static void +rk_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc) +{ + struct rk_gpio_softc *sc = device_get_softc(dev); + struct rk_pin_irqsrc *rkisrc = (struct rk_pin_irqsrc *)isrc; + + RK_GPIO_LOCK(sc); + rk_gpio_write_bit(sc, RK_GPIO_INTMASK, rkisrc->irq, 1); + RK_GPIO_UNLOCK(sc); +} + +static void +rk_pic_post_ithread(device_t dev, struct intr_irqsrc *isrc) +{ + struct rk_gpio_softc *sc = device_get_softc(dev); + struct rk_pin_irqsrc *rkisrc = (struct rk_pin_irqsrc *)isrc; + + RK_GPIO_LOCK(sc); + rk_gpio_write_bit(sc, RK_GPIO_INTMASK, rkisrc->irq, 0); + RK_GPIO_UNLOCK(sc); +} + static device_method_t rk_gpio_methods[] = { /* Device interface */ DEVMETHOD(device_probe, rk_gpio_probe), @@ -873,6 +963,10 @@ static device_method_t rk_gpio_methods[] = { DEVMETHOD(pic_map_intr, rk_pic_map_intr), DEVMETHOD(pic_setup_intr, rk_pic_setup_intr), DEVMETHOD(pic_teardown_intr, rk_pic_teardown_intr), + DEVMETHOD(pic_disable_intr, rk_pic_disable_intr), + DEVMETHOD(pic_enable_intr, rk_pic_enable_intr), + DEVMETHOD(pic_pre_ithread, rk_pic_pre_ithread), + DEVMETHOD(pic_post_ithread, rk_pic_post_ithread), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_node, rk_gpio_get_node), diff --git a/sys/cam/ctl/scsi_ctl.c b/sys/cam/ctl/scsi_ctl.c index 68f1cabf6d07..6a55aba2669b 100644 --- a/sys/cam/ctl/scsi_ctl.c +++ b/sys/cam/ctl/scsi_ctl.c @@ -522,7 +522,8 @@ ctlferegister(struct cam_periph *periph, void *arg) new_ccb->ccb_h.io_ptr = new_io; LIST_INSERT_HEAD(&softc->atio_list, &new_ccb->ccb_h, periph_links.le); - xpt_setup_ccb(&new_ccb->ccb_h, periph->path, CAM_PRIORITY_NONE); + xpt_setup_ccb(&new_ccb->ccb_h, periph->path, + CAM_PRIORITY_NORMAL); new_ccb->ccb_h.func_code = XPT_ACCEPT_TARGET_IO; new_ccb->ccb_h.cbfcnp = ctlfedone; new_ccb->ccb_h.flags |= CAM_UNLOCKED; @@ -569,7 +570,8 @@ ctlferegister(struct cam_periph *periph, void *arg) new_ccb->ccb_h.io_ptr = new_io; LIST_INSERT_HEAD(&softc->inot_list, &new_ccb->ccb_h, periph_links.le); - xpt_setup_ccb(&new_ccb->ccb_h, periph->path, CAM_PRIORITY_NONE); + xpt_setup_ccb(&new_ccb->ccb_h, periph->path, + CAM_PRIORITY_NORMAL); new_ccb->ccb_h.func_code = XPT_IMMEDIATE_NOTIFY; new_ccb->ccb_h.cbfcnp = ctlfedone; new_ccb->ccb_h.flags |= CAM_UNLOCKED; @@ -1003,7 +1005,7 @@ ctlfe_requeue_ccb(struct cam_periph *periph, union ccb *ccb, int unlock) * target/lun. Reset the target and LUN fields back to the wildcard * values before we send them back down to the SIM. */ - xpt_setup_ccb_flags(&ccb->ccb_h, periph->path, CAM_PRIORITY_NONE, + xpt_setup_ccb_flags(&ccb->ccb_h, periph->path, CAM_PRIORITY_NORMAL, ccb->ccb_h.flags); xpt_action(ccb); diff --git a/sys/compat/linux/linux_mmap.c b/sys/compat/linux/linux_mmap.c index a8e790a29da4..9fecb6ebb2ad 100644 --- a/sys/compat/linux/linux_mmap.c +++ b/sys/compat/linux/linux_mmap.c @@ -63,6 +63,10 @@ static int linux_mmap_check_fp(struct file *fp, int flags, int prot, int maxprot) { + /* Linux returns EBADF if mmap() is called on an O_PATH file descriptor */ + if (fp->f_ops == &path_fileops) + return (EBADF); + /* Linux mmap() just fails for O_WRONLY files */ if ((fp->f_flag & FREAD) == 0) return (EACCES); diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c index cade61e8446f..901c59702840 100644 --- a/sys/compat/linuxkpi/common/src/linux_80211.c +++ b/sys/compat/linuxkpi/common/src/linux_80211.c @@ -1607,12 +1607,13 @@ lkpi_iv_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k) } sta = LSTA_TO_STA(lsta); - keylen = k->wk_keylen; + keylen = ieee80211_crypto_get_key_len(k); lcipher = lkpi_net80211_to_l80211_cipher_suite( - k->wk_cipher->ic_cipher, k->wk_keylen); + k->wk_cipher->ic_cipher, ieee80211_crypto_get_key_len(k)); switch (lcipher) { case WLAN_CIPHER_SUITE_TKIP: - keylen += 2 * k->wk_cipher->ic_miclen; + keylen += ieee80211_crypto_get_key_txmic_len(k); + keylen += ieee80211_crypto_get_key_rxmic_len(k); break; case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_GCMP: @@ -1643,8 +1644,9 @@ lkpi_iv_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k) kc->hw_key_idx = /* set by hw and needs to be passed for TX */; #endif atomic64_set(&kc->tx_pn, k->wk_keytsc); - kc->keylen = k->wk_keylen; - memcpy(kc->key, k->wk_key, k->wk_keylen); + kc->keylen = ieee80211_crypto_get_key_len(k); + memcpy(kc->key, ieee80211_crypto_get_key_data(k), + ieee80211_crypto_get_key_len(k)); if (k->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV)) kc->flags |= IEEE80211_KEY_FLAG_PAIRWISE; @@ -1656,8 +1658,12 @@ lkpi_iv_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k) switch (kc->cipher) { case WLAN_CIPHER_SUITE_TKIP: - memcpy(kc->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY, k->wk_txmic, k->wk_cipher->ic_miclen); - memcpy(kc->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY, k->wk_rxmic, k->wk_cipher->ic_miclen); + memcpy(kc->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY, + ieee80211_crypto_get_key_txmic_data(k), + ieee80211_crypto_get_key_txmic_len(k)); + memcpy(kc->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY, + ieee80211_crypto_get_key_rxmic_data(k), + ieee80211_crypto_get_key_rxmic_len(k)); break; case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_GCMP: @@ -5531,10 +5537,10 @@ lkpi_hw_crypto_prepare_tkip(struct ieee80211_key *k, * "enmic" (though we do not do that). */ /* any conditions to not apply this? */ - if (skb_tailroom(skb) < k->wk_cipher->ic_miclen) + if (skb_tailroom(skb) < ieee80211_crypto_get_key_txmic_len(k)) return (ENOBUFS); - p = skb_put(skb, k->wk_cipher->ic_miclen); + p = skb_put(skb, ieee80211_crypto_get_key_txmic_len(k)); if ((kc->flags & IEEE80211_KEY_FLAG_PUT_MIC_SPACE) != 0) goto encrypt; diff --git a/sys/compat/linuxkpi/common/src/linux_acpi.c b/sys/compat/linuxkpi/common/src/linux_acpi.c index 85a3afe5d01d..680d111d0194 100644 --- a/sys/compat/linuxkpi/common/src/linux_acpi.c +++ b/sys/compat/linuxkpi/common/src/linux_acpi.c @@ -126,7 +126,7 @@ linux_handle_power_suspend_event(void *arg __unused, enum power_stype stype) /* * XXX: obiwac Not 100% sure this is correct, but * acpi_target_sleep_state does seem to be set to - * ACPI_STATE_S3 during s2idle on Linux. + * ACPI_STATE_S3 during suspend-to-idle (aka s2idle) on Linux. */ linux_acpi_target_sleep_state = ACPI_STATE_S3; pm_suspend_target_state = PM_SUSPEND_TO_IDLE; diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64 index 172f79cc5773..2f6052da7e51 100644 --- a/sys/conf/files.arm64 +++ b/sys/conf/files.arm64 @@ -76,6 +76,7 @@ arm64/arm64/ofw_machdep.c optional fdt arm64/arm64/pl031_rtc.c optional fdt pl031 arm64/arm64/ptrauth.c standard \ compile-with "${NORMAL_C:N-mbranch-protection*} -mbranch-protection=bti" +arm64/arm64/mte.c standard arm64/arm64/pmap.c standard arm64/arm64/ptrace_machdep.c standard arm64/arm64/rsi.c standard diff --git a/sys/ddb/db_ps.c b/sys/ddb/db_ps.c index 8e027997ea75..59dcde453b93 100644 --- a/sys/ddb/db_ps.c +++ b/sys/ddb/db_ps.c @@ -358,8 +358,7 @@ DB_SHOW_COMMAND(thread, db_show_thread) if (td->td_name[0] != '\0') db_printf(" name: %s\n", td->td_name); db_printf(" pcb: %p\n", td->td_pcb); - db_printf(" stack: %p-%p\n", td->td_kstack, - td->td_kstack + td->td_kstack_pages * PAGE_SIZE - 1); + db_printf(" stack: %p-%p\n", td->td_kstack, td_kstack_top(td) - 1); db_printf(" flags: %#x ", td->td_flags); db_printf(" pflags: %#x\n", td->td_pflags); db_printf(" state: "); diff --git a/sys/dev/acpi_support/acpi_ibm.c b/sys/dev/acpi_support/acpi_ibm.c index 693d793532c1..a5c44b1f81b9 100644 --- a/sys/dev/acpi_support/acpi_ibm.c +++ b/sys/dev/acpi_support/acpi_ibm.c @@ -1449,8 +1449,8 @@ acpi_ibm_eventhandler(struct acpi_ibm_softc *sc, int arg) switch (arg) { /* * XXX "Suspend-to-RAM" here is as opposed to suspend-to-disk, but it is - * fine if our suspend sleep state transition request puts us in s2idle - * instead of suspend-to-RAM. + * fine if our suspend sleep state transition request puts us in + * suspend-to-idle instead of actual suspend-to-RAM. */ case IBM_EVENT_SUSPEND_TO_RAM: (void)power_pm_suspend(POWER_TRANSITION_SUSPEND); diff --git a/sys/dev/bnxt/bnxt_en/bnxt_sriov.c b/sys/dev/bnxt/bnxt_en/bnxt_sriov.c index 270c18165fb7..071feffbadfd 100644 --- a/sys/dev/bnxt/bnxt_en/bnxt_sriov.c +++ b/sys/dev/bnxt/bnxt_en/bnxt_sriov.c @@ -7,6 +7,8 @@ #include "bnxt_hwrm.h" #include "bnxt_sriov.h" +#ifdef PCI_IOV + static int bnxt_set_vf_admin_mac(struct bnxt_softc *softc, struct bnxt_vf_info *vf, const uint8_t *mac) @@ -973,6 +975,43 @@ void bnxt_sriov_attach(struct bnxt_softc *softc) device_printf(dev, "Failed to initialize SR-IOV (error=%d)\n", rc); } +#else + +void +bnxt_sriov_attach(struct bnxt_softc *softc __unused) +{ +} + +int +bnxt_cfg_hw_sriov(struct bnxt_softc *softc __unused, + uint16_t *num_vfs __unused, bool reset __unused) +{ + return (0); +} + +int +bnxt_approve_mac(struct bnxt_softc *sc __unused) +{ + return (0); +} + +void +bnxt_hwrm_exec_fwd_req(struct bnxt_softc *softc __unused) +{ +} + +bool +bnxt_promisc_ok(struct bnxt_softc *softc __unused) +{ + return (true); +} + +void +bnxt_update_vf_mac(struct bnxt_softc *sc __unused) +{ +} +#endif + void bnxt_reenable_sriov(struct bnxt_softc *bp) { if (BNXT_PF(bp)) { diff --git a/sys/dev/bnxt/bnxt_en/bnxt_sriov.h b/sys/dev/bnxt/bnxt_en/bnxt_sriov.h index 176f54af0aa8..24ea11f29b83 100644 --- a/sys/dev/bnxt/bnxt_en/bnxt_sriov.h +++ b/sys/dev/bnxt/bnxt_en/bnxt_sriov.h @@ -8,10 +8,6 @@ #include "opt_global.h" #include "bnxt.h" -#ifndef PCI_IOV -#define PCI_IOV 1 -#endif - /* macro definations */ #define BNXT_MAX_VFS 4 diff --git a/sys/dev/bnxt/bnxt_en/if_bnxt.c b/sys/dev/bnxt/bnxt_en/if_bnxt.c index 6618016f3932..6d82302615e1 100644 --- a/sys/dev/bnxt/bnxt_en/if_bnxt.c +++ b/sys/dev/bnxt/bnxt_en/if_bnxt.c @@ -2875,11 +2875,9 @@ bnxt_attach_post(if_ctx_t ctx) bnxt_dcb_init(softc); bnxt_rdma_aux_device_init(softc); -#if PCI_IOV /* SR-IOV attach */ if (BNXT_PF(softc) && BNXT_CHIP_P5_PLUS(softc)) bnxt_sriov_attach(softc); -#endif failed: return rc; diff --git a/sys/dev/cxgbe/adapter.h b/sys/dev/cxgbe/adapter.h index 24a482b74dfb..8c5cf052b689 100644 --- a/sys/dev/cxgbe/adapter.h +++ b/sys/dev/cxgbe/adapter.h @@ -194,6 +194,7 @@ enum { IHF_CLR_ALL_SET = (1 << 5), /* Clear all set bits */ IHF_CLR_ALL_UNIGNORED = (1 << 6), /* Clear all unignored bits */ IHF_RUN_ALL_ACTIONS = (1 << 7), /* As if all cause are set */ + IHF_CLR_DELAYED = (1 << 9), /* Cleared in a delayed call */ }; #define IS_DETACHING(vi) ((vi)->flags & VI_DETACHING) diff --git a/sys/dev/cxgbe/common/t4_hw.c b/sys/dev/cxgbe/common/t4_hw.c index f4eef54e5c6b..41606201ad39 100644 --- a/sys/dev/cxgbe/common/t4_hw.c +++ b/sys/dev/cxgbe/common/t4_hw.c @@ -4794,6 +4794,27 @@ struct intr_info { const struct intr_action *actions; }; +/* Helper to clear interrupts that have IHF_CLR_DELAYED. */ +static void +clear_int_cause_reg(struct adapter *sc, const struct intr_info *ii, int flags) +{ + u32 cause, ucause; + + cause = ucause = t4_read_reg(sc, ii->cause_reg); + if (cause == 0) + return; + flags |= ii->flags; + if (flags & IHF_IGNORE_IF_DISABLED) + ucause &= t4_read_reg(sc, ii->enable_reg); + if (flags & IHF_CLR_ALL_SET) { + t4_write_reg(sc, ii->cause_reg, cause); + (void)t4_read_reg(sc, ii->cause_reg); + } else if (ucause != 0 && flags & IHF_CLR_ALL_UNIGNORED) { + t4_write_reg(sc, ii->cause_reg, ucause); + (void)t4_read_reg(sc, ii->cause_reg); + } +} + static inline char intr_alert_char(u32 cause, u32 enable, u32 fatal) { @@ -4869,8 +4890,8 @@ t4_handle_intr(struct adapter *sc, const struct intr_info *ii, uint32_t acause, } } - /* clear */ - if (cause != 0) { + /* Clear here unless delayed clear is requested. */ + if (cause != 0 && (flags & IHF_CLR_DELAYED) == 0) { if (flags & IHF_CLR_ALL_SET) { t4_write_reg(sc, ii->cause_reg, cause); (void)t4_read_reg(sc, ii->cause_reg); @@ -5003,22 +5024,63 @@ static bool pcie_intr_handler(struct adapter *adap, int arg, int flags) .details = NULL, .actions = NULL, }; + static const struct intr_details pcie_intr_cause_ext_details[] = { + { F_IPFORMQPERR, "PCIe IP FormQ Buffer PERR" }, + { F_IPFORMQCERR, "PCIe IP FormQ Buffer CERR" }, + { F_TRGT1GRPCERR, "TRGT1 Group FIFOs CERR" }, + { F_IPSOTCERR, "PCIe IP SOT Buffer SRAM CERR" }, + { F_IPRETRYCERR, "PCIe IP Replay Buffer CERR" }, + { F_IPRXDATAGRPCERR, "PCIe IP Rx Data Group SRAMs CERR" }, + { F_IPRXHDRGRPCERR, "PCIe IP Rx Header Group SRAMs CERR" }, + { F_A0ARBRSPORDFIFOPERR, "A0 Arbiter Response Order FIFO Parity Error" }, + { F_HRSPCERR, "Master HMA Channel Response Data SRAM CERR" }, + { F_HREQRDCERR, "Master HMA Channel Read Request SRAM CERR" }, + { F_HREQWRCERR, "Master HMA Channel Write Request SRAM CERR" }, + { F_DRSPCERR, "Master DMA Channel Response Data SRAM CERR" }, + { F_DREQRDCERR, "Master DMA Channel Read Request SRAM CERR" }, + { F_DREQWRCERR, "Master DMA Channel Write Request SRAM CERR" }, + { F_CRSPCERR, "Master CMD Channel Response Data SRAM CERR" }, + { F_ARSPPERR, "Master ARM Channel Response Data SRAM PERR" }, + { F_AREQRDPERR, "Master ARM Channel Read Request SRAM PERR" }, + { F_AREQWRPERR, "Master ARM Channel Write Request SRAM PERR" }, + { F_PIOREQGRPCERR, "PIO Request Group FIFOs CERR" }, + { F_ARSPCERR, "Master ARM Channel Response Data SRAM CERR" }, + { F_AREQRDCERR, "Master ARM Channel Read Request SRAM CERR" }, + { F_AREQWRCERR, "Master ARM Channel Write Request SRAM CERR" }, + { F_MARSPPERR, "INIC MA Ctrl and Data Rsp Perr" }, + { F_INICMAWDATAORDPERR, "INIC Ma Arb Write Ord Data Fifo Perr" }, + { F_EMUPERR, "CFG EMU SRAM PERR" }, + { F_ERRSPPERR, "CFG EMU SRAM CERR" }, + { F_MSTGRPCERR, "Master Data Path and Response Read Queue SRAM CERR" }, + { 0 } + }; struct intr_info pcie_int_cause_ext = { .name = "PCIE_INT_CAUSE_EXT", .cause_reg = A_PCIE_INT_CAUSE_EXT, .enable_reg = A_PCIE_INT_ENABLE_EXT, .fatal = 0, .flags = 0, - .details = NULL, + .details = pcie_intr_cause_ext_details, .actions = NULL, }; + static const struct intr_details pcie_intr_cause_x8_details[] = { + { F_X8TGTGRPPERR, "x8 TGT Group FIFOs parity error" }, + { F_X8IPSOTPERR, "PCIe x8 IP SOT Buffer SRAM PERR" }, + { F_X8IPRETRYPERR, "PCIe x8 IP Replay Buffer PERR" }, + { F_X8IPRXDATAGRPPERR, "PCIe x8 IP Rx Data Group SRAMs PERR" }, + { F_X8IPRXHDRGRPPERR, "PCIe x8 IP Rx Header Group SRAMs PERR" }, + { F_X8IPCORECERR, "x8 IP SOT, Retry, RxData, RxHdr SRAM CERR" }, + { F_X8MSTGRPPERR, "x8 Master Data Path and Response Read Queue SRAM PERR" }, + { F_X8MSTGRPCERR, "x8 Master Data Path and Response Read Queue SRAM CERR" }, + { 0 } + }; struct intr_info pcie_int_cause_x8 = { .name = "PCIE_INT_CAUSE_X8", .cause_reg = A_PCIE_INT_CAUSE_X8, .enable_reg = A_PCIE_INT_ENABLE_X8, .fatal = 0, .flags = 0, - .details = NULL, + .details = pcie_intr_cause_x8_details, .actions = NULL, }; bool fatal = false; @@ -5050,80 +5112,247 @@ static bool tp_intr_handler(struct adapter *adap, int arg, int flags) { F_FLMTXFLSTEMPTY, "TP out of Tx pages" }, { 0 } }; - static const struct intr_info tp_intr_info = { + static const struct intr_details t7_tp_intr_details[] = { + { F_FLMTXFLSTEMPTY, "Offload memory manager Tx free list empty" }, + { F_TPCERR, "TP modules flagged Correctable Error" }, + { F_OTHERPERR, "TP Other modules (Core, TM, FLM, MMGR, DB) Parity Error" }, + { F_TPEING1PERR, "TP-ESide Ingress1 Parity Error" }, + { F_TPEING0PERR, "TP-ESide Ingress0 Parity Error" }, + { F_TPEEGPERR, "TP-ESide Egress Parity Error" }, + { F_TPCPERR, "TP-CSide Parity Error" }, + { 0 } + }; + struct intr_info tp_intr_info = { .name = "TP_INT_CAUSE", .cause_reg = A_TP_INT_CAUSE, .enable_reg = A_TP_INT_ENABLE, .fatal = 0x7fffffff, - .flags = IHF_FATAL_IFF_ENABLED, - .details = tp_intr_details, + .flags = IHF_FATAL_IFF_ENABLED | IHF_CLR_DELAYED, + .details = NULL, .actions = NULL, }; - static const struct intr_info tp_inic_perr_cause = { - .name = "TP_INIC_PERR_CAUSE", - .cause_reg = A_TP_INIC_PERR_CAUSE, - .enable_reg = A_TP_INIC_PERR_ENABLE, + static const struct intr_details tp_cerr_cause_details[] = { + { F_TPCEGDATAFIFO, "TPCSide Egress Data FIFO" }, + { F_TPCLBKDATAFIFO, "TPCSide Loopback Data FIFO" }, + { F_RSSLKPSRAM, "RSS Lookup SRAM" }, + { F_SRQSRAM, "SRQ SRAM" }, + { F_ARPDASRAM, "ARP DA SRAM" }, + { F_ARPSASRAM, "ARP SA SRAM" }, + { F_ARPGRESRAM, "ARP GRE SRAM" }, + { F_ARPIPSECSRAM1, "ARP IPSec SRAM0" }, + { F_ARPIPSECSRAM0, "ARP IPSec SRAM1" }, + { 0 } + }; + static const struct intr_info tp_cerr_cause = { + .name = "TP_CERR_CAUSE", + .cause_reg = A_TP_CERR_CAUSE, + .enable_reg = A_TP_CERR_ENABLE, .fatal = 0xffffffff, .flags = IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = tp_cerr_cause_details, .actions = NULL, }; + static const struct intr_details tp_c_perr_details[] = { + { F_DMXFIFOOVFL, "Demux FIFO Overflow" }, + { F_URX2TPCDDPINTF, "ULPRX to TPC DDP Interface and FIFO" }, + { F_TPCDISPTOKENFIFO, "TPC Dispatch Token FIFO" }, + { F_TPCDISPCPLFIFO3, "TPC Dispatch CPL FIFO Ch3" }, + { F_TPCDISPCPLFIFO2, "TPC Dispatch CPL FIFO Ch2" }, + { F_TPCDISPCPLFIFO1, "TPC Dispatch CPL FIFO Ch1" }, + { F_TPCDISPCPLFIFO0, "TPC Dispatch CPL FIFO Ch0" }, + { F_URXPLDINTFCRC3, "ULPRX to TPC Payload Interface CRC Error Ch3" }, + { F_URXPLDINTFCRC2, "ULPRX to TPC Payload Interface CRC Error Ch2" }, + { F_URXPLDINTFCRC1, "ULPRX to TPC Payload Interface CRC Error Ch1" }, + { F_URXPLDINTFCRC0, "ULPRX to TPC Payload Interface CRC Error Ch0" }, + { F_DMXDBFIFO, "Demux DB FIFO" }, + { F_DMXDBSRAM, "Demux DB SRAM" }, + { F_DMXCPLFIFO, "Demux CPL FIFO" }, + { F_DMXCPLSRAM, "Demux CPL SRAM" }, + { F_DMXCSUMFIFO, "Demux Checksum FIFO" }, + { F_DMXLENFIFO, "Demux Length FIFO" }, + { F_DMXCHECKFIFO, "Demux Check CRC16 FIFO" }, + { F_DMXWINFIFO, "Demux Winner FIFO" }, + { F_EGTOKENFIFO, "Egress Token FIFO Parity Error" }, + { F_EGDATAFIFO, "Egress FIFO Parity Error" }, + { F_UTX2TPCINTF3, "ULPTX to TPC Interface Parity Error Ch3" }, + { F_UTX2TPCINTF2, "ULPTX to TPC Interface Parity Error Ch2" }, + { F_UTX2TPCINTF1, "ULPTX to TPC Interface Parity Error Ch1" }, + { F_UTX2TPCINTF0, "ULPTX to TPC Interface Parity Error Ch0" }, + { F_LBKTOKENFIFO, "Loopback Token FIFO Parity Error" }, + { F_LBKDATAFIFO, "Loopback FIFO Parity Error" }, + { 0 } + }; static const struct intr_info tp_c_perr_cause = { .name = "TP_C_PERR_CAUSE", .cause_reg = A_TP_C_PERR_CAUSE, .enable_reg = A_TP_C_PERR_ENABLE, .fatal = 0xffffffff, .flags = IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = tp_c_perr_details, .actions = NULL, }; + static const struct intr_details tp_e_eg_perr_details[] = { + { F_MPSLPBKTOKENFIFO, "MPS Loopback Token FIFO parity error" }, + { F_MPSMACTOKENFIFO, "MPS MAC Token FIFO parity error" }, + { F_DISPIPSECFIFO3, "Ch3 Dispatch IPSec FIFO parity error" }, + { F_DISPTCPFIFO3, "Ch3 Dispatch TCP FIFO parity error" }, + { F_DISPIPFIFO3, "Ch3 Dispatch IP FIFO parity error" }, + { F_DISPETHFIFO3, "Ch3 Dispatch ETH FIFO parity error" }, + { F_DISPGREFIFO3, "Ch3 Dispatch GRE FIFO parity error" }, + { F_DISPCPL5FIFO3, "Ch3 Dispatch CPL5 FIFO parity error" }, + { F_DISPIPSECFIFO2, "Ch2 Dispatch IPSec FIFO parity error" }, + { F_DISPTCPFIFO2, "Ch2 Dispatch TCP FIFO parity error" }, + { F_DISPIPFIFO2, "Ch2 Dispatch IP FIFO parity error" }, + { F_DISPETHFIFO2, "Ch2 Dispatch ETH FIFO parity error" }, + { F_DISPGREFIFO2, "Ch2 Dispatch GRE FIFO parity error" }, + { F_DISPCPL5FIFO2, "Ch2 Dispatch CPL5 FIFO parity error" }, + { F_DISPIPSECFIFO1, "Ch1 Dispatch IPSec FIFO parity error" }, + { F_DISPTCPFIFO1, "Ch1 Dispatch TCP FIFO parity error" }, + { F_DISPIPFIFO1, "Ch1 Dispatch IP FIFO parity error" }, + { F_DISPETHFIFO1, "Ch1 Dispatch ETH FIFO parity error" }, + { F_DISPGREFIFO1, "Ch1 Dispatch GRE FIFO parity error" }, + { F_DISPCPL5FIFO1, "Ch1 Dispatch CPL5 FIFO parity error" }, + { F_DISPIPSECFIFO0, "Ch0 Dispatch IPSec FIFO parity error" }, + { F_DISPTCPFIFO0, "Ch0 Dispatch TCP FIFO parity error" }, + { F_DISPIPFIFO0, "Ch0 Dispatch IP FIFO parity error" }, + { F_DISPETHFIFO0, "Ch0 Dispatch ETH FIFO parity error" }, + { F_DISPGREFIFO0, "Ch0 Dispatch GRE FIFO parity error" }, + { F_DISPCPL5FIFO0, "Ch0 Dispatch CPL5 FIFO parity error" }, + { 0 } + }; static const struct intr_info tp_e_eg_perr_cause = { .name = "TP_E_EG_PERR_CAUSE", .cause_reg = A_TP_E_EG_PERR_CAUSE, .enable_reg = A_TP_E_EG_PERR_ENABLE, .fatal = 0xffffffff, .flags = IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = tp_e_eg_perr_details, .actions = NULL, }; + static const struct intr_details tp_e_in0_perr_details[] = { + { F_DMXISSFIFO, "Demux ISS FIFO parity error" }, + { F_DMXERRFIFO, "Demux Error FIFO parity error" }, + { F_DMXATTFIFO, "Demux Attributes FIFO parity error" }, + { F_DMXTCPFIFO, "Demux TCP Fields FIFO parity error" }, + { F_DMXMPAFIFO, "Demux MPA FIFO parity error" }, + { F_DMXOPTFIFO, "Demux TCP Options FIFO parity error" }, + { F_INGTOKENFIFO, "Demux Ingress Token FIFO parity error" }, + { F_DMXPLDCHKOVFL1, "Ch1 PLD TxCheck FIFO Overflow" }, + { F_DMXPLDCHKFIFO1, "Ch1 PLD TxCheck FIFO parity error" }, + { F_DMXOPTFIFO1, "Ch1 Options buffer parity error" }, + { F_DMXMPAFIFO1, "Ch1 MPA FIFO parity error" }, + { F_DMXDBFIFO1, "Ch1 DB FIFO parity error" }, + { F_DMXATTFIFO1, "Ch1 Attribute FIFO parity error" }, + { F_DMXISSFIFO1, "Ch1 ISS FIFO parity error" }, + { F_DMXTCPFIFO1, "Ch1 TCP Fields FIFO parity error" }, + { F_DMXERRFIFO1, "Ch1 Error FIFO parity error" }, + { F_MPS2TPINTF1, "Ch1 MPS2TP Interface parity error" }, + { F_DMXPLDCHKOVFL0, "Ch0 PLD TxCheck FIFO Overflow" }, + { F_DMXPLDCHKFIFO0, "Ch0 PLD TxCheck FIFO parity error" }, + { F_DMXOPTFIFO0, "Ch0 Options buffer parity error" }, + { F_DMXMPAFIFO0, "Ch0 MPA FIFO parity error" }, + { F_DMXDBFIFO0, "Ch0 DB FIFO parity error" }, + { F_DMXATTFIFO0, "Ch0 Attribute FIFO parity error" }, + { F_DMXISSFIFO0, "Ch0 ISS FIFO parity error" }, + { F_DMXTCPFIFO0, "Ch0 TCP Fields FIFO parity error" }, + { F_DMXERRFIFO0, "Ch0 Error FIFO parity error" }, + { F_MPS2TPINTF0, "Ch0 MPS2TP Interface parity error" }, + { 0 } + }; static const struct intr_info tp_e_in0_perr_cause = { .name = "TP_E_IN0_PERR_CAUSE", .cause_reg = A_TP_E_IN0_PERR_CAUSE, .enable_reg = A_TP_E_IN0_PERR_ENABLE, .fatal = 0xffffffff, .flags = IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = tp_e_in0_perr_details, .actions = NULL, }; + static const struct intr_details tp_e_in1_perr_details[] = { + { F_DMXPLDCHKOVFL3, "Ch3 PLD TxCheck FIFO Overflow" }, + { F_DMXPLDCHKFIFO3, "Ch3 PLD TxCheck FIFO parity error" }, + { F_DMXOPTFIFO3, "Ch3 Options buffer parity error" }, + { F_DMXMPAFIFO3, "Ch3 MPA FIFO parity error" }, + { F_DMXDBFIFO3, "Ch3 DB FIFO parity error" }, + { F_DMXATTFIFO3, "Ch3 Attribute FIFO parity error" }, + { F_DMXISSFIFO3, "Ch3 ISS FIFO parity error" }, + { F_DMXTCPFIFO3, "Ch3 TCP Fields FIFO parity error" }, + { F_DMXERRFIFO3, "Ch3 Error FIFO parity error" }, + { F_MPS2TPINTF3, "Ch3 MPS2TP Interface parity error" }, + { F_DMXPLDCHKOVFL2, "Ch2 PLD TxCheck FIFO Overflow" }, + { F_DMXPLDCHKFIFO2, "Ch2 PLD TxCheck FIFO parity error" }, + { F_DMXOPTFIFO2, "Ch2 Options buffer parity error" }, + { F_DMXMPAFIFO2, "Ch2 MPA FIFO parity error" }, + { F_DMXDBFIFO2, "Ch2 DB FIFO parity error" }, + { F_DMXATTFIFO2, "Ch2 Attribute FIFO parity error" }, + { F_DMXISSFIFO2, "Ch2 ISS FIFO parity error" }, + { F_DMXTCPFIFO2, "Ch2 TCP Fields FIFO parity error" }, + { F_DMXERRFIFO2, "Ch2 Error FIFO parity error" }, + { F_MPS2TPINTF2, "Ch2 MPS2TP Interface parity error" }, + { 0 } + }; static const struct intr_info tp_e_in1_perr_cause = { .name = "TP_E_IN1_PERR_CAUSE", .cause_reg = A_TP_E_IN1_PERR_CAUSE, .enable_reg = A_TP_E_IN1_PERR_ENABLE, .fatal = 0xffffffff, .flags = IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = tp_e_in1_perr_details, .actions = NULL, }; + static const struct intr_details tp_other_perr_details[] = { + { F_DMARBTPERR, "DMARBT MA Rsp Interface parity Error" }, + { F_MMGRCACHEDATASRAM, "TP MMGR Cache Data SRAM" }, + { F_MMGRCACHETAGFIFO, "TP MMGR Cache Tag FIFO" }, + { F_DBL2TLUTPERR, "TP DB Lookup Table" }, + { F_DBTXTIDPERR, "TP DB FIFOs" }, + { F_DBEXTPERR, "TP DB Extended Opcode FIFO" }, + { F_DBOPPERR, "TP DB Opcode FIFO" }, + { F_TMCACHEPERR, "TP TM Cache SRAM" }, + { F_TPPROTOSRAM, "TP Protocol SRAM" }, + { F_HSPSRAM, "HighSpeed SRAM" }, + { F_RATEGRPSRAM, "Rate Group SRAM" }, + { F_TXFBSEQFIFO, "Tx Feedback Sequence Number FIFO" }, + { F_CMDATASRAM, "Cache Data SRAM" }, + { F_CMTAGFIFO, "Cache Tag FIFO" }, + { F_RFCOPFIFO, "RCF Opcode FIFO" }, + { F_DELINVFIFO, "Delete Invalid FIFO" }, + { F_RSSCFGSRAM, "RSS Config or Round-Robin SRAM" }, + { F_RSSKEYSRAM, "RSS Key SRAM" }, + { F_RSSLKPSRAM, "RSS Lookup SRAM" }, + { F_SRQSRAM, "SRQ SRAM" }, + { F_ARPDASRAM, "ARP DA SRAM" }, + { F_ARPSASRAM, "ARP SA SRAM" }, + { F_ARPGRESRAM, "ARP GRE SRAM" }, + { F_ARPIPSECSRAM1, "ARP IPSec SRAM0" }, + { F_ARPIPSECSRAM0, "ARP IPSec SRAM1" }, + { 0 } + }; static const struct intr_info tp_o_perr_cause = { .name = "TP_O_PERR_CAUSE", .cause_reg = A_TP_O_PERR_CAUSE, .enable_reg = A_TP_O_PERR_ENABLE, .fatal = 0xffffffff, .flags = IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = tp_other_perr_details, .actions = NULL, }; bool fatal; - fatal = t4_handle_intr(adap, &tp_intr_info, 0, flags); if (chip_id(adap) > CHELSIO_T6) { - fatal |= t4_handle_intr(adap, &tp_inic_perr_cause, 0, flags); + tp_intr_info.details = t7_tp_intr_details; + fatal = t4_handle_intr(adap, &tp_intr_info, 0, flags); + fatal |= t4_handle_intr(adap, &tp_cerr_cause, 0, flags); fatal |= t4_handle_intr(adap, &tp_c_perr_cause, 0, flags); fatal |= t4_handle_intr(adap, &tp_e_eg_perr_cause, 0, flags); fatal |= t4_handle_intr(adap, &tp_e_in0_perr_cause, 0, flags); fatal |= t4_handle_intr(adap, &tp_e_in1_perr_cause, 0, flags); fatal |= t4_handle_intr(adap, &tp_o_perr_cause, 0, flags); + } else { + tp_intr_info.details = tp_intr_details; + fatal = t4_handle_intr(adap, &tp_intr_info, 0, flags); } + clear_int_cause_reg(adap, &tp_intr_info, flags); return (fatal); } @@ -5133,16 +5362,86 @@ static bool tp_intr_handler(struct adapter *adap, int arg, int flags) */ static bool sge_intr_handler(struct adapter *adap, int arg, int flags) { + static const struct intr_details sge_int1_details[] = { + { F_PERR_FLM_CREDITFIFO, "SGE FLM credit FIFO parity error" }, + { F_PERR_IMSG_HINT_FIFO, "SGE IMSG hint FIFO parity error" }, + { F_PERR_HEADERSPLIT_FIFO3 | F_PERR_HEADERSPLIT_FIFO2, + "SGE header split FIFO parity error" }, + { F_PERR_PAYLOAD_FIFO3 | F_PERR_PAYLOAD_FIFO2, + "SGE payload FIFO parity error" }, + { F_PERR_PC_RSP, "SGE PC response parity error" }, + { F_PERR_PC_REQ, "SGE PC request parity error" }, + { 0x003c0000, "SGE DBP PC response FIFO parity error" }, + { F_PERR_DMARBT, "SGE DMA RBT parity error" }, + { F_PERR_FLM_DBPFIFO, "SGE FLM DBP FIFO parity error" }, + { F_PERR_FLM_MCREQ_FIFO, "SGE FLM MC request FIFO parity error" }, + { F_PERR_FLM_HINTFIFO, "SGE FLM hint FIFO parity error" }, + { 0x00003c00, "SGE align control FIFO parity error" }, + { 0x000003c0, "SGE EDMA FIFO parity error" }, + { 0x0000003c, "SGE PD FIFO parity error" }, + { F_PERR_ING_CTXT_MIFRSP, "SGE Ingress context MIF response parity error" }, + { F_PERR_EGR_CTXT_MIFRSP, "SGE Egress context MIF response parity error" }, + { 0 } + }; static const struct intr_info sge_int1_info = { .name = "SGE_INT_CAUSE1", .cause_reg = A_SGE_INT_CAUSE1, .enable_reg = A_SGE_INT_ENABLE1, .fatal = 0xffffffff, .flags = IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = sge_int1_details, .actions = NULL, }; - static const struct intr_info sge_int2_info = { + static const struct intr_details t7_sge_int2_details[] = { + { F_TF_FIFO_PERR, "SGE TF FIFO parity error" }, + { F_PERR_EGR_DBP_TX_COAL, "SGE egress DBP TX coal parity error" }, + { F_PERR_DBP_FL_FIFO, "SGE DBP FL FIFO parity error" }, + { F_DEQ_LL_PERR, "SGE linked list SRAM parity error" }, + { F_ENQ_PERR, "SGE enq tag SRAM parity error" }, + { F_DEQ_OUT_PERR, "SGE tbuf deq output FIFO parity error" }, + { F_BUF_PERR, "SGE tbuf main buffer parity error" }, + { F_PERR_CONM_SRAM, "SGE CONM SRAM parity error" }, + { F_PERR_ISW_IDMA3_FIFO | F_PERR_ISW_IDMA2_FIFO | + F_PERR_ISW_IDMA1_FIFO | F_PERR_ISW_IDMA0_FIFO, + "SGE ISW IDMA FIFO parity error" }, + { F_PERR_ISW_DBP_FIFO, "SGE ISW DBP FIFO parity error" }, + { F_PERR_ISW_GTS_FIFO, "SGE ISW GTS FIFO parity error" }, + { F_PERR_ITP_EVR, "SGE ITP EVR parity error" }, + { F_PERR_FLM_CNTXMEM, "SGE FLM context memory parity error" }, + { F_PERR_FLM_L1CACHE, "SGE FLM L1 cache parity error" }, + { F_SGE_IPP_FIFO_PERR, "SGE IPP FIFO parity error" }, + { F_PERR_DBP_HP_FIFO, "SGE DBP HP FIFO parity error" }, + { F_PERR_DB_FIFO, "SGE doorbell FIFO parity error" }, + { F_PERR_ING_CTXT_CACHE | F_PERR_EGR_CTXT_CACHE, + "SGE context cache parity error" }, + { F_PERR_BASE_SIZE, "SGE base size parity error" }, + { 0 } + }; + static const struct intr_details t6_sge_int2_details[] = { + { F_PERR_DBP_HINT_FL_FIFO, "SGE DBP hint FL FIFO parity error" }, + { F_PERR_EGR_DBP_TX_COAL, "SGE egress DBP TX coal parity error" }, + { F_PERR_DBP_FL_FIFO, "SGE DBP FL FIFO parity error" }, + { F_DEQ_LL_PERR, "SGE tbuf dequeue linked list SRAM parity error" }, + { F_ENQ_PERR, "SGE tbuf enqueue tag SRAM parity error" }, + { F_DEQ_OUT_PERR, "SGE tbuf dequeue output FIFO parity error" }, + { F_BUF_PERR, "SGE tbuf main buffer parity error" }, + { F_PERR_CONM_SRAM, "SGE CONM SRAM parity error" }, + { F_PERR_ISW_IDMA1_FIFO, "SGE ISW IDMA FIFO parity error" }, + { F_PERR_ISW_IDMA0_FIFO, "SGE ISW IDMA FIFO parity error" }, + { F_PERR_ISW_DBP_FIFO, "SGE ISW DBP FIFO parity error" }, + { F_PERR_ISW_GTS_FIFO, "SGE ISW GTS FIFO parity error" }, + { F_PERR_ITP_EVR, "SGE ITP EVR parity error" }, + { F_PERR_FLM_CNTXMEM, "SGE FLM context memory parity error" }, + { F_PERR_FLM_L1CACHE, "SGE FLM L1 cache parity error" }, + { F_PERR_DBP_HINT_FIFO, "SGE DBP hint FIFO parity error" }, + { F_PERR_DBP_HP_FIFO, "SGE DBP high priority FIFO parity error" }, + { F_PERR_DB_FIFO, "SGE DBP merge DB FIFO parity error" }, + { F_PERR_ING_CTXT_CACHE, "SGE ingress context cache parity error" }, + { F_PERR_EGR_CTXT_CACHE, "SGE egress context cache parity error" }, + { F_PERR_BASE_SIZE, "SGE base size parity error" }, + { 0 } + }; + struct intr_info sge_int2_info = { .name = "SGE_INT_CAUSE2", .cause_reg = A_SGE_INT_CAUSE2, .enable_reg = A_SGE_INT_ENABLE2, @@ -5231,16 +5530,105 @@ static bool sge_intr_handler(struct adapter *adap, int arg, int flags) .details = NULL, .actions = NULL, }; + static const struct intr_details sge_int4_details[] = { + { F_ERR_ISHIFT_UR1 | F_ERR_ISHIFT_UR0, "SGE ishift underrun" }, + { F_BAR2_EGRESS_LEN_OR_ADDR_ERR, "SGE BAR2 PL access length or alignment error" }, + { F_ERR_CPL_EXCEED_MAX_IQE_SIZE1 | F_ERR_CPL_EXCEED_MAX_IQE_SIZE0, + "SGE CPL exceeds max IQE size" }, + { F_ERR_WR_LEN_TOO_LARGE3 | F_ERR_WR_LEN_TOO_LARGE2 | + F_ERR_WR_LEN_TOO_LARGE1 | F_ERR_WR_LEN_TOO_LARGE0, + "SGE WR length too large" }, + { F_ERR_LARGE_MINFETCH_WITH_TXCOAL3 | F_ERR_LARGE_MINFETCH_WITH_TXCOAL2 | + F_ERR_LARGE_MINFETCH_WITH_TXCOAL1 | F_ERR_LARGE_MINFETCH_WITH_TXCOAL0, + "SGE invalid MinFetchBurst with TxCoalesce" }, + { F_COAL_WITH_HP_DISABLE_ERR, "SGE coalesce with HP disable error" }, + { F_BAR2_EGRESS_COAL0_ERR, "SGE BAR2 PL access addr offset 0" }, + { F_BAR2_EGRESS_SIZE_ERR, "SGE BAR2 illegal egress QID access" }, + { F_FLM_PC_RSP_ERR, "SGE FLM PC response error" }, + { F_ERR_TH3_MAX_FETCH | F_ERR_TH2_MAX_FETCH | + F_ERR_TH1_MAX_FETCH | F_ERR_TH0_MAX_FETCH, + "SGE max fetch violation" }, + { F_ERR_RX_CPL_PACKET_SIZE1 | F_ERR_RX_CPL_PACKET_SIZE0, + "SGE CPL length mismatch error" }, + { F_ERR_BAD_UPFL_INC_CREDIT3 | F_ERR_BAD_UPFL_INC_CREDIT2 | + F_ERR_BAD_UPFL_INC_CREDIT1 | F_ERR_BAD_UPFL_INC_CREDIT0, + "SGE upfl credit wrap error" }, + { F_ERR_PHYSADDR_LEN0_IDMA1 | F_ERR_PHYSADDR_LEN0_IDMA0, + "SGE CPL_RX_PHYS_ADDR length 0 error" }, + { F_ERR_FLM_INVALID_PKT_DROP1 | F_ERR_FLM_INVALID_PKT_DROP0, + "SGE IDMA packet drop due to invalid FLM context" }, + { F_ERR_UNEXPECTED_TIMER, "SGE unexpected timer error" }, + { 0 } + }; static const struct intr_info sge_int4_info = { .name = "SGE_INT_CAUSE4", .cause_reg = A_SGE_INT_CAUSE4, .enable_reg = A_SGE_INT_ENABLE4, .fatal = 0, .flags = 0, - .details = NULL, + .details = sge_int4_details, .actions = NULL, }; - static const struct intr_info sge_int5_info = { + static const struct intr_details t7_sge_int5_details[] = { + { F_ERR_T_RXCRC, "SGE RxCRC error" }, + { F_PERR_MC_RSPDATA, "SGE MC response data parity error" }, + { F_PERR_PC_RSPDATA, "SGE PC response data parity error" }, + { F_PERR_PD_RDRSPDATA, "SGE PD read response data parity error" }, + { F_PERR_U_RXDATA, "SGE U Rx data parity error" }, + { F_PERR_UD_RXDATA, "SGE UD Rx data parity error" }, + { F_PERR_UP_DATA, "SGE uP data parity error" }, + { F_PERR_CIM2SGE_RXDATA, "SGE CIM2SGE Rx data parity error" }, + { F_PERR_IMSG_PD_FIFO, "SGE IMSG PD FIFO parity error" }, + { F_PERR_ULPTX_FIFO1 | F_PERR_ULPTX_FIFO0, "SGE ULPTX FIFO parity error" }, + { F_PERR_IDMA2IMSG_FIFO3 | F_PERR_IDMA2IMSG_FIFO2 | + F_PERR_IDMA2IMSG_FIFO1 | F_PERR_IDMA2IMSG_FIFO0, + "SGE IDMA2IMSG FIFO parity error" }, + { F_PERR_POINTER_DATA_FIFO3 | F_PERR_POINTER_DATA_FIFO2 | + F_PERR_POINTER_DATA_FIFO1 | F_PERR_POINTER_DATA_FIFO0, + "SGE pointer data FIFO parity error" }, + { F_PERR_POINTER_HDR_FIFO3 | F_PERR_POINTER_HDR_FIFO2 | + F_PERR_POINTER_HDR_FIFO1 | F_PERR_POINTER_HDR_FIFO0, + "SGE pointer header FIFO parity error" }, + { F_PERR_PAYLOAD_FIFO1 | F_PERR_PAYLOAD_FIFO0, + "SGE payload FIFO parity error" }, + { F_PERR_MGT_BAR2_FIFO, "SGE MGT BAR2 FIFO parity error" }, + { F_PERR_HEADERSPLIT_FIFO1 | F_PERR_HEADERSPLIT_FIFO0, + "SGE header split FIFO parity error" }, + { F_PERR_HINT_DELAY_FIFO, "SGE hint delay FIFO parity error" }, + { 0 } + }; + static const struct intr_details t6_sge_int5_details[] = { + { F_ERR_T_RXCRC, "SGE T RxCRC parity error" }, + { F_PERR_MC_RSPDATA, "SGE MC response data parity error" }, + { F_PERR_PC_RSPDATA, "SGE PC response data parity error" }, + { F_PERR_U_RXDATA | F_PERR_UD_RXDATA, "SGE ULP Rx data parity error" }, + { F_PERR_UP_DATA, "SGE uP data parity error" }, + { F_PERR_CIM2SGE_RXDATA, "SGE CIM2SGE Rx data parity error" }, + { F_PERR_HINT_DELAY_FIFO1 | F_PERR_HINT_DELAY_FIFO0, + "SGE hint delay FIFO parity error" }, + { F_PERR_IMSG_PD_FIFO, "SGE IMSG PD FIFO parity error" }, + { F_PERR_ULPTX_FIFO1 | F_PERR_ULPTX_FIFO0, + "SGE ULPTX FIFO parity error" }, + { F_PERR_IDMA2IMSG_FIFO1 | F_PERR_IDMA2IMSG_FIFO0, + "SGE IDMA2IMSG FIFO parity error" }, + { F_PERR_POINTER_DATA_FIFO1 | F_PERR_POINTER_DATA_FIFO0, + "SGE pointer data FIFO parity error" }, + { F_PERR_POINTER_HDR_FIFO1 | F_PERR_POINTER_HDR_FIFO0, + "SGE pointer header FIFO parity error" }, + { F_PERR_PAYLOAD_FIFO1 | F_PERR_PAYLOAD_FIFO0, + "SGE payload FIFO parity error" }, + { F_PERR_EDMA_INPUT_FIFO3 | F_PERR_EDMA_INPUT_FIFO2 | + F_PERR_EDMA_INPUT_FIFO1 | F_PERR_EDMA_INPUT_FIFO0, + "SGE EDMA input FIFO parity error" }, + { F_PERR_MGT_BAR2_FIFO, "SGE MGT BAR2 FIFO parity error" }, + { F_PERR_HEADERSPLIT_FIFO1 | F_PERR_HEADERSPLIT_FIFO0, + "SGE header split FIFO parity error" }, + { F_PERR_CIM_FIFO1 | F_PERR_CIM_FIFO0, "SGE CIM FIFO parity error" }, + { F_PERR_IDMA_SWITCH_OUTPUT_FIFO1 | F_PERR_IDMA_SWITCH_OUTPUT_FIFO0, + "SGE IDMA switch output FIFO parity error" }, + { 0 } + }; + struct intr_info sge_int5_info = { .name = "SGE_INT_CAUSE5", .cause_reg = A_SGE_INT_CAUSE5, .enable_reg = A_SGE_INT_ENABLE5, @@ -5249,31 +5637,94 @@ static bool sge_intr_handler(struct adapter *adap, int arg, int flags) .details = NULL, .actions = NULL, }; + static const struct intr_details sge_int6_details[] = { + /* T7+ */ + { 0xe0000000, "SGE fatal DEQ0 DRDY error" }, + { 0x1c000000, "SGE fatal OUT0 DRDY error" }, + { F_IMSG_DBG3_STUCK | F_IMSG_DBG2_STUCK | + F_IMSG_DBG1_STUCK | F_IMSG_DBG0_STUCK, + "SGE IMSG stuck due to insufficient credits" }, + /* T6 + */ + { F_ERR_DB_SYNC, "SGE doorbell sync failed" }, + { F_ERR_GTS_SYNC, "SGE GTS sync failed" }, + { F_FATAL_LARGE_COAL, "SGE BAR2 payload too large" }, + { F_PL_BAR2_FRM_ERR, "SGE BAR2 framing error" }, + { F_SILENT_DROP_TX_COAL, "SGE silent drop of Tx coal WR" }, + { F_ERR_INV_CTXT4, "SGE context access for invalid queue thread 4" }, + { F_ERR_BAD_DB_PIDX4, "SGE doorbell pidx too large thread 4" }, + { F_ERR_BAD_UPFL_INC_CREDIT4, "SGE upfl credit wrap thread 4" }, + { F_FATAL_TAG_MISMATCH, "SGE doorbell tag mismatch" }, + { F_FATAL_ENQ_CTL_RDY, "SGE enq_ctl_fifo overflow" }, + { F_ERR_PC_RSP_LEN3 | F_ERR_PC_RSP_LEN2 | + F_ERR_PC_RSP_LEN1 | F_ERR_PC_RSP_LEN0, + "SGE PCIe response error for DBP threads" }, + { F_FATAL_ENQ2LL_VLD, "SGE tbuf fatal_enq2ll_vld" }, + { F_FATAL_LL_EMPTY, "SGE tbuf fatal_ll_empty" }, + { F_FATAL_OFF_WDENQ, "SGE tbuf fatal_off_wdenq" }, + { 0x00000018, "SGE tbuf fatal_deq1_drdy" }, + { 0x00000006, "SGE tbuf fatal_out1_drdy" }, + { F_FATAL_DEQ, "SGE tbuf fatal_deq" }, + { 0 } + }; static const struct intr_info sge_int6_info = { .name = "SGE_INT_CAUSE6", .cause_reg = A_SGE_INT_CAUSE6, .enable_reg = A_SGE_INT_ENABLE6, .fatal = 0, .flags = 0, - .details = NULL, + .details = sge_int6_details, .actions = NULL, }; + static const struct intr_details sge_int7_details[] = { + { F_HINT_FIFO_FULL, "SGE hint FIFO full" }, + { F_CERR_HINT_DELAY_FIFO, "SGE hint delay FIFO ECC error" }, + { F_COAL_TIMER_FIFO_PERR, "SGE coalescing timer FIFO parity error" }, + { F_CMP_FIFO_PERR, "SGE CMP FIFO parity error" }, + { F_SGE_IPP_FIFO_CERR, "SGE IPP FIFO ECC error" }, + { F_CERR_ING_CTXT_CACHE | F_CERR_EGR_CTXT_CACHE, + "SGE context cache ECC error" }, + { F_IMSG_CNTX_PERR, "SGE IMSG context parity error" }, + { F_PD_FIFO_PERR, "SGE PD FIFO parity error" }, + { F_IMSG_512_FIFO_PERR, "SGE IMSG 512 FIFO parity error" }, + { F_CPLSW_FIFO_PERR, "SGE CPLSW FIFO parity error" }, + { F_IMSG_FIFO_PERR, "SGE IMSG FIFO parity error" }, + { F_CERR_ITP_EVR, "SGE ITP EVR ECC error" }, + { F_CERR_CONM_SRAM, "SGE CONM SRAM ECC error" }, + { F_CERR_FLM_CNTXMEM, "SGE FLM context memory ECC error" }, + { F_CERR_FUNC_QBASE, "SGE function queue base ECC error" }, + { F_IMSG_CNTX_CERR, "SGE IMSG context ECC error" }, + { F_PD_FIFO_CERR, "SGE PD FIFO ECC error" }, + { F_IMSG_512_FIFO_CERR, "SGE IMSG 512 FIFO ECC error" }, + { F_CPLSW_FIFO_CERR, "SGE CPLSW FIFO ECC error" }, + { F_IMSG_FIFO_CERR, "SGE IMSG FIFO ECC error" }, + { 0x0000001e, "SGE header split FIFO ECC error" }, // Bits 4:1 + { F_CERR_FLM_L1CACHE, "SGE FLM L1 cache ECC error" }, + { 0 } + }; static const struct intr_info sge_int7_info = { .name = "SGE_INT_CAUSE7", .cause_reg = A_SGE_INT_CAUSE7, .enable_reg = A_SGE_INT_ENABLE7, .fatal = 0, .flags = 0, - .details = NULL, + .details = sge_int7_details, .actions = NULL, }; + static const struct intr_details sge_int8_details[] = { + { F_TRACE_RXPERR, "SGE trace packet parity error" }, + { F_U3_RXPERR | F_U2_RXPERR | F_U1_RXPERR | F_U0_RXPERR, + "SGE ULP interface parity error" }, + { F_T3_RXPERR | F_T2_RXPERR | F_T1_RXPERR | F_T0_RXPERR, + "SGE TP interface parity error" }, + { 0 } + }; static const struct intr_info sge_int8_info = { .name = "SGE_INT_CAUSE8", .cause_reg = A_SGE_INT_CAUSE8, .enable_reg = A_SGE_INT_ENABLE8, .fatal = 0, .flags = 0, - .details = NULL, + .details = sge_int8_details, .actions = NULL, }; bool fatal; @@ -5281,8 +5732,14 @@ static bool sge_intr_handler(struct adapter *adap, int arg, int flags) if (chip_id(adap) <= CHELSIO_T5) { sge_int3_info.details = sge_int3_details; + } else if (chip_id(adap) == CHELSIO_T6) { + sge_int3_info.details = t6_sge_int3_details; + sge_int2_info.details = t6_sge_int2_details; + sge_int5_info.details = t6_sge_int5_details; } else { sge_int3_info.details = t6_sge_int3_details; + sge_int2_info.details = t7_sge_int2_details; + sge_int5_info.details = t7_sge_int5_details; } fatal = false; @@ -5316,6 +5773,19 @@ static bool sge_intr_handler(struct adapter *adap, int arg, int flags) */ static bool cim_intr_handler(struct adapter *adap, int arg, int flags) { + static const struct intr_details cim_host_t7_intr_details[] = { + { F_CORE7ACCINT, "CIM slave core 7 access interrupt "}, + { F_CORE6ACCINT, "CIM slave core 6 access interrupt "}, + { F_CORE5ACCINT, "CIM slave core 5 access interrupt "}, + { F_CORE4ACCINT, "CIM slave core 4 access interrupt "}, + { F_CORE3ACCINT, "CIM slave core 3 access interrupt "}, + { F_CORE2ACCINT, "CIM slave core 2 access interrupt "}, + { F_CORE1ACCINT, "CIM slave core 1 access interrupt "}, + { F_TIMER1INT, "CIM TIMER0 interrupt" }, + { F_TIMER0INT, "CIM TIMER0 interrupt" }, + { F_PREFDROPINT, "CIM control register prefetch drop" }, + { 0} + }; static const struct intr_details cim_host_intr_details[] = { /* T6+ */ { F_PCIE2CIMINTFPARERR, "CIM IBQ PCIe interface parity error" }, @@ -5328,8 +5798,8 @@ static bool cim_intr_handler(struct adapter *adap, int arg, int flags) { F_SGE2CIMINTFPARERR, "CIM IBQ SGE interface parity error" }, { F_ULP2CIMINTFPARERR, "CIM IBQ ULP_TX interface parity error" }, { F_TP2CIMINTFPARERR, "CIM IBQ TP interface parity error" }, - { F_OBQSGERX1PARERR, "CIM OBQ SGE1_RX parity error" }, - { F_OBQSGERX0PARERR, "CIM OBQ SGE0_RX parity error" }, + { F_OBQSGERX1PARERR, "CIM OBQ PCIE_RX parity error" }, + { F_OBQSGERX0PARERR, "CIM OBQ SGE_RX parity error" }, /* T4+ */ { F_TIEQOUTPARERRINT, "CIM TIEQ outgoing FIFO parity error" }, @@ -5354,16 +5824,17 @@ static bool cim_intr_handler(struct adapter *adap, int arg, int flags) { F_PREFDROPINT, "CIM control register prefetch drop" }, { 0} }; - static const struct intr_info cim_host_intr_info = { + struct intr_info cim_host_intr_info = { .name = "CIM_HOST_INT_CAUSE", .cause_reg = A_CIM_HOST_INT_CAUSE, .enable_reg = A_CIM_HOST_INT_ENABLE, .fatal = 0x007fffe6, .flags = IHF_FATAL_IFF_ENABLED, - .details = cim_host_intr_details, + .details = NULL, .actions = NULL, }; static const struct intr_details cim_host_upacc_intr_details[] = { + { F_CONWRERRINT, "CIM condition write error "}, { F_EEPROMWRINT, "CIM EEPROM came out of busy state" }, { F_TIMEOUTMAINT, "CIM PIF MA timeout" }, { F_TIMEOUTINT, "CIM PIF timeout" }, @@ -5423,18 +5894,54 @@ static bool cim_intr_handler(struct adapter *adap, int arg, int flags) .details = NULL, .actions = NULL, }; + static const struct intr_details cim_perr_cause_details[] = { + { F_T7_MA_CIM_INTFPERR, "MA2CIM interface parity error" }, + { F_T7_MBHOSTPARERR, "Mailbox Host Read parity error" }, + { F_MAARBINVRSPTAG, "MA Arbiter Invalid Response Tag (Fatal)" }, + { F_MAARBFIFOPARERR, "MA Arbiter FIFO Parity Error" }, + { F_SEMSRAMPARERR, "Semaphore logic SRAM Parity Error" }, + { F_RSACPARERR, "RSA Code SRAM Parity Error" }, + { F_RSADPARERR, "RSA Data SRAM Parity Error" }, + { F_T7_PLCIM_MSTRSPDATAPARERR, "PL2CIM Master response data parity error" }, + { F_T7_PCIE2CIMINTFPARERR, "IBQ PCIE intf parity error" }, + { F_T7_NCSI2CIMINTFPARERR, "IBQ NCSI intf parity error" }, + { F_T7_SGE2CIMINTFPARERR, "IBQ SGE Intf Parity error" }, + { F_T7_ULP2CIMINTFPARERR, "IBQ ULP_TX intf parity error" }, + { F_T7_TP2CIMINTFPARERR, "IBQ TP intf parity error" }, + { F_CORE7PARERR, "Slave Core7 parity error" }, + { F_CORE6PARERR, "Slave Core6 parity error" }, + { F_CORE5PARERR, "Slave Core5 parity error" }, + { F_CORE4PARERR, "Slave Core4 parity error" }, + { F_CORE3PARERR, "Slave Core3 parity error" }, + { F_CORE2PARERR, "Slave Core2 parity error" }, + { F_CORE1PARERR, "Slave Core1 parity error" }, + { F_GFTPARERR, "GFT block Memory parity error" }, + { F_MPSRSPDATAPARERR, "MPS lookup interface Response parity error" }, + { F_ER_RSPDATAPARERR, "Expansion ROM/Flash Interface Response Parity Error" }, + { F_FLOWFIFOPARERR, "SGE FlowID Prefetch FIFO Parity Error" }, + { F_OBQSRAMPARERR, "OBQ SRAM Parity Error" }, + { F_TIEQOUTPARERR, "TIE Queue Outgoing FIFO parity error" }, + { F_TIEQINPARERR, "TIE Queue Incoming FIFO parity error" }, + { F_PIFRSPPARERR, "PIF Response interface FIFO Parity error" }, + { F_PIFREQPARERR, "PIF Request interface FIFO Parity error" }, + { 0 } + }; static const struct intr_info cim_perr_cause = { .name = "CIM_PERR_CAUSE", .cause_reg = A_CIM_PERR_CAUSE, .enable_reg = A_CIM_PERR_ENABLE, .fatal = 0xffffffff, .flags = IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = cim_perr_cause_details, .actions = NULL, }; u32 val, fw_err; bool fatal; + if (chip_id(adap) >= CHELSIO_T7) + cim_host_intr_info.details = cim_host_t7_intr_details; + else + cim_host_intr_info.details = cim_host_intr_details; /* * When the Firmware detects an internal error which normally wouldn't * raise a Host Interrupt, it forces a CIM Timer0 interrupt in order @@ -5477,62 +5984,237 @@ static bool ulprx_intr_handler(struct adapter *adap, int arg, int flags) { 0x007fffff, "ULPRX parity error" }, { 0 } }; - static const struct intr_info ulprx_intr_info = { + static const struct intr_details t6_ulprx_int_cause_details[] = { + { F_SE_CNT_MISMATCH_1, "SE count mismatch in channel1" }, + { F_SE_CNT_MISMATCH_0, "SE count mismatch in channel 0" }, + { F_CAUSE_CTX_1, "Context access error on channel 1" }, + { F_CAUSE_CTX_0, "Context access error on channel 0" }, + { F_CAUSE_FF, "filp-flop based fifos" }, + { F_CAUSE_APF_1, "Arb prefetch memory, channel 1" }, + { F_CAUSE_APF_0, "Arb prefetch memory, channel 0" }, + { F_CAUSE_AF_1, "Arb fetch memory, channel 1" }, + { F_CAUSE_AF_0, "Arb fetch memory, channel 0" }, + { F_CAUSE_DDPDF_1, "ddp_data_fifo Fifo, channel 1" }, + { F_CAUSE_DDPMF_1, "ddp_msg_fifo Fifo, channel 1" }, + { F_CAUSE_MEMRF_1, "mem_req_fifo_d Fifo, channel 1" }, + { F_CAUSE_PRSDF_1, "prsr_data_fifo Fifo, channel 1" }, + { F_CAUSE_DDPDF_0, "ddp_data_fifo Fifo, channel 0" }, + { F_CAUSE_DDPMF_0, "ddp_msg_fifo Fifo, channel 0" }, + { F_CAUSE_MEMRF_0, "mem_req_fifo_d Fifo, channel 0" }, + { F_CAUSE_PRSDF_0, "prsr_data_fifo Fifo, channel 0" }, + { F_CAUSE_PCMDF_1, "Pcmd Fifo, channel 1" }, + { F_CAUSE_TPTCF_1, "tpt_ctl_fifo Fifo, channel 1" }, + { F_CAUSE_DDPCF_1, "ddp_ctl_fifo Fifo, channel 1" }, + { F_CAUSE_MPARF_1, "mpar_ctl_fifo Fifo, channel 1" }, + { F_CAUSE_MPARC_1, "mpac_ctl_fifo Fifo, channel 1" }, + { F_CAUSE_PCMDF_0, "Pcmd Fifo, channel 0" }, + { F_CAUSE_TPTCF_0, "tpt_ctl_fifo Fifo, channel 0" }, + { F_CAUSE_DDPCF_0, "ddp_ctl_fifo Fifo, channel 0" }, + { F_CAUSE_MPARF_0, "mpar_ctl_fifo Fifo, channel 0" }, + { F_CAUSE_MPARC_0, "mpac_ctl_fifo Fifo, channel 0" }, + { 0 } + }; + static const struct intr_details t7_ulprx_int_cause_details[] = { + { F_CERR_PCMD_FIFO_3, "PCMD FIFO correctable Error3" }, + { F_CERR_PCMD_FIFO_2, "PCMD FIFO correctable Error2" }, + { F_CERR_PCMD_FIFO_1, "PCMD FIFO correctable Error1" }, + { F_CERR_PCMD_FIFO_0, "PCMD FIFO correctable Error0" }, + { F_CERR_DATA_FIFO_3, "DDP Data FIFO correctable Error3" }, + { F_CERR_DATA_FIFO_2, "DDP Data FIFO correctable Error2" }, + { F_CERR_DATA_FIFO_1, "DDP Data FIFO correctable Error1" }, + { F_CERR_DATA_FIFO_0, "DDP Data FIFO correctable Error0" }, + { F_SE_CNT_MISMATCH_3, "SE count mismatch in channel3" }, + { F_SE_CNT_MISMATCH_2, "SE count mismatch in channel2" }, + { F_T7_SE_CNT_MISMATCH_1, "SE count mismatch in channel1" }, + { F_T7_SE_CNT_MISMATCH_0, "SE count mismatch in channel 0" }, + { F_T7_ENABLE_CTX_3, "Context access error on channel 3" }, + { F_T7_ENABLE_CTX_2, "Context access error on channel 2" }, + { F_T7_ENABLE_CTX_1, "Context access error on channel 1" }, + { F_T7_ENABLE_CTX_0, "Context access error on channel 0" }, + { F_T7_ENABLE_ALN_SDC_ERR_3, "SDC error reported by aligner in channel3" }, + { F_T7_ENABLE_ALN_SDC_ERR_2, "SDC error reported by aligner in channel2" }, + { F_T7_ENABLE_ALN_SDC_ERR_1, "SDC error reported by aligner in channel1" }, + { F_T7_ENABLE_ALN_SDC_ERR_0, "SDC error reported by aligner in channel0" }, + { 0 } + }; + struct intr_info ulprx_intr_info = { .name = "ULP_RX_INT_CAUSE", .cause_reg = A_ULP_RX_INT_CAUSE, .enable_reg = A_ULP_RX_INT_ENABLE, .fatal = 0x07ffffff, .flags = IHF_FATAL_IFF_ENABLED, - .details = ulprx_intr_details, + .details = NULL, .actions = NULL, }; + static const struct intr_details ulprx_int_cause_2_details[] = { + { F_ULPRX2MA_INTFPERR, "SDC error reported by ULPRX2MA interface parity checker" }, + { F_ALN_SDC_ERR_1, "SDC error reported by aligner in channel 1" }, + { F_ALN_SDC_ERR_0, "SDC error reported by aligner in channel 0" }, + { F_PF_UNTAGGED_TPT_1, "Parity error from Untagged TPT prefetch fifo channel 1" }, + { F_PF_UNTAGGED_TPT_0, "Parity error from Untagged TPT prefetch fifo channel 0" }, + { F_PF_PBL_1, "Parity error from PBL prefetch fifo channel 1" }, + { F_PF_PBL_0, "Parity error from PBL prefetch fifo channel 0" }, + { F_DDP_HINT_1, "DDP hint fifo Perr in channel 1" }, + { F_DDP_HINT_0, "DDP hint fifo Perr in channel 0" }, + { 0 } + }; static const struct intr_info ulprx_intr2_info = { .name = "ULP_RX_INT_CAUSE_2", .cause_reg = A_ULP_RX_INT_CAUSE_2, .enable_reg = A_ULP_RX_INT_ENABLE_2, .fatal = 0, .flags = 0, - .details = NULL, + .details = ulprx_int_cause_2_details, .actions = NULL, }; + static const struct intr_details ulprx_int_cause_pcmd_details[] = { + { F_CAUSE_PCMD_SFIFO_3, "Small FIFOs, channel 3" }, + { F_CAUSE_PCMD_FIFO_3, "pcmd_ctl_fifo, channel 3" }, + { F_CAUSE_PCMD_DDP_HINT_3, "ddp_hint_ctl_fifo FIFO, channel 3" }, + { F_CAUSE_PCMD_TPT_3, "tpt_ctl_fifo FIFO, channel 3" }, + { F_CAUSE_PCMD_DDP_3, "ddp_ctl_fifo FIFO, channel 3" }, + { F_CAUSE_PCMD_MPAR_3, "mpar_ctl_fifo FIFO, channel 3" }, + { F_CAUSE_PCMD_MPAC_3, "mpac_ctl_fifo FIFO, channel 3" }, + { F_CAUSE_PCMD_SFIFO_2, "Small FIFOs, channel 2" }, + { F_CAUSE_PCMD_FIFO_2, "pcmd_ctl_fifo, channel 2" }, + { F_CAUSE_PCMD_DDP_HINT_2, "ddp_hint_ctl_fifo FIFO, channel 2" }, + { F_CAUSE_PCMD_TPT_2, "tpt_ctl_fifo FIFO, channel 2" }, + { F_CAUSE_PCMD_DDP_2, "ddp_ctl_fifo FIFO, channel 2" }, + { F_CAUSE_PCMD_MPAR_2, "mpar_ctl_fifo FIFO, channel 2" }, + { F_CAUSE_PCMD_MPAC_2, "mpac_ctl_fifo FIFO, channel 2" }, + { F_CAUSE_PCMD_SFIFO_1, "Small FIFOs, channel 1" }, + { F_CAUSE_PCMD_FIFO_1, "pcmd_ctl_fifo, channel 1" }, + { F_CAUSE_PCMD_DDP_HINT_1, "ddp_hint_ctl_fifo FIFO, channel 1" }, + { F_CAUSE_PCMD_TPT_1, "tpt_ctl_fifo FIFO, channel 1" }, + { F_CAUSE_PCMD_DDP_1, "ddp_ctl_fifo FIFO, channel 1" }, + { F_CAUSE_PCMD_MPAR_1, "mpar_ctl_fifo FIFO, channel 1" }, + { F_CAUSE_PCMD_MPAC_1, "mpac_ctl_fifo FIFO, channel 1" }, + { F_CAUSE_PCMD_SFIFO_0, "Small FIFOs, channel 0" }, + { F_CAUSE_PCMD_FIFO_0, "pcmd_ctl_fifo, channel 0" }, + { F_CAUSE_PCMD_DDP_HINT_0, "ddp_hint_ctl_fifo FIFO, channel 0" }, + { F_CAUSE_PCMD_TPT_0, "tpt_ctl_fifo FIFO, channel 0" }, + { F_CAUSE_PCMD_DDP_0, "ddp_ctl_fifo FIFO, channel 0" }, + { F_CAUSE_PCMD_MPAR_0, "mpar_ctl_fifo FIFO, channel 0" }, + { F_CAUSE_PCMD_MPAC_0, "mpac_ctl_fifo FIFO, channel 0" }, + { 0 } + }; static const struct intr_info ulprx_int_cause_pcmd = { .name = "ULP_RX_INT_CAUSE_PCMD", .cause_reg = A_ULP_RX_INT_CAUSE_PCMD, .enable_reg = A_ULP_RX_INT_ENABLE_PCMD, .fatal = 0, .flags = 0, - .details = NULL, + .details = ulprx_int_cause_pcmd_details, .actions = NULL, }; + static const struct intr_details ulprx_int_cause_data_details[] = { + { F_CAUSE_DATA_SNOOP_3, "Snoop FIFO, channel 3" }, + { F_CAUSE_DATA_SFIFO_3, "Small FIFO, channel 3" }, + { F_CAUSE_DATA_FIFO_3, "data_ctl_fifo FIFO, channel 3" }, + { F_CAUSE_DATA_DDP_3, "ddp_ctl_fifo FIFO, channel 3" }, + { F_CAUSE_DATA_CTX_3, "ctx_ctl_fifo FIFO, channel 3" }, + { F_CAUSE_DATA_PARSER_3, "parser_ctl_fifo FIFO, channel 3" }, + { F_CAUSE_DATA_SNOOP_2, "Snoop FIFO, channel 2" }, + { F_CAUSE_DATA_SFIFO_2, "Small FIFO, channel 2" }, + { F_CAUSE_DATA_FIFO_2, "data_ctl_fifo FIFO, channel 2" }, + { F_CAUSE_DATA_DDP_2, "ddp_ctl_fifo FIFO, channel 2" }, + { F_CAUSE_DATA_CTX_2, "ctx_ctl_fifo FIFO, channel 2" }, + { F_CAUSE_DATA_PARSER_2, "parser_ctl_fifo FIFO, channel 2" }, + { F_CAUSE_DATA_SNOOP_1, "Snoop FIFO, channel 1" }, + { F_CAUSE_DATA_SFIFO_1, "Small FIFO, channel 1" }, + { F_CAUSE_DATA_FIFO_1, "data_ctl_fifo FIFO, channel 1" }, + { F_CAUSE_DATA_DDP_1, "ddp_ctl_fifo FIFO, channel 1" }, + { F_CAUSE_DATA_CTX_1, "ctx_ctl_fifo FIFO, channel 1" }, + { F_CAUSE_DATA_PARSER_1, "parser_ctl_fifo FIFO, channel 1" }, + { F_CAUSE_DATA_SNOOP_0, "Snoop FIFO, channel 0" }, + { F_CAUSE_DATA_SFIFO_0, "Small FIFO, channel 0" }, + { F_CAUSE_DATA_FIFO_0, "data_ctl_fifo FIFO, channel 0" }, + { F_CAUSE_DATA_DDP_0, "ddp_ctl_fifo FIFO, channel 0" }, + { F_CAUSE_DATA_CTX_0, "ctx_ctl_fifo FIFO, channel 0" }, + { F_CAUSE_DATA_PARSER_0, "parser_ctl_fifo FIFO, channel 0" }, + { 0 } + }; static const struct intr_info ulprx_int_cause_data = { .name = "ULP_RX_INT_CAUSE_DATA", .cause_reg = A_ULP_RX_INT_CAUSE_DATA, .enable_reg = A_ULP_RX_INT_ENABLE_DATA, .fatal = 0, .flags = 0, - .details = NULL, + .details = ulprx_int_cause_data_details, .actions = NULL, }; + static const struct intr_details ulprx_int_cause_arb_details[] = { + { F_CAUSE_ARB_PBL_PF_3, "pbl_pf_ctl_fifo FIFO, channel 3" }, + { F_CAUSE_ARB_PF_3, "pf_ctl_fifo FIFO, channel 3" }, + { F_CAUSE_ARB_TPT_PF_3, "tpt_pf_ctl_fifo FIFO, channel 3" }, + { F_CAUSE_ARB_F_3, "f_ctl_fifo FIFO, channel 3" }, + { F_CAUSE_ARB_PBL_PF_2, "pbl_pf_ctl_fifo FIFO, channel 2" }, + { F_CAUSE_ARB_PF_2, "pf_ctl_fifo FIFO, channel 2" }, + { F_CAUSE_ARB_TPT_PF_2, "tpt_pf_ctl_fifo FIFO, channel 2" }, + { F_CAUSE_ARB_F_2, "f_ctl_fifo FIFO, channel 2" }, + { F_CAUSE_ARB_PBL_PF_1, "pbl_pf_ctl_fifo FIFO, channel 1" }, + { F_CAUSE_ARB_PF_1, "pf_ctl_fifo FIFO, channel 1" }, + { F_CAUSE_ARB_TPT_PF_1, "tpt_pf_ctl_fifo FIFO, channel 1" }, + { F_CAUSE_ARB_F_1, "f_ctl_fifo FIFO, channel 1" }, + { F_CAUSE_ARB_PBL_PF_0, "pbl_pf_ctl_fifo FIFO, channel 0" }, + { F_CAUSE_ARB_PF_0, "pf_ctl_fifo FIFO, channel 0" }, + { F_CAUSE_ARB_TPT_PF_0, "tpt_pf_ctl_fifo FIFO, channel 0" }, + { F_CAUSE_ARB_F_0, "f_ctl_fifo FIFO, channel 0" }, + { 0 } + }; static const struct intr_info ulprx_int_cause_arb = { .name = "ULP_RX_INT_CAUSE_ARB", .cause_reg = A_ULP_RX_INT_CAUSE_ARB, .enable_reg = A_ULP_RX_INT_ENABLE_ARB, .fatal = 0, .flags = 0, - .details = NULL, + .details = ulprx_int_cause_arb_details, .actions = NULL, }; + static const struct intr_details ulprx_int_cause_interface_details[] = { + { F_CAUSE_ULPRX2SBT_RSPPERR, "ULPRX2SBT_RspPerr" }, + { F_CAUSE_ULPRX2MA_RSPPERR, "ULPRX2MA_RspPerr" }, + { F_CAUSE_PIO_BUS_PERR, "Pio_Bus_Perr" }, + { F_CAUSE_PM2ULP_SNOOPDATA_3, "PM2ULP_SnoopData, channel 3" }, + { F_CAUSE_PM2ULP_SNOOPDATA_2, "PM2ULP_SnoopData, channel 2" }, + { F_CAUSE_PM2ULP_SNOOPDATA_1, "PM2ULP_SnoopData, channel 1" }, + { F_CAUSE_PM2ULP_SNOOPDATA_0, "PM2ULP_SnoopData, channel 0" }, + { F_CAUSE_TLS2ULP_DATA_3, "TLS2ULP_Data, channel 3" }, + { F_CAUSE_TLS2ULP_DATA_2, "TLS2ULP_Data, channel 2" }, + { F_CAUSE_TLS2ULP_DATA_1, "TLS2ULP_Data, channel 1" }, + { F_CAUSE_TLS2ULP_DATA_0, "TLS2ULP_Data, channel 0" }, + { F_CAUSE_TLS2ULP_PLENDATA_3, "TLS2ULP_PLenData, channel 3" }, + { F_CAUSE_TLS2ULP_PLENDATA_2, "TLS2ULP_PLenData, channel 2" }, + { F_CAUSE_TLS2ULP_PLENDATA_1, "TLS2ULP_PLenData, channel 1" }, + { F_CAUSE_TLS2ULP_PLENDATA_0, "TLS2ULP_PLenData, channel 0" }, + { F_CAUSE_PM2ULP_DATA_3, "Pm2Ulp_Data, channel 3" }, + { F_CAUSE_PM2ULP_DATA_2, "Pm2Ulp_Data, channel 2" }, + { F_CAUSE_PM2ULP_DATA_1, "Pm2Ulp_Data, channel 1" }, + { F_CAUSE_PM2ULP_DATA_0, "Pm2Ulp_Data, channel 0" }, + { F_CAUSE_TP2ULP_PCMD_3, "Tp2Ulp_Pcmd, channel 3" }, + { F_CAUSE_TP2ULP_PCMD_2, "Tp2Ulp_Pcmd, channel 2" }, + { F_CAUSE_TP2ULP_PCMD_1, "Tp2Ulp_Pcmd, channel 1" }, + { F_CAUSE_TP2ULP_PCMD_0, "Tp2Ulp_Pcmd, channel 0" }, + { 0 } + }; static const struct intr_info ulprx_int_cause_intf = { .name = "ULP_RX_INT_CAUSE_INTERFACE", .cause_reg = A_ULP_RX_INT_CAUSE_INTERFACE, .enable_reg = A_ULP_RX_INT_ENABLE_INTERFACE, .fatal = 0, .flags = 0, - .details = NULL, + .details = ulprx_int_cause_interface_details, .actions = NULL, }; bool fatal = false; + if (chip_id(adap) <= CHELSIO_T5) + ulprx_intr_info.details = ulprx_intr_details; + else if (chip_id(adap) <= CHELSIO_T6) + ulprx_intr_info.details = t6_ulprx_int_cause_details; + else + ulprx_intr_info.details = t7_ulprx_int_cause_details; + fatal |= t4_handle_intr(adap, &ulprx_intr_info, 0, flags); if (chip_id(adap) < CHELSIO_T7) fatal |= t4_handle_intr(adap, &ulprx_intr2_info, 0, flags); @@ -5559,90 +6241,298 @@ static bool ulptx_intr_handler(struct adapter *adap, int arg, int flags) { 0x0fffffff, "ULPTX parity error" }, { 0 } }; - static const struct intr_info ulptx_intr_info = { + static const struct intr_details t6_ulptx_int_cause_details[] = { + { F_PBL_BOUND_ERR_CH3 | F_PBL_BOUND_ERR_CH2 | + F_PBL_BOUND_ERR_CH1 | F_PBL_BOUND_ERR_CH0, + "PBL address out of bounds" }, + { F_SGE2ULP_FIFO_PERR_SET3 | F_SGE2ULP_FIFO_PERR_SET2 | + F_SGE2ULP_FIFO_PERR_SET1 | F_SGE2ULP_FIFO_PERR_SET0, + "SGE2ULP fifo parity error" }, + { F_CIM2ULP_FIFO_PERR_SET3 | F_CIM2ULP_FIFO_PERR_SET2 | + F_CIM2ULP_FIFO_PERR_SET1 | F_CIM2ULP_FIFO_PERR_SET0, + "CIM2ULP fifo parity error" }, + { F_CQE_FIFO_PERR_SET3 | F_CQE_FIFO_PERR_SET2 | + F_CQE_FIFO_PERR_SET1 | F_CQE_FIFO_PERR_SET0, + "CQE fifo parity error" }, + { F_PBL_FIFO_PERR_SET3 | F_PBL_FIFO_PERR_SET2 | + F_PBL_FIFO_PERR_SET1 | F_PBL_FIFO_PERR_SET0, + "PBL fifo parity error" }, + { F_CMD_FIFO_PERR_SET3 | F_CMD_FIFO_PERR_SET2 | + F_CMD_FIFO_PERR_SET1 | F_CMD_FIFO_PERR_SET0, + "Command fifo parity error" }, + { F_LSO_HDR_SRAM_PERR_SET3 | F_LSO_HDR_SRAM_PERR_SET2 | + F_LSO_HDR_SRAM_PERR_SET1 | F_LSO_HDR_SRAM_PERR_SET0, + "LSO hdr parity error" }, + { 0 } + }; + struct intr_info ulptx_intr_info = { .name = "ULP_TX_INT_CAUSE", .cause_reg = A_ULP_TX_INT_CAUSE, .enable_reg = A_ULP_TX_INT_ENABLE, .fatal = 0x0fffffff, .flags = IHF_FATAL_IFF_ENABLED, - .details = ulptx_intr_details, + .details = NULL, + .actions = NULL, + }; + static const struct intr_details ulptx_int_cause_1_details[] = { + { F_PBL_BOUND_ERR_CH3 | F_PBL_BOUND_ERR_CH2 | + F_PBL_BOUND_ERR_CH1 | F_PBL_BOUND_ERR_CH0, + "PBL address out of bounds (configured PBL_ULIMIT/LLIMIT)" }, + { F_SGE2ULP_FIFO_PERR_SET3 | F_SGE2ULP_FIFO_PERR_SET2 | + F_SGE2ULP_FIFO_PERR_SET1 | F_SGE2ULP_FIFO_PERR_SET0, + "SGE2ULP FIFO parity error" }, + { F_CIM2ULP_FIFO_PERR_SET3 | F_CIM2ULP_FIFO_PERR_SET2 | + F_CIM2ULP_FIFO_PERR_SET1 | F_CIM2ULP_FIFO_PERR_SET0, + "CIM2ULP FIFO parity error" }, + { F_CQE_FIFO_PERR_SET3 | F_CQE_FIFO_PERR_SET2 | + F_CQE_FIFO_PERR_SET1 | F_CQE_FIFO_PERR_SET0, + "CQE FIFO parity error" }, + { F_PBL_FIFO_PERR_SET3 | F_PBL_FIFO_PERR_SET2 | + F_PBL_FIFO_PERR_SET1 | F_PBL_FIFO_PERR_SET0, + "PBL FIFO parity error" }, + { F_CMD_FIFO_PERR_SET3 | F_CMD_FIFO_PERR_SET2 | + F_CMD_FIFO_PERR_SET1 | F_CMD_FIFO_PERR_SET0, + "Command FIFO parity error" }, + { F_LSO_HDR_SRAM_PERR_SET3 | F_LSO_HDR_SRAM_PERR_SET2 | + F_LSO_HDR_SRAM_PERR_SET1 | F_LSO_HDR_SRAM_PERR_SET0, + "LSO HDR parity error" }, + { F_TLS_DSGL_PARERR3 | F_TLS_DSGL_PARERR2 | + F_TLS_DSGL_PARERR1 | F_TLS_DSGL_PARERR0, + "TLS Glue DSGL FIFO parity error" }, + { 0 } + }; + static const struct intr_info ulptx_intr_info1 = { + .name = "ULP_TX_INT_CAUSE_1", + .cause_reg = A_ULP_TX_INT_CAUSE_1, + .enable_reg = A_ULP_TX_INT_ENABLE_1, + .fatal = 0x0fffffff, + .flags = IHF_FATAL_IFF_ENABLED, + .details = ulptx_int_cause_1_details, .actions = NULL, }; + static const struct intr_details ulptx_int_cause_2_details[] = { + { F_EDMA_IN_FIFO_PERR_SET3 | F_EDMA_IN_FIFO_PERR_SET2 | + F_EDMA_IN_FIFO_PERR_SET1 | F_EDMA_IN_FIFO_PERR_SET0, + "EDMA input FIFO parity error" }, + { F_ALIGN_CTL_FIFO_PERR_SET3 | F_ALIGN_CTL_FIFO_PERR_SET2 | + F_ALIGN_CTL_FIFO_PERR_SET1 | F_ALIGN_CTL_FIFO_PERR_SET0, + "Align control FIFO parity error" }, + { F_SGE_FIFO_PERR_SET3 | F_SGE_FIFO_PERR_SET2 | + F_SGE_FIFO_PERR_SET1 | F_SGE_FIFO_PERR_SET0, + "SGE FIFO parity error" }, + { F_STAG_FIFO_PERR_SET3 | F_STAG_FIFO_PERR_SET2 | + F_STAG_FIFO_PERR_SET1 | F_STAG_FIFO_PERR_SET0, + "STAG FIFO parity error" }, + { F_MAP_FIFO_PERR_SET3 | F_MAP_FIFO_PERR_SET2 | + F_MAP_FIFO_PERR_SET1 | F_MAP_FIFO_PERR_SET0, + "MAP FIFO parity error" }, + { F_DMA_FIFO_PERR_SET3 | F_DMA_FIFO_PERR_SET2 | + F_DMA_FIFO_PERR_SET1 | F_DMA_FIFO_PERR_SET0, + "DMA FIFO parity error" }, + { F_FSO_HDR_SRAM_PERR_SET3 | F_FSO_HDR_SRAM_PERR_SET2 | + F_FSO_HDR_SRAM_PERR_SET1 | F_FSO_HDR_SRAM_PERR_SET0, + "FSO HDR memory parity error" }, + { F_T10_PI_SRAM_PERR_SET3 | F_T10_PI_SRAM_PERR_SET2 | + F_T10_PI_SRAM_PERR_SET1 | F_T10_PI_SRAM_PERR_SET0, + "T10 PI memory parity error" }, + { 0 } + }; static const struct intr_info ulptx_intr_info2 = { .name = "ULP_TX_INT_CAUSE_2", .cause_reg = A_ULP_TX_INT_CAUSE_2, .enable_reg = A_ULP_TX_INT_ENABLE_2, .fatal = 0xffffffff, .flags = IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = ulptx_int_cause_2_details, .actions = NULL, }; + static const struct intr_details ulptx_int_cause_3_details[] = { + { F_GF_SGE_FIFO_PARERR3 | F_GF_SGE_FIFO_PARERR2 | + F_GF_SGE_FIFO_PARERR1 | F_GF_SGE_FIFO_PARERR0, + "GF SGE interface FIFO parity error" }, + { F_DEDUPE_SGE_FIFO_PARERR3 | F_DEDUPE_SGE_FIFO_PARERR2 | + F_DEDUPE_SGE_FIFO_PARERR1 | F_DEDUPE_SGE_FIFO_PARERR0, + "DeDupe SGE interface FIFO parity error" }, + { F_GF3_DSGL_FIFO_PARERR | F_GF2_DSGL_FIFO_PARERR | + F_GF1_DSGL_FIFO_PARERR | F_GF0_DSGL_FIFO_PARERR, + "GF DSGL FIFO parity error" }, + { F_DEDUPE3_DSGL_FIFO_PARERR | F_DEDUPE2_DSGL_FIFO_PARERR | + F_DEDUPE1_DSGL_FIFO_PARERR | F_DEDUPE0_DSGL_FIFO_PARERR, + "DeDupe DSGL FIFO parity error" }, + { F_XP10_SGE_FIFO_PARERR, "XP10 SGE FIFO parity error (Ch0)" }, + { F_DSGL_PAR_ERR, "XP10 DSGL interface parity error" }, + { F_CDDIP_INT, "XP10 decompression interrupt" }, + { F_CCEIP_INT, "XP10 compression interrupt" }, + { F_TLS_SGE_FIFO_PARERR3 | F_TLS_SGE_FIFO_PARERR2 | + F_TLS_SGE_FIFO_PARERR1 | F_TLS_SGE_FIFO_PARERR0, + "TLS Glue SGE FIFO parity error" }, + { F_ULP2SMARBT_RSP_PERR, "ULP2SMARBT response data/CTL parity error" }, + { F_ULPTX2MA_RSP_PERR, "ULP2MA response data/CTL parity error" }, + { F_PCIE2ULP_PERR3 | F_PCIE2ULP_PERR2 | + F_PCIE2ULP_PERR1 | F_PCIE2ULP_PERR0, + "PCIE2ULP EDMA response parity error" }, + { F_CIM2ULP_PERR, "CIM2ULP command parity error (all ports)" }, + { 0 } + }; static const struct intr_info ulptx_intr_info3 = { .name = "ULP_TX_INT_CAUSE_3", .cause_reg = A_ULP_TX_INT_CAUSE_3, .enable_reg = A_ULP_TX_INT_ENABLE_3, .fatal = 0xffffffff, .flags = IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = ulptx_int_cause_3_details, .actions = NULL, }; + static const struct intr_details ulptx_int_cause_4_details[] = { + { F_XP10_2_ULP_PERR, "XP10 to ULP parity error" }, + { F_ULP_2_XP10_PERR, "ULP to XP10 parity error" }, + { F_CMD_FIFO_LB1 | F_CMD_FIFO_LB0, + "Command FIFO LB error" }, + { F_TF_TP_PERR, "TF TP parity error" }, + { F_TF_SGE_PERR, "TF SGE parity error" }, + { F_TF_MEM_PERR, "TF memory parity error" }, + { F_TF_MP_PERR, "TF MP parity error" }, + { 0 } + }; static const struct intr_info ulptx_intr_info4 = { .name = "ULP_TX_INT_CAUSE_4", .cause_reg = A_ULP_TX_INT_CAUSE_4, .enable_reg = A_ULP_TX_INT_ENABLE_4, .fatal = 0xffffffff, .flags = IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = ulptx_int_cause_4_details, .actions = NULL, }; + static const struct intr_details ulptx_int_cause_5_details[] = { + { F_DEDUPE_PERR3 | F_DEDUPE_PERR2 | + F_DEDUPE_PERR1 | F_DEDUPE_PERR0, + "DeDupe parity error" }, + { F_GF_PERR3 | F_GF_PERR2 | + F_GF_PERR1 | F_GF_PERR0, + "GF parity error" }, + { F_SGE2ULP_INV_PERR, "SGE2ULP invalid parity error" }, + { F_T7_PL_BUSPERR, "PL bus parity error" }, + { F_TLSTX2ULPTX_PERR3 | F_TLSTX2ULPTX_PERR2 | + F_TLSTX2ULPTX_PERR1 | F_TLSTX2ULPTX_PERR0, + "TLS to ULP parity error" }, + { F_XP10_2_ULP_PL_PERR, "XP10 to ULP PL parity error" }, + { F_ULP_2_XP10_PL_PERR, "ULP to XP10 PL parity error" }, + { 0 } + }; static const struct intr_info ulptx_intr_info5 = { .name = "ULP_TX_INT_CAUSE_5", .cause_reg = A_ULP_TX_INT_CAUSE_5, .enable_reg = A_ULP_TX_INT_ENABLE_5, .fatal = 0xffffffff, .flags = IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = ulptx_int_cause_5_details, .actions = NULL, }; + static const struct intr_details ulptx_int_cause_6_details[] = { + { F_DDR_HDR_FIFO_PERR_SET3 | F_DDR_HDR_FIFO_PERR_SET2 | + F_DDR_HDR_FIFO_PERR_SET1 | F_DDR_HDR_FIFO_PERR_SET0, + "DDR HDR FIFO parity error" }, + { F_PRE_MP_RSP_PERR_SET3 | F_PRE_MP_RSP_PERR_SET2 | + F_PRE_MP_RSP_PERR_SET1 | F_PRE_MP_RSP_PERR_SET0, + "Pre-MP response parity error" }, + { F_PRE_CQE_FIFO_PERR_SET3 | F_PRE_CQE_FIFO_PERR_SET2 | + F_PRE_CQE_FIFO_PERR_SET1 | F_PRE_CQE_FIFO_PERR_SET0, + "Pre-CQE FIFO parity error" }, + { F_RSP_FIFO_PERR_SET, "Response FIFO parity error" }, + { 0 } + }; static const struct intr_info ulptx_intr_info6 = { .name = "ULP_TX_INT_CAUSE_6", .cause_reg = A_ULP_TX_INT_CAUSE_6, .enable_reg = A_ULP_TX_INT_ENABLE_6, .fatal = 0xffffffff, .flags = IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = ulptx_int_cause_6_details, .actions = NULL, }; + static const struct intr_details ulptx_int_cause_7_details[] = { + { F_TLS_SGE_FIFO_CORERR3 | F_TLS_SGE_FIFO_CORERR2 | + F_TLS_SGE_FIFO_CORERR1 | F_TLS_SGE_FIFO_CORERR0, + "TLS SGE FIFO correctable error" }, + { F_LSO_HDR_SRAM_CERR_SET3 | F_LSO_HDR_SRAM_CERR_SET2 | + F_LSO_HDR_SRAM_CERR_SET1 | F_LSO_HDR_SRAM_CERR_SET0, + "LSO HDR SRAM correctable error" }, + { F_CORE_CMD_FIFO_CERR_SET_CH3_LB1 | F_CORE_CMD_FIFO_CERR_SET_CH2_LB1 | + F_CORE_CMD_FIFO_CERR_SET_CH1_LB1 | F_CORE_CMD_FIFO_CERR_SET_CH0_LB1, + "Core command FIFO LB1 correctable error" }, + { F_CORE_CMD_FIFO_CERR_SET_CH3_LB0 | F_CORE_CMD_FIFO_CERR_SET_CH2_LB0 | + F_CORE_CMD_FIFO_CERR_SET_CH1_LB0 | F_CORE_CMD_FIFO_CERR_SET_CH0_LB0, + "Core command FIFO LB0 correctable error" }, + { F_CQE_FIFO_CERR_SET3 | F_CQE_FIFO_CERR_SET2 | + F_CQE_FIFO_CERR_SET1 | F_CQE_FIFO_CERR_SET0, + "CQE FIFO correctable error" }, + { F_PRE_CQE_FIFO_CERR_SET3 | F_PRE_CQE_FIFO_CERR_SET2 | + F_PRE_CQE_FIFO_CERR_SET1 | F_PRE_CQE_FIFO_CERR_SET0, + "Pre-CQE FIFO correctable error" }, + { 0 } + }; static const struct intr_info ulptx_intr_info7 = { .name = "ULP_TX_INT_CAUSE_7", .cause_reg = A_ULP_TX_INT_CAUSE_7, .enable_reg = A_ULP_TX_INT_ENABLE_7, .fatal = 0, .flags = 0, - .details = NULL, + .details = ulptx_int_cause_7_details, .actions = NULL, }; + static const struct intr_details ulptx_int_cause_8_details[] = { + { F_MEM_RSP_FIFO_CERR_SET3 | F_MEM_RSP_FIFO_CERR_SET2 | + F_MEM_RSP_FIFO_CERR_SET1 | F_MEM_RSP_FIFO_CERR_SET0, + "Memory response FIFO correctable error" }, + { F_PI_SRAM_CERR_SET3 | F_PI_SRAM_CERR_SET2 | + F_PI_SRAM_CERR_SET1 | F_PI_SRAM_CERR_SET0, + "PI SRAM correctable error" }, + { F_PRE_MP_RSP_CERR_SET3 | F_PRE_MP_RSP_CERR_SET2 | + F_PRE_MP_RSP_CERR_SET1 | F_PRE_MP_RSP_CERR_SET0, + "Pre-MP response correctable error" }, + { F_DDR_HDR_FIFO_CERR_SET3 | F_DDR_HDR_FIFO_CERR_SET2 | + F_DDR_HDR_FIFO_CERR_SET1 | F_DDR_HDR_FIFO_CERR_SET0, + "DDR HDR FIFO correctable error" }, + { F_CMD_FIFO_CERR_SET3 | F_CMD_FIFO_CERR_SET2 | + F_CMD_FIFO_CERR_SET1 | F_CMD_FIFO_CERR_SET0, + "Command FIFO correctable error" }, + { F_GF_SGE_FIFO_CORERR3 | F_GF_SGE_FIFO_CORERR2 | + F_GF_SGE_FIFO_CORERR1 | F_GF_SGE_FIFO_CORERR0, + "GF SGE FIFO correctable error" }, + { F_DEDUPE_SGE_FIFO_CORERR3 | F_DEDUPE_SGE_FIFO_CORERR2 | + F_DEDUPE_SGE_FIFO_CORERR1 | F_DEDUPE_SGE_FIFO_CORERR0, + "DeDupe SGE FIFO correctable error" }, + { F_RSP_FIFO_CERR_SET, "Response FIFO correctable error" }, + { 0 } + }; static const struct intr_info ulptx_intr_info8 = { .name = "ULP_TX_INT_CAUSE_8", .cause_reg = A_ULP_TX_INT_CAUSE_8, .enable_reg = A_ULP_TX_INT_ENABLE_8, .fatal = 0, .flags = 0, - .details = NULL, + .details = ulptx_int_cause_8_details, .actions = NULL, }; bool fatal = false; - fatal |= t4_handle_intr(adap, &ulptx_intr_info, 0, flags); - if (chip_id(adap) > CHELSIO_T4) - fatal |= t4_handle_intr(adap, &ulptx_intr_info2, 0, flags); if (chip_id(adap) > CHELSIO_T6) { + fatal |= t4_handle_intr(adap, &ulptx_intr_info1, 0, flags); + fatal |= t4_handle_intr(adap, &ulptx_intr_info2, 0, flags); fatal |= t4_handle_intr(adap, &ulptx_intr_info3, 0, flags); fatal |= t4_handle_intr(adap, &ulptx_intr_info4, 0, flags); fatal |= t4_handle_intr(adap, &ulptx_intr_info5, 0, flags); fatal |= t4_handle_intr(adap, &ulptx_intr_info6, 0, flags); fatal |= t4_handle_intr(adap, &ulptx_intr_info7, 0, flags); fatal |= t4_handle_intr(adap, &ulptx_intr_info8, 0, flags); + } else { + if (chip_id(adap) == CHELSIO_T6) + ulptx_intr_info.details = t6_ulptx_int_cause_details; + else + ulptx_intr_info.details = ulptx_intr_details; + fatal |= t4_handle_intr(adap, &ulptx_intr_info, 0, flags); + if (chip_id(adap) > CHELSIO_T4) + fatal |= t4_handle_intr(adap, &ulptx_intr_info2, 0, flags); } return (fatal); @@ -5671,6 +6561,25 @@ static bool pmtx_dump_dbg_stats(struct adapter *adap, int arg, int flags) */ static bool pmtx_intr_handler(struct adapter *adap, int arg, int flags) { + static const struct intr_details t7_pmtx_int_cause_fields[] = { + { F_MASTER_PERR, "PM_TX master parity error" }, + { F_T7_ZERO_C_CMD_ERROR, "PM_TX PCMD with zero length error" }, + { F_OESPI_COR_ERR, " oespi FIFO Correctable Error" }, + { F_ICSPI_COR_ERR, " icspi FIFO Correctable Error" }, + { F_ICSPI_OVFL, " icspi FIFO overflow" }, + { F_T7_PCMD_LEN_OVFL0, "PMTX channel 0 pcmd too large" }, + { F_T7_PCMD_LEN_OVFL1, "PMTX channel 1 pcmd too large" }, + { F_T7_PCMD_LEN_OVFL2, "PMTX channel 2 pcmd too large" }, + { F_PCMD_LEN_OVFL3, "PMTX channel 2 pcmd too large" }, + { F_T7_ZERO_C_CMD_ERROR, "PMTX 0-length pcmd" }, + { 0x00f00000, "PM_TX PCMD length larger than oespi capacity" }, + { 0x000f0000, "PM_TX icspi 2x FIFO Rx framing error" }, + { 0x0000f000, "PM_TX icspi FIFO Tx framing error" }, + { 0x00000f00, "PM_TX oespi FIFO Rx framing error" }, + { 0x000000f0, "PM_TX oespi FIFO Tx framing error" }, + { 0x0000000f, "PM_TX oespi 2x FIFO Tx framing error" }, + { 0 } + }; static const struct intr_details pmtx_int_cause_fields[] = { { F_PCMD_LEN_OVFL0, "PMTX channel 0 pcmd too large" }, { F_PCMD_LEN_OVFL1, "PMTX channel 1 pcmd too large" }, @@ -5692,17 +6601,58 @@ static bool pmtx_intr_handler(struct adapter *adap, int arg, int flags) { 0xffffffff, -1, pmtx_dump_dbg_stats }, { 0 }, }; - static const struct intr_info pmtx_int_cause = { + struct intr_info pmtx_int_cause = { .name = "PM_TX_INT_CAUSE", .cause_reg = A_PM_TX_INT_CAUSE, .enable_reg = A_PM_TX_INT_ENABLE, .fatal = 0xffffffff, - .flags = 0, - .details = pmtx_int_cause_fields, + .flags = IHF_CLR_DELAYED, + .details = NULL, .actions = pmtx_int_cause_actions, }; + static const struct intr_details pmtx_perr_cause_details[] = { + { F_ICSPI_OVFL, "icspi FIFO Overflow" }, + { F_OSPI_OVERFLOW3_TX, " OSPI overflow on channel 3 error." }, + { F_OSPI_OVERFLOW2_TX, " OSPI overflow on channel 2 error." }, + { F_OSPI_OVERFLOW1_TX, " OSPI overflow on channel 1 error." }, + { F_OSPI_OVERFLOW0_TX, " OSPI overflow on channel 0 error." }, + { F_T7_BUNDLE_LEN_OVFL_EN, "This bit indicates bundle_len_ovfl_err." }, + { F_T7_M_INTFPERREN, "This bit indicates Parity error from MA interfaces." }, + { F_T7_1_SDC_ERR, + "SDC Error reported by Check PCMD which carries CRC16 from TP-CSide." }, + { F_MC_WCNT_FIFO_PERR, "MC Interface Write count FIFO Parity error" }, + { F_MC_WDATA_FIFO_PERR, "MC Interface Write Data FIFO Parity error" }, + { F_MC_RCNT_FIFO_PERR, "MC Interface Read count FIFO Parity error" }, + { F_MC_RDATA_FIFO_PERR, "MC Interface Read Data FIFO Parity error" }, + { F_TOKEN_PAR_ERROR, "c_pcmd, Token FIFO par error" }, + { F_BUNDLE_LEN_PAR_ERROR, "oespi par error" }, + { F_OESPI_PAR_ERROR, "oespi par error" }, + { F_DB_OPTIONS_PAR_ERROR, "db_options par error" }, + { F_ICSPI_PAR_ERROR, "icspi par error" }, + { F_C_PCMD_TOKEN_PAR_ERROR, "c_pcmd par error" }, + { 0 } + }; + static struct intr_info pmtx_perr_cause = { + .name = "PM_TX_PERR_CAUSE", + .cause_reg = A_PM_TX_PERR_CAUSE, + .enable_reg = A_PM_TX_PERR_ENABLE, + .fatal = 0xffffffff, + .flags = 0, + .details = pmtx_perr_cause_details, + .actions = NULL, + }; + bool fatal; + + if (chip_id(adap) >= CHELSIO_T7) + pmtx_int_cause.details = t7_pmtx_int_cause_fields; + else + pmtx_int_cause.details = pmtx_int_cause_fields; + fatal = t4_handle_intr(adap, &pmtx_int_cause, 0, flags); + if (chip_id(adap) >= CHELSIO_T7) + fatal |= t4_handle_intr(adap, &pmtx_perr_cause, 0, flags); + clear_int_cause_reg(adap, &pmtx_int_cause, flags); - return (t4_handle_intr(adap, &pmtx_int_cause, 0, flags)); + return (fatal); } /* @@ -5710,6 +6660,20 @@ static bool pmtx_intr_handler(struct adapter *adap, int arg, int flags) */ static bool pmrx_intr_handler(struct adapter *adap, int arg, int flags) { + static const struct intr_details t7_pmrx_int_cause_fields[] = { + { F_MASTER_PERR, "PM_RX master parity error" }, + { 0x18000000, "PMRX ospi overflow" }, + { F_BUNDLE_LEN_OVFL, "PMRX bundle len FIFO overflow" }, + { F_SDC_ERR, "PMRX SDC error" }, + { F_ZERO_E_CMD_ERROR, "PMRX 0-length pcmd" }, + { 0x003c0000, "PMRX iespi FIFO2X Rx framing error" }, + { 0x0003c000, "PMRX iespi Rx framing error" }, + { 0x00003c00, "PMRX iespi Tx framing error" }, + { 0x00000300, "PMRX ocspi Rx framing error" }, + { 0x000000c0, "PMRX ocspi Tx framing error" }, + { 0x00000030, "PMRX ocspi FIFO2X Tx framing error" }, + { 0 } + }; static const struct intr_details pmrx_int_cause_fields[] = { /* T6+ */ { 0x18000000, "PMRX ospi overflow" }, @@ -5732,17 +6696,90 @@ static bool pmrx_intr_handler(struct adapter *adap, int arg, int flags) { F_E_PCMD_PAR_ERROR, "PMRX e_pcmd parity error"}, { 0 } }; - static const struct intr_info pmrx_int_cause = { + struct intr_info pmrx_int_cause = { .name = "PM_RX_INT_CAUSE", .cause_reg = A_PM_RX_INT_CAUSE, .enable_reg = A_PM_RX_INT_ENABLE, .fatal = 0x1fffffff, + .flags = IHF_FATAL_IFF_ENABLED | IHF_CLR_DELAYED, + .details = NULL, + .actions = NULL, + }; + static const struct intr_details pm_rx_int_cause_2_details[] = { + { F_CACHE_SRAM_ODD_CERR, "Cache Data Odd SRAM Correctable Error" }, + { F_CACHE_SRAM_EVEN_CERR, "Cache Data Even SRAM Correctable Error" }, + { F_CACHE_LRU_LEFT_CERR, "Cache LRU Left SRAM Correctable Error" }, + { F_CACHE_LRU_RIGHT_CERR, "Cache LRU Right SRAM Correctable Error" }, + { F_CACHE_ISLAND_CERR, "Cache Island SRAM Correctable Error" }, + { F_OCSPI_CERR, "ocspi FIFO Correctable Error" }, + { F_IESPI_CERR, "iespi FIFO Correctable Error" }, + { F_OCSPI2_RX_FRAMING_ERROR, "ocspi FIFO channel 2 Rx/wr framing error" }, + { F_OCSPI3_RX_FRAMING_ERROR, "ocspi FIFO channel 3 Rx/wr framing error" }, + { F_OCSPI2_TX_FRAMING_ERROR, "ocspi FIFO channel 2 Tx/rd framing error" }, + { F_OCSPI3_TX_FRAMING_ERROR, "ocspi FIFO channel 3 Tx/rd framing error" }, + { F_OCSPI2_OFIFO2X_TX_FRAMING_ERROR, "ocspi 2x FIFO 2 Tx/rd framing error" }, + { F_OCSPI3_OFIFO2X_TX_FRAMING_ERROR, "ocspi 2x FIFO 3 Tx/rd framing error" }, + { 0 } + }; + static struct intr_info pmrx_int_cause2 = { + .name = "PM_RX_INT_CAUSE_2", + .cause_reg = A_PM_RX_INT_CAUSE_2, + .enable_reg = A_PM_RX_INT_ENABLE_2, + .fatal = 0x1fffffff, + .flags = IHF_FATAL_IFF_ENABLED, + .details = pm_rx_int_cause_2_details, + .actions = NULL, + }; + static const struct intr_details pm_rx_perr_cause_details[] = { + { F_T7_SDC_ERR, "SDC error. CRC provided by TP and PM didn't match." }, + { F_T7_MA_INTF_SDC_ERR, "MA intf SDC perr" }, + { F_E_PCMD_PERR, "ulp_rx 2 pm_rx PCMD interface parity error." }, + { F_CACHE_RSP_DFIFO_PERR, "Cache Response Data FIFO Parity error" }, + { F_CACHE_SRAM_ODD_PERR, "Cache Odd SRAM error" }, + { F_CACHE_SRAM_EVEN_PERR, "Cache Even SRAM error" }, + { F_CACHE_RSVD_PERR, "Cache Reserved Parity error" }, + { F_CACHE_LRU_LEFT_PERR, "Cache LRU Left SRAM error" }, + { F_CACHE_LRU_RIGHT_PERR, "Cache LRU Rigth SRAM error" }, + { F_CACHE_RSP_CMD_PERR, "Cache Response Command FIFO error" }, + { F_CACHE_SRAM_CMD_PERR, "Cache SRAM Command FIFO error" }, + { F_CACHE_MA_CMD_PERR, "Cache MA Command FIFO error" }, + { F_CACHE_TCAM_PERR, "Cache TCAM Parity error" }, + { F_CACHE_ISLAND_PERR, "Cache island SRAM Parity error" }, + { F_MC_WCNT_FIFO_PERR, "MC Interface Write count FIFO Parity error" }, + { F_MC_WDATA_FIFO_PERR, "MC Interface Write Data FIFO Parity error" }, + { F_MC_RCNT_FIFO_PERR, "MC Interface Read count FIFO Parity error" }, + { F_MC_RDATA_FIFO_PERR, "MC Interface Read Data FIFO Parity error" }, + { F_TOKEN_FIFO_PERR, "Token FIFO Parity error" }, + { F_T7_BUNDLE_LEN_PARERR, "Bundle len fifo had parity error." }, + { F_OCSPI_PAR_ERROR, "ocspi par error vector" }, + { F_DB_OPTIONS_PAR_ERROR, "db_options par error" }, + { F_IESPI_PAR_ERROR, "iespi par error" }, + { F_E_PCMD_PAR_ERROR, "e_pcmd par error" }, + { 0 } + }; + static struct intr_info pmrx_perr_cause = { + .name = "PM_RX_PERR_CAUSE", + .cause_reg = A_PM_RX_PERR_CAUSE, + .enable_reg = A_PM_RX_PERR_ENABLE, + .fatal = 0x1fffffff, .flags = IHF_FATAL_IFF_ENABLED, - .details = pmrx_int_cause_fields, + .details = pm_rx_perr_cause_details, .actions = NULL, }; + bool fatal; + + if (chip_id(adap) >= CHELSIO_T7) { + pmrx_int_cause.details = t7_pmrx_int_cause_fields; + fatal = t4_handle_intr(adap, &pmrx_int_cause, 0, flags); + fatal |= t4_handle_intr(adap, &pmrx_int_cause2, 0, flags); + fatal |= t4_handle_intr(adap, &pmrx_perr_cause, 0, flags); + } else { + pmrx_int_cause.details = pmrx_int_cause_fields; + fatal = t4_handle_intr(adap, &pmrx_int_cause, 0, flags); + } + clear_int_cause_reg(adap, &pmrx_int_cause, flags); - return (t4_handle_intr(adap, &pmrx_int_cause, 0, flags)); + return (fatal); } /* @@ -5751,6 +6788,9 @@ static bool pmrx_intr_handler(struct adapter *adap, int arg, int flags) static bool cplsw_intr_handler(struct adapter *adap, int arg, int flags) { static const struct intr_details cplsw_int_cause_fields[] = { + /* T7+ */ + { F_PERR_CPL_128TO128_3, "CPLSW 128TO128 FIFO3 parity error" }, + { F_PERR_CPL_128TO128_2, "CPLSW 128TO128 FIFO2 parity error" }, /* T5+ */ { F_PERR_CPL_128TO128_1, "CPLSW 128TO128 FIFO1 parity error" }, { F_PERR_CPL_128TO128_0, "CPLSW 128TO128 FIFO0 parity error" }, @@ -5803,6 +6843,8 @@ static bool le_intr_handler(struct adapter *adap, int arg, int flags) { 0 } }; static const struct intr_details t6_le_intr_details[] = { + { F_CACHEINTPERR, "Parity error in cache module" }, + { F_CACHESRAMPERR, "Parity error in data sram " }, { F_CLIPSUBERR, "LE CLIP CAM reverse substitution error" }, { F_CLCAMFIFOERR, "LE CLIP CAM internal FIFO error" }, { F_CTCAMINVLDENT, "Invalid IPv6 CLIP TCAM entry" }, @@ -5865,51 +6907,206 @@ static bool mps_intr_handler(struct adapter *adap, int arg, int flags) .details = mps_rx_perr_intr_details, .actions = NULL, }; + static const struct intr_details mps_rx_func_intr_details[] = { + { F_MTU_ERR3, "MTU error interrupt enable bit for loopback group 3" }, + { F_MTU_ERR2, "MTU error interrupt enable bit for loopback group 2" }, + { F_MTU_ERR1, "MTU error interrupt enable bit for loopback group 1" }, + { F_MTU_ERR0, "MTU error interrupt enable bit for loopback group 0" }, + { F_DBG_LEN_ERR, "Oring of len error in traffic transfer b/w internal modules" }, + { F_DBG_SPI_ERR, "Oring of spi error in traffic transfer b/w internal modules" }, + { F_DBG_SE_CNT_ERR, "Oring of se cnt error in traffic transfer" }, + { F_DBG_SPI_LEN_SE_CNT_ERR, "Oring of all se_cnt|len|spi errors" }, + { 0 } + }; + static const struct intr_info mps_rx_func_intr_info = { + .name = "MPS_RX_FUNC_INT_CAUSE", + .cause_reg = A_MPS_RX_FUNC_INT_CAUSE, + .enable_reg = A_MPS_RX_FUNC_INT_ENABLE, + .fatal = 0xffffffff, + .flags = IHF_FATAL_IFF_ENABLED, + .details = mps_rx_func_intr_details, + .actions = NULL, + }; + static const struct intr_details mpsrx_int_cause_2_details[] = { + { F_CRYPTO2MPS_RX0_PERR | F_CRYPTO2MPS_RX1_PERR | + F_CRYPTO2MPS_RX2_PERR | F_CRYPTO2MPS_RX3_PERR, + "Crypto to MPS RX interface parity error" }, + { F_INIC2MPS_TX1_PERR | F_INIC2MPS_TX0_PERR, + "INIC to MPS TX interface parity error" }, + { F_XGMAC2MPS_RX1_PERR | F_XGMAC2MPS_RX0_PERR, + "XGMAC to MPS RX interface parity error" }, + { F_RX_FINAL_TF_FIFO_PERR, + "Final RX token FIFO output parity error" }, + { F_MPS_DWRR_FIFO_PERR, + "MPS DWRR MTU FIFO parity error" }, + { F_MAC_TF_FIFO_PERR, + "MAC token FIFO parity error" }, + { F_MAC2MPS_PT3_PERR | F_MAC2MPS_PT2_PERR | + F_MAC2MPS_PT1_PERR | F_MAC2MPS_PT0_PERR, + "MAC to MPS interface parity error" }, + { F_TP_LPBK_FIFO_PERR, "TP loopback FIFO parity error" }, + { F_TP_LPBK_TF_PERR, "Loopback token FIFO parity error" }, + { 0 } + }; static const struct intr_info mps_rx_perr_intr_info2 = { .name = "MPS_RX_PERR_INT_CAUSE2", .cause_reg = A_MPS_RX_PERR_INT_CAUSE2, .enable_reg = A_MPS_RX_PERR_INT_ENABLE2, .fatal = 0xffffffff, .flags = IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = mpsrx_int_cause_2_details, .actions = NULL, }; + static const struct intr_details mpsrx_int_cause_3_details[] = { + { F_FIFO_REPL_CH3_CERR | F_FIFO_REPL_CH2_CERR | + F_FIFO_REPL_CH1_CERR | F_FIFO_REPL_CH0_CERR, + "Replication FIFO ECC error" }, + { F_VLAN_FILTER_RAM_CERR, "VLAN filter SRAM ECC error" }, + { F_MPS_RX_TD_STAT_FIFO_PERR_CH3 | F_MPS_RX_TD_STAT_FIFO_PERR_CH2 | + F_MPS_RX_TD_STAT_FIFO_PERR_CH1 | F_MPS_RX_TD_STAT_FIFO_PERR_CH0, + "MPS RX TD status descriptor FIFO parity error" }, + { F_RPLCT_HDR_FIFO_IN_PERR_CH3 | F_RPLCT_HDR_FIFO_IN_PERR_CH2 | + F_RPLCT_HDR_FIFO_IN_PERR_CH1 | F_RPLCT_HDR_FIFO_IN_PERR_CH0, + "MPS RX replication header input FIFO parity error" }, + { F_ID_FIFO_IN_PERR_CH3 | F_ID_FIFO_IN_PERR_CH2 | + F_ID_FIFO_IN_PERR_CH1 | F_ID_FIFO_IN_PERR_CH0, + "MPS RX replication ID input FIFO parity error" }, + { F_DESC_HDR2_PERR_CH3 | F_DESC_HDR2_PERR_CH2 | + F_DESC_HDR2_PERR_CH1 | F_DESC_HDR2_PERR_CH0, + "MPS RX replication descriptor/header2 FIFO parity error" }, + { F_FIFO_REPL_PERR_CH3 | F_FIFO_REPL_PERR_CH2 | + F_FIFO_REPL_PERR_CH1 | F_FIFO_REPL_PERR_CH0, + "Replication FIFO parity error" }, + { F_MPS_RX_TD_PERR_CH3 | F_MPS_RX_TD_PERR_CH2 | + F_MPS_RX_TD_PERR_CH1 | F_MPS_RX_TD_PERR_CH0, + "MPS RX TD input FIFO parity error" }, + { 0 } + }; static const struct intr_info mps_rx_perr_intr_info3 = { .name = "MPS_RX_PERR_INT_CAUSE3", .cause_reg = A_MPS_RX_PERR_INT_CAUSE3, .enable_reg = A_MPS_RX_PERR_INT_ENABLE3, .fatal = 0xffffffff, .flags = IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = mpsrx_int_cause_3_details, .actions = NULL, }; + static const struct intr_details mpsrx_int_cause_4_details[] = { + { F_VNI_MULTICAST_FIFO_ECC_ERR_CH3 | F_VNI_MULTICAST_FIFO_ECC_ERR_CH2, + "RX out VNI multicast SRAM ECC error" }, + { F_HASH_SRAM_CLS_ENG1 | F_HASH_SRAM_CLS_ENG0, + "Classification engine hash SRAM ECC error" }, + { F_CLS_TCAM_SRAM_CLS_ENG1 | F_CLS_TCAM_SRAM_CLS_ENG0, + "Classification engine TCAM SRAM ECC error" }, + { F_CLS_TCAM_CRC_SRAM_CLS_ENG1 | F_CLS_TCAM_CRC_SRAM_CLS_ENG0, + "Classification engine TCAM CRC SRAM ECC error" }, + { F_DWRR_CH_FIFO_ECC_ERR, "DWRR output FIFO ECC error" }, + { F_MAC_RX_FIFO_ECC_ERR, "MAC RX FIFO ECC error" }, + { F_LPBK_RX_FIFO_ECC_ERR, "Loopback RX FIFO ECC error" }, + { F_CRS_DATA_STORE_N_FWD_CH3 | F_CRS_DATA_STORE_N_FWD_CH2 | + F_CRS_DATA_STORE_N_FWD_CH1 | F_CRS_DATA_STORE_N_FWD_CH0, + "CRS store and forward FIFO ECC error" }, + { F_TRACE_FWD_FIFO_CERR_CH3 | F_TRACE_FWD_FIFO_CERR_CH2 | + F_TRACE_FWD_FIFO_CERR_CH1 | F_TRACE_FWD_FIFO_CERR_CH0, + "Trace packet forward FIFO ECC error" }, + { F_TRANSPARENT_ENCAP_FWD_FIFO_CERR_CH3 | F_TRANSPARENT_ENCAP_FWD_FIFO_CERR_CH2 | + F_TRANSPARENT_ENCAP_FWD_FIFO_CERR_CH1 | F_TRANSPARENT_ENCAP_FWD_FIFO_CERR_CH0, + "Transparent encap forward FIFO ECC error" }, + { F_PTP_TRACE_FWD_FIFO_CERR_CH3 | F_PTP_TRACE_FWD_FIFO_CERR_CH2 | + F_PTP_TRACE_FWD_FIFO_CERR_CH1 | F_PTP_TRACE_FWD_FIFO_CERR_CH0, + "PTP packet forward FIFO ECC error" }, + { 0 } + }; static const struct intr_info mps_rx_perr_intr_info4 = { .name = "MPS_RX_PERR_INT_CAUSE4", .cause_reg = A_MPS_RX_PERR_INT_CAUSE4, .enable_reg = A_MPS_RX_PERR_INT_ENABLE4, .fatal = 0xffffffff, .flags = IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = mpsrx_int_cause_4_details, .actions = NULL, }; + static const struct intr_details mpsrx_int_cause_5_details[] = { + { F_MPS2CRYP_RX_FIFO3_PERR | F_MPS2CRYP_RX_FIFO2_PERR | + F_MPS2CRYP_RX_FIFO1_PERR | F_MPS2CRYP_RX_FIFO0_PERR, + "MPS to Crypto RX interface FIFO parity error" }, + { F_VNI_MULTICAST_SRAM2_PERR | F_VNI_MULTICAST_SRAM1_PERR | + F_VNI_MULTICAST_SRAM0_PERR, + "VNI multicast SRAM parity error" }, + { F_MAC_MULTICAST_SRAM4_PERR | F_MAC_MULTICAST_SRAM3_PERR | + F_MAC_MULTICAST_SRAM2_PERR | F_MAC_MULTICAST_SRAM1_PERR | + F_MAC_MULTICAST_SRAM0_PERR, + "MAC multicast SRAM parity error" }, + { F_MEM_WRAP_IPSEC_HDR_UPD_FIFO3_PERR | F_MEM_WRAP_IPSEC_HDR_UPD_FIFO2_PERR | + F_MEM_WRAP_IPSEC_HDR_UPD_FIFO1_PERR | F_MEM_WRAP_IPSEC_HDR_UPD_FIFO0_PERR, + "IPsec header update storing FIFO parity error" }, + { F_MEM_WRAP_CR2MPS_RX_FIFO3_PERR | F_MEM_WRAP_CR2MPS_RX_FIFO2_PERR | + F_MEM_WRAP_CR2MPS_RX_FIFO1_PERR | F_MEM_WRAP_CR2MPS_RX_FIFO0_PERR, + "IPsec storing FIFO parity error" }, + { F_MEM_WRAP_NON_IPSEC_FIFO3_PERR | F_MEM_WRAP_NON_IPSEC_FIFO2_PERR | + F_MEM_WRAP_NON_IPSEC_FIFO1_PERR | F_MEM_WRAP_NON_IPSEC_FIFO0_PERR, + "Non-IPsec storing FIFO parity error" }, + { F_MEM_WRAP_TP_DB_REQ_FIFO3_PERR | F_MEM_WRAP_TP_DB_REQ_FIFO2_PERR | + F_MEM_WRAP_TP_DB_REQ_FIFO1_PERR | F_MEM_WRAP_TP_DB_REQ_FIFO0_PERR, + "TP DB request storing FIFO parity error" }, + { F_MEM_WRAP_CNTRL_FIFO3_PERR | F_MEM_WRAP_CNTRL_FIFO2_PERR | + F_MEM_WRAP_CNTRL_FIFO1_PERR | F_MEM_WRAP_CNTRL_FIFO0_PERR, + "Header flit storing FIFO parity error" }, + { 0 } + }; static const struct intr_info mps_rx_perr_intr_info5 = { .name = "MPS_RX_PERR_INT_CAUSE5", .cause_reg = A_MPS_RX_PERR_INT_CAUSE5, .enable_reg = A_MPS_RX_PERR_INT_ENABLE5, .fatal = 0xffffffff, .flags = IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = mpsrx_int_cause_5_details, .actions = NULL, }; + static const struct intr_details mpsrx_int_cause_6_details[] = { + { F_T7_MEM_WRAP_IPSEC_HDR_UPD_FIFO3_PERR | F_T7_MEM_WRAP_IPSEC_HDR_UPD_FIFO2_PERR | + F_T7_MEM_WRAP_IPSEC_HDR_UPD_FIFO1_PERR | F_T7_MEM_WRAP_IPSEC_HDR_UPD_FIFO0_PERR, + "IPsec header update storing FIFO parity error" }, + { F_MEM_WRAP_CR2MPS_UPDTD_HDR_FIFO3_PERR | F_MEM_WRAP_CR2MPS_UPDTD_HDR_FIFO2_PERR | + F_MEM_WRAP_CR2MPS_UPDTD_HDR_FIFO1_PERR | F_MEM_WRAP_CR2MPS_UPDTD_HDR_FIFO0_PERR, + "IPsec updated header only storing FIFO parity error" }, + { F_MEM_WRAP_CR2MPS_RX_FIFO3_PERR | F_MEM_WRAP_CR2MPS_RX_FIFO2_PERR | + F_MEM_WRAP_CR2MPS_RX_FIFO1_PERR | F_MEM_WRAP_CR2MPS_RX_FIFO0_PERR, + "IPsec storing FIFO parity error" }, + { F_MEM_WRAP_NON_IPSEC_FIFO3_PERR | F_MEM_WRAP_NON_IPSEC_FIFO2_PERR | + F_MEM_WRAP_NON_IPSEC_FIFO1_PERR | F_MEM_WRAP_NON_IPSEC_FIFO0_PERR, + "Non-IPsec storing FIFO parity error" }, + { F_MEM_WRAP_TP_DB_REQ_FIFO3_PERR | F_MEM_WRAP_TP_DB_REQ_FIFO2_PERR | + F_MEM_WRAP_TP_DB_REQ_FIFO1_PERR | F_MEM_WRAP_TP_DB_REQ_FIFO0_PERR, + "TP DB request storing FIFO parity error" }, + { F_MEM_WRAP_CNTRL_FIFO3_PERR | F_MEM_WRAP_CNTRL_FIFO2_PERR | + F_MEM_WRAP_CNTRL_FIFO1_PERR | F_MEM_WRAP_CNTRL_FIFO0_PERR, + "Header flit storing FIFO parity error" }, + { 0 } + }; static const struct intr_info mps_rx_perr_intr_info6 = { .name = "MPS_RX_PERR_INT_CAUSE6", .cause_reg = A_MPS_RX_PERR_INT_CAUSE6, .enable_reg = A_MPS_RX_PERR_INT_ENABLE6, .fatal = 0xffffffff, .flags = IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = mpsrx_int_cause_6_details, .actions = NULL, }; + static const struct intr_details t7_mpstx_int_cause_details[] = { + { F_T7_PORTERR, "Tx received a frame for TP destined to a disable port" }, + { F_T7_FRMERR, "Framing error in received Data from TP or Data to MAC" }, + { F_T7_SECNTERR, "SOP-EOP count error in received Data from TP or Data to MAC" }, + { F_T7_BUBBLE, "Valid is deasserted between SOP and EOP" }, + { F_TX_TF_FIFO_PERR, "Parity error of TX token fifo" }, + { F_TX_FIFO_PERR, "Parity error of TX MPS2MAC underrun fifo" }, + { 0x0003c000, "Parity error of fifo storing non-ipsec +1 flit ipsec pkt" }, + { 0x00003fc0, "Interface parity error on TP/Crypto to MPS TX" }, + { F_NCSI2MPS, "interface Parity Error on ncsi2mps_tx_ch3" }, + { F_NCSIFIFO, "Parity Error in mps_tx_arbiter input FIFO (from NCSI)" }, + { 0x0000000f, "Parity Error in mps_tx_arbiter input FIFO (from TP)" }, + { 0 } + }; static const struct intr_details mps_tx_intr_details[] = { { F_PORTERR, "MPS Tx destination port is disabled" }, { F_FRMERR, "MPS Tx framing error" }, @@ -5921,22 +7118,27 @@ static bool mps_intr_handler(struct adapter *adap, int arg, int flags) { V_TPFIFO(M_TPFIFO), "MPS Tx TP FIFO parity error" }, { 0 } }; - static const struct intr_info mps_tx_intr_info = { + struct intr_info mps_tx_intr_info = { .name = "MPS_TX_INT_CAUSE", .cause_reg = A_MPS_TX_INT_CAUSE, .enable_reg = A_MPS_TX_INT_ENABLE, .fatal = 0x1ffff, .flags = IHF_FATAL_IFF_ENABLED, - .details = mps_tx_intr_details, + .details = NULL, .actions = NULL, }; + static const struct intr_details mpstx_int_cause_2_details[] = { + { F_TX_FIFO_PERR, "ECC error of TX MPS2MAC underrun fifo" }, + { 0x0000000f, "ECC error of fifo storing non-ipsec +1 flit ipsec pkt" }, + { 0 } + }; static const struct intr_info mps_tx_intr_info2 = { .name = "MPS_TX_INT2_CAUSE", .cause_reg = A_MPS_TX_INT2_CAUSE, .enable_reg = A_MPS_TX_INT2_ENABLE, .fatal = 0xffffffff, .flags = IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = mpstx_int_cause_2_details, .actions = NULL, }; static const struct intr_info mps_tx_intr_info3 = { @@ -5972,22 +7174,51 @@ static bool mps_intr_handler(struct adapter *adap, int arg, int flags) .details = mps_trc_intr_details, .actions = NULL, }; + static const struct intr_details t7_mps_trc_intr_details[] = { + { F_T7_TRCPLERRENB, "TRC PL error" }, + { F_T7_MISCPERR, "TRC header register parity error" }, + { 0x0000ff00, "TRC packet FIFO parity error" }, + { 0x000000ff, "TRC filter memory parity error" }, + { 0 } + }; static const struct intr_info t7_mps_trc_intr_info = { .name = "MPS_TRC_INT_CAUSE", .cause_reg = A_T7_MPS_TRC_INT_CAUSE, .enable_reg = A_T7_MPS_TRC_INT_ENABLE, .fatal = 0xffffffff, .flags = IHF_FATAL_IFF_ENABLED, - .details = mps_trc_intr_details, + .details = t7_mps_trc_intr_details, .actions = NULL, }; + static const struct intr_details t7_trc_int_cause2_details[] = { + { 0x0001e000, "TRC Tx2Rx down-converter correctable error" }, + { 0x00001800, "TRC MPS2MAC down-converter correctable error" }, + { 0x00000600, "TRC MAC2MPS down-converter correctable error" }, + { 0x000001e0, "TRC Tx2Rx down-converter parity error" }, + { 0x00000018, "TRC MAC2MPS down-converter parity error" }, + { 0x00000006, "TRC MPS2MAC down-converter parity error" }, + { 0 } + }; static const struct intr_info t7_mps_trc_intr_info2 = { .name = "MPS_TRC_INT_CAUSE2", .cause_reg = A_MPS_TRC_INT_CAUSE2, .enable_reg = A_MPS_TRC_INT_ENABLE2, .fatal = 0xffffffff, .flags = IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = t7_trc_int_cause2_details, + .actions = NULL, + }; + static const struct intr_details mps_stat_intr_details[] = { + { F_PLREADSYNCERR, "MPS pl read sync error" }, + { 0 } + }; + static const struct intr_info mps_stat_intr_info = { + .name = "MPS_STAT_INT_CAUSE", + .cause_reg = A_MPS_STAT_INT_CAUSE, + .enable_reg = A_MPS_STAT_INT_ENABLE, + .fatal = 0xf, + .flags = IHF_FATAL_IFF_ENABLED, + .details = mps_stat_intr_details, .actions = NULL, }; static const struct intr_details mps_stat_sram_intr_details[] = { @@ -6030,6 +7261,9 @@ static bool mps_intr_handler(struct adapter *adap, int arg, int flags) .actions = NULL, }; static const struct intr_details mps_cls_intr_details[] = { + { F_T7_PLERRENB, "PL error"}, + { F_CIM2MPS_INTF_PAR, "cim2mps interface parity"}, + { F_TCAM_CRC_SRAM, "tcam crc sram parity error"}, { F_HASHSRAM, "MPS hash SRAM parity error" }, { F_MATCHTCAM, "MPS match TCAM parity error" }, { F_MATCHSRAM, "MPS match SRAM parity error" }, @@ -6058,9 +7292,14 @@ static bool mps_intr_handler(struct adapter *adap, int arg, int flags) .actions = NULL, }; bool fatal = false; + if (chip_id(adap) >= CHELSIO_T7) + mps_tx_intr_info.details = t7_mpstx_int_cause_details; + else + mps_tx_intr_info.details = mps_tx_intr_details; fatal |= t4_handle_intr(adap, &mps_rx_perr_intr_info, 0, flags); if (chip_id(adap) > CHELSIO_T6) { + fatal |= t4_handle_intr(adap, &mps_rx_func_intr_info, 0, flags); fatal |= t4_handle_intr(adap, &mps_rx_perr_intr_info2, 0, flags); fatal |= t4_handle_intr(adap, &mps_rx_perr_intr_info3, 0, flags); fatal |= t4_handle_intr(adap, &mps_rx_perr_intr_info4, 0, flags); @@ -6076,6 +7315,7 @@ static bool mps_intr_handler(struct adapter *adap, int arg, int flags) fatal |= t4_handle_intr(adap, &t7_mps_trc_intr_info2, 0, flags); } else fatal |= t4_handle_intr(adap, &mps_trc_intr_info, 0, flags); + fatal |= t4_handle_intr(adap, &mps_stat_intr_info, 0, flags); fatal |= t4_handle_intr(adap, &mps_stat_sram_intr_info, 0, flags); fatal |= t4_handle_intr(adap, &mps_stat_tx_intr_info, 0, flags); fatal |= t4_handle_intr(adap, &mps_stat_rx_intr_info, 0, flags); @@ -6087,7 +7327,6 @@ static bool mps_intr_handler(struct adapter *adap, int arg, int flags) t4_read_reg(adap, A_MPS_INT_CAUSE); /* flush */ return (fatal); - } /* @@ -6096,7 +7335,7 @@ static bool mps_intr_handler(struct adapter *adap, int arg, int flags) static bool mem_intr_handler(struct adapter *adap, int idx, int flags) { static const char name[4][5] = { "EDC0", "EDC1", "MC0", "MC1" }; - unsigned int count_reg, v; + unsigned int count_reg = 0, v; static const struct intr_details mem_intr_details[] = { { F_ECC_UE_INT_CAUSE, "Uncorrectable ECC data error(s)" }, { F_ECC_CE_INT_CAUSE, "Correctable ECC data error(s)" }, @@ -6104,10 +7343,10 @@ static bool mem_intr_handler(struct adapter *adap, int idx, int flags) { 0 } }; static const struct intr_details t7_mem_intr_details[] = { - { F_DDRPHY_INT_CAUSE, "DDRPHY" }, - { F_DDRCTL_INT_CAUSE, "DDRCTL" }, - { F_T7_ECC_CE_INT_CAUSE, "Correctable ECC data error(s)" }, + { F_DDRPHY_INT_CAUSE, "DDR PHY" }, + { F_DDRCTL_INT_CAUSE, "DDR Controller" }, { F_T7_ECC_UE_INT_CAUSE, "Uncorrectable ECC data error(s)" }, + { F_T7_ECC_CE_INT_CAUSE, "Correctable ECC data error(s)" }, { F_PERR_INT_CAUSE, "FIFO parity error" }, { 0 } }; @@ -6115,8 +7354,8 @@ static bool mem_intr_handler(struct adapter *adap, int idx, int flags) struct intr_info ii = { .name = &rname[0], .fatal = F_PERR_INT_CAUSE | F_ECC_UE_INT_CAUSE, + .flags = IHF_CLR_DELAYED, .details = mem_intr_details, - .flags = 0, .actions = NULL, }; bool fatal = false; @@ -6137,15 +7376,6 @@ static bool mem_intr_handler(struct adapter *adap, int idx, int flags) count_reg = EDC_T5_REG(A_EDC_H_ECC_STATUS, i); } fatal |= t4_handle_intr(adap, &ii, 0, flags); - if (chip_id(adap) > CHELSIO_T6) { - snprintf(rname, sizeof(rname), "EDC%u_PAR_CAUSE", i); - ii.cause_reg = EDC_T5_REG(A_EDC_H_PAR_CAUSE, i); - ii.enable_reg = EDC_T5_REG(A_EDC_H_PAR_ENABLE, i); - ii.fatal = 0xffffffff; - ii.details = NULL; - ii.flags = IHF_FATAL_IFF_ENABLED; - fatal |= t4_handle_intr(adap, &ii, 0, flags); - } break; case MEM_MC1: if (is_t4(adap) || is_t6(adap)) @@ -6167,52 +7397,30 @@ static bool mem_intr_handler(struct adapter *adap, int idx, int flags) ii.enable_reg = MC_T7_REG(A_T7_MC_P_INT_ENABLE, i); ii.fatal = F_PERR_INT_CAUSE | F_T7_ECC_UE_INT_CAUSE; ii.details = t7_mem_intr_details; - count_reg = MC_T7_REG(A_T7_MC_P_ECC_STATUS, i); } fatal |= t4_handle_intr(adap, &ii, 0, flags); - - snprintf(rname, sizeof(rname), "MC%u_PAR_CAUSE", i); - if (is_t4(adap)) { - ii.cause_reg = A_MC_PAR_CAUSE; - ii.enable_reg = A_MC_PAR_ENABLE; - } else if (chip_id(adap) < CHELSIO_T7) { - ii.cause_reg = MC_REG(A_MC_P_PAR_CAUSE, i); - ii.enable_reg = MC_REG(A_MC_P_PAR_ENABLE, i); - } else { - ii.cause_reg = MC_T7_REG(A_T7_MC_P_PAR_CAUSE, i); - ii.enable_reg = MC_T7_REG(A_T7_MC_P_PAR_ENABLE, i); - } - ii.fatal = 0xffffffff; - ii.details = NULL; - ii.flags = IHF_FATAL_IFF_ENABLED; - fatal |= t4_handle_intr(adap, &ii, 0, flags); - - if (chip_id(adap) > CHELSIO_T6) { - snprintf(rname, sizeof(rname), "MC%u_DDRCTL_INT_CAUSE", i); - ii.cause_reg = MC_T7_REG(A_MC_P_DDRCTL_INT_CAUSE, i); - ii.enable_reg = MC_T7_REG(A_MC_P_DDRCTL_INT_ENABLE, i); - fatal |= t4_handle_intr(adap, &ii, 0, flags); - } break; } - v = t4_read_reg(adap, count_reg); - if (v != 0) { - if (G_ECC_UECNT(v) != 0 && !(flags & IHF_NO_SHOW)) { - CH_ALERT(adap, - " %s: %u uncorrectable ECC data error(s)\n", - name[idx], G_ECC_UECNT(v)); - } - if (G_ECC_CECNT(v) != 0 && !(flags & IHF_NO_SHOW)) { - if (idx <= MEM_EDC1) - t4_edc_err_read(adap, idx); - CH_WARN_RATELIMIT(adap, - " %s: %u correctable ECC data error(s)\n", - name[idx], G_ECC_CECNT(v)); + if (count_reg != 0) { + v = t4_read_reg(adap, count_reg); + if (v != 0) { + if (G_ECC_UECNT(v) != 0 && !(flags & IHF_NO_SHOW)) { + CH_ALERT(adap, + " %s: %u uncorrectable ECC data error(s)\n", + name[idx], G_ECC_UECNT(v)); + } + if (G_ECC_CECNT(v) != 0 && !(flags & IHF_NO_SHOW)) { + if (idx <= MEM_EDC1) + t4_edc_err_read(adap, idx); + CH_WARN_RATELIMIT(adap, + " %s: %u correctable ECC data error(s)\n", + name[idx], G_ECC_CECNT(v)); + } + t4_write_reg(adap, count_reg, 0xffffffff); } - t4_write_reg(adap, count_reg, 0xffffffff); } - + clear_int_cause_reg(adap, &ii, flags); return (fatal); } @@ -6231,14 +7439,13 @@ static bool ma_wrap_status(struct adapter *adap, int arg, int flags) return (false); } - /* * MA interrupt handler. */ static bool ma_intr_handler(struct adapter *adap, int arg, int flags) { static const struct intr_action ma_intr_actions[] = { - { F_MEM_WRAP_INT_CAUSE, 0, ma_wrap_status }, + { F_MEM_WRAP_INT_CAUSE, -1, ma_wrap_status }, { 0 }, }; static const struct intr_info ma_intr_info = { @@ -6284,10 +7491,29 @@ static bool ma_intr_handler(struct adapter *adap, int arg, int flags) */ static bool smb_intr_handler(struct adapter *adap, int arg, int flags) { - static const struct intr_details smb_int_cause_fields[] = { - { F_MSTTXFIFOPARINT, "SMB master Tx FIFO parity error" }, - { F_MSTRXFIFOPARINT, "SMB master Rx FIFO parity error" }, - { F_SLVFIFOPARINT, "SMB slave FIFO parity error" }, + static const struct intr_details smb_int_cause_details[] = { + { F_MSTTXFIFOPARINT, "Master has Parity Error in Tx Fifo" }, + { F_MSTRXFIFOPARINT, "Master has Parity Error in Rx Fifo" }, + { F_SLVFIFOPARINT, "Slave has Parity Error in Fifo" }, + { F_SLVUNEXPBUSSTOPINT, "Slave get Unexpected BusStop" }, + { F_SLVUNEXPBUSSTARTINT, "Slave get Unexpected BusStart" }, + { F_SLVCOMMANDCODEINVINT, "Slave get Invalid Command Code" }, + { F_SLVBYTECNTERRINT, "Slave get Erroneous ByteCount value" }, + { F_SLVUNEXPACKMSTINT, "Slave get Unexpected Ack from Master" }, + { F_SLVUNEXPNACKMSTINT, "Slave get Unexpected Nack from Master" }, + { F_SLVNOBUSSTOPINT, "Slave did not get Bus Stop" }, + { F_SLVNOREPSTARTINT, "Slave has no Repeated Start" }, + { F_SLVRXADDRINT, "Slave has Address Error" }, + { F_SLVRXPECERRINT, "Slave has Pec Error" }, + { F_SLVPREPTOARPINT, "PL has invalid request" }, + { F_SLVTIMEOUTINT, "Slave has timed out" }, + { F_SLVERRINT, "Slave detected error during the current transfer" }, + { F_SLVDONEINT, "Slave has completed the current transaction" }, + { F_SLVRXRDYINT, "Slave has received bytes to be processed by uP" }, + { F_MSTTIMEOUTINT, "Master has timed out" }, + { F_MSTNACKINT, "Master has detected a NAck on the transfer" }, + { F_MSTLOSTARBINT, "Master has lost arbitration all the timeline" }, + { F_MSTDONEINT, "Master has completed the current transaction" }, { 0 } }; static const struct intr_info smb_int_cause = { @@ -6296,9 +7522,10 @@ static bool smb_intr_handler(struct adapter *adap, int arg, int flags) .enable_reg = A_SMB_INT_ENABLE, .fatal = F_SLVFIFOPARINT | F_MSTRXFIFOPARINT | F_MSTTXFIFOPARINT, .flags = 0, - .details = smb_int_cause_fields, + .details = smb_int_cause_details, .actions = NULL, }; + return (t4_handle_intr(adap, &smb_int_cause, 0, flags)); } @@ -6308,6 +7535,7 @@ static bool smb_intr_handler(struct adapter *adap, int arg, int flags) static bool ncsi_intr_handler(struct adapter *adap, int arg, int flags) { static const struct intr_details ncsi_int_cause_fields[] = { + { F_CIM2NC_PERR, " CIM to NC parity error" }, { F_CIM_DM_PRTY_ERR, "NC-SI CIM parity error" }, { F_MPS_DM_PRTY_ERR, "NC-SI MPS parity error" }, { F_TXFIFO_PRTY_ERR, "NC-SI Tx FIFO parity error" }, @@ -6324,13 +7552,31 @@ static bool ncsi_intr_handler(struct adapter *adap, int arg, int flags) .details = ncsi_int_cause_fields, .actions = NULL, }; + static const struct intr_details ncsi_xgmac0_int_cause_details[] = { + { F_XAUIPCSDECERR, "RGMII PCS DEC Error" }, + { F_RGMIIRXFIFOOVERFLOW, "RGMII receive FIFO over flow" }, + { F_RGMIIRXFIFOUNDERFLOW, "RGMII receive FIFO under flow" }, + { F_RXPKTSIZEERROR, "Receive over size packet" }, + { F_WOLPATDETECTED, "WOL pattern detected" }, + { 0x000e0000, "Tx FIFO parity error" }, + { 0x0001c000, "Rx FIFO parity error" }, + { F_TXFIFO_UNDERRUN, "Tx FIFO underrun" }, + { F_RXFIFO_OVERFLOW, "Rx FIFO overflow" }, + { 0x00000f00, "XAUI SERDES BIST error" }, + { 0x000000f0, "XAUI SERDES receive low signal change" }, + { F_XAUIPCSCTCERR, "XAUI PCS CTC FIFO error" }, + { F_XAUIPCSALIGNCHANGE, "XAUI PCS alignment change" }, + { F_RGMIILINKSTSCHANGE, "RGMII link status change" }, + { F_XGM_INT, "XGM Core embedded interrupt (2nd level)" }, + { 0 } + }; static const struct intr_info ncsi_xgmac0_int_cause = { .name = "NCSI_XGMAC0_INT_CAUSE", .cause_reg = A_NCSI_XGMAC0_INT_CAUSE, .enable_reg = A_NCSI_XGMAC0_INT_ENABLE, .fatal = 0, .flags = 0, - .details = NULL, + .details = ncsi_xgmac0_int_cause_details, .actions = NULL, }; bool fatal = false; @@ -6346,32 +7592,71 @@ static bool ncsi_intr_handler(struct adapter *adap, int arg, int flags) */ static bool mac_intr_handler(struct adapter *adap, int port, int flags) { + static const struct intr_details mac_int_cause_cmn_details[] = { + { 0x3fffc0, "HSS PLL lock error " }, + { F_FLOCK_ASSERTED, "frequency lock coming out of DPLL sub-block is asserted" }, + { F_FLOCK_LOST, "frequency lock coming out of DPLL sub-blocki is lost." }, + { F_PHASE_LOCK_ASSERTED, "PHASE LOCK from DPLL sub-block is asserted" }, + { F_PHASE_LOCK_LOST, "PHASE LOCK from DPLL sub-block is lost." }, + { F_LOCK_ASSERTED, "Lock from frac_n PLL inside t7_clk module is asserted" }, + { F_LOCK_LOST, "Lock from frac_n PLL inside t7_clk module is lost " }, + { 0 } + }; static const struct intr_info mac_int_cause_cmn = { .name = "MAC_INT_CAUSE_CMN", .cause_reg = A_MAC_INT_CAUSE_CMN, .enable_reg = A_MAC_INT_EN_CMN, .fatal = 0, .flags = 0, - .details = NULL, + .details = mac_int_cause_cmn_details, .actions = NULL, }; + static const struct intr_details mac_perr_int_cause_mtip_details[] = { + { F_PERR_MAC0_TX, "MTIP MAC TX memory for MAC 0 (the 200G MAC for port 0)" }, + { F_PERR_MAC1_TX, "MTIP MAC TX memory for MAC 1 (the 200G MAC for port 1)" }, + { F_PERR_MAC2_TX, "MTIP MAC TX memory for MAC 2 (the 10-100G MAC for port 0)" }, + { F_PERR_MAC3_TX, "MTIP MAC TX memory for MAC 3 (the 10-100G MAC for port 1)" }, + { F_PERR_MAC4_TX, "MTIP MAC TX memory for MAC 4 (the 10-100G MAC for port 2)" }, + { F_PERR_MAC5_TX, "MTIP MAC TX memory for MAC 5 (the 10-100G MAC for port 3)" }, + { F_PERR_MAC0_RX, "MTIP MAC RX memory for MAC 0 (the 200G MAC for port 0)" }, + { F_PERR_MAC1_RX, "MTIP MAC RX memory for MAC 1 (the 200G MAC for port 1)" }, + { F_PERR_MAC2_RX, "MTIP MAC RX memory for MAC 2 (the 10-100G MAC for port 0)" }, + { F_PERR_MAC3_RX, "MTIP MAC RX memory for MAC 3 (the 10-100G MAC for port 1)" }, + { F_PERR_MAC4_RX, "MTIP MAC RX memory for MAC 4 (the 10-100G MAC for port 2)" }, + { F_PERR_MAC5_RX, "MTIP MAC RX memory for MAC 5 (the 10-100G MAC for port 3)" }, + { F_PERR_MAC_STAT_RX, "MTIP MAC RX statistics memory (1 for all 4 10-100G MACs)" }, + { F_PERR_MAC_STAT_TX, "MTIP MAC TX statistics memory (1 for all 4 10-100G MACs)" }, + { F_PERR_MAC_STAT_CAP, "MTIP MAC stat capture memory (1 for all 4 100G MACs)" }, + { 0 } + }; static const struct intr_info mac_perr_cause_mtip = { .name = "MAC_PERR_INT_CAUSE_MTIP", .cause_reg = A_MAC_PERR_INT_CAUSE_MTIP, .enable_reg = A_MAC_PERR_INT_EN_MTIP, .fatal = 0xffffffff, .flags = IHF_FATAL_IFF_ENABLED | IHF_IGNORE_IF_DISABLED, - .details = NULL, + .details = mac_perr_int_cause_mtip_details, .actions = NULL, }; - static const struct intr_info mac_cerr_cause_mtip = { - .name = "MAC_CERR_INT_CAUSE_MTIP", - .cause_reg = A_MAC_CERR_INT_CAUSE_MTIP, - .enable_reg = A_MAC_CERR_INT_EN_MTIP, - .fatal = 0, - .flags = 0, - .details = NULL, - .actions = NULL, + static const struct intr_details ios_intr_cause_quad0_details[] = { + { F_Q0_MAILBOX_INT_ASSERT, "Etopus Quad0 Mailbox interrupt cause" }, + { 0x00f00000, "Etopus Quad0 training failure" }, + { 0x000f0000, "Etopus Quad0 training complete" }, + { 0x0000f000, "Etopus Quad0 AN TX interrupt" }, + { 0x00000f00, "Etopus Quad0 signal detect assertion" }, + { 0x000000f0, "Etopus Quad0 CDR LOL assertion" }, + { 0x0000000f, "Etopus Quad0 LOS signal assertion" }, + { 0 } + }; + static const struct intr_details ios_intr_cause_quad1_details[] = { + { F_Q1_MAILBOX_INT_ASSERT, "Etopus Quad1 Mailbox interrupt cause" }, + { 0x00f00000, "Etopus Quad1 training failure" }, + { 0x000f0000, "Etopus Quad1 training complete" }, + { 0x0000f000, "Etopus Quad1 AN TX interrupt" }, + { 0x00000f00, "Etopus Quad1 signal detect assertion" }, + { 0x000000f0, "Etopus Quad1 CDR LOL assertion" }, + { 0x0000000f, "Etopus Quad1 LOS signal assertion" }, + { 0 } }; static const struct intr_info mac_ios_int_cause_quad0 = { .name = "MAC_IOS_INTR_CAUSE_QUAD0", @@ -6379,7 +7664,7 @@ static bool mac_intr_handler(struct adapter *adap, int port, int flags) .enable_reg = A_MAC_IOS_INTR_EN_QUAD0, .fatal = 0, .flags = 0, - .details = NULL, + .details = ios_intr_cause_quad0_details, .actions = NULL, }; static const struct intr_info mac_ios_int_cause_quad1 = { @@ -6388,7 +7673,7 @@ static bool mac_intr_handler(struct adapter *adap, int port, int flags) .enable_reg = A_MAC_IOS_INTR_EN_QUAD1, .fatal = 0, .flags = 0, - .details = NULL, + .details = ios_intr_cause_quad1_details, .actions = NULL, }; static const struct intr_details mac_intr_details[] = { @@ -6396,6 +7681,33 @@ static bool mac_intr_handler(struct adapter *adap, int port, int flags) { F_RXFIFO_PRTY_ERR, "MAC Rx FIFO parity error" }, { 0 } }; + static const struct intr_details t7_mac_int_cause_details[] = { + { F_MAC2MPS_PERR_CAUSE, "MPS2MAC Data parity error per port" }, + { F_MAC_PPS_INT_CAUSE, "One second interrupt based on PTP timer" }, + { F_MAC_TX_TS_AVAIL_INT_CAUSE, + "Time stamp is available for the last IEEE 1588 event frame" }, + { F_MAC_PATDETWAKE_INT_CAUSE, "Wake up pattern match packet received" }, + { F_MAC_MAGIC_WAKE_INT_CAUSE, "Magic packet received" }, + { F_MAC_SIGDETCHG_INT_CAUSE, "Signal Detect Change" }, + { F_MAC_PCS_LINK_GOOD_CAUSE, "PCS link good (xaui pcsr or 1g)" }, + { F_MAC_PCS_LINK_FAIL_CAUSE, "PCS Failure (xaui pcsr or 1g)" }, + { F_RXFIFOOVERFLOW, "RX Fifo Over flow error" }, + { F_MAC_REM_FAULT_INT_CAUSE, "Remote fault received by XGMAC" }, + { F_MAC_LOC_FAULT_INT_CAUSE, "Local fault received by XGMAC" }, + { F_MAC_LINK_DOWN_INT_CAUSE, "Link is down" }, + { F_MAC_LINK_UP_INT_CAUSE, "Link is up" }, + { F_MAC_AN_DONE_INT_CAUSE, "Autonegotiation complete" }, + { F_MAC_AN_PGRD_INT_CAUSE, "An page received" }, + { F_MAC_TXFIFO_ERR_INT_CAUSE, "Tx FIFO parity error" }, + { F_MAC_RXFIFO_ERR_INT_CAUSE, "Rx FIFO parity error" }, + { 0 } + }; + static const struct intr_details mac_perr_int_cause_details[] = { + { F_T6_PERR_PKT_RAM, "WoL packet data memory" }, + { F_T6_PERR_MASK_RAM, "WoL mask memory" }, + { F_T6_PERR_CRC_RAM, "WoL CRC memory" }, + { 0 } + }; char name[32]; struct intr_info ii; bool fatal = false; @@ -6428,7 +7740,7 @@ static bool mac_intr_handler(struct adapter *adap, int port, int flags) ii.enable_reg = T7_PORT_REG(port, A_T7_MAC_PORT_INT_EN); ii.fatal = 0xffffffff; ii.flags = IHF_FATAL_IFF_ENABLED; - ii.details = NULL; + ii.details = t7_mac_int_cause_details; ii.actions = NULL; } fatal |= t4_handle_intr(adap, &ii, 0, flags); @@ -6443,7 +7755,7 @@ static bool mac_intr_handler(struct adapter *adap, int port, int flags) ii.enable_reg = T7_PORT_REG(port, A_T7_MAC_PORT_PERR_INT_EN); ii.fatal = 0xffffffff; ii.flags = IHF_FATAL_IFF_ENABLED; - ii.details = NULL; + ii.details = mac_perr_int_cause_details; ii.actions = NULL; } else { ii.name = &name[0]; @@ -6484,7 +7796,6 @@ static bool mac_intr_handler(struct adapter *adap, int port, int flags) MPASS(chip_id(adap) >= CHELSIO_T7); fatal |= t4_handle_intr(adap, &mac_int_cause_cmn, 0, flags); fatal |= t4_handle_intr(adap, &mac_perr_cause_mtip, 0, flags); - fatal |= t4_handle_intr(adap, &mac_cerr_cause_mtip, 0, flags); fatal |= t4_handle_intr(adap, &mac_ios_int_cause_quad0, 0, flags); fatal |= t4_handle_intr(adap, &mac_ios_int_cause_quad1, 0, flags); @@ -6506,28 +7817,40 @@ static bool pl_timeout_status(struct adapter *adap, int arg, int flags) static bool plpl_intr_handler(struct adapter *adap, int arg, int flags) { static const struct intr_details plpl_int_cause_fields[] = { + { F_FATALPERR, "Fatal parity error" }, + { F_PERRVFID, "VFID_MAP parity error" }, + { 0 } + }; + static const struct intr_details t5_plpl_int_cause_fields[] = { { F_PL_BUSPERR, "Bus parity error" }, { F_FATALPERR, "Fatal parity error" }, { F_INVALIDACCESS, "Global reserved memory access" }, { F_TIMEOUT, "Bus timeout" }, { F_PLERR, "Module reserved access" }, - { F_PERRVFID, "VFID_MAP parity error" }, { 0 } }; static const struct intr_action plpl_int_cause_actions[] = { { F_TIMEOUT, -1, pl_timeout_status }, { 0 }, }; - static const struct intr_info plpl_int_cause = { + struct intr_info plpl_int_cause = { .name = "PL_PL_INT_CAUSE", .cause_reg = A_PL_PL_INT_CAUSE, .enable_reg = A_PL_PL_INT_ENABLE, - .fatal = F_FATALPERR | F_PERRVFID, - .flags = IHF_FATAL_IFF_ENABLED | IHF_IGNORE_IF_DISABLED, - .details = plpl_int_cause_fields, - .actions = plpl_int_cause_actions, + .fatal = F_FATALPERR, + .flags = IHF_FATAL_IFF_ENABLED, + .details = NULL, + .actions = NULL, }; + if (is_t4(adap)) { + plpl_int_cause.fatal |= F_PERRVFID; + plpl_int_cause.details = plpl_int_cause_fields; + } else { + plpl_int_cause.fatal |= F_INVALIDACCESS; + plpl_int_cause.details = t5_plpl_int_cause_fields; + plpl_int_cause.actions = plpl_int_cause_actions; + } return (t4_handle_intr(adap, &plpl_int_cause, 0, flags)); } @@ -6587,7 +7910,7 @@ static bool hma_intr_handler(struct adapter *adap, int idx, int flags) { F_RTF_INT_CAUSE, "Region translation fault" }, { F_PCIEMST_INT_CAUSE, "PCIe master access error" }, { F_MAMST_INT_CAUSE, "MA master access error" }, - { 1, "FIFO parity error" }, + { F_PERR_INT_CAUSE, "FIFO parity error" }, { 0 } }; static const struct intr_info hma_int_cause = { @@ -6682,15 +8005,6 @@ static bool gcache_intr_handler(struct adapter *adap, int idx, int flags) { F_ILLADDRACCESS0_INT_CAUSE, "GC0 illegal address access" }, { 0 } }; - static const struct intr_info gcache_perr_cause = { - .name = "GCACHE_PAR_CAUSE", - .cause_reg = A_GCACHE_PAR_CAUSE, - .enable_reg = A_GCACHE_PAR_ENABLE, - .fatal = 0xffffffff, - .flags = IHF_FATAL_IFF_ENABLED, - .details = NULL, - .actions = NULL, - }; static const struct intr_info gcache_int_cause = { .name = "GCACHE_INT_CAUSE", .cause_reg = A_GCACHE_INT_CAUSE, @@ -6700,12 +8014,7 @@ static bool gcache_intr_handler(struct adapter *adap, int idx, int flags) .details = gcache_int_cause_fields, .actions = NULL, }; - bool fatal = false; - - fatal |= t4_handle_intr(adap, &gcache_int_cause, 0, flags); - fatal |= t4_handle_intr(adap, &gcache_perr_cause, 0, flags); - - return (fatal); + return (t4_handle_intr(adap, &gcache_int_cause, 0, flags)); } /* @@ -6713,67 +8022,218 @@ static bool gcache_intr_handler(struct adapter *adap, int idx, int flags) */ static bool arm_intr_handler(struct adapter *adap, int idx, int flags) { + static const struct intr_details arm_perr_int_cause0_details[] = { + { F_INIC_WRDATA_FIFO_PERR, "INT CAUSE for INIC Write Data Fifo Parity Error" }, + { F_INIC_RDATA_FIFO_PERR, "INT CAUSE for INIC Read Data Fifo Parity Error" }, + { F_MSI_MEM_PERR, "INT CAUSE for MSI Memory Parity Error" }, + { 0x18000000, "INT CAUSE for ARM Doorbell SRAM Parity Error" }, + { F_EMMC_FIFOPARINT, "INT CAUSE for EMMC Fifo Parity Interrupt" }, + { F_ICB_RAM_PERR, "INT CAUSE for ICB SRAM Parity Error" }, + { F_MESS2AXI4_WRFIFO_PERR, "INT CAUSE for Message2AXI4 Write FIFO Parity Error" }, + { F_RC_WFIFO_OUTPERR, "INT CAUSE for AXI2RC Write FIFO Parity Error" }, + { 0x00600000, "INT CAUSE for AXI2RC SRAM Parity Error" }, + { F_MSI_FIFO_PAR_ERR, "INT CAUSE for APB2MSI FIFO Parity Error" }, + { F_INIC2MA_INTFPERR, "INT CAUSE for INIC to MA Interface Parity Error" }, + { F_RDATAFIFO0_PERR, "INT CAUSE for AXI2MA M0 Read Data Fifo Parity Error" }, + { F_RDATAFIFO1_PERR, "INT CAUSE for AXI2MA M1 Read Data Fifo Parity Error" }, + { F_WRDATAFIFO0_PERR, "INT CAUSE for AXI2MA M0 Write Data Fifo Parity Error" }, + { F_WRDATAFIFO1_PERR, "INT CAUSE for AXI2MA M1 Write Data Fifo Parity Error" }, + { F_WR512DATAFIFO0_PERR, + "INT CAUSE for AXI2MA M0 Write Data 512b Fifo Parity Error" }, + { F_WR512DATAFIFO1_PERR, + "INT CAUSE for AXI2MA M1 Write Data 512b Fifo Parity Error" }, + { F_ROBUFF_PARERR3, "INT CAUSE for Reorder Buffer Parity Error" }, + { F_ROBUFF_PARERR2, "INT CAUSE for Reorder Buffer Parity Error" }, + { F_ROBUFF_PARERR1, "INT CAUSE for Reorder Buffer Parity Error" }, + { F_ROBUFF_PARERR0, "INT CAUSE for Reorder Buffer Parity Error" }, + { F_MA2AXI_REQDATAPARERR, "INT CAUSE for MA2AXI Request Data Parity Error" }, + { F_MA2AXI_REQCTLPARERR, "INT CAUSE for MA2AXI Request Control Parity Error" }, + { F_MA_RSPPERR, "INT CAUSE for MA Response Parity Error" }, + { F_PCIE2MA_REQCTLPARERR, "INT CAUSE for PCIe to MA Control Parity Error" }, + { F_PCIE2MA_REQDATAPARERR, "INT CAUSE for PCIe to MA Data Parity Error" }, + { F_INIC2MA_REQCTLPARERR, "INT CAUSE for INIC to MA Control Parity Error" }, + { F_INIC2MA_REQDATAPARERR, "INT CAUSE for INIC to MA Data Parity Error" }, + { F_MA_RSPUE, "INT CAUSE for MA Response Uncorrectable Error" }, + { F_APB2PL_RSPDATAPERR, "INT CAUSE for APB2PL Response Data Parity Error" }, + { 0 } + }; static const struct intr_info arm_perr_cause0 = { .name = "ARM_PERR_INT_CAUSE0", .cause_reg = A_ARM_PERR_INT_CAUSE0, .enable_reg = A_ARM_PERR_INT_ENB0, .fatal = 0xffffffff, .flags = IHF_IGNORE_IF_DISABLED | IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = arm_perr_int_cause0_details, .actions = NULL, }; + static const struct intr_details arm_perr_int_cause1_details[] = { + { F_ARWFIFO0_PERR, "AXI2MA M0 Read-Write FIFO Parity Error" }, + { F_ARWFIFO1_PERR, "AXI2MA M1 Read-Write FIFO Parity Error" }, + { F_ARWIDFIFO0_PERR, "AXI2MA M0 Read-Write ID FIFO Parity Error" }, + { F_ARWIDFIFO1_PERR, "AXI2MA M1 Read-Write ID FIFO Parity Error" }, + { F_ARIDFIFO0_PERR, "AXI2MA M0 Read FIFO Parity Error" }, + { F_ARIDFIFO1_PERR, "AXI2MA M1 Read FIFO Parity Error" }, + { F_RRSPADDR_FIFO0_PERR, "AXI2MA M0 Read Response Address FIFO Parity Error" }, + { F_RRSPADDR_FIFO1_PERR, "AXI2MA M1 Read Response Address FIFO Parity Error" }, + { F_WRSTRB_FIFO0_PERR, "AXI2MA M0 Write Strobe FIFO Parity Error" }, + { F_WRSTRB_FIFO1_PERR, "AXI2MA M1 Write Strobe FIFO Parity Error" }, + { F_MA2AXI_RSPDATAPARERR, "MA2AXI Response FIFO Parity Error" }, + { F_MA2AXI_DATA_PAR_ERR, "MA2AXI Write Data FIFO Parity Error" }, + { F_MA2AXI_WR_ORD_FIFO_PARERR, "MA2AXI Ordered Write Data FIFO Parity Error" }, + { F_NVME_DB_EMU_TRACKER_FIFO_PERR, "NVMe DB Emulation Tracker FIFO Parity Error" }, + { F_NVME_DB_EMU_QUEUE_AW_ADDR_FIFO_PERR, + "NVMe DB Emulation Queue AW Addr Parity Error" }, + { F_NVME_DB_EMU_INTERRUPT_OFFSET_FIFO_PERR, + "NVMe DB Emulation Interrupt Offset FIFO Parity Error" }, + { F_NVME_DB_EMU_ID_FIFO0_PERR, "NVMe DB Emulation ID FIFO0 Parity Error" }, + { F_NVME_DB_EMU_ID_FIFO1_PERR, "NVMe DB Emulation ID FIFO1 Parity Error" }, + { F_RC_ARWFIFO_PERR, "AXI2RC Read-Write FIFO Parity Error" }, + { F_RC_ARIDBURSTADDRFIFO_PERR, + "AXI2RC Read ID, Burst and Address FIFO Parity Error" }, + { F_RC_CFG_FIFO_PERR, "AXI2RC Config FIFO Parity Error" }, + { F_RC_RSPFIFO_PERR, "AXI2RC Response Parity Error" }, + { F_INIC_ARIDFIFO_PERR, "CCI2INIC Read ID FIFO Parity Error" }, + { F_INIC_ARWFIFO_PERR, "CCI2INIC Read-Write FIFO ontrol Parity Error" }, + { F_AXI2MA_128_RD_ADDR_SIZE_FIFO_PERR, + "AXI2MA(CCI2INIC) Read Address Size FIFO Parity Error" }, + { F_AXI2RC_128_RD_ADDR_SIZE_FIFO_PERR, + "AXI2RC Read Address Size FIFO Parity Error" }, + { F_ARM_MA_512B_RD_ADDR_SIZE_FIFO0_PERR, + "ARM_MA_512b Read Address Size FIFO0 Parity Error" }, + { F_ARM_MA_512B_RD_ADDR_SIZE_FIFO1_PERR, + "ARM_MA_512b Read Address Size FIFO1 Parity Error" }, + { F_ARM_MA_512B_ARB_FIFO_PERR, "ARM_MA_512b Arbiter FIFO Parity Error" }, + { F_PCIE_INIC_MA_ARB_FIFO_PERR, "PCIe-INIC Arbiter FIFO Parity Error" }, + { F_PCIE_INIC_ARB_RSPPERR, "PCIe-INIC Arbiter Response Parity Error" }, + { F_ITE_CACHE_PERR, "GIC500 ITE Cache SRAM Parity Error" }, + { 0 } + }; static const struct intr_info arm_perr_cause1 = { .name = "ARM_PERR_INT_CAUSE1", .cause_reg = A_ARM_PERR_INT_CAUSE1, .enable_reg = A_ARM_PERR_INT_ENB1, .fatal = 0xffffffff, .flags = IHF_IGNORE_IF_DISABLED | IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = arm_perr_int_cause1_details, .actions = NULL, }; + static const struct intr_details arm_perr_int_cause2_details[] = { + { F_INIC_WSTRB_FIFO_PERR, "AXI2MA_128 INIC Write Strobe FIFO Parity Error" }, + { F_INIC_BID_FIFO_PERR, "AXI2MA_128 INIC bID FIFO Parity Error" }, + { F_CC_SRAM_PKA_PERR, "CryptoCell ram_pka_wrapper FIFO Parity Error" }, + { F_CC_SRAM_SEC_PERR, "CryptoCell sec_sram_wrapper FIFO Parity Error" }, + { F_MESS2AXI4_PARERR, "Message2AXI4 IBQ I/P Interface Parity Error" }, + { F_CCI2INIC_INTF_PARERR, "CCI2INIC Response Interface Parity Error" }, + { 0 } + }; static const struct intr_info arm_perr_cause2 = { .name = "ARM_PERR_INT_CAUSE2", .cause_reg = A_ARM_PERR_INT_CAUSE2, .enable_reg = A_ARM_PERR_INT_ENB2, .fatal = 0xffffffff, .flags = IHF_IGNORE_IF_DISABLED | IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = arm_perr_int_cause2_details, .actions = NULL, }; + static const struct intr_details arm_cerr_int_cause0_details[] = { + { F_WRDATA_FIFO0_CERR, "AXI2MA M0 Write Data FIFO Correctable Error" }, + { F_WRDATA_FIFO1_CERR, "AXI2MA M1 Write Data FIFO Correctable Error" }, + { F_WR512DATAFIFO0_CERR, "AXI2MA M0 Write Data 512b FIFO Correctable Error" }, + { F_WR512DATAFIFO1_CERR, "AXI2MA M1 Write Data 512b FIFO Correctable Error" }, + { F_RDATAFIFO0_CERR, "AXI2MA M0 Read Data FIFO Correctable Error" }, + { F_RDATAFIFO1_CERR, "AXI2MA M1 Read Data FIFO Correctable Error" }, + { F_ROBUFF_CORERR0, "Reorder Buffer Correctable Error" }, + { F_ROBUFF_CORERR1, "Reorder Buffer Correctable Error" }, + { F_ROBUFF_CORERR2, "Reorder Buffer Correctable Error" }, + { F_ROBUFF_CORERR3, "Reorder Buffer Correctable Error" }, + { F_MA2AXI_RSPDATACORERR, "MA2AXI Response FIFO Correctable Error" }, + { 0x00180000, "AXI2RC SRAM Correctable Error" }, + { F_RC_WFIFO_OUTCERR, "AXI2RC Write FIFO Correctable Error" }, + { F_RC_RSPFIFO_CERR, "AXI2RC Response Correctable Error" }, + { F_MSI_MEM_CERR, "MSI Memory FIFO Correctable Error" }, + { F_INIC_WRDATA_FIFO_CERR, "INIC Write Data FIFO Correctable Error" }, + { F_INIC_RDATAFIFO_CERR, "INIC Read Data FIFO Correctable Error" }, + { 0x00003000, "ARM Doorbell SRAM Correctable Error" }, + { F_ICB_RAM_CERR, "ICB SRAM Parity Error" }, + { F_CC_SRAM_PKA_CERR, "CryptoCell ram_pka_wrapper FIFO Correctable Error" }, + { F_CC_SRAM_SEC_CERR, "CryptoCell sec_sram_wrapper FIFO Correctable Error" }, + { 0 } + }; static const struct intr_info arm_cerr_cause0 = { - .name = "ARM_CERR_INT_CAUSE", + .name = "ARM_CERR_INT_CAUSE0", .cause_reg = A_ARM_CERR_INT_CAUSE0, .enable_reg = A_ARM_CERR_INT_ENB0, .fatal = 0, .flags = IHF_IGNORE_IF_DISABLED | IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = arm_cerr_int_cause0_details, .actions = NULL, }; + static const struct intr_details arm_err_int_cause0_details[] = { + { F_STRB0_ERROR, "Strobe Error from AXI2MA 0" }, + { F_STRB1_ERROR, "Strobe Error from AXI2MA 1" }, + { F_PCIE_INIC_MA_ARB_INV_RSP_TAG, "Invalid Response Tag for PCIE-INIc MA ARB" }, + { F_ERROR0_NOCMD_DATA, "AXI2MA 0 No Command Data Error" }, + { F_ERROR1_NOCMD_DATA, "AXI2MA 1 No Command Data Error" }, + { F_INIC_STRB_ERROR, "AXI2MA_128b INIC Strobe Error" }, + { 0 } + }; static const struct intr_info arm_err_cause0 = { - .name = "ARM_ERR_INT_CAUSE", + .name = "ARM_ERR_INT_CAUSE0", .cause_reg = A_ARM_ERR_INT_CAUSE0, .enable_reg = A_ARM_ERR_INT_ENB0, .fatal = 0, .flags = IHF_IGNORE_IF_DISABLED | IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = arm_err_int_cause0_details, .actions = NULL, }; + + static const struct intr_details arm_peripheral_int_cause_details[] = { + { F_TIMER_INT, "TIMER_INT" }, + { F_NVME_INT, "NVME_INT" }, + { F_EMMC_WAKEUP_INT, "EMMC_WAKEUP_INT" }, + { F_EMMC_INT, "EMMC_INT" }, + { F_USB_MC_INT, "USB_MC_INT" }, + { F_USB_DMA_INT, "USB_DMA_INT" }, + { 0 } + }; static const struct intr_info arm_periph_cause = { .name = "ARM_PERIPHERAL_INT_CAUSE", .cause_reg = A_ARM_PERIPHERAL_INT_CAUSE, .enable_reg = A_ARM_PERIPHERAL_INT_ENB, .fatal = 0, .flags = IHF_IGNORE_IF_DISABLED | IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = arm_peripheral_int_cause_details, .actions = NULL, }; + static const struct intr_details arm_arm_uart_int_cause_details[] = { + { F_RX_FIFO_NOT_EMPTY, "intcause for uart rx fifo" }, + { F_TX_FIFO_EMPTY, "intcause for uart tx fifo" }, + { 0 } + }; + static const struct intr_info arm_uart_cause = { + .name = "ARM_ARM_UART_INT_CAUSE", + .cause_reg = A_ARM_ARM_UART_INT_CAUSE, + .enable_reg = A_ARM_ARM_UART_INT_EN, + .fatal = 0, + .flags = IHF_FATAL_IFF_ENABLED, + .details = arm_arm_uart_int_cause_details, + .actions = NULL, + }; + static const struct intr_details arm_nvme_db_emu_int_cause_details[] = { + { F_INVALID_BRESP, "Invalid CCI Write Response" }, + { F_DATA_LEN_OF, + "Incorrect Write Request to be written to incorrect Devices/Regions" }, + { F_INVALID_EMU_ADDR, "Invalid Emulation Address Range Configuration" }, + { F_INVALID_AXI_ADDR_CFG, "Invalid AXI Address Configuration" }, + { 0 } + }; static const struct intr_info arm_nvme_db_emu_cause = { .name = "ARM_NVME_DB_EMU_INT_CAUSE", .cause_reg = A_ARM_NVME_DB_EMU_INT_CAUSE, .enable_reg = A_ARM_NVME_DB_EMU_INT_ENABLE, .fatal = 0, .flags = IHF_IGNORE_IF_DISABLED | IHF_FATAL_IFF_ENABLED, - .details = NULL, + .details = arm_nvme_db_emu_int_cause_details, .actions = NULL, }; bool fatal = false; @@ -6785,12 +8245,13 @@ static bool arm_intr_handler(struct adapter *adap, int idx, int flags) fatal |= t4_handle_intr(adap, &arm_err_cause0, 0, flags); fatal |= t4_handle_intr(adap, &arm_periph_cause, 0, flags); fatal |= t4_handle_intr(adap, &arm_nvme_db_emu_cause, 0, flags); + fatal |= t4_handle_intr(adap, &arm_uart_cause, 0, flags); return (fatal); } static inline uint32_t -get_perr_ucause(struct adapter *sc, const struct intr_info *ii) +get_ucause(struct adapter *sc, const struct intr_info *ii) { uint32_t cause; @@ -6977,7 +8438,8 @@ bool t4_slow_intr_handler(struct adapter *adap, int flags) .cause_reg = A_PL_PERR_CAUSE, .enable_reg = A_PL_PERR_ENABLE, .fatal = 0xffffffff, - .flags = IHF_IGNORE_IF_DISABLED | IHF_FATAL_IFF_ENABLED, + .flags = IHF_IGNORE_IF_DISABLED | IHF_FATAL_IFF_ENABLED | + IHF_CLR_DELAYED, .details = pl_int_cause_fields, .actions = NULL, }; @@ -7117,7 +8579,8 @@ bool t4_slow_intr_handler(struct adapter *adap, int flags) .cause_reg = A_PL_PERR_CAUSE, .enable_reg = A_PL_PERR_ENABLE, .fatal = 0xffffffff, - .flags = IHF_IGNORE_IF_DISABLED | IHF_FATAL_IFF_ENABLED, + .flags = IHF_IGNORE_IF_DISABLED | IHF_FATAL_IFF_ENABLED | + IHF_CLR_DELAYED, .details = t7_pl_perr_cause_fields, .actions = NULL, }; @@ -7125,23 +8588,19 @@ bool t4_slow_intr_handler(struct adapter *adap, int flags) uint32_t perr; if (chip_id(adap) < CHELSIO_T7) { - perr = get_perr_ucause(adap, &pl_perr_cause); - fatal |= t4_handle_intr(adap, &pl_perr_cause, 0, - flags & ~(IHF_CLR_ALL_SET | IHF_CLR_ALL_UNIGNORED)); + perr = get_ucause(adap, &pl_perr_cause); + fatal |= t4_handle_intr(adap, &pl_perr_cause, 0, flags); fatal |= t4_handle_intr(adap, &pl_int_cause, t4_perr_to_ic(adap, perr), flags); - t4_write_reg(adap, pl_perr_cause.cause_reg, perr); - (void)t4_read_reg(adap, pl_perr_cause.cause_reg); + clear_int_cause_reg(adap, &pl_perr_cause, flags); } else { - perr = get_perr_ucause(adap, &t7_pl_perr_cause); - fatal |= t4_handle_intr(adap, &t7_pl_perr_cause, 0, - flags & ~(IHF_CLR_ALL_SET | IHF_CLR_ALL_UNIGNORED)); + perr = get_ucause(adap, &t7_pl_perr_cause); + fatal |= t4_handle_intr(adap, &t7_pl_perr_cause, 0, flags); fatal |= t4_handle_intr(adap, &t7_pl_int_cause, t7_perr_to_ic1(perr), flags); fatal |= t4_handle_intr(adap, &t7_pl_int_cause2, t7_perr_to_ic2(perr), flags); - t4_write_reg(adap, t7_pl_perr_cause.cause_reg, perr); - (void)t4_read_reg(adap, t7_pl_perr_cause.cause_reg); + clear_int_cause_reg(adap, &t7_pl_perr_cause, flags); } return (fatal); } diff --git a/sys/dev/ffec/if_ffec.c b/sys/dev/ffec/if_ffec.c index 17fab283fc81..cf171a854406 100644 --- a/sys/dev/ffec/if_ffec.c +++ b/sys/dev/ffec/if_ffec.c @@ -850,7 +850,7 @@ ffec_rxfinish_onebuf(struct ffec_softc *sc, int len) * biggest header is, instead of the whole 1530ish-byte frame. */ if (sc->fecflags & FECFLAG_RACC) { - m->m_data = mtod(m, uint8_t *) + 2; + m_adj(m, 2); } else { src = mtod(m, uint8_t*); dst = src - ETHER_ALIGN; diff --git a/sys/dev/sound/macio/onyx.c b/sys/dev/sound/macio/onyx.c index f4f825a705cc..5ba22dd7c495 100644 --- a/sys/dev/sound/macio/onyx.c +++ b/sys/dev/sound/macio/onyx.c @@ -268,38 +268,21 @@ static int onyx_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) { struct onyx_softc *sc; - struct mtx *mixer_lock; - int locked; uint8_t l, r; sc = device_get_softc(mix_getdevinfo(m)); - mixer_lock = mixer_get_lock(m); - locked = mtx_owned(mixer_lock); switch (dev) { case SOUND_MIXER_VOLUME: - - /* - * We need to unlock the mixer lock because iicbus_transfer() - * may sleep. The mixer lock itself is unnecessary here - * because it is meant to serialize hardware access, which - * is taken care of by the I2C layer, so this is safe. - */ if (left > 100 || right > 100) return (0); l = left + 128; r = right + 128; - if (locked) - mtx_unlock(mixer_lock); - onyx_write(sc, PCM3052_REG_LEFT_ATTN, l); onyx_write(sc, PCM3052_REG_RIGHT_ATTN, r); - if (locked) - mtx_lock(mixer_lock); - return (left | (right << 8)); } diff --git a/sys/dev/sound/macio/snapper.c b/sys/dev/sound/macio/snapper.c index f14009f447a8..ed83990d563b 100644 --- a/sys/dev/sound/macio/snapper.c +++ b/sys/dev/sound/macio/snapper.c @@ -436,14 +436,10 @@ static int snapper_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) { struct snapper_softc *sc; - struct mtx *mixer_lock; - int locked; u_int l, r; u_char reg[6]; sc = device_get_softc(mix_getdevinfo(m)); - mixer_lock = mixer_get_lock(m); - locked = mtx_owned(mixer_lock); if (left > 100 || right > 100) return (0); @@ -460,21 +456,8 @@ snapper_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) reg[4] = (r & 0x00ff00) >> 8; reg[5] = r & 0x0000ff; - /* - * We need to unlock the mixer lock because iicbus_transfer() - * may sleep. The mixer lock itself is unnecessary here - * because it is meant to serialize hardware access, which - * is taken care of by the I2C layer, so this is safe. - */ - - if (locked) - mtx_unlock(mixer_lock); - snapper_write(sc, SNAPPER_VOLUME, reg); - if (locked) - mtx_lock(mixer_lock); - return (left | (right << 8)); } diff --git a/sys/dev/sound/macio/tumbler.c b/sys/dev/sound/macio/tumbler.c index bd40ea6b4f6b..89af4434e7fe 100644 --- a/sys/dev/sound/macio/tumbler.c +++ b/sys/dev/sound/macio/tumbler.c @@ -383,14 +383,10 @@ static int tumbler_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) { struct tumbler_softc *sc; - struct mtx *mixer_lock; - int locked; u_int l, r; u_char reg[6]; sc = device_get_softc(mix_getdevinfo(m)); - mixer_lock = mixer_get_lock(m); - locked = mtx_owned(mixer_lock); switch (dev) { case SOUND_MIXER_VOLUME: @@ -407,21 +403,8 @@ tumbler_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) reg[4] = (r & 0x00ff00) >> 8; reg[5] = r & 0x0000ff; - /* - * We need to unlock the mixer lock because iicbus_transfer() - * may sleep. The mixer lock itself is unnecessary here - * because it is meant to serialize hardware access, which - * is taken care of by the I2C layer, so this is safe. - */ - - if (locked) - mtx_unlock(mixer_lock); - tumbler_write(sc, TUMBLER_VOLUME, reg); - if (locked) - mtx_lock(mixer_lock); - return (left | (right << 8)); } diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c index c1e0d8d3bc52..a0ee16a14386 100644 --- a/sys/dev/sound/pcm/channel.c +++ b/sys/dev/sound/pcm/channel.c @@ -2177,7 +2177,7 @@ chn_syncstate(struct pcm_channel *c) if (c->feederflags & (1 << FEEDER_EQ)) { struct pcm_feeder *f; - int treble, bass, state; + int treble, bass; /* CHN_UNLOCK(c); */ treble = mix_get(m, SOUND_MIXER_TREBLE); @@ -2209,15 +2209,6 @@ chn_syncstate(struct pcm_channel *c) device_printf(c->dev, "EQ: Failed to set preamp -- %d\n", d->eqpreamp); - if (d->flags & SD_F_EQ_BYPASSED) - state = FEEDEQ_BYPASS; - else if (d->flags & SD_F_EQ_ENABLED) - state = FEEDEQ_ENABLE; - else - state = FEEDEQ_DISABLE; - if (FEEDER_SET(f, FEEDEQ_STATE, state) != 0) - device_printf(c->dev, - "EQ: Failed to set state -- %d\n", state); } } } diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c index 0f76791448ca..bc92a3fbd530 100644 --- a/sys/dev/sound/pcm/dsp.c +++ b/sys/dev/sound/pcm/dsp.c @@ -728,8 +728,7 @@ dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, if (d->mixer_dev != NULL) { PCM_ACQUIRE_QUICK(d); - ret = mixer_ioctl_cmd(d->mixer_dev, cmd, arg, -1, td, - MIXER_CMD_DIRECT); + ret = mixer_ioctl_cmd(d->mixer_dev, cmd, arg, -1, td); PCM_RELEASE_QUICK(d); } else ret = EBADF; @@ -1526,8 +1525,7 @@ dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, if (d->mixer_dev != NULL) { PCM_ACQUIRE_QUICK(d); - ret = mixer_ioctl_cmd(d->mixer_dev, xcmd, arg, -1, td, - MIXER_CMD_DIRECT); + ret = mixer_ioctl_cmd(d->mixer_dev, xcmd, arg, -1, td); PCM_RELEASE_QUICK(d); } else ret = ENOTSUP; @@ -1539,8 +1537,7 @@ dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, case SNDCTL_DSP_SET_RECSRC: if (d->mixer_dev != NULL) { PCM_ACQUIRE_QUICK(d); - ret = mixer_ioctl_cmd(d->mixer_dev, cmd, arg, -1, td, - MIXER_CMD_DIRECT); + ret = mixer_ioctl_cmd(d->mixer_dev, cmd, arg, -1, td); PCM_RELEASE_QUICK(d); } else ret = ENOTSUP; diff --git a/sys/dev/sound/pcm/feeder.h b/sys/dev/sound/pcm/feeder.h index e1e91d468455..127b479cd7c9 100644 --- a/sys/dev/sound/pcm/feeder.h +++ b/sys/dev/sound/pcm/feeder.h @@ -119,11 +119,6 @@ enum { FEEDEQ_TREBLE, FEEDEQ_BASS, FEEDEQ_PREAMP, - FEEDEQ_STATE, - FEEDEQ_DISABLE, - FEEDEQ_ENABLE, - FEEDEQ_BYPASS, - FEEDEQ_UNKNOWN }; int feeder_eq_validrate(uint32_t); diff --git a/sys/dev/sound/pcm/feeder_chain.c b/sys/dev/sound/pcm/feeder_chain.c index 4fc846f77496..35bb12a062ec 100644 --- a/sys/dev/sound/pcm/feeder_chain.c +++ b/sys/dev/sound/pcm/feeder_chain.c @@ -725,7 +725,7 @@ feeder_chain(struct pcm_channel *c) /* Soft EQ only applicable for PLAY. */ if (cdesc.dummy == 0 && - c->direction == PCMDIR_PLAY && (d->flags & SD_F_EQ) && + c->direction == PCMDIR_PLAY && (d->flags & SD_F_EQ_ENABLED) && (((d->flags & SD_F_EQ_PC) && !(c->flags & CHN_F_HAS_VCHAN)) || (!(d->flags & SD_F_EQ_PC) && !(c->flags & CHN_F_VIRTUAL)))) diff --git a/sys/dev/sound/pcm/feeder_eq.c b/sys/dev/sound/pcm/feeder_eq.c index 4cf9d4f6695f..0a28dfa1ba17 100644 --- a/sys/dev/sound/pcm/feeder_eq.c +++ b/sys/dev/sound/pcm/feeder_eq.c @@ -3,7 +3,7 @@ * * Copyright (c) 2008-2009 Ariff Abdullah <ariff@FreeBSD.org> * All rights reserved. - * Copyright (c) 2024-2025 The FreeBSD Foundation + * Copyright (c) 2024-2026 The FreeBSD Foundation * * Portions of this software were developed by Christos Margiolis * <christos@FreeBSD.org> under sponsorship from the FreeBSD Foundation. @@ -122,7 +122,6 @@ struct feed_eq_info { uint32_t rate; uint32_t align; int32_t preamp; - int state; }; #if !defined(_KERNEL) && defined(FEEDEQ_ERR_CLIP) @@ -148,19 +147,6 @@ feed_eq_biquad(struct feed_eq_info *info, uint8_t *dst, uint32_t count, pmul = feed_eq_preamp[info->preamp].mul; pshift = feed_eq_preamp[info->preamp].shift; - if (info->state == FEEDEQ_DISABLE) { - j = count * info->channels; - dst += j * AFMT_BPS(fmt); - do { - dst -= AFMT_BPS(fmt); - v = pcm_sample_read(dst, fmt); - v = ((intpcm64_t)pmul * v) >> pshift; - pcm_sample_write(dst, v, fmt); - } while (--j != 0); - - return; - } - treble = &(info->coeff[info->treble.gain].treble); bass = &(info->coeff[info->bass.gain].bass); @@ -290,7 +276,6 @@ feed_eq_init(struct pcm_feeder *f) info->treble.gain = FEEDEQ_L2GAIN(50); info->bass.gain = FEEDEQ_L2GAIN(50); info->preamp = FEEDEQ_PREAMP2IDX(FEEDEQ_PREAMP_DEFAULT); - info->state = FEEDEQ_UNKNOWN; f->data = info; @@ -316,8 +301,6 @@ feed_eq_set(struct pcm_feeder *f, int what, int value) if (feeder_eq_validrate(value) == 0) return (EINVAL); info->rate = (uint32_t)value; - if (info->state == FEEDEQ_UNKNOWN) - info->state = FEEDEQ_ENABLE; return (feed_eq_setup(info)); case FEEDEQ_TREBLE: case FEEDEQ_BASS: @@ -333,13 +316,6 @@ feed_eq_set(struct pcm_feeder *f, int what, int value) return (EINVAL); info->preamp = FEEDEQ_PREAMP2IDX(value); break; - case FEEDEQ_STATE: - if (!(value == FEEDEQ_BYPASS || value == FEEDEQ_ENABLE || - value == FEEDEQ_DISABLE)) - return (EINVAL); - info->state = value; - feed_eq_reset(info); - break; default: return (EINVAL); } @@ -370,15 +346,6 @@ feed_eq_feed(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, info = f->data; - /* - * 3 major states: - * FEEDEQ_BYPASS - Bypass entirely, nothing happened. - * FEEDEQ_ENABLE - Preamp+biquad filtering. - * FEEDEQ_DISABLE - Preamp only. - */ - if (info->state == FEEDEQ_BYPASS) - return (FEEDER_FEED(f->source, c, b, count, source)); - dst = b; count = SND_FXROUND(count, info->align); @@ -472,8 +439,6 @@ static int sysctl_dev_pcm_eq(SYSCTL_HANDLER_ARGS) { struct snddev_info *d; - struct pcm_channel *c; - struct pcm_feeder *f; int err, val, oval; d = oidp->oid_arg1; @@ -482,9 +447,7 @@ sysctl_dev_pcm_eq(SYSCTL_HANDLER_ARGS) PCM_LOCK(d); PCM_WAIT(d); - if (d->flags & SD_F_EQ_BYPASSED) - val = 2; - else if (d->flags & SD_F_EQ_ENABLED) + if (d->flags & SD_F_EQ_ENABLED) val = 1; else val = 0; @@ -495,30 +458,17 @@ sysctl_dev_pcm_eq(SYSCTL_HANDLER_ARGS) err = sysctl_handle_int(oidp, &val, 0, req); if (err == 0 && req->newptr != NULL && val != oval) { - if (!(val == 0 || val == 1 || val == 2)) { + if (!(val == 0 || val == 1)) { PCM_RELEASE_QUICK(d); return (EINVAL); } PCM_LOCK(d); - d->flags &= ~(SD_F_EQ_ENABLED | SD_F_EQ_BYPASSED); - if (val == 2) { - val = FEEDEQ_BYPASS; - d->flags |= SD_F_EQ_BYPASSED; - } else if (val == 1) { - val = FEEDEQ_ENABLE; + if (val == 1) d->flags |= SD_F_EQ_ENABLED; - } else - val = FEEDEQ_DISABLE; - - CHN_FOREACH(c, d, channels.pcm.busy) { - CHN_LOCK(c); - f = feeder_find(c, FEEDER_EQ); - if (f != NULL) - (void)FEEDER_SET(f, FEEDEQ_STATE, val); - CHN_UNLOCK(c); - } + else + d->flags &= ~SD_F_EQ_ENABLED; PCM_RELEASE(d); PCM_UNLOCK(d); @@ -592,17 +542,11 @@ void feeder_eq_initsys(device_t dev) { struct snddev_info *d; - const char *preamp; char buf[64]; d = device_get_softc(dev); - if (!(resource_string_value(device_get_name(dev), device_get_unit(dev), - "eq_preamp", &preamp) == 0 && - (d->eqpreamp = feed_eq_scan_preamp_arg(preamp)) != - FEEDEQ_PREAMP_INVALID)) - d->eqpreamp = FEEDEQ_PREAMP_DEFAULT; - + d->eqpreamp = FEEDEQ_PREAMP_DEFAULT; if (d->eqpreamp < FEEDEQ_PREAMP_MIN) d->eqpreamp = FEEDEQ_PREAMP_MIN; else if (d->eqpreamp > FEEDEQ_PREAMP_MAX) @@ -612,7 +556,7 @@ feeder_eq_initsys(device_t dev) SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "eq", CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, d, sizeof(d), sysctl_dev_pcm_eq, "I", - "Bass/Treble Equalizer (0=disable, 1=enable, 2=bypass)"); + "Bass/Treble Equalizer (0=disable, 1=enable)"); (void)snprintf(buf, sizeof(buf), "Bass/Treble Equalizer Preamp " "(-/+ %d.0dB , %d.%ddB step)", diff --git a/sys/dev/sound/pcm/mixer.c b/sys/dev/sound/pcm/mixer.c index 6ed2d0c3ce5c..3ddee24417cc 100644 --- a/sys/dev/sound/pcm/mixer.c +++ b/sys/dev/sound/pcm/mixer.c @@ -5,6 +5,10 @@ * Portions Copyright (c) Ryan Beasley <ryan.beasley@gmail.com> - GSoC 2006 * Copyright (c) 1999 Cameron Grant <cg@FreeBSD.org> * All rights reserved. + * Copyright (c) 2026 The FreeBSD Foundation + * + * Portions of this software were developed by Christos Margiolis + * <christos@FreeBSD.org> under sponsorship from the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -37,36 +41,6 @@ #include "feeder_if.h" #include "mixer_if.h" -static MALLOC_DEFINE(M_MIXER, "mixer", "mixer"); - -static int mixer_bypass = 1; -SYSCTL_INT(_hw_snd, OID_AUTO, vpc_mixer_bypass, CTLFLAG_RWTUN, - &mixer_bypass, 0, - "control channel pcm/rec volume, bypassing real mixer device"); - -#define MIXER_NAMELEN 16 -struct snd_mixer { - KOBJ_FIELDS; - void *devinfo; - int hwvol_mixer; - int hwvol_step; - int type; - device_t dev; - u_int32_t devs; - u_int32_t mutedevs; - u_int32_t recdevs; - u_int32_t recsrc; - u_int16_t level[32]; - u_int16_t level_muted[32]; - u_int8_t parent[32]; - u_int32_t child[32]; - u_int8_t realdev[32]; - char name[MIXER_NAMELEN]; - struct mtx lock; - oss_mixer_enuminfo enuminfo; - int modify_counter; -}; - static u_int16_t snd_mixerdefaults[SOUND_MIXER_NRDEVICES] = { [SOUND_MIXER_VOLUME] = 75, [SOUND_MIXER_BASS] = 50, @@ -304,7 +278,7 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int32_t muted, u_int lev) if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL)) (void)mixer_set_softpcmvol(m, d, l, r); else if ((dev == SOUND_MIXER_TREBLE || - dev == SOUND_MIXER_BASS) && (d->flags & SD_F_EQ)) + dev == SOUND_MIXER_BASS) && (d->flags & SD_F_EQ_ENABLED)) (void)mixer_set_eq(m, d, dev, (l + r) >> 1); else if (realdev != SOUND_MIXER_NONE && MIXER_SET(m, realdev, l, r) < 0) { @@ -484,8 +458,7 @@ mix_setdevs(struct snd_mixer *m, u_int32_t v) d = device_get_softc(m->dev); if (d != NULL && (d->flags & SD_F_SOFTPCMVOL)) v |= SOUND_MASK_PCM; - if (d != NULL && (d->flags & SD_F_EQ)) - v |= SOUND_MASK_TREBLE | SOUND_MASK_BASS; + v |= SOUND_MASK_TREBLE | SOUND_MASK_BASS; for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { if (m->parent[i] < SOUND_MIXER_NRDEVICES) v |= 1 << m->parent[i]; @@ -501,64 +474,12 @@ mix_setdevs(struct snd_mixer *m, u_int32_t v) * recording devices. This function records that value in a structure * used by the rest of the mixer code. * - * This function also populates a structure used by the SNDCTL_DSP_*RECSRC* - * family of ioctls that are part of OSSV4. All recording device labels - * are concatenated in ascending order corresponding to their routing - * numbers. (Ex: a system might have 0 => 'vol', 1 => 'cd', 2 => 'line', - * etc.) For now, these labels are just the standard recording device - * names (cd, line1, etc.), but will eventually be fully dynamic and user - * controlled. - * * @param m mixer device context container thing * @param v mask of recording devices */ void mix_setrecdevs(struct snd_mixer *m, u_int32_t v) { - oss_mixer_enuminfo *ei; - char *loc; - int i, nvalues, nwrote, nleft, ncopied; - - ei = &m->enuminfo; - - nvalues = 0; - nwrote = 0; - nleft = sizeof(ei->strings); - loc = ei->strings; - - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { - if ((1 << i) & v) { - ei->strindex[nvalues] = nwrote; - ncopied = strlcpy(loc, snd_mixernames[i], nleft) + 1; - /* strlcpy retval doesn't include terminator */ - - nwrote += ncopied; - nleft -= ncopied; - nvalues++; - - /* - * XXX I don't think this should ever be possible. - * Even with a move to dynamic device/channel names, - * each label is limited to ~16 characters, so that'd - * take a LOT to fill this buffer. - */ - if ((nleft <= 0) || (nvalues >= OSS_ENUM_MAXVALUE)) { - device_printf(m->dev, - "mix_setrecdevs: Not enough room to store device names--please file a bug report.\n"); - device_printf(m->dev, - "mix_setrecdevs: Please include details about your sound hardware, OS version, etc.\n"); - break; - } - - loc = &ei->strings[nwrote]; - } - } - - /* - * NB: The SNDCTL_DSP_GET_RECSRC_NAMES ioctl ignores the dev - * and ctrl fields. - */ - ei->nvalues = nvalues; m->recdevs = v; } @@ -639,7 +560,7 @@ mixer_obj_create(device_t dev, kobj_class_t cls, void *devinfo, KASSERT(type == MIXER_TYPE_PRIMARY || type == MIXER_TYPE_SECONDARY, ("invalid mixer type=%d", type)); - m = (struct snd_mixer *)kobj_create(cls, M_MIXER, M_WAITOK | M_ZERO); + m = (struct snd_mixer *)kobj_create(cls, M_DEVBUF, M_WAITOK | M_ZERO); snprintf(m->name, sizeof(m->name), "%s:mixer", device_get_nameunit(dev)); if (desc != NULL) { @@ -658,9 +579,8 @@ mixer_obj_create(device_t dev, kobj_class_t cls, void *devinfo, } if (MIXER_INIT(m)) { - mtx_lock(&m->lock); mtx_destroy(&m->lock); - kobj_delete((kobj_t)m, M_MIXER); + kobj_delete((kobj_t)m, M_DEVBUF); return (NULL); } @@ -679,7 +599,7 @@ mixer_delete(struct snd_mixer *m) MIXER_UNINIT(m); mtx_destroy(&m->lock); - kobj_delete((kobj_t)m, M_MIXER); + kobj_delete((kobj_t)m, M_DEVBUF); return (0); } @@ -706,15 +626,6 @@ mixer_init(device_t dev, kobj_class_t cls, void *devinfo) name = device_get_name(dev); unit = device_get_unit(dev); - if (resource_int_value(name, unit, "eq", &val) == 0 && - val != 0) { - snddev->flags |= SD_F_EQ; - if ((val & SD_F_EQ_MASK) == val) - snddev->flags |= val; - else - snddev->flags |= SD_F_EQ_DEFAULT; - snddev->eqpreamp = 0; - } m = mixer_obj_create(dev, cls, devinfo, MIXER_TYPE_PRIMARY, NULL); if (m == NULL) @@ -762,8 +673,7 @@ mixer_init(device_t dev, kobj_class_t cls, void *devinfo) } if (snddev->flags & SD_F_SOFTPCMVOL) device_printf(dev, "Soft PCM mixer ENABLED\n"); - if (snddev->flags & SD_F_EQ) - device_printf(dev, "EQ Treble/Bass ENABLED\n"); + device_printf(dev, "EQ Treble/Bass ENABLED\n"); } return (0); @@ -804,7 +714,7 @@ mixer_uninit(device_t dev) MIXER_UNINIT(m); mtx_destroy(&m->lock); - kobj_delete((kobj_t)m, M_MIXER); + kobj_delete((kobj_t)m, M_DEVBUF); d->mixer_dev = NULL; @@ -1046,113 +956,6 @@ mixer_close(struct cdev *i_dev, int flags, int mode, struct thread *td) } static int -mixer_ioctl_channel(struct cdev *dev, u_long cmd, caddr_t arg, int mode, - struct thread *td, int from) -{ - struct snddev_info *d; - struct snd_mixer *m; - struct pcm_channel *c, *rdch, *wrch; - pid_t pid; - int j, ret; - - if (td == NULL || td->td_proc == NULL) - return (-1); - - m = dev->si_drv1; - d = device_get_softc(m->dev); - j = cmd & 0xff; - - switch (j) { - case SOUND_MIXER_PCM: - case SOUND_MIXER_RECLEV: - case SOUND_MIXER_DEVMASK: - case SOUND_MIXER_CAPS: - case SOUND_MIXER_STEREODEVS: - break; - default: - return (-1); - } - - pid = td->td_proc->p_pid; - rdch = NULL; - wrch = NULL; - c = NULL; - ret = -1; - - /* - * This is unfair. Imagine single proc opening multiple - * instances of same direction. What we do right now - * is looking for the first matching proc/pid, and just - * that. Nothing more. Consider it done. - * - * The better approach of controlling specific channel - * pcm or rec volume is by doing mixer ioctl - * (SNDCTL_DSP_[SET|GET][PLAY|REC]VOL / SOUND_MIXER_[PCM|RECLEV] - * on its open fd, rather than cracky mixer bypassing here. - */ - CHN_FOREACH(c, d, channels.pcm.opened) { - CHN_LOCK(c); - if (c->pid != pid || - !(c->feederflags & (1 << FEEDER_VOLUME))) { - CHN_UNLOCK(c); - continue; - } - if (rdch == NULL && c->direction == PCMDIR_REC) { - rdch = c; - if (j == SOUND_MIXER_RECLEV) - goto mixer_ioctl_channel_proc; - } else if (wrch == NULL && c->direction == PCMDIR_PLAY) { - wrch = c; - if (j == SOUND_MIXER_PCM) - goto mixer_ioctl_channel_proc; - } - CHN_UNLOCK(c); - if (rdch != NULL && wrch != NULL) - break; - } - - if (rdch == NULL && wrch == NULL) - return (-1); - - if ((j == SOUND_MIXER_DEVMASK || j == SOUND_MIXER_CAPS || - j == SOUND_MIXER_STEREODEVS) && - (cmd & ~0xff) == MIXER_READ(0)) { - mtx_lock(&m->lock); - *(int *)arg = mix_getdevs(m); - mtx_unlock(&m->lock); - if (rdch != NULL) - *(int *)arg |= SOUND_MASK_RECLEV; - if (wrch != NULL) - *(int *)arg |= SOUND_MASK_PCM; - ret = 0; - } - - return (ret); - -mixer_ioctl_channel_proc: - - KASSERT(c != NULL, ("%s(): NULL channel", __func__)); - CHN_LOCKASSERT(c); - - if ((cmd & ~0xff) == MIXER_WRITE(0)) { - int left, right, center; - - left = *(int *)arg & 0x7f; - right = (*(int *)arg >> 8) & 0x7f; - center = (left + right) >> 1; - chn_setvolume_multi(c, SND_VOL_C_PCM, left, right, center); - } else if ((cmd & ~0xff) == MIXER_READ(0)) { - *(int *)arg = chn_getvolume_matrix(c, SND_VOL_C_PCM, SND_CHN_T_FL); - *(int *)arg |= - chn_getvolume_matrix(c, SND_VOL_C_PCM, SND_CHN_T_FR) << 8; - } - - CHN_UNLOCK(c); - - return (0); -} - -static int mixer_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td) { @@ -1169,15 +972,7 @@ mixer_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, PCM_GIANT_ENTER(d); PCM_ACQUIRE_QUICK(d); - ret = -1; - - if (mixer_bypass != 0 && (d->flags & SD_F_VPC)) - ret = mixer_ioctl_channel(i_dev, cmd, arg, mode, td, - MIXER_CMD_CDEV); - - if (ret == -1) - ret = mixer_ioctl_cmd(i_dev, cmd, arg, mode, td, - MIXER_CMD_CDEV); + ret = mixer_ioctl_cmd(i_dev, cmd, arg, mode, td); PCM_RELEASE_QUICK(d); PCM_GIANT_LEAVE(d); @@ -1200,7 +995,7 @@ mixer_mixerinfo(struct snd_mixer *m, mixer_info *mi) */ int mixer_ioctl_cmd(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, - struct thread *td, int from) + struct thread *td) { struct snd_mixer *m; int ret = EINVAL, *arg_i = (int *)arg; @@ -1238,10 +1033,31 @@ mixer_ioctl_cmd(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, mtx_lock(&m->lock); switch (cmd) { - case SNDCTL_DSP_GET_RECSRC_NAMES: - bcopy((void *)&m->enuminfo, arg, sizeof(oss_mixer_enuminfo)); + case SNDCTL_DSP_GET_RECSRC_NAMES: { + oss_mixer_enuminfo *ei = (oss_mixer_enuminfo *)arg; + char *loc; + int i, nvalues, nwrote, nleft, ncopied; + + nvalues = 0; + nwrote = 0; + nleft = sizeof(ei->strings); + loc = ei->strings; + + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + if (!((1 << i) & m->recdevs)) + continue; + ei->strindex[nvalues] = nwrote; + ncopied = strlcpy(loc, snd_mixernames[i], nleft) + 1; + nwrote += ncopied; + nleft -= ncopied; + nvalues++; + loc = &ei->strings[nwrote]; + } + ei->nvalues = nvalues; + ret = 0; goto done; + } case SNDCTL_DSP_GET_RECSRC: ret = mixer_get_recroute(m, arg_i); goto done; @@ -1515,13 +1331,3 @@ mixer_oss_mixerinfo(struct cdev *i_dev, oss_mixerinfo *mi) return (EINVAL); } - -/* - * Allow the sound driver to use the mixer lock to protect its mixer - * data: - */ -struct mtx * -mixer_get_lock(struct snd_mixer *m) -{ - return (&m->lock); -} diff --git a/sys/dev/sound/pcm/mixer.h b/sys/dev/sound/pcm/mixer.h index 3ce8a4f5adee..6f764307cfc8 100644 --- a/sys/dev/sound/pcm/mixer.h +++ b/sys/dev/sound/pcm/mixer.h @@ -4,6 +4,10 @@ * Copyright (c) 2005-2009 Ariff Abdullah <ariff@FreeBSD.org> * Copyright (c) 1999 Cameron Grant <cg@FreeBSD.org> * All rights reserved. + * Copyright (c) 2026 The FreeBSD Foundation + * + * Portions of this software were developed by Christos Margiolis + * <christos@FreeBSD.org> under sponsorship from the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,13 +34,35 @@ #ifndef _PCM_MIXER_H_ #define _PCM_MIXER_H_ +#define MIXER_NAMELEN 16 +struct snd_mixer { + KOBJ_FIELDS; + void *devinfo; + int hwvol_mixer; + int hwvol_step; + int type; + device_t dev; + u_int32_t devs; + u_int32_t mutedevs; + u_int32_t recdevs; + u_int32_t recsrc; + u_int16_t level[32]; + u_int16_t level_muted[32]; + u_int8_t parent[32]; + u_int32_t child[32]; + u_int8_t realdev[32]; + char name[MIXER_NAMELEN]; + struct mtx lock; + int modify_counter; +}; + struct snd_mixer *mixer_create(device_t dev, kobj_class_t cls, void *devinfo, const char *desc); int mixer_delete(struct snd_mixer *m); int mixer_init(device_t dev, kobj_class_t cls, void *devinfo); int mixer_uninit(device_t dev); int mixer_reinit(device_t dev); -int mixer_ioctl_cmd(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td, int from); +int mixer_ioctl_cmd(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td); int mixer_oss_mixerinfo(struct cdev *i_dev, oss_mixerinfo *mi); int mixer_hwvol_init(device_t dev); @@ -61,21 +87,11 @@ void mix_setparentchild(struct snd_mixer *m, u_int32_t parent, u_int32_t childs) void mix_setrealdev(struct snd_mixer *m, u_int32_t dev, u_int32_t realdev); u_int32_t mix_getparent(struct snd_mixer *m, u_int32_t dev); void *mix_getdevinfo(struct snd_mixer *m); -struct mtx *mixer_get_lock(struct snd_mixer *m); - -#define MIXER_CMD_DIRECT 0 /* send command within driver */ -#define MIXER_CMD_CDEV 1 /* send command from cdev/ioctl */ #define MIXER_TYPE_PRIMARY 0 /* mixer_init() */ #define MIXER_TYPE_SECONDARY 1 /* mixer_create() */ -/* - * this is a kludge to allow hiding of the struct snd_mixer definition - * 512 should be enough for all architectures - */ -#define MIXER_SIZE (512 + sizeof(struct kobj) + \ - sizeof(oss_mixer_enuminfo)) - -#define MIXER_DECLARE(name) static DEFINE_CLASS(name, name ## _methods, MIXER_SIZE) +#define MIXER_DECLARE(name) static DEFINE_CLASS(name, name ## _methods, \ + sizeof(struct snd_mixer)) #endif /* _PCM_MIXER_H_ */ diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c index 9eb2dffeb908..235142eb5209 100644 --- a/sys/dev/sound/pcm/sound.c +++ b/sys/dev/sound/pcm/sound.c @@ -77,11 +77,30 @@ snd_setup_intr(device_t dev, struct resource *res, int flags, driver_intr_t hand return bus_setup_intr(dev, res, flags, NULL, hand, param, cookiep); } +static void +pcm_hotswap(void) +{ + struct snddev_info *d; + char buf[32]; + + bus_topo_assert(); + if (snd_unit >= 0) { + d = devclass_get_softc(pcm_devclass, snd_unit); + if (!PCM_REGISTERED(d)) + return; + snprintf(buf, sizeof(buf), "cdev=dsp%d", snd_unit); + if (d->reccount > 0) + devctl_notify("SND", "CONN", "IN", buf); + if (d->playcount > 0) + devctl_notify("SND", "CONN", "OUT", buf); + } else + devctl_notify("SND", "CONN", "NODEV", NULL); +} + static int sysctl_hw_snd_default_unit(SYSCTL_HANDLER_ARGS) { struct snddev_info *d; - char buf[32]; int error, unit; unit = snd_unit; @@ -95,13 +114,8 @@ sysctl_hw_snd_default_unit(SYSCTL_HANDLER_ARGS) } snd_unit = unit; snd_unit_auto = 0; + pcm_hotswap(); bus_topo_unlock(); - - snprintf(buf, sizeof(buf), "cdev=dsp%d", snd_unit); - if (d->reccount > 0) - devctl_notify("SND", "CONN", "IN", buf); - if (d->playcount > 0) - devctl_notify("SND", "CONN", "OUT", buf); } return (error); } @@ -373,6 +387,7 @@ int pcm_register(device_t dev, char *str) { struct snddev_info *d = device_get_softc(dev); + int err; /* should only be called once */ if (d->flags & SD_F_REGISTERED) @@ -415,9 +430,15 @@ pcm_register(device_t dev, char *str) "mode (1=mixer, 2=play, 4=rec. The values are OR'ed if more than " "one mode is supported)"); vchan_initsys(dev); - if (d->flags & SD_F_EQ) - feeder_eq_initsys(dev); + feeder_eq_initsys(dev); + + sndstat_register(dev, SNDST_TYPE_PCM, d->status); + err = dsp_make_dev(dev); + if (err) + return (err); + + bus_topo_lock(); if (snd_unit_auto < 0) snd_unit_auto = (snd_unit < 0) ? 1 : 0; if (snd_unit < 0 || snd_unit_auto > 1) @@ -425,9 +446,11 @@ pcm_register(device_t dev, char *str) else if (snd_unit_auto == 1) snd_unit = pcm_best_unit(snd_unit); - sndstat_register(dev, SNDST_TYPE_PCM, d->status); + if (snd_unit == device_get_unit(dev)) + pcm_hotswap(); + bus_topo_unlock(); - return (dsp_make_dev(dev)); + return (0); } int @@ -470,13 +493,14 @@ pcm_unregister(device_t dev) cv_destroy(&d->cv); mtx_destroy(&d->lock); + bus_topo_lock(); if (snd_unit == device_get_unit(dev)) { snd_unit = pcm_best_unit(-1); if (snd_unit_auto == 0) snd_unit_auto = 1; - if (snd_unit < 0) - devctl_notify("SND", "CONN", "NODEV", NULL); + pcm_hotswap(); } + bus_topo_unlock(); return (0); } diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h index 4795eb7585c5..4d527d69086a 100644 --- a/sys/dev/sound/pcm/sound.h +++ b/sys/dev/sound/pcm/sound.h @@ -105,17 +105,13 @@ struct snd_mixer; #define SD_F_REGISTERED 0x00000020 #define SD_F_BITPERFECT 0x00000040 #define SD_F_VPC 0x00000080 /* volume-per-channel */ -#define SD_F_EQ 0x00000100 /* EQ */ +/* unused 0x00000100 */ #define SD_F_EQ_ENABLED 0x00000200 /* EQ enabled */ -#define SD_F_EQ_BYPASSED 0x00000400 /* EQ bypassed */ +/* unused 0x00000400 */ #define SD_F_EQ_PC 0x00000800 /* EQ per-channel */ #define SD_F_PVCHANS 0x00001000 /* Playback vchans enabled */ #define SD_F_RVCHANS 0x00002000 /* Recording vchans enabled */ -#define SD_F_EQ_DEFAULT (SD_F_EQ | SD_F_EQ_ENABLED) -#define SD_F_EQ_MASK (SD_F_EQ | SD_F_EQ_ENABLED | \ - SD_F_EQ_BYPASSED | SD_F_EQ_PC) - #define SD_F_BITS "\020" \ "\001SIMPLEX" \ /* "\002 */ \ @@ -125,9 +121,9 @@ struct snd_mixer; "\006REGISTERED" \ "\007BITPERFECT" \ "\010VPC" \ - "\011EQ" \ + /* "\011 */ \ "\012EQ_ENABLED" \ - "\013EQ_BYPASSED" \ + /* "\013 */ \ "\014EQ_PC" \ "\015PVCHANS" \ "\016RVCHANS" diff --git a/sys/dev/sound/usb/uaudio.c b/sys/dev/sound/usb/uaudio.c index f477eb768fde..eedd52774b70 100644 --- a/sys/dev/sound/usb/uaudio.c +++ b/sys/dev/sound/usb/uaudio.c @@ -356,7 +356,7 @@ struct uaudio_hid { struct uaudio_softc_child { device_t pcm_device; - struct mtx *mixer_lock; + struct mtx mixer_lock; struct snd_mixer *mixer_dev; uint32_t mix_info; @@ -2955,12 +2955,9 @@ uaudio_mixer_sysctl_handler(SYSCTL_HANDLER_ARGS) sc = (struct uaudio_softc *)oidp->oid_arg1; hint = oidp->oid_arg2; - if (sc->sc_child[0].mixer_lock == NULL) - return (ENXIO); - /* lookup mixer node */ - mtx_lock(sc->sc_child[0].mixer_lock); + mtx_lock(&sc->sc_child[0].mixer_lock); for (pmc = sc->sc_mixer_root; pmc != NULL; pmc = pmc->next) { for (chan = 0; chan != (int)pmc->nchan; chan++) { if (pmc->wValue[chan] != -1 && @@ -2971,7 +2968,7 @@ uaudio_mixer_sysctl_handler(SYSCTL_HANDLER_ARGS) } } found: - mtx_unlock(sc->sc_child[0].mixer_lock); + mtx_unlock(&sc->sc_child[0].mixer_lock); error = sysctl_handle_int(oidp, &temp, 0, req); if (error != 0 || req->newptr == NULL) @@ -2979,7 +2976,7 @@ found: /* update mixer value */ - mtx_lock(sc->sc_child[0].mixer_lock); + mtx_lock(&sc->sc_child[0].mixer_lock); if (pmc != NULL && temp >= pmc->minval && temp <= pmc->maxval) { @@ -2989,7 +2986,7 @@ found: /* start the transfer, if not already started */ usbd_transfer_start(sc->sc_mixer_xfer[0]); } - mtx_unlock(sc->sc_child[0].mixer_lock); + mtx_unlock(&sc->sc_child[0].mixer_lock); return (0); } @@ -3220,10 +3217,7 @@ uaudio_mixer_reload_all(struct uaudio_softc *sc) struct uaudio_mixer_node *pmc; int chan; - if (sc->sc_child[0].mixer_lock == NULL) - return; - - mtx_lock(sc->sc_child[0].mixer_lock); + mtx_lock(&sc->sc_child[0].mixer_lock); for (pmc = sc->sc_mixer_root; pmc != NULL; pmc = pmc->next) { /* use reset defaults for non-oss controlled settings */ if (pmc->ctl == SOUND_MIXER_NRDEVICES) @@ -3235,7 +3229,7 @@ uaudio_mixer_reload_all(struct uaudio_softc *sc) /* start HID volume keys, if any */ usbd_transfer_start(sc->sc_hid.xfer[0]); - mtx_unlock(sc->sc_child[0].mixer_lock); + mtx_unlock(&sc->sc_child[0].mixer_lock); } static void @@ -5392,8 +5386,8 @@ uaudio_mixer_bsd2value(struct uaudio_mixer_node *mc, int val) } static void -uaudio_mixer_ctl_set(struct uaudio_softc *sc, struct uaudio_mixer_node *mc, - uint8_t chan, int val) +uaudio_mixer_ctl_set(struct uaudio_softc *sc, unsigned index, + struct uaudio_mixer_node *mc, uint8_t chan, int val) { val = uaudio_mixer_bsd2value(mc, val); @@ -5402,7 +5396,9 @@ uaudio_mixer_ctl_set(struct uaudio_softc *sc, struct uaudio_mixer_node *mc, /* start the transfer, if not already started */ + mtx_lock(&sc->sc_child[index].mixer_lock); usbd_transfer_start(sc->sc_mixer_xfer[0]); + mtx_unlock(&sc->sc_child[index].mixer_lock); } static void @@ -5439,13 +5435,13 @@ uaudio_mixer_init_sub(struct uaudio_softc *sc, struct snd_mixer *m) DPRINTF("child=%u\n", i); - sc->sc_child[i].mixer_lock = mixer_get_lock(m); + mtx_init(&sc->sc_child[i].mixer_lock, "uaudio mixer lock", NULL, MTX_DEF); sc->sc_child[i].mixer_dev = m; if (i == 0 && usbd_transfer_setup(sc->sc_udev, &sc->sc_mixer_iface_index, sc->sc_mixer_xfer, uaudio_mixer_config, 1, sc, - sc->sc_child[i].mixer_lock)) { + &sc->sc_child[i].mixer_lock)) { DPRINTFN(0, "could not allocate USB transfer for mixer!\n"); return (ENOMEM); } @@ -5470,7 +5466,7 @@ uaudio_mixer_uninit_sub(struct uaudio_softc *sc, struct snd_mixer *m) if (index == 0) usbd_transfer_unsetup(sc->sc_mixer_xfer, 1); - sc->sc_child[index].mixer_lock = NULL; + mtx_destroy(&sc->sc_child[index].mixer_lock); return (0); } @@ -5488,7 +5484,7 @@ uaudio_mixer_set(struct uaudio_softc *sc, struct snd_mixer *m, for (mc = sc->sc_mixer_root; mc != NULL; mc = mc->next) { if (mc->ctl == type) { for (chan = 0; chan < mc->nchan; chan++) { - uaudio_mixer_ctl_set(sc, mc, chan, + uaudio_mixer_ctl_set(sc, index, mc, chan, chan == 0 ? left : right); } } @@ -5529,7 +5525,7 @@ uaudio_mixer_setrecsrc(struct uaudio_softc *sc, struct snd_mixer *m, uint32_t sr for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) { if (temp != (1U << mc->slctrtype[i - 1])) continue; - uaudio_mixer_ctl_set(sc, mc, 0, i); + uaudio_mixer_ctl_set(sc, index, mc, 0, i); break; } } @@ -6186,9 +6182,6 @@ uaudio_hid_attach(struct uaudio_softc *sc, if (!(sc->sc_hid.flags & UAUDIO_HID_VALID)) return (-1); - if (sc->sc_child[0].mixer_lock == NULL) - return (-1); - /* Get HID descriptor */ error = usbd_req_get_hid_desc(uaa->device, NULL, &d_ptr, &d_len, M_TEMP, sc->sc_hid.iface_index); @@ -6247,7 +6240,7 @@ uaudio_hid_attach(struct uaudio_softc *sc, /* allocate USB transfers */ error = usbd_transfer_setup(uaa->device, &sc->sc_hid.iface_index, sc->sc_hid.xfer, uaudio_hid_config, UAUDIO_HID_N_TRANSFER, - sc, sc->sc_child[0].mixer_lock); + sc, &sc->sc_child[0].mixer_lock); if (error) { DPRINTF("error=%s\n", usbd_errstr(error)); return (-1); diff --git a/sys/dev/sound/usb/uaudio_pcm.c b/sys/dev/sound/usb/uaudio_pcm.c index c24c111f983c..4b1762cfc3ec 100644 --- a/sys/dev/sound/usb/uaudio_pcm.c +++ b/sys/dev/sound/usb/uaudio_pcm.c @@ -134,39 +134,18 @@ ua_mixer_init(struct snd_mixer *m) static int ua_mixer_set(struct snd_mixer *m, unsigned type, unsigned left, unsigned right) { - struct mtx *mtx = mixer_get_lock(m); - uint8_t do_unlock; - - if (mtx_owned(mtx)) { - do_unlock = 0; - } else { - do_unlock = 1; - mtx_lock(mtx); - } uaudio_mixer_set(mix_getdevinfo(m), m, type, left, right); - if (do_unlock) { - mtx_unlock(mtx); - } + return (left | (right << 8)); } static uint32_t ua_mixer_setrecsrc(struct snd_mixer *m, uint32_t src) { - struct mtx *mtx = mixer_get_lock(m); int retval; - uint8_t do_unlock; - if (mtx_owned(mtx)) { - do_unlock = 0; - } else { - do_unlock = 1; - mtx_lock(mtx); - } retval = uaudio_mixer_setrecsrc(mix_getdevinfo(m), m, src); - if (do_unlock) { - mtx_unlock(mtx); - } + return (retval); } diff --git a/sys/dev/uart/uart_dev_ns8250.c b/sys/dev/uart/uart_dev_ns8250.c index c13eabe9055e..d6940dc80005 100644 --- a/sys/dev/uart/uart_dev_ns8250.c +++ b/sys/dev/uart/uart_dev_ns8250.c @@ -529,40 +529,40 @@ UART_CLASS(uart_ns8250_class); */ #ifdef DEV_ACPI static struct acpi_spcr_compat_data acpi_spcr_compat_data[] = { - { &uart_ns8250_class, ACPI_DBG2_16550_COMPATIBLE }, - { &uart_ns8250_class, ACPI_DBG2_16550_SUBSET }, - { &uart_ns8250_class, ACPI_DBG2_16550_WITH_GAS }, + { &uart_ns8250_class, ACPI_DBG2_16550_COMPATIBLE }, + { &uart_ns8250_class, ACPI_DBG2_16550_SUBSET }, + { &uart_ns8250_class, ACPI_DBG2_16550_WITH_GAS }, { NULL, 0 }, }; UART_ACPI_SPCR_CLASS(acpi_spcr_compat_data); static struct acpi_uart_compat_data acpi_compat_data[] = { {"AMD0020", &uart_ns8250_class, 2, 0, 48000000, UART_F_BUSY_DETECT, "AMD / Synopsys Designware UART"}, - {"AMDI0020", &uart_ns8250_class, 2, 0, 48000000, UART_F_BUSY_DETECT, "AMD / Synopsys Designware UART"}, - {"APMC0D08", &uart_ns8250_class, 2, 4, 0, 0, "APM compatible UART"}, - {"MRVL0001", &uart_ns8250_class, 2, 0, 200000000, UART_F_BUSY_DETECT, "Marvell / Synopsys Designware UART"}, - {"SCX0006", &uart_ns8250_class, 2, 0, 62500000, UART_F_BUSY_DETECT, "SynQuacer / Synopsys Designware UART"}, - {"HISI0031", &uart_ns8250_class, 2, 0, 200000000, UART_F_BUSY_DETECT, "HiSilicon / Synopsys Designware UART"}, - {"INTC1006", &uart_ns8250_class, 2, 0, 25000000, 0, "Intel ARM64 UART"}, - {"NXP0018", &uart_ns8250_class, 0, 0, 350000000, UART_F_BUSY_DETECT, "NXP / Synopsys Designware UART"}, - {"PNP0500", &uart_ns8250_class, 0, 0, 0, 0, "Standard PC COM port"}, - {"PNP0501", &uart_ns8250_class, 0, 0, 0, 0, "16550A-compatible COM port"}, - {"PNP0502", &uart_ns8250_class, 0, 0, 0, 0, "Multiport serial device (non-intelligent 16550)"}, - {"PNP0510", &uart_ns8250_class, 0, 0, 0, 0, "Generic IRDA-compatible device"}, - {"PNP0511", &uart_ns8250_class, 0, 0, 0, 0, "Generic IRDA-compatible device"}, - {"WACF004", &uart_ns8250_class, 0, 0, 0, 0, "Wacom Tablet PC Screen"}, - {"WACF00E", &uart_ns8250_class, 0, 0, 0, 0, "Wacom Tablet PC Screen 00e"}, - {"FUJ02E5", &uart_ns8250_class, 0, 0, 0, 0, "Wacom Tablet at FuS Lifebook T"}, - {NULL, NULL, 0 , 0, 0, 0, NULL}, + {"AMDI0020", &uart_ns8250_class, 2, 0, 48000000, UART_F_BUSY_DETECT, "AMD / Synopsys Designware UART"}, + {"APMC0D08", &uart_ns8250_class, 2, 4, 0, 0, "APM compatible UART"}, + {"MRVL0001", &uart_ns8250_class, 2, 0, 200000000, UART_F_BUSY_DETECT, "Marvell / Synopsys Designware UART"}, + {"SCX0006", &uart_ns8250_class, 2, 0, 62500000, UART_F_BUSY_DETECT, "SynQuacer / Synopsys Designware UART"}, + {"HISI0031", &uart_ns8250_class, 2, 0, 200000000, UART_F_BUSY_DETECT, "HiSilicon / Synopsys Designware UART"}, + {"INTC1006", &uart_ns8250_class, 2, 0, 25000000, 0, "Intel ARM64 UART"}, + {"NXP0018", &uart_ns8250_class, 0, 0, 350000000, UART_F_BUSY_DETECT, "NXP / Synopsys Designware UART"}, + {"PNP0500", &uart_ns8250_class, 0, 0, 0, 0, "Standard PC COM port"}, + {"PNP0501", &uart_ns8250_class, 0, 0, 0, 0, "16550A-compatible COM port"}, + {"PNP0502", &uart_ns8250_class, 0, 0, 0, 0, "Multiport serial device (non-intelligent 16550)"}, + {"PNP0510", &uart_ns8250_class, 0, 0, 0, 0, "Generic IRDA-compatible device"}, + {"PNP0511", &uart_ns8250_class, 0, 0, 0, 0, "Generic IRDA-compatible device"}, + {"WACF004", &uart_ns8250_class, 0, 0, 0, 0, "Wacom Tablet PC Screen"}, + {"WACF00E", &uart_ns8250_class, 0, 0, 0, 0, "Wacom Tablet PC Screen 00e"}, + {"FUJ02E5", &uart_ns8250_class, 0, 0, 0, 0, "Wacom Tablet at FuS Lifebook T"}, + {NULL, NULL, 0, 0, 0, 0, NULL}, }; UART_ACPI_CLASS_AND_DEVICE(acpi_compat_data); #endif #ifdef FDT static struct ofw_compat_data compat_data[] = { - {"ns16550", (uintptr_t)&uart_ns8250_class}, - {"ns16550a", (uintptr_t)&uart_ns8250_class}, - {NULL, (uintptr_t)NULL}, + {"ns16550", (uintptr_t)&uart_ns8250_class}, + {"ns16550a", (uintptr_t)&uart_ns8250_class}, + {NULL, (uintptr_t)NULL}, }; UART_FDT_CLASS_AND_DEVICE(compat_data); #endif diff --git a/sys/dev/uart/uart_dev_pl011.c b/sys/dev/uart/uart_dev_pl011.c index ae3c4d3218cf..f0d7bcda1fa4 100644 --- a/sys/dev/uart/uart_dev_pl011.c +++ b/sys/dev/uart/uart_dev_pl011.c @@ -382,32 +382,32 @@ static struct uart_class uart_pl011_class = { }; UART_CLASS(uart_pl011_class); -#ifdef FDT -static struct ofw_compat_data fdt_compat_data[] = { - {"arm,pl011", (uintptr_t)&uart_pl011_class}, - {NULL, (uintptr_t)NULL}, -}; -UART_FDT_CLASS_AND_DEVICE(fdt_compat_data); -#endif - #ifdef DEV_ACPI static struct acpi_spcr_compat_data acpi_spcr_compat_data[] = { - { &uart_pl011_class, ACPI_DBG2_ARM_PL011 }, - { &uart_pl011_class, ACPI_DBG2_ARM_SBSA_GENERIC }, - { &uart_pl011_class, ACPI_DBG2_ARM_SBSA_32BIT }, + { &uart_pl011_class, ACPI_DBG2_ARM_PL011 }, + { &uart_pl011_class, ACPI_DBG2_ARM_SBSA_GENERIC }, + { &uart_pl011_class, ACPI_DBG2_ARM_SBSA_32BIT }, { NULL, 0 }, }; UART_ACPI_SPCR_CLASS(acpi_spcr_compat_data); static struct acpi_uart_compat_data acpi_compat_data[] = { - {"ARMH0011", &uart_pl011_class, 2, 0, 0, 0, "uart pl011"}, - {"ARMHB000", &uart_pl011_class, 2, 0, 0, 0, "uart pl011"}, - {"ARMHB000", &uart_pl011_class, 2, 0, 0, 0, "uart pl011"}, - {NULL, NULL, 0, 0, 0, 0, NULL}, + {"ARMH0011", &uart_pl011_class, 2, 0, 0, 0, "uart pl011"}, + {"ARMHB000", &uart_pl011_class, 2, 0, 0, 0, "uart pl011"}, + {"ARMHB000", &uart_pl011_class, 2, 0, 0, 0, "uart pl011"}, + {NULL, NULL, 0, 0, 0, 0, NULL}, }; UART_ACPI_CLASS_AND_DEVICE(acpi_compat_data); #endif +#ifdef FDT +static struct ofw_compat_data fdt_compat_data[] = { + {"arm,pl011", (uintptr_t)&uart_pl011_class}, + {NULL, (uintptr_t)NULL}, +}; +UART_FDT_CLASS_AND_DEVICE(fdt_compat_data); +#endif + static int uart_pl011_bus_attach(struct uart_softc *sc) { diff --git a/sys/dev/usb/usb_transfer.c b/sys/dev/usb/usb_transfer.c index 67745cf49397..d41121ed3a06 100644 --- a/sys/dev/usb/usb_transfer.c +++ b/sys/dev/usb/usb_transfer.c @@ -1889,8 +1889,10 @@ usbd_transfer_submit(struct usb_xfer *xfer) */ #if USB_HAVE_BUSDMA if (xfer->flags_int.bdma_enable) { + USB_BUS_LOCK(bus); /* insert the USB transfer last in the BUS-DMA queue */ usb_command_wrapper(&xfer->xroot->dma_q, xfer); + USB_BUS_UNLOCK(bus); return; } #endif diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c index f9afb9afe45f..71992f18e8fb 100644 --- a/sys/i386/i386/machdep.c +++ b/sys/i386/i386/machdep.c @@ -1492,8 +1492,8 @@ init386(int first) PCPU_SET(fsgs_gdt, &gdt[GUFS_SEL].sd); /* Initialize the tss (except for the final esp0) early for vm86. */ - common_tss0.tss_esp0 = (vm_offset_t)thread0.td_kstack + - thread0.td_kstack_pages * PAGE_SIZE - VM86_STACK_SPACE; + common_tss0.tss_esp0 = (vm_offset_t)td_kstack_top(&thread0) - + VM86_STACK_SPACE; common_tss0.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL); common_tss0.tss_ioopt = sizeof(struct i386tss) << 16; gsel_tss = GSEL(GPROC0_SEL, SEL_KPL); diff --git a/sys/i386/i386/vm_machdep.c b/sys/i386/i386/vm_machdep.c index 672ec9360c35..72fe83d3fdd4 100644 --- a/sys/i386/i386/vm_machdep.c +++ b/sys/i386/i386/vm_machdep.c @@ -89,7 +89,7 @@ get_pcb_user_save_td(struct thread *td) { char *p; - p = td->td_kstack + td->td_kstack_pages * PAGE_SIZE - + p = td_kstack_top(td) - roundup2(cpu_max_ext_state_size, XSAVE_AREA_ALIGN); KASSERT(__is_aligned(p, XSAVE_AREA_ALIGN), ("Unaligned pcb_user_save area")); @@ -110,7 +110,7 @@ get_pcb_td(struct thread *td) { char *p; - p = td->td_kstack + td->td_kstack_pages * PAGE_SIZE - + p = td_kstack_top(td) - roundup2(cpu_max_ext_state_size, XSAVE_AREA_ALIGN) - sizeof(struct pcb); return ((struct pcb *)p); @@ -232,9 +232,7 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) return; } - /* Point the pcb to the top of the stack */ - pcb2 = get_pcb_td(td2); - td2->td_pcb = pcb2; + pcb2 = td2->td_pcb; copy_thread(td1, td2); @@ -248,11 +246,7 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) /* * Copy the trap frame for the return to user mode as if from a * syscall. This copies most of the user mode register values. - * The -VM86_STACK_SPACE (-16) is so we can expand the trapframe - * if we go to vm86. */ - td2->td_frame = (struct trapframe *)((caddr_t)td2->td_pcb - - VM86_STACK_SPACE) - 1; bcopy(td1->td_frame, td2->td_frame, sizeof(struct trapframe)); /* Set child return values. */ @@ -378,19 +372,22 @@ cpu_thread_clean(struct thread *td) void cpu_thread_alloc(struct thread *td) { +} + +void +cpu_thread_new_kstack(struct thread *td) +{ struct pcb *pcb; - struct xstate_hdr *xhdr; + /* + * The -VM86_STACK_SPACE (-16) is so we can expand the trapframe + * if we go to vm86. + */ td->td_pcb = pcb = get_pcb_td(td); td->td_frame = (struct trapframe *)((caddr_t)pcb - VM86_STACK_SPACE) - 1; pcb->pcb_ext = NULL; pcb->pcb_save = get_pcb_user_save_pcb(pcb); - if (use_xsave) { - xhdr = (struct xstate_hdr *)(pcb->pcb_save + 1); - bzero(xhdr, sizeof(*xhdr)); - xhdr->xstate_bv = xsave_mask; - } } void diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c index af0841c75549..e3969223c170 100644 --- a/sys/kern/imgact_elf.c +++ b/sys/kern/imgact_elf.c @@ -84,6 +84,8 @@ #define ELF_NOTE_ROUNDSIZE 4 #define OLD_EI_BRAND 8 +#define ELF_OFFPAGE_PHNUM 128 + /* * ELF_ABI_NAME is a string name of the ELF ABI. ELF_ABI_ID is used * to build variable names. @@ -93,8 +95,8 @@ static int __elfN(check_header)(const Elf_Ehdr *hdr); static const Elf_Brandinfo *__elfN(get_brandinfo)(struct image_params *imgp, - const char *interp, int32_t *osrel, uint32_t *fctl0); -static int __elfN(load_file)(struct proc *p, const char *file, u_long *addr, + const Elf_Phdr *phdr, const char *interp, int32_t *osrel, uint32_t *fctl0); +static int __elfN(load_file)(struct thread *td, const char *file, u_long *addr, u_long *entry); static int __elfN(load_section)(const struct image_params *imgp, vm_ooffset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, @@ -103,7 +105,7 @@ static int __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp); static bool __elfN(freebsd_trans_osrel)(const Elf_Note *note, int32_t *osrel); static bool kfreebsd_trans_osrel(const Elf_Note *note, int32_t *osrel); -static bool __elfN(check_note)(struct image_params *imgp, +static bool __elfN(check_note)(struct image_params *imgp, const Elf_Phdr *phdr, const Elf_Brandnote *checknote, int32_t *osrel, bool *has_fctl0, uint32_t *fctl0); static vm_prot_t __elfN(trans_prot)(Elf_Word); @@ -339,8 +341,8 @@ __elfN(brand_inuse)(const Elf_Brandinfo *entry) } static const Elf_Brandinfo * -__elfN(get_brandinfo)(struct image_params *imgp, const char *interp, - int32_t *osrel, uint32_t *fctl0) +__elfN(get_brandinfo)(struct image_params *imgp, const Elf_Phdr *phdr, + const char *interp, int32_t *osrel, uint32_t *fctl0) { const Elf_Ehdr *hdr = (const Elf_Ehdr *)imgp->image_header; const Elf_Brandinfo *bi, *bi_m; @@ -369,8 +371,8 @@ __elfN(get_brandinfo)(struct image_params *imgp, const char *interp, has_fctl0 = false; *fctl0 = 0; *osrel = 0; - ret = __elfN(check_note)(imgp, bi->brand_note, osrel, - &has_fctl0, fctl0); + ret = __elfN(check_note)(imgp, phdr, bi->brand_note, + osrel, &has_fctl0, fctl0); /* Give brand a chance to veto check_note's guess */ if (ret && bi->header_supported) { ret = bi->header_supported(imgp, osrel, @@ -780,19 +782,20 @@ __elfN(load_sections)(const struct image_params *imgp, const Elf_Ehdr *hdr, * the entry point for the loaded file. */ static int -__elfN(load_file)(struct proc *p, const char *file, u_long *addr, - u_long *entry) +__elfN(load_file)(struct thread *td, const char *file, u_long *addr, + u_long *entry) { struct { struct nameidata nd; struct vattr attr; struct image_params image_params; - } *tempdata; + } *tempdata = NULL; const Elf_Ehdr *hdr = NULL; const Elf_Phdr *phdr = NULL; struct nameidata *nd; struct vattr *attr; struct image_params *imgp; + void *m_phdrs = NULL; u_long rbase; u_long base_addr = 0; int error; @@ -802,7 +805,7 @@ __elfN(load_file)(struct proc *p, const char *file, u_long *addr, * XXXJA: This check can go away once we are sufficiently confident * that the checks in namei() are correct. */ - if (IN_CAPABILITY_MODE(curthread)) + if (IN_CAPABILITY_MODE(td)) return (ECAPMODE); #endif @@ -814,7 +817,8 @@ __elfN(load_file)(struct proc *p, const char *file, u_long *addr, /* * Initialize part of the common data */ - imgp->proc = p; + imgp->td = td; + imgp->proc = td->td_proc; imgp->attr = attr; NDINIT(nd, LOOKUP, ISOPEN | FOLLOW | LOCKSHARED | LOCKLEAF, @@ -851,24 +855,35 @@ __elfN(load_file)(struct proc *p, const char *file, u_long *addr, goto fail; } - /* Only support headers that fit within first page for now */ - if (!__elfN(phdr_in_zero_page)(hdr)) { + if (!aligned(imgp->image_header + hdr->e_phoff, Elf_Addr)) { error = ENOEXEC; goto fail; } - - phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff); - if (!aligned(phdr, Elf_Addr)) { - error = ENOEXEC; - goto fail; + if (__elfN(phdr_in_zero_page)(hdr)) { + phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff); + } else { + if (hdr->e_phnum > ELF_OFFPAGE_PHNUM) { + error = ENOEXEC; + goto fail; + } + VOP_UNLOCK(imgp->vp); + phdr = m_phdrs = malloc(hdr->e_phnum * sizeof(Elf_Phdr), + M_TEMP, M_WAITOK | M_ZERO); + vn_lock(imgp->vp, LK_SHARED | LK_RETRY); + error = vn_rdwr(UIO_READ, imgp->vp, m_phdrs, + hdr->e_phnum * sizeof(Elf_Phdr), hdr->e_phoff, + UIO_SYSSPACE, IO_NODELOCKED, imgp->td->td_ucred, + NOCRED, NULL, imgp->td); + if (error != 0) + goto fail; } error = __elfN(load_sections)(imgp, hdr, phdr, rbase, &base_addr); if (error != 0) goto fail; - if (p->p_sysent->sv_protect != NULL) - p->p_sysent->sv_protect(imgp, SVP_INTERP); + if (imgp->proc->p_sysent->sv_protect != NULL) + imgp->proc->p_sysent->sv_protect(imgp, SVP_INTERP); *addr = base_addr; *entry = (unsigned long)hdr->e_entry + rbase; @@ -882,6 +897,7 @@ fail: VOP_UNSET_TEXT_CHECKED(nd->ni_vp); vput(nd->ni_vp); } + free(m_phdrs, M_TEMP); free(tempdata, M_TEMP); return (error); @@ -1008,7 +1024,6 @@ static int __elfN(get_interp)(struct image_params *imgp, const Elf_Phdr *phdr, char **interpp, bool *free_interpp) { - struct thread *td; char *interp; int error, interp_name_len; @@ -1016,8 +1031,6 @@ __elfN(get_interp)(struct image_params *imgp, const Elf_Phdr *phdr, ("%s: p_type %u != PT_INTERP", __func__, phdr->p_type)); ASSERT_VOP_LOCKED(imgp->vp, __func__); - td = curthread; - /* Path to interpreter */ if (phdr->p_filesz < 2 || phdr->p_filesz > MAXPATHLEN) { uprintf("Invalid PT_INTERP\n"); @@ -1045,8 +1058,8 @@ __elfN(get_interp)(struct image_params *imgp, const Elf_Phdr *phdr, error = vn_rdwr(UIO_READ, imgp->vp, interp, interp_name_len, phdr->p_offset, - UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, - NOCRED, NULL, td); + UIO_SYSSPACE, IO_NODELOCKED, imgp->td->td_ucred, + NOCRED, NULL, imgp->td); if (error != 0) { free(interp, M_TEMP); uprintf("i/o error PT_INTERP %d\n", error); @@ -1079,13 +1092,13 @@ __elfN(load_interp)(struct image_params *imgp, const Elf_Brandinfo *brand_info, if (brand_info->interp_newpath != NULL && (brand_info->interp_path == NULL || strcmp(interp, brand_info->interp_path) == 0)) { - error = __elfN(load_file)(imgp->proc, + error = __elfN(load_file)(imgp->td, brand_info->interp_newpath, addr, entry); if (error == 0) return (0); } - error = __elfN(load_file)(imgp->proc, interp, addr, entry); + error = __elfN(load_file)(imgp->td, interp, addr, entry); if (error == 0) return (0); @@ -1102,7 +1115,6 @@ __elfN(load_interp)(struct image_params *imgp, const Elf_Brandinfo *brand_info, static int __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp) { - struct thread *td; const Elf_Ehdr *hdr; const Elf_Phdr *phdr; Elf_Auxargs *elf_auxargs; @@ -1111,6 +1123,7 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp) char *interp; const Elf_Brandinfo *brand_info; struct sysentvec *sv; + void *m_phdrs; u_long addr, baddr, entry, proghdr; u_long maxalign, maxsalign, mapsz, maxv, maxv1, anon_loc; uint32_t fctl0; @@ -1135,16 +1148,6 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp) * detected an ELF file. */ - if (!__elfN(phdr_in_zero_page)(hdr)) { - uprintf("Program headers not in the first page\n"); - return (ENOEXEC); - } - phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff); - if (!aligned(phdr, Elf_Addr)) { - uprintf("Unaligned program headers\n"); - return (ENOEXEC); - } - n = error = 0; baddr = 0; osrel = 0; @@ -1152,7 +1155,33 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp) entry = proghdr = 0; interp = NULL; free_interp = false; - td = curthread; + m_phdrs = NULL; + + if (!aligned(imgp->image_header + hdr->e_phoff, Elf_Addr)) { + uprintf("Unaligned program headers\n"); + return (ENOEXEC); + } + if (hdr->e_phoff + hdr->e_phnum * hdr->e_phentsize < hdr->e_phoff) { + uprintf("PHDRS wrap\n"); + return (ENOEXEC); + } + if (__elfN(phdr_in_zero_page)(hdr)) { + phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff); + } else if (hdr->e_phnum > ELF_OFFPAGE_PHNUM) { + uprintf("Too many program headers\n"); + return (ENOEXEC); + } else { + VOP_UNLOCK(imgp->vp); + phdr = m_phdrs = malloc(hdr->e_phnum * sizeof(Elf_Phdr), + M_TEMP, M_WAITOK | M_ZERO); + vn_lock(imgp->vp, LK_SHARED | LK_RETRY); + error = vn_rdwr(UIO_READ, imgp->vp, m_phdrs, + hdr->e_phnum * sizeof(Elf_Phdr), hdr->e_phoff, + UIO_SYSSPACE, IO_NODELOCKED, imgp->td->td_ucred, + NOCRED, NULL, imgp->td); + if (error != 0) + goto ret; + } /* * Somewhat arbitrary, limit accepted max alignment for the @@ -1234,7 +1263,7 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp) } } - brand_info = __elfN(get_brandinfo)(imgp, interp, &osrel, &fctl0); + brand_info = __elfN(get_brandinfo)(imgp, phdr, interp, &osrel, &fctl0); if (brand_info == NULL) { uprintf("ELF binary type \"%u\" not known.\n", hdr->e_ident[EI_OSABI]); @@ -1329,7 +1358,7 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp) map = &vmspace->vm_map; maxv = sv->sv_usrstack; if ((imgp->map_flags & MAP_ASLR_STACK) == 0) - maxv -= lim_max(td, RLIMIT_STACK); + maxv -= lim_max(imgp->td, RLIMIT_STACK); if (error == 0 && mapsz >= maxv - vm_map_min(map)) { uprintf("Excessive mapping size\n"); error = ENOEXEC; @@ -1339,7 +1368,7 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp) KASSERT((map->flags & MAP_ASLR) != 0, ("ET_DYN_ADDR_RAND but !MAP_ASLR")); error = __CONCAT(rnd_, __elfN(base))(map, - vm_map_min(map) + mapsz + lim_max(td, RLIMIT_DATA), + vm_map_min(map) + mapsz + lim_max(imgp->td, RLIMIT_DATA), /* reserve half of the address space to interpreter */ maxv / 2, maxalign, &imgp->et_dyn_addr); } @@ -1362,7 +1391,7 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp) * calculation is that it leaves room for the heap to grow to * its maximum allowed size. */ - addr = round_page((vm_offset_t)vmspace->vm_daddr + lim_max(td, + addr = round_page((vm_offset_t)vmspace->vm_daddr + lim_max(imgp->td, RLIMIT_DATA)); if ((map->flags & MAP_ASLR) != 0) { maxv1 = maxv / 2 + addr / 2; @@ -1438,6 +1467,7 @@ ret: ASSERT_VOP_LOCKED(imgp->vp, "skipped relock"); if (free_interp) free(interp, M_TEMP); + free(m_phdrs, M_TEMP); return (error); } @@ -2809,7 +2839,7 @@ __elfN(parse_notes)(const struct image_params *imgp, const Elf_Note *checknote, } error = vn_rdwr(UIO_READ, imgp->vp, buf, pnote->p_filesz, pnote->p_offset, UIO_SYSSPACE, IO_NODELOCKED, - curthread->td_ucred, NOCRED, NULL, curthread); + imgp->td->td_ucred, NOCRED, NULL, imgp->td); if (error != 0) { uprintf("i/o error PT_NOTE\n"); goto retf; @@ -2918,17 +2948,16 @@ note_fctl_cb(const Elf_Note *note, void *arg0, bool *res) * as for headers. */ static bool -__elfN(check_note)(struct image_params *imgp, const Elf_Brandnote *brandnote, - int32_t *osrel, bool *has_fctl0, uint32_t *fctl0) +__elfN(check_note)(struct image_params *imgp, const Elf_Phdr *phdr, + const Elf_Brandnote *brandnote, int32_t *osrel, bool *has_fctl0, + uint32_t *fctl0) { - const Elf_Phdr *phdr; const Elf_Ehdr *hdr; struct brandnote_cb_arg b_arg; struct fctl_cb_arg f_arg; int i, j; hdr = (const Elf_Ehdr *)imgp->image_header; - phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff); b_arg.brandnote = brandnote; b_arg.osrel = osrel; f_arg.has_fctl0 = has_fctl0; diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 958ec559fd8d..4066682cbcc5 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -448,6 +448,7 @@ do_execve(struct thread *td, struct image_args *args, struct mac *mac_p, */ bzero(imgp, sizeof(*imgp)); imgp->proc = p; + imgp->td = td; imgp->attr = &attr; imgp->args = args; oldcred = p->p_ucred; diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c index ec65bd16dd50..15a327e66c7d 100644 --- a/sys/kern/kern_thread.c +++ b/sys/kern/kern_thread.c @@ -803,6 +803,7 @@ thread_alloc(int pages) kasan_thread_alloc(td); kmsan_thread_alloc(td); cpu_thread_alloc(td); + cpu_thread_new_kstack(td); EVENTHANDLER_DIRECT_INVOKE(thread_ctor, td); return (td); } @@ -815,7 +816,7 @@ thread_recycle(struct thread *td, int pages) vm_thread_dispose(td); if (!vm_thread_new(td, pages)) return (ENOMEM); - cpu_thread_alloc(td); + cpu_thread_new_kstack(td); } kasan_thread_alloc(td); kmsan_thread_alloc(td); diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index b3e1d4be9fee..1032f6cd1bf0 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -1430,7 +1430,7 @@ _Out_ _Contains_timet_ struct ffclock_estimate *cest ); } -244 AUE_NULL STD { +244 AUE_NULL STD|CAPENABLED { int clock_nanosleep( clockid_t clock_id, int flags, diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 66d2c610139f..84b175b42eec 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -2805,7 +2805,6 @@ in_pcbrehash(struct inpcb *inp) struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; struct inpcbhead *head; uint32_t hash; - bool connected; INP_WLOCK_ASSERT(inp); INP_HASH_WLOCK_ASSERT(pcbinfo); @@ -2815,34 +2814,24 @@ in_pcbrehash(struct inpcb *inp) #ifdef INET6 if (inp->inp_vflag & INP_IPV6) { + MPASS(!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)); hash = INP6_PCBHASH(&inp->in6p_faddr, inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask); - connected = !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr); } else #endif { + MPASS(!in_nullhost(inp->inp_faddr)); hash = INP_PCBHASH(&inp->inp_faddr, inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask); - connected = !in_nullhost(inp->inp_faddr); } /* See the comment in in_pcbinshash(). */ - if (connected && (inp->inp_flags & INP_INLBGROUP) != 0) + if ((inp->inp_flags & INP_INLBGROUP) != 0) in_pcbremlbgrouphash(inp); - /* - * When rehashing, the caller must ensure that either the new or the old - * foreign address was unspecified. - */ - if (connected) { - CK_LIST_REMOVE(inp, inp_hash_wild); - head = &pcbinfo->ipi_hash_exact[hash]; - CK_LIST_INSERT_HEAD(head, inp, inp_hash_exact); - } else { - CK_LIST_REMOVE(inp, inp_hash_exact); - head = &pcbinfo->ipi_hash_wild[hash]; - CK_LIST_INSERT_HEAD(head, inp, inp_hash_wild); - } + CK_LIST_REMOVE(inp, inp_hash_wild); + head = &pcbinfo->ipi_hash_exact[hash]; + CK_LIST_INSERT_HEAD(head, inp, inp_hash_exact); } void diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index 8132899bb0d9..0cf6be2f9b33 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -465,15 +465,6 @@ in6_pcbconnect(struct inpcb *inp, struct sockaddr_in6 *sin6, struct ucred *cred, bzero(&laddr6, sizeof(laddr6)); laddr6.sin6_family = AF_INET6; - if (V_fib_hash_outbound) { - uint32_t hash_type, hash_val; - - hash_val = fib6_calc_software_hash(&inp->in6p_laddr, - &sin6->sin6_addr, 0, sin6->sin6_port, - inp->inp_socket->so_proto->pr_protocol, &hash_type); - inp->inp_flowid = hash_val; - inp->inp_flowtype = hash_type; - } /* * Call inner routine, to assign local interface address. * in6_pcbladdr() may automatically fill in sin6_scope_id. @@ -520,6 +511,16 @@ in6_pcbconnect(struct inpcb *inp, struct sockaddr_in6 *sin6, struct ucred *cred, in_pcbrehash(inp); INP_HASH_WUNLOCK(pcbinfo); + if (V_fib_hash_outbound) { + uint32_t hash_type, hash_val; + + hash_val = fib6_calc_software_hash(&inp->in6p_laddr, + &sin6->sin6_addr, 0, sin6->sin6_port, + inp->inp_socket->so_proto->pr_protocol, &hash_type); + inp->inp_flowid = hash_val; + inp->inp_flowtype = hash_type; + } + return (0); } diff --git a/sys/netlink/route/rt.c b/sys/netlink/route/rt.c index ee17737426ed..17aae399c10a 100644 --- a/sys/netlink/route/rt.c +++ b/sys/netlink/route/rt.c @@ -217,7 +217,7 @@ dump_rc_nhg(struct nl_writer *nw, const struct route_nhop_data *rnd, struct rtms return; rtnh->rtnh_flags = 0; rtnh->rtnh_ifindex = if_getindex(wn[i].nh->nh_ifp); - rtnh->rtnh_hops = wn[i].weight; + rtnh->rtnh_hops = MIN(wn[i].weight, UINT8_MAX); dump_rc_nhop_gw(nw, wn[i].nh); uint32_t rtflags = nhop_get_rtflags(wn[i].nh); if (rtflags != base_rtflags) @@ -242,7 +242,8 @@ dump_rc_nhg(struct nl_writer *nw, const struct route_nhop_data *rnd, struct rtms } nlattr_set_len(nw, off); nlattr_add_u32(nw, NL_RTA_PRIORITY, nhop_metric); - nlattr_add_u32(nw, NL_RTA_WEIGHT, nhop_weight); + if (nhop_weight != RT_DEFAULT_WEIGHT) + nlattr_add_u32(nw, NL_RTA_WEIGHT, nhop_weight); } static void diff --git a/sys/powerpc/include/stack.h b/sys/powerpc/include/stack.h index 928256b26468..533ff0fa2056 100644 --- a/sys/powerpc/include/stack.h +++ b/sys/powerpc/include/stack.h @@ -38,7 +38,7 @@ extern int end[]; /* Get the current kernel thread stack usage. */ #define GET_STACK_USAGE(total, used) do { \ struct thread *td = curthread; \ - (total) = td->td_kstack_pages * PAGE_SIZE - sizeof(struct pcb); \ + (total) = ptoa(td->td_kstack_pages) - sizeof(struct pcb); \ (used) = td->td_kstack + (total) - (char *)&td; \ } while (0) @@ -46,8 +46,7 @@ static __inline bool kstack_contains(struct thread *td, vm_offset_t va, size_t len) { return (va >= (vm_offset_t)td->td_kstack && va + len >= va && - va + len <= (vm_offset_t)td->td_kstack + td->td_kstack_pages * - PAGE_SIZE - sizeof(struct pcb)); + va + len <= (vm_offset_t)td_kstack_top(td) - sizeof(struct pcb)); } #endif /* _SYS_PROC_H_ */ diff --git a/sys/powerpc/powerpc/exec_machdep.c b/sys/powerpc/powerpc/exec_machdep.c index 00c04b4ddbaa..18e0ba004a13 100644 --- a/sys/powerpc/powerpc/exec_machdep.c +++ b/sys/powerpc/powerpc/exec_machdep.c @@ -1080,10 +1080,15 @@ cpu_thread_clean(struct thread *td) void cpu_thread_alloc(struct thread *td) { +} + +void +cpu_thread_new_kstack(struct thread *td) +{ struct pcb *pcb; - pcb = (struct pcb *)__align_down(td->td_kstack + td->td_kstack_pages * - PAGE_SIZE - sizeof(struct pcb), 0x40); + pcb = (struct pcb *)__align_down(td_kstack_top(td) - sizeof(struct pcb), + 0x40); td->td_pcb = pcb; td->td_frame = (struct trapframe *)pcb - 1; } diff --git a/sys/powerpc/powerpc/machdep.c b/sys/powerpc/powerpc/machdep.c index a975bebebaad..e1e0885e3ecf 100644 --- a/sys/powerpc/powerpc/machdep.c +++ b/sys/powerpc/powerpc/machdep.c @@ -487,8 +487,8 @@ powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp, /* * Finish setting up thread0. */ - thread0.td_pcb = (struct pcb *)__align_down(thread0.td_kstack + - thread0.td_kstack_pages * PAGE_SIZE - sizeof(struct pcb), 16); + thread0.td_pcb = (struct pcb *)__align_down(td_kstack_top(&thread0) - + sizeof(struct pcb), 16); bzero((void *)thread0.td_pcb, sizeof(struct pcb)); pc->pc_curpcb = thread0.td_pcb; diff --git a/sys/powerpc/powerpc/vm_machdep.c b/sys/powerpc/powerpc/vm_machdep.c index 00fdc301a7e7..1dc28739ad7c 100644 --- a/sys/powerpc/powerpc/vm_machdep.c +++ b/sys/powerpc/powerpc/vm_machdep.c @@ -123,9 +123,7 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) if (td1 == curthread) cpu_update_pcb(td1); - pcb = (struct pcb *)__align_down(td2->td_kstack + - td2->td_kstack_pages * PAGE_SIZE - sizeof(struct pcb), 0x40); - td2->td_pcb = pcb; + pcb = td2->td_pcb; /* Copy the pcb */ bcopy(td1->td_pcb, pcb, sizeof(struct pcb)); @@ -135,7 +133,7 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) * Copy the trap frame for the return to user mode as if from a * syscall. This copies most of the user mode register values. */ - tf = (struct trapframe *)pcb - 1; + tf = td2->td_frame; bcopy(td1->td_frame, tf, sizeof(*tf)); /* Set up trap frame. */ @@ -143,8 +141,6 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) tf->fixreg[FIRSTARG + 1] = 0; tf->cr &= ~0x10000000; - td2->td_frame = tf; - cf = (struct callframe *)tf - 1; memset(cf, 0, sizeof(struct callframe)); #if defined(__powerpc64__) && (!defined(_CALL_ELF) || _CALL_ELF == 1) diff --git a/sys/riscv/include/stack.h b/sys/riscv/include/stack.h index 03b5794c2b13..fac8d4f317b6 100644 --- a/sys/riscv/include/stack.h +++ b/sys/riscv/include/stack.h @@ -48,12 +48,10 @@ bool unwind_frame(struct thread *, struct unwind_state *); #ifdef _SYS_PROC_H_ -#include <machine/pcb.h> - /* Get the current kernel thread stack usage. */ #define GET_STACK_USAGE(total, used) do { \ struct thread *td = curthread; \ - (total) = td->td_kstack_pages * PAGE_SIZE - sizeof(struct pcb); \ + (total) = ptoa(td->td_kstack_pages); \ (used) = td->td_kstack + (total) - (char *)&td; \ } while (0) @@ -61,8 +59,7 @@ static __inline bool kstack_contains(struct thread *td, vm_offset_t va, size_t len) { return (va >= (vm_offset_t)td->td_kstack && va + len >= va && - va + len <= (vm_offset_t)td->td_kstack + td->td_kstack_pages * - PAGE_SIZE - sizeof(struct pcb)); + va + len <= (vm_offset_t)td_kstack_top(td)); } #endif /* _SYS_PROC_H_ */ diff --git a/sys/riscv/riscv/genassym.c b/sys/riscv/riscv/genassym.c index c216c686db9a..998183e92db6 100644 --- a/sys/riscv/riscv/genassym.c +++ b/sys/riscv/riscv/genassym.c @@ -63,7 +63,6 @@ ASSYM(PMAP_MAPDEV_EARLY_SIZE, PMAP_MAPDEV_EARLY_SIZE); ASSYM(PM_SATP, offsetof(struct pmap, pm_satp)); ASSYM(PCB_ONFAULT, offsetof(struct pcb, pcb_onfault)); -ASSYM(PCB_SIZE, sizeof(struct pcb)); ASSYM(PCB_RA, offsetof(struct pcb, pcb_ra)); ASSYM(PCB_SP, offsetof(struct pcb, pcb_sp)); ASSYM(PCB_GP, offsetof(struct pcb, pcb_gp)); diff --git a/sys/riscv/riscv/locore.S b/sys/riscv/riscv/locore.S index 305ed8d79f10..e2126af5cad2 100644 --- a/sys/riscv/riscv/locore.S +++ b/sys/riscv/riscv/locore.S @@ -241,8 +241,8 @@ va: /* Clear frame pointer */ mv s0, zero - /* Allocate space for thread0 PCB and riscv_bootparams */ - addi sp, sp, -(PCB_SIZE + RISCV_BOOTPARAMS_SIZE) & ~STACKALIGNBYTES + /* Allocate space for riscv_bootparams */ + addi sp, sp, -RISCV_BOOTPARAMS_SIZE & ~STACKALIGNBYTES /* Clear BSS */ la t0, _C_LABEL(__bss_start) diff --git a/sys/riscv/riscv/machdep.c b/sys/riscv/riscv/machdep.c index 91219676454b..f5479c479109 100644 --- a/sys/riscv/riscv/machdep.c +++ b/sys/riscv/riscv/machdep.c @@ -105,6 +105,7 @@ struct pcpu __pcpu[MAXCPU]; static struct trapframe proc0_tf; +static struct pcb pcb0; int early_boot = 1; int cold = 1; @@ -296,8 +297,7 @@ init_proc0(void *kstack) proc_linkup0(&proc0, &thread0); thread0.td_kstack = kstack; thread0.td_kstack_pages = KSTACK_PAGES; - thread0.td_pcb = (struct pcb *)(thread0.td_kstack + - thread0.td_kstack_pages * PAGE_SIZE) - 1; + thread0.td_pcb = &pcb0; thread0.td_pcb->pcb_fpflags = 0; thread0.td_frame = &proc0_tf; pcpup->pc_curpcb = thread0.td_pcb; diff --git a/sys/riscv/riscv/vm_machdep.c b/sys/riscv/riscv/vm_machdep.c index 206110157233..e538921c9f60 100644 --- a/sys/riscv/riscv/vm_machdep.c +++ b/sys/riscv/riscv/vm_machdep.c @@ -32,8 +32,8 @@ * SUCH DAMAGE. */ -#include <sys/param.h> #include <sys/systm.h> +#include <sys/kernel.h> #include <sys/limits.h> #include <sys/proc.h> #include <sys/sf_buf.h> @@ -58,24 +58,23 @@ #define TP_OFFSET 16 /* sizeof(struct tcb) */ #endif -static void -cpu_set_pcb_frame(struct thread *td) -{ - td->td_pcb = (struct pcb *)(td->td_kstack + - td->td_kstack_pages * PAGE_SIZE) - 1; +static uma_zone_t pcb_zone; +void +cpu_thread_new_kstack(struct thread *td) +{ /* * td->td_frame + TF_SIZE will be the saved kernel stack pointer whilst * in userspace, so keep it aligned so it's also aligned when we * subtract TF_SIZE in the trap handler (and here for the initial stack * pointer). This also keeps the struct kernframe just afterwards - * aligned no matter what's in it or struct pcb. + * aligned no matter what's in it. * * NB: TF_SIZE not sizeof(struct trapframe) as we need the rounded * value to match the trap handler. */ td->td_frame = (struct trapframe *)(STACKALIGN( - (char *)td->td_pcb - sizeof(struct kernframe)) - TF_SIZE); + td_kstack_top(td) - sizeof(struct kernframe)) - TF_SIZE); } /* @@ -100,8 +99,6 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) critical_exit(); } - cpu_set_pcb_frame(td2); - pcb2 = td2->td_pcb; bcopy(td1->td_pcb, pcb2, sizeof(*pcb2)); @@ -230,12 +227,13 @@ cpu_thread_exit(struct thread *td) void cpu_thread_alloc(struct thread *td) { - cpu_set_pcb_frame(td); + td->td_pcb = uma_zalloc(pcb_zone, M_WAITOK); } void cpu_thread_free(struct thread *td) { + uma_zfree(pcb_zone, td->td_pcb); } void @@ -289,3 +287,11 @@ cpu_sync_core(void) { fence_i(); } + +static void +pcbinit(void *dummy __unused) +{ + pcb_zone = uma_zcreate("pcb", sizeof(struct pcb), NULL, NULL, NULL, + NULL, UMA_ALIGNOF(struct pcb), 0); +} +SYSINIT(pcbinit, SI_SUB_INTRINSIC, SI_ORDER_ANY, pcbinit, NULL); diff --git a/sys/security/mac_do/mac_do.c b/sys/security/mac_do/mac_do.c index ba49da22ce67..93f2084d1c93 100644 --- a/sys/security/mac_do/mac_do.c +++ b/sys/security/mac_do/mac_do.c @@ -1,8 +1,9 @@ -/*- +/* * SPDX-License-Identifier: BSD-2-Clause * - * Copyright(c) 2024 Baptiste Daroussin <bapt@FreeBSD.org> - * Copyright (c) 2024 The FreeBSD Foundation + * Copyright (c) 2024 Baptiste Daroussin <bapt@FreeBSD.org> + * Copyright (c) 2024, 2026, The FreeBSD Foundation + * Copyright (c) 2025 Kushagra Srivastava <kushagra1403@gmail.com> * * Portions of this software were developed by Olivier Certner * <olce.freebsd@certner.fr> at Kumacom SARL under sponsorship from the FreeBSD @@ -23,6 +24,7 @@ #include <sys/priv.h> #include <sys/proc.h> #include <sys/refcount.h> +#include <sys/rmlock.h> #include <sys/socket.h> #include <sys/stdarg.h> #include <sys/sx.h> @@ -32,6 +34,24 @@ #include <security/mac/mac_policy.h> + +#ifdef INVARIANTS +/* + * Should typically be moved to libkern (and perhaps libc) at some point, and be + * optimized if to be used outside of INVARIANTS. + */ +static bool +is_zeroed(const void *const buf, const size_t size) +{ + const char *const p = buf; + + for (size_t i = 0; i < size; ++i) + if (p[i] != 0) + return (false); + return (true); +} +#endif + static SYSCTL_NODE(_security_mac, OID_AUTO, do, CTLFLAG_RW|CTLFLAG_MPSAFE, 0, "mac_do policy controls"); @@ -46,7 +66,16 @@ SYSCTL_INT(_security_mac_do, OID_AUTO, print_parse_error, CTLFLAG_RWTUN, static MALLOC_DEFINE(M_MAC_DO, "mac_do", "mac_do(4) security module"); -#define MAC_RULE_STRING_LEN 1024 +#define MAX_RULE_STRING_SIZE 1024 +_Static_assert(MAX_RULE_STRING_SIZE > 0, + "MAX_RULE_STRING_SIZE: No space for the NUL terminator!"); + +#define MAX_EXEC_PATHS_SIZE 2048 +#define MAX_EXEC_PATHS 8 +_Static_assert(MAX_EXEC_PATHS_SIZE > 0, + "MAX_EXEC_PATHS_SIZE: No space for the NUL terminator!"); + +struct rmlock mac_do_rml; static unsigned osd_jail_slot; static unsigned osd_thread_slot; @@ -67,6 +96,11 @@ static const char *id_type_to_str[] = { #define PARSE_ERROR_SIZE 256 +/* + * All functions having a parse error parameter must return through it a parse + * error object if and only if they return an error value (non-zero); else, NULL + * must be returned through it. + */ struct parse_error { size_t pos; char msg[PARSE_ERROR_SIZE]; @@ -123,11 +157,15 @@ typedef uint16_t flags_t; #define MDF_MAY_REJ_SUPP (1u << 11) /* (t,gid) Some explicit ID (not MDF_CURRENT) has MDF_SUPP_MUST. */ #define MDF_EXPLICIT_SUPP_MUST (1u << 12) -/* (t,gid) Whether any target clause is about primary groups. Used during - * parsing only. */ +/* + * (t,gid) Whether any target clause is about primary groups. Used during + * parsing only. + */ #define MDF_HAS_PRIMARY_CLAUSE (1u << 13) -/* (t,gid) Whether any target clause is about supplementary groups. Used during - * parsing only. */ +/* + * (t,gid) Whether any target clause is about supplementary groups. Used during + * parsing only. + */ #define MDF_HAS_SUPP_CLAUSE (1u << 14) #define MDF_TYPE_GID_MASK (MDF_ANY_SUPP | MDF_MAY_REJ_SUPP | \ MDF_EXPLICIT_SUPP_MUST | MDF_HAS_PRIMARY_CLAUSE | MDF_HAS_SUPP_CLAUSE) @@ -144,7 +182,7 @@ struct id_spec { /* * This limits the number of target clauses per type to 65535. With the current - * value of MAC_RULE_STRING_LEN (1024), this is way more than enough anyway. + * value of MAX_RULE_STRING_SIZE (1024), this is way more than enough anyway. */ typedef uint16_t id_nb_t; /* We only have a few IT_* types. */ @@ -165,8 +203,24 @@ struct rule { STAILQ_HEAD(rulehead, rule); struct rules { - char string[MAC_RULE_STRING_LEN]; + char string[MAX_RULE_STRING_SIZE]; struct rulehead head; +}; + +struct exec_paths { + char exec_paths_str[MAX_EXEC_PATHS_SIZE]; + char exec_paths[MAX_EXEC_PATHS][PATH_MAX]; + int exec_path_count; +}; + +/* + * Once in use, i.e., being pointed to by a jail, a configuration structure MUST + * NEVER CHANGE (except for the 'use_count' field). This invariant is + * fundamental to correctness! + */ +struct conf { + struct rules rules; + struct exec_paths exec_paths; volatile u_int use_count __aligned(CACHE_LINE_SIZE); }; @@ -181,6 +235,7 @@ struct id_elem { STAILQ_HEAD(id_list, id_elem); + #ifdef INVARIANTS static void check_type(const id_type_t type) @@ -221,7 +276,7 @@ check_type_and_id_flags(const id_type_t type, const flags_t flags) } break; default: - __assert_unreachable(); + __assert_unreachable(); } return; @@ -281,6 +336,18 @@ unexpected_flags: #define check_type_and_type_flags(...) #endif /* INVARIANTS */ +static bool +has_rules(const struct rules *const rules) +{ + return (rules->string[0] != '\0'); +} + +static bool +has_exec_paths(const struct exec_paths *const exec_paths) +{ + return (exec_paths->exec_paths_str[0] != '\0'); +} + /* * Returns EALREADY if both flags have some overlap, or EINVAL if flags are * incompatible, else 0 with flags successfully merged into 'dest'. @@ -323,23 +390,36 @@ toast_rules(struct rules *const rules) free(rule->gids, M_MAC_DO); free(rule, M_MAC_DO); } - free(rules, M_MAC_DO); } -static struct rules * -alloc_rules(void) +static inline void +init_rules(struct rules *const rules) { - struct rules *const rules = malloc(sizeof(*rules), M_MAC_DO, M_WAITOK); - - _Static_assert(MAC_RULE_STRING_LEN > 0, "MAC_RULE_STRING_LEN <= 0!"); - rules->string[0] = 0; + MPASS(is_zeroed(rules, sizeof(*rules))); STAILQ_INIT(&rules->head); - rules->use_count = 0; - return (rules); +} + +static inline void +init_exec_paths(struct exec_paths *const exec_paths) +{ + MPASS(is_zeroed(exec_paths, sizeof(*exec_paths))); +} + +static struct conf * +new_conf(void) +{ + struct conf *const conf = malloc(sizeof(*conf), M_MAC_DO, + M_WAITOK | M_ZERO); + + init_rules(&conf->rules); + init_exec_paths(&conf->exec_paths); + refcount_init(&conf->use_count, 1); + + return (conf); } static bool -is_null_or_empty(const char *s) +is_null_or_empty(const char *const s) { return (s == NULL || s[0] == '\0'); } @@ -433,7 +513,8 @@ static void make_parse_error(struct parse_error **const parse_error, const size_t pos, const char *const fmt, ...) { - struct parse_error *const err = malloc(sizeof(*err), M_MAC_DO, M_WAITOK); + struct parse_error *const err = malloc(sizeof(*err), M_MAC_DO, + M_WAITOK); va_list ap; err->pos = pos; @@ -740,6 +821,7 @@ parse_target_clause(char *to, struct rule *const rule, check_type_and_finish: check_type_and_type_flags(type, *tflags); finish: + MPASS(error == 0 && *parse_error == NULL); return (0); einval: /* We must have built a parse error on error. */ @@ -817,7 +899,7 @@ pour_list_into_rule(const id_type_t type, struct id_list *const list, make_parse_error(parse_error, 0, "Incompatible flags or duplicate " "GID %u.", id); - return (EINVAL); + goto einval; } check_type_and_id_flags(type, array[ref_idx].flags); @@ -831,7 +913,7 @@ pour_list_into_rule(const id_type_t type, struct id_list *const list, */ make_parse_error(parse_error, 0, "Duplicate UID %u.", id); - return (EINVAL); + goto einval; default: __assert_unreachable(); @@ -840,7 +922,12 @@ pour_list_into_rule(const id_type_t type, struct id_list *const list, *nb = ref_idx + 1; } + MPASS(*parse_error == NULL); return (0); + +einval: + MPASS(*parse_error != NULL); + return (EINVAL); } /* @@ -966,6 +1053,7 @@ parse_single_rule(char *rule, struct rules *const rules, } STAILQ_INSERT_TAIL(&rules->head, new, r_entries); + MPASS(error == 0 && *parse_error == NULL); return (0); einval: @@ -983,13 +1071,13 @@ einval: /* * Parse rules specification and produce rule structures out of it. * - * Returns 0 on success, with '*rulesp' made to point to a 'struct rule' - * representing the rules. On error, the returned value is non-zero and - * '*rulesp' is unchanged. If 'string' has length greater or equal to - * MAC_RULE_STRING_LEN, ENAMETOOLONG is returned. If it is not in the expected - * format, EINVAL is returned. If an error is returned, '*parse_error' is set - * to point to a 'struct parse_error' giving an error message for the problem, - * else '*parse_error' is set to NULL. + * Must be called with '*parse_error' set to NULL. Returns 0 on success, with + * '*rulesp' made to point to a 'struct rule' representing the rules. On error, + * the returned value is non-zero and '*rulesp' is unchanged. If 'string' has + * length greater or equal to MAX_RULE_STRING_SIZE, ENAMETOOLONG is returned. If + * it is not in the expected format, EINVAL is returned. If an error is + * returned, '*parse_error' is set to point to a 'struct parse_error' giving an + * error message for the problem. * * Expected format: A >-colon-separated list of rules of the form * "<from>><target>" (for backwards compatibility, a semi-colon ":" is accepted @@ -1007,24 +1095,20 @@ einval: * - "gid=1010>gid=1011,gid=1012,gid=1013" */ static int -parse_rules(const char *const string, struct rules **const rulesp, +parse_rules(const char *const string, struct rules *const rules, struct parse_error **const parse_error) { const size_t len = strlen(string); char *copy, *p, *rule; - struct rules *rules; int error = 0; - *parse_error = NULL; - - if (len >= MAC_RULE_STRING_LEN) { + if (len >= MAX_RULE_STRING_SIZE) { make_parse_error(parse_error, 0, "Rule specification string is too long (%zu, max %zu)", - len, MAC_RULE_STRING_LEN - 1); + len, MAX_RULE_STRING_SIZE - 1); return (ENAMETOOLONG); } - rules = alloc_rules(); bcopy(string, rules->string, len + 1); MPASS(rules->string[len] == '\0'); /* Catch some races. */ @@ -1040,72 +1124,188 @@ parse_rules(const char *const string, struct rules **const rulesp, if (error != 0) { (*parse_error)->pos += rule - copy; toast_rules(rules); - goto out; + goto error; + } + } + + MPASS(error == 0 && *parse_error == NULL); +out: + free(copy, M_MAC_DO); + return (error); +error: + MPASS(error != 0 && *parse_error != NULL); + goto out; +} + +/* + * Similar constraints as parse_rules() (which see). + */ +static int +parse_exec_paths(const char *const string, struct exec_paths *const exec_paths, + struct parse_error **const parse_error) +{ + const size_t len = strlen(string); + char *copy, *p, *path; + int error = 0; + + if (len >= MAX_EXEC_PATHS_SIZE) { + make_parse_error(parse_error, 0, + "Exec path specification string is too long (%zu, max %u)", + len, MAX_EXEC_PATHS_SIZE - 1); + return (ENAMETOOLONG); + } + + bcopy(string, exec_paths->exec_paths_str, len + 1); + MPASS(exec_paths->exec_paths_str[len] == '\0'); + + copy = malloc(len + 1, M_MAC_DO, M_WAITOK); + bcopy(string, copy, len + 1); + MPASS(copy[len] == '\0'); + + p = copy; + while ((path = strsep(&p, ":")) != NULL) { + size_t path_len; + + if (*path == '\0') + continue; + + if (exec_paths->exec_path_count >= MAX_EXEC_PATHS) { + make_parse_error(parse_error, path - copy, + "Too many exec paths specified (max %d)", + MAX_EXEC_PATHS); + error = EINVAL; + goto error; } + + path_len = strlen(path); + if (path_len >= PATH_MAX) { + make_parse_error(parse_error, path - copy, + "Exec paths too long (%zu, max %u)", + path_len, PATH_MAX - 1); + error = ENAMETOOLONG; + goto error; + } + + strlcpy(exec_paths->exec_paths[exec_paths->exec_path_count], + path, PATH_MAX); + exec_paths->exec_path_count++; } - *rulesp = rules; + MPASS(error == 0 && *parse_error == NULL); out: free(copy, M_MAC_DO); return (error); +error: + MPASS(error != 0 && *parse_error != NULL); + goto out; +} + +static void +hold_conf(struct conf *const conf) +{ + int old_count __diagused = refcount_acquire(&conf->use_count); + + KASSERT(old_count != 0, + ("MAC/do: Trying to resurrect a destroyed configuration.")); +} + +static void +drop_conf(struct conf *const conf) +{ + if (refcount_release(&conf->use_count)) { + toast_rules(&conf->rules); + free(conf, M_MAC_DO); + } } /* - * Find rules applicable to the passed prison. + * Find configuration applicable to the passed prison. + * + * Returns the applicable configuration (which always exists), with an + * additional reference that must be freed by the caller. 'pr' must not be + * locked. + * + * The applicable configuration is that of the closest ancestor prison + * (including itself) of the passed prison that actually has a 'struct conf' + * associated to it. * - * Returns the applicable rules (and never NULL). 'pr' must be unlocked. - * 'aprp' is set to the (ancestor) prison holding these, and it must be unlocked - * once the caller is done accessing the rules. '*aprp' is equal to 'pr' if and - * only if the current jail has its own set of rules. + * If 'hpr' is not NULL, it is used to return a pointer to the (unlocked) prison + * holding the applicable configuration. + * + * The find_conf_unlocked() variant needs 'mac_do_rml' to be (read- or write-) + * locked. The find_conf() variant will take a read lock for the duration of + * the search. + * + * The configuration returned by this function is sequentially consistent with + * other concurrent reads and configuration modifications, even in the presence + * of concurrent changes of configurations higher up in the jail tree (whether + * they "change" the value of some parameters, install a new configuration where + * there wasn't any, breaking inheritance from higher up, or remove an existing + * one, establishing inheritance from higher up). */ -static struct rules * -find_rules(struct prison *const pr, struct prison **const aprp) +static struct conf * +find_conf_locked(struct prison *const pr, struct prison **const hpr) { - struct prison *cpr, *ppr; - struct rules *rules; + struct prison *cpr, *ppr; /* Current and parent. */ + struct conf *conf; + rm_assert(&mac_do_rml, RA_LOCKED); + /* + * We do not need to take any locks here to climb the prison tree as + * either the start prison ('pr') is that of the current thread (and our + * ancestors are necessarily stable), or it is a prison passed by the jail + * machinery to an OSD method, in which case the prison tree lock is + * already being held. + */ cpr = pr; for (;;) { - prison_lock(cpr); - rules = osd_jail_get(cpr, osd_jail_slot); - if (rules != NULL) + conf = osd_jail_get_unlocked(cpr, osd_jail_slot); + if (conf != NULL) break; - prison_unlock(cpr); ppr = cpr->pr_parent; - MPASS(ppr != NULL); /* prison0 always has rules. */ + /* + * 'prison0' always has a mac_do(4) configuration because we + * installed one on module load/activation and nothing can + * destroy it as 'prison0' is not a regular jail and the + * 'mac.do' parameter cannot be set to 'inherit' on it, which is + * the only way to clear an existing configuration. + */ + KASSERT(ppr != NULL, + ("MAC/do: 'prison0' must always have a configuration.")); cpr = ppr; } - *aprp = cpr; - return (rules); + hold_conf(conf); + if (hpr != NULL) + *hpr = cpr; + return (conf); } -static void -hold_rules(struct rules *const rules) +static struct conf * +find_conf(struct prison *const pr, struct prison **const hpr) { - refcount_acquire(&rules->use_count); -} + struct conf *conf; + struct rm_priotracker rmpt; -static void -drop_rules(struct rules *const rules) -{ - if (refcount_release(&rules->use_count)) - toast_rules(rules); + rm_rlock(&mac_do_rml, &rmpt); + conf = find_conf_locked(pr, hpr); + rm_runlock(&mac_do_rml, &rmpt); + return (conf); } #ifdef INVARIANTS static void -check_rules_use_count(const struct rules *const rules, u_int expected) +check_conf_use_count(const struct conf *const conf, u_int expected) { - const u_int use_count = refcount_load(&rules->use_count); + const u_int use_count = refcount_load(&conf->use_count); if (use_count != expected) - panic("MAC/do: Rules at %p: Use count is %u, expected %u", - rules, use_count, expected); + panic("MAC/do: Configuration at %p: Use count is %u, " + "expected %u", conf, use_count, expected); } #else -#define check_rules_use_count(...) +#define check_conf_use_count(...) #endif /* INVARIANTS */ /* @@ -1117,7 +1317,7 @@ check_rules_use_count(const struct rules *const rules, u_int expected) static void dealloc_jail_osd(void *const value) { - struct rules *const rules = value; + struct conf *const conf = value; /* * If called because the "holding" jail goes down, no one should be @@ -1133,124 +1333,259 @@ dealloc_jail_osd(void *const value) * we ensure that all thread's slots are freed first in mac_do_destroy() * to be able to check that only one reference remains. */ - check_rules_use_count(rules, 1); - toast_rules(rules); + check_conf_use_count(conf, 1); + drop_conf(conf); +} + +/* + * Sets a mac_do(4) configuration on a jail. + * + * 'conf' is the new conf to set (can be NULL), and an additional reference will + * be taken on it to represent the jail holding it (if not NULL). 'rsv' must + * have been allocated through osd_reserve() (if 'conf' is not NULL; else can + * be NULL). + * + * The previous configuration on the jail (or NULL) is returned (with an + * associated reference if not NULL). + */ +static struct conf * +set_conf_locked(struct prison *const pr, struct conf *const conf, + void **const rsv) +{ + struct conf *old_conf; + int error __diagused; + + KASSERT(conf == NULL || rsv != NULL, + ("MAC/do: OSD reserve needed to avoid allocating memory")); + rm_assert(&mac_do_rml, RA_WLOCKED); + + if (conf != NULL) + hold_conf(conf); + old_conf = osd_jail_get_unlocked(pr, osd_jail_slot); + error = osd_jail_set_reserved(pr, osd_jail_slot, rsv, conf); + KASSERT(error == 0, ("MAC/do: osd_jail_set_reserved() failed " + "with 'conf' = %p and 'rsv' = %p", conf, rsv)); + if (conf == NULL) + /* + * This completely frees the OSD slot, but doesn't call the + * destructor since we've just put NULL into the slot. + */ + osd_jail_del(pr, osd_jail_slot); + return (old_conf); +} + +/* + * Immediately replace the jail's configuration. + * + * To be used only if the configuration to set does not depend in any way on the + * currently applicable configuration. + * + * Takes care of write-locking 'mac_do_rml', which should be unlocked on entry + * and will be unlocked on exit. + */ +static void +set_conf(struct prison *const pr, struct conf *const conf) +{ + void **const rsv = conf != NULL ? osd_reserve(osd_jail_slot) : NULL; + struct conf *old_conf; + + rm_wlock(&mac_do_rml); + old_conf = set_conf_locked(pr, conf, rsv); + rm_wunlock(&mac_do_rml); + if (old_conf != NULL) + drop_conf(old_conf); } /* * Remove the rules specifically associated to a prison. * * In practice, this means that the rules become inherited (from the closest - * ascendant that has some). + * ancestor that has some). * * Destroys the 'osd_jail_slot' slot of the passed jail. */ -static void -remove_rules(struct prison *const pr) +static struct conf * +remove_conf_locked(struct prison *const pr) { - struct rules *old_rules; - int error __unused; + return (set_conf_locked(pr, NULL, NULL)); +} - prison_lock(pr); - /* - * We burden ourselves with extracting rules first instead of just - * letting osd_jail_del() call dealloc_jail_osd() as we want to - * decrement their use count, and possibly free them, outside of the - * prison lock. - */ - old_rules = osd_jail_get(pr, osd_jail_slot); - error = osd_jail_set(pr, osd_jail_slot, NULL); - /* osd_set() never allocates memory when 'value' is NULL, nor fails. */ - MPASS(error == 0); - /* - * This completely frees the OSD slot, but doesn't call the destructor - * since we've just put NULL in the slot. - */ - osd_jail_del(pr, osd_jail_slot); - prison_unlock(pr); +static struct conf * +new_default_conf(void) +{ + const char *const mdo_path = "/usr/bin/mdo"; + struct conf *conf = new_conf(); + + strlcpy(conf->exec_paths.exec_paths_str, mdo_path, + MAX_EXEC_PATHS_SIZE); + strlcpy(conf->exec_paths.exec_paths[0], mdo_path, + PATH_MAX); + conf->exec_paths.exec_path_count = 1; - if (old_rules != NULL) - drop_rules(old_rules); + return (conf); } -/* - * Assign already built rules to a jail. - */ static void -set_rules(struct prison *const pr, struct rules *const rules) +clone_rules(struct rules *const dst, const struct rules *const src) { - struct rules *old_rules; - void **rsv; + const struct rule *src_rule; + + strlcpy(dst->string, src->string, sizeof(dst->string)); - check_rules_use_count(rules, 0); - hold_rules(rules); - rsv = osd_reserve(osd_jail_slot); + STAILQ_FOREACH(src_rule, &src->head, r_entries) { + struct rule *const dst_rule = malloc(sizeof(*dst_rule), + M_MAC_DO, M_WAITOK); + bcopy(src_rule, dst_rule, sizeof(*dst_rule)); - prison_lock(pr); - old_rules = osd_jail_get(pr, osd_jail_slot); - osd_jail_set_reserved(pr, osd_jail_slot, rsv, rules); - prison_unlock(pr); - if (old_rules != NULL) - drop_rules(old_rules); + if (src_rule->uids_nb > 0) { + const size_t uids_size = sizeof(*dst_rule->uids) * + src_rule->uids_nb; + + dst_rule->uids = malloc(uids_size, M_MAC_DO, M_WAITOK); + bcopy(src_rule->uids, dst_rule->uids, uids_size); + } + + if (src_rule->gids_nb > 0) { + const size_t gids_size = sizeof(*dst_rule->gids) * + src_rule->gids_nb; + + dst_rule->gids = malloc(gids_size, M_MAC_DO, M_WAITOK); + bcopy(src_rule->gids, dst_rule->gids, gids_size); + } + + STAILQ_INSERT_TAIL(&dst->head, dst_rule, r_entries); + } +} + +static void +clone_exec_paths(struct exec_paths *const dst, + const struct exec_paths *const src) +{ + MPASS(is_zeroed(dst, sizeof(*dst))); + dst->exec_path_count = src->exec_path_count; + for (int i = 0; i < src->exec_path_count; i++) + strlcpy(dst->exec_paths[i], src->exec_paths[i], + sizeof(dst->exec_paths[i])); + + strlcpy(dst->exec_paths_str, src->exec_paths_str, + sizeof(dst->exec_paths_str)); } /* - * Assigns empty rules to a jail. + * Sets/modifies the MAC/do configuration for a jail. + * + * Must be called with '*parse_error' set to NULL. + * + * Supports explicitly setting all parameters or only some of them. An + * unspecified parameter must be passed as NULL. The values of unspecified + * parameters are copied from those of the passed model configuration (which is + * expected to be the currently applicable configuration, i.e., that of the + * closest ancestor jail that has one). + * + * 'mac_do_rml' needs to be write-locked (and stays so). 'old_conf' serves to + * return, on no error, the old configuration with a reference (which must be + * eventually freed). */ -static void -set_empty_rules(struct prison *const pr) +static int +parse_and_set_conf(struct prison *const pr, const char *const rules_string, + const char *const exec_paths_string, const struct conf *const model_conf, + struct conf **const old_conf, struct parse_error **const parse_error) { - struct rules *const rules = alloc_rules(); + struct conf *const conf = new_conf(); + int error = 0; + + KASSERT(model_conf != NULL || + (rules_string != NULL && exec_paths_string != NULL), + ("MAC/do: %s: Model configuration needed!", __func__)); + + if (rules_string != NULL) { + error = parse_rules(rules_string, &conf->rules, parse_error); + if (error != 0) + goto error; + } + else + clone_rules(&conf->rules, &model_conf->rules); + + if (exec_paths_string != NULL) { + error = parse_exec_paths(exec_paths_string, &conf->exec_paths, + parse_error); + if (error != 0) + goto error; + } else + clone_exec_paths(&conf->exec_paths, + &model_conf->exec_paths); - set_rules(pr, rules); + MPASS(error == 0); + *old_conf = set_conf_locked(pr, conf, osd_reserve(osd_jail_slot)); + + MPASS(error == 0 && *parse_error == NULL); +out: + drop_conf(conf); + return (error); +error: + MPASS(error != 0 && *parse_error != NULL); + goto out; } /* - * Parse a rules specification and assign them to a jail. + * Calls parse_and_set_conf() and closes the current configuration transaction. * - * Returns the same error code as parse_rules() (which see). + * Closes the transaction by unlocking 'mac_do_rml' and releasing the old + * configuration returned by parse_and_set_conf(). */ static int -parse_and_set_rules(struct prison *const pr, const char *rules_string, +parse_and_commit_conf(struct prison *const pr, const char *const rules_string, + const char *const exec_paths_string, const struct conf *const model_conf, struct parse_error **const parse_error) { - struct rules *rules; + struct conf *old_conf; int error; - error = parse_rules(rules_string, &rules, parse_error); - if (error != 0) - return (error); - set_rules(pr, rules); - return (0); + error = parse_and_set_conf(pr, rules_string, exec_paths_string, + model_conf, &old_conf, parse_error); + rm_wunlock(&mac_do_rml); + + if (error == 0 && old_conf != NULL) + drop_conf(old_conf); + return (error); } + static int mac_do_sysctl_rules(SYSCTL_HANDLER_ARGS) { - char *const buf = malloc(MAC_RULE_STRING_LEN, M_MAC_DO, M_WAITOK); - struct prison *const td_pr = req->td->td_ucred->cr_prison; - struct prison *pr; - struct rules *rules; - struct parse_error *parse_error; + char *const buf = malloc(MAX_RULE_STRING_SIZE, M_MAC_DO, M_WAITOK); + struct prison *const pr = req->td->td_ucred->cr_prison; + struct conf *conf; + struct parse_error *parse_error = NULL; int error; - rules = find_rules(td_pr, &pr); - strlcpy(buf, rules->string, MAC_RULE_STRING_LEN); - prison_unlock(pr); + if (req->newptr != NULL) { + rm_wlock(&mac_do_rml); + conf = find_conf_locked(pr, NULL); + } else + conf = find_conf(pr, NULL); + strlcpy(buf, conf->rules.string, MAX_RULE_STRING_SIZE); - error = sysctl_handle_string(oidp, buf, MAC_RULE_STRING_LEN, req); - if (error != 0 || req->newptr == NULL) + error = sysctl_handle_string(oidp, buf, MAX_RULE_STRING_SIZE, req); + if (req->newptr == NULL) goto out; + if (error != 0) { + rm_wunlock(&mac_do_rml); + goto out; + } - /* Set our prison's rules, not that of the jail we inherited from. */ - error = parse_and_set_rules(td_pr, buf, &parse_error); + /* Unlocks 'mac_do_rml'. */ + error = parse_and_commit_conf(pr, buf, NULL, conf, &parse_error); if (error != 0) { if (print_parse_error) printf("MAC/do: Parse error at index %zu: %s\n", parse_error->pos, parse_error->msg); free_parse_error(parse_error); } + out: + drop_conf(conf); free(buf, M_MAC_DO); return (error); } @@ -1262,32 +1597,71 @@ SYSCTL_PROC(_security_mac_do, OID_AUTO, rules, SYSCTL_JAIL_PARAM_SYS_SUBNODE(mac, do, CTLFLAG_RW, "Jail MAC/do parameters"); -SYSCTL_JAIL_PARAM_STRING(_mac_do, rules, CTLFLAG_RW, MAC_RULE_STRING_LEN, +SYSCTL_JAIL_PARAM_STRING(_mac_do, rules, CTLFLAG_RW, MAX_RULE_STRING_SIZE, "Jail MAC/do rules"); - static int -mac_do_jail_create(void *obj, void *data __unused) +mac_do_sysctl_exec_paths(SYSCTL_HANDLER_ARGS) { - struct prison *const pr = obj; + char *const buf = malloc(MAX_EXEC_PATHS_SIZE, M_MAC_DO, M_WAITOK); + struct prison *const pr = req->td->td_ucred->cr_prison; + struct conf *conf; + struct parse_error *parse_error = NULL; + int error; - set_empty_rules(pr); - return (0); + if (req->newptr != NULL) { + rm_wlock(&mac_do_rml); + conf = find_conf_locked(pr, NULL); + } else + conf = find_conf(pr, NULL); + strlcpy(buf, conf->exec_paths.exec_paths_str, MAX_EXEC_PATHS_SIZE); + + error = sysctl_handle_string(oidp, buf, MAX_EXEC_PATHS_SIZE, req); + if (req->newptr == NULL) + goto out; + if (error != 0) { + rm_wunlock(&mac_do_rml); + goto out; + } + + /* Unlocks 'mac_do_rml'. */ + error = parse_and_commit_conf(pr, NULL, buf, conf, &parse_error); + if (error != 0) { + if (print_parse_error) + printf("MAC/do: Parse error at index %zu: %s\n", + parse_error->pos, parse_error->msg); + free_parse_error(parse_error); + } + +out: + drop_conf(conf); + free(buf, M_MAC_DO); + return (error); } +SYSCTL_PROC(_security_mac_do, OID_AUTO, exec_paths, + CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE, + 0, 0, mac_do_sysctl_exec_paths, "A", + "Colon-separated list of allowed executables"); + +SYSCTL_JAIL_PARAM_STRING(_mac_do, exec_paths, CTLFLAG_RW, MAX_EXEC_PATHS_SIZE, + "Jail MAC/do executable paths"); + static int mac_do_jail_get(void *obj, void *data) { - struct prison *ppr, *const pr = obj; + struct prison *const pr = obj; struct vfsoptlist *const opts = data; - struct rules *rules; + struct prison *hpr_out; + struct conf *const applicable_conf = find_conf(pr, &hpr_out); + const struct prison *const hpr = hpr_out; + const struct rules *const rules = &applicable_conf->rules; + const struct exec_paths *const exec_paths = &applicable_conf->exec_paths; int jsys, error; - rules = find_rules(pr, &ppr); + jsys = hpr == pr ? (has_rules(rules) && has_exec_paths(exec_paths) ? + JAIL_SYS_NEW : JAIL_SYS_DISABLE) : JAIL_SYS_INHERIT; - jsys = pr == ppr ? - (STAILQ_EMPTY(&rules->head) ? JAIL_SYS_DISABLE : JAIL_SYS_NEW) : - JAIL_SYS_INHERIT; error = vfs_setopt(opts, "mac.do", &jsys, sizeof(jsys)); if (error != 0 && error != ENOENT) goto done; @@ -1296,9 +1670,14 @@ mac_do_jail_get(void *obj, void *data) if (error != 0 && error != ENOENT) goto done; + error = vfs_setopts(opts, "mac.do.exec_paths", + exec_paths->exec_paths_str); + if (error != 0 && error != ENOENT) + goto done; + error = 0; done: - prison_unlock(ppr); + drop_conf(applicable_conf); return (error); } @@ -1317,11 +1696,16 @@ static int mac_do_jail_check(void *obj, void *data) { struct vfsoptlist *opts = data; - char *rules_string; - int error, jsys, size; + char *rules_string, *exec_paths_string; + int error, jsys, rules_size = 0, exec_paths_size = 0; + bool absent_or_empty_rules, absent_or_empty_exec_paths; error = vfs_copyopt(opts, "mac.do", &jsys, sizeof(jsys)); if (error == ENOENT) + /* + * Mark unspecified. Will fill it up below depending on the + * other options. + */ jsys = -1; else { if (error != 0) @@ -1332,75 +1716,117 @@ mac_do_jail_check(void *obj, void *data) } /* - * We use vfs_getopt() here instead of vfs_getopts() to get the length. - * We perform the additional checks done by the latter here, even if - * jail_set() calls vfs_getopts() itself later (they becoming - * inconsistent wouldn't cause any security problem). + * We use vfs_getopt() below instead of vfs_getopts() to get the + * string's buffer size. We perform the additional checks done by the + * latter here, even if jail_set() calls vfs_getopts() itself later + * (they becoming inconsistent wouldn't cause any security problem). */ - error = vfs_getopt(opts, "mac.do.rules", (void**)&rules_string, &size); - if (error == ENOENT) { - /* - * Default (in absence of "mac.do.rules") is to disable (and, in - * particular, not inherit). - */ - if (jsys == -1) - jsys = JAIL_SYS_DISABLE; - if (jsys == JAIL_SYS_NEW) { - vfs_opterror(opts, "'mac.do.rules' must be specified " - "given 'mac.do''s value"); + /* Rules. */ + error = vfs_getopt(opts, "mac.do.rules", (void **)&rules_string, + &rules_size); + if (error == ENOENT) + rules_string = NULL; + else { + if (error != 0) + return (error); + if (rules_size == 0 || rules_string[rules_size - 1] != '\0') { + vfs_opterror(opts, + "'mac.do.rules' not a proper string"); return (EINVAL); } + if (rules_size > MAX_RULE_STRING_SIZE) { + vfs_opterror(opts, "'mac.do.rules' too long"); + return (ENAMETOOLONG); + } + } - /* Absence of "mac.do.rules" at this point is OK. */ - error = 0; - } else { + /* Executable paths. */ + error = vfs_getopt(opts, "mac.do.exec_paths", + (void **)&exec_paths_string, &exec_paths_size); + if (error == ENOENT) + exec_paths_string = NULL; + else { if (error != 0) return (error); - - /* Not a proper string. */ - if (size == 0 || rules_string[size - 1] != '\0') { - vfs_opterror(opts, "'mac.do.rules' not a proper string"); + if (exec_paths_size == 0 || + exec_paths_string[exec_paths_size - 1] != '\0') { + vfs_opterror(opts, + "'mac.do.exec_paths' not a proper string"); return (EINVAL); } - - if (size > MAC_RULE_STRING_LEN) { - vfs_opterror(opts, "'mdo.rules' too long"); + if (exec_paths_size > MAX_EXEC_PATHS_SIZE) { + vfs_opterror(opts, "'mac.do.exec_paths' too long"); return (ENAMETOOLONG); } + } - if (jsys == -1) - /* Default (if "mac.do.rules" is present). */ - jsys = rules_string[0] == '\0' ? JAIL_SYS_DISABLE : - JAIL_SYS_NEW; + absent_or_empty_rules = is_null_or_empty(rules_string); + absent_or_empty_exec_paths = is_null_or_empty(exec_paths_string); + /* If not specified, infer 'jsys' from passed options. */ + if (jsys == -1) { /* - * Be liberal and accept JAIL_SYS_DISABLE and JAIL_SYS_INHERIT - * with an explicit empty rules specification. + * Default in absence of "mac.do.rules" and "mac.do.exec_paths" + * is to disable. We never implicitly inherit, as that changes + * reasoning about configurations. */ - switch (jsys) { - case JAIL_SYS_DISABLE: - case JAIL_SYS_INHERIT: - if (rules_string[0] != '\0') { - vfs_opterror(opts, "'mac.do.rules' specified " - "but should not given 'mac.do''s value"); - return (EINVAL); - } - break; + if (!absent_or_empty_rules || !absent_or_empty_exec_paths) + jsys = JAIL_SYS_NEW; + else + jsys = JAIL_SYS_DISABLE; + } + + /* Final checks based on resolved 'jsys'. */ + switch (jsys) { + case JAIL_SYS_DISABLE: + /* + * Tolerate specified but empty rules or execution paths + * (instead of not being specified). Also, tolerate that one of + * them is not empty (but not both). Indeed, as soon as one is + * empty, mac_do(4) is effectively disabled. This allows the + * administrator to still specify a value for one of them, which + * is then used for new sub-jails that do not inherit and for + * which no value for the parameter is explicitly specified + * (because then the value passed here is copied). + */ + if (!absent_or_empty_rules && !absent_or_empty_exec_paths) { + vfs_opterror(opts, + "One of 'mac.do.rules' and 'mac_do.exec_paths' " + "should not be specified or should be empty when " + "'mac.do' is 'disabled'"); + return (EINVAL); } + break; + + case JAIL_SYS_INHERIT: + /* + * Canonically, no parameters should be specified in this case. + * However, we tolerate empty ones, and also non-empty ones + * provided they match the inherited values, so that we can + * report the *resolved* value of current parameters via + * mac_do_jail_get() and have them re-applicable to this jail in + * a similar situation. Testing that inherited values are the + * same as passed ones is more expensive than a single test and + * requires some atomicity, which is why we do not perform that + * here but only in mac_do_jail_set(). + */ + break; } - return (error); + return (0); } static int mac_do_jail_set(void *obj, void *data) { - struct prison *pr = obj; - struct vfsoptlist *opts = data; - char *rules_string; - struct parse_error *parse_error; + struct prison *const pr = obj; + struct vfsoptlist *const opts = data; + char *rules_string, *exec_paths_string; + struct parse_error *parse_error = NULL; + struct conf *model_conf; int error, jsys; + bool absent_or_empty_rules, absent_or_empty_exec_paths; /* * The invariants checks used below correspond to what has already been @@ -1414,60 +1840,147 @@ mac_do_jail_set(void *obj, void *data) rules_string = vfs_getopts(opts, "mac.do.rules", &error); MPASS(error == 0 || error == ENOENT); - if (error == 0) { - MPASS(strlen(rules_string) < MAC_RULE_STRING_LEN); - if (jsys == -1) - /* Default (if "mac.do.rules" is present). */ - jsys = rules_string[0] == '\0' ? JAIL_SYS_DISABLE : - JAIL_SYS_NEW; + exec_paths_string = vfs_getopts(opts, "mac.do.exec_paths", &error); + MPASS(error == 0 || error == ENOENT); + + absent_or_empty_rules = is_null_or_empty(rules_string); + absent_or_empty_exec_paths = is_null_or_empty(exec_paths_string); + + if (jsys == -1) { + if (!absent_or_empty_rules || !absent_or_empty_exec_paths) + jsys = JAIL_SYS_NEW; else - MPASS(jsys == JAIL_SYS_NEW || - ((jsys == JAIL_SYS_DISABLE || - jsys == JAIL_SYS_INHERIT) && - rules_string[0] == '\0')); - } else { - MPASS(jsys != JAIL_SYS_NEW); - if (jsys == -1) + jsys = JAIL_SYS_DISABLE; + } + + if (jsys == JAIL_SYS_INHERIT) { + struct conf *old_conf = NULL; + + error = 0; + rm_wlock(&mac_do_rml); + + if (!absent_or_empty_rules || !absent_or_empty_exec_paths) { /* - * Default (in absence of "mac.do.rules") is to disable - * (and, in particular, not inherit). + * Some values specified. Check that they match the + * ones we are going to inherit. */ - jsys = JAIL_SYS_DISABLE; - /* If disabled, we'll store an empty rule specification. */ - if (jsys == JAIL_SYS_DISABLE) - rules_string = ""; + model_conf = find_conf_locked(pr->pr_parent, NULL); + if (strcmp(model_conf->rules.string, rules_string) + != 0) { + error = EINVAL; + vfs_opterror(opts, + "'mac.do' is 'inherited' but 'mac.do.rules'" + " was specified with a different value " + "than the one to be inherited (\"%s\")", + model_conf->rules.string); + } + if (strcmp(model_conf->exec_paths.exec_paths_str, + exec_paths_string) != 0) { + error = EINVAL; + vfs_opterror(opts, + "'mac.do' is 'inherited' but " + "'mac.do.exec_paths' was specified with a " + "different value than the one to be " + "inherited (\"%s\")", + model_conf->exec_paths.exec_paths_str); + } + drop_conf(model_conf); + } + + if (error == 0) + old_conf = remove_conf_locked(pr); + + rm_wunlock(&mac_do_rml); + + if (old_conf != NULL) + drop_conf(old_conf); + + return (error); } + model_conf = NULL; + /* Freeze configuration accesses. */ + rm_wlock(&mac_do_rml); + switch (jsys) { - case JAIL_SYS_INHERIT: - remove_rules(pr); - error = 0; - break; case JAIL_SYS_DISABLE: - case JAIL_SYS_NEW: - error = parse_and_set_rules(pr, rules_string, &parse_error); - if (error != 0) { - vfs_opterror(opts, - "MAC/do: Parse error at index %zu: %s\n", - parse_error->pos, parse_error->msg); - free_parse_error(parse_error); + /* + * mac_do(4) is disabled iff one of the parameter's string is + * empty. The parse_and_commit_conf() call below treats passing + * NULL for a parameter as a flag to copy its value from the + * relevant ancestor jail's configuration, so we have to watch + * for the final result having an empty parameter if no + * parameter has been explicitly passed as empty. Thanks to + * mac_do_jail_check(), we know that at least one parameter is + * absent or empty (see the comment for the corresponding case + * there). + */ + MPASS(absent_or_empty_rules || absent_or_empty_exec_paths); + if (!absent_or_empty_rules) + exec_paths_string = ""; + else if (!absent_or_empty_exec_paths) + rules_string = ""; + else { + /* + * Both are either empty or absent. If at least one is + * absent, we retrieve the applicable configuration as + * it will serve as a template (provides default + * values). + */ + if (rules_string == NULL || exec_paths_string == NULL) + model_conf = find_conf_locked(pr, NULL); + /* If both are absent, we have to examine if, in the + * currently applicable configuration, one of the + * parameters, which we are going to copy, is + * effectively empty. If both of those are non-empty, + * we keep the executable paths and empty the rules, + * since we expect that this is more convenient to + * administrators that may want to enable mac_do(4) + * later by just setting new rules. + */ + if (rules_string == NULL && exec_paths_string == NULL && + has_rules(&model_conf->rules) && + has_exec_paths(&model_conf->exec_paths)) + rules_string = ""; } break; + + case JAIL_SYS_NEW: + /* See the comment before the same test above. */ + if (rules_string == NULL || exec_paths_string == NULL) + model_conf = find_conf_locked(pr, NULL); + break; + default: __assert_unreachable(); } + + /* Unlocks 'mac_do_rml'. */ + error = parse_and_commit_conf(pr, rules_string, exec_paths_string, + model_conf, &parse_error); + if (model_conf != NULL) + drop_conf(model_conf); + if (error != 0) { + vfs_opterror(opts, + "MAC/do: Parse error at index %zu: %s\n", + parse_error->pos, parse_error->msg); + free_parse_error(parse_error); + } + return (error); } /* * OSD jail methods. * - * There is no PR_METHOD_REMOVE, as OSD storage is destroyed by the common jail - * code (see prison_cleanup()), which triggers a run of our dealloc_jail_osd() - * destructor. + * There is no PR_METHOD_REMOVE method, as OSD storage is destroyed by the + * common jail code (see prison_cleanup()), which triggers a run of our + * dealloc_jail_osd() destructor. There is neither a PR_METHOD_CREATE as + * PR_METHOD_SET is called just after (or the created jail destroyed if some + * PR_METHOD_CREATE fails), and our mac_do_jail_set() will ensure a jail is + * properly configured. */ static const osd_method_t osd_methods[PR_MAXMETHOD] = { - [PR_METHOD_CREATE] = mac_do_jail_create, [PR_METHOD_GET] = mac_do_jail_get, [PR_METHOD_CHECK] = mac_do_jail_check, [PR_METHOD_SET] = mac_do_jail_set, @@ -1492,8 +2005,8 @@ struct mac_do_data_header { * indicates this header is uninitialized. */ int priv; - /* Rules to apply. */ - struct rules *rules; + /* The configuration that applies. */ + struct conf *conf; }; /* @@ -1536,7 +2049,7 @@ clear_data(void *const data) struct mac_do_data_header *const hdr = data; if (hdr != NULL) { - drop_rules(hdr->rules); + drop_conf(hdr->conf); /* We don't deallocate so as to save time on next access. */ hdr->priv = 0; } @@ -1558,7 +2071,7 @@ is_data_reusable(const void *const data, const size_t size) static void set_data_header(void *const data, const size_t size, const int priv, - struct rules *const rules) + struct conf *const conf) { struct mac_do_data_header *const hdr = data; @@ -1567,7 +2080,7 @@ set_data_header(void *const data, const size_t size, const int priv, MPASS(size <= hdr->allocated_size); hdr->size = size; hdr->priv = priv; - hdr->rules = rules; + hdr->conf = conf; } /* The proc lock (and any other non-sleepable lock) must not be held. */ @@ -1933,7 +2446,7 @@ static int mac_do_priv_grant(struct ucred *cred, int priv) { struct mac_do_setcred_data *const data = fetch_data(); - const struct rules *rules; + struct rules *rules; const struct ucred *new_cred; const struct rule *rule; u_int setcred_flags; @@ -1950,7 +2463,7 @@ mac_do_priv_grant(struct ucred *cred, int priv) /* No. */ return (EPERM); - rules = data->hdr.rules; + rules = &data->hdr.conf->rules; new_cred = data->new_cred; KASSERT(new_cred != NULL, ("priv_check*() called before mac_cred_check_setcred()")); @@ -1987,7 +2500,10 @@ mac_do_priv_grant(struct ucred *cred, int priv) static int check_proc(void) { + struct prison *const pr = curproc->p_ucred->cr_prison; char *path, *to_free; + struct conf *conf; + struct exec_paths *exec_paths; int error; /* @@ -2010,7 +2526,18 @@ check_proc(void) */ if (vn_fullpath_jail(curproc->p_textvp, &path, &to_free) != 0) return (EPERM); - error = strcmp(path, "/usr/bin/mdo") == 0 ? 0 : EPERM; + + error = EPERM; + conf = find_conf(pr, NULL); + exec_paths = &conf->exec_paths; + + for (int i = 0; i < exec_paths->exec_path_count; i++) + if (strcmp(exec_paths->exec_paths[i], path) == 0) { + error = 0; + break; + } + + drop_conf(conf); free(to_free, M_TEMP); return (error); } @@ -2018,9 +2545,9 @@ check_proc(void) static void mac_do_setcred_enter(void) { - struct rules *rules; - struct prison *pr; + struct prison *const pr = curproc->p_ucred->cr_prison; struct mac_do_setcred_data * data; + struct conf *conf; int error; /* @@ -2042,9 +2569,7 @@ mac_do_setcred_enter(void) /* * Find the currently applicable rules. */ - rules = find_rules(curproc->p_ucred->cr_prison, &pr); - hold_rules(rules); - prison_unlock(pr); + conf = find_conf(pr, NULL); /* * Setup thread data to be used by other hooks. @@ -2052,7 +2577,7 @@ mac_do_setcred_enter(void) data = fetch_data(); if (!is_data_reusable(data, sizeof(*data))) data = alloc_data(data, sizeof(*data)); - set_data_header(data, sizeof(*data), PRIV_CRED_SETCRED, rules); + set_data_header(data, sizeof(*data), PRIV_CRED_SETCRED, conf); /* Not really necessary, but helps to catch programming errors. */ data->new_cred = NULL; data->setcred_flags = 0; @@ -2099,14 +2624,18 @@ mac_do_setcred_exit(void) static void mac_do_init(struct mac_policy_conf *mpc) { + struct conf *const default_conf = new_default_conf(); struct prison *pr; + rm_init_flags(&mac_do_rml, "mac_do(4)", RM_SLEEPABLE); + osd_jail_slot = osd_jail_register(dealloc_jail_osd, osd_methods); - set_empty_rules(&prison0); + set_conf(&prison0, default_conf); sx_slock(&allprison_lock); TAILQ_FOREACH(pr, &allprison, pr_list) - set_empty_rules(pr); + set_conf(pr, default_conf); sx_sunlock(&allprison_lock); + drop_conf(default_conf); osd_thread_slot = osd_thread_register(dealloc_thread_osd); } @@ -2120,6 +2649,7 @@ mac_do_destroy(struct mac_policy_conf *mpc) */ osd_thread_deregister(osd_thread_slot); osd_jail_deregister(osd_jail_slot); + rm_destroy(&mac_do_rml); } static struct mac_policy_ops do_ops = { diff --git a/sys/sys/imgact.h b/sys/sys/imgact.h index c1c94a2eabfd..51cda4406cad 100644 --- a/sys/sys/imgact.h +++ b/sys/sys/imgact.h @@ -57,6 +57,7 @@ struct image_args { struct image_params { struct proc *proc; /* our process */ + struct thread *td; struct label *execlabel; /* optional exec label */ struct vnode *vp; /* pointer to vnode of file to exec */ struct vm_object *object; /* The vm object for this vp */ diff --git a/sys/sys/proc.h b/sys/sys/proc.h index b560ea2e8020..ed69a09422e2 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -1246,6 +1246,7 @@ void cpu_thread_alloc(struct thread *); void cpu_thread_clean(struct thread *); void cpu_thread_exit(struct thread *); void cpu_thread_free(struct thread *); +void cpu_thread_new_kstack(struct thread *); struct thread *thread_alloc(int pages); int thread_check_susp(struct thread *td, bool sleep); void thread_cow_get_proc(struct thread *newtd, struct proc *p); @@ -1326,6 +1327,12 @@ td_get_sched(struct thread *td) return ((struct td_sched *)&td[1]); } +static __inline char * +td_kstack_top(struct thread *td) +{ + return (td->td_kstack + ptoa(td->td_kstack_pages)); +} + static __inline void ruxreset(struct rusage_ext *rux) { diff --git a/sys/sys/resource.h b/sys/sys/resource.h index 9e0635cdb328..6d8d17a05e02 100644 --- a/sys/sys/resource.h +++ b/sys/sys/resource.h @@ -145,7 +145,7 @@ static const char *rlimit_ident[] = { "kqueues", "umtx", "pipebuf", - "vmm", + "vms", }; #endif diff --git a/sys/sys/signal.h b/sys/sys/signal.h index 863b981c2b7a..792087f735a1 100644 --- a/sys/sys/signal.h +++ b/sys/sys/signal.h @@ -307,8 +307,8 @@ struct __siginfo32 { #define SEGV_ACCERR 2 /* Invalid permissions for mapped */ /* object. */ #define SEGV_PKUERR 100 /* x86: PKU violation */ -#define SEGV_MTEAERR 100 /* arm64: Asynchronous Arm MTE error */ -#define SEGV_MTESERR 101 /* arm64: Synchronous Arm MTE error */ +#define SEGV_MTEAERR 200 /* arm64: Asynchronous Arm MTE error */ +#define SEGV_MTESERR 201 /* arm64: Synchronous Arm MTE error */ /* codes for SIGFPE */ #define FPE_INTOVF 1 /* Integer overflow. */ diff --git a/sys/sys/systm.h b/sys/sys/systm.h index 7f655b48ba08..88c25f06e0cb 100644 --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -554,6 +554,14 @@ void intr_prof_stack_use(struct thread *td, struct trapframe *frame); void counted_warning(unsigned *counter, const char *msg); /* + * Safely read one byte of kernel memory at address addr, placing the + * value into *valp. Returns 0 on success, EFAULT if read was + * impossible, e.g. due to the address not being mapped or not having + * necessary permissions. + */ +int safe_read(vm_offset_t addr, char *valp); + +/* * APIs to manage deprecation and obsolescence. */ void _gone_in(int major, const char *msg, ...) __printflike(2, 3); diff --git a/sys/vm/vm_glue.c b/sys/vm/vm_glue.c index 191711ec7765..02e1c993529e 100644 --- a/sys/vm/vm_glue.c +++ b/sys/vm/vm_glue.c @@ -739,7 +739,7 @@ intr_prof_stack_use(struct thread *td, struct trapframe *frame) if (TRAPF_USERMODE(frame)) return; - stack_top = td->td_kstack + td->td_kstack_pages * PAGE_SIZE; + stack_top = td_kstack_top(td); current = (char *)&stack_top; /* diff --git a/sys/x86/x86/ucode.c b/sys/x86/x86/ucode.c index 72133de211f8..3d7008eb30f2 100644 --- a/sys/x86/x86/ucode.c +++ b/sys/x86/x86/ucode.c @@ -80,7 +80,7 @@ static const void *ucode_data; static struct ucode_ops *ucode_loader; /* Variables used for reporting success or failure. */ -enum { +static enum { NO_ERROR, NO_MATCH, VERIFICATION_FAILED, @@ -204,7 +204,6 @@ ucode_intel_match(const uint8_t *data, size_t *len) uint64_t platformid; size_t resid; uint32_t data_size, flags, regs[4], sig, total_size; - int i; do_cpuid(1, regs); sig = regs[0]; @@ -226,19 +225,35 @@ ucode_intel_match(const uint8_t *data, size_t *len) if (total_size == 0) total_size = UCODE_INTEL_DEFAULT_DATA_SIZE + sizeof(struct ucode_intel_header); - if (data_size > total_size + sizeof(struct ucode_intel_header)) + + if (total_size > data_size + sizeof(struct ucode_intel_header)) table = (const struct ucode_intel_extsig_table *) ((const uint8_t *)(hdr + 1) + data_size); else table = NULL; - if (hdr->processor_signature == sig) { - if ((hdr->processor_flags & flags) != 0) { - *len = data_size; - return (hdr + 1); + if (hdr->processor_signature == sig && + (hdr->processor_flags & flags) != 0) { + *len = data_size; + return (hdr + 1); + } + if (table != NULL) { + size_t extsize; + + extsize = total_size - + (data_size + sizeof(struct ucode_intel_header)); + if (extsize < sizeof(struct ucode_intel_extsig_table)) { + ucode_error = VERIFICATION_FAILED; + break; } - } else if (table != NULL) { - for (i = 0; i < table->signature_count; i++) { + extsize -= sizeof(struct ucode_intel_extsig_table); + for (uint32_t i = 0; i < table->signature_count; i++) { + if (extsize < sizeof(struct ucode_intel_extsig)) { + ucode_error = VERIFICATION_FAILED; + goto out; + } + extsize -= sizeof(struct ucode_intel_extsig); + entry = &table->entries[i]; if (entry->processor_signature == sig && (entry->processor_flags & flags) != 0) { @@ -248,6 +263,7 @@ ucode_intel_match(const uint8_t *data, size_t *len) } } } +out: return (NULL); } diff --git a/tests/sys/acl/run b/tests/sys/acl/run index f8e9c8d87f71..42dbc7373f7f 100644 --- a/tests/sys/acl/run +++ b/tests/sys/acl/run @@ -105,7 +105,7 @@ if (isatty(fileno(STDOUT))) { } } print $status, "\n"; -exit $failed ? 1 : 0; +exit($failed ? 1 : 0); sub process_test($$$$) { diff --git a/tests/sys/acl/tools-posix.test b/tests/sys/acl/tools-posix.test index 2b2a27d24a0d..aa92911761a6 100644 --- a/tests/sys/acl/tools-posix.test +++ b/tests/sys/acl/tools-posix.test @@ -80,7 +80,7 @@ $ getfacl -qh lll > group::r-x > other::r-x -$ getfacl -q lll +$ getfacl -nq lll > user::rw- > user:42:r-- > group::r-- @@ -89,7 +89,7 @@ $ getfacl -q lll > other::r-- $ setfacl -hm u:44:x,g:45:w lll -$ getfacl -h lll +$ getfacl -hn lll > # file: lll > # owner: root > # group: wheel @@ -111,7 +111,7 @@ $ rm lll # Test removing entries. $ setfacl -x user:42: xxx -$ getfacl xxx +$ getfacl -n xxx > # file: xxx > # owner: root > # group: wheel @@ -369,7 +369,7 @@ $ rm ddd/xxx $ setfacl -dm u::rwx,g::rx,o::rx,mask::rwx ddd $ setfacl -dm g:42:rwx,u:43:r ddd -$ getfacl -dq ddd +$ getfacl -dnq ddd > user::rwx > user:43:r-- > group::r-x @@ -378,7 +378,7 @@ $ getfacl -dq ddd > other::r-x $ touch ddd/xxx -$ getfacl -q ddd/xxx +$ getfacl -nq ddd/xxx > user::rw- > user:43:r-- > group::r-x # effective: r-- @@ -387,7 +387,7 @@ $ getfacl -q ddd/xxx > other::r-- $ mkdir ddd/ddd -$ getfacl -q ddd/ddd +$ getfacl -nq ddd/ddd > user::rwx > user:43:r-- > group::r-x @@ -405,7 +405,7 @@ $ ls -l fff | cut -d' ' -f1 > prw-r--r-- $ setfacl -m u:42:r,g:43:w fff -$ getfacl fff +$ getfacl -n fff > # file: fff > # owner: root > # group: wheel diff --git a/tests/sys/kern/ptrace_test.c b/tests/sys/kern/ptrace_test.c index c1a5d226e990..3a55a6f48033 100644 --- a/tests/sys/kern/ptrace_test.c +++ b/tests/sys/kern/ptrace_test.c @@ -3614,6 +3614,10 @@ ATF_TC_BODY(ptrace__PT_STEP_with_signal, tc) ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI); REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGABRT); +#if defined(__riscv) + atf_tc_expect_fail("PT_STEP not implemented on riscv, see sys/riscv/riscv/ptrace_machdep.c"); +#endif + /* Step the child process inserting SIGUSR1. */ REQUIRE_EQ(ptrace(PT_STEP, fpid, (caddr_t)1, SIGUSR1), 0); @@ -3731,6 +3735,10 @@ ATF_TC_BODY(ptrace__step_siginfo, tc) ATF_REQUIRE(WIFSTOPPED(status)); REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); +#if defined(__riscv) + atf_tc_expect_fail("PT_STEP not implemented on riscv, see sys/riscv/riscv/ptrace_machdep.c"); +#endif + /* Step the child ignoring the SIGSTOP. */ REQUIRE_EQ(ptrace(PT_STEP, fpid, (caddr_t)1, 0), 0); diff --git a/tests/sys/mac/do/Makefile b/tests/sys/mac/do/Makefile index 980067ea56e6..0c40f65b65f6 100644 --- a/tests/sys/mac/do/Makefile +++ b/tests/sys/mac/do/Makefile @@ -2,13 +2,12 @@ PACKAGE= tests TESTSDIR= ${TESTSBASE}/sys/mac/do -ATF_TESTS_SH+= valid_configs invalid_configs +ATF_TESTS_SH+= valid_configs invalid_configs consistency ${PACKAGE}FILES+= common.sh TEST_METADATA+= execenv="jail" TEST_METADATA+= required_kmods="mac_do" TEST_METADATA+= required_user="root" -TEST_METADATA+= required_programs="sysctl" .include <bsd.test.mk> diff --git a/tests/sys/mac/do/common.sh b/tests/sys/mac/do/common.sh index 88529adcc1f3..4f0e838bbf5f 100644 --- a/tests/sys/mac/do/common.sh +++ b/tests/sys/mac/do/common.sh @@ -1,5 +1,6 @@ +# Copyright (c) 2026 The FreeBSD Foundation # -# Copyright (c) 2026, The FreeBSD Foundation +# SPDX-License-Identifier: BSD-2-Clause # # This software was developed by Olivier Certner <olce@FreeBSD.org> at # Kumacom SARL under sponsorship from the FreeBSD Foundation. @@ -9,11 +10,79 @@ rules_parameter() echo "$1".rules } +exec_paths_parameter() +{ + echo "$1".exec_paths +} + +: ${MDO:=/usr/bin/mdo} + +ROOT_KNOB=security.mac.do +RULES_KNOB=$(rules_parameter ${ROOT_KNOB}) +EXEC_PATHS_KNOB=$(exec_paths_parameter ${ROOT_KNOB}) +PPE_KNOB=${ROOT_KNOB}.print_parse_error + +ROOT_JAIL_PARAM=mac.do +RULES_JAIL_PARAM=$(rules_parameter ${ROOT_JAIL_PARAM}) +EXEC_PATHS_JAIL_PARAM=$(exec_paths_parameter ${ROOT_JAIL_PARAM}) + +# To be overridden to execute commands in a sub-jail +JEXEC= + +# Exit status: 0 iff disabled +mac_do_disabled() +{ + [ -z "$($JEXEC sysctl -n ${RULES_KNOB})" ] || + [ -z "$($JEXEC sysctl -n ${EXEC_PATHS_KNOB})" ] +} + +mac_do_check_disabled() +{ + mac_do_disabled || atf_fail "mac_do(4) expected disabled but is not." +} -CONF_ROOT_KNOB=security.mac.do -RULES_KNOB=$(rules_parameter ${CONF_ROOT_KNOB}) -PPE_KNOB=${CONF_ROOT_KNOB}.print_parse_error +mac_do_ensure_disabled() +{ + mac_do_disabled || $JEXEC sysctl ${RULES_KNOB}="" +} +sysctl_rules() +{ + $JEXEC sysctl -n ${RULES_KNOB} +} + +sysctl_exec_paths() +{ + $JEXEC sysctl -n ${EXEC_PATHS_KNOB} +} + +# $1 = sysctl func, $2 = expected value +sysctl_check() +{ + local func value + + func=$1 + value=$2 + atf_check [ "$($func)" = "$value" ] +} + +# $1 = value +sysctl_check_rules() +{ + local value + + value=$1 + sysctl_check sysctl_rules $value +} + +# $1 = value +sysctl_check_exec_paths() +{ + local value + + value=$1 + sysctl_check sysctl_exec_paths $value +} # $1 = knob name, $2 = value sysctl_set_and_check() @@ -22,8 +91,8 @@ sysctl_set_and_check() knob=$1 value=$2 - atf_check -o ignore sysctl "$knob"="$value" - atf_check -o inline:"$value\n" sysctl -n "$knob" + atf_check -o ignore $JEXEC sysctl "$knob"="$value" + atf_check -o inline:"$value\n" $JEXEC sysctl -n "$knob" } # $1 = knob name, $2 = value @@ -34,8 +103,8 @@ sysctl_set_and_check_fails() knob=$1 value=$2 orig_value=$(sysctl -n "$knob") - atf_check -s not-exit:0 -o ignore -e ignore sysctl "$knob"="$value" - atf_check -o inline:"${orig_value}\n" sysctl -n "$knob" + atf_check -s not-exit:0 -o ignore -e ignore $JEXEC sysctl "$knob"="$value" + atf_check -o inline:"${orig_value}\n" $JEXEC sysctl -n "$knob" } # $1 = sysctl function, $2 = value @@ -45,9 +114,9 @@ sysctl_set_and_check_rules_common() func=$1 value=$2 - "$func" ${RULES_KNOB} "$value" - # Same spec but using the older in-rule separator (':') + # Use older in-rule separator (':') first to have final value as specified "$func" ${RULES_KNOB} "$(echo "$value" | sed 's%>%:%')" + "$func" ${RULES_KNOB} "$value" } # $1 = value @@ -68,5 +137,40 @@ sysctl_set_and_check_fails_rules() sysctl_set_and_check_rules_common sysctl_set_and_check_fails "$value" } +# $1 = sysctl function, $2 = value +sysctl_set_and_check_exec_paths_common() +{ + local func value + + func=$1 + value=$2 + # Use older in-rule separator (':') first to have final value as specified + "$func" ${EXEC_PATHS_KNOB} "$(echo "$value" | sed 's%>%:%')" + "$func" ${EXEC_PATHS_KNOB} "$value" +} + +# $1 = value +sysctl_set_and_check_exec_paths() +{ + local value + + value=$1 + sysctl_set_and_check_exec_paths_common sysctl_set_and_check "$value" +} + +# Create a persistent subjail. Echoes its JID. +launch_subjail() +{ + ( + set -o pipefail + $JEXEC jail -c -J /dev/stdout persist=true | + sed -nE 's%^.*jid=([0-9]+).*$%\1%p' + ) || atf_fail "Cannot create a subjail (check children limits?)" +} + +atf_require_prog sysctl +atf_require_prog jail +atf_require_prog sed + # Do not pollute kernel logs with parse errors sysctl $PPE_KNOB=0 >/dev/null 2>&1 diff --git a/tests/sys/mac/do/consistency.sh b/tests/sys/mac/do/consistency.sh new file mode 100644 index 000000000000..6a64917edb6d --- /dev/null +++ b/tests/sys/mac/do/consistency.sh @@ -0,0 +1,211 @@ +# Copyright (c) 2026 The FreeBSD Foundation +# +# SPDX-License-Identifier: BSD-2-Clause +# +# This software was developed by Olivier Certner <olce@FreeBSD.org> at +# Kumacom SARL under sponsorship from the FreeBSD Foundation. + +SJ_JID_FILE=sj.jid + +atf_test_case concurrent_rules_exec_paths_changes +concurrent_rules_exec_paths_changes_head() +{ + atf_set descr "Consistency of rules and exec paths changes on same jail" +} +concurrent_rules_exec_paths_changes_body() +{ + local rules exec_paths rules_es exec_paths_es + + for I in $(jot - 1 1000); do + sysctl_set_and_check_rules "uid=$I>uid=1001" + done & + rules=$! + + for I in $(jot - 1 1000); do + sysctl_set_and_check_exec_paths /nowhere/nonexistent$I + done & + exec_paths=$! + + wait $rules + rules_es=$? + + wait $exec_paths + exec_paths_es=$? + + # atf_check called in the asynchronous AND-OR lists above causes exit of the + # subshells and also a write to the ATF result file. These writes are + # concurrent and may cause the result file to be malformed. Consequently, + # it is important that, once execution becomes sequential again, atf_fail() is + # called again (and not just exit()). + if [ $rules_es -ne 0 ] || [ $exec_paths_es -ne 0 ]; then + atf_fail "Rules exit status: $rules_es, \ +exec paths exit status: $exec_paths_es" + fi +} + +atf_test_case inheritance cleanup +inheritance_head() +{ + atf_set descr "Simple inheritance test (values propagated to child jail)" +} +inheritance_body() +{ + local sj rules exec_paths + + # For the sake of not running the test under Kyua + mac_do_ensure_disabled + + sj=$(launch_subjail) + echo $sj > "${SJ_JID_FILE}" + + jail -m jid=$sj ${ROOT_JAIL_PARAM}=inherit + JEXEC="jexec $sj" + mac_do_check_disabled + JEXEC= + + rules="uid=1001>uid=0" + sysctl_set_and_check_rules $rules + JEXEC="jexec $sj" + sysctl_check_rules $rules + JEXEC= + + rules="gid=1001>uid=0" + sysctl_set_and_check_rules $rules + JEXEC="jexec $sj" + sysctl_check_rules $rules + JEXEC= + + # Not really necessary, just to keep mac_do(4) disabled + sysctl_set_and_check_rules "" + + exec_paths="/nowhere/nonexistent" + sysctl_set_and_check_exec_paths $exec_paths + JEXEC="jexec $sj" + sysctl_check_exec_paths $exec_paths + JEXEC= + + exec_paths="$MDO" + sysctl_set_and_check_exec_paths $exec_paths + JEXEC="jexec $sj" + sysctl_check_exec_paths $exec_paths + JEXEC= +} +inheritance_cleanup() +{ + # We clean up our subjail manually just for the sake of launching this test + # with atf-sh. Kyua is informed that these tests should run in a jail, and + # kills it automatically after the test, which kills all subjails. It is + # annoying that atf-sh does not offer a more practical way to pass + # information from the body to the cleanup part than a file. + jail -r $(cat "${SJ_JID_FILE}") + rm -f "${SJ_JID_FILE}" +} + +atf_test_case inheritance_relax_parent_jail cleanup +inheritance_relax_parent_jail_head() +{ + atf_set descr \ + "Test sequential consistency in a \"relax parent rules\" scenario" +} +inheritance_relax_parent_jail_body() +{ + local sj rules exec_paths subproc + + sj=$(launch_subjail) + echo $sj > "${SJ_JID_FILE}" + + jail -m jid=$sj ${ROOT_JAIL_PARAM}=inherit + rules="uid=1001>uid=0" + sysctl_set_and_check_rules $rules + # Additional inheritance sanity check + JEXEC="jexec $sj" + sysctl_check_rules $rules + JEXEC= + exec_paths="$MDO" + sysctl_set_and_check_exec_paths $exec_paths + # Additional inheritance sanity check + JEXEC="jexec $sj" + sysctl_check_exec_paths $exec_paths + JEXEC= + + # Launch a process that tries to become 'root' from user 1002, and verify + # that this always fails. + { for I in $(jot - 1 1000); do + jexec $sj "$MDO" -u 1002 -g 1002 -G 1002 "$MDO" -i true 2>/dev/null && + exit 1 + done; true; } & + subproc=$! + + # Decouple the subjail from the parent jail, copying its parameters + jail -m jid=$sj ${ROOT_JAIL_PARAM}=new + # Allow user 1002 to become 'root' on the parent jail + sysctl_set_and_check_rules "$rules;uid=1002>uid=0" + JEXEC="jexec $sj" + # Additional sanity check (that rules of the subjail are now independent) + [ "$(sysctl_rules)" == $rules ] || atf_fail "Rules not copied" + [ "$(sysctl_exec_paths)" == $exec_paths ] || + atf_fail "Exec paths not copied" + JEXEC= + + wait $subproc || atf_fail "A transition wrongly succeeded in the subjail!" +} +inheritance_relax_parent_jail_cleanup() +{ + # See inheritance_cleanup() for explanations + jail -r $(cat "${SJ_JID_FILE}") + rm -f "${SJ_JID_FILE}" +} + +atf_test_case same_knob_and_jail_parameter cleanup +same_knob_and_jail_parameter_head() +{ + atf_set descr \ + "Corresponding sysctl knobs and jail parameters have same value" +} +same_knob_and_jail_parameter_body() +{ + local sj rules exec_paths subproc + + sj=$(launch_subjail) + echo $sj > "${SJ_JID_FILE}" + + # Set sysctl knobs, observe parameters + rules="uid=19999>uid=21700" + exec_paths="/improbable/path/he" + JEXEC="jexec $sj" + sysctl_set_and_check_rules $rules + sysctl_set_and_check_exec_paths $exec_paths + JEXEC= + atf_check -o inline:"$rules\n" jls -j $sj ${RULES_JAIL_PARAM} + atf_check -o inline:"${exec_paths}\n" jls -j $sj ${EXEC_PATHS_JAIL_PARAM} + + # Set parameters, observe knobs + rules="uid=128000>uid=-1" + exec_paths="/hello/i_ve/changed" + jail -m jid=$sj ${RULES_JAIL_PARAM}=$rules \ + ${EXEC_PATHS_JAIL_PARAM}=${exec_paths} + JEXEC="jexec $sj" + sysctl_check_rules $rules + sysctl_check_exec_paths $exec_paths + JEXEC= +} +same_knob_and_jail_parameter_cleanup() +{ + # See inheritance_cleanup() for explanations + jail -r $(cat "${SJ_JID_FILE}") + rm -f "${SJ_JID_FILE}" +} + + +atf_init_test_cases() +{ + . $(atf_get_srcdir)/common.sh + atf_require_prog jot + # Needs an absolute path for mdo(1), to set it in exec_paths + atf_require_prog "$MDO" + + atf_add_test_case concurrent_rules_exec_paths_changes + atf_add_test_case inheritance + atf_add_test_case inheritance_relax_parent_jail + atf_add_test_case same_knob_and_jail_parameter +} diff --git a/tests/sys/mac/do/invalid_configs.sh b/tests/sys/mac/do/invalid_configs.sh index f24309cb2f3b..d1a9eb8c1e96 100644 --- a/tests/sys/mac/do/invalid_configs.sh +++ b/tests/sys/mac/do/invalid_configs.sh @@ -1,6 +1,6 @@ -#!/usr/bin/env atf-sh +# Copyright (c) 2026 The FreeBSD Foundation # -# Copyright (c) 2026, The FreeBSD Foundation +# SPDX-License-Identifier: BSD-2-Clause # # This software was developed by Olivier Certner <olce@FreeBSD.org> at # Kumacom SARL under sponsorship from the FreeBSD Foundation. @@ -75,7 +75,7 @@ rules_wrong_separator_body() atf_init_test_cases() { - . $(atf_get_srcdir)/common.sh + . "$(atf_get_srcdir)"/common.sh atf_add_test_case rule_no_target_part atf_add_test_case rule_no_match_part diff --git a/tests/sys/mac/do/valid_configs.sh b/tests/sys/mac/do/valid_configs.sh index bd5b53b5d5d8..fc1c9a370854 100644 --- a/tests/sys/mac/do/valid_configs.sh +++ b/tests/sys/mac/do/valid_configs.sh @@ -1,6 +1,6 @@ -#!/usr/bin/env atf-sh +# Copyright (c) 2026 The FreeBSD Foundation # -# Copyright (c) 2026, The FreeBSD Foundation +# SPDX-License-Identifier: BSD-2-Clause # # This software was developed by Olivier Certner <olce@FreeBSD.org> at # Kumacom SARL under sponsorship from the FreeBSD Foundation. @@ -120,7 +120,7 @@ gid= 1001 >gid =5" atf_init_test_cases() { - . $(atf_get_srcdir)/common.sh + . "$(atf_get_srcdir)"/common.sh atf_add_test_case rule_uid_to_any atf_add_test_case rule_uid_to_uid diff --git a/tools/test/stress2/misc/all.exclude b/tools/test/stress2/misc/all.exclude index 9ec5bffde0f6..7109555c5508 100644 --- a/tools/test/stress2/misc/all.exclude +++ b/tools/test/stress2/misc/all.exclude @@ -39,6 +39,9 @@ mount7.sh https://people.freebsd.org/~pho/stress/log/log0549.txt 20240912 mlockall2.sh Unrecoverable OOM killing seen 20190203 mlockall6.sh https://people.freebsd.org/~pho/stress/log/log0430.txt 20230403 mlockall7.sh Needs further investigation 20210123 +msdos22.sh Waiting for fix 20260529 +msdos23.sh Waiting for fix 20260529 +msdos24.sh Waiting for fix 20260529 msetdomain.sh May change policy for random threads to domainset_fixed 20210104 newfs4.sh watchdog fired. newbuf (still seen 20240729) 20190225 nfs10.sh Double fault 20151013 diff --git a/tools/test/stress2/misc/msdos22.sh b/tools/test/stress2/misc/msdos22.sh new file mode 100755 index 000000000000..158a52a7aa7b --- /dev/null +++ b/tools/test/stress2/misc/msdos22.sh @@ -0,0 +1,79 @@ +#!/bin/sh + +# Test file operations using long random file names consisting only of ASCII characters + +MDUNIT=10 +FS=/mnt +LOCALE=C.UTF-8 +FILES=1000 + +export LANG=$LOCALE + +randomfilename () { + name="f" + count=$(jot -r 1 10 3) + for r in $(jot -r $count 7 0); do + r=$(( r + 0 )) + c='_' + if [ $r -gt 0 ]; then + for i in $(jot $r); do + name="$name$i" + done + fi + count=$(( count - 1 )) + if [ "$count" -gt 0 ]; then + name="$name$c" + fi + done + echo "$name" +} + +( + set -e + + mdconfig -u $MDUNIT -t malloc -s 512m + newfs_msdos -c 8 -F 32 /dev/md$MDUNIT > /dev/null 2>&1 + mkdir -p $FS + mount_msdosfs /dev/md$MDUNIT $FS + + mkdir -p $FS/test + cd $FS/test + + for i in $(jot $FILES); do + newfile=$(randomfilename) + case $testfiles in + *"$newfile"*) continue;; + esac + testfiles="$(randomfilename) +$testfiles" + done + + for f in $testfiles; do + echo "$f" > $f + done + for f in $(echo "$testfiles" | sort -R); do + cp $f $f.tmp + done + for f in $(echo "$testfiles" | sort -R); do + mv $f.tmp $f + done + for f in $(echo "$testfiles" | sort -R); do + rm $f + done +) + +failed=$? + +cd + +[ "$failed" -ne 0 ] && ls $FS/test + +umount /dev/md$MDUNIT + +#[ "$failed" -ne 0 ] && hd /dev/md$MDUNIT > /tmp/msdos22.dump + +fsck_msdosfs -y /dev/md$MDUNIT + +mdconfig -d -u $MDUNIT 2>/dev/null + +exit $failed diff --git a/tools/test/stress2/misc/msdos23.sh b/tools/test/stress2/misc/msdos23.sh new file mode 100755 index 000000000000..18982c34f68b --- /dev/null +++ b/tools/test/stress2/misc/msdos23.sh @@ -0,0 +1,79 @@ +#!/bin/sh + +# Test file operations using random file names containing non-ASCII characters + +MDUNIT=10 +FS=/mnt +LOCALE=C.UTF-8 +FILES=1000 + +export LANG=$LOCALE + +randomfilename () { + name="f" + count=$(jot -r 1 10 3) + for r in $(jot -r $count 7 0); do + r=$(( r + 0 )) + c='ยท' + if [ $r -gt 0 ]; then + for i in $(jot $r); do + name="$name$i" + done + fi + count=$(( count - 1 )) + if [ "$count" -gt 0 ]; then + name="$name$c" + fi + done + echo "$name" +} + +( + set -e + + mdconfig -u $MDUNIT -t malloc -s 512m + newfs_msdos -c 8 -F 32 /dev/md$MDUNIT > /dev/null 2>&1 + mkdir -p $FS + mount_msdosfs -L $LOCALE /dev/md$MDUNIT $FS + + mkdir -p $FS/test + cd $FS/test + + for i in $(jot $FILES); do + newfile=$(randomfilename) + case $testfiles in + *"$newfile"*) continue;; + esac + testfiles="$(randomfilename) +$testfiles" + done + + for f in $testfiles; do + echo "$f" > $f + done + for f in $(echo "$testfiles" | sort -R); do + cp $f $f.tmp + done + for f in $(echo "$testfiles" | sort -R); do + mv $f.tmp $f + done + for f in $(echo "$testfiles" | sort -R); do + rm $f + done +) + +failed=$? + +cd + +[ "$failed" -ne 0 ] && ls $FS/test + +umount /dev/md$MDUNIT + +#[ "$failed" -ne 0 ] && hd /dev/md$MDUNIT > /tmp/msdos23.dump + +fsck_msdosfs -y /dev/md$MDUNIT + +mdconfig -d -u $MDUNIT 2>/dev/null + +exit $failed diff --git a/tools/test/stress2/misc/msdos24.sh b/tools/test/stress2/misc/msdos24.sh new file mode 100755 index 000000000000..195c4ba8d9b9 --- /dev/null +++ b/tools/test/stress2/misc/msdos24.sh @@ -0,0 +1,80 @@ +#!/bin/sh + +# Test file operations using long random file names containing UTF-16 surrogate pairs + +MDUNIT=10 +FS=/mnt +LOCALE=C.UTF-8 +FILES=1000 + +export LANG=$LOCALE + +randomfilename () { + name="f" + count=$(jot -r 1 10 3) + for r in $(jot -r $count 7 0); do + r=$(( r + 0 )) + emoji="\0360\0237\0230\020$r" + c=$(echo -e $emoji) + if [ $r -gt 0 ]; then + for i in $(jot $r); do + name="$name$i" + done + fi + count=$(( count - 1 )) + if [ "$count" -gt 0 ]; then + name="$name$c" + fi + done + echo "$name" +} + +( + set -e + + mdconfig -u $MDUNIT -t malloc -s 512m + newfs_msdos -c 8 -F 32 /dev/md$MDUNIT > /dev/null 2>&1 + mkdir -p $FS + mount_msdosfs -L $LOCALE /dev/md$MDUNIT $FS + + mkdir -p $FS/test + cd $FS/test + + for i in $(jot $FILES); do + newfile=$(randomfilename) + case $testfiles in + *"$newfile"*) continue;; + esac + testfiles="$(randomfilename) +$testfiles" + done + + for f in $testfiles; do + echo "$f" > $f + done + for f in $(echo "$testfiles" | sort -R); do + cp $f $f.tmp + done + for f in $(echo "$testfiles" | sort -R); do + mv $f.tmp $f + done + for f in $(echo "$testfiles" | sort -R); do + rm $f + done +) + +failed=$? + +cd + +[ "$failed" -ne 0 ] && ls $FS/test + +umount /dev/md$MDUNIT + +#[ "$failed" -ne 0 ] && hd /dev/md$MDUNIT > /tmp/msdos24.dump + +fsck_msdosfs -y /dev/md$MDUNIT + +mdconfig -d -u $MDUNIT 2>/dev/null + +exit $failed diff --git a/usr.bin/cap_mkdb/cap_mkdb.c b/usr.bin/cap_mkdb/cap_mkdb.c index 7ee6d2ddd2b3..019dad1ee72e 100644 --- a/usr.bin/cap_mkdb/cap_mkdb.c +++ b/usr.bin/cap_mkdb/cap_mkdb.c @@ -117,6 +117,7 @@ main(int argc, char *argv[]) if (capdbp->close(capdbp) < 0) err(1, "%s", capname); + free(capname); capname = NULL; exit(0); } @@ -151,7 +152,7 @@ db_build(char **ifiles) data.data = NULL; key.data = NULL; - for (reccnt = 0, bplen = 0; (st = cgetnext(&bp, ifiles)) > 0;) { + for (reccnt = 0, bplen = 0; (st = cgetnext(&bp, ifiles)) > 0; free(bp)) { /* * Allocate enough memory to store record, terminating diff --git a/usr.bin/limits/limits.c b/usr.bin/limits/limits.c index fbb19289e6ca..a6e95e7c37a9 100644 --- a/usr.bin/limits/limits.c +++ b/usr.bin/limits/limits.c @@ -247,7 +247,7 @@ static struct { { "kqueues", login_getcapnum }, { "umtxp", login_getcapnum }, { "pipebuf", login_getcapnum }, - { "vmms", login_getcapnum }, + { "vms", login_getcapnum }, }; _Static_assert(nitems(resources) == RLIM_NLIMITS, diff --git a/usr.bin/xinstall/Makefile b/usr.bin/xinstall/Makefile index fd95b97160fe..c05a50420c82 100644 --- a/usr.bin/xinstall/Makefile +++ b/usr.bin/xinstall/Makefile @@ -11,7 +11,7 @@ MAN= install.1 CFLAGS+= -I${SRCTOP}/contrib/mtree CFLAGS+= -I${SRCTOP}/lib/libnetbsd -LIBADD= md +LIBADD= md util CFLAGS+= -DWITH_MD5 -DWITH_RIPEMD160 .ifdef BOOTSTRAPPING diff --git a/usr.bin/xinstall/install.1 b/usr.bin/xinstall/install.1 index c923321f20fe..169bf4ef11fe 100644 --- a/usr.bin/xinstall/install.1 +++ b/usr.bin/xinstall/install.1 @@ -33,7 +33,7 @@ .Nd install binaries .Sh SYNOPSIS .Nm -.Op Fl bCcpSsUv +.Op Fl bCcpSsUvz .Op Fl B Ar suffix .Op Fl D Ar destdir .Op Fl f Ar flags @@ -45,9 +45,10 @@ .Op Fl N Ar dbdir .Op Fl o Ar owner .Op Fl T Ar tags +.Op Fl z Ar size .Ar file1 file2 .Nm -.Op Fl bCcpSsUv +.Op Fl bCcpSsUvz .Op Fl B Ar suffix .Op Fl D Ar destdir .Op Fl f Ar flags @@ -59,6 +60,7 @@ .Op Fl N Ar dbdir .Op Fl o Ar owner .Op Fl T Ar tags +.Op Fl z Ar size .Ar file1 ... fileN directory .Nm .Fl d @@ -264,6 +266,13 @@ Cause .Nm to be verbose, showing files as they are installed or backed up. +.It Fl z Ar maxsize +Limit the comparison feature of +.Fl C +to files no larger than +.Ar maxsize . +Files exceeding this limit bypass the comparison step and are directly overwritten. +The default maximum size is 128MiB. .El .Pp By default, diff --git a/usr.bin/xinstall/xinstall.c b/usr.bin/xinstall/xinstall.c index 1aed8c1b24e4..d389bdbe3737 100644 --- a/usr.bin/xinstall/xinstall.c +++ b/usr.bin/xinstall/xinstall.c @@ -57,6 +57,7 @@ #include <string.h> #include <sysexits.h> #include <unistd.h> +#include <util.h> #include <vis.h> #include "mtree.h" @@ -87,7 +88,7 @@ #define HAVE_STRUCT_STAT_ST_FLAGS 0 #endif -#define MAX_CMP_SIZE (16 * 1024 * 1024) +#define MAX_CMP_SIZE (128 * 1024 * 1024) #define LN_ABSOLUTE 0x01 #define LN_RELATIVE 0x02 @@ -137,6 +138,7 @@ static FILE *metafp; static const char *group, *owner; static const char *suffix = BACKUP_SUFFIX; static char *destdir, *digest, *fflags, *metafile, *tags; +static size_t max_compare_size = MAX_CMP_SIZE; static int compare(int, const char *, size_t, int, const char *, size_t, char **); @@ -168,12 +170,13 @@ main(int argc, char *argv[]) u_int iflags; char *p; const char *to_name; + uint64_t num; fset = 0; iflags = 0; set = NULL; group = owner = NULL; - while ((ch = getopt(argc, argv, "B:bCcD:df:g:h:l:M:m:N:o:pSsT:Uv")) != + while ((ch = getopt(argc, argv, "B:bCcD:df:g:h:l:M:m:N:o:pSsT:Uvz:")) != -1) switch((char)ch) { case 'B': @@ -270,6 +273,13 @@ main(int argc, char *argv[]) case 'v': verbose = 1; break; + case 'z': + if (expand_number(optarg, &num) != 0 || num == 0) { + errx(EX_USAGE, "invalid max compare filesize:" + " %s", optarg); + } + max_compare_size = num; + break; case '?': default: usage(); @@ -1092,7 +1102,7 @@ compare(int from_fd, const char *from_name __unused, size_t from_len, do_digest = (digesttype != DIGEST_NONE && dresp != NULL && *dresp == NULL); - if (from_len <= MAX_CMP_SIZE) { + if (from_len <= max_compare_size) { static char *buf, *buf1, *buf2; static size_t bufsize; int n1, n2; @@ -1484,11 +1494,11 @@ usage(void) { (void)fprintf(stderr, "usage: install [-bCcpSsUv] [-f flags] [-g group] [-m mode] [-o owner]\n" -" [-M log] [-D dest] [-h hash] [-T tags]\n" +" [-M log] [-D dest] [-h hash] [-T tags] [-z maxcmpsize]\n" " [-B suffix] [-l linkflags] [-N dbdir]\n" " file1 file2\n" " install [-bCcpSsUv] [-f flags] [-g group] [-m mode] [-o owner]\n" -" [-M log] [-D dest] [-h hash] [-T tags]\n" +" [-M log] [-D dest] [-h hash] [-T tags] [-z maxcmpsize]\n" " [-B suffix] [-l linkflags] [-N dbdir]\n" " file1 ... fileN directory\n" " install -dU [-vU] [-g group] [-m mode] [-N dbdir] [-o owner]\n" diff --git a/usr.sbin/bsdinstall/distextract/distextract.c b/usr.sbin/bsdinstall/distextract/distextract.c index 32bd9453eb80..35cf19aae33f 100644 --- a/usr.sbin/bsdinstall/distextract/distextract.c +++ b/usr.sbin/bsdinstall/distextract/distextract.c @@ -291,6 +291,8 @@ extract_files(struct bsddialog_fileminibar *file) /* If that went well, perform the extraction */ if (retval == ARCHIVE_OK) retval = archive_read_extract(archive, entry, + ARCHIVE_EXTRACT_SECURE_NODOTDOT | + ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS | ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_XATTR | ARCHIVE_EXTRACT_FFLAGS); diff --git a/usr.sbin/bsdinstall/scripts/script b/usr.sbin/bsdinstall/scripts/script index 93d07c7899c3..4c792d80df6a 100755 --- a/usr.sbin/bsdinstall/scripts/script +++ b/usr.sbin/bsdinstall/scripts/script @@ -50,6 +50,7 @@ f_include $BSDCFG_SHARE/variable.subr ############################################################ GLOBALS : ${TMPDIR:="/tmp"} +: ${DISTRIBUTIONS=""}; export DISTRIBUTIONS # # Strings that should be moved to an i18n file and loaded with f_include_lang() diff --git a/usr.sbin/certctl/certctl.c b/usr.sbin/certctl/certctl.c index 0a07703bf37b..462f6c1730a9 100644 --- a/usr.sbin/certctl/certctl.c +++ b/usr.sbin/certctl/certctl.c @@ -1093,6 +1093,7 @@ int main(int argc, char *argv[]) { const char *command; + unsigned int i; int opt; while ((opt = getopt(argc, argv, "BcD:d:g:lL:M:no:Uv")) != -1) @@ -1155,8 +1156,8 @@ main(int argc, char *argv[]) set_defaults(); - for (unsigned i = 0; commands[i].name != NULL; i++) + for (i = 0; commands[i].name != NULL; i++) if (strcmp(command, commands[i].name) == 0) - exit(!!commands[i].func(argc, argv)); + exit(commands[i].func(argc, argv) == 0 ? 0 : 1); usage(); } diff --git a/usr.sbin/crashinfo/crashinfo.sh b/usr.sbin/crashinfo/crashinfo.sh index 68115f09f9d4..87e5565b98e3 100755 --- a/usr.sbin/crashinfo/crashinfo.sh +++ b/usr.sbin/crashinfo/crashinfo.sh @@ -149,11 +149,13 @@ fi VMCORE=$CRASHDIR/vmcore.$DUMPNR INFO=$CRASHDIR/info.$DUMPNR FILE=$CRASHDIR/core.txt.$DUMPNR +LINK=$CRASHDIR/core.txt.last HOSTNAME=`hostname` if $BATCH; then echo "Writing crash summary to $FILE." exec > $FILE 2>&1 + ln -sf $FILE $LINK fi GDB=/usr/local/bin/gdb @@ -204,6 +206,7 @@ machine=$(gdb_command $KERNEL 'printf "%s", machine') if ! $BATCH; then echo "Writing crash summary to $FILE." exec > $FILE 2>&1 + ln -sf $FILE $LINK fi echo "$HOSTNAME dumped core - see $VMCORE" diff --git a/usr.sbin/ctld/ctld.cc b/usr.sbin/ctld/ctld.cc index 9bdf15976911..834bef4ef363 100644 --- a/usr.sbin/ctld/ctld.cc +++ b/usr.sbin/ctld/ctld.cc @@ -1175,21 +1175,12 @@ conf::add_port(struct target *target, struct pport *pp) return (false); } - pp->link(); return (true); } bool -conf::add_port(struct kports &kports, struct target *target, int pp, int vp) +conf::add_port(struct target *target, const std::string &pname, int pp, int vp) { - struct pport *pport; - - std::string pname = freebsd::stringf("ioctl/%d/%d", pp, vp); - - pport = kports.find_port(pname); - if (pport != NULL) - return (add_port(target, pport)); - std::string name = pname + "-" + target->name(); const auto &pair = conf_ports.try_emplace(name, std::make_unique<ioctl_port>(target, pp, vp)); @@ -1387,6 +1378,19 @@ target::set_auth_type(const char *type) bool target::add_physical_port(std::string_view pport) { + /* Normalize ioctl port names. */ + std::string pname; + if (pport.compare(0, strlen("ioctl/"), "ioctl/") == 0) { + int ret, pp, vp; + + pname = std::string(pport); + ret = sscanf(pname.c_str(), "ioctl/%d/%d", &pp, &vp); + if (ret == 2) { + pname = freebsd::stringf("ioctl/%d/%d", pp, vp); + pport = pname; + } + } + for (const auto &s : t_pports) { if (s == pport) { log_warnx("duplicate physical port \"%s\" for target " @@ -2636,6 +2640,7 @@ conf_new_from_file(const char *path, bool ucl) bool conf::add_pports(struct kports &kports) { + std::unordered_map<struct pport *, struct target *> linked_ports; struct pport *pp; int ret, i_pp, i_vp; @@ -2643,35 +2648,50 @@ conf::add_pports(struct kports &kports) struct target *targ = kv.second.get(); for (const auto &pport : targ->pports()) { - ret = sscanf(pport.c_str(), "ioctl/%d/%d", &i_pp, - &i_vp); - if (ret > 0) { - if (!add_port(kports, targ, i_pp, i_vp)) { - log_warnx("can't create new ioctl port " - "for %s", targ->label()); + /* + * If this port is already present in the + * kernel, reuse the existing port. + */ + pp = kports.find_port(pport); + if (pp != nullptr) { + const auto &pair = linked_ports.try_emplace(pp, + targ); + if (!pair.second) { + log_warnx("can't link port \"%s\" to " + "%s, port already linked to %s", + pport.c_str(), targ->label(), + pair.first->second->label()); return (false); } + if (!add_port(targ, pp)) { + log_warnx( + "can't link port \"%s\" to %s", + pport.c_str(), targ->label()); + return (false); + } continue; } - pp = kports.find_port(pport); - if (pp == NULL) { - log_warnx("unknown port \"%s\" for %s", - pport.c_str(), targ->label()); - return (false); - } - if (pp->linked()) { - log_warnx("can't link port \"%s\" to %s, " - "port already linked to some target", - pport.c_str(), targ->label()); - return (false); - } - if (!add_port(targ, pp)) { - log_warnx("can't link port \"%s\" to %s", - pport.c_str(), targ->label()); - return (false); + /* + * If this port is an ioctl port, create a new + * port. + */ + ret = sscanf(pport.c_str(), "ioctl/%d/%d", &i_pp, + &i_vp); + if (ret == 2) { + if (!add_port(targ, pport, i_pp, i_vp)) { + log_warnx("can't create new port %s " + "for %s", pport.c_str(), + targ->label()); + return (false); + } + continue; } + + log_warnx("unknown port \"%s\" for %s", + pport.c_str(), targ->label()); + return (false); } } return (true); diff --git a/usr.sbin/ctld/ctld.hh b/usr.sbin/ctld/ctld.hh index 7ae033804157..3bc92449e372 100644 --- a/usr.sbin/ctld/ctld.hh +++ b/usr.sbin/ctld/ctld.hh @@ -487,7 +487,7 @@ struct conf { bool add_port(struct target *target, struct portal_group *pg, uint32_t ctl_port); bool add_port(struct target *target, struct pport *pp); - bool add_port(struct kports &kports, struct target *target, int pp, + bool add_port(struct target *target, const std::string &pname, int pp, int vp); bool add_pports(struct kports &kports); @@ -567,13 +567,9 @@ struct pport { const char *name() const { return pp_name.c_str(); } uint32_t ctl_port() const { return pp_ctl_port; } - bool linked() const { return pp_linked; } - void link() { pp_linked = true; } - private: std::string pp_name; uint32_t pp_ctl_port; - bool pp_linked = false; }; struct kports { diff --git a/usr.sbin/ctld/kernel.cc b/usr.sbin/ctld/kernel.cc index a6b0a79850ec..ef7ef87af090 100644 --- a/usr.sbin/ctld/kernel.cc +++ b/usr.sbin/ctld/kernel.cc @@ -446,8 +446,8 @@ add_iscsi_port(struct kports &kports, struct conf *conf, const struct cctl_port &port, std::string &name) { if (port.cfiscsi_target.empty()) { - log_debugx("CTL port %u \"%s\" wasn't managed by ctld; ", - port.port_id, name.c_str()); + log_debugx("CTL iSCSI port %u \"%s\" is not managed by ctld; " + "ignoring", port.port_id, name.c_str()); if (!kports.has_port(name)) { if (!kports.add_port(name, port.port_id)) { log_warnx("kports::add_port failed"); @@ -498,8 +498,8 @@ add_nvmf_port(struct conf *conf, const struct cctl_port &port, std::string &name) { if (port.nqn.empty() || port.ctld_transport_group_name.empty()) { - log_debugx("CTL port %u \"%s\" wasn't managed by ctld; ", - port.port_id, name.c_str()); + log_debugx("CTL NVMeoF port %u \"%s\" is not managed by ctld; " + "ignoring", port.port_id, name.c_str()); return; } @@ -549,7 +549,10 @@ conf_new_from_kernel(struct kports &kports) continue; std::string name = port.port_name; - if (port.pp != 0) { + if (port.port_frontend == "ioctl") + name += "/" + std::to_string(port.pp) + "/" + + std::to_string(port.vp); + else if (port.pp != 0 || port.vp != 0) { name += "/" + std::to_string(port.pp); if (port.vp != 0) name += "/" + std::to_string(port.vp); @@ -567,7 +570,7 @@ conf_new_from_kernel(struct kports &kports) for (const auto &lun : devlist.lun_list) { if (lun.ctld_name.empty()) { - log_debugx("CTL lun %ju wasn't managed by ctld; " + log_debugx("CTL lun %ju is not managed by ctld; " "ignoring", (uintmax_t)lun.lun_id); continue; } diff --git a/usr.sbin/sndctl/sndctl.8 b/usr.sbin/sndctl/sndctl.8 index 73414bd95325..44dcb791ca51 100644 --- a/usr.sbin/sndctl/sndctl.8 +++ b/usr.sbin/sndctl/sndctl.8 @@ -27,7 +27,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd December 2, 2025 +.Dd April 17, 2026 .Dt SNDCTL 8 .Os .Sh NAME @@ -82,6 +82,8 @@ The device controls are as follows: .It bitperfect Ta Boolean Ta Read/Write Ta Bit-perfect mode enabled .It autoconv Ta Boolean Ta Read/Write Ta Auto-conversions enabled .It realtime Ta Boolean Ta Read/Write Ta Real-time mode enabled +.It eq Ta Boolean Ta Read/Write Ta Equalization enabled +.It eq_preamp Ta String Ta Read/Write Ta Equalization preamp value (in dB) .It play Ta Group Ta Read Ta Playback properties .It play.format Ta String Ta Read/Write Ta Playback format .It play.rate Ta Number Ta Read/Write Ta Playback sample rate diff --git a/usr.sbin/sndctl/sndctl.c b/usr.sbin/sndctl/sndctl.c index bbc2da6a4ab9..778643a2a978 100644 --- a/usr.sbin/sndctl/sndctl.c +++ b/usr.sbin/sndctl/sndctl.c @@ -97,6 +97,8 @@ struct snd_dev { int bitperfect; int realtime; int autoconv; + int eq; + char eq_preamp[BUFSIZ]; struct { char format[FMTSTR_LEN]; int rate; @@ -130,6 +132,8 @@ struct map { static int mod_bitperfect(struct snd_dev *, void *); static int mod_autoconv(struct snd_dev *, void *); static int mod_realtime(struct snd_dev *, void *); +static int mod_eq(struct snd_dev *, void *); +static int mod_eq_preamp(struct snd_dev *, void *); static int mod_play_vchans(struct snd_dev *, void *); static int mod_play_rate(struct snd_dev *, void *); static int mod_play_format(struct snd_dev *, void *); @@ -149,6 +153,8 @@ static struct snd_ctl dev_ctls[] = { { "bitperfect", F(bitperfect), NUM, mod_bitperfect }, { "autoconv", F(autoconv), NUM, mod_autoconv }, { "realtime", F(realtime), NUM, mod_realtime }, + { "eq", F(eq), NUM, mod_eq }, + { "eq_preamp", F(eq_preamp), STR, mod_eq_preamp }, { "play", F(play), GRP, NULL }, { "play.format", F(play.format), STR, mod_play_format }, { "play.rate", F(play.rate), NUM, mod_play_rate }, @@ -436,6 +442,7 @@ read_dev(char *path) struct sndstioc_nv_arg arg; struct snd_dev *dp = NULL; struct snd_chan *ch; + char buf[64]; size_t nitems, nchans, i, j; int fd, caps, unit, t1, t2, t3; @@ -557,6 +564,14 @@ read_dev(char *path) if (t1 == 0 && t2 == 0 && t3 == 0) dp->realtime = 1; + snprintf(buf, sizeof(buf), "dev.pcm.%d.eq", dp->unit); + if (sysctl_int(buf, NULL, &dp->eq)) + xo_err(1, "%s: sysctl", dp->name); + + snprintf(buf, sizeof(buf), "dev.pcm.%d.eq_preamp", dp->unit); + if (sysctl_str(buf, NULL, dp->eq_preamp, sizeof(dp->eq_preamp))) + xo_err(1, "%s: sysctl", dp->name); + if (!nvlist_exists(nvlist_get_nvlist(di[i], SNDST_DSPS_PROVIDER_INFO), SNDST_DSPS_SOUND4_CHAN_INFO)) xo_errx(1, "%s: channel info list empty", dp->name); @@ -843,6 +858,32 @@ mod_realtime(struct snd_dev *dp, void *arg) } static int +mod_eq(struct snd_dev *dp, void *arg) +{ + char buf[64]; + + if (dp->from_user) + return (-1); + + snprintf(buf, sizeof(buf), "dev.pcm.%d.eq", dp->unit); + + return (sysctl_int(buf, arg, &dp->eq)); +} + +static int +mod_eq_preamp(struct snd_dev *dp, void *arg) +{ + char buf[64]; + + if (dp->from_user) + return (-1); + + snprintf(buf, sizeof(buf), "dev.pcm.%d.eq_preamp", dp->unit); + + return (sysctl_str(buf, arg, dp->eq_preamp, sizeof(dp->eq_preamp))); +} + +static int mod_play_vchans(struct snd_dev *dp, void *arg) { char buf[64]; diff --git a/usr.sbin/spi/spi.c b/usr.sbin/spi/spi.c index 1ced2371e3d0..bbbc3d322b00 100644 --- a/usr.sbin/spi/spi.c +++ b/usr.sbin/spi/spi.c @@ -30,6 +30,7 @@ #include <sys/spigenio.h> #include <sys/sysctl.h> +#include <assert.h> #include <errno.h> #include <fcntl.h> #include <inttypes.h> @@ -364,30 +365,24 @@ main(int argc, char *argv[], char *envp[] __unused) /* do data transfer */ - if (stream) { - while (!err && !feof(stdin)) { - if (fdir == DIR_READ) { - err = perform_read(hdev, &opt); - } - else if (fdir == DIR_WRITE) { - err = perform_write(hdev, &opt); - } - else if (fdir == DIR_READWRITE) { - err = perform_readwrite(hdev, &opt); - } - } - } - else { - if (fdir == DIR_READ) { + assert(fdir != DIR_NONE); + do { + switch (fdir) { + case DIR_READ: err = perform_read(hdev, &opt); - } - else if (fdir == DIR_WRITE) { + break; + case DIR_WRITE: err = perform_write(hdev, &opt); - } - else if (fdir == DIR_READWRITE) { + break; + case DIR_READWRITE: err = perform_readwrite(hdev, &opt); + break; + default: + fprintf(stderr, "Invalid state (%d)\n", fdir); + err = EINVAL; + break; } - } + } while (stream && !err && !feof(stdin)); the_end: diff --git a/usr.sbin/virtual_oss/virtual_oss/virtual_oss.c b/usr.sbin/virtual_oss/virtual_oss/virtual_oss.c index 1d95c87d57b1..42a748a5e3bd 100644 --- a/usr.sbin/virtual_oss/virtual_oss/virtual_oss.c +++ b/usr.sbin/virtual_oss/virtual_oss/virtual_oss.c @@ -783,8 +783,8 @@ virtual_oss_process(void *arg __unused) /* check if compressor should be applied */ voss_compressor(buffer_temp, pvp->rx_compressor_gain, - &pvp->rx_compressor_param, samples, - samples * src_chans, (1ULL << (pvp->bits - 1)) - 1ULL); + &pvp->rx_compressor_param, samples * src_chans, + src_chans, (1ULL << (pvp->bits - 1)) - 1ULL); TAILQ_FOREACH(pvc, &pvp->head, entry) { |
