diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc index e1ced44236f..e86a4a24489 100644 --- a/ObsoleteFiles.inc +++ b/ObsoleteFiles.inc @@ -150,9 +150,7 @@ OLD_FILES+=usr/lib/clang/4.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_ OLD_DIRS+=usr/lib/clang/4.0.0/lib/freebsd OLD_DIRS+=usr/lib/clang/4.0.0/lib OLD_DIRS+=usr/lib/clang/4.0.0 -# 20170426: Remove cy(4) -OLD_FILES+=usr/share/man/man4/cy.4.gz -# 20170425: NATM configuration support removed +# 20170427: NATM configuration support removed OLD_FILES+=etc/rc.d/atm1 OLD_FILES+=etc/rc.d/atm2 OLD_FILES+=etc/rc.d/atm3 @@ -190,6 +188,7 @@ OLD_FILES+=usr/share/man/man4/ng_atm.4.gz OLD_FILES+=usr/share/man/man4/patm.4.gz OLD_FILES+=usr/share/man/man4/utopia.4.gz OLD_FILES+=usr/share/man/man8/atmconfig.8.gz +OLD_FILES+=usr/share/man/man9/utopia.9.gz OLD_FILES+=usr/share/snmp/defs/atm_freebsd.def OLD_FILES+=usr/share/snmp/defs/atm_tree.def OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-ATM-FREEBSD-MIB.txt diff --git a/bin/sh/expand.c b/bin/sh/expand.c index af88771babe..30f0ec50ec5 100644 --- a/bin/sh/expand.c +++ b/bin/sh/expand.c @@ -462,6 +462,7 @@ expbackq(union node *cmd, int quoted, int flag, struct worddest *dst) int quotes = flag & (EXP_GLOB | EXP_CASE); size_t nnl; const char *ifs; + int startloc; INTOFF; p = grabstackstr(dest); @@ -469,6 +470,7 @@ expbackq(union node *cmd, int quoted, int flag, struct worddest *dst) ungrabstackstr(p, dest); p = in.buf; + startloc = dest - stackblock(); nnl = 0; if (!quoted && flag & EXP_SPLIT) ifs = ifsset() ? ifsval() : " \t\n"; @@ -490,31 +492,24 @@ expbackq(union node *cmd, int quoted, int flag, struct worddest *dst) lastc = *p++; if (lastc == '\0') continue; - if (lastc == '\n') { - nnl++; - } else { - if (nnl > 0) { - if (strchr(ifs, '\n') != NULL) { - NEXTWORD('\n', flag, dest, dst); - nnl = 0; - } else { - CHECKSTRSPACE(nnl + 2, dest); - while (nnl > 0) { - nnl--; - USTPUTC('\n', dest); - } - } - } - if (strchr(ifs, lastc) != NULL) + if (nnl > 0 && lastc != '\n') { + NEXTWORD('\n', flag, dest, dst); + nnl = 0; + } + if (strchr(ifs, lastc) != NULL) { + if (lastc == '\n') + nnl++; + else NEXTWORD(lastc, flag, dest, dst); - else { - CHECKSTRSPACE(2, dest); - if (quotes && syntax[(int)lastc] == CCTL) - USTPUTC(CTLESC, dest); - USTPUTC(lastc, dest); - } + } else { + CHECKSTRSPACE(2, dest); + if (quotes && syntax[(int)lastc] == CCTL) + USTPUTC(CTLESC, dest); + USTPUTC(lastc, dest); } } + while (dest > stackblock() + startloc && STTOPC(dest) == '\n') + STUNPUTC(dest); if (in.fd >= 0) close(in.fd); diff --git a/bin/sh/tests/expansion/Makefile b/bin/sh/tests/expansion/Makefile index 078220ef990..f3cfc22b17c 100644 --- a/bin/sh/tests/expansion/Makefile +++ b/bin/sh/tests/expansion/Makefile @@ -46,6 +46,8 @@ ${PACKAGE}FILES+= cmdsubst21.0 ${PACKAGE}FILES+= cmdsubst22.0 ${PACKAGE}FILES+= cmdsubst23.0 ${PACKAGE}FILES+= cmdsubst24.0 +${PACKAGE}FILES+= cmdsubst25.0 +${PACKAGE}FILES+= cmdsubst26.0 ${PACKAGE}FILES+= export1.0 ${PACKAGE}FILES+= export2.0 ${PACKAGE}FILES+= export3.0 diff --git a/bin/sh/tests/expansion/cmdsubst25.0 b/bin/sh/tests/expansion/cmdsubst25.0 new file mode 100644 index 00000000000..83cca7d0b97 --- /dev/null +++ b/bin/sh/tests/expansion/cmdsubst25.0 @@ -0,0 +1,7 @@ +# $FreeBSD$ + +IFS=' ' +set -- `printf '\n '` +IFS=: +[ "$*" = ' +' ] diff --git a/bin/sh/tests/expansion/cmdsubst26.0 b/bin/sh/tests/expansion/cmdsubst26.0 new file mode 100644 index 00000000000..68a624b1247 --- /dev/null +++ b/bin/sh/tests/expansion/cmdsubst26.0 @@ -0,0 +1,6 @@ +# $FreeBSD$ + +nl=' +' +v=$nl`printf '\n'` +[ "$v" = "$nl" ] diff --git a/contrib/blacklist/README b/contrib/blacklist/README index 44e1026ac4d..7da3317a77f 100644 --- a/contrib/blacklist/README +++ b/contrib/blacklist/README @@ -1,4 +1,4 @@ -# $NetBSD: README,v 1.7 2015/01/26 00:34:50 christos Exp $ +# $NetBSD: README,v 1.8 2017/04/13 17:59:34 christos Exp $ This package contains library that can be used by network daemons to communicate with a packet filter via a daemon to enforce opening and @@ -98,6 +98,16 @@ group "internal" on $int_if { ... } +You can use 'blacklistctl dump -a' to list all the current entries +in the database; the ones that have nfail / where urrent +>= otal, should have an id assosiated with them; this means that +there is a packet filter rule added for that entry. For npf, you +can examine the packet filter dynamic rule entries using 'npfctl +rule list'. The number of current entries can exceed +the total. This happens because entering packet filter rules is +asynchronous; there could be other connection before the rule +becomes activated. + Enjoy, christos diff --git a/contrib/blacklist/bin/blacklistctl.8 b/contrib/blacklist/bin/blacklistctl.8 index f28ab28df11..7c652111774 100644 --- a/contrib/blacklist/bin/blacklistctl.8 +++ b/contrib/blacklist/bin/blacklistctl.8 @@ -1,4 +1,4 @@ -.\" $NetBSD: blacklistctl.8,v 1.7 2015/04/30 06:20:43 riz Exp $ +.\" $NetBSD: blacklistctl.8,v 1.9 2016/06/08 12:48:37 wiz Exp $ .\" .\" Copyright (c) 2015 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -77,7 +77,8 @@ it to make sure that there is only one rule active. .Nm first appeared in .Nx 7 . -.Fx support for +.Fx +support for .Nm was implemented in .Fx 11 . diff --git a/contrib/blacklist/bin/blacklistctl.c b/contrib/blacklist/bin/blacklistctl.c index 3ac65a508b0..8cef404d74b 100644 --- a/contrib/blacklist/bin/blacklistctl.c +++ b/contrib/blacklist/bin/blacklistctl.c @@ -1,4 +1,4 @@ -/* $NetBSD: blacklistctl.c,v 1.20 2016/04/04 15:52:56 christos Exp $ */ +/* $NetBSD: blacklistctl.c,v 1.21 2016/11/02 03:15:07 jnemeth Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -33,7 +33,7 @@ #endif #include -__RCSID("$NetBSD: blacklistctl.c,v 1.20 2016/04/04 15:52:56 christos Exp $"); +__RCSID("$NetBSD: blacklistctl.c,v 1.21 2016/11/02 03:15:07 jnemeth Exp $"); #include #include diff --git a/contrib/blacklist/bin/blacklistd.c b/contrib/blacklist/bin/blacklistd.c index 256ae68b61b..f5c35eae1ad 100644 --- a/contrib/blacklist/bin/blacklistd.c +++ b/contrib/blacklist/bin/blacklistd.c @@ -1,4 +1,4 @@ -/* $NetBSD: blacklistd.c,v 1.35 2016/09/26 19:43:43 christos Exp $ */ +/* $NetBSD: blacklistd.c,v 1.37 2017/02/18 00:26:16 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -32,7 +32,7 @@ #include "config.h" #endif #include -__RCSID("$NetBSD: blacklistd.c,v 1.35 2016/09/26 19:43:43 christos Exp $"); +__RCSID("$NetBSD: blacklistd.c,v 1.37 2017/02/18 00:26:16 christos Exp $"); #include #include @@ -403,12 +403,14 @@ int main(int argc, char *argv[]) { int c, tout, flags, flush, restore, ret; - const char *spath, *blsock; + const char *spath, **blsock; + size_t nblsock, maxblsock; setprogname(argv[0]); spath = NULL; - blsock = _PATH_BLSOCK; + blsock = NULL; + maxblsock = nblsock = 0; flush = 0; restore = 0; tout = 0; @@ -440,7 +442,17 @@ main(int argc, char *argv[]) restore++; break; case 's': - blsock = optarg; + if (nblsock >= maxblsock) { + maxblsock += 10; + void *p = realloc(blsock, + sizeof(*blsock) * maxblsock); + if (p == NULL) + err(EXIT_FAILURE, + "Can't allocate memory for %zu sockets", + maxblsock); + blsock = p; + } + blsock[nblsock++] = optarg; break; case 't': tout = atoi(optarg) * 1000; @@ -487,9 +499,11 @@ main(int argc, char *argv[]) size_t nfd = 0; size_t maxfd = 0; - if (spath == NULL) - addfd(&pfd, &bl, &nfd, &maxfd, blsock); - else { + for (size_t i = 0; i < nblsock; i++) + addfd(&pfd, &bl, &nfd, &maxfd, blsock[i]); + free(blsock); + + if (spath) { FILE *fp = fopen(spath, "r"); char *line; if (fp == NULL) @@ -499,6 +513,8 @@ main(int argc, char *argv[]) addfd(&pfd, &bl, &nfd, &maxfd, line); fclose(fp); } + if (nfd == 0) + addfd(&pfd, &bl, &nfd, &maxfd, _PATH_BLSOCK); state = state_open(dbfile, flags, 0600); if (state == NULL) diff --git a/contrib/blacklist/bin/blacklistd.conf.5 b/contrib/blacklist/bin/blacklistd.conf.5 index aa10e340829..9d44012c8a6 100644 --- a/contrib/blacklist/bin/blacklistd.conf.5 +++ b/contrib/blacklist/bin/blacklistd.conf.5 @@ -1,4 +1,4 @@ -.\" $NetBSD: blacklistd.conf.5,v 1.3 2015/04/30 06:20:43 riz Exp $ +.\" $NetBSD: blacklistd.conf.5,v 1.5 2016/06/08 12:48:37 wiz Exp $ .\" .\" Copyright (c) 2015 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -218,7 +218,8 @@ bnx0:ssh * * * * 3 6h .Nm first appeared in .Nx 7 . -.Fx support for +.Fx +support for .Nm was implemented in .Fx 11 . diff --git a/contrib/blacklist/etc/rc.d/blacklistd b/contrib/blacklist/etc/rc.d/blacklistd index 2e46f518fc7..278a6742e63 100644 --- a/contrib/blacklist/etc/rc.d/blacklistd +++ b/contrib/blacklist/etc/rc.d/blacklistd @@ -1,6 +1,6 @@ #!/bin/sh # -# $NetBSD: blacklistd,v 1.1 2015/01/22 17:49:41 christos Exp $ +# $NetBSD: blacklistd,v 1.2 2016/10/17 22:47:16 christos Exp $ # # PROVIDE: blacklistd @@ -18,7 +18,7 @@ start_precmd="${name}_precmd" extra_commands="reload" _sockfile="/var/run/${name}.sockets" -_sockname="blsock" +_sockname="blacklistd.sock" blacklistd_precmd() { diff --git a/contrib/blacklist/lib/bl.c b/contrib/blacklist/lib/bl.c index 3c3201d26ae..9f93b91f4c8 100644 --- a/contrib/blacklist/lib/bl.c +++ b/contrib/blacklist/lib/bl.c @@ -1,4 +1,4 @@ -/* $NetBSD: bl.c,v 1.27 2015/12/30 16:42:48 christos Exp $ */ +/* $NetBSD: bl.c,v 1.28 2016/07/29 17:13:09 christos Exp $ */ /*- * Copyright (c) 2014 The NetBSD Foundation, Inc. @@ -33,7 +33,7 @@ #endif #include -__RCSID("$NetBSD: bl.c,v 1.27 2015/12/30 16:42:48 christos Exp $"); +__RCSID("$NetBSD: bl.c,v 1.28 2016/07/29 17:13:09 christos Exp $"); #include #include diff --git a/contrib/blacklist/lib/libblacklist.3 b/contrib/blacklist/lib/libblacklist.3 index e13682031b8..bab2ad1ffc2 100644 --- a/contrib/blacklist/lib/libblacklist.3 +++ b/contrib/blacklist/lib/libblacklist.3 @@ -1,4 +1,4 @@ -.\" $NetBSD: libblacklist.3,v 1.3 2015/01/25 23:09:28 wiz Exp $ +.\" $NetBSD: libblacklist.3,v 1.7 2017/02/04 23:33:56 wiz Exp $ .\" .\" Copyright (c) 2015 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -36,7 +36,7 @@ .Nm blacklist_r , .Nm blacklist , .Nm blacklist_sa -.Nm blacklist_sa_r , +.Nm blacklist_sa_r .Nd Blacklistd notification library .Sh LIBRARY .Lb libblacklist @@ -62,7 +62,7 @@ block or release port access to prevent Denial of Service attacks. .Pp The function .Fn blacklist_open -creates a the necessary state to communicate with +creates the necessary state to communicate with .Xr blacklistd 8 and returns a pointer to it, or .Dv NULL @@ -106,18 +106,25 @@ All functions log errors to .Xr syslogd 8 . .Sh RETURN VALUES The function -.Fn bl_open +.Fn blacklist_open returns a cookie on success and .Dv NULL -on failure setting errno to an appropriate value. +on failure setting +.Dv errno +to an appropriate value. .Pp -The -.Fn bl_send -function returns +The functions +.Fn blacklist , +.Fn blacklist_sa , +and +.Fn blacklist_sa_r +return .Dv 0 on success and -.Dv -1 -on failure setting errno to an appropriate value. +.Dv \-1 +on failure setting +.Dv errno +to an appropriate value. .Sh SEE ALSO .Xr blacklistd.conf 5 , .Xr blacklistd 8 diff --git a/contrib/blacklist/libexec/blacklistd-helper b/contrib/blacklist/libexec/blacklistd-helper index 37f94a65b81..2d0a89e8fb0 100644 --- a/contrib/blacklist/libexec/blacklistd-helper +++ b/contrib/blacklist/libexec/blacklistd-helper @@ -19,8 +19,8 @@ fi if [ -z "$pf" ]; then for f in npf pf ipf; do if [ -f "/etc/$f.conf" ]; then - pf="$f" - break + pf="$f" + break fi done fi diff --git a/contrib/blacklist/port/Makefile.am b/contrib/blacklist/port/Makefile.am index f1b36ca880a..43bf6c94b42 100644 --- a/contrib/blacklist/port/Makefile.am +++ b/contrib/blacklist/port/Makefile.am @@ -1,11 +1,11 @@ # ACLOCAL_AMFLAGS = -I m4 lib_LTLIBRARIES = libblacklist.la -include_HEADERS = blacklist.h +include_HEADERS = ../include/blacklist.h bin_PROGRAMS = blacklistd blacklistctl srvtest cltest -VPATH = ../bin:../lib:../test +VPATH = ../bin:../lib:../test:../include AM_CPPFLAGS = -I../include -DDOT="." AM_CFLAGS = @WARNINGS@ diff --git a/contrib/blacklist/port/sockaddr_snprintf.c b/contrib/blacklist/port/sockaddr_snprintf.c index 41e5e0c0ed2..558755b6294 100644 --- a/contrib/blacklist/port/sockaddr_snprintf.c +++ b/contrib/blacklist/port/sockaddr_snprintf.c @@ -1,4 +1,4 @@ -/* $NetBSD: sockaddr_snprintf.c,v 1.10 2016/04/05 12:28:57 christos Exp $ */ +/* $NetBSD: sockaddr_snprintf.c,v 1.11 2016/06/01 22:57:51 christos Exp $ */ /*- * Copyright (c) 2004 The NetBSD Foundation, Inc. @@ -34,7 +34,7 @@ #include #if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: sockaddr_snprintf.c,v 1.10 2016/04/05 12:28:57 christos Exp $"); +__RCSID("$NetBSD: sockaddr_snprintf.c,v 1.11 2016/06/01 22:57:51 christos Exp $"); #endif /* LIBC_SCCS and not lint */ #include @@ -219,7 +219,7 @@ sockaddr_snprintf(char * const sbuf, const size_t len, const char * const fmt, case AF_LINK: sdl = ((const struct sockaddr_dl *)(const void *)sa); (void)strlcpy(addr = abuf, link_ntoa(sdl), sizeof(abuf)); - if ((w = strchr(addr, ':')) != 0) { + if ((w = strchr(addr, ':')) != NULL) { *w++ = '\0'; addr = w; } diff --git a/contrib/elftoolchain/cxxfilt/cxxfilt.c b/contrib/elftoolchain/cxxfilt/cxxfilt.c index aef9023ffbb..9a051fb4151 100644 --- a/contrib/elftoolchain/cxxfilt/cxxfilt.c +++ b/contrib/elftoolchain/cxxfilt/cxxfilt.c @@ -189,8 +189,6 @@ main(int argc, char **argv) if (c == EOF) break; putchar(c); - if (c == '\n') - fflush(stdout); } else { if ((size_t) p >= sizeof(buf) - 1) warnx("buffer overflowed"); diff --git a/contrib/hyperv/tools/hv_kvp_daemon.c b/contrib/hyperv/tools/hv_kvp_daemon.c index 50bd27628b3..2770a8d6bc9 100644 --- a/contrib/hyperv/tools/hv_kvp_daemon.c +++ b/contrib/hyperv/tools/hv_kvp_daemon.c @@ -61,6 +61,10 @@ typedef uint16_t __u16; typedef uint32_t __u32; typedef uint64_t __u64; +#define POOL_FILE_MODE (S_IRUSR | S_IWUSR) +#define POOL_DIR_MODE (POOL_FILE_MODE | S_IXUSR) +#define POOL_DIR "/var/db/hyperv/pool" + /* * ENUM Data */ @@ -285,11 +289,12 @@ kvp_file_init(void) int i; int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK; - if (mkdir("/var/db/hyperv/pool", S_IRUSR | S_IWUSR | S_IROTH) < 0 && + if (mkdir(POOL_DIR, POOL_DIR_MODE) < 0 && (errno != EEXIST && errno != EISDIR)) { KVP_LOG(LOG_ERR, " Failed to create /var/db/hyperv/pool\n"); exit(EXIT_FAILURE); } + chmod(POOL_DIR, POOL_DIR_MODE); /* fix old mistake */ for (i = 0; i < HV_KVP_POOL_COUNT; i++) { @@ -297,11 +302,12 @@ kvp_file_init(void) records_read = 0; num_blocks = 1; snprintf(fname, MAX_FILE_NAME, "/var/db/hyperv/pool/.kvp_pool_%d", i); - fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH); + fd = open(fname, O_RDWR | O_CREAT, POOL_FILE_MODE); if (fd == -1) { return (1); } + fchmod(fd, POOL_FILE_MODE); /* fix old mistake */ filep = fopen(fname, "r"); diff --git a/contrib/libarchive/cpio/cpio.c b/contrib/libarchive/cpio/cpio.c index 42e26cdf0af..cade829571b 100644 --- a/contrib/libarchive/cpio/cpio.c +++ b/contrib/libarchive/cpio/cpio.c @@ -628,6 +628,7 @@ mode_out(struct cpio *cpio) blocks == 1 ? "block" : "blocks"); } archive_write_free(cpio->archive); + archive_entry_linkresolver_free(cpio->linkresolver); } static const char * @@ -1194,12 +1195,15 @@ mode_pass(struct cpio *cpio, const char *destdir) struct lafe_line_reader *lr; const char *p; int r; + size_t destdir_len; /* Ensure target dir has a trailing '/' to simplify path surgery. */ - cpio->destdir = malloc(strlen(destdir) + 8); - strcpy(cpio->destdir, destdir); - if (destdir[strlen(destdir) - 1] != '/') - strcat(cpio->destdir, "/"); + destdir_len = strlen(destdir); + cpio->destdir = malloc(destdir_len + 8); + memcpy(cpio->destdir, destdir, destdir_len); + if (destdir_len == 0 || destdir[destdir_len - 1] != '/') + cpio->destdir[destdir_len++] = '/'; + cpio->destdir[destdir_len++] = '\0'; cpio->archive = archive_write_disk_new(); if (cpio->archive == NULL) @@ -1240,6 +1244,7 @@ mode_pass(struct cpio *cpio, const char *destdir) } archive_write_free(cpio->archive); + free(cpio->pass_destpath); } /* diff --git a/contrib/libarchive/cpio/test/test_option_Z_upper.c b/contrib/libarchive/cpio/test/test_option_Z_upper.c index d69a85ea58a..ff388427e37 100644 --- a/contrib/libarchive/cpio/test/test_option_Z_upper.c +++ b/contrib/libarchive/cpio/test/test_option_Z_upper.c @@ -43,17 +43,18 @@ DEFINE_TEST(test_option_Z_upper) if (strstr(p, "compression not available") != NULL) { skipping("This version of bsdcpio was compiled " "without compress support"); + free(p); return; } failure("-Z option is broken"); assertEqualInt(r, 0); - goto done; + free(p); + return; } free(p); /* Check that the archive file has a compress signature. */ p = slurpfile(&s, "archive.out"); assert(s > 2); assertEqualMem(p, "\x1f\x9d", 2); -done: free(p); } diff --git a/contrib/libarchive/cpio/test/test_option_a.c b/contrib/libarchive/cpio/test/test_option_a.c index af4b48e577d..94bcc6a61ff 100644 --- a/contrib/libarchive/cpio/test/test_option_a.c +++ b/contrib/libarchive/cpio/test/test_option_a.c @@ -96,7 +96,8 @@ DEFINE_TEST(test_option_a) test_create(); /* Sanity check; verify that atimes really do get modified. */ - assert((p = slurpfile(NULL, "f0")) != NULL); + p = slurpfile(NULL, "f0"); + assert(p != NULL); free(p); assertEqualInt(0, stat("f0", &st)); if (st.st_atime == files[0].atime_sec) { diff --git a/contrib/libarchive/cpio/test/test_option_b64encode.c b/contrib/libarchive/cpio/test/test_option_b64encode.c index 8f6b4157c01..7c15a823060 100644 --- a/contrib/libarchive/cpio/test/test_option_b64encode.c +++ b/contrib/libarchive/cpio/test/test_option_b64encode.c @@ -42,6 +42,7 @@ DEFINE_TEST(test_option_b64encode) p = slurpfile(&s, "archive.out"); assert(s > 2); assertEqualMem(p, "begin-base64 644", 16); + free(p); /* Archive it with uuencode only. */ assertEqualInt(0, @@ -51,4 +52,5 @@ DEFINE_TEST(test_option_b64encode) p = slurpfile(&s, "archive.out"); assert(s > 2); assertEqualMem(p, "begin-base64 644", 16); + free(p); } diff --git a/contrib/libarchive/cpio/test/test_option_grzip.c b/contrib/libarchive/cpio/test/test_option_grzip.c index dfce2e064e0..7e7dd2c8e6f 100644 --- a/contrib/libarchive/cpio/test/test_option_grzip.c +++ b/contrib/libarchive/cpio/test/test_option_grzip.c @@ -44,9 +44,10 @@ DEFINE_TEST(test_option_grzip) systemf("echo f | %s -o --grzip >archive.out 2>archive.err", testprog)); p = slurpfile(&s, "archive.err"); - p[s] = '\0'; + free(p); /* Check that the archive file has an grzip signature. */ p = slurpfile(&s, "archive.out"); assert(s > 2); assertEqualMem(p, "GRZipII\x00\x02\x04:)", 12); + free(p); } diff --git a/contrib/libarchive/cpio/test/test_option_lrzip.c b/contrib/libarchive/cpio/test/test_option_lrzip.c index a84f75157a4..8d9c0d576cc 100644 --- a/contrib/libarchive/cpio/test/test_option_lrzip.c +++ b/contrib/libarchive/cpio/test/test_option_lrzip.c @@ -44,9 +44,10 @@ DEFINE_TEST(test_option_lrzip) systemf("echo f | %s -o --lrzip >archive.out 2>archive.err", testprog)); p = slurpfile(&s, "archive.err"); - p[s] = '\0'; + free(p); /* Check that the archive file has an lzma signature. */ p = slurpfile(&s, "archive.out"); assert(s > 2); assertEqualMem(p, "LRZI\x00", 5); + free(p); } diff --git a/contrib/libarchive/cpio/test/test_option_lz4.c b/contrib/libarchive/cpio/test/test_option_lz4.c index afd683ddc77..88dfbd63bae 100644 --- a/contrib/libarchive/cpio/test/test_option_lz4.c +++ b/contrib/libarchive/cpio/test/test_option_lz4.c @@ -43,6 +43,7 @@ DEFINE_TEST(test_option_lz4) if (strstr(p, "compression not available") != NULL) { skipping("This version of bsdcpio was compiled " "without lz4 support"); + free(p); return; } /* POSIX permits different handling of the spawnp @@ -52,6 +53,7 @@ DEFINE_TEST(test_option_lz4) if (strstr(p, "Can't launch") != NULL && !canLz4()) { skipping("This version of bsdcpio uses an external lz4 program " "but no such program is available on this system."); + free(p); return; } /* Some systems successfully spawn the new process, @@ -61,6 +63,7 @@ DEFINE_TEST(test_option_lz4) if (strstr(p, "Can't write") != NULL && !canLz4()) { skipping("This version of bsdcpio uses an external lz4 program " "but no such program is available on this system."); + free(p); return; } /* On some systems the error won't be detected until closing @@ -68,14 +71,18 @@ DEFINE_TEST(test_option_lz4) if (strstr(p, "Error closing") != NULL && !canLz4()) { skipping("This version of bsdcpio uses an external lz4 program " "but no such program is available on this system."); + free(p); return; } + free(p); failure("--lz4 option is broken: %s", p); assertEqualInt(r, 0); return; } + free(p); /* Check that the archive file has an lz4 signature. */ p = slurpfile(&s, "archive.out"); assert(s > 2); assertEqualMem(p, "\x04\x22\x4d\x18", 4); + free(p); } diff --git a/contrib/libarchive/cpio/test/test_option_lzma.c b/contrib/libarchive/cpio/test/test_option_lzma.c index c6e33530150..b7cad3d1e99 100644 --- a/contrib/libarchive/cpio/test/test_option_lzma.c +++ b/contrib/libarchive/cpio/test/test_option_lzma.c @@ -43,14 +43,18 @@ DEFINE_TEST(test_option_lzma) if (strstr(p, "compression not available") != NULL) { skipping("This version of bsdcpio was compiled " "without lzma support"); + free(p); return; } failure("--lzma option is broken"); assertEqualInt(r, 0); + free(p); return; } + free(p); /* Check that the archive file has an lzma signature. */ p = slurpfile(&s, "archive.out"); assert(s > 2); assertEqualMem(p, "\x5d\00\00", 3); + free(p); } diff --git a/contrib/libarchive/cpio/test/test_option_lzop.c b/contrib/libarchive/cpio/test/test_option_lzop.c index 9f1666e9c5b..aa40ef5b639 100644 --- a/contrib/libarchive/cpio/test/test_option_lzop.c +++ b/contrib/libarchive/cpio/test/test_option_lzop.c @@ -39,7 +39,7 @@ DEFINE_TEST(test_option_lzop) r = systemf("echo f | %s -o --lzop >archive.out 2>archive.err", testprog); p = slurpfile(&s, "archive.err"); - p[s] = '\0'; + free(p); if (r != 0) { if (!canLzop()) { skipping("lzop is not supported on this platform"); @@ -53,4 +53,5 @@ DEFINE_TEST(test_option_lzop) p = slurpfile(&s, "archive.out"); assert(s > 2); assertEqualMem(p, "\x89\x4c\x5a\x4f\x00\x0d\x0a\x1a\x0a", 9); + free(p); } diff --git a/contrib/libarchive/cpio/test/test_option_uuencode.c b/contrib/libarchive/cpio/test/test_option_uuencode.c index ecf354f8f39..a42a0e03096 100644 --- a/contrib/libarchive/cpio/test/test_option_uuencode.c +++ b/contrib/libarchive/cpio/test/test_option_uuencode.c @@ -42,6 +42,7 @@ DEFINE_TEST(test_option_uuencode) p = slurpfile(&s, "archive.out"); assert(s > 2); assertEqualMem(p, "begin 644", 9); + free(p); /* Archive it with uuencode only. */ assertEqualInt(0, @@ -51,4 +52,5 @@ DEFINE_TEST(test_option_uuencode) p = slurpfile(&s, "archive.out"); assert(s > 2); assertEqualMem(p, "begin 644", 9); + free(p); } diff --git a/contrib/libarchive/cpio/test/test_option_xz.c b/contrib/libarchive/cpio/test/test_option_xz.c index 02b5dfaad4a..f0d3b33d45b 100644 --- a/contrib/libarchive/cpio/test/test_option_xz.c +++ b/contrib/libarchive/cpio/test/test_option_xz.c @@ -44,14 +44,18 @@ DEFINE_TEST(test_option_xz) if (strstr(p, "compression not available") != NULL) { skipping("This version of bsdcpio was compiled " "without xz support"); + free(p); return; } + free(p); failure("--xz option is broken"); assertEqualInt(r, 0); return; } + free(p); /* Check that the archive file has an xz signature. */ p = slurpfile(&s, "archive.out"); assert(s > 2); assertEqualMem(p, "\xFD\x37\x7A\x58\x5A\x00", 6); + free(p); } diff --git a/contrib/libarchive/cpio/test/test_option_y.c b/contrib/libarchive/cpio/test/test_option_y.c index 75c956388e0..ddb498ffc12 100644 --- a/contrib/libarchive/cpio/test/test_option_y.c +++ b/contrib/libarchive/cpio/test/test_option_y.c @@ -38,7 +38,7 @@ DEFINE_TEST(test_option_y) r = systemf("echo f | %s -oy >archive.out 2>archive.err", testprog); p = slurpfile(&s, "archive.err"); - p[s] = '\0'; + free(p); if (r != 0) { if (!canBzip2()) { skipping("bzip2 is not supported on this platform"); @@ -46,14 +46,12 @@ DEFINE_TEST(test_option_y) } failure("-y option is broken"); assertEqualInt(r, 0); - goto done; + return; } assertTextFileContents("1 block\n", "archive.err"); /* Check that the archive file has a bzip2 signature. */ - free(p); p = slurpfile(&s, "archive.out"); assert(s > 2); assertEqualMem(p, "BZh9", 4); -done: free(p); } diff --git a/contrib/libarchive/cpio/test/test_option_z.c b/contrib/libarchive/cpio/test/test_option_z.c index 0b68a42babb..803232d045c 100644 --- a/contrib/libarchive/cpio/test/test_option_z.c +++ b/contrib/libarchive/cpio/test/test_option_z.c @@ -38,7 +38,7 @@ DEFINE_TEST(test_option_z) r = systemf("echo f | %s -oz >archive.out 2>archive.err", testprog); p = slurpfile(&s, "archive.err"); - p[s] = '\0'; + free(p); if (r != 0) { if (!canGzip()) { skipping("gzip is not supported on this platform"); @@ -52,4 +52,5 @@ DEFINE_TEST(test_option_z) p = slurpfile(&s, "archive.out"); assert(s > 4); assertEqualMem(p, "\x1f\x8b\x08\x00", 4); + free(p); } diff --git a/contrib/libarchive/libarchive/archive_entry_sparse.c b/contrib/libarchive/libarchive/archive_entry_sparse.c index fed74f5121d..74917b37b80 100644 --- a/contrib/libarchive/libarchive/archive_entry_sparse.c +++ b/contrib/libarchive/libarchive/archive_entry_sparse.c @@ -51,7 +51,7 @@ archive_entry_sparse_clear(struct archive_entry *entry) void archive_entry_sparse_add_entry(struct archive_entry *entry, - int64_t offset, int64_t length) + la_int64_t offset, la_int64_t length) { struct ae_sparse *sp; @@ -135,7 +135,7 @@ archive_entry_sparse_reset(struct archive_entry * entry) int archive_entry_sparse_next(struct archive_entry * entry, - int64_t *offset, int64_t *length) + la_int64_t *offset, la_int64_t *length) { if (entry->sparse_p) { *offset = entry->sparse_p->offset; diff --git a/contrib/libarchive/libarchive/archive_getdate.c b/contrib/libarchive/libarchive/archive_getdate.c index fe43ae820ae..030c083ce71 100644 --- a/contrib/libarchive/libarchive/archive_getdate.c +++ b/contrib/libarchive/libarchive/archive_getdate.c @@ -691,7 +691,7 @@ Convert(time_t Month, time_t Day, time_t Year, time_t Hours, time_t Minutes, time_t Seconds, time_t Timezone, enum DSTMODE DSTmode) { - int DaysInMonth[12] = { + signed char DaysInMonth[12] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; time_t Julian; diff --git a/contrib/libarchive/libarchive/archive_openssl_hmac_private.h b/contrib/libarchive/libarchive/archive_openssl_hmac_private.h index 2deeb5f5590..59f95b80af8 100644 --- a/contrib/libarchive/libarchive/archive_openssl_hmac_private.h +++ b/contrib/libarchive/libarchive/archive_openssl_hmac_private.h @@ -28,7 +28,7 @@ #include #include -#if OPENSSL_VERSION_NUMBER < 0x10100000L +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) #include /* malloc, free */ #include /* memset */ static inline HMAC_CTX *HMAC_CTX_new(void) diff --git a/contrib/libarchive/libarchive/archive_read.c b/contrib/libarchive/libarchive/archive_read.c index dc89ee57b9e..a29173e83b3 100644 --- a/contrib/libarchive/libarchive/archive_read.c +++ b/contrib/libarchive/libarchive/archive_read.c @@ -881,7 +881,8 @@ archive_read_data(struct archive *_a, void *buff, size_t s) len = a->read_data_remaining; if (len > s) len = s; - memcpy(dest, a->read_data_block, len); + if (len) + memcpy(dest, a->read_data_block, len); s -= len; a->read_data_block += len; a->read_data_remaining -= len; diff --git a/contrib/libarchive/libarchive/archive_read_disk_entry_from_file.c b/contrib/libarchive/libarchive/archive_read_disk_entry_from_file.c index 700f9e3ae1a..548ba89ef3d 100644 --- a/contrib/libarchive/libarchive/archive_read_disk_entry_from_file.c +++ b/contrib/libarchive/libarchive/archive_read_disk_entry_from_file.c @@ -928,11 +928,10 @@ setup_sparse(struct archive_read_disk *a, return (ARCHIVE_OK); /* Does filesystem support the reporting of hole ? */ - if (*fd < 0) { + if (*fd < 0) path = archive_read_disk_entry_setup_path(a, entry, fd); - if (path == NULL) - return (ARCHIVE_FAILED); - } + else + path = NULL; if (*fd >= 0) { #ifdef _PC_MIN_HOLE_SIZE @@ -943,6 +942,8 @@ setup_sparse(struct archive_read_disk *a, if (initial_off != 0) lseek(*fd, 0, SEEK_SET); } else { + if (path == NULL) + return (ARCHIVE_FAILED); #ifdef _PC_MIN_HOLE_SIZE if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0) return (ARCHIVE_OK); diff --git a/contrib/libarchive/libarchive/archive_read_support_filter_lz4.c b/contrib/libarchive/libarchive/archive_read_support_filter_lz4.c index 663e2d3d601..147f5027ff4 100644 --- a/contrib/libarchive/libarchive/archive_read_support_filter_lz4.c +++ b/contrib/libarchive/libarchive/archive_read_support_filter_lz4.c @@ -494,7 +494,7 @@ lz4_filter_read_data_block(struct archive_read_filter *self, const void **p) if (read_buf == NULL) goto truncated_error; compressed_size = archive_le32dec(read_buf); - if ((compressed_size & ~(1 << 31)) > state->flags.block_maximum_size) + if ((compressed_size & 0x7fffffff) > state->flags.block_maximum_size) goto malformed_error; /* A compressed size == 0 means the end of stream blocks. */ if (compressed_size == 0) { @@ -504,8 +504,8 @@ lz4_filter_read_data_block(struct archive_read_filter *self, const void **p) checksum_size = state->flags.block_checksum; /* Check if the block is uncompressed. */ - if (compressed_size & (1 << 31)) { - compressed_size &= ~(1 << 31); + if (compressed_size & 0x80000000U) { + compressed_size &= 0x7fffffff; uncompressed_size = compressed_size; } else uncompressed_size = 0;/* Unknown yet. */ diff --git a/contrib/libarchive/libarchive/archive_read_support_format_cab.c b/contrib/libarchive/libarchive/archive_read_support_format_cab.c index 2cf0d453abd..e5ff5a12cd9 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_cab.c +++ b/contrib/libarchive/libarchive/archive_read_support_format_cab.c @@ -116,19 +116,11 @@ struct lzx_dec { * coding tree, which is a binary tree. But a use of a large * index table causes L1 cache read miss many times. */ -#define HTBL_BITS 10 int max_bits; - int shift_bits; int tbl_bits; int tree_used; - int tree_avail; /* Direct access table. */ uint16_t *tbl; - /* Binary tree table for extra bits over the direct access. */ - struct htree_t { - uint16_t left; - uint16_t right; - } *tree; } at, lt, mt, pt; int loop; @@ -352,7 +344,6 @@ static int lzx_huffman_init(struct huffman *, size_t, int); static void lzx_huffman_free(struct huffman *); static int lzx_make_huffman_table(struct huffman *); static inline int lzx_decode_huffman(struct huffman *, unsigned); -static int lzx_decode_huffman_tree(struct huffman *, unsigned, int); int @@ -3127,7 +3118,6 @@ getdata: static int lzx_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits) { - int bits; if (hf->bitlen == NULL || hf->len_size != (int)len_size) { free(hf->bitlen); @@ -3138,21 +3128,11 @@ lzx_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits) } else memset(hf->bitlen, 0, len_size * sizeof(hf->bitlen[0])); if (hf->tbl == NULL) { - if (tbl_bits < HTBL_BITS) - bits = tbl_bits; - else - bits = HTBL_BITS; - hf->tbl = malloc(((size_t)1 << bits) * sizeof(hf->tbl[0])); + hf->tbl = malloc(((size_t)1 << tbl_bits) * sizeof(hf->tbl[0])); if (hf->tbl == NULL) return (ARCHIVE_FATAL); hf->tbl_bits = tbl_bits; } - if (hf->tree == NULL && tbl_bits > HTBL_BITS) { - hf->tree_avail = 1 << (tbl_bits - HTBL_BITS + 4); - hf->tree = malloc(hf->tree_avail * sizeof(hf->tree[0])); - if (hf->tree == NULL) - return (ARCHIVE_FATAL); - } return (ARCHIVE_OK); } @@ -3161,7 +3141,6 @@ lzx_huffman_free(struct huffman *hf) { free(hf->bitlen); free(hf->tbl); - free(hf->tree); } /* @@ -3174,7 +3153,7 @@ lzx_make_huffman_table(struct huffman *hf) const unsigned char *bitlen; int bitptn[17], weight[17]; int i, maxbits = 0, ptn, tbl_size, w; - int diffbits, len_avail; + int len_avail; /* * Initialize bit patterns. @@ -3205,28 +3184,11 @@ lzx_make_huffman_table(struct huffman *hf) weight[i] >>= ebits; } } - if (maxbits > HTBL_BITS) { - int htbl_max; - uint16_t *p; - - diffbits = maxbits - HTBL_BITS; - for (i = 1; i <= HTBL_BITS; i++) { - bitptn[i] >>= diffbits; - weight[i] >>= diffbits; - } - htbl_max = bitptn[HTBL_BITS] + - weight[HTBL_BITS] * hf->freq[HTBL_BITS]; - p = &(hf->tbl[htbl_max]); - while (p < &hf->tbl[1U<shift_bits = diffbits; /* * Make the table. */ - tbl_size = 1 << HTBL_BITS; + tbl_size = 1 << hf->tbl_bits; tbl = hf->tbl; bitlen = hf->bitlen; len_avail = hf->len_size; @@ -3234,120 +3196,32 @@ lzx_make_huffman_table(struct huffman *hf) for (i = 0; i < len_avail; i++) { uint16_t *p; int len, cnt; - uint16_t bit; - int extlen; - struct htree_t *ht; if (bitlen[i] == 0) continue; /* Get a bit pattern */ len = bitlen[i]; + if (len > tbl_size) + return (0); ptn = bitptn[len]; cnt = weight[len]; - if (len <= HTBL_BITS) { - /* Calculate next bit pattern */ - if ((bitptn[len] = ptn + cnt) > tbl_size) - return (0);/* Invalid */ - /* Update the table */ - p = &(tbl[ptn]); - while (--cnt >= 0) - p[cnt] = (uint16_t)i; - continue; - } - - /* - * A bit length is too big to be housed to a direct table, - * so we use a tree model for its extra bits. - */ - bitptn[len] = ptn + cnt; - bit = 1U << (diffbits -1); - extlen = len - HTBL_BITS; - - p = &(tbl[ptn >> diffbits]); - if (*p == 0) { - *p = len_avail + hf->tree_used; - ht = &(hf->tree[hf->tree_used++]); - if (hf->tree_used > hf->tree_avail) - return (0);/* Invalid */ - ht->left = 0; - ht->right = 0; - } else { - if (*p < len_avail || - *p >= (len_avail + hf->tree_used)) - return (0);/* Invalid */ - ht = &(hf->tree[*p - len_avail]); - } - while (--extlen > 0) { - if (ptn & bit) { - if (ht->left < len_avail) { - ht->left = len_avail + hf->tree_used; - ht = &(hf->tree[hf->tree_used++]); - if (hf->tree_used > hf->tree_avail) - return (0);/* Invalid */ - ht->left = 0; - ht->right = 0; - } else { - ht = &(hf->tree[ht->left - len_avail]); - } - } else { - if (ht->right < len_avail) { - ht->right = len_avail + hf->tree_used; - ht = &(hf->tree[hf->tree_used++]); - if (hf->tree_used > hf->tree_avail) - return (0);/* Invalid */ - ht->left = 0; - ht->right = 0; - } else { - ht = &(hf->tree[ht->right - len_avail]); - } - } - bit >>= 1; - } - if (ptn & bit) { - if (ht->left != 0) - return (0);/* Invalid */ - ht->left = (uint16_t)i; - } else { - if (ht->right != 0) - return (0);/* Invalid */ - ht->right = (uint16_t)i; - } + /* Calculate next bit pattern */ + if ((bitptn[len] = ptn + cnt) > tbl_size) + return (0);/* Invalid */ + /* Update the table */ + p = &(tbl[ptn]); + while (--cnt >= 0) + p[cnt] = (uint16_t)i; } return (1); } -static int -lzx_decode_huffman_tree(struct huffman *hf, unsigned rbits, int c) -{ - struct htree_t *ht; - int extlen; - - ht = hf->tree; - extlen = hf->shift_bits; - while (c >= hf->len_size) { - c -= hf->len_size; - if (extlen-- <= 0 || c >= hf->tree_used) - return (0); - if (rbits & (1U << extlen)) - c = ht[c].left; - else - c = ht[c].right; - } - return (c); -} - static inline int lzx_decode_huffman(struct huffman *hf, unsigned rbits) { int c; - /* - * At first search an index table for a bit pattern. - * If it fails, search a huffman tree for. - */ - c = hf->tbl[rbits >> hf->shift_bits]; + c = hf->tbl[rbits]; if (c < hf->len_size) return (c); - /* This bit pattern needs to be found out at a huffman tree. */ - return (lzx_decode_huffman_tree(hf, rbits, c)); + return (0); } - diff --git a/contrib/libarchive/libarchive/archive_read_support_format_cpio.c b/contrib/libarchive/libarchive/archive_read_support_format_cpio.c index 43e6ff93d8d..6b4d241fd34 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_cpio.c +++ b/contrib/libarchive/libarchive/archive_read_support_format_cpio.c @@ -165,7 +165,7 @@ __FBSDID("$FreeBSD$"); struct links_entry { struct links_entry *next; struct links_entry *previous; - int links; + unsigned int links; dev_t dev; int64_t ino; char *name; diff --git a/contrib/libarchive/libarchive/archive_read_support_format_iso9660.c b/contrib/libarchive/libarchive/archive_read_support_format_iso9660.c index ebbfc2fa5c2..36549a38f11 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_iso9660.c +++ b/contrib/libarchive/libarchive/archive_read_support_format_iso9660.c @@ -3021,8 +3021,9 @@ heap_add_entry(struct archive_read *a, struct heap_queue *heap, ENOMEM, "Out of memory"); return (ARCHIVE_FATAL); } - memcpy(new_pending_files, heap->files, - heap->allocated * sizeof(new_pending_files[0])); + if (heap->allocated) + memcpy(new_pending_files, heap->files, + heap->allocated * sizeof(new_pending_files[0])); if (heap->files != NULL) free(heap->files); heap->files = new_pending_files; diff --git a/contrib/libarchive/libarchive/archive_read_support_format_mtree.c b/contrib/libarchive/libarchive/archive_read_support_format_mtree.c index 72de1dcb09e..d2770f1cf70 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_mtree.c +++ b/contrib/libarchive/libarchive/archive_read_support_format_mtree.c @@ -130,9 +130,7 @@ static ssize_t readline(struct archive_read *, struct mtree *, char **, ssize_t) static int skip(struct archive_read *a); static int read_header(struct archive_read *, struct archive_entry *); -static int64_t mtree_atol10(char **); -static int64_t mtree_atol8(char **); -static int64_t mtree_atol(char **); +static int64_t mtree_atol(char **, int base); /* * There's no standard for TIME_T_MAX/TIME_T_MIN. So we compute them @@ -1418,7 +1416,7 @@ parse_device(dev_t *pdev, struct archive *a, char *val) "Too many arguments"); return ARCHIVE_WARN; } - numbers[argc++] = (unsigned long)mtree_atol(&p); + numbers[argc++] = (unsigned long)mtree_atol(&p, 0); } if (argc < 2) { archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT, @@ -1433,7 +1431,7 @@ parse_device(dev_t *pdev, struct archive *a, char *val) } } else { /* file system raw value. */ - result = (dev_t)mtree_atol(&val); + result = (dev_t)mtree_atol(&val, 0); } *pdev = result; return ARCHIVE_OK; @@ -1513,7 +1511,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, case 'g': if (strcmp(key, "gid") == 0) { *parsed_kws |= MTREE_HAS_GID; - archive_entry_set_gid(entry, mtree_atol10(&val)); + archive_entry_set_gid(entry, mtree_atol(&val, 10)); break; } if (strcmp(key, "gname") == 0) { @@ -1523,7 +1521,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, } case 'i': if (strcmp(key, "inode") == 0) { - archive_entry_set_ino(entry, mtree_atol10(&val)); + archive_entry_set_ino(entry, mtree_atol(&val, 10)); break; } case 'l': @@ -1535,14 +1533,14 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, if (strcmp(key, "md5") == 0 || strcmp(key, "md5digest") == 0) break; if (strcmp(key, "mode") == 0) { - if (val[0] >= '0' && val[0] <= '9') { + if (val[0] >= '0' && val[0] <= '7') { *parsed_kws |= MTREE_HAS_PERM; archive_entry_set_perm(entry, - (mode_t)mtree_atol8(&val)); + (mode_t)mtree_atol(&val, 8)); } else { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "Symbolic mode \"%s\" unsupported", val); + "Symbolic or non-octal mode \"%s\" unsupported", val); return ARCHIVE_WARN; } break; @@ -1551,7 +1549,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, if (strcmp(key, "nlink") == 0) { *parsed_kws |= MTREE_HAS_NLINK; archive_entry_set_nlink(entry, - (unsigned int)mtree_atol10(&val)); + (unsigned int)mtree_atol(&val, 10)); break; } case 'r': @@ -1582,7 +1580,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, strcmp(key, "sha512digest") == 0) break; if (strcmp(key, "size") == 0) { - archive_entry_set_size(entry, mtree_atol10(&val)); + archive_entry_set_size(entry, mtree_atol(&val, 10)); break; } case 't': @@ -1601,13 +1599,13 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, long ns = 0; *parsed_kws |= MTREE_HAS_MTIME; - m = mtree_atol10(&val); + m = mtree_atol(&val, 10); /* Replicate an old mtree bug: * 123456789.1 represents 123456789 * seconds and 1 nanosecond. */ if (*val == '.') { ++val; - ns = (long)mtree_atol10(&val); + ns = (long)mtree_atol(&val, 10); if (ns < 0) ns = 0; else if (ns > 999999999) @@ -1670,7 +1668,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, case 'u': if (strcmp(key, "uid") == 0) { *parsed_kws |= MTREE_HAS_UID; - archive_entry_set_uid(entry, mtree_atol10(&val)); + archive_entry_set_uid(entry, mtree_atol(&val, 10)); break; } if (strcmp(key, "uname") == 0) { @@ -1825,77 +1823,9 @@ parse_escapes(char *src, struct mtree_entry *mentry) *dest = '\0'; } -/* - * Note that this implementation does not (and should not!) obey - * locale settings; you cannot simply substitute strtol here, since - * it does obey locale. - */ -static int64_t -mtree_atol8(char **p) -{ - int64_t l, limit, last_digit_limit; - int digit, base; - - base = 8; - limit = INT64_MAX / base; - last_digit_limit = INT64_MAX % base; - - l = 0; - digit = **p - '0'; - while (digit >= 0 && digit < base) { - if (l>limit || (l == limit && digit > last_digit_limit)) { - l = INT64_MAX; /* Truncate on overflow. */ - break; - } - l = (l * base) + digit; - digit = *++(*p) - '0'; - } - return (l); -} - -/* - * Note that this implementation does not (and should not!) obey - * locale settings; you cannot simply substitute strtol here, since - * it does obey locale. - * - * Convert the number pointed to by 'p' into a 64-bit signed integer. - * On return, 'p' points to the first non-digit following the number. - * On overflow, the function returns INT64_MIN or INT64_MAX. - */ -static int64_t -mtree_atol10(char **p) -{ - const int base = 10; - const int64_t limit = INT64_MAX / base; - const int64_t last_digit_limit = INT64_MAX % base; - int64_t l; - int sign; - - if (**p == '-') { - sign = -1; - ++(*p); - } else { - sign = 1; - } - - l = 0; - while (**p >= '0' && **p < '0' + base) { - int digit = **p - '0'; - if (l > limit || (l == limit && digit > last_digit_limit)) { - while (**p >= '0' && **p < '0' + base) { - ++(*p); - } - return (sign < 0) ? INT64_MIN : INT64_MAX; - } - l = (l * base) + digit; - ++(*p); - } - return (sign < 0) ? -l : l; -} - /* Parse a hex digit. */ static int -parsehex(char c) +parsedigit(char c) { if (c >= '0' && c <= '9') return c - '0'; @@ -1913,45 +1843,50 @@ parsehex(char c) * it does obey locale. */ static int64_t -mtree_atol16(char **p) +mtree_atol(char **p, int base) { - int64_t l, limit, last_digit_limit; - int base, digit, sign; + int64_t l, limit; + int digit, last_digit_limit; - base = 16; + if (base == 0) { + if (**p != '0') + base = 10; + else if ((*p)[1] == 'x' || (*p)[1] == 'X') { + *p += 2; + base = 16; + } else { + base = 8; + } + } if (**p == '-') { - sign = -1; - limit = ((uint64_t)(INT64_MAX) + 1) / base; - last_digit_limit = ((uint64_t)(INT64_MAX) + 1) % base; + limit = INT64_MIN / base; + last_digit_limit = INT64_MIN % base; ++(*p); + + l = 0; + digit = parsedigit(**p); + while (digit >= 0 && digit < base) { + if (l < limit || (l == limit && digit > last_digit_limit)) + return INT64_MIN; + l = (l * base) - digit; + digit = parsedigit(*++(*p)); + } + return l; } else { - sign = 1; limit = INT64_MAX / base; last_digit_limit = INT64_MAX % base; - } - l = 0; - digit = parsehex(**p); - while (digit >= 0 && digit < base) { - if (l > limit || (l == limit && digit > last_digit_limit)) - return (sign < 0) ? INT64_MIN : INT64_MAX; - l = (l * base) + digit; - digit = parsehex(*++(*p)); + l = 0; + digit = parsedigit(**p); + while (digit >= 0 && digit < base) { + if (l > limit || (l == limit && digit > last_digit_limit)) + return INT64_MAX; + l = (l * base) + digit; + digit = parsedigit(*++(*p)); + } + return l; } - return (sign < 0) ? -l : l; -} - -static int64_t -mtree_atol(char **p) -{ - if (**p != '0') - return mtree_atol10(p); - if ((*p)[1] == 'x' || (*p)[1] == 'X') { - *p += 2; - return mtree_atol16(p); - } - return mtree_atol8(p); } /* diff --git a/contrib/libarchive/libarchive/archive_read_support_format_rar.c b/contrib/libarchive/libarchive/archive_read_support_format_rar.c index 1e9849fdd62..cbb14c32dc3 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_rar.c +++ b/contrib/libarchive/libarchive/archive_read_support_format_rar.c @@ -1750,7 +1750,7 @@ read_exttime(const char *p, struct rar *rar, const char *endp) return (-1); for (j = 0; j < count; j++) { - rem = ((*p) << 16) | (rem >> 8); + rem = (((unsigned)(unsigned char)*p) << 16) | (rem >> 8); p++; } tm = localtime(&t); diff --git a/contrib/libarchive/libarchive/archive_string.c b/contrib/libarchive/libarchive/archive_string.c index f738c549ffb..3501a9e0914 100644 --- a/contrib/libarchive/libarchive/archive_string.c +++ b/contrib/libarchive/libarchive/archive_string.c @@ -202,7 +202,8 @@ archive_string_append(struct archive_string *as, const char *p, size_t s) { if (archive_string_ensure(as, as->length + s + 1) == NULL) return (NULL); - memmove(as->s + as->length, p, s); + if (s) + memmove(as->s + as->length, p, s); as->length += s; as->s[as->length] = 0; return (as); diff --git a/contrib/libarchive/libarchive/archive_write_set_format_pax.c b/contrib/libarchive/libarchive/archive_write_set_format_pax.c index da4fe975f86..318ca78c554 100644 --- a/contrib/libarchive/libarchive/archive_write_set_format_pax.c +++ b/contrib/libarchive/libarchive/archive_write_set_format_pax.c @@ -1196,8 +1196,12 @@ archive_write_pax_header(struct archive_write *a, "GNU.sparse.major", 1); add_pax_attr_int(&(pax->pax_header), "GNU.sparse.minor", 0); + /* + * Make sure to store the original path, since + * truncation to ustar limit happened already. + */ add_pax_attr(&(pax->pax_header), - "GNU.sparse.name", entry_name.s); + "GNU.sparse.name", path); add_pax_attr_int(&(pax->pax_header), "GNU.sparse.realsize", archive_entry_size(entry_main)); @@ -1650,13 +1654,14 @@ build_pax_attribute_name(char *dest, const char *src) * GNU PAX Format 1.0 requires the special name, which pattern is: * /GNUSparseFile./ * + * Since reproducable archives are more important, use 0 as pid. + * * This function is used for only Sparse file, a file type of which * is regular file. */ static char * build_gnu_sparse_name(char *dest, const char *src) { - char buff[64]; const char *p; /* Handle the null filename case. */ @@ -1682,15 +1687,9 @@ build_gnu_sparse_name(char *dest, const char *src) break; } -#if HAVE_GETPID && 0 /* Disable this as pax attribute name. */ - sprintf(buff, "GNUSparseFile.%d", getpid()); -#else - /* If the platform can't fetch the pid, don't include it. */ - strcpy(buff, "GNUSparseFile"); -#endif /* General case: build a ustar-compatible name adding * "/GNUSparseFile/". */ - build_ustar_entry_name(dest, src, p - src, buff); + build_ustar_entry_name(dest, src, p - src, "GNUSparseFile.0"); return (dest); } diff --git a/contrib/libarchive/libarchive/libarchive_changes.3 b/contrib/libarchive/libarchive/libarchive_changes.3 index 881a67cdd41..adc87febd71 100644 --- a/contrib/libarchive/libarchive/libarchive_changes.3 +++ b/contrib/libarchive/libarchive/libarchive_changes.3 @@ -28,6 +28,7 @@ .Dt LIBARCHIVE_CHANGES 3 .Os .Sh NAME +.Nm libarchive_changes .Nd changes in libarchive interface .\" .Sh CHANGES IN LIBARCHIVE 3 diff --git a/contrib/libarchive/libarchive/test/test_read_format_mtree.c b/contrib/libarchive/libarchive/test/test_read_format_mtree.c index 80881a84778..f6f71a36199 100644 --- a/contrib/libarchive/libarchive/test/test_read_format_mtree.c +++ b/contrib/libarchive/libarchive/test/test_read_format_mtree.c @@ -183,7 +183,7 @@ test_read_format_mtree1(void) min_time = archive_entry_mtime(ae); assert(min_time <= 0); /* Simply asserting min_time - 1 > 0 breaks with some compiler optimizations. */ - t = min_time - 1; + t = (time_t)((uintmax_t)min_time - 1); assert(t > 0); assertEqualInt(archive_entry_is_encrypted(ae), 0); assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED); diff --git a/contrib/libarchive/libarchive/test/test_read_format_zip_with_invalid_traditional_eocd.c b/contrib/libarchive/libarchive/test/test_read_format_zip_with_invalid_traditional_eocd.c new file mode 100644 index 00000000000..dc94f94f157 --- /dev/null +++ b/contrib/libarchive/libarchive/test/test_read_format_zip_with_invalid_traditional_eocd.c @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 2017 Phillip Berndt + * All rights reserved. + * + * 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(S) ``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(S) 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 "test.h" +__FBSDID("$FreeBSD$"); + +/* + * Issue 869: zip files without a valid EOCD header aren't loaded even if they + * have a valid ZIP64 version of said header. + */ + +DEFINE_TEST(test_read_format_zip_with_invalid_traditional_eocd) +{ + const char *refname = "test_read_format_zip_with_invalid_traditional_eocd.zip"; + char *p; + size_t s; + struct archive *a; + struct archive_entry *ae; + + extract_reference_file(refname); + p = slurpfile(&s, refname); + + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip_seekable(a)); + assertEqualIntA(a, ARCHIVE_OK, read_open_memory_seek(a, p, s, 1)); + + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualString("test1.txt", archive_entry_pathname(ae)); + assertEqualInt(0, archive_entry_size(ae)); + + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualString("test2.txt", archive_entry_pathname(ae)); + assertEqualInt(0, archive_entry_size(ae)); + + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a)); + free(p); +} diff --git a/contrib/libarchive/libarchive/test/test_read_format_zip_with_invalid_traditional_eocd.zip.uu b/contrib/libarchive/libarchive/test/test_read_format_zip_with_invalid_traditional_eocd.zip.uu new file mode 100644 index 00000000000..63744f145ea --- /dev/null +++ b/contrib/libarchive/libarchive/test/test_read_format_zip_with_invalid_traditional_eocd.zip.uu @@ -0,0 +1,14 @@ +begin 644 test_read_format_zip_without_eocd.zip +M4$L#!"T`"````-IT@DH`````__________\)`"``=&5S=#$N='AT`0`<```` +M```````````````````````````````````````````````````````````` +M`%!+`P0M``@```#:=()*`````/__________"0`@`'1Ev) - /**************************************** ** Compiler-specific Functions and Macros *****************************************/ -#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +#define GCC_VERSION ((__GNUC__-0) * 100 + (__GNUC_MINOR__ - 0)) + +#if GCC_VERSION >= 409 +__attribute__((__no_sanitize_undefined__)) +#endif +static inline U32 A32(const void * x) +{ + return (((const U32_S *)(x))->v); +} /* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */ #if defined(_MSC_VER) diff --git a/contrib/libarchive/test_utils/test_main.c b/contrib/libarchive/test_utils/test_main.c index d74045934be..0e1413693f4 100644 --- a/contrib/libarchive/test_utils/test_main.c +++ b/contrib/libarchive/test_utils/test_main.c @@ -1102,6 +1102,7 @@ assertion_file_contains_lines_any_order(const char *file, int line, failure_start(pathname, line, "Can't allocate memory"); failure_finish(NULL); free(expected); + free(buff); return (0); } for (i = 0; lines[i] != NULL; ++i) { @@ -1124,6 +1125,7 @@ assertion_file_contains_lines_any_order(const char *file, int line, failure_start(pathname, line, "Can't allocate memory"); failure_finish(NULL); free(expected); + free(buff); return (0); } for (j = 0, p = buff; p < buff + buff_size; diff --git a/contrib/netbsd-tests/lib/libc/rpc/t_rpc.c b/contrib/netbsd-tests/lib/libc/rpc/t_rpc.c index e5d4321625f..59bcd559076 100644 --- a/contrib/netbsd-tests/lib/libc/rpc/t_rpc.c +++ b/contrib/netbsd-tests/lib/libc/rpc/t_rpc.c @@ -325,10 +325,6 @@ ATF_TC_HEAD(raw, tc) ATF_TC_BODY(raw, tc) { -#ifdef __FreeBSD__ - atf_tc_expect_fail("fails with: clnt_call: " - "RPC: Can't decode result -- PR # 211804"); -#endif rawtest(NULL); } diff --git a/contrib/netbsd-tests/usr.bin/grep/d_context_e.in b/contrib/netbsd-tests/usr.bin/grep/d_context_e.in new file mode 100644 index 00000000000..45325631720 --- /dev/null +++ b/contrib/netbsd-tests/usr.bin/grep/d_context_e.in @@ -0,0 +1,10 @@ +monkey +banana +apple +fruit +monkey +banna +apple +fruit +apple +monkey diff --git a/contrib/netbsd-tests/usr.bin/grep/d_context_e.out b/contrib/netbsd-tests/usr.bin/grep/d_context_e.out new file mode 100644 index 00000000000..1167e107286 --- /dev/null +++ b/contrib/netbsd-tests/usr.bin/grep/d_context_e.out @@ -0,0 +1,9 @@ +monkey +banana +apple +fruit +monkey +banna +-- +apple +monkey diff --git a/contrib/netbsd-tests/usr.bin/grep/d_context_f.out b/contrib/netbsd-tests/usr.bin/grep/d_context_f.out new file mode 100644 index 00000000000..2df9efd9ffb --- /dev/null +++ b/contrib/netbsd-tests/usr.bin/grep/d_context_f.out @@ -0,0 +1,9 @@ +monkey +banana +apple +fruit +monkey +banna +apple +fruit +apple diff --git a/contrib/netbsd-tests/usr.bin/grep/d_context_g.out b/contrib/netbsd-tests/usr.bin/grep/d_context_g.out new file mode 100644 index 00000000000..c1b5048aa9c --- /dev/null +++ b/contrib/netbsd-tests/usr.bin/grep/d_context_g.out @@ -0,0 +1,8 @@ +apple +fruit +-- +banna +apple +fruit +apple +monkey diff --git a/contrib/netbsd-tests/usr.bin/grep/t_grep.sh b/contrib/netbsd-tests/usr.bin/grep/t_grep.sh index 0d0e99f6e1d..267ee87446e 100755 --- a/contrib/netbsd-tests/usr.bin/grep/t_grep.sh +++ b/contrib/netbsd-tests/usr.bin/grep/t_grep.sh @@ -93,6 +93,12 @@ word_regexps_body() { atf_check -o file:"$(atf_get_srcdir)/d_word_regexps.out" \ grep -w separated $(atf_get_srcdir)/d_input + + # Begin FreeBSD + printf "xmatch pmatch\n" > test1 + + atf_check -o inline:"pmatch\n" grep -Eow "(match )?pmatch" test1 + # End FreeBSD } atf_test_case begin_end @@ -165,6 +171,12 @@ context_body() atf_check -o file:d_context_b.out grep -A3 tilt d_context_a.in atf_check -o file:d_context_c.out grep -B4 Whig d_context_a.in atf_check -o file:d_context_d.out grep -C1 pig d_context_a.in d_context_b.in + atf_check -o file:d_context_e.out \ + grep -E -C1 '(banana|monkey)' d_context_e.in + atf_check -o file:d_context_f.out \ + grep -Ev -B2 '(banana|monkey|fruit)' d_context_e.in + atf_check -o file:d_context_g.out \ + grep -Ev -A1 '(banana|monkey|fruit)' d_context_e.in } atf_test_case file_exp @@ -363,7 +375,7 @@ egrep_empty_invalid_head() } egrep_empty_invalid_body() { - atf_check -s exit:1 egrep '{' /dev/null + atf_check -e ignore -s not-exit:0 egrep '{' /dev/null } atf_test_case zerolen @@ -380,6 +392,32 @@ zerolen_body() atf_check -o inline:"Eggs\nCheese\n" grep -v -e "^$" test1 } +atf_test_case wflag_emptypat +wflag_emptypat_head() +{ + atf_set "descr" "Check for proper handling of -w with an empty pattern (PR 105221)" +} +wflag_emptypat_body() +{ + grep_type + if [ $? -eq $GREP_TYPE_GNU_FREEBSD ]; then + atf_expect_fail "this test does not pass with GNU grep in base" + fi + + printf "" > test1 + printf "\n" > test2 + printf "qaz" > test3 + printf " qaz\n" > test4 + + atf_check -s exit:1 -o empty grep -w -e "" test1 + + atf_check -o file:test2 grep -w -e "" test2 + + atf_check -s exit:1 -o empty grep -w -e "" test3 + + atf_check -o file:test4 grep -w -e "" test4 +} + atf_test_case fgrep_sanity fgrep_sanity_head() { @@ -439,6 +477,23 @@ grep_sanity_body() atf_check -o inline:"M\n" grep -o -e "M\{1\}" test2 } + +atf_test_case wv_combo_break +wv_combo_break_head() +{ + atf_set "descr" "Check for incorrectly matching lines with both -w and -v flags (PR 218467)" +} +wv_combo_break_body() +{ + printf "x xx\n" > test1 + printf "xx x\n" > test2 + + atf_check -o file:test1 grep -w "x" test1 + atf_check -o file:test2 grep -w "x" test2 + + atf_check -s exit:1 grep -v -w "x" test1 + atf_check -s exit:1 grep -v -w "x" test2 +} # End FreeBSD atf_init_test_cases() @@ -467,6 +522,8 @@ atf_init_test_cases() atf_add_test_case escmap atf_add_test_case egrep_empty_invalid atf_add_test_case zerolen + atf_add_test_case wflag_emptypat + atf_add_test_case wv_combo_break atf_add_test_case fgrep_sanity atf_add_test_case egrep_sanity atf_add_test_case grep_sanity diff --git a/etc/autofs/special_media b/etc/autofs/special_media index c825d0eb7cc..08b75bc1760 100755 --- a/etc/autofs/special_media +++ b/etc/autofs/special_media @@ -39,6 +39,15 @@ print_map_entry() { _p="$2" case "${_fstype}" in + "exfat") + if [ -f "/usr/local/sbin/mount.exfat" ]; then + echo "-mountprog=/usr/local/sbin/mount.exfat,fstype=${_fstype},nosuid :/dev/${_p}" + else + /usr/bin/logger -p info -t "special_media[$$]" \ + "Cannot mount ${_fstype} formatted device /dev/${_p}: Install sysutils/fusefs-exfat first" + exit 1 + fi + ;; "ntfs") if [ -f "/usr/local/bin/ntfs-3g" ]; then echo "-mountprog=/usr/local/bin/ntfs-3g,fstype=${_fstype},nosuid :/dev/${_p}" diff --git a/etc/rc.d/ipfw b/etc/rc.d/ipfw index beccaffaf31..deb9bdad137 100755 --- a/etc/rc.d/ipfw +++ b/etc/rc.d/ipfw @@ -56,7 +56,7 @@ ipfw_start() # if checkyesno firewall_logging; then echo 'Firewall logging enabled.' - sysctl net.inet.ip.fw.verbose=1 >/dev/null + ${SYSCTL} net.inet.ip.fw.verbose=1 >/dev/null fi if checkyesno firewall_logif; then ifconfig ipfw0 create @@ -78,11 +78,11 @@ ipfw_poststart() # Enable the firewall # - if ! ${SYSCTL} net.inet.ip.fw.enable=1 1>/dev/null 2>&1; then + if ! ${SYSCTL} net.inet.ip.fw.enable=1 >/dev/null 2>&1; then warn "failed to enable IPv4 firewall" fi if afexists inet6; then - if ! ${SYSCTL} net.inet6.ip6.fw.enable=1 1>/dev/null 2>&1 + if ! ${SYSCTL} net.inet6.ip6.fw.enable=1 >/dev/null 2>&1 then warn "failed to enable IPv6 firewall" fi @@ -95,9 +95,9 @@ ipfw_stop() # Disable the firewall # - ${SYSCTL} net.inet.ip.fw.enable=0 + ${SYSCTL} net.inet.ip.fw.enable=0 >/dev/null if afexists inet6; then - ${SYSCTL} net.inet6.ip6.fw.enable=0 + ${SYSCTL} net.inet6.ip6.fw.enable=0 >/dev/null fi # Stop firewall coscripts diff --git a/etc/rc.d/routing b/etc/rc.d/routing index 10cb48319a0..e909523ab70 100755 --- a/etc/rc.d/routing +++ b/etc/rc.d/routing @@ -281,7 +281,7 @@ static_inet6() esac ifconfig ${ipv6_default_interface} inet6 defaultif - sysctl net.inet6.ip6.use_defaultzone=1 + ${SYSCTL} net.inet6.ip6.use_defaultzone=1 > /dev/null } ropts_init() diff --git a/include/stdio.h b/include/stdio.h index 99773885f1f..73e92a5462c 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -338,7 +338,7 @@ int ferror_unlocked(FILE *); int fileno_unlocked(FILE *); #endif -#if __POSIX_VISIBLE >= 200112 +#if __POSIX_VISIBLE >= 200112 || __XSI_VISIBLE >= 500 int fseeko(FILE *, __off_t, int); __off_t ftello(FILE *); #endif diff --git a/lib/libarchive/tests/Makefile b/lib/libarchive/tests/Makefile index 6321fd0a300..9252de27116 100644 --- a/lib/libarchive/tests/Makefile +++ b/lib/libarchive/tests/Makefile @@ -195,6 +195,7 @@ TESTS_SRCS= \ test_read_format_zip_traditional_encryption_data.c \ test_read_format_zip_winzip_aes.c \ test_read_format_zip_winzip_aes_large.c \ + test_read_format_zip_with_invalid_traditional_eocd.c \ test_read_format_zip_zip64.c \ test_read_large.c \ test_read_pax_schily_xattr.c \ @@ -541,6 +542,7 @@ ${PACKAGE}FILES+= test_read_format_zip_sfx.uu ${PACKAGE}FILES+= test_read_format_zip_symlink.zip.uu ${PACKAGE}FILES+= test_read_format_zip_traditional_encryption_data.zip.uu ${PACKAGE}FILES+= test_read_format_zip_ux.zip.uu +${PACKAGE}FILES+= test_read_format_zip_with_invalid_traditional_eocd.zip.uu ${PACKAGE}FILES+= test_read_format_zip_winzip_aes128.zip.uu ${PACKAGE}FILES+= test_read_format_zip_winzip_aes256.zip.uu ${PACKAGE}FILES+= test_read_format_zip_winzip_aes256_large.zip.uu diff --git a/lib/libbluetooth/bluetooth.h b/lib/libbluetooth/bluetooth.h index 451606bec41..6e00777291f 100644 --- a/lib/libbluetooth/bluetooth.h +++ b/lib/libbluetooth/bluetooth.h @@ -46,6 +46,7 @@ #include #include +#include #include #include #include diff --git a/lib/libc/gen/glob.c b/lib/libc/gen/glob.c index 51bf347d297..c4364407cde 100644 --- a/lib/libc/gen/glob.c +++ b/lib/libc/gen/glob.c @@ -903,61 +903,74 @@ globextend(const Char *path, glob_t *pglob, struct glob_limit *limit, } /* - * pattern matching function for filenames. Each occurrence of the * - * pattern causes a recursion level. + * pattern matching function for filenames. */ static int match(Char *name, Char *pat, Char *patend) { int ok, negate_range; - Char c, k; + Char c, k, *nextp, *nextn; struct xlocale_collate *table = (struct xlocale_collate*)__get_locale()->components[XLC_COLLATE]; - while (pat < patend) { - c = *pat++; - switch (c & M_MASK) { - case M_ALL: - if (pat == patend) - return (1); - do - if (match(name, pat, patend)) - return (1); - while (*name++ != EOS); - return (0); - case M_ONE: - if (*name++ == EOS) - return (0); - break; - case M_SET: - ok = 0; - if ((k = *name++) == EOS) - return (0); - if ((negate_range = ((*pat & M_MASK) == M_NOT)) != 0) - ++pat; - while (((c = *pat++) & M_MASK) != M_END) - if ((*pat & M_MASK) == M_RNG) { - if (table->__collate_load_error ? - CHAR(c) <= CHAR(k) && - CHAR(k) <= CHAR(pat[1]) : - __wcollate_range_cmp(CHAR(c), - CHAR(k)) <= 0 && - __wcollate_range_cmp(CHAR(k), - CHAR(pat[1])) <= 0) + nextn = NULL; + nextp = NULL; + + while (1) { + while (pat < patend) { + c = *pat++; + switch (c & M_MASK) { + case M_ALL: + if (pat == patend) + return (1); + if (*name == EOS) + return (0); + nextn = name + 1; + nextp = pat - 1; + break; + case M_ONE: + if (*name++ == EOS) + goto fail; + break; + case M_SET: + ok = 0; + if ((k = *name++) == EOS) + goto fail; + negate_range = ((*pat & M_MASK) == M_NOT); + if (negate_range != 0) + ++pat; + while (((c = *pat++) & M_MASK) != M_END) + if ((*pat & M_MASK) == M_RNG) { + if (table->__collate_load_error ? + CHAR(c) <= CHAR(k) && + CHAR(k) <= CHAR(pat[1]) : + __wcollate_range_cmp(CHAR(c), + CHAR(k)) <= 0 && + __wcollate_range_cmp(CHAR(k), + CHAR(pat[1])) <= 0) + ok = 1; + pat += 2; + } else if (c == k) ok = 1; - pat += 2; - } else if (c == k) - ok = 1; - if (ok == negate_range) - return (0); - break; - default: - if (*name++ != c) - return (0); - break; + if (ok == negate_range) + goto fail; + break; + default: + if (*name++ != c) + goto fail; + break; + } } + if (*name == EOS) + return (1); + + fail: + if (nextn == NULL) + break; + pat = nextp; + name = nextn; } - return (*name == EOS); + return (0); } /* Free allocated data belonging to a glob_t structure. */ diff --git a/lib/libc/gen/sem_new.c b/lib/libc/gen/sem_new.c index d36d1e25f7c..3bf898192fc 100644 --- a/lib/libc/gen/sem_new.c +++ b/lib/libc/gen/sem_new.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -77,36 +78,34 @@ struct sem_nameinfo { static pthread_once_t once = PTHREAD_ONCE_INIT; static pthread_mutex_t sem_llock; -static LIST_HEAD(,sem_nameinfo) sem_list = LIST_HEAD_INITIALIZER(sem_list); +static LIST_HEAD(, sem_nameinfo) sem_list = LIST_HEAD_INITIALIZER(sem_list); static void -sem_prefork() +sem_prefork(void) { _pthread_mutex_lock(&sem_llock); } static void -sem_postfork() +sem_postfork(void) { + _pthread_mutex_unlock(&sem_llock); } static void -sem_child_postfork() +sem_child_postfork(void) { + _pthread_mutex_unlock(&sem_llock); } static void sem_module_init(void) { - pthread_mutexattr_t ma; - _pthread_mutexattr_init(&ma); - _pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE); - _pthread_mutex_init(&sem_llock, &ma); - _pthread_mutexattr_destroy(&ma); + _pthread_mutex_init(&sem_llock, NULL); _pthread_atfork(sem_prefork, sem_postfork, sem_child_postfork); } @@ -116,10 +115,8 @@ sem_check_validity(sem_t *sem) if (sem->_magic == SEM_MAGIC) return (0); - else { - errno = EINVAL; - return (-1); - } + errno = EINVAL; + return (-1); } int @@ -142,13 +139,16 @@ sem_t * _sem_open(const char *name, int flags, ...) { char path[PATH_MAX]; - struct stat sb; va_list ap; - struct sem_nameinfo *ni = NULL; - sem_t *sem = NULL; - int fd = -1, mode, len, errsave; - int value = 0; + struct sem_nameinfo *ni; + sem_t *sem, tmp; + int errsave, fd, len, mode, value; + + ni = NULL; + sem = NULL; + fd = -1; + value = 0; if (name[0] != '/') { errno = EINVAL; @@ -213,8 +213,6 @@ _sem_open(const char *name, int flags, ...) goto error; } if (sb.st_size < sizeof(sem_t)) { - sem_t tmp; - tmp._magic = SEM_MAGIC; tmp._kern._count = value; tmp._kern._flags = USYNC_PROCESS_SHARED | SEM_NAMED; @@ -222,8 +220,8 @@ _sem_open(const char *name, int flags, ...) goto error; } flock(fd, LOCK_UN); - sem = (sem_t *)mmap(NULL, sizeof(sem_t), PROT_READ|PROT_WRITE, - MAP_SHARED|MAP_NOSYNC, fd, 0); + sem = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_NOSYNC, fd, 0); if (sem == MAP_FAILED) { sem = NULL; if (errno == ENOMEM) @@ -259,6 +257,7 @@ int _sem_close(sem_t *sem) { struct sem_nameinfo *ni; + bool last; if (sem_check_validity(sem) != 0) return (-1); @@ -273,22 +272,17 @@ _sem_close(sem_t *sem) _pthread_mutex_lock(&sem_llock); LIST_FOREACH(ni, &sem_list, next) { if (sem == ni->sem) { - if (--ni->open_count > 0) { - _pthread_mutex_unlock(&sem_llock); - return (0); + last = --ni->open_count == 0; + if (last) + LIST_REMOVE(ni, next); + _pthread_mutex_unlock(&sem_llock); + if (last) { + munmap(sem, sizeof(*sem)); + free(ni); } - else - break; + return (0); } } - - if (ni) { - LIST_REMOVE(ni, next); - _pthread_mutex_unlock(&sem_llock); - munmap(sem, sizeof(*sem)); - free(ni); - return (0); - } _pthread_mutex_unlock(&sem_llock); errno = EINVAL; return (-1); @@ -342,7 +336,8 @@ _sem_getvalue(sem_t * __restrict sem, int * __restrict sval) static __inline int usem_wake(struct _usem2 *sem) { - return _umtx_op(sem, UMTX_OP_SEM2_WAKE, 0, NULL, NULL); + + return (_umtx_op(sem, UMTX_OP_SEM2_WAKE, 0, NULL, NULL)); } static __inline int @@ -436,6 +431,7 @@ int _sem_timedwait(sem_t * __restrict sem, const struct timespec * __restrict abstime) { + return (_sem_clockwait_np(sem, CLOCK_REALTIME, TIMER_ABSTIME, abstime, NULL)); }; @@ -443,7 +439,8 @@ _sem_timedwait(sem_t * __restrict sem, int _sem_wait(sem_t *sem) { - return _sem_timedwait(sem, NULL); + + return (_sem_timedwait(sem, NULL)); } /* diff --git a/lib/libc/regex/regcomp.c b/lib/libc/regex/regcomp.c index 216cfa2b8c1..bc83aeda539 100644 --- a/lib/libc/regex/regcomp.c +++ b/lib/libc/regex/regcomp.c @@ -444,6 +444,8 @@ p_ere_exp(struct parse *p) (void)REQUIRE(!MORE() || !isdigit((uch)PEEK()), REG_BADRPT); /* FALLTHROUGH */ default: + if (p->error != 0) + return; p->next--; wc = WGETNEXT(); ordinary(p, wc); @@ -651,6 +653,8 @@ p_simp_re(struct parse *p, (void)REQUIRE(starordinary, REG_BADRPT); /* FALLTHROUGH */ default: + if (p->error != 0) + return(0); /* Definitely not $... */ p->next--; wc = WGETNEXT(); ordinary(p, wc); diff --git a/lib/libc/riscv/SYS.h b/lib/libc/riscv/SYS.h index abd93c91efc..7339b70ff94 100644 --- a/lib/libc/riscv/SYS.h +++ b/lib/libc/riscv/SYS.h @@ -54,8 +54,10 @@ END(__sys_##name) ENTRY(__sys_##name); \ WEAK_REFERENCE(__sys_##name, _##name); \ _SYSCALL(name); \ - bnez t0, cerror; \ + bnez t0, 1f; \ ret; \ +1: la t1, cerror; \ + jr t1; \ END(__sys_##name) #define RSYSCALL(name) \ @@ -63,6 +65,8 @@ ENTRY(__sys_##name); \ WEAK_REFERENCE(__sys_##name, name); \ WEAK_REFERENCE(__sys_##name, _##name); \ _SYSCALL(name); \ - bnez t0, cerror; \ + bnez t0, 1f; \ ret; \ +1: la t1, cerror; \ + jr t1; \ END(__sys_##name) diff --git a/lib/libc/riscv/sys/vfork.S b/lib/libc/riscv/sys/vfork.S index a5057802b6c..e7a0b82dc21 100644 --- a/lib/libc/riscv/sys/vfork.S +++ b/lib/libc/riscv/sys/vfork.S @@ -42,10 +42,12 @@ ENTRY(__sys_vfork) mv a2, ra _SYSCALL(vfork) - bnez t0, cerror + bnez t0, 1f addi a1, a1, -1 and a0, a0, a1 mv ra, a2 ret +1: la t1, cerror + jr t1 END(__sys_vfork) diff --git a/lib/libc/rpc/svc.c b/lib/libc/rpc/svc.c index 507d2e2774b..a002216e6e5 100644 --- a/lib/libc/rpc/svc.c +++ b/lib/libc/rpc/svc.c @@ -108,18 +108,19 @@ xprt_register(SVCXPRT *xprt) rwlock_wrlock(&svc_fd_lock); if (__svc_xports == NULL) { __svc_xports = (SVCXPRT **) - mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *)); + mem_alloc((FD_SETSIZE + 1) * sizeof(SVCXPRT *)); if (__svc_xports == NULL) { rwlock_unlock(&svc_fd_lock); return; } - memset(__svc_xports, '\0', FD_SETSIZE * sizeof(SVCXPRT *)); + memset(__svc_xports, '\0', (FD_SETSIZE + 1) * sizeof(SVCXPRT *)); } if (sock < FD_SETSIZE) { __svc_xports[sock] = xprt; FD_SET(sock, &svc_fdset); svc_maxfd = max(svc_maxfd, sock); - } + } else if (sock == FD_SETSIZE) + __svc_xports[sock] = xprt; rwlock_unlock(&svc_fd_lock); } @@ -157,7 +158,8 @@ __xprt_do_unregister(SVCXPRT *xprt, bool_t dolock) if (__svc_xports[svc_maxfd]) break; } - } + } else if ((sock == FD_SETSIZE) && (__svc_xports[sock] == xprt)) + __svc_xports[sock] = NULL; if (dolock) rwlock_unlock(&svc_fd_lock); } diff --git a/lib/libc/sys/cpuset.2 b/lib/libc/sys/cpuset.2 index d16b3ff3751..d39a5c5eaea 100644 --- a/lib/libc/sys/cpuset.2 +++ b/lib/libc/sys/cpuset.2 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd October 20, 2015 +.Dd May 3, 2017 .Dt CPUSET 2 .Os .Sh NAME @@ -101,6 +101,8 @@ argument may have the following values: .It Dv CPU_WHICH_JAIL Ta "id is jid (jail id)" .It Dv CPU_WHICH_CPUSET Ta "id is a cpusetid_t (cpuset id)" .It Dv CPU_WHICH_IRQ Ta "id is an irq number" +.It Dv CPU_WHICH_INTRHANDLER Ta "id is an irq number for an interrupt handler" +.It Dv CPU_WHICH_ITHREAD Ta "id is an irq number for an ithread" .It Dv CPU_WHICH_DOMAIN Ta "id is a NUMA domain" .El .Pp diff --git a/lib/libc/tests/gen/Makefile b/lib/libc/tests/gen/Makefile index 2ec336ee5b2..0c990f17669 100644 --- a/lib/libc/tests/gen/Makefile +++ b/lib/libc/tests/gen/Makefile @@ -8,6 +8,7 @@ ATF_TESTS_C+= fmtmsg_test ATF_TESTS_C+= fnmatch2_test ATF_TESTS_C+= fpclassify2_test ATF_TESTS_C+= ftw_test +ATF_TESTS_C+= glob2_test ATF_TESTS_C+= popen_test ATF_TESTS_C+= posix_spawn_test ATF_TESTS_C+= wordexp_test diff --git a/lib/libc/tests/gen/glob2_test.c b/lib/libc/tests/gen/glob2_test.c new file mode 100644 index 00000000000..dfcce0eed3d --- /dev/null +++ b/lib/libc/tests/gen/glob2_test.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2017 Dell EMC Isilon + * All rights reserved. + * + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * Derived from Russ Cox' pathological case test program used for the + * https://research.swtch.com/glob article. + */ +ATF_TC_WITHOUT_HEAD(glob_pathological_test); +ATF_TC_BODY(glob_pathological_test, tc) +{ + struct timespec t, t2; + glob_t g; + const char *longname = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + char pattern[1000], *p; + double dt; + unsigned i, j, k, mul; + int fd, rc; + + fd = open(longname, O_CREAT | O_RDWR, 0666); + ATF_REQUIRE(fd >= 0); + + /* + * Test up to 100 a* groups. Exponential implementations typically go + * bang at i=7 or 8. + */ + for (i = 0; i < 100; i++) { + /* + * Create a*...b pattern with i 'a*' groups. + */ + p = pattern; + for (k = 0; k < i; k++) { + *p++ = 'a'; + *p++ = '*'; + } + *p++ = 'b'; + *p = '\0'; + + clock_gettime(CLOCK_REALTIME, &t); + for (j = 0; j < mul; j++) { + memset(&g, 0, sizeof g); + rc = glob(pattern, 0, 0, &g); + if (rc == GLOB_NOSPACE || rc == GLOB_ABORTED) { + ATF_REQUIRE_MSG(rc == GLOB_NOMATCH, + "an unexpected error occurred: " + "rc=%d errno=%d", rc, errno); + /* NORETURN */ + } + + ATF_CHECK_MSG(rc == GLOB_NOMATCH, + "A bogus match occurred: '%s' ~ '%s'", pattern, + g.gl_pathv[0]); + globfree(&g); + } + clock_gettime(CLOCK_REALTIME, &t2); + + t2.tv_sec -= t.tv_sec; + t2.tv_nsec -= t.tv_nsec; + dt = t2.tv_sec + (double)t2.tv_nsec/1e9; + dt /= mul; + + ATF_CHECK_MSG(dt < 1, "glob(3) took far too long: %d %.9f", i, + dt); + + if (dt >= 0.0001) + mul = 1; + } +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, glob_pathological_test); + + return (atf_no_error()); +} diff --git a/lib/libedit/editline.3 b/lib/libedit/editline.3 index 0234b0d75d2..c09ffeb2e01 100644 --- a/lib/libedit/editline.3 +++ b/lib/libedit/editline.3 @@ -28,7 +28,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 24, 2016 +.Dd April 28, 2017 .Dt EDITLINE 3 .Os .Sh NAME @@ -767,7 +767,7 @@ Return the previous element in the history. Return the next element in the history. .It Dv H_CURR Return the current element in the history. -.It Dv H_SET +.It Dv H_SET , Fa "int position" Set the cursor to point to the requested element. .It Dv H_ADD , Fa "const char *str" Append diff --git a/lib/libsysdecode/flags.c b/lib/libsysdecode/flags.c index b4749bfcc09..82c8de8353e 100644 --- a/lib/libsysdecode/flags.c +++ b/lib/libsysdecode/flags.c @@ -47,8 +47,10 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include +#include #include #include #include @@ -750,10 +752,16 @@ sysdecode_sockopt_name(int level, int optname) if (level == IPPROTO_IP) /* XXX: UNIX domain socket options use a level of 0 also. */ return (lookup_value(sockoptip, optname)); + if (level == IPPROTO_IPV6) + return (lookup_value(sockoptipv6, optname)); + if (level == IPPROTO_SCTP) + return (lookup_value(sockoptsctp, optname)); if (level == IPPROTO_TCP) return (lookup_value(sockopttcp, optname)); if (level == IPPROTO_UDP) return (lookup_value(sockoptudp, optname)); + if (level == IPPROTO_UDPLITE) + return (lookup_value(sockoptudplite, optname)); return (NULL); } diff --git a/lib/libsysdecode/mktables b/lib/libsysdecode/mktables index 101b4f8da52..317bf341e15 100644 --- a/lib/libsysdecode/mktables +++ b/lib/libsysdecode/mktables @@ -130,8 +130,11 @@ gen_table "sockfamily" "AF_[[:alnum:]]+[[:space:]]+" "sys/ gen_table "sockipproto" "IPPROTO_[[:alnum:]]+[[:space:]]+" "netinet/in.h" gen_table "sockopt" "SO_[A-Z]+[[:space:]]+0x[0-9]+" "sys/socket.h" gen_table "sockoptip" "(IP_[[:alnum:]_]+|MCAST_[[:alnum:]_]+_GROUP)[[:space:]]+" "netinet/in.h" "IP_DEFAULT|IP_MIN|IP_MAX|IP_PORTRANGE" +gen_table "sockoptipv6" "IPV6_[[:alnum:]_]+[[:space:]]+[0-9]+" "netinet6/in6.h" "IPV6_ADDR_|IPV6_TAG_DIRECT|IPV6_OPTIONS|IPV6_RECVOPTS|IPV6_RECVRETOPTS|IPV6_RECVDSTADDR|IPV6_RETOPTS|IPV6_2292|IPV6_RECVRTHDRDSTOPTS|IPV6_REACHCONF|IPV6_PKTOPTIONS" +gen_table "sockoptsctp" "SCTP_[[:alnum:]_]+[[:space:]]+[0-9]+" "netinet/sctp.h" gen_table "sockopttcp" "TCP_[[:alnum:]_]+[[:space:]]+[0-9]+" "netinet/tcp.h" "TCP_MIN|TCP_MAX[^S]|TCP_MSS|TCP_[[:alnum:]_]+_MAX" gen_table "sockoptudp" "UDP_[[:alnum:]]+[[:space:]]+[0-9]+" "netinet/udp.h" "UDP_ENCAP_" +gen_table "sockoptudplite" "UDPLITE_[[:alnum:]_]+[[:space:]]+[0-9]+" "netinet/udplite.h" gen_table "socktype" "SOCK_[A-Z]+[[:space:]]+[1-9]+[0-9]*" "sys/socket.h" gen_table "thrcreateflags" "THR_[A-Z]+[[:space:]]+0x[0-9]+" "sys/thr.h" gen_table "umtxop" "UMTX_OP_[[:alnum:]_]+[[:space:]]+[0-9]+" "sys/umtx.h" diff --git a/libexec/getty/gettytab.5 b/libexec/getty/gettytab.5 index 89c51c526f8..0011f3ac65a 100644 --- a/libexec/getty/gettytab.5 +++ b/libexec/getty/gettytab.5 @@ -81,8 +81,8 @@ table. .It "c2 num unused tty control flags to leave terminal as" .It "ce bool false use crt erase algorithm" .It "ck bool false use crt kill algorithm" -.It "cl str" Ta Dv NULL Ta -.No "screen clear sequence" +.It "cl str" Ta Dv NULL +.Ta No "screen clear sequence" .It "co bool false console - add" .Ql \en after login prompt @@ -94,31 +94,31 @@ scripts .It "dc num 0 chat debug bitmask" .It "de num 0 delay secs and flush input before writing first prompt" .It "df str %+ the" Xr strftime 3 "format used for \&%d in the banner message" -.It "ds str" Ta So Li ^Y Sc Ta -.No "delayed suspend character" +.It "ds str" Ta So Li ^Y +.Sc Ta No "delayed suspend character" .It "dx bool false set" .Dv DECCTLQ .It "ec bool false leave echo" .Em OFF .It "ep bool false terminal uses even parity" -.It "er str" Ta So Li ^? Sc Ta -.No "erase character" -.It "et str" Ta So Li ^D Sc Ta -.No "end of text" +.It "er str" Ta So Li ^? +.Sc Ta No "erase character" +.It "et str" Ta So Li ^D +.Sc Ta No "end of text" .Pq Dv EOF character -.It "ev str" Ta Dv NULL Ta -.No "initial environment" +.It "ev str" Ta Dv NULL +.Ta No "initial environment" .It "f0 num unused tty mode flags to write messages" .It "f1 num unused tty mode flags to read login name" .It "f2 num unused tty mode flags to leave terminal as" -.It "fl str" Ta So Li ^O Sc Ta -.No "output flush character" +.It "fl str" Ta So Li ^O +.Sc Ta No "output flush character" .It "hc bool false do" .Em NOT hangup line on last close -.It "he str" Ta Dv NULL Ta -.No "hostname editing regular expression" +.It "he str" Ta Dv NULL +.Ta No "hostname editing regular expression" .It "hn str hostname hostname" .It "ht bool false terminal has real tabs" .It "hw bool false do cts/rts hardware flow control" @@ -128,21 +128,21 @@ hangup line on last close .It "ic str unused expect-send chat script for modem initialization" .It "if str unused display named file before prompt, like /etc/issue" .It "ig bool false ignore garbage characters in login name" -.It "im str" Ta Dv NULL Ta -.No "initial (banner) message" -.It "in str" Ta So Li ^C Sc Ta -.No "interrupt character" +.It "im str" Ta Dv NULL +.Ta No "initial (banner) message" +.It "in str" Ta So Li ^C +.Sc Ta No "interrupt character" .It "is num unused input speed" -.It "kl str" Ta So Li ^U Sc Ta -.No "kill character" +.It "kl str" Ta So Li ^U +.Sc Ta No "kill character" .It "l0 num unused tty local flags to write messages" .It "l1 num unused tty local flags to read login name" .It "l2 num unused tty local flags to leave terminal as" .It "lm str login: login prompt" -.It "ln str" Ta So Li ^V Sc Ta -.No "``literal next'' character" -.It "lo str" Ta Pa /usr/bin/login Ta -.No "program to exec when name obtained" +.It "ln str" Ta So Li ^V +.Sc Ta No "``literal next'' character" +.It "lo str" Ta Pa /usr/bin/login +.Ta No "program to exec when name obtained" .It "mb bool false do flow control based on carrier" .It "nc bool false terminal does not supply carrier (set clocal)" .It "nl bool false terminal has (or might have) a newline character" @@ -153,8 +153,8 @@ hangup line on last close .It "o2 num unused tty output flags to leave terminal as" .It "op bool false terminal uses odd parity" .It "os num unused output speed" -.It "pc str" Ta So Li \e0 Sc Ta -.No "pad character" +.It "pc str" Ta So Li \e0 +.Sc Ta No "pad character" .It "pe bool false use printer (hard copy) erase algorithm" .It "pf num 0 delay" between first prompt and following flush (seconds) @@ -165,25 +165,25 @@ is specified .It "ps bool false line connected to a" .Tn MICOM port selector -.It "qu str" Ta So Li \&^\e Sc Ta -.No "quit character" -.It "rp str" Ta So Li ^R Sc Ta -.No "line retype character" +.It "qu str" Ta So Li \&^\e +.Sc Ta No "quit character" +.It "rp str" Ta So Li ^R +.Sc Ta No "line retype character" .It "rt num unused ring timeout when using" .Va \&ac .It "rw bool false do" .Em NOT use raw for input, use cbreak .It "sp num unused line speed (input and output)" -.It "su str" Ta So Li ^Z Sc Ta -.No "suspend character" +.It "su str" Ta So Li ^Z +.Sc Ta No "suspend character" .It "tc str none table continuation" .It "to num 0 timeout (seconds)" -.It "tt str" Ta Dv NULL Ta -.No "terminal type (for environment)" +.It "tt str" Ta Dv NULL +.Ta No "terminal type (for environment)" .It "ub bool false do unbuffered output (of prompts etc)" -.It "we str" Ta So Li ^W Sc Ta -.No "word erase character" +.It "we str" Ta So Li ^W +.Sc Ta No "word erase character" .It "xc bool false do" .Em NOT echo control chars as diff --git a/release/doc/en_US.ISO8859-1/hardware/article.xml b/release/doc/en_US.ISO8859-1/hardware/article.xml index 3fc5a37fe0f..8269adc114f 100644 --- a/release/doc/en_US.ISO8859-1/hardware/article.xml +++ b/release/doc/en_US.ISO8859-1/hardware/article.xml @@ -905,27 +905,6 @@ [&arch.i386;] DEC DEFEA EISA (&man.fpa.4; driver) - - ATM Interfaces - - [&arch.i386;] Midway-based ATM interfaces - (&man.en.4; driver) - - [&arch.i386;, &arch.sparc64;] FORE Systems, - Inc. PCA-200E ATM PCI Adapters (hfa and &man.fatm.4; - drivers) - - [&arch.i386;] IDT NICStAR 77201/211-based ATM - Adapters (&man.idt.4; driver) - - [&arch.i386;, &arch.sparc64;] FORE Systems, - Inc. HE155 and HE622 ATM interfaces (&man.hatm.4; - driver) - - [&arch.i386;] IDT77252-based ATM cards - (&man.patm.4; driver) - - Wireless Network Interfaces diff --git a/rescue/rescue/Makefile b/rescue/rescue/Makefile index 4bbb1ccd2ae..1d913b9adc7 100644 --- a/rescue/rescue/Makefile +++ b/rescue/rescue/Makefile @@ -156,7 +156,6 @@ CRUNCH_PROGS_sbin+= bsdlabel fdisk CRUNCH_ALIAS_bsdlabel= disklabel .endif -CRUNCH_SRCDIR_ilmid= ${SRCTOP}/sbin/atm/ilmid CRUNCH_SRCDIR_rtquery= ${SRCTOP}/sbin/routed/rtquery CRUNCH_SRCDIR_ipf= ${SRCTOP}/sbin/ipf/ipf .if ${MK_ZFS} != "no" diff --git a/sbin/camcontrol/camcontrol.8 b/sbin/camcontrol/camcontrol.8 index 0ded7558077..aa77ba8e062 100644 --- a/sbin/camcontrol/camcontrol.8 +++ b/sbin/camcontrol/camcontrol.8 @@ -27,7 +27,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 17, 2017 +.Dd May 3, 2017 .Dt CAMCONTROL 8 .Os .Sh NAME @@ -102,10 +102,10 @@ .Op device id .Nm .Ic rescan -.Aq all | bus Ns Op :target:lun +.Aq all | device id | bus Ns Op :target:lun .Nm .Ic reset -.Aq all | bus Ns Op :target:lun +.Aq all | device id | bus Ns Op :target:lun .Nm .Ic defects .Op device id @@ -578,12 +578,20 @@ start bit cleared and the load/eject bit set. .It Ic rescan Tell the kernel to scan all buses in the system (with the .Ar all -argument), the given bus (XPT_SCAN_BUS), or bus:target:lun +argument), the given bus (XPT_SCAN_BUS), bus:target:lun or device (XPT_SCAN_LUN) for new devices or devices that have gone away. The user may specify a scan of all buses, a single bus, or a lun. Scanning all luns on a target is not supported. +.Pp +If a device is specified by peripheral name and unit number, for instance +da4, it may only be rescanned if that device currently exists in the CAM EDT +(Existing Device Table). +If the device is no longer there (see +.Nm +devlist ), +you must use the bus:target:lun form to rescan it. .It Ic reprobe Tell the kernel to refresh the information about the device and notify the upper layer, @@ -593,8 +601,8 @@ the disk size visible to the rest of the system. .It Ic reset Tell the kernel to reset all buses in the system (with the .Ar all -argument) or the given bus (XPT_RESET_BUS) by issuing a SCSI bus -reset for that bus, or to reset the given bus:target:lun +argument), the given bus (XPT_RESET_BUS) by issuing a SCSI bus +reset for that bus, or to reset the given bus:target:lun or device (XPT_RESET_DEV), typically by issuing a BUS DEVICE RESET message after connecting to that device. Note that this can have a destructive impact @@ -2488,7 +2496,7 @@ Specify the strptime format string, as documented in strptime(3). The time must also be specified with the .Fl T option. -.It Fl T +.It Fl T Ar time Provide the time in the format specified with the .Fl f option. @@ -2814,8 +2822,8 @@ drive .Pa ada0 . .Pp .Bd -literal -offset indent -camcontrol timestamp sa0 -s -f "%A %c" \e - -T "Wednesday Wed Oct 26 21:43:57 2016" +camcontrol timestamp sa0 -s -f "%a, %d %b %Y %T %z" \e + -T "Wed, 26 Oct 2016 21:43:57 -0600" .Ed .Pp Set the timestamp of drive diff --git a/sbin/camcontrol/camcontrol.c b/sbin/camcontrol/camcontrol.c index 10f2778a932..3de48507c8f 100644 --- a/sbin/camcontrol/camcontrol.c +++ b/sbin/camcontrol/camcontrol.c @@ -3131,12 +3131,107 @@ dorescan_or_reset(int argc, char **argv, int rescan) tstr++; if (strncasecmp(tstr, "all", strlen("all")) == 0) arglist |= CAM_ARG_BUS; - else { + else if (isdigit(*tstr)) { rv = parse_btl(argv[optind], &bus, &target, &lun, &arglist); if (rv != 1 && rv != 3) { warnx(must, rescan? "rescan" : "reset"); return(1); } + } else { + char name[30]; + int unit; + int fd = -1; + union ccb ccb; + + /* + * Note that resetting or rescanning a device used to + * require a bus or bus:target:lun. This is because the + * device in question may not exist and you're trying to + * get the controller to rescan to find it. It may also be + * because the device is hung / unresponsive, and opening + * an unresponsive device is not desireable. + * + * It can be more convenient to reference a device by + * peripheral name and unit number, though, and it is + * possible to get the bus:target:lun for devices that + * currently exist in the EDT. So this can work for + * devices that we want to reset, or devices that exist + * that we want to rescan, but not devices that do not + * exist yet. + * + * So, we are careful here to look up the bus/target/lun + * for the device the user wants to operate on, specified + * by peripheral instance (e.g. da0, pass32) without + * actually opening that device. The process is similar to + * what cam_lookup_pass() does, except that we don't + * actually open the passthrough driver instance in the end. + */ + + if (cam_get_device(tstr, name, sizeof(name), &unit) == -1) { + warnx("%s", cam_errbuf); + error = 1; + goto bailout; + } + + if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) { + warn("Unable to open %s", XPT_DEVICE); + error = 1; + goto bailout; + } + + bzero(&ccb, sizeof(ccb)); + + /* + * The function code isn't strictly necessary for the + * GETPASSTHRU ioctl. + */ + ccb.ccb_h.func_code = XPT_GDEVLIST; + + /* + * These two are necessary for the GETPASSTHRU ioctl to + * work. + */ + strlcpy(ccb.cgdl.periph_name, name, + sizeof(ccb.cgdl.periph_name)); + ccb.cgdl.unit_number = unit; + + /* + * Attempt to get the passthrough device. This ioctl will + * fail if the device name is null, if the device doesn't + * exist, or if the passthrough driver isn't in the kernel. + */ + if (ioctl(fd, CAMGETPASSTHRU, &ccb) == -1) { + warn("Unable to find bus:target:lun for device %s%d", + name, unit); + error = 1; + close(fd); + goto bailout; + } + if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { + const struct cam_status_entry *entry; + + entry = cam_fetch_status_entry(ccb.ccb_h.status); + warnx("Unable to find bus:target_lun for device %s%d, " + "CAM status: %s (%#x)", name, unit, + entry ? entry->status_text : "Unknown", + ccb.ccb_h.status); + error = 1; + close(fd); + goto bailout; + } + + /* + * The kernel fills in the bus/target/lun. We don't + * need the passthrough device name and unit number since + * we aren't going to open it. + */ + bus = ccb.ccb_h.path_id; + target = ccb.ccb_h.target_id; + lun = ccb.ccb_h.target_lun; + + arglist |= CAM_ARG_BUS | CAM_ARG_TARGET | CAM_ARG_LUN; + + close(fd); } if ((arglist & CAM_ARG_BUS) @@ -3146,6 +3241,8 @@ dorescan_or_reset(int argc, char **argv, int rescan) else error = rescan_or_reset_bus(bus, rescan); +bailout: + return(error); } @@ -8916,8 +9013,8 @@ usage(int printlong) " camcontrol eject [dev_id][generic args]\n" " camcontrol reprobe [dev_id][generic args]\n" #endif /* MINIMALISTIC */ -" camcontrol rescan \n" -" camcontrol reset \n" +" camcontrol rescan \n" +" camcontrol reset \n" #ifndef MINIMALISTIC " camcontrol defects [dev_id][generic args] <-f format> [-P][-G]\n" " [-q][-s][-S offset][-X]\n" @@ -8996,8 +9093,8 @@ usage(int printlong) "load send a Start Unit command to the device with the load bit set\n" "eject send a Stop Unit command to the device with the eject bit set\n" "reprobe update capacity information of the given device\n" -"rescan rescan all buses, the given bus, or bus:target:lun\n" -"reset reset all buses, the given bus, or bus:target:lun\n" +"rescan rescan all buses, the given bus, bus:target:lun or device\n" +"reset reset all buses, the given bus, bus:target:lun or device\n" "defects read the defect list of the specified device\n" "modepage display or edit (-e) the given mode page\n" "cmd send the given SCSI command, may need -i or -o as well\n" diff --git a/sbin/camcontrol/fwdownload.c b/sbin/camcontrol/fwdownload.c index 1d4f64014ba..a233a492dd2 100644 --- a/sbin/camcontrol/fwdownload.c +++ b/sbin/camcontrol/fwdownload.c @@ -550,8 +550,7 @@ fw_validate_ibm(struct cam_device *dev, int retry_count, int timeout, int fd, fprintf(stdout, "Firmware file is valid for this drive.\n"); retval = 0; bailout: - if (ccb != NULL) - cam_freeccb(ccb); + cam_freeccb(ccb); return (retval); } @@ -753,8 +752,8 @@ fw_check_device_ready(struct cam_device *dev, camcontrol_devtype devtype, goto bailout; } bailout: - if (ccb != NULL) - cam_freeccb(ccb); + free(ptr); + cam_freeccb(ccb); return (retval); } @@ -913,8 +912,7 @@ fw_download_img(struct cam_device *cam_dev, struct fw_vendor *vp, bailout: if (quiet == 0) progress_complete(&progress, size - img_size); - if (ccb != NULL) - cam_freeccb(ccb); + cam_freeccb(ccb); return (retval); } @@ -923,6 +921,7 @@ fwdownload(struct cam_device *device, int argc, char **argv, char *combinedopt, int printerrors, int task_attr, int retry_count, int timeout) { + union ccb *ccb = NULL; struct fw_vendor *vp; char *fw_img_path = NULL; struct ata_params *ident_buf = NULL; @@ -965,8 +964,6 @@ fwdownload(struct cam_device *device, int argc, char **argv, if ((devtype == CC_DT_ATA) || (devtype == CC_DT_ATA_BEHIND_SCSI)) { - union ccb *ccb; - ccb = cam_getccb(device); if (ccb == NULL) { warnx("couldn't allocate CCB"); @@ -976,7 +973,6 @@ fwdownload(struct cam_device *device, int argc, char **argv, if (ata_do_identify(device, retry_count, timeout, ccb, &ident_buf) != 0) { - cam_freeccb(ccb); retval = 1; goto bailout; } @@ -1048,6 +1044,7 @@ fwdownload(struct cam_device *device, int argc, char **argv, fprintf(stdout, "Firmware download successful\n"); bailout: + cam_freeccb(ccb); free(buf); return (retval); } diff --git a/sbin/camcontrol/timestamp.c b/sbin/camcontrol/timestamp.c index 771c8f7d013..3b02937449c 100644 --- a/sbin/camcontrol/timestamp.c +++ b/sbin/camcontrol/timestamp.c @@ -282,12 +282,18 @@ set_timestamp(struct cam_device *device, char *format_string, ts = (uint64_t) time_value; } else { bzero(&time_struct, sizeof(struct tm)); - strptime(timestamp_string, format_string, &time_struct); + if (strptime(timestamp_string, format_string, + &time_struct) == NULL) { + warnx("%s: strptime(3) failed", __func__); + error = 1; + goto bailout; + } time_value = mktime(&time_struct); ts = (uint64_t) time_value; } /* Convert time from seconds to milliseconds */ ts *= 1000; + bzero(&ts_p, sizeof(ts_p)); scsi_create_timestamp(ts_p.timestamp, ts); scsi_set_timestamp(&ccb->csio, diff --git a/sbin/geom/class/part/geom_part.c b/sbin/geom/class/part/geom_part.c index c6bd6d48765..d21e5eb6b65 100644 --- a/sbin/geom/class/part/geom_part.c +++ b/sbin/geom/class/part/geom_part.c @@ -73,6 +73,7 @@ volatile sig_atomic_t undo_restore; static struct gclass *find_class(struct gmesh *, const char *); static struct ggeom * find_geom(struct gclass *, const char *); +static int geom_is_withered(struct ggeom *); static const char *find_geomcfg(struct ggeom *, const char *); static const char *find_provcfg(struct gprovider *, const char *); static struct gprovider *find_provider(struct ggeom *, off_t); @@ -215,7 +216,7 @@ find_geom(struct gclass *classp, const char *name) LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { if (strcmp(gp->lg_name, name) != 0) continue; - if (find_geomcfg(gp, "wither") == NULL) + if (!geom_is_withered(gp)) return (gp); else wgp = gp; @@ -223,6 +224,18 @@ find_geom(struct gclass *classp, const char *name) return (wgp); } +static int +geom_is_withered(struct ggeom *gp) +{ + struct gconfig *gc; + + LIST_FOREACH(gc, &gp->lg_config, lg_config) { + if (!strcmp(gc->lg_name, "wither")) + return (1); + } + return (0); +} + static const char * find_geomcfg(struct ggeom *gp, const char *cfg) { @@ -614,7 +627,7 @@ gpart_show_geom(struct ggeom *gp, const char *element, int show_providers) off_t length, secsz; int idx, wblocks, wname, wmax; - if (find_geomcfg(gp, "wither")) + if (geom_is_withered(gp)) return; scheme = find_geomcfg(gp, "scheme"); if (scheme == NULL) diff --git a/sbin/ifconfig/af_inet6.c b/sbin/ifconfig/af_inet6.c index d5a9246c4d2..e93d94355eb 100644 --- a/sbin/ifconfig/af_inet6.c +++ b/sbin/ifconfig/af_inet6.c @@ -349,12 +349,14 @@ in6_getaddr(const char *s, int which) bzero(&hints, sizeof(struct addrinfo)); hints.ai_family = AF_INET6; error = getaddrinfo(s, NULL, &hints, &res); + if (error != 0) { + if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1) + errx(1, "%s: bad value", s); + } else { + bcopy(res->ai_addr, sin, res->ai_addrlen); + freeaddrinfo(res); + } } - if (error != 0) { - if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1) - errx(1, "%s: bad value", s); - } else - bcopy(res->ai_addr, sin, res->ai_addrlen); } static int diff --git a/sbin/ifconfig/af_nd6.c b/sbin/ifconfig/af_nd6.c index dec9f197036..68789ca5899 100644 --- a/sbin/ifconfig/af_nd6.c +++ b/sbin/ifconfig/af_nd6.c @@ -57,8 +57,7 @@ static const char rcsid[] = #define MAX_SYSCTL_TRY 5 #define ND6BITS "\020\001PERFORMNUD\002ACCEPT_RTADV\003PREFER_SOURCE" \ "\004IFDISABLED\005DONT_SET_IFROUTE\006AUTO_LINKLOCAL" \ - "\007NO_RADR\010NO_PREFER_IFACE\011IGNORELOOP\012NO_DAD" \ - "\020DEFAULTIF" + "\007NO_RADR\010NO_PREFER_IFACE\011NO_DAD\020DEFAULTIF" static int isnd6defif(int); void setnd6flags(const char *, int, int, const struct afswtch *); diff --git a/sbin/ifconfig/ifclone.c b/sbin/ifconfig/ifclone.c index e25fa9b0123..b81e8d26af8 100644 --- a/sbin/ifconfig/ifclone.c +++ b/sbin/ifconfig/ifclone.c @@ -87,6 +87,7 @@ list_cloners(void) putchar('\n'); free(buf); + close(s); } struct clone_defcb { diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8 index 660ff5609b2..f1a35a0050b 100644 --- a/sbin/ifconfig/ifconfig.8 +++ b/sbin/ifconfig/ifconfig.8 @@ -28,7 +28,7 @@ .\" From: @(#)ifconfig.8 8.3 (Berkeley) 1/5/94 .\" $FreeBSD$ .\" -.Dd January 18, 2017 +.Dd April 29, 2017 .Dt IFCONFIG 8 .Os .Sh NAME @@ -2518,7 +2518,7 @@ means Disable lacp strict compliance on the interface. .El .Pp -The following parameters are specific to IP tunnel interfaces, +The following parameters apply to IP tunnel interfaces, .Xr gif 4 : .Bl -tag -width indent .It Cm tunnel Ar src_addr dest_addr @@ -2568,9 +2568,26 @@ Clear a flag .Cm send_rev_ethip_ver . .El .Pp -The following parameters are specific to GRE tunnel interfaces, +The following parameters apply to GRE tunnel interfaces, .Xr gre 4 : .Bl -tag -width indent +.It Cm tunnel Ar src_addr dest_addr +Configure the physical source and destination address for GRE tunnel +interfaces. +The arguments +.Ar src_addr +and +.Ar dest_addr +are interpreted as the outer source/destination for the encapsulating +IPv4/IPv6 header. +.It Fl tunnel +Unconfigure the physical source and destination address for GRE tunnel +interfaces previously configured with +.Cm tunnel . +.It Cm deletetunnel +Another name for the +.Fl tunnel +parameter. .It Cm grekey Ar key Configure the GRE key to be used for outgoing packets. Note that diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c index 8f42c5a04de..7f3289a8749 100644 --- a/sbin/ifconfig/ifconfig.c +++ b/sbin/ifconfig/ifconfig.c @@ -106,7 +106,7 @@ static int ifconfig(int argc, char *const *argv, int iscreate, static void status(const struct afswtch *afp, const struct sockaddr_dl *sdl, struct ifaddrs *ifa); static void tunnel_status(int s); -static void usage(void); +static void usage(void) _Noreturn; static struct afswtch *af_getbyname(const char *name); static struct afswtch *af_getbyfamily(int af); @@ -802,26 +802,24 @@ top: */ p = (setaddr ? &setifdstaddr_cmd : &setifaddr_cmd); } - if (p->c_u.c_func || p->c_u.c_func2) { - if (p->c_parameter == NEXTARG) { - if (argv[1] == NULL) - errx(1, "'%s' requires argument", - p->c_name); - p->c_u.c_func(argv[1], 0, s, afp); + if (p->c_parameter == NEXTARG && p->c_u.c_func) { + if (argv[1] == NULL) + errx(1, "'%s' requires argument", + p->c_name); + p->c_u.c_func(argv[1], 0, s, afp); + argc--, argv++; + } else if (p->c_parameter == OPTARG && p->c_u.c_func) { + p->c_u.c_func(argv[1], 0, s, afp); + if (argv[1] != NULL) argc--, argv++; - } else if (p->c_parameter == OPTARG) { - p->c_u.c_func(argv[1], 0, s, afp); - if (argv[1] != NULL) - argc--, argv++; - } else if (p->c_parameter == NEXTARG2) { - if (argc < 3) - errx(1, "'%s' requires 2 arguments", - p->c_name); - p->c_u.c_func2(argv[1], argv[2], s, afp); - argc -= 2, argv += 2; - } else - p->c_u.c_func(*argv, p->c_parameter, s, afp); - } + } else if (p->c_parameter == NEXTARG2 && p->c_u.c_func2) { + if (argc < 3) + errx(1, "'%s' requires 2 arguments", + p->c_name); + p->c_u.c_func2(argv[1], argv[2], s, afp); + argc -= 2, argv += 2; + } else if (p->c_u.c_func) + p->c_u.c_func(*argv, p->c_parameter, s, afp); argc--, argv++; } @@ -1297,8 +1295,8 @@ printb(const char *s, unsigned v, const char *bits) printf("%s=%o", s, v); else printf("%s=%x", s, v); - bits++; if (bits) { + bits++; putchar('<'); while ((i = *bits++) != '\0') { if (v & (1 << (i-1))) { @@ -1376,8 +1374,11 @@ ifmaybeload(const char *name) } } - /* not present, we should try to load it */ - kldload(ifkind); + /* + * Try to load the module. But ignore failures, because ifconfig can't + * infer the names of all drivers (eg mlx4en(4)). + */ + (void) kldload(ifkind); } static struct cmd basic_cmds[] = { diff --git a/sbin/ifconfig/iflagg.c b/sbin/ifconfig/iflagg.c index e1b50cfb9fb..825acf69d33 100644 --- a/sbin/ifconfig/iflagg.c +++ b/sbin/ifconfig/iflagg.c @@ -200,24 +200,17 @@ static void lagg_status(int s) { struct lagg_protos lpr[] = LAGG_PROTOS; - struct lagg_reqport rp, rpbuf[LAGG_MAX_PORTS]; + struct lagg_reqport rpbuf[LAGG_MAX_PORTS]; struct lagg_reqall ra; struct lagg_reqopts ro; struct lagg_reqflags rf; struct lacp_opreq *lp; const char *proto = ""; - int i, isport = 0; + int i; - bzero(&rp, sizeof(rp)); bzero(&ra, sizeof(ra)); bzero(&ro, sizeof(ro)); - strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname)); - strlcpy(rp.rp_portname, name, sizeof(rp.rp_portname)); - - if (ioctl(s, SIOCGLAGGPORT, &rp) == 0) - isport = 1; - strlcpy(ra.ra_ifname, name, sizeof(ra.ra_ifname)); ra.ra_size = sizeof(rpbuf); ra.ra_port = rpbuf; @@ -257,8 +250,6 @@ lagg_status(int s) sep = ","; } } - if (isport) - printf(" laggdev %s", rp.rp_ifname); putchar('\n'); if (verbose) { printf("\tlagg options:\n"); diff --git a/sbin/ifconfig/ifmedia.c b/sbin/ifconfig/ifmedia.c index c289193509f..abcad7f368c 100644 --- a/sbin/ifconfig/ifmedia.c +++ b/sbin/ifconfig/ifmedia.c @@ -371,7 +371,7 @@ setmediamode(const char *val, int d, int s, const struct afswtch *afp) } /********************************************************************** - * A good chunk of this is duplicated from sys/net/ifmedia.c + * A good chunk of this is duplicated from sys/net/if_media.c **********************************************************************/ static struct ifmedia_description ifm_type_descriptions[] = diff --git a/sbin/ifconfig/ifpfsync.c b/sbin/ifconfig/ifpfsync.c index 9dbe1d67a56..82199ee5ace 100644 --- a/sbin/ifconfig/ifpfsync.c +++ b/sbin/ifconfig/ifpfsync.c @@ -120,6 +120,7 @@ setpfsync_syncpeer(const char *val, int d, int s, const struct afswtch *rafp) if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1) err(1, "SIOCSETPFSYNC"); + freeaddrinfo(peerres); } /* ARGSUSED */ diff --git a/sbin/ipfw/dummynet.c b/sbin/ipfw/dummynet.c index 20c563ba0ce..e26171f4c53 100644 --- a/sbin/ipfw/dummynet.c +++ b/sbin/ipfw/dummynet.c @@ -1881,7 +1881,7 @@ parse_range(int ac, char *av[], uint32_t *v, int len) av--; } if (v[1] < v[0] || - v[1] >= DN_MAX_ID-1 || + v[0] >= DN_MAX_ID-1 || v[1] >= DN_MAX_ID-1) { continue; /* invalid entry */ } diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8 index 999bf8a658c..d9a991b720c 100644 --- a/sbin/ipfw/ipfw.8 +++ b/sbin/ipfw/ipfw.8 @@ -50,7 +50,9 @@ in-kernel NAT. .Nm .Oo Cm set Ar N Oc Cm table Ar name Cm create Ar create-options .Nm -.Oo Cm set Ar N Oc Cm table Ar name Cm destroy +.Oo Cm set Ar N Oc Cm table +.Brq Ar name | all +.Cm destroy .Nm .Oo Cm set Ar N Oc Cm table Ar name Cm modify Ar modify-options .Nm diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c index 887a5a597b2..29f7384d5ad 100644 --- a/sbin/ipfw/ipfw2.c +++ b/sbin/ipfw/ipfw2.c @@ -3187,15 +3187,14 @@ fill_flags_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, void ipfw_delete(char *av[]) { + ipfw_range_tlv rt; + char *sep; int i, j; int exitval = EX_OK; int do_set = 0; - char *sep; - ipfw_range_tlv rt; av++; NEED1("missing rule specification"); - memset(&rt, 0, sizeof(rt)); if ( *av && _substrcmp(*av, "set") == 0) { /* Do not allow using the following syntax: * ipfw set N delete set M @@ -3222,6 +3221,7 @@ ipfw_delete(char *av[]) } else if (co.do_pipe) { exitval = ipfw_delete_pipe(co.do_pipe, i); } else { + memset(&rt, 0, sizeof(rt)); if (do_set != 0) { rt.set = i & 31; rt.flags = IPFW_RCFLAG_SET; @@ -5157,18 +5157,17 @@ void ipfw_zero(int ac, char *av[], int optname) { ipfw_range_tlv rt; - uint32_t arg; - int failed = EX_OK; char const *errstr; char const *name = optname ? "RESETLOG" : "ZERO"; + uint32_t arg; + int failed = EX_OK; optname = optname ? IP_FW_XRESETLOG : IP_FW_XZERO; - memset(&rt, 0, sizeof(rt)); - av++; ac--; if (ac == 0) { /* clear all entries */ + memset(&rt, 0, sizeof(rt)); rt.flags = IPFW_RCFLAG_ALL; if (do_range_cmd(optname, &rt) < 0) err(EX_UNAVAILABLE, "setsockopt(IP_FW_X%s)", name); @@ -5186,6 +5185,7 @@ ipfw_zero(int ac, char *av[], int optname) if (errstr) errx(EX_DATAERR, "invalid rule number %s\n", *av); + memset(&rt, 0, sizeof(rt)); rt.start_rule = arg; rt.end_rule = arg; rt.flags |= IPFW_RCFLAG_RANGE; diff --git a/sbin/ipfw/tables.c b/sbin/ipfw/tables.c index 6f41de337c0..bc0c61b5576 100644 --- a/sbin/ipfw/tables.c +++ b/sbin/ipfw/tables.c @@ -54,6 +54,7 @@ static int table_swap(ipfw_obj_header *oh, char *second); static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i); static int table_show_info(ipfw_xtable_info *i, void *arg); +static int table_destroy_one(ipfw_xtable_info *i, void *arg); static int table_flush_one(ipfw_xtable_info *i, void *arg); static int table_show_one(ipfw_xtable_info *i, void *arg); static int table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh); @@ -132,7 +133,7 @@ lookup_host (char *host, struct in_addr *ipaddr) * This one handles all table-related commands * ipfw table NAME create ... * ipfw table NAME modify ... - * ipfw table NAME destroy + * ipfw table {NAME | all} destroy * ipfw table NAME swap NAME * ipfw table NAME lock * ipfw table NAME unlock @@ -200,6 +201,7 @@ ipfw_table_handler(int ac, char *av[]) case TOK_INFO: case TOK_DETAIL: case TOK_FLUSH: + case TOK_DESTROY: break; default: if (is_all != 0) @@ -223,13 +225,21 @@ ipfw_table_handler(int ac, char *av[]) table_modify(&oh, ac, av); break; case TOK_DESTROY: - if (table_destroy(&oh) == 0) - break; - if (errno != ESRCH) - err(EX_OSERR, "failed to destroy table %s", tablename); - /* ESRCH isn't fatal, warn if not quiet mode */ - if (co.do_quiet == 0) - warn("failed to destroy table %s", tablename); + if (is_all == 0) { + if (table_destroy(&oh) == 0) + break; + if (errno != ESRCH) + err(EX_OSERR, "failed to destroy table %s", + tablename); + /* ESRCH isn't fatal, warn if not quiet mode */ + if (co.do_quiet == 0) + warn("failed to destroy table %s", tablename); + } else { + error = tables_foreach(table_destroy_one, &oh, 1); + if (error != 0) + err(EX_OSERR, + "failed to destroy tables list"); + } break; case TOK_FLUSH: if (is_all == 0) { @@ -567,6 +577,22 @@ table_destroy(ipfw_obj_header *oh) return (0); } +static int +table_destroy_one(ipfw_xtable_info *i, void *arg) +{ + ipfw_obj_header *oh; + + oh = (ipfw_obj_header *)arg; + table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); + if (table_destroy(oh) != 0) { + if (co.do_quiet == 0) + warn("failed to destroy table(%s) in set %u", + i->tablename, i->set); + return (-1); + } + return (0); +} + /* * Flushes given table specified by @oh->ntlv. * Returns 0 on success. @@ -1628,18 +1654,19 @@ tables_foreach(table_cb_t *f, void *arg, int sort) } if (sort != 0) - qsort(olh + 1, olh->count, olh->objsize, tablename_cmp); + qsort(olh + 1, olh->count, olh->objsize, + tablename_cmp); info = (ipfw_xtable_info *)(olh + 1); for (i = 0; i < olh->count; i++) { - error = f(info, arg); /* Ignore errors for now */ - info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize); + if (co.use_set == 0 || info->set == co.use_set - 1) + error = f(info, arg); + info = (ipfw_xtable_info *)((caddr_t)info + + olh->objsize); } - free(olh); break; } - return (0); } diff --git a/sbin/kldconfig/kldconfig.8 b/sbin/kldconfig/kldconfig.8 index 3cc288f5a36..680d9b82094 100644 --- a/sbin/kldconfig/kldconfig.8 +++ b/sbin/kldconfig/kldconfig.8 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 15, 2001 +.Dd April 27, 2017 .Dt KLDCONFIG 8 .Os .Sh NAME @@ -98,6 +98,7 @@ The default module search path used by the kernel. .Sh SEE ALSO .Xr kldload 2 , .Xr kldload 8 , +.Xr kldxref 8 , .Xr sysctl 8 .Sh HISTORY The diff --git a/sbin/kldload/kldload.8 b/sbin/kldload/kldload.8 index b84b8630999..9401c22819d 100644 --- a/sbin/kldload/kldload.8 +++ b/sbin/kldload/kldload.8 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 18, 2012 +.Dd April 27, 2017 .Dt KLDLOAD 8 .Os .Sh NAME @@ -116,7 +116,8 @@ Modules may also be auto-loaded through their addition to .Xr security 7 , .Xr kldconfig 8 , .Xr kldstat 8 , -.Xr kldunload 8 +.Xr kldunload 8 , +.Xr kldxref 8 .Sh HISTORY The .Nm diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index 748bde20236..b58d128a956 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -118,6 +118,7 @@ MAN= aac.4 \ cxgb.4 \ cxgbe.4 \ cxgbev.4 \ + cy.4 \ cyapa.4 \ da.4 \ dc.4 \ diff --git a/share/man/man4/cy.4 b/share/man/man4/cy.4 new file mode 100644 index 00000000000..c0c807286f1 --- /dev/null +++ b/share/man/man4/cy.4 @@ -0,0 +1,257 @@ +.\" Copyright (c) 1990, 1991 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Systems Programming Group of the University of Utah Computer +.\" Science Department. +.\" 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. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. +.\" +.\" from: @(#)dca.4 5.2 (Berkeley) 3/27/91 +.\" from: com.4,v 1.1 1993/08/06 11:19:07 cgd Exp +.\" from: sio.4,v 1.16 1995/06/26 06:05:30 bde Exp $ +.\" $FreeBSD$ +.\" +.Dd May 24, 2004 +.Dt CY 4 +.Os +.Sh NAME +.Nm cy +.Nd Cyclades Cyclom-Y serial driver +.Sh SYNOPSIS +For one ISA card: +.Bd -ragged -offset indent -compact +.Cd "device cy" +.Pp +In +.Pa /boot/device.hints : +.Cd hint.cy.0.at="isa" +.Cd hint.cy.0.irq="10" +.Cd hint.cy.0.maddr="0xd4000" +.Cd hint.cy.0.msize="0x2000" +.Ed +.Pp +For two ISA cards: +.Bd -ragged -offset indent -compact +.Cd "device cy" +.Pp +In +.Pa /boot/device.hints : +.Cd hint.cy.0.at="isa" +.Cd hint.cy.0.irq="10" +.Cd hint.cy.0.maddr="0xd4000" +.Cd hint.cy.0.msize="0x2000" +.Cd hint.cy.1.at="isa" +.Cd hint.cy.1.irq="11" +.Cd hint.cy.1.maddr="0xd6000" +.Cd hint.cy.1.msize="0x2000" +.Ed +.Pp +For PCI cards: +.Bd -ragged -offset indent -compact +.Cd "device cy" +.Cd "options CY_PCI_FASTINTR" +.Pp +No lines are required in +.Pa /boot/device.hints +for PCI cards. +.Ed +.Pp +Minor numbering: +.Bd -literal -offset indent -compact +0b\fIMMMMMMMMMMMMMMMMxxxxxxxxOLIMMMMM\fR + call\fBO\fRut + \fBL\fRock + \fBI\fRnitial + \fBMMMMMMMMMMMMMMMM MMMMMM\fRinor +.Ed +.Sh DESCRIPTION +The +.Nm +driver provides support for Cirrus Logic CD1400-based +.Tn EIA +.Tn RS-232C +.Pf ( Tn CCITT +.Tn V.24 ) +communications interfaces (ports) on Cyclades Cyclom-Y boards. +Each CD1400 provides 4 ports. +Cyclom-Y boards with various numbers of CD1400's are available. +This driver supports up to 8 CD1400's (32 ports) per board. +.Pp +Input and output for each line may set independently +to the following speeds: +50, 75, 110, 134.5, 150, 300, 600, 1200, 1800, 2400, 4800, 9600, +19200, 38400, 57600, or 115200 bps. +Other speeds of up to 150000 are supported by the termios interface +but not by the sgttyb compatibility interface. +The CD1400 is not fast enough to handle speeds above 115200 bps +effectively. +It can transmit on a single line at slightly more than 115200 bps, +but when 4 lines are active in both directions its limit is about +90000 bps on each line. +.\" XXX the following should be true for all serial drivers and +.\" should not be repeated in the man pages for all serial drivers. +.\" It was copied from sio.4. The only change was s/sio/cy/g. +.Pp +Serial ports controlled by the +.Nm +driver can be used for both `callin' and `callout'. +For each port there is a callin device and a callout device. +The minor number of the callout device is 128 higher +than that of the corresponding callin port. +The callin device is general purpose. +Processes opening it normally wait for carrier +and for the callout device to become inactive. +The callout device is used to steal the port from +processes waiting for carrier on the callin device. +Processes opening it do not wait for carrier +and put any processes waiting for carrier on the callin device into +a deeper sleep so that they do not conflict with the callout session. +The callout device is abused for handling programs that are supposed +to work on general ports and need to open the port without waiting +but are too stupid to do so. +.Pp +The +.Nm +driver also supports an initial-state and a lock-state control +device for each of the callin and the callout "data" devices. +The minor number of the initial-state device is 32 higher +than that of the corresponding data device. +The minor number of the lock-state device is 64 higher +than that of the corresponding data device. +The termios settings of a data device are copied +from those of the corresponding initial-state device +on first opens and are not inherited from previous opens. +Use +.Xr stty 1 +in the normal way on the initial-state devices to program +initial termios states suitable for your setup. +.Pp +The lock termios state acts as flags to disable changing +the termios state. +E.g., to lock a flag variable such as +CRTSCTS, use +.Em "stty crtscts" +on the lock-state device. +Speeds and special characters +may be locked by setting the corresponding value in the lock-state +device to any nonzero value. +.Pp +Correct programs talking to correctly wired external devices +work with almost arbitrary initial states and almost no locking, +but other setups may benefit from changing some of the default +initial state and locking the state. +In particular, the initial states for non (POSIX) standard flags +should be set to suit the devices attached and may need to be +locked to prevent buggy programs from changing them. +E.g., CRTSCTS should be locked on for devices that support +RTS/CTS handshaking at all times and off for devices that do not +support it at all. +CLOCAL should be locked on for devices +that do not support carrier. +HUPCL may be locked off if you do not +want to hang up for some reason. +In general, very bad things happen +if something is locked to the wrong state, and things should not +be locked for devices that support more than one setting. +The +CLOCAL flag on callin ports should be locked off for logins +to avoid certain security holes, but this needs to be done by +getty if the callin port is used for anything else. +.Ss Kernel Configuration Options +The +.Em CY_PCI_FASTINTR +option should be used to avoid suboptimal interrupt handling for +PCI Cyclades boards. +The PCI BIOS must be configured with the +.Nm +interrupt not shared with any other active device +for this option to work. +This option is not the default because it is currently harmful in +certain cases where it does not work. +.Sh FILES +.\" XXX more cloning: s/d/c/g and add a ? for the card number. +.Bl -tag -width /dev/ttyic?? -compact +.It Pa /dev/ttyc?? +for callin ports +.It Pa /dev/ttyic?? +.It Pa /dev/ttylc?? +corresponding callin initial-state and lock-state devices +.Pp +.\" XXX more cloning: s/a/c/g. No consistency :-(. +.It Pa /dev/cuac?? +for callout ports +.It Pa /dev/cuaic?? +.It Pa /dev/cualc?? +corresponding callout initial-state and lock-state devices +.El +.Pp +.Bl -tag -width /etc/rc.serial -compact +.It Pa /etc/rc.serial +examples of setting the initial-state and lock-state devices +.El +.Pp +The first question mark in these device names is short for the +card number +(a decimal number between 0 and 65535 inclusive). +The second question mark is short for the port number +(a letter in the range [0-9a-v]). +.Sh DIAGNOSTICS +.Bl -diag +.\" XXX back to s/sio/cy/g. +.It cy%d: silo overflow. +Problem in the interrupt handler. +.El +.Bl -diag +.It cy%d: interrupt-level buffer overflow. +Problem in the bottom half of the driver. +.El +.Bl -diag +.It cy%d: tty-level buffer overflow. +Problem in the application. +Input has arrived faster than the given module could process it +and some has been lost. +.El +.\" .Bl -diag +.\" .It sio%d: reduced fifo trigger level to %d. +.\" Attempting to avoid further silo overflows. +.\" .El +.Sh SEE ALSO +.Xr stty 1 , +.Xr termios 4 , +.Xr tty 4 , +.Xr comcontrol 8 , +.Xr pstat 8 +.Sh HISTORY +The +.Nm +driver is derived from the +.Nm sio +driver and the +.Nx +.Nm +driver and is +.Ud +.Sh BUGS +Serial consoles are not implemented. diff --git a/share/man/man4/pass.4 b/share/man/man4/pass.4 index 3a2e1e72bc1..e09b08e007c 100644 --- a/share/man/man4/pass.4 +++ b/share/man/man4/pass.4 @@ -27,7 +27,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 17, 2015 +.Dd May 3, 2017 .Dt PASS 4 .Os .Sh NAME @@ -85,6 +85,11 @@ Some examples of xpt-only CCBs are XPT_SCAN_BUS, XPT_DEV_MATCH, XPT_RESET_BUS, XPT_SCAN_LUN, XPT_ENG_INQ, and XPT_ENG_EXEC. These CCB types have various attributes that make it illogical or impossible to service them through the passthrough interface. +.Pp +If the user would like the kernel to do error recovery, the +.Dv CAM_PASS_ERR_RECOVER +flag must be set on the CCB, and the retry_count field set to the number +of retries. .It CAMGETPASSTHRU union ccb * This ioctl takes an XPT_GDEVLIST CCB, and returns the passthrough device corresponding to the device in question. @@ -160,6 +165,11 @@ available for userland use with the and .Dv CAMIOGET ioctls and will be preserved across calls. +.Pp +If the user would like the kernel to do error recovery, the +.Dv CAM_PASS_ERR_RECOVER +flag must be set on the CCB, and the retry_count field set to the number +of retries. .It CAMIOGET union ccb * Retrieve completed CAM CCBs queued via the .Dv CAMIOQUEUE diff --git a/share/man/man4/usb.4 b/share/man/man4/usb.4 index 4db0d73a8a4..20370b1f479 100644 --- a/share/man/man4/usb.4 +++ b/share/man/man4/usb.4 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd November 26, 2013 +.Dd April 29, 2017 .Dt USB 4 .Os .Sh NAME @@ -78,8 +78,7 @@ bus. .Pp The .Nm uhub -device will always be present as it is needed for the -root hub. +device will always be present as it is needed for the root hub. .Sh INTRODUCTION TO USB The .Tn USB @@ -94,38 +93,34 @@ The most common USB speeds are: Each .Tn USB has a USB controller that is the master of the bus. -The physical communication is simplex which means the host controller only communicates with one USB device at a time. +The physical communication is simplex which means the host controller only +communicates with one USB device at a time. .Pp There can be up to 127 devices connected to an USB HUB tree. -The addresses are assigned -dynamically by the host when each device is attached to the bus. +The addresses are assigned dynamically by the host when each device is +attached to the bus. .Pp Within each device there can be up to 16 endpoints. -Each endpoint -is individually addressed and the addresses are static. +Each endpoint is individually addressed and the addresses are static. Each of these endpoints will communicate in one of four different modes: .Em control , isochronous , bulk , or .Em interrupt . A device always has at least one endpoint. -This endpoint has address 0 and is a control -endpoint and is used to give commands to and extract basic data, -such as descriptors, from the device. +This endpoint has address 0 and is a control endpoint and is used to give +commands to and extract basic data, such as descriptors, from the device. Each endpoint, except the control endpoint, is unidirectional. .Pp The endpoints in a device are grouped into interfaces. -An interface is a logical unit within a device; e.g.\& -a compound device with both a keyboard and a trackball would present -one interface for each. -An interface can sometimes be set into different modes, -called alternate settings, which affects how it operates. -Different alternate settings can have different endpoints -within it. +An interface is a logical unit within a device, e.g., a compound device with +both a keyboard and a trackball, would present one interface for each. +An interface can sometimes be set into different modes, called alternate +settings, which affects how it operates. +Different alternate settings can have different endpoints within it. .Pp A device may operate in different configurations. -Depending on the -configuration, the device may present different sets of endpoints -and interfaces. +Depending on the configuration, the device may present different sets of +endpoints and interfaces. .Pp The bus enumeration of the .Tn USB @@ -144,7 +139,6 @@ specifications can be found at: .D1 Pa http://www.usb.org/developers/docs/ .Pp .Xr libusb 3 , -.Xr usbdi 4 , .Xr aue 4 , .Xr axe 4 , .Xr axge 4 , @@ -166,8 +160,9 @@ specifications can be found at: .Xr uplcom 4 , .Xr urio 4 , .Xr uvscom 4 , -.Xr usbconfig 8 , .Xr xhci 4 +.Xr usbconfig 8 , +.Xr usbdi 9 , .Sh STANDARDS The .Nm diff --git a/share/man/man7/arch.7 b/share/man/man7/arch.7 index cc20866470e..286b473fbe2 100644 --- a/share/man/man7/arch.7 +++ b/share/man/man7/arch.7 @@ -26,7 +26,7 @@ .\" .\" $FreeBSD$ .\" -.Dd January 21, 2017 +.Dd May 3, 2017 .Dt ARCH 7 .Os .Sh NAME @@ -36,8 +36,9 @@ Differences between CPU architectures and platforms supported by .Fx . .Pp +If not explicitly mentioned, sizes are in bytes. .Ss Type sizes -On all supported architectures, +On all supported architectures: .Bl -column -offset -indent "long long" "Size" .It Sy Type Ta Sy Size .It short Ta 2 @@ -47,28 +48,36 @@ On all supported architectures, .It float Ta 4 .It double Ta 8 .El -.Bl -column -offset indent "Sy Architecture" "Sy sizeof(void *)" "Sy sizeof(long double)" -.It Sy Architecture Ta Sy sizeof(void *) Ta Sy sizeof(long double) -.It amd64 Ta 8 Ta 16 -.It arm Ta 4 Ta 8 -.It armeb Ta 4 Ta 8 -.It armv6 Ta 4 Ta 8 -.It arm64 Ta 8 Ta 16 -.It i386 Ta 4 Ta 12 -.It mips Ta 4 Ta 8 -.It mipsel Ta 4 Ta 8 -.It mipselhf Ta 4 Ta 8 -.It mipshf Ta 4 Ta 8 -.It mipsn32 Ta 4 Ta 8 -.It mips64 Ta 8 Ta 8 -.It mips64el Ta 8 Ta 8 -.It mips64elhf Ta 8 Ta 8 -.It mips64hf Ta 8 Ta 8 -.It powerpc Ta 4 Ta 8 -.It powerpc64 Ta 8 Ta 8 -.It riscv Ta 8 Ta 16 -.It sparc64 Ta 8 Ta 16 +.Pp +Machine-dependent type sizes: +.Bl -column -offset indent "Sy Architecture" "Sy void *" "Sy long double" "Sy time_t" +.It Sy Architecture Ta Sy void * Ta Sy long double Ta Sy time_t +.It amd64 Ta 8 Ta 16 Ta 8 +.It arm Ta 4 Ta 8 Ta 8 +.It armeb Ta 4 Ta 8 Ta 8 +.It armv6 Ta 4 Ta 8 Ta 8 +.It arm64 Ta 8 Ta 16 Ta 8 +.It i386 Ta 4 Ta 12 Ta 4 +.It mips Ta 4 Ta 8 Ta 8 +.It mipsel Ta 4 Ta 8 Ta 8 +.It mipselhf Ta 4 Ta 8 Ta 8 +.It mipshf Ta 4 Ta 8 Ta 8 +.It mipsn32 Ta 4 Ta 8 Ta 8 +.It mips64 Ta 8 Ta 8 Ta 8 +.It mips64el Ta 8 Ta 8 Ta 8 +.It mips64elhf Ta 8 Ta 8 Ta 8 +.It mips64hf Ta 8 Ta 8 Ta 8 +.It powerpc Ta 4 Ta 8 Ta 4 +.It powerpcspe Ta 4 Ta 8 Ta 4 +.It powerpc64 Ta 8 Ta 8 Ta 8 +.It riscv64 Ta 8 Ta 16 Ta 8 +.It riscv64sf Ta 8 Ta 16 Ta 8 +.It sparc64 Ta 8 Ta 16 Ta 8 .El +.Pp +.Sy time_t +is 8 bytes on all supported architectures except i386 and 32-bit +variants of powerpc. .Ss Endianness and Char Signedness .Bl -column -offset indent "Sy Architecture" "Sy Endianness" "Sy char Signedness" .It Sy Architecture Ta Sy Endianness Ta Sy char Signedness @@ -88,8 +97,10 @@ On all supported architectures, .It mips64elhf Ta little Ta signed .It mips64hf Ta big Ta signed .It powerpc Ta big Ta unsigned +.It powerpcspe Ta big Ta unsigned .It powerpc64 Ta big Ta unsigned -.It riscv Ta little Ta signed +.It riscv64 Ta little Ta signed +.It riscv64sf Ta little Ta signed .It sparc64 Ta big Ta signed .El .Ss Page Size @@ -111,8 +122,10 @@ On all supported architectures, .It mips64elhf Ta 4K .It mips64hf Ta 4K .It powerpc Ta 4K +.It powerpcspe Ta 4K .It powerpc64 Ta 4K -.It riscv Ta 4K +.It riscv64 Ta 4K +.It riscv64sf Ta 4K .It sparc64 Ta 8K .El .Ss Floating Point @@ -134,6 +147,7 @@ On all supported architectures, .It mips64elhf Ta hard Ta identical to double .It mips64hf Ta hard Ta identical to double .It powerpc Ta hard Ta hard, double precision +.It powerpcspe Ta hard Ta hard, double precision .It powerpc64 Ta hard Ta hard, double precision .It riscv64 Ta hard Ta hard, double precision .It riscv64sf Ta soft Ta soft, double precision @@ -180,8 +194,10 @@ Architecture-specific macros: .It mips64elhf Ta Dv __mips__, Dv __mips_n64 .It mips64hf Ta Dv __mips__, Dv __MIPSEB__, Dv __mips_n64 .It powerpc Ta Dv __powerpc__ +.It powerpcspe Ta Dv __powerpc__, Dv __SPE__ .It powerpc64 Ta Dv __powerpc__, Dv __powerpc64__ -.It riscv Ta Dv __riscv__, Dv __riscv64 +.It riscv64 Ta Dv __riscv__, Dv __riscv64 +.It riscv64sf Ta Dv __riscv__, Dv __riscv64 .It sparc64 Ta Dv __sparc64__ .El .Sh SEE ALSO diff --git a/share/man/man7/hier.7 b/share/man/man7/hier.7 index 51fb16399ac..9234d8fabff 100644 --- a/share/man/man7/hier.7 +++ b/share/man/man7/hier.7 @@ -28,7 +28,7 @@ .\" @(#)hier.7 8.1 (Berkeley) 6/5/93 .\" $FreeBSD$ .\" -.Dd April 6, 2017 +.Dd April 25, 2017 .Dt HIER 7 .Os .Sh NAME @@ -220,10 +220,6 @@ see .Xr ppbus 4 .It Pa usb/ USB subsystem -.It Pa utopia/ -physical chip driver for ATM interfaces; -see -.Xr utopia 4 .It Pa wi/ .Xr wi 4 WaveLAN driver diff --git a/share/man/man8/Makefile b/share/man/man8/Makefile index 53485750e90..ab135e1bafd 100644 --- a/share/man/man8/Makefile +++ b/share/man/man8/Makefile @@ -18,7 +18,6 @@ MAN= crash.8 \ MLINKS= \ nanobsd.8 nanobsd.sh.8 \ - rc.8 rc.atm.8 \ rc.8 rc.d.8 \ rc.8 rc.firewall.8 \ rc.8 rc.local.8 \ diff --git a/share/man/man8/rc.8 b/share/man/man8/rc.8 index 68a6effecfd..2aa7d3aa6ad 100644 --- a/share/man/man8/rc.8 +++ b/share/man/man8/rc.8 @@ -31,7 +31,7 @@ .\" @(#)rc.8 8.2 (Berkeley) 12/11/93 .\" $FreeBSD$ .\" -.Dd April 23, 2016 +.Dd April 25, 2017 .Dt RC 8 .Os .Sh NAME @@ -455,15 +455,6 @@ disables the loading of firewall rules will load the rules in the given filename (full path required). .El .Pp -The -.Pa /etc/rc.d/atm* -scripts are used to configure ATM network interfaces. -The interfaces are configured in three passes. -The first pass performs the initial interface configuration. -The second pass completes the interface configuration and defines PVCs and -permanent ATMARP entries. -The third pass starts any ATM daemons. -.Pp Most daemons, including network related daemons, have their own script in .Pa /etc/rc.d/ , which can be used to start, stop, and check the status of the service. diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile index dc3b0a14fe2..0307bf25967 100644 --- a/share/man/man9/Makefile +++ b/share/man/man9/Makefile @@ -299,7 +299,6 @@ MAN= accept_filter.9 \ uidinfo.9 \ uio.9 \ unr.9 \ - utopia.9 \ vaccess.9 \ vaccess_acl_nfs4.9 \ vaccess_acl_posix1e.9 \ diff --git a/share/man/man9/netisr.9 b/share/man/man9/netisr.9 index ac648d100d7..efcb8ed8e7b 100644 --- a/share/man/man9/netisr.9 +++ b/share/man/man9/netisr.9 @@ -27,7 +27,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 3, 2016 +.Dd April 25, 2017 .Dt NETISR 9 .Os .Sh NAME @@ -220,8 +220,6 @@ Routing socket loopback ARP .It Dv NETISR_IPV6 IPv6 -.It Dv NETISR_NATM -ATM .It Dv NETISR_EPAIR .Xr netstat 1 , .Xr epair 4 diff --git a/share/man/man9/utopia.9 b/share/man/man9/utopia.9 deleted file mode 100644 index 99be5fa809b..00000000000 --- a/share/man/man9/utopia.9 +++ /dev/null @@ -1,353 +0,0 @@ -.\" Copyright (c) 2003 -.\" Fraunhofer Institute for Open Communication Systems (FhG Fokus). -.\" All rights reserved. -.\" -.\" 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. -.\" -.\" Author: Hartmut Brandt -.\" -.\" $FreeBSD$ -.\" -.Dd May 8, 2003 -.Dt UTOPIA 9 -.Os -.Sh NAME -.Nm utopia -.Nd "driver module for ATM PHY chips" -.Sh SYNOPSIS -.In dev/utopia/utopia.h -.Ft int -.Fo utopia_attach -.Fa "struct utopia *utp" "struct ifatm *ifatm" "struct ifmedia *media" -.Fa "struct mtx *lock" "struct sysctl_ctx_list *ctx" -.Fa "struct sysctl_oid_list *tree" "const struct utopia_methods *vtab" -.Fc -.Ft void -.Fn utopia_detach "struct utopia *utp" -.Ft int -.Fn utopia_start "struct utopia *utp" -.Ft void -.Fn utopia_stop "struct utopia *utp" -.Ft void -.Fn utopia_init_media "struct utopia *utp" -.Ft void -.Fn utopia_reset_media "struct utopia *utp" -.Ft int -.Fn utopia_reset "struct utopia *utp" -.Ft int -.Fn utopia_set_sdh "struct utopia *utp" "int sdh" -.Ft int -.Fn utopia_set_unass "struct utopia *utp" "int unass" -.Ft int -.Fn utopia_set_noscramb "struct utopia *utp" "int noscramb" -.Ft int -.Fn utopia_update_carrier "struct utopia *utp" -.Ft int -.Fn utopia_set_loopback "struct utopia *utp" "u_int mode" -.Ft void -.Fn utopia_intr "struct utopia *utp" -.Ft void -.Fn utopia_update_stats "struct utopia *utp" -.Sh DESCRIPTION -This module is used by all ATM drivers for cards that use a number of known -PHY chips to provide uniform functionality. -The module implements status monitoring in either interrupt or polling mode, -media option handling and application access to PHY registers. -.Pp -To use this interface, a driver must implement two functions for reading and -writing PHY registers, and initialize the following structure with pointers -to these functions: -.Bd -literal -offset indent -struct utopia_methods { - int (*readregs)(struct ifatm *, u_int reg, - uint8_t *val, u_int *n); - int (*writereg)(struct ifatm *, u_int reg, - u_int mask, u_int val); -}; -.Ed -.Pp -The -.Fn readregs -function should read PHY registers starting at register -.Fa reg . -The maximum number of registers to read is given by the integer pointed -to by -.Fa n . -The function should either return 0 on success, or an error code. -In the first case, -.Fa *n -should be set to the actual number of registers read. -The -.Fn writereg -function should write one register. -It must change all bits for which the corresponding bit in -.Fa mask -is 1 to the value of the corresponding bit in -.Fa val . -It returns either 0 on success, or an error code. -.Pp -The ATM driver's private state block -.Pq Va softc -must begin with a -.Vt "struct ifatm" . -.Pp -The -.Vt "struct utopia" -holds the current state of the PHY chip and contains the following fields: -.Bd -literal -offset indent -struct utopia { - struct ifatm *ifatm; /* driver data */ - struct ifmedia *media; /* driver supplied */ - struct mtx *lock; /* driver supplied */ - const struct utopia_methods *methods; - LIST_ENTRY(utopia) link; /* list of these structures */ - u_int flags; /* flags set by the driver */ - u_int state; /* current state */ - u_int carrier; /* carrier state */ - u_int loopback; /* loopback mode */ - const struct utopia_chip *chip; /* chip operations */ - struct utopia_stats1 stats; /* statistics */ -}; -.Ed -The public accessible fields have the following functions: -.Bl -tag -width indent -.It Va ifatm -Pointer to the driver's private data -.Pq Va softc . -.It Va media -Pointer to the driver's media structure. -.It Va lock -Pointer to a mutex provided by the driver. -This mutex is used to synchronize -with the kernel thread that handles device polling. -It is locked in several -places: -.Bl -enum -offset indent -.It -In -.Fn utopia_detach -the mutex is locked to sleep and wait for the kernel thread to remove the -.Vt "struct utopia" -from the list of all -.Nm -devices. -Before returning to the caller the mutex is unlocked. -.It -In the -.Nm -kernel thread the mutex is locked, and the -.Fn utopia_carrier_update -function is called with this mutex locked. -This will result in the driver's -.Fn readregs -function being called with the mutex locked. -.It -In the sysctl handlers the mutex will be locked before calling into the driver's -.Fn readreg -or -.Fn writereg -functions. -.El -.It Va flags -Flags set by either the driver or the -.Nm -module. -The following flags are -defined: -.Bl -tag -width indent -.It Dv UTP_FL_NORESET -If this flag is set, the module will not try to write the -SUNI master reset register. -(Set by the driver.) -.It Dv UTP_FL_POLL_CARRIER -If this flag is set, the module will periodically poll the carrier state -(as opposed to interrupt driven carrier state changes). -(Set by the driver.) -.El -.It Va state -Flags describing the current state of the PHY chip. -These are managed -by the module: -.Bl -tag -width indent -.It Dv UTP_ST_ACTIVE -The driver is active and the PHY registers can be accessed. -This is set by calling -.Fn utopia_start , -which should be called either in the attach routine of the driver or -in the network interface initialisation routine (depending on whether the -registers are accessible all the time or only when the interface is up). -.It Dv UTP_ST_SDH -Interface is in SDH mode as opposed to SONET mode. -.It Dv UTP_ST_UNASS -Interface is producing unassigned cells instead of idle cells. -.It Dv UTP_ST_NOSCRAMB -Cell scrambling is switched off. -.It Dv UTP_ST_DETACH -(Internal use.) -Interface is currently detaching. -.It Dv UTP_ST_ATTACHED -The attach routine has been run successfully. -.El -.It Va carrier -The carrier state of the interface. -This field can have one of three values: -.Bl -tag -width indent -.It Dv UTP_CARR_UNKNOWN -Carrier state is still unknown. -.It Dv UTP_CARR_OK -Carrier has been detected. -.It Dv UTP_CARR_LOST -Carrier has been lost. -.El -.It Va loopback -This is the current loopback mode of the interface. -Note that not all -chips support all loopback modes. -Refer to the chip documentation. -The -following modes may be supported: -.Bl -tag -width indent -.It Dv UTP_LOOP_NONE -No loopback, normal operation. -.It Dv UTP_LOOP_TIME -Timing source loopback. -The transmitter clock is driven by the receive clock. -.It Dv UTP_LOOP_DIAG -Diagnostic loopback. -.It Dv UTP_LOOP_LINE -Serial line loopback. -.It Dv UTP_LOOP_PARAL -Parallel diagnostic loopback. -.It Dv UTP_LOOP_TWIST -Twisted pair diagnostic loopback. -.It Dv UTP_LOOP_PATH -Diagnostic path loopback. -.El -.It Va chip -This points to a function vector for chip specific functions. -Two fields -in this vector are publicly available: -.Bl -tag -width indent -.It Va type -This is the type of the detected PHY chip. -One of: -.Pp -.Bl -tag -width indent -compact -.It Dv UTP_TYPE_UNKNOWN Pq No 0 -.It Dv UTP_TYPE_SUNI_LITE Pq No 1 -.It Dv UTP_TYPE_SUNI_ULTRA Pq No 2 -.It Dv UTP_TYPE_SUNI_622 Pq No 3 -.It Dv UTP_TYPE_IDT77105 Pq No 4 -.El -.It Va name -This is a string with the name of the PHY chip. -.El -.El -.Pp -The following functions are used by the driver during attach/detach and/or -initialisation/stopping the interface: -.Bl -tag -width indent -.It Fn utopia_attach -Attach the PHY chip. -This is called with a preallocated -.Vt "struct utopia" -(which may be part of the driver's -.Va softc ) . -The module initializes all fields of the -.Nm -state and the media field. -User settable flags should be set after the call to -.Fn utopia_attach . -This function may fail due to the inability to install the sysctl handlers. -In this case it will return \-1. -On success, 0 is returned and the -.Dv UTP_ST_ATTACHED -flag is set. -.It Fn utopia_detach -Remove the -.Nm -attachment from the system. -This cancels all outstanding polling -timeouts. -.It Fn utopia_start -Start operation of that PHY. -This should be called at a time -when the PHY registers are known to be accessible. -This may be either in -the driver's attach function or when the interface is set running. -.It Fn utopia_stop -Stop operation of the PHY attachment. -This may be called either in the detach -function of the driver or when the interface is brought down. -.It Fn utopia_init_media -This must be called if the media field in the ATM MIB was changed. -The function -makes sure, that the ifmedia fields contain the same information as the -ATM MIB. -.It Fn utopia_reset_media -This may be called to remove all media information from the ifmedia field. -.El -.Pp -The following functions can be used to modify the PHY state while the interface -is running: -.Bl -tag -width indent -.It Fn utopia_reset -Reset the operational parameters to the default state (SONET, idle cells, -scrambling enabled). -Returns 0 on success, an error code otherwise, leaving -the state undefined. -.It Fn utopia_set_sdh -If the argument is zero the chip is switched to Sonet mode, if it is non-zero -the chip is switched to SDH mode. -Returns 0 on success, an error code otherwise, -leaving the previous state. -.It Fn utopia_set_unass -If the argument is zero the chip is switched to produce idle cells, if it is -non-zero the chip is switched to produce unassigned cells. -Returns 0 on success, -an error code otherwise, leaving the previous state. -.It Fn utopia_set_noscramb -If the argument is zero enables scrambling, if it is -non-zero disables scrambling. -Returns 0 on success, -an error code otherwise, leaving the previous state. -.It Fn utopia_update_carrier -Check the carrier state and update the carrier field in the state structure. -This will generate a message to the Netgraph stack if the carrier state changes. -For chips that are polled this is called automatically, for interrupt -driven attachments this must be called on interrupts from the PHY chip. -.It Fn utopia_set_loopback -Set the loopback mode of the chip. -Returns 0 on success, an error code -otherwise, leaving the previous state. -.It Fn utopia_intr -Called when an interrupt from the PHY chip is detected. -This resets the -interrupt state by reading all registers and, if the interrupt was from the -RSOP, checks the carrier state. -.It Fn utopia_update_stats -Update the statistics with counters read from the chip. -.El -.Sh SEE ALSO -.Xr utopia 4 -.Sh AUTHORS -.An Harti Brandt Aq Mt harti@FreeBSD.org diff --git a/share/misc/committers-src.dot b/share/misc/committers-src.dot index 03d46ee961e..f43203936cc 100644 --- a/share/misc/committers-src.dot +++ b/share/misc/committers-src.dot @@ -334,6 +334,7 @@ wkoszek [label="Wojciech A. Koszek\nwkoszek@FreeBSD.org\n2006/02/21"] wma [label="Wojciech Macek\nwma@FreeBSD.org\n2016/01/18"] wollman [label="Garrett Wollman\nwollman@FreeBSD.org\n????/??/??"] wsalamon [label="Wayne Salamon\nwsalamon@FreeBSD.org\n2005/06/25"] +wulf [label="Vladimir Kondratyev\nwulf@FreeBSD.org\n2017/04/27"] yongari [label="Pyun YongHyeon\nyongari@FreeBSD.org\n2004/08/01"] zbb [label="Zbigniew Bodek\nzbb@FreeBSD.org\n2013/09/02"] zec [label="Marko Zec\nzec@FreeBSD.org\n2008/06/22"] @@ -385,6 +386,7 @@ avg -> smh bapt -> allanjude bapt -> araujo bapt -> bdrewery +bapt -> wulf benno -> grehan @@ -496,6 +498,7 @@ gnn -> jtl gnn -> karels gonzo -> jmcneill +gonzo -> wulf grehan -> bryanv grehan -> rgrimes diff --git a/share/mk/src.opts.mk b/share/mk/src.opts.mk index 70c6f83f3f4..9d1c739ac50 100644 --- a/share/mk/src.opts.mk +++ b/share/mk/src.opts.mk @@ -339,16 +339,6 @@ MK_LDNS_UTILS:= no MK_UNBOUND:= no .endif -.if ${MK_LLD} == "no" -MK_LLD_IS_LD:= no -.endif - -# LLD requires LLVM libraries, and we do not yet compare in-tree and host LLD -# versions to avoid building it if they are identical. -.if ${MK_LLD_IS_LD} != "no" -MK_SYSTEM_COMPILER:= no -.endif - .if ${MK_SOURCELESS} == "no" MK_SOURCELESS_HOST:= no MK_SOURCELESS_UCODE:= no diff --git a/sys/Makefile b/sys/Makefile index 7d88c4ecdf2..6af2e2c28de 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -3,7 +3,7 @@ # Directories to include in cscope name file and TAGS. CSCOPEDIRS= boot bsm cam cddl compat conf contrib crypto ddb dev fs gdb \ geom gnu isa kern libkern modules net net80211 \ - netgraph netinet netinet6 netipsec netnatm netpfil \ + netgraph netinet netinet6 netipsec netpfil \ netsmb nfs nfsclient nfsserver nlm ofed opencrypto \ rpc security sys ufs vm xdr xen ${CSCOPE_ARCHDIR} .if !defined(CSCOPE_ARCHDIR) @@ -32,7 +32,8 @@ ${.CURDIR}/cscope.files: .PHONY find ${CSCOPEDIRS} -name "*.[chSsly]" -a -type f > ${.TARGET} cscope-clean: - rm -f cscope.files cscope.out cscope.in.out cscope.po.out + cd ${.CURDIR}; \ + rm -f cscope.files cscope.out cscope.in.out cscope.po.out # # Installs SCM hooks to update the cscope database every time the source tree diff --git a/sys/amd64/pci/pci_cfgreg.c b/sys/amd64/pci/pci_cfgreg.c index 0039008b345..2e6e7284589 100644 --- a/sys/amd64/pci/pci_cfgreg.c +++ b/sys/amd64/pci/pci_cfgreg.c @@ -64,6 +64,7 @@ static vm_offset_t pcie_base; static int pcie_minbus, pcie_maxbus; static uint32_t pcie_badslots; static struct mtx pcicfg_mtx; +MTX_SYSINIT(pcicfg_mtx, &pcicfg_mtx, "pcicfg_mtx", MTX_SPIN); static int mcfg_enable = 1; SYSCTL_INT(_hw_pci, OID_AUTO, mcfg, CTLFLAG_RDTUN, &mcfg_enable, 0, "Enable support for PCI-e memory mapped config access"); @@ -74,15 +75,9 @@ SYSCTL_INT(_hw_pci, OID_AUTO, mcfg, CTLFLAG_RDTUN, &mcfg_enable, 0, int pci_cfgregopen(void) { - static int once = 0; uint64_t pciebar; uint16_t did, vid; - if (!once) { - mtx_init(&pcicfg_mtx, "pcicfg", NULL, MTX_SPIN); - once = 1; - } - if (cfgmech != CFGMECH_NONE) return (1); cfgmech = CFGMECH_1; @@ -138,6 +133,9 @@ pci_cfgregread(int bus, int slot, int func, int reg, int bytes) { uint32_t line; + if (cfgmech == CFGMECH_NONE) + return (0xffffffff); + /* * Some BIOS writers seem to want to ignore the spec and put * 0 in the intline rather than 255 to indicate none. Some use @@ -162,6 +160,9 @@ void pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes) { + if (cfgmech == CFGMECH_NONE) + return; + if (cfgmech == CFGMECH_PCIE && (bus >= pcie_minbus && bus <= pcie_maxbus) && (bus != 0 || !(1 << slot & pcie_badslots))) diff --git a/sys/amd64/vmm/amd/amdvi_hw.c b/sys/amd64/vmm/amd/amdvi_hw.c new file mode 100644 index 00000000000..7d21e83838f --- /dev/null +++ b/sys/amd64/vmm/amd/amdvi_hw.c @@ -0,0 +1,1509 @@ +/*- + * Copyright (c) 2016, Anish Gupta (anish@freebsd.org) + * All rights reserved. + * + * 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 unmodified, 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 ``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 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "pcib_if.h" + +#include "io/iommu.h" +#include "amdvi_priv.h" + +SYSCTL_DECL(_hw_vmm); +SYSCTL_NODE(_hw_vmm, OID_AUTO, amdvi, CTLFLAG_RW, NULL, NULL); + +#define MOD_INC(a, s, m) (((a) + (s)) % ((m) * (s))) +#define MOD_DEC(a, s, m) (((a) - (s)) % ((m) * (s))) + +/* Print RID or device ID in PCI string format. */ +#define RID2PCI_STR(d) PCI_RID2BUS(d), PCI_RID2SLOT(d), PCI_RID2FUNC(d) + +static void amdvi_dump_cmds(struct amdvi_softc *softc); +static void amdvi_print_dev_cap(struct amdvi_softc *softc); + +MALLOC_DEFINE(M_AMDVI, "amdvi", "amdvi"); + +extern device_t *ivhd_devs; + +extern int ivhd_count; +SYSCTL_INT(_hw_vmm_amdvi, OID_AUTO, count, CTLFLAG_RDTUN, &ivhd_count, + 0, NULL); + +static int amdvi_enable_user = 0; +SYSCTL_INT(_hw_vmm_amdvi, OID_AUTO, enable, CTLFLAG_RDTUN, + &amdvi_enable_user, 0, NULL); +TUNABLE_INT("hw.vmm.amdvi_enable", &amdvi_enable_user); + +#ifdef AMDVI_ATS_ENABLE +/* XXX: ATS is not tested. */ +static int amdvi_enable_iotlb = 1; +SYSCTL_INT(_hw_vmm_amdvi, OID_AUTO, iotlb_enabled, CTLFLAG_RDTUN, + &amdvi_enable_iotlb, 0, NULL); +TUNABLE_INT("hw.vmm.enable_iotlb", &amdvi_enable_iotlb); +#endif + +static int amdvi_host_ptp = 1; /* Use page tables for host. */ +SYSCTL_INT(_hw_vmm_amdvi, OID_AUTO, host_ptp, CTLFLAG_RDTUN, + &amdvi_host_ptp, 0, NULL); +TUNABLE_INT("hw.vmm.amdvi.host_ptp", &amdvi_host_ptp); + +/* Page table level used <= supported by h/w[v1=7]. */ +static int amdvi_ptp_level = 4; +SYSCTL_INT(_hw_vmm_amdvi, OID_AUTO, ptp_level, CTLFLAG_RDTUN, + &amdvi_ptp_level, 0, NULL); +TUNABLE_INT("hw.vmm.amdvi.ptp_level", &amdvi_ptp_level); + +/* Disable fault event reporting. */ +static int amdvi_disable_io_fault = 0; +SYSCTL_INT(_hw_vmm_amdvi, OID_AUTO, disable_io_fault, CTLFLAG_RDTUN, + &amdvi_disable_io_fault, 0, NULL); +TUNABLE_INT("hw.vmm.amdvi.disable_io_fault", &amdvi_disable_io_fault); + +static uint32_t amdvi_dom_id = 0; /* 0 is reserved for host. */ +SYSCTL_UINT(_hw_vmm_amdvi, OID_AUTO, domain_id, CTLFLAG_RD, + &amdvi_dom_id, 0, NULL); +/* + * Device table entry. + * Bus(256) x Dev(32) x Fun(8) x DTE(256 bits or 32 bytes). + * = 256 * 2 * PAGE_SIZE. + */ +static struct amdvi_dte amdvi_dte[PCI_NUM_DEV_MAX] __aligned(PAGE_SIZE); +CTASSERT(PCI_NUM_DEV_MAX == 0x10000); +CTASSERT(sizeof(amdvi_dte) == 0x200000); + +static SLIST_HEAD (, amdvi_domain) dom_head; + +static inline void +amdvi_pci_write(struct amdvi_softc *softc, int off, uint32_t data) +{ + + pci_cfgregwrite(PCI_RID2BUS(softc->pci_rid), + PCI_RID2SLOT(softc->pci_rid), PCI_RID2FUNC(softc->pci_rid), + off, data, 4); +} + +static inline uint32_t +amdvi_pci_read(struct amdvi_softc *softc, int off) +{ + + return (pci_cfgregread(PCI_RID2BUS(softc->pci_rid), + PCI_RID2SLOT(softc->pci_rid), PCI_RID2FUNC(softc->pci_rid), + off, 4)); +} + +static int +amdvi_find_pci_cap(struct amdvi_softc *softc, uint8_t capability, int *off) +{ + uint32_t read; + uint8_t ptr; + + read = amdvi_pci_read(softc, PCIR_COMMAND); + if (((read >> 16) & PCIM_STATUS_CAPPRESENT) == 0) + return (ENXIO); + + /* Read the starting of capability pointer. */ + read = amdvi_pci_read(softc, PCIR_CAP_PTR); + ptr = read & 0xFF; + + while (ptr != 0) { + read = amdvi_pci_read(softc, ptr); + if ((read & 0xFF) == capability) { + *off = ptr; + return (0); + } + ptr = (read >> 8) & 0xFF; + } + + return (ENOENT); +} + +#ifdef AMDVI_ATS_ENABLE +/* XXX: Should be in pci.c */ +/* + * Check if device has ATS capability and its enabled. + * If ATS is absent or disabled, return (-1), otherwise ATS + * queue length. + */ +static int +amdvi_find_ats_qlen(uint16_t devid) +{ + device_t dev; + uint32_t off, cap; + int qlen = -1; + + dev = pci_find_bsf(PCI_RID2BUS(devid), PCI_RID2SLOT(devid), + PCI_RID2FUNC(devid)); + + if (!dev) { + return (-1); + } +#define PCIM_ATS_EN BIT(31) + + if (pci_find_extcap(dev, PCIZ_ATS, &off) == 0) { + cap = pci_read_config(dev, off + 4, 4); + qlen = (cap & 0x1F); + qlen = qlen ? qlen : 32; + printf("AMD-Vi: PCI device %d.%d.%d ATS %s qlen=%d\n", + RID2PCI_STR(devid), + (cap & PCIM_ATS_EN) ? "enabled" : "Disabled", + qlen); + qlen = (cap & PCIM_ATS_EN) ? qlen : -1; + } + + return (qlen); +} + +/* + * Check if an endpoint device support device IOTLB or ATS. + */ +static inline bool +amdvi_dev_support_iotlb(struct amdvi_softc *softc, uint16_t devid) +{ + struct ivhd_dev_cfg *cfg; + int qlen, i; + bool pci_ats, ivhd_ats; + + qlen = amdvi_find_ats_qlen(devid); + if (qlen < 0) + return (false); + + KASSERT(softc, ("softc is NULL")); + cfg = softc->dev_cfg; + + ivhd_ats = false; + for (i = 0; i < softc->dev_cfg_cnt; i++) { + if ((cfg->start_id <= devid) && (cfg->end_id >= devid)) { + ivhd_ats = cfg->enable_ats; + break; + } + cfg++; + } + + pci_ats = (qlen < 0) ? false : true; + if (pci_ats != ivhd_ats) + device_printf(softc->dev, + "BIOS bug: mismatch in ATS setting for %d.%d.%d," + "ATS inv qlen = %d\n", RID2PCI_STR(devid), qlen); + + /* Ignore IVRS setting and respect PCI setting. */ + return (pci_ats); +} +#endif + +/* Enable IOTLB support for IOMMU if its supported. */ +static inline void +amdvi_hw_enable_iotlb(struct amdvi_softc *softc) +{ +#ifndef AMDVI_ATS_ENABLE + softc->iotlb = false; +#else + bool supported; + + supported = (softc->ivhd_flag & IVHD_FLAG_IOTLB) ? true : false; + + if (softc->pci_cap & AMDVI_PCI_CAP_IOTLB) { + if (!supported) + device_printf(softc->dev, "IOTLB disabled by BIOS.\n"); + + if (supported && !amdvi_enable_iotlb) { + device_printf(softc->dev, "IOTLB disabled by user.\n"); + supported = false; + } + } else + supported = false; + + softc->iotlb = supported; + +#endif +} + +static int +amdvi_init_cmd(struct amdvi_softc *softc) +{ + struct amdvi_ctrl *ctrl = softc->ctrl; + + ctrl->cmd.len = 8; /* Use 256 command buffer entries. */ + softc->cmd_max = 1 << ctrl->cmd.len; + + softc->cmd = malloc(sizeof(struct amdvi_cmd) * + softc->cmd_max, M_AMDVI, M_WAITOK | M_ZERO); + + if ((uintptr_t)softc->cmd & PAGE_MASK) + panic("AMDVi: Command buffer not aligned on page boundary."); + + ctrl->cmd.base = vtophys(softc->cmd) / PAGE_SIZE; + /* + * XXX: Reset the h/w pointers in case IOMMU is restarting, + * h/w doesn't clear these pointers based on empirical data. + */ + ctrl->cmd_tail = 0; + ctrl->cmd_head = 0; + + return (0); +} + +/* + * Note: Update tail pointer after we have written the command since tail + * pointer update cause h/w to execute new commands, see section 3.3 + * of AMD IOMMU spec ver 2.0. + */ +/* Get the command tail pointer w/o updating it. */ +static struct amdvi_cmd * +amdvi_get_cmd_tail(struct amdvi_softc *softc) +{ + struct amdvi_ctrl *ctrl; + struct amdvi_cmd *tail; + + KASSERT(softc, ("softc is NULL")); + KASSERT(softc->cmd != NULL, ("cmd is NULL")); + + ctrl = softc->ctrl; + KASSERT(ctrl != NULL, ("ctrl is NULL")); + + tail = (struct amdvi_cmd *)((uint8_t *)softc->cmd + + ctrl->cmd_tail); + + return (tail); +} + +/* + * Update the command tail pointer which will start command execution. + */ +static void +amdvi_update_cmd_tail(struct amdvi_softc *softc) +{ + struct amdvi_ctrl *ctrl; + int size; + + size = sizeof(struct amdvi_cmd); + KASSERT(softc->cmd != NULL, ("cmd is NULL")); + + ctrl = softc->ctrl; + KASSERT(ctrl != NULL, ("ctrl is NULL")); + + ctrl->cmd_tail = MOD_INC(ctrl->cmd_tail, size, softc->cmd_max); + softc->total_cmd++; + +#ifdef AMDVI_DEBUG_CMD + device_printf(softc->dev, "cmd_tail: %s Tail:0x%x, Head:0x%x.\n", + ctrl->cmd_tail, + ctrl->cmd_head); +#endif + +} + +/* + * Various commands supported by IOMMU. + */ + +/* Completion wait command. */ +static void +amdvi_cmd_cmp(struct amdvi_softc *softc, const uint64_t data) +{ + struct amdvi_cmd *cmd; + uint64_t pa; + + cmd = amdvi_get_cmd_tail(softc); + KASSERT(cmd != NULL, ("Cmd is NULL")); + + pa = vtophys(&softc->cmp_data); + cmd->opcode = AMDVI_CMP_WAIT_OPCODE; + cmd->word0 = (pa & 0xFFFFFFF8) | + (AMDVI_CMP_WAIT_STORE); + //(AMDVI_CMP_WAIT_FLUSH | AMDVI_CMP_WAIT_STORE); + cmd->word1 = (pa >> 32) & 0xFFFFF; + cmd->addr = data; + + amdvi_update_cmd_tail(softc); +} + +/* Invalidate device table entry. */ +static void +amdvi_cmd_inv_dte(struct amdvi_softc *softc, uint16_t devid) +{ + struct amdvi_cmd *cmd; + + cmd = amdvi_get_cmd_tail(softc); + KASSERT(cmd != NULL, ("Cmd is NULL")); + cmd->opcode = AMDVI_INVD_DTE_OPCODE; + cmd->word0 = devid; + amdvi_update_cmd_tail(softc); +#ifdef AMDVI_DEBUG_CMD + device_printf(softc->dev, "Invalidated DTE:0x%x\n", devid); +#endif +} + +/* Invalidate IOMMU page, use for invalidation of domain. */ +static void +amdvi_cmd_inv_iommu_pages(struct amdvi_softc *softc, uint16_t domain_id, + uint64_t addr, bool guest_nested, + bool pde, bool page) +{ + struct amdvi_cmd *cmd; + + cmd = amdvi_get_cmd_tail(softc); + KASSERT(cmd != NULL, ("Cmd is NULL")); + + + cmd->opcode = AMDVI_INVD_PAGE_OPCODE; + cmd->word1 = domain_id; + /* + * Invalidate all addresses for this domain. + */ + cmd->addr = addr; + cmd->addr |= pde ? AMDVI_INVD_PAGE_PDE : 0; + cmd->addr |= page ? AMDVI_INVD_PAGE_S : 0; + + amdvi_update_cmd_tail(softc); +} + +#ifdef AMDVI_ATS_ENABLE +/* Invalidate device IOTLB. */ +static void +amdvi_cmd_inv_iotlb(struct amdvi_softc *softc, uint16_t devid) +{ + struct amdvi_cmd *cmd; + int qlen; + + if (!softc->iotlb) + return; + + qlen = amdvi_find_ats_qlen(devid); + if (qlen < 0) { + panic("AMDVI: Invalid ATS qlen(%d) for device %d.%d.%d\n", + qlen, RID2PCI_STR(devid)); + } + cmd = amdvi_get_cmd_tail(softc); + KASSERT(cmd != NULL, ("Cmd is NULL")); + +#ifdef AMDVI_DEBUG_CMD + device_printf(softc->dev, "Invalidate IOTLB devID 0x%x" + " Qlen:%d\n", devid, qlen); +#endif + cmd->opcode = AMDVI_INVD_IOTLB_OPCODE; + cmd->word0 = devid; + cmd->word1 = qlen; + cmd->addr = AMDVI_INVD_IOTLB_ALL_ADDR | + AMDVI_INVD_IOTLB_S; + amdvi_update_cmd_tail(softc); +} +#endif + +#ifdef notyet /* For Interrupt Remap. */ +static void +amdvi_cmd_inv_intr_map(struct amdvi_softc *softc, + uint16_t devid) +{ + struct amdvi_cmd *cmd; + + cmd = amdvi_get_cmd_tail(softc); + KASSERT(cmd != NULL, ("Cmd is NULL")); + cmd->opcode = AMDVI_INVD_INTR_OPCODE; + cmd->word0 = devid; + amdvi_update_cmd_tail(softc); +#ifdef AMDVI_DEBUG_CMD + device_printf(softc->dev, "Invalidate INTR map of devID 0x%x\n", devid); +#endif +} +#endif + +/* Invalidate domain using INVALIDATE_IOMMU_PAGES command. */ +static void +amdvi_inv_domain(struct amdvi_softc *softc, uint16_t domain_id) +{ + struct amdvi_cmd *cmd; + + cmd = amdvi_get_cmd_tail(softc); + KASSERT(cmd != NULL, ("Cmd is NULL")); + + /* + * See section 3.3.3 of IOMMU spec rev 2.0, software note + * for invalidating domain. + */ + amdvi_cmd_inv_iommu_pages(softc, domain_id, AMDVI_INVD_PAGE_ALL_ADDR, + false, true, true); + +#ifdef AMDVI_DEBUG_CMD + device_printf(softc->dev, "Invalidate domain:0x%x\n", domain_id); + +#endif +} + +static bool +amdvi_cmp_wait(struct amdvi_softc *softc) +{ + struct amdvi_ctrl *ctrl; + const uint64_t VERIFY = 0xA5A5; + volatile uint64_t *read; + int i; + bool status; + + ctrl = softc->ctrl; + read = &softc->cmp_data; + *read = 0; + amdvi_cmd_cmp(softc, VERIFY); + /* Wait for h/w to update completion data. */ + for (i = 0; i < 100 && (*read != VERIFY); i++) { + DELAY(1000); /* 1 ms */ + } + status = (VERIFY == softc->cmp_data) ? true : false; + +#ifdef AMDVI_DEBUG_CMD + if (status) + device_printf(softc->dev, "CMD completion DONE Tail:0x%x, + "Head:0x%x, loop:%d.\n", ctrl->cmd_tail, + ctrl->cmd_head, loop); +#endif + return (status); +} + +static void +amdvi_wait(struct amdvi_softc *softc) +{ + struct amdvi_ctrl *ctrl; + int i; + + KASSERT(softc, ("softc is NULL")); + + ctrl = softc->ctrl; + KASSERT(ctrl != NULL, ("ctrl is NULL")); + /* Don't wait if h/w is not enabled. */ + if ((ctrl->control & AMDVI_CTRL_EN) == 0) + return; + + for (i = 0; i < 10; i++) { + if (amdvi_cmp_wait(softc)) + return; + } + + device_printf(softc->dev, "Error: completion failed" + " tail:0x%x, head:0x%x.\n", + ctrl->cmd_tail, ctrl->cmd_head); + amdvi_dump_cmds(softc); +} + +static void +amdvi_dump_cmds(struct amdvi_softc *softc) +{ + struct amdvi_ctrl *ctrl; + struct amdvi_cmd *cmd; + int off, i; + + ctrl = softc->ctrl; + device_printf(softc->dev, "Dump all the commands:\n"); + /* + * If h/w is stuck in completion, it is the previous command, + * start dumping from previous command onward. + */ + off = MOD_DEC(ctrl->cmd_head, sizeof(struct amdvi_cmd), + softc->cmd_max); + for (i = 0; off != ctrl->cmd_tail && + i < softc->cmd_max; i++) { + cmd = (struct amdvi_cmd *)((uint8_t *)softc->cmd + off); + printf(" [CMD%d, off:0x%x] opcode= 0x%x 0x%x" + " 0x%x 0x%lx\n", i, off, cmd->opcode, + cmd->word0, cmd->word1, cmd->addr); + off = (off + sizeof(struct amdvi_cmd)) % + (softc->cmd_max * sizeof(struct amdvi_cmd)); + } +} + +static int +amdvi_init_event(struct amdvi_softc *softc) +{ + struct amdvi_ctrl *ctrl; + + ctrl = softc->ctrl; + ctrl->event.len = 8; + softc->event_max = 1 << ctrl->event.len; + softc->event = malloc(sizeof(struct amdvi_event) * + softc->event_max, M_AMDVI, M_WAITOK | M_ZERO); + if ((uintptr_t)softc->event & PAGE_MASK) { + device_printf(softc->dev, "Event buffer not aligned on page."); + return (false); + } + ctrl->event.base = vtophys(softc->event) / PAGE_SIZE; + + /* Reset the pointers. */ + ctrl->evt_head = 0; + ctrl->evt_tail = 0; + + return (0); +} + +static inline void +amdvi_decode_evt_flag(uint16_t flag) +{ + + flag &= AMDVI_EVENT_FLAG_MASK; + printf("0x%b]\n", flag, + "\020" + "\001GN" + "\002NX" + "\003US" + "\004I" + "\005PR" + "\006RW" + "\007PE" + "\010RZ" + "\011TR" + ); +} + +/* See section 2.5.4 of AMD IOMMU spec ver 2.62.*/ +static inline void +amdvi_decode_evt_flag_type(uint8_t type) +{ + + switch (AMDVI_EVENT_FLAG_TYPE(type)) { + case 0: + printf("RSVD\n"); + break; + case 1: + printf("Master Abort\n"); + break; + case 2: + printf("Target Abort\n"); + break; + case 3: + printf("Data Err\n"); + break; + default: + break; + } +} + +static void +amdvi_decode_inv_dte_evt(uint16_t devid, uint16_t domid, uint64_t addr, + uint16_t flag) +{ + + printf("\t[IO_PAGE_FAULT EVT: devId:0x%x DomId:0x%x" + " Addr:0x%lx", + devid, domid, addr); + amdvi_decode_evt_flag(flag); +} + +static void +amdvi_decode_pf_evt(uint16_t devid, uint16_t domid, uint64_t addr, + uint16_t flag) +{ + + printf("\t[IO_PAGE_FAULT EVT: devId:0x%x DomId:0x%x" + " Addr:0x%lx", + devid, domid, addr); + amdvi_decode_evt_flag(flag); +} + +static void +amdvi_decode_dte_hwerr_evt(uint16_t devid, uint16_t domid, + uint64_t addr, uint16_t flag) +{ + + printf("\t[DEV_TAB_HW_ERR EVT: devId:0x%x DomId:0x%x" + " Addr:0x%lx", devid, domid, addr); + amdvi_decode_evt_flag(flag); + amdvi_decode_evt_flag_type(flag); +} + +static void +amdvi_decode_page_hwerr_evt(uint16_t devid, uint16_t domid, uint64_t addr, + uint16_t flag) +{ + + printf("\t[PAGE_TAB_HW_ERR EVT: devId:0x%x DomId:0x%x" + " Addr:0x%lx", devid, domid, addr); + amdvi_decode_evt_flag(flag); + amdvi_decode_evt_flag_type(AMDVI_EVENT_FLAG_TYPE(flag)); +} + +static void +amdvi_decode_evt(struct amdvi_event *evt) +{ + struct amdvi_cmd *cmd; + + switch (evt->opcode) { + case AMDVI_EVENT_INVALID_DTE: + amdvi_decode_inv_dte_evt(evt->devid, evt->pasid_domid, + evt->addr, evt->flag); + break; + + case AMDVI_EVENT_PFAULT: + amdvi_decode_pf_evt(evt->devid, evt->pasid_domid, + evt->addr, evt->flag); + break; + + case AMDVI_EVENT_DTE_HW_ERROR: + amdvi_decode_dte_hwerr_evt(evt->devid, evt->pasid_domid, + evt->addr, evt->flag); + break; + + case AMDVI_EVENT_PAGE_HW_ERROR: + amdvi_decode_page_hwerr_evt(evt->devid, evt->pasid_domid, + evt->addr, evt->flag); + break; + + case AMDVI_EVENT_ILLEGAL_CMD: + /* FALL THROUGH */ + case AMDVI_EVENT_CMD_HW_ERROR: + printf("\t[%s EVT]", (evt->opcode == AMDVI_EVENT_ILLEGAL_CMD) ? + "ILLEGAL CMD" : "CMD HW ERR"); + cmd = (struct amdvi_cmd *)PHYS_TO_DMAP(evt->addr); + printf("\tCMD opcode= 0x%x 0x%x 0x%x 0x%lx\n", + cmd->opcode, cmd->word0, cmd->word1, cmd->addr); + break; + + case AMDVI_EVENT_IOTLB_TIMEOUT: + printf("\t[IOTLB_INV_TIMEOUT devid:0x%x addr:0x%lx", + evt->devid, evt->addr); + break; + + case AMDVI_EVENT_INVALID_DTE_REQ: + printf("\t[INV_DTE devid:0x%x addr:0x%lx", + evt->devid, evt->addr); + break; + + case AMDVI_EVENT_INVALID_PPR_REQ: + case AMDVI_EVENT_COUNTER_ZERO: + printf("AMD-Vi: v2 events.\n"); + break; + + default: + printf("Unsupported AMD-Vi event:%d", evt->opcode); + } +} + +static void +amdvi_print_events(struct amdvi_softc *softc) +{ + struct amdvi_ctrl *ctrl; + struct amdvi_event *event; + int i, size; + + ctrl = softc->ctrl; + size = sizeof(struct amdvi_event); + for (i = 0; i < softc->event_max; i++) { + event = &softc->event[ctrl->evt_head / size]; + if (!event->opcode) + break; + device_printf(softc->dev, "\t[Event%d: Head:0x%x Tail:0x%x]\n", + i, ctrl->evt_head, ctrl->evt_tail); + amdvi_decode_evt(event); + ctrl->evt_head = MOD_INC(ctrl->evt_head, size, + softc->event_max); + } +} + +static int +amdvi_init_dte(struct amdvi_softc *softc) +{ + struct amdvi_ctrl *ctrl; + + ctrl = softc->ctrl; + ctrl->dte.base = vtophys(amdvi_dte) / PAGE_SIZE; + ctrl->dte.size = 0x1FF; /* 2MB device table. */ + + return (0); +} + +/* + * Not all capabilities of IOMMU are available in ACPI IVHD flag + * or EFR entry, read directly from device. + */ +static int +amdvi_print_pci_cap(device_t dev) +{ + struct amdvi_softc *softc; + uint32_t off, cap; + + + softc = device_get_softc(dev); + off = softc->cap_off; + + /* + * Section 3.7.1 of IOMMU sepc rev 2.0. + * Read capability from device. + */ + cap = amdvi_pci_read(softc, off); + + /* Make sure capability type[18:16] is 3. */ + KASSERT((((cap >> 16) & 0x7) == 0x3), + ("Not a IOMMU capability 0x%x@0x%x", cap, off)); + + softc->pci_cap = cap >> 24; + device_printf(softc->dev, "PCI cap 0x%x@0x%x feature:%b\n", + cap, off, softc->pci_cap, + "\020\001IOTLB\002HT\003NPCache\004EFR"); + + /* IOMMU spec Rev 2.0, section 3.7.2.1 */ + softc->pci_efr = softc->ctrl->ex_feature; + if (softc->pci_efr) { + device_printf(softc->dev, "PCI extended Feature:%b\n", + (int)softc->pci_efr, + "\020\001PreFSup\002PPRSup\003XTSup\004NXSup\006IASup" + "\007GASup\008HESup\009PCSup"); + device_printf(softc->dev, + "PCI HATS = %d GATS = %d GLXSup = %d, max PASID: 0x%x ", + (int)((softc->pci_efr >> 10) & 0x3), + (int)((softc->pci_efr >> 12) & 0x3), + (int)((softc->pci_efr >> 14) & 0x3), + (int)((softc->pci_efr >> 32) & 0x1F) + 1); + } + + return (0); +} + +static void +amdvi_event_intr(void *arg) +{ + struct amdvi_softc *softc; + struct amdvi_ctrl *ctrl; + + softc = (struct amdvi_softc *)arg; + ctrl = softc->ctrl; + device_printf(softc->dev, "EVT INTR %ld Status:0x%x" + " EVT Head:0x%x Tail:0x%x]\n", softc->event_intr_cnt++, + ctrl->status, ctrl->evt_head, ctrl->evt_tail); + printf(" [CMD Total 0x%lx] Tail:0x%x, Head:0x%x.\n", + softc->total_cmd, ctrl->cmd_tail, ctrl->cmd_head); + + amdvi_print_events(softc); +} + +static void +amdvi_free_evt_intr_res(device_t dev) +{ + + struct amdvi_softc *softc; + + softc = device_get_softc(dev); + if (softc->event_tag != NULL) { + bus_teardown_intr(dev, softc->event_res, softc->event_tag); + } + if (softc->event_res != NULL) { + bus_release_resource(dev, SYS_RES_IRQ, softc->event_rid, + softc->event_res); + } + bus_delete_resource(dev, SYS_RES_IRQ, softc->event_rid); + PCIB_RELEASE_MSI(device_get_parent(device_get_parent(dev)), + dev, 1, &softc->event_irq); +} + +static bool +amdvi_alloc_intr_resources(struct amdvi_softc *softc) +{ + device_t dev, pcib; + uint64_t msi_addr; + uint32_t msi_data, temp; + int err, msi_off; + + dev = softc->dev; + pcib = device_get_parent(device_get_parent(dev)); + softc->event_irq = -1; + softc->event_rid = 0; + /* + * Section 3.7.1 of IOMMU rev 2.0. With MSI, there is only one + * interrupt. XXX: Enable MSI/X support. + */ + + err = PCIB_ALLOC_MSI(pcib, dev, 1, 1, &softc->event_irq); + if (err) { + device_printf(dev, + "Couldn't find event MSI IRQ resource.\n"); + return (ENOENT); + } + err = bus_set_resource(dev, SYS_RES_IRQ, softc->event_rid, + softc->event_irq, 1); + if (err) { + device_printf(dev, "Couldn't set event MSI resource.\n"); + return (ENXIO); + } + softc->event_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, + &softc->event_rid, RF_ACTIVE); + if (!softc->event_res) { + device_printf(dev, + "Unable to allocate event INTR resource.\n"); + return (ENOMEM); + } + + if (bus_setup_intr(dev, softc->event_res, + INTR_TYPE_MISC | INTR_MPSAFE, NULL, amdvi_event_intr, + softc, &softc->event_tag)) { + device_printf(dev, "Fail to setup event intr\n"); + bus_release_resource(softc->dev, SYS_RES_IRQ, + softc->event_rid, softc->event_res); + softc->event_res = NULL; + return (ENXIO); + } + + bus_describe_intr(dev, softc->event_res, softc->event_tag, + "fault"); + + err = amdvi_find_pci_cap(softc, PCIY_MSI, &msi_off); + if (err) { + device_printf(dev, "Couldn't find MSI capability, err = %d.\n", + err); + return (err); + } + + err = PCIB_MAP_MSI(pcib, dev, softc->event_irq, &msi_addr, + &msi_data); + if (err) { + device_printf(dev, + "Event interrupt config failed, err=%d.\n", + err); + amdvi_free_evt_intr_res(softc->dev); + return (err); + } + + /* Configure MSI */ + amdvi_pci_write(softc, msi_off + PCIR_MSI_ADDR, msi_addr); + amdvi_pci_write(softc, msi_off + PCIR_MSI_ADDR_HIGH, + msi_addr >> 32); + amdvi_pci_write(softc, msi_off + PCIR_MSI_DATA_64BIT, msi_data); + + /* Now enable MSI interrupt. */ + temp = amdvi_pci_read(softc, msi_off); + temp |= (PCIM_MSICTRL_MSI_ENABLE << 16); /* MSI enable. */ + amdvi_pci_write(softc, msi_off, temp); + + return (0); +} + + +static void +amdvi_print_dev_cap(struct amdvi_softc *softc) +{ + struct ivhd_dev_cfg *cfg; + int i; + + cfg = softc->dev_cfg; + for (i = 0; i < softc->dev_cfg_cnt; i++) { + device_printf(softc->dev, "device [0x%x - 0x%x]" + "config:%b%s\n", cfg->start_id, cfg->end_id, + cfg->data, + "\020\001INIT\002ExtInt\003NMI" + "\007LINT0\008LINT1", + cfg->enable_ats ? "ATS enabled" : ""); + cfg++; + } +} + +static int +amdvi_handle_sysctl(SYSCTL_HANDLER_ARGS) +{ + struct amdvi_softc *softc; + int result, type, error = 0; + + softc = (struct amdvi_softc *)arg1; + type = arg2; + + switch (type) { + case 0: + result = softc->ctrl->cmd_head; + error = sysctl_handle_int(oidp, &result, 0, + req); + break; + case 1: + result = softc->ctrl->cmd_tail; + error = sysctl_handle_int(oidp, &result, 0, + req); + break; + case 2: + result = softc->ctrl->evt_head; + error = sysctl_handle_int(oidp, &result, 0, + req); + break; + case 3: + result = softc->ctrl->evt_tail; + error = sysctl_handle_int(oidp, &result, 0, + req); + break; + + default: + device_printf(softc->dev, "Unknown sysctl:%d\n", type); + } + + return (error); +} + +static void +amdvi_add_sysctl(struct amdvi_softc *softc) +{ + struct sysctl_oid_list *child; + struct sysctl_ctx_list *ctx; + device_t dev; + + dev = softc->dev; + ctx = device_get_sysctl_ctx(dev); + child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); + + SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "event_intr_count", CTLFLAG_RD, + &softc->event_intr_cnt, "Event interrupt count"); + SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "command_count", CTLFLAG_RD, + &softc->total_cmd, "Command submitted count"); + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "pci_rid", CTLFLAG_RD, + (int *)&softc->pci_rid, 0, + "IOMMU RID"); + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "start_dev_rid", CTLFLAG_RD, + (int *)&softc->start_dev_rid, 0, + "Start of device under this IOMMU"); + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "end_dev_rid", CTLFLAG_RD, + (int *)&softc->end_dev_rid, 0, + "End of device under this IOMMU"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "command_head", + CTLTYPE_UINT | CTLFLAG_RD, softc, 0, + amdvi_handle_sysctl, "IU", "Command head"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "command_tail", + CTLTYPE_UINT | CTLFLAG_RD, softc, 1, + amdvi_handle_sysctl, "IU", "Command tail"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "event_head", + CTLTYPE_UINT | CTLFLAG_RD, softc, 2, + amdvi_handle_sysctl, "IU", "Command head"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "event_tail", + CTLTYPE_UINT | CTLFLAG_RD, softc, 3, + amdvi_handle_sysctl, "IU", "Command tail"); +} + +int +amdvi_setup_hw(struct amdvi_softc *softc) +{ + device_t dev; + int status; + + dev = softc->dev; + + amdvi_hw_enable_iotlb(softc); + + amdvi_print_dev_cap(softc); + + if ((status = amdvi_print_pci_cap(dev)) != 0) { + device_printf(dev, "PCI capability.\n"); + return (status); + } + if ((status = amdvi_init_cmd(softc)) != 0) { + device_printf(dev, "Couldn't configure command buffer.\n"); + return (status); + } + if ((status = amdvi_init_event(softc)) != 0) { + device_printf(dev, "Couldn't configure event buffer.\n"); + return (status); + } + if ((status = amdvi_init_dte(softc)) != 0) { + device_printf(dev, "Couldn't configure device table.\n"); + return (status); + } + if ((status = amdvi_alloc_intr_resources(softc)) != 0) { + return (status); + } + amdvi_add_sysctl(softc); + return (0); +} + +int +amdvi_teardown_hw(struct amdvi_softc *softc) +{ + device_t dev; + + dev = softc->dev; + + /* + * Called after disable, h/w is stopped by now, free all the resources. + */ + amdvi_free_evt_intr_res(dev); + + if (softc->cmd) + free(softc->cmd, M_AMDVI); + + if (softc->event) + free(softc->event, M_AMDVI); + + return (0); +} + +/*********** bhyve interfaces *********************/ +static int +amdvi_init(void) +{ + if (!ivhd_count) { + return (EIO); + } + if (!amdvi_enable_user && ivhd_count) { + printf("bhyve: Found %d AMD-Vi/IOMMU device(s), " + "use hw.vmm.amdvi_enable=1 to enable pass-through.\n", + ivhd_count); + return (EINVAL); + } + return (0); +} + +static void +amdvi_cleanup(void) +{ + /* Nothing. */ +} + +static uint16_t +amdvi_domainId(void) +{ + + /* + * If we hit maximum domain limit, rollover leaving host + * domain(0). + * XXX: make sure that this domain is not used. + */ + if (amdvi_dom_id == AMDVI_MAX_DOMAIN) + amdvi_dom_id = 1; + + return ((uint16_t)amdvi_dom_id++); +} + +static void +amdvi_do_inv_domain(uint16_t domain_id, bool create) +{ + struct amdvi_softc *softc; + int i; + + for (i = 0; i < ivhd_count; i++) { + softc = device_get_softc(ivhd_devs[i]); + KASSERT(softc, ("softc is NULL")); + /* + * If not present pages are cached, invalidate page after + * creating domain. + */ +#if 0 + if (create && ((softc->pci_cap & AMDVI_PCI_CAP_NPCACHE) == 0)) + continue; +#endif + amdvi_inv_domain(softc, domain_id); + amdvi_wait(softc); + } +} + +static void * +amdvi_create_domain(vm_paddr_t maxaddr) +{ + struct amdvi_domain *dom; + + dom = malloc(sizeof(struct amdvi_domain), M_AMDVI, M_ZERO | M_WAITOK); + dom->id = amdvi_domainId(); + //dom->maxaddr = maxaddr; +#ifdef AMDVI_DEBUG_CMD + printf("Created domain #%d\n", dom->id); +#endif + /* + * Host domain(#0) don't create translation table. + */ + if (dom->id || amdvi_host_ptp) + dom->ptp = malloc(PAGE_SIZE, M_AMDVI, M_WAITOK | M_ZERO); + + dom->ptp_level = amdvi_ptp_level; + + amdvi_do_inv_domain(dom->id, true); + SLIST_INSERT_HEAD(&dom_head, dom, next); + + return (dom); +} + +static void +amdvi_free_ptp(uint64_t *ptp, int level) +{ + int i; + + if (level < 1) + return; + + for (i = 0; i < NPTEPG ; i++) { + if ((ptp[i] & AMDVI_PT_PRESENT) == 0) + continue; + /* XXX: Add super-page or PTE mapping > 4KB. */ +#ifdef notyet + /* Super-page mapping. */ + if (AMDVI_PD_SUPER(ptp[i])) + continue; +#endif + + amdvi_free_ptp((uint64_t *)PHYS_TO_DMAP(ptp[i] + & AMDVI_PT_MASK), level - 1); + + } + + free(ptp, M_AMDVI); +} + +static void +amdvi_destroy_domain(void *arg) +{ + struct amdvi_domain *domain; + + domain = (struct amdvi_domain *)arg; + KASSERT(domain, ("domain is NULL")); +#ifdef AMDVI_DEBUG_CMD + printf("Destroying domain %d\n", domain->id); +#endif + if (domain->ptp) + amdvi_free_ptp(domain->ptp, domain->ptp_level); + + amdvi_do_inv_domain(domain->id, false); + SLIST_REMOVE(&dom_head, domain, amdvi_domain, next); + free(domain, M_AMDVI); +} + +static uint64_t +amdvi_set_pt(uint64_t *pt, int level, vm_paddr_t gpa, + vm_paddr_t hpa, uint64_t pg_size, bool create) +{ + uint64_t *page, pa; + int shift, index; + const int PT_SHIFT = 9; + const int PT_INDEX_MASK = (1 << PT_SHIFT) - 1; /* Based on PT_SHIFT */ + + if (!pg_size) + return (0); + + if (hpa & (pg_size - 1)) { + printf("HPA is not size aligned.\n"); + return (0); + } + if (gpa & (pg_size - 1)) { + printf("HPA is not size aligned.\n"); + return (0); + } + shift = PML4SHIFT; + while ((shift > PAGE_SHIFT) && (pg_size < (1UL << shift))) { + index = (gpa >> shift) & PT_INDEX_MASK; + + if ((pt[index] == 0) && create) { + page = malloc(PAGE_SIZE, M_AMDVI, M_WAITOK | M_ZERO); + pa = vtophys(page); + pt[index] = pa | AMDVI_PT_PRESENT | AMDVI_PT_RW | + ((level - 1) << AMDVI_PD_LEVEL_SHIFT); + } +#ifdef AMDVI_DEBUG_PTE + if ((gpa % 0x1000000) == 0) + printf("[level%d, shift = %d]PTE:0x%lx\n", + level, shift, pt[index]); +#endif +#define PTE2PA(x) ((uint64_t)(x) & AMDVI_PT_MASK) + pa = PTE2PA(pt[index]); + pt = (uint64_t *)PHYS_TO_DMAP(pa); + shift -= PT_SHIFT; + level--; + } + + /* Leaf entry. */ + index = (gpa >> shift) & PT_INDEX_MASK; + + if (create) { + pt[index] = hpa | AMDVI_PT_RW | AMDVI_PT_PRESENT; + } else + pt[index] = 0; + +#ifdef AMDVI_DEBUG_PTE + if ((gpa % 0x1000000) == 0) + printf("[Last level%d, shift = %d]PTE:0x%lx\n", + level, shift, pt[index]); +#endif + return (1ULL << shift); +} + +static uint64_t +amdvi_update_mapping(struct amdvi_domain *domain, vm_paddr_t gpa, + vm_paddr_t hpa, uint64_t size, bool create) +{ + uint64_t mapped, *ptp, len; + int level; + + KASSERT(domain, ("domain is NULL")); + level = domain->ptp_level; + KASSERT(level, ("Page table level is 0")); + + ptp = domain->ptp; + KASSERT(ptp, ("PTP is NULL")); + mapped = 0; + while (mapped < size) { + len = amdvi_set_pt(ptp, level, gpa + mapped, hpa + mapped, + PAGE_SIZE, create); + if (!len) { + printf("Error: Couldn't map HPA:0x%lx GPA:0x%lx\n", + hpa, gpa); + return (0); + } + mapped += len; + } + + return (mapped); +} + +static uint64_t +amdvi_create_mapping(void *arg, vm_paddr_t gpa, vm_paddr_t hpa, + uint64_t len) +{ + struct amdvi_domain *domain; + + domain = (struct amdvi_domain *)arg; + + if (domain->id && !domain->ptp) { + printf("ptp is NULL"); + return (-1); + } + + /* + * If host domain is created w/o page table, skip IOMMU page + * table set-up. + */ + if (domain->ptp) + return (amdvi_update_mapping(domain, gpa, hpa, len, true)); + else + return (len); +} + +static uint64_t +amdvi_destroy_mapping(void *arg, vm_paddr_t gpa, uint64_t len) +{ + struct amdvi_domain *domain; + + domain = (struct amdvi_domain *)arg; + /* + * If host domain is created w/o page table, skip IOMMU page + * table set-up. + */ + if (domain->ptp) + return (amdvi_update_mapping(domain, gpa, 0, len, false)); + return + (len); +} + +static struct amdvi_softc * +amdvi_find_iommu(uint16_t devid) +{ + struct amdvi_softc *softc; + int i; + + for (i = 0; i < ivhd_count; i++) { + softc = device_get_softc(ivhd_devs[i]); + if ((devid >= softc->start_dev_rid) && + (devid <= softc->end_dev_rid)) + return (softc); + } + + /* + * XXX: BIOS bug, device not in IVRS table, assume its from first IOMMU. + */ + printf("BIOS bug device(%d.%d.%d) doesn't have IVHD entry.\n", + RID2PCI_STR(devid)); + + return (device_get_softc(ivhd_devs[0])); +} + +/* + * Set-up device table entry. + * IOMMU spec Rev 2.0, section 3.2.2.2, some of the fields must + * be set concurrently, e.g. read and write bits. + */ +static void +amdvi_set_dte(struct amdvi_domain *domain, uint16_t devid, bool enable) +{ + struct amdvi_softc *softc; + struct amdvi_dte temp; + + softc = amdvi_find_iommu(devid); + KASSERT(softc, ("softc is NULL for pci_rid:0x%x\n", devid)); + + memset(&temp, 0, sizeof(struct amdvi_dte)); + +#ifdef AMDVI_ATS_ENABLE + /* If IOMMU and device support IOTLB, enable it. */ + if (amdvi_dev_support_iotlb(softc, devid) && softc->iotlb) + temp.iotlb_enable = 1; +#endif + + /* Avoid duplicate I/O faults. */ + temp.sup_second_io_fault = 1; + temp.sup_all_io_fault = amdvi_disable_io_fault; + + temp.dt_valid = 1; + temp.domain_id = domain->id; + + if (enable) { + if (domain->ptp) { + temp.pt_base = vtophys(domain->ptp) >> 12; + temp.pt_level = amdvi_ptp_level; + } + /* + * XXX: Page table valid[TV] bit must be set even if host domain + * page tables are not enabled. + */ + temp.pt_valid = 1; + temp.read_allow = 1; + temp.write_allow = 1; + } + amdvi_dte[devid] = temp; +} + +static void +amdvi_inv_device(uint16_t devid) +{ + struct amdvi_softc *softc; + + softc = amdvi_find_iommu(devid); + KASSERT(softc, ("softc is NULL")); + + amdvi_cmd_inv_dte(softc, devid); +#ifdef AMDVI_ATS_ENABLE + if (amdvi_dev_support_iotlb(softc, devid)) + amdvi_cmd_inv_iotlb(softc, devid); +#endif + amdvi_wait(softc); +} + +static void +amdvi_add_device(void *arg, uint16_t devid) +{ + struct amdvi_domain *domain; + + domain = (struct amdvi_domain *)arg; + KASSERT(domain != NULL, ("domain is NULL")); +#ifdef AMDVI_DEBUG_CMD + printf("Assigning device(%d.%d.%d) to domain:%d\n", + RID2PCI_STR(devid), domain->id); +#endif + amdvi_set_dte(domain, devid, true); + amdvi_inv_device(devid); +} + +static void +amdvi_remove_device(void *arg, uint16_t devid) +{ + struct amdvi_domain *domain; + + domain = (struct amdvi_domain *)arg; +#ifdef AMDVI_DEBUG_CMD + printf("Remove device(0x%x) from domain:%d\n", + devid, domain->id); +#endif + amdvi_set_dte(domain, devid, false); + amdvi_inv_device(devid); +} + +static void +amdvi_enable(void) +{ + struct amdvi_ctrl *ctrl; + struct amdvi_softc *softc; + uint64_t val; + int i; + + for (i = 0; i < ivhd_count; i++) { + softc = device_get_softc(ivhd_devs[i]); + KASSERT(softc, ("softc is NULL\n")); + ctrl = softc->ctrl; + KASSERT(ctrl, ("ctrl is NULL\n")); + + val = ( AMDVI_CTRL_EN | + AMDVI_CTRL_CMD | + AMDVI_CTRL_ELOG | + AMDVI_CTRL_ELOGINT | + AMDVI_CTRL_INV_TO_1S); + + if (softc->ivhd_flag & IVHD_FLAG_COH) + val |= AMDVI_CTRL_COH; + if (softc->ivhd_flag & IVHD_FLAG_HTT) + val |= AMDVI_CTRL_HTT; + if (softc->ivhd_flag & IVHD_FLAG_RPPW) + val |= AMDVI_CTRL_RPPW; + if (softc->ivhd_flag & IVHD_FLAG_PPW) + val |= AMDVI_CTRL_PPW; + if (softc->ivhd_flag & IVHD_FLAG_ISOC) + val |= AMDVI_CTRL_ISOC; + + ctrl->control = val; + } +} + +static void +amdvi_disable(void) +{ + struct amdvi_ctrl *ctrl; + struct amdvi_softc *softc; + int i; + + for (i = 0; i < ivhd_count; i++) { + softc = device_get_softc(ivhd_devs[i]); + KASSERT(softc, ("softc is NULL\n")); + ctrl = softc->ctrl; + KASSERT(ctrl, ("ctrl is NULL\n")); + + ctrl->control = 0; + } +} + +static void +amdvi_inv_tlb(void *arg) +{ + struct amdvi_domain *domain; + + domain = (struct amdvi_domain *)arg; + KASSERT(domain, ("domain is NULL")); + amdvi_do_inv_domain(domain->id, false); +} + +struct iommu_ops iommu_ops_amd = { + amdvi_init, + amdvi_cleanup, + amdvi_enable, + amdvi_disable, + amdvi_create_domain, + amdvi_destroy_domain, + amdvi_create_mapping, + amdvi_destroy_mapping, + amdvi_add_device, + amdvi_remove_device, + amdvi_inv_tlb +}; diff --git a/sys/amd64/vmm/amd/amdvi_priv.h b/sys/amd64/vmm/amd/amdvi_priv.h new file mode 100755 index 00000000000..990b6f7bfd1 --- /dev/null +++ b/sys/amd64/vmm/amd/amdvi_priv.h @@ -0,0 +1,395 @@ +/*- + * Copyright (c) 2016 Anish Gupta (anish@freebsd.org) + * All rights reserved. + * + * 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 unmodified, 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 ``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 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. + * + * $FreeBSD$ + */ + +#ifndef _AMDVI_PRIV_H_ +#define _AMDVI_PRIV_H_ + +#define BIT(n) (1ULL << (n)) +/* Return value of bits[n:m] where n and (n >= ) m are bit positions. */ +#define REG_BITS(x, n, m) (((x) >> (m)) & \ + ((1 << (((n) - (m)) + 1)) - 1)) + +/* + * IOMMU PCI capability. + */ +#define AMDVI_PCI_CAP_IOTLB BIT(0) /* IOTLB is supported. */ +#define AMDVI_PCI_CAP_HT BIT(1) /* HyperTransport tunnel support. */ +#define AMDVI_PCI_CAP_NPCACHE BIT(2) /* Not present page cached. */ +#define AMDVI_PCI_CAP_EFR BIT(3) /* Extended features. */ +#define AMDVI_PCI_CAP_EXT BIT(4) /* Miscellaneous information reg. */ + +/* + * IOMMU extended features. + */ +#define AMDVI_EX_FEA_PREFSUP BIT(0) /* Prefetch command support. */ +#define AMDVI_EX_FEA_PPRSUP BIT(1) /* PPR support */ +#define AMDVI_EX_FEA_XTSUP BIT(2) /* Reserved */ +#define AMDVI_EX_FEA_NXSUP BIT(3) /* No-execute. */ +#define AMDVI_EX_FEA_GTSUP BIT(4) /* Guest translation support. */ +#define AMDVI_EX_FEA_EFRW BIT(5) /* Reserved */ +#define AMDVI_EX_FEA_IASUP BIT(6) /* Invalidate all command supp. */ +#define AMDVI_EX_FEA_GASUP BIT(7) /* Guest APIC or AVIC support. */ +#define AMDVI_EX_FEA_HESUP BIT(8) /* Hardware Error. */ +#define AMDVI_EX_FEA_PCSUP BIT(9) /* Performance counters support. */ +/* XXX: add more EFER bits. */ + +/* + * Device table entry or DTE + * NOTE: Must be 256-bits/32 bytes aligned. + */ +struct amdvi_dte { + uint32_t dt_valid:1; /* Device Table valid. */ + uint32_t pt_valid:1; /* Page translation valid. */ + uint8_t :7; /* Reserved[8:2] */ + uint8_t pt_level:3; /* Paging level, 0 to disable. */ + uint64_t pt_base:40; /* Page table root pointer. */ + uint8_t :3; /* Reserved[54:52] */ + uint8_t gv_valid:1; /* Revision 2, GVA to SPA. */ + uint8_t gv_level:2; /* Revision 2, GLX level. */ + uint8_t gv_cr3_lsb:3; /* Revision 2, GCR3[14:12] */ + uint8_t read_allow:1; /* I/O read enabled. */ + uint8_t write_allow:1; /* I/O write enabled. */ + uint8_t :1; /* Reserved[63] */ + uint16_t domain_id:16; /* Domain ID */ + uint16_t gv_cr3_lsb2:16; /* Revision 2, GCR3[30:15] */ + uint8_t iotlb_enable:1; /* Device support IOTLB */ + uint8_t sup_second_io_fault:1; /* Suppress subsequent I/O faults. */ + uint8_t sup_all_io_fault:1; /* Suppress all I/O page faults. */ + uint8_t IOctl:2; /* Port I/O control. */ + uint8_t iotlb_cache_disable:1; /* IOTLB cache hints. */ + uint8_t snoop_disable:1; /* Snoop disable. */ + uint8_t allow_ex:1; /* Allow exclusion. */ + uint8_t sysmgmt:2; /* System management message.*/ + uint8_t :1; /* Reserved[106] */ + uint32_t gv_cr3_msb:21; /* Revision 2, GCR3[51:31] */ + uint8_t intmap_valid:1; /* Interrupt map valid. */ + uint8_t intmap_len:4; /* Interrupt map table length. */ + uint8_t intmap_ign:1; /* Ignore unmapped interrupts. */ + uint64_t intmap_base:46; /* IntMap base. */ + uint8_t :4; /* Reserved[183:180] */ + uint8_t init_pass:1; /* INIT pass through or PT */ + uint8_t extintr_pass:1; /* External Interrupt PT */ + uint8_t nmi_pass:1; /* NMI PT */ + uint8_t :1; /* Reserved[187] */ + uint8_t intr_ctrl:2; /* Interrupt control */ + uint8_t lint0_pass:1; /* LINT0 PT */ + uint8_t lint1_pass:1; /* LINT1 PT */ + uint64_t :64; /* Reserved[255:192] */ +} __attribute__((__packed__)); +CTASSERT(sizeof(struct amdvi_dte) == 32); + +/* + * IOMMU command entry. + */ +struct amdvi_cmd { + uint32_t word0; + uint32_t word1:28; + uint8_t opcode:4; + uint64_t addr; +} __attribute__((__packed__)); + +/* Command opcodes. */ +#define AMDVI_CMP_WAIT_OPCODE 0x1 /* Completion wait. */ +#define AMDVI_INVD_DTE_OPCODE 0x2 /* Invalidate device table entry. */ +#define AMDVI_INVD_PAGE_OPCODE 0x3 /* Invalidate pages. */ +#define AMDVI_INVD_IOTLB_OPCODE 0x4 /* Invalidate IOTLB pages. */ +#define AMDVI_INVD_INTR_OPCODE 0x5 /* Invalidate Interrupt table. */ +#define AMDVI_PREFETCH_PAGES_OPCODE 0x6 /* Prefetch IOMMU pages. */ +#define AMDVI_COMP_PPR_OPCODE 0x7 /* Complete PPR request. */ +#define AMDVI_INV_ALL_OPCODE 0x8 /* Invalidate all. */ + +/* Completion wait attributes. */ +#define AMDVI_CMP_WAIT_STORE BIT(0) /* Write back data. */ +#define AMDVI_CMP_WAIT_INTR BIT(1) /* Completion wait interrupt. */ +#define AMDVI_CMP_WAIT_FLUSH BIT(2) /* Flush queue. */ + +/* Invalidate page. */ +#define AMDVI_INVD_PAGE_S BIT(0) /* Invalidation size. */ +#define AMDVI_INVD_PAGE_PDE BIT(1) /* Invalidate PDE. */ +#define AMDVI_INVD_PAGE_GN_GVA BIT(2) /* GPA or GVA. */ + +#define AMDVI_INVD_PAGE_ALL_ADDR (0x7FFFFFFFFFFFFULL << 12) + +/* Invalidate IOTLB. */ +#define AMDVI_INVD_IOTLB_S BIT(0) /* Invalidation size 4k or addr */ +#define AMDVI_INVD_IOTLB_GN_GVA BIT(2) /* GPA or GVA. */ + +#define AMDVI_INVD_IOTLB_ALL_ADDR (0x7FFFFFFFFFFFFULL << 12) +/* XXX: add more command entries. */ + +/* + * IOMMU event entry. + */ +struct amdvi_event { + uint16_t devid; + uint16_t pasid_hi; + uint16_t pasid_domid; /* PASID low or DomainID */ + uint16_t flag:12; + uint8_t opcode:4; + uint64_t addr; +} __attribute__((__packed__)); +CTASSERT(sizeof(struct amdvi_event) == 16); + +/* Various event types. */ +#define AMDVI_EVENT_INVALID_DTE 0x1 +#define AMDVI_EVENT_PFAULT 0x2 +#define AMDVI_EVENT_DTE_HW_ERROR 0x3 +#define AMDVI_EVENT_PAGE_HW_ERROR 0x4 +#define AMDVI_EVENT_ILLEGAL_CMD 0x5 +#define AMDVI_EVENT_CMD_HW_ERROR 0x6 +#define AMDVI_EVENT_IOTLB_TIMEOUT 0x7 +#define AMDVI_EVENT_INVALID_DTE_REQ 0x8 +#define AMDVI_EVENT_INVALID_PPR_REQ 0x9 +#define AMDVI_EVENT_COUNTER_ZERO 0xA + +#define AMDVI_EVENT_FLAG_MASK 0x1FF /* Mask for event flags. */ +#define AMDVI_EVENT_FLAG_TYPE(x) (((x) >> 9) & 0x3) + +/* + * IOMMU control block. + */ +struct amdvi_ctrl { + struct { + uint16_t size:9; + uint16_t :3; + uint64_t base:40; /* Devtable register base. */ + uint16_t :12; + } dte; + struct { + uint16_t :12; + uint64_t base:40; + uint8_t :4; + uint8_t len:4; + uint8_t :4; + } cmd; + struct { + uint16_t :12; + uint64_t base:40; + uint8_t :4; + uint8_t len:4; + uint8_t :4; + } event; + uint16_t control :13; + uint64_t :51; + struct { + uint8_t enable:1; + uint8_t allow:1; + uint16_t :10; + uint64_t base:40; + uint16_t :12; + uint16_t :12; + uint64_t limit:40; + uint16_t :12; + } excl; + /* + * Revision 2 only. + */ + uint64_t ex_feature; + struct { + uint16_t :12; + uint64_t base:40; + uint8_t :4; + uint8_t len:4; + uint8_t :4; + } ppr; + uint64_t first_event; + uint64_t second_event; + uint64_t event_status; + /* Revision 2 only, end. */ + uint8_t pad1[0x1FA8]; /* Padding. */ + uint32_t cmd_head:19; + uint64_t :45; + uint32_t cmd_tail:19; + uint64_t :45; + uint32_t evt_head:19; + uint64_t :45; + uint32_t evt_tail:19; + uint64_t :45; + uint64_t :56; + uint8_t status:8; + uint64_t pad2; + uint8_t :4; + uint16_t ppr_head:15; + uint64_t :45; + uint8_t :4; + uint16_t ppr_tail:15; + uint64_t :45; + uint8_t pad3[0x1FC0]; /* Padding. */ + + /* XXX: More for rev2. */ +} __attribute__((__packed__)); +CTASSERT(offsetof(struct amdvi_ctrl, pad1)== 0x58); +CTASSERT(offsetof(struct amdvi_ctrl, pad2)== 0x2028); +CTASSERT(offsetof(struct amdvi_ctrl, pad3)== 0x2040); + +#define AMDVI_MMIO_V1_SIZE (4 * PAGE_SIZE) /* v1 size */ +/* + * AMF IOMMU v2 size including event counters + */ +#define AMDVI_MMIO_V2_SIZE (8 * PAGE_SIZE) + +CTASSERT(sizeof(struct amdvi_ctrl) == 0x4000); +CTASSERT(sizeof(struct amdvi_ctrl) == AMDVI_MMIO_V1_SIZE); + +/* IVHD flag */ +#define IVHD_FLAG_HTT BIT(0) /* Hypertransport Tunnel. */ +#define IVHD_FLAG_PPW BIT(1) /* Pass posted write. */ +#define IVHD_FLAG_RPPW BIT(2) /* Response pass posted write. */ +#define IVHD_FLAG_ISOC BIT(3) /* Isoc support. */ +#define IVHD_FLAG_IOTLB BIT(4) /* IOTLB support. */ +#define IVHD_FLAG_COH BIT(5) /* Coherent control, default 1 */ +#define IVHD_FLAG_PFS BIT(6) /* Prefetch IOMMU pages. */ +#define IVHD_FLAG_PPRS BIT(7) /* Peripheral page support. */ + +/* IVHD device entry data setting. */ +#define IVHD_DEV_LINT0_PASS BIT(6) /* LINT0 interrupts. */ +#define IVHD_DEV_LINT1_PASS BIT(7) /* LINT1 interrupts. */ + +/* Bit[5:4] for System Mgmt. Bit3 is reserved. */ +#define IVHD_DEV_INIT_PASS BIT(0) /* INIT */ +#define IVHD_DEV_EXTINTR_PASS BIT(1) /* ExtInt */ +#define IVHD_DEV_NMI_PASS BIT(2) /* NMI */ + +/* IVHD 8-byte extended data settings. */ +#define IVHD_DEV_EXT_ATS_DISABLE BIT(31) /* Disable ATS */ + +/* IOMMU control register. */ +#define AMDVI_CTRL_EN BIT(0) /* IOMMU enable. */ +#define AMDVI_CTRL_HTT BIT(1) /* Hypertransport tunnel enable. */ +#define AMDVI_CTRL_ELOG BIT(2) /* Event log enable. */ +#define AMDVI_CTRL_ELOGINT BIT(3) /* Event log interrupt. */ +#define AMDVI_CTRL_COMINT BIT(4) /* Completion wait interrupt. */ +#define AMDVI_CTRL_PPW BIT(8) +#define AMDVI_CTRL_RPPW BIT(9) +#define AMDVI_CTRL_COH BIT(10) +#define AMDVI_CTRL_ISOC BIT(11) +#define AMDVI_CTRL_CMD BIT(12) /* Command buffer enable. */ +#define AMDVI_CTRL_PPRLOG BIT(13) +#define AMDVI_CTRL_PPRINT BIT(14) +#define AMDVI_CTRL_PPREN BIT(15) +#define AMDVI_CTRL_GTE BIT(16) /* Guest translation enable. */ +#define AMDVI_CTRL_GAE BIT(17) /* Guest APIC enable. */ + +/* Invalidation timeout. */ +#define AMDVI_CTRL_INV_NO_TO 0 /* No timeout. */ +#define AMDVI_CTRL_INV_TO_1ms 1 /* 1 ms */ +#define AMDVI_CTRL_INV_TO_10ms 2 /* 10 ms */ +#define AMDVI_CTRL_INV_TO_100ms 3 /* 100 ms */ +#define AMDVI_CTRL_INV_TO_1S 4 /* 1 second */ +#define AMDVI_CTRL_INV_TO_10S 5 /* 10 second */ +#define AMDVI_CTRL_INV_TO_100S 6 /* 100 second */ + +/* + * Max number of PCI devices. + * 256 bus x 32 slot/devices x 8 functions. + */ +#define PCI_NUM_DEV_MAX 0x10000 + +/* Maximum number of domains supported by IOMMU. */ +#define AMDVI_MAX_DOMAIN (BIT(16) - 1) + +/* + * IOMMU Page Table attributes. + */ +#define AMDVI_PT_PRESENT BIT(0) +#define AMDVI_PT_COHERENT BIT(60) +#define AMDVI_PT_READ BIT(61) +#define AMDVI_PT_WRITE BIT(62) + +#define AMDVI_PT_RW (AMDVI_PT_READ | AMDVI_PT_WRITE) +#define AMDVI_PT_MASK 0xFFFFFFFFFF000UL /* Only [51:12] for PA */ + +#define AMDVI_PD_LEVEL_SHIFT 9 +#define AMDVI_PD_SUPER(x) (((x) >> AMDVI_PD_LEVEL_SHIFT) == 7) +/* + * IOMMU Status, offset 0x2020 + */ +#define AMDVI_STATUS_EV_OF BIT(0) /* Event overflow. */ +#define AMDVI_STATUS_EV_INTR BIT(1) /* Event interrupt. */ +/* Completion wait command completed. */ +#define AMDVI_STATUS_CMP BIT(2) + +#define IVRS_CTRL_RID 1 /* MMIO RID */ + +/* ACPI IVHD */ +struct ivhd_dev_cfg { + uint32_t start_id; + uint32_t end_id; + uint8_t data; /* Device configuration. */ + bool enable_ats; /* ATS enabled for the device. */ + int ats_qlen; /* ATS invalidation queue depth. */ +}; + +struct amdvi_domain { + uint64_t *ptp; /* Highest level page table */ + int ptp_level; /* Level of page tables */ + u_int id; /* Domain id */ + SLIST_ENTRY (amdvi_domain) next; +}; + +/* + * AMD IOMMU softc. + */ +struct amdvi_softc { + struct amdvi_ctrl *ctrl; /* Control area. */ + device_t dev; /* IOMMU device. */ + bool iotlb; /* IOTLB supported by IOMMU */ + struct amdvi_cmd *cmd; /* Command descriptor area. */ + int cmd_max; /* Max number of commands. */ + uint64_t cmp_data; /* Command completion write back. */ + struct amdvi_event *event; /* Event descriptor area. */ + struct resource *event_res; /* Event interrupt resource. */ + void *event_tag; /* Event interrupt tag. */ + int event_max; /* Max number of events. */ + int event_irq; + int event_rid; + /* ACPI various flags. */ + uint32_t ivhd_flag; /* ACPI IVHD flag. */ + uint32_t ivhd_efr; /* ACPI v1 Reserved or v2 EFR . */ + /* PCI related. */ + uint16_t cap_off; /* PCI Capability offset. */ + uint8_t pci_cap; /* PCI capability. */ + uint64_t pci_efr; /* PCI EFR for rev2.0 */ + uint16_t pci_seg; /* IOMMU PCI domain/segment. */ + uint16_t pci_rid; /* PCI BDF of IOMMU */ + /* Device range under this IOMMU. */ + uint16_t start_dev_rid; /* First device under this IOMMU. */ + uint16_t end_dev_rid; /* Last device under this IOMMU. */ + + /* BIOS provided device configuration for end points. */ + struct ivhd_dev_cfg dev_cfg[10]; + int dev_cfg_cnt; + + /* Software statistics. */ + uint64_t event_intr_cnt; /* Total event INTR count. */ + uint64_t total_cmd; /* Total number of commands. */ +}; + +int amdvi_setup_hw(struct amdvi_softc *softc); +int amdvi_teardown_hw(struct amdvi_softc *softc); +#endif /* _AMDVI_PRIV_H_ */ diff --git a/sys/amd64/vmm/amd/ivrs_drv.c b/sys/amd64/vmm/amd/ivrs_drv.c new file mode 100755 index 00000000000..511fbcf993f --- /dev/null +++ b/sys/amd64/vmm/amd/ivrs_drv.c @@ -0,0 +1,498 @@ +/*- + * Copyright (c) 2016, Anish Gupta (anish@freebsd.org) + * All rights reserved. + * + * 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 unmodified, 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 ``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 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 +__FBSDID("$FreeBSD$"); + +#include "opt_acpi.h" +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + +#include "io/iommu.h" +#include "amdvi_priv.h" + +device_t *ivhd_devs; /* IVHD or AMD-Vi device list. */ +int ivhd_count; /* Number of IVHD or AMD-Vi devices. */ + +extern int amdvi_ptp_level; /* Page table levels. */ + +typedef int (*ivhd_iter_t)(ACPI_IVRS_HEADER * ptr, void *arg); + +/* + * Iterate IVRS table for IVHD and IVMD device type. + */ +static void +ivrs_hdr_iterate_tbl(ivhd_iter_t iter, void *arg) +{ + ACPI_TABLE_IVRS *ivrs; + ACPI_IVRS_HEADER *ivrs_hdr, *end; + ACPI_STATUS status; + + status = AcpiGetTable(ACPI_SIG_IVRS, 1, (ACPI_TABLE_HEADER **)&ivrs); + if (ACPI_FAILURE(status)) + return; + + if (ivrs->Header.Length == 0) { + return; + } + + ivrs_hdr = (ACPI_IVRS_HEADER *)(ivrs + 1); + end = (ACPI_IVRS_HEADER *)((char *)ivrs + ivrs->Header.Length); + + while (ivrs_hdr < end) { + switch (ivrs_hdr->Type) { + case ACPI_IVRS_TYPE_HARDWARE: /* Legacy */ + case 0x11: + case 0x40: /* ACPI HID */ + if (!iter(ivrs_hdr, arg)) + return; + break; + + case ACPI_IVRS_TYPE_MEMORY1: + case ACPI_IVRS_TYPE_MEMORY2: + case ACPI_IVRS_TYPE_MEMORY3: + if (!iter(ivrs_hdr, arg)) + return; + + break; + + default: + printf("AMD-Vi:Not IVHD/IVMD type(%d)", ivrs_hdr->Type); + + } + + ivrs_hdr = (ACPI_IVRS_HEADER *)((uint8_t *)ivrs_hdr + + ivrs_hdr->Length); + if (ivrs_hdr->Length < 0) { + printf("AMD-Vi:IVHD/IVMD is corrupted, length : %d\n", ivrs_hdr->Length); + break; + } + } +} + +static int +ivrs_is_ivhd(UINT8 type) +{ + + if ((type == ACPI_IVRS_TYPE_HARDWARE) || (type == 0x11) || (type == 0x40)) + return (1); + + return (0); +} + +/* Count the number of AMD-Vi devices in the system. */ +static int +ivhd_count_iter(ACPI_IVRS_HEADER * ivrs_he, void *arg) +{ + + if (ivrs_is_ivhd(ivrs_he->Type)) + ivhd_count++; + + return (1); +} + +struct find_ivrs_hdr_args { + int i; + ACPI_IVRS_HEADER *ptr; +}; + +static int +ivrs_hdr_find_iter(ACPI_IVRS_HEADER * ivrs_hdr, void *args) +{ + struct find_ivrs_hdr_args *fi; + + fi = (struct find_ivrs_hdr_args *)args; + if (ivrs_is_ivhd(ivrs_hdr->Type)) { + if (fi->i == 0) { + fi->ptr = ivrs_hdr; + return (0); + } + fi->i--; + } + + return (1); +} + +static ACPI_IVRS_HARDWARE * +ivhd_find_by_index(int idx) +{ + struct find_ivrs_hdr_args fi; + + fi.i = idx; + fi.ptr = NULL; + + ivrs_hdr_iterate_tbl(ivrs_hdr_find_iter, &fi); + + return ((ACPI_IVRS_HARDWARE *)fi.ptr); +} + +static void +ivhd_dev_add_entry(struct amdvi_softc *softc, uint32_t start_id, + uint32_t end_id, uint8_t cfg, bool ats) +{ + struct ivhd_dev_cfg *dev_cfg; + + /* If device doesn't have special data, don't add it. */ + if (!cfg) + return; + + dev_cfg = &softc->dev_cfg[softc->dev_cfg_cnt++]; + dev_cfg->start_id = start_id; + dev_cfg->end_id = end_id; + dev_cfg->data = cfg; + dev_cfg->enable_ats = ats; +} + +/* + * Record device attributes as suggested by BIOS. + */ +static int +ivhd_dev_parse(ACPI_IVRS_HARDWARE * ivhd, struct amdvi_softc *softc) +{ + ACPI_IVRS_DE_HEADER *de, *end; + int range_start_id = 0, range_end_id = 0; + uint32_t *extended; + uint8_t all_data = 0, range_data = 0; + bool range_enable_ats = false, enable_ats; + + softc->start_dev_rid = ~0; + softc->end_dev_rid = 0; + + de = (ACPI_IVRS_DE_HEADER *) ((uint8_t *)ivhd + + sizeof(ACPI_IVRS_HARDWARE)); + end = (ACPI_IVRS_DE_HEADER *) ((uint8_t *)ivhd + + ivhd->Header.Length); + + while (de < (ACPI_IVRS_DE_HEADER *) end) { + softc->start_dev_rid = MIN(softc->start_dev_rid, de->Id); + softc->end_dev_rid = MAX(softc->end_dev_rid, de->Id); + switch (de->Type) { + case ACPI_IVRS_TYPE_ALL: + all_data = de->DataSetting; + break; + + case ACPI_IVRS_TYPE_SELECT: + case ACPI_IVRS_TYPE_ALIAS_SELECT: + case ACPI_IVRS_TYPE_EXT_SELECT: + enable_ats = false; + if (de->Type == ACPI_IVRS_TYPE_EXT_SELECT) { + extended = (uint32_t *)(de + 1); + enable_ats = + (*extended & IVHD_DEV_EXT_ATS_DISABLE) ? + false : true; + } + ivhd_dev_add_entry(softc, de->Id, de->Id, + de->DataSetting | all_data, enable_ats); + break; + + case ACPI_IVRS_TYPE_START: + case ACPI_IVRS_TYPE_ALIAS_START: + case ACPI_IVRS_TYPE_EXT_START: + range_start_id = de->Id; + range_data = de->DataSetting; + if (de->Type == ACPI_IVRS_TYPE_EXT_START) { + extended = (uint32_t *)(de + 1); + range_enable_ats = + (*extended & IVHD_DEV_EXT_ATS_DISABLE) ? + false : true; + } + break; + + case ACPI_IVRS_TYPE_END: + range_end_id = de->Id; + ivhd_dev_add_entry(softc, range_start_id, range_end_id, + range_data | all_data, range_enable_ats); + range_start_id = range_end_id = 0; + range_data = 0; + all_data = 0; + break; + + case ACPI_IVRS_TYPE_PAD4: + break; + + case ACPI_IVRS_TYPE_SPECIAL: + /* HPET or IOAPIC */ + break; + default: + if ((de->Type < 5) || + (de->Type >= ACPI_IVRS_TYPE_PAD8)) + device_printf(softc->dev, + "Unknown dev entry:0x%x\n", de->Type); + } + + if (softc->dev_cfg_cnt > + (sizeof(softc->dev_cfg) / sizeof(softc->dev_cfg[0]))) { + device_printf(softc->dev, + "WARN Too many device entries.\n"); + return (EINVAL); + } + de++; + } + + KASSERT((softc->end_dev_rid >= softc->start_dev_rid), + ("Device end[0x%x] < start[0x%x.\n", + softc->end_dev_rid, softc->start_dev_rid)); + + return (0); +} + +static void +ivhd_identify(driver_t *driver, device_t parent) +{ + ACPI_TABLE_IVRS *ivrs; + ACPI_IVRS_HARDWARE *ivhd; + ACPI_STATUS status; + uint32_t info; + int i, count = 0; + + if (acpi_disabled("ivhd")) + return; + + status = AcpiGetTable(ACPI_SIG_IVRS, 1, (ACPI_TABLE_HEADER **)&ivrs); + if (ACPI_FAILURE(status)) + return; + + if (ivrs->Header.Length == 0) { + return; + } + + info = ivrs->Info; + printf("AMD-Vi IVRS VAsize = %d PAsize = %d GVAsize = %d flags:%b\n", + REG_BITS(info, 21, 15), REG_BITS(info, 14, 8), + REG_BITS(info, 7, 5), REG_BITS(info, 22, 22), + "\020\001HtAtsResv"); + + ivrs_hdr_iterate_tbl(ivhd_count_iter, NULL); + if (!ivhd_count) + return; + + ivhd_devs = malloc(sizeof(device_t) * ivhd_count, M_DEVBUF, + M_WAITOK | M_ZERO); + for (i = 0; i < ivhd_count; i++) { + ivhd = ivhd_find_by_index(i); + if (ivhd == NULL) { + printf("Can't find IVHD entry%d\n", i); + continue; + } + + ivhd_devs[i] = BUS_ADD_CHILD(parent, 1, "ivhd", i); + /* + * XXX: In case device was not destroyed before, add will fail. + * locate the old device instance. + */ + if (ivhd_devs[i] == NULL) { + ivhd_devs[i] = device_find_child(parent, "ivhd", i); + if (ivhd_devs[i] == NULL) { + printf("AMD-Vi: cant find AMD-Vi dev%d\n", i); + break; + } + } + count++; + } + + /* + * Update device count in case failed to attach. + */ + ivhd_count = count; +} + +static int +ivhd_probe(device_t dev) +{ + + if (acpi_get_handle(dev) != NULL) + return (ENXIO); + device_set_desc(dev, "AMD-Vi/IOMMU or ivhd"); + + return (BUS_PROBE_NOWILDCARD); +} + +static int +ivhd_print_cap(struct amdvi_softc *softc, ACPI_IVRS_HARDWARE * ivhd) +{ + device_t dev; + int max_ptp_level; + + dev = softc->dev; + device_printf(dev, "Flag:%b\n", softc->ivhd_flag, + "\020\001HtTunEn\002PassPW\003ResPassPW\004Isoc\005IotlbSup" + "\006Coherent\007PreFSup\008PPRSup"); + /* + * If no extended feature[EFR], its rev1 with maximum paging level as 7. + */ + max_ptp_level = 7; + if (softc->ivhd_efr) { + device_printf(dev, "EFR HATS = %d GATS = %d GLXSup = %d " + "MsiNumPr = %d PNBanks= %d PNCounters= %d\n" + "max PASID = %d EFR: %b \n", + REG_BITS(softc->ivhd_efr, 31, 30), + REG_BITS(softc->ivhd_efr, 29, 28), + REG_BITS(softc->ivhd_efr, 4, 3), + REG_BITS(softc->ivhd_efr, 27, 23), + REG_BITS(softc->ivhd_efr, 22, 17), + REG_BITS(softc->ivhd_efr, 16, 13), + REG_BITS(softc->ivhd_efr, 12, 8), + softc->ivhd_efr, "\020\001XTSup\002NXSup\003GTSup\005IASup" + "\006GASup\007HESup\008PPRSup"); + + max_ptp_level = REG_BITS(softc->ivhd_efr, 31, 30) + 4; + } + + /* Make sure device support minimum page level as requested by user. */ + if (max_ptp_level < amdvi_ptp_level) { + device_printf(dev, "Insufficient PTP level:%d\n", + max_ptp_level); + return (EINVAL); + } + + device_printf(softc->dev, "max supported paging level:%d restricting to: %d\n", + max_ptp_level, amdvi_ptp_level); + device_printf(softc->dev, "device supported range " + "[0x%x - 0x%x]\n", softc->start_dev_rid, softc->end_dev_rid); + + return (0); +} + +static int +ivhd_attach(device_t dev) +{ + ACPI_IVRS_HARDWARE *ivhd; + struct amdvi_softc *softc; + int status, unit; + + unit = device_get_unit(dev); + /* Make sure its same device for which attach is called. */ + if (ivhd_devs[unit] != dev) + panic("Not same device old %p new %p", ivhd_devs[unit], dev); + + softc = device_get_softc(dev); + softc->dev = dev; + ivhd = ivhd_find_by_index(unit); + if (ivhd == NULL) + return (EINVAL); + + softc->pci_seg = ivhd->PciSegmentGroup; + softc->pci_rid = ivhd->Header.DeviceId; + softc->ivhd_flag = ivhd->Header.Flags; + softc->ivhd_efr = ivhd->Reserved; + /* + * PCI capability has more capabilities that are not part of IVRS. + */ + softc->cap_off = ivhd->CapabilityOffset; + +#ifdef notyet + /* IVHD Info bit[4:0] is event MSI/X number. */ + softc->event_msix = ivhd->Info & 0x1F; +#endif + softc->ctrl = (struct amdvi_ctrl *) PHYS_TO_DMAP(ivhd->BaseAddress); + status = ivhd_dev_parse(ivhd, softc); + if (status != 0) { + device_printf(dev, + "endpoint device parsing error=%d\n", status); + } + + status = ivhd_print_cap(softc, ivhd); + if (status != 0) { + return (status); + } + + status = amdvi_setup_hw(softc); + if (status != 0) { + device_printf(dev, "couldn't be initialised, error=%d\n", + status); + return (status); + } + + return (0); +} + +static int +ivhd_detach(device_t dev) +{ + struct amdvi_softc *softc; + + softc = device_get_softc(dev); + + amdvi_teardown_hw(softc); + + /* + * XXX: delete the device. + * don't allow detach, return EBUSY. + */ + return (0); +} + +static int +ivhd_suspend(device_t dev) +{ + + return (0); +} + +static int +ivhd_resume(device_t dev) +{ + + return (0); +} + +static device_method_t ivhd_methods[] = { + DEVMETHOD(device_identify, ivhd_identify), + DEVMETHOD(device_probe, ivhd_probe), + DEVMETHOD(device_attach, ivhd_attach), + DEVMETHOD(device_detach, ivhd_detach), + DEVMETHOD(device_suspend, ivhd_suspend), + DEVMETHOD(device_resume, ivhd_resume), + DEVMETHOD_END +}; + +static driver_t ivhd_driver = { + "ivhd", + ivhd_methods, + sizeof(struct amdvi_softc), +}; + +static devclass_t ivhd_devclass; + +/* + * Load this module at the end after PCI re-probing to configure interrupt. + */ +DRIVER_MODULE_ORDERED(ivhd, acpi, ivhd_driver, ivhd_devclass, 0, 0, + SI_ORDER_ANY); +MODULE_DEPEND(ivhd, acpi, 1, 1, 1); +MODULE_DEPEND(ivhd, pci, 1, 1, 1); diff --git a/sys/arm64/arm64/machdep.c b/sys/arm64/arm64/machdep.c index 186460f41e8..e804b15d11c 100644 --- a/sys/arm64/arm64/machdep.c +++ b/sys/arm64/arm64/machdep.c @@ -1141,9 +1141,13 @@ DB_SHOW_COMMAND(vtop, db_show_vtop) if (have_addr) { phys = arm64_address_translate_s1e1r(addr); - db_printf("Physical address reg (read): 0x%016lx\n", phys); + db_printf("EL1 physical address reg (read): 0x%016lx\n", phys); phys = arm64_address_translate_s1e1w(addr); - db_printf("Physical address reg (write): 0x%016lx\n", phys); + db_printf("EL1 physical address reg (write): 0x%016lx\n", phys); + phys = arm64_address_translate_s1e0r(addr); + db_printf("EL0 physical address reg (read): 0x%016lx\n", phys); + phys = arm64_address_translate_s1e0w(addr); + db_printf("EL0 physical address reg (write): 0x%016lx\n", phys); } else db_printf("show vtop \n"); } diff --git a/sys/boot/efi/loader/main.c b/sys/boot/efi/loader/main.c index a58ebe12038..24cafa64c52 100644 --- a/sys/boot/efi/loader/main.c +++ b/sys/boot/efi/loader/main.c @@ -507,8 +507,7 @@ command_reboot(int argc, char *argv[]) if (devsw[i]->dv_cleanup != NULL) (devsw[i]->dv_cleanup)(); - RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 23, - (CHAR16 *)"Reboot from the loader"); + RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); /* NOTREACHED */ return (CMD_ERROR); diff --git a/sys/boot/i386/zfsboot/zfsboot.c b/sys/boot/i386/zfsboot/zfsboot.c index e76e58fc80e..88b5231efe4 100644 --- a/sys/boot/i386/zfsboot/zfsboot.c +++ b/sys/boot/i386/zfsboot/zfsboot.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include "lib.h" #include "rbx.h" #include "drv.h" +#include "edd.h" #include "util.h" #include "cons.h" #include "bootargs.h" @@ -125,6 +126,7 @@ static int parse_cmd(void); static void bios_getmem(void); void *malloc(size_t n); void free(void *ptr); +int main(void); void * malloc(size_t n) @@ -468,6 +470,56 @@ copy_dsk(struct dsk *dsk) return (newdsk); } +/* + * Get disk size from eax=0x800 and 0x4800. We need to probe both + * because 0x4800 may not be available and we would like to get more + * or less correct disk size - if it is possible at all. + * Note we do not really want to touch drv.c because that code is shared + * with boot2 and we can not afford to grow that code. + */ +static uint64_t +drvsize_ext(struct dsk *dskp) +{ + uint64_t size, tmp; + int cyl, hds, sec; + + v86.ctl = V86_FLAGS; + v86.addr = 0x13; + v86.eax = 0x800; + v86.edx = dskp->drive; + v86int(); + + /* Don't error out if we get bad sector number, try EDD as well */ + if (V86_CY(v86.efl) || /* carry set */ + (v86.edx & 0xff) <= (unsigned)(dskp->drive & 0x7f)) /* unit # bad */ + return (0); + + cyl = ((v86.ecx & 0xc0) << 2) + ((v86.ecx & 0xff00) >> 8) + 1; + /* Convert max head # -> # of heads */ + hds = ((v86.edx & 0xff00) >> 8) + 1; + sec = v86.ecx & 0x3f; + + size = (uint64_t)cyl * hds * sec; + + /* Determine if we can use EDD with this device. */ + v86.ctl = V86_FLAGS; + v86.addr = 0x13; + v86.eax = 0x4100; + v86.edx = dskp->drive; + v86.ebx = 0x55aa; + v86int(); + if (V86_CY(v86.efl) || /* carry set */ + (v86.ebx & 0xffff) != 0xaa55 || /* signature */ + (v86.ecx & EDD_INTERFACE_FIXED_DISK) == 0) + return (size); + + tmp = drvsize(dskp); + if (tmp > size) + size = tmp; + + return (size); +} + /* * The "layered" ioctl to read disk/partition size. Unfortunately * the zfsboot case is hardest, because we do not have full software @@ -480,7 +532,7 @@ ldi_get_size(void *priv) uint64_t size = dskp->size; if (dskp->start == 0) - size = drvsize(dskp); + size = drvsize_ext(dskp); return (size * DEV_BSIZE); } @@ -515,7 +567,7 @@ probe_drive(struct dsk *dsk) * out the partition table and probe each slice/partition * in turn for a vdev or GELI encrypted vdev. */ - elba = drvsize(dsk); + elba = drvsize_ext(dsk); if (elba > 0) { elba--; } diff --git a/sys/cam/cam_periph.c b/sys/cam/cam_periph.c index 57acd907d66..bfc98024bd5 100644 --- a/sys/cam/cam_periph.c +++ b/sys/cam/cam_periph.c @@ -643,8 +643,9 @@ cam_periph_invalidate(struct cam_periph *periph) CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("Periph invalidated\n")); if ((periph->flags & CAM_PERIPH_ANNOUNCED) && !rebooting) { struct sbuf sb; + char buffer[160]; - sbuf_new(&sb, NULL, 160, SBUF_FIXEDLEN); + sbuf_new(&sb, buffer, 160, SBUF_FIXEDLEN); xpt_denounce_periph_sbuf(periph, &sb); sbuf_finish(&sb); sbuf_putbuf(&sb); diff --git a/sys/cam/scsi/scsi_all.c b/sys/cam/scsi/scsi_all.c index cf45c095c25..b2874203752 100644 --- a/sys/cam/scsi/scsi_all.c +++ b/sys/cam/scsi/scsi_all.c @@ -1614,7 +1614,7 @@ static struct asc_table_entry asc_table[] = { { SST(0x20, 0x01, SS_RDEF, /* XXX TBD */ "Access denied - initiator pending-enrolled") }, /* DT PWROMAEBK */ - { SST(0x20, 0x02, SS_RDEF, /* XXX TBD */ + { SST(0x20, 0x02, SS_FATAL | EPERM, "Access denied - no access rights") }, /* DT PWROMAEBK */ { SST(0x20, 0x03, SS_RDEF, /* XXX TBD */ diff --git a/sys/cam/scsi/scsi_all.h b/sys/cam/scsi/scsi_all.h index d231ca19f29..3a11a15e489 100644 --- a/sys/cam/scsi/scsi_all.h +++ b/sys/cam/scsi/scsi_all.h @@ -565,6 +565,7 @@ struct scsi_log_sense #define SLS_ERROR_LASTN_PAGE 0x07 #define SLS_LOGICAL_BLOCK_PROVISIONING 0x0c #define SLS_SELF_TEST_PAGE 0x10 +#define SLS_SOLID_STATE_MEDIA 0x11 #define SLS_STAT_AND_PERF 0x19 #define SLS_IE_PAGE 0x2f #define SLS_PAGE_CTRL_MASK 0xC0 @@ -624,6 +625,13 @@ struct scsi_log_param_header { u_int8_t param_len; }; +struct scsi_log_media_pct_used { + struct scsi_log_param_header hdr; +#define SLP_SS_MEDIA_PCT_USED 0x0001 + uint8_t reserved[3]; + uint8_t pct_used; +}; + struct scsi_log_stat_and_perf { struct scsi_log_param_header hdr; #define SLP_SAP 0x0001 diff --git a/sys/cam/scsi/scsi_pass.c b/sys/cam/scsi/scsi_pass.c index aa13a01d115..0941c4f4d66 100644 --- a/sys/cam/scsi/scsi_pass.c +++ b/sys/cam/scsi/scsi_pass.c @@ -2229,9 +2229,9 @@ passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb) * that request. Otherwise, it's up to the user to perform any * error recovery. */ - cam_periph_runccb(ccb, passerror, /* cam_flags */ CAM_RETRY_SELTO, - /* sense_flags */ ((ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ? - SF_RETRY_UA : SF_NO_RECOVERY) | SF_NO_PRINT, + cam_periph_runccb(ccb, (ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ? + passerror : NULL, /* cam_flags */ CAM_RETRY_SELTO, + /* sense_flags */ SF_RETRY_UA | SF_NO_PRINT, softc->device_stats); cam_periph_unmapmem(ccb, &mapinfo); diff --git a/sys/cam/scsi/scsi_sa.h b/sys/cam/scsi/scsi_sa.h index 6ecef659844..3e414611ab4 100644 --- a/sys/cam/scsi/scsi_sa.h +++ b/sys/cam/scsi/scsi_sa.h @@ -486,6 +486,19 @@ struct scsi_medium_type_data { u_int8_t description[20]; }; +/* + * Manufacturer-assigned Serial Number VPD page. + * Current as of SSC-5r03, 28 September 2016. + */ +struct scsi_vpd_mfg_serial_number +{ + u_int8_t device; + u_int8_t page_code; +#define SVPD_MFG_SERIAL_NUMBER_PAGE_CODE 0xB1 + u_int8_t page_length[2]; + u_int8_t mfg_serial_num[]; +}; + /* * Security Protocol Specific values for the Tape Data Encryption protocol * (0x20) used with SECURITY PROTOCOL IN. See below for values used with diff --git a/sys/cddl/contrib/opensolaris/uts/common/dtrace/fasttrap.c b/sys/cddl/contrib/opensolaris/uts/common/dtrace/fasttrap.c index 845da7a7080..b38b311a331 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/dtrace/fasttrap.c +++ b/sys/cddl/contrib/opensolaris/uts/common/dtrace/fasttrap.c @@ -2269,10 +2269,6 @@ static int fasttrap_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int fflag, struct thread *td) { -#ifdef notyet - struct kinfo_proc kp; - const cred_t *cr = td->td_ucred; -#endif if (!dtrace_attached()) return (EAGAIN); @@ -2328,47 +2324,24 @@ fasttrap_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int fflag, proc_t *p; pid_t pid = probe->ftps_pid; -#ifdef illumos mutex_enter(&pidlock); -#endif /* * Report an error if the process doesn't exist * or is actively being birthed. */ - sx_slock(&proctree_lock); - p = pfind(pid); - if (p) - fill_kinfo_proc(p, &kp); - sx_sunlock(&proctree_lock); - if (p == NULL || kp.ki_stat == SIDL) { -#ifdef illumos + if ((p = pfind(pid)) == NULL || p->p_stat == SIDL) { mutex_exit(&pidlock); -#endif return (ESRCH); } -#ifdef illumos mutex_enter(&p->p_lock); mutex_exit(&pidlock); -#else - PROC_LOCK_ASSERT(p, MA_OWNED); -#endif -#ifdef notyet if ((ret = priv_proc_cred_perm(cr, p, NULL, VREAD | VWRITE)) != 0) { -#ifdef illumos mutex_exit(&p->p_lock); -#else - PROC_UNLOCK(p); -#endif return (ret); } -#endif /* notyet */ -#ifdef illumos mutex_exit(&p->p_lock); -#else - PROC_UNLOCK(p); -#endif } #endif /* notyet */ @@ -2382,7 +2355,7 @@ err: fasttrap_instr_query_t instr; fasttrap_tracepoint_t *tp; uint_t index; -#ifdef illumos +#ifdef notyet int ret; #endif @@ -2396,48 +2369,25 @@ err: proc_t *p; pid_t pid = instr.ftiq_pid; -#ifdef illumos mutex_enter(&pidlock); -#endif /* * Report an error if the process doesn't exist * or is actively being birthed. */ - sx_slock(&proctree_lock); - p = pfind(pid); - if (p) - fill_kinfo_proc(p, &kp); - sx_sunlock(&proctree_lock); - if (p == NULL || kp.ki_stat == SIDL) { -#ifdef illumos + if ((p == pfind(pid)) == NULL || p->p_stat == SIDL) { mutex_exit(&pidlock); -#endif return (ESRCH); } -#ifdef illumos mutex_enter(&p->p_lock); mutex_exit(&pidlock); -#else - PROC_LOCK_ASSERT(p, MA_OWNED); -#endif -#ifdef notyet if ((ret = priv_proc_cred_perm(cr, p, NULL, VREAD)) != 0) { -#ifdef illumos mutex_exit(&p->p_lock); -#else - PROC_UNLOCK(p); -#endif return (ret); } -#endif /* notyet */ -#ifdef illumos mutex_exit(&p->p_lock); -#else - PROC_UNLOCK(p); -#endif } #endif /* notyet */ diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c index da17320321c..8f8298e4ff3 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c @@ -2161,8 +2161,6 @@ static int dbuf_findbp(dnode_t *dn, int level, uint64_t blkid, int fail_sparse, dmu_buf_impl_t **parentp, blkptr_t **bpp) { - int nlevels, epbs; - *parentp = NULL; *bpp = NULL; @@ -2181,17 +2179,35 @@ dbuf_findbp(dnode_t *dn, int level, uint64_t blkid, int fail_sparse, return (0); } - if (dn->dn_phys->dn_nlevels == 0) - nlevels = 1; - else - nlevels = dn->dn_phys->dn_nlevels; - - epbs = dn->dn_indblkshift - SPA_BLKPTRSHIFT; + int nlevels = + (dn->dn_phys->dn_nlevels == 0) ? 1 : dn->dn_phys->dn_nlevels; + int epbs = dn->dn_indblkshift - SPA_BLKPTRSHIFT; ASSERT3U(level * epbs, <, 64); ASSERT(RW_LOCK_HELD(&dn->dn_struct_rwlock)); + /* + * This assertion shouldn't trip as long as the max indirect block size + * is less than 1M. The reason for this is that up to that point, + * the number of levels required to address an entire object with blocks + * of size SPA_MINBLOCKSIZE satisfies nlevels * epbs + 1 <= 64. In + * other words, if N * epbs + 1 > 64, then if (N-1) * epbs + 1 > 55 + * (i.e. we can address the entire object), objects will all use at most + * N-1 levels and the assertion won't overflow. However, once epbs is + * 13, 4 * 13 + 1 = 53, but 5 * 13 + 1 = 66. Then, 4 levels will not be + * enough to address an entire object, so objects will have 5 levels, + * but then this assertion will overflow. + * + * All this is to say that if we ever increase DN_MAX_INDBLKSHIFT, we + * need to redo this logic to handle overflows. + */ + ASSERT(level >= nlevels || + ((nlevels - level - 1) * epbs) + + highbit64(dn->dn_phys->dn_nblkptr) <= 64); if (level >= nlevels || - (blkid > (dn->dn_phys->dn_maxblkid >> (level * epbs)))) { + blkid >= ((uint64_t)dn->dn_phys->dn_nblkptr << + ((nlevels - level - 1) * epbs)) || + (fail_sparse && + blkid > (dn->dn_phys->dn_maxblkid >> (level * epbs)))) { /* the buffer has no parent yet */ return (SET_ERROR(ENOENT)); } else if (level < nlevels-1) { @@ -2209,6 +2225,8 @@ dbuf_findbp(dnode_t *dn, int level, uint64_t blkid, int fail_sparse, } *bpp = ((blkptr_t *)(*parentp)->db.db_data) + (blkid & ((1ULL << epbs) - 1)); + if (blkid > (dn->dn_phys->dn_maxblkid >> (level * epbs))) + ASSERT(BP_IS_HOLE(*bpp)); return (0); } else { /* the block is referenced from the dnode */ @@ -3317,13 +3335,13 @@ dbuf_write_children_ready(zio_t *zio, arc_buf_t *buf, void *vdb) dmu_buf_impl_t *db = vdb; dnode_t *dn; blkptr_t *bp; - uint64_t i; - int epbs; + unsigned int epbs, i; ASSERT3U(db->db_level, >, 0); DB_DNODE_ENTER(db); dn = DB_DNODE(db); epbs = dn->dn_phys->dn_indblkshift - SPA_BLKPTRSHIFT; + ASSERT3U(epbs, <, 31); /* Determine if all our children are holes */ for (i = 0, bp = db->db.db_data; i < 1 << epbs; i++, bp++) { @@ -3336,8 +3354,14 @@ dbuf_write_children_ready(zio_t *zio, arc_buf_t *buf, void *vdb) * we may get compressed away. */ if (i == 1 << epbs) { - /* didn't find any non-holes */ + /* + * We only found holes. Grab the rwlock to prevent + * anybody from reading the blocks we're about to + * zero out. + */ + rw_enter(&dn->dn_struct_rwlock, RW_WRITER); bzero(db->db.db_data, db->db.db_size); + rw_exit(&dn->dn_struct_rwlock); } DB_DNODE_EXIT(db); } diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c index 3ed68f71335..b71a43f7b55 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c @@ -1705,6 +1705,7 @@ typedef struct dmu_objset_find_ctx { taskq_t *dc_tq; dsl_pool_t *dc_dp; uint64_t dc_ddobj; + char *dc_ddname; /* last component of ddobj's name */ int (*dc_func)(dsl_pool_t *, dsl_dataset_t *, void *); void *dc_arg; int dc_flags; @@ -1716,7 +1717,6 @@ static void dmu_objset_find_dp_impl(dmu_objset_find_ctx_t *dcp) { dsl_pool_t *dp = dcp->dc_dp; - dmu_objset_find_ctx_t *child_dcp; dsl_dir_t *dd; dsl_dataset_t *ds; zap_cursor_t zc; @@ -1728,7 +1728,12 @@ dmu_objset_find_dp_impl(dmu_objset_find_ctx_t *dcp) if (*dcp->dc_error != 0) goto out; - err = dsl_dir_hold_obj(dp, dcp->dc_ddobj, NULL, FTAG, &dd); + /* + * Note: passing the name (dc_ddname) here is optional, but it + * improves performance because we don't need to call + * zap_value_search() to determine the name. + */ + err = dsl_dir_hold_obj(dp, dcp->dc_ddobj, dcp->dc_ddname, FTAG, &dd); if (err != 0) goto out; @@ -1753,9 +1758,11 @@ dmu_objset_find_dp_impl(dmu_objset_find_ctx_t *dcp) sizeof (uint64_t)); ASSERT3U(attr->za_num_integers, ==, 1); - child_dcp = kmem_alloc(sizeof (*child_dcp), KM_SLEEP); + dmu_objset_find_ctx_t *child_dcp = + kmem_alloc(sizeof (*child_dcp), KM_SLEEP); *child_dcp = *dcp; child_dcp->dc_ddobj = attr->za_first_integer; + child_dcp->dc_ddname = spa_strdup(attr->za_name); if (dcp->dc_tq != NULL) (void) taskq_dispatch(dcp->dc_tq, dmu_objset_find_dp_cb, child_dcp, TQ_SLEEP); @@ -1798,16 +1805,25 @@ dmu_objset_find_dp_impl(dmu_objset_find_ctx_t *dcp) } } - dsl_dir_rele(dd, FTAG); kmem_free(attr, sizeof (zap_attribute_t)); - if (err != 0) + if (err != 0) { + dsl_dir_rele(dd, FTAG); goto out; + } /* * Apply to self. */ err = dsl_dataset_hold_obj(dp, thisobj, FTAG, &ds); + + /* + * Note: we hold the dir while calling dsl_dataset_hold_obj() so + * that the dir will remain cached, and we won't have to re-instantiate + * it (which could be expensive due to finding its name via + * zap_value_search()). + */ + dsl_dir_rele(dd, FTAG); if (err != 0) goto out; err = dcp->dc_func(dp, ds, dcp->dc_arg); @@ -1822,6 +1838,8 @@ out: mutex_exit(dcp->dc_error_lock); } + if (dcp->dc_ddname != NULL) + spa_strfree(dcp->dc_ddname); kmem_free(dcp, sizeof (*dcp)); } @@ -1866,6 +1884,7 @@ dmu_objset_find_dp(dsl_pool_t *dp, uint64_t ddobj, dcp->dc_tq = NULL; dcp->dc_dp = dp; dcp->dc_ddobj = ddobj; + dcp->dc_ddname = NULL; dcp->dc_func = func; dcp->dc_arg = arg; dcp->dc_flags = flags; diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dnode_sync.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dnode_sync.c index 760915d8f38..a17414c0d4b 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dnode_sync.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dnode_sync.c @@ -236,8 +236,8 @@ free_children(dmu_buf_impl_t *db, uint64_t blkid, uint64_t nblks, dnode_t *dn; blkptr_t *bp; dmu_buf_impl_t *subdb; - uint64_t start, end, dbstart, dbend, i; - int epbs, shift; + uint64_t start, end, dbstart, dbend; + unsigned int epbs, shift, i; /* * There is a small possibility that this block will not be cached: @@ -254,6 +254,7 @@ free_children(dmu_buf_impl_t *db, uint64_t blkid, uint64_t nblks, DB_DNODE_ENTER(db); dn = DB_DNODE(db); epbs = dn->dn_phys->dn_indblkshift - SPA_BLKPTRSHIFT; + ASSERT3U(epbs, <, 31); shift = (db->db_level - 1) * epbs; dbstart = db->db_blkid << epbs; start = blkid >> shift; @@ -273,12 +274,12 @@ free_children(dmu_buf_impl_t *db, uint64_t blkid, uint64_t nblks, FREE_VERIFY(db, start, end, tx); free_blocks(dn, bp, end-start+1, tx); } else { - for (i = start; i <= end; i++, bp++) { + for (uint64_t id = start; id <= end; id++, bp++) { if (BP_IS_HOLE(bp)) continue; rw_enter(&dn->dn_struct_rwlock, RW_READER); VERIFY0(dbuf_hold_impl(dn, db->db_level - 1, - i, TRUE, FALSE, FTAG, &subdb)); + id, TRUE, FALSE, FTAG, &subdb)); rw_exit(&dn->dn_struct_rwlock); ASSERT3P(bp, ==, subdb->db_blkptr); @@ -293,8 +294,14 @@ free_children(dmu_buf_impl_t *db, uint64_t blkid, uint64_t nblks, break; } if (i == 1 << epbs) { - /* didn't find any non-holes */ + /* + * We only found holes. Grab the rwlock to prevent + * anybody from reading the blocks we're about to + * zero out. + */ + rw_enter(&dn->dn_struct_rwlock, RW_WRITER); bzero(db->db.db_data, db->db.db_size); + rw_exit(&dn->dn_struct_rwlock); free_blocks(dn, db->db_blkptr, 1, tx); } else { /* diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/metaslab.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/metaslab.c index 2fd9297cfe0..baa65219b68 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/metaslab.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/metaslab.c @@ -533,7 +533,6 @@ metaslab_verify_space(metaslab_t *msp, uint64_t txg) { spa_t *spa = msp->ms_group->mg_vd->vdev_spa; uint64_t allocated = 0; - uint64_t freed = 0; uint64_t sm_free_space, msp_free_space; ASSERT(MUTEX_HELD(&msp->ms_lock)); @@ -563,10 +562,9 @@ metaslab_verify_space(metaslab_t *msp, uint64_t txg) allocated += range_tree_space(msp->ms_alloctree[(txg + t) & TXG_MASK]); } - freed = range_tree_space(msp->ms_freetree[TXG_CLEAN(txg) & TXG_MASK]); msp_free_space = range_tree_space(msp->ms_tree) + allocated + - msp->ms_deferspace + freed; + msp->ms_deferspace + range_tree_space(msp->ms_freedtree); VERIFY3U(sm_free_space, ==, msp_free_space); } @@ -1499,7 +1497,7 @@ metaslab_init(metaslab_group_t *mg, uint64_t id, uint64_t object, uint64_t txg, /* * We create the main range tree here, but we don't create the - * alloctree and freetree until metaslab_sync_done(). This serves + * other range trees until metaslab_sync_done(). This serves * two purposes: it allows metaslab_sync_done() to detect the * addition of new space; and for debugging, it ensures that we'd * data fault on any attempt to use this metaslab before it's ready. @@ -1557,10 +1555,11 @@ metaslab_fini(metaslab_t *msp) metaslab_unload(msp); range_tree_destroy(msp->ms_tree); + range_tree_destroy(msp->ms_freeingtree); + range_tree_destroy(msp->ms_freedtree); for (int t = 0; t < TXG_SIZE; t++) { range_tree_destroy(msp->ms_alloctree[t]); - range_tree_destroy(msp->ms_freetree[t]); } for (int t = 0; t < TXG_DEFER_SIZE; t++) { @@ -2171,7 +2170,6 @@ static void metaslab_condense(metaslab_t *msp, uint64_t txg, dmu_tx_t *tx) { spa_t *spa = msp->ms_group->mg_vd->vdev_spa; - range_tree_t *freetree = msp->ms_freetree[txg & TXG_MASK]; range_tree_t *condense_tree; space_map_t *sm = msp->ms_sm; @@ -2202,9 +2200,9 @@ metaslab_condense(metaslab_t *msp, uint64_t txg, dmu_tx_t *tx) /* * Remove what's been freed in this txg from the condense_tree. * Since we're in sync_pass 1, we know that all the frees from - * this txg are in the freetree. + * this txg are in the freeingtree. */ - range_tree_walk(freetree, range_tree_remove, condense_tree); + range_tree_walk(msp->ms_freeingtree, range_tree_remove, condense_tree); for (int t = 0; t < TXG_DEFER_SIZE; t++) { range_tree_walk(msp->ms_defertree[t], @@ -2260,9 +2258,6 @@ metaslab_sync(metaslab_t *msp, uint64_t txg) spa_t *spa = vd->vdev_spa; objset_t *mos = spa_meta_objset(spa); range_tree_t *alloctree = msp->ms_alloctree[txg & TXG_MASK]; - range_tree_t **freetree = &msp->ms_freetree[txg & TXG_MASK]; - range_tree_t **freed_tree = - &msp->ms_freetree[TXG_CLEAN(txg) & TXG_MASK]; dmu_tx_t *tx; uint64_t object = space_map_object(msp->ms_sm); @@ -2271,14 +2266,14 @@ metaslab_sync(metaslab_t *msp, uint64_t txg) /* * This metaslab has just been added so there's no work to do now. */ - if (*freetree == NULL) { + if (msp->ms_freeingtree == NULL) { ASSERT3P(alloctree, ==, NULL); return; } ASSERT3P(alloctree, !=, NULL); - ASSERT3P(*freetree, !=, NULL); - ASSERT3P(*freed_tree, !=, NULL); + ASSERT3P(msp->ms_freeingtree, !=, NULL); + ASSERT3P(msp->ms_freedtree, !=, NULL); /* * Normally, we don't want to process a metaslab if there @@ -2286,14 +2281,14 @@ metaslab_sync(metaslab_t *msp, uint64_t txg) * is being forced to condense we need to let it through. */ if (range_tree_space(alloctree) == 0 && - range_tree_space(*freetree) == 0 && + range_tree_space(msp->ms_freeingtree) == 0 && !msp->ms_condense_wanted) return; /* * The only state that can actually be changing concurrently with * metaslab_sync() is the metaslab's ms_tree. No other thread can - * be modifying this txg's alloctree, freetree, freed_tree, or + * be modifying this txg's alloctree, freeingtree, freedtree, or * space_map_phys_t. Therefore, we only hold ms_lock to satify * space map ASSERTs. We drop it whenever we call into the DMU, * because the DMU can call down to us (e.g. via zio_free()) at @@ -2330,7 +2325,7 @@ metaslab_sync(metaslab_t *msp, uint64_t txg) metaslab_condense(msp, txg, tx); } else { space_map_write(msp->ms_sm, alloctree, SM_ALLOC, tx); - space_map_write(msp->ms_sm, *freetree, SM_FREE, tx); + space_map_write(msp->ms_sm, msp->ms_freeingtree, SM_FREE, tx); } if (msp->ms_loaded) { @@ -2350,7 +2345,7 @@ metaslab_sync(metaslab_t *msp, uint64_t txg) * to accurately reflect all free space even if some space * is not yet available for allocation (i.e. deferred). */ - space_map_histogram_add(msp->ms_sm, *freed_tree, tx); + space_map_histogram_add(msp->ms_sm, msp->ms_freedtree, tx); /* * Add back any deferred free space that has not been @@ -2372,7 +2367,7 @@ metaslab_sync(metaslab_t *msp, uint64_t txg) * then we will lose some accuracy but will correct it the next * time we load the space map. */ - space_map_histogram_add(msp->ms_sm, *freetree, tx); + space_map_histogram_add(msp->ms_sm, msp->ms_freeingtree, tx); metaslab_group_histogram_add(mg, msp); metaslab_group_histogram_verify(mg); @@ -2380,20 +2375,21 @@ metaslab_sync(metaslab_t *msp, uint64_t txg) /* * For sync pass 1, we avoid traversing this txg's free range tree - * and instead will just swap the pointers for freetree and - * freed_tree. We can safely do this since the freed_tree is + * and instead will just swap the pointers for freeingtree and + * freedtree. We can safely do this since the freed_tree is * guaranteed to be empty on the initial pass. */ if (spa_sync_pass(spa) == 1) { - range_tree_swap(freetree, freed_tree); + range_tree_swap(&msp->ms_freeingtree, &msp->ms_freedtree); } else { - range_tree_vacate(*freetree, range_tree_add, *freed_tree); + range_tree_vacate(msp->ms_freeingtree, + range_tree_add, msp->ms_freedtree); } range_tree_vacate(alloctree, NULL, NULL); ASSERT0(range_tree_space(msp->ms_alloctree[txg & TXG_MASK])); ASSERT0(range_tree_space(msp->ms_alloctree[TXG_CLEAN(txg) & TXG_MASK])); - ASSERT0(range_tree_space(msp->ms_freetree[txg & TXG_MASK])); + ASSERT0(range_tree_space(msp->ms_freeingtree)); mutex_exit(&msp->ms_lock); @@ -2415,7 +2411,6 @@ metaslab_sync_done(metaslab_t *msp, uint64_t txg) metaslab_group_t *mg = msp->ms_group; vdev_t *vd = mg->mg_vd; spa_t *spa = vd->vdev_spa; - range_tree_t **freed_tree; range_tree_t **defer_tree; int64_t alloc_delta, defer_delta; boolean_t defer_allowed = B_TRUE; @@ -2426,20 +2421,24 @@ metaslab_sync_done(metaslab_t *msp, uint64_t txg) /* * If this metaslab is just becoming available, initialize its - * alloctrees, freetrees, and defertree and add its capacity to - * the vdev. + * range trees and add its capacity to the vdev. */ - if (msp->ms_freetree[TXG_CLEAN(txg) & TXG_MASK] == NULL) { + if (msp->ms_freedtree == NULL) { for (int t = 0; t < TXG_SIZE; t++) { ASSERT(msp->ms_alloctree[t] == NULL); - ASSERT(msp->ms_freetree[t] == NULL); msp->ms_alloctree[t] = range_tree_create(NULL, msp, &msp->ms_lock); - msp->ms_freetree[t] = range_tree_create(NULL, msp, - &msp->ms_lock); } + ASSERT3P(msp->ms_freeingtree, ==, NULL); + msp->ms_freeingtree = range_tree_create(NULL, msp, + &msp->ms_lock); + + ASSERT3P(msp->ms_freedtree, ==, NULL); + msp->ms_freedtree = range_tree_create(NULL, msp, + &msp->ms_lock); + for (int t = 0; t < TXG_DEFER_SIZE; t++) { ASSERT(msp->ms_defertree[t] == NULL); @@ -2450,7 +2449,6 @@ metaslab_sync_done(metaslab_t *msp, uint64_t txg) vdev_space_update(vd, 0, 0, msp->ms_size); } - freed_tree = &msp->ms_freetree[TXG_CLEAN(txg) & TXG_MASK]; defer_tree = &msp->ms_defertree[txg % TXG_DEFER_SIZE]; uint64_t free_space = metaslab_class_get_space(spa_normal_class(spa)) - @@ -2462,7 +2460,7 @@ metaslab_sync_done(metaslab_t *msp, uint64_t txg) defer_delta = 0; alloc_delta = space_map_alloc_delta(msp->ms_sm); if (defer_allowed) { - defer_delta = range_tree_space(*freed_tree) - + defer_delta = range_tree_space(msp->ms_freedtree) - range_tree_space(*defer_tree); } else { defer_delta -= range_tree_space(*defer_tree); @@ -2470,9 +2468,6 @@ metaslab_sync_done(metaslab_t *msp, uint64_t txg) vdev_space_update(vd, alloc_delta + defer_delta, defer_delta, 0); - ASSERT0(range_tree_space(msp->ms_alloctree[txg & TXG_MASK])); - ASSERT0(range_tree_space(msp->ms_freetree[txg & TXG_MASK])); - /* * If there's a metaslab_load() in progress, wait for it to complete * so that we have a consistent view of the in-core space map. @@ -2488,9 +2483,9 @@ metaslab_sync_done(metaslab_t *msp, uint64_t txg) range_tree_vacate(*defer_tree, msp->ms_loaded ? range_tree_add : NULL, msp->ms_tree); if (defer_allowed) { - range_tree_swap(freed_tree, defer_tree); + range_tree_swap(&msp->ms_freedtree, defer_tree); } else { - range_tree_vacate(*freed_tree, + range_tree_vacate(msp->ms_freedtree, msp->ms_loaded ? range_tree_add : NULL, msp->ms_tree); } @@ -3250,10 +3245,10 @@ metaslab_free_dva(spa_t *spa, const dva_t *dva, uint64_t txg, boolean_t now) range_tree_add(msp->ms_tree, offset, size); msp->ms_max_size = metaslab_block_maxsize(msp); } else { - if (range_tree_space(msp->ms_freetree[txg & TXG_MASK]) == 0) + VERIFY3U(txg, ==, spa->spa_syncing_txg); + if (range_tree_space(msp->ms_freeingtree) == 0) vdev_dirty(vd, VDD_METASLAB, msp, txg); - range_tree_add(msp->ms_freetree[txg & TXG_MASK], - offset, size); + range_tree_add(msp->ms_freeingtree, offset, size); } mutex_exit(&msp->ms_lock); @@ -3485,8 +3480,8 @@ metaslab_check_free(spa_t *spa, const blkptr_t *bp) if (msp->ms_loaded) range_tree_verify(msp->ms_tree, offset, size); - for (int j = 0; j < TXG_SIZE; j++) - range_tree_verify(msp->ms_freetree[j], offset, size); + range_tree_verify(msp->ms_freeingtree, offset, size); + range_tree_verify(msp->ms_freedtree, offset, size); for (int j = 0; j < TXG_DEFER_SIZE; j++) range_tree_verify(msp->ms_defertree[j], offset, size); } diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c index 601f4deb505..1cec5658923 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c @@ -2731,10 +2731,14 @@ spa_load_impl(spa_t *spa, uint64_t pool_guid, nvlist_t *config, error = spa_dir_prop(spa, DMU_POOL_VDEV_ZAP_MAP, &spa->spa_all_vdev_zaps); - if (error != ENOENT && error != 0) { + if (error == ENOENT) { + VERIFY(!nvlist_exists(mos_config, + ZPOOL_CONFIG_HAS_PER_VDEV_ZAPS)); + spa->spa_avz_action = AVZ_ACTION_INITIALIZE; + ASSERT0(vdev_count_verify_zaps(spa->spa_root_vdev)); + } else if (error != 0) { return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO)); - } else if (error == 0 && !nvlist_exists(mos_config, - ZPOOL_CONFIG_HAS_PER_VDEV_ZAPS)) { + } else if (!nvlist_exists(mos_config, ZPOOL_CONFIG_HAS_PER_VDEV_ZAPS)) { /* * An older version of ZFS overwrote the sentinel value, so * we have orphaned per-vdev ZAPs in the MOS. Defer their @@ -6498,6 +6502,7 @@ spa_sync_config_object(spa_t *spa, dmu_tx_t *tx) spa_config_enter(spa, SCL_STATE, FTAG, RW_READER); ASSERT(spa->spa_avz_action == AVZ_ACTION_NONE || + spa->spa_avz_action == AVZ_ACTION_INITIALIZE || spa->spa_all_vdev_zaps != 0); if (spa->spa_avz_action == AVZ_ACTION_REBUILD) { diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu.h index 0d3b04414d7..489a93dedc3 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu.h @@ -567,12 +567,7 @@ typedef struct dmu_buf_user { * NOTE: This function should only be called once on a given dmu_buf_user_t. * To allow enforcement of this, dbu must already be zeroed on entry. */ -#ifdef __lint -/* Very ugly, but it beats issuing suppression directives in many Makefiles. */ -extern void -dmu_buf_init_user(dmu_buf_user_t *dbu, dmu_buf_evict_func_t *evict_func, - dmu_buf_evict_func_t *evict_func_async, dmu_buf_t **clear_on_evict_dbufp); -#else /* __lint */ +/*ARGSUSED*/ inline void dmu_buf_init_user(dmu_buf_user_t *dbu, dmu_buf_evict_func_t *evict_func_sync, dmu_buf_evict_func_t *evict_func_async, dmu_buf_t **clear_on_evict_dbufp) @@ -588,7 +583,6 @@ dmu_buf_init_user(dmu_buf_user_t *dbu, dmu_buf_evict_func_t *evict_func_sync, dbu->dbu_clear_on_evict_dbufp = clear_on_evict_dbufp; #endif } -#endif /* __lint */ /* * Attach user data to a dbuf and mark it for normal (when the dbuf's diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dnode.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dnode.h index a3538f52f96..733751f07ca 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dnode.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dnode.h @@ -58,6 +58,12 @@ extern "C" { */ #define DNODE_SHIFT 9 /* 512 bytes */ #define DN_MIN_INDBLKSHIFT 12 /* 4k */ +/* + * If we ever increase this value beyond 20, we need to revisit all logic that + * does x << level * ebps to handle overflow. With a 1M indirect block size, + * 4 levels of indirect blocks would not be able to guarantee addressing an + * entire object, so 5 levels will be used, but 5 * (20 - 7) = 65. + */ #define DN_MAX_INDBLKSHIFT 17 /* 128k */ #define DNODE_BLOCK_SHIFT 14 /* 16k */ #define DNODE_CORE_SIZE 64 /* 64 bytes for dnode sans blkptrs */ diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/metaslab_impl.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/metaslab_impl.h index 02c6926752b..783cd371272 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/metaslab_impl.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/metaslab_impl.h @@ -255,21 +255,24 @@ struct metaslab_group { #define MAX_LBAS 64 /* - * Each metaslab maintains a set of in-core trees to track metaslab operations. - * The in-core free tree (ms_tree) contains the current list of free segments. - * As blocks are allocated, the allocated segment are removed from the ms_tree - * and added to a per txg allocation tree (ms_alloctree). As blocks are freed, - * they are added to the per txg free tree (ms_freetree). These per txg - * trees allow us to process all allocations and frees in syncing context - * where it is safe to update the on-disk space maps. One additional in-core - * tree is maintained to track deferred frees (ms_defertree). Once a block - * is freed it will move from the ms_freetree to the ms_defertree. A deferred - * free means that a block has been freed but cannot be used by the pool - * until TXG_DEFER_SIZE transactions groups later. For example, a block - * that is freed in txg 50 will not be available for reallocation until - * txg 52 (50 + TXG_DEFER_SIZE). This provides a safety net for uberblock - * rollback. A pool could be safely rolled back TXG_DEFERS_SIZE - * transactions groups and ensure that no block has been reallocated. + * Each metaslab maintains a set of in-core trees to track metaslab + * operations. The in-core free tree (ms_tree) contains the list of + * free segments which are eligible for allocation. As blocks are + * allocated, the allocated segments are removed from the ms_tree and + * added to a per txg allocation tree (ms_alloctree). This allows us to + * process all allocations in syncing context where it is safe to update + * the on-disk space maps. Frees are also processed in syncing context. + * Most frees are generated from syncing context, and those that are not + * are held in the spa_free_bplist for processing in syncing context. + * An additional set of in-core trees is maintained to track deferred + * frees (ms_defertree). Once a block is freed it will move from the + * ms_freedtree to the ms_defertree. A deferred free means that a block + * has been freed but cannot be used by the pool until TXG_DEFER_SIZE + * transactions groups later. For example, a block that is freed in txg + * 50 will not be available for reallocation until txg 52 (50 + + * TXG_DEFER_SIZE). This provides a safety net for uberblock rollback. + * A pool could be safely rolled back TXG_DEFERS_SIZE transactions + * groups and ensure that no block has been reallocated. * * The simplified transition diagram looks like this: * @@ -277,33 +280,34 @@ struct metaslab_group { * ALLOCATE * | * V - * free segment (ms_tree) --------> ms_alloctree ----> (write to space map) + * free segment (ms_tree) -----> ms_alloctree[4] ----> (write to space map) * ^ - * | - * | ms_freetree <--- FREE + * | ms_freeingtree <--- FREE * | | + * | v + * | ms_freedtree * | | - * | | - * +----------- ms_defertree <-------+---------> (write to space map) + * +-------- ms_defertree[2] <-------+---------> (write to space map) * * * Each metaslab's space is tracked in a single space map in the MOS, - * which is only updated in syncing context. Each time we sync a txg, - * we append the allocs and frees from that txg to the space map. - * The pool space is only updated once all metaslabs have finished syncing. + * which is only updated in syncing context. Each time we sync a txg, + * we append the allocs and frees from that txg to the space map. The + * pool space is only updated once all metaslabs have finished syncing. * - * To load the in-core free tree we read the space map from disk. - * This object contains a series of alloc and free records that are - * combined to make up the list of all free segments in this metaslab. These + * To load the in-core free tree we read the space map from disk. This + * object contains a series of alloc and free records that are combined + * to make up the list of all free segments in this metaslab. These * segments are represented in-core by the ms_tree and are stored in an * AVL tree. * * As the space map grows (as a result of the appends) it will - * eventually become space-inefficient. When the metaslab's in-core free tree - * is zfs_condense_pct/100 times the size of the minimal on-disk - * representation, we rewrite it in its minimized form. If a metaslab - * needs to condense then we must set the ms_condensing flag to ensure - * that allocations are not performed on the metaslab that is being written. + * eventually become space-inefficient. When the metaslab's in-core + * free tree is zfs_condense_pct/100 times the size of the minimal + * on-disk representation, we rewrite it in its minimized form. If a + * metaslab needs to condense then we must set the ms_condensing flag to + * ensure that allocations are not performed on the metaslab that is + * being written. */ struct metaslab { kmutex_t ms_lock; @@ -315,10 +319,17 @@ struct metaslab { uint64_t ms_fragmentation; range_tree_t *ms_alloctree[TXG_SIZE]; - range_tree_t *ms_freetree[TXG_SIZE]; - range_tree_t *ms_defertree[TXG_DEFER_SIZE]; range_tree_t *ms_tree; + /* + * The following range trees are accessed only from syncing context. + * ms_free*tree only have entries while syncing, and are empty + * between syncs. + */ + range_tree_t *ms_freeingtree; /* to free this syncing txg */ + range_tree_t *ms_freedtree; /* already freed this syncing txg */ + range_tree_t *ms_defertree[TXG_DEFER_SIZE]; + boolean_t ms_condensing; /* condensing? */ boolean_t ms_condense_wanted; diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa.h index 984c1741596..a28408f1c89 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa.h @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011, 2014 by Delphix. All rights reserved. + * Copyright (c) 2011, 2016 by Delphix. All rights reserved. * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved. * Copyright 2013 Saso Kiselkov. All rights reserved. @@ -36,6 +36,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -611,8 +612,6 @@ _NOTE(CONSTCOND) } while (0) ASSERT(len < size); \ } -#include - #define BP_GET_BUFC_TYPE(bp) \ (((BP_GET_LEVEL(bp) > 0) || (DMU_OT_IS_METADATA(BP_GET_TYPE(bp)))) ? \ ARC_BUFC_METADATA : ARC_BUFC_DATA) diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa_impl.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa_impl.h index 33d671327de..f308e738743 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa_impl.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa_impl.h @@ -120,7 +120,8 @@ typedef struct spa_taskqs { typedef enum spa_all_vdev_zap_action { AVZ_ACTION_NONE = 0, AVZ_ACTION_DESTROY, /* Destroy all per-vdev ZAPs and the AVZ. */ - AVZ_ACTION_REBUILD /* Populate the new AVZ, see spa_avz_rebuild */ + AVZ_ACTION_REBUILD, /* Populate the new AVZ, see spa_avz_rebuild */ + AVZ_ACTION_INITIALIZE } spa_avz_action_t; struct spa { diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c index 564469d2964..00fc6802c31 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c @@ -962,7 +962,7 @@ zio_free_sync(zio_t *pio, spa_t *spa, uint64_t txg, const blkptr_t *bp, flags |= ZIO_FLAG_DONT_QUEUE; zio = zio_create(pio, spa, txg, bp, NULL, size, - BP_GET_PSIZE(bp), NULL, NULL, ZIO_TYPE_FREE, ZIO_PRIORITY_NOW, + size, NULL, NULL, ZIO_TYPE_FREE, ZIO_PRIORITY_NOW, flags, NULL, 0, NULL, ZIO_STAGE_OPEN, stage); return (zio); diff --git a/sys/cddl/dev/dtrace/dtrace_load.c b/sys/cddl/dev/dtrace/dtrace_load.c index 3ff12e0582d..029af60d1cd 100644 --- a/sys/cddl/dev/dtrace/dtrace_load.c +++ b/sys/cddl/dev/dtrace/dtrace_load.c @@ -97,11 +97,9 @@ dtrace_load(void *dummy) mutex_init(&dtrace_errlock,"dtrace error lock", MUTEX_DEFAULT, NULL); #endif + mutex_enter(&cpu_lock); mutex_enter(&dtrace_provider_lock); mutex_enter(&dtrace_lock); - mutex_enter(&cpu_lock); - - ASSERT(MUTEX_HELD(&cpu_lock)); dtrace_state_cache = kmem_cache_create("dtrace_state_cache", sizeof (dtrace_dstate_percpu_t) * NCPU, DTRACE_STATE_ALIGN, @@ -151,13 +149,9 @@ dtrace_load(void *dummy) dtrace_probeid_error = dtrace_probe_create((dtrace_provider_id_t) dtrace_provider, NULL, NULL, "ERROR", 1, NULL); - mutex_exit(&cpu_lock); - mutex_exit(&dtrace_lock); mutex_exit(&dtrace_provider_lock); - mutex_enter(&cpu_lock); - #ifdef EARLY_AP_STARTUP CPU_FOREACH(i) { (void) dtrace_cpu_setup(CPU_CONFIG, i); @@ -173,6 +167,4 @@ dtrace_load(void *dummy) "dtrace/dtrace"); helper_dev = make_dev(&helper_cdevsw, 0, UID_ROOT, GID_WHEEL, 0660, "dtrace/helper"); - - return; } diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c index 37b8595ea34..6480fc823a5 100644 --- a/sys/compat/linux/linux_file.c +++ b/sys/compat/linux/linux_file.c @@ -826,7 +826,7 @@ linux_symlinkat(struct thread *td, struct linux_symlinkat_args *args) int error, dfd; dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; - LCONVPATHEXIST_AT(td, args->oldname, &path, dfd); + LCONVPATHEXIST(td, args->oldname, &path); /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd); if (to == NULL) { diff --git a/sys/compat/linux/linux_futex.c b/sys/compat/linux/linux_futex.c index 3075afbc266..7cbdaea6f5a 100644 --- a/sys/compat/linux/linux_futex.c +++ b/sys/compat/linux/linux_futex.c @@ -952,6 +952,11 @@ retry1: args->uaddr, args->val, args->uaddr2, args->val3, args->timeout); + if (args->uaddr == args->uaddr2) { + LIN_SDT_PROBE1(futex, linux_sys_futex, return, EINVAL); + return (EINVAL); + } + retry2: error = futex_get(args->uaddr, NULL, &f, flags | FUTEX_DONTLOCK); if (error) { @@ -959,9 +964,7 @@ retry2: return (error); } - if (args->uaddr != args->uaddr2) - error = futex_get(args->uaddr2, NULL, &f2, - flags | FUTEX_DONTLOCK); + error = futex_get(args->uaddr2, NULL, &f2, flags | FUTEX_DONTLOCK); if (error) { futex_put(f, NULL); diff --git a/sys/compat/linuxkpi/common/include/asm/smp.h b/sys/compat/linuxkpi/common/include/asm/smp.h new file mode 100644 index 00000000000..aeb9a797aa4 --- /dev/null +++ b/sys/compat/linuxkpi/common/include/asm/smp.h @@ -0,0 +1,40 @@ +/*- + * Copyright (c) 2017 Mark Johnston + * + * 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. + * + * $FreeBSD$ + */ + +#ifndef _ASM_SMP_H_ +#define _ASM_SMP_H_ + +#if defined(__i386__) || defined(__amd64__) + +#define wbinvd_on_all_cpus() linux_wbinvd_on_all_cpus() + +int linux_wbinvd_on_all_cpus(void); + +#endif + +#endif /* _ASM_SMP_H_ */ diff --git a/sys/compat/linuxkpi/common/include/linux/smp.h b/sys/compat/linuxkpi/common/include/linux/smp.h new file mode 100644 index 00000000000..3f568401554 --- /dev/null +++ b/sys/compat/linuxkpi/common/include/linux/smp.h @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 2017 Mark Johnston + * + * 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. + * + * $FreeBSD$ + */ + +#ifndef _LINUX_SMP_H_ +#define _LINUX_SMP_H_ + +#define on_each_cpu(cb, data, wait) ({ \ + CTASSERT(wait); \ + linux_on_each_cpu(cb, data); \ +}) + +extern int linux_on_each_cpu(void (*)(void *), void *); + +#endif /* _LINUX_SMP_H_ */ diff --git a/sys/compat/linuxkpi/common/src/linux_compat.c b/sys/compat/linuxkpi/common/src/linux_compat.c index 9d3e13de806..b608d049567 100644 --- a/sys/compat/linuxkpi/common/src/linux_compat.c +++ b/sys/compat/linuxkpi/common/src/linux_compat.c @@ -48,6 +48,9 @@ __FBSDID("$FreeBSD$"); #include #include +#include +#include +#include #include @@ -74,8 +77,11 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include -#include +#if defined(__i386__) || defined(__amd64__) +#include +#endif SYSCTL_NODE(_compat, OID_AUTO, linuxkpi, CTLFLAG_RW, 0, "LinuxKPI parameters"); @@ -1619,6 +1625,31 @@ linux_irq_handler(void *ent) irqe->handler(irqe->irq, irqe->arg); } +#if defined(__i386__) || defined(__amd64__) +static void +wbinvd_cb(void *arg __unused) +{ + + wbinvd(); +} + +int +linux_wbinvd_on_all_cpus(void) +{ + + return (linux_on_each_cpu(wbinvd_cb, NULL)); +} +#endif + +int +linux_on_each_cpu(void callback(void *), void *data) +{ + + smp_rendezvous(smp_no_rendezvous_barrier, callback, + smp_no_rendezvous_barrier, data); + return (0); +} + struct linux_cdev * linux_find_cdev(const char *name, unsigned major, unsigned minor) { diff --git a/sys/compat/linuxkpi/common/src/linux_page.c b/sys/compat/linuxkpi/common/src/linux_page.c index c2adc909743..98c6a6eae98 100644 --- a/sys/compat/linuxkpi/common/src/linux_page.c +++ b/sys/compat/linuxkpi/common/src/linux_page.c @@ -71,14 +71,16 @@ __FBSDID("$FreeBSD$"); void * linux_page_address(struct page *page) { + + if (page->object != kmem_object && page->object != kernel_object) { #ifdef LINUXKPI_HAVE_DMAP - return ((void *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(page))); + return ((void *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(page))); #else - if (page->object != kmem_object && page->object != kernel_object) return (NULL); +#endif + } return ((void *)(uintptr_t)(VM_MIN_KERNEL_ADDRESS + IDX_TO_OFF(page->pindex))); -#endif } vm_page_t diff --git a/sys/conf/files b/sys/conf/files index e49b5085f9b..c63c4e17711 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1331,6 +1331,8 @@ dev/cxgbe/t4_main.c optional cxgbe pci \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/t4_netmap.c optional cxgbe pci \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" +dev/cxgbe/t4_sched.c optional cxgbe pci \ + compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/t4_sge.c optional cxgbe pci \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/t4_l2t.c optional cxgbe pci \ @@ -1425,6 +1427,9 @@ t6fw.fw optional cxgbe \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "t6fw.fw" +dev/cy/cy.c optional cy +dev/cy/cy_isa.c optional cy isa +dev/cy/cy_pci.c optional cy pci dev/cyapa/cyapa.c optional cyapa iicbus dev/dc/if_dc.c optional dc pci dev/dc/dcphy.c optional dc pci diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64 index cb2b84ca522..ad05c4b7953 100644 --- a/sys/conf/files.arm64 +++ b/sys/conf/files.arm64 @@ -191,6 +191,7 @@ libkern/fls.c standard libkern/flsl.c standard libkern/flsll.c standard libkern/memset.c standard +libkern/arm64/crc32c_armv8.S standard cddl/contrib/opensolaris/common/atomic/aarch64/opensolaris_atomic.S optional zfs | dtrace compile-with "${CDDL_C}" cddl/dev/dtrace/aarch64/dtrace_asm.S optional dtrace compile-with "${DTRACE_S}" cddl/dev/dtrace/aarch64/dtrace_subr.c optional dtrace compile-with "${DTRACE_C}" diff --git a/sys/contrib/ena-com/ena_admin_defs.h b/sys/contrib/ena-com/ena_admin_defs.h new file mode 100644 index 00000000000..1d845c08256 --- /dev/null +++ b/sys/contrib/ena-com/ena_admin_defs.h @@ -0,0 +1,1412 @@ +/*- + * BSD LICENSE + * + * Copyright (c) 2015-2017 Amazon.com, Inc. or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + */ + +#ifndef _ENA_ADMIN_H_ +#define _ENA_ADMIN_H_ + +enum ena_admin_aq_opcode { + ENA_ADMIN_CREATE_SQ = 1, + + ENA_ADMIN_DESTROY_SQ = 2, + + ENA_ADMIN_CREATE_CQ = 3, + + ENA_ADMIN_DESTROY_CQ = 4, + + ENA_ADMIN_GET_FEATURE = 8, + + ENA_ADMIN_SET_FEATURE = 9, + + ENA_ADMIN_GET_STATS = 11, +}; + +enum ena_admin_aq_completion_status { + ENA_ADMIN_SUCCESS = 0, + + ENA_ADMIN_RESOURCE_ALLOCATION_FAILURE = 1, + + ENA_ADMIN_BAD_OPCODE = 2, + + ENA_ADMIN_UNSUPPORTED_OPCODE = 3, + + ENA_ADMIN_MALFORMED_REQUEST = 4, + + /* Additional status is provided in ACQ entry extended_status */ + ENA_ADMIN_ILLEGAL_PARAMETER = 5, + + ENA_ADMIN_UNKNOWN_ERROR = 6, +}; + +enum ena_admin_aq_feature_id { + ENA_ADMIN_DEVICE_ATTRIBUTES = 1, + + ENA_ADMIN_MAX_QUEUES_NUM = 2, + + ENA_ADMIN_HW_HINTS = 3, + + ENA_ADMIN_RSS_HASH_FUNCTION = 10, + + ENA_ADMIN_STATELESS_OFFLOAD_CONFIG = 11, + + ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG = 12, + + ENA_ADMIN_MTU = 14, + + ENA_ADMIN_RSS_HASH_INPUT = 18, + + ENA_ADMIN_INTERRUPT_MODERATION = 20, + + ENA_ADMIN_AENQ_CONFIG = 26, + + ENA_ADMIN_LINK_CONFIG = 27, + + ENA_ADMIN_HOST_ATTR_CONFIG = 28, + + ENA_ADMIN_FEATURES_OPCODE_NUM = 32, +}; + +enum ena_admin_placement_policy_type { + /* descriptors and headers are in host memory */ + ENA_ADMIN_PLACEMENT_POLICY_HOST = 1, + + /* descriptors and headers are in device memory (a.k.a Low Latency + * Queue) + */ + ENA_ADMIN_PLACEMENT_POLICY_DEV = 3, +}; + +enum ena_admin_link_types { + ENA_ADMIN_LINK_SPEED_1G = 0x1, + + ENA_ADMIN_LINK_SPEED_2_HALF_G = 0x2, + + ENA_ADMIN_LINK_SPEED_5G = 0x4, + + ENA_ADMIN_LINK_SPEED_10G = 0x8, + + ENA_ADMIN_LINK_SPEED_25G = 0x10, + + ENA_ADMIN_LINK_SPEED_40G = 0x20, + + ENA_ADMIN_LINK_SPEED_50G = 0x40, + + ENA_ADMIN_LINK_SPEED_100G = 0x80, + + ENA_ADMIN_LINK_SPEED_200G = 0x100, + + ENA_ADMIN_LINK_SPEED_400G = 0x200, +}; + +enum ena_admin_completion_policy_type { + /* completion queue entry for each sq descriptor */ + ENA_ADMIN_COMPLETION_POLICY_DESC = 0, + + /* completion queue entry upon request in sq descriptor */ + ENA_ADMIN_COMPLETION_POLICY_DESC_ON_DEMAND = 1, + + /* current queue head pointer is updated in OS memory upon sq + * descriptor request + */ + ENA_ADMIN_COMPLETION_POLICY_HEAD_ON_DEMAND = 2, + + /* current queue head pointer is updated in OS memory for each sq + * descriptor + */ + ENA_ADMIN_COMPLETION_POLICY_HEAD = 3, +}; + +/* basic stats return ena_admin_basic_stats while extanded stats return a + * buffer (string format) with additional statistics per queue and per + * device id + */ +enum ena_admin_get_stats_type { + ENA_ADMIN_GET_STATS_TYPE_BASIC = 0, + + ENA_ADMIN_GET_STATS_TYPE_EXTENDED = 1, +}; + +enum ena_admin_get_stats_scope { + ENA_ADMIN_SPECIFIC_QUEUE = 0, + + ENA_ADMIN_ETH_TRAFFIC = 1, +}; + +struct ena_admin_aq_common_desc { + /* 11:0 : command_id + * 15:12 : reserved12 + */ + uint16_t command_id; + + /* as appears in ena_admin_aq_opcode */ + uint8_t opcode; + + /* 0 : phase + * 1 : ctrl_data - control buffer address valid + * 2 : ctrl_data_indirect - control buffer address + * points to list of pages with addresses of control + * buffers + * 7:3 : reserved3 + */ + uint8_t flags; +}; + +/* used in ena_admin_aq_entry. Can point directly to control data, or to a + * page list chunk. Used also at the end of indirect mode page list chunks, + * for chaining. + */ +struct ena_admin_ctrl_buff_info { + uint32_t length; + + struct ena_common_mem_addr address; +}; + +struct ena_admin_sq { + uint16_t sq_idx; + + /* 4:0 : reserved + * 7:5 : sq_direction - 0x1 - Tx; 0x2 - Rx + */ + uint8_t sq_identity; + + uint8_t reserved1; +}; + +struct ena_admin_aq_entry { + struct ena_admin_aq_common_desc aq_common_descriptor; + + union { + uint32_t inline_data_w1[3]; + + struct ena_admin_ctrl_buff_info control_buffer; + } u; + + uint32_t inline_data_w4[12]; +}; + +struct ena_admin_acq_common_desc { + /* command identifier to associate it with the aq descriptor + * 11:0 : command_id + * 15:12 : reserved12 + */ + uint16_t command; + + uint8_t status; + + /* 0 : phase + * 7:1 : reserved1 + */ + uint8_t flags; + + uint16_t extended_status; + + /* serves as a hint what AQ entries can be revoked */ + uint16_t sq_head_indx; +}; + +struct ena_admin_acq_entry { + struct ena_admin_acq_common_desc acq_common_descriptor; + + uint32_t response_specific_data[14]; +}; + +struct ena_admin_aq_create_sq_cmd { + struct ena_admin_aq_common_desc aq_common_descriptor; + + /* 4:0 : reserved0_w1 + * 7:5 : sq_direction - 0x1 - Tx, 0x2 - Rx + */ + uint8_t sq_identity; + + uint8_t reserved8_w1; + + /* 3:0 : placement_policy - Describing where the SQ + * descriptor ring and the SQ packet headers reside: + * 0x1 - descriptors and headers are in OS memory, + * 0x3 - descriptors and headers in device memory + * (a.k.a Low Latency Queue) + * 6:4 : completion_policy - Describing what policy + * to use for generation completion entry (cqe) in + * the CQ associated with this SQ: 0x0 - cqe for each + * sq descriptor, 0x1 - cqe upon request in sq + * descriptor, 0x2 - current queue head pointer is + * updated in OS memory upon sq descriptor request + * 0x3 - current queue head pointer is updated in OS + * memory for each sq descriptor + * 7 : reserved15_w1 + */ + uint8_t sq_caps_2; + + /* 0 : is_physically_contiguous - Described if the + * queue ring memory is allocated in physical + * contiguous pages or split. + * 7:1 : reserved17_w1 + */ + uint8_t sq_caps_3; + + /* associated completion queue id. This CQ must be created prior to + * SQ creation + */ + uint16_t cq_idx; + + /* submission queue depth in entries */ + uint16_t sq_depth; + + /* SQ physical base address in OS memory. This field should not be + * used for Low Latency queues. Has to be page aligned. + */ + struct ena_common_mem_addr sq_ba; + + /* specifies queue head writeback location in OS memory. Valid if + * completion_policy is set to completion_policy_head_on_demand or + * completion_policy_head. Has to be cache aligned + */ + struct ena_common_mem_addr sq_head_writeback; + + uint32_t reserved0_w7; + + uint32_t reserved0_w8; +}; + +enum ena_admin_sq_direction { + ENA_ADMIN_SQ_DIRECTION_TX = 1, + + ENA_ADMIN_SQ_DIRECTION_RX = 2, +}; + +struct ena_admin_acq_create_sq_resp_desc { + struct ena_admin_acq_common_desc acq_common_desc; + + uint16_t sq_idx; + + uint16_t reserved; + + /* queue doorbell address as an offset to PCIe MMIO REG BAR */ + uint32_t sq_doorbell_offset; + + /* low latency queue ring base address as an offset to PCIe MMIO + * LLQ_MEM BAR + */ + uint32_t llq_descriptors_offset; + + /* low latency queue headers' memory as an offset to PCIe MMIO + * LLQ_MEM BAR + */ + uint32_t llq_headers_offset; +}; + +struct ena_admin_aq_destroy_sq_cmd { + struct ena_admin_aq_common_desc aq_common_descriptor; + + struct ena_admin_sq sq; +}; + +struct ena_admin_acq_destroy_sq_resp_desc { + struct ena_admin_acq_common_desc acq_common_desc; +}; + +struct ena_admin_aq_create_cq_cmd { + struct ena_admin_aq_common_desc aq_common_descriptor; + + /* 4:0 : reserved5 + * 5 : interrupt_mode_enabled - if set, cq operates + * in interrupt mode, otherwise - polling + * 7:6 : reserved6 + */ + uint8_t cq_caps_1; + + /* 4:0 : cq_entry_size_words - size of CQ entry in + * 32-bit words, valid values: 4, 8. + * 7:5 : reserved7 + */ + uint8_t cq_caps_2; + + /* completion queue depth in # of entries. must be power of 2 */ + uint16_t cq_depth; + + /* msix vector assigned to this cq */ + uint32_t msix_vector; + + /* cq physical base address in OS memory. CQ must be physically + * contiguous + */ + struct ena_common_mem_addr cq_ba; +}; + +struct ena_admin_acq_create_cq_resp_desc { + struct ena_admin_acq_common_desc acq_common_desc; + + uint16_t cq_idx; + + /* actual cq depth in number of entries */ + uint16_t cq_actual_depth; + + uint32_t numa_node_register_offset; + + uint32_t cq_head_db_register_offset; + + uint32_t cq_interrupt_unmask_register_offset; +}; + +struct ena_admin_aq_destroy_cq_cmd { + struct ena_admin_aq_common_desc aq_common_descriptor; + + uint16_t cq_idx; + + uint16_t reserved1; +}; + +struct ena_admin_acq_destroy_cq_resp_desc { + struct ena_admin_acq_common_desc acq_common_desc; +}; + +/* ENA AQ Get Statistics command. Extended statistics are placed in control + * buffer pointed by AQ entry + */ +struct ena_admin_aq_get_stats_cmd { + struct ena_admin_aq_common_desc aq_common_descriptor; + + union { + /* command specific inline data */ + uint32_t inline_data_w1[3]; + + struct ena_admin_ctrl_buff_info control_buffer; + } u; + + /* stats type as defined in enum ena_admin_get_stats_type */ + uint8_t type; + + /* stats scope defined in enum ena_admin_get_stats_scope */ + uint8_t scope; + + uint16_t reserved3; + + /* queue id. used when scope is specific_queue */ + uint16_t queue_idx; + + /* device id, value 0xFFFF means mine. only privileged device can get + * stats of other device + */ + uint16_t device_id; +}; + +/* Basic Statistics Command. */ +struct ena_admin_basic_stats { + uint32_t tx_bytes_low; + + uint32_t tx_bytes_high; + + uint32_t tx_pkts_low; + + uint32_t tx_pkts_high; + + uint32_t rx_bytes_low; + + uint32_t rx_bytes_high; + + uint32_t rx_pkts_low; + + uint32_t rx_pkts_high; + + uint32_t rx_drops_low; + + uint32_t rx_drops_high; +}; + +struct ena_admin_acq_get_stats_resp { + struct ena_admin_acq_common_desc acq_common_desc; + + struct ena_admin_basic_stats basic_stats; +}; + +struct ena_admin_get_set_feature_common_desc { + /* 1:0 : select - 0x1 - current value; 0x3 - default + * value + * 7:3 : reserved3 + */ + uint8_t flags; + + /* as appears in ena_admin_aq_feature_id */ + uint8_t feature_id; + + uint16_t reserved16; +}; + +struct ena_admin_device_attr_feature_desc { + uint32_t impl_id; + + uint32_t device_version; + + /* bitmap of ena_admin_aq_feature_id */ + uint32_t supported_features; + + uint32_t reserved3; + + /* Indicates how many bits are used physical address access. */ + uint32_t phys_addr_width; + + /* Indicates how many bits are used virtual address access. */ + uint32_t virt_addr_width; + + /* unicast MAC address (in Network byte order) */ + uint8_t mac_addr[6]; + + uint8_t reserved7[2]; + + uint32_t max_mtu; +}; + +struct ena_admin_queue_feature_desc { + /* including LLQs */ + uint32_t max_sq_num; + + uint32_t max_sq_depth; + + uint32_t max_cq_num; + + uint32_t max_cq_depth; + + uint32_t max_llq_num; + + uint32_t max_llq_depth; + + uint32_t max_header_size; + + /* Maximum Descriptors number, including meta descriptor, allowed for + * a single Tx packet + */ + uint16_t max_packet_tx_descs; + + /* Maximum Descriptors number allowed for a single Rx packet */ + uint16_t max_packet_rx_descs; +}; + +struct ena_admin_set_feature_mtu_desc { + /* exclude L2 */ + uint32_t mtu; +}; + +struct ena_admin_set_feature_host_attr_desc { + /* host OS info base address in OS memory. host info is 4KB of + * physically contiguous + */ + struct ena_common_mem_addr os_info_ba; + + /* host debug area base address in OS memory. debug area must be + * physically contiguous + */ + struct ena_common_mem_addr debug_ba; + + /* debug area size */ + uint32_t debug_area_size; +}; + +struct ena_admin_feature_intr_moder_desc { + /* interrupt delay granularity in usec */ + uint16_t intr_delay_resolution; + + uint16_t reserved; +}; + +struct ena_admin_get_feature_link_desc { + /* Link speed in Mb */ + uint32_t speed; + + /* bit field of enum ena_admin_link types */ + uint32_t supported; + + /* 0 : autoneg + * 1 : duplex - Full Duplex + * 31:2 : reserved2 + */ + uint32_t flags; +}; + +struct ena_admin_feature_aenq_desc { + /* bitmask for AENQ groups the device can report */ + uint32_t supported_groups; + + /* bitmask for AENQ groups to report */ + uint32_t enabled_groups; +}; + +struct ena_admin_feature_offload_desc { + /* 0 : TX_L3_csum_ipv4 + * 1 : TX_L4_ipv4_csum_part - The checksum field + * should be initialized with pseudo header checksum + * 2 : TX_L4_ipv4_csum_full + * 3 : TX_L4_ipv6_csum_part - The checksum field + * should be initialized with pseudo header checksum + * 4 : TX_L4_ipv6_csum_full + * 5 : tso_ipv4 + * 6 : tso_ipv6 + * 7 : tso_ecn + */ + uint32_t tx; + + /* Receive side supported stateless offload + * 0 : RX_L3_csum_ipv4 - IPv4 checksum + * 1 : RX_L4_ipv4_csum - TCP/UDP/IPv4 checksum + * 2 : RX_L4_ipv6_csum - TCP/UDP/IPv6 checksum + * 3 : RX_hash - Hash calculation + */ + uint32_t rx_supported; + + uint32_t rx_enabled; +}; + +enum ena_admin_hash_functions { + ENA_ADMIN_TOEPLITZ = 1, + + ENA_ADMIN_CRC32 = 2, +}; + +struct ena_admin_feature_rss_flow_hash_control { + uint32_t keys_num; + + uint32_t reserved; + + uint32_t key[10]; +}; + +struct ena_admin_feature_rss_flow_hash_function { + /* 7:0 : funcs - bitmask of ena_admin_hash_functions */ + uint32_t supported_func; + + /* 7:0 : selected_func - bitmask of + * ena_admin_hash_functions + */ + uint32_t selected_func; + + /* initial value */ + uint32_t init_val; +}; + +/* RSS flow hash protocols */ +enum ena_admin_flow_hash_proto { + ENA_ADMIN_RSS_TCP4 = 0, + + ENA_ADMIN_RSS_UDP4 = 1, + + ENA_ADMIN_RSS_TCP6 = 2, + + ENA_ADMIN_RSS_UDP6 = 3, + + ENA_ADMIN_RSS_IP4 = 4, + + ENA_ADMIN_RSS_IP6 = 5, + + ENA_ADMIN_RSS_IP4_FRAG = 6, + + ENA_ADMIN_RSS_NOT_IP = 7, + + /* TCPv6 with extension header */ + ENA_ADMIN_RSS_TCP6_EX = 8, + + /* IPv6 with extension header */ + ENA_ADMIN_RSS_IP6_EX = 9, + + ENA_ADMIN_RSS_PROTO_NUM = 16, +}; + +/* RSS flow hash fields */ +enum ena_admin_flow_hash_fields { + /* Ethernet Dest Addr */ + ENA_ADMIN_RSS_L2_DA = BIT(0), + + /* Ethernet Src Addr */ + ENA_ADMIN_RSS_L2_SA = BIT(1), + + /* ipv4/6 Dest Addr */ + ENA_ADMIN_RSS_L3_DA = BIT(2), + + /* ipv4/6 Src Addr */ + ENA_ADMIN_RSS_L3_SA = BIT(3), + + /* tcp/udp Dest Port */ + ENA_ADMIN_RSS_L4_DP = BIT(4), + + /* tcp/udp Src Port */ + ENA_ADMIN_RSS_L4_SP = BIT(5), +}; + +struct ena_admin_proto_input { + /* flow hash fields (bitwise according to ena_admin_flow_hash_fields) */ + uint16_t fields; + + uint16_t reserved2; +}; + +struct ena_admin_feature_rss_hash_control { + struct ena_admin_proto_input supported_fields[ENA_ADMIN_RSS_PROTO_NUM]; + + struct ena_admin_proto_input selected_fields[ENA_ADMIN_RSS_PROTO_NUM]; + + struct ena_admin_proto_input reserved2[ENA_ADMIN_RSS_PROTO_NUM]; + + struct ena_admin_proto_input reserved3[ENA_ADMIN_RSS_PROTO_NUM]; +}; + +struct ena_admin_feature_rss_flow_hash_input { + /* supported hash input sorting + * 1 : L3_sort - support swap L3 addresses if DA is + * smaller than SA + * 2 : L4_sort - support swap L4 ports if DP smaller + * SP + */ + uint16_t supported_input_sort; + + /* enabled hash input sorting + * 1 : enable_L3_sort - enable swap L3 addresses if + * DA smaller than SA + * 2 : enable_L4_sort - enable swap L4 ports if DP + * smaller than SP + */ + uint16_t enabled_input_sort; +}; + +enum ena_admin_os_type { + ENA_ADMIN_OS_LINUX = 1, + + ENA_ADMIN_OS_WIN = 2, + + ENA_ADMIN_OS_DPDK = 3, + + ENA_ADMIN_OS_FREEBSD = 4, + + ENA_ADMIN_OS_IPXE = 5, +}; + +struct ena_admin_host_info { + /* defined in enum ena_admin_os_type */ + uint32_t os_type; + + /* os distribution string format */ + uint8_t os_dist_str[128]; + + /* OS distribution numeric format */ + uint32_t os_dist; + + /* kernel version string format */ + uint8_t kernel_ver_str[32]; + + /* Kernel version numeric format */ + uint32_t kernel_ver; + + /* 7:0 : major + * 15:8 : minor + * 23:16 : sub_minor + */ + uint32_t driver_version; + + /* features bitmap */ + uint32_t supported_network_features[4]; +}; + +struct ena_admin_rss_ind_table_entry { + uint16_t cq_idx; + + uint16_t reserved; +}; + +struct ena_admin_feature_rss_ind_table { + /* min supported table size (2^min_size) */ + uint16_t min_size; + + /* max supported table size (2^max_size) */ + uint16_t max_size; + + /* table size (2^size) */ + uint16_t size; + + uint16_t reserved; + + /* index of the inline entry. 0xFFFFFFFF means invalid */ + uint32_t inline_index; + + /* used for updating single entry, ignored when setting the entire + * table through the control buffer. + */ + struct ena_admin_rss_ind_table_entry inline_entry; +}; + +/* When hint value is 0, driver should use it's own predefined value */ +struct ena_admin_ena_hw_hints { + /* value in ms */ + uint16_t mmio_read_timeout; + + /* value in ms */ + uint16_t driver_watchdog_timeout; + + /* Per packet tx completion timeout. value in ms */ + uint16_t missing_tx_completion_timeout; + + uint16_t missed_tx_completion_count_threshold_to_reset; + + /* value in ms */ + uint16_t admin_completion_tx_timeout; + + uint16_t netdev_wd_timeout; + + uint16_t max_tx_sgl_size; + + uint16_t max_rx_sgl_size; + + uint16_t reserved[8]; +}; + +struct ena_admin_get_feat_cmd { + struct ena_admin_aq_common_desc aq_common_descriptor; + + struct ena_admin_ctrl_buff_info control_buffer; + + struct ena_admin_get_set_feature_common_desc feat_common; + + uint32_t raw[11]; +}; + +struct ena_admin_get_feat_resp { + struct ena_admin_acq_common_desc acq_common_desc; + + union { + uint32_t raw[14]; + + struct ena_admin_device_attr_feature_desc dev_attr; + + struct ena_admin_queue_feature_desc max_queue; + + struct ena_admin_feature_aenq_desc aenq; + + struct ena_admin_get_feature_link_desc link; + + struct ena_admin_feature_offload_desc offload; + + struct ena_admin_feature_rss_flow_hash_function flow_hash_func; + + struct ena_admin_feature_rss_flow_hash_input flow_hash_input; + + struct ena_admin_feature_rss_ind_table ind_table; + + struct ena_admin_feature_intr_moder_desc intr_moderation; + + struct ena_admin_ena_hw_hints hw_hints; + } u; +}; + +struct ena_admin_set_feat_cmd { + struct ena_admin_aq_common_desc aq_common_descriptor; + + struct ena_admin_ctrl_buff_info control_buffer; + + struct ena_admin_get_set_feature_common_desc feat_common; + + union { + uint32_t raw[11]; + + /* mtu size */ + struct ena_admin_set_feature_mtu_desc mtu; + + /* host attributes */ + struct ena_admin_set_feature_host_attr_desc host_attr; + + /* AENQ configuration */ + struct ena_admin_feature_aenq_desc aenq; + + /* rss flow hash function */ + struct ena_admin_feature_rss_flow_hash_function flow_hash_func; + + /* rss flow hash input */ + struct ena_admin_feature_rss_flow_hash_input flow_hash_input; + + /* rss indirection table */ + struct ena_admin_feature_rss_ind_table ind_table; + } u; +}; + +struct ena_admin_set_feat_resp { + struct ena_admin_acq_common_desc acq_common_desc; + + union { + uint32_t raw[14]; + } u; +}; + +struct ena_admin_aenq_common_desc { + uint16_t group; + + uint16_t syndrom; + + /* 0 : phase */ + uint8_t flags; + + uint8_t reserved1[3]; + + uint32_t timestamp_low; + + uint32_t timestamp_high; +}; + +/* asynchronous event notification groups */ +enum ena_admin_aenq_group { + ENA_ADMIN_LINK_CHANGE = 0, + + ENA_ADMIN_FATAL_ERROR = 1, + + ENA_ADMIN_WARNING = 2, + + ENA_ADMIN_NOTIFICATION = 3, + + ENA_ADMIN_KEEP_ALIVE = 4, + + ENA_ADMIN_AENQ_GROUPS_NUM = 5, +}; + +enum ena_admin_aenq_notification_syndrom { + ENA_ADMIN_SUSPEND = 0, + + ENA_ADMIN_RESUME = 1, + + ENA_ADMIN_UPDATE_HINTS = 2, +}; + +struct ena_admin_aenq_entry { + struct ena_admin_aenq_common_desc aenq_common_desc; + + /* command specific inline data */ + uint32_t inline_data_w4[12]; +}; + +struct ena_admin_aenq_link_change_desc { + struct ena_admin_aenq_common_desc aenq_common_desc; + + /* 0 : link_status */ + uint32_t flags; +}; + +struct ena_admin_aenq_keep_alive_desc { + struct ena_admin_aenq_common_desc aenq_common_desc; + + uint32_t rx_drops_low; + + uint32_t rx_drops_high; +}; + +struct ena_admin_ena_mmio_req_read_less_resp { + uint16_t req_id; + + uint16_t reg_off; + + /* value is valid when poll is cleared */ + uint32_t reg_val; +}; + +/* aq_common_desc */ +#define ENA_ADMIN_AQ_COMMON_DESC_COMMAND_ID_MASK GENMASK(11, 0) +#define ENA_ADMIN_AQ_COMMON_DESC_PHASE_MASK BIT(0) +#define ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_SHIFT 1 +#define ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_MASK BIT(1) +#define ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_SHIFT 2 +#define ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_MASK BIT(2) + +/* sq */ +#define ENA_ADMIN_SQ_SQ_DIRECTION_SHIFT 5 +#define ENA_ADMIN_SQ_SQ_DIRECTION_MASK GENMASK(7, 5) + +/* acq_common_desc */ +#define ENA_ADMIN_ACQ_COMMON_DESC_COMMAND_ID_MASK GENMASK(11, 0) +#define ENA_ADMIN_ACQ_COMMON_DESC_PHASE_MASK BIT(0) + +/* aq_create_sq_cmd */ +#define ENA_ADMIN_AQ_CREATE_SQ_CMD_SQ_DIRECTION_SHIFT 5 +#define ENA_ADMIN_AQ_CREATE_SQ_CMD_SQ_DIRECTION_MASK GENMASK(7, 5) +#define ENA_ADMIN_AQ_CREATE_SQ_CMD_PLACEMENT_POLICY_MASK GENMASK(3, 0) +#define ENA_ADMIN_AQ_CREATE_SQ_CMD_COMPLETION_POLICY_SHIFT 4 +#define ENA_ADMIN_AQ_CREATE_SQ_CMD_COMPLETION_POLICY_MASK GENMASK(6, 4) +#define ENA_ADMIN_AQ_CREATE_SQ_CMD_IS_PHYSICALLY_CONTIGUOUS_MASK BIT(0) + +/* aq_create_cq_cmd */ +#define ENA_ADMIN_AQ_CREATE_CQ_CMD_INTERRUPT_MODE_ENABLED_SHIFT 5 +#define ENA_ADMIN_AQ_CREATE_CQ_CMD_INTERRUPT_MODE_ENABLED_MASK BIT(5) +#define ENA_ADMIN_AQ_CREATE_CQ_CMD_CQ_ENTRY_SIZE_WORDS_MASK GENMASK(4, 0) + +/* get_set_feature_common_desc */ +#define ENA_ADMIN_GET_SET_FEATURE_COMMON_DESC_SELECT_MASK GENMASK(1, 0) + +/* get_feature_link_desc */ +#define ENA_ADMIN_GET_FEATURE_LINK_DESC_AUTONEG_MASK BIT(0) +#define ENA_ADMIN_GET_FEATURE_LINK_DESC_DUPLEX_SHIFT 1 +#define ENA_ADMIN_GET_FEATURE_LINK_DESC_DUPLEX_MASK BIT(1) + +/* feature_offload_desc */ +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L3_CSUM_IPV4_MASK BIT(0) +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_PART_SHIFT 1 +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_PART_MASK BIT(1) +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_FULL_SHIFT 2 +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_FULL_MASK BIT(2) +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_PART_SHIFT 3 +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_PART_MASK BIT(3) +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_FULL_SHIFT 4 +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_FULL_MASK BIT(4) +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV4_SHIFT 5 +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV4_MASK BIT(5) +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV6_SHIFT 6 +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV6_MASK BIT(6) +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_ECN_SHIFT 7 +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_ECN_MASK BIT(7) +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L3_CSUM_IPV4_MASK BIT(0) +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV4_CSUM_SHIFT 1 +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV4_CSUM_MASK BIT(1) +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV6_CSUM_SHIFT 2 +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV6_CSUM_MASK BIT(2) +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_HASH_SHIFT 3 +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_HASH_MASK BIT(3) + +/* feature_rss_flow_hash_function */ +#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_FUNCTION_FUNCS_MASK GENMASK(7, 0) +#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_FUNCTION_SELECTED_FUNC_MASK GENMASK(7, 0) + +/* feature_rss_flow_hash_input */ +#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L3_SORT_SHIFT 1 +#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L3_SORT_MASK BIT(1) +#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L4_SORT_SHIFT 2 +#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L4_SORT_MASK BIT(2) +#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_ENABLE_L3_SORT_SHIFT 1 +#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_ENABLE_L3_SORT_MASK BIT(1) +#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_ENABLE_L4_SORT_SHIFT 2 +#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_ENABLE_L4_SORT_MASK BIT(2) + +/* host_info */ +#define ENA_ADMIN_HOST_INFO_MAJOR_MASK GENMASK(7, 0) +#define ENA_ADMIN_HOST_INFO_MINOR_SHIFT 8 +#define ENA_ADMIN_HOST_INFO_MINOR_MASK GENMASK(15, 8) +#define ENA_ADMIN_HOST_INFO_SUB_MINOR_SHIFT 16 +#define ENA_ADMIN_HOST_INFO_SUB_MINOR_MASK GENMASK(23, 16) + +/* aenq_common_desc */ +#define ENA_ADMIN_AENQ_COMMON_DESC_PHASE_MASK BIT(0) + +/* aenq_link_change_desc */ +#define ENA_ADMIN_AENQ_LINK_CHANGE_DESC_LINK_STATUS_MASK BIT(0) + +#if !defined(ENA_DEFS_LINUX_MAINLINE) +static inline uint16_t get_ena_admin_aq_common_desc_command_id(const struct ena_admin_aq_common_desc *p) +{ + return p->command_id & ENA_ADMIN_AQ_COMMON_DESC_COMMAND_ID_MASK; +} + +static inline void set_ena_admin_aq_common_desc_command_id(struct ena_admin_aq_common_desc *p, uint16_t val) +{ + p->command_id |= val & ENA_ADMIN_AQ_COMMON_DESC_COMMAND_ID_MASK; +} + +static inline uint8_t get_ena_admin_aq_common_desc_phase(const struct ena_admin_aq_common_desc *p) +{ + return p->flags & ENA_ADMIN_AQ_COMMON_DESC_PHASE_MASK; +} + +static inline void set_ena_admin_aq_common_desc_phase(struct ena_admin_aq_common_desc *p, uint8_t val) +{ + p->flags |= val & ENA_ADMIN_AQ_COMMON_DESC_PHASE_MASK; +} + +static inline uint8_t get_ena_admin_aq_common_desc_ctrl_data(const struct ena_admin_aq_common_desc *p) +{ + return (p->flags & ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_MASK) >> ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_SHIFT; +} + +static inline void set_ena_admin_aq_common_desc_ctrl_data(struct ena_admin_aq_common_desc *p, uint8_t val) +{ + p->flags |= (val << ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_SHIFT) & ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_MASK; +} + +static inline uint8_t get_ena_admin_aq_common_desc_ctrl_data_indirect(const struct ena_admin_aq_common_desc *p) +{ + return (p->flags & ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_MASK) >> ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_SHIFT; +} + +static inline void set_ena_admin_aq_common_desc_ctrl_data_indirect(struct ena_admin_aq_common_desc *p, uint8_t val) +{ + p->flags |= (val << ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_SHIFT) & ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_MASK; +} + +static inline uint8_t get_ena_admin_sq_sq_direction(const struct ena_admin_sq *p) +{ + return (p->sq_identity & ENA_ADMIN_SQ_SQ_DIRECTION_MASK) >> ENA_ADMIN_SQ_SQ_DIRECTION_SHIFT; +} + +static inline void set_ena_admin_sq_sq_direction(struct ena_admin_sq *p, uint8_t val) +{ + p->sq_identity |= (val << ENA_ADMIN_SQ_SQ_DIRECTION_SHIFT) & ENA_ADMIN_SQ_SQ_DIRECTION_MASK; +} + +static inline uint16_t get_ena_admin_acq_common_desc_command_id(const struct ena_admin_acq_common_desc *p) +{ + return p->command & ENA_ADMIN_ACQ_COMMON_DESC_COMMAND_ID_MASK; +} + +static inline void set_ena_admin_acq_common_desc_command_id(struct ena_admin_acq_common_desc *p, uint16_t val) +{ + p->command |= val & ENA_ADMIN_ACQ_COMMON_DESC_COMMAND_ID_MASK; +} + +static inline uint8_t get_ena_admin_acq_common_desc_phase(const struct ena_admin_acq_common_desc *p) +{ + return p->flags & ENA_ADMIN_ACQ_COMMON_DESC_PHASE_MASK; +} + +static inline void set_ena_admin_acq_common_desc_phase(struct ena_admin_acq_common_desc *p, uint8_t val) +{ + p->flags |= val & ENA_ADMIN_ACQ_COMMON_DESC_PHASE_MASK; +} + +static inline uint8_t get_ena_admin_aq_create_sq_cmd_sq_direction(const struct ena_admin_aq_create_sq_cmd *p) +{ + return (p->sq_identity & ENA_ADMIN_AQ_CREATE_SQ_CMD_SQ_DIRECTION_MASK) >> ENA_ADMIN_AQ_CREATE_SQ_CMD_SQ_DIRECTION_SHIFT; +} + +static inline void set_ena_admin_aq_create_sq_cmd_sq_direction(struct ena_admin_aq_create_sq_cmd *p, uint8_t val) +{ + p->sq_identity |= (val << ENA_ADMIN_AQ_CREATE_SQ_CMD_SQ_DIRECTION_SHIFT) & ENA_ADMIN_AQ_CREATE_SQ_CMD_SQ_DIRECTION_MASK; +} + +static inline uint8_t get_ena_admin_aq_create_sq_cmd_placement_policy(const struct ena_admin_aq_create_sq_cmd *p) +{ + return p->sq_caps_2 & ENA_ADMIN_AQ_CREATE_SQ_CMD_PLACEMENT_POLICY_MASK; +} + +static inline void set_ena_admin_aq_create_sq_cmd_placement_policy(struct ena_admin_aq_create_sq_cmd *p, uint8_t val) +{ + p->sq_caps_2 |= val & ENA_ADMIN_AQ_CREATE_SQ_CMD_PLACEMENT_POLICY_MASK; +} + +static inline uint8_t get_ena_admin_aq_create_sq_cmd_completion_policy(const struct ena_admin_aq_create_sq_cmd *p) +{ + return (p->sq_caps_2 & ENA_ADMIN_AQ_CREATE_SQ_CMD_COMPLETION_POLICY_MASK) >> ENA_ADMIN_AQ_CREATE_SQ_CMD_COMPLETION_POLICY_SHIFT; +} + +static inline void set_ena_admin_aq_create_sq_cmd_completion_policy(struct ena_admin_aq_create_sq_cmd *p, uint8_t val) +{ + p->sq_caps_2 |= (val << ENA_ADMIN_AQ_CREATE_SQ_CMD_COMPLETION_POLICY_SHIFT) & ENA_ADMIN_AQ_CREATE_SQ_CMD_COMPLETION_POLICY_MASK; +} + +static inline uint8_t get_ena_admin_aq_create_sq_cmd_is_physically_contiguous(const struct ena_admin_aq_create_sq_cmd *p) +{ + return p->sq_caps_3 & ENA_ADMIN_AQ_CREATE_SQ_CMD_IS_PHYSICALLY_CONTIGUOUS_MASK; +} + +static inline void set_ena_admin_aq_create_sq_cmd_is_physically_contiguous(struct ena_admin_aq_create_sq_cmd *p, uint8_t val) +{ + p->sq_caps_3 |= val & ENA_ADMIN_AQ_CREATE_SQ_CMD_IS_PHYSICALLY_CONTIGUOUS_MASK; +} + +static inline uint8_t get_ena_admin_aq_create_cq_cmd_interrupt_mode_enabled(const struct ena_admin_aq_create_cq_cmd *p) +{ + return (p->cq_caps_1 & ENA_ADMIN_AQ_CREATE_CQ_CMD_INTERRUPT_MODE_ENABLED_MASK) >> ENA_ADMIN_AQ_CREATE_CQ_CMD_INTERRUPT_MODE_ENABLED_SHIFT; +} + +static inline void set_ena_admin_aq_create_cq_cmd_interrupt_mode_enabled(struct ena_admin_aq_create_cq_cmd *p, uint8_t val) +{ + p->cq_caps_1 |= (val << ENA_ADMIN_AQ_CREATE_CQ_CMD_INTERRUPT_MODE_ENABLED_SHIFT) & ENA_ADMIN_AQ_CREATE_CQ_CMD_INTERRUPT_MODE_ENABLED_MASK; +} + +static inline uint8_t get_ena_admin_aq_create_cq_cmd_cq_entry_size_words(const struct ena_admin_aq_create_cq_cmd *p) +{ + return p->cq_caps_2 & ENA_ADMIN_AQ_CREATE_CQ_CMD_CQ_ENTRY_SIZE_WORDS_MASK; +} + +static inline void set_ena_admin_aq_create_cq_cmd_cq_entry_size_words(struct ena_admin_aq_create_cq_cmd *p, uint8_t val) +{ + p->cq_caps_2 |= val & ENA_ADMIN_AQ_CREATE_CQ_CMD_CQ_ENTRY_SIZE_WORDS_MASK; +} + +static inline uint8_t get_ena_admin_get_set_feature_common_desc_select(const struct ena_admin_get_set_feature_common_desc *p) +{ + return p->flags & ENA_ADMIN_GET_SET_FEATURE_COMMON_DESC_SELECT_MASK; +} + +static inline void set_ena_admin_get_set_feature_common_desc_select(struct ena_admin_get_set_feature_common_desc *p, uint8_t val) +{ + p->flags |= val & ENA_ADMIN_GET_SET_FEATURE_COMMON_DESC_SELECT_MASK; +} + +static inline uint32_t get_ena_admin_get_feature_link_desc_autoneg(const struct ena_admin_get_feature_link_desc *p) +{ + return p->flags & ENA_ADMIN_GET_FEATURE_LINK_DESC_AUTONEG_MASK; +} + +static inline void set_ena_admin_get_feature_link_desc_autoneg(struct ena_admin_get_feature_link_desc *p, uint32_t val) +{ + p->flags |= val & ENA_ADMIN_GET_FEATURE_LINK_DESC_AUTONEG_MASK; +} + +static inline uint32_t get_ena_admin_get_feature_link_desc_duplex(const struct ena_admin_get_feature_link_desc *p) +{ + return (p->flags & ENA_ADMIN_GET_FEATURE_LINK_DESC_DUPLEX_MASK) >> ENA_ADMIN_GET_FEATURE_LINK_DESC_DUPLEX_SHIFT; +} + +static inline void set_ena_admin_get_feature_link_desc_duplex(struct ena_admin_get_feature_link_desc *p, uint32_t val) +{ + p->flags |= (val << ENA_ADMIN_GET_FEATURE_LINK_DESC_DUPLEX_SHIFT) & ENA_ADMIN_GET_FEATURE_LINK_DESC_DUPLEX_MASK; +} + +static inline uint32_t get_ena_admin_feature_offload_desc_TX_L3_csum_ipv4(const struct ena_admin_feature_offload_desc *p) +{ + return p->tx & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L3_CSUM_IPV4_MASK; +} + +static inline void set_ena_admin_feature_offload_desc_TX_L3_csum_ipv4(struct ena_admin_feature_offload_desc *p, uint32_t val) +{ + p->tx |= val & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L3_CSUM_IPV4_MASK; +} + +static inline uint32_t get_ena_admin_feature_offload_desc_TX_L4_ipv4_csum_part(const struct ena_admin_feature_offload_desc *p) +{ + return (p->tx & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_PART_MASK) >> ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_PART_SHIFT; +} + +static inline void set_ena_admin_feature_offload_desc_TX_L4_ipv4_csum_part(struct ena_admin_feature_offload_desc *p, uint32_t val) +{ + p->tx |= (val << ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_PART_SHIFT) & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_PART_MASK; +} + +static inline uint32_t get_ena_admin_feature_offload_desc_TX_L4_ipv4_csum_full(const struct ena_admin_feature_offload_desc *p) +{ + return (p->tx & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_FULL_MASK) >> ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_FULL_SHIFT; +} + +static inline void set_ena_admin_feature_offload_desc_TX_L4_ipv4_csum_full(struct ena_admin_feature_offload_desc *p, uint32_t val) +{ + p->tx |= (val << ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_FULL_SHIFT) & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_FULL_MASK; +} + +static inline uint32_t get_ena_admin_feature_offload_desc_TX_L4_ipv6_csum_part(const struct ena_admin_feature_offload_desc *p) +{ + return (p->tx & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_PART_MASK) >> ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_PART_SHIFT; +} + +static inline void set_ena_admin_feature_offload_desc_TX_L4_ipv6_csum_part(struct ena_admin_feature_offload_desc *p, uint32_t val) +{ + p->tx |= (val << ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_PART_SHIFT) & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_PART_MASK; +} + +static inline uint32_t get_ena_admin_feature_offload_desc_TX_L4_ipv6_csum_full(const struct ena_admin_feature_offload_desc *p) +{ + return (p->tx & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_FULL_MASK) >> ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_FULL_SHIFT; +} + +static inline void set_ena_admin_feature_offload_desc_TX_L4_ipv6_csum_full(struct ena_admin_feature_offload_desc *p, uint32_t val) +{ + p->tx |= (val << ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_FULL_SHIFT) & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_FULL_MASK; +} + +static inline uint32_t get_ena_admin_feature_offload_desc_tso_ipv4(const struct ena_admin_feature_offload_desc *p) +{ + return (p->tx & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV4_MASK) >> ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV4_SHIFT; +} + +static inline void set_ena_admin_feature_offload_desc_tso_ipv4(struct ena_admin_feature_offload_desc *p, uint32_t val) +{ + p->tx |= (val << ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV4_SHIFT) & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV4_MASK; +} + +static inline uint32_t get_ena_admin_feature_offload_desc_tso_ipv6(const struct ena_admin_feature_offload_desc *p) +{ + return (p->tx & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV6_MASK) >> ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV6_SHIFT; +} + +static inline void set_ena_admin_feature_offload_desc_tso_ipv6(struct ena_admin_feature_offload_desc *p, uint32_t val) +{ + p->tx |= (val << ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV6_SHIFT) & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV6_MASK; +} + +static inline uint32_t get_ena_admin_feature_offload_desc_tso_ecn(const struct ena_admin_feature_offload_desc *p) +{ + return (p->tx & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_ECN_MASK) >> ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_ECN_SHIFT; +} + +static inline void set_ena_admin_feature_offload_desc_tso_ecn(struct ena_admin_feature_offload_desc *p, uint32_t val) +{ + p->tx |= (val << ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_ECN_SHIFT) & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_ECN_MASK; +} + +static inline uint32_t get_ena_admin_feature_offload_desc_RX_L3_csum_ipv4(const struct ena_admin_feature_offload_desc *p) +{ + return p->rx_supported & ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L3_CSUM_IPV4_MASK; +} + +static inline void set_ena_admin_feature_offload_desc_RX_L3_csum_ipv4(struct ena_admin_feature_offload_desc *p, uint32_t val) +{ + p->rx_supported |= val & ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L3_CSUM_IPV4_MASK; +} + +static inline uint32_t get_ena_admin_feature_offload_desc_RX_L4_ipv4_csum(const struct ena_admin_feature_offload_desc *p) +{ + return (p->rx_supported & ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV4_CSUM_MASK) >> ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV4_CSUM_SHIFT; +} + +static inline void set_ena_admin_feature_offload_desc_RX_L4_ipv4_csum(struct ena_admin_feature_offload_desc *p, uint32_t val) +{ + p->rx_supported |= (val << ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV4_CSUM_SHIFT) & ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV4_CSUM_MASK; +} + +static inline uint32_t get_ena_admin_feature_offload_desc_RX_L4_ipv6_csum(const struct ena_admin_feature_offload_desc *p) +{ + return (p->rx_supported & ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV6_CSUM_MASK) >> ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV6_CSUM_SHIFT; +} + +static inline void set_ena_admin_feature_offload_desc_RX_L4_ipv6_csum(struct ena_admin_feature_offload_desc *p, uint32_t val) +{ + p->rx_supported |= (val << ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV6_CSUM_SHIFT) & ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV6_CSUM_MASK; +} + +static inline uint32_t get_ena_admin_feature_offload_desc_RX_hash(const struct ena_admin_feature_offload_desc *p) +{ + return (p->rx_supported & ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_HASH_MASK) >> ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_HASH_SHIFT; +} + +static inline void set_ena_admin_feature_offload_desc_RX_hash(struct ena_admin_feature_offload_desc *p, uint32_t val) +{ + p->rx_supported |= (val << ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_HASH_SHIFT) & ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_HASH_MASK; +} + +static inline uint32_t get_ena_admin_feature_rss_flow_hash_function_funcs(const struct ena_admin_feature_rss_flow_hash_function *p) +{ + return p->supported_func & ENA_ADMIN_FEATURE_RSS_FLOW_HASH_FUNCTION_FUNCS_MASK; +} + +static inline void set_ena_admin_feature_rss_flow_hash_function_funcs(struct ena_admin_feature_rss_flow_hash_function *p, uint32_t val) +{ + p->supported_func |= val & ENA_ADMIN_FEATURE_RSS_FLOW_HASH_FUNCTION_FUNCS_MASK; +} + +static inline uint32_t get_ena_admin_feature_rss_flow_hash_function_selected_func(const struct ena_admin_feature_rss_flow_hash_function *p) +{ + return p->selected_func & ENA_ADMIN_FEATURE_RSS_FLOW_HASH_FUNCTION_SELECTED_FUNC_MASK; +} + +static inline void set_ena_admin_feature_rss_flow_hash_function_selected_func(struct ena_admin_feature_rss_flow_hash_function *p, uint32_t val) +{ + p->selected_func |= val & ENA_ADMIN_FEATURE_RSS_FLOW_HASH_FUNCTION_SELECTED_FUNC_MASK; +} + +static inline uint16_t get_ena_admin_feature_rss_flow_hash_input_L3_sort(const struct ena_admin_feature_rss_flow_hash_input *p) +{ + return (p->supported_input_sort & ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L3_SORT_MASK) >> ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L3_SORT_SHIFT; +} + +static inline void set_ena_admin_feature_rss_flow_hash_input_L3_sort(struct ena_admin_feature_rss_flow_hash_input *p, uint16_t val) +{ + p->supported_input_sort |= (val << ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L3_SORT_SHIFT) & ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L3_SORT_MASK; +} + +static inline uint16_t get_ena_admin_feature_rss_flow_hash_input_L4_sort(const struct ena_admin_feature_rss_flow_hash_input *p) +{ + return (p->supported_input_sort & ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L4_SORT_MASK) >> ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L4_SORT_SHIFT; +} + +static inline void set_ena_admin_feature_rss_flow_hash_input_L4_sort(struct ena_admin_feature_rss_flow_hash_input *p, uint16_t val) +{ + p->supported_input_sort |= (val << ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L4_SORT_SHIFT) & ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L4_SORT_MASK; +} + +static inline uint16_t get_ena_admin_feature_rss_flow_hash_input_enable_L3_sort(const struct ena_admin_feature_rss_flow_hash_input *p) +{ + return (p->enabled_input_sort & ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_ENABLE_L3_SORT_MASK) >> ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_ENABLE_L3_SORT_SHIFT; +} + +static inline void set_ena_admin_feature_rss_flow_hash_input_enable_L3_sort(struct ena_admin_feature_rss_flow_hash_input *p, uint16_t val) +{ + p->enabled_input_sort |= (val << ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_ENABLE_L3_SORT_SHIFT) & ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_ENABLE_L3_SORT_MASK; +} + +static inline uint16_t get_ena_admin_feature_rss_flow_hash_input_enable_L4_sort(const struct ena_admin_feature_rss_flow_hash_input *p) +{ + return (p->enabled_input_sort & ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_ENABLE_L4_SORT_MASK) >> ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_ENABLE_L4_SORT_SHIFT; +} + +static inline void set_ena_admin_feature_rss_flow_hash_input_enable_L4_sort(struct ena_admin_feature_rss_flow_hash_input *p, uint16_t val) +{ + p->enabled_input_sort |= (val << ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_ENABLE_L4_SORT_SHIFT) & ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_ENABLE_L4_SORT_MASK; +} + +static inline uint32_t get_ena_admin_host_info_major(const struct ena_admin_host_info *p) +{ + return p->driver_version & ENA_ADMIN_HOST_INFO_MAJOR_MASK; +} + +static inline void set_ena_admin_host_info_major(struct ena_admin_host_info *p, uint32_t val) +{ + p->driver_version |= val & ENA_ADMIN_HOST_INFO_MAJOR_MASK; +} + +static inline uint32_t get_ena_admin_host_info_minor(const struct ena_admin_host_info *p) +{ + return (p->driver_version & ENA_ADMIN_HOST_INFO_MINOR_MASK) >> ENA_ADMIN_HOST_INFO_MINOR_SHIFT; +} + +static inline void set_ena_admin_host_info_minor(struct ena_admin_host_info *p, uint32_t val) +{ + p->driver_version |= (val << ENA_ADMIN_HOST_INFO_MINOR_SHIFT) & ENA_ADMIN_HOST_INFO_MINOR_MASK; +} + +static inline uint32_t get_ena_admin_host_info_sub_minor(const struct ena_admin_host_info *p) +{ + return (p->driver_version & ENA_ADMIN_HOST_INFO_SUB_MINOR_MASK) >> ENA_ADMIN_HOST_INFO_SUB_MINOR_SHIFT; +} + +static inline void set_ena_admin_host_info_sub_minor(struct ena_admin_host_info *p, uint32_t val) +{ + p->driver_version |= (val << ENA_ADMIN_HOST_INFO_SUB_MINOR_SHIFT) & ENA_ADMIN_HOST_INFO_SUB_MINOR_MASK; +} + +static inline uint8_t get_ena_admin_aenq_common_desc_phase(const struct ena_admin_aenq_common_desc *p) +{ + return p->flags & ENA_ADMIN_AENQ_COMMON_DESC_PHASE_MASK; +} + +static inline void set_ena_admin_aenq_common_desc_phase(struct ena_admin_aenq_common_desc *p, uint8_t val) +{ + p->flags |= val & ENA_ADMIN_AENQ_COMMON_DESC_PHASE_MASK; +} + +static inline uint32_t get_ena_admin_aenq_link_change_desc_link_status(const struct ena_admin_aenq_link_change_desc *p) +{ + return p->flags & ENA_ADMIN_AENQ_LINK_CHANGE_DESC_LINK_STATUS_MASK; +} + +static inline void set_ena_admin_aenq_link_change_desc_link_status(struct ena_admin_aenq_link_change_desc *p, uint32_t val) +{ + p->flags |= val & ENA_ADMIN_AENQ_LINK_CHANGE_DESC_LINK_STATUS_MASK; +} + +#endif /* !defined(ENA_DEFS_LINUX_MAINLINE) */ +#endif /*_ENA_ADMIN_H_ */ diff --git a/sys/contrib/ena-com/ena_com.c b/sys/contrib/ena-com/ena_com.c new file mode 100644 index 00000000000..c17ac243df0 --- /dev/null +++ b/sys/contrib/ena-com/ena_com.c @@ -0,0 +1,2761 @@ +/*- + * BSD LICENSE + * + * Copyright (c) 2015-2017 Amazon.com, Inc. or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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 "ena_com.h" +#ifdef ENA_INTERNAL +#include "ena_gen_info.h" +#endif + +/*****************************************************************************/ +/*****************************************************************************/ + +/* Timeout in micro-sec */ +#define ADMIN_CMD_TIMEOUT_US (3000000) + +#define ENA_ASYNC_QUEUE_DEPTH 16 +#define ENA_ADMIN_QUEUE_DEPTH 32 + +#define MIN_ENA_VER (((ENA_COMMON_SPEC_VERSION_MAJOR) << \ + ENA_REGS_VERSION_MAJOR_VERSION_SHIFT) \ + | (ENA_COMMON_SPEC_VERSION_MINOR)) + +#define ENA_CTRL_MAJOR 0 +#define ENA_CTRL_MINOR 0 +#define ENA_CTRL_SUB_MINOR 1 + +#define MIN_ENA_CTRL_VER \ + (((ENA_CTRL_MAJOR) << \ + (ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_SHIFT)) | \ + ((ENA_CTRL_MINOR) << \ + (ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_SHIFT)) | \ + (ENA_CTRL_SUB_MINOR)) + +#define ENA_DMA_ADDR_TO_UINT32_LOW(x) ((u32)((u64)(x))) +#define ENA_DMA_ADDR_TO_UINT32_HIGH(x) ((u32)(((u64)(x)) >> 32)) + +#define ENA_MMIO_READ_TIMEOUT 0xFFFFFFFF + +/*****************************************************************************/ +/*****************************************************************************/ +/*****************************************************************************/ + +enum ena_cmd_status { + ENA_CMD_SUBMITTED, + ENA_CMD_COMPLETED, + /* Abort - canceled by the driver */ + ENA_CMD_ABORTED, +}; + +struct ena_comp_ctx { + ena_wait_event_t wait_event; + struct ena_admin_acq_entry *user_cqe; + u32 comp_size; + enum ena_cmd_status status; + /* status from the device */ + u8 comp_status; + u8 cmd_opcode; + bool occupied; +}; + +struct ena_com_stats_ctx { + struct ena_admin_aq_get_stats_cmd get_cmd; + struct ena_admin_acq_get_stats_resp get_resp; +}; + +static inline int ena_com_mem_addr_set(struct ena_com_dev *ena_dev, + struct ena_common_mem_addr *ena_addr, + dma_addr_t addr) +{ + if ((addr & GENMASK_ULL(ena_dev->dma_addr_bits - 1, 0)) != addr) { + ena_trc_err("dma address has more bits that the device supports\n"); + return ENA_COM_INVAL; + } + + ena_addr->mem_addr_low = (u32)addr; + ena_addr->mem_addr_high = (u64)addr >> 32; + + return 0; +} + +static int ena_com_admin_init_sq(struct ena_com_admin_queue *queue) +{ + struct ena_com_admin_sq *sq = &queue->sq; + u16 size = ADMIN_SQ_SIZE(queue->q_depth); + + ENA_MEM_ALLOC_COHERENT(queue->q_dmadev, size, sq->entries, sq->dma_addr, + sq->mem_handle); + + if (!sq->entries) { + ena_trc_err("memory allocation failed"); + return ENA_COM_NO_MEM; + } + + sq->head = 0; + sq->tail = 0; + sq->phase = 1; + + sq->db_addr = NULL; + + return 0; +} + +static int ena_com_admin_init_cq(struct ena_com_admin_queue *queue) +{ + struct ena_com_admin_cq *cq = &queue->cq; + u16 size = ADMIN_CQ_SIZE(queue->q_depth); + + ENA_MEM_ALLOC_COHERENT(queue->q_dmadev, size, cq->entries, cq->dma_addr, + cq->mem_handle); + + if (!cq->entries) { + ena_trc_err("memory allocation failed"); + return ENA_COM_NO_MEM; + } + + cq->head = 0; + cq->phase = 1; + + return 0; +} + +static int ena_com_admin_init_aenq(struct ena_com_dev *dev, + struct ena_aenq_handlers *aenq_handlers) +{ + struct ena_com_aenq *aenq = &dev->aenq; + u32 addr_low, addr_high, aenq_caps; + u16 size; + + dev->aenq.q_depth = ENA_ASYNC_QUEUE_DEPTH; + size = ADMIN_AENQ_SIZE(ENA_ASYNC_QUEUE_DEPTH); + ENA_MEM_ALLOC_COHERENT(dev->dmadev, size, + aenq->entries, + aenq->dma_addr, + aenq->mem_handle); + + if (!aenq->entries) { + ena_trc_err("memory allocation failed"); + return ENA_COM_NO_MEM; + } + + aenq->head = aenq->q_depth; + aenq->phase = 1; + + addr_low = ENA_DMA_ADDR_TO_UINT32_LOW(aenq->dma_addr); + addr_high = ENA_DMA_ADDR_TO_UINT32_HIGH(aenq->dma_addr); + + ENA_REG_WRITE32(dev->bus, addr_low, dev->reg_bar + ENA_REGS_AENQ_BASE_LO_OFF); + ENA_REG_WRITE32(dev->bus, addr_high, dev->reg_bar + ENA_REGS_AENQ_BASE_HI_OFF); + + aenq_caps = 0; + aenq_caps |= dev->aenq.q_depth & ENA_REGS_AENQ_CAPS_AENQ_DEPTH_MASK; + aenq_caps |= (sizeof(struct ena_admin_aenq_entry) << + ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_SHIFT) & + ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_MASK; + ENA_REG_WRITE32(dev->bus, aenq_caps, dev->reg_bar + ENA_REGS_AENQ_CAPS_OFF); + + if (unlikely(!aenq_handlers)) { + ena_trc_err("aenq handlers pointer is NULL\n"); + return ENA_COM_INVAL; + } + + aenq->aenq_handlers = aenq_handlers; + + return 0; +} + +static inline void comp_ctxt_release(struct ena_com_admin_queue *queue, + struct ena_comp_ctx *comp_ctx) +{ + comp_ctx->occupied = false; + ATOMIC32_DEC(&queue->outstanding_cmds); +} + +static struct ena_comp_ctx *get_comp_ctxt(struct ena_com_admin_queue *queue, + u16 command_id, bool capture) +{ + if (unlikely(command_id >= queue->q_depth)) { + ena_trc_err("command id is larger than the queue size. cmd_id: %u queue size %d\n", + command_id, queue->q_depth); + return NULL; + } + + if (unlikely(queue->comp_ctx[command_id].occupied && capture)) { + ena_trc_err("Completion context is occupied\n"); + return NULL; + } + + if (capture) { + ATOMIC32_INC(&queue->outstanding_cmds); + queue->comp_ctx[command_id].occupied = true; + } + + return &queue->comp_ctx[command_id]; +} + +static struct ena_comp_ctx *__ena_com_submit_admin_cmd(struct ena_com_admin_queue *admin_queue, + struct ena_admin_aq_entry *cmd, + size_t cmd_size_in_bytes, + struct ena_admin_acq_entry *comp, + size_t comp_size_in_bytes) +{ + struct ena_comp_ctx *comp_ctx; + u16 tail_masked, cmd_id; + u16 queue_size_mask; + u16 cnt; + + queue_size_mask = admin_queue->q_depth - 1; + + tail_masked = admin_queue->sq.tail & queue_size_mask; + + /* In case of queue FULL */ + cnt = admin_queue->sq.tail - admin_queue->sq.head; + if (cnt >= admin_queue->q_depth) { + ena_trc_dbg("admin queue is FULL (tail %d head %d depth: %d)\n", + admin_queue->sq.tail, + admin_queue->sq.head, + admin_queue->q_depth); + admin_queue->stats.out_of_space++; + return ERR_PTR(ENA_COM_NO_SPACE); + } + + cmd_id = admin_queue->curr_cmd_id; + + cmd->aq_common_descriptor.flags |= admin_queue->sq.phase & + ENA_ADMIN_AQ_COMMON_DESC_PHASE_MASK; + + cmd->aq_common_descriptor.command_id |= cmd_id & + ENA_ADMIN_AQ_COMMON_DESC_COMMAND_ID_MASK; + + comp_ctx = get_comp_ctxt(admin_queue, cmd_id, true); + if (unlikely(!comp_ctx)) + return ERR_PTR(ENA_COM_INVAL); + + comp_ctx->status = ENA_CMD_SUBMITTED; + comp_ctx->comp_size = (u32)comp_size_in_bytes; + comp_ctx->user_cqe = comp; + comp_ctx->cmd_opcode = cmd->aq_common_descriptor.opcode; + + ENA_WAIT_EVENT_CLEAR(comp_ctx->wait_event); + + memcpy(&admin_queue->sq.entries[tail_masked], cmd, cmd_size_in_bytes); + + admin_queue->curr_cmd_id = (admin_queue->curr_cmd_id + 1) & + queue_size_mask; + + admin_queue->sq.tail++; + admin_queue->stats.submitted_cmd++; + + if (unlikely((admin_queue->sq.tail & queue_size_mask) == 0)) + admin_queue->sq.phase = !admin_queue->sq.phase; + + ENA_REG_WRITE32(admin_queue->bus, admin_queue->sq.tail, + admin_queue->sq.db_addr); + + return comp_ctx; +} + +static inline int ena_com_init_comp_ctxt(struct ena_com_admin_queue *queue) +{ + size_t size = queue->q_depth * sizeof(struct ena_comp_ctx); + struct ena_comp_ctx *comp_ctx; + u16 i; + + queue->comp_ctx = ENA_MEM_ALLOC(queue->q_dmadev, size); + if (unlikely(!queue->comp_ctx)) { + ena_trc_err("memory allocation failed"); + return ENA_COM_NO_MEM; + } + + for (i = 0; i < queue->q_depth; i++) { + comp_ctx = get_comp_ctxt(queue, i, false); + if (comp_ctx) + ENA_WAIT_EVENT_INIT(comp_ctx->wait_event); + } + + return 0; +} + +static struct ena_comp_ctx *ena_com_submit_admin_cmd(struct ena_com_admin_queue *admin_queue, + struct ena_admin_aq_entry *cmd, + size_t cmd_size_in_bytes, + struct ena_admin_acq_entry *comp, + size_t comp_size_in_bytes) +{ + unsigned long flags; + struct ena_comp_ctx *comp_ctx; + + ENA_SPINLOCK_LOCK(admin_queue->q_lock, flags); + if (unlikely(!admin_queue->running_state)) { + ENA_SPINLOCK_UNLOCK(admin_queue->q_lock, flags); + return ERR_PTR(ENA_COM_NO_DEVICE); + } + comp_ctx = __ena_com_submit_admin_cmd(admin_queue, cmd, + cmd_size_in_bytes, + comp, + comp_size_in_bytes); + if (unlikely(IS_ERR(comp_ctx))) + admin_queue->running_state = false; + ENA_SPINLOCK_UNLOCK(admin_queue->q_lock, flags); + + return comp_ctx; +} + +static int ena_com_init_io_sq(struct ena_com_dev *ena_dev, + struct ena_com_create_io_ctx *ctx, + struct ena_com_io_sq *io_sq) +{ + size_t size; + int dev_node = 0; + + memset(&io_sq->desc_addr, 0x0, sizeof(io_sq->desc_addr)); + + io_sq->desc_entry_size = + (io_sq->direction == ENA_COM_IO_QUEUE_DIRECTION_TX) ? + sizeof(struct ena_eth_io_tx_desc) : + sizeof(struct ena_eth_io_rx_desc); + + size = io_sq->desc_entry_size * io_sq->q_depth; + io_sq->bus = ena_dev->bus; + + if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST) { + ENA_MEM_ALLOC_COHERENT_NODE(ena_dev->dmadev, + size, + io_sq->desc_addr.virt_addr, + io_sq->desc_addr.phys_addr, + io_sq->desc_addr.mem_handle, + ctx->numa_node, + dev_node); + if (!io_sq->desc_addr.virt_addr) { + ENA_MEM_ALLOC_COHERENT(ena_dev->dmadev, + size, + io_sq->desc_addr.virt_addr, + io_sq->desc_addr.phys_addr, + io_sq->desc_addr.mem_handle); + } + } else { + ENA_MEM_ALLOC_NODE(ena_dev->dmadev, + size, + io_sq->desc_addr.virt_addr, + ctx->numa_node, + dev_node); + if (!io_sq->desc_addr.virt_addr) { + io_sq->desc_addr.virt_addr = + ENA_MEM_ALLOC(ena_dev->dmadev, size); + } + } + + if (!io_sq->desc_addr.virt_addr) { + ena_trc_err("memory allocation failed"); + return ENA_COM_NO_MEM; + } + + io_sq->tail = 0; + io_sq->next_to_comp = 0; + io_sq->phase = 1; + + return 0; +} + +static int ena_com_init_io_cq(struct ena_com_dev *ena_dev, + struct ena_com_create_io_ctx *ctx, + struct ena_com_io_cq *io_cq) +{ + size_t size; + int prev_node = 0; + + memset(&io_cq->cdesc_addr, 0x0, sizeof(io_cq->cdesc_addr)); + + /* Use the basic completion descriptor for Rx */ + io_cq->cdesc_entry_size_in_bytes = + (io_cq->direction == ENA_COM_IO_QUEUE_DIRECTION_TX) ? + sizeof(struct ena_eth_io_tx_cdesc) : + sizeof(struct ena_eth_io_rx_cdesc_base); + + size = io_cq->cdesc_entry_size_in_bytes * io_cq->q_depth; + io_cq->bus = ena_dev->bus; + + ENA_MEM_ALLOC_COHERENT_NODE(ena_dev->dmadev, + size, + io_cq->cdesc_addr.virt_addr, + io_cq->cdesc_addr.phys_addr, + io_cq->cdesc_addr.mem_handle, + ctx->numa_node, + prev_node); + if (!io_cq->cdesc_addr.virt_addr) { + ENA_MEM_ALLOC_COHERENT(ena_dev->dmadev, + size, + io_cq->cdesc_addr.virt_addr, + io_cq->cdesc_addr.phys_addr, + io_cq->cdesc_addr.mem_handle); + } + + if (!io_cq->cdesc_addr.virt_addr) { + ena_trc_err("memory allocation failed"); + return ENA_COM_NO_MEM; + } + + io_cq->phase = 1; + io_cq->head = 0; + + return 0; +} + +static void ena_com_handle_single_admin_completion(struct ena_com_admin_queue *admin_queue, + struct ena_admin_acq_entry *cqe) +{ + struct ena_comp_ctx *comp_ctx; + u16 cmd_id; + + cmd_id = cqe->acq_common_descriptor.command & + ENA_ADMIN_ACQ_COMMON_DESC_COMMAND_ID_MASK; + + comp_ctx = get_comp_ctxt(admin_queue, cmd_id, false); + if (unlikely(!comp_ctx)) { + ena_trc_err("comp_ctx is NULL. Changing the admin queue running state\n"); + admin_queue->running_state = false; + return; + } + + comp_ctx->status = ENA_CMD_COMPLETED; + comp_ctx->comp_status = cqe->acq_common_descriptor.status; + + if (comp_ctx->user_cqe) + memcpy(comp_ctx->user_cqe, (void *)cqe, comp_ctx->comp_size); + + if (!admin_queue->polling) + ENA_WAIT_EVENT_SIGNAL(comp_ctx->wait_event); +} + +static void ena_com_handle_admin_completion(struct ena_com_admin_queue *admin_queue) +{ + struct ena_admin_acq_entry *cqe = NULL; + u16 comp_num = 0; + u16 head_masked; + u8 phase; + + head_masked = admin_queue->cq.head & (admin_queue->q_depth - 1); + phase = admin_queue->cq.phase; + + cqe = &admin_queue->cq.entries[head_masked]; + + /* Go over all the completions */ + while ((cqe->acq_common_descriptor.flags & + ENA_ADMIN_ACQ_COMMON_DESC_PHASE_MASK) == phase) { + /* Do not read the rest of the completion entry before the + * phase bit was validated + */ + rmb(); + ena_com_handle_single_admin_completion(admin_queue, cqe); + + head_masked++; + comp_num++; + if (unlikely(head_masked == admin_queue->q_depth)) { + head_masked = 0; + phase = !phase; + } + + cqe = &admin_queue->cq.entries[head_masked]; + } + + admin_queue->cq.head += comp_num; + admin_queue->cq.phase = phase; + admin_queue->sq.head += comp_num; + admin_queue->stats.completed_cmd += comp_num; +} + +static int ena_com_comp_status_to_errno(u8 comp_status) +{ + if (unlikely(comp_status != 0)) + ena_trc_err("admin command failed[%u]\n", comp_status); + + if (unlikely(comp_status > ENA_ADMIN_UNKNOWN_ERROR)) + return ENA_COM_INVAL; + + switch (comp_status) { + case ENA_ADMIN_SUCCESS: + return 0; + case ENA_ADMIN_RESOURCE_ALLOCATION_FAILURE: + return ENA_COM_NO_MEM; + case ENA_ADMIN_UNSUPPORTED_OPCODE: + return ENA_COM_PERMISSION; + case ENA_ADMIN_BAD_OPCODE: + case ENA_ADMIN_MALFORMED_REQUEST: + case ENA_ADMIN_ILLEGAL_PARAMETER: + case ENA_ADMIN_UNKNOWN_ERROR: + return ENA_COM_INVAL; + } + + return 0; +} + +static int ena_com_wait_and_process_admin_cq_polling(struct ena_comp_ctx *comp_ctx, + struct ena_com_admin_queue *admin_queue) +{ + unsigned long flags, timeout; + int ret; + + timeout = ENA_GET_SYSTEM_TIMEOUT(admin_queue->completion_timeout); + + while (1) { + ENA_SPINLOCK_LOCK(admin_queue->q_lock, flags); + ena_com_handle_admin_completion(admin_queue); + ENA_SPINLOCK_UNLOCK(admin_queue->q_lock, flags); + + if (comp_ctx->status != ENA_CMD_SUBMITTED) + break; + + if (ENA_TIME_EXPIRE(timeout)) { + ena_trc_err("Wait for completion (polling) timeout\n"); + /* ENA didn't have any completion */ + ENA_SPINLOCK_LOCK(admin_queue->q_lock, flags); + admin_queue->stats.no_completion++; + admin_queue->running_state = false; + ENA_SPINLOCK_UNLOCK(admin_queue->q_lock, flags); + + ret = ENA_COM_TIMER_EXPIRED; + goto err; + } + + ENA_MSLEEP(100); + } + + if (unlikely(comp_ctx->status == ENA_CMD_ABORTED)) { + ena_trc_err("Command was aborted\n"); + ENA_SPINLOCK_LOCK(admin_queue->q_lock, flags); + admin_queue->stats.aborted_cmd++; + ENA_SPINLOCK_UNLOCK(admin_queue->q_lock, flags); + ret = ENA_COM_NO_DEVICE; + goto err; + } + + ENA_WARN(comp_ctx->status != ENA_CMD_COMPLETED, + "Invalid comp status %d\n", comp_ctx->status); + + ret = ena_com_comp_status_to_errno(comp_ctx->comp_status); +err: + comp_ctxt_release(admin_queue, comp_ctx); + return ret; +} + +static int ena_com_wait_and_process_admin_cq_interrupts(struct ena_comp_ctx *comp_ctx, + struct ena_com_admin_queue *admin_queue) +{ + unsigned long flags; + int ret; + + ENA_WAIT_EVENT_WAIT(comp_ctx->wait_event, + admin_queue->completion_timeout); + + /* In case the command wasn't completed find out the root cause. + * There might be 2 kinds of errors + * 1) No completion (timeout reached) + * 2) There is completion but the device didn't get any msi-x interrupt. + */ + if (unlikely(comp_ctx->status == ENA_CMD_SUBMITTED)) { + ENA_SPINLOCK_LOCK(admin_queue->q_lock, flags); + ena_com_handle_admin_completion(admin_queue); + admin_queue->stats.no_completion++; + ENA_SPINLOCK_UNLOCK(admin_queue->q_lock, flags); + + if (comp_ctx->status == ENA_CMD_COMPLETED) + ena_trc_err("The ena device have completion but the driver didn't receive any MSI-X interrupt (cmd %d)\n", + comp_ctx->cmd_opcode); + else + ena_trc_err("The ena device doesn't send any completion for the admin cmd %d status %d\n", + comp_ctx->cmd_opcode, comp_ctx->status); + + admin_queue->running_state = false; + ret = ENA_COM_TIMER_EXPIRED; + goto err; + } + + ret = ena_com_comp_status_to_errno(comp_ctx->comp_status); +err: + comp_ctxt_release(admin_queue, comp_ctx); + return ret; +} + +/* This method read the hardware device register through posting writes + * and waiting for response + * On timeout the function will return ENA_MMIO_READ_TIMEOUT + */ +static u32 ena_com_reg_bar_read32(struct ena_com_dev *ena_dev, u16 offset) +{ + struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read; + volatile struct ena_admin_ena_mmio_req_read_less_resp *read_resp = + mmio_read->read_resp; + u32 mmio_read_reg, timeout, ret; + unsigned long flags; + int i; + + ENA_MIGHT_SLEEP(); + + timeout = mmio_read->reg_read_to ? : ENA_REG_READ_TIMEOUT; + + /* If readless is disabled, perform regular read */ + if (!mmio_read->readless_supported) + return ENA_REG_READ32(ena_dev->bus, ena_dev->reg_bar + offset); + + ENA_SPINLOCK_LOCK(mmio_read->lock, flags); + mmio_read->seq_num++; + + read_resp->req_id = mmio_read->seq_num + 0xDEAD; + mmio_read_reg = (offset << ENA_REGS_MMIO_REG_READ_REG_OFF_SHIFT) & + ENA_REGS_MMIO_REG_READ_REG_OFF_MASK; + mmio_read_reg |= mmio_read->seq_num & + ENA_REGS_MMIO_REG_READ_REQ_ID_MASK; + + /* make sure read_resp->req_id get updated before the hw can write + * there + */ + wmb(); + + ENA_REG_WRITE32(ena_dev->bus, mmio_read_reg, ena_dev->reg_bar + ENA_REGS_MMIO_REG_READ_OFF); + + for (i = 0; i < timeout; i++) { + if (read_resp->req_id == mmio_read->seq_num) + break; + + ENA_UDELAY(1); + } + + if (unlikely(i == timeout)) { + ena_trc_err("reading reg failed for timeout. expected: req id[%hu] offset[%hu] actual: req id[%hu] offset[%hu]\n", + mmio_read->seq_num, + offset, + read_resp->req_id, + read_resp->reg_off); + ret = ENA_MMIO_READ_TIMEOUT; + goto err; + } + + if (read_resp->reg_off != offset) { + ena_trc_err("Read failure: wrong offset provided"); + ret = ENA_MMIO_READ_TIMEOUT; + } else { + ret = read_resp->reg_val; + } +err: + ENA_SPINLOCK_UNLOCK(mmio_read->lock, flags); + + return ret; +} + +/* There are two types to wait for completion. + * Polling mode - wait until the completion is available. + * Async mode - wait on wait queue until the completion is ready + * (or the timeout expired). + * It is expected that the IRQ called ena_com_handle_admin_completion + * to mark the completions. + */ +static int ena_com_wait_and_process_admin_cq(struct ena_comp_ctx *comp_ctx, + struct ena_com_admin_queue *admin_queue) +{ + if (admin_queue->polling) + return ena_com_wait_and_process_admin_cq_polling(comp_ctx, + admin_queue); + + return ena_com_wait_and_process_admin_cq_interrupts(comp_ctx, + admin_queue); +} + +static int ena_com_destroy_io_sq(struct ena_com_dev *ena_dev, + struct ena_com_io_sq *io_sq) +{ + struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; + struct ena_admin_aq_destroy_sq_cmd destroy_cmd; + struct ena_admin_acq_destroy_sq_resp_desc destroy_resp; + u8 direction; + int ret; + + memset(&destroy_cmd, 0x0, sizeof(destroy_cmd)); + + if (io_sq->direction == ENA_COM_IO_QUEUE_DIRECTION_TX) + direction = ENA_ADMIN_SQ_DIRECTION_TX; + else + direction = ENA_ADMIN_SQ_DIRECTION_RX; + + destroy_cmd.sq.sq_identity |= (direction << + ENA_ADMIN_SQ_SQ_DIRECTION_SHIFT) & + ENA_ADMIN_SQ_SQ_DIRECTION_MASK; + + destroy_cmd.sq.sq_idx = io_sq->idx; + destroy_cmd.aq_common_descriptor.opcode = ENA_ADMIN_DESTROY_SQ; + + ret = ena_com_execute_admin_command(admin_queue, + (struct ena_admin_aq_entry *)&destroy_cmd, + sizeof(destroy_cmd), + (struct ena_admin_acq_entry *)&destroy_resp, + sizeof(destroy_resp)); + + if (unlikely(ret && (ret != ENA_COM_NO_DEVICE))) + ena_trc_err("failed to destroy io sq error: %d\n", ret); + + return ret; +} + +static void ena_com_io_queue_free(struct ena_com_dev *ena_dev, + struct ena_com_io_sq *io_sq, + struct ena_com_io_cq *io_cq) +{ + size_t size; + + if (io_cq->cdesc_addr.virt_addr) { + size = io_cq->cdesc_entry_size_in_bytes * io_cq->q_depth; + + ENA_MEM_FREE_COHERENT(ena_dev->dmadev, + size, + io_cq->cdesc_addr.virt_addr, + io_cq->cdesc_addr.phys_addr, + io_cq->cdesc_addr.mem_handle); + + io_cq->cdesc_addr.virt_addr = NULL; + } + + if (io_sq->desc_addr.virt_addr) { + size = io_sq->desc_entry_size * io_sq->q_depth; + + if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST) + ENA_MEM_FREE_COHERENT(ena_dev->dmadev, + size, + io_sq->desc_addr.virt_addr, + io_sq->desc_addr.phys_addr, + io_sq->desc_addr.mem_handle); + else + ENA_MEM_FREE(ena_dev->dmadev, io_sq->desc_addr.virt_addr); + + io_sq->desc_addr.virt_addr = NULL; + } +} + +static int wait_for_reset_state(struct ena_com_dev *ena_dev, u32 timeout, + u16 exp_state) +{ + u32 val, i; + + for (i = 0; i < timeout; i++) { + val = ena_com_reg_bar_read32(ena_dev, ENA_REGS_DEV_STS_OFF); + + if (unlikely(val == ENA_MMIO_READ_TIMEOUT)) { + ena_trc_err("Reg read timeout occurred\n"); + return ENA_COM_TIMER_EXPIRED; + } + + if ((val & ENA_REGS_DEV_STS_RESET_IN_PROGRESS_MASK) == + exp_state) + return 0; + + /* The resolution of the timeout is 100ms */ + ENA_MSLEEP(100); + } + + return ENA_COM_TIMER_EXPIRED; +} + +static bool ena_com_check_supported_feature_id(struct ena_com_dev *ena_dev, + enum ena_admin_aq_feature_id feature_id) +{ + u32 feature_mask = 1 << feature_id; + + /* Device attributes is always supported */ + if ((feature_id != ENA_ADMIN_DEVICE_ATTRIBUTES) && + !(ena_dev->supported_features & feature_mask)) + return false; + + return true; +} + +static int ena_com_get_feature_ex(struct ena_com_dev *ena_dev, + struct ena_admin_get_feat_resp *get_resp, + enum ena_admin_aq_feature_id feature_id, + dma_addr_t control_buf_dma_addr, + u32 control_buff_size) +{ + struct ena_com_admin_queue *admin_queue; + struct ena_admin_get_feat_cmd get_cmd; + int ret; + + if (!ena_com_check_supported_feature_id(ena_dev, feature_id)) { + ena_trc_dbg("Feature %d isn't supported\n", feature_id); + return ENA_COM_PERMISSION; + } + + memset(&get_cmd, 0x0, sizeof(get_cmd)); + admin_queue = &ena_dev->admin_queue; + + get_cmd.aq_common_descriptor.opcode = ENA_ADMIN_GET_FEATURE; + + if (control_buff_size) + get_cmd.aq_common_descriptor.flags = + ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_MASK; + else + get_cmd.aq_common_descriptor.flags = 0; + + ret = ena_com_mem_addr_set(ena_dev, + &get_cmd.control_buffer.address, + control_buf_dma_addr); + if (unlikely(ret)) { + ena_trc_err("memory address set failed\n"); + return ret; + } + + get_cmd.control_buffer.length = control_buff_size; + + get_cmd.feat_common.feature_id = feature_id; + + ret = ena_com_execute_admin_command(admin_queue, + (struct ena_admin_aq_entry *) + &get_cmd, + sizeof(get_cmd), + (struct ena_admin_acq_entry *) + get_resp, + sizeof(*get_resp)); + + if (unlikely(ret)) + ena_trc_err("Failed to submit get_feature command %d error: %d\n", + feature_id, ret); + + return ret; +} + +static int ena_com_get_feature(struct ena_com_dev *ena_dev, + struct ena_admin_get_feat_resp *get_resp, + enum ena_admin_aq_feature_id feature_id) +{ + return ena_com_get_feature_ex(ena_dev, + get_resp, + feature_id, + 0, + 0); +} + +static int ena_com_hash_key_allocate(struct ena_com_dev *ena_dev) +{ + struct ena_rss *rss = &ena_dev->rss; + + ENA_MEM_ALLOC_COHERENT(ena_dev->dmadev, + sizeof(*rss->hash_key), + rss->hash_key, + rss->hash_key_dma_addr, + rss->hash_key_mem_handle); + + if (unlikely(!rss->hash_key)) + return ENA_COM_NO_MEM; + + return 0; +} + +static void ena_com_hash_key_destroy(struct ena_com_dev *ena_dev) +{ + struct ena_rss *rss = &ena_dev->rss; + + if (rss->hash_key) + ENA_MEM_FREE_COHERENT(ena_dev->dmadev, + sizeof(*rss->hash_key), + rss->hash_key, + rss->hash_key_dma_addr, + rss->hash_key_mem_handle); + rss->hash_key = NULL; +} + +static int ena_com_hash_ctrl_init(struct ena_com_dev *ena_dev) +{ + struct ena_rss *rss = &ena_dev->rss; + + ENA_MEM_ALLOC_COHERENT(ena_dev->dmadev, + sizeof(*rss->hash_ctrl), + rss->hash_ctrl, + rss->hash_ctrl_dma_addr, + rss->hash_ctrl_mem_handle); + + if (unlikely(!rss->hash_ctrl)) + return ENA_COM_NO_MEM; + + return 0; +} + +static void ena_com_hash_ctrl_destroy(struct ena_com_dev *ena_dev) +{ + struct ena_rss *rss = &ena_dev->rss; + + if (rss->hash_ctrl) + ENA_MEM_FREE_COHERENT(ena_dev->dmadev, + sizeof(*rss->hash_ctrl), + rss->hash_ctrl, + rss->hash_ctrl_dma_addr, + rss->hash_ctrl_mem_handle); + rss->hash_ctrl = NULL; +} + +static int ena_com_indirect_table_allocate(struct ena_com_dev *ena_dev, + u16 log_size) +{ + struct ena_rss *rss = &ena_dev->rss; + struct ena_admin_get_feat_resp get_resp; + size_t tbl_size; + int ret; + + ret = ena_com_get_feature(ena_dev, &get_resp, + ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG); + if (unlikely(ret)) + return ret; + + if ((get_resp.u.ind_table.min_size > log_size) || + (get_resp.u.ind_table.max_size < log_size)) { + ena_trc_err("indirect table size doesn't fit. requested size: %d while min is:%d and max %d\n", + 1 << log_size, + 1 << get_resp.u.ind_table.min_size, + 1 << get_resp.u.ind_table.max_size); + return ENA_COM_INVAL; + } + + tbl_size = (1ULL << log_size) * + sizeof(struct ena_admin_rss_ind_table_entry); + + ENA_MEM_ALLOC_COHERENT(ena_dev->dmadev, + tbl_size, + rss->rss_ind_tbl, + rss->rss_ind_tbl_dma_addr, + rss->rss_ind_tbl_mem_handle); + if (unlikely(!rss->rss_ind_tbl)) + goto mem_err1; + + tbl_size = (1ULL << log_size) * sizeof(u16); + rss->host_rss_ind_tbl = + ENA_MEM_ALLOC(ena_dev->dmadev, tbl_size); + if (unlikely(!rss->host_rss_ind_tbl)) + goto mem_err2; + + rss->tbl_log_size = log_size; + + return 0; + +mem_err2: + tbl_size = (1ULL << log_size) * + sizeof(struct ena_admin_rss_ind_table_entry); + + ENA_MEM_FREE_COHERENT(ena_dev->dmadev, + tbl_size, + rss->rss_ind_tbl, + rss->rss_ind_tbl_dma_addr, + rss->rss_ind_tbl_mem_handle); + rss->rss_ind_tbl = NULL; +mem_err1: + rss->tbl_log_size = 0; + return ENA_COM_NO_MEM; +} + +static void ena_com_indirect_table_destroy(struct ena_com_dev *ena_dev) +{ + struct ena_rss *rss = &ena_dev->rss; + size_t tbl_size = (1ULL << rss->tbl_log_size) * + sizeof(struct ena_admin_rss_ind_table_entry); + + if (rss->rss_ind_tbl) + ENA_MEM_FREE_COHERENT(ena_dev->dmadev, + tbl_size, + rss->rss_ind_tbl, + rss->rss_ind_tbl_dma_addr, + rss->rss_ind_tbl_mem_handle); + rss->rss_ind_tbl = NULL; + + if (rss->host_rss_ind_tbl) + ENA_MEM_FREE(ena_dev->dmadev, rss->host_rss_ind_tbl); + rss->host_rss_ind_tbl = NULL; +} + +static int ena_com_create_io_sq(struct ena_com_dev *ena_dev, + struct ena_com_io_sq *io_sq, u16 cq_idx) +{ + struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; + struct ena_admin_aq_create_sq_cmd create_cmd; + struct ena_admin_acq_create_sq_resp_desc cmd_completion; + u8 direction; + int ret; + + memset(&create_cmd, 0x0, sizeof(create_cmd)); + + create_cmd.aq_common_descriptor.opcode = ENA_ADMIN_CREATE_SQ; + + if (io_sq->direction == ENA_COM_IO_QUEUE_DIRECTION_TX) + direction = ENA_ADMIN_SQ_DIRECTION_TX; + else + direction = ENA_ADMIN_SQ_DIRECTION_RX; + + create_cmd.sq_identity |= (direction << + ENA_ADMIN_AQ_CREATE_SQ_CMD_SQ_DIRECTION_SHIFT) & + ENA_ADMIN_AQ_CREATE_SQ_CMD_SQ_DIRECTION_MASK; + + create_cmd.sq_caps_2 |= io_sq->mem_queue_type & + ENA_ADMIN_AQ_CREATE_SQ_CMD_PLACEMENT_POLICY_MASK; + + create_cmd.sq_caps_2 |= (ENA_ADMIN_COMPLETION_POLICY_DESC << + ENA_ADMIN_AQ_CREATE_SQ_CMD_COMPLETION_POLICY_SHIFT) & + ENA_ADMIN_AQ_CREATE_SQ_CMD_COMPLETION_POLICY_MASK; + + create_cmd.sq_caps_3 |= + ENA_ADMIN_AQ_CREATE_SQ_CMD_IS_PHYSICALLY_CONTIGUOUS_MASK; + + create_cmd.cq_idx = cq_idx; + create_cmd.sq_depth = io_sq->q_depth; + + if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST) { + ret = ena_com_mem_addr_set(ena_dev, + &create_cmd.sq_ba, + io_sq->desc_addr.phys_addr); + if (unlikely(ret)) { + ena_trc_err("memory address set failed\n"); + return ret; + } + } + + ret = ena_com_execute_admin_command(admin_queue, + (struct ena_admin_aq_entry *)&create_cmd, + sizeof(create_cmd), + (struct ena_admin_acq_entry *)&cmd_completion, + sizeof(cmd_completion)); + if (unlikely(ret)) { + ena_trc_err("Failed to create IO SQ. error: %d\n", ret); + return ret; + } + + io_sq->idx = cmd_completion.sq_idx; + + io_sq->db_addr = (u32 __iomem *)((uintptr_t)ena_dev->reg_bar + + (uintptr_t)cmd_completion.sq_doorbell_offset); + + if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) { + io_sq->header_addr = (u8 __iomem *)((uintptr_t)ena_dev->mem_bar + + cmd_completion.llq_headers_offset); + + io_sq->desc_addr.pbuf_dev_addr = + (u8 __iomem *)((uintptr_t)ena_dev->mem_bar + + cmd_completion.llq_descriptors_offset); + } + + ena_trc_dbg("created sq[%u], depth[%u]\n", io_sq->idx, io_sq->q_depth); + + return ret; +} + +static int ena_com_ind_tbl_convert_to_device(struct ena_com_dev *ena_dev) +{ + struct ena_rss *rss = &ena_dev->rss; + struct ena_com_io_sq *io_sq; + u16 qid; + int i; + + for (i = 0; i < 1 << rss->tbl_log_size; i++) { + qid = rss->host_rss_ind_tbl[i]; + if (qid >= ENA_TOTAL_NUM_QUEUES) + return ENA_COM_INVAL; + + io_sq = &ena_dev->io_sq_queues[qid]; + + if (io_sq->direction != ENA_COM_IO_QUEUE_DIRECTION_RX) + return ENA_COM_INVAL; + + rss->rss_ind_tbl[i].cq_idx = io_sq->idx; + } + + return 0; +} + +static int ena_com_ind_tbl_convert_from_device(struct ena_com_dev *ena_dev) +{ + u16 dev_idx_to_host_tbl[ENA_TOTAL_NUM_QUEUES] = { (u16)-1 }; + struct ena_rss *rss = &ena_dev->rss; + u8 idx; + u16 i; + + for (i = 0; i < ENA_TOTAL_NUM_QUEUES; i++) + dev_idx_to_host_tbl[ena_dev->io_sq_queues[i].idx] = i; + + for (i = 0; i < 1 << rss->tbl_log_size; i++) { + if (rss->rss_ind_tbl[i].cq_idx > ENA_TOTAL_NUM_QUEUES) + return ENA_COM_INVAL; + idx = (u8)rss->rss_ind_tbl[i].cq_idx; + + if (dev_idx_to_host_tbl[idx] > ENA_TOTAL_NUM_QUEUES) + return ENA_COM_INVAL; + + rss->host_rss_ind_tbl[i] = dev_idx_to_host_tbl[idx]; + } + + return 0; +} + +static int ena_com_init_interrupt_moderation_table(struct ena_com_dev *ena_dev) +{ + size_t size; + + size = sizeof(struct ena_intr_moder_entry) * ENA_INTR_MAX_NUM_OF_LEVELS; + + ena_dev->intr_moder_tbl = ENA_MEM_ALLOC(ena_dev->dmadev, size); + if (!ena_dev->intr_moder_tbl) + return ENA_COM_NO_MEM; + + ena_com_config_default_interrupt_moderation_table(ena_dev); + + return 0; +} + +static void ena_com_update_intr_delay_resolution(struct ena_com_dev *ena_dev, + u16 intr_delay_resolution) +{ + struct ena_intr_moder_entry *intr_moder_tbl = ena_dev->intr_moder_tbl; + unsigned int i; + + if (!intr_delay_resolution) { + ena_trc_err("Illegal intr_delay_resolution provided. Going to use default 1 usec resolution\n"); + intr_delay_resolution = 1; + } + ena_dev->intr_delay_resolution = intr_delay_resolution; + + /* update Rx */ + for (i = 0; i < ENA_INTR_MAX_NUM_OF_LEVELS; i++) + intr_moder_tbl[i].intr_moder_interval /= intr_delay_resolution; + + /* update Tx */ + ena_dev->intr_moder_tx_interval /= intr_delay_resolution; +} + +/*****************************************************************************/ +/******************************* API ******************************/ +/*****************************************************************************/ + +int ena_com_execute_admin_command(struct ena_com_admin_queue *admin_queue, + struct ena_admin_aq_entry *cmd, + size_t cmd_size, + struct ena_admin_acq_entry *comp, + size_t comp_size) +{ + struct ena_comp_ctx *comp_ctx; + int ret; + + comp_ctx = ena_com_submit_admin_cmd(admin_queue, cmd, cmd_size, + comp, comp_size); + if (unlikely(IS_ERR(comp_ctx))) { + if (comp_ctx == ERR_PTR(ENA_COM_NO_DEVICE)) + ena_trc_dbg("Failed to submit command [%ld]\n", + PTR_ERR(comp_ctx)); + else + ena_trc_err("Failed to submit command [%ld]\n", + PTR_ERR(comp_ctx)); + + return PTR_ERR(comp_ctx); + } + + ret = ena_com_wait_and_process_admin_cq(comp_ctx, admin_queue); + if (unlikely(ret)) { + if (admin_queue->running_state) + ena_trc_err("Failed to process command. ret = %d\n", + ret); + else + ena_trc_dbg("Failed to process command. ret = %d\n", + ret); + } + return ret; +} + +int ena_com_create_io_cq(struct ena_com_dev *ena_dev, + struct ena_com_io_cq *io_cq) +{ + struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; + struct ena_admin_aq_create_cq_cmd create_cmd; + struct ena_admin_acq_create_cq_resp_desc cmd_completion; + int ret; + + memset(&create_cmd, 0x0, sizeof(create_cmd)); + + create_cmd.aq_common_descriptor.opcode = ENA_ADMIN_CREATE_CQ; + + create_cmd.cq_caps_2 |= (io_cq->cdesc_entry_size_in_bytes / 4) & + ENA_ADMIN_AQ_CREATE_CQ_CMD_CQ_ENTRY_SIZE_WORDS_MASK; + create_cmd.cq_caps_1 |= + ENA_ADMIN_AQ_CREATE_CQ_CMD_INTERRUPT_MODE_ENABLED_MASK; + + create_cmd.msix_vector = io_cq->msix_vector; + create_cmd.cq_depth = io_cq->q_depth; + + ret = ena_com_mem_addr_set(ena_dev, + &create_cmd.cq_ba, + io_cq->cdesc_addr.phys_addr); + if (unlikely(ret)) { + ena_trc_err("memory address set failed\n"); + return ret; + } + + ret = ena_com_execute_admin_command(admin_queue, + (struct ena_admin_aq_entry *)&create_cmd, + sizeof(create_cmd), + (struct ena_admin_acq_entry *)&cmd_completion, + sizeof(cmd_completion)); + if (unlikely(ret)) { + ena_trc_err("Failed to create IO CQ. error: %d\n", ret); + return ret; + } + + io_cq->idx = cmd_completion.cq_idx; + + io_cq->unmask_reg = (u32 __iomem *)((uintptr_t)ena_dev->reg_bar + + cmd_completion.cq_interrupt_unmask_register_offset); + + if (cmd_completion.cq_head_db_register_offset) + io_cq->cq_head_db_reg = + (u32 __iomem *)((uintptr_t)ena_dev->reg_bar + + cmd_completion.cq_head_db_register_offset); + + if (cmd_completion.numa_node_register_offset) + io_cq->numa_node_cfg_reg = + (u32 __iomem *)((uintptr_t)ena_dev->reg_bar + + cmd_completion.numa_node_register_offset); + + ena_trc_dbg("created cq[%u], depth[%u]\n", io_cq->idx, io_cq->q_depth); + + return ret; +} + +int ena_com_get_io_handlers(struct ena_com_dev *ena_dev, u16 qid, + struct ena_com_io_sq **io_sq, + struct ena_com_io_cq **io_cq) +{ + if (qid >= ENA_TOTAL_NUM_QUEUES) { + ena_trc_err("Invalid queue number %d but the max is %d\n", + qid, ENA_TOTAL_NUM_QUEUES); + return ENA_COM_INVAL; + } + + *io_sq = &ena_dev->io_sq_queues[qid]; + *io_cq = &ena_dev->io_cq_queues[qid]; + + return 0; +} + +void ena_com_abort_admin_commands(struct ena_com_dev *ena_dev) +{ + struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; + struct ena_comp_ctx *comp_ctx; + u16 i; + + if (!admin_queue->comp_ctx) + return; + + for (i = 0; i < admin_queue->q_depth; i++) { + comp_ctx = get_comp_ctxt(admin_queue, i, false); + if (unlikely(!comp_ctx)) + break; + + comp_ctx->status = ENA_CMD_ABORTED; + + ENA_WAIT_EVENT_SIGNAL(comp_ctx->wait_event); + } +} + +void ena_com_wait_for_abort_completion(struct ena_com_dev *ena_dev) +{ + struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; + unsigned long flags; + + ENA_SPINLOCK_LOCK(admin_queue->q_lock, flags); + while (ATOMIC32_READ(&admin_queue->outstanding_cmds) != 0) { + ENA_SPINLOCK_UNLOCK(admin_queue->q_lock, flags); + ENA_MSLEEP(20); + ENA_SPINLOCK_LOCK(admin_queue->q_lock, flags); + } + ENA_SPINLOCK_UNLOCK(admin_queue->q_lock, flags); +} + +int ena_com_destroy_io_cq(struct ena_com_dev *ena_dev, + struct ena_com_io_cq *io_cq) +{ + struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; + struct ena_admin_aq_destroy_cq_cmd destroy_cmd; + struct ena_admin_acq_destroy_cq_resp_desc destroy_resp; + int ret; + + memset(&destroy_cmd, 0x0, sizeof(destroy_cmd)); + + destroy_cmd.cq_idx = io_cq->idx; + destroy_cmd.aq_common_descriptor.opcode = ENA_ADMIN_DESTROY_CQ; + + ret = ena_com_execute_admin_command(admin_queue, + (struct ena_admin_aq_entry *)&destroy_cmd, + sizeof(destroy_cmd), + (struct ena_admin_acq_entry *)&destroy_resp, + sizeof(destroy_resp)); + + if (unlikely(ret && (ret != ENA_COM_NO_DEVICE))) + ena_trc_err("Failed to destroy IO CQ. error: %d\n", ret); + + return ret; +} + +bool ena_com_get_admin_running_state(struct ena_com_dev *ena_dev) +{ + return ena_dev->admin_queue.running_state; +} + +void ena_com_set_admin_running_state(struct ena_com_dev *ena_dev, bool state) +{ + struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; + unsigned long flags; + + ENA_SPINLOCK_LOCK(admin_queue->q_lock, flags); + ena_dev->admin_queue.running_state = state; + ENA_SPINLOCK_UNLOCK(admin_queue->q_lock, flags); +} + +void ena_com_admin_aenq_enable(struct ena_com_dev *ena_dev) +{ + u16 depth = ena_dev->aenq.q_depth; + + ENA_WARN(ena_dev->aenq.head != depth, "Invalid AENQ state\n"); + + /* Init head_db to mark that all entries in the queue + * are initially available + */ + ENA_REG_WRITE32(ena_dev->bus, depth, ena_dev->reg_bar + ENA_REGS_AENQ_HEAD_DB_OFF); +} + +int ena_com_set_aenq_config(struct ena_com_dev *ena_dev, u32 groups_flag) +{ + struct ena_com_admin_queue *admin_queue; + struct ena_admin_set_feat_cmd cmd; + struct ena_admin_set_feat_resp resp; + struct ena_admin_get_feat_resp get_resp; + int ret; + + ret = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_AENQ_CONFIG); + if (ret) { + ena_trc_info("Can't get aenq configuration\n"); + return ret; + } + + if ((get_resp.u.aenq.supported_groups & groups_flag) != groups_flag) { + ena_trc_warn("Trying to set unsupported aenq events. supported flag: %x asked flag: %x\n", + get_resp.u.aenq.supported_groups, + groups_flag); + return ENA_COM_PERMISSION; + } + + memset(&cmd, 0x0, sizeof(cmd)); + admin_queue = &ena_dev->admin_queue; + + cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE; + cmd.aq_common_descriptor.flags = 0; + cmd.feat_common.feature_id = ENA_ADMIN_AENQ_CONFIG; + cmd.u.aenq.enabled_groups = groups_flag; + + ret = ena_com_execute_admin_command(admin_queue, + (struct ena_admin_aq_entry *)&cmd, + sizeof(cmd), + (struct ena_admin_acq_entry *)&resp, + sizeof(resp)); + + if (unlikely(ret)) + ena_trc_err("Failed to config AENQ ret: %d\n", ret); + + return ret; +} + +int ena_com_get_dma_width(struct ena_com_dev *ena_dev) +{ + u32 caps = ena_com_reg_bar_read32(ena_dev, ENA_REGS_CAPS_OFF); + int width; + + if (unlikely(caps == ENA_MMIO_READ_TIMEOUT)) { + ena_trc_err("Reg read timeout occurred\n"); + return ENA_COM_TIMER_EXPIRED; + } + + width = (caps & ENA_REGS_CAPS_DMA_ADDR_WIDTH_MASK) >> + ENA_REGS_CAPS_DMA_ADDR_WIDTH_SHIFT; + + ena_trc_dbg("ENA dma width: %d\n", width); + + if ((width < 32) || width > ENA_MAX_PHYS_ADDR_SIZE_BITS) { + ena_trc_err("DMA width illegal value: %d\n", width); + return ENA_COM_INVAL; + } + + ena_dev->dma_addr_bits = width; + + return width; +} + +int ena_com_validate_version(struct ena_com_dev *ena_dev) +{ + u32 ver; + u32 ctrl_ver; + u32 ctrl_ver_masked; + + /* Make sure the ENA version and the controller version are at least + * as the driver expects + */ + ver = ena_com_reg_bar_read32(ena_dev, ENA_REGS_VERSION_OFF); + ctrl_ver = ena_com_reg_bar_read32(ena_dev, + ENA_REGS_CONTROLLER_VERSION_OFF); + + if (unlikely((ver == ENA_MMIO_READ_TIMEOUT) || + (ctrl_ver == ENA_MMIO_READ_TIMEOUT))) { + ena_trc_err("Reg read timeout occurred\n"); + return ENA_COM_TIMER_EXPIRED; + } + + ena_trc_info("ena device version: %d.%d\n", + (ver & ENA_REGS_VERSION_MAJOR_VERSION_MASK) >> + ENA_REGS_VERSION_MAJOR_VERSION_SHIFT, + ver & ENA_REGS_VERSION_MINOR_VERSION_MASK); + + if (ver < MIN_ENA_VER) { + ena_trc_err("ENA version is lower than the minimal version the driver supports\n"); + return -1; + } + + ena_trc_info("ena controller version: %d.%d.%d implementation version %d\n", + (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_MASK) + >> ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_SHIFT, + (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_MASK) + >> ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_SHIFT, + (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_SUBMINOR_VERSION_MASK), + (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_IMPL_ID_MASK) >> + ENA_REGS_CONTROLLER_VERSION_IMPL_ID_SHIFT); + + ctrl_ver_masked = + (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_MASK) | + (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_MASK) | + (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_SUBMINOR_VERSION_MASK); + + /* Validate the ctrl version without the implementation ID */ + if (ctrl_ver_masked < MIN_ENA_CTRL_VER) { + ena_trc_err("ENA ctrl version is lower than the minimal ctrl version the driver supports\n"); + return -1; + } + + return 0; +} + +void ena_com_admin_destroy(struct ena_com_dev *ena_dev) +{ + struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; + struct ena_com_admin_cq *cq = &admin_queue->cq; + struct ena_com_admin_sq *sq = &admin_queue->sq; + struct ena_com_aenq *aenq = &ena_dev->aenq; + u16 size; + + ENA_WAIT_EVENT_DESTROY(admin_queue->comp_ctx->wait_event); + + ENA_SPINLOCK_DESTROY(admin_queue->q_lock); + + if (admin_queue->comp_ctx) + ENA_MEM_FREE(ena_dev->dmadev, admin_queue->comp_ctx); + + admin_queue->comp_ctx = NULL; + size = ADMIN_SQ_SIZE(admin_queue->q_depth); + if (sq->entries) + ENA_MEM_FREE_COHERENT(ena_dev->dmadev, size, sq->entries, + sq->dma_addr, sq->mem_handle); + sq->entries = NULL; + + size = ADMIN_CQ_SIZE(admin_queue->q_depth); + if (cq->entries) + ENA_MEM_FREE_COHERENT(ena_dev->dmadev, size, cq->entries, + cq->dma_addr, cq->mem_handle); + cq->entries = NULL; + + size = ADMIN_AENQ_SIZE(aenq->q_depth); + if (ena_dev->aenq.entries) + ENA_MEM_FREE_COHERENT(ena_dev->dmadev, size, aenq->entries, + aenq->dma_addr, aenq->mem_handle); + aenq->entries = NULL; +} + +void ena_com_set_admin_polling_mode(struct ena_com_dev *ena_dev, bool polling) +{ + ena_dev->admin_queue.polling = polling; +} + +int ena_com_mmio_reg_read_request_init(struct ena_com_dev *ena_dev) +{ + struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read; + + ENA_SPINLOCK_INIT(mmio_read->lock); + ENA_MEM_ALLOC_COHERENT(ena_dev->dmadev, + sizeof(*mmio_read->read_resp), + mmio_read->read_resp, + mmio_read->read_resp_dma_addr, + mmio_read->read_resp_mem_handle); + if (unlikely(!mmio_read->read_resp)) + return ENA_COM_NO_MEM; + + ena_com_mmio_reg_read_request_write_dev_addr(ena_dev); + + mmio_read->read_resp->req_id = 0x0; + mmio_read->seq_num = 0x0; + mmio_read->readless_supported = true; + + return 0; +} + +void ena_com_set_mmio_read_mode(struct ena_com_dev *ena_dev, bool readless_supported) +{ + struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read; + + mmio_read->readless_supported = readless_supported; +} + +void ena_com_mmio_reg_read_request_destroy(struct ena_com_dev *ena_dev) +{ + struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read; + + ENA_REG_WRITE32(ena_dev->bus, 0x0, ena_dev->reg_bar + ENA_REGS_MMIO_RESP_LO_OFF); + ENA_REG_WRITE32(ena_dev->bus, 0x0, ena_dev->reg_bar + ENA_REGS_MMIO_RESP_HI_OFF); + + ENA_MEM_FREE_COHERENT(ena_dev->dmadev, + sizeof(*mmio_read->read_resp), + mmio_read->read_resp, + mmio_read->read_resp_dma_addr, + mmio_read->read_resp_mem_handle); + + mmio_read->read_resp = NULL; + + ENA_SPINLOCK_DESTROY(mmio_read->lock); +} + +void ena_com_mmio_reg_read_request_write_dev_addr(struct ena_com_dev *ena_dev) +{ + struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read; + u32 addr_low, addr_high; + + addr_low = ENA_DMA_ADDR_TO_UINT32_LOW(mmio_read->read_resp_dma_addr); + addr_high = ENA_DMA_ADDR_TO_UINT32_HIGH(mmio_read->read_resp_dma_addr); + + ENA_REG_WRITE32(ena_dev->bus, addr_low, ena_dev->reg_bar + ENA_REGS_MMIO_RESP_LO_OFF); + ENA_REG_WRITE32(ena_dev->bus, addr_high, ena_dev->reg_bar + ENA_REGS_MMIO_RESP_HI_OFF); +} + +int ena_com_admin_init(struct ena_com_dev *ena_dev, + struct ena_aenq_handlers *aenq_handlers, + bool init_spinlock) +{ + struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; + u32 aq_caps, acq_caps, dev_sts, addr_low, addr_high; + int ret; + +#ifdef ENA_INTERNAL + ena_trc_info("ena_defs : Version:[%s] Build date [%s]", + ENA_GEN_COMMIT, ENA_GEN_DATE); +#endif + dev_sts = ena_com_reg_bar_read32(ena_dev, ENA_REGS_DEV_STS_OFF); + + if (unlikely(dev_sts == ENA_MMIO_READ_TIMEOUT)) { + ena_trc_err("Reg read timeout occurred\n"); + return ENA_COM_TIMER_EXPIRED; + } + + if (!(dev_sts & ENA_REGS_DEV_STS_READY_MASK)) { + ena_trc_err("Device isn't ready, abort com init\n"); + return ENA_COM_NO_DEVICE; + } + + admin_queue->q_depth = ENA_ADMIN_QUEUE_DEPTH; + + admin_queue->bus = ena_dev->bus; + admin_queue->q_dmadev = ena_dev->dmadev; + admin_queue->polling = false; + admin_queue->curr_cmd_id = 0; + + ATOMIC32_SET(&admin_queue->outstanding_cmds, 0); + + if (init_spinlock) + ENA_SPINLOCK_INIT(admin_queue->q_lock); + + ret = ena_com_init_comp_ctxt(admin_queue); + if (ret) + goto error; + + ret = ena_com_admin_init_sq(admin_queue); + if (ret) + goto error; + + ret = ena_com_admin_init_cq(admin_queue); + if (ret) + goto error; + + admin_queue->sq.db_addr = (u32 __iomem *)((uintptr_t)ena_dev->reg_bar + + ENA_REGS_AQ_DB_OFF); + + addr_low = ENA_DMA_ADDR_TO_UINT32_LOW(admin_queue->sq.dma_addr); + addr_high = ENA_DMA_ADDR_TO_UINT32_HIGH(admin_queue->sq.dma_addr); + + ENA_REG_WRITE32(ena_dev->bus, addr_low, ena_dev->reg_bar + ENA_REGS_AQ_BASE_LO_OFF); + ENA_REG_WRITE32(ena_dev->bus, addr_high, ena_dev->reg_bar + ENA_REGS_AQ_BASE_HI_OFF); + + addr_low = ENA_DMA_ADDR_TO_UINT32_LOW(admin_queue->cq.dma_addr); + addr_high = ENA_DMA_ADDR_TO_UINT32_HIGH(admin_queue->cq.dma_addr); + + ENA_REG_WRITE32(ena_dev->bus, addr_low, ena_dev->reg_bar + ENA_REGS_ACQ_BASE_LO_OFF); + ENA_REG_WRITE32(ena_dev->bus, addr_high, ena_dev->reg_bar + ENA_REGS_ACQ_BASE_HI_OFF); + + aq_caps = 0; + aq_caps |= admin_queue->q_depth & ENA_REGS_AQ_CAPS_AQ_DEPTH_MASK; + aq_caps |= (sizeof(struct ena_admin_aq_entry) << + ENA_REGS_AQ_CAPS_AQ_ENTRY_SIZE_SHIFT) & + ENA_REGS_AQ_CAPS_AQ_ENTRY_SIZE_MASK; + + acq_caps = 0; + acq_caps |= admin_queue->q_depth & ENA_REGS_ACQ_CAPS_ACQ_DEPTH_MASK; + acq_caps |= (sizeof(struct ena_admin_acq_entry) << + ENA_REGS_ACQ_CAPS_ACQ_ENTRY_SIZE_SHIFT) & + ENA_REGS_ACQ_CAPS_ACQ_ENTRY_SIZE_MASK; + + ENA_REG_WRITE32(ena_dev->bus, aq_caps, ena_dev->reg_bar + ENA_REGS_AQ_CAPS_OFF); + ENA_REG_WRITE32(ena_dev->bus, acq_caps, ena_dev->reg_bar + ENA_REGS_ACQ_CAPS_OFF); + ret = ena_com_admin_init_aenq(ena_dev, aenq_handlers); + if (ret) + goto error; + + admin_queue->running_state = true; + + return 0; +error: + ena_com_admin_destroy(ena_dev); + + return ret; +} + +int ena_com_create_io_queue(struct ena_com_dev *ena_dev, + struct ena_com_create_io_ctx *ctx) +{ + struct ena_com_io_sq *io_sq; + struct ena_com_io_cq *io_cq; + int ret; + + if (ctx->qid >= ENA_TOTAL_NUM_QUEUES) { + ena_trc_err("Qid (%d) is bigger than max num of queues (%d)\n", + ctx->qid, ENA_TOTAL_NUM_QUEUES); + return ENA_COM_INVAL; + } + + io_sq = &ena_dev->io_sq_queues[ctx->qid]; + io_cq = &ena_dev->io_cq_queues[ctx->qid]; + + memset(io_sq, 0x0, sizeof(*io_sq)); + memset(io_cq, 0x0, sizeof(*io_cq)); + + /* Init CQ */ + io_cq->q_depth = ctx->queue_size; + io_cq->direction = ctx->direction; + io_cq->qid = ctx->qid; + + io_cq->msix_vector = ctx->msix_vector; + + io_sq->q_depth = ctx->queue_size; + io_sq->direction = ctx->direction; + io_sq->qid = ctx->qid; + + io_sq->mem_queue_type = ctx->mem_queue_type; + + if (ctx->direction == ENA_COM_IO_QUEUE_DIRECTION_TX) + /* header length is limited to 8 bits */ + io_sq->tx_max_header_size = + ENA_MIN32(ena_dev->tx_max_header_size, SZ_256); + + ret = ena_com_init_io_sq(ena_dev, ctx, io_sq); + if (ret) + goto error; + ret = ena_com_init_io_cq(ena_dev, ctx, io_cq); + if (ret) + goto error; + + ret = ena_com_create_io_cq(ena_dev, io_cq); + if (ret) + goto error; + + ret = ena_com_create_io_sq(ena_dev, io_sq, io_cq->idx); + if (ret) + goto destroy_io_cq; + + return 0; + +destroy_io_cq: + ena_com_destroy_io_cq(ena_dev, io_cq); +error: + ena_com_io_queue_free(ena_dev, io_sq, io_cq); + return ret; +} + +void ena_com_destroy_io_queue(struct ena_com_dev *ena_dev, u16 qid) +{ + struct ena_com_io_sq *io_sq; + struct ena_com_io_cq *io_cq; + + if (qid >= ENA_TOTAL_NUM_QUEUES) { + ena_trc_err("Qid (%d) is bigger than max num of queues (%d)\n", + qid, ENA_TOTAL_NUM_QUEUES); + return; + } + + io_sq = &ena_dev->io_sq_queues[qid]; + io_cq = &ena_dev->io_cq_queues[qid]; + + ena_com_destroy_io_sq(ena_dev, io_sq); + ena_com_destroy_io_cq(ena_dev, io_cq); + + ena_com_io_queue_free(ena_dev, io_sq, io_cq); +} + +int ena_com_get_link_params(struct ena_com_dev *ena_dev, + struct ena_admin_get_feat_resp *resp) +{ + return ena_com_get_feature(ena_dev, resp, ENA_ADMIN_LINK_CONFIG); +} + +int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev, + struct ena_com_dev_get_features_ctx *get_feat_ctx) +{ + struct ena_admin_get_feat_resp get_resp; + int rc; + + rc = ena_com_get_feature(ena_dev, &get_resp, + ENA_ADMIN_DEVICE_ATTRIBUTES); + if (rc) + return rc; + + memcpy(&get_feat_ctx->dev_attr, &get_resp.u.dev_attr, + sizeof(get_resp.u.dev_attr)); + ena_dev->supported_features = get_resp.u.dev_attr.supported_features; + + rc = ena_com_get_feature(ena_dev, &get_resp, + ENA_ADMIN_MAX_QUEUES_NUM); + if (rc) + return rc; + + memcpy(&get_feat_ctx->max_queues, &get_resp.u.max_queue, + sizeof(get_resp.u.max_queue)); + ena_dev->tx_max_header_size = get_resp.u.max_queue.max_header_size; + + rc = ena_com_get_feature(ena_dev, &get_resp, + ENA_ADMIN_AENQ_CONFIG); + if (rc) + return rc; + + memcpy(&get_feat_ctx->aenq, &get_resp.u.aenq, + sizeof(get_resp.u.aenq)); + + rc = ena_com_get_feature(ena_dev, &get_resp, + ENA_ADMIN_STATELESS_OFFLOAD_CONFIG); + if (rc) + return rc; + + memcpy(&get_feat_ctx->offload, &get_resp.u.offload, + sizeof(get_resp.u.offload)); + + /* Driver hints isn't mandatory admin command. So in case the + * command isn't supported set driver hints to 0 + */ + rc = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_HW_HINTS); + + if (!rc) + memcpy(&get_feat_ctx->hw_hints, &get_resp.u.hw_hints, + sizeof(get_resp.u.hw_hints)); + else if (rc == ENA_COM_PERMISSION) + memset(&get_feat_ctx->hw_hints, 0x0, sizeof(get_feat_ctx->hw_hints)); + else + return rc; + + return 0; +} + +void ena_com_admin_q_comp_intr_handler(struct ena_com_dev *ena_dev) +{ + ena_com_handle_admin_completion(&ena_dev->admin_queue); +} + +/* ena_handle_specific_aenq_event: + * return the handler that is relevant to the specific event group + */ +static ena_aenq_handler ena_com_get_specific_aenq_cb(struct ena_com_dev *dev, + u16 group) +{ + struct ena_aenq_handlers *aenq_handlers = dev->aenq.aenq_handlers; + + if ((group < ENA_MAX_HANDLERS) && aenq_handlers->handlers[group]) + return aenq_handlers->handlers[group]; + + return aenq_handlers->unimplemented_handler; +} + +/* ena_aenq_intr_handler: + * handles the aenq incoming events. + * pop events from the queue and apply the specific handler + */ +void ena_com_aenq_intr_handler(struct ena_com_dev *dev, void *data) +{ + struct ena_admin_aenq_entry *aenq_e; + struct ena_admin_aenq_common_desc *aenq_common; + struct ena_com_aenq *aenq = &dev->aenq; + ena_aenq_handler handler_cb; + u16 masked_head, processed = 0; + u8 phase; + + masked_head = aenq->head & (aenq->q_depth - 1); + phase = aenq->phase; + aenq_e = &aenq->entries[masked_head]; /* Get first entry */ + aenq_common = &aenq_e->aenq_common_desc; + + /* Go over all the events */ + while ((aenq_common->flags & ENA_ADMIN_AENQ_COMMON_DESC_PHASE_MASK) == + phase) { + ena_trc_dbg("AENQ! Group[%x] Syndrom[%x] timestamp: [%jus]\n", + aenq_common->group, + aenq_common->syndrom, + (u64)aenq_common->timestamp_low + + ((u64)aenq_common->timestamp_high << 32)); + + /* Handle specific event*/ + handler_cb = ena_com_get_specific_aenq_cb(dev, + aenq_common->group); + handler_cb(data, aenq_e); /* call the actual event handler*/ + + /* Get next event entry */ + masked_head++; + processed++; + + if (unlikely(masked_head == aenq->q_depth)) { + masked_head = 0; + phase = !phase; + } + aenq_e = &aenq->entries[masked_head]; + aenq_common = &aenq_e->aenq_common_desc; + } + + aenq->head += processed; + aenq->phase = phase; + + /* Don't update aenq doorbell if there weren't any processed events */ + if (!processed) + return; + + /* write the aenq doorbell after all AENQ descriptors were read */ + mb(); + ENA_REG_WRITE32(dev->bus, (u32)aenq->head, dev->reg_bar + ENA_REGS_AENQ_HEAD_DB_OFF); +} + +int ena_com_dev_reset(struct ena_com_dev *ena_dev) +{ + u32 stat, timeout, cap, reset_val; + int rc; + + stat = ena_com_reg_bar_read32(ena_dev, ENA_REGS_DEV_STS_OFF); + cap = ena_com_reg_bar_read32(ena_dev, ENA_REGS_CAPS_OFF); + + if (unlikely((stat == ENA_MMIO_READ_TIMEOUT) || + (cap == ENA_MMIO_READ_TIMEOUT))) { + ena_trc_err("Reg read32 timeout occurred\n"); + return ENA_COM_TIMER_EXPIRED; + } + + if ((stat & ENA_REGS_DEV_STS_READY_MASK) == 0) { + ena_trc_err("Device isn't ready, can't reset device\n"); + return ENA_COM_INVAL; + } + + timeout = (cap & ENA_REGS_CAPS_RESET_TIMEOUT_MASK) >> + ENA_REGS_CAPS_RESET_TIMEOUT_SHIFT; + if (timeout == 0) { + ena_trc_err("Invalid timeout value\n"); + return ENA_COM_INVAL; + } + + /* start reset */ + reset_val = ENA_REGS_DEV_CTL_DEV_RESET_MASK; + ENA_REG_WRITE32(ena_dev->bus, reset_val, ena_dev->reg_bar + ENA_REGS_DEV_CTL_OFF); + + /* Write again the MMIO read request address */ + ena_com_mmio_reg_read_request_write_dev_addr(ena_dev); + + rc = wait_for_reset_state(ena_dev, timeout, + ENA_REGS_DEV_STS_RESET_IN_PROGRESS_MASK); + if (rc != 0) { + ena_trc_err("Reset indication didn't turn on\n"); + return rc; + } + + /* reset done */ + ENA_REG_WRITE32(ena_dev->bus, 0, ena_dev->reg_bar + ENA_REGS_DEV_CTL_OFF); + rc = wait_for_reset_state(ena_dev, timeout, 0); + if (rc != 0) { + ena_trc_err("Reset indication didn't turn off\n"); + return rc; + } + + timeout = (cap & ENA_REGS_CAPS_ADMIN_CMD_TO_MASK) >> + ENA_REGS_CAPS_ADMIN_CMD_TO_SHIFT; + if (timeout) + /* the resolution of timeout reg is 100ms */ + ena_dev->admin_queue.completion_timeout = timeout * 100000; + else + ena_dev->admin_queue.completion_timeout = ADMIN_CMD_TIMEOUT_US; + + return 0; +} + +static int ena_get_dev_stats(struct ena_com_dev *ena_dev, + struct ena_com_stats_ctx *ctx, + enum ena_admin_get_stats_type type) +{ + struct ena_admin_aq_get_stats_cmd *get_cmd = &ctx->get_cmd; + struct ena_admin_acq_get_stats_resp *get_resp = &ctx->get_resp; + struct ena_com_admin_queue *admin_queue; + int ret; + + admin_queue = &ena_dev->admin_queue; + + get_cmd->aq_common_descriptor.opcode = ENA_ADMIN_GET_STATS; + get_cmd->aq_common_descriptor.flags = 0; + get_cmd->type = type; + + ret = ena_com_execute_admin_command(admin_queue, + (struct ena_admin_aq_entry *)get_cmd, + sizeof(*get_cmd), + (struct ena_admin_acq_entry *)get_resp, + sizeof(*get_resp)); + + if (unlikely(ret)) + ena_trc_err("Failed to get stats. error: %d\n", ret); + + return ret; +} + +int ena_com_get_dev_basic_stats(struct ena_com_dev *ena_dev, + struct ena_admin_basic_stats *stats) +{ + struct ena_com_stats_ctx ctx; + int ret; + + memset(&ctx, 0x0, sizeof(ctx)); + ret = ena_get_dev_stats(ena_dev, &ctx, ENA_ADMIN_GET_STATS_TYPE_BASIC); + if (likely(ret == 0)) + memcpy(stats, &ctx.get_resp.basic_stats, + sizeof(ctx.get_resp.basic_stats)); + + return ret; +} + +int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, int mtu) +{ + struct ena_com_admin_queue *admin_queue; + struct ena_admin_set_feat_cmd cmd; + struct ena_admin_set_feat_resp resp; + int ret; + + if (!ena_com_check_supported_feature_id(ena_dev, ENA_ADMIN_MTU)) { + ena_trc_dbg("Feature %d isn't supported\n", ENA_ADMIN_MTU); + return ENA_COM_PERMISSION; + } + + memset(&cmd, 0x0, sizeof(cmd)); + admin_queue = &ena_dev->admin_queue; + + cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE; + cmd.aq_common_descriptor.flags = 0; + cmd.feat_common.feature_id = ENA_ADMIN_MTU; + cmd.u.mtu.mtu = mtu; + + ret = ena_com_execute_admin_command(admin_queue, + (struct ena_admin_aq_entry *)&cmd, + sizeof(cmd), + (struct ena_admin_acq_entry *)&resp, + sizeof(resp)); + + if (unlikely(ret)) + ena_trc_err("Failed to set mtu %d. error: %d\n", mtu, ret); + + return ret; +} + +int ena_com_get_offload_settings(struct ena_com_dev *ena_dev, + struct ena_admin_feature_offload_desc *offload) +{ + int ret; + struct ena_admin_get_feat_resp resp; + + ret = ena_com_get_feature(ena_dev, &resp, + ENA_ADMIN_STATELESS_OFFLOAD_CONFIG); + if (unlikely(ret)) { + ena_trc_err("Failed to get offload capabilities %d\n", ret); + return ret; + } + + memcpy(offload, &resp.u.offload, sizeof(resp.u.offload)); + + return 0; +} + +int ena_com_set_hash_function(struct ena_com_dev *ena_dev) +{ + struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; + struct ena_rss *rss = &ena_dev->rss; + struct ena_admin_set_feat_cmd cmd; + struct ena_admin_set_feat_resp resp; + struct ena_admin_get_feat_resp get_resp; + int ret; + + if (!ena_com_check_supported_feature_id(ena_dev, + ENA_ADMIN_RSS_HASH_FUNCTION)) { + ena_trc_dbg("Feature %d isn't supported\n", + ENA_ADMIN_RSS_HASH_FUNCTION); + return ENA_COM_PERMISSION; + } + + /* Validate hash function is supported */ + ret = ena_com_get_feature(ena_dev, &get_resp, + ENA_ADMIN_RSS_HASH_FUNCTION); + if (unlikely(ret)) + return ret; + + if (get_resp.u.flow_hash_func.supported_func & (1 << rss->hash_func)) { + ena_trc_err("Func hash %d isn't supported by device, abort\n", + rss->hash_func); + return ENA_COM_PERMISSION; + } + + memset(&cmd, 0x0, sizeof(cmd)); + + cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE; + cmd.aq_common_descriptor.flags = + ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_MASK; + cmd.feat_common.feature_id = ENA_ADMIN_RSS_HASH_FUNCTION; + cmd.u.flow_hash_func.init_val = rss->hash_init_val; + cmd.u.flow_hash_func.selected_func = 1 << rss->hash_func; + + ret = ena_com_mem_addr_set(ena_dev, + &cmd.control_buffer.address, + rss->hash_key_dma_addr); + if (unlikely(ret)) { + ena_trc_err("memory address set failed\n"); + return ret; + } + + cmd.control_buffer.length = sizeof(*rss->hash_key); + + ret = ena_com_execute_admin_command(admin_queue, + (struct ena_admin_aq_entry *)&cmd, + sizeof(cmd), + (struct ena_admin_acq_entry *)&resp, + sizeof(resp)); + if (unlikely(ret)) { + ena_trc_err("Failed to set hash function %d. error: %d\n", + rss->hash_func, ret); + return ENA_COM_INVAL; + } + + return 0; +} + +int ena_com_fill_hash_function(struct ena_com_dev *ena_dev, + enum ena_admin_hash_functions func, + const u8 *key, u16 key_len, u32 init_val) +{ + struct ena_rss *rss = &ena_dev->rss; + struct ena_admin_get_feat_resp get_resp; + struct ena_admin_feature_rss_flow_hash_control *hash_key = + rss->hash_key; + int rc; + + /* Make sure size is a mult of DWs */ + if (unlikely(key_len & 0x3)) + return ENA_COM_INVAL; + + rc = ena_com_get_feature_ex(ena_dev, &get_resp, + ENA_ADMIN_RSS_HASH_FUNCTION, + rss->hash_key_dma_addr, + sizeof(*rss->hash_key)); + if (unlikely(rc)) + return rc; + + if (!((1 << func) & get_resp.u.flow_hash_func.supported_func)) { + ena_trc_err("Flow hash function %d isn't supported\n", func); + return ENA_COM_PERMISSION; + } + + switch (func) { + case ENA_ADMIN_TOEPLITZ: + if (key_len > sizeof(hash_key->key)) { + ena_trc_err("key len (%hu) is bigger than the max supported (%zu)\n", + key_len, sizeof(hash_key->key)); + return ENA_COM_INVAL; + } + + memcpy(hash_key->key, key, key_len); + rss->hash_init_val = init_val; + hash_key->keys_num = key_len >> 2; + break; + case ENA_ADMIN_CRC32: + rss->hash_init_val = init_val; + break; + default: + ena_trc_err("Invalid hash function (%d)\n", func); + return ENA_COM_INVAL; + } + + rc = ena_com_set_hash_function(ena_dev); + + /* Restore the old function */ + if (unlikely(rc)) + ena_com_get_hash_function(ena_dev, NULL, NULL); + + return rc; +} + +int ena_com_get_hash_function(struct ena_com_dev *ena_dev, + enum ena_admin_hash_functions *func, + u8 *key) +{ + struct ena_rss *rss = &ena_dev->rss; + struct ena_admin_get_feat_resp get_resp; + struct ena_admin_feature_rss_flow_hash_control *hash_key = + rss->hash_key; + int rc; + + rc = ena_com_get_feature_ex(ena_dev, &get_resp, + ENA_ADMIN_RSS_HASH_FUNCTION, + rss->hash_key_dma_addr, + sizeof(*rss->hash_key)); + if (unlikely(rc)) + return rc; + + rss->hash_func = get_resp.u.flow_hash_func.selected_func; + if (func) + *func = rss->hash_func; + + if (key) + memcpy(key, hash_key->key, (size_t)(hash_key->keys_num) << 2); + + return 0; +} + +int ena_com_get_hash_ctrl(struct ena_com_dev *ena_dev, + enum ena_admin_flow_hash_proto proto, + u16 *fields) +{ + struct ena_rss *rss = &ena_dev->rss; + struct ena_admin_get_feat_resp get_resp; + int rc; + + rc = ena_com_get_feature_ex(ena_dev, &get_resp, + ENA_ADMIN_RSS_HASH_INPUT, + rss->hash_ctrl_dma_addr, + sizeof(*rss->hash_ctrl)); + if (unlikely(rc)) + return rc; + + if (fields) + *fields = rss->hash_ctrl->selected_fields[proto].fields; + + return 0; +} + +int ena_com_set_hash_ctrl(struct ena_com_dev *ena_dev) +{ + struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; + struct ena_rss *rss = &ena_dev->rss; + struct ena_admin_feature_rss_hash_control *hash_ctrl = rss->hash_ctrl; + struct ena_admin_set_feat_cmd cmd; + struct ena_admin_set_feat_resp resp; + int ret; + + if (!ena_com_check_supported_feature_id(ena_dev, + ENA_ADMIN_RSS_HASH_INPUT)) { + ena_trc_dbg("Feature %d isn't supported\n", + ENA_ADMIN_RSS_HASH_INPUT); + return ENA_COM_PERMISSION; + } + + memset(&cmd, 0x0, sizeof(cmd)); + + cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE; + cmd.aq_common_descriptor.flags = + ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_MASK; + cmd.feat_common.feature_id = ENA_ADMIN_RSS_HASH_INPUT; + cmd.u.flow_hash_input.enabled_input_sort = + ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L3_SORT_MASK | + ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L4_SORT_MASK; + + ret = ena_com_mem_addr_set(ena_dev, + &cmd.control_buffer.address, + rss->hash_ctrl_dma_addr); + if (unlikely(ret)) { + ena_trc_err("memory address set failed\n"); + return ret; + } + cmd.control_buffer.length = sizeof(*hash_ctrl); + + ret = ena_com_execute_admin_command(admin_queue, + (struct ena_admin_aq_entry *)&cmd, + sizeof(cmd), + (struct ena_admin_acq_entry *)&resp, + sizeof(resp)); + if (unlikely(ret)) + ena_trc_err("Failed to set hash input. error: %d\n", ret); + + return ret; +} + +int ena_com_set_default_hash_ctrl(struct ena_com_dev *ena_dev) +{ + struct ena_rss *rss = &ena_dev->rss; + struct ena_admin_feature_rss_hash_control *hash_ctrl = + rss->hash_ctrl; + u16 available_fields = 0; + int rc, i; + + /* Get the supported hash input */ + rc = ena_com_get_hash_ctrl(ena_dev, 0, NULL); + if (unlikely(rc)) + return rc; + + hash_ctrl->selected_fields[ENA_ADMIN_RSS_TCP4].fields = + ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA | + ENA_ADMIN_RSS_L4_DP | ENA_ADMIN_RSS_L4_SP; + + hash_ctrl->selected_fields[ENA_ADMIN_RSS_UDP4].fields = + ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA | + ENA_ADMIN_RSS_L4_DP | ENA_ADMIN_RSS_L4_SP; + + hash_ctrl->selected_fields[ENA_ADMIN_RSS_TCP6].fields = + ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA | + ENA_ADMIN_RSS_L4_DP | ENA_ADMIN_RSS_L4_SP; + + hash_ctrl->selected_fields[ENA_ADMIN_RSS_UDP6].fields = + ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA | + ENA_ADMIN_RSS_L4_DP | ENA_ADMIN_RSS_L4_SP; + + hash_ctrl->selected_fields[ENA_ADMIN_RSS_IP4].fields = + ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA; + + hash_ctrl->selected_fields[ENA_ADMIN_RSS_IP6].fields = + ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA; + + hash_ctrl->selected_fields[ENA_ADMIN_RSS_IP4_FRAG].fields = + ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA; + + hash_ctrl->selected_fields[ENA_ADMIN_RSS_NOT_IP].fields = + ENA_ADMIN_RSS_L2_DA | ENA_ADMIN_RSS_L2_SA; + + for (i = 0; i < ENA_ADMIN_RSS_PROTO_NUM; i++) { + available_fields = hash_ctrl->selected_fields[i].fields & + hash_ctrl->supported_fields[i].fields; + if (available_fields != hash_ctrl->selected_fields[i].fields) { + ena_trc_err("hash control doesn't support all the desire configuration. proto %x supported %x selected %x\n", + i, hash_ctrl->supported_fields[i].fields, + hash_ctrl->selected_fields[i].fields); + return ENA_COM_PERMISSION; + } + } + + rc = ena_com_set_hash_ctrl(ena_dev); + + /* In case of failure, restore the old hash ctrl */ + if (unlikely(rc)) + ena_com_get_hash_ctrl(ena_dev, 0, NULL); + + return rc; +} + +int ena_com_fill_hash_ctrl(struct ena_com_dev *ena_dev, + enum ena_admin_flow_hash_proto proto, + u16 hash_fields) +{ + struct ena_rss *rss = &ena_dev->rss; + struct ena_admin_feature_rss_hash_control *hash_ctrl = rss->hash_ctrl; + u16 supported_fields; + int rc; + + if (proto >= ENA_ADMIN_RSS_PROTO_NUM) { + ena_trc_err("Invalid proto num (%u)\n", proto); + return ENA_COM_INVAL; + } + + /* Get the ctrl table */ + rc = ena_com_get_hash_ctrl(ena_dev, proto, NULL); + if (unlikely(rc)) + return rc; + + /* Make sure all the fields are supported */ + supported_fields = hash_ctrl->supported_fields[proto].fields; + if ((hash_fields & supported_fields) != hash_fields) { + ena_trc_err("proto %d doesn't support the required fields %x. supports only: %x\n", + proto, hash_fields, supported_fields); + } + + hash_ctrl->selected_fields[proto].fields = hash_fields; + + rc = ena_com_set_hash_ctrl(ena_dev); + + /* In case of failure, restore the old hash ctrl */ + if (unlikely(rc)) + ena_com_get_hash_ctrl(ena_dev, 0, NULL); + + return 0; +} + +int ena_com_indirect_table_fill_entry(struct ena_com_dev *ena_dev, + u16 entry_idx, u16 entry_value) +{ + struct ena_rss *rss = &ena_dev->rss; + + if (unlikely(entry_idx >= (1 << rss->tbl_log_size))) + return ENA_COM_INVAL; + + if (unlikely((entry_value > ENA_TOTAL_NUM_QUEUES))) + return ENA_COM_INVAL; + + rss->host_rss_ind_tbl[entry_idx] = entry_value; + + return 0; +} + +int ena_com_indirect_table_set(struct ena_com_dev *ena_dev) +{ + struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; + struct ena_rss *rss = &ena_dev->rss; + struct ena_admin_set_feat_cmd cmd; + struct ena_admin_set_feat_resp resp; + int ret; + + if (!ena_com_check_supported_feature_id(ena_dev, + ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG)) { + ena_trc_dbg("Feature %d isn't supported\n", + ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG); + return ENA_COM_PERMISSION; + } + + ret = ena_com_ind_tbl_convert_to_device(ena_dev); + if (ret) { + ena_trc_err("Failed to convert host indirection table to device table\n"); + return ret; + } + + memset(&cmd, 0x0, sizeof(cmd)); + + cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE; + cmd.aq_common_descriptor.flags = + ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_MASK; + cmd.feat_common.feature_id = ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG; + cmd.u.ind_table.size = rss->tbl_log_size; + cmd.u.ind_table.inline_index = 0xFFFFFFFF; + + ret = ena_com_mem_addr_set(ena_dev, + &cmd.control_buffer.address, + rss->rss_ind_tbl_dma_addr); + if (unlikely(ret)) { + ena_trc_err("memory address set failed\n"); + return ret; + } + + cmd.control_buffer.length = (1ULL << rss->tbl_log_size) * + sizeof(struct ena_admin_rss_ind_table_entry); + + ret = ena_com_execute_admin_command(admin_queue, + (struct ena_admin_aq_entry *)&cmd, + sizeof(cmd), + (struct ena_admin_acq_entry *)&resp, + sizeof(resp)); + + if (unlikely(ret)) + ena_trc_err("Failed to set indirect table. error: %d\n", ret); + + return ret; +} + +int ena_com_indirect_table_get(struct ena_com_dev *ena_dev, u32 *ind_tbl) +{ + struct ena_rss *rss = &ena_dev->rss; + struct ena_admin_get_feat_resp get_resp; + u32 tbl_size; + int i, rc; + + tbl_size = (1ULL << rss->tbl_log_size) * + sizeof(struct ena_admin_rss_ind_table_entry); + + rc = ena_com_get_feature_ex(ena_dev, &get_resp, + ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG, + rss->rss_ind_tbl_dma_addr, + tbl_size); + if (unlikely(rc)) + return rc; + + if (!ind_tbl) + return 0; + + rc = ena_com_ind_tbl_convert_from_device(ena_dev); + if (unlikely(rc)) + return rc; + + for (i = 0; i < (1 << rss->tbl_log_size); i++) + ind_tbl[i] = rss->host_rss_ind_tbl[i]; + + return 0; +} + +int ena_com_rss_init(struct ena_com_dev *ena_dev, u16 indr_tbl_log_size) +{ + int rc; + + memset(&ena_dev->rss, 0x0, sizeof(ena_dev->rss)); + + rc = ena_com_indirect_table_allocate(ena_dev, indr_tbl_log_size); + if (unlikely(rc)) + goto err_indr_tbl; + + rc = ena_com_hash_key_allocate(ena_dev); + if (unlikely(rc)) + goto err_hash_key; + + rc = ena_com_hash_ctrl_init(ena_dev); + if (unlikely(rc)) + goto err_hash_ctrl; + + return 0; + +err_hash_ctrl: + ena_com_hash_key_destroy(ena_dev); +err_hash_key: + ena_com_indirect_table_destroy(ena_dev); +err_indr_tbl: + + return rc; +} + +void ena_com_rss_destroy(struct ena_com_dev *ena_dev) +{ + ena_com_indirect_table_destroy(ena_dev); + ena_com_hash_key_destroy(ena_dev); + ena_com_hash_ctrl_destroy(ena_dev); + + memset(&ena_dev->rss, 0x0, sizeof(ena_dev->rss)); +} + +int ena_com_allocate_host_info(struct ena_com_dev *ena_dev) +{ + struct ena_host_attribute *host_attr = &ena_dev->host_attr; + + ENA_MEM_ALLOC_COHERENT(ena_dev->dmadev, + SZ_4K, + host_attr->host_info, + host_attr->host_info_dma_addr, + host_attr->host_info_dma_handle); + if (unlikely(!host_attr->host_info)) + return ENA_COM_NO_MEM; + + return 0; +} + +int ena_com_allocate_debug_area(struct ena_com_dev *ena_dev, + u32 debug_area_size) +{ + struct ena_host_attribute *host_attr = &ena_dev->host_attr; + + ENA_MEM_ALLOC_COHERENT(ena_dev->dmadev, + debug_area_size, + host_attr->debug_area_virt_addr, + host_attr->debug_area_dma_addr, + host_attr->debug_area_dma_handle); + if (unlikely(!host_attr->debug_area_virt_addr)) { + host_attr->debug_area_size = 0; + return ENA_COM_NO_MEM; + } + + host_attr->debug_area_size = debug_area_size; + + return 0; +} + +void ena_com_delete_host_info(struct ena_com_dev *ena_dev) +{ + struct ena_host_attribute *host_attr = &ena_dev->host_attr; + + if (host_attr->host_info) { + ENA_MEM_FREE_COHERENT(ena_dev->dmadev, + SZ_4K, + host_attr->host_info, + host_attr->host_info_dma_addr, + host_attr->host_info_dma_handle); + host_attr->host_info = NULL; + } +} + +void ena_com_delete_debug_area(struct ena_com_dev *ena_dev) +{ + struct ena_host_attribute *host_attr = &ena_dev->host_attr; + + if (host_attr->debug_area_virt_addr) { + ENA_MEM_FREE_COHERENT(ena_dev->dmadev, + host_attr->debug_area_size, + host_attr->debug_area_virt_addr, + host_attr->debug_area_dma_addr, + host_attr->debug_area_dma_handle); + host_attr->debug_area_virt_addr = NULL; + } +} + +int ena_com_set_host_attributes(struct ena_com_dev *ena_dev) +{ + struct ena_host_attribute *host_attr = &ena_dev->host_attr; + struct ena_com_admin_queue *admin_queue; + struct ena_admin_set_feat_cmd cmd; + struct ena_admin_set_feat_resp resp; + + int ret; + + /* Host attribute config is called before ena_com_get_dev_attr_feat + * so ena_com can't check if the feature is supported. + */ + + memset(&cmd, 0x0, sizeof(cmd)); + admin_queue = &ena_dev->admin_queue; + + cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE; + cmd.feat_common.feature_id = ENA_ADMIN_HOST_ATTR_CONFIG; + + ret = ena_com_mem_addr_set(ena_dev, + &cmd.u.host_attr.debug_ba, + host_attr->debug_area_dma_addr); + if (unlikely(ret)) { + ena_trc_err("memory address set failed\n"); + return ret; + } + + ret = ena_com_mem_addr_set(ena_dev, + &cmd.u.host_attr.os_info_ba, + host_attr->host_info_dma_addr); + if (unlikely(ret)) { + ena_trc_err("memory address set failed\n"); + return ret; + } + + cmd.u.host_attr.debug_area_size = host_attr->debug_area_size; + + ret = ena_com_execute_admin_command(admin_queue, + (struct ena_admin_aq_entry *)&cmd, + sizeof(cmd), + (struct ena_admin_acq_entry *)&resp, + sizeof(resp)); + + if (unlikely(ret)) + ena_trc_err("Failed to set host attributes: %d\n", ret); + + return ret; +} + +/* Interrupt moderation */ +bool ena_com_interrupt_moderation_supported(struct ena_com_dev *ena_dev) +{ + return ena_com_check_supported_feature_id(ena_dev, + ENA_ADMIN_INTERRUPT_MODERATION); +} + +int ena_com_update_nonadaptive_moderation_interval_tx(struct ena_com_dev *ena_dev, + u32 tx_coalesce_usecs) +{ + if (!ena_dev->intr_delay_resolution) { + ena_trc_err("Illegal interrupt delay granularity value\n"); + return ENA_COM_FAULT; + } + + ena_dev->intr_moder_tx_interval = tx_coalesce_usecs / + ena_dev->intr_delay_resolution; + + return 0; +} + +int ena_com_update_nonadaptive_moderation_interval_rx(struct ena_com_dev *ena_dev, + u32 rx_coalesce_usecs) +{ + if (!ena_dev->intr_delay_resolution) { + ena_trc_err("Illegal interrupt delay granularity value\n"); + return ENA_COM_FAULT; + } + + /* We use LOWEST entry of moderation table for storing + * nonadaptive interrupt coalescing values + */ + ena_dev->intr_moder_tbl[ENA_INTR_MODER_LOWEST].intr_moder_interval = + rx_coalesce_usecs / ena_dev->intr_delay_resolution; + + return 0; +} + +void ena_com_destroy_interrupt_moderation(struct ena_com_dev *ena_dev) +{ + if (ena_dev->intr_moder_tbl) + ENA_MEM_FREE(ena_dev->dmadev, ena_dev->intr_moder_tbl); + ena_dev->intr_moder_tbl = NULL; +} + +int ena_com_init_interrupt_moderation(struct ena_com_dev *ena_dev) +{ + struct ena_admin_get_feat_resp get_resp; + u16 delay_resolution; + int rc; + + rc = ena_com_get_feature(ena_dev, &get_resp, + ENA_ADMIN_INTERRUPT_MODERATION); + + if (rc) { + if (rc == ENA_COM_PERMISSION) { + ena_trc_dbg("Feature %d isn't supported\n", + ENA_ADMIN_INTERRUPT_MODERATION); + rc = 0; + } else { + ena_trc_err("Failed to get interrupt moderation admin cmd. rc: %d\n", + rc); + } + + /* no moderation supported, disable adaptive support */ + ena_com_disable_adaptive_moderation(ena_dev); + return rc; + } + + rc = ena_com_init_interrupt_moderation_table(ena_dev); + if (rc) + goto err; + + /* if moderation is supported by device we set adaptive moderation */ + delay_resolution = get_resp.u.intr_moderation.intr_delay_resolution; + ena_com_update_intr_delay_resolution(ena_dev, delay_resolution); + ena_com_enable_adaptive_moderation(ena_dev); + + return 0; +err: + ena_com_destroy_interrupt_moderation(ena_dev); + return rc; +} + +void ena_com_config_default_interrupt_moderation_table(struct ena_com_dev *ena_dev) +{ + struct ena_intr_moder_entry *intr_moder_tbl = ena_dev->intr_moder_tbl; + + if (!intr_moder_tbl) + return; + + intr_moder_tbl[ENA_INTR_MODER_LOWEST].intr_moder_interval = + ENA_INTR_LOWEST_USECS; + intr_moder_tbl[ENA_INTR_MODER_LOWEST].pkts_per_interval = + ENA_INTR_LOWEST_PKTS; + intr_moder_tbl[ENA_INTR_MODER_LOWEST].bytes_per_interval = + ENA_INTR_LOWEST_BYTES; + + intr_moder_tbl[ENA_INTR_MODER_LOW].intr_moder_interval = + ENA_INTR_LOW_USECS; + intr_moder_tbl[ENA_INTR_MODER_LOW].pkts_per_interval = + ENA_INTR_LOW_PKTS; + intr_moder_tbl[ENA_INTR_MODER_LOW].bytes_per_interval = + ENA_INTR_LOW_BYTES; + + intr_moder_tbl[ENA_INTR_MODER_MID].intr_moder_interval = + ENA_INTR_MID_USECS; + intr_moder_tbl[ENA_INTR_MODER_MID].pkts_per_interval = + ENA_INTR_MID_PKTS; + intr_moder_tbl[ENA_INTR_MODER_MID].bytes_per_interval = + ENA_INTR_MID_BYTES; + + intr_moder_tbl[ENA_INTR_MODER_HIGH].intr_moder_interval = + ENA_INTR_HIGH_USECS; + intr_moder_tbl[ENA_INTR_MODER_HIGH].pkts_per_interval = + ENA_INTR_HIGH_PKTS; + intr_moder_tbl[ENA_INTR_MODER_HIGH].bytes_per_interval = + ENA_INTR_HIGH_BYTES; + + intr_moder_tbl[ENA_INTR_MODER_HIGHEST].intr_moder_interval = + ENA_INTR_HIGHEST_USECS; + intr_moder_tbl[ENA_INTR_MODER_HIGHEST].pkts_per_interval = + ENA_INTR_HIGHEST_PKTS; + intr_moder_tbl[ENA_INTR_MODER_HIGHEST].bytes_per_interval = + ENA_INTR_HIGHEST_BYTES; +} + +unsigned int ena_com_get_nonadaptive_moderation_interval_tx(struct ena_com_dev *ena_dev) +{ + return ena_dev->intr_moder_tx_interval; +} + +unsigned int ena_com_get_nonadaptive_moderation_interval_rx(struct ena_com_dev *ena_dev) +{ + struct ena_intr_moder_entry *intr_moder_tbl = ena_dev->intr_moder_tbl; + + if (intr_moder_tbl) + return intr_moder_tbl[ENA_INTR_MODER_LOWEST].intr_moder_interval; + + return 0; +} + +void ena_com_init_intr_moderation_entry(struct ena_com_dev *ena_dev, + enum ena_intr_moder_level level, + struct ena_intr_moder_entry *entry) +{ + struct ena_intr_moder_entry *intr_moder_tbl = ena_dev->intr_moder_tbl; + + if (level >= ENA_INTR_MAX_NUM_OF_LEVELS) + return; + + intr_moder_tbl[level].intr_moder_interval = entry->intr_moder_interval; + if (ena_dev->intr_delay_resolution) + intr_moder_tbl[level].intr_moder_interval /= + ena_dev->intr_delay_resolution; + intr_moder_tbl[level].pkts_per_interval = entry->pkts_per_interval; + + /* use hardcoded value until ethtool supports bytecount parameter */ + if (entry->bytes_per_interval != ENA_INTR_BYTE_COUNT_NOT_SUPPORTED) + intr_moder_tbl[level].bytes_per_interval = entry->bytes_per_interval; +} + +void ena_com_get_intr_moderation_entry(struct ena_com_dev *ena_dev, + enum ena_intr_moder_level level, + struct ena_intr_moder_entry *entry) +{ + struct ena_intr_moder_entry *intr_moder_tbl = ena_dev->intr_moder_tbl; + + if (level >= ENA_INTR_MAX_NUM_OF_LEVELS) + return; + + entry->intr_moder_interval = intr_moder_tbl[level].intr_moder_interval; + if (ena_dev->intr_delay_resolution) + entry->intr_moder_interval *= ena_dev->intr_delay_resolution; + entry->pkts_per_interval = + intr_moder_tbl[level].pkts_per_interval; + entry->bytes_per_interval = intr_moder_tbl[level].bytes_per_interval; +} diff --git a/sys/contrib/ena-com/ena_com.h b/sys/contrib/ena-com/ena_com.h new file mode 100644 index 00000000000..3d8bf0e6737 --- /dev/null +++ b/sys/contrib/ena-com/ena_com.h @@ -0,0 +1,1054 @@ +/*- + * BSD LICENSE + * + * Copyright (c) 2015-2017 Amazon.com, Inc. or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + */ + +#ifndef ENA_COM +#define ENA_COM + +#ifndef ENA_INTERNAL +#include "ena_plat.h" +#else +#include "ena_plat.h" +#include "ena_includes.h" +#endif + +#define ENA_MAX_NUM_IO_QUEUES 128U +/* We need to queues for each IO (on for Tx and one for Rx) */ +#define ENA_TOTAL_NUM_QUEUES (2 * (ENA_MAX_NUM_IO_QUEUES)) + +#define ENA_MAX_HANDLERS 256 + +#define ENA_MAX_PHYS_ADDR_SIZE_BITS 48 + +/* Unit in usec */ +#define ENA_REG_READ_TIMEOUT 200000 + +#define ADMIN_SQ_SIZE(depth) ((depth) * sizeof(struct ena_admin_aq_entry)) +#define ADMIN_CQ_SIZE(depth) ((depth) * sizeof(struct ena_admin_acq_entry)) +#define ADMIN_AENQ_SIZE(depth) ((depth) * sizeof(struct ena_admin_aenq_entry)) + +/*****************************************************************************/ +/*****************************************************************************/ +/* ENA adaptive interrupt moderation settings */ + +#define ENA_INTR_LOWEST_USECS (0) +#define ENA_INTR_LOWEST_PKTS (3) +#define ENA_INTR_LOWEST_BYTES (2 * 1524) + +#define ENA_INTR_LOW_USECS (32) +#define ENA_INTR_LOW_PKTS (12) +#define ENA_INTR_LOW_BYTES (16 * 1024) + +#define ENA_INTR_MID_USECS (80) +#define ENA_INTR_MID_PKTS (48) +#define ENA_INTR_MID_BYTES (64 * 1024) + +#define ENA_INTR_HIGH_USECS (128) +#define ENA_INTR_HIGH_PKTS (96) +#define ENA_INTR_HIGH_BYTES (128 * 1024) + +#define ENA_INTR_HIGHEST_USECS (192) +#define ENA_INTR_HIGHEST_PKTS (128) +#define ENA_INTR_HIGHEST_BYTES (192 * 1024) + +#define ENA_INTR_INITIAL_TX_INTERVAL_USECS 196 +#define ENA_INTR_INITIAL_RX_INTERVAL_USECS 4 +#define ENA_INTR_DELAY_OLD_VALUE_WEIGHT 6 +#define ENA_INTR_DELAY_NEW_VALUE_WEIGHT 4 +#define ENA_INTR_MODER_LEVEL_STRIDE 1 +#define ENA_INTR_BYTE_COUNT_NOT_SUPPORTED 0xFFFFFF + +#define ENA_HW_HINTS_NO_TIMEOUT 0xFFFF + +enum ena_intr_moder_level { + ENA_INTR_MODER_LOWEST = 0, + ENA_INTR_MODER_LOW, + ENA_INTR_MODER_MID, + ENA_INTR_MODER_HIGH, + ENA_INTR_MODER_HIGHEST, + ENA_INTR_MAX_NUM_OF_LEVELS, +}; + +struct ena_intr_moder_entry { + unsigned int intr_moder_interval; + unsigned int pkts_per_interval; + unsigned int bytes_per_interval; +}; + +enum queue_direction { + ENA_COM_IO_QUEUE_DIRECTION_TX, + ENA_COM_IO_QUEUE_DIRECTION_RX +}; + +struct ena_com_buf { + dma_addr_t paddr; /**< Buffer physical address */ + u16 len; /**< Buffer length in bytes */ +}; + +struct ena_com_rx_buf_info { + u16 len; + u16 req_id; +}; + +struct ena_com_io_desc_addr { + u8 __iomem *pbuf_dev_addr; /* LLQ address */ + u8 *virt_addr; + dma_addr_t phys_addr; + ena_mem_handle_t mem_handle; +}; + +struct ena_com_tx_meta { + u16 mss; + u16 l3_hdr_len; + u16 l3_hdr_offset; + u16 l4_hdr_len; /* In words */ +}; + +struct ena_com_io_cq { + struct ena_com_io_desc_addr cdesc_addr; + void *bus; + + /* Interrupt unmask register */ + u32 __iomem *unmask_reg; + + /* The completion queue head doorbell register */ + u32 __iomem *cq_head_db_reg; + + /* numa configuration register (for TPH) */ + u32 __iomem *numa_node_cfg_reg; + + /* The value to write to the above register to unmask + * the interrupt of this queue + */ + u32 msix_vector; + + enum queue_direction direction; + + /* holds the number of cdesc of the current packet */ + u16 cur_rx_pkt_cdesc_count; + /* save the firt cdesc idx of the current packet */ + u16 cur_rx_pkt_cdesc_start_idx; + + u16 q_depth; + /* Caller qid */ + u16 qid; + + /* Device queue index */ + u16 idx; + u16 head; + u16 last_head_update; + u8 phase; + u8 cdesc_entry_size_in_bytes; + +} ____cacheline_aligned; + +struct ena_com_io_sq { + struct ena_com_io_desc_addr desc_addr; + void *bus; + + u32 __iomem *db_addr; + u8 __iomem *header_addr; + + enum queue_direction direction; + enum ena_admin_placement_policy_type mem_queue_type; + + u32 msix_vector; + struct ena_com_tx_meta cached_tx_meta; + + u16 q_depth; + u16 qid; + + u16 idx; + u16 tail; + u16 next_to_comp; + u32 tx_max_header_size; + u8 phase; + u8 desc_entry_size; + u8 dma_addr_bits; +} ____cacheline_aligned; + +struct ena_com_admin_cq { + struct ena_admin_acq_entry *entries; + ena_mem_handle_t mem_handle; + dma_addr_t dma_addr; + + u16 head; + u8 phase; +}; + +struct ena_com_admin_sq { + struct ena_admin_aq_entry *entries; + ena_mem_handle_t mem_handle; + dma_addr_t dma_addr; + + u32 __iomem *db_addr; + + u16 head; + u16 tail; + u8 phase; + +}; + +struct ena_com_stats_admin { + u32 aborted_cmd; + u32 submitted_cmd; + u32 completed_cmd; + u32 out_of_space; + u32 no_completion; +}; + +struct ena_com_admin_queue { + void *q_dmadev; + void *bus; + ena_spinlock_t q_lock; /* spinlock for the admin queue */ + + struct ena_comp_ctx *comp_ctx; + u32 completion_timeout; + u16 q_depth; + struct ena_com_admin_cq cq; + struct ena_com_admin_sq sq; + + /* Indicate if the admin queue should poll for completion */ + bool polling; + + u16 curr_cmd_id; + + /* Indicate that the ena was initialized and can + * process new admin commands + */ + bool running_state; + + /* Count the number of outstanding admin commands */ + ena_atomic32_t outstanding_cmds; + + struct ena_com_stats_admin stats; +}; + +struct ena_aenq_handlers; + +struct ena_com_aenq { + u16 head; + u8 phase; + struct ena_admin_aenq_entry *entries; + dma_addr_t dma_addr; + ena_mem_handle_t mem_handle; + u16 q_depth; + struct ena_aenq_handlers *aenq_handlers; +}; + +struct ena_com_mmio_read { + struct ena_admin_ena_mmio_req_read_less_resp *read_resp; + dma_addr_t read_resp_dma_addr; + ena_mem_handle_t read_resp_mem_handle; + u32 reg_read_to; /* in us */ + u16 seq_num; + bool readless_supported; + /* spin lock to ensure a single outstanding read */ + ena_spinlock_t lock; +}; + +struct ena_rss { + /* Indirect table */ + u16 *host_rss_ind_tbl; + struct ena_admin_rss_ind_table_entry *rss_ind_tbl; + dma_addr_t rss_ind_tbl_dma_addr; + ena_mem_handle_t rss_ind_tbl_mem_handle; + u16 tbl_log_size; + + /* Hash key */ + enum ena_admin_hash_functions hash_func; + struct ena_admin_feature_rss_flow_hash_control *hash_key; + dma_addr_t hash_key_dma_addr; + ena_mem_handle_t hash_key_mem_handle; + u32 hash_init_val; + + /* Flow Control */ + struct ena_admin_feature_rss_hash_control *hash_ctrl; + dma_addr_t hash_ctrl_dma_addr; + ena_mem_handle_t hash_ctrl_mem_handle; + +}; + +struct ena_host_attribute { + /* Debug area */ + u8 *debug_area_virt_addr; + dma_addr_t debug_area_dma_addr; + ena_mem_handle_t debug_area_dma_handle; + u32 debug_area_size; + + /* Host information */ + struct ena_admin_host_info *host_info; + dma_addr_t host_info_dma_addr; + ena_mem_handle_t host_info_dma_handle; +}; + +/* Each ena_dev is a PCI function. */ +struct ena_com_dev { + struct ena_com_admin_queue admin_queue; + struct ena_com_aenq aenq; + struct ena_com_io_cq io_cq_queues[ENA_TOTAL_NUM_QUEUES]; + struct ena_com_io_sq io_sq_queues[ENA_TOTAL_NUM_QUEUES]; + u8 __iomem *reg_bar; + void __iomem *mem_bar; + void *dmadev; + void *bus; + enum ena_admin_placement_policy_type tx_mem_queue_type; + u32 tx_max_header_size; + u16 stats_func; /* Selected function for extended statistic dump */ + u16 stats_queue; /* Selected queue for extended statistic dump */ + + struct ena_com_mmio_read mmio_read; + + struct ena_rss rss; + u32 supported_features; + u32 dma_addr_bits; + + struct ena_host_attribute host_attr; + bool adaptive_coalescing; + u16 intr_delay_resolution; + u32 intr_moder_tx_interval; + struct ena_intr_moder_entry *intr_moder_tbl; +}; + +struct ena_com_dev_get_features_ctx { + struct ena_admin_queue_feature_desc max_queues; + struct ena_admin_device_attr_feature_desc dev_attr; + struct ena_admin_feature_aenq_desc aenq; + struct ena_admin_feature_offload_desc offload; + struct ena_admin_ena_hw_hints hw_hints; +}; + +struct ena_com_create_io_ctx { + enum ena_admin_placement_policy_type mem_queue_type; + enum queue_direction direction; + int numa_node; + u32 msix_vector; + u16 queue_size; + u16 qid; +}; + +typedef void (*ena_aenq_handler)(void *data, + struct ena_admin_aenq_entry *aenq_e); + +/* Holds aenq handlers. Indexed by AENQ event group */ +struct ena_aenq_handlers { + ena_aenq_handler handlers[ENA_MAX_HANDLERS]; + ena_aenq_handler unimplemented_handler; +}; + +/*****************************************************************************/ +/*****************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif + +/* ena_com_mmio_reg_read_request_init - Init the mmio reg read mechanism + * @ena_dev: ENA communication layer struct + * + * Initialize the register read mechanism. + * + * @note: This method must be the first stage in the initialization sequence. + * + * @return - 0 on success, negative value on failure. + */ +int ena_com_mmio_reg_read_request_init(struct ena_com_dev *ena_dev); + +/* ena_com_set_mmio_read_mode - Enable/disable the mmio reg read mechanism + * @ena_dev: ENA communication layer struct + * @readless_supported: readless mode (enable/disable) + */ +void ena_com_set_mmio_read_mode(struct ena_com_dev *ena_dev, + bool readless_supported); + +/* ena_com_mmio_reg_read_request_write_dev_addr - Write the mmio reg read return + * value physical address. + * @ena_dev: ENA communication layer struct + */ +void ena_com_mmio_reg_read_request_write_dev_addr(struct ena_com_dev *ena_dev); + +/* ena_com_mmio_reg_read_request_destroy - Destroy the mmio reg read mechanism + * @ena_dev: ENA communication layer struct + */ +void ena_com_mmio_reg_read_request_destroy(struct ena_com_dev *ena_dev); + +/* ena_com_admin_init - Init the admin and the async queues + * @ena_dev: ENA communication layer struct + * @aenq_handlers: Those handlers to be called upon event. + * @init_spinlock: Indicate if this method should init the admin spinlock or + * the spinlock was init before (for example, in a case of FLR). + * + * Initialize the admin submission and completion queues. + * Initialize the asynchronous events notification queues. + * + * @return - 0 on success, negative value on failure. + */ +int ena_com_admin_init(struct ena_com_dev *ena_dev, + struct ena_aenq_handlers *aenq_handlers, + bool init_spinlock); + +/* ena_com_admin_destroy - Destroy the admin and the async events queues. + * @ena_dev: ENA communication layer struct + * + * @note: Before calling this method, the caller must validate that the device + * won't send any additional admin completions/aenq. + * To achieve that, a FLR is recommended. + */ +void ena_com_admin_destroy(struct ena_com_dev *ena_dev); + +/* ena_com_dev_reset - Perform device FLR to the device. + * @ena_dev: ENA communication layer struct + * + * @return - 0 on success, negative value on failure. + */ +int ena_com_dev_reset(struct ena_com_dev *ena_dev); + +/* ena_com_create_io_queue - Create io queue. + * @ena_dev: ENA communication layer struct + * @ctx - create context structure + * + * Create the submission and the completion queues. + * + * @return - 0 on success, negative value on failure. + */ +int ena_com_create_io_queue(struct ena_com_dev *ena_dev, + struct ena_com_create_io_ctx *ctx); + +/* ena_com_destroy_io_queue - Destroy IO queue with the queue id - qid. + * @ena_dev: ENA communication layer struct + * @qid - the caller virtual queue id. + */ +void ena_com_destroy_io_queue(struct ena_com_dev *ena_dev, u16 qid); + +/* ena_com_get_io_handlers - Return the io queue handlers + * @ena_dev: ENA communication layer struct + * @qid - the caller virtual queue id. + * @io_sq - IO submission queue handler + * @io_cq - IO completion queue handler. + * + * @return - 0 on success, negative value on failure. + */ +int ena_com_get_io_handlers(struct ena_com_dev *ena_dev, u16 qid, + struct ena_com_io_sq **io_sq, + struct ena_com_io_cq **io_cq); + +/* ena_com_admin_aenq_enable - ENAble asynchronous event notifications + * @ena_dev: ENA communication layer struct + * + * After this method, aenq event can be received via AENQ. + */ +void ena_com_admin_aenq_enable(struct ena_com_dev *ena_dev); + +/* ena_com_set_admin_running_state - Set the state of the admin queue + * @ena_dev: ENA communication layer struct + * + * Change the state of the admin queue (enable/disable) + */ +void ena_com_set_admin_running_state(struct ena_com_dev *ena_dev, bool state); + +/* ena_com_get_admin_running_state - Get the admin queue state + * @ena_dev: ENA communication layer struct + * + * Retrieve the state of the admin queue (enable/disable) + * + * @return - current polling mode (enable/disable) + */ +bool ena_com_get_admin_running_state(struct ena_com_dev *ena_dev); + +/* ena_com_set_admin_polling_mode - Set the admin completion queue polling mode + * @ena_dev: ENA communication layer struct + * @polling: ENAble/Disable polling mode + * + * Set the admin completion mode. + */ +void ena_com_set_admin_polling_mode(struct ena_com_dev *ena_dev, bool polling); + +/* ena_com_set_admin_polling_mode - Get the admin completion queue polling mode + * @ena_dev: ENA communication layer struct + * + * Get the admin completion mode. + * If polling mode is on, ena_com_execute_admin_command will perform a + * polling on the admin completion queue for the commands completion, + * otherwise it will wait on wait event. + * + * @return state + */ +bool ena_com_get_ena_admin_polling_mode(struct ena_com_dev *ena_dev); + +/* ena_com_admin_q_comp_intr_handler - admin queue interrupt handler + * @ena_dev: ENA communication layer struct + * + * This method go over the admin completion queue and wake up all the pending + * threads that wait on the commands wait event. + * + * @note: Should be called after MSI-X interrupt. + */ +void ena_com_admin_q_comp_intr_handler(struct ena_com_dev *ena_dev); + +/* ena_com_aenq_intr_handler - AENQ interrupt handler + * @ena_dev: ENA communication layer struct + * + * This method go over the async event notification queue and call the proper + * aenq handler. + */ +void ena_com_aenq_intr_handler(struct ena_com_dev *dev, void *data); + +/* ena_com_abort_admin_commands - Abort all the outstanding admin commands. + * @ena_dev: ENA communication layer struct + * + * This method aborts all the outstanding admin commands. + * The caller should then call ena_com_wait_for_abort_completion to make sure + * all the commands were completed. + */ +void ena_com_abort_admin_commands(struct ena_com_dev *ena_dev); + +/* ena_com_wait_for_abort_completion - Wait for admin commands abort. + * @ena_dev: ENA communication layer struct + * + * This method wait until all the outstanding admin commands will be completed. + */ +void ena_com_wait_for_abort_completion(struct ena_com_dev *ena_dev); + +/* ena_com_validate_version - Validate the device parameters + * @ena_dev: ENA communication layer struct + * + * This method validate the device parameters are the same as the saved + * parameters in ena_dev. + * This method is useful after device reset, to validate the device mac address + * and the device offloads are the same as before the reset. + * + * @return - 0 on success negative value otherwise. + */ +int ena_com_validate_version(struct ena_com_dev *ena_dev); + +/* ena_com_get_link_params - Retrieve physical link parameters. + * @ena_dev: ENA communication layer struct + * @resp: Link parameters + * + * Retrieve the physical link parameters, + * like speed, auto-negotiation and full duplex support. + * + * @return - 0 on Success negative value otherwise. + */ +int ena_com_get_link_params(struct ena_com_dev *ena_dev, + struct ena_admin_get_feat_resp *resp); + +/* ena_com_get_dma_width - Retrieve physical dma address width the device + * supports. + * @ena_dev: ENA communication layer struct + * + * Retrieve the maximum physical address bits the device can handle. + * + * @return: > 0 on Success and negative value otherwise. + */ +int ena_com_get_dma_width(struct ena_com_dev *ena_dev); + +/* ena_com_set_aenq_config - Set aenq groups configurations + * @ena_dev: ENA communication layer struct + * @groups flag: bit fields flags of enum ena_admin_aenq_group. + * + * Configure which aenq event group the driver would like to receive. + * + * @return: 0 on Success and negative value otherwise. + */ +int ena_com_set_aenq_config(struct ena_com_dev *ena_dev, u32 groups_flag); + +/* ena_com_get_dev_attr_feat - Get device features + * @ena_dev: ENA communication layer struct + * @get_feat_ctx: returned context that contain the get features. + * + * @return: 0 on Success and negative value otherwise. + */ +int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev, + struct ena_com_dev_get_features_ctx *get_feat_ctx); + +/* ena_com_get_dev_basic_stats - Get device basic statistics + * @ena_dev: ENA communication layer struct + * @stats: stats return value + * + * @return: 0 on Success and negative value otherwise. + */ +int ena_com_get_dev_basic_stats(struct ena_com_dev *ena_dev, + struct ena_admin_basic_stats *stats); + +/* ena_com_set_dev_mtu - Configure the device mtu. + * @ena_dev: ENA communication layer struct + * @mtu: mtu value + * + * @return: 0 on Success and negative value otherwise. + */ +int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, int mtu); + +/* ena_com_get_offload_settings - Retrieve the device offloads capabilities + * @ena_dev: ENA communication layer struct + * @offlad: offload return value + * + * @return: 0 on Success and negative value otherwise. + */ +int ena_com_get_offload_settings(struct ena_com_dev *ena_dev, + struct ena_admin_feature_offload_desc *offload); + +/* ena_com_rss_init - Init RSS + * @ena_dev: ENA communication layer struct + * @log_size: indirection log size + * + * Allocate RSS/RFS resources. + * The caller then can configure rss using ena_com_set_hash_function, + * ena_com_set_hash_ctrl and ena_com_indirect_table_set. + * + * @return: 0 on Success and negative value otherwise. + */ +int ena_com_rss_init(struct ena_com_dev *ena_dev, u16 log_size); + +/* ena_com_rss_destroy - Destroy rss + * @ena_dev: ENA communication layer struct + * + * Free all the RSS/RFS resources. + */ +void ena_com_rss_destroy(struct ena_com_dev *ena_dev); + +/* ena_com_fill_hash_function - Fill RSS hash function + * @ena_dev: ENA communication layer struct + * @func: The hash function (Toeplitz or crc) + * @key: Hash key (for toeplitz hash) + * @key_len: key length (max length 10 DW) + * @init_val: initial value for the hash function + * + * Fill the ena_dev resources with the desire hash function, hash key, key_len + * and key initial value (if needed by the hash function). + * To flush the key into the device the caller should call + * ena_com_set_hash_function. + * + * @return: 0 on Success and negative value otherwise. + */ +int ena_com_fill_hash_function(struct ena_com_dev *ena_dev, + enum ena_admin_hash_functions func, + const u8 *key, u16 key_len, u32 init_val); + +/* ena_com_set_hash_function - Flush the hash function and it dependencies to + * the device. + * @ena_dev: ENA communication layer struct + * + * Flush the hash function and it dependencies (key, key length and + * initial value) if needed. + * + * @note: Prior to this method the caller should call ena_com_fill_hash_function + * + * @return: 0 on Success and negative value otherwise. + */ +int ena_com_set_hash_function(struct ena_com_dev *ena_dev); + +/* ena_com_get_hash_function - Retrieve the hash function and the hash key + * from the device. + * @ena_dev: ENA communication layer struct + * @func: hash function + * @key: hash key + * + * Retrieve the hash function and the hash key from the device. + * + * @note: If the caller called ena_com_fill_hash_function but didn't flash + * it to the device, the new configuration will be lost. + * + * @return: 0 on Success and negative value otherwise. + */ +int ena_com_get_hash_function(struct ena_com_dev *ena_dev, + enum ena_admin_hash_functions *func, + u8 *key); + +/* ena_com_fill_hash_ctrl - Fill RSS hash control + * @ena_dev: ENA communication layer struct. + * @proto: The protocol to configure. + * @hash_fields: bit mask of ena_admin_flow_hash_fields + * + * Fill the ena_dev resources with the desire hash control (the ethernet + * fields that take part of the hash) for a specific protocol. + * To flush the hash control to the device, the caller should call + * ena_com_set_hash_ctrl. + * + * @return: 0 on Success and negative value otherwise. + */ +int ena_com_fill_hash_ctrl(struct ena_com_dev *ena_dev, + enum ena_admin_flow_hash_proto proto, + u16 hash_fields); + +/* ena_com_set_hash_ctrl - Flush the hash control resources to the device. + * @ena_dev: ENA communication layer struct + * + * Flush the hash control (the ethernet fields that take part of the hash) + * + * @note: Prior to this method the caller should call ena_com_fill_hash_ctrl. + * + * @return: 0 on Success and negative value otherwise. + */ +int ena_com_set_hash_ctrl(struct ena_com_dev *ena_dev); + +/* ena_com_get_hash_ctrl - Retrieve the hash control from the device. + * @ena_dev: ENA communication layer struct + * @proto: The protocol to retrieve. + * @fields: bit mask of ena_admin_flow_hash_fields. + * + * Retrieve the hash control from the device. + * + * @note, If the caller called ena_com_fill_hash_ctrl but didn't flash + * it to the device, the new configuration will be lost. + * + * @return: 0 on Success and negative value otherwise. + */ +int ena_com_get_hash_ctrl(struct ena_com_dev *ena_dev, + enum ena_admin_flow_hash_proto proto, + u16 *fields); + +/* ena_com_set_default_hash_ctrl - Set the hash control to a default + * configuration. + * @ena_dev: ENA communication layer struct + * + * Fill the ena_dev resources with the default hash control configuration. + * To flush the hash control to the device, the caller should call + * ena_com_set_hash_ctrl. + * + * @return: 0 on Success and negative value otherwise. + */ +int ena_com_set_default_hash_ctrl(struct ena_com_dev *ena_dev); + +/* ena_com_indirect_table_fill_entry - Fill a single entry in the RSS + * indirection table + * @ena_dev: ENA communication layer struct. + * @entry_idx - indirection table entry. + * @entry_value - redirection value + * + * Fill a single entry of the RSS indirection table in the ena_dev resources. + * To flush the indirection table to the device, the called should call + * ena_com_indirect_table_set. + * + * @return: 0 on Success and negative value otherwise. + */ +int ena_com_indirect_table_fill_entry(struct ena_com_dev *ena_dev, + u16 entry_idx, u16 entry_value); + +/* ena_com_indirect_table_set - Flush the indirection table to the device. + * @ena_dev: ENA communication layer struct + * + * Flush the indirection hash control to the device. + * Prior to this method the caller should call ena_com_indirect_table_fill_entry + * + * @return: 0 on Success and negative value otherwise. + */ +int ena_com_indirect_table_set(struct ena_com_dev *ena_dev); + +/* ena_com_indirect_table_get - Retrieve the indirection table from the device. + * @ena_dev: ENA communication layer struct + * @ind_tbl: indirection table + * + * Retrieve the RSS indirection table from the device. + * + * @note: If the caller called ena_com_indirect_table_fill_entry but didn't flash + * it to the device, the new configuration will be lost. + * + * @return: 0 on Success and negative value otherwise. + */ +int ena_com_indirect_table_get(struct ena_com_dev *ena_dev, u32 *ind_tbl); + +/* ena_com_allocate_host_info - Allocate host info resources. + * @ena_dev: ENA communication layer struct + * + * @return: 0 on Success and negative value otherwise. + */ +int ena_com_allocate_host_info(struct ena_com_dev *ena_dev); + +/* ena_com_allocate_debug_area - Allocate debug area. + * @ena_dev: ENA communication layer struct + * @debug_area_size - debug area size. + * + * @return: 0 on Success and negative value otherwise. + */ +int ena_com_allocate_debug_area(struct ena_com_dev *ena_dev, + u32 debug_area_size); + +/* ena_com_delete_debug_area - Free the debug area resources. + * @ena_dev: ENA communication layer struct + * + * Free the allocate debug area. + */ +void ena_com_delete_debug_area(struct ena_com_dev *ena_dev); + +/* ena_com_delete_host_info - Free the host info resources. + * @ena_dev: ENA communication layer struct + * + * Free the allocate host info. + */ +void ena_com_delete_host_info(struct ena_com_dev *ena_dev); + +/* ena_com_set_host_attributes - Update the device with the host + * attributes (debug area and host info) base address. + * @ena_dev: ENA communication layer struct + * + * @return: 0 on Success and negative value otherwise. + */ +int ena_com_set_host_attributes(struct ena_com_dev *ena_dev); + +/* ena_com_create_io_cq - Create io completion queue. + * @ena_dev: ENA communication layer struct + * @io_cq - io completion queue handler + + * Create IO completion queue. + * + * @return - 0 on success, negative value on failure. + */ +int ena_com_create_io_cq(struct ena_com_dev *ena_dev, + struct ena_com_io_cq *io_cq); + +/* ena_com_destroy_io_cq - Destroy io completion queue. + * @ena_dev: ENA communication layer struct + * @io_cq - io completion queue handler + + * Destroy IO completion queue. + * + * @return - 0 on success, negative value on failure. + */ +int ena_com_destroy_io_cq(struct ena_com_dev *ena_dev, + struct ena_com_io_cq *io_cq); + +/* ena_com_execute_admin_command - Execute admin command + * @admin_queue: admin queue. + * @cmd: the admin command to execute. + * @cmd_size: the command size. + * @cmd_completion: command completion return value. + * @cmd_comp_size: command completion size. + + * Submit an admin command and then wait until the device will return a + * completion. + * The completion will be copyed into cmd_comp. + * + * @return - 0 on success, negative value on failure. + */ +int ena_com_execute_admin_command(struct ena_com_admin_queue *admin_queue, + struct ena_admin_aq_entry *cmd, + size_t cmd_size, + struct ena_admin_acq_entry *cmd_comp, + size_t cmd_comp_size); + +/* ena_com_init_interrupt_moderation - Init interrupt moderation + * @ena_dev: ENA communication layer struct + * + * @return - 0 on success, negative value on failure. + */ +int ena_com_init_interrupt_moderation(struct ena_com_dev *ena_dev); + +/* ena_com_destroy_interrupt_moderation - Destroy interrupt moderation resources + * @ena_dev: ENA communication layer struct + */ +void ena_com_destroy_interrupt_moderation(struct ena_com_dev *ena_dev); + +/* ena_com_interrupt_moderation_supported - Return if interrupt moderation + * capability is supported by the device. + * + * @return - supported or not. + */ +bool ena_com_interrupt_moderation_supported(struct ena_com_dev *ena_dev); + +/* ena_com_config_default_interrupt_moderation_table - Restore the interrupt + * moderation table back to the default parameters. + * @ena_dev: ENA communication layer struct + */ +void ena_com_config_default_interrupt_moderation_table(struct ena_com_dev *ena_dev); + +/* ena_com_update_nonadaptive_moderation_interval_tx - Update the + * non-adaptive interval in Tx direction. + * @ena_dev: ENA communication layer struct + * @tx_coalesce_usecs: Interval in usec. + * + * @return - 0 on success, negative value on failure. + */ +int ena_com_update_nonadaptive_moderation_interval_tx(struct ena_com_dev *ena_dev, + u32 tx_coalesce_usecs); + +/* ena_com_update_nonadaptive_moderation_interval_rx - Update the + * non-adaptive interval in Rx direction. + * @ena_dev: ENA communication layer struct + * @rx_coalesce_usecs: Interval in usec. + * + * @return - 0 on success, negative value on failure. + */ +int ena_com_update_nonadaptive_moderation_interval_rx(struct ena_com_dev *ena_dev, + u32 rx_coalesce_usecs); + +/* ena_com_get_nonadaptive_moderation_interval_tx - Retrieve the + * non-adaptive interval in Tx direction. + * @ena_dev: ENA communication layer struct + * + * @return - interval in usec + */ +unsigned int ena_com_get_nonadaptive_moderation_interval_tx(struct ena_com_dev *ena_dev); + +/* ena_com_get_nonadaptive_moderation_interval_rx - Retrieve the + * non-adaptive interval in Rx direction. + * @ena_dev: ENA communication layer struct + * + * @return - interval in usec + */ +unsigned int ena_com_get_nonadaptive_moderation_interval_rx(struct ena_com_dev *ena_dev); + +/* ena_com_init_intr_moderation_entry - Update a single entry in the interrupt + * moderation table. + * @ena_dev: ENA communication layer struct + * @level: Interrupt moderation table level + * @entry: Entry value + * + * Update a single entry in the interrupt moderation table. + */ +void ena_com_init_intr_moderation_entry(struct ena_com_dev *ena_dev, + enum ena_intr_moder_level level, + struct ena_intr_moder_entry *entry); + +/* ena_com_get_intr_moderation_entry - Init ena_intr_moder_entry. + * @ena_dev: ENA communication layer struct + * @level: Interrupt moderation table level + * @entry: Entry to fill. + * + * Initialize the entry according to the adaptive interrupt moderation table. + */ +void ena_com_get_intr_moderation_entry(struct ena_com_dev *ena_dev, + enum ena_intr_moder_level level, + struct ena_intr_moder_entry *entry); + +static inline bool ena_com_get_adaptive_moderation_enabled(struct ena_com_dev *ena_dev) +{ + return ena_dev->adaptive_coalescing; +} + +static inline void ena_com_enable_adaptive_moderation(struct ena_com_dev *ena_dev) +{ + ena_dev->adaptive_coalescing = true; +} + +static inline void ena_com_disable_adaptive_moderation(struct ena_com_dev *ena_dev) +{ + ena_dev->adaptive_coalescing = false; +} + +/* ena_com_calculate_interrupt_delay - Calculate new interrupt delay + * @ena_dev: ENA communication layer struct + * @pkts: Number of packets since the last update + * @bytes: Number of bytes received since the last update. + * @smoothed_interval: Returned interval + * @moder_tbl_idx: Current table level as input update new level as return + * value. + */ +static inline void ena_com_calculate_interrupt_delay(struct ena_com_dev *ena_dev, + unsigned int pkts, + unsigned int bytes, + unsigned int *smoothed_interval, + unsigned int *moder_tbl_idx) +{ + enum ena_intr_moder_level curr_moder_idx, new_moder_idx; + struct ena_intr_moder_entry *curr_moder_entry; + struct ena_intr_moder_entry *pred_moder_entry; + struct ena_intr_moder_entry *new_moder_entry; + struct ena_intr_moder_entry *intr_moder_tbl = ena_dev->intr_moder_tbl; + unsigned int interval; + + /* We apply adaptive moderation on Rx path only. + * Tx uses static interrupt moderation. + */ + if (!pkts || !bytes) + /* Tx interrupt, or spurious interrupt, + * in both cases we just use same delay values + */ + return; + + curr_moder_idx = (enum ena_intr_moder_level)(*moder_tbl_idx); + if (unlikely(curr_moder_idx >= ENA_INTR_MAX_NUM_OF_LEVELS)) { + ena_trc_err("Wrong moderation index %u\n", curr_moder_idx); + return; + } + + curr_moder_entry = &intr_moder_tbl[curr_moder_idx]; + new_moder_idx = curr_moder_idx; + + if (curr_moder_idx == ENA_INTR_MODER_LOWEST) { + if ((pkts > curr_moder_entry->pkts_per_interval) || + (bytes > curr_moder_entry->bytes_per_interval)) + new_moder_idx = + (enum ena_intr_moder_level)(curr_moder_idx + ENA_INTR_MODER_LEVEL_STRIDE); + } else { + pred_moder_entry = &intr_moder_tbl[curr_moder_idx - ENA_INTR_MODER_LEVEL_STRIDE]; + + if ((pkts <= pred_moder_entry->pkts_per_interval) || + (bytes <= pred_moder_entry->bytes_per_interval)) + new_moder_idx = + (enum ena_intr_moder_level)(curr_moder_idx - ENA_INTR_MODER_LEVEL_STRIDE); + else if ((pkts > curr_moder_entry->pkts_per_interval) || + (bytes > curr_moder_entry->bytes_per_interval)) { + if (curr_moder_idx != ENA_INTR_MODER_HIGHEST) + new_moder_idx = + (enum ena_intr_moder_level)(curr_moder_idx + ENA_INTR_MODER_LEVEL_STRIDE); + } + } + new_moder_entry = &intr_moder_tbl[new_moder_idx]; + + interval = new_moder_entry->intr_moder_interval; + *smoothed_interval = ( + (interval * ENA_INTR_DELAY_NEW_VALUE_WEIGHT + + ENA_INTR_DELAY_OLD_VALUE_WEIGHT * (*smoothed_interval)) + 5) / + 10; + + *moder_tbl_idx = new_moder_idx; +} + +/* ena_com_update_intr_reg - Prepare interrupt register + * @intr_reg: interrupt register to update. + * @rx_delay_interval: Rx interval in usecs + * @tx_delay_interval: Tx interval in usecs + * @unmask: unask enable/disable + * + * Prepare interrupt update register with the supplied parameters. + */ +static inline void ena_com_update_intr_reg(struct ena_eth_io_intr_reg *intr_reg, + u32 rx_delay_interval, + u32 tx_delay_interval, + bool unmask) +{ + intr_reg->intr_control = 0; + intr_reg->intr_control |= rx_delay_interval & + ENA_ETH_IO_INTR_REG_RX_INTR_DELAY_MASK; + + intr_reg->intr_control |= + (tx_delay_interval << ENA_ETH_IO_INTR_REG_TX_INTR_DELAY_SHIFT) + & ENA_ETH_IO_INTR_REG_TX_INTR_DELAY_MASK; + + if (unmask) + intr_reg->intr_control |= ENA_ETH_IO_INTR_REG_INTR_UNMASK_MASK; +} + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ +#endif /* !(ENA_COM) */ diff --git a/sys/contrib/ena-com/ena_common_defs.h b/sys/contrib/ena-com/ena_common_defs.h new file mode 100644 index 00000000000..f2d8189860a --- /dev/null +++ b/sys/contrib/ena-com/ena_common_defs.h @@ -0,0 +1,50 @@ +/*- + * BSD LICENSE + * + * Copyright (c) 2015-2017 Amazon.com, Inc. or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + */ + +#ifndef _ENA_COMMON_H_ +#define _ENA_COMMON_H_ + +#define ENA_COMMON_SPEC_VERSION_MAJOR 0 /* */ +#define ENA_COMMON_SPEC_VERSION_MINOR 10 /* */ + +/* ENA operates with 48-bit memory addresses. ena_mem_addr_t */ +struct ena_common_mem_addr { + uint32_t mem_addr_low; + + uint16_t mem_addr_high; + + /* MBZ */ + uint16_t reserved16; +}; + +#endif /*_ENA_COMMON_H_ */ diff --git a/sys/contrib/ena-com/ena_eth_com.c b/sys/contrib/ena-com/ena_eth_com.c new file mode 100644 index 00000000000..fbf561e1637 --- /dev/null +++ b/sys/contrib/ena-com/ena_eth_com.c @@ -0,0 +1,509 @@ +/*- + * BSD LICENSE + * + * Copyright (c) 2015-2017 Amazon.com, Inc. or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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 "ena_eth_com.h" + +static inline struct ena_eth_io_rx_cdesc_base *ena_com_get_next_rx_cdesc( + struct ena_com_io_cq *io_cq) +{ + struct ena_eth_io_rx_cdesc_base *cdesc; + u16 expected_phase, head_masked; + u16 desc_phase; + + head_masked = io_cq->head & (io_cq->q_depth - 1); + expected_phase = io_cq->phase; + + cdesc = (struct ena_eth_io_rx_cdesc_base *)(io_cq->cdesc_addr.virt_addr + + (head_masked * io_cq->cdesc_entry_size_in_bytes)); + + desc_phase = (READ_ONCE(cdesc->status) & ENA_ETH_IO_RX_CDESC_BASE_PHASE_MASK) >> + ENA_ETH_IO_RX_CDESC_BASE_PHASE_SHIFT; + + if (desc_phase != expected_phase) + return NULL; + + return cdesc; +} + +static inline void ena_com_cq_inc_head(struct ena_com_io_cq *io_cq) +{ + io_cq->head++; + + /* Switch phase bit in case of wrap around */ + if (unlikely((io_cq->head & (io_cq->q_depth - 1)) == 0)) + io_cq->phase ^= 1; +} + +static inline void *get_sq_desc(struct ena_com_io_sq *io_sq) +{ + u16 tail_masked; + u32 offset; + + tail_masked = io_sq->tail & (io_sq->q_depth - 1); + + offset = tail_masked * io_sq->desc_entry_size; + + return (void *)((uintptr_t)io_sq->desc_addr.virt_addr + offset); +} + +static inline void ena_com_copy_curr_sq_desc_to_dev(struct ena_com_io_sq *io_sq) +{ + u16 tail_masked = io_sq->tail & (io_sq->q_depth - 1); + u32 offset = tail_masked * io_sq->desc_entry_size; + + /* In case this queue isn't a LLQ */ + if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST) + return; + + memcpy_toio(io_sq->desc_addr.pbuf_dev_addr + offset, + io_sq->desc_addr.virt_addr + offset, + io_sq->desc_entry_size); +} + +static inline void ena_com_sq_update_tail(struct ena_com_io_sq *io_sq) +{ + io_sq->tail++; + + /* Switch phase bit in case of wrap around */ + if (unlikely((io_sq->tail & (io_sq->q_depth - 1)) == 0)) + io_sq->phase ^= 1; +} + +static inline int ena_com_write_header(struct ena_com_io_sq *io_sq, + u8 *head_src, u16 header_len) +{ + u16 tail_masked = io_sq->tail & (io_sq->q_depth - 1); + u8 __iomem *dev_head_addr = + io_sq->header_addr + (tail_masked * io_sq->tx_max_header_size); + + if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST) + return 0; + + if (unlikely(!io_sq->header_addr)) { + ena_trc_err("Push buffer header ptr is NULL\n"); + return ENA_COM_INVAL; + } + + memcpy_toio(dev_head_addr, head_src, header_len); + + return 0; +} + +static inline struct ena_eth_io_rx_cdesc_base * + ena_com_rx_cdesc_idx_to_ptr(struct ena_com_io_cq *io_cq, u16 idx) +{ + idx &= (io_cq->q_depth - 1); + return (struct ena_eth_io_rx_cdesc_base *) + ((uintptr_t)io_cq->cdesc_addr.virt_addr + + idx * io_cq->cdesc_entry_size_in_bytes); +} + +static inline u16 ena_com_cdesc_rx_pkt_get(struct ena_com_io_cq *io_cq, + u16 *first_cdesc_idx) +{ + struct ena_eth_io_rx_cdesc_base *cdesc; + u16 count = 0, head_masked; + u32 last = 0; + + do { + cdesc = ena_com_get_next_rx_cdesc(io_cq); + if (!cdesc) + break; + + ena_com_cq_inc_head(io_cq); + count++; + last = (READ_ONCE(cdesc->status) & ENA_ETH_IO_RX_CDESC_BASE_LAST_MASK) >> + ENA_ETH_IO_RX_CDESC_BASE_LAST_SHIFT; + } while (!last); + + if (last) { + *first_cdesc_idx = io_cq->cur_rx_pkt_cdesc_start_idx; + count += io_cq->cur_rx_pkt_cdesc_count; + + head_masked = io_cq->head & (io_cq->q_depth - 1); + + io_cq->cur_rx_pkt_cdesc_count = 0; + io_cq->cur_rx_pkt_cdesc_start_idx = head_masked; + + ena_trc_dbg("ena q_id: %d packets were completed. first desc idx %u descs# %d\n", + io_cq->qid, *first_cdesc_idx, count); + } else { + io_cq->cur_rx_pkt_cdesc_count += count; + count = 0; + } + + return count; +} + +static inline bool ena_com_meta_desc_changed(struct ena_com_io_sq *io_sq, + struct ena_com_tx_ctx *ena_tx_ctx) +{ + int rc; + + if (ena_tx_ctx->meta_valid) { + rc = memcmp(&io_sq->cached_tx_meta, + &ena_tx_ctx->ena_meta, + sizeof(struct ena_com_tx_meta)); + + if (unlikely(rc != 0)) + return true; + } + + return false; +} + +static inline void ena_com_create_and_store_tx_meta_desc(struct ena_com_io_sq *io_sq, + struct ena_com_tx_ctx *ena_tx_ctx) +{ + struct ena_eth_io_tx_meta_desc *meta_desc = NULL; + struct ena_com_tx_meta *ena_meta = &ena_tx_ctx->ena_meta; + + meta_desc = get_sq_desc(io_sq); + memset(meta_desc, 0x0, sizeof(struct ena_eth_io_tx_meta_desc)); + + meta_desc->len_ctrl |= ENA_ETH_IO_TX_META_DESC_META_DESC_MASK; + + meta_desc->len_ctrl |= ENA_ETH_IO_TX_META_DESC_EXT_VALID_MASK; + + /* bits 0-9 of the mss */ + meta_desc->word2 |= (ena_meta->mss << + ENA_ETH_IO_TX_META_DESC_MSS_LO_SHIFT) & + ENA_ETH_IO_TX_META_DESC_MSS_LO_MASK; + /* bits 10-13 of the mss */ + meta_desc->len_ctrl |= ((ena_meta->mss >> 10) << + ENA_ETH_IO_TX_META_DESC_MSS_HI_SHIFT) & + ENA_ETH_IO_TX_META_DESC_MSS_HI_MASK; + + /* Extended meta desc */ + meta_desc->len_ctrl |= ENA_ETH_IO_TX_META_DESC_ETH_META_TYPE_MASK; + meta_desc->len_ctrl |= ENA_ETH_IO_TX_META_DESC_META_STORE_MASK; + meta_desc->len_ctrl |= (io_sq->phase << + ENA_ETH_IO_TX_META_DESC_PHASE_SHIFT) & + ENA_ETH_IO_TX_META_DESC_PHASE_MASK; + + meta_desc->len_ctrl |= ENA_ETH_IO_TX_META_DESC_FIRST_MASK; + meta_desc->word2 |= ena_meta->l3_hdr_len & + ENA_ETH_IO_TX_META_DESC_L3_HDR_LEN_MASK; + meta_desc->word2 |= (ena_meta->l3_hdr_offset << + ENA_ETH_IO_TX_META_DESC_L3_HDR_OFF_SHIFT) & + ENA_ETH_IO_TX_META_DESC_L3_HDR_OFF_MASK; + + meta_desc->word2 |= (ena_meta->l4_hdr_len << + ENA_ETH_IO_TX_META_DESC_L4_HDR_LEN_IN_WORDS_SHIFT) & + ENA_ETH_IO_TX_META_DESC_L4_HDR_LEN_IN_WORDS_MASK; + + meta_desc->len_ctrl |= ENA_ETH_IO_TX_META_DESC_META_STORE_MASK; + + /* Cached the meta desc */ + memcpy(&io_sq->cached_tx_meta, ena_meta, + sizeof(struct ena_com_tx_meta)); + + ena_com_copy_curr_sq_desc_to_dev(io_sq); + ena_com_sq_update_tail(io_sq); +} + +static inline void ena_com_rx_set_flags(struct ena_com_rx_ctx *ena_rx_ctx, + struct ena_eth_io_rx_cdesc_base *cdesc) +{ + ena_rx_ctx->l3_proto = cdesc->status & + ENA_ETH_IO_RX_CDESC_BASE_L3_PROTO_IDX_MASK; + ena_rx_ctx->l4_proto = + (cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_L4_PROTO_IDX_MASK) >> + ENA_ETH_IO_RX_CDESC_BASE_L4_PROTO_IDX_SHIFT; + ena_rx_ctx->l3_csum_err = + (cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM_ERR_MASK) >> + ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM_ERR_SHIFT; + ena_rx_ctx->l4_csum_err = + (cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_MASK) >> + ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_SHIFT; + ena_rx_ctx->hash = cdesc->hash; + ena_rx_ctx->frag = + (cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_MASK) >> + ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_SHIFT; + + ena_trc_dbg("ena_rx_ctx->l3_proto %d ena_rx_ctx->l4_proto %d\nena_rx_ctx->l3_csum_err %d ena_rx_ctx->l4_csum_err %d\nhash frag %d frag: %d cdesc_status: %x\n", + ena_rx_ctx->l3_proto, + ena_rx_ctx->l4_proto, + ena_rx_ctx->l3_csum_err, + ena_rx_ctx->l4_csum_err, + ena_rx_ctx->hash, + ena_rx_ctx->frag, + cdesc->status); +} + +/*****************************************************************************/ +/***************************** API **********************************/ +/*****************************************************************************/ + +int ena_com_prepare_tx(struct ena_com_io_sq *io_sq, + struct ena_com_tx_ctx *ena_tx_ctx, + int *nb_hw_desc) +{ + struct ena_eth_io_tx_desc *desc = NULL; + struct ena_com_buf *ena_bufs = ena_tx_ctx->ena_bufs; + void *push_header = ena_tx_ctx->push_header; + u16 header_len = ena_tx_ctx->header_len; + u16 num_bufs = ena_tx_ctx->num_bufs; + int total_desc, i, rc; + bool have_meta; + u64 addr_hi; + + ENA_WARN(io_sq->direction != ENA_COM_IO_QUEUE_DIRECTION_TX, + "wrong Q type"); + + /* num_bufs +1 for potential meta desc */ + if (ena_com_sq_empty_space(io_sq) < (num_bufs + 1)) { + ena_trc_err("Not enough space in the tx queue\n"); + return ENA_COM_NO_MEM; + } + + if (unlikely(header_len > io_sq->tx_max_header_size)) { + ena_trc_err("header size is too large %d max header: %d\n", + header_len, io_sq->tx_max_header_size); + return ENA_COM_INVAL; + } + + /* start with pushing the header (if needed) */ + rc = ena_com_write_header(io_sq, push_header, header_len); + if (unlikely(rc)) + return rc; + + have_meta = ena_tx_ctx->meta_valid && ena_com_meta_desc_changed(io_sq, + ena_tx_ctx); + if (have_meta) + ena_com_create_and_store_tx_meta_desc(io_sq, ena_tx_ctx); + + /* If the caller doesn't want send packets */ + if (unlikely(!num_bufs && !header_len)) { + *nb_hw_desc = have_meta ? 0 : 1; + return 0; + } + + desc = get_sq_desc(io_sq); + memset(desc, 0x0, sizeof(struct ena_eth_io_tx_desc)); + + /* Set first desc when we don't have meta descriptor */ + if (!have_meta) + desc->len_ctrl |= ENA_ETH_IO_TX_DESC_FIRST_MASK; + + desc->buff_addr_hi_hdr_sz |= (header_len << + ENA_ETH_IO_TX_DESC_HEADER_LENGTH_SHIFT) & + ENA_ETH_IO_TX_DESC_HEADER_LENGTH_MASK; + desc->len_ctrl |= (io_sq->phase << ENA_ETH_IO_TX_DESC_PHASE_SHIFT) & + ENA_ETH_IO_TX_DESC_PHASE_MASK; + + desc->len_ctrl |= ENA_ETH_IO_TX_DESC_COMP_REQ_MASK; + + /* Bits 0-9 */ + desc->meta_ctrl |= (ena_tx_ctx->req_id << + ENA_ETH_IO_TX_DESC_REQ_ID_LO_SHIFT) & + ENA_ETH_IO_TX_DESC_REQ_ID_LO_MASK; + + desc->meta_ctrl |= (ena_tx_ctx->df << + ENA_ETH_IO_TX_DESC_DF_SHIFT) & + ENA_ETH_IO_TX_DESC_DF_MASK; + + /* Bits 10-15 */ + desc->len_ctrl |= ((ena_tx_ctx->req_id >> 10) << + ENA_ETH_IO_TX_DESC_REQ_ID_HI_SHIFT) & + ENA_ETH_IO_TX_DESC_REQ_ID_HI_MASK; + + if (ena_tx_ctx->meta_valid) { + desc->meta_ctrl |= (ena_tx_ctx->tso_enable << + ENA_ETH_IO_TX_DESC_TSO_EN_SHIFT) & + ENA_ETH_IO_TX_DESC_TSO_EN_MASK; + desc->meta_ctrl |= ena_tx_ctx->l3_proto & + ENA_ETH_IO_TX_DESC_L3_PROTO_IDX_MASK; + desc->meta_ctrl |= (ena_tx_ctx->l4_proto << + ENA_ETH_IO_TX_DESC_L4_PROTO_IDX_SHIFT) & + ENA_ETH_IO_TX_DESC_L4_PROTO_IDX_MASK; + desc->meta_ctrl |= (ena_tx_ctx->l3_csum_enable << + ENA_ETH_IO_TX_DESC_L3_CSUM_EN_SHIFT) & + ENA_ETH_IO_TX_DESC_L3_CSUM_EN_MASK; + desc->meta_ctrl |= (ena_tx_ctx->l4_csum_enable << + ENA_ETH_IO_TX_DESC_L4_CSUM_EN_SHIFT) & + ENA_ETH_IO_TX_DESC_L4_CSUM_EN_MASK; + desc->meta_ctrl |= (ena_tx_ctx->l4_csum_partial << + ENA_ETH_IO_TX_DESC_L4_CSUM_PARTIAL_SHIFT) & + ENA_ETH_IO_TX_DESC_L4_CSUM_PARTIAL_MASK; + } + + for (i = 0; i < num_bufs; i++) { + /* The first desc share the same desc as the header */ + if (likely(i != 0)) { + ena_com_copy_curr_sq_desc_to_dev(io_sq); + ena_com_sq_update_tail(io_sq); + + desc = get_sq_desc(io_sq); + memset(desc, 0x0, sizeof(struct ena_eth_io_tx_desc)); + + desc->len_ctrl |= (io_sq->phase << + ENA_ETH_IO_TX_DESC_PHASE_SHIFT) & + ENA_ETH_IO_TX_DESC_PHASE_MASK; + } + + desc->len_ctrl |= ena_bufs->len & + ENA_ETH_IO_TX_DESC_LENGTH_MASK; + + addr_hi = ((ena_bufs->paddr & + GENMASK_ULL(io_sq->dma_addr_bits - 1, 32)) >> 32); + + desc->buff_addr_lo = (u32)ena_bufs->paddr; + desc->buff_addr_hi_hdr_sz |= addr_hi & + ENA_ETH_IO_TX_DESC_ADDR_HI_MASK; + ena_bufs++; + } + + /* set the last desc indicator */ + desc->len_ctrl |= ENA_ETH_IO_TX_DESC_LAST_MASK; + + ena_com_copy_curr_sq_desc_to_dev(io_sq); + + ena_com_sq_update_tail(io_sq); + + total_desc = ENA_MAX16(num_bufs, 1); + total_desc += have_meta ? 1 : 0; + + *nb_hw_desc = total_desc; + return 0; +} + +int ena_com_rx_pkt(struct ena_com_io_cq *io_cq, + struct ena_com_io_sq *io_sq, + struct ena_com_rx_ctx *ena_rx_ctx) +{ + struct ena_com_rx_buf_info *ena_buf = &ena_rx_ctx->ena_bufs[0]; + struct ena_eth_io_rx_cdesc_base *cdesc = NULL; + u16 cdesc_idx = 0; + u16 nb_hw_desc; + u16 i; + + ENA_WARN(io_cq->direction != ENA_COM_IO_QUEUE_DIRECTION_RX, + "wrong Q type"); + + nb_hw_desc = ena_com_cdesc_rx_pkt_get(io_cq, &cdesc_idx); + if (nb_hw_desc == 0) { + ena_rx_ctx->descs = nb_hw_desc; + return 0; + } + + ena_trc_dbg("fetch rx packet: queue %d completed desc: %d\n", + io_cq->qid, nb_hw_desc); + + if (unlikely(nb_hw_desc > ena_rx_ctx->max_bufs)) { + ena_trc_err("Too many RX cdescs (%d) > MAX(%d)\n", + nb_hw_desc, ena_rx_ctx->max_bufs); + return ENA_COM_NO_SPACE; + } + + for (i = 0; i < nb_hw_desc; i++) { + cdesc = ena_com_rx_cdesc_idx_to_ptr(io_cq, cdesc_idx + i); + + ena_buf->len = cdesc->length; + ena_buf->req_id = cdesc->req_id; + ena_buf++; + } + + /* Update SQ head ptr */ + io_sq->next_to_comp += nb_hw_desc; + + ena_trc_dbg("[%s][QID#%d] Updating SQ head to: %d\n", __func__, + io_sq->qid, io_sq->next_to_comp); + + /* Get rx flags from the last pkt */ + ena_com_rx_set_flags(ena_rx_ctx, cdesc); + + ena_rx_ctx->descs = nb_hw_desc; + return 0; +} + +int ena_com_add_single_rx_desc(struct ena_com_io_sq *io_sq, + struct ena_com_buf *ena_buf, + u16 req_id) +{ + struct ena_eth_io_rx_desc *desc; + + ENA_WARN(io_sq->direction != ENA_COM_IO_QUEUE_DIRECTION_RX, + "wrong Q type"); + + if (unlikely(ena_com_sq_empty_space(io_sq) == 0)) + return ENA_COM_NO_SPACE; + + desc = get_sq_desc(io_sq); + memset(desc, 0x0, sizeof(struct ena_eth_io_rx_desc)); + + desc->length = ena_buf->len; + + desc->ctrl |= ENA_ETH_IO_RX_DESC_FIRST_MASK; + desc->ctrl |= ENA_ETH_IO_RX_DESC_LAST_MASK; + desc->ctrl |= io_sq->phase & ENA_ETH_IO_RX_DESC_PHASE_MASK; + desc->ctrl |= ENA_ETH_IO_RX_DESC_COMP_REQ_MASK; + + desc->req_id = req_id; + + desc->buff_addr_lo = (u32)ena_buf->paddr; + desc->buff_addr_hi = + ((ena_buf->paddr & GENMASK_ULL(io_sq->dma_addr_bits - 1, 32)) >> 32); + + ena_com_sq_update_tail(io_sq); + + return 0; +} + +int ena_com_tx_comp_req_id_get(struct ena_com_io_cq *io_cq, u16 *req_id) +{ + u8 expected_phase, cdesc_phase; + struct ena_eth_io_tx_cdesc *cdesc; + u16 masked_head; + + masked_head = io_cq->head & (io_cq->q_depth - 1); + expected_phase = io_cq->phase; + + cdesc = (struct ena_eth_io_tx_cdesc *) + ((uintptr_t)io_cq->cdesc_addr.virt_addr + + (masked_head * io_cq->cdesc_entry_size_in_bytes)); + + /* When the current completion descriptor phase isn't the same as the + * expected, it mean that the device still didn't update + * this completion. + */ + cdesc_phase = READ_ONCE(cdesc->flags) & ENA_ETH_IO_TX_CDESC_PHASE_MASK; + if (cdesc_phase != expected_phase) + return ENA_COM_TRY_AGAIN; + + ena_com_cq_inc_head(io_cq); + + *req_id = READ_ONCE(cdesc->req_id); + + return 0; +} diff --git a/sys/contrib/ena-com/ena_eth_com.h b/sys/contrib/ena-com/ena_eth_com.h new file mode 100644 index 00000000000..ec32d77ef9d --- /dev/null +++ b/sys/contrib/ena-com/ena_eth_com.h @@ -0,0 +1,167 @@ +/*- + * BSD LICENSE + * + * Copyright (c) 2015-2017 Amazon.com, Inc. or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + */ + +#ifndef ENA_ETH_COM_H_ +#define ENA_ETH_COM_H_ + +#if defined(__cplusplus) +extern "C" { +#endif +#include "ena_com.h" + +/* head update threshold in units of (queue size / ENA_COMP_HEAD_THRESH) */ +#define ENA_COMP_HEAD_THRESH 4 + +struct ena_com_tx_ctx { + struct ena_com_tx_meta ena_meta; + struct ena_com_buf *ena_bufs; + /* For LLQ, header buffer - pushed to the device mem space */ + void *push_header; + + enum ena_eth_io_l3_proto_index l3_proto; + enum ena_eth_io_l4_proto_index l4_proto; + u16 num_bufs; + u16 req_id; + /* For regular queue, indicate the size of the header + * For LLQ, indicate the size of the pushed buffer + */ + u16 header_len; + + u8 meta_valid; + u8 tso_enable; + u8 l3_csum_enable; + u8 l4_csum_enable; + u8 l4_csum_partial; + u8 df; /* Don't fragment */ +}; + +struct ena_com_rx_ctx { + struct ena_com_rx_buf_info *ena_bufs; + enum ena_eth_io_l3_proto_index l3_proto; + enum ena_eth_io_l4_proto_index l4_proto; + bool l3_csum_err; + bool l4_csum_err; + /* fragmented packet */ + bool frag; + u32 hash; + u16 descs; + int max_bufs; +}; + +int ena_com_prepare_tx(struct ena_com_io_sq *io_sq, + struct ena_com_tx_ctx *ena_tx_ctx, + int *nb_hw_desc); + +int ena_com_rx_pkt(struct ena_com_io_cq *io_cq, + struct ena_com_io_sq *io_sq, + struct ena_com_rx_ctx *ena_rx_ctx); + +int ena_com_add_single_rx_desc(struct ena_com_io_sq *io_sq, + struct ena_com_buf *ena_buf, + u16 req_id); + +int ena_com_tx_comp_req_id_get(struct ena_com_io_cq *io_cq, u16 *req_id); + +static inline void ena_com_unmask_intr(struct ena_com_io_cq *io_cq, + struct ena_eth_io_intr_reg *intr_reg) +{ + ENA_REG_WRITE32(io_cq->bus, intr_reg->intr_control, io_cq->unmask_reg); +} + +static inline int ena_com_sq_empty_space(struct ena_com_io_sq *io_sq) +{ + u16 tail, next_to_comp, cnt; + + next_to_comp = io_sq->next_to_comp; + tail = io_sq->tail; + cnt = tail - next_to_comp; + + return io_sq->q_depth - 1 - cnt; +} + +static inline int ena_com_write_sq_doorbell(struct ena_com_io_sq *io_sq) +{ + u16 tail; + + tail = io_sq->tail; + + ena_trc_dbg("write submission queue doorbell for queue: %d tail: %d\n", + io_sq->qid, tail); + + ENA_REG_WRITE32(io_sq->bus, tail, io_sq->db_addr); + + return 0; +} + +static inline int ena_com_update_dev_comp_head(struct ena_com_io_cq *io_cq) +{ + u16 unreported_comp, head; + bool need_update; + + head = io_cq->head; + unreported_comp = head - io_cq->last_head_update; + need_update = unreported_comp > (io_cq->q_depth / ENA_COMP_HEAD_THRESH); + + if (io_cq->cq_head_db_reg && need_update) { + ena_trc_dbg("Write completion queue doorbell for queue %d: head: %d\n", + io_cq->qid, head); + ENA_REG_WRITE32(io_cq->bus, head, io_cq->cq_head_db_reg); + io_cq->last_head_update = head; + } + + return 0; +} + +static inline void ena_com_update_numa_node(struct ena_com_io_cq *io_cq, + u8 numa_node) +{ + struct ena_eth_io_numa_node_cfg_reg numa_cfg; + + if (!io_cq->numa_node_cfg_reg) + return; + + numa_cfg.numa_cfg = (numa_node & ENA_ETH_IO_NUMA_NODE_CFG_REG_NUMA_MASK) + | ENA_ETH_IO_NUMA_NODE_CFG_REG_ENABLED_MASK; + + ENA_REG_WRITE32(io_cq->bus, numa_cfg.numa_cfg, io_cq->numa_node_cfg_reg); +} + +static inline void ena_com_comp_ack(struct ena_com_io_sq *io_sq, u16 elem) +{ + io_sq->next_to_comp += elem; +} + +#if defined(__cplusplus) +} +#endif +#endif /* ENA_ETH_COM_H_ */ diff --git a/sys/contrib/ena-com/ena_eth_io_defs.h b/sys/contrib/ena-com/ena_eth_io_defs.h new file mode 100644 index 00000000000..c16fed8e2de --- /dev/null +++ b/sys/contrib/ena-com/ena_eth_io_defs.h @@ -0,0 +1,960 @@ +/*- + * BSD LICENSE + * + * Copyright (c) 2015-2017 Amazon.com, Inc. or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + */ + +#ifndef _ENA_ETH_IO_H_ +#define _ENA_ETH_IO_H_ + +enum ena_eth_io_l3_proto_index { + ENA_ETH_IO_L3_PROTO_UNKNOWN = 0, + + ENA_ETH_IO_L3_PROTO_IPV4 = 8, + + ENA_ETH_IO_L3_PROTO_IPV6 = 11, + + ENA_ETH_IO_L3_PROTO_FCOE = 21, + + ENA_ETH_IO_L3_PROTO_ROCE = 22, +}; + +enum ena_eth_io_l4_proto_index { + ENA_ETH_IO_L4_PROTO_UNKNOWN = 0, + + ENA_ETH_IO_L4_PROTO_TCP = 12, + + ENA_ETH_IO_L4_PROTO_UDP = 13, + + ENA_ETH_IO_L4_PROTO_ROUTEABLE_ROCE = 23, +}; + +struct ena_eth_io_tx_desc { + /* 15:0 : length - Buffer length in bytes, must + * include any packet trailers that the ENA supposed + * to update like End-to-End CRC, Authentication GMAC + * etc. This length must not include the + * 'Push_Buffer' length. This length must not include + * the 4-byte added in the end for 802.3 Ethernet FCS + * 21:16 : req_id_hi - Request ID[15:10] + * 22 : reserved22 - MBZ + * 23 : meta_desc - MBZ + * 24 : phase + * 25 : reserved1 - MBZ + * 26 : first - Indicates first descriptor in + * transaction + * 27 : last - Indicates last descriptor in + * transaction + * 28 : comp_req - Indicates whether completion + * should be posted, after packet is transmitted. + * Valid only for first descriptor + * 30:29 : reserved29 - MBZ + * 31 : reserved31 - MBZ + */ + uint32_t len_ctrl; + + /* 3:0 : l3_proto_idx - L3 protocol. This field + * required when l3_csum_en,l3_csum or tso_en are set. + * 4 : DF - IPv4 DF, must be 0 if packet is IPv4 and + * DF flags of the IPv4 header is 0. Otherwise must + * be set to 1 + * 6:5 : reserved5 + * 7 : tso_en - Enable TSO, For TCP only. + * 12:8 : l4_proto_idx - L4 protocol. This field need + * to be set when l4_csum_en or tso_en are set. + * 13 : l3_csum_en - enable IPv4 header checksum. + * 14 : l4_csum_en - enable TCP/UDP checksum. + * 15 : ethernet_fcs_dis - when set, the controller + * will not append the 802.3 Ethernet Frame Check + * Sequence to the packet + * 16 : reserved16 + * 17 : l4_csum_partial - L4 partial checksum. when + * set to 0, the ENA calculates the L4 checksum, + * where the Destination Address required for the + * TCP/UDP pseudo-header is taken from the actual + * packet L3 header. when set to 1, the ENA doesn't + * calculate the sum of the pseudo-header, instead, + * the checksum field of the L4 is used instead. When + * TSO enabled, the checksum of the pseudo-header + * must not include the tcp length field. L4 partial + * checksum should be used for IPv6 packet that + * contains Routing Headers. + * 20:18 : reserved18 - MBZ + * 21 : reserved21 - MBZ + * 31:22 : req_id_lo - Request ID[9:0] + */ + uint32_t meta_ctrl; + + uint32_t buff_addr_lo; + + /* address high and header size + * 15:0 : addr_hi - Buffer Pointer[47:32] + * 23:16 : reserved16_w2 + * 31:24 : header_length - Header length. For Low + * Latency Queues, this fields indicates the number + * of bytes written to the headers' memory. For + * normal queues, if packet is TCP or UDP, and longer + * than max_header_size, then this field should be + * set to the sum of L4 header offset and L4 header + * size(without options), otherwise, this field + * should be set to 0. For both modes, this field + * must not exceed the max_header_size. + * max_header_size value is reported by the Max + * Queues Feature descriptor + */ + uint32_t buff_addr_hi_hdr_sz; +}; + +struct ena_eth_io_tx_meta_desc { + /* 9:0 : req_id_lo - Request ID[9:0] + * 11:10 : reserved10 - MBZ + * 12 : reserved12 - MBZ + * 13 : reserved13 - MBZ + * 14 : ext_valid - if set, offset fields in Word2 + * are valid Also MSS High in Word 0 and bits [31:24] + * in Word 3 + * 15 : reserved15 + * 19:16 : mss_hi + * 20 : eth_meta_type - 0: Tx Metadata Descriptor, 1: + * Extended Metadata Descriptor + * 21 : meta_store - Store extended metadata in queue + * cache + * 22 : reserved22 - MBZ + * 23 : meta_desc - MBO + * 24 : phase + * 25 : reserved25 - MBZ + * 26 : first - Indicates first descriptor in + * transaction + * 27 : last - Indicates last descriptor in + * transaction + * 28 : comp_req - Indicates whether completion + * should be posted, after packet is transmitted. + * Valid only for first descriptor + * 30:29 : reserved29 - MBZ + * 31 : reserved31 - MBZ + */ + uint32_t len_ctrl; + + /* 5:0 : req_id_hi + * 31:6 : reserved6 - MBZ + */ + uint32_t word1; + + /* 7:0 : l3_hdr_len + * 15:8 : l3_hdr_off + * 21:16 : l4_hdr_len_in_words - counts the L4 header + * length in words. there is an explicit assumption + * that L4 header appears right after L3 header and + * L4 offset is based on l3_hdr_off+l3_hdr_len + * 31:22 : mss_lo + */ + uint32_t word2; + + uint32_t reserved; +}; + +struct ena_eth_io_tx_cdesc { + /* Request ID[15:0] */ + uint16_t req_id; + + uint8_t status; + + /* flags + * 0 : phase + * 7:1 : reserved1 + */ + uint8_t flags; + + uint16_t sub_qid; + + uint16_t sq_head_idx; +}; + +struct ena_eth_io_rx_desc { + /* In bytes. 0 means 64KB */ + uint16_t length; + + /* MBZ */ + uint8_t reserved2; + + /* 0 : phase + * 1 : reserved1 - MBZ + * 2 : first - Indicates first descriptor in + * transaction + * 3 : last - Indicates last descriptor in transaction + * 4 : comp_req + * 5 : reserved5 - MBO + * 7:6 : reserved6 - MBZ + */ + uint8_t ctrl; + + uint16_t req_id; + + /* MBZ */ + uint16_t reserved6; + + uint32_t buff_addr_lo; + + uint16_t buff_addr_hi; + + /* MBZ */ + uint16_t reserved16_w3; +}; + +/* 4-word format Note: all ethernet parsing information are valid only when + * last=1 + */ +struct ena_eth_io_rx_cdesc_base { + /* 4:0 : l3_proto_idx + * 6:5 : src_vlan_cnt + * 7 : reserved7 - MBZ + * 12:8 : l4_proto_idx + * 13 : l3_csum_err - when set, either the L3 + * checksum error detected, or, the controller didn't + * validate the checksum. This bit is valid only when + * l3_proto_idx indicates IPv4 packet + * 14 : l4_csum_err - when set, either the L4 + * checksum error detected, or, the controller didn't + * validate the checksum. This bit is valid only when + * l4_proto_idx indicates TCP/UDP packet, and, + * ipv4_frag is not set + * 15 : ipv4_frag - Indicates IPv4 fragmented packet + * 23:16 : reserved16 + * 24 : phase + * 25 : l3_csum2 - second checksum engine result + * 26 : first - Indicates first descriptor in + * transaction + * 27 : last - Indicates last descriptor in + * transaction + * 29:28 : reserved28 + * 30 : buffer - 0: Metadata descriptor. 1: Buffer + * Descriptor was used + * 31 : reserved31 + */ + uint32_t status; + + uint16_t length; + + uint16_t req_id; + + /* 32-bit hash result */ + uint32_t hash; + + uint16_t sub_qid; + + uint16_t reserved; +}; + +/* 8-word format */ +struct ena_eth_io_rx_cdesc_ext { + struct ena_eth_io_rx_cdesc_base base; + + uint32_t buff_addr_lo; + + uint16_t buff_addr_hi; + + uint16_t reserved16; + + uint32_t reserved_w6; + + uint32_t reserved_w7; +}; + +struct ena_eth_io_intr_reg { + /* 14:0 : rx_intr_delay + * 29:15 : tx_intr_delay + * 30 : intr_unmask + * 31 : reserved + */ + uint32_t intr_control; +}; + +struct ena_eth_io_numa_node_cfg_reg { + /* 7:0 : numa + * 30:8 : reserved + * 31 : enabled + */ + uint32_t numa_cfg; +}; + +/* tx_desc */ +#define ENA_ETH_IO_TX_DESC_LENGTH_MASK GENMASK(15, 0) +#define ENA_ETH_IO_TX_DESC_REQ_ID_HI_SHIFT 16 +#define ENA_ETH_IO_TX_DESC_REQ_ID_HI_MASK GENMASK(21, 16) +#define ENA_ETH_IO_TX_DESC_META_DESC_SHIFT 23 +#define ENA_ETH_IO_TX_DESC_META_DESC_MASK BIT(23) +#define ENA_ETH_IO_TX_DESC_PHASE_SHIFT 24 +#define ENA_ETH_IO_TX_DESC_PHASE_MASK BIT(24) +#define ENA_ETH_IO_TX_DESC_FIRST_SHIFT 26 +#define ENA_ETH_IO_TX_DESC_FIRST_MASK BIT(26) +#define ENA_ETH_IO_TX_DESC_LAST_SHIFT 27 +#define ENA_ETH_IO_TX_DESC_LAST_MASK BIT(27) +#define ENA_ETH_IO_TX_DESC_COMP_REQ_SHIFT 28 +#define ENA_ETH_IO_TX_DESC_COMP_REQ_MASK BIT(28) +#define ENA_ETH_IO_TX_DESC_L3_PROTO_IDX_MASK GENMASK(3, 0) +#define ENA_ETH_IO_TX_DESC_DF_SHIFT 4 +#define ENA_ETH_IO_TX_DESC_DF_MASK BIT(4) +#define ENA_ETH_IO_TX_DESC_TSO_EN_SHIFT 7 +#define ENA_ETH_IO_TX_DESC_TSO_EN_MASK BIT(7) +#define ENA_ETH_IO_TX_DESC_L4_PROTO_IDX_SHIFT 8 +#define ENA_ETH_IO_TX_DESC_L4_PROTO_IDX_MASK GENMASK(12, 8) +#define ENA_ETH_IO_TX_DESC_L3_CSUM_EN_SHIFT 13 +#define ENA_ETH_IO_TX_DESC_L3_CSUM_EN_MASK BIT(13) +#define ENA_ETH_IO_TX_DESC_L4_CSUM_EN_SHIFT 14 +#define ENA_ETH_IO_TX_DESC_L4_CSUM_EN_MASK BIT(14) +#define ENA_ETH_IO_TX_DESC_ETHERNET_FCS_DIS_SHIFT 15 +#define ENA_ETH_IO_TX_DESC_ETHERNET_FCS_DIS_MASK BIT(15) +#define ENA_ETH_IO_TX_DESC_L4_CSUM_PARTIAL_SHIFT 17 +#define ENA_ETH_IO_TX_DESC_L4_CSUM_PARTIAL_MASK BIT(17) +#define ENA_ETH_IO_TX_DESC_REQ_ID_LO_SHIFT 22 +#define ENA_ETH_IO_TX_DESC_REQ_ID_LO_MASK GENMASK(31, 22) +#define ENA_ETH_IO_TX_DESC_ADDR_HI_MASK GENMASK(15, 0) +#define ENA_ETH_IO_TX_DESC_HEADER_LENGTH_SHIFT 24 +#define ENA_ETH_IO_TX_DESC_HEADER_LENGTH_MASK GENMASK(31, 24) + +/* tx_meta_desc */ +#define ENA_ETH_IO_TX_META_DESC_REQ_ID_LO_MASK GENMASK(9, 0) +#define ENA_ETH_IO_TX_META_DESC_EXT_VALID_SHIFT 14 +#define ENA_ETH_IO_TX_META_DESC_EXT_VALID_MASK BIT(14) +#define ENA_ETH_IO_TX_META_DESC_MSS_HI_SHIFT 16 +#define ENA_ETH_IO_TX_META_DESC_MSS_HI_MASK GENMASK(19, 16) +#define ENA_ETH_IO_TX_META_DESC_ETH_META_TYPE_SHIFT 20 +#define ENA_ETH_IO_TX_META_DESC_ETH_META_TYPE_MASK BIT(20) +#define ENA_ETH_IO_TX_META_DESC_META_STORE_SHIFT 21 +#define ENA_ETH_IO_TX_META_DESC_META_STORE_MASK BIT(21) +#define ENA_ETH_IO_TX_META_DESC_META_DESC_SHIFT 23 +#define ENA_ETH_IO_TX_META_DESC_META_DESC_MASK BIT(23) +#define ENA_ETH_IO_TX_META_DESC_PHASE_SHIFT 24 +#define ENA_ETH_IO_TX_META_DESC_PHASE_MASK BIT(24) +#define ENA_ETH_IO_TX_META_DESC_FIRST_SHIFT 26 +#define ENA_ETH_IO_TX_META_DESC_FIRST_MASK BIT(26) +#define ENA_ETH_IO_TX_META_DESC_LAST_SHIFT 27 +#define ENA_ETH_IO_TX_META_DESC_LAST_MASK BIT(27) +#define ENA_ETH_IO_TX_META_DESC_COMP_REQ_SHIFT 28 +#define ENA_ETH_IO_TX_META_DESC_COMP_REQ_MASK BIT(28) +#define ENA_ETH_IO_TX_META_DESC_REQ_ID_HI_MASK GENMASK(5, 0) +#define ENA_ETH_IO_TX_META_DESC_L3_HDR_LEN_MASK GENMASK(7, 0) +#define ENA_ETH_IO_TX_META_DESC_L3_HDR_OFF_SHIFT 8 +#define ENA_ETH_IO_TX_META_DESC_L3_HDR_OFF_MASK GENMASK(15, 8) +#define ENA_ETH_IO_TX_META_DESC_L4_HDR_LEN_IN_WORDS_SHIFT 16 +#define ENA_ETH_IO_TX_META_DESC_L4_HDR_LEN_IN_WORDS_MASK GENMASK(21, 16) +#define ENA_ETH_IO_TX_META_DESC_MSS_LO_SHIFT 22 +#define ENA_ETH_IO_TX_META_DESC_MSS_LO_MASK GENMASK(31, 22) + +/* tx_cdesc */ +#define ENA_ETH_IO_TX_CDESC_PHASE_MASK BIT(0) + +/* rx_desc */ +#define ENA_ETH_IO_RX_DESC_PHASE_MASK BIT(0) +#define ENA_ETH_IO_RX_DESC_FIRST_SHIFT 2 +#define ENA_ETH_IO_RX_DESC_FIRST_MASK BIT(2) +#define ENA_ETH_IO_RX_DESC_LAST_SHIFT 3 +#define ENA_ETH_IO_RX_DESC_LAST_MASK BIT(3) +#define ENA_ETH_IO_RX_DESC_COMP_REQ_SHIFT 4 +#define ENA_ETH_IO_RX_DESC_COMP_REQ_MASK BIT(4) + +/* rx_cdesc_base */ +#define ENA_ETH_IO_RX_CDESC_BASE_L3_PROTO_IDX_MASK GENMASK(4, 0) +#define ENA_ETH_IO_RX_CDESC_BASE_SRC_VLAN_CNT_SHIFT 5 +#define ENA_ETH_IO_RX_CDESC_BASE_SRC_VLAN_CNT_MASK GENMASK(6, 5) +#define ENA_ETH_IO_RX_CDESC_BASE_L4_PROTO_IDX_SHIFT 8 +#define ENA_ETH_IO_RX_CDESC_BASE_L4_PROTO_IDX_MASK GENMASK(12, 8) +#define ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM_ERR_SHIFT 13 +#define ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM_ERR_MASK BIT(13) +#define ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_SHIFT 14 +#define ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_MASK BIT(14) +#define ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_SHIFT 15 +#define ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_MASK BIT(15) +#define ENA_ETH_IO_RX_CDESC_BASE_PHASE_SHIFT 24 +#define ENA_ETH_IO_RX_CDESC_BASE_PHASE_MASK BIT(24) +#define ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM2_SHIFT 25 +#define ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM2_MASK BIT(25) +#define ENA_ETH_IO_RX_CDESC_BASE_FIRST_SHIFT 26 +#define ENA_ETH_IO_RX_CDESC_BASE_FIRST_MASK BIT(26) +#define ENA_ETH_IO_RX_CDESC_BASE_LAST_SHIFT 27 +#define ENA_ETH_IO_RX_CDESC_BASE_LAST_MASK BIT(27) +#define ENA_ETH_IO_RX_CDESC_BASE_BUFFER_SHIFT 30 +#define ENA_ETH_IO_RX_CDESC_BASE_BUFFER_MASK BIT(30) + +/* intr_reg */ +#define ENA_ETH_IO_INTR_REG_RX_INTR_DELAY_MASK GENMASK(14, 0) +#define ENA_ETH_IO_INTR_REG_TX_INTR_DELAY_SHIFT 15 +#define ENA_ETH_IO_INTR_REG_TX_INTR_DELAY_MASK GENMASK(29, 15) +#define ENA_ETH_IO_INTR_REG_INTR_UNMASK_SHIFT 30 +#define ENA_ETH_IO_INTR_REG_INTR_UNMASK_MASK BIT(30) + +/* numa_node_cfg_reg */ +#define ENA_ETH_IO_NUMA_NODE_CFG_REG_NUMA_MASK GENMASK(7, 0) +#define ENA_ETH_IO_NUMA_NODE_CFG_REG_ENABLED_SHIFT 31 +#define ENA_ETH_IO_NUMA_NODE_CFG_REG_ENABLED_MASK BIT(31) + +#if !defined(ENA_DEFS_LINUX_MAINLINE) +static inline uint32_t get_ena_eth_io_tx_desc_length(const struct ena_eth_io_tx_desc *p) +{ + return p->len_ctrl & ENA_ETH_IO_TX_DESC_LENGTH_MASK; +} + +static inline void set_ena_eth_io_tx_desc_length(struct ena_eth_io_tx_desc *p, uint32_t val) +{ + p->len_ctrl |= val & ENA_ETH_IO_TX_DESC_LENGTH_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_desc_req_id_hi(const struct ena_eth_io_tx_desc *p) +{ + return (p->len_ctrl & ENA_ETH_IO_TX_DESC_REQ_ID_HI_MASK) >> ENA_ETH_IO_TX_DESC_REQ_ID_HI_SHIFT; +} + +static inline void set_ena_eth_io_tx_desc_req_id_hi(struct ena_eth_io_tx_desc *p, uint32_t val) +{ + p->len_ctrl |= (val << ENA_ETH_IO_TX_DESC_REQ_ID_HI_SHIFT) & ENA_ETH_IO_TX_DESC_REQ_ID_HI_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_desc_meta_desc(const struct ena_eth_io_tx_desc *p) +{ + return (p->len_ctrl & ENA_ETH_IO_TX_DESC_META_DESC_MASK) >> ENA_ETH_IO_TX_DESC_META_DESC_SHIFT; +} + +static inline void set_ena_eth_io_tx_desc_meta_desc(struct ena_eth_io_tx_desc *p, uint32_t val) +{ + p->len_ctrl |= (val << ENA_ETH_IO_TX_DESC_META_DESC_SHIFT) & ENA_ETH_IO_TX_DESC_META_DESC_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_desc_phase(const struct ena_eth_io_tx_desc *p) +{ + return (p->len_ctrl & ENA_ETH_IO_TX_DESC_PHASE_MASK) >> ENA_ETH_IO_TX_DESC_PHASE_SHIFT; +} + +static inline void set_ena_eth_io_tx_desc_phase(struct ena_eth_io_tx_desc *p, uint32_t val) +{ + p->len_ctrl |= (val << ENA_ETH_IO_TX_DESC_PHASE_SHIFT) & ENA_ETH_IO_TX_DESC_PHASE_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_desc_first(const struct ena_eth_io_tx_desc *p) +{ + return (p->len_ctrl & ENA_ETH_IO_TX_DESC_FIRST_MASK) >> ENA_ETH_IO_TX_DESC_FIRST_SHIFT; +} + +static inline void set_ena_eth_io_tx_desc_first(struct ena_eth_io_tx_desc *p, uint32_t val) +{ + p->len_ctrl |= (val << ENA_ETH_IO_TX_DESC_FIRST_SHIFT) & ENA_ETH_IO_TX_DESC_FIRST_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_desc_last(const struct ena_eth_io_tx_desc *p) +{ + return (p->len_ctrl & ENA_ETH_IO_TX_DESC_LAST_MASK) >> ENA_ETH_IO_TX_DESC_LAST_SHIFT; +} + +static inline void set_ena_eth_io_tx_desc_last(struct ena_eth_io_tx_desc *p, uint32_t val) +{ + p->len_ctrl |= (val << ENA_ETH_IO_TX_DESC_LAST_SHIFT) & ENA_ETH_IO_TX_DESC_LAST_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_desc_comp_req(const struct ena_eth_io_tx_desc *p) +{ + return (p->len_ctrl & ENA_ETH_IO_TX_DESC_COMP_REQ_MASK) >> ENA_ETH_IO_TX_DESC_COMP_REQ_SHIFT; +} + +static inline void set_ena_eth_io_tx_desc_comp_req(struct ena_eth_io_tx_desc *p, uint32_t val) +{ + p->len_ctrl |= (val << ENA_ETH_IO_TX_DESC_COMP_REQ_SHIFT) & ENA_ETH_IO_TX_DESC_COMP_REQ_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_desc_l3_proto_idx(const struct ena_eth_io_tx_desc *p) +{ + return p->meta_ctrl & ENA_ETH_IO_TX_DESC_L3_PROTO_IDX_MASK; +} + +static inline void set_ena_eth_io_tx_desc_l3_proto_idx(struct ena_eth_io_tx_desc *p, uint32_t val) +{ + p->meta_ctrl |= val & ENA_ETH_IO_TX_DESC_L3_PROTO_IDX_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_desc_DF(const struct ena_eth_io_tx_desc *p) +{ + return (p->meta_ctrl & ENA_ETH_IO_TX_DESC_DF_MASK) >> ENA_ETH_IO_TX_DESC_DF_SHIFT; +} + +static inline void set_ena_eth_io_tx_desc_DF(struct ena_eth_io_tx_desc *p, uint32_t val) +{ + p->meta_ctrl |= (val << ENA_ETH_IO_TX_DESC_DF_SHIFT) & ENA_ETH_IO_TX_DESC_DF_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_desc_tso_en(const struct ena_eth_io_tx_desc *p) +{ + return (p->meta_ctrl & ENA_ETH_IO_TX_DESC_TSO_EN_MASK) >> ENA_ETH_IO_TX_DESC_TSO_EN_SHIFT; +} + +static inline void set_ena_eth_io_tx_desc_tso_en(struct ena_eth_io_tx_desc *p, uint32_t val) +{ + p->meta_ctrl |= (val << ENA_ETH_IO_TX_DESC_TSO_EN_SHIFT) & ENA_ETH_IO_TX_DESC_TSO_EN_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_desc_l4_proto_idx(const struct ena_eth_io_tx_desc *p) +{ + return (p->meta_ctrl & ENA_ETH_IO_TX_DESC_L4_PROTO_IDX_MASK) >> ENA_ETH_IO_TX_DESC_L4_PROTO_IDX_SHIFT; +} + +static inline void set_ena_eth_io_tx_desc_l4_proto_idx(struct ena_eth_io_tx_desc *p, uint32_t val) +{ + p->meta_ctrl |= (val << ENA_ETH_IO_TX_DESC_L4_PROTO_IDX_SHIFT) & ENA_ETH_IO_TX_DESC_L4_PROTO_IDX_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_desc_l3_csum_en(const struct ena_eth_io_tx_desc *p) +{ + return (p->meta_ctrl & ENA_ETH_IO_TX_DESC_L3_CSUM_EN_MASK) >> ENA_ETH_IO_TX_DESC_L3_CSUM_EN_SHIFT; +} + +static inline void set_ena_eth_io_tx_desc_l3_csum_en(struct ena_eth_io_tx_desc *p, uint32_t val) +{ + p->meta_ctrl |= (val << ENA_ETH_IO_TX_DESC_L3_CSUM_EN_SHIFT) & ENA_ETH_IO_TX_DESC_L3_CSUM_EN_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_desc_l4_csum_en(const struct ena_eth_io_tx_desc *p) +{ + return (p->meta_ctrl & ENA_ETH_IO_TX_DESC_L4_CSUM_EN_MASK) >> ENA_ETH_IO_TX_DESC_L4_CSUM_EN_SHIFT; +} + +static inline void set_ena_eth_io_tx_desc_l4_csum_en(struct ena_eth_io_tx_desc *p, uint32_t val) +{ + p->meta_ctrl |= (val << ENA_ETH_IO_TX_DESC_L4_CSUM_EN_SHIFT) & ENA_ETH_IO_TX_DESC_L4_CSUM_EN_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_desc_ethernet_fcs_dis(const struct ena_eth_io_tx_desc *p) +{ + return (p->meta_ctrl & ENA_ETH_IO_TX_DESC_ETHERNET_FCS_DIS_MASK) >> ENA_ETH_IO_TX_DESC_ETHERNET_FCS_DIS_SHIFT; +} + +static inline void set_ena_eth_io_tx_desc_ethernet_fcs_dis(struct ena_eth_io_tx_desc *p, uint32_t val) +{ + p->meta_ctrl |= (val << ENA_ETH_IO_TX_DESC_ETHERNET_FCS_DIS_SHIFT) & ENA_ETH_IO_TX_DESC_ETHERNET_FCS_DIS_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_desc_l4_csum_partial(const struct ena_eth_io_tx_desc *p) +{ + return (p->meta_ctrl & ENA_ETH_IO_TX_DESC_L4_CSUM_PARTIAL_MASK) >> ENA_ETH_IO_TX_DESC_L4_CSUM_PARTIAL_SHIFT; +} + +static inline void set_ena_eth_io_tx_desc_l4_csum_partial(struct ena_eth_io_tx_desc *p, uint32_t val) +{ + p->meta_ctrl |= (val << ENA_ETH_IO_TX_DESC_L4_CSUM_PARTIAL_SHIFT) & ENA_ETH_IO_TX_DESC_L4_CSUM_PARTIAL_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_desc_req_id_lo(const struct ena_eth_io_tx_desc *p) +{ + return (p->meta_ctrl & ENA_ETH_IO_TX_DESC_REQ_ID_LO_MASK) >> ENA_ETH_IO_TX_DESC_REQ_ID_LO_SHIFT; +} + +static inline void set_ena_eth_io_tx_desc_req_id_lo(struct ena_eth_io_tx_desc *p, uint32_t val) +{ + p->meta_ctrl |= (val << ENA_ETH_IO_TX_DESC_REQ_ID_LO_SHIFT) & ENA_ETH_IO_TX_DESC_REQ_ID_LO_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_desc_addr_hi(const struct ena_eth_io_tx_desc *p) +{ + return p->buff_addr_hi_hdr_sz & ENA_ETH_IO_TX_DESC_ADDR_HI_MASK; +} + +static inline void set_ena_eth_io_tx_desc_addr_hi(struct ena_eth_io_tx_desc *p, uint32_t val) +{ + p->buff_addr_hi_hdr_sz |= val & ENA_ETH_IO_TX_DESC_ADDR_HI_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_desc_header_length(const struct ena_eth_io_tx_desc *p) +{ + return (p->buff_addr_hi_hdr_sz & ENA_ETH_IO_TX_DESC_HEADER_LENGTH_MASK) >> ENA_ETH_IO_TX_DESC_HEADER_LENGTH_SHIFT; +} + +static inline void set_ena_eth_io_tx_desc_header_length(struct ena_eth_io_tx_desc *p, uint32_t val) +{ + p->buff_addr_hi_hdr_sz |= (val << ENA_ETH_IO_TX_DESC_HEADER_LENGTH_SHIFT) & ENA_ETH_IO_TX_DESC_HEADER_LENGTH_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_meta_desc_req_id_lo(const struct ena_eth_io_tx_meta_desc *p) +{ + return p->len_ctrl & ENA_ETH_IO_TX_META_DESC_REQ_ID_LO_MASK; +} + +static inline void set_ena_eth_io_tx_meta_desc_req_id_lo(struct ena_eth_io_tx_meta_desc *p, uint32_t val) +{ + p->len_ctrl |= val & ENA_ETH_IO_TX_META_DESC_REQ_ID_LO_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_meta_desc_ext_valid(const struct ena_eth_io_tx_meta_desc *p) +{ + return (p->len_ctrl & ENA_ETH_IO_TX_META_DESC_EXT_VALID_MASK) >> ENA_ETH_IO_TX_META_DESC_EXT_VALID_SHIFT; +} + +static inline void set_ena_eth_io_tx_meta_desc_ext_valid(struct ena_eth_io_tx_meta_desc *p, uint32_t val) +{ + p->len_ctrl |= (val << ENA_ETH_IO_TX_META_DESC_EXT_VALID_SHIFT) & ENA_ETH_IO_TX_META_DESC_EXT_VALID_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_meta_desc_mss_hi(const struct ena_eth_io_tx_meta_desc *p) +{ + return (p->len_ctrl & ENA_ETH_IO_TX_META_DESC_MSS_HI_MASK) >> ENA_ETH_IO_TX_META_DESC_MSS_HI_SHIFT; +} + +static inline void set_ena_eth_io_tx_meta_desc_mss_hi(struct ena_eth_io_tx_meta_desc *p, uint32_t val) +{ + p->len_ctrl |= (val << ENA_ETH_IO_TX_META_DESC_MSS_HI_SHIFT) & ENA_ETH_IO_TX_META_DESC_MSS_HI_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_meta_desc_eth_meta_type(const struct ena_eth_io_tx_meta_desc *p) +{ + return (p->len_ctrl & ENA_ETH_IO_TX_META_DESC_ETH_META_TYPE_MASK) >> ENA_ETH_IO_TX_META_DESC_ETH_META_TYPE_SHIFT; +} + +static inline void set_ena_eth_io_tx_meta_desc_eth_meta_type(struct ena_eth_io_tx_meta_desc *p, uint32_t val) +{ + p->len_ctrl |= (val << ENA_ETH_IO_TX_META_DESC_ETH_META_TYPE_SHIFT) & ENA_ETH_IO_TX_META_DESC_ETH_META_TYPE_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_meta_desc_meta_store(const struct ena_eth_io_tx_meta_desc *p) +{ + return (p->len_ctrl & ENA_ETH_IO_TX_META_DESC_META_STORE_MASK) >> ENA_ETH_IO_TX_META_DESC_META_STORE_SHIFT; +} + +static inline void set_ena_eth_io_tx_meta_desc_meta_store(struct ena_eth_io_tx_meta_desc *p, uint32_t val) +{ + p->len_ctrl |= (val << ENA_ETH_IO_TX_META_DESC_META_STORE_SHIFT) & ENA_ETH_IO_TX_META_DESC_META_STORE_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_meta_desc_meta_desc(const struct ena_eth_io_tx_meta_desc *p) +{ + return (p->len_ctrl & ENA_ETH_IO_TX_META_DESC_META_DESC_MASK) >> ENA_ETH_IO_TX_META_DESC_META_DESC_SHIFT; +} + +static inline void set_ena_eth_io_tx_meta_desc_meta_desc(struct ena_eth_io_tx_meta_desc *p, uint32_t val) +{ + p->len_ctrl |= (val << ENA_ETH_IO_TX_META_DESC_META_DESC_SHIFT) & ENA_ETH_IO_TX_META_DESC_META_DESC_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_meta_desc_phase(const struct ena_eth_io_tx_meta_desc *p) +{ + return (p->len_ctrl & ENA_ETH_IO_TX_META_DESC_PHASE_MASK) >> ENA_ETH_IO_TX_META_DESC_PHASE_SHIFT; +} + +static inline void set_ena_eth_io_tx_meta_desc_phase(struct ena_eth_io_tx_meta_desc *p, uint32_t val) +{ + p->len_ctrl |= (val << ENA_ETH_IO_TX_META_DESC_PHASE_SHIFT) & ENA_ETH_IO_TX_META_DESC_PHASE_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_meta_desc_first(const struct ena_eth_io_tx_meta_desc *p) +{ + return (p->len_ctrl & ENA_ETH_IO_TX_META_DESC_FIRST_MASK) >> ENA_ETH_IO_TX_META_DESC_FIRST_SHIFT; +} + +static inline void set_ena_eth_io_tx_meta_desc_first(struct ena_eth_io_tx_meta_desc *p, uint32_t val) +{ + p->len_ctrl |= (val << ENA_ETH_IO_TX_META_DESC_FIRST_SHIFT) & ENA_ETH_IO_TX_META_DESC_FIRST_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_meta_desc_last(const struct ena_eth_io_tx_meta_desc *p) +{ + return (p->len_ctrl & ENA_ETH_IO_TX_META_DESC_LAST_MASK) >> ENA_ETH_IO_TX_META_DESC_LAST_SHIFT; +} + +static inline void set_ena_eth_io_tx_meta_desc_last(struct ena_eth_io_tx_meta_desc *p, uint32_t val) +{ + p->len_ctrl |= (val << ENA_ETH_IO_TX_META_DESC_LAST_SHIFT) & ENA_ETH_IO_TX_META_DESC_LAST_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_meta_desc_comp_req(const struct ena_eth_io_tx_meta_desc *p) +{ + return (p->len_ctrl & ENA_ETH_IO_TX_META_DESC_COMP_REQ_MASK) >> ENA_ETH_IO_TX_META_DESC_COMP_REQ_SHIFT; +} + +static inline void set_ena_eth_io_tx_meta_desc_comp_req(struct ena_eth_io_tx_meta_desc *p, uint32_t val) +{ + p->len_ctrl |= (val << ENA_ETH_IO_TX_META_DESC_COMP_REQ_SHIFT) & ENA_ETH_IO_TX_META_DESC_COMP_REQ_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_meta_desc_req_id_hi(const struct ena_eth_io_tx_meta_desc *p) +{ + return p->word1 & ENA_ETH_IO_TX_META_DESC_REQ_ID_HI_MASK; +} + +static inline void set_ena_eth_io_tx_meta_desc_req_id_hi(struct ena_eth_io_tx_meta_desc *p, uint32_t val) +{ + p->word1 |= val & ENA_ETH_IO_TX_META_DESC_REQ_ID_HI_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_meta_desc_l3_hdr_len(const struct ena_eth_io_tx_meta_desc *p) +{ + return p->word2 & ENA_ETH_IO_TX_META_DESC_L3_HDR_LEN_MASK; +} + +static inline void set_ena_eth_io_tx_meta_desc_l3_hdr_len(struct ena_eth_io_tx_meta_desc *p, uint32_t val) +{ + p->word2 |= val & ENA_ETH_IO_TX_META_DESC_L3_HDR_LEN_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_meta_desc_l3_hdr_off(const struct ena_eth_io_tx_meta_desc *p) +{ + return (p->word2 & ENA_ETH_IO_TX_META_DESC_L3_HDR_OFF_MASK) >> ENA_ETH_IO_TX_META_DESC_L3_HDR_OFF_SHIFT; +} + +static inline void set_ena_eth_io_tx_meta_desc_l3_hdr_off(struct ena_eth_io_tx_meta_desc *p, uint32_t val) +{ + p->word2 |= (val << ENA_ETH_IO_TX_META_DESC_L3_HDR_OFF_SHIFT) & ENA_ETH_IO_TX_META_DESC_L3_HDR_OFF_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_meta_desc_l4_hdr_len_in_words(const struct ena_eth_io_tx_meta_desc *p) +{ + return (p->word2 & ENA_ETH_IO_TX_META_DESC_L4_HDR_LEN_IN_WORDS_MASK) >> ENA_ETH_IO_TX_META_DESC_L4_HDR_LEN_IN_WORDS_SHIFT; +} + +static inline void set_ena_eth_io_tx_meta_desc_l4_hdr_len_in_words(struct ena_eth_io_tx_meta_desc *p, uint32_t val) +{ + p->word2 |= (val << ENA_ETH_IO_TX_META_DESC_L4_HDR_LEN_IN_WORDS_SHIFT) & ENA_ETH_IO_TX_META_DESC_L4_HDR_LEN_IN_WORDS_MASK; +} + +static inline uint32_t get_ena_eth_io_tx_meta_desc_mss_lo(const struct ena_eth_io_tx_meta_desc *p) +{ + return (p->word2 & ENA_ETH_IO_TX_META_DESC_MSS_LO_MASK) >> ENA_ETH_IO_TX_META_DESC_MSS_LO_SHIFT; +} + +static inline void set_ena_eth_io_tx_meta_desc_mss_lo(struct ena_eth_io_tx_meta_desc *p, uint32_t val) +{ + p->word2 |= (val << ENA_ETH_IO_TX_META_DESC_MSS_LO_SHIFT) & ENA_ETH_IO_TX_META_DESC_MSS_LO_MASK; +} + +static inline uint8_t get_ena_eth_io_tx_cdesc_phase(const struct ena_eth_io_tx_cdesc *p) +{ + return p->flags & ENA_ETH_IO_TX_CDESC_PHASE_MASK; +} + +static inline void set_ena_eth_io_tx_cdesc_phase(struct ena_eth_io_tx_cdesc *p, uint8_t val) +{ + p->flags |= val & ENA_ETH_IO_TX_CDESC_PHASE_MASK; +} + +static inline uint8_t get_ena_eth_io_rx_desc_phase(const struct ena_eth_io_rx_desc *p) +{ + return p->ctrl & ENA_ETH_IO_RX_DESC_PHASE_MASK; +} + +static inline void set_ena_eth_io_rx_desc_phase(struct ena_eth_io_rx_desc *p, uint8_t val) +{ + p->ctrl |= val & ENA_ETH_IO_RX_DESC_PHASE_MASK; +} + +static inline uint8_t get_ena_eth_io_rx_desc_first(const struct ena_eth_io_rx_desc *p) +{ + return (p->ctrl & ENA_ETH_IO_RX_DESC_FIRST_MASK) >> ENA_ETH_IO_RX_DESC_FIRST_SHIFT; +} + +static inline void set_ena_eth_io_rx_desc_first(struct ena_eth_io_rx_desc *p, uint8_t val) +{ + p->ctrl |= (val << ENA_ETH_IO_RX_DESC_FIRST_SHIFT) & ENA_ETH_IO_RX_DESC_FIRST_MASK; +} + +static inline uint8_t get_ena_eth_io_rx_desc_last(const struct ena_eth_io_rx_desc *p) +{ + return (p->ctrl & ENA_ETH_IO_RX_DESC_LAST_MASK) >> ENA_ETH_IO_RX_DESC_LAST_SHIFT; +} + +static inline void set_ena_eth_io_rx_desc_last(struct ena_eth_io_rx_desc *p, uint8_t val) +{ + p->ctrl |= (val << ENA_ETH_IO_RX_DESC_LAST_SHIFT) & ENA_ETH_IO_RX_DESC_LAST_MASK; +} + +static inline uint8_t get_ena_eth_io_rx_desc_comp_req(const struct ena_eth_io_rx_desc *p) +{ + return (p->ctrl & ENA_ETH_IO_RX_DESC_COMP_REQ_MASK) >> ENA_ETH_IO_RX_DESC_COMP_REQ_SHIFT; +} + +static inline void set_ena_eth_io_rx_desc_comp_req(struct ena_eth_io_rx_desc *p, uint8_t val) +{ + p->ctrl |= (val << ENA_ETH_IO_RX_DESC_COMP_REQ_SHIFT) & ENA_ETH_IO_RX_DESC_COMP_REQ_MASK; +} + +static inline uint32_t get_ena_eth_io_rx_cdesc_base_l3_proto_idx(const struct ena_eth_io_rx_cdesc_base *p) +{ + return p->status & ENA_ETH_IO_RX_CDESC_BASE_L3_PROTO_IDX_MASK; +} + +static inline void set_ena_eth_io_rx_cdesc_base_l3_proto_idx(struct ena_eth_io_rx_cdesc_base *p, uint32_t val) +{ + p->status |= val & ENA_ETH_IO_RX_CDESC_BASE_L3_PROTO_IDX_MASK; +} + +static inline uint32_t get_ena_eth_io_rx_cdesc_base_src_vlan_cnt(const struct ena_eth_io_rx_cdesc_base *p) +{ + return (p->status & ENA_ETH_IO_RX_CDESC_BASE_SRC_VLAN_CNT_MASK) >> ENA_ETH_IO_RX_CDESC_BASE_SRC_VLAN_CNT_SHIFT; +} + +static inline void set_ena_eth_io_rx_cdesc_base_src_vlan_cnt(struct ena_eth_io_rx_cdesc_base *p, uint32_t val) +{ + p->status |= (val << ENA_ETH_IO_RX_CDESC_BASE_SRC_VLAN_CNT_SHIFT) & ENA_ETH_IO_RX_CDESC_BASE_SRC_VLAN_CNT_MASK; +} + +static inline uint32_t get_ena_eth_io_rx_cdesc_base_l4_proto_idx(const struct ena_eth_io_rx_cdesc_base *p) +{ + return (p->status & ENA_ETH_IO_RX_CDESC_BASE_L4_PROTO_IDX_MASK) >> ENA_ETH_IO_RX_CDESC_BASE_L4_PROTO_IDX_SHIFT; +} + +static inline void set_ena_eth_io_rx_cdesc_base_l4_proto_idx(struct ena_eth_io_rx_cdesc_base *p, uint32_t val) +{ + p->status |= (val << ENA_ETH_IO_RX_CDESC_BASE_L4_PROTO_IDX_SHIFT) & ENA_ETH_IO_RX_CDESC_BASE_L4_PROTO_IDX_MASK; +} + +static inline uint32_t get_ena_eth_io_rx_cdesc_base_l3_csum_err(const struct ena_eth_io_rx_cdesc_base *p) +{ + return (p->status & ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM_ERR_MASK) >> ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM_ERR_SHIFT; +} + +static inline void set_ena_eth_io_rx_cdesc_base_l3_csum_err(struct ena_eth_io_rx_cdesc_base *p, uint32_t val) +{ + p->status |= (val << ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM_ERR_SHIFT) & ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM_ERR_MASK; +} + +static inline uint32_t get_ena_eth_io_rx_cdesc_base_l4_csum_err(const struct ena_eth_io_rx_cdesc_base *p) +{ + return (p->status & ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_MASK) >> ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_SHIFT; +} + +static inline void set_ena_eth_io_rx_cdesc_base_l4_csum_err(struct ena_eth_io_rx_cdesc_base *p, uint32_t val) +{ + p->status |= (val << ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_SHIFT) & ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_MASK; +} + +static inline uint32_t get_ena_eth_io_rx_cdesc_base_ipv4_frag(const struct ena_eth_io_rx_cdesc_base *p) +{ + return (p->status & ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_MASK) >> ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_SHIFT; +} + +static inline void set_ena_eth_io_rx_cdesc_base_ipv4_frag(struct ena_eth_io_rx_cdesc_base *p, uint32_t val) +{ + p->status |= (val << ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_SHIFT) & ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_MASK; +} + +static inline uint32_t get_ena_eth_io_rx_cdesc_base_phase(const struct ena_eth_io_rx_cdesc_base *p) +{ + return (p->status & ENA_ETH_IO_RX_CDESC_BASE_PHASE_MASK) >> ENA_ETH_IO_RX_CDESC_BASE_PHASE_SHIFT; +} + +static inline void set_ena_eth_io_rx_cdesc_base_phase(struct ena_eth_io_rx_cdesc_base *p, uint32_t val) +{ + p->status |= (val << ENA_ETH_IO_RX_CDESC_BASE_PHASE_SHIFT) & ENA_ETH_IO_RX_CDESC_BASE_PHASE_MASK; +} + +static inline uint32_t get_ena_eth_io_rx_cdesc_base_l3_csum2(const struct ena_eth_io_rx_cdesc_base *p) +{ + return (p->status & ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM2_MASK) >> ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM2_SHIFT; +} + +static inline void set_ena_eth_io_rx_cdesc_base_l3_csum2(struct ena_eth_io_rx_cdesc_base *p, uint32_t val) +{ + p->status |= (val << ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM2_SHIFT) & ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM2_MASK; +} + +static inline uint32_t get_ena_eth_io_rx_cdesc_base_first(const struct ena_eth_io_rx_cdesc_base *p) +{ + return (p->status & ENA_ETH_IO_RX_CDESC_BASE_FIRST_MASK) >> ENA_ETH_IO_RX_CDESC_BASE_FIRST_SHIFT; +} + +static inline void set_ena_eth_io_rx_cdesc_base_first(struct ena_eth_io_rx_cdesc_base *p, uint32_t val) +{ + p->status |= (val << ENA_ETH_IO_RX_CDESC_BASE_FIRST_SHIFT) & ENA_ETH_IO_RX_CDESC_BASE_FIRST_MASK; +} + +static inline uint32_t get_ena_eth_io_rx_cdesc_base_last(const struct ena_eth_io_rx_cdesc_base *p) +{ + return (p->status & ENA_ETH_IO_RX_CDESC_BASE_LAST_MASK) >> ENA_ETH_IO_RX_CDESC_BASE_LAST_SHIFT; +} + +static inline void set_ena_eth_io_rx_cdesc_base_last(struct ena_eth_io_rx_cdesc_base *p, uint32_t val) +{ + p->status |= (val << ENA_ETH_IO_RX_CDESC_BASE_LAST_SHIFT) & ENA_ETH_IO_RX_CDESC_BASE_LAST_MASK; +} + +static inline uint32_t get_ena_eth_io_rx_cdesc_base_buffer(const struct ena_eth_io_rx_cdesc_base *p) +{ + return (p->status & ENA_ETH_IO_RX_CDESC_BASE_BUFFER_MASK) >> ENA_ETH_IO_RX_CDESC_BASE_BUFFER_SHIFT; +} + +static inline void set_ena_eth_io_rx_cdesc_base_buffer(struct ena_eth_io_rx_cdesc_base *p, uint32_t val) +{ + p->status |= (val << ENA_ETH_IO_RX_CDESC_BASE_BUFFER_SHIFT) & ENA_ETH_IO_RX_CDESC_BASE_BUFFER_MASK; +} + +static inline uint32_t get_ena_eth_io_intr_reg_rx_intr_delay(const struct ena_eth_io_intr_reg *p) +{ + return p->intr_control & ENA_ETH_IO_INTR_REG_RX_INTR_DELAY_MASK; +} + +static inline void set_ena_eth_io_intr_reg_rx_intr_delay(struct ena_eth_io_intr_reg *p, uint32_t val) +{ + p->intr_control |= val & ENA_ETH_IO_INTR_REG_RX_INTR_DELAY_MASK; +} + +static inline uint32_t get_ena_eth_io_intr_reg_tx_intr_delay(const struct ena_eth_io_intr_reg *p) +{ + return (p->intr_control & ENA_ETH_IO_INTR_REG_TX_INTR_DELAY_MASK) >> ENA_ETH_IO_INTR_REG_TX_INTR_DELAY_SHIFT; +} + +static inline void set_ena_eth_io_intr_reg_tx_intr_delay(struct ena_eth_io_intr_reg *p, uint32_t val) +{ + p->intr_control |= (val << ENA_ETH_IO_INTR_REG_TX_INTR_DELAY_SHIFT) & ENA_ETH_IO_INTR_REG_TX_INTR_DELAY_MASK; +} + +static inline uint32_t get_ena_eth_io_intr_reg_intr_unmask(const struct ena_eth_io_intr_reg *p) +{ + return (p->intr_control & ENA_ETH_IO_INTR_REG_INTR_UNMASK_MASK) >> ENA_ETH_IO_INTR_REG_INTR_UNMASK_SHIFT; +} + +static inline void set_ena_eth_io_intr_reg_intr_unmask(struct ena_eth_io_intr_reg *p, uint32_t val) +{ + p->intr_control |= (val << ENA_ETH_IO_INTR_REG_INTR_UNMASK_SHIFT) & ENA_ETH_IO_INTR_REG_INTR_UNMASK_MASK; +} + +static inline uint32_t get_ena_eth_io_numa_node_cfg_reg_numa(const struct ena_eth_io_numa_node_cfg_reg *p) +{ + return p->numa_cfg & ENA_ETH_IO_NUMA_NODE_CFG_REG_NUMA_MASK; +} + +static inline void set_ena_eth_io_numa_node_cfg_reg_numa(struct ena_eth_io_numa_node_cfg_reg *p, uint32_t val) +{ + p->numa_cfg |= val & ENA_ETH_IO_NUMA_NODE_CFG_REG_NUMA_MASK; +} + +static inline uint32_t get_ena_eth_io_numa_node_cfg_reg_enabled(const struct ena_eth_io_numa_node_cfg_reg *p) +{ + return (p->numa_cfg & ENA_ETH_IO_NUMA_NODE_CFG_REG_ENABLED_MASK) >> ENA_ETH_IO_NUMA_NODE_CFG_REG_ENABLED_SHIFT; +} + +static inline void set_ena_eth_io_numa_node_cfg_reg_enabled(struct ena_eth_io_numa_node_cfg_reg *p, uint32_t val) +{ + p->numa_cfg |= (val << ENA_ETH_IO_NUMA_NODE_CFG_REG_ENABLED_SHIFT) & ENA_ETH_IO_NUMA_NODE_CFG_REG_ENABLED_MASK; +} + +#endif /* !defined(ENA_DEFS_LINUX_MAINLINE) */ +#endif /*_ENA_ETH_IO_H_ */ diff --git a/sys/contrib/ena-com/ena_plat.h b/sys/contrib/ena-com/ena_plat.h new file mode 100644 index 00000000000..481f7aa4bba --- /dev/null +++ b/sys/contrib/ena-com/ena_plat.h @@ -0,0 +1,376 @@ +/*- + * BSD LICENSE + * + * Copyright (c) 2015-2017 Amazon.com, Inc. or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + */ + +#ifndef ENA_PLAT_H_ +#define ENA_PLAT_H_ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +extern struct ena_bus_space ebs; + +/* Levels */ +#define ENA_ALERT (1 << 0) /* Alerts are providing more error info. */ +#define ENA_WARNING (1 << 1) /* Driver output is more error sensitive. */ +#define ENA_INFO (1 << 2) /* Provides additional driver info. */ +#define ENA_DBG (1 << 3) /* Driver output for debugging. */ +/* Detailed info that will be printed with ENA_INFO or ENA_DEBUG flag. */ +#define ENA_TXPTH (1 << 4) /* Allows TX path tracing. */ +#define ENA_RXPTH (1 << 5) /* Allows RX path tracing. */ +#define ENA_RSC (1 << 6) /* Goes with TXPTH or RXPTH, free/alloc res. */ +#define ENA_IOQ (1 << 7) /* Detailed info about IO queues. */ +#define ENA_ADMQ (1 << 8) /* Detailed info about admin queue. */ + +#ifndef ENA_DEBUG_LEVEL +#define ENA_DEBUG_LEVEL (ENA_ALERT | ENA_WARNING) +#endif + +#ifdef ENA_TRACE +#define ena_trace_raw(level, fmt, args...) \ + do { \ + if (((level) & ENA_DEBUG_LEVEL) != (level)) \ + break; \ + printf(fmt, ##args); \ + } while (0) + +#define ena_trace(level, fmt, args...) \ + ena_trace_raw(level, "%s() [TID:%d]: " \ + fmt " \n", __func__, curthread->td_tid, ##args) + +#else /* ENA_TRACE */ +#define ena_trace_raw(...) +#define ena_trace(...) +#endif /* ENA_TRACE */ + +#define ena_trc_dbg(format, arg...) ena_trace(ENA_DBG, format, ##arg) +#define ena_trc_info(format, arg...) ena_trace(ENA_INFO, format, ##arg) +#define ena_trc_warn(format, arg...) ena_trace(ENA_WARNING, format, ##arg) +#define ena_trc_err(format, arg...) ena_trace(ENA_ALERT, format, ##arg) + +#define unlikely(x) __predict_false(x) +#define likely(x) __predict_true(x) + +#define __iomem +#define ____cacheline_aligned __aligned(CACHE_LINE_SIZE) + +#define MAX_ERRNO 4095 +#define IS_ERR_VALUE(x) unlikely((x) <= (unsigned long)MAX_ERRNO) + +#define WARN_ON(condition) \ + do { \ + int __ret_warn_on = !!(condition); \ + if (unlikely(__ret_warn_on)) \ + printf("%s %s", __FUNCTION__, __FILE__); \ + unlikely(__ret_warn_on); \ + } while (0) + +#define ENA_ASSERT(cond, format, arg...) \ + do { \ + if (unlikely(!(cond))) { \ + ena_trc_err( \ + "Assert failed on %s:%s:%d:" format, \ + __FILE__, __func__, __LINE__, ##arg); \ + WARN_ON(cond); \ + } \ + } while (0) + +#define ENA_WARN(cond, format, arg...) \ + do { \ + if (unlikely((cond))) { \ + ena_trc_warn(format, ##arg); \ + } \ + } while (0) + +static inline long IS_ERR(const void *ptr) +{ + return IS_ERR_VALUE((unsigned long)ptr); +} + +static inline void *ERR_PTR(long error) +{ + return (void *)error; +} + +static inline long PTR_ERR(const void *ptr) +{ + return (long) ptr; +} + +#define GENMASK(h, l) (((1U << ((h) - (l) + 1)) - 1) << (l)) +#define GENMASK_ULL(h, l) (((~0ULL) << (l)) & (~0ULL >> (64 - 1 - (h)))) +#define BIT(x) (1 << (x)) + +#define ENA_ABORT() BUG() +#define BUG() panic("ENA BUG") + +#define SZ_256 (256) +#define SZ_4K (4096) + +#define ENA_COM_OK 0 +#define ENA_COM_FAULT EFAULT +#define ENA_COM_INVAL EINVAL +#define ENA_COM_NO_MEM ENOMEM +#define ENA_COM_NO_SPACE ENOSPC +#define ENA_COM_TRY_AGAIN -1 +#define ENA_COM_NO_DEVICE ENODEV +#define ENA_COM_PERMISSION EPERM +#define ENA_COM_TIMER_EXPIRED ETIMEDOUT + +#define ENA_MSLEEP(x) pause_sbt("ena", SBT_1MS * (x), SBT_1MS, 0) +#define ENA_UDELAY(x) DELAY(x) +#define ENA_GET_SYSTEM_TIMEOUT(timeout_us) \ + ((long)cputick2usec(cpu_ticks()) + (timeout_us)) +#define ENA_TIME_EXPIRE(timeout) ((timeout) < (long)cputick2usec(cpu_ticks())) +#define ENA_MIGHT_SLEEP() + +#define min_t(type, _x, _y) ((type)(_x) < (type)(_y) ? (type)(_x) : (type)(_y)) +#define max_t(type, _x, _y) ((type)(_x) > (type)(_y) ? (type)(_x) : (type)(_y)) + +#define ENA_MIN32(x,y) MIN(x, y) +#define ENA_MIN16(x,y) MIN(x, y) +#define ENA_MIN8(x,y) MIN(x, y) + +#define ENA_MAX32(x,y) MAX(x, y) +#define ENA_MAX16(x,y) MAX(x, y) +#define ENA_MAX8(x,y) MAX(x, y) + +/* Spinlock related methods */ +#define ena_spinlock_t struct mtx +#define ENA_SPINLOCK_INIT(spinlock) \ + mtx_init(&(spinlock), "ena_spin", NULL, MTX_SPIN) +#define ENA_SPINLOCK_DESTROY(spinlock) \ + do { \ + if (mtx_initialized(&(spinlock))) \ + mtx_destroy(&(spinlock)); \ + } while (0) +#define ENA_SPINLOCK_LOCK(spinlock, flags) \ + do { \ + (void)(flags); \ + mtx_lock_spin(&(spinlock)); \ + } while (0) +#define ENA_SPINLOCK_UNLOCK(spinlock, flags) \ + do { \ + (void)(flags); \ + mtx_unlock_spin(&(spinlock)); \ + } while (0) + + +/* Wait queue related methods */ +#define ena_wait_event_t struct { struct cv wq; struct mtx mtx; } +#define ENA_WAIT_EVENT_INIT(waitqueue) \ + do { \ + cv_init(&((waitqueue).wq), "cv"); \ + mtx_init(&((waitqueue).mtx), "wq", NULL, MTX_DEF); \ + } while (0) +#define ENA_WAIT_EVENT_DESTROY(waitqueue) \ + do { \ + cv_destroy(&((waitqueue).wq)); \ + mtx_destroy(&((waitqueue).mtx)); \ + } while (0) +#define ENA_WAIT_EVENT_CLEAR(waitqueue) \ + cv_init(&((waitqueue).wq), (waitqueue).wq.cv_description) +#define ENA_WAIT_EVENT_WAIT(waitqueue, timeout_us) \ + do { \ + mtx_lock(&((waitqueue).mtx)); \ + cv_timedwait(&((waitqueue).wq), &((waitqueue).mtx), \ + timeout_us * hz / 1000 / 1000 ); \ + mtx_unlock(&((waitqueue).mtx)); \ + } while (0) +#define ENA_WAIT_EVENT_SIGNAL(waitqueue) cv_broadcast(&((waitqueue).wq)) + +#define dma_addr_t bus_addr_t +#define u8 uint8_t +#define u16 uint16_t +#define u32 uint32_t +#define u64 uint64_t + +typedef struct { + bus_addr_t paddr; + caddr_t vaddr; + bus_dma_tag_t tag; + bus_dmamap_t map; + bus_dma_segment_t seg; + int nseg; +} ena_mem_handle_t; + +struct ena_bus { + bus_space_handle_t reg_bar_h; + bus_space_tag_t reg_bar_t; + bus_space_handle_t mem_bar_h; + bus_space_tag_t mem_bar_t; +}; + +typedef uint32_t ena_atomic32_t; + +void ena_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nseg, + int error); +int ena_dma_alloc(device_t dmadev, bus_size_t size, ena_mem_handle_t *dma, + int mapflags); + +#define ENA_MEM_ALLOC(dmadev, size) malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO) +#define ENA_MEM_ALLOC_NODE(dmadev, size, virt, node, dev_node) (virt = NULL) +#define ENA_MEM_FREE(dmadev, ptr) free(ptr, M_DEVBUF) +#define ENA_MEM_ALLOC_COHERENT_NODE(dmadev, size, virt, phys, handle, node, \ + dev_node) \ + do { \ + ((virt) = NULL); \ + (void)(dev_node); \ + } while (0) + +#define ENA_MEM_ALLOC_COHERENT(dmadev, size, virt, phys, dma) \ + do { \ + ena_dma_alloc((dmadev), (size), &(dma), 0); \ + (virt) = (void *)(dma).vaddr; \ + (phys) = (dma).paddr; \ + } while (0) + +#define ENA_MEM_FREE_COHERENT(dmadev, size, virt, phys, dma) \ + do { \ + (void)size; \ + bus_dmamap_unload((dma).tag, (dma).map); \ + bus_dmamem_free((dma).tag, (virt), (dma).map); \ + bus_dma_tag_destroy((dma).tag); \ + (dma).tag = NULL; \ + (virt) = NULL; \ + } while (0) + +/* Register R/W methods */ +#define ENA_REG_WRITE32(bus, value, offset) \ + bus_space_write_4( \ + ((struct ena_bus*)bus)->reg_bar_t, \ + ((struct ena_bus*)bus)->reg_bar_h, \ + (bus_size_t)(offset), (value)) + +#define ENA_REG_READ32(bus, offset) \ + bus_space_read_4( \ + ((struct ena_bus*)bus)->reg_bar_t, \ + ((struct ena_bus*)bus)->reg_bar_h, \ + (bus_size_t)(offset)) + +#define time_after(a,b) ((long)((unsigned long)(b) - (unsigned long)(a)) < 0) + +#define VLAN_HLEN sizeof(struct ether_vlan_header) +#define CSUM_OFFLOAD (CSUM_IP|CSUM_TCP|CSUM_UDP) + +#if defined(__i386__) || defined(__amd64__) +static __inline +void prefetch(void *x) +{ + __asm volatile("prefetcht0 %0" :: "m" (*(unsigned long *)x)); +} +#else +#define prefetch(x) +#endif + +/* DMA buffers access */ +#define dma_unmap_addr(p, name) ((p)->dma->name) +#define dma_unmap_addr_set(p, name, v) (((p)->dma->name) = (v)) +#define dma_unmap_len(p, name) ((p)->name) +#define dma_unmap_len_set(p, name, v) (((p)->name) = (v)) + +#define memcpy_toio memcpy + +#define ATOMIC32_INC(I32_PTR) atomic_add_int(I32_PTR, 1) +#define ATOMIC32_DEC(I32_PTR) atomic_add_int(I32_PTR, -1) +#define ATOMIC32_READ(I32_PTR) atomic_load_acq_int(I32_PTR) +#define ATOMIC32_SET(I32_PTR, VAL) atomic_store_rel_int(I32_PTR, VAL) + +#define barrier() __asm__ __volatile__("": : :"memory") +#define ACCESS_ONCE(x) (*(volatile __typeof(x) *)&(x)) +#define READ_ONCE(x) ({ \ + __typeof(x) __var; \ + barrier(); \ + __var = ACCESS_ONCE(x); \ + barrier(); \ + __var; \ + }) + +#include "ena_common_defs.h" +#include "ena_admin_defs.h" +#include "ena_eth_io_defs.h" +#include "ena_regs_defs.h" + +#endif /* ENA_PLAT_H_ */ diff --git a/sys/contrib/ena-com/ena_regs_defs.h b/sys/contrib/ena-com/ena_regs_defs.h new file mode 100644 index 00000000000..1438fb8faf9 --- /dev/null +++ b/sys/contrib/ena-com/ena_regs_defs.h @@ -0,0 +1,137 @@ +/*- + * BSD LICENSE + * + * Copyright (c) 2015-2017 Amazon.com, Inc. or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + */ + +#ifndef _ENA_REGS_H_ +#define _ENA_REGS_H_ + +/* ena_registers offsets */ +#define ENA_REGS_VERSION_OFF 0x0 +#define ENA_REGS_CONTROLLER_VERSION_OFF 0x4 +#define ENA_REGS_CAPS_OFF 0x8 +#define ENA_REGS_CAPS_EXT_OFF 0xc +#define ENA_REGS_AQ_BASE_LO_OFF 0x10 +#define ENA_REGS_AQ_BASE_HI_OFF 0x14 +#define ENA_REGS_AQ_CAPS_OFF 0x18 +#define ENA_REGS_ACQ_BASE_LO_OFF 0x20 +#define ENA_REGS_ACQ_BASE_HI_OFF 0x24 +#define ENA_REGS_ACQ_CAPS_OFF 0x28 +#define ENA_REGS_AQ_DB_OFF 0x2c +#define ENA_REGS_ACQ_TAIL_OFF 0x30 +#define ENA_REGS_AENQ_CAPS_OFF 0x34 +#define ENA_REGS_AENQ_BASE_LO_OFF 0x38 +#define ENA_REGS_AENQ_BASE_HI_OFF 0x3c +#define ENA_REGS_AENQ_HEAD_DB_OFF 0x40 +#define ENA_REGS_AENQ_TAIL_OFF 0x44 +#define ENA_REGS_INTR_MASK_OFF 0x4c +#define ENA_REGS_DEV_CTL_OFF 0x54 +#define ENA_REGS_DEV_STS_OFF 0x58 +#define ENA_REGS_MMIO_REG_READ_OFF 0x5c +#define ENA_REGS_MMIO_RESP_LO_OFF 0x60 +#define ENA_REGS_MMIO_RESP_HI_OFF 0x64 +#define ENA_REGS_RSS_IND_ENTRY_UPDATE_OFF 0x68 + +/* version register */ +#define ENA_REGS_VERSION_MINOR_VERSION_MASK 0xff +#define ENA_REGS_VERSION_MAJOR_VERSION_SHIFT 8 +#define ENA_REGS_VERSION_MAJOR_VERSION_MASK 0xff00 + +/* controller_version register */ +#define ENA_REGS_CONTROLLER_VERSION_SUBMINOR_VERSION_MASK 0xff +#define ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_SHIFT 8 +#define ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_MASK 0xff00 +#define ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_SHIFT 16 +#define ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_MASK 0xff0000 +#define ENA_REGS_CONTROLLER_VERSION_IMPL_ID_SHIFT 24 +#define ENA_REGS_CONTROLLER_VERSION_IMPL_ID_MASK 0xff000000 + +/* caps register */ +#define ENA_REGS_CAPS_CONTIGUOUS_QUEUE_REQUIRED_MASK 0x1 +#define ENA_REGS_CAPS_RESET_TIMEOUT_SHIFT 1 +#define ENA_REGS_CAPS_RESET_TIMEOUT_MASK 0x3e +#define ENA_REGS_CAPS_DMA_ADDR_WIDTH_SHIFT 8 +#define ENA_REGS_CAPS_DMA_ADDR_WIDTH_MASK 0xff00 +#define ENA_REGS_CAPS_ADMIN_CMD_TO_SHIFT 16 +#define ENA_REGS_CAPS_ADMIN_CMD_TO_MASK 0xf0000 + +/* aq_caps register */ +#define ENA_REGS_AQ_CAPS_AQ_DEPTH_MASK 0xffff +#define ENA_REGS_AQ_CAPS_AQ_ENTRY_SIZE_SHIFT 16 +#define ENA_REGS_AQ_CAPS_AQ_ENTRY_SIZE_MASK 0xffff0000 + +/* acq_caps register */ +#define ENA_REGS_ACQ_CAPS_ACQ_DEPTH_MASK 0xffff +#define ENA_REGS_ACQ_CAPS_ACQ_ENTRY_SIZE_SHIFT 16 +#define ENA_REGS_ACQ_CAPS_ACQ_ENTRY_SIZE_MASK 0xffff0000 + +/* aenq_caps register */ +#define ENA_REGS_AENQ_CAPS_AENQ_DEPTH_MASK 0xffff +#define ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_SHIFT 16 +#define ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_MASK 0xffff0000 + +/* dev_ctl register */ +#define ENA_REGS_DEV_CTL_DEV_RESET_MASK 0x1 +#define ENA_REGS_DEV_CTL_AQ_RESTART_SHIFT 1 +#define ENA_REGS_DEV_CTL_AQ_RESTART_MASK 0x2 +#define ENA_REGS_DEV_CTL_QUIESCENT_SHIFT 2 +#define ENA_REGS_DEV_CTL_QUIESCENT_MASK 0x4 +#define ENA_REGS_DEV_CTL_IO_RESUME_SHIFT 3 +#define ENA_REGS_DEV_CTL_IO_RESUME_MASK 0x8 + +/* dev_sts register */ +#define ENA_REGS_DEV_STS_READY_MASK 0x1 +#define ENA_REGS_DEV_STS_AQ_RESTART_IN_PROGRESS_SHIFT 1 +#define ENA_REGS_DEV_STS_AQ_RESTART_IN_PROGRESS_MASK 0x2 +#define ENA_REGS_DEV_STS_AQ_RESTART_FINISHED_SHIFT 2 +#define ENA_REGS_DEV_STS_AQ_RESTART_FINISHED_MASK 0x4 +#define ENA_REGS_DEV_STS_RESET_IN_PROGRESS_SHIFT 3 +#define ENA_REGS_DEV_STS_RESET_IN_PROGRESS_MASK 0x8 +#define ENA_REGS_DEV_STS_RESET_FINISHED_SHIFT 4 +#define ENA_REGS_DEV_STS_RESET_FINISHED_MASK 0x10 +#define ENA_REGS_DEV_STS_FATAL_ERROR_SHIFT 5 +#define ENA_REGS_DEV_STS_FATAL_ERROR_MASK 0x20 +#define ENA_REGS_DEV_STS_QUIESCENT_STATE_IN_PROGRESS_SHIFT 6 +#define ENA_REGS_DEV_STS_QUIESCENT_STATE_IN_PROGRESS_MASK 0x40 +#define ENA_REGS_DEV_STS_QUIESCENT_STATE_ACHIEVED_SHIFT 7 +#define ENA_REGS_DEV_STS_QUIESCENT_STATE_ACHIEVED_MASK 0x80 + +/* mmio_reg_read register */ +#define ENA_REGS_MMIO_REG_READ_REQ_ID_MASK 0xffff +#define ENA_REGS_MMIO_REG_READ_REG_OFF_SHIFT 16 +#define ENA_REGS_MMIO_REG_READ_REG_OFF_MASK 0xffff0000 + +/* rss_ind_entry_update register */ +#define ENA_REGS_RSS_IND_ENTRY_UPDATE_INDEX_MASK 0xffff +#define ENA_REGS_RSS_IND_ENTRY_UPDATE_CQ_IDX_SHIFT 16 +#define ENA_REGS_RSS_IND_ENTRY_UPDATE_CQ_IDX_MASK 0xffff0000 + +#endif /*_ENA_REGS_H_ */ diff --git a/sys/dev/acpica/acpi_pcib_acpi.c b/sys/dev/acpica/acpi_pcib_acpi.c index 98e3b296219..d26ee0c37cd 100644 --- a/sys/dev/acpica/acpi_pcib_acpi.c +++ b/sys/dev/acpica/acpi_pcib_acpi.c @@ -313,32 +313,42 @@ acpi_pcib_osc(struct acpi_hpcib_softc *sc, uint32_t osc_ctl) 0x96, 0x57, 0x74, 0x41, 0xc0, 0x3d, 0xd7, 0x66 }; - /* Status Field */ - cap_set[PCI_OSC_STATUS] = 0; + /* + * Don't invoke _OSC if a control is already granted. + * However, always invoke _OSC during attach when 0 is passed. + */ + if (osc_ctl != 0 && (sc->ap_osc_ctl & osc_ctl) == osc_ctl) + return (0); /* Support Field: Extended PCI Config Space, MSI */ cap_set[PCI_OSC_SUPPORT] = PCIM_OSC_SUPPORT_EXT_PCI_CONF | PCIM_OSC_SUPPORT_MSI; /* Control Field */ - sc->ap_osc_ctl |= osc_ctl; - cap_set[PCI_OSC_CTL] = sc->ap_osc_ctl; + cap_set[PCI_OSC_CTL] = sc->ap_osc_ctl | osc_ctl; status = acpi_EvaluateOSC(sc->ap_handle, pci_host_bridge_uuid, 1, nitems(cap_set), cap_set, cap_set, false); if (ACPI_FAILURE(status)) { - if (status == AE_NOT_FOUND) + if (status == AE_NOT_FOUND) { + sc->ap_osc_ctl |= osc_ctl; return (0); + } device_printf(sc->ap_dev, "_OSC failed: %s\n", AcpiFormatException(status)); return (EIO); } - if (cap_set[PCI_OSC_STATUS] == 0) - sc->ap_osc_ctl = cap_set[PCI_OSC_CTL]; - - if (cap_set[PCI_OSC_STATUS] != 0 || - (cap_set[PCI_OSC_CTL] & osc_ctl) != osc_ctl) + /* + * _OSC may return an error in the status word, but will + * update the control mask always. _OSC should not revoke + * previously-granted controls. + */ + if ((cap_set[PCI_OSC_CTL] & sc->ap_osc_ctl) != sc->ap_osc_ctl) + device_printf(sc->ap_dev, "_OSC revoked %#x\n", + (cap_set[PCI_OSC_CTL] & sc->ap_osc_ctl) ^ sc->ap_osc_ctl); + sc->ap_osc_ctl = cap_set[PCI_OSC_CTL]; + if ((sc->ap_osc_ctl & osc_ctl) != osc_ctl) return (EIO); return (0); @@ -727,7 +737,7 @@ acpi_pcib_request_feature(device_t pcib, device_t dev, enum pci_feature feature) uint32_t osc_ctl; struct acpi_hpcib_softc *sc; - sc = device_get_softc(dev); + sc = device_get_softc(pcib); switch (feature) { case PCI_FEATURE_HP: diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h index 6382205d3e3..647e59b8d17 100644 --- a/sys/dev/acpica/acpivar.h +++ b/sys/dev/acpica/acpivar.h @@ -301,6 +301,12 @@ void acpi_EnterDebugger(void); device_printf(dev, x); \ } while (0) +/* Values for the first status word returned by _OSC. */ +#define ACPI_OSC_FAILURE (1 << 1) +#define ACPI_OSC_BAD_UUID (1 << 2) +#define ACPI_OSC_BAD_REVISION (1 << 3) +#define ACPI_OSC_CAPS_MASKED (1 << 4) + /* Values for the device _STA (status) method. */ #define ACPI_STA_PRESENT (1 << 0) #define ACPI_STA_ENABLED (1 << 1) diff --git a/sys/dev/bnxt/bnxt.h b/sys/dev/bnxt/bnxt.h index 03a24493281..aa88d503cc3 100644 --- a/sys/dev/bnxt/bnxt.h +++ b/sys/dev/bnxt/bnxt.h @@ -78,6 +78,7 @@ __FBSDID("$FreeBSD$"); #define BCM57417_NPAR1 0x16c0 #define BCM57417_NPAR2 0x16cc #define BCM57417_SFP 0x16e2 +#define BCM57454 0x1614 #define BCM58700 0x16cd #define NETXTREME_C_VF1 0x16cb #define NETXTREME_C_VF2 0x16e1 diff --git a/sys/dev/bnxt/if_bnxt.c b/sys/dev/bnxt/if_bnxt.c index fa689b8756a..1c6c66f1427 100644 --- a/sys/dev/bnxt/if_bnxt.c +++ b/sys/dev/bnxt/if_bnxt.c @@ -127,6 +127,8 @@ static pci_vendor_info_t bnxt_vendor_info_array[] = "Broadcom BCM57417 NetXtreme-E Ethernet Partition"), PVID(BROADCOM_VENDOR_ID, BCM57417_SFP, "Broadcom BCM57417 NetXtreme-E 10Gb/25Gb Ethernet"), + PVID(BROADCOM_VENDOR_ID, BCM57454, + "Broadcom BCM57454 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb Ethernet"), PVID(BROADCOM_VENDOR_ID, BCM58700, "Broadcom BCM58700 Nitro 1Gb/2.5Gb/10Gb Ethernet"), PVID(BROADCOM_VENDOR_ID, NETXTREME_C_VF1, diff --git a/sys/dev/cxgbe/adapter.h b/sys/dev/cxgbe/adapter.h index 8c23cbdb8ce..e71afdd6b14 100644 --- a/sys/dev/cxgbe/adapter.h +++ b/sys/dev/cxgbe/adapter.h @@ -231,15 +231,36 @@ struct vi_info { uint8_t hw_addr[ETHER_ADDR_LEN]; /* factory MAC address, won't change */ }; -enum { - /* tx_sched_class flags */ - TX_SC_OK = (1 << 0), /* Set up in hardware, active. */ +struct tx_ch_rl_params { + enum fw_sched_params_rate ratemode; /* %port (REL) or kbps (ABS) */ + uint32_t maxrate; }; -struct tx_sched_class { +enum { + TX_CLRL_REFRESH = (1 << 0), /* Need to update hardware state. */ + TX_CLRL_ERROR = (1 << 1), /* Error, hardware state unknown. */ +}; + +struct tx_cl_rl_params { int refcount; - int flags; - struct t4_sched_class_params params; + u_int flags; + enum fw_sched_params_rate ratemode; /* %port REL or ABS value */ + enum fw_sched_params_unit rateunit; /* kbps or pps (when ABS) */ + enum fw_sched_params_mode mode; /* aggr or per-flow */ + uint32_t maxrate; + uint16_t pktsize; +}; + +/* Tx scheduler parameters for a channel/port */ +struct tx_sched_params { + /* Channel Rate Limiter */ + struct tx_ch_rl_params ch_rl; + + /* Class WRR */ + /* XXX */ + + /* Class Rate Limiter */ + struct tx_cl_rl_params cl_rl[]; }; struct port_info { @@ -251,7 +272,7 @@ struct port_info { int up_vis; int uld_vis; - struct tx_sched_class *tc; /* traffic classes for this channel */ + struct tx_sched_params *sched_params; struct mtx pi_lock; char lockname[16]; @@ -825,6 +846,9 @@ struct adapter { struct memwin memwin[NUM_MEMWIN]; /* memory windows */ + struct mtx tc_lock; + struct task tc_task; + const char *last_op; const void *last_op_thr; int last_op_flags; @@ -1106,8 +1130,6 @@ int t4_detach_common(device_t); int t4_filter_rpl(struct sge_iq *, const struct rss_header *, struct mbuf *); int t4_map_bars_0_and_4(struct adapter *); int t4_map_bar_2(struct adapter *); -int t4_set_sched_class(struct adapter *, struct t4_sched_params *); -int t4_set_sched_queue(struct adapter *, struct t4_sched_queue *); int t4_setup_intr_handlers(struct adapter *); void t4_sysctls(struct adapter *); int begin_synchronized_op(struct adapter *, struct vi_info *, int, char *); @@ -1168,6 +1190,15 @@ int t4_set_tracer(struct adapter *, struct t4_tracer *); int t4_trace_pkt(struct sge_iq *, const struct rss_header *, struct mbuf *); int t5_trace_pkt(struct sge_iq *, const struct rss_header *, struct mbuf *); +/* t4_sched.c */ +int t4_set_sched_class(struct adapter *, struct t4_sched_params *); +int t4_set_sched_queue(struct adapter *, struct t4_sched_queue *); +int t4_init_tx_sched(struct adapter *); +int t4_free_tx_sched(struct adapter *); +void t4_update_tx_sched(struct adapter *); +int t4_reserve_cl_rl_kbps(struct adapter *, int, u_int, int *); +void t4_release_cl_rl_kbps(struct adapter *, int, int); + static inline struct wrqe * alloc_wrqe(int wr_len, struct sge_wrq *wrq) { diff --git a/sys/dev/cxgbe/common/common.h b/sys/dev/cxgbe/common/common.h index f1904fbdfca..2a6868abaa0 100644 --- a/sys/dev/cxgbe/common/common.h +++ b/sys/dev/cxgbe/common/common.h @@ -774,6 +774,13 @@ int t4_sched_params(struct adapter *adapter, int type, int level, int mode, int rateunit, int ratemode, int channel, int cl, int minrate, int maxrate, int weight, int pktsize, int sleep_ok); +int t4_sched_params_ch_rl(struct adapter *adapter, int channel, int ratemode, + unsigned int maxrate, int sleep_ok); +int t4_sched_params_cl_wrr(struct adapter *adapter, int channel, int cl, + int weight, int sleep_ok); +int t4_sched_params_cl_rl_kbps(struct adapter *adapter, int channel, int cl, + int mode, unsigned int maxrate, int pktsize, + int sleep_ok); int t4_config_watchdog(struct adapter *adapter, unsigned int mbox, unsigned int pf, unsigned int vf, unsigned int timeout, unsigned int action); diff --git a/sys/dev/cxgbe/common/t4_hw.c b/sys/dev/cxgbe/common/t4_hw.c index af3a855bc6d..bf8b53527d5 100644 --- a/sys/dev/cxgbe/common/t4_hw.c +++ b/sys/dev/cxgbe/common/t4_hw.c @@ -9396,6 +9396,79 @@ int t4_sched_params(struct adapter *adapter, int type, int level, int mode, NULL, sleep_ok); } +int t4_sched_params_ch_rl(struct adapter *adapter, int channel, int ratemode, + unsigned int maxrate, int sleep_ok) +{ + struct fw_sched_cmd cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_SCHED_CMD) | + F_FW_CMD_REQUEST | + F_FW_CMD_WRITE); + cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); + + cmd.u.params.sc = FW_SCHED_SC_PARAMS; + cmd.u.params.type = FW_SCHED_TYPE_PKTSCHED; + cmd.u.params.level = FW_SCHED_PARAMS_LEVEL_CH_RL; + cmd.u.params.ch = channel; + cmd.u.params.rate = ratemode; /* REL or ABS */ + cmd.u.params.max = cpu_to_be32(maxrate);/* % or kbps */ + + return t4_wr_mbox_meat(adapter,adapter->mbox, &cmd, sizeof(cmd), + NULL, sleep_ok); +} + +int t4_sched_params_cl_wrr(struct adapter *adapter, int channel, int cl, + int weight, int sleep_ok) +{ + struct fw_sched_cmd cmd; + + if (weight < 0 || weight > 100) + return -EINVAL; + + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_SCHED_CMD) | + F_FW_CMD_REQUEST | + F_FW_CMD_WRITE); + cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); + + cmd.u.params.sc = FW_SCHED_SC_PARAMS; + cmd.u.params.type = FW_SCHED_TYPE_PKTSCHED; + cmd.u.params.level = FW_SCHED_PARAMS_LEVEL_CL_WRR; + cmd.u.params.ch = channel; + cmd.u.params.cl = cl; + cmd.u.params.weight = cpu_to_be16(weight); + + return t4_wr_mbox_meat(adapter,adapter->mbox, &cmd, sizeof(cmd), + NULL, sleep_ok); +} + +int t4_sched_params_cl_rl_kbps(struct adapter *adapter, int channel, int cl, + int mode, unsigned int maxrate, int pktsize, int sleep_ok) +{ + struct fw_sched_cmd cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_SCHED_CMD) | + F_FW_CMD_REQUEST | + F_FW_CMD_WRITE); + cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); + + cmd.u.params.sc = FW_SCHED_SC_PARAMS; + cmd.u.params.type = FW_SCHED_TYPE_PKTSCHED; + cmd.u.params.level = FW_SCHED_PARAMS_LEVEL_CL_RL; + cmd.u.params.mode = mode; + cmd.u.params.ch = channel; + cmd.u.params.cl = cl; + cmd.u.params.unit = FW_SCHED_PARAMS_UNIT_BITRATE; + cmd.u.params.rate = FW_SCHED_PARAMS_RATE_ABS; + cmd.u.params.max = cpu_to_be32(maxrate); + cmd.u.params.pktsize = cpu_to_be16(pktsize); + + return t4_wr_mbox_meat(adapter,adapter->mbox, &cmd, sizeof(cmd), + NULL, sleep_ok); +} + /* * t4_config_watchdog - configure (enable/disable) a watchdog timer * @adapter: the adapter diff --git a/sys/dev/cxgbe/t4_main.c b/sys/dev/cxgbe/t4_main.c index 86f3652f977..e3eec95defc 100644 --- a/sys/dev/cxgbe/t4_main.c +++ b/sys/dev/cxgbe/t4_main.c @@ -998,9 +998,6 @@ t4_attach(device_t dev) mtx_init(&pi->pi_lock, pi->lockname, 0, MTX_DEF); sc->chan_map[pi->tx_chan] = i; - pi->tc = malloc(sizeof(struct tx_sched_class) * - sc->chip_params->nsched_cls, M_CXGBE, M_ZERO | M_WAITOK); - if (port_top_speed(pi) >= 10) { n10g++; } else { @@ -1088,6 +1085,7 @@ t4_attach(device_t dev) M_ZERO | M_WAITOK); t4_init_l2t(sc, M_WAITOK); + t4_init_tx_sched(sc); /* * Second pass over the ports. This time we know the number of rx and @@ -1312,6 +1310,9 @@ t4_detach_common(device_t dev) for (i = 0; i < sc->intr_count; i++) t4_free_irq(sc, &sc->irq[i]); + if ((sc->flags & (IS_VF | FW_OK)) == FW_OK) + t4_free_tx_sched(sc); + for (i = 0; i < MAX_NPORTS; i++) { pi = sc->port[i]; if (pi) { @@ -1321,7 +1322,6 @@ t4_detach_common(device_t dev) mtx_destroy(&pi->pi_lock); free(pi->vi, M_CXGBE); - free(pi->tc, M_CXGBE); free(pi, M_CXGBE); } } @@ -5338,9 +5338,9 @@ cxgbe_sysctls(struct port_info *pi) * dev.(cxgbe|cxl).X.tc. */ oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "tc", CTLFLAG_RD, NULL, - "Tx scheduler traffic classes"); + "Tx scheduler traffic classes (cl_rl)"); for (i = 0; i < sc->chip_params->nsched_cls; i++) { - struct tx_sched_class *tc = &pi->tc[i]; + struct tx_cl_rl_params *tc = &pi->sched_params->cl_rl[i]; snprintf(name, sizeof(name), "%d", i); children2 = SYSCTL_CHILDREN(SYSCTL_ADD_NODE(ctx, @@ -7855,10 +7855,9 @@ static int sysctl_tc_params(SYSCTL_HANDLER_ARGS) { struct adapter *sc = arg1; - struct tx_sched_class *tc; - struct t4_sched_class_params p; + struct tx_cl_rl_params tc; struct sbuf *sb; - int i, rc, port_id, flags, mbps, gbps; + int i, rc, port_id, mbps, gbps; rc = sysctl_wire_old_buffer(req, 0); if (rc != 0) @@ -7873,52 +7872,34 @@ sysctl_tc_params(SYSCTL_HANDLER_ARGS) MPASS(sc->port[port_id] != NULL); i = arg2 & 0xffff; MPASS(i < sc->chip_params->nsched_cls); - tc = &sc->port[port_id]->tc[i]; - rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK, - "t4tc_p"); - if (rc) - goto done; - flags = tc->flags; - p = tc->params; - end_synchronized_op(sc, LOCK_HELD); + mtx_lock(&sc->tc_lock); + tc = sc->port[port_id]->sched_params->cl_rl[i]; + mtx_unlock(&sc->tc_lock); - if ((flags & TX_SC_OK) == 0) { - sbuf_printf(sb, "none"); + if (tc.flags & TX_CLRL_ERROR) { + sbuf_printf(sb, "error"); goto done; } - if (p.level == SCHED_CLASS_LEVEL_CL_WRR) { - sbuf_printf(sb, "cl-wrr weight %u", p.weight); - goto done; - } else if (p.level == SCHED_CLASS_LEVEL_CL_RL) - sbuf_printf(sb, "cl-rl"); - else if (p.level == SCHED_CLASS_LEVEL_CH_RL) - sbuf_printf(sb, "ch-rl"); - else { - rc = ENXIO; - goto done; - } - - if (p.ratemode == SCHED_CLASS_RATEMODE_REL) { + if (tc.ratemode == SCHED_CLASS_RATEMODE_REL) { /* XXX: top speed or actual link speed? */ gbps = port_top_speed(sc->port[port_id]); - sbuf_printf(sb, " %u%% of %uGbps", p.maxrate, gbps); - } - else if (p.ratemode == SCHED_CLASS_RATEMODE_ABS) { - switch (p.rateunit) { + sbuf_printf(sb, " %u%% of %uGbps", tc.maxrate, gbps); + } else if (tc.ratemode == SCHED_CLASS_RATEMODE_ABS) { + switch (tc.rateunit) { case SCHED_CLASS_RATEUNIT_BITS: - mbps = p.maxrate / 1000; - gbps = p.maxrate / 1000000; - if (p.maxrate == gbps * 1000000) + mbps = tc.maxrate / 1000; + gbps = tc.maxrate / 1000000; + if (tc.maxrate == gbps * 1000000) sbuf_printf(sb, " %uGbps", gbps); - else if (p.maxrate == mbps * 1000) + else if (tc.maxrate == mbps * 1000) sbuf_printf(sb, " %uMbps", mbps); else - sbuf_printf(sb, " %uKbps", p.maxrate); + sbuf_printf(sb, " %uKbps", tc.maxrate); break; case SCHED_CLASS_RATEUNIT_PKTS: - sbuf_printf(sb, " %upps", p.maxrate); + sbuf_printf(sb, " %upps", tc.maxrate); break; default: rc = ENXIO; @@ -7926,7 +7907,7 @@ sysctl_tc_params(SYSCTL_HANDLER_ARGS) } } - switch (p.mode) { + switch (tc.mode) { case SCHED_CLASS_MODE_CLASS: sbuf_printf(sb, " aggregate"); break; @@ -8828,225 +8809,6 @@ read_i2c(struct adapter *sc, struct t4_i2c_data *i2cd) return (rc); } -static int -in_range(int val, int lo, int hi) -{ - - return (val < 0 || (val <= hi && val >= lo)); -} - -static int -set_sched_class_config(struct adapter *sc, int minmax) -{ - int rc; - - if (minmax < 0) - return (EINVAL); - - rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4sscc"); - if (rc) - return (rc); - rc = -t4_sched_config(sc, FW_SCHED_TYPE_PKTSCHED, minmax, 1); - end_synchronized_op(sc, 0); - - return (rc); -} - -static int -set_sched_class_params(struct adapter *sc, struct t4_sched_class_params *p, - int sleep_ok) -{ - int rc, top_speed, fw_level, fw_mode, fw_rateunit, fw_ratemode; - struct port_info *pi; - struct tx_sched_class *tc; - - if (p->level == SCHED_CLASS_LEVEL_CL_RL) - fw_level = FW_SCHED_PARAMS_LEVEL_CL_RL; - else if (p->level == SCHED_CLASS_LEVEL_CL_WRR) - fw_level = FW_SCHED_PARAMS_LEVEL_CL_WRR; - else if (p->level == SCHED_CLASS_LEVEL_CH_RL) - fw_level = FW_SCHED_PARAMS_LEVEL_CH_RL; - else - return (EINVAL); - - if (p->mode == SCHED_CLASS_MODE_CLASS) - fw_mode = FW_SCHED_PARAMS_MODE_CLASS; - else if (p->mode == SCHED_CLASS_MODE_FLOW) - fw_mode = FW_SCHED_PARAMS_MODE_FLOW; - else - return (EINVAL); - - if (p->rateunit == SCHED_CLASS_RATEUNIT_BITS) - fw_rateunit = FW_SCHED_PARAMS_UNIT_BITRATE; - else if (p->rateunit == SCHED_CLASS_RATEUNIT_PKTS) - fw_rateunit = FW_SCHED_PARAMS_UNIT_PKTRATE; - else - return (EINVAL); - - if (p->ratemode == SCHED_CLASS_RATEMODE_REL) - fw_ratemode = FW_SCHED_PARAMS_RATE_REL; - else if (p->ratemode == SCHED_CLASS_RATEMODE_ABS) - fw_ratemode = FW_SCHED_PARAMS_RATE_ABS; - else - return (EINVAL); - - /* Vet our parameters ... */ - if (!in_range(p->channel, 0, sc->chip_params->nchan - 1)) - return (ERANGE); - - pi = sc->port[sc->chan_map[p->channel]]; - if (pi == NULL) - return (ENXIO); - MPASS(pi->tx_chan == p->channel); - top_speed = port_top_speed(pi) * 1000000; /* Gbps -> Kbps */ - - if (!in_range(p->cl, 0, sc->chip_params->nsched_cls) || - !in_range(p->minrate, 0, top_speed) || - !in_range(p->maxrate, 0, top_speed) || - !in_range(p->weight, 0, 100)) - return (ERANGE); - - /* - * Translate any unset parameters into the firmware's - * nomenclature and/or fail the call if the parameters - * are required ... - */ - if (p->rateunit < 0 || p->ratemode < 0 || p->channel < 0 || p->cl < 0) - return (EINVAL); - - if (p->minrate < 0) - p->minrate = 0; - if (p->maxrate < 0) { - if (p->level == SCHED_CLASS_LEVEL_CL_RL || - p->level == SCHED_CLASS_LEVEL_CH_RL) - return (EINVAL); - else - p->maxrate = 0; - } - if (p->weight < 0) { - if (p->level == SCHED_CLASS_LEVEL_CL_WRR) - return (EINVAL); - else - p->weight = 0; - } - if (p->pktsize < 0) { - if (p->level == SCHED_CLASS_LEVEL_CL_RL || - p->level == SCHED_CLASS_LEVEL_CH_RL) - return (EINVAL); - else - p->pktsize = 0; - } - - rc = begin_synchronized_op(sc, NULL, - sleep_ok ? (SLEEP_OK | INTR_OK) : HOLD_LOCK, "t4sscp"); - if (rc) - return (rc); - tc = &pi->tc[p->cl]; - tc->params = *p; - rc = -t4_sched_params(sc, FW_SCHED_TYPE_PKTSCHED, fw_level, fw_mode, - fw_rateunit, fw_ratemode, p->channel, p->cl, p->minrate, p->maxrate, - p->weight, p->pktsize, sleep_ok); - if (rc == 0) - tc->flags |= TX_SC_OK; - else { - /* - * Unknown state at this point, see tc->params for what was - * attempted. - */ - tc->flags &= ~TX_SC_OK; - } - end_synchronized_op(sc, sleep_ok ? 0 : LOCK_HELD); - - return (rc); -} - -int -t4_set_sched_class(struct adapter *sc, struct t4_sched_params *p) -{ - - if (p->type != SCHED_CLASS_TYPE_PACKET) - return (EINVAL); - - if (p->subcmd == SCHED_CLASS_SUBCMD_CONFIG) - return (set_sched_class_config(sc, p->u.config.minmax)); - - if (p->subcmd == SCHED_CLASS_SUBCMD_PARAMS) - return (set_sched_class_params(sc, &p->u.params, 1)); - - return (EINVAL); -} - -int -t4_set_sched_queue(struct adapter *sc, struct t4_sched_queue *p) -{ - struct port_info *pi = NULL; - struct vi_info *vi; - struct sge_txq *txq; - uint32_t fw_mnem, fw_queue, fw_class; - int i, rc; - - rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setsq"); - if (rc) - return (rc); - - if (p->port >= sc->params.nports) { - rc = EINVAL; - goto done; - } - - /* XXX: Only supported for the main VI. */ - pi = sc->port[p->port]; - vi = &pi->vi[0]; - if (!(vi->flags & VI_INIT_DONE)) { - /* tx queues not set up yet */ - rc = EAGAIN; - goto done; - } - - if (!in_range(p->queue, 0, vi->ntxq - 1) || - !in_range(p->cl, 0, sc->chip_params->nsched_cls - 1)) { - rc = EINVAL; - goto done; - } - - /* - * Create a template for the FW_PARAMS_CMD mnemonic and value (TX - * Scheduling Class in this case). - */ - fw_mnem = (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DMAQ) | - V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DMAQ_EQ_SCHEDCLASS_ETH)); - fw_class = p->cl < 0 ? 0xffffffff : p->cl; - - /* - * If op.queue is non-negative, then we're only changing the scheduling - * on a single specified TX queue. - */ - if (p->queue >= 0) { - txq = &sc->sge.txq[vi->first_txq + p->queue]; - fw_queue = (fw_mnem | V_FW_PARAMS_PARAM_YZ(txq->eq.cntxt_id)); - rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &fw_queue, - &fw_class); - goto done; - } - - /* - * Change the scheduling on all the TX queues for the - * interface. - */ - for_each_txq(vi, i, txq) { - fw_queue = (fw_mnem | V_FW_PARAMS_PARAM_YZ(txq->eq.cntxt_id)); - rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &fw_queue, - &fw_class); - if (rc) - goto done; - } - - rc = 0; -done: - end_synchronized_op(sc, 0); - return (rc); -} - int t4_os_find_pci_capability(struct adapter *sc, int cap) { diff --git a/sys/dev/cxgbe/t4_sched.c b/sys/dev/cxgbe/t4_sched.c new file mode 100644 index 00000000000..c8a3e7796b4 --- /dev/null +++ b/sys/dev/cxgbe/t4_sched.c @@ -0,0 +1,461 @@ +/*- + * Copyright (c) 2017 Chelsio Communications, Inc. + * All rights reserved. + * Written by: Navdeep Parhar + * + * 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 +__FBSDID("$FreeBSD$"); + +#include "opt_inet.h" +#include "opt_inet6.h" + +#include +#include +#include +#include +#include +#include + +#include "common/common.h" +#include "common/t4_regs.h" +#include "common/t4_regs_values.h" +#include "common/t4_msg.h" + + +static int +in_range(int val, int lo, int hi) +{ + + return (val < 0 || (val <= hi && val >= lo)); +} + +static int +set_sched_class_config(struct adapter *sc, int minmax) +{ + int rc; + + if (minmax < 0) + return (EINVAL); + + rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4sscc"); + if (rc) + return (rc); + rc = -t4_sched_config(sc, FW_SCHED_TYPE_PKTSCHED, minmax, 1); + end_synchronized_op(sc, 0); + + return (rc); +} + +static int +set_sched_class_params(struct adapter *sc, struct t4_sched_class_params *p, + int sleep_ok) +{ + int rc, top_speed, fw_level, fw_mode, fw_rateunit, fw_ratemode; + struct port_info *pi; + struct tx_cl_rl_params *tc; + + if (p->level == SCHED_CLASS_LEVEL_CL_RL) + fw_level = FW_SCHED_PARAMS_LEVEL_CL_RL; + else if (p->level == SCHED_CLASS_LEVEL_CL_WRR) + fw_level = FW_SCHED_PARAMS_LEVEL_CL_WRR; + else if (p->level == SCHED_CLASS_LEVEL_CH_RL) + fw_level = FW_SCHED_PARAMS_LEVEL_CH_RL; + else + return (EINVAL); + + if (p->mode == SCHED_CLASS_MODE_CLASS) + fw_mode = FW_SCHED_PARAMS_MODE_CLASS; + else if (p->mode == SCHED_CLASS_MODE_FLOW) + fw_mode = FW_SCHED_PARAMS_MODE_FLOW; + else + return (EINVAL); + + if (p->rateunit == SCHED_CLASS_RATEUNIT_BITS) + fw_rateunit = FW_SCHED_PARAMS_UNIT_BITRATE; + else if (p->rateunit == SCHED_CLASS_RATEUNIT_PKTS) + fw_rateunit = FW_SCHED_PARAMS_UNIT_PKTRATE; + else + return (EINVAL); + + if (p->ratemode == SCHED_CLASS_RATEMODE_REL) + fw_ratemode = FW_SCHED_PARAMS_RATE_REL; + else if (p->ratemode == SCHED_CLASS_RATEMODE_ABS) + fw_ratemode = FW_SCHED_PARAMS_RATE_ABS; + else + return (EINVAL); + + /* Vet our parameters ... */ + if (!in_range(p->channel, 0, sc->chip_params->nchan - 1)) + return (ERANGE); + + pi = sc->port[sc->chan_map[p->channel]]; + if (pi == NULL) + return (ENXIO); + MPASS(pi->tx_chan == p->channel); + top_speed = port_top_speed(pi) * 1000000; /* Gbps -> Kbps */ + + if (!in_range(p->cl, 0, sc->chip_params->nsched_cls) || + !in_range(p->minrate, 0, top_speed) || + !in_range(p->maxrate, 0, top_speed) || + !in_range(p->weight, 0, 100)) + return (ERANGE); + + /* + * Translate any unset parameters into the firmware's + * nomenclature and/or fail the call if the parameters + * are required ... + */ + if (p->rateunit < 0 || p->ratemode < 0 || p->channel < 0 || p->cl < 0) + return (EINVAL); + + if (p->minrate < 0) + p->minrate = 0; + if (p->maxrate < 0) { + if (p->level == SCHED_CLASS_LEVEL_CL_RL || + p->level == SCHED_CLASS_LEVEL_CH_RL) + return (EINVAL); + else + p->maxrate = 0; + } + if (p->weight < 0) { + if (p->level == SCHED_CLASS_LEVEL_CL_WRR) + return (EINVAL); + else + p->weight = 0; + } + if (p->pktsize < 0) { + if (p->level == SCHED_CLASS_LEVEL_CL_RL || + p->level == SCHED_CLASS_LEVEL_CH_RL) + return (EINVAL); + else + p->pktsize = 0; + } + + rc = begin_synchronized_op(sc, NULL, + sleep_ok ? (SLEEP_OK | INTR_OK) : HOLD_LOCK, "t4sscp"); + if (rc) + return (rc); + if (p->level == SCHED_CLASS_LEVEL_CL_RL) { + tc = &pi->sched_params->cl_rl[p->cl]; + if (tc->refcount > 0) { + rc = EBUSY; + goto done; + } else { + tc->ratemode = fw_ratemode; + tc->rateunit = fw_rateunit; + tc->mode = fw_mode; + tc->maxrate = p->maxrate; + tc->pktsize = p->pktsize; + } + } + rc = -t4_sched_params(sc, FW_SCHED_TYPE_PKTSCHED, fw_level, fw_mode, + fw_rateunit, fw_ratemode, p->channel, p->cl, p->minrate, p->maxrate, + p->weight, p->pktsize, sleep_ok); + if (p->level == SCHED_CLASS_LEVEL_CL_RL && rc != 0) { + /* + * Unknown state at this point, see parameters in tc for what + * was attempted. + */ + tc->flags |= TX_CLRL_ERROR; + } +done: + end_synchronized_op(sc, sleep_ok ? 0 : LOCK_HELD); + + return (rc); +} + +static void +update_tx_sched(void *context, int pending) +{ + int i, j, mode, rateunit, ratemode, maxrate, pktsize, rc; + struct port_info *pi; + struct tx_cl_rl_params *tc; + struct adapter *sc = context; + const int n = sc->chip_params->nsched_cls; + + mtx_lock(&sc->tc_lock); + for_each_port(sc, i) { + pi = sc->port[i]; + tc = &pi->sched_params->cl_rl[0]; + for (j = 0; j < n; j++, tc++) { + MPASS(mtx_owned(&sc->tc_lock)); + if ((tc->flags & TX_CLRL_REFRESH) == 0) + continue; + + mode = tc->mode; + rateunit = tc->rateunit; + ratemode = tc->ratemode; + maxrate = tc->maxrate; + pktsize = tc->pktsize; + mtx_unlock(&sc->tc_lock); + + if (begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, + "t4utxs") != 0) { + mtx_lock(&sc->tc_lock); + continue; + } + rc = t4_sched_params(sc, FW_SCHED_TYPE_PKTSCHED, + FW_SCHED_PARAMS_LEVEL_CL_RL, mode, rateunit, + ratemode, pi->tx_chan, j, 0, maxrate, 0, pktsize, + 1); + end_synchronized_op(sc, 0); + + mtx_lock(&sc->tc_lock); + if (rc != 0) { + tc->flags |= TX_CLRL_ERROR; + } else if (tc->mode == mode && + tc->rateunit == rateunit && + tc->maxrate == maxrate && + tc->pktsize == tc->pktsize) { + tc->flags &= ~(TX_CLRL_REFRESH | TX_CLRL_ERROR); + } + } + } + mtx_unlock(&sc->tc_lock); +} + +int +t4_set_sched_class(struct adapter *sc, struct t4_sched_params *p) +{ + + if (p->type != SCHED_CLASS_TYPE_PACKET) + return (EINVAL); + + if (p->subcmd == SCHED_CLASS_SUBCMD_CONFIG) + return (set_sched_class_config(sc, p->u.config.minmax)); + + if (p->subcmd == SCHED_CLASS_SUBCMD_PARAMS) + return (set_sched_class_params(sc, &p->u.params, 1)); + + return (EINVAL); +} + +int +t4_set_sched_queue(struct adapter *sc, struct t4_sched_queue *p) +{ + struct port_info *pi = NULL; + struct vi_info *vi; + struct sge_txq *txq; + uint32_t fw_mnem, fw_queue, fw_class; + int i, rc; + + rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setsq"); + if (rc) + return (rc); + + if (p->port >= sc->params.nports) { + rc = EINVAL; + goto done; + } + + /* XXX: Only supported for the main VI. */ + pi = sc->port[p->port]; + vi = &pi->vi[0]; + if (!(vi->flags & VI_INIT_DONE)) { + /* tx queues not set up yet */ + rc = EAGAIN; + goto done; + } + + if (!in_range(p->queue, 0, vi->ntxq - 1) || + !in_range(p->cl, 0, sc->chip_params->nsched_cls - 1)) { + rc = EINVAL; + goto done; + } + + /* + * Create a template for the FW_PARAMS_CMD mnemonic and value (TX + * Scheduling Class in this case). + */ + fw_mnem = (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DMAQ) | + V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DMAQ_EQ_SCHEDCLASS_ETH)); + fw_class = p->cl < 0 ? 0xffffffff : p->cl; + + /* + * If op.queue is non-negative, then we're only changing the scheduling + * on a single specified TX queue. + */ + if (p->queue >= 0) { + txq = &sc->sge.txq[vi->first_txq + p->queue]; + fw_queue = (fw_mnem | V_FW_PARAMS_PARAM_YZ(txq->eq.cntxt_id)); + rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &fw_queue, + &fw_class); + goto done; + } + + /* + * Change the scheduling on all the TX queues for the + * interface. + */ + for_each_txq(vi, i, txq) { + fw_queue = (fw_mnem | V_FW_PARAMS_PARAM_YZ(txq->eq.cntxt_id)); + rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &fw_queue, + &fw_class); + if (rc) + goto done; + } + + rc = 0; +done: + end_synchronized_op(sc, 0); + return (rc); +} + +int +t4_init_tx_sched(struct adapter *sc) +{ + int i, j; + const int n = sc->chip_params->nsched_cls; + struct port_info *pi; + struct tx_cl_rl_params *tc; + static const uint32_t init_kbps[] = { + 100 * 1000, + 200 * 1000, + 400 * 1000, + 500 * 1000, + 800 * 1000, + 1000 * 1000, + 1200 * 1000, + 1500 * 1000, + 1800 * 1000, + 2000 * 1000, + 2500 * 1000, + 3000 * 1000, + 3500 * 1000, + 4000 * 1000, + 5000 * 1000, + 10000 * 1000 + }; + + mtx_init(&sc->tc_lock, "tx_sched lock", NULL, MTX_DEF); + TASK_INIT(&sc->tc_task, 0, update_tx_sched, sc); + for_each_port(sc, i) { + pi = sc->port[i]; + pi->sched_params = malloc(sizeof(*pi->sched_params) + + n * sizeof(*tc), M_CXGBE, M_ZERO | M_WAITOK); + tc = &pi->sched_params->cl_rl[0]; + for (j = 0; j < n; j++, tc++) { + tc->flags = TX_CLRL_REFRESH; + tc->refcount = 0; + tc->ratemode = FW_SCHED_PARAMS_RATE_ABS; + tc->rateunit = FW_SCHED_PARAMS_UNIT_BITRATE; + tc->mode = FW_SCHED_PARAMS_MODE_FLOW; + tc->maxrate = init_kbps[min(j, nitems(init_kbps) - 1)]; + tc->pktsize = ETHERMTU; /* XXX */ + + t4_sched_params_cl_rl_kbps(sc, pi->tx_chan, j, tc->mode, + tc->maxrate, tc->pktsize, 1); + } + } + + return (0); +} + +int +t4_free_tx_sched(struct adapter *sc) +{ + int i; + + taskqueue_drain(taskqueue_thread, &sc->tc_task); + + for_each_port(sc, i) + free(sc->port[i]->sched_params, M_CXGBE); + + if (mtx_initialized(&sc->tc_lock)) + mtx_destroy(&sc->tc_lock); + + return (0); +} + +void +t4_update_tx_sched(struct adapter *sc) +{ + + taskqueue_enqueue(taskqueue_thread, &sc->tc_task); +} + +int +t4_reserve_cl_rl_kbps(struct adapter *sc, int port_id, u_int maxrate, + int *tc_idx) +{ + int rc = 0, fa = -1, i; + struct tx_cl_rl_params *tc; + + MPASS(port_id >= 0 && port_id < sc->params.nports); + + tc = &sc->port[port_id]->sched_params->cl_rl[0]; + mtx_lock(&sc->tc_lock); + for (i = 0; i < sc->chip_params->nsched_cls; i++, tc++) { + if (fa < 0 && tc->refcount == 0) + fa = i; + + if (tc->ratemode == FW_SCHED_PARAMS_RATE_ABS && + tc->rateunit == FW_SCHED_PARAMS_UNIT_BITRATE && + tc->mode == FW_SCHED_PARAMS_MODE_FLOW && + tc->maxrate == maxrate) { + tc->refcount++; + *tc_idx = i; + goto done; + } + } + /* Not found */ + MPASS(i == sc->chip_params->nsched_cls); + if (fa != -1) { + tc = &sc->port[port_id]->sched_params->cl_rl[fa]; + tc->flags = TX_CLRL_REFRESH; + tc->refcount = 1; + tc->ratemode = FW_SCHED_PARAMS_RATE_ABS; + tc->rateunit = FW_SCHED_PARAMS_UNIT_BITRATE; + tc->mode = FW_SCHED_PARAMS_MODE_FLOW; + tc->maxrate = maxrate; + tc->pktsize = ETHERMTU; /* XXX */ + *tc_idx = fa; + t4_update_tx_sched(sc); + } else { + *tc_idx = -1; + rc = ENOSPC; + } +done: + mtx_unlock(&sc->tc_lock); + return (rc); +} + +void +t4_release_cl_rl_kbps(struct adapter *sc, int port_id, int tc_idx) +{ + struct tx_cl_rl_params *tc; + + MPASS(port_id >= 0 && port_id < sc->params.nports); + MPASS(tc_idx >= 0 && tc_idx < sc->chip_params->nsched_cls); + + mtx_lock(&sc->tc_lock); + tc = &sc->port[port_id]->sched_params->cl_rl[tc_idx]; + MPASS(tc->refcount > 0); + MPASS(tc->ratemode == FW_SCHED_PARAMS_RATE_ABS); + MPASS(tc->rateunit == FW_SCHED_PARAMS_UNIT_BITRATE); + MPASS(tc->mode == FW_SCHED_PARAMS_MODE_FLOW); + tc->refcount--; + mtx_unlock(&sc->tc_lock); +} diff --git a/sys/dev/cxgbe/t4_sge.c b/sys/dev/cxgbe/t4_sge.c index 8ad49c9c31f..496b91dbbaa 100644 --- a/sys/dev/cxgbe/t4_sge.c +++ b/sys/dev/cxgbe/t4_sge.c @@ -5243,7 +5243,7 @@ sysctl_tc(SYSCTL_HANDLER_ARGS) struct port_info *pi; struct adapter *sc; struct sge_txq *txq; - struct tx_sched_class *tc; + struct tx_cl_rl_params *tc; int qidx = arg2, rc, tc_idx; uint32_t fw_queue, fw_class; @@ -5257,14 +5257,14 @@ sysctl_tc(SYSCTL_HANDLER_ARGS) if (rc != 0 || req->newptr == NULL) return (rc); + if (sc->flags & IS_VF) + return (EPERM); + /* Note that -1 is legitimate input (it means unbind). */ if (tc_idx < -1 || tc_idx >= sc->chip_params->nsched_cls) return (EINVAL); - rc = begin_synchronized_op(sc, vi, SLEEP_OK | INTR_OK, "t4stc"); - if (rc) - return (rc); - + mtx_lock(&sc->tc_lock); if (tc_idx == txq->tc_idx) { rc = 0; /* No change, nothing to do. */ goto done; @@ -5278,35 +5278,45 @@ sysctl_tc(SYSCTL_HANDLER_ARGS) fw_class = 0xffffffff; /* Unbind. */ else { /* - * Bind to a different class. Ethernet txq's are only allowed - * to bind to cl-rl mode-class for now. XXX: too restrictive. + * Bind to a different class. */ - tc = &pi->tc[tc_idx]; - if (tc->flags & TX_SC_OK && - tc->params.level == SCHED_CLASS_LEVEL_CL_RL && - tc->params.mode == SCHED_CLASS_MODE_CLASS) { - /* Ok to proceed. */ - fw_class = tc_idx; - } else { - rc = tc->flags & TX_SC_OK ? EBUSY : ENXIO; + tc = &pi->sched_params->cl_rl[tc_idx]; + if (tc->flags & TX_CLRL_ERROR) { + /* Previous attempt to set the cl-rl params failed. */ + rc = EIO; goto done; + } else { + /* + * Ok to proceed. Place a reference on the new class + * while still holding on to the reference on the + * previous class, if any. + */ + fw_class = tc_idx; + tc->refcount++; } } + mtx_unlock(&sc->tc_lock); + rc = begin_synchronized_op(sc, vi, SLEEP_OK | INTR_OK, "t4stc"); + if (rc) + return (rc); rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &fw_queue, &fw_class); + end_synchronized_op(sc, 0); + + mtx_lock(&sc->tc_lock); if (rc == 0) { if (txq->tc_idx != -1) { - tc = &pi->tc[txq->tc_idx]; + tc = &pi->sched_params->cl_rl[txq->tc_idx]; MPASS(tc->refcount > 0); tc->refcount--; } - if (tc_idx != -1) { - tc = &pi->tc[tc_idx]; - tc->refcount++; - } txq->tc_idx = tc_idx; + } else { + tc = &pi->sched_params->cl_rl[tc_idx]; + MPASS(tc->refcount > 0); + tc->refcount--; } done: - end_synchronized_op(sc, 0); + mtx_unlock(&sc->tc_lock); return (rc); } diff --git a/sys/dev/cxgbe/t4_vf.c b/sys/dev/cxgbe/t4_vf.c index 3ae3ee8774e..3791c710cc2 100644 --- a/sys/dev/cxgbe/t4_vf.c +++ b/sys/dev/cxgbe/t4_vf.c @@ -659,9 +659,6 @@ t4vf_attach(device_t dev) mtx_init(&pi->pi_lock, pi->lockname, 0, MTX_DEF); sc->chan_map[pi->tx_chan] = i; - pi->tc = malloc(sizeof(struct tx_sched_class) * - sc->chip_params->nsched_cls, M_CXGBE, M_ZERO | M_WAITOK); - if (port_top_speed(pi) >= 10) { n10g++; } else { diff --git a/sys/dev/cy/cy.c b/sys/dev/cy/cy.c new file mode 100644 index 00000000000..ad4fa145cf7 --- /dev/null +++ b/sys/dev/cy/cy.c @@ -0,0 +1,2242 @@ +/*- + * cyclades cyclom-y serial driver + * Andrew Herbert , 17 August 1993 + * + * Copyright (c) 1993 Andrew Herbert. + * All rights reserved. + * + * 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. + * 3. The name Andrew Herbert may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ``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 I 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 +__FBSDID("$FreeBSD$"); + +#include "opt_compat.h" + +/* + * TODO: + * Atomic COR change. + * Consoles. + */ + +/* + * Temporary compile-time configuration options. + */ +#define RxFifoThreshold (CD1400_RX_FIFO_SIZE / 2) + /* Number of chars in the receiver FIFO before an + * an interrupt is generated. Should depend on + * line speed. Needs to be about 6 on a 486DX33 + * for 4 active ports at 115200 bps. Why doesn't + * 10 work? + */ +#define PollMode /* Use polling-based irq service routine, not the + * hardware svcack lines. Must be defined for + * Cyclom-16Y boards. Less efficient for Cyclom-8Ys, + * and stops 4 * 115200 bps from working. + */ +#undef Smarts /* Enable slightly more CD1400 intelligence. Mainly + * the output CR/LF processing, plus we can avoid a + * few checks usually done in ttyinput(). + * + * XXX not fully implemented, and not particularly + * worthwhile. + */ +#undef CyDebug /* Include debugging code (not very expensive). */ + +/* These will go away. */ +#undef SOFT_CTS_OFLOW +#define SOFT_HOTCHAR + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#define NCY 10 /* KLUDGE */ + +#define NPORTS (NCY * CY_MAX_PORTS) + +#define CY_MAX_PORTS (CD1400_NO_OF_CHANNELS * CY_MAX_CD1400s) + +/* We encode the cyclom unit number (cyu) in spare bits in the IVR's. */ +#define CD1400_xIVR_CHAN_SHIFT 3 +#define CD1400_xIVR_CHAN 0x1F + +/* + * ETC states. com->etc may also contain a hardware ETC command value, + * meaning that execution of that command is pending. + */ +#define ETC_NONE 0 /* we depend on bzero() setting this */ +#define ETC_BREAK_STARTING 1 +#define ETC_BREAK_STARTED 2 +#define ETC_BREAK_ENDING 3 +#define ETC_BREAK_ENDED 4 + +#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */ + +/* + * com state bits. + * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher + * than the other bits so that they can be tested as a group without masking + * off the low bits. + * + * The following com and tty flags correspond closely: + * CS_BUSY = TS_BUSY (maintained by cystart(), cypoll() and + * comstop()) + * CS_TTGO = ~TS_TTSTOP (maintained by cyparam() and cystart()) + * CS_CTS_OFLOW = CCTS_OFLOW (maintained by cyparam()) + * CS_RTS_IFLOW = CRTS_IFLOW (maintained by cyparam()) + * TS_FLUSH is not used. + * XXX I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON. + * XXX CS_*FLOW should be CF_*FLOW in com->flags (control flags not state). + */ +#define CS_BUSY 0x80 /* output in progress */ +#define CS_TTGO 0x40 /* output not stopped by XOFF */ +#define CS_ODEVREADY 0x20 /* external device h/w ready (CTS) */ +#define CS_CHECKMSR 1 /* check of MSR scheduled */ +#define CS_CTS_OFLOW 2 /* use CTS output flow control */ +#define CS_ODONE 4 /* output completed */ +#define CS_RTS_IFLOW 8 /* use RTS input flow control */ +#define CSE_ODONE 1 /* output transmitted */ + +static char const * const error_desc[] = { +#define CE_OVERRUN 0 + "silo overflow", +#define CE_INTERRUPT_BUF_OVERFLOW 1 + "interrupt-level buffer overflow", +#define CE_TTY_BUF_OVERFLOW 2 + "tty-level buffer overflow", +}; + +#define CE_NTYPES 3 +#define CE_RECORD(com, errnum) (++(com)->delta_error_counts[errnum]) + +#ifdef SMP +#define COM_LOCK() mtx_lock_spin(&cy_lock) +#define COM_UNLOCK() mtx_unlock_spin(&cy_lock) +#else +#define COM_LOCK() +#define COM_UNLOCK() +#endif + +/* types. XXX - should be elsewhere */ +typedef u_char bool_t; /* boolean */ + +/* queue of linear buffers */ +struct lbq { + u_char *l_head; /* next char to process */ + u_char *l_tail; /* one past the last char to process */ + struct lbq *l_next; /* next in queue */ + bool_t l_queued; /* nonzero if queued */ +}; + +/* com device structure */ +struct com_s { + u_char state; /* miscellaneous flag bits */ + u_char etc; /* pending Embedded Transmit Command */ + u_char extra_state; /* more flag bits, separate for order trick */ + u_char gfrcr_image; /* copy of value read from GFRCR */ + u_char mcr_dtr; /* MCR bit that is wired to DTR */ + u_char mcr_image; /* copy of value written to MCR */ + u_char mcr_rts; /* MCR bit that is wired to RTS */ + int unit; /* unit number */ + + /* + * The high level of the driver never reads status registers directly + * because there would be too many side effects to handle conveniently. + * Instead, it reads copies of the registers stored here by the + * interrupt handler. + */ + u_char last_modem_status; /* last MSR read by intr handler */ + u_char prev_modem_status; /* last MSR handled by high level */ + + u_char *ibuf; /* start of input buffer */ + u_char *ibufend; /* end of input buffer */ + u_char *ibufold; /* old input buffer, to be freed */ + u_char *ihighwater; /* threshold in input buffer */ + u_char *iptr; /* next free spot in input buffer */ + int ibufsize; /* size of ibuf (not include error bytes) */ + int ierroff; /* offset of error bytes in ibuf */ + + struct lbq obufq; /* head of queue of output buffers */ + struct lbq obufs[2]; /* output buffers */ + + int cy_align; /* index for register alignment */ + cy_addr cy_iobase; /* base address of this port's cyclom */ + cy_addr iobase; /* base address of this port's cd1400 */ + int mcr_rts_reg; /* cd1400 reg number of reg holding mcr_rts */ + + struct tty *tp; /* cross reference */ + + u_long bytes_in; /* statistics */ + u_long bytes_out; + u_int delta_error_counts[CE_NTYPES]; + u_long error_counts[CE_NTYPES]; + + u_int recv_exception; /* exception chars received */ + u_int mdm; /* modem signal changes */ +#ifdef CyDebug + u_int start_count; /* no. of calls to cystart() */ + u_int start_real; /* no. of calls that did something */ +#endif + u_char car; /* CD1400 CAR shadow (if first unit in cd) */ + u_char channel_control;/* CD1400 CCR control command shadow */ + u_char cor[3]; /* CD1400 COR1-3 shadows */ + u_char intr_enable; /* CD1400 SRER shadow */ + + /* + * Data area for output buffers. Someday we should build the output + * buffer queue without copying data. + */ + u_char obuf1[256]; + u_char obuf2[256]; +}; + +devclass_t cy_devclass; +char cy_driver_name[] = "cy"; + +static void cd1400_channel_cmd(struct com_s *com, int cmd); +static void cd1400_channel_cmd_wait(struct com_s *com); +static void cd_etc(struct com_s *com, int etc); +static int cd_getreg(struct com_s *com, int reg); +static void cd_setreg(struct com_s *com, int reg, int val); +static void cyinput(struct com_s *com); +static int cyparam(struct tty *tp, struct termios *t); +static void cypoll(void *arg); +static void cysettimeout(void); +static int cysetwater(struct com_s *com, speed_t speed); +static int cyspeed(speed_t speed, u_long cy_clock, int *prescaler_io); +static void cystart(struct tty *tp); +static void comstop(struct tty *tp, int rw); +static timeout_t cywakeup; +static void disc_optim(struct tty *tp, struct termios *t, + struct com_s *com); + +static t_break_t cybreak; +static t_modem_t cymodem; +static t_open_t cyopen; +static t_close_t cyclose; + +#ifdef CyDebug +void cystatus(int unit); +#endif + +static struct mtx cy_lock; +static int cy_inited; + +/* table and macro for fast conversion from a unit number to its com struct */ +static struct com_s *p_cy_addr[NPORTS]; +#define cy_addr(unit) (p_cy_addr[unit]) + +static u_int cy_events; /* input chars + weighted output completions */ +static void *cy_fast_ih; +static void *cy_slow_ih; +static int cy_timeout; +static int cy_timeouts_until_log; +static struct callout_handle cy_timeout_handle + = CALLOUT_HANDLE_INITIALIZER(&cy_timeout_handle); + +#ifdef CyDebug +static u_int cd_inbs; +static u_int cy_inbs; +static u_int cd_outbs; +static u_int cy_outbs; +static u_int cy_svrr_probes; +static u_int cy_timeouts; +#endif + +static int cy_chip_offset[] = { + 0x0000, 0x0400, 0x0800, 0x0c00, 0x0200, 0x0600, 0x0a00, 0x0e00, +}; +static int cy_nr_cd1400s[NCY]; +static int cy_total_devices; +#undef RxFifoThreshold +static int volatile RxFifoThreshold = (CD1400_RX_FIFO_SIZE / 2); + +int +cy_units(cy_addr cy_iobase, int cy_align) +{ + int cyu; + u_char firmware_version; + int i; + cy_addr iobase; + + for (cyu = 0; cyu < CY_MAX_CD1400s; ++cyu) { + iobase = cy_iobase + (cy_chip_offset[cyu] << cy_align); + + /* wait for chip to become ready for new command */ + for (i = 0; i < 10; i++) { + DELAY(50); + if (!cd_inb(iobase, CD1400_CCR, cy_align)) + break; + } + + /* clear the GFRCR register */ + cd_outb(iobase, CD1400_GFRCR, cy_align, 0); + + /* issue a reset command */ + cd_outb(iobase, CD1400_CCR, cy_align, + CD1400_CCR_CMDRESET | CD1400_CCR_FULLRESET); + + /* XXX bogus initialization to avoid a gcc bug/warning. */ + firmware_version = 0; + + /* wait for the CD1400 to initialize itself */ + for (i = 0; i < 200; i++) { + DELAY(50); + + /* retrieve firmware version */ + firmware_version = cd_inb(iobase, CD1400_GFRCR, + cy_align); + if ((firmware_version & 0xf0) == 0x40) + break; + } + + /* + * Anything in the 0x40-0x4F range is fine. + * If one CD1400 is bad then we don't support higher + * numbered good ones on this board. + */ + if ((firmware_version & 0xf0) != 0x40) + break; + } + return (cyu); +} + +void * +cyattach_common(cy_addr cy_iobase, int cy_align) +{ + int adapter; + int cyu; + u_char firmware_version; + cy_addr iobase; + int ncyu; + int unit; + struct tty *tp; + + while (cy_inited != 2) + if (atomic_cmpset_int(&cy_inited, 0, 1)) { + mtx_init(&cy_lock, cy_driver_name, NULL, MTX_SPIN); + atomic_store_rel_int(&cy_inited, 2); + } + + adapter = cy_total_devices; + if ((u_int)adapter >= NCY) { + printf( + "cy%d: can't attach adapter: insufficient cy devices configured\n", + adapter); + return (NULL); + } + ncyu = cy_units(cy_iobase, cy_align); + if (ncyu == 0) + return (NULL); + cy_nr_cd1400s[adapter] = ncyu; + cy_total_devices++; + + unit = adapter * CY_MAX_PORTS; + for (cyu = 0; cyu < ncyu; ++cyu) { + int cdu; + + iobase = (cy_addr) (cy_iobase + + (cy_chip_offset[cyu] << cy_align)); + firmware_version = cd_inb(iobase, CD1400_GFRCR, cy_align); + + /* Set up a receive timeout period of than 1+ ms. */ + cd_outb(iobase, CD1400_PPR, cy_align, + howmany(CY_CLOCK(firmware_version) + / CD1400_PPR_PRESCALER, 1000)); + + for (cdu = 0; cdu < CD1400_NO_OF_CHANNELS; ++cdu, ++unit) { + struct com_s *com; + int s; + + com = malloc(sizeof *com, M_DEVBUF, M_NOWAIT | M_ZERO); + if (com == NULL) + break; + com->unit = unit; + com->gfrcr_image = firmware_version; + if (CY_RTS_DTR_SWAPPED(firmware_version)) { + com->mcr_dtr = CD1400_MSVR1_RTS; + com->mcr_rts = CD1400_MSVR2_DTR; + com->mcr_rts_reg = CD1400_MSVR2; + } else { + com->mcr_dtr = CD1400_MSVR2_DTR; + com->mcr_rts = CD1400_MSVR1_RTS; + com->mcr_rts_reg = CD1400_MSVR1; + } + com->obufs[0].l_head = com->obuf1; + com->obufs[1].l_head = com->obuf2; + + com->cy_align = cy_align; + com->cy_iobase = cy_iobase; + com->iobase = iobase; + com->car = ~CD1400_CAR_CHAN; + + tp = com->tp = ttyalloc(); + tp->t_open = cyopen; + tp->t_close = cyclose; + tp->t_oproc = cystart; + tp->t_stop = comstop; + tp->t_param = cyparam; + tp->t_break = cybreak; + tp->t_modem = cymodem; + tp->t_sc = com; + + if (cysetwater(com, tp->t_init_in.c_ispeed) != 0) { + free(com, M_DEVBUF); + return (NULL); + } + + s = spltty(); + cy_addr(unit) = com; + splx(s); + + if (cy_fast_ih == NULL) { + swi_add(&tty_intr_event, "cy", cypoll, NULL, SWI_TTY, 0, + &cy_fast_ih); + swi_add(&clk_intr_event, "cy", cypoll, NULL, SWI_CLOCK, 0, + &cy_slow_ih); + } + ttycreate(tp, TS_CALLOUT, "c%r%r", + adapter, unit % CY_MAX_PORTS); + } + } + + /* ensure an edge for the next interrupt */ + cy_outb(cy_iobase, CY_CLEAR_INTR, cy_align, 0); + + return (cy_addr(adapter * CY_MAX_PORTS)); +} + +static int +cyopen(struct tty *tp, struct cdev *dev) +{ + struct com_s *com; + int s; + + com = tp->t_sc; + s = spltty(); + /* + * We jump to this label after all non-interrupted sleeps to pick + * up any changes of the device state. + */ + + /* Encode per-board unit in LIVR for access in intr routines. */ + cd_setreg(com, CD1400_LIVR, + (com->unit & CD1400_xIVR_CHAN) << CD1400_xIVR_CHAN_SHIFT); + + /* + * Flush fifos. This requires a full channel reset which + * also disables the transmitter and receiver. Recover + * from this. + */ + cd1400_channel_cmd(com, + CD1400_CCR_CMDRESET | CD1400_CCR_CHANRESET); + cd1400_channel_cmd(com, com->channel_control); + + critical_enter(); + COM_LOCK(); + com->prev_modem_status = com->last_modem_status + = cd_getreg(com, CD1400_MSVR2); + cd_setreg(com, CD1400_SRER, + com->intr_enable + = CD1400_SRER_MDMCH | CD1400_SRER_RXDATA); + COM_UNLOCK(); + critical_exit(); + cysettimeout(); + return (0); +} + + +static void +cyclose(struct tty *tp) +{ + cy_addr iobase; + struct com_s *com; + int s; + int unit; + + com = tp->t_sc; + unit = com->unit; + iobase = com->iobase; + s = spltty(); + /* XXX */ + critical_enter(); + COM_LOCK(); + com->etc = ETC_NONE; + cd_setreg(com, CD1400_COR2, com->cor[1] &= ~CD1400_COR2_ETC); + COM_UNLOCK(); + critical_exit(); + cd_etc(com, CD1400_ETC_STOPBREAK); + cd1400_channel_cmd(com, CD1400_CCR_CMDRESET | CD1400_CCR_FTF); + + { + critical_enter(); + COM_LOCK(); + cd_setreg(com, CD1400_SRER, com->intr_enable = 0); + COM_UNLOCK(); + critical_exit(); + tp = com->tp; + if ((tp->t_cflag & HUPCL) + /* + * XXX we will miss any carrier drop between here and the + * next open. Perhaps we should watch DCD even when the + * port is closed; it is not sufficient to check it at + * the next open because it might go up and down while + * we're not watching. + */ + || (!tp->t_actout + && !(com->prev_modem_status & CD1400_MSVR2_CD) + && !(tp->t_init_in.c_cflag & CLOCAL)) + || !(tp->t_state & TS_ISOPEN)) { + (void)cymodem(tp, 0, SER_DTR); + + /* Disable receiver (leave transmitter enabled). */ + com->channel_control = CD1400_CCR_CMDCHANCTL + | CD1400_CCR_XMTEN + | CD1400_CCR_RCVDIS; + cd1400_channel_cmd(com, com->channel_control); + + ttydtrwaitstart(tp); + } + } + tp->t_actout = FALSE; + wakeup(&tp->t_actout); + wakeup(TSA_CARR_ON(tp)); /* restart any wopeners */ + splx(s); +} + +/* + * This function: + * a) needs to be called with COM_LOCK() held, and + * b) needs to return with COM_LOCK() held. + */ +static void +cyinput(struct com_s *com) +{ + u_char *buf; + int incc; + u_char line_status; + int recv_data; + struct tty *tp; + + buf = com->ibuf; + tp = com->tp; + if (!(tp->t_state & TS_ISOPEN)) { + cy_events -= (com->iptr - com->ibuf); + com->iptr = com->ibuf; + return; + } + if (tp->t_state & TS_CAN_BYPASS_L_RINT) { + /* + * Avoid the grotesquely inefficient lineswitch routine + * (ttyinput) in "raw" mode. It usually takes about 450 + * instructions (that's without canonical processing or echo!). + * slinput is reasonably fast (usually 40 instructions plus + * call overhead). + */ + + do { + /* + * This may look odd, but it is using save-and-enable + * semantics instead of the save-and-disable semantics + * that are used everywhere else. + */ + COM_UNLOCK(); + critical_exit(); + incc = com->iptr - buf; + if (tp->t_rawq.c_cc + incc > tp->t_ihiwat + && (com->state & CS_RTS_IFLOW + || tp->t_iflag & IXOFF) + && !(tp->t_state & TS_TBLOCK)) + ttyblock(tp); + com->delta_error_counts[CE_TTY_BUF_OVERFLOW] + += b_to_q((char *)buf, incc, &tp->t_rawq); + buf += incc; + tk_nin += incc; + tk_rawcc += incc; + tp->t_rawcc += incc; + ttwakeup(tp); + if (tp->t_state & TS_TTSTOP + && (tp->t_iflag & IXANY + || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { + tp->t_state &= ~TS_TTSTOP; + tp->t_lflag &= ~FLUSHO; + cystart(tp); + } + critical_enter(); + COM_LOCK(); + } while (buf < com->iptr); + } else { + do { + /* + * This may look odd, but it is using save-and-enable + * semantics instead of the save-and-disable semantics + * that are used everywhere else. + */ + COM_UNLOCK(); + critical_exit(); + line_status = buf[com->ierroff]; + recv_data = *buf++; + if (line_status + & (CD1400_RDSR_BREAK | CD1400_RDSR_FE | CD1400_RDSR_OE | CD1400_RDSR_PE)) { + if (line_status & CD1400_RDSR_BREAK) + recv_data |= TTY_BI; + if (line_status & CD1400_RDSR_FE) + recv_data |= TTY_FE; + if (line_status & CD1400_RDSR_OE) + recv_data |= TTY_OE; + if (line_status & CD1400_RDSR_PE) + recv_data |= TTY_PE; + } + ttyld_rint(tp, recv_data); + critical_enter(); + COM_LOCK(); + } while (buf < com->iptr); + } + cy_events -= (com->iptr - com->ibuf); + com->iptr = com->ibuf; + + /* + * There is now room for another low-level buffer full of input, + * so enable RTS if it is now disabled and there is room in the + * high-level buffer. + */ + if ((com->state & CS_RTS_IFLOW) && !(com->mcr_image & com->mcr_rts) && + !(tp->t_state & TS_TBLOCK)) + cd_setreg(com, com->mcr_rts_reg, + com->mcr_image |= com->mcr_rts); +} + +int +cyintr(void *vcom) +{ + struct com_s *basecom; + int baseu; + int cy_align; + cy_addr cy_iobase; + int cyu; + cy_addr iobase; + u_char status; + int unit; + + COM_LOCK(); /* XXX could this be placed down lower in the loop? */ + + basecom = (struct com_s *)vcom; + baseu = basecom->unit; + cy_align = basecom->cy_align; + cy_iobase = basecom->cy_iobase; + unit = baseu / CY_MAX_PORTS; + + /* check each CD1400 in turn */ + for (cyu = 0; cyu < cy_nr_cd1400s[unit]; ++cyu) { + iobase = (cy_addr) (cy_iobase + + (cy_chip_offset[cyu] << cy_align)); + /* poll to see if it has any work */ + status = cd_inb(iobase, CD1400_SVRR, cy_align); + if (status == 0) + continue; // XXX - FILTER_STRAY? +#ifdef CyDebug + ++cy_svrr_probes; +#endif + /* service requests as appropriate, giving priority to RX */ + if (status & CD1400_SVRR_RXRDY) { + struct com_s *com; + u_int count; + u_char *ioptr; + u_char line_status; + u_char recv_data; + u_char serv_type; +#ifdef PollMode + u_char save_rir; +#endif + +#ifdef PollMode + save_rir = cd_inb(iobase, CD1400_RIR, cy_align); + + /* enter rx service */ + cd_outb(iobase, CD1400_CAR, cy_align, save_rir); + cy_addr(baseu + cyu * CD1400_NO_OF_CHANNELS)->car + = save_rir & CD1400_CAR_CHAN; + + serv_type = cd_inb(iobase, CD1400_RIVR, cy_align); + com = cy_addr(baseu + + ((serv_type >> CD1400_xIVR_CHAN_SHIFT) + & CD1400_xIVR_CHAN)); +#else + /* ack receive service */ + serv_type = cy_inb(iobase, CY8_SVCACKR, cy_align); + + com = cy_addr(baseu + + + ((serv_type >> CD1400_xIVR_CHAN_SHIFT) + & CD1400_xIVR_CHAN)); +#endif + + if (serv_type & CD1400_RIVR_EXCEPTION) { + ++com->recv_exception; + line_status = cd_inb(iobase, CD1400_RDSR, cy_align); + /* break/unnattached error bits or real input? */ + recv_data = cd_inb(iobase, CD1400_RDSR, cy_align); +#ifndef SOFT_HOTCHAR + if (line_status & CD1400_RDSR_SPECIAL + && com->tp->t_hotchar != 0) + swi_sched(cy_fast_ih, 0); + +#endif +#if 1 /* XXX "intelligent" PFO error handling would break O error handling */ + if (line_status & (CD1400_RDSR_PE|CD1400_RDSR_FE|CD1400_RDSR_BREAK)) { + /* + Don't store PE if IGNPAR and BI if IGNBRK, + this hack allows "raw" tty optimization + works even if IGN* is set. + */ + if ( com->tp == NULL + || !(com->tp->t_state & TS_ISOPEN) + || ((line_status & (CD1400_RDSR_PE|CD1400_RDSR_FE)) + && (com->tp->t_iflag & IGNPAR)) + || ((line_status & CD1400_RDSR_BREAK) + && (com->tp->t_iflag & IGNBRK))) + goto cont; + if ( (line_status & (CD1400_RDSR_PE|CD1400_RDSR_FE)) + && (com->tp->t_state & TS_CAN_BYPASS_L_RINT) + && ((line_status & CD1400_RDSR_FE) + || ((line_status & CD1400_RDSR_PE) + && (com->tp->t_iflag & INPCK)))) + recv_data = 0; + } +#endif /* 1 */ + ++com->bytes_in; +#ifdef SOFT_HOTCHAR + if (com->tp->t_hotchar != 0 && recv_data == com->tp->t_hotchar) + swi_sched(cy_fast_ih, 0); +#endif + ioptr = com->iptr; + if (ioptr >= com->ibufend) + CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW); + else { + if (com->tp != NULL && com->tp->t_do_timestamp) + microtime(&com->tp->t_timestamp); + ++cy_events; + ioptr[0] = recv_data; + ioptr[com->ierroff] = line_status; + com->iptr = ++ioptr; + if (ioptr == com->ihighwater + && com->state & CS_RTS_IFLOW) + cd_outb(iobase, com->mcr_rts_reg, + cy_align, + com->mcr_image &= + ~com->mcr_rts); + if (line_status & CD1400_RDSR_OE) + CE_RECORD(com, CE_OVERRUN); + } + goto cont; + } else { + int ifree; + + count = cd_inb(iobase, CD1400_RDCR, cy_align); + if (!count) + goto cont; + com->bytes_in += count; + ioptr = com->iptr; + ifree = com->ibufend - ioptr; + if (count > ifree) { + count -= ifree; + cy_events += ifree; + if (ifree != 0) { + if (com->tp != NULL && com->tp->t_do_timestamp) + microtime(&com->tp->t_timestamp); + do { + recv_data = cd_inb(iobase, + CD1400_RDSR, + cy_align); +#ifdef SOFT_HOTCHAR + if (com->tp->t_hotchar != 0 + && recv_data + == com->tp->t_hotchar) + swi_sched(cy_fast_ih, + 0); +#endif + ioptr[0] = recv_data; + ioptr[com->ierroff] = 0; + ++ioptr; + } while (--ifree != 0); + } + com->delta_error_counts + [CE_INTERRUPT_BUF_OVERFLOW] += count; + do { + recv_data = cd_inb(iobase, CD1400_RDSR, + cy_align); +#ifdef SOFT_HOTCHAR + if (com->tp->t_hotchar != 0 + && recv_data == com->tp->t_hotchar) + swi_sched(cy_fast_ih, 0); +#endif + } while (--count != 0); + } else { + if (com->tp != NULL && com->tp->t_do_timestamp) + microtime(&com->tp->t_timestamp); + if (ioptr <= com->ihighwater + && ioptr + count > com->ihighwater + && com->state & CS_RTS_IFLOW) + cd_outb(iobase, com->mcr_rts_reg, + cy_align, + com->mcr_image + &= ~com->mcr_rts); + cy_events += count; + do { + recv_data = cd_inb(iobase, CD1400_RDSR, + cy_align); +#ifdef SOFT_HOTCHAR + if (com->tp->t_hotchar != 0 + && recv_data == com->tp->t_hotchar) + swi_sched(cy_fast_ih, 0); +#endif + ioptr[0] = recv_data; + ioptr[com->ierroff] = 0; + ++ioptr; + } while (--count != 0); + } + com->iptr = ioptr; + } +cont: + + /* terminate service context */ +#ifdef PollMode + cd_outb(iobase, CD1400_RIR, cy_align, + save_rir + & ~(CD1400_RIR_RDIREQ | CD1400_RIR_RBUSY)); +#else + cd_outb(iobase, CD1400_EOSRR, cy_align, 0); +#endif + } + if (status & CD1400_SVRR_MDMCH) { + struct com_s *com; + u_char modem_status; +#ifdef PollMode + u_char save_mir; +#else + u_char vector; +#endif + +#ifdef PollMode + save_mir = cd_inb(iobase, CD1400_MIR, cy_align); + + /* enter modem service */ + cd_outb(iobase, CD1400_CAR, cy_align, save_mir); + cy_addr(baseu + cyu * CD1400_NO_OF_CHANNELS)->car + = save_mir & CD1400_CAR_CHAN; + + com = cy_addr(baseu + cyu * CD1400_NO_OF_CHANNELS + + (save_mir & CD1400_MIR_CHAN)); +#else + /* ack modem service */ + vector = cy_inb(iobase, CY8_SVCACKM, cy_align); + + com = cy_addr(baseu + + ((vector >> CD1400_xIVR_CHAN_SHIFT) + & CD1400_xIVR_CHAN)); +#endif + ++com->mdm; + modem_status = cd_inb(iobase, CD1400_MSVR2, cy_align); + if (modem_status != com->last_modem_status) { + /* + * Schedule high level to handle DCD changes. Note + * that we don't use the delta bits anywhere. Some + * UARTs mess them up, and it's easy to remember the + * previous bits and calculate the delta. + */ + com->last_modem_status = modem_status; + if (!(com->state & CS_CHECKMSR)) { + cy_events += LOTS_OF_EVENTS; + com->state |= CS_CHECKMSR; + swi_sched(cy_fast_ih, 0); + } + +#ifdef SOFT_CTS_OFLOW + /* handle CTS change immediately for crisp flow ctl */ + if (com->state & CS_CTS_OFLOW) { + if (modem_status & CD1400_MSVR2_CTS) { + com->state |= CS_ODEVREADY; + if (com->state >= (CS_BUSY | CS_TTGO + | CS_ODEVREADY) + && !(com->intr_enable + & CD1400_SRER_TXRDY)) + cd_outb(iobase, CD1400_SRER, + cy_align, + com->intr_enable + = com->intr_enable + & ~CD1400_SRER_TXMPTY + | CD1400_SRER_TXRDY); + } else { + com->state &= ~CS_ODEVREADY; + if (com->intr_enable + & CD1400_SRER_TXRDY) + cd_outb(iobase, CD1400_SRER, + cy_align, + com->intr_enable + = com->intr_enable + & ~CD1400_SRER_TXRDY + | CD1400_SRER_TXMPTY); + } + } +#endif + } + + /* terminate service context */ +#ifdef PollMode + cd_outb(iobase, CD1400_MIR, cy_align, + save_mir + & ~(CD1400_MIR_RDIREQ | CD1400_MIR_RBUSY)); +#else + cd_outb(iobase, CD1400_EOSRR, cy_align, 0); +#endif + } + if (status & CD1400_SVRR_TXRDY) { + struct com_s *com; +#ifdef PollMode + u_char save_tir; +#else + u_char vector; +#endif + +#ifdef PollMode + save_tir = cd_inb(iobase, CD1400_TIR, cy_align); + + /* enter tx service */ + cd_outb(iobase, CD1400_CAR, cy_align, save_tir); + cy_addr(baseu + cyu * CD1400_NO_OF_CHANNELS)->car + = save_tir & CD1400_CAR_CHAN; + + com = cy_addr(baseu + + cyu * CD1400_NO_OF_CHANNELS + + (save_tir & CD1400_TIR_CHAN)); +#else + /* ack transmit service */ + vector = cy_inb(iobase, CY8_SVCACKT, cy_align); + + com = cy_addr(baseu + + ((vector >> CD1400_xIVR_CHAN_SHIFT) + & CD1400_xIVR_CHAN)); +#endif + + if (com->etc != ETC_NONE) { + if (com->intr_enable & CD1400_SRER_TXRDY) { + /* + * Here due to sloppy SRER_TXRDY + * enabling. Ignore. Come back when + * tx is empty. + */ + cd_outb(iobase, CD1400_SRER, cy_align, + com->intr_enable + = (com->intr_enable + & ~CD1400_SRER_TXRDY) + | CD1400_SRER_TXMPTY); + goto terminate_tx_service; + } + switch (com->etc) { + case CD1400_ETC_SENDBREAK: + case CD1400_ETC_STOPBREAK: + /* + * Start the command. Come back on + * next tx empty interrupt, hopefully + * after command has been executed. + */ + cd_outb(iobase, CD1400_COR2, cy_align, + com->cor[1] |= CD1400_COR2_ETC); + cd_outb(iobase, CD1400_TDR, cy_align, + CD1400_ETC_CMD); + cd_outb(iobase, CD1400_TDR, cy_align, + com->etc); + if (com->etc == CD1400_ETC_SENDBREAK) + com->etc = ETC_BREAK_STARTING; + else + com->etc = ETC_BREAK_ENDING; + goto terminate_tx_service; + case ETC_BREAK_STARTING: + /* + * BREAK is now on. Continue with + * SRER_TXMPTY processing, hopefully + * don't come back. + */ + com->etc = ETC_BREAK_STARTED; + break; + case ETC_BREAK_STARTED: + /* + * Came back due to sloppy SRER_TXMPTY + * enabling. Hope again. + */ + break; + case ETC_BREAK_ENDING: + /* + * BREAK is now off. Continue with + * SRER_TXMPTY processing and don't + * come back. The SWI handler will + * restart tx interrupts if necessary. + */ + cd_outb(iobase, CD1400_COR2, cy_align, + com->cor[1] + &= ~CD1400_COR2_ETC); + com->etc = ETC_BREAK_ENDED; + if (!(com->state & CS_ODONE)) { + cy_events += LOTS_OF_EVENTS; + com->state |= CS_ODONE; + swi_sched(cy_fast_ih, 0); + } + break; + case ETC_BREAK_ENDED: + /* + * Shouldn't get here. Hope again. + */ + break; + } + } + if (com->intr_enable & CD1400_SRER_TXMPTY) { + if (!(com->extra_state & CSE_ODONE)) { + cy_events += LOTS_OF_EVENTS; + com->extra_state |= CSE_ODONE; + swi_sched(cy_fast_ih, 0); + } + cd_outb(iobase, CD1400_SRER, cy_align, + com->intr_enable + &= ~CD1400_SRER_TXMPTY); + goto terminate_tx_service; + } + if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) { + u_char *ioptr; + u_int ocount; + + ioptr = com->obufq.l_head; + ocount = com->obufq.l_tail - ioptr; + if (ocount > CD1400_TX_FIFO_SIZE) + ocount = CD1400_TX_FIFO_SIZE; + com->bytes_out += ocount; + do + cd_outb(iobase, CD1400_TDR, cy_align, + *ioptr++); + while (--ocount != 0); + com->obufq.l_head = ioptr; + if (ioptr >= com->obufq.l_tail) { + struct lbq *qp; + + qp = com->obufq.l_next; + qp->l_queued = FALSE; + qp = qp->l_next; + if (qp != NULL) { + com->obufq.l_head = qp->l_head; + com->obufq.l_tail = qp->l_tail; + com->obufq.l_next = qp; + } else { + /* output just completed */ + com->state &= ~CS_BUSY; + + /* + * The setting of CSE_ODONE may be + * stale here. We currently only + * use it when CS_BUSY is set, and + * fixing it when we clear CS_BUSY + * is easiest. + */ + if (com->extra_state & CSE_ODONE) { + cy_events -= LOTS_OF_EVENTS; + com->extra_state &= ~CSE_ODONE; + } + + cd_outb(iobase, CD1400_SRER, cy_align, + com->intr_enable + = (com->intr_enable + & ~CD1400_SRER_TXRDY) + | CD1400_SRER_TXMPTY); + } + if (!(com->state & CS_ODONE)) { + cy_events += LOTS_OF_EVENTS; + com->state |= CS_ODONE; + + /* handle at high level ASAP */ + swi_sched(cy_fast_ih, 0); + } + } + } + + /* terminate service context */ +terminate_tx_service: +#ifdef PollMode + cd_outb(iobase, CD1400_TIR, cy_align, + save_tir + & ~(CD1400_TIR_RDIREQ | CD1400_TIR_RBUSY)); +#else + cd_outb(iobase, CD1400_EOSRR, cy_align, 0); +#endif + } + } + + /* ensure an edge for the next interrupt */ + cy_outb(cy_iobase, CY_CLEAR_INTR, cy_align, 0); + + swi_sched(cy_slow_ih, SWI_DELAY); + + COM_UNLOCK(); + return (FILTER_HANDLED); +} + +static void +cybreak(struct tty *tp, int sig) +{ + struct com_s *com; + + com = tp->t_sc; + if (sig) + cd_etc(com, CD1400_ETC_SENDBREAK); + else + cd_etc(com, CD1400_ETC_STOPBREAK); +} + +static void +cypoll(void *arg) +{ + int unit; + +#ifdef CyDebug + ++cy_timeouts; +#endif + if (cy_events == 0) + return; +repeat: + for (unit = 0; unit < NPORTS; ++unit) { + struct com_s *com; + int incc; + struct tty *tp; + + com = cy_addr(unit); + if (com == NULL) + continue; + tp = com->tp; + if (tp == NULL) { + /* + * XXX forget any events related to closed devices + * (actually never opened devices) so that we don't + * loop. + */ + critical_enter(); + COM_LOCK(); + incc = com->iptr - com->ibuf; + com->iptr = com->ibuf; + if (com->state & CS_CHECKMSR) { + incc += LOTS_OF_EVENTS; + com->state &= ~CS_CHECKMSR; + } + cy_events -= incc; + COM_UNLOCK(); + critical_exit(); + if (incc != 0) + log(LOG_DEBUG, + "cy%d: %d events for device with no tp\n", + unit, incc); + continue; + } + if (com->iptr != com->ibuf) { + critical_enter(); + COM_LOCK(); + cyinput(com); + COM_UNLOCK(); + critical_exit(); + } + if (com->state & CS_CHECKMSR) { + u_char delta_modem_status; + + critical_enter(); + COM_LOCK(); + cyinput(com); + delta_modem_status = com->last_modem_status + ^ com->prev_modem_status; + com->prev_modem_status = com->last_modem_status; + cy_events -= LOTS_OF_EVENTS; + com->state &= ~CS_CHECKMSR; + COM_UNLOCK(); + critical_exit(); + if (delta_modem_status & CD1400_MSVR2_CD) + ttyld_modem(tp, + com->prev_modem_status & CD1400_MSVR2_CD); + } + if (com->extra_state & CSE_ODONE) { + critical_enter(); + COM_LOCK(); + cy_events -= LOTS_OF_EVENTS; + com->extra_state &= ~CSE_ODONE; + COM_UNLOCK(); + critical_exit(); + if (!(com->state & CS_BUSY)) { + tp->t_state &= ~TS_BUSY; + ttwwakeup(com->tp); + } + if (com->etc != ETC_NONE) { + if (com->etc == ETC_BREAK_ENDED) + com->etc = ETC_NONE; + wakeup(&com->etc); + } + } + if (com->state & CS_ODONE) { + critical_enter(); + COM_LOCK(); + cy_events -= LOTS_OF_EVENTS; + com->state &= ~CS_ODONE; + COM_UNLOCK(); + critical_exit(); + ttyld_start(tp); + } + if (cy_events == 0) + break; + } + if (cy_events >= LOTS_OF_EVENTS) + goto repeat; +} + +static int +cyparam(struct tty *tp, struct termios *t) +{ + int bits; + int cflag; + struct com_s *com; + u_char cor_change; + u_long cy_clock; + int idivisor; + int iflag; + int iprescaler; + int itimeout; + int odivisor; + int oprescaler; + u_char opt; + int s; + + com = tp->t_sc; + + /* check requested parameters */ + cy_clock = CY_CLOCK(com->gfrcr_image); + idivisor = cyspeed(t->c_ispeed, cy_clock, &iprescaler); + if (idivisor <= 0) + return (EINVAL); + odivisor = cyspeed(t->c_ospeed != 0 ? t->c_ospeed : tp->t_ospeed, + cy_clock, &oprescaler); + if (odivisor <= 0) + return (EINVAL); + + /* parameters are OK, convert them to the com struct and the device */ + s = spltty(); + if (t->c_ospeed == 0) + (void)cymodem(tp, 0, SER_DTR); + else + (void)cymodem(tp, SER_DTR, 0); + + (void) cysetwater(com, t->c_ispeed); + + /* XXX we don't actually change the speed atomically. */ + + cd_setreg(com, CD1400_RBPR, idivisor); + cd_setreg(com, CD1400_RCOR, iprescaler); + cd_setreg(com, CD1400_TBPR, odivisor); + cd_setreg(com, CD1400_TCOR, oprescaler); + + /* + * channel control + * receiver enable + * transmitter enable (always set) + */ + cflag = t->c_cflag; + opt = CD1400_CCR_CMDCHANCTL | CD1400_CCR_XMTEN + | (cflag & CREAD ? CD1400_CCR_RCVEN : CD1400_CCR_RCVDIS); + if (opt != com->channel_control) { + com->channel_control = opt; + cd1400_channel_cmd(com, opt); + } + +#ifdef Smarts + /* set special chars */ + /* XXX if one is _POSIX_VDISABLE, can't use some others */ + if (t->c_cc[VSTOP] != _POSIX_VDISABLE) + cd_setreg(com, CD1400_SCHR1, t->c_cc[VSTOP]); + if (t->c_cc[VSTART] != _POSIX_VDISABLE) + cd_setreg(com, CD1400_SCHR2, t->c_cc[VSTART]); + if (t->c_cc[VINTR] != _POSIX_VDISABLE) + cd_setreg(com, CD1400_SCHR3, t->c_cc[VINTR]); + if (t->c_cc[VSUSP] != _POSIX_VDISABLE) + cd_setreg(com, CD1400_SCHR4, t->c_cc[VSUSP]); +#endif + + /* + * set channel option register 1 - + * parity mode + * stop bits + * char length + */ + opt = 0; + /* parity */ + if (cflag & PARENB) { + if (cflag & PARODD) + opt |= CD1400_COR1_PARODD; + opt |= CD1400_COR1_PARNORMAL; + } + iflag = t->c_iflag; + if (!(iflag & INPCK)) + opt |= CD1400_COR1_NOINPCK; + bits = 1 + 1; + /* stop bits */ + if (cflag & CSTOPB) { + ++bits; + opt |= CD1400_COR1_STOP2; + } + /* char length */ + switch (cflag & CSIZE) { + case CS5: + bits += 5; + opt |= CD1400_COR1_CS5; + break; + case CS6: + bits += 6; + opt |= CD1400_COR1_CS6; + break; + case CS7: + bits += 7; + opt |= CD1400_COR1_CS7; + break; + default: + bits += 8; + opt |= CD1400_COR1_CS8; + break; + } + cor_change = 0; + if (opt != com->cor[0]) { + cor_change |= CD1400_CCR_COR1; + cd_setreg(com, CD1400_COR1, com->cor[0] = opt); + } + + /* + * Set receive time-out period, normally to max(one char time, 5 ms). + */ + itimeout = howmany(1000 * bits, t->c_ispeed); +#ifdef SOFT_HOTCHAR +#define MIN_RTP 1 +#else +#define MIN_RTP 5 +#endif + if (itimeout < MIN_RTP) + itimeout = MIN_RTP; + if (!(t->c_lflag & ICANON) && t->c_cc[VMIN] != 0 && t->c_cc[VTIME] != 0 + && t->c_cc[VTIME] * 10 > itimeout) + itimeout = t->c_cc[VTIME] * 10; + if (itimeout > 255) + itimeout = 255; + cd_setreg(com, CD1400_RTPR, itimeout); + + /* + * set channel option register 2 - + * flow control + */ + opt = 0; +#ifdef Smarts + if (iflag & IXANY) + opt |= CD1400_COR2_IXANY; + if (iflag & IXOFF) + opt |= CD1400_COR2_IXOFF; +#endif +#ifndef SOFT_CTS_OFLOW + if (cflag & CCTS_OFLOW) + opt |= CD1400_COR2_CCTS_OFLOW; +#endif + critical_enter(); + COM_LOCK(); + if (opt != com->cor[1]) { + cor_change |= CD1400_CCR_COR2; + cd_setreg(com, CD1400_COR2, com->cor[1] = opt); + } + COM_UNLOCK(); + critical_exit(); + + /* + * set channel option register 3 - + * receiver FIFO interrupt threshold + * flow control + */ + opt = RxFifoThreshold; +#ifdef Smarts + if (t->c_lflag & ICANON) + opt |= CD1400_COR3_SCD34; /* detect INTR & SUSP chars */ + if (iflag & IXOFF) + /* detect and transparently handle START and STOP chars */ + opt |= CD1400_COR3_FCT | CD1400_COR3_SCD12; +#endif + if (opt != com->cor[2]) { + cor_change |= CD1400_CCR_COR3; + cd_setreg(com, CD1400_COR3, com->cor[2] = opt); + } + + /* notify the CD1400 if COR1-3 have changed */ + if (cor_change) + cd1400_channel_cmd(com, CD1400_CCR_CMDCORCHG | cor_change); + + /* + * set channel option register 4 - + * CR/NL processing + * break processing + * received exception processing + */ + opt = 0; + if (iflag & IGNCR) + opt |= CD1400_COR4_IGNCR; +#ifdef Smarts + /* + * we need a new ttyinput() for this, as we don't want to + * have ICRNL && INLCR being done in both layers, or to have + * synchronisation problems + */ + if (iflag & ICRNL) + opt |= CD1400_COR4_ICRNL; + if (iflag & INLCR) + opt |= CD1400_COR4_INLCR; +#endif + if (iflag & IGNBRK) + opt |= CD1400_COR4_IGNBRK | CD1400_COR4_NOBRKINT; + /* + * The `-ignbrk -brkint parmrk' case is not handled by the hardware, + * so only tell the hardware about -brkint if -parmrk. + */ + if (!(iflag & (BRKINT | PARMRK))) + opt |= CD1400_COR4_NOBRKINT; +#if 0 + /* XXX using this "intelligence" breaks reporting of overruns. */ + if (iflag & IGNPAR) + opt |= CD1400_COR4_PFO_DISCARD; + else { + if (iflag & PARMRK) + opt |= CD1400_COR4_PFO_ESC; + else + opt |= CD1400_COR4_PFO_NUL; + } +#else + opt |= CD1400_COR4_PFO_EXCEPTION; +#endif + cd_setreg(com, CD1400_COR4, opt); + + /* + * set channel option register 5 - + */ + opt = 0; + if (iflag & ISTRIP) + opt |= CD1400_COR5_ISTRIP; + if (t->c_iflag & IEXTEN) + /* enable LNEXT (e.g. ctrl-v quoting) handling */ + opt |= CD1400_COR5_LNEXT; +#ifdef Smarts + if (t->c_oflag & ONLCR) + opt |= CD1400_COR5_ONLCR; + if (t->c_oflag & OCRNL) + opt |= CD1400_COR5_OCRNL; +#endif + cd_setreg(com, CD1400_COR5, opt); + + /* + * We always generate modem status change interrupts for CD changes. + * Among other things, this is necessary to track TS_CARR_ON for + * pstat to print even when the driver doesn't care. CD changes + * should be rare so interrupts for them are not worth extra code to + * avoid. We avoid interrupts for other modem status changes (except + * for CTS changes when SOFT_CTS_OFLOW is configured) since this is + * simplest and best. + */ + + /* + * set modem change option register 1 + * generate modem interrupts on which 1 -> 0 input transitions + * also controls auto-DTR output flow-control, which we don't use + */ + opt = CD1400_MCOR1_CDzd; +#ifdef SOFT_CTS_OFLOW + if (cflag & CCTS_OFLOW) + opt |= CD1400_MCOR1_CTSzd; +#endif + cd_setreg(com, CD1400_MCOR1, opt); + + /* + * set modem change option register 2 + * generate modem interrupts on specific 0 -> 1 input transitions + */ + opt = CD1400_MCOR2_CDod; +#ifdef SOFT_CTS_OFLOW + if (cflag & CCTS_OFLOW) + opt |= CD1400_MCOR2_CTSod; +#endif + cd_setreg(com, CD1400_MCOR2, opt); + + /* + * XXX should have done this long ago, but there is too much state + * to change all atomically. + */ + critical_enter(); + COM_LOCK(); + + com->state &= ~CS_TTGO; + if (!(tp->t_state & TS_TTSTOP)) + com->state |= CS_TTGO; + if (cflag & CRTS_IFLOW) { + com->state |= CS_RTS_IFLOW; + /* + * If CS_RTS_IFLOW just changed from off to on, the change + * needs to be propagated to CD1400_MSVR1_RTS. This isn't urgent, + * so do it later by calling cystart() instead of repeating + * a lot of code from cystart() here. + */ + } else if (com->state & CS_RTS_IFLOW) { + com->state &= ~CS_RTS_IFLOW; + /* + * CS_RTS_IFLOW just changed from on to off. Force CD1400_MSVR1_RTS + * on here, since cystart() won't do it later. + */ + cd_setreg(com, com->mcr_rts_reg, + com->mcr_image |= com->mcr_rts); + } + + /* + * Set up state to handle output flow control. + * XXX - worth handling MDMBUF (DCD) flow control at the lowest level? + * Now has 10+ msec latency, while CTS flow has 50- usec latency. + */ + com->state |= CS_ODEVREADY; +#ifdef SOFT_CTS_OFLOW + com->state &= ~CS_CTS_OFLOW; + if (cflag & CCTS_OFLOW) { + com->state |= CS_CTS_OFLOW; + if (!(com->last_modem_status & CD1400_MSVR2_CTS)) + com->state &= ~CS_ODEVREADY; + } +#endif + /* XXX shouldn't call functions while intrs are disabled. */ + disc_optim(tp, t, com); +#if 0 + /* + * Recover from fiddling with CS_TTGO. We used to call cyintr1() + * unconditionally, but that defeated the careful discarding of + * stale input in cyopen(). + */ + if (com->state >= (CS_BUSY | CS_TTGO)) + cyintr1(com); +#endif + if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) { + if (!(com->intr_enable & CD1400_SRER_TXRDY)) + cd_setreg(com, CD1400_SRER, + com->intr_enable + = (com->intr_enable & ~CD1400_SRER_TXMPTY) + | CD1400_SRER_TXRDY); + } else { + if (com->intr_enable & CD1400_SRER_TXRDY) + cd_setreg(com, CD1400_SRER, + com->intr_enable + = (com->intr_enable & ~CD1400_SRER_TXRDY) + | CD1400_SRER_TXMPTY); + } + + COM_UNLOCK(); + critical_exit(); + splx(s); + cystart(tp); + if (com->ibufold != NULL) { + free(com->ibufold, M_DEVBUF); + com->ibufold = NULL; + } + return (0); +} + +static int +cysetwater(struct com_s *com, speed_t speed) +{ + int cp4ticks; + u_char *ibuf; + int ibufsize; + struct tty *tp; + + /* + * Make the buffer size large enough to handle a softtty interrupt + * latency of about 2 ticks without loss of throughput or data + * (about 3 ticks if input flow control is not used or not honoured, + * but a bit less for CS5-CS7 modes). + */ + cp4ticks = speed / 10 / hz * 4; + for (ibufsize = 128; ibufsize < cp4ticks;) + ibufsize <<= 1; + if (ibufsize == com->ibufsize) { + return (0); + } + + /* + * Allocate input buffer. The extra factor of 2 in the size is + * to allow for an error byte for each input byte. + */ + ibuf = malloc(2 * ibufsize, M_DEVBUF, M_NOWAIT); + if (ibuf == NULL) { + return (ENOMEM); + } + + /* Initialize non-critical variables. */ + com->ibufold = com->ibuf; + com->ibufsize = ibufsize; + tp = com->tp; + if (tp != NULL) { + tp->t_ififosize = 2 * ibufsize; + tp->t_ispeedwat = (speed_t)-1; + tp->t_ospeedwat = (speed_t)-1; + } + + /* + * Read current input buffer, if any. Continue with interrupts + * disabled. + */ + critical_enter(); + COM_LOCK(); + if (com->iptr != com->ibuf) + cyinput(com); + + /*- + * Initialize critical variables, including input buffer watermarks. + * The external device is asked to stop sending when the buffer + * exactly reaches high water, or when the high level requests it. + * The high level is notified immediately (rather than at a later + * clock tick) when this watermark is reached. + * The buffer size is chosen so the watermark should almost never + * be reached. + * The low watermark is invisibly 0 since the buffer is always + * emptied all at once. + */ + com->iptr = com->ibuf = ibuf; + com->ibufend = ibuf + ibufsize; + com->ierroff = ibufsize; + com->ihighwater = ibuf + 3 * ibufsize / 4; + + COM_UNLOCK(); + critical_exit(); + return (0); +} + +static void +cystart(struct tty *tp) +{ + struct com_s *com; + int s; +#ifdef CyDebug + bool_t started; +#endif + + com = tp->t_sc; + s = spltty(); + +#ifdef CyDebug + ++com->start_count; + started = FALSE; +#endif + + critical_enter(); + COM_LOCK(); + if (tp->t_state & TS_TTSTOP) { + com->state &= ~CS_TTGO; + if (com->intr_enable & CD1400_SRER_TXRDY) + cd_setreg(com, CD1400_SRER, + com->intr_enable + = (com->intr_enable & ~CD1400_SRER_TXRDY) + | CD1400_SRER_TXMPTY); + } else { + com->state |= CS_TTGO; + if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY) + && !(com->intr_enable & CD1400_SRER_TXRDY)) + cd_setreg(com, CD1400_SRER, + com->intr_enable + = (com->intr_enable & ~CD1400_SRER_TXMPTY) + | CD1400_SRER_TXRDY); + } + if (tp->t_state & TS_TBLOCK) { + if (com->mcr_image & com->mcr_rts && com->state & CS_RTS_IFLOW) +#if 0 + outb(com->modem_ctl_port, com->mcr_image &= ~CD1400_MSVR1_RTS); +#else + cd_setreg(com, com->mcr_rts_reg, + com->mcr_image &= ~com->mcr_rts); +#endif + } else { + if (!(com->mcr_image & com->mcr_rts) + && com->iptr < com->ihighwater + && com->state & CS_RTS_IFLOW) +#if 0 + outb(com->modem_ctl_port, com->mcr_image |= CD1400_MSVR1_RTS); +#else + cd_setreg(com, com->mcr_rts_reg, + com->mcr_image |= com->mcr_rts); +#endif + } + COM_UNLOCK(); + critical_exit(); + if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { + ttwwakeup(tp); + splx(s); + return; + } + if (tp->t_outq.c_cc != 0) { + struct lbq *qp; + struct lbq *next; + + if (!com->obufs[0].l_queued) { +#ifdef CyDebug + started = TRUE; +#endif + com->obufs[0].l_tail + = com->obuf1 + q_to_b(&tp->t_outq, com->obuf1, + sizeof com->obuf1); + com->obufs[0].l_next = NULL; + com->obufs[0].l_queued = TRUE; + critical_enter(); + COM_LOCK(); + if (com->state & CS_BUSY) { + qp = com->obufq.l_next; + while ((next = qp->l_next) != NULL) + qp = next; + qp->l_next = &com->obufs[0]; + } else { + com->obufq.l_head = com->obufs[0].l_head; + com->obufq.l_tail = com->obufs[0].l_tail; + com->obufq.l_next = &com->obufs[0]; + com->state |= CS_BUSY; + if (com->state >= (CS_BUSY | CS_TTGO + | CS_ODEVREADY)) + cd_setreg(com, CD1400_SRER, + com->intr_enable + = (com->intr_enable + & ~CD1400_SRER_TXMPTY) + | CD1400_SRER_TXRDY); + } + COM_UNLOCK(); + critical_exit(); + } + if (tp->t_outq.c_cc != 0 && !com->obufs[1].l_queued) { +#ifdef CyDebug + started = TRUE; +#endif + com->obufs[1].l_tail + = com->obuf2 + q_to_b(&tp->t_outq, com->obuf2, + sizeof com->obuf2); + com->obufs[1].l_next = NULL; + com->obufs[1].l_queued = TRUE; + critical_enter(); + COM_LOCK(); + if (com->state & CS_BUSY) { + qp = com->obufq.l_next; + while ((next = qp->l_next) != NULL) + qp = next; + qp->l_next = &com->obufs[1]; + } else { + com->obufq.l_head = com->obufs[1].l_head; + com->obufq.l_tail = com->obufs[1].l_tail; + com->obufq.l_next = &com->obufs[1]; + com->state |= CS_BUSY; + if (com->state >= (CS_BUSY | CS_TTGO + | CS_ODEVREADY)) + cd_setreg(com, CD1400_SRER, + com->intr_enable + = (com->intr_enable + & ~CD1400_SRER_TXMPTY) + | CD1400_SRER_TXRDY); + } + COM_UNLOCK(); + critical_exit(); + } + tp->t_state |= TS_BUSY; + } +#ifdef CyDebug + if (started) + ++com->start_real; +#endif +#if 0 + critical_enter(); + COM_LOCK(); + if (com->state >= (CS_BUSY | CS_TTGO)) + cyintr1(com); /* fake interrupt to start output */ + COM_UNLOCK(); + critical_exit(); +#endif + ttwwakeup(tp); + splx(s); +} + +static void +comstop(struct tty *tp, int rw) +{ + struct com_s *com; + bool_t wakeup_etc; + + com = tp->t_sc; + wakeup_etc = FALSE; + critical_enter(); + COM_LOCK(); + if (rw & FWRITE) { + com->obufs[0].l_queued = FALSE; + com->obufs[1].l_queued = FALSE; + if (com->extra_state & CSE_ODONE) { + cy_events -= LOTS_OF_EVENTS; + com->extra_state &= ~CSE_ODONE; + if (com->etc != ETC_NONE) { + if (com->etc == ETC_BREAK_ENDED) + com->etc = ETC_NONE; + wakeup_etc = TRUE; + } + } + com->tp->t_state &= ~TS_BUSY; + if (com->state & CS_ODONE) + cy_events -= LOTS_OF_EVENTS; + com->state &= ~(CS_ODONE | CS_BUSY); + } + if (rw & FREAD) { + /* XXX no way to reset only input fifo. */ + cy_events -= (com->iptr - com->ibuf); + com->iptr = com->ibuf; + } + COM_UNLOCK(); + critical_exit(); + if (wakeup_etc) + wakeup(&com->etc); + if (rw & FWRITE && com->etc == ETC_NONE) + cd1400_channel_cmd(com, CD1400_CCR_CMDRESET | CD1400_CCR_FTF); + cystart(tp); +} + +static int +cymodem(struct tty *tp, int sigon, int sigoff) +{ + struct com_s *com; + int mcr; + int msr; + + com = tp->t_sc; + if (sigon == 0 && sigoff == 0) { + sigon = 0; + mcr = com->mcr_image; + if (mcr & com->mcr_dtr) + sigon |= SER_DTR; + if (mcr & com->mcr_rts) + /* XXX wired on for Cyclom-8Ys */ + sigon |= SER_RTS; + + /* + * We must read the modem status from the hardware because + * we don't generate modem status change interrupts for all + * changes, so com->prev_modem_status is not guaranteed to + * be up to date. This is safe, unlike for sio, because + * reading the status register doesn't clear pending modem + * status change interrupts. + */ + msr = cd_getreg(com, CD1400_MSVR2); + + if (msr & CD1400_MSVR2_CTS) + sigon |= SER_CTS; + if (msr & CD1400_MSVR2_CD) + sigon |= SER_DCD; + if (msr & CD1400_MSVR2_DSR) + sigon |= SER_DSR; + if (msr & CD1400_MSVR2_RI) + /* XXX not connected except for Cyclom-16Y? */ + sigon |= SER_RI; + return (sigon); + } + mcr = com->mcr_image; + if (sigon & SER_DTR) + mcr |= com->mcr_dtr; + if (sigoff & SER_DTR) + mcr &= ~com->mcr_dtr; + if (sigon & SER_RTS) + mcr |= com->mcr_rts; + if (sigoff & SER_RTS) + mcr &= ~com->mcr_rts; + critical_enter(); + COM_LOCK(); + com->mcr_image = mcr; + cd_setreg(com, CD1400_MSVR1, mcr); + cd_setreg(com, CD1400_MSVR2, mcr); + COM_UNLOCK(); + critical_exit(); + return (0); +} + +static void +cysettimeout() +{ + struct com_s *com; + bool_t someopen; + int unit; + + /* + * Set our timeout period to 1 second if no polled devices are open. + * Otherwise set it to max(1/200, 1/hz). + * Enable timeouts iff some device is open. + */ + untimeout(cywakeup, (void *)NULL, cy_timeout_handle); + cy_timeout = hz; + someopen = FALSE; + for (unit = 0; unit < NPORTS; ++unit) { + com = cy_addr(unit); + if (com != NULL && com->tp != NULL + && com->tp->t_state & TS_ISOPEN) { + someopen = TRUE; + } + } + if (someopen) { + cy_timeouts_until_log = hz / cy_timeout; + cy_timeout_handle = timeout(cywakeup, (void *)NULL, + cy_timeout); + } else { + /* Flush error messages, if any. */ + cy_timeouts_until_log = 1; + cywakeup((void *)NULL); + untimeout(cywakeup, (void *)NULL, cy_timeout_handle); + } +} + +static void +cywakeup(void *chan) +{ + struct com_s *com; + int unit; + + cy_timeout_handle = timeout(cywakeup, (void *)NULL, cy_timeout); + + /* + * Check for and log errors, but not too often. + */ + if (--cy_timeouts_until_log > 0) + return; + cy_timeouts_until_log = hz / cy_timeout; + for (unit = 0; unit < NPORTS; ++unit) { + int errnum; + + com = cy_addr(unit); + if (com == NULL) + continue; + for (errnum = 0; errnum < CE_NTYPES; ++errnum) { + u_int delta; + u_long total; + + critical_enter(); + COM_LOCK(); + delta = com->delta_error_counts[errnum]; + com->delta_error_counts[errnum] = 0; + COM_UNLOCK(); + critical_exit(); + if (delta == 0) + continue; + total = com->error_counts[errnum] += delta; + log(LOG_ERR, "cy%d: %u more %s%s (total %lu)\n", + unit, delta, error_desc[errnum], + delta == 1 ? "" : "s", total); + } + } +} + +static void +disc_optim(struct tty *tp, struct termios *t, struct com_s *com) +{ +#ifndef SOFT_HOTCHAR + u_char opt; +#endif + + ttyldoptim(tp); +#ifndef SOFT_HOTCHAR + opt = com->cor[2] & ~CD1400_COR3_SCD34; + if (com->tp->t_hotchar != 0) { + cd_setreg(com, CD1400_SCHR3, com->tp->t_hotchar); + cd_setreg(com, CD1400_SCHR4, com->tp->t_hotchar); + opt |= CD1400_COR3_SCD34; + } + if (opt != com->cor[2]) { + cd_setreg(com, CD1400_COR3, com->cor[2] = opt); + cd1400_channel_cmd(com, CD1400_CCR_CMDCORCHG | CD1400_CCR_COR3); + } +#endif +} + +#ifdef Smarts +/* standard line discipline input routine */ +int +cyinput(int c, struct tty *tp) +{ + /* XXX duplicate ttyinput(), but without the IXOFF/IXON/ISTRIP/IPARMRK + * bits, as they are done by the CD1400. Hardly worth the effort, + * given that high-throughput session are raw anyhow. + */ +} +#endif /* Smarts */ + +static int +cyspeed(speed_t speed, u_long cy_clock, int *prescaler_io) +{ + int actual; + int error; + int divider; + int prescaler; + int prescaler_unit; + + if (speed == 0) + return (0); + if (speed < 0 || speed > 150000) + return (-1); + + /* determine which prescaler to use */ + for (prescaler_unit = 4, prescaler = 2048; prescaler_unit; + prescaler_unit--, prescaler >>= 2) { + if (cy_clock / prescaler / speed > 63) + break; + } + + divider = (cy_clock / prescaler * 2 / speed + 1) / 2; /* round off */ + if (divider > 255) + divider = 255; + actual = cy_clock/prescaler/divider; + + /* 10 times error in percent: */ + error = ((actual - (long)speed) * 2000 / (long)speed + 1) / 2; + + /* 3.0% max error tolerance */ + if (error < -30 || error > 30) + return (-1); + + *prescaler_io = prescaler_unit; + return (divider); +} + +static void +cd1400_channel_cmd(struct com_s *com, int cmd) +{ + cd1400_channel_cmd_wait(com); + cd_setreg(com, CD1400_CCR, cmd); + cd1400_channel_cmd_wait(com); +} + +static void +cd1400_channel_cmd_wait(struct com_s *com) +{ + struct timeval start; + struct timeval tv; + long usec; + + if (cd_getreg(com, CD1400_CCR) == 0) + return; + microtime(&start); + for (;;) { + if (cd_getreg(com, CD1400_CCR) == 0) + return; + microtime(&tv); + usec = 1000000 * (tv.tv_sec - start.tv_sec) + + tv.tv_usec - start.tv_usec; + if (usec >= 5000) { + log(LOG_ERR, + "cy%d: channel command timeout (%ld usec)\n", + com->unit, usec); + return; + } + } +} + +static void +cd_etc(struct com_s *com, int etc) +{ + + /* + * We can't change the hardware's ETC state while there are any + * characters in the tx fifo, since those characters would be + * interpreted as commands! Unputting characters from the fifo + * is difficult, so we wait up to 12 character times for the fifo + * to drain. The command will be delayed for up to 2 character + * times for the tx to become empty. Unputting characters from + * the tx holding and shift registers is impossible, so we wait + * for the tx to become empty so that the command is sure to be + * executed soon after we issue it. + */ + critical_enter(); + COM_LOCK(); + if (com->etc == etc) + goto wait; + if ((etc == CD1400_ETC_SENDBREAK + && (com->etc == ETC_BREAK_STARTING + || com->etc == ETC_BREAK_STARTED)) + || (etc == CD1400_ETC_STOPBREAK + && (com->etc == ETC_BREAK_ENDING || com->etc == ETC_BREAK_ENDED + || com->etc == ETC_NONE))) { + COM_UNLOCK(); + critical_exit(); + return; + } + com->etc = etc; + cd_setreg(com, CD1400_SRER, + com->intr_enable + = (com->intr_enable & ~CD1400_SRER_TXRDY) | CD1400_SRER_TXMPTY); +wait: + COM_UNLOCK(); + critical_exit(); + while (com->etc == etc + && tsleep(&com->etc, TTIPRI | PCATCH, "cyetc", 0) == 0) + continue; +} + +static int +cd_getreg(struct com_s *com, int reg) +{ + struct com_s *basecom; + u_char car; + int cy_align; + cy_addr iobase; +#ifdef SMP + int need_unlock; +#endif + int val; + + basecom = cy_addr(com->unit & ~(CD1400_NO_OF_CHANNELS - 1)); + car = com->unit & CD1400_CAR_CHAN; + cy_align = com->cy_align; + iobase = com->iobase; + critical_enter(); +#ifdef SMP + need_unlock = 0; + if (!mtx_owned(&cy_lock)) { + COM_LOCK(); + need_unlock = 1; + } +#endif + if (basecom->car != car) + cd_outb(iobase, CD1400_CAR, cy_align, basecom->car = car); + val = cd_inb(iobase, reg, cy_align); +#ifdef SMP + if (need_unlock) + COM_UNLOCK(); +#endif + critical_exit(); + return (val); +} + +static void +cd_setreg(struct com_s *com, int reg, int val) +{ + struct com_s *basecom; + u_char car; + int cy_align; + cy_addr iobase; +#ifdef SMP + int need_unlock; +#endif + + basecom = cy_addr(com->unit & ~(CD1400_NO_OF_CHANNELS - 1)); + car = com->unit & CD1400_CAR_CHAN; + cy_align = com->cy_align; + iobase = com->iobase; + critical_enter(); +#ifdef SMP + need_unlock = 0; + if (!mtx_owned(&cy_lock)) { + COM_LOCK(); + need_unlock = 1; + } +#endif + if (basecom->car != car) + cd_outb(iobase, CD1400_CAR, cy_align, basecom->car = car); + cd_outb(iobase, reg, cy_align, val); +#ifdef SMP + if (need_unlock) + COM_UNLOCK(); +#endif + critical_exit(); +} + +#ifdef CyDebug +/* useful in ddb */ +void +cystatus(int unit) +{ + struct com_s *com; + cy_addr iobase; + u_int ocount; + struct tty *tp; + + com = cy_addr(unit); + printf("info for channel %d\n", unit); + printf("------------------\n"); + printf("total cyclom service probes:\t%d\n", cy_svrr_probes); + printf("calls to upper layer:\t\t%d\n", cy_timeouts); + if (com == NULL) + return; + iobase = com->iobase; + printf("\n"); + printf("cd1400 base address:\\tt%p\n", iobase); + printf("saved channel_control:\t\t0x%02x\n", com->channel_control); + printf("saved cor1-3:\t\t\t0x%02x 0x%02x 0x%02x\n", + com->cor[0], com->cor[1], com->cor[2]); + printf("service request enable reg:\t0x%02x (0x%02x cached)\n", + cd_getreg(com, CD1400_SRER), com->intr_enable); + printf("service request register:\t0x%02x\n", + cd_inb(iobase, CD1400_SVRR, com->cy_align)); + printf("modem status:\t\t\t0x%02x (0x%02x cached)\n", + cd_getreg(com, CD1400_MSVR2), com->prev_modem_status); + printf("rx/tx/mdm interrupt registers:\t0x%02x 0x%02x 0x%02x\n", + cd_inb(iobase, CD1400_RIR, com->cy_align), + cd_inb(iobase, CD1400_TIR, com->cy_align), + cd_inb(iobase, CD1400_MIR, com->cy_align)); + printf("\n"); + printf("com state:\t\t\t0x%02x\n", com->state); + printf("calls to cystart():\t\t%d (%d useful)\n", + com->start_count, com->start_real); + printf("rx buffer chars free:\t\t%d\n", com->iptr - com->ibuf); + ocount = 0; + if (com->obufs[0].l_queued) + ocount += com->obufs[0].l_tail - com->obufs[0].l_head; + if (com->obufs[1].l_queued) + ocount += com->obufs[1].l_tail - com->obufs[1].l_head; + printf("tx buffer chars:\t\t%u\n", ocount); + printf("received chars:\t\t\t%d\n", com->bytes_in); + printf("received exceptions:\t\t%d\n", com->recv_exception); + printf("modem signal deltas:\t\t%d\n", com->mdm); + printf("transmitted chars:\t\t%d\n", com->bytes_out); + printf("\n"); + tp = com->tp; + if (tp != NULL) { + printf("tty state:\t\t\t0x%08x\n", tp->t_state); + printf( + "upper layer queue lengths:\t%d raw, %d canon, %d output\n", + tp->t_rawq.c_cc, tp->t_canq.c_cc, tp->t_outq.c_cc); + } else + printf("tty state:\t\t\tclosed\n"); +} +#endif /* CyDebug */ diff --git a/sys/dev/cy/cy_isa.c b/sys/dev/cy/cy_isa.c new file mode 100644 index 00000000000..448cc033dcb --- /dev/null +++ b/sys/dev/cy/cy_isa.c @@ -0,0 +1,150 @@ +/*- + * cyclades cyclom-y serial driver + * Andrew Herbert , 17 August 1993 + * + * Copyright (c) 1993 Andrew Herbert. + * All rights reserved. + * + * 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. + * 3. The name Andrew Herbert may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ``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 I 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. + */ + +/* + * Cyclades Y ISA serial interface driver + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +static int cy_isa_attach(device_t dev); +static int cy_isa_probe(device_t dev); + +static device_method_t cy_isa_methods[] = { + /* Device interface. */ + DEVMETHOD(device_probe, cy_isa_probe), + DEVMETHOD(device_attach, cy_isa_attach), + + { 0, 0 } +}; + +static driver_t cy_isa_driver = { + cy_driver_name, + cy_isa_methods, + 0, +}; + +DRIVER_MODULE(cy, isa, cy_isa_driver, cy_devclass, 0, 0); + +static int +cy_isa_probe(device_t dev) +{ + struct resource *mem_res; + cy_addr iobase; + int error, mem_rid; + + if (isa_get_logicalid(dev) != 0) /* skip PnP probes */ + return (ENXIO); + + mem_rid = 0; + mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &mem_rid, + RF_ACTIVE); + if (mem_res == NULL) { + device_printf(dev, "ioport resource allocation failed\n"); + return (ENXIO); + } + iobase = rman_get_virtual(mem_res); + + /* Cyclom-16Y hardware reset (Cyclom-8Ys don't care) */ + cy_inb(iobase, CY16_RESET, 0); /* XXX? */ + DELAY(500); /* wait for the board to get its act together */ + + /* this is needed to get the board out of reset */ + cy_outb(iobase, CY_CLEAR_INTR, 0, 0); + DELAY(500); + + error = (cy_units(iobase, 0) == 0 ? ENXIO : 0); + bus_release_resource(dev, SYS_RES_MEMORY, mem_rid, mem_res); + return (error); +} + +static int +cy_isa_attach(device_t dev) +{ + struct resource *irq_res, *mem_res; + void *irq_cookie, *vaddr, *vsc; + int irq_rid, mem_rid; + + irq_res = NULL; + mem_res = NULL; + + mem_rid = 0; + mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &mem_rid, + RF_ACTIVE); + if (mem_res == NULL) { + device_printf(dev, "memory resource allocation failed\n"); + goto fail; + } + vaddr = rman_get_virtual(mem_res); + + vsc = cyattach_common(vaddr, 0); + if (vsc == NULL) { + device_printf(dev, "no ports found!\n"); + goto fail; + } + + irq_rid = 0; + irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &irq_rid, + RF_SHAREABLE | RF_ACTIVE); + if (irq_res == NULL) { + device_printf(dev, "interrupt resource allocation failed\n"); + goto fail; + } + if (bus_setup_intr(dev, irq_res, INTR_TYPE_TTY, + cyintr, NULL, vsc, &irq_cookie) != 0) { + device_printf(dev, "interrupt setup failed\n"); + goto fail; + } + + return (0); + +fail: + if (irq_res != NULL) + bus_release_resource(dev, SYS_RES_IRQ, irq_rid, irq_res); + if (mem_res != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, mem_rid, mem_res); + return (ENXIO); +} diff --git a/sys/dev/cy/cy_pci.c b/sys/dev/cy/cy_pci.c new file mode 100644 index 00000000000..3f9a1826f6b --- /dev/null +++ b/sys/dev/cy/cy_pci.c @@ -0,0 +1,192 @@ +/*- + * Copyright (c) 1996, David Greenman + * All rights reserved. + * + * 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 unmodified, 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. + */ + +/* + * Cyclades Y PCI serial interface driver + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_cy_pci_fastintr.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#define CY_PCI_BASE_ADDR0 0x10 +#define CY_PCI_BASE_ADDR1 0x14 +#define CY_PCI_BASE_ADDR2 0x18 + +#define CY_PLX_9050_ICS 0x4c +#define CY_PLX_9060_ICS 0x68 +#define CY_PLX_9050_ICS_IENABLE 0x040 +#define CY_PLX_9050_ICS_LOCAL_IENABLE 0x001 +#define CY_PLX_9050_ICS_LOCAL_IPOLARITY 0x002 +#define CY_PLX_9060_ICS_IENABLE 0x100 +#define CY_PLX_9060_ICS_LOCAL_IENABLE 0x800 + +/* Cyclom-Y Custom Register for PLX ID. */ +#define PLX_VER 0x3400 +#define PLX_9050 0x0b +#define PLX_9060 0x0c +#define PLX_9080 0x0d + +static int cy_pci_attach(device_t dev); +static int cy_pci_probe(device_t dev); + +static device_method_t cy_pci_methods[] = { + /* Device interface. */ + DEVMETHOD(device_probe, cy_pci_probe), + DEVMETHOD(device_attach, cy_pci_attach), + + { 0, 0 } +}; + +static driver_t cy_pci_driver = { + cy_driver_name, + cy_pci_methods, + 0, +}; + +DRIVER_MODULE(cy, pci, cy_pci_driver, cy_devclass, 0, 0); +MODULE_DEPEND(cy, pci, 1, 1, 1); + +static int +cy_pci_probe(dev) + device_t dev; +{ + u_int32_t device_id; + + device_id = pci_get_devid(dev); + device_id &= ~0x00060000; + if (device_id != 0x0100120e && device_id != 0x0101120e) + return (ENXIO); + device_set_desc(dev, "Cyclades Cyclom-Y Serial Adapter"); + return (BUS_PROBE_DEFAULT); +} + +static int +cy_pci_attach(dev) + device_t dev; +{ + struct resource *ioport_res, *irq_res, *mem_res; + void *irq_cookie, *vaddr, *vsc; + u_int32_t ioport; + int irq_setup, ioport_rid, irq_rid, mem_rid; + u_char plx_ver; + + ioport_res = NULL; + irq_res = NULL; + mem_res = NULL; + + ioport_rid = CY_PCI_BASE_ADDR1; + ioport_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &ioport_rid, + RF_ACTIVE); + if (ioport_res == NULL) { + device_printf(dev, "ioport resource allocation failed\n"); + goto fail; + } + ioport = rman_get_start(ioport_res); + + mem_rid = CY_PCI_BASE_ADDR2; + mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &mem_rid, + RF_ACTIVE); + if (mem_res == NULL) { + device_printf(dev, "memory resource allocation failed\n"); + goto fail; + } + vaddr = rman_get_virtual(mem_res); + + vsc = cyattach_common(vaddr, 1); + if (vsc == NULL) { + device_printf(dev, "no ports found!\n"); + goto fail; + } + + irq_rid = 0; + irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &irq_rid, + RF_SHAREABLE | RF_ACTIVE); + if (irq_res == NULL) { + device_printf(dev, "interrupt resource allocation failed\n"); + goto fail; + } +#ifdef CY_PCI_FASTINTR + irq_setup = bus_setup_intr(dev, irq_res, INTR_TYPE_TTY, + cyintr, NULL, vsc, &irq_cookie); +#else + irq_setup = ENXIO; +#endif + if (irq_setup != 0) + irq_setup = bus_setup_intr(dev, irq_res, INTR_TYPE_TTY, + NULL, (driver_intr_t *)cyintr, vsc, &irq_cookie); + if (irq_setup != 0) { + device_printf(dev, "interrupt setup failed\n"); + goto fail; + } + + /* + * Enable the "local" interrupt input to generate a + * PCI interrupt. + */ + plx_ver = *((u_char *)vaddr + PLX_VER) & 0x0f; + switch (plx_ver) { + case PLX_9050: + outw(ioport + CY_PLX_9050_ICS, + CY_PLX_9050_ICS_IENABLE | CY_PLX_9050_ICS_LOCAL_IENABLE | + CY_PLX_9050_ICS_LOCAL_IPOLARITY); + break; + case PLX_9060: + case PLX_9080: + default: /* Old board, use PLX_9060 values. */ + outw(ioport + CY_PLX_9060_ICS, + inw(ioport + CY_PLX_9060_ICS) | CY_PLX_9060_ICS_IENABLE | + CY_PLX_9060_ICS_LOCAL_IENABLE); + break; + } + + return (0); + +fail: + if (ioport_res != NULL) + bus_release_resource(dev, SYS_RES_IOPORT, ioport_rid, + ioport_res); + if (irq_res != NULL) + bus_release_resource(dev, SYS_RES_IRQ, irq_rid, irq_res); + if (mem_res != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, mem_rid, mem_res); + return (ENXIO); +} diff --git a/sys/dev/cy/cyreg.h b/sys/dev/cy/cyreg.h new file mode 100644 index 00000000000..88a36eb4a65 --- /dev/null +++ b/sys/dev/cy/cyreg.h @@ -0,0 +1,75 @@ +/*- + * Copyright (c) 1995 Bruce Evans. + * All rights reserved. + * + * 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. + * 3. Neither the name of the author nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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. + * + * $FreeBSD$ + */ + +/* + * Definitions for Cyclades Cyclom-Y serial boards. + */ + +/* + * Cyclades register offsets. These are physical offsets for ISA boards + * and physical offsets divided by 2 for PCI boards. + */ +#define CY8_SVCACKR 0x100 /* (r) */ +#define CY8_SVCACKT 0x200 /* (r) */ +#define CY8_SVCACKM 0x300 /* (r) */ +#define CY16_RESET 0x1400 /* (r) */ +#define CY_CLEAR_INTR 0x1800 /* intr ack address (w) */ + +#define CY_MAX_CD1400s 8 /* for Cyclom-32Y */ + +#define CY_CLOCK(version) ((version) >= 0x48 ? 60000000 : 25000000) +#define CY_RTS_DTR_SWAPPED(version) ((version) >= 0x48) + +/* + * The `cd' macros are for access to cd1400 registers. The `cy' macros + * are for access to Cyclades registers. Both sets of macros scale the + * register number to get an offset, but the scales are different for + * mostly historical reasons. + */ +#ifdef CyDebug +#define cd_inb(iobase, reg, cy_align) \ + (++cd_inbs, *((iobase) + (2 * (reg) << (cy_align)))) +#define cy_inb(iobase, reg, cy_align) \ + (++cy_inbs, *((iobase) + ((reg) << (cy_align)))) +#define cd_outb(iobase, reg, cy_align, val) \ + (++cd_outbs, (void)(*((iobase) + (2 * (reg) << (cy_align))) = (val))) +#define cy_outb(iobase, reg, cy_align, val) \ + (++cy_outbs, (void)(*((iobase) + ((reg) << (cy_align))) = (val))) +#else +#define cd_inb(iobase, reg, cy_align) \ + (*((iobase) + (2 * (reg) << (cy_align)))) +#define cy_inb(iobase, reg, cy_align) \ + (*((iobase) + ((reg) << (cy_align)))) +#define cd_outb(iobase, reg, cy_align, val) \ + ((void)(*((iobase) + (2 * (reg) << (cy_align))) = (val))) +#define cy_outb(iobase, reg, cy_align, val) \ + ((void)(*((iobase) + ((reg) << (cy_align))) = (val))) +#endif diff --git a/sys/dev/cy/cyvar.h b/sys/dev/cy/cyvar.h new file mode 100644 index 00000000000..6b770e8761f --- /dev/null +++ b/sys/dev/cy/cyvar.h @@ -0,0 +1,36 @@ +/*- + * Copyright (c) 2004 Bruce D. Evans + * All rights reserved. + * + * 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. + * + * $FreeBSD$ + */ + +typedef u_char volatile *cy_addr; + +extern devclass_t cy_devclass; +extern char cy_driver_name[]; + +void *cyattach_common(cy_addr cy_iobase, int cy_align); +driver_filter_t cyintr; +int cy_units(cy_addr cy_iobase, int cy_align); diff --git a/sys/dev/drm2/radeon/radeon_drv.c b/sys/dev/drm2/radeon/radeon_drv.c index 7c433c6ed88..fd0495927fd 100644 --- a/sys/dev/drm2/radeon/radeon_drv.c +++ b/sys/dev/drm2/radeon/radeon_drv.c @@ -127,54 +127,71 @@ int radeon_pcie_gen2 = -1; int radeon_msi = -1; int radeon_lockup_timeout = 10000; +TUNABLE_INT("drm.radeon.no_wb", &radeon_no_wb); MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); module_param_named(no_wb, radeon_no_wb, int, 0444); +TUNABLE_INT("drm.radeon.modeset", &radeon_modeset); MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); module_param_named(modeset, radeon_modeset, int, 0400); +TUNABLE_INT("drm.radeon.dynclks", &radeon_dynclks); MODULE_PARM_DESC(dynclks, "Disable/Enable dynamic clocks"); module_param_named(dynclks, radeon_dynclks, int, 0444); +TUNABLE_INT("drm.radeon.r4xx_atom", &radeon_r4xx_atom); MODULE_PARM_DESC(r4xx_atom, "Enable ATOMBIOS modesetting for R4xx"); module_param_named(r4xx_atom, radeon_r4xx_atom, int, 0444); +TUNABLE_INT("drm.radeon.vramlimit", &radeon_vram_limit); MODULE_PARM_DESC(vramlimit, "Restrict VRAM for testing"); module_param_named(vramlimit, radeon_vram_limit, int, 0600); +TUNABLE_INT("drm.radeon.agpmode", &radeon_agpmode); MODULE_PARM_DESC(agpmode, "AGP Mode (-1 == PCI)"); module_param_named(agpmode, radeon_agpmode, int, 0444); +TUNABLE_INT("drm.radeon.gartsize", &radeon_gart_size); MODULE_PARM_DESC(gartsize, "Size of PCIE/IGP gart to setup in megabytes (32, 64, etc)"); module_param_named(gartsize, radeon_gart_size, int, 0600); +TUNABLE_INT("drm.radeon.benchmark", &radeon_benchmarking); MODULE_PARM_DESC(benchmark, "Run benchmark"); module_param_named(benchmark, radeon_benchmarking, int, 0444); +TUNABLE_INT("drm.radeon.test", &radeon_testing); MODULE_PARM_DESC(test, "Run tests"); module_param_named(test, radeon_testing, int, 0444); +TUNABLE_INT("drm.radeon.connector_table", &radeon_connector_table); MODULE_PARM_DESC(connector_table, "Force connector table"); module_param_named(connector_table, radeon_connector_table, int, 0444); +TUNABLE_INT("drm.radeon.tv", &radeon_tv); MODULE_PARM_DESC(tv, "TV enable (0 = disable)"); module_param_named(tv, radeon_tv, int, 0444); +TUNABLE_INT("drm.radeon.audio", &radeon_audio); MODULE_PARM_DESC(audio, "Audio enable (1 = enable)"); module_param_named(audio, radeon_audio, int, 0444); +TUNABLE_INT("drm.radeon.disp_priority", &radeon_disp_priority); MODULE_PARM_DESC(disp_priority, "Display Priority (0 = auto, 1 = normal, 2 = high)"); module_param_named(disp_priority, radeon_disp_priority, int, 0444); +TUNABLE_INT("drm.radeon.hw_i2c", &radeon_hw_i2c); MODULE_PARM_DESC(hw_i2c, "hw i2c engine enable (0 = disable)"); module_param_named(hw_i2c, radeon_hw_i2c, int, 0444); +TUNABLE_INT("drm.radeon.pcie_gen2", &radeon_pcie_gen2); MODULE_PARM_DESC(pcie_gen2, "PCIE Gen2 mode (-1 = auto, 0 = disable, 1 = enable)"); module_param_named(pcie_gen2, radeon_pcie_gen2, int, 0444); +TUNABLE_INT("drm.radeon.msi", &radeon_msi); MODULE_PARM_DESC(msi, "MSI support (1 = enable, 0 = disable, -1 = auto)"); module_param_named(msi, radeon_msi, int, 0444); +TUNABLE_INT("drm.radeon.lockup_timeout", &radeon_lockup_timeout); MODULE_PARM_DESC(lockup_timeout, "GPU lockup timeout in ms (defaul 10000 = 10 seconds, 0 = disable)"); module_param_named(lockup_timeout, radeon_lockup_timeout, int, 0444); diff --git a/sys/dev/etherswitch/e6000sw/e6000sw.c b/sys/dev/etherswitch/e6000sw/e6000sw.c index adac7ff68cb..3c86426d056 100644 --- a/sys/dev/etherswitch/e6000sw/e6000sw.c +++ b/sys/dev/etherswitch/e6000sw/e6000sw.c @@ -214,7 +214,6 @@ e6000sw_probe(device_t dev) e6000sw_softc_t *sc; const char *description; unsigned int id; - uint16_t dev_addr; phandle_t dsa_node, switch_node; dsa_node = fdt_find_compatible(OF_finddevice("/"), @@ -229,21 +228,11 @@ e6000sw_probe(device_t dev) sc->dev = dev; sc->node = switch_node; - /* Read ADDR[4:1]n using indirect access */ - MDIO_WRITE(dev, REG_GLOBAL2, SCR_AND_MISC_REG, - SCR_AND_MISC_PTR_CFG); - dev_addr = MDIO_READ(dev, REG_GLOBAL2, SCR_AND_MISC_REG) & - SCR_AND_MISC_DATA_CFG_MASK; - if (dev_addr != 0) { - sc->multi_chip = true; - device_printf(dev, "multi-chip addresing mode\n"); - } else { - device_printf(dev, "single-chip addressing mode\n"); - } - if (OF_getencprop(sc->node, "reg", &sc->sw_addr, sizeof(sc->sw_addr)) < 0) return (ENXIO); + if (sc->sw_addr != 0 && (sc->sw_addr % 2) == 0) + sc->multi_chip = true; /* Lock is necessary due to assertions. */ sx_init(&sc->sx, "e6000sw"); @@ -368,6 +357,11 @@ e6000sw_attach(device_t dev) err = 0; sc = device_get_softc(dev); + if (sc->multi_chip) + device_printf(dev, "multi-chip addressing mode\n"); + else + device_printf(dev, "single-chip addressing mode\n"); + E6000SW_LOCK(sc); e6000sw_setup(dev, sc); bzero(member_ports, sizeof(member_ports)); diff --git a/sys/dev/fdt/fdt_common.c b/sys/dev/fdt/fdt_common.c index 3e59fb97707..cf7b39b4a71 100644 --- a/sys/dev/fdt/fdt_common.c +++ b/sys/dev/fdt/fdt_common.c @@ -422,7 +422,7 @@ fdt_addrsize_cells(phandle_t node, int *addr_cells, int *size_cells) */ cell_size = sizeof(cell); if (OF_getencprop(node, "#address-cells", &cell, cell_size) < cell_size) - *addr_cells = 2; + cell = 2; *addr_cells = (int)cell; if (OF_getencprop(node, "#size-cells", &cell, cell_size) < cell_size) diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c index c75b95ed55e..f1fb54ad118 100644 --- a/sys/dev/isp/isp.c +++ b/sys/dev/isp/isp.c @@ -2771,10 +2771,11 @@ isp_getpdb(ispsoftc_t *isp, int chan, uint16_t id, isp_pdb_t *pdb) pdb->portid = BITS2WORD_24XX(un.bill.pdb_portid_bits); ISP_MEMCPY(pdb->portname, un.bill.pdb_portname, 8); ISP_MEMCPY(pdb->nodename, un.bill.pdb_nodename, 8); - isp_prt(isp, ISP_LOGDEBUG1, - "Chan %d handle 0x%x Port 0x%06x flags 0x%x curstate %x", + isp_prt(isp, ISP_LOGDEBUG0, + "Chan %d handle 0x%x Port 0x%06x flags 0x%x curstate %x laststate %x", chan, id, pdb->portid, un.bill.pdb_flags, - un.bill.pdb_curstate); + un.bill.pdb_curstate, un.bill.pdb_laststate); + if (un.bill.pdb_curstate < PDB2400_STATE_PLOGI_DONE || un.bill.pdb_curstate > PDB2400_STATE_LOGGED_IN) { mbs.param[0] = MBOX_NOT_LOGGED_IN; return (mbs.param[0]); diff --git a/sys/dev/isp/isp_freebsd.c b/sys/dev/isp/isp_freebsd.c index 5ce037a154c..4b9e0b386bc 100644 --- a/sys/dev/isp/isp_freebsd.c +++ b/sys/dev/isp/isp_freebsd.c @@ -2567,8 +2567,7 @@ isp_watchdog(void *arg) } isp_destroy_handle(isp, handle); isp_prt(isp, ISP_LOGERR, "%s: timeout for handle 0x%x", __func__, handle); - xs->ccb_h.status &= ~CAM_STATUS_MASK; - xs->ccb_h.status |= CAM_CMD_TIMEOUT; + XS_SETERR(xs, CAM_CMD_TIMEOUT); isp_done(xs); } else { if (ohandle != ISP_HANDLE_FREE) { @@ -2739,9 +2738,6 @@ isp_loop_dead(ispsoftc_t *isp, int chan) if (lp->state == FC_PORTDB_STATE_NIL) continue; - /* - * XXX: CLEAN UP AND COMPLETE ANY PENDING COMMANDS FIRST! - */ for (i = 0; i < isp->isp_maxcmds; i++) { struct ccb_scsiio *xs; @@ -2757,6 +2753,25 @@ isp_loop_dead(ispsoftc_t *isp, int chan) isp_prt(isp, ISP_LOGWARN, "command handle 0x%x for %d.%d.%jx orphaned by loop down timeout", isp->isp_xflist[i].handle, chan, XS_TGT(xs), (uintmax_t)XS_LUN(xs)); + + /* + * Just like in isp_watchdog, abort the outstanding + * command or immediately free its resources if it is + * not active + */ + if (isp_control(isp, ISPCTL_ABORT_CMD, xs) == 0) { + continue; + } + + if (XS_XFRLEN(xs)) { + ISP_DMAFREE(isp, xs, isp->isp_xflist[i].handle); + } + isp_destroy_handle(isp, isp->isp_xflist[i].handle); + isp_prt(isp, ISP_LOGWARN, "command handle 0x%x for %d.%d.%jx could not be aborted and was destroyed", + isp->isp_xflist[i].handle, chan, XS_TGT(xs), + (uintmax_t)XS_LUN(xs)); + XS_SETERR(xs, HBA_BUSRESET); + isp_done(xs); } isp_prt(isp, ISP_LOGCONFIG, prom3, chan, dbidx, lp->portid, "Loop Down Timeout"); @@ -3562,7 +3577,7 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...) static const char prom[] = "Chan %d [%d] WWPN 0x%16jx PortID 0x%06x handle 0x%x %s %s"; char buf[64]; char *msg = NULL; - target_id_t tgt; + target_id_t tgt = 0; fcportdb_t *lp; struct isp_fc *fc; struct cam_path *tmppath; @@ -3639,31 +3654,51 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...) } break; } + case ISPASYNC_LOOP_RESET: + { + uint16_t lipp; + fcparam *fcp; + va_start(ap, cmd); + bus = va_arg(ap, int); + va_end(ap); + + lipp = ISP_READ(isp, OUTMAILBOX1); + fcp = FCPARAM(isp, bus); + + isp_prt(isp, ISP_LOGINFO, "Chan %d LOOP Reset, LIP primitive %x", bus, lipp); + /* + * Per FCP-4, a Reset LIP should result in a CRN reset. Other + * LIPs and loop up/down events should never reset the CRN. For + * an as of yet unknown reason, 24xx series cards (and + * potentially others) can interrupt with a LIP Reset status + * when no LIP reset came down the wire. Additionally, the LIP + * primitive accompanying this status would not be a valid LIP + * Reset primitive, but some variation of an invalid AL_PA + * LIP. As a result, we have to verify the AL_PD in the LIP + * addresses our port before blindly resetting. + */ + if (FCP_IS_DEST_ALPD(fcp, (lipp & 0x00FF))) + isp_fcp_reset_crn(isp, bus, /*tgt*/0, /*tgt_set*/ 0); + isp_loop_changed(isp, bus); + break; + } case ISPASYNC_LIP: if (msg == NULL) msg = "LIP Received"; /* FALLTHROUGH */ - case ISPASYNC_LOOP_RESET: - if (msg == NULL) - msg = "LOOP Reset"; - /* FALLTHROUGH */ case ISPASYNC_LOOP_DOWN: if (msg == NULL) msg = "LOOP Down"; + /* FALLTHROUGH */ + case ISPASYNC_LOOP_UP: + if (msg == NULL) + msg = "LOOP Up"; va_start(ap, cmd); bus = va_arg(ap, int); va_end(ap); - isp_fcp_reset_crn(isp, bus, /*tgt*/0, /*tgt_set*/ 0); isp_loop_changed(isp, bus); isp_prt(isp, ISP_LOGINFO, "Chan %d %s", bus, msg); break; - case ISPASYNC_LOOP_UP: - va_start(ap, cmd); - bus = va_arg(ap, int); - va_end(ap); - isp_loop_changed(isp, bus); - isp_prt(isp, ISP_LOGINFO, "Chan %d Loop UP", bus); - break; case ISPASYNC_DEV_ARRIVED: va_start(ap, cmd); bus = va_arg(ap, int); @@ -3692,6 +3727,7 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...) } break; case ISPASYNC_DEV_CHANGED: + case ISPASYNC_DEV_STAYED: va_start(ap, cmd); bus = va_arg(ap, int); lp = va_arg(ap, fcportdb_t *); @@ -3699,18 +3735,23 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...) fc = ISP_FC_PC(isp, bus); tgt = FC_PORTDB_TGT(isp, bus, lp); isp_gen_role_str(buf, sizeof (buf), lp->new_prli_word3); - isp_prt(isp, ISP_LOGCONFIG, prom, bus, tgt, lp->port_wwn, lp->new_portid, lp->handle, buf, "changed"); -changed: + if (cmd == ISPASYNC_DEV_CHANGED) + isp_prt(isp, ISP_LOGCONFIG, prom, bus, tgt, lp->port_wwn, lp->new_portid, lp->handle, buf, "changed"); + else + isp_prt(isp, ISP_LOGCONFIG, prom, bus, tgt, lp->port_wwn, lp->portid, lp->handle, buf, "stayed"); + if (lp->is_target != ((FCPARAM(isp, bus)->role & ISP_ROLE_INITIATOR) && (lp->new_prli_word3 & PRLI_WD3_TARGET_FUNCTION))) { lp->is_target = !lp->is_target; if (lp->is_target) { - isp_fcp_reset_crn(isp, bus, tgt, /*tgt_set*/ 1); + if (cmd == ISPASYNC_DEV_CHANGED) + isp_fcp_reset_crn(isp, bus, tgt, /*tgt_set*/ 1); isp_make_here(isp, lp, bus, tgt); } else { isp_make_gone(isp, lp, bus, tgt); - isp_fcp_reset_crn(isp, bus, tgt, /*tgt_set*/ 1); + if (cmd == ISPASYNC_DEV_CHANGED) + isp_fcp_reset_crn(isp, bus, tgt, /*tgt_set*/ 1); } } if (lp->is_initiator != @@ -3726,16 +3767,6 @@ changed: xpt_async(AC_CONTRACT, fc->path, &ac); } break; - case ISPASYNC_DEV_STAYED: - va_start(ap, cmd); - bus = va_arg(ap, int); - lp = va_arg(ap, fcportdb_t *); - va_end(ap); - fc = ISP_FC_PC(isp, bus); - tgt = FC_PORTDB_TGT(isp, bus, lp); - isp_gen_role_str(buf, sizeof (buf), lp->prli_word3); - isp_prt(isp, ISP_LOGCONFIG, prom, bus, tgt, lp->port_wwn, lp->portid, lp->handle, buf, "stayed"); - goto changed; case ISPASYNC_DEV_GONE: va_start(ap, cmd); bus = va_arg(ap, int); @@ -3781,10 +3812,45 @@ changed: va_end(ap); if (evt == ISPASYNC_CHANGE_PDB) { + int tgt_set = 0; msg = "Port Database Changed"; isp_prt(isp, ISP_LOGINFO, "Chan %d %s (nphdl 0x%x state 0x%x reason 0x%x)", bus, msg, nphdl, nlstate, reason); + /* + * Port database syncs are not sufficient for + * determining that logins or logouts are done on the + * loop, but this information is directly available from + * the reason code from the incoming mbox. We must reset + * the fcp crn on these events according to FCP-4 + */ + switch (reason) { + case PDB24XX_AE_IMPL_LOGO_1: + case PDB24XX_AE_IMPL_LOGO_2: + case PDB24XX_AE_IMPL_LOGO_3: + case PDB24XX_AE_PLOGI_RCVD: + case PDB24XX_AE_PRLI_RCVD: + case PDB24XX_AE_PRLO_RCVD: + case PDB24XX_AE_LOGO_RCVD: + case PDB24XX_AE_PLOGI_DONE: + case PDB24XX_AE_PRLI_DONE: + /* + * If the event is not global, twiddle tgt and + * tgt_set to nominate only the target + * associated with the nphdl. + */ + if (nphdl != PDB24XX_AE_GLOBAL) { + /* Break if we don't yet have the pdb */ + if (!isp_find_pdb_by_handle(isp, bus, nphdl, &lp)) + break; + tgt = FC_PORTDB_TGT(isp, bus, lp); + tgt_set = 1; + } + isp_fcp_reset_crn(isp, bus, tgt, tgt_set); + break; + default: + break; /* NOP */ + } } else if (evt == ISPASYNC_CHANGE_SNS) { msg = "Name Server Database Changed"; isp_prt(isp, ISP_LOGINFO, "Chan %d %s (PortID 0x%06x)", diff --git a/sys/dev/isp/ispmbox.h b/sys/dev/isp/ispmbox.h index f672b429b59..e747c5544fb 100644 --- a/sys/dev/isp/ispmbox.h +++ b/sys/dev/isp/ispmbox.h @@ -1421,6 +1421,10 @@ typedef struct { /* * Port Database Changed Async Event information for 24XX cards */ +/* N-Port Handle */ +#define PDB24XX_AE_GLOBAL 0xFFFF + +/* Reason Codes */ #define PDB24XX_AE_OK 0x00 #define PDB24XX_AE_IMPL_LOGO_1 0x01 #define PDB24XX_AE_IMPL_LOGO_2 0x02 @@ -1440,7 +1444,7 @@ typedef struct { #define PDB24XX_AE_FLOGI_TIMO 0x10 #define PDB24XX_AE_ABX_LOGO 0x11 #define PDB24XX_AE_PLOGI_DONE 0x12 -#define PDB24XX_AE_PRLI_DONJE 0x13 +#define PDB24XX_AE_PRLI_DONE 0x13 #define PDB24XX_AE_OPN_1 0x14 #define PDB24XX_AE_OPN_2 0x15 #define PDB24XX_AE_TXERR 0x16 diff --git a/sys/dev/isp/ispvar.h b/sys/dev/isp/ispvar.h index a19430ca126..89c132b3987 100644 --- a/sys/dev/isp/ispvar.h +++ b/sys/dev/isp/ispvar.h @@ -502,6 +502,10 @@ typedef struct { #define TOPO_IS_FABRIC(x) ((x) == TOPO_FL_PORT || (x) == TOPO_F_PORT) +#define FCP_AL_DA_ALL 0xFF +#define FCP_AL_PA(fcp) ((uint8_t)(fcp->isp_portid)) +#define FCP_IS_DEST_ALPD(fcp, alpd) (FCP_AL_PA((fcp)) == FCP_AL_DA_ALL || FCP_AL_PA((fcp)) == alpd) + /* * Soft Structure per host adapter */ diff --git a/sys/dev/mlx4/mlx4_en/en.h b/sys/dev/mlx4/mlx4_en/en.h index 337df730665..686896dac39 100644 --- a/sys/dev/mlx4/mlx4_en/en.h +++ b/sys/dev/mlx4/mlx4_en/en.h @@ -587,7 +587,8 @@ struct mlx4_en_priv { struct callout watchdog_timer; struct ifmedia media; volatile int blocked; - struct sysctl_oid *sysctl; + struct sysctl_oid *conf_sysctl; + struct sysctl_oid *stat_sysctl; struct sysctl_ctx_list conf_ctx; struct sysctl_ctx_list stat_ctx; #define MLX4_EN_MAC_HASH_IDX 5 diff --git a/sys/dev/mlx4/mlx4_en/mlx4_en_netdev.c b/sys/dev/mlx4/mlx4_en/mlx4_en_netdev.c index fb958c59180..20a72ad904f 100644 --- a/sys/dev/mlx4/mlx4_en/mlx4_en_netdev.c +++ b/sys/dev/mlx4/mlx4_en/mlx4_en_netdev.c @@ -1639,7 +1639,7 @@ void mlx4_en_free_resources(struct mlx4_en_priv *priv) mlx4_en_destroy_cq(priv, &priv->rx_cq[i]); } - if (priv->sysctl) + if (priv->stat_sysctl != NULL) sysctl_ctx_free(&priv->stat_ctx); } @@ -1754,7 +1754,7 @@ void mlx4_en_destroy_netdev(struct net_device *dev) mlx4_en_free_resources(priv); /* freeing the sysctl conf cannot be called from within mlx4_en_free_resources */ - if (priv->sysctl) + if (priv->conf_sysctl != NULL) sysctl_ctx_free(&priv->conf_ctx); kfree(priv->tx_ring); @@ -2573,9 +2573,9 @@ static void mlx4_en_sysctl_conf(struct mlx4_en_priv *priv) pnameunit = device_get_nameunit(priv->mdev->pdev->dev.bsddev); sysctl_ctx_init(ctx); - priv->sysctl = SYSCTL_ADD_NODE(ctx, SYSCTL_STATIC_CHILDREN(_hw), + priv->conf_sysctl = SYSCTL_ADD_NODE(ctx, SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, dev->if_xname, CTLFLAG_RD, 0, "mlx4 10gig ethernet"); - node = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(priv->sysctl), OID_AUTO, + node = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(priv->conf_sysctl), OID_AUTO, "conf", CTLFLAG_RD, NULL, "Configuration"); node_list = SYSCTL_CHILDREN(node); @@ -2638,7 +2638,6 @@ static void mlx4_en_sysctl_conf(struct mlx4_en_priv *priv) static void mlx4_en_sysctl_stat(struct mlx4_en_priv *priv) { struct sysctl_ctx_list *ctx; - struct sysctl_oid *node; struct sysctl_oid_list *node_list; struct sysctl_oid *ring_node; struct sysctl_oid_list *ring_list; @@ -2649,9 +2648,9 @@ static void mlx4_en_sysctl_stat(struct mlx4_en_priv *priv) ctx = &priv->stat_ctx; sysctl_ctx_init(ctx); - node = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(priv->sysctl), OID_AUTO, + priv->stat_sysctl = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(priv->conf_sysctl), OID_AUTO, "stat", CTLFLAG_RD, NULL, "Statistics"); - node_list = SYSCTL_CHILDREN(node); + node_list = SYSCTL_CHILDREN(priv->stat_sysctl); #ifdef MLX4_EN_PERF_STAT SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "tx_poll", CTLFLAG_RD, diff --git a/sys/dev/mlx5/mlx5_en/mlx5_en_main.c b/sys/dev/mlx5/mlx5_en/mlx5_en_main.c index 8507ed4b2e2..2219f77c629 100644 --- a/sys/dev/mlx5/mlx5_en/mlx5_en_main.c +++ b/sys/dev/mlx5/mlx5_en/mlx5_en_main.c @@ -542,19 +542,33 @@ mlx5e_update_stats_work(struct work_struct *work) s->tx_csum_offload = s->tx_packets - tx_offload_none; s->rx_csum_good = s->rx_packets - s->rx_csum_none; - /* Update per port counters */ + /* Get physical port counters */ mlx5e_update_pport_counters(priv); #if (__FreeBSD_version < 1100000) /* no get_counters interface in fbsd 10 */ ifp->if_ipackets = s->rx_packets; - ifp->if_ierrors = s->rx_error_packets; + ifp->if_ierrors = s->rx_error_packets + + priv->stats.pport.alignment_err + + priv->stats.pport.check_seq_err + + priv->stats.pport.crc_align_errors + + priv->stats.pport.drop_events + + priv->stats.pport.in_range_len_errors + + priv->stats.pport.jabbers + + priv->stats.pport.out_of_range_len + + priv->stats.pport.oversize_pkts + + priv->stats.pport.symbol_err + + priv->stats.pport.too_long_errors + + priv->stats.pport.undersize_pkts + + priv->stats.pport.unsupported_op_rx; ifp->if_iqdrops = s->rx_out_of_buffer; ifp->if_opackets = s->tx_packets; ifp->if_oerrors = s->tx_error_packets; ifp->if_snd.ifq_drops = s->tx_queue_dropped; ifp->if_ibytes = s->rx_bytes; ifp->if_obytes = s->tx_bytes; + ifp->if_collisions = + priv->stats.pport.collisions; #endif free_out: @@ -2449,7 +2463,19 @@ mlx5e_get_counter(struct ifnet *ifp, ift_counter cnt) retval = priv->stats.vport.rx_packets; break; case IFCOUNTER_IERRORS: - retval = priv->stats.vport.rx_error_packets; + retval = priv->stats.vport.rx_error_packets + + priv->stats.pport.alignment_err + + priv->stats.pport.check_seq_err + + priv->stats.pport.crc_align_errors + + priv->stats.pport.drop_events + + priv->stats.pport.in_range_len_errors + + priv->stats.pport.jabbers + + priv->stats.pport.out_of_range_len + + priv->stats.pport.oversize_pkts + + priv->stats.pport.symbol_err + + priv->stats.pport.too_long_errors + + priv->stats.pport.undersize_pkts + + priv->stats.pport.unsupported_op_rx; break; case IFCOUNTER_IQDROPS: retval = priv->stats.vport.rx_out_of_buffer; @@ -2475,6 +2501,9 @@ mlx5e_get_counter(struct ifnet *ifp, ift_counter cnt) case IFCOUNTER_OQDROPS: retval = priv->stats.vport.tx_queue_dropped; break; + case IFCOUNTER_COLLISIONS: + retval = priv->stats.pport.collisions; + break; default: retval = if_get_counter_default(ifp, cnt); break; diff --git a/sys/dev/nand/nandsim.c b/sys/dev/nand/nandsim.c index aeb35f352b7..a1ac13ab763 100644 --- a/sys/dev/nand/nandsim.c +++ b/sys/dev/nand/nandsim.c @@ -71,6 +71,7 @@ static struct nandsim_chip *get_nandsim_chip(uint8_t, uint8_t); static struct cdevsw nandsim_cdevsw = { .d_version = D_VERSION, + .d_flags = D_NEEDGIANT, .d_ioctl = nandsim_ioctl, .d_name = "nandsim", }; @@ -639,7 +640,7 @@ nandsim_modevent(module_t mod __unused, int type, void *data __unused) switch (type) { case MOD_LOAD: nandsim_dev = make_dev(&nandsim_cdevsw, 0, - UID_ROOT, GID_WHEEL, 0666, "nandsim.ioctl"); + UID_ROOT, GID_WHEEL, 0600, "nandsim.ioctl"); break; case MOD_UNLOAD: for (i = 0; i < MAX_SIM_DEV; i++) { diff --git a/sys/dev/pci/pci_pci.c b/sys/dev/pci/pci_pci.c index 2fc3504ecea..cf11334d416 100644 --- a/sys/dev/pci/pci_pci.c +++ b/sys/dev/pci/pci_pci.c @@ -76,7 +76,7 @@ static void pcib_pcie_ab_timeout(void *arg); static void pcib_pcie_cc_timeout(void *arg); static void pcib_pcie_dll_timeout(void *arg); #endif -static int pcib_request_feature(device_t pcib, device_t dev, +static int pcib_request_feature_default(device_t pcib, device_t dev, enum pci_feature feature); static device_method_t pcib_methods[] = { @@ -121,7 +121,7 @@ static device_method_t pcib_methods[] = { DEVMETHOD(pcib_try_enable_ari, pcib_try_enable_ari), DEVMETHOD(pcib_ari_enabled, pcib_ari_enabled), DEVMETHOD(pcib_decode_rid, pcib_ari_decode_rid), - DEVMETHOD(pcib_request_feature, pcib_request_feature), + DEVMETHOD(pcib_request_feature, pcib_request_feature_default), DEVMETHOD_END }; @@ -964,8 +964,7 @@ pcib_probe_hotplug(struct pcib_softc *sc) * Now that we're sure we want to do hot plug, ask the * firmware, if any, if that's OK. */ - if (pcib_request_feature(device_get_parent(device_get_parent(dev)), dev, - PCI_FEATURE_HP) != 0) { + if (pcib_request_feature(dev, PCI_FEATURE_HP) != 0) { if (bootverbose) device_printf(dev, "Unable to activate hot plug feature.\n"); return; @@ -2863,6 +2862,17 @@ pcib_request_feature_allow(device_t pcib, device_t dev, return (0); } +int +pcib_request_feature(device_t dev, enum pci_feature feature) +{ + + /* + * Invoke PCIB_REQUEST_FEATURE of this bridge first in case + * the firmware overrides the method of PCI-PCI bridges. + */ + return (PCIB_REQUEST_FEATURE(dev, dev, feature)); +} + /* * Pass the request to use this PCI feature up the tree. Either there's a * firmware like ACPI that's using this feature that will approve (or deny) the @@ -2871,7 +2881,8 @@ pcib_request_feature_allow(device_t pcib, device_t dev, * to make use of the feature or render it harmless. */ static int -pcib_request_feature(device_t pcib, device_t dev, enum pci_feature feature) +pcib_request_feature_default(device_t pcib, device_t dev, + enum pci_feature feature) { device_t bus; diff --git a/sys/dev/pci/pcib_private.h b/sys/dev/pci/pcib_private.h index 1004e1339d7..5482e12d5bb 100644 --- a/sys/dev/pci/pcib_private.h +++ b/sys/dev/pci/pcib_private.h @@ -193,6 +193,7 @@ int pcib_get_id(device_t pcib, device_t dev, enum pci_id_type type, uintptr_t *id); void pcib_decode_rid(device_t pcib, uint16_t rid, int *bus, int *slot, int *func); +int pcib_request_feature(device_t dev, enum pci_feature feature); int pcib_request_feature_allow(device_t pcib, device_t dev, enum pci_feature feature); #endif diff --git a/sys/dev/sdhci/sdhci_fdt.c b/sys/dev/sdhci/sdhci_fdt.c index 2e1b30e4b37..c5c300a2774 100644 --- a/sys/dev/sdhci/sdhci_fdt.c +++ b/sys/dev/sdhci/sdhci_fdt.c @@ -70,6 +70,9 @@ struct sdhci_fdt_softc { int num_slots; /* Number of slots on this controller*/ struct sdhci_slot slots[MAX_SLOTS]; struct resource *mem_res[MAX_SLOTS]; /* Memory resource */ + + bool wp_inverted; /* WP pin is inverted */ + bool no_18v; /* No 1.8V support */ }; static uint8_t @@ -110,8 +113,13 @@ static uint32_t sdhci_fdt_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t off) { struct sdhci_fdt_softc *sc = device_get_softc(dev); + uint32_t val32; - return (bus_read_4(sc->mem_res[slot->num], off)); + val32 = bus_read_4(sc->mem_res[slot->num], off); + if (off == SDHCI_CAPABILITIES && sc->no_18v) + val32 &= ~SDHCI_CAN_VDD_180; + + return (val32); } static void @@ -151,6 +159,14 @@ sdhci_fdt_intr(void *arg) sdhci_generic_intr(&sc->slots[i]); } +static int +sdhci_fdt_get_ro(device_t bus, device_t dev) +{ + struct sdhci_fdt_softc *sc = device_get_softc(bus); + + return (sdhci_generic_get_ro(bus, dev) ^ sc->wp_inverted); +} + static int sdhci_fdt_probe(device_t dev) { @@ -182,6 +198,10 @@ sdhci_fdt_probe(device_t dev) sc->num_slots = cid; if ((OF_getencprop(node, "max-frequency", &cid, sizeof(cid))) > 0) sc->max_clk = cid; + if (OF_hasprop(node, "no-1-8-v")) + sc->no_18v = true; + if (OF_hasprop(node, "wp-inverted")) + sc->wp_inverted = true; return (0); } @@ -279,7 +299,7 @@ static device_method_t sdhci_fdt_methods[] = { /* mmcbr_if */ DEVMETHOD(mmcbr_update_ios, sdhci_generic_update_ios), DEVMETHOD(mmcbr_request, sdhci_generic_request), - DEVMETHOD(mmcbr_get_ro, sdhci_generic_get_ro), + DEVMETHOD(mmcbr_get_ro, sdhci_fdt_get_ro), DEVMETHOD(mmcbr_acquire_host, sdhci_generic_acquire_host), DEVMETHOD(mmcbr_release_host, sdhci_generic_release_host), diff --git a/sys/dev/sound/pcm/feeder_matrix.c b/sys/dev/sound/pcm/feeder_matrix.c index e59c1247fd5..5274ed46b79 100644 --- a/sys/dev/sound/pcm/feeder_matrix.c +++ b/sys/dev/sound/pcm/feeder_matrix.c @@ -750,8 +750,8 @@ feeder_matrix_oss_get_channel_order(struct pcmchan_matrix *m, tmpmap = 0x0000000000000000ULL; - for (i = 0; m->map[i].type != SND_CHN_T_MAX && - i < SND_CHN_OSS_MAX; i++) { + for (i = 0; i < SND_CHN_OSS_MAX && m->map[i].type != SND_CHN_T_MAX; + i++) { if ((1 << m->map[i].type) & ~SND_CHN_OSS_VALIDMASK) return (EINVAL); tmpmap |= diff --git a/sys/dev/uart/uart_dev_lpc.c b/sys/dev/uart/uart_dev_lpc.c index 306c9f15150..48d7be3d02d 100644 --- a/sys/dev/uart/uart_dev_lpc.c +++ b/sys/dev/uart/uart_dev_lpc.c @@ -345,9 +345,6 @@ lpc_ns8250_putc(struct uart_bas *bas, int c) DELAY(4); uart_setreg(bas, REG_DATA, c); uart_barrier(bas); - limit = 250000; - while ((uart_getreg(bas, REG_LSR) & LSR_TEMT) == 0 && --limit) - DELAY(4); } static int @@ -890,8 +887,13 @@ lpc_ns8250_bus_transmit(struct uart_softc *sc) bas = &sc->sc_bas; uart_lock(sc->sc_hwmtx); - while ((uart_getreg(bas, REG_LSR) & LSR_THRE) == 0) - ; + if (sc->sc_txdatasz > 1) { + if ((uart_getreg(bas, REG_LSR) & LSR_TEMT) == 0) + lpc_ns8250_drain(bas, UART_DRAIN_TRANSMITTER); + } else { + while ((uart_getreg(bas, REG_LSR) & LSR_THRE) == 0) + DELAY(4); + } for (i = 0; i < sc->sc_txdatasz; i++) { uart_setreg(bas, REG_DATA, sc->sc_txbuf[i]); uart_barrier(bas); diff --git a/sys/dev/uart/uart_dev_ns8250.c b/sys/dev/uart/uart_dev_ns8250.c index 74d7bb7c1f9..dbb013c3e95 100644 --- a/sys/dev/uart/uart_dev_ns8250.c +++ b/sys/dev/uart/uart_dev_ns8250.c @@ -315,7 +315,7 @@ ns8250_init(struct uart_bas *bas, int baudrate, int databits, int stopbits, /* Disable the FIFO (if present). */ val = 0; #ifdef CPU_XBURST - val = FCR_UART_ON; + val |= FCR_UART_ON; #endif uart_setreg(bas, REG_FCR, val); uart_barrier(bas); @@ -346,9 +346,6 @@ ns8250_putc(struct uart_bas *bas, int c) DELAY(4); uart_setreg(bas, REG_DATA, c); uart_barrier(bas); - limit = 250000; - while ((uart_getreg(bas, REG_LSR) & LSR_TEMT) == 0 && --limit) - DELAY(4); } static int @@ -999,8 +996,13 @@ ns8250_bus_transmit(struct uart_softc *sc) bas = &sc->sc_bas; uart_lock(sc->sc_hwmtx); - while ((uart_getreg(bas, REG_LSR) & LSR_THRE) == 0) - ; + if (sc->sc_txdatasz > 1) { + if ((uart_getreg(bas, REG_LSR) & LSR_TEMT) == 0) + ns8250_drain(bas, UART_DRAIN_TRANSMITTER); + } else { + while ((uart_getreg(bas, REG_LSR) & LSR_THRE) == 0) + DELAY(4); + } for (i = 0; i < sc->sc_txdatasz; i++) { uart_setreg(bas, REG_DATA, sc->sc_txbuf[i]); uart_barrier(bas); diff --git a/sys/dev/vt/vt_core.c b/sys/dev/vt/vt_core.c index 72d30364bb3..8320231fc12 100644 --- a/sys/dev/vt/vt_core.c +++ b/sys/dev/vt/vt_core.c @@ -1150,29 +1150,28 @@ vt_mark_mouse_position_as_dirty(struct vt_device *vd) #endif static void -vt_set_border(struct vt_window *vw, term_color_t c) +vt_set_border(struct vt_device *vd, term_color_t c) { - struct vt_device *vd = vw->vw_device; - term_rect_t *vda = &vw->vw_draw_area; + term_rect_t *tarea = &vd->vd_curwindow->vw_draw_area; int x, y; /* Top bar. */ - for (y = 0; y < vda->tr_begin.tp_row; y++) + for (y = 0; y < tarea->tr_begin.tp_row; y++) for (x = 0; x < vd->vd_width; x++) vd->vd_driver->vd_setpixel(vd, x, y, c); - for (y = vda->tr_begin.tp_row; y <= vda->tr_end.tp_row; y++) { + for (y = tarea->tr_begin.tp_row; y < tarea->tr_end.tp_row; y++) { /* Left bar. */ - for (x = 0; x < vda->tr_begin.tp_col; x++) + for (x = 0; x < tarea->tr_begin.tp_col; x++) vd->vd_driver->vd_setpixel(vd, x, y, c); /* Right bar. */ - for (x = vda->tr_end.tp_col + 1; x < vd->vd_width; x++) + for (x = tarea->tr_end.tp_col; x < vd->vd_width; x++) vd->vd_driver->vd_setpixel(vd, x, y, c); } /* Bottom bar. */ - for (y = vda->tr_end.tp_row + 1; y < vd->vd_height; y++) + for (y = tarea->tr_end.tp_row; y < vd->vd_height; y++) for (x = 0; x < vd->vd_width; x++) vd->vd_driver->vd_setpixel(vd, x, y, c); } @@ -1242,7 +1241,7 @@ vt_flush(struct vt_device *vd) if (vd->vd_flags & VDF_INVALID) { vd->vd_flags &= ~VDF_INVALID; - vt_set_border(vw, TC_BLACK); + vt_set_border(vd, TC_BLACK); vt_termrect(vd, vf, &tarea); if (vt_draw_logo_cpus) vtterm_draw_cpu_logos(vd); diff --git a/sys/fs/ext2fs/ext2_alloc.c b/sys/fs/ext2fs/ext2_alloc.c index 46f16084698..55c1471201b 100644 --- a/sys/fs/ext2fs/ext2_alloc.c +++ b/sys/fs/ext2fs/ext2_alloc.c @@ -131,6 +131,25 @@ nospace: return (ENOSPC); } +/* + * Allocate EA's block for inode. + */ +daddr_t +ext2_allocfacl(struct inode *ip) +{ + struct m_ext2fs *fs; + daddr_t facl; + + fs = ip->i_e2fs; + + EXT2_LOCK(ip->i_ump); + facl = ext2_alloccg(ip, ino_to_cg(fs, ip->i_number), 0, fs->e2fs_bsize); + if (0 == facl) + EXT2_UNLOCK(ip->i_ump); + + return (facl); +} + /* * Reallocate a sequence of blocks into a contiguous sequence of blocks. * diff --git a/sys/fs/ext2fs/ext2_extattr.c b/sys/fs/ext2fs/ext2_extattr.c index 27f4405722a..28ba8f9ad1a 100644 --- a/sys/fs/ext2fs/ext2_extattr.c +++ b/sys/fs/ext2fs/ext2_extattr.c @@ -44,21 +44,66 @@ #include #include #include +#include static int ext2_extattr_index_to_bsd(int index) { switch (index) { - case EXT4_XATTR_INDEX_USER: - return EXTATTR_NAMESPACE_USER; - case EXT4_XATTR_INDEX_SYSTEM: - return EXTATTR_NAMESPACE_SYSTEM; + return (EXTATTR_NAMESPACE_SYSTEM); - default: - return EXTATTR_NAMESPACE_EMPTY; + case EXT4_XATTR_INDEX_USER: + return (EXTATTR_NAMESPACE_USER); } + + return (EXTATTR_NAMESPACE_EMPTY); +} + +static int +ext2_extattr_index_to_linux(int index) +{ + switch (index) { + case EXTATTR_NAMESPACE_SYSTEM: + return (EXT4_XATTR_INDEX_SYSTEM); + + case EXTATTR_NAMESPACE_USER: + return (EXT4_XATTR_INDEX_USER); + } + + return (-1); +} + +int +ext2_extattr_valid_attrname(int attrnamespace, const char *attrname) +{ + if (attrnamespace == EXTATTR_NAMESPACE_EMPTY) + return (EINVAL); + + if (strlen(attrname) == 0) + return (EINVAL); + + if (strlen(attrname) + 1 > EXT2_EXTATTR_NAMELEN_MAX) + return (ENAMETOOLONG); + + return (0); +} + +static int +ext2_extattr_check(struct ext2fs_extattr_entry *entry, char *end) +{ + struct ext2fs_extattr_entry *next; + + while (!EXT2_IS_LAST_ENTRY(entry)) { + next = EXT2_EXTATTR_NEXT(entry); + if ((char *)next >= end) + return (EIO); + + entry = next; + } + + return (0); } int @@ -69,8 +114,6 @@ ext2_extattr_inode_list(struct inode *ip, int attrnamespace, struct buf *bp; struct ext2fs_extattr_dinode_header *header; struct ext2fs_extattr_entry *entry; - struct ext2fs_extattr_entry *next; - char *end; int error; fs = ip->i_e2fs; @@ -95,21 +138,15 @@ ext2_extattr_inode_list(struct inode *ip, int attrnamespace, return (0); } - /* Check attributes integrity */ - entry = EXT2_IFIRST(header); - end = (char *)dinode + EXT2_INODE_SIZE(fs); - while (!EXT2_IS_LAST_ENTRY(entry)) { - next = EXT2_EXTATTR_NEXT(entry); - if ((char *)next >= end) { - brelse(bp); - return (EIO); - } - - entry = next; + error = ext2_extattr_check(EXT2_IFIRST(header), + (char *)dinode + EXT2_INODE_SIZE(fs)); + if (error) { + brelse(bp); + return (error); } for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry); - entry = EXT2_EXTATTR_NEXT(entry)) { + entry = EXT2_EXTATTR_NEXT(entry)) { if (ext2_extattr_index_to_bsd(entry->e_name_index) != attrnamespace) continue; @@ -121,12 +158,14 @@ ext2_extattr_inode_list(struct inode *ip, int attrnamespace, memcpy(&attr_name[1], entry->e_name, entry->e_name_len); error = uiomove(attr_name, entry->e_name_len + 1, uio); free(attr_name, M_TEMP); + if (error) + break; } } brelse(bp); - return (0); + return (error); } int @@ -137,8 +176,6 @@ ext2_extattr_block_list(struct inode *ip, int attrnamespace, struct buf *bp; struct ext2fs_extattr_header *header; struct ext2fs_extattr_entry *entry; - struct ext2fs_extattr_entry *next; - char *end; int error; fs = ip->i_e2fs; @@ -157,17 +194,10 @@ ext2_extattr_block_list(struct inode *ip, int attrnamespace, return (EINVAL); } - /* Check attributes integrity */ - end = bp->b_data + bp->b_bufsize; - entry = EXT2_FIRST_ENTRY(bp); - while (!EXT2_IS_LAST_ENTRY(entry)) { - next = EXT2_EXTATTR_NEXT(entry); - if ((char *)next >= end) { - brelse(bp); - return (EIO); - } - - entry = next; + error = ext2_extattr_check(EXT2_FIRST_ENTRY(bp), bp->b_data + bp->b_bufsize); + if (error) { + brelse(bp); + return (error); } for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry); @@ -183,12 +213,14 @@ ext2_extattr_block_list(struct inode *ip, int attrnamespace, memcpy(&attr_name[1], entry->e_name, entry->e_name_len); error = uiomove(attr_name, entry->e_name_len + 1, uio); free(attr_name, M_TEMP); + if (error) + break; } } brelse(bp); - return (0); + return (error); } int @@ -199,8 +231,6 @@ ext2_extattr_inode_get(struct inode *ip, int attrnamespace, struct buf *bp; struct ext2fs_extattr_dinode_header *header; struct ext2fs_extattr_entry *entry; - struct ext2fs_extattr_entry *next; - char *end; int error; fs = ip->i_e2fs; @@ -222,20 +252,14 @@ ext2_extattr_inode_get(struct inode *ip, int attrnamespace, if (header->h_magic != EXTATTR_MAGIC) { brelse(bp); - return (0); + return (ENOATTR); } - /* Check attributes integrity */ - entry = EXT2_IFIRST(header); - end = (char *)dinode + EXT2_INODE_SIZE(fs); - while (!EXT2_IS_LAST_ENTRY(entry)) { - next = EXT2_EXTATTR_NEXT(entry); - if ((char *)next >= end) { - brelse(bp); - return (EIO); - } - - entry = next; + error = ext2_extattr_check(EXT2_IFIRST(header), + (char *)dinode + EXT2_INODE_SIZE(fs)); + if (error) { + brelse(bp); + return (error); } for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry); @@ -248,19 +272,18 @@ ext2_extattr_inode_get(struct inode *ip, int attrnamespace, if (uio == NULL) *size += entry->e_value_size; else { - error = uiomove(((char *)EXT2_IFIRST(header)) + entry->e_value_offs, - entry->e_value_size, uio); - if (error) { - brelse(bp); - return (error); - } + error = uiomove(((char *)EXT2_IFIRST(header)) + + entry->e_value_offs, entry->e_value_size, uio); } + + brelse(bp); + return (error); } } brelse(bp); - return (0); + return (ENOATTR); } int @@ -271,8 +294,6 @@ ext2_extattr_block_get(struct inode *ip, int attrnamespace, struct buf *bp; struct ext2fs_extattr_header *header; struct ext2fs_extattr_entry *entry; - struct ext2fs_extattr_entry *next; - char *end; int error; fs = ip->i_e2fs; @@ -291,17 +312,10 @@ ext2_extattr_block_get(struct inode *ip, int attrnamespace, return (EINVAL); } - /* Check attributes integrity */ - end = bp->b_data + bp->b_bufsize; - entry = EXT2_FIRST_ENTRY(bp); - while (!EXT2_IS_LAST_ENTRY(entry)) { - next = EXT2_EXTATTR_NEXT(entry); - if ((char *)next >= end) { - brelse(bp); - return (EIO); - } - - entry = next; + error = ext2_extattr_check(EXT2_FIRST_ENTRY(bp), bp->b_data + bp->b_bufsize); + if (error) { + brelse(bp); + return (error); } for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry); @@ -316,15 +330,725 @@ ext2_extattr_block_get(struct inode *ip, int attrnamespace, else { error = uiomove(bp->b_data + entry->e_value_offs, entry->e_value_size, uio); - if (error) { - brelse(bp); - return (error); - } } + + brelse(bp); + return (error); } } brelse(bp); + return (ENOATTR); +} + +static uint16_t +ext2_extattr_delete_value(char *off, + struct ext2fs_extattr_entry *first_entry, + struct ext2fs_extattr_entry *entry, char *end) +{ + uint16_t min_offs; + struct ext2fs_extattr_entry *next; + + min_offs = end - off; + next = first_entry; + while (!EXT2_IS_LAST_ENTRY(next)) { + if (min_offs > next->e_value_offs && next->e_value_offs > 0) + min_offs = next->e_value_offs; + + next = EXT2_EXTATTR_NEXT(next); + } + + if (entry->e_value_size == 0) + return (min_offs); + + memmove(off + min_offs + EXT2_EXTATTR_SIZE(entry->e_value_size), + off + min_offs, entry->e_value_offs - min_offs); + + /* Adjust all value offsets */ + next = first_entry; + while (!EXT2_IS_LAST_ENTRY(next)) + { + if (next->e_value_offs > 0 && + next->e_value_offs < entry->e_value_offs) + next->e_value_offs += + EXT2_EXTATTR_SIZE(entry->e_value_size); + + next = EXT2_EXTATTR_NEXT(next); + } + + min_offs += EXT2_EXTATTR_SIZE(entry->e_value_size); + + return (min_offs); +} + +static void +ext2_extattr_delete_entry(char *off, + struct ext2fs_extattr_entry *first_entry, + struct ext2fs_extattr_entry *entry, char *end) +{ + char *pad; + struct ext2fs_extattr_entry *next; + + /* Clean entry value */ + ext2_extattr_delete_value(off, first_entry, entry, end); + + /* Clean the entry */ + next = first_entry; + while (!EXT2_IS_LAST_ENTRY(next)) + next = EXT2_EXTATTR_NEXT(next); + + pad = (char*)next + sizeof(uint32_t); + + memmove(entry, (char *)entry + EXT2_EXTATTR_LEN(entry->e_name_len), + pad - ((char *)entry + EXT2_EXTATTR_LEN(entry->e_name_len))); +} + +int +ext2_extattr_inode_delete(struct inode *ip, int attrnamespace, const char *name) +{ + struct m_ext2fs *fs; + struct buf *bp; + struct ext2fs_extattr_dinode_header *header; + struct ext2fs_extattr_entry *entry; + int error; + + fs = ip->i_e2fs; + + if ((error = bread(ip->i_devvp, + fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), + (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) { + brelse(bp); + return (error); + } + + struct ext2fs_dinode *dinode = (struct ext2fs_dinode *) + ((char *)bp->b_data + + EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number)); + + /* Check attributes magic value */ + header = (struct ext2fs_extattr_dinode_header *)((char *)dinode + + E2FS_REV0_INODE_SIZE + dinode->e2di_extra_isize); + + if (header->h_magic != EXTATTR_MAGIC) { + brelse(bp); + return (ENOATTR); + } + + error = ext2_extattr_check(EXT2_IFIRST(header), + (char *)dinode + EXT2_INODE_SIZE(fs)); + if (error) { + brelse(bp); + return (error); + } + + /* If I am last entry, just make magic zero */ + entry = EXT2_IFIRST(header); + if (EXT2_IS_LAST_ENTRY(EXT2_EXTATTR_NEXT(entry))) { + if (strlen(name) == entry->e_name_len && + 0 == strncmp(entry->e_name, name, entry->e_name_len)) { + memset(header, 0, sizeof(struct ext2fs_extattr_dinode_header)); + + return (bwrite(bp)); + } + } + + for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry); + entry = EXT2_EXTATTR_NEXT(entry)) { + if (ext2_extattr_index_to_bsd(entry->e_name_index) != attrnamespace) + continue; + + if (strlen(name) == entry->e_name_len && + 0 == strncmp(entry->e_name, name, entry->e_name_len)) { + ext2_extattr_delete_entry((char *)EXT2_IFIRST(header), + EXT2_IFIRST(header), entry, + (char *)dinode + EXT2_INODE_SIZE(fs)); + + return (bwrite(bp)); + } + } + + brelse(bp); + + return (ENOATTR); +} + +static int +ext2_extattr_block_clone(struct inode *ip, struct buf **bpp) +{ + struct m_ext2fs *fs; + struct buf *sbp; + struct buf *cbp; + struct ext2fs_extattr_header *header; + uint64_t facl; + + fs = ip->i_e2fs; + sbp = *bpp; + + header = EXT2_HDR(sbp); + if (header->h_magic != EXTATTR_MAGIC || header->h_refcount == 1) + return (EINVAL); + + facl = ext2_allocfacl(ip); + if (!facl) + return (ENOSPC); + + cbp = getblk(ip->i_devvp, fsbtodb(fs, facl), fs->e2fs_bsize, 0, 0, 0); + if (!cbp) { + ext2_blkfree(ip, facl, fs->e2fs_bsize); + return (EIO); + } + + memcpy(cbp->b_data, sbp->b_data, fs->e2fs_bsize); + header->h_refcount--; + bwrite(sbp); + + ip->i_facl = facl; + ext2_update(ip->i_vnode, 1); + + header = EXT2_HDR(cbp); + header->h_refcount = 1; + + *bpp = cbp; + + return (0); +} + +int +ext2_extattr_block_delete(struct inode *ip, int attrnamespace, const char *name) +{ + struct m_ext2fs *fs; + struct buf *bp; + struct ext2fs_extattr_header *header; + struct ext2fs_extattr_entry *entry; + int error; + + fs = ip->i_e2fs; + + error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl), + fs->e2fs_bsize, NOCRED, &bp); + if (error) { + brelse(bp); + return (error); + } + + /* Check attributes magic value */ + header = EXT2_HDR(bp); + if (header->h_magic != EXTATTR_MAGIC || header->h_blocks != 1) { + brelse(bp); + return (EINVAL); + } + + error = ext2_extattr_check(EXT2_FIRST_ENTRY(bp), bp->b_data + bp->b_bufsize); + if (error) { + brelse(bp); + return (error); + } + + if (header->h_refcount > 1) { + error = ext2_extattr_block_clone(ip, &bp); + if (error) { + brelse(bp); + return (error); + } + } + + /* If I am last entry, clean me and free the block */ + entry = EXT2_FIRST_ENTRY(bp); + if (EXT2_IS_LAST_ENTRY(EXT2_EXTATTR_NEXT(entry))) { + if (strlen(name) == entry->e_name_len && + 0 == strncmp(entry->e_name, name, entry->e_name_len)) { + ip->i_blocks -= btodb(fs->e2fs_bsize); + ext2_blkfree(ip, ip->i_facl, fs->e2fs_bsize); + ip->i_facl = 0; + error = ext2_update(ip->i_vnode, 1); + + brelse(bp); + return (error); + } + } + + for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry); + entry = EXT2_EXTATTR_NEXT(entry)) { + if (ext2_extattr_index_to_bsd(entry->e_name_index) != attrnamespace) + continue; + + if (strlen(name) == entry->e_name_len && + 0 == strncmp(entry->e_name, name, entry->e_name_len)) { + ext2_extattr_delete_entry(bp->b_data, + EXT2_FIRST_ENTRY(bp), entry, + bp->b_data + bp->b_bufsize); + + return (bwrite(bp)); + } + } + + brelse(bp); + + return (ENOATTR); +} + +static struct ext2fs_extattr_entry * +allocate_entry(const char *name, int attrnamespace, uint16_t offs, + uint32_t size, uint32_t hash) +{ + size_t name_len; + struct ext2fs_extattr_entry *entry; + + name_len = strlen(name); + entry = malloc(sizeof(struct ext2fs_extattr_entry) + name_len, + M_TEMP, M_WAITOK); + + entry->e_name_len = name_len; + entry->e_name_index = ext2_extattr_index_to_linux(attrnamespace); + entry->e_value_offs = offs; + entry->e_value_block = 0; + entry->e_value_size = size; + entry->e_hash = hash; + memcpy(entry->e_name, name, name_len); + + return (entry); +} + +static void +free_entry(struct ext2fs_extattr_entry *entry) +{ + + free(entry, M_TEMP); +} + +static int +ext2_extattr_get_size(struct ext2fs_extattr_entry *first_entry, + struct ext2fs_extattr_entry *exist_entry, int header_size, + int name_len, int new_size) +{ + struct ext2fs_extattr_entry *entry; + int size; + + size = header_size; + size += sizeof(uint32_t); + + if (NULL == exist_entry) { + size += EXT2_EXTATTR_LEN(name_len); + size += EXT2_EXTATTR_SIZE(new_size); + } + + if (first_entry) + for (entry = first_entry; !EXT2_IS_LAST_ENTRY(entry); + entry = EXT2_EXTATTR_NEXT(entry)) { + if (entry != exist_entry) + size += EXT2_EXTATTR_LEN(entry->e_name_len) + + EXT2_EXTATTR_SIZE(entry->e_value_size); + else + size += EXT2_EXTATTR_LEN(entry->e_name_len) + + EXT2_EXTATTR_SIZE(new_size); + } + + return (size); +} + +static void +ext2_extattr_set_exist_entry(char *off, + struct ext2fs_extattr_entry *first_entry, + struct ext2fs_extattr_entry *entry, + char *end, struct uio *uio) +{ + uint16_t min_offs; + + min_offs = ext2_extattr_delete_value(off, first_entry, entry, end); + + entry->e_value_size = uio->uio_resid; + if (entry->e_value_size) + entry->e_value_offs = min_offs - + EXT2_EXTATTR_SIZE(uio->uio_resid); + else + entry->e_value_offs = 0; + + uiomove(off + entry->e_value_offs, entry->e_value_size, uio); +} + +static struct ext2fs_extattr_entry * +ext2_extattr_set_new_entry(char *off, struct ext2fs_extattr_entry *first_entry, + const char *name, int attrnamespace, char *end, struct uio *uio) +{ + int name_len; + char *pad; + uint16_t min_offs; + struct ext2fs_extattr_entry *entry; + struct ext2fs_extattr_entry *new_entry; + + /* Find pad's */ + min_offs = end - off; + entry = first_entry; + while (!EXT2_IS_LAST_ENTRY(entry)) { + if (min_offs > entry->e_value_offs && entry->e_value_offs > 0) + min_offs = entry->e_value_offs; + + entry = EXT2_EXTATTR_NEXT(entry); + } + + pad = (char*)entry + sizeof(uint32_t); + + /* Find entry insert position */ + name_len = strlen(name); + entry = first_entry; + while (!EXT2_IS_LAST_ENTRY(entry)) { + if (!(attrnamespace - entry->e_name_index) && + !(name_len - entry->e_name_len)) + if (memcmp(name, entry->e_name, name_len) <= 0) + break; + + entry = EXT2_EXTATTR_NEXT(entry); + } + + /* Create new entry and insert it */ + new_entry = allocate_entry(name, attrnamespace, 0, uio->uio_resid, 0); + memmove((char *)entry + EXT2_EXTATTR_LEN(new_entry->e_name_len), entry, + pad - (char*)entry); + + memcpy(entry, new_entry, EXT2_EXTATTR_LEN(new_entry->e_name_len)); + free_entry(new_entry); + + new_entry = entry; + if (new_entry->e_value_size > 0) + new_entry->e_value_offs = min_offs - + EXT2_EXTATTR_SIZE(new_entry->e_value_size); + + uiomove(off + new_entry->e_value_offs, new_entry->e_value_size, uio); + + return (new_entry); +} + +int +ext2_extattr_inode_set(struct inode *ip, int attrnamespace, + const char *name, struct uio *uio) +{ + struct m_ext2fs *fs; + struct buf *bp; + struct ext2fs_extattr_dinode_header *header; + struct ext2fs_extattr_entry *entry; + size_t size = 0, max_size; + int error; + + fs = ip->i_e2fs; + + if ((error = bread(ip->i_devvp, + fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), + (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) { + brelse(bp); + return (error); + } + + struct ext2fs_dinode *dinode = (struct ext2fs_dinode *) + ((char *)bp->b_data + + EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number)); + + /* Check attributes magic value */ + header = (struct ext2fs_extattr_dinode_header *)((char *)dinode + + E2FS_REV0_INODE_SIZE + dinode->e2di_extra_isize); + + if (header->h_magic != EXTATTR_MAGIC) { + brelse(bp); + return (ENOSPC); + } + + error = ext2_extattr_check(EXT2_IFIRST(header), (char *)dinode + + EXT2_INODE_SIZE(fs)); + if (error) { + brelse(bp); + return (error); + } + + /* Find if entry exist */ + for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry); + entry = EXT2_EXTATTR_NEXT(entry)) { + if (ext2_extattr_index_to_bsd(entry->e_name_index) != attrnamespace) + continue; + + if (strlen(name) == entry->e_name_len && + 0 == strncmp(entry->e_name, name, entry->e_name_len)) + break; + } + + max_size = EXT2_INODE_SIZE(fs) - E2FS_REV0_INODE_SIZE - + dinode->e2di_extra_isize; + + if (!EXT2_IS_LAST_ENTRY(entry)) { + size = ext2_extattr_get_size(EXT2_IFIRST(header), entry, + sizeof(struct ext2fs_extattr_dinode_header), + entry->e_name_len, uio->uio_resid); + if (size > max_size) { + brelse(bp); + return (ENOSPC); + } + + ext2_extattr_set_exist_entry((char *)EXT2_IFIRST(header), + EXT2_IFIRST(header), entry, (char *)header + max_size, uio); + } else { + /* Ensure that the same entry does not exist in the block */ + if (ip->i_facl) { + error = ext2_extattr_block_get(ip, attrnamespace, name, + NULL, &size); + if (error != ENOATTR || size > 0) { + brelse(bp); + if (size > 0) + error = ENOSPC; + + return (error); + } + } + + size = ext2_extattr_get_size(EXT2_IFIRST(header), NULL, + sizeof(struct ext2fs_extattr_dinode_header), + entry->e_name_len, uio->uio_resid); + if (size > max_size) { + brelse(bp); + return (ENOSPC); + } + + ext2_extattr_set_new_entry((char *)EXT2_IFIRST(header), + EXT2_IFIRST(header), name, attrnamespace, + (char *)header + max_size, uio); + } + + return (bwrite(bp)); +} + +static void +ext2_extattr_hash_entry(struct ext2fs_extattr_header *header, + struct ext2fs_extattr_entry *entry) +{ + uint32_t hash = 0; + char *name = entry->e_name; + int n; + + for (n=0; n < entry->e_name_len; n++) { + hash = (hash << EXT2_EXTATTR_NAME_HASH_SHIFT) ^ + (hash >> (8*sizeof(hash) - EXT2_EXTATTR_NAME_HASH_SHIFT)) ^ + (*name++); + } + + if (entry->e_value_block == 0 && entry->e_value_size != 0) { + uint32_t *value = (uint32_t *)((char *)header + entry->e_value_offs); + for (n = (entry->e_value_size + + EXT2_EXTATTR_ROUND) >> EXT2_EXTATTR_PAD_BITS; n; n--) { + hash = (hash << EXT2_EXTATTR_VALUE_HASH_SHIFT) ^ + (hash >> (8*sizeof(hash) - EXT2_EXTATTR_VALUE_HASH_SHIFT)) ^ + (*value++); + } + } + + entry->e_hash = hash; +} + +static void +ext2_extattr_rehash(struct ext2fs_extattr_header *header, + struct ext2fs_extattr_entry *entry) +{ + struct ext2fs_extattr_entry *here; + uint32_t hash = 0; + + ext2_extattr_hash_entry(header, entry); + + here = EXT2_ENTRY(header+1); + while (!EXT2_IS_LAST_ENTRY(here)) { + if (!here->e_hash) { + /* Block is not shared if an entry's hash value == 0 */ + hash = 0; + break; + } + + hash = (hash << EXT2_EXTATTR_BLOCK_HASH_SHIFT) ^ + (hash >> (8*sizeof(hash) - EXT2_EXTATTR_BLOCK_HASH_SHIFT)) ^ + here->e_hash; + + here = EXT2_EXTATTR_NEXT(here); + } + + header->h_hash = hash; +} + +int +ext2_extattr_block_set(struct inode *ip, int attrnamespace, + const char *name, struct uio *uio) +{ + struct m_ext2fs *fs; + struct buf *bp; + struct ext2fs_extattr_header *header; + struct ext2fs_extattr_entry *entry; + size_t size; + int error; + + fs = ip->i_e2fs; + + if (ip->i_facl) { + error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl), + fs->e2fs_bsize, NOCRED, &bp); + if (error) { + brelse(bp); + return (error); + } + + /* Check attributes magic value */ + header = EXT2_HDR(bp); + if (header->h_magic != EXTATTR_MAGIC || header->h_blocks != 1) { + brelse(bp); + return (EINVAL); + } + + error = ext2_extattr_check(EXT2_FIRST_ENTRY(bp), + bp->b_data + bp->b_bufsize); + if (error) { + brelse(bp); + return (error); + } + + if (header->h_refcount > 1) { + error = ext2_extattr_block_clone(ip, &bp); + if (error) { + brelse(bp); + return (error); + } + + header = EXT2_HDR(bp); + } + + /* Find if entry exist */ + for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry); + entry = EXT2_EXTATTR_NEXT(entry)) { + if (ext2_extattr_index_to_bsd(entry->e_name_index) != attrnamespace) + continue; + + if (strlen(name) == entry->e_name_len && + 0 == strncmp(entry->e_name, name, entry->e_name_len)) + break; + } + + if (!EXT2_IS_LAST_ENTRY(entry)) { + size = ext2_extattr_get_size(EXT2_FIRST_ENTRY(bp), entry, + sizeof(struct ext2fs_extattr_header), + entry->e_name_len, uio->uio_resid); + if (size > bp->b_bufsize) { + brelse(bp); + return (ENOSPC); + } + + ext2_extattr_set_exist_entry(bp->b_data, EXT2_FIRST_ENTRY(bp), + entry, bp->b_data + bp->b_bufsize, uio); + } else { + size = ext2_extattr_get_size(EXT2_FIRST_ENTRY(bp), NULL, + sizeof(struct ext2fs_extattr_header), + strlen(name), uio->uio_resid); + if (size > bp->b_bufsize) { + brelse(bp); + return (ENOSPC); + } + + entry = ext2_extattr_set_new_entry(bp->b_data, EXT2_FIRST_ENTRY(bp), + name, attrnamespace, bp->b_data + bp->b_bufsize, uio); + + /* Clean the same entry in the inode */ + error = ext2_extattr_inode_delete(ip, attrnamespace, name); + if (error && error != ENOATTR) { + brelse(bp); + return (error); + } + } + + ext2_extattr_rehash(header, entry); + + return (bwrite(bp)); + } + + size = ext2_extattr_get_size(NULL, NULL, + sizeof(struct ext2fs_extattr_header), strlen(name), uio->uio_resid); + if (size > fs->e2fs_bsize) + return (ENOSPC); + + /* Allocate block, fill EA header and insert entry */ + ip->i_facl = ext2_allocfacl(ip); + if (0 == ip->i_facl) + return (ENOSPC); + + ip->i_blocks += btodb(fs->e2fs_bsize); + ext2_update(ip->i_vnode, 1); + + bp = getblk(ip->i_devvp, fsbtodb(fs, ip->i_facl), fs->e2fs_bsize, 0, 0, 0); + if (!bp) { + ext2_blkfree(ip, ip->i_facl, fs->e2fs_bsize); + ip->i_blocks -= btodb(fs->e2fs_bsize); + ip->i_facl = 0; + ext2_update(ip->i_vnode, 1); + return (EIO); + } + + header = EXT2_HDR(bp); + header->h_magic = EXTATTR_MAGIC; + header->h_refcount = 1; + header->h_blocks = 1; + header->h_hash = 0; + memset(header->h_reserved, 0, sizeof(header->h_reserved)); + memcpy(bp->b_data, header, sizeof(struct ext2fs_extattr_header)); + memset(EXT2_FIRST_ENTRY(bp), 0, sizeof(uint32_t)); + + entry = ext2_extattr_set_new_entry(bp->b_data, EXT2_FIRST_ENTRY(bp), + name, attrnamespace, bp->b_data + bp->b_bufsize, uio); + + /* Clean the same entry in the inode */ + error = ext2_extattr_inode_delete(ip, attrnamespace, name); + if (error && error != ENOATTR) { + brelse(bp); + return (error); + } + + ext2_extattr_rehash(header, entry); + + return (bwrite(bp)); +} + +int ext2_extattr_free(struct inode *ip) +{ + struct m_ext2fs *fs; + struct buf *bp; + struct ext2fs_extattr_header *header; + int error; + + fs = ip->i_e2fs; + + if (!ip->i_facl) + return (0); + + error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl), + fs->e2fs_bsize, NOCRED, &bp); + if (error) { + brelse(bp); + return (error); + } + + /* Check attributes magic value */ + header = EXT2_HDR(bp); + if (header->h_magic != EXTATTR_MAGIC || header->h_blocks != 1) { + brelse(bp); + return (EINVAL); + } + + error = ext2_extattr_check(EXT2_FIRST_ENTRY(bp), bp->b_data + bp->b_bufsize); + if (error) { + brelse(bp); + return (error); + } + + if (header->h_refcount > 1) { + header->h_refcount--; + bwrite(bp); + } else { + ext2_blkfree(ip, ip->i_facl, ip->i_e2fs->e2fs_bsize); + brelse(bp); + } + + ip->i_blocks -= btodb(ip->i_e2fs->e2fs_bsize); + ip->i_facl = 0; + ext2_update(ip->i_vnode, 1); + return (0); } diff --git a/sys/fs/ext2fs/ext2_extattr.h b/sys/fs/ext2fs/ext2_extattr.h index 94091ed8ef4..50ab6908a0d 100644 --- a/sys/fs/ext2fs/ext2_extattr.h +++ b/sys/fs/ext2fs/ext2_extattr.h @@ -30,25 +30,34 @@ #define _FS_EXT2FS_EXT2_EXTARTTR_H_ /* Linux xattr name indexes */ -#define EXT4_XATTR_INDEX_USER 1 +#define EXT4_XATTR_INDEX_USER 1 #define EXT4_XATTR_INDEX_POSIX_ACL_ACCESS 2 #define EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT 3 -#define EXT4_XATTR_INDEX_TRUSTED 4 -#define EXT4_XATTR_INDEX_LUSTRE 5 -#define EXT4_XATTR_INDEX_SECURITY 6 -#define EXT4_XATTR_INDEX_SYSTEM 7 -#define EXT4_XATTR_INDEX_RICHACL 8 -#define EXT4_XATTR_INDEX_ENCRYPTION 9 +#define EXT4_XATTR_INDEX_TRUSTED 4 +#define EXT4_XATTR_INDEX_LUSTRE 5 +#define EXT4_XATTR_INDEX_SECURITY 6 +#define EXT4_XATTR_INDEX_SYSTEM 7 +#define EXT4_XATTR_INDEX_RICHACL 8 +#define EXT4_XATTR_INDEX_ENCRYPTION 9 /* Magic value in attribute blocks */ #define EXTATTR_MAGIC 0xEA020000 +/* Max EA name length */ +#define EXT2_EXTATTR_NAMELEN_MAX 255 + +/* EA hash constants */ +#define EXT2_EXTATTR_NAME_HASH_SHIFT 5 +#define EXT2_EXTATTR_VALUE_HASH_SHIFT 16 +#define EXT2_EXTATTR_BLOCK_HASH_SHIFT 16 + + struct ext2fs_extattr_header { int32_t h_magic; /* magic number for identification */ int32_t h_refcount; /* reference count */ int32_t h_blocks; /* number of disk blocks used */ int32_t h_hash; /* hash value of all attributes */ - uint32_t h_reserved[4]; /* zero right now */ + uint32_t h_reserved[4]; /* zero right now */ }; struct ext2fs_extattr_dinode_header { @@ -56,21 +65,15 @@ struct ext2fs_extattr_dinode_header { }; struct ext2fs_extattr_entry { - uint8_t e_name_len; /* length of name */ + uint8_t e_name_len; /* length of name */ uint8_t e_name_index; /* attribute name index */ uint16_t e_value_offs; /* offset in disk block of value */ uint32_t e_value_block; /* disk block attribute is stored on (n/i) */ uint32_t e_value_size; /* size of attribute value */ - uint32_t e_hash; /* hash value of name and value */ - char e_name[0]; /* attribute name */ + uint32_t e_hash; /* hash value of name and value */ + char e_name[0]; /* attribute name */ }; -#define EXT2_IHDR(inode, raw_inode) \ - ((struct ext4_xattr_ibody_header *) \ - ((void *)raw_inode + \ - EXT4_GOOD_OLD_INODE_SIZE + \ - EXT4_I(inode)->i_extra_isize)) - #define EXT2_IFIRST(hdr) ((struct ext2fs_extattr_entry *)((hdr)+1)) #define EXT2_HDR(bh) ((struct ext2fs_extattr_header *)((bh)->b_data)) @@ -85,10 +88,20 @@ struct ext2fs_extattr_entry { (((name_len) + EXT2_EXTATTR_ROUND + \ sizeof(struct ext2fs_extattr_entry)) & ~EXT2_EXTATTR_ROUND) +#define EXT2_EXTATTR_SIZE(size) \ + (((size) + EXT2_EXTATTR_ROUND) & ~EXT2_EXTATTR_ROUND) + #define EXT2_EXTATTR_NEXT(entry) \ ( (struct ext2fs_extattr_entry *)( \ (char *)(entry) + EXT2_EXTATTR_LEN((entry)->e_name_len)) ) +int ext2_extattr_inode_delete(struct inode *ip, int attrnamespace, + const char *name); + +int ext2_extattr_block_delete(struct inode *ip, int attrnamespace, + const char *name); + +int ext2_extattr_free(struct inode *ip); int ext2_extattr_inode_list(struct inode *ip, int attrnamespace, struct uio *uio, size_t *size); @@ -101,4 +114,12 @@ int ext2_extattr_inode_get(struct inode *ip, int attrnamespace, int ext2_extattr_block_get(struct inode *ip, int attrnamespace, const char *name, struct uio *uio, size_t *size); +int ext2_extattr_inode_set(struct inode *ip, int attrnamespace, + const char *name, struct uio *uio); + +int ext2_extattr_block_set(struct inode *ip, int attrnamespace, + const char *name, struct uio *uio); + +int ext2_extattr_valid_attrname(int attrnamespace, const char *attrname); + #endif /* !_FS_EXT2FS_EXT2_EXTARTTR_H_ */ diff --git a/sys/fs/ext2fs/ext2_extern.h b/sys/fs/ext2fs/ext2_extern.h index 3f4654f77e7..9a72e5fab07 100644 --- a/sys/fs/ext2fs/ext2_extern.h +++ b/sys/fs/ext2fs/ext2_extern.h @@ -51,6 +51,7 @@ struct vnode; int ext2_add_entry(struct vnode *, struct ext2fs_direct_2 *); int ext2_alloc(struct inode *, daddr_t, e4fs_daddr_t, int, struct ucred *, e4fs_daddr_t *); +daddr_t ext2_allocfacl(struct inode *ip); int ext2_balloc(struct inode *, e2fs_lbn_t, int, struct ucred *, struct buf **, int); int ext2_blkatoff(struct vnode *, off_t, char **, struct buf **); diff --git a/sys/fs/ext2fs/ext2_inode.c b/sys/fs/ext2fs/ext2_inode.c index 44e9295c626..d153bf8257d 100644 --- a/sys/fs/ext2fs/ext2_inode.c +++ b/sys/fs/ext2fs/ext2_inode.c @@ -53,6 +53,7 @@ #include #include #include +#include static int ext2_indirtrunc(struct inode *, daddr_t, daddr_t, daddr_t, int, e4fs_daddr_t *); @@ -488,6 +489,7 @@ ext2_inactive(struct vop_inactive_args *ap) if (ip->i_mode == 0) goto out; if (ip->i_nlink <= 0) { + ext2_extattr_free(ip); error = ext2_truncate(vp, (off_t)0, 0, NOCRED, td); ip->i_rdev = 0; mode = ip->i_mode; diff --git a/sys/fs/ext2fs/ext2_inode_cnv.c b/sys/fs/ext2fs/ext2_inode_cnv.c index aabf4df3726..64ef17667e8 100644 --- a/sys/fs/ext2fs/ext2_inode_cnv.c +++ b/sys/fs/ext2fs/ext2_inode_cnv.c @@ -51,8 +51,8 @@ ext2_print_inode(struct inode *in) printf("Inode: %5ju", (uintmax_t)in->i_number); printf( /* "Inode: %5d" */ - " Type: %10s Mode: 0x%o Flags: 0x%x Version: %d\n", - "n/a", in->i_mode, in->i_flags, in->i_gen); + " Type: %10s Mode: 0x%o Flags: 0x%x Version: %d acl: 0x%llx\n", + "n/a", in->i_mode, in->i_flags, in->i_gen, in->i_facl); printf("User: %5u Group: %5u Size: %ju\n", in->i_uid, in->i_gid, (uintmax_t)in->i_size); printf("Links: %3d Blockcount: %ju\n", @@ -167,6 +167,8 @@ ext2_i2ei(struct inode *ip, struct ext2fs_dinode *ei) ei->e2di_flags |= (ip->i_flag & IN_E4EXTENTS) ? EXT4_EXTENTS : 0; ei->e2di_nblock = ip->i_blocks & 0xffffffff; ei->e2di_nblock_high = ip->i_blocks >> 32 & 0xffff; + ei->e2di_facl = ip->i_facl & 0xffffffff; + ei->e2di_facl_high = ip->i_facl >> 32 & 0xffff; ei->e2di_gen = ip->i_gen; ei->e2di_uid = ip->i_uid; ei->e2di_gid = ip->i_gid; diff --git a/sys/fs/ext2fs/ext2_vnops.c b/sys/fs/ext2fs/ext2_vnops.c index b88d7219a3a..b507a620088 100644 --- a/sys/fs/ext2fs/ext2_vnops.c +++ b/sys/fs/ext2fs/ext2_vnops.c @@ -117,8 +117,10 @@ static vop_setattr_t ext2_setattr; static vop_strategy_t ext2_strategy; static vop_symlink_t ext2_symlink; static vop_write_t ext2_write; +static vop_deleteextattr_t ext2_deleteextattr; static vop_getextattr_t ext2_getextattr; static vop_listextattr_t ext2_listextattr; +static vop_setextattr_t ext2_setextattr; static vop_vptofh_t ext2_vptofh; static vop_close_t ext2fifo_close; static vop_kqfilter_t ext2fifo_kqfilter; @@ -157,8 +159,10 @@ struct vop_vector ext2_vnodeops = { .vop_strategy = ext2_strategy, .vop_symlink = ext2_symlink, .vop_write = ext2_write, + .vop_deleteextattr = ext2_deleteextattr, .vop_getextattr = ext2_getextattr, .vop_listextattr = ext2_listextattr, + .vop_setextattr = ext2_setextattr, .vop_vptofh = ext2_vptofh, }; @@ -1485,6 +1489,42 @@ ext2_pathconf(struct vop_pathconf_args *ap) return (error); } +/* + * Vnode operation to remove a named attribute. + */ +static int +ext2_deleteextattr(struct vop_deleteextattr_args *ap) +{ + struct inode *ip; + struct m_ext2fs *fs; + int error; + + ip = VTOI(ap->a_vp); + fs = ip->i_e2fs; + + if (!EXT2_HAS_COMPAT_FEATURE(ip->i_e2fs, EXT2F_COMPAT_EXT_ATTR)) + return (EOPNOTSUPP); + + if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) + return (EOPNOTSUPP); + + error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, + ap->a_cred, ap->a_td, VWRITE); + if (error) + return (error); + + if (EXT2_INODE_SIZE(fs) != E2FS_REV0_INODE_SIZE) { + error = ext2_extattr_inode_delete(ip, ap->a_attrnamespace, ap->a_name); + if (error != ENOATTR) + return (error); + } + + if (ip->i_facl) + error = ext2_extattr_block_delete(ip, ap->a_attrnamespace, ap->a_name); + + return (error); +} + /* * Vnode operation to retrieve a named extended attribute. */ @@ -1515,7 +1555,7 @@ ext2_getextattr(struct vop_getextattr_args *ap) if (EXT2_INODE_SIZE(fs) != E2FS_REV0_INODE_SIZE) { error = ext2_extattr_inode_get(ip, ap->a_attrnamespace, ap->a_name, ap->a_uio, ap->a_size); - if (error) + if (error != ENOATTR) return (error); } @@ -1556,17 +1596,58 @@ ext2_listextattr(struct vop_listextattr_args *ap) if (EXT2_INODE_SIZE(fs) != E2FS_REV0_INODE_SIZE) { error = ext2_extattr_inode_list(ip, ap->a_attrnamespace, ap->a_uio, ap->a_size); - if(error) + if (error) return (error); } - if(ip->i_facl) + if (ip->i_facl) error = ext2_extattr_block_list(ip, ap->a_attrnamespace, ap->a_uio, ap->a_size); return (error); } +/* + * Vnode operation to set a named attribute. + */ +static int +ext2_setextattr(struct vop_setextattr_args *ap) +{ + struct inode *ip; + struct m_ext2fs *fs; + int error; + + ip = VTOI(ap->a_vp); + fs = ip->i_e2fs; + + if (!EXT2_HAS_COMPAT_FEATURE(ip->i_e2fs, EXT2F_COMPAT_EXT_ATTR)) + return (EOPNOTSUPP); + + if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) + return (EOPNOTSUPP); + + error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, + ap->a_cred, ap->a_td, VWRITE); + if (error) + return (error); + + error = ext2_extattr_valid_attrname(ap->a_attrnamespace, ap->a_name); + if (error) + return (error); + + if (EXT2_INODE_SIZE(fs) != E2FS_REV0_INODE_SIZE) { + error = ext2_extattr_inode_set(ip, ap->a_attrnamespace, + ap->a_name, ap->a_uio); + if (error != ENOSPC) + return (error); + } + + error = ext2_extattr_block_set(ip, ap->a_attrnamespace, + ap->a_name, ap->a_uio); + + return (error); +} + /* * Vnode pointer to File handle */ diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c index e8970921fd4..c5c6592b84c 100644 --- a/sys/fs/nfsclient/nfs_clrpcops.c +++ b/sys/fs/nfsclient/nfs_clrpcops.c @@ -5238,7 +5238,7 @@ nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp, stateid.other[1] = stateidp->other[1]; stateid.other[2] = stateidp->other[2]; error = nfsrpc_layoutget(nmp, nfhp->nfh_fh, - nfhp->nfh_len, iomode, (uint64_t)0, INT64_MAX, + nfhp->nfh_len, iomode, (uint64_t)0, UINT64_MAX, (uint64_t)0, layoutlen, &stateid, &retonclose, &flh, cred, p, NULL); } else { @@ -5248,7 +5248,7 @@ nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp, stateid.other[1] = lyp->nfsly_stateid.other[1]; stateid.other[2] = lyp->nfsly_stateid.other[2]; error = nfsrpc_layoutget(nmp, nfhp->nfh_fh, - nfhp->nfh_len, iomode, off, INT64_MAX, + nfhp->nfh_len, iomode, off, UINT64_MAX, (uint64_t)0, layoutlen, &stateid, &retonclose, &flh, cred, p, NULL); } diff --git a/sys/geom/mirror/g_mirror.c b/sys/geom/mirror/g_mirror.c index 826412a6700..4447ce2a2dd 100644 --- a/sys/geom/mirror/g_mirror.c +++ b/sys/geom/mirror/g_mirror.c @@ -2225,7 +2225,9 @@ g_mirror_determine_state(struct g_mirror_disk *disk) sc = disk->d_softc; if (sc->sc_syncid == disk->d_sync.ds_syncid) { if ((disk->d_flags & - G_MIRROR_DISK_FLAG_SYNCHRONIZING) == 0) { + G_MIRROR_DISK_FLAG_SYNCHRONIZING) == 0 && + (g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE) == 0 || + (disk->d_flags & G_MIRROR_DISK_FLAG_DIRTY) == 0)) { /* Disk does not need synchronization. */ state = G_MIRROR_DISK_STATE_ACTIVE; } else { diff --git a/sys/kern/kern_cpuset.c b/sys/kern/kern_cpuset.c index b7417b3c2e7..9e83f568889 100644 --- a/sys/kern/kern_cpuset.c +++ b/sys/kern/kern_cpuset.c @@ -1115,6 +1115,8 @@ kern_cpuset_getaffinity(struct thread *td, cpulevel_t level, cpuwhich_t which, case CPU_WHICH_JAIL: break; case CPU_WHICH_IRQ: + case CPU_WHICH_INTRHANDLER: + case CPU_WHICH_ITHREAD: case CPU_WHICH_DOMAIN: error = EINVAL; goto out; @@ -1145,7 +1147,9 @@ kern_cpuset_getaffinity(struct thread *td, cpulevel_t level, cpuwhich_t which, CPU_COPY(&set->cs_mask, mask); break; case CPU_WHICH_IRQ: - error = intr_getaffinity(id, mask); + case CPU_WHICH_INTRHANDLER: + case CPU_WHICH_ITHREAD: + error = intr_getaffinity(id, which, mask); break; case CPU_WHICH_DOMAIN: if (id < 0 || id >= MAXMEMDOM) @@ -1239,6 +1243,8 @@ kern_cpuset_setaffinity(struct thread *td, cpulevel_t level, cpuwhich_t which, case CPU_WHICH_JAIL: break; case CPU_WHICH_IRQ: + case CPU_WHICH_INTRHANDLER: + case CPU_WHICH_ITHREAD: case CPU_WHICH_DOMAIN: error = EINVAL; goto out; @@ -1268,7 +1274,9 @@ kern_cpuset_setaffinity(struct thread *td, cpulevel_t level, cpuwhich_t which, } break; case CPU_WHICH_IRQ: - error = intr_setaffinity(id, mask); + case CPU_WHICH_INTRHANDLER: + case CPU_WHICH_ITHREAD: + error = intr_setaffinity(id, which, mask); break; default: error = EINVAL; diff --git a/sys/kern/kern_intr.c b/sys/kern/kern_intr.c index c9944089ef1..95eff38f056 100644 --- a/sys/kern/kern_intr.c +++ b/sys/kern/kern_intr.c @@ -287,13 +287,11 @@ intr_event_create(struct intr_event **event, void *source, int flags, int irq, /* * Bind an interrupt event to the specified CPU. Note that not all * platforms support binding an interrupt to a CPU. For those - * platforms this request will fail. For supported platforms, any - * associated ithreads as well as the primary interrupt context will - * be bound to the specificed CPU. Using a cpu id of NOCPU unbinds + * platforms this request will fail. Using a cpu id of NOCPU unbinds * the interrupt event. */ -int -intr_event_bind(struct intr_event *ie, int cpu) +static int +_intr_event_bind(struct intr_event *ie, int cpu, bool bindirq, bool bindithread) { lwpid_t id; int error; @@ -313,35 +311,75 @@ intr_event_bind(struct intr_event *ie, int cpu) * If we have any ithreads try to set their mask first to verify * permissions, etc. */ - mtx_lock(&ie->ie_lock); - if (ie->ie_thread != NULL) { - id = ie->ie_thread->it_thread->td_tid; - mtx_unlock(&ie->ie_lock); - error = cpuset_setithread(id, cpu); - if (error) - return (error); - } else - mtx_unlock(&ie->ie_lock); - error = ie->ie_assign_cpu(ie->ie_source, cpu); - if (error) { + if (bindithread) { mtx_lock(&ie->ie_lock); if (ie->ie_thread != NULL) { - cpu = ie->ie_cpu; id = ie->ie_thread->it_thread->td_tid; mtx_unlock(&ie->ie_lock); - (void)cpuset_setithread(id, cpu); + error = cpuset_setithread(id, cpu); + if (error) + return (error); } else mtx_unlock(&ie->ie_lock); + } + if (bindirq) + error = ie->ie_assign_cpu(ie->ie_source, cpu); + if (error) { + if (bindithread) { + mtx_lock(&ie->ie_lock); + if (ie->ie_thread != NULL) { + cpu = ie->ie_cpu; + id = ie->ie_thread->it_thread->td_tid; + mtx_unlock(&ie->ie_lock); + (void)cpuset_setithread(id, cpu); + } else + mtx_unlock(&ie->ie_lock); + } return (error); } - mtx_lock(&ie->ie_lock); - ie->ie_cpu = cpu; - mtx_unlock(&ie->ie_lock); + if (bindirq) { + mtx_lock(&ie->ie_lock); + ie->ie_cpu = cpu; + mtx_unlock(&ie->ie_lock); + } return (error); } +/* + * Bind an interrupt event to the specified CPU. For supported platforms, any + * associated ithreads as well as the primary interrupt context will be bound + * to the specificed CPU. + */ +int +intr_event_bind(struct intr_event *ie, int cpu) +{ + + return (_intr_event_bind(ie, cpu, true, true)); +} + +/* + * Bind an interrupt event to the specified CPU, but do not bind associated + * ithreads. + */ +int +intr_event_bind_irqonly(struct intr_event *ie, int cpu) +{ + + return (_intr_event_bind(ie, cpu, true, false)); +} + +/* + * Bind an interrupt event's ithread to the specified CPU. + */ +int +intr_event_bind_ithread(struct intr_event *ie, int cpu) +{ + + return (_intr_event_bind(ie, cpu, false, true)); +} + static struct intr_event * intr_lookup(int irq) { @@ -358,7 +396,7 @@ intr_lookup(int irq) } int -intr_setaffinity(int irq, void *m) +intr_setaffinity(int irq, int mode, void *m) { struct intr_event *ie; cpuset_t *mask; @@ -382,26 +420,62 @@ intr_setaffinity(int irq, void *m) ie = intr_lookup(irq); if (ie == NULL) return (ESRCH); - return (intr_event_bind(ie, cpu)); + switch (mode) { + case CPU_WHICH_IRQ: + return (intr_event_bind(ie, cpu)); + case CPU_WHICH_INTRHANDLER: + return (intr_event_bind_irqonly(ie, cpu)); + case CPU_WHICH_ITHREAD: + return (intr_event_bind_ithread(ie, cpu)); + default: + return (EINVAL); + } } int -intr_getaffinity(int irq, void *m) +intr_getaffinity(int irq, int mode, void *m) { struct intr_event *ie; + struct thread *td; + struct proc *p; cpuset_t *mask; + lwpid_t id; + int error; mask = m; ie = intr_lookup(irq); if (ie == NULL) return (ESRCH); + + error = 0; CPU_ZERO(mask); - mtx_lock(&ie->ie_lock); - if (ie->ie_cpu == NOCPU) - CPU_COPY(cpuset_root, mask); - else - CPU_SET(ie->ie_cpu, mask); - mtx_unlock(&ie->ie_lock); + switch (mode) { + case CPU_WHICH_IRQ: + case CPU_WHICH_INTRHANDLER: + mtx_lock(&ie->ie_lock); + if (ie->ie_cpu == NOCPU) + CPU_COPY(cpuset_root, mask); + else + CPU_SET(ie->ie_cpu, mask); + mtx_unlock(&ie->ie_lock); + break; + case CPU_WHICH_ITHREAD: + mtx_lock(&ie->ie_lock); + if (ie->ie_thread == NULL) { + mtx_unlock(&ie->ie_lock); + CPU_COPY(cpuset_root, mask); + } else { + id = ie->ie_thread->it_thread->td_tid; + mtx_unlock(&ie->ie_lock); + error = cpuset_which(CPU_WHICH_TID, id, &p, &td, NULL); + if (error != 0) + return (error); + CPU_COPY(&td->td_cpuset->cs_mask, mask); + PROC_UNLOCK(p); + } + default: + return (EINVAL); + } return (0); } diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c index f7a354eb730..b894245dae0 100644 --- a/sys/kern/kern_thread.c +++ b/sys/kern/kern_thread.c @@ -65,6 +65,57 @@ __FBSDID("$FreeBSD$"); #include #include +/* + * Asserts below verify the stability of struct thread and struct proc + * layout, as exposed by KBI to modules. On head, the KBI is allowed + * to drift, change to the structures must be accompanied by the + * assert update. + * + * On the stable branches after KBI freeze, conditions must not be + * violated. Typically new fields are moved to the end of the + * structures. + */ +#ifdef __amd64__ +_Static_assert(offsetof(struct thread, td_flags) == 0xf4, + "struct thread KBI td_flags"); +_Static_assert(offsetof(struct thread, td_pflags) == 0xfc, + "struct thread KBI td_pflags"); +_Static_assert(offsetof(struct thread, td_frame) == 0x410, + "struct thread KBI td_frame"); +_Static_assert(offsetof(struct thread, td_emuldata) == 0x4b8, + "struct thread KBI td_emuldata"); +_Static_assert(offsetof(struct proc, p_flag) == 0xb0, + "struct proc KBI p_flag"); +_Static_assert(offsetof(struct proc, p_pid) == 0xbc, + "struct proc KBI p_pid"); +_Static_assert(offsetof(struct proc, p_filemon) == 0x3d0, + "struct proc KBI p_filemon"); +_Static_assert(offsetof(struct proc, p_comm) == 0x3e0, + "struct proc KBI p_comm"); +_Static_assert(offsetof(struct proc, p_emuldata) == 0x4b8, + "struct proc KBI p_emuldata"); +#endif +#ifdef __i386__ +_Static_assert(offsetof(struct thread, td_flags) == 0x9c, + "struct thread KBI td_flags"); +_Static_assert(offsetof(struct thread, td_pflags) == 0xa4, + "struct thread KBI td_pflags"); +_Static_assert(offsetof(struct thread, td_frame) == 0x2c8, + "struct thread KBI td_frame"); +_Static_assert(offsetof(struct thread, td_emuldata) == 0x314, + "struct thread KBI td_emuldata"); +_Static_assert(offsetof(struct proc, p_flag) == 0x68, + "struct proc KBI p_flag"); +_Static_assert(offsetof(struct proc, p_pid) == 0x74, + "struct proc KBI p_pid"); +_Static_assert(offsetof(struct proc, p_filemon) == 0x27c, + "struct proc KBI p_filemon"); +_Static_assert(offsetof(struct proc, p_comm) == 0x288, + "struct proc KBI p_comm"); +_Static_assert(offsetof(struct proc, p_emuldata) == 0x314, + "struct proc KBI p_emuldata"); +#endif + SDT_PROVIDER_DECLARE(proc); SDT_PROBE_DEFINE(proc, , , lwp__exit); diff --git a/sys/kern/subr_gtaskqueue.c b/sys/kern/subr_gtaskqueue.c index bb83412c549..6a39a3aac14 100644 --- a/sys/kern/subr_gtaskqueue.c +++ b/sys/kern/subr_gtaskqueue.c @@ -679,7 +679,7 @@ taskqgroup_attach(struct taskqgroup *qgroup, struct grouptask *gtask, CPU_ZERO(&mask); CPU_SET(qgroup->tqg_queue[qid].tgc_cpu, &mask); mtx_unlock(&qgroup->tqg_lock); - intr_setaffinity(irq, &mask); + intr_setaffinity(irq, CPU_WHICH_IRQ, &mask); } else mtx_unlock(&qgroup->tqg_lock); } @@ -698,7 +698,7 @@ taskqgroup_attach_deferred(struct taskqgroup *qgroup, struct grouptask *gtask) CPU_ZERO(&mask); CPU_SET(cpu, &mask); - intr_setaffinity(gtask->gt_irq, &mask); + intr_setaffinity(gtask->gt_irq, CPU_WHICH_IRQ, &mask); mtx_lock(&qgroup->tqg_lock); } @@ -745,7 +745,7 @@ taskqgroup_attach_cpu(struct taskqgroup *qgroup, struct grouptask *gtask, CPU_ZERO(&mask); CPU_SET(cpu, &mask); if (irq != -1 && tqg_smp_started) - intr_setaffinity(irq, &mask); + intr_setaffinity(irq, CPU_WHICH_IRQ, &mask); return (0); } @@ -779,7 +779,7 @@ taskqgroup_attach_cpu_deferred(struct taskqgroup *qgroup, struct grouptask *gtas CPU_SET(cpu, &mask); if (irq != -1) - intr_setaffinity(irq, &mask); + intr_setaffinity(irq, CPU_WHICH_IRQ, &mask); return (0); } diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index b9507c0239e..5dc4636b3d7 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -735,13 +735,12 @@ cache_negative_remove(struct namecache *ncp, bool neg_locked) list_locked = true; mtx_lock(&neglist->nl_lock); } - } else { - mtx_assert(&neglist->nl_lock, MA_OWNED); - mtx_assert(&ncneg_hot.nl_lock, MA_OWNED); } if (ncp->nc_flag & NCF_HOTNEGATIVE) { + mtx_assert(&ncneg_hot.nl_lock, MA_OWNED); TAILQ_REMOVE(&ncneg_hot.nl_list, ncp, nc_dst); } else { + mtx_assert(&neglist->nl_lock, MA_OWNED); TAILQ_REMOVE(&neglist->nl_list, ncp, nc_dst); } if (list_locked) @@ -816,7 +815,6 @@ cache_negative_zap_one(void) mtx_unlock(&ncneg_hot.nl_lock); mtx_lock(dvlp); rw_wlock(blp); - mtx_lock(&ncneg_hot.nl_lock); mtx_lock(&neglist->nl_lock); ncp2 = TAILQ_FIRST(&neglist->nl_list); if (ncp != ncp2 || dvlp != VP2VNODELOCK(ncp2->nc_dvp) || @@ -830,7 +828,6 @@ cache_negative_zap_one(void) cache_zap_locked(ncp, true); out_unlock_all: mtx_unlock(&neglist->nl_lock); - mtx_unlock(&ncneg_hot.nl_lock); rw_wunlock(blp); mtx_unlock(dvlp); out: diff --git a/sys/libkern/arm64/crc32c_armv8.S b/sys/libkern/arm64/crc32c_armv8.S new file mode 100644 index 00000000000..072dfd6427b --- /dev/null +++ b/sys/libkern/arm64/crc32c_armv8.S @@ -0,0 +1,78 @@ +/*- + * Copyright (c) 2017 Michael Tuexen + * All rights reserved. + * + * 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 +__FBSDID("$FreeBSD$"); + +/* + * uint32_t + * armv8_crc32c(uint32_t crc, const unsigned char *buf, unsigned int len) + */ + +ENTRY(armv8_crc32c) + cbz w2, end + tbz x1, #0x0, half_word_aligned + sub w2, w2, 0x1 + ldr w10, [x1], #0x1 + crc32cb w0, w0, w10 +half_word_aligned: + cmp w2, #0x2 + b.lo last_byte + tbz x1, #0x1, word_aligned + sub w2, w2, 0x2 + ldr w10, [x1], #0x2 + crc32ch w0, w0, w10 +word_aligned: + cmp w2, #0x4 + b.lo last_half_word + tbz x1, #0x2, double_word_aligned + sub w2, w2, 0x4 + ldr w10, [x1], #0x4 + crc32cw w0, w0, w10 +double_word_aligned: + lsr w9, w2, #0x3 + cbz w9, last_word +loop: + ldr x10, [x1], #0x8 + crc32cx w0, w0, x10 + subs w9, w9, #1 + b.ne loop +last_word: + tbz w2, #0x2, last_half_word + ldr w10, [x1], #0x4 + crc32cw w0, w0, w10 +last_half_word: + tbz w2, #0x1, last_byte + ldr w10, [x1], #0x2 + crc32ch w0, w0, w10 +last_byte: + tbz w2, #0x0, end + ldr w10, [x1], #0x1 + crc32cb w0, w0, w10 +end: + ret +END(armv8_crc32c) diff --git a/sys/libkern/crc32.c b/sys/libkern/crc32.c index 6bc469ec377..7eaacd45466 100644 --- a/sys/libkern/crc32.c +++ b/sys/libkern/crc32.c @@ -54,6 +54,10 @@ __FBSDID("$FreeBSD$"); #include #endif +#if defined(__aarch64__) +#include +#endif + const uint32_t crc32_tab[] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, @@ -759,6 +763,18 @@ calculate_crc32c(uint32_t crc32c, if ((cpu_feature2 & CPUID2_SSE42) != 0) { return (sse42_crc32c(crc32c, buffer, length)); } else +#endif +#if defined(__aarch64__) + uint64_t reg; + + /* + * We only test for CRC32 support on the CPU with index 0 assuming that + * this applies to all CPUs. + */ + reg = READ_SPECIALREG(id_aa64isar0_el1); + if (ID_AA64ISAR0_CRC32(reg) != ID_AA64ISAR0_CRC32_NONE) { + return (armv8_crc32c(crc32c, buffer, length)); + } else #endif if (length < 4) { return (singletable_crc32c(crc32c, buffer, length)); diff --git a/sys/mips/conf/CARAMBOLA2 b/sys/mips/conf/CARAMBOLA2 index 77db1eee30b..952462134b6 100644 --- a/sys/mips/conf/CARAMBOLA2 +++ b/sys/mips/conf/CARAMBOLA2 @@ -24,6 +24,8 @@ hints "CARAMBOLA2.hints" # Board memory - 64MB options AR71XX_REALMEM=(64*1024*1024) +options EARLY_PRINTF + # i2c GPIO bus #device gpioiic #device iicbb diff --git a/sys/mips/conf/std.AR933X b/sys/mips/conf/std.AR933X index f082b31731d..18a7e14a763 100644 --- a/sys/mips/conf/std.AR933X +++ b/sys/mips/conf/std.AR933X @@ -20,7 +20,7 @@ files "../atheros/files.ar71xx" hints "AR933X_BASE.hints" makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols -makeoptions MODULES_OVERRIDE="gpio ar71xx if_gif if_vlan if_gre if_tap if_tun if_bridge bridgestp usb wlan wlan_xauth wlan_acl wlan_wep wlan_tkip wlan_ccmp wlan_rssadapt wlan_amrr hwpmc ipfw ipfw_nat libalias ipfw_nptv6 rtwn rtwn_usb rtwnfw otus otusfw" +makeoptions MODULES_OVERRIDE="gpio ar71xx if_gif if_vlan if_gre if_tap if_tun if_bridge bridgestp usb wlan wlan_xauth wlan_acl wlan_wep wlan_tkip wlan_ccmp wlan_rssadapt wlan_amrr hwpmc ipfw ipfw_nat libalias ipfw_nptv6 rtwn rtwn_usb rtwnfw otus otusfw hwpmc_mips24k" options DDB options KDB @@ -51,10 +51,10 @@ options VM_KMEM_SIZE_SCALE=1 options NBUF=128 # Limit UMTX hash size -# options UMTX_NUM_CHAINS=64 +options UMTX_CHAINS=64 # PMC -#options HWPMC_HOOKS +options HWPMC_HOOKS #device hwpmc #device hwpmc_mips24k diff --git a/sys/mips/conf/std.AR934X b/sys/mips/conf/std.AR934X index 50b6f01c373..815c7d364c7 100644 --- a/sys/mips/conf/std.AR934X +++ b/sys/mips/conf/std.AR934X @@ -20,7 +20,7 @@ files "../atheros/files.ar71xx" hints "AR934X_BASE.hints" makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols -makeoptions MODULES_OVERRIDE="gpio ar71xx if_gif if_vlan if_gre if_tap if_tun if_bridge bridgestp usb wlan wlan_xauth wlan_acl wlan_wep wlan_tkip wlan_ccmp wlan_rssadapt wlan_amrr hwpmc ipfw ipfw_nat libalias ipfw_nptv6 rtwn rtwn_usb rtwnfw otus otusfw" +makeoptions MODULES_OVERRIDE="gpio ar71xx if_gif if_vlan if_gre if_tap if_tun if_bridge bridgestp usb wlan wlan_xauth wlan_acl wlan_wep wlan_tkip wlan_ccmp wlan_rssadapt wlan_amrr hwpmc ipfw ipfw_nat libalias ipfw_nptv6 rtwn rtwn_usb rtwnfw otus otusfw hwpmc_mips24k" # makeoptions MODULES_OVERRIDE="" options DDB @@ -47,10 +47,10 @@ options NO_SYSCTL_DESCR options NBUF=128 # Limit UMTX hash size -# options UMTX_NUM_CHAINS=64 +options UMTX_CHAINS=64 # PMC -#options HWPMC_HOOKS +options HWPMC_HOOKS #device hwpmc #device hwpmc_mips24k diff --git a/sys/modules/cxgbe/if_cxgbe/Makefile b/sys/modules/cxgbe/if_cxgbe/Makefile index 5c711c4899d..61f9e00be05 100644 --- a/sys/modules/cxgbe/if_cxgbe/Makefile +++ b/sys/modules/cxgbe/if_cxgbe/Makefile @@ -21,6 +21,7 @@ SRCS+= t4_l2t.c SRCS+= t4_main.c SRCS+= t4_mp_ring.c SRCS+= t4_netmap.c +SRCS+= t4_sched.c SRCS+= t4_sge.c SRCS+= t4_tracer.c diff --git a/sys/modules/vmm/Makefile b/sys/modules/vmm/Makefile index 882864a69b2..cb9152f3d56 100644 --- a/sys/modules/vmm/Makefile +++ b/sys/modules/vmm/Makefile @@ -2,7 +2,7 @@ KMOD= vmm -SRCS= opt_acpi.h opt_ddb.h device_if.h bus_if.h pci_if.h +SRCS= opt_acpi.h opt_ddb.h device_if.h bus_if.h pci_if.h pcib_if.h acpi_if.h SRCS+= vmx_assym.h svm_assym.h DPSRCS= vmx_genassym.c svm_genassym.c @@ -51,7 +51,8 @@ SRCS+= vmcb.c \ svm.c \ svm_support.S \ npt.c \ - amdv.c \ + ivrs_drv.c \ + amdvi_hw.c \ svm_msr.c CLEANFILES= vmx_assym.h vmx_genassym.o svm_assym.h svm_genassym.o diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index d04b6029983..e67e287bd86 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -940,8 +940,12 @@ bridge_set_ifcap(struct bridge_softc *sc, struct bridge_iflist *bif, int set) error = (*ifp->if_ioctl)(ifp, SIOCSIFCAP, (caddr_t)&ifr); if (error) if_printf(sc->sc_ifp, - "error setting interface capabilities on %s\n", - ifp->if_xname); + "error setting capabilities on %s: %d\n", + ifp->if_xname, error); + if ((ifp->if_capenable & ~set) != 0) + if_printf(sc->sc_ifp, + "can't disable some capabilities on %s: 0x%x\n", + ifp->if_xname, ifp->if_capenable & ~set); } } diff --git a/sys/net/if_lagg.c b/sys/net/if_lagg.c index ff8caa11982..f76ddf348db 100644 --- a/sys/net/if_lagg.c +++ b/sys/net/if_lagg.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -99,10 +100,7 @@ static VNET_DEFINE(struct if_clone *, lagg_cloner); #define V_lagg_cloner VNET(lagg_cloner) static const char laggname[] = "lagg"; -static void lagg_lladdr(struct lagg_softc *, uint8_t *); static void lagg_capabilities(struct lagg_softc *); -static void lagg_port_lladdr(struct lagg_port *, uint8_t *, lagg_llqtype); -static void lagg_port_setlladdr(void *, int); static int lagg_port_create(struct lagg_softc *, struct ifnet *); static int lagg_port_destroy(struct lagg_port *, int); static struct mbuf *lagg_input(struct ifnet *, struct mbuf *); @@ -124,8 +122,9 @@ static int lagg_snd_tag_alloc(struct ifnet *, union if_snd_tag_alloc_params *, struct m_snd_tag **); #endif -static int lagg_ether_setmulti(struct lagg_softc *); -static int lagg_ether_cmdmulti(struct lagg_port *, int); +static int lagg_setmulti(struct lagg_port *); +static int lagg_clrmulti(struct lagg_port *); +static int lagg_setcaps(struct lagg_port *, int cap); static int lagg_setflag(struct lagg_port *, int, int, int (*func)(struct ifnet *, int)); static int lagg_setflags(struct lagg_port *, int status); @@ -317,6 +316,7 @@ static void lagg_proto_attach(struct lagg_softc *sc, lagg_proto pr) { + LAGG_XLOCK_ASSERT(sc); KASSERT(sc->sc_proto == LAGG_PROTO_NONE, ("%s: sc %p has proto", __func__, sc)); @@ -333,8 +333,8 @@ lagg_proto_detach(struct lagg_softc *sc) { lagg_proto pr; + LAGG_XLOCK_ASSERT(sc); LAGG_WLOCK_ASSERT(sc); - pr = sc->sc_proto; sc->sc_proto = LAGG_PROTO_NONE; @@ -433,15 +433,14 @@ lagg_register_vlan(void *arg, struct ifnet *ifp, u_int16_t vtag) { struct lagg_softc *sc = ifp->if_softc; struct lagg_port *lp; - struct rm_priotracker tracker; if (ifp->if_softc != arg) /* Not our event */ return; - LAGG_RLOCK(sc, &tracker); + LAGG_SLOCK(sc); SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) EVENTHANDLER_INVOKE(vlan_config, lp->lp_ifp, vtag); - LAGG_RUNLOCK(sc, &tracker); + LAGG_SUNLOCK(sc); } /* @@ -453,15 +452,14 @@ lagg_unregister_vlan(void *arg, struct ifnet *ifp, u_int16_t vtag) { struct lagg_softc *sc = ifp->if_softc; struct lagg_port *lp; - struct rm_priotracker tracker; if (ifp->if_softc != arg) /* Not our event */ return; - LAGG_RLOCK(sc, &tracker); + LAGG_SLOCK(sc); SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) EVENTHANDLER_INVOKE(vlan_unconfig, lp->lp_ifp, vtag); - LAGG_RUNLOCK(sc, &tracker); + LAGG_SUNLOCK(sc); } static int @@ -477,7 +475,10 @@ lagg_clone_create(struct if_clone *ifc, int unit, caddr_t params) free(sc, M_DEVBUF); return (ENOSPC); } + LAGG_LOCK_INIT(sc); + LAGG_SX_INIT(sc); + LAGG_XLOCK(sc); if (V_def_use_flowid) sc->sc_opts |= LAGG_OPT_USE_FLOWID; sc->flowid_shift = V_def_flowid_shift; @@ -487,9 +488,7 @@ lagg_clone_create(struct if_clone *ifc, int unit, caddr_t params) lagg_proto_attach(sc, LAGG_PROTO_DEFAULT); - LAGG_LOCK_INIT(sc); SLIST_INIT(&sc->sc_ports); - TASK_INIT(&sc->sc_lladdr_task, 0, lagg_port_setlladdr, sc); /* Initialise pseudo media types */ ifmedia_init(&sc->sc_media, 0, lagg_media_change, @@ -527,6 +526,7 @@ lagg_clone_create(struct if_clone *ifc, int unit, caddr_t params) LAGG_LIST_LOCK(); SLIST_INSERT_HEAD(&V_lagg_list, sc, sc_entries); LAGG_LIST_UNLOCK(); + LAGG_XUNLOCK(sc); return (0); } @@ -537,8 +537,8 @@ lagg_clone_destroy(struct ifnet *ifp) struct lagg_softc *sc = (struct lagg_softc *)ifp->if_softc; struct lagg_port *lp; - LAGG_WLOCK(sc); - + LAGG_XLOCK(sc); + sc->sc_destroying = 1; lagg_stop(sc); ifp->if_flags &= ~IFF_UP; @@ -546,15 +546,14 @@ lagg_clone_destroy(struct ifnet *ifp) EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach); /* Shutdown and remove lagg ports */ - while ((lp = SLIST_FIRST(&sc->sc_ports)) != NULL) { - lp->lp_detaching = LAGG_CLONE_DESTROY; + while ((lp = SLIST_FIRST(&sc->sc_ports)) != NULL) lagg_port_destroy(lp, 1); - } + /* Unhook the aggregation protocol */ + LAGG_WLOCK(sc); lagg_proto_detach(sc); LAGG_UNLOCK_ASSERT(sc); - taskqueue_drain(taskqueue_swi, &sc->sc_lladdr_task); ifmedia_removeall(&sc->sc_media); ether_ifdetach(ifp); if_free(ifp); @@ -562,48 +561,13 @@ lagg_clone_destroy(struct ifnet *ifp) LAGG_LIST_LOCK(); SLIST_REMOVE(&V_lagg_list, sc, lagg_softc, sc_entries); LAGG_LIST_UNLOCK(); + LAGG_XUNLOCK(sc); + LAGG_SX_DESTROY(sc); LAGG_LOCK_DESTROY(sc); free(sc, M_DEVBUF); } -/* - * Set link-layer address on the lagg interface itself. - * - * Set noinline to be dtrace-friendly - */ -static __noinline void -lagg_lladdr(struct lagg_softc *sc, uint8_t *lladdr) -{ - struct ifnet *ifp = sc->sc_ifp; - struct lagg_port lp; - - if (memcmp(lladdr, IF_LLADDR(ifp), ETHER_ADDR_LEN) == 0) - return; - - LAGG_WLOCK_ASSERT(sc); - /* - * Set the link layer address on the lagg interface. - * lagg_proto_lladdr() notifies the MAC change to - * the aggregation protocol. iflladdr_event handler which - * may trigger gratuitous ARPs for INET will be handled in - * a taskqueue. - */ - bcopy(lladdr, IF_LLADDR(ifp), ETHER_ADDR_LEN); - lagg_proto_lladdr(sc); - - /* - * Send notification request for lagg interface - * itself. Note that new lladdr is already set. - */ - bzero(&lp, sizeof(lp)); - lp.lp_ifp = sc->sc_ifp; - lp.lp_softc = sc; - - /* Do not request lladdr change */ - lagg_port_lladdr(&lp, lladdr, LAGG_LLQTYPE_VIRT); -} - static void lagg_capabilities(struct lagg_softc *sc) { @@ -612,7 +576,7 @@ lagg_capabilities(struct lagg_softc *sc) u_long hwa = ~0UL; struct ifnet_hw_tsomax hw_tsomax; - LAGG_WLOCK_ASSERT(sc); + LAGG_XLOCK_ASSERT(sc); memset(&hw_tsomax, 0, sizeof(hw_tsomax)); @@ -640,97 +604,10 @@ lagg_capabilities(struct lagg_softc *sc) if_printf(sc->sc_ifp, "capabilities 0x%08x enabled 0x%08x\n", cap, ena); } -} -/* - * Enqueue interface lladdr notification. - * If request is already queued, it is updated. - * If setting lladdr is also desired, @do_change has to be set to 1. - * - * Set noinline to be dtrace-friendly - */ -static __noinline void -lagg_port_lladdr(struct lagg_port *lp, uint8_t *lladdr, lagg_llqtype llq_type) -{ - struct lagg_softc *sc = lp->lp_softc; - struct ifnet *ifp = lp->lp_ifp; - struct lagg_llq *llq; - - LAGG_WLOCK_ASSERT(sc); - - /* - * Do not enqueue requests where lladdr is the same for - * "physical" interfaces (e.g. ports in lagg) - */ - if (llq_type == LAGG_LLQTYPE_PHYS && - memcmp(IF_LLADDR(ifp), lladdr, ETHER_ADDR_LEN) == 0) - return; - - /* Check to make sure its not already queued to be changed */ - SLIST_FOREACH(llq, &sc->sc_llq_head, llq_entries) { - if (llq->llq_ifp == ifp) { - /* Update lladdr, it may have changed */ - bcopy(lladdr, llq->llq_lladdr, ETHER_ADDR_LEN); - return; - } - } - - llq = malloc(sizeof(struct lagg_llq), M_DEVBUF, M_NOWAIT | M_ZERO); - if (llq == NULL) /* XXX what to do */ - return; - - if_ref(ifp); - llq->llq_ifp = ifp; - llq->llq_type = llq_type; - bcopy(lladdr, llq->llq_lladdr, ETHER_ADDR_LEN); - /* XXX: We should insert to tail */ - SLIST_INSERT_HEAD(&sc->sc_llq_head, llq, llq_entries); - - taskqueue_enqueue(taskqueue_swi, &sc->sc_lladdr_task); -} - -/* - * Set the interface MAC address from a taskqueue to avoid a LOR. - * - * Set noinline to be dtrace-friendly - */ -static __noinline void -lagg_port_setlladdr(void *arg, int pending) -{ - struct lagg_softc *sc = (struct lagg_softc *)arg; - struct lagg_llq *llq, *head; - struct ifnet *ifp; - - /* Grab a local reference of the queue and remove it from the softc */ - LAGG_WLOCK(sc); - head = SLIST_FIRST(&sc->sc_llq_head); - SLIST_FIRST(&sc->sc_llq_head) = NULL; - LAGG_WUNLOCK(sc); - - /* - * Traverse the queue and set the lladdr on each ifp. It is safe to do - * unlocked as we have the only reference to it. - */ - for (llq = head; llq != NULL; llq = head) { - ifp = llq->llq_ifp; - - CURVNET_SET(ifp->if_vnet); - - /* - * Set the link layer address on the laggport interface. - * Note that if_setlladdr() or iflladdr_event handler - * may result in arp transmission / lltable updates. - */ - if (llq->llq_type == LAGG_LLQTYPE_PHYS) - if_setlladdr(ifp, llq->llq_lladdr, - ETHER_ADDR_LEN); - else - EVENTHANDLER_INVOKE(iflladdr_event, ifp); - CURVNET_RESTORE(); - head = SLIST_NEXT(llq, llq_entries); - if_rele(ifp); - free(llq, M_DEVBUF); - } + /* Apply unified capabilities back to the lagg ports. */ + SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) + lagg_setcaps(lp, ena); } static int @@ -741,7 +618,7 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp) int error, i; uint64_t *pval; - LAGG_WLOCK_ASSERT(sc); + LAGG_XLOCK_ASSERT(sc); /* Limit the maximal number of lagg ports */ if (sc->sc_count >= LAGG_MAX_PORTS) @@ -769,9 +646,8 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp) return (EINVAL); } - if ((lp = malloc(sizeof(struct lagg_port), - M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) - return (ENOMEM); + lp = malloc(sizeof(struct lagg_port), M_DEVBUF, M_WAITOK|M_ZERO); + lp->lp_softc = sc; /* Check if port is a stacked lagg */ LAGG_LIST_LOCK(); @@ -794,6 +670,26 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp) } LAGG_LIST_UNLOCK(); + if_ref(ifp); + lp->lp_ifp = ifp; + + bcopy(IF_LLADDR(ifp), lp->lp_lladdr, ETHER_ADDR_LEN); + lp->lp_ifcapenable = ifp->if_capenable; + if (SLIST_EMPTY(&sc->sc_ports)) { + LAGG_WLOCK(sc); + bcopy(IF_LLADDR(ifp), IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); + lagg_proto_lladdr(sc); + LAGG_WUNLOCK(sc); + EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp); + } else { + if_setlladdr(ifp, IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); + } + lagg_setflags(lp, 1); + + LAGG_WLOCK(sc); + if (SLIST_EMPTY(&sc->sc_ports)) + sc->sc_primary = lp; + /* Change the interface type */ lp->lp_iftype = ifp->if_type; ifp->if_type = IFT_IEEE8023ADLAG; @@ -803,25 +699,10 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp) lp->lp_output = ifp->if_output; ifp->if_output = lagg_port_output; - if_ref(ifp); - lp->lp_ifp = ifp; - lp->lp_softc = sc; - - /* Save port link layer address */ - bcopy(IF_LLADDR(ifp), lp->lp_lladdr, ETHER_ADDR_LEN); - - if (SLIST_EMPTY(&sc->sc_ports)) { - sc->sc_primary = lp; - /* First port in lagg. Update/notify lagg lladdress */ - lagg_lladdr(sc, IF_LLADDR(ifp)); - } else { - - /* - * Update link layer address for this port and - * send notifications to other subsystems. - */ - lagg_port_lladdr(lp, IF_LLADDR(sc->sc_ifp), LAGG_LLQTYPE_PHYS); - } + /* Read port counters */ + pval = lp->port_counters.val; + for (i = 0; i < IFCOUNTERS; i++, pval++) + *pval = ifp->if_get_counter(ifp, i); /* * Insert into the list of ports. @@ -842,24 +723,21 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp) SLIST_INSERT_HEAD(&sc->sc_ports, lp, lp_entries); sc->sc_count++; - /* Update lagg capabilities */ - lagg_capabilities(sc); - lagg_linkstate(sc); - - /* Read port counters */ - pval = lp->port_counters.val; - for (i = 0; i < IFCOUNTERS; i++, pval++) - *pval = ifp->if_get_counter(ifp, i); - /* Add multicast addresses and interface flags to this port */ - lagg_ether_cmdmulti(lp, 1); - lagg_setflags(lp, 1); + lagg_setmulti(lp); if ((error = lagg_proto_addport(sc, lp)) != 0) { /* Remove the port, without calling pr_delport. */ lagg_port_destroy(lp, 0); + LAGG_UNLOCK_ASSERT(sc); return (error); } + LAGG_WUNLOCK(sc); + + /* Update lagg capabilities */ + lagg_capabilities(sc); + lagg_linkstate(sc); + return (0); } @@ -871,8 +749,7 @@ lagg_port_checkstacking(struct lagg_softc *sc) struct lagg_port *lp; int m = 0; - LAGG_WLOCK_ASSERT(sc); - + LAGG_SXLOCK_ASSERT(sc); SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { if (lp->lp_flags & LAGG_PORT_STACK) { sc_ptr = (struct lagg_softc *)lp->lp_ifp->if_softc; @@ -889,25 +766,20 @@ lagg_port_destroy(struct lagg_port *lp, int rundelport) { struct lagg_softc *sc = lp->lp_softc; struct lagg_port *lp_ptr, *lp0; - struct lagg_llq *llq; struct ifnet *ifp = lp->lp_ifp; uint64_t *pval, vdiff; int i; - LAGG_WLOCK_ASSERT(sc); + LAGG_XLOCK_ASSERT(sc); - if (rundelport) + if (rundelport) { + LAGG_WLOCK(sc); lagg_proto_delport(sc, lp); + } else + LAGG_WLOCK_ASSERT(sc); - /* - * Remove multicast addresses and interface flags from this port and - * reset the MAC address, skip if the interface is being detached. - */ - if (lp->lp_detaching == 0) { - lagg_ether_cmdmulti(lp, 0); - lagg_setflags(lp, 0); - lagg_port_lladdr(lp, lp->lp_lladdr, LAGG_LLQTYPE_PHYS); - } + if (lp->lp_detaching == 0) + lagg_clrmulti(lp); /* Restore interface */ ifp->if_type = lp->lp_iftype; @@ -930,43 +802,37 @@ lagg_port_destroy(struct lagg_port *lp, int rundelport) if (lp == sc->sc_primary) { uint8_t lladdr[ETHER_ADDR_LEN]; - if ((lp0 = SLIST_FIRST(&sc->sc_ports)) == NULL) { + if ((lp0 = SLIST_FIRST(&sc->sc_ports)) == NULL) bzero(&lladdr, ETHER_ADDR_LEN); - } else { - bcopy(lp0->lp_lladdr, - lladdr, ETHER_ADDR_LEN); - } - if (lp->lp_detaching != LAGG_CLONE_DESTROY) - lagg_lladdr(sc, lladdr); - - /* Mark lp0 as new primary */ + else + bcopy(lp0->lp_lladdr, lladdr, ETHER_ADDR_LEN); sc->sc_primary = lp0; + if (sc->sc_destroying == 0) { + bcopy(lladdr, IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); + lagg_proto_lladdr(sc); + LAGG_WUNLOCK(sc); + EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp); + } else + LAGG_WUNLOCK(sc); /* - * Enqueue lladdr update/notification for each port - * (new primary needs update as well, to switch from - * old lladdr to its 'real' one). + * Update lladdr for each port (new primary needs update + * as well, to switch from old lladdr to its 'real' one) */ SLIST_FOREACH(lp_ptr, &sc->sc_ports, lp_entries) - lagg_port_lladdr(lp_ptr, lladdr, LAGG_LLQTYPE_PHYS); - } - - /* Remove any pending lladdr changes from the queue */ - if (lp->lp_detaching != 0) { - SLIST_FOREACH(llq, &sc->sc_llq_head, llq_entries) { - if (llq->llq_ifp == ifp) { - SLIST_REMOVE(&sc->sc_llq_head, llq, lagg_llq, - llq_entries); - if_rele(llq->llq_ifp); - free(llq, M_DEVBUF); - break; /* Only appears once */ - } - } - } + if_setlladdr(lp_ptr->lp_ifp, lladdr, ETHER_ADDR_LEN); + } else + LAGG_WUNLOCK(sc); if (lp->lp_ifflags) if_printf(ifp, "%s: lp_ifflags unclean\n", __func__); + if (lp->lp_detaching == 0) { + lagg_setflags(lp, 0); + lagg_setcaps(lp, lp->lp_ifcapenable); + if_setlladdr(ifp, lp->lp_lladdr, ETHER_ADDR_LEN); + } + if_rele(ifp); free(lp, M_DEVBUF); @@ -984,7 +850,6 @@ lagg_port_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) struct lagg_softc *sc; struct lagg_port *lp = NULL; int error = 0; - struct rm_priotracker tracker; /* Should be checked by the caller */ if (ifp->if_type != IFT_IEEE8023ADLAG || @@ -999,15 +864,15 @@ lagg_port_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; } - LAGG_RLOCK(sc, &tracker); + LAGG_SLOCK(sc); if ((lp = ifp->if_lagg) == NULL || lp->lp_softc != sc) { error = ENOENT; - LAGG_RUNLOCK(sc, &tracker); + LAGG_SUNLOCK(sc); break; } lagg_port2req(lp, rp); - LAGG_RUNLOCK(sc, &tracker); + LAGG_SUNLOCK(sc); break; case SIOCSIFCAP: @@ -1020,9 +885,9 @@ lagg_port_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; /* Update lagg interface capabilities */ - LAGG_WLOCK(sc); + LAGG_XLOCK(sc); lagg_capabilities(sc); - LAGG_WUNLOCK(sc); + LAGG_XUNLOCK(sc); break; case SIOCSIFMTU: @@ -1132,10 +997,10 @@ lagg_port_ifdetach(void *arg __unused, struct ifnet *ifp) sc = lp->lp_softc; - LAGG_WLOCK(sc); - lp->lp_detaching = LAGG_PORT_DETACH; + LAGG_XLOCK(sc); + lp->lp_detaching = 1; lagg_port_destroy(lp, 1); - LAGG_WUNLOCK(sc); + LAGG_XUNLOCK(sc); } static void @@ -1185,10 +1050,11 @@ lagg_init(void *xsc) struct ifnet *ifp = sc->sc_ifp; struct lagg_port *lp; - if (ifp->if_drv_flags & IFF_DRV_RUNNING) + LAGG_XLOCK(sc); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + LAGG_XUNLOCK(sc); return; - - LAGG_WLOCK(sc); + } ifp->if_drv_flags |= IFF_DRV_RUNNING; @@ -1197,12 +1063,15 @@ lagg_init(void *xsc) * This might be if_setlladdr() notification * that lladdr has been changed. */ - SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) - lagg_port_lladdr(lp, IF_LLADDR(ifp), LAGG_LLQTYPE_PHYS); + SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { + if (memcmp(IF_LLADDR(ifp), IF_LLADDR(lp->lp_ifp), + ETHER_ADDR_LEN) != 0) + if_setlladdr(lp->lp_ifp, IF_LLADDR(ifp), ETHER_ADDR_LEN); + } lagg_proto_init(sc); - LAGG_WUNLOCK(sc); + LAGG_XUNLOCK(sc); } static void @@ -1210,7 +1079,7 @@ lagg_stop(struct lagg_softc *sc) { struct ifnet *ifp = sc->sc_ifp; - LAGG_WLOCK_ASSERT(sc); + LAGG_XLOCK_ASSERT(sc); if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) return; @@ -1234,22 +1103,14 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) struct thread *td = curthread; char *buf, *outbuf; int count, buflen, len, error = 0; - struct rm_priotracker tracker; bzero(&rpbuf, sizeof(rpbuf)); switch (cmd) { case SIOCGLAGG: - LAGG_RLOCK(sc, &tracker); - count = 0; - SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) - count++; - buflen = count * sizeof(struct lagg_reqport); - LAGG_RUNLOCK(sc, &tracker); - + LAGG_SLOCK(sc); + buflen = sc->sc_count * sizeof(struct lagg_reqport); outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO); - - LAGG_RLOCK(sc, &tracker); ra->ra_proto = sc->sc_proto; lagg_proto_request(sc, &ra->ra_psc); count = 0; @@ -1265,7 +1126,7 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) buf += sizeof(rpbuf); len -= sizeof(rpbuf); } - LAGG_RUNLOCK(sc, &tracker); + LAGG_SUNLOCK(sc); ra->ra_ports = count; ra->ra_size = count * sizeof(rpbuf); error = copyout(outbuf, ra->ra_port, ra->ra_size); @@ -1280,12 +1141,15 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; } + LAGG_XLOCK(sc); LAGG_WLOCK(sc); lagg_proto_detach(sc); LAGG_UNLOCK_ASSERT(sc); lagg_proto_attach(sc, ra->ra_proto); + LAGG_XUNLOCK(sc); break; case SIOCGLAGGOPTS: + LAGG_SLOCK(sc); ro->ro_opts = sc->sc_opts; if (sc->sc_proto == LAGG_PROTO_LACP) { struct lacp_softc *lsc; @@ -1309,6 +1173,7 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) ro->ro_bkt = sc->sc_bkt; ro->ro_flapping = sc->sc_flapping; ro->ro_flowid_shift = sc->flowid_shift; + LAGG_SUNLOCK(sc); break; case SIOCSLAGGOPTS: if (sc->sc_proto == LAGG_PROTO_ROUNDROBIN) { @@ -1350,13 +1215,13 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; } - LAGG_WLOCK(sc); + LAGG_XLOCK(sc); if (valid == 0 || (lacp == 1 && sc->sc_proto != LAGG_PROTO_LACP)) { /* Invalid combination of options specified. */ error = EINVAL; - LAGG_WUNLOCK(sc); + LAGG_XUNLOCK(sc); break; /* Return from SIOCSLAGGOPTS. */ } /* @@ -1411,18 +1276,18 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; } } - LAGG_WUNLOCK(sc); + LAGG_XUNLOCK(sc); break; case SIOCGLAGGFLAGS: rf->rf_flags = 0; - LAGG_RLOCK(sc, &tracker); + LAGG_SLOCK(sc); if (sc->sc_flags & MBUF_HASHFLAG_L2) rf->rf_flags |= LAGG_F_HASHL2; if (sc->sc_flags & MBUF_HASHFLAG_L3) rf->rf_flags |= LAGG_F_HASHL3; if (sc->sc_flags & MBUF_HASHFLAG_L4) rf->rf_flags |= LAGG_F_HASHL4; - LAGG_RUNLOCK(sc, &tracker); + LAGG_SUNLOCK(sc); break; case SIOCSLAGGHASH: error = priv_check(td, PRIV_NET_LAGG); @@ -1432,7 +1297,7 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) error = EINVAL; break; } - LAGG_WLOCK(sc); + LAGG_XLOCK(sc); sc->sc_flags = 0; if (rf->rf_flags & LAGG_F_HASHL2) sc->sc_flags |= MBUF_HASHFLAG_L2; @@ -1440,7 +1305,7 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) sc->sc_flags |= MBUF_HASHFLAG_L3; if (rf->rf_flags & LAGG_F_HASHL4) sc->sc_flags |= MBUF_HASHFLAG_L4; - LAGG_WUNLOCK(sc); + LAGG_XUNLOCK(sc); break; case SIOCGLAGGPORT: if (rp->rp_portname[0] == '\0' || @@ -1449,17 +1314,17 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; } - LAGG_RLOCK(sc, &tracker); + LAGG_SLOCK(sc); if ((lp = (struct lagg_port *)tpif->if_lagg) == NULL || lp->lp_softc != sc) { error = ENOENT; - LAGG_RUNLOCK(sc, &tracker); + LAGG_SUNLOCK(sc); if_rele(tpif); break; } lagg_port2req(lp, rp); - LAGG_RUNLOCK(sc, &tracker); + LAGG_SUNLOCK(sc); if_rele(tpif); break; case SIOCSLAGGPORT: @@ -1491,9 +1356,9 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) tpif->if_xname); } #endif - LAGG_WLOCK(sc); + LAGG_XLOCK(sc); error = lagg_port_create(sc, tpif); - LAGG_WUNLOCK(sc); + LAGG_XUNLOCK(sc); if_rele(tpif); break; case SIOCSLAGGDELPORT: @@ -1506,26 +1371,25 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; } - LAGG_WLOCK(sc); + LAGG_XLOCK(sc); if ((lp = (struct lagg_port *)tpif->if_lagg) == NULL || lp->lp_softc != sc) { error = ENOENT; - LAGG_WUNLOCK(sc); + LAGG_XUNLOCK(sc); if_rele(tpif); break; } error = lagg_port_destroy(lp, 1); - LAGG_WUNLOCK(sc); + LAGG_XUNLOCK(sc); if_rele(tpif); break; case SIOCSIFFLAGS: /* Set flags on ports too */ - LAGG_WLOCK(sc); + LAGG_XLOCK(sc); SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { lagg_setflags(lp, 1); } - LAGG_WUNLOCK(sc); if (!(ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) { @@ -1533,23 +1397,28 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) * If interface is marked down and it is running, * then stop and disable it. */ - LAGG_WLOCK(sc); lagg_stop(sc); - LAGG_WUNLOCK(sc); + LAGG_XUNLOCK(sc); } else if ((ifp->if_flags & IFF_UP) && !(ifp->if_drv_flags & IFF_DRV_RUNNING)) { /* * If interface is marked up and it is stopped, then * start it. */ + LAGG_XUNLOCK(sc); (*ifp->if_init)(sc); - } + } else + LAGG_XUNLOCK(sc); break; case SIOCADDMULTI: case SIOCDELMULTI: LAGG_WLOCK(sc); - error = lagg_ether_setmulti(sc); + SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { + lagg_clrmulti(lp); + lagg_setmulti(lp); + } LAGG_WUNLOCK(sc); + error = 0; break; case SIOCSIFMEDIA: case SIOCGIFMEDIA: @@ -1557,8 +1426,18 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; case SIOCSIFCAP: + LAGG_XLOCK(sc); + SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { + if (lp->lp_ioctl != NULL) + (*lp->lp_ioctl)(lp->lp_ifp, cmd, data); + } + lagg_capabilities(sc); + LAGG_XUNLOCK(sc); + error = 0; + break; + case SIOCSIFMTU: - /* Do not allow the MTU or caps to be directly changed */ + /* Do not allow the MTU to be directly changed */ error = EINVAL; break; @@ -1616,23 +1495,7 @@ lagg_snd_tag_alloc(struct ifnet *ifp, #endif static int -lagg_ether_setmulti(struct lagg_softc *sc) -{ - struct lagg_port *lp; - - LAGG_WLOCK_ASSERT(sc); - - SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { - /* First, remove any existing filter entries. */ - lagg_ether_cmdmulti(lp, 0); - /* copy all addresses from the lagg interface to the port */ - lagg_ether_cmdmulti(lp, 1); - } - return (0); -} - -static int -lagg_ether_cmdmulti(struct lagg_port *lp, int set) +lagg_setmulti(struct lagg_port *lp) { struct lagg_softc *sc = lp->lp_softc; struct ifnet *ifp = lp->lp_ifp; @@ -1642,41 +1505,59 @@ lagg_ether_cmdmulti(struct lagg_port *lp, int set) int error; LAGG_WLOCK_ASSERT(sc); - - if (set) { - IF_ADDR_WLOCK(scifp); - TAILQ_FOREACH(ifma, &scifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - mc = malloc(sizeof(struct lagg_mc), M_DEVBUF, M_NOWAIT); - if (mc == NULL) { - IF_ADDR_WUNLOCK(scifp); - return (ENOMEM); - } - bcopy(ifma->ifma_addr, &mc->mc_addr, - ifma->ifma_addr->sa_len); - mc->mc_addr.sdl_index = ifp->if_index; - mc->mc_ifma = NULL; - SLIST_INSERT_HEAD(&lp->lp_mc_head, mc, mc_entries); - } - IF_ADDR_WUNLOCK(scifp); - SLIST_FOREACH (mc, &lp->lp_mc_head, mc_entries) { - error = if_addmulti(ifp, - (struct sockaddr *)&mc->mc_addr, &mc->mc_ifma); - if (error) - return (error); - } - } else { - while ((mc = SLIST_FIRST(&lp->lp_mc_head)) != NULL) { - SLIST_REMOVE(&lp->lp_mc_head, mc, lagg_mc, mc_entries); - if (mc->mc_ifma && lp->lp_detaching == 0) - if_delmulti_ifma(mc->mc_ifma); - free(mc, M_DEVBUF); + IF_ADDR_WLOCK(scifp); + TAILQ_FOREACH(ifma, &scifp->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + mc = malloc(sizeof(struct lagg_mc), M_DEVBUF, M_NOWAIT); + if (mc == NULL) { + IF_ADDR_WUNLOCK(scifp); + return (ENOMEM); } + bcopy(ifma->ifma_addr, &mc->mc_addr, + ifma->ifma_addr->sa_len); + mc->mc_addr.sdl_index = ifp->if_index; + mc->mc_ifma = NULL; + SLIST_INSERT_HEAD(&lp->lp_mc_head, mc, mc_entries); + } + IF_ADDR_WUNLOCK(scifp); + SLIST_FOREACH (mc, &lp->lp_mc_head, mc_entries) { + error = if_addmulti(ifp, + (struct sockaddr *)&mc->mc_addr, &mc->mc_ifma); + if (error) + return (error); } return (0); } +static int +lagg_clrmulti(struct lagg_port *lp) +{ + struct lagg_mc *mc; + + LAGG_WLOCK_ASSERT(lp->lp_softc); + while ((mc = SLIST_FIRST(&lp->lp_mc_head)) != NULL) { + SLIST_REMOVE(&lp->lp_mc_head, mc, lagg_mc, mc_entries); + if (mc->mc_ifma && lp->lp_detaching == 0) + if_delmulti_ifma(mc->mc_ifma); + free(mc, M_DEVBUF); + } + return (0); +} + +static int +lagg_setcaps(struct lagg_port *lp, int cap) +{ + struct ifreq ifr; + + if (lp->lp_ifp->if_capenable == cap) + return (0); + if (lp->lp_ioctl == NULL) + return (ENXIO); + ifr.ifr_reqcap = cap; + return ((*lp->lp_ioctl)(lp->lp_ifp, SIOCSIFCAP, (caddr_t)&ifr)); +} + /* Handle a ref counted flag that should be set on the lagg port as well */ static int lagg_setflag(struct lagg_port *lp, int flag, int status, @@ -1687,7 +1568,7 @@ lagg_setflag(struct lagg_port *lp, int flag, int status, struct ifnet *ifp = lp->lp_ifp; int error; - LAGG_WLOCK_ASSERT(sc); + LAGG_XLOCK_ASSERT(sc); status = status ? (scifp->if_flags & flag) : 0; /* Now "status" contains the flag value or 0 */ @@ -1821,17 +1702,16 @@ lagg_media_status(struct ifnet *ifp, struct ifmediareq *imr) { struct lagg_softc *sc = (struct lagg_softc *)ifp->if_softc; struct lagg_port *lp; - struct rm_priotracker tracker; imr->ifm_status = IFM_AVALID; imr->ifm_active = IFM_ETHER | IFM_AUTO; - LAGG_RLOCK(sc, &tracker); + LAGG_SLOCK(sc); SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { if (LAGG_PORTACTIVE(lp)) imr->ifm_status |= IFM_ACTIVE; } - LAGG_RUNLOCK(sc, &tracker); + LAGG_SUNLOCK(sc); } static void @@ -1841,6 +1721,8 @@ lagg_linkstate(struct lagg_softc *sc) int new_link = LINK_STATE_DOWN; uint64_t speed; + LAGG_XLOCK_ASSERT(sc); + /* Our link is considered up if at least one of our ports is active */ SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { if (lp->lp_ifp->if_link_state == LINK_STATE_UP) { @@ -1881,10 +1763,10 @@ lagg_port_state(struct ifnet *ifp, int state) if (sc == NULL) return; - LAGG_WLOCK(sc); + LAGG_XLOCK(sc); lagg_linkstate(sc); lagg_proto_linkstate(sc, lp); - LAGG_WUNLOCK(sc); + LAGG_XUNLOCK(sc); } struct lagg_port * @@ -1893,7 +1775,6 @@ lagg_link_active(struct lagg_softc *sc, struct lagg_port *lp) struct lagg_port *lp_next, *rval = NULL; // int new_link = LINK_STATE_DOWN; - LAGG_RLOCK_ASSERT(sc); /* * Search a port which reports an active link state. */ @@ -2250,6 +2131,8 @@ lagg_lacp_lladdr(struct lagg_softc *sc) { struct lagg_port *lp; + LAGG_SXLOCK_ASSERT(sc); + /* purge all the lacp ports */ SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) lacp_port_destroy(lp); diff --git a/sys/net/if_lagg.h b/sys/net/if_lagg.h index 81eeeb89e70..7098136d209 100644 --- a/sys/net/if_lagg.h +++ b/sys/net/if_lagg.h @@ -202,19 +202,6 @@ struct lagg_mc { SLIST_ENTRY(lagg_mc) mc_entries; }; -typedef enum { - LAGG_LLQTYPE_PHYS = 0, /* Task related to physical (underlying) port */ - LAGG_LLQTYPE_VIRT, /* Task related to lagg interface itself */ -} lagg_llqtype; - -/* List of interfaces to have the MAC address modified */ -struct lagg_llq { - struct ifnet *llq_ifp; - uint8_t llq_lladdr[ETHER_ADDR_LEN]; - lagg_llqtype llq_type; - SLIST_ENTRY(lagg_llq) llq_entries; -}; - struct lagg_counters { uint64_t val[IFCOUNTERS]; }; @@ -222,6 +209,7 @@ struct lagg_counters { struct lagg_softc { struct ifnet *sc_ifp; /* virtual interface */ struct rmlock sc_mtx; + struct sx sc_sx; int sc_proto; /* lagg protocol */ u_int sc_count; /* number of ports */ u_int sc_active; /* active port count */ @@ -232,13 +220,11 @@ struct lagg_softc { void *sc_psc; /* protocol data */ uint32_t sc_seq; /* sequence counter */ uint32_t sc_flags; + int sc_destroying; /* destroying lagg */ SLIST_HEAD(__tplhd, lagg_port) sc_ports; /* list of interfaces */ SLIST_ENTRY(lagg_softc) sc_entries; - struct task sc_lladdr_task; - SLIST_HEAD(__llqhd, lagg_llq) sc_llq_head; /* interfaces to program - the lladdr on */ eventhandler_tag vlan_attach; eventhandler_tag vlan_detach; struct callout sc_callout; @@ -258,12 +244,10 @@ struct lagg_port { uint32_t lp_prio; /* port priority */ uint32_t lp_flags; /* port flags */ int lp_ifflags; /* saved ifp flags */ + int lp_ifcapenable; /* saved ifp capenable */ void *lh_cookie; /* if state hook */ void *lp_psc; /* protocol data */ int lp_detaching; /* ifnet is detaching */ -#define LAGG_PORT_DETACH 0x01 /* detach lagg port */ -#define LAGG_CLONE_DESTROY 0x02 /* destroy lagg clone */ - SLIST_HEAD(__mclhd, lagg_mc) lp_mc_head; /* multicast addresses */ /* Redirected callbacks */ @@ -285,6 +269,16 @@ struct lagg_port { #define LAGG_WLOCK_ASSERT(_sc) rm_assert(&(_sc)->sc_mtx, RA_WLOCKED) #define LAGG_UNLOCK_ASSERT(_sc) rm_assert(&(_sc)->sc_mtx, RA_UNLOCKED) +#define LAGG_SX_INIT(_sc) sx_init(&(_sc)->sc_sx, "if_lagg sx") +#define LAGG_SX_DESTROY(_sc) sx_destroy(&(_sc)->sc_sx) +#define LAGG_SLOCK(_sc) sx_slock(&(_sc)->sc_sx) +#define LAGG_XLOCK(_sc) sx_xlock(&(_sc)->sc_sx) +#define LAGG_SUNLOCK(_sc) sx_sunlock(&(_sc)->sc_sx) +#define LAGG_XUNLOCK(_sc) sx_xunlock(&(_sc)->sc_sx) +#define LAGG_SXLOCK_ASSERT(_sc) sx_assert(&(_sc)->sc_sx, SA_LOCKED) +#define LAGG_SLOCK_ASSERT(_sc) sx_assert(&(_sc)->sc_sx, SA_SLOCKED) +#define LAGG_XLOCK_ASSERT(_sc) sx_assert(&(_sc)->sc_sx, SA_XLOCKED) + extern struct mbuf *(*lagg_input_p)(struct ifnet *, struct mbuf *); extern void (*lagg_linkstate_p)(struct ifnet *, int ); diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c index 0c5fb6f375b..dbfac38f9bf 100644 --- a/sys/net/if_vlan.c +++ b/sys/net/if_vlan.c @@ -113,6 +113,7 @@ struct ifvlan { #define PARENT(ifv) ((ifv)->ifv_trunk->parent) void *ifv_cookie; int ifv_pflags; /* special flags we have set on parent */ + int ifv_capenable; struct ifv_linkmib { int ifvm_encaplen; /* encapsulation length */ int ifvm_mtufudge; /* MTU fudged by this much */ @@ -1294,6 +1295,7 @@ exists: ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN; ifv->ifv_mintu = ETHERMIN; ifv->ifv_pflags = 0; + ifv->ifv_capenable = -1; /* * If the parent supports the VLAN_MTU capability, @@ -1545,9 +1547,14 @@ vlan_capabilities(struct ifvlan *ifv) struct ifnet *p = PARENT(ifv); struct ifnet *ifp = ifv->ifv_ifp; struct ifnet_hw_tsomax hw_tsomax; + int cap = 0, ena = 0, mena; + u_long hwa = 0; TRUNK_LOCK_ASSERT(TRUNK(ifv)); + /* Mask parent interface enabled capabilities disabled by user. */ + mena = p->if_capenable & ifv->ifv_capenable; + /* * If the parent interface can do checksum offloading * on VLANs, then propagate its hardware-assisted @@ -1555,20 +1562,18 @@ vlan_capabilities(struct ifvlan *ifv) * offloading requires hardware VLAN tagging. */ if (p->if_capabilities & IFCAP_VLAN_HWCSUM) - ifp->if_capabilities = - p->if_capabilities & (IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6); - + cap |= p->if_capabilities & (IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6); if (p->if_capenable & IFCAP_VLAN_HWCSUM && p->if_capenable & IFCAP_VLAN_HWTAGGING) { - ifp->if_capenable = - p->if_capenable & (IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6); - ifp->if_hwassist = p->if_hwassist & (CSUM_IP | CSUM_TCP | - CSUM_UDP | CSUM_SCTP | CSUM_TCP_IPV6 | CSUM_UDP_IPV6 | - CSUM_SCTP_IPV6); - } else { - ifp->if_capenable = 0; - ifp->if_hwassist = 0; + ena |= mena & (IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6); + if (ena & IFCAP_TXCSUM) + hwa |= p->if_hwassist & (CSUM_IP | CSUM_TCP | + CSUM_UDP | CSUM_SCTP); + if (ena & IFCAP_TXCSUM_IPV6) + hwa |= p->if_hwassist & (CSUM_TCP_IPV6 | + CSUM_UDP_IPV6 | CSUM_SCTP_IPV6); } + /* * If the parent interface can do TSO on VLANs then * propagate the hardware-assisted flag. TSO on VLANs @@ -1578,15 +1583,23 @@ vlan_capabilities(struct ifvlan *ifv) if_hw_tsomax_common(p, &hw_tsomax); if_hw_tsomax_update(ifp, &hw_tsomax); if (p->if_capabilities & IFCAP_VLAN_HWTSO) - ifp->if_capabilities |= p->if_capabilities & IFCAP_TSO; + cap |= p->if_capabilities & IFCAP_TSO; if (p->if_capenable & IFCAP_VLAN_HWTSO) { - ifp->if_capenable |= p->if_capenable & IFCAP_TSO; - ifp->if_hwassist |= p->if_hwassist & CSUM_TSO; - } else { - ifp->if_capenable &= ~(p->if_capenable & IFCAP_TSO); - ifp->if_hwassist &= ~(p->if_hwassist & CSUM_TSO); + ena |= mena & IFCAP_TSO; + if (ena & IFCAP_TSO) + hwa |= p->if_hwassist & CSUM_TSO; } + /* + * If the parent interface can do LRO and checksum offloading on + * VLANs, then guess it may do LRO on VLANs. False positive here + * cost nothing, while false negative may lead to some confusions. + */ + if (p->if_capabilities & IFCAP_VLAN_HWCSUM) + cap |= p->if_capabilities & IFCAP_LRO; + if (p->if_capenable & IFCAP_VLAN_HWCSUM) + ena |= p->if_capenable & IFCAP_LRO; + /* * If the parent interface can offload TCP connections over VLANs then * propagate its TOE capability to the VLAN interface. @@ -1597,20 +1610,31 @@ vlan_capabilities(struct ifvlan *ifv) */ #define IFCAP_VLAN_TOE IFCAP_TOE if (p->if_capabilities & IFCAP_VLAN_TOE) - ifp->if_capabilities |= p->if_capabilities & IFCAP_TOE; + cap |= p->if_capabilities & IFCAP_TOE; if (p->if_capenable & IFCAP_VLAN_TOE) { TOEDEV(ifp) = TOEDEV(p); - ifp->if_capenable |= p->if_capenable & IFCAP_TOE; + ena |= mena & IFCAP_TOE; } + /* + * If the parent interface supports dynamic link state, so does the + * VLAN interface. + */ + cap |= (p->if_capabilities & IFCAP_LINKSTATE); + ena |= (mena & IFCAP_LINKSTATE); + #ifdef RATELIMIT /* * If the parent interface supports ratelimiting, so does the * VLAN interface. */ - ifp->if_capabilities |= (p->if_capabilities & IFCAP_TXRTLMT); - ifp->if_capenable |= (p->if_capenable & IFCAP_TXRTLMT); + cap |= (p->if_capabilities & IFCAP_TXRTLMT); + ena |= (mena & IFCAP_TXRTLMT); #endif + + ifp->if_capabilities = cap; + ifp->if_capenable = ena; + ifp->if_hwassist = hwa; } static void @@ -1814,6 +1838,18 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) vlan_tag_recalculate(ifv); break; + case SIOCSIFCAP: + VLAN_LOCK(); + ifv->ifv_capenable = ifr->ifr_reqcap; + trunk = TRUNK(ifv); + if (trunk != NULL) { + TRUNK_LOCK(trunk); + vlan_capabilities(ifv); + TRUNK_UNLOCK(trunk); + } + VLAN_UNLOCK(); + break; + default: error = EINVAL; break; diff --git a/sys/netgraph/bluetooth/hci/ng_hci_evnt.c b/sys/netgraph/bluetooth/hci/ng_hci_evnt.c index 1c1aeee3b6b..647bfccabaa 100644 --- a/sys/netgraph/bluetooth/hci/ng_hci_evnt.c +++ b/sys/netgraph/bluetooth/hci/ng_hci_evnt.c @@ -417,7 +417,6 @@ le_advertizing_report(ng_hci_unit_p unit, struct mbuf *event) } else getmicrotime(&n->updated); -#if 0 { /* * TODO: Make these information @@ -425,21 +424,36 @@ le_advertizing_report(ng_hci_unit_p unit, struct mbuf *event) */ u_int8_t length_data; - char *rssi; - - NG_HCI_M_PULLUP(event, sizeof(u_int8_t)); + event = m_pullup(event, sizeof(u_int8_t)); + if(event == NULL){ + NG_HCI_WARN("%s: Event datasize Pullup Failed\n", __func__); + goto out; + } length_data = *mtod(event, u_int8_t *); m_adj(event, sizeof(u_int8_t)); + n->extinq_size = (length_data < NG_HCI_EXTINQ_MAX)? + length_data : NG_HCI_EXTINQ_MAX; + /*Advertizement data*/ - NG_HCI_M_PULLUP(event, length_data); - m_adj(event, length_data); - NG_HCI_M_PULLUP(event, sizeof(char )); + event = m_pullup(event, n->extinq_size); + if(event == NULL){ + NG_HCI_WARN("%s: Event data pullup Failed\n", __func__); + goto out; + } + m_copydata(event, 0, n->extinq_size, n->extinq_data); + m_adj(event, n->extinq_size); + event = m_pullup(event, sizeof(char )); /*Get RSSI*/ - rssi = mtod(event, char *); + if(event == NULL){ + NG_HCI_WARN("%s: Event rssi pull up Failed\n", __func__); + + goto out; + } + n->page_scan_mode = *mtod(event, char *); m_adj(event, sizeof(u_int8_t)); } -#endif } + out: NG_FREE_M(event); return (error); diff --git a/sys/netgraph/bluetooth/hci/ng_hci_main.c b/sys/netgraph/bluetooth/hci/ng_hci_main.c index 9abe595c977..ae00ea6d18e 100644 --- a/sys/netgraph/bluetooth/hci/ng_hci_main.c +++ b/sys/netgraph/bluetooth/hci/ng_hci_main.c @@ -93,7 +93,22 @@ NETGRAPH_INIT(hci, &typestruct); MODULE_VERSION(ng_hci, NG_BLUETOOTH_VERSION); MODULE_DEPEND(ng_hci, ng_bluetooth, NG_BLUETOOTH_VERSION, NG_BLUETOOTH_VERSION, NG_BLUETOOTH_VERSION); +static int ng_hci_linktype_to_addrtype(int linktype); +static int ng_hci_linktype_to_addrtype(int linktype) +{ + switch(linktype){ + case NG_HCI_LINK_LE_PUBLIC: + return BDADDR_LE_PUBLIC; + case NG_HCI_LINK_LE_RANDOM: + return BDADDR_LE_RANDOM; + case NG_HCI_LINK_ACL: + /*FALLTHROUGH*/ + default: + return BDADDR_BREDR; + } + return BDADDR_BREDR; +} /***************************************************************************** ***************************************************************************** ** Netgraph methods implementation @@ -481,11 +496,15 @@ ng_hci_default_rcvmsg(node_p node, item_p item, hook_p lasthook) e2->page_scan_rep_mode = n->page_scan_rep_mode; e2->page_scan_mode = n->page_scan_mode; e2->clock_offset = n->clock_offset; + e2->addrtype = + ng_hci_linktype_to_addrtype(n->addrtype); + e2->extinq_size = n->extinq_size; bcopy(&n->bdaddr, &e2->bdaddr, sizeof(e2->bdaddr)); bcopy(&n->features, &e2->features, sizeof(e2->features)); - + bcopy(&n->extinq_data, &e2->extinq_data, + n->extinq_size); e2 ++; if (--s <= 0) break; diff --git a/sys/netgraph/bluetooth/hci/ng_hci_var.h b/sys/netgraph/bluetooth/hci/ng_hci_var.h index 171c437c13f..7909ce6299b 100644 --- a/sys/netgraph/bluetooth/hci/ng_hci_var.h +++ b/sys/netgraph/bluetooth/hci/ng_hci_var.h @@ -210,7 +210,8 @@ typedef struct ng_hci_neighbor { u_int8_t page_scan_rep_mode; /* PS rep. mode */ u_int8_t page_scan_mode; /* page scan mode */ u_int16_t clock_offset; /* clock offset */ - + uint8_t extinq_size; + uint8_t extinq_data[NG_HCI_EXTINQ_MAX]; LIST_ENTRY(ng_hci_neighbor) next; } ng_hci_neighbor_t; typedef ng_hci_neighbor_t * ng_hci_neighbor_p; diff --git a/sys/netgraph/bluetooth/include/ng_bluetooth.h b/sys/netgraph/bluetooth/include/ng_bluetooth.h index 2b85facad51..3015b9f1b9b 100644 --- a/sys/netgraph/bluetooth/include/ng_bluetooth.h +++ b/sys/netgraph/bluetooth/include/ng_bluetooth.h @@ -224,5 +224,9 @@ u_int32_t bluetooth_l2cap_rtx_timeout (void); u_int32_t bluetooth_l2cap_ertx_timeout (void); u_int32_t bluetooth_sco_rtx_timeout (void); +#define BDADDR_BREDR 0 +#define BDADDR_LE_PUBLIC 1 +#define BDADDR_LE_RANDOM 2 + #endif /* _NETGRAPH_BLUETOOTH_H_ */ diff --git a/sys/netgraph/bluetooth/include/ng_btsocket.h b/sys/netgraph/bluetooth/include/ng_btsocket.h index 4815e4373b3..515770b3cdc 100644 --- a/sys/netgraph/bluetooth/include/ng_btsocket.h +++ b/sys/netgraph/bluetooth/include/ng_btsocket.h @@ -228,10 +228,6 @@ struct sockaddr_l2cap_compat { bdaddr_t l2cap_bdaddr; /* address */ }; -#define BDADDR_BREDR 0 -#define BDADDR_LE_PUBLIC 1 -#define BDADDR_LE_RANDOM 2 - struct sockaddr_l2cap { u_char l2cap_len; /* total length */ u_char l2cap_family; /* address family */ diff --git a/sys/netgraph/bluetooth/include/ng_hci.h b/sys/netgraph/bluetooth/include/ng_hci.h index 7fe1dc7a6f0..34cd1a68f22 100644 --- a/sys/netgraph/bluetooth/include/ng_hci.h +++ b/sys/netgraph/bluetooth/include/ng_hci.h @@ -80,6 +80,7 @@ #define NG_HCI_FEATURES_SIZE 8 /* LMP features */ #define NG_HCI_UNIT_NAME_SIZE 248 /* unit name size */ #define NG_HCI_COMMANDS_SIZE 64 /*Command list BMP size*/ +#define NG_HCI_EXTINQ_MAX 240 /**/ /* HCI specification */ #define NG_HCI_SPEC_V10 0x00 /* v1.0 */ #define NG_HCI_SPEC_V11 0x01 /* v1.1 */ @@ -561,6 +562,9 @@ typedef struct { u_int16_t clock_offset; /* clock offset */ bdaddr_t bdaddr; /* bdaddr */ u_int8_t features[NG_HCI_FEATURES_SIZE]; /* features */ + uint8_t addrtype; + uint8_t extinq_size; /* MAX 240*/ + uint8_t extinq_data[NG_HCI_EXTINQ_MAX]; } ng_hci_node_neighbor_cache_entry_ep; #define NG_HCI_MAX_NEIGHBOR_NUM \ diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index 53657f4a07f..85d3053a658 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -11147,7 +11147,7 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst, ip->ip_v = IPVERSION; ip->ip_hl = (sizeof(struct ip) >> 2); ip->ip_tos = 0; - ip->ip_off = 0; + ip->ip_off = htons(IP_DF); ip_fillid(ip); ip->ip_ttl = MODULE_GLOBAL(ip_defttl); if (port) { diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index db3f39c2e5c..551a9cb914c 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -3933,6 +3933,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, stcb->asoc.vrf_id, stcb->sctp_ep->fibnum); + net->src_addr_selected = 0; if (SCTP_ROUTE_HAS_VALID_IFN(&net->ro)) { /* Get source address */ net->ro._s_addr = sctp_source_address_selection(stcb->sctp_ep, @@ -3942,18 +3943,18 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, 0, stcb->asoc.vrf_id); if (net->ro._s_addr != NULL) { + uint32_t imtu, rmtu, hcmtu; + net->src_addr_selected = 1; /* Now get the interface MTU */ if (net->ro._s_addr->ifn_p != NULL) { - net->mtu = SCTP_GATHER_MTU_FROM_INTFC(net->ro._s_addr->ifn_p); + imtu = SCTP_GATHER_MTU_FROM_INTFC(net->ro._s_addr->ifn_p); + } else { + imtu = 0; } - } else { - net->src_addr_selected = 0; - } - if (net->mtu > 0) { - uint32_t rmtu; - rmtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, net->ro.ro_rt); + hcmtu = sctp_hc_get_mtu(&net->ro._l_addr, stcb->sctp_ep->fibnum); + net->mtu = sctp_min_mtu(hcmtu, rmtu, imtu); if (rmtu == 0) { /* * Start things off to match mtu of @@ -3961,17 +3962,8 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, */ SCTP_SET_MTU_OF_ROUTE(&net->ro._l_addr.sa, net->ro.ro_rt, net->mtu); - } else { - /* - * we take the route mtu over the interface, - * since the route may be leading out the - * loopback, or a different interface. - */ - net->mtu = rmtu; } } - } else { - net->src_addr_selected = 0; } if (net->mtu == 0) { switch (newaddr->sa_family) { diff --git a/sys/netinet/sctp_timer.c b/sys/netinet/sctp_timer.c index 6a1c600ac69..4c87ee683f8 100644 --- a/sys/netinet/sctp_timer.c +++ b/sys/netinet/sctp_timer.c @@ -667,6 +667,7 @@ start_again: stcb->asoc.peers_rwnd += SCTP_BASE_SYSCTL(sctp_peer_chunk_oh); } chk->sent = SCTP_DATAGRAM_RESEND; + chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; SCTP_STAT_INCR(sctps_markedretrans); /* reset the TSN for striking and other FR stuff */ @@ -740,6 +741,7 @@ start_again: chk->whoTo = alt; if (chk->sent != SCTP_DATAGRAM_RESEND) { chk->sent = SCTP_DATAGRAM_RESEND; + chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); cnt_mk++; } @@ -1084,6 +1086,7 @@ sctp_cookie_timer(struct sctp_inpcb *inp, sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); } cookie->sent = SCTP_DATAGRAM_RESEND; + cookie->flags |= CHUNK_FLAGS_FRAGMENT_OK; /* * Now call the output routine to kick out the cookie again, Note we * don't mark any chunks for retran so that FR will need to kick in @@ -1130,6 +1133,7 @@ sctp_strreset_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, sctp_free_remote_addr(chk->whoTo); if (chk->sent != SCTP_DATAGRAM_RESEND) { chk->sent = SCTP_DATAGRAM_RESEND; + chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); } chk->whoTo = alt; @@ -1147,6 +1151,7 @@ sctp_strreset_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, if (strrst->sent != SCTP_DATAGRAM_RESEND) sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); strrst->sent = SCTP_DATAGRAM_RESEND; + strrst->flags |= CHUNK_FLAGS_FRAGMENT_OK; /* restart the timer */ sctp_timer_start(SCTP_TIMER_TYPE_STRRESET, inp, stcb, strrst->whoTo); @@ -1211,6 +1216,7 @@ sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, chk->whoTo = alt; if (chk->sent != SCTP_DATAGRAM_RESEND) { chk->sent = SCTP_DATAGRAM_RESEND; + chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); } atomic_add_int(&alt->ref_count, 1); @@ -1225,6 +1231,7 @@ sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, if (asconf->sent != SCTP_DATAGRAM_RESEND && chk->sent != SCTP_DATAGRAM_UNSENT) sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); chk->sent = SCTP_DATAGRAM_RESEND; + chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; } if (!(net->dest_state & SCTP_ADDR_REACHABLE)) { /* @@ -1237,6 +1244,7 @@ sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, if (asconf->sent != SCTP_DATAGRAM_RESEND) sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); asconf->sent = SCTP_DATAGRAM_RESEND; + asconf->flags |= CHUNK_FLAGS_FRAGMENT_OK; /* send another ASCONF if any and we can do */ sctp_send_asconf(stcb, alt, SCTP_ADDR_NOT_LOCKED); diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index b433df57a59..75d817559bc 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -225,6 +225,11 @@ sctp_notify(struct sctp_inpcb *inp, } if (net->mtu > next_mtu) { net->mtu = next_mtu; + if (net->port) { + sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu + sizeof(struct udphdr)); + } else { + sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu); + } } /* Update the association MTU */ if (stcb->asoc.smallest_mtu > next_mtu) { diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index 2951ad68614..1dd3c3e2f0c 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -49,6 +49,9 @@ __FBSDID("$FreeBSD$"); #include #include #include +#if defined(INET6) || defined(INET) +#include +#endif #include #include #include @@ -7235,3 +7238,90 @@ sctp_over_udp_start(void) #endif return (0); } + +#if defined(INET6) || defined(INET) + +/* + * sctp_min_mtu ()returns the minimum of all non-zero arguments. + * If all arguments are zero, zero is returned. + */ +uint32_t +sctp_min_mtu(uint32_t mtu1, uint32_t mtu2, uint32_t mtu3) +{ + if (mtu1 > 0) { + if (mtu2 > 0) { + if (mtu3 > 0) { + return (min(mtu1, min(mtu2, mtu3))); + } else { + return (min(mtu1, mtu2)); + } + } else { + if (mtu3 > 0) { + return (min(mtu1, mtu3)); + } else { + return (mtu1); + } + } + } else { + if (mtu2 > 0) { + if (mtu3 > 0) { + return (min(mtu2, mtu3)); + } else { + return (mtu2); + } + } else { + return (mtu3); + } + } +} + +void +sctp_hc_set_mtu(union sctp_sockstore *addr, uint16_t fibnum, uint32_t mtu) +{ + struct in_conninfo inc; + + memset(&inc, 0, sizeof(struct in_conninfo)); + inc.inc_fibnum = fibnum; + switch (addr->sa.sa_family) { +#ifdef INET + case AF_INET: + inc.inc_faddr = addr->sin.sin_addr; + break; +#endif +#ifdef INET6 + case AF_INET6: + inc.inc_flags |= INC_ISIPV6; + inc.inc6_faddr = addr->sin6.sin6_addr; + break; +#endif + default: + return; + } + tcp_hc_updatemtu(&inc, (u_long)mtu); +} + +uint32_t +sctp_hc_get_mtu(union sctp_sockstore *addr, uint16_t fibnum) +{ + struct in_conninfo inc; + + memset(&inc, 0, sizeof(struct in_conninfo)); + inc.inc_fibnum = fibnum; + switch (addr->sa.sa_family) { +#ifdef INET + case AF_INET: + inc.inc_faddr = addr->sin.sin_addr; + break; +#endif +#ifdef INET6 + case AF_INET6: + inc.inc_flags |= INC_ISIPV6; + inc.inc6_faddr = addr->sin6.sin6_addr; + break; +#endif + default: + return (0); + } + return ((uint32_t)tcp_hc_getmtu(&inc)); +} +#endif diff --git a/sys/netinet/sctputil.h b/sys/netinet/sctputil.h index dd45e49a996..50118b7a5ed 100644 --- a/sys/netinet/sctputil.h +++ b/sys/netinet/sctputil.h @@ -387,6 +387,11 @@ sctp_auditing(int, struct sctp_inpcb *, struct sctp_tcb *, struct sctp_nets *); void sctp_audit_log(uint8_t, uint8_t); +#endif +#if defined(INET6) || defined(INET) +uint32_t sctp_min_mtu(uint32_t, uint32_t, uint32_t); +void sctp_hc_set_mtu(union sctp_sockstore *, uint16_t, uint32_t); +uint32_t sctp_hc_get_mtu(union sctp_sockstore *, uint16_t); #endif #endif /* _KERNEL */ #endif diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c index d424ea8a9e4..b655bf69d8d 100644 --- a/sys/netpfil/pf/pf_ioctl.c +++ b/sys/netpfil/pf/pf_ioctl.c @@ -178,7 +178,7 @@ static int hook_pf(void); static int dehook_pf(void); static int shutdown_pf(void); static int pf_load(void); -static int pf_unload(void); +static void pf_unload(void); static struct cdevsw pf_cdevsw = { .d_ioctl = pfioctl, @@ -3789,10 +3789,9 @@ pf_unload_vnet(void) pf_mtag_cleanup(); } -static int +static void pf_unload(void) { - int error = 0; sx_xlock(&pf_end_lock); pf_end_threads = 1; @@ -3810,8 +3809,6 @@ pf_unload(void) rw_destroy(&pf_rules_lock); sx_destroy(&pf_ioctl_lock); sx_destroy(&pf_end_lock); - - return (error); } static void @@ -3829,6 +3826,7 @@ vnet_pf_uninit(const void *unused __unused) pf_unload_vnet(); } +SYSUNINIT(pf_unload, SI_SUB_PROTO_FIREWALL, SI_ORDER_SECOND, pf_unload, NULL); VNET_SYSUNINIT(vnet_pf_uninit, SI_SUB_PROTO_FIREWALL, SI_ORDER_THIRD, vnet_pf_uninit, NULL); @@ -3849,7 +3847,8 @@ pf_modevent(module_t mod, int type, void *data) error = EBUSY; break; case MOD_UNLOAD: - error = pf_unload(); + /* Handled in SYSUNINIT(pf_unload) to ensure it's done after + * the vnet_pf_uninit()s */ break; default: error = EINVAL; diff --git a/sys/sparc64/pci/psycho.c b/sys/sparc64/pci/psycho.c index d63f7083d46..f7e7c961a97 100644 --- a/sys/sparc64/pci/psycho.c +++ b/sys/sparc64/pci/psycho.c @@ -944,14 +944,14 @@ psycho_route_interrupt(device_t bridge, device_t dev, int pin) if (pin > 4) return (pin); /* - * Guess the INO; we always assume that this is a non-OBIO - * device, and that pin is a "real" intpin number. Determine - * the mapping register to be used by the slot number. - * We only need to do this on E450s, it seems; here, the slot numbers - * for bus A are one-based, while those for bus B seemingly have an - * offset of 2 (hence the factor of 3 below). + * Guess the INO; we always assume that this is a non-OBIO device, + * and that pin is a "real" intpin number. Determine the mapping + * register to be used by the slot number. + * We only need to do this on E450s and U30s, though; here, the + * slot numbers for bus A are one-based, while those for bus B + * seemingly have an offset of 2 (hence the factor of 3 below). */ - sc = device_get_softc(dev); + sc = device_get_softc(bridge); intrmap = PSR_PCIA0_INT_MAP + 8 * (pci_get_slot(dev) - 1 + 3 * sc->sc_half); mintr = INTINO(PSYCHO_READ8(sc, intrmap)) + pin - 1; diff --git a/sys/sys/cpuset.h b/sys/sys/cpuset.h index c459e7b05d2..783347750d1 100644 --- a/sys/sys/cpuset.h +++ b/sys/sys/cpuset.h @@ -83,6 +83,8 @@ #define CPU_WHICH_IRQ 4 /* Specifies an irq #. */ #define CPU_WHICH_JAIL 5 /* Specifies a jail id. */ #define CPU_WHICH_DOMAIN 6 /* Specifies a NUMA domain id. */ +#define CPU_WHICH_INTRHANDLER 7 /* Specifies an irq # (not ithread). */ +#define CPU_WHICH_ITHREAD 8 /* Specifies an irq's ithread. */ /* * Reserved cpuset identifiers. diff --git a/sys/sys/interrupt.h b/sys/sys/interrupt.h index c320e5fc8f1..44b769f2e06 100644 --- a/sys/sys/interrupt.h +++ b/sys/sys/interrupt.h @@ -162,6 +162,8 @@ int intr_event_add_handler(struct intr_event *ie, const char *name, driver_filter_t filter, driver_intr_t handler, void *arg, u_char pri, enum intr_type flags, void **cookiep); int intr_event_bind(struct intr_event *ie, int cpu); +int intr_event_bind_irqonly(struct intr_event *ie, int cpu); +int intr_event_bind_ithread(struct intr_event *ie, int cpu); int intr_event_create(struct intr_event **event, void *source, int flags, int irq, void (*pre_ithread)(void *), void (*post_ithread)(void *), void (*post_filter)(void *), @@ -173,9 +175,9 @@ int intr_event_destroy(struct intr_event *ie); void intr_event_execute_handlers(struct proc *p, struct intr_event *ie); int intr_event_handle(struct intr_event *ie, struct trapframe *frame); int intr_event_remove_handler(void *cookie); -int intr_getaffinity(int irq, void *mask); +int intr_getaffinity(int irq, int mode, void *mask); void *intr_handler_source(void *cookie); -int intr_setaffinity(int irq, void *mask); +int intr_setaffinity(int irq, int mode, void *mask); void _intr_drain(int irq); /* Linux compat only. */ int swi_add(struct intr_event **eventp, const char *name, driver_intr_t handler, void *arg, int pri, enum intr_type flags, diff --git a/sys/sys/libkern.h b/sys/sys/libkern.h index 9267908332a..ee765580fd4 100644 --- a/sys/sys/libkern.h +++ b/sys/sys/libkern.h @@ -210,6 +210,9 @@ calculate_crc32c(uint32_t crc32c, const unsigned char *buffer, #if defined(__amd64__) || defined(__i386__) uint32_t sse42_crc32c(uint32_t, const unsigned char *, unsigned); #endif +#if defined(__aarch64__) +uint32_t armv8_crc32c(uint32_t, const unsigned char *, unsigned int); +#endif #endif diff --git a/sys/vm/vm_meter.c b/sys/vm/vm_meter.c index 5f4cd46ab1e..b4666a400b2 100644 --- a/sys/vm/vm_meter.c +++ b/sys/vm/vm_meter.c @@ -266,8 +266,27 @@ static SYSCTL_NODE(_vm_stats, OID_AUTO, vm, CTLFLAG_RW, 0, "VM meter vm stats"); SYSCTL_NODE(_vm_stats, OID_AUTO, misc, CTLFLAG_RW, 0, "VM meter misc stats"); +static int +sysctl_handle_vmstat(SYSCTL_HANDLER_ARGS) +{ + uint64_t val; +#ifdef COMPAT_FREEBSD11 + uint32_t val32; +#endif + + val = counter_u64_fetch(*(counter_u64_t *)arg1); +#ifdef COMPAT_FREEBSD11 + if (req->oldlen == sizeof(val32)) { + val32 = val; /* truncate */ + return (SYSCTL_OUT(req, &val32, sizeof(val32))); + } +#endif + return (SYSCTL_OUT(req, &val, sizeof(val))); +} + #define VM_STATS(parent, var, descr) \ - SYSCTL_COUNTER_U64(parent, OID_AUTO, var, CTLFLAG_RD, &vm_cnt.var, descr) + SYSCTL_OID(parent, OID_AUTO, var, CTLTYPE_U64 | CTLFLAG_MPSAFE | \ + CTLFLAG_RD, &vm_cnt.var, 0, sysctl_handle_vmstat, "QU", descr); #define VM_STATS_VM(var, descr) VM_STATS(_vm_stats_vm, var, descr) #define VM_STATS_SYS(var, descr) VM_STATS(_vm_stats_sys, var, descr) diff --git a/sys/x86/x86/mca.c b/sys/x86/x86/mca.c index bc63ae9423f..d6ec8886d05 100644 --- a/sys/x86/x86/mca.c +++ b/sys/x86/x86/mca.c @@ -653,7 +653,7 @@ amd_thresholding_update(enum scan_mode mode, int bank, int valid) * count of the number of valid MC records found. */ static int -mca_scan(enum scan_mode mode) +mca_scan(enum scan_mode mode, int *recoverablep) { struct mca_record rec; uint64_t mcg_cap, ucmask; @@ -704,7 +704,9 @@ mca_scan(enum scan_mode mode) } if (mode == POLLED) mca_fill_freelist(); - return (mode == MCE ? recoverable : count); + if (recoverablep != NULL) + *recoverablep = recoverable; + return (count); } /* @@ -726,7 +728,7 @@ mca_scan_cpus(void *context, int pending) CPU_FOREACH(cpu) { sched_bind(td, cpu); thread_unlock(td); - count += mca_scan(POLLED); + count += mca_scan(POLLED, NULL); thread_lock(td); sched_unbind(td); } @@ -1150,7 +1152,7 @@ void mca_intr(void) { uint64_t mcg_status; - int old_count, recoverable; + int recoverable, count; if (!(cpu_feature & CPUID_MCA)) { /* @@ -1164,20 +1166,18 @@ mca_intr(void) } /* Scan the banks and check for any non-recoverable errors. */ - old_count = mca_count; - recoverable = mca_scan(MCE); + count = mca_scan(MCE, &recoverable); mcg_status = rdmsr(MSR_MCG_STATUS); if (!(mcg_status & MCG_STATUS_RIPV)) recoverable = 0; if (!recoverable) { /* - * Wait for at least one error to be logged before - * panic'ing. Some errors will assert a machine check - * on all CPUs, but only certain CPUs will find a valid - * bank to log. + * Only panic if the error was detected local to this CPU. + * Some errors will assert a machine check on all CPUs, but + * only certain CPUs will find a valid bank to log. */ - while (mca_count == old_count) + while (count == 0) cpu_spinwait(); panic("Unrecoverable machine check exception"); @@ -1199,7 +1199,7 @@ cmc_intr(void) * Serialize MCA bank scanning to prevent collisions from * sibling threads. */ - count = mca_scan(CMCI); + count = mca_scan(CMCI, NULL); /* If we found anything, log them to the console. */ if (count != 0) { diff --git a/tests/sys/geom/class/mirror/8_test.sh b/tests/sys/geom/class/mirror/8_test.sh new file mode 100755 index 00000000000..9eefc9d5e01 --- /dev/null +++ b/tests/sys/geom/class/mirror/8_test.sh @@ -0,0 +1,53 @@ +#!/bin/sh +# $FreeBSD$ + +# Regression test for r317712. + +. `dirname $0`/conf.sh + +echo 1..1 + +ddbs=2048 +m1=`mktemp $base.XXXXXX` || exit 1 +m2=`mktemp $base.XXXXXX` || exit 1 + +dd if=/dev/zero of=$m1 bs=$ddbs count=1024 >/dev/null 2>&1 +dd if=/dev/zero of=$m2 bs=$ddbs count=1024 >/dev/null 2>&1 + +us0=$(mdconfig -t vnode -f $m1) || exit 1 +us1=$(mdconfig -t vnode -f $m2) || exit 1 + +gmirror label $name /dev/$us0 /dev/$us1 || exit 1 +devwait + +# Ensure that the mirrors are marked dirty, and then disconnect them. +# We need to have the gmirror provider open when destroying the MDs since +# gmirror will automatically mark the mirrors clean when the provider is closed. +exec 9>/dev/mirror/$name +dd if=/dev/zero bs=$ddbs count=1 >&9 2>/dev/null +mdconfig -d -u ${us0#md} -o force || exit 1 +mdconfig -d -u ${us1#md} -o force || exit 1 +exec 9>&- + +dd if=/dev/random of=$m1 bs=$ddbs count=1 conv=notrunc >/dev/null 2>&1 +us0=$(attach_md -t vnode -f $m1) || exit 1 +devwait # This will take kern.geom.mirror.timeout seconds. + +# Re-attach the second mirror and wait for it to synchronize. +us1=$(attach_md -t vnode -f $m2) || exit 1 +while [ $(gmirror status $name | grep ACTIVE | wc -l) -ne 2 ]; do + sleep 1 +done + +# Verify the two mirrors are identical. Destroy the gmirror first so that +# the mirror metadata is wiped; otherwise the metadata blocks will fail +# the comparison. It would be nice to do this with a "gmirror verify" +# command instead. +gmirror destroy $name +if cmp -s ${m1} ${m2}; then + echo "ok 1" +else + echo "not ok 1" +fi + +rm -f $m1 $m2 diff --git a/tests/sys/geom/class/mirror/9_test.sh b/tests/sys/geom/class/mirror/9_test.sh new file mode 100755 index 00000000000..072499fd8b9 --- /dev/null +++ b/tests/sys/geom/class/mirror/9_test.sh @@ -0,0 +1,62 @@ +#!/bin/sh +# $FreeBSD$ + +# Regression test for r306743. + +. `dirname $0`/conf.sh + +echo 1..1 + +ddbs=2048 +m1=`mktemp $base.XXXXXX` || exit 1 +m2=`mktemp $base.XXXXXX` || exit 1 +m3=`mktemp $base.XXXXXX` || exit 1 + +dd if=/dev/zero of=$m1 bs=$ddbs count=1024 >/dev/null 2>&1 +dd if=/dev/zero of=$m2 bs=$ddbs count=1024 >/dev/null 2>&1 +dd if=/dev/zero of=$m3 bs=$ddbs count=1024 >/dev/null 2>&1 + +us0=$(attach_md -t vnode -f $m1) || exit 1 +us1=$(attach_md -t vnode -f $m2) || exit 1 +us2=$(attach_md -t vnode -f $m3) || exit 1 + +gmirror label $name /dev/$us0 /dev/$us1 || exit 1 +devwait + +# Break one of the mirrors by forcing a single metadata write error. +# When dd closes the mirror provider, gmirror will attempt to mark the mirrors +# clean, and will kick one of the mirrors out upon hitting the error. +sysctl debug.fail_point.g_mirror_metadata_write='1*return(5)' || exit 1 +dd if=/dev/random of=/dev/mirror/$name bs=$ddbs count=1 >/dev/null 2>&1 +sysctl debug.fail_point.g_mirror_metadata_write='off' || exit 1 + +# Replace the broken mirror, and then stop the gmirror. +gmirror forget $name || exit 1 +gmirror insert $name /dev/$us2 || exit 1 +while [ $(gmirror status $name | grep ACTIVE | wc -l) -ne 2 ]; do + sleep 1 +done +gmirror stop $name || exit 1 + +# Restart the gmirror on the original two mirrors. One of them is broken, +# so we should end up with a degraded gmirror. +gmirror activate $name /dev/$us0 /dev/$us1 || exit 1 +devwait +dd if=/dev/random of=/dev/mirror/$name bs=$ddbs count=1 >/dev/null 2>&1 + +# Re-add the replacement mirror and verify the two mirrors are synchronized. +# Destroy the gmirror first so that the mirror metadata is wiped; otherwise +# the metadata blocks will fail the comparison. It would be nice to do this +# with a "gmirror verify" command instead. +gmirror activate $name /dev/$us2 || exit 1 +while [ $(gmirror status $name | grep ACTIVE | wc -l) -ne 2 ]; do + sleep 1 +done +gmirror destroy $name || exit 1 +if cmp -s $m1 $m3; then + echo "ok 1" +else + echo "not ok 1" +fi + +rm -f $m1 $m2 $m3 diff --git a/tests/sys/geom/class/mirror/Makefile b/tests/sys/geom/class/mirror/Makefile index 2665631d606..66f9249405e 100644 --- a/tests/sys/geom/class/mirror/Makefile +++ b/tests/sys/geom/class/mirror/Makefile @@ -11,6 +11,8 @@ TAP_TESTS_SH+= 4_test TAP_TESTS_SH+= 5_test TAP_TESTS_SH+= 6_test TAP_TESTS_SH+= 7_test +TAP_TESTS_SH+= 8_test +TAP_TESTS_SH+= 9_test ${PACKAGE}FILES+= conf.sh diff --git a/tests/sys/kern/Makefile b/tests/sys/kern/Makefile index 4efa4a43448..4b05d31c777 100644 --- a/tests/sys/kern/Makefile +++ b/tests/sys/kern/Makefile @@ -30,10 +30,16 @@ NETBSD_ATF_TESTS_C+= mqueue_test CFLAGS.mqueue_test+= -I${SRCTOP}/tests LIBADD.mqueue_test+= rt -.if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "i386" +.if ${MACHINE_ARCH} == "amd64" || \ + ${MACHINE_ARCH} == "i386" || \ + ${MACHINE_ARCH} == "aarch64" ATF_TESTS_C+= libkern_crc32 CFLAGS.libkern_crc32+= -DUSERSPACE_TESTING +.if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "i386" LDADD.libkern_crc32+= ${SRCTOP}/sys/libkern/x86/crc32_sse42.c +.else +LDADD.libkern_crc32+= ${SRCTOP}/sys/libkern/arm64/crc32c_armv8.S +.endif .endif # subr_unit.c contains functions whose prototypes lie in headers that cannot be diff --git a/tests/sys/kern/libkern_crc32.c b/tests/sys/kern/libkern_crc32.c index 5eef045c457..03d02312434 100644 --- a/tests/sys/kern/libkern_crc32.c +++ b/tests/sys/kern/libkern_crc32.c @@ -32,7 +32,13 @@ #include +#if defined(__amd64__) || defined(__i386__) extern uint32_t sse42_crc32c(uint32_t, const unsigned char *, unsigned); +#elif defined(__aarch64__) +extern uint32_t armv8_crc32c(uint32_t, const unsigned char *, unsigned); +#else +#error These tests are not supported on this platform +#endif ATF_TC_WITHOUT_HEAD(crc32c_basic_correctness); ATF_TC_BODY(crc32c_basic_correctness, tc) @@ -79,8 +85,13 @@ ATF_TC_BODY(crc32c_basic_correctness, tc) ATF_REQUIRE(nitems(inputs) == nitems(results)); for (i = 0; i < nitems(inputs); i++) { +#if defined(__amd64__) || defined(__i386__) act = sse42_crc32c(~0, (const void *)&inputs[i], sizeof(inputs[0])); +#else + act = armv8_crc32c(~0, (const void *)&inputs[i], + sizeof(inputs[0])); +#endif ATF_REQUIRE_MSG(act == results[i], "crc32c(0x%jx) = 0x%08x, got 0x%08x", (uintmax_t)inputs[i], results[i], act); @@ -100,7 +111,11 @@ ATF_TC_BODY(crc32c_alignment, tc) for (i = 1; i < 8; i++) { memcpy(&buf[i], &input, sizeof(input)); +#if defined(__amd64__) || defined(__i386__) act = sse42_crc32c(~0, (const void *)&buf[i], sizeof(input)); +#else + act = armv8_crc32c(~0, (const void *)&buf[i], sizeof(input)); +#endif ATF_REQUIRE_MSG(act == result, "crc32c(0x%jx) = 0x%08x, got 0x%08x", (uintmax_t)input, result, act); @@ -117,7 +132,11 @@ ATF_TC_BODY(crc32c_trailing_bytes, tc) const uint32_t result = 0xec638d62; uint32_t act; +#if defined(__amd64__) || defined(__i386__) act = sse42_crc32c(~0, input, sizeof(input)); +#else + act = armv8_crc32c(~0, input, sizeof(input)); +#endif ATF_REQUIRE_MSG(act == result, "expected 0x%08x, got 0x%08x", result, act); } diff --git a/tests/sys/kern/unix_seqpacket_test.c b/tests/sys/kern/unix_seqpacket_test.c index 7305ab35f28..3499b894614 100644 --- a/tests/sys/kern/unix_seqpacket_test.c +++ b/tests/sys/kern/unix_seqpacket_test.c @@ -127,7 +127,7 @@ shutdown_send_sigpipe_handler(int __unused x) * Parameterized test function bodies */ static void -test_eagain(size_t sndbufsize, size_t rcvbufsize) +test_eagain(int sndbufsize, int rcvbufsize) { int i; int sv[2]; @@ -165,7 +165,7 @@ test_eagain(size_t sndbufsize, size_t rcvbufsize) } static void -test_sendrecv_symmetric_buffers(size_t bufsize, int blocking) { +test_sendrecv_symmetric_buffers(int bufsize, int blocking) { int s; int sv[2]; const ssize_t pktsize = bufsize / 2; @@ -209,7 +209,7 @@ test_sendrecv_symmetric_buffers(size_t bufsize, int blocking) { } static void -test_pipe_simulator(size_t sndbufsize, size_t rcvbufsize) +test_pipe_simulator(int sndbufsize, int rcvbufsize) { int num_sent, num_received; int sv[2]; @@ -341,7 +341,7 @@ test_pipe_reader(void* args) static void -test_pipe(size_t sndbufsize, size_t rcvbufsize) +test_pipe(int sndbufsize, int rcvbufsize) { test_pipe_thread_data_t writer_data, reader_data; pthread_t writer, reader; @@ -875,8 +875,8 @@ ATF_TC_WITHOUT_HEAD(emsgsize); ATF_TC_BODY(emsgsize, tc) { int sv[2]; - const size_t sndbufsize = 8192; - const size_t rcvbufsize = 8192; + const int sndbufsize = 8192; + const int rcvbufsize = 8192; const size_t pktsize = (sndbufsize + rcvbufsize) * 2; char sndbuf[pktsize]; ssize_t ssize; @@ -904,8 +904,8 @@ ATF_TC_WITHOUT_HEAD(emsgsize_nonblocking); ATF_TC_BODY(emsgsize_nonblocking, tc) { int sv[2]; - const size_t sndbufsize = 8192; - const size_t rcvbufsize = 8192; + const int sndbufsize = 8192; + const int rcvbufsize = 8192; const size_t pktsize = (sndbufsize + rcvbufsize) * 2; char sndbuf[pktsize]; ssize_t ssize; @@ -962,8 +962,8 @@ ATF_TC_BODY(rcvbuf_oversized, tc) int i; int sv[2]; const ssize_t pktsize = 1024; - const size_t sndbufsize = 8192; - const size_t rcvbufsize = 131072; + const int sndbufsize = 8192; + const int rcvbufsize = 131072; const size_t geometric_mean_bufsize = 32768; const int numpkts = geometric_mean_bufsize / pktsize; char sndbuf[pktsize]; diff --git a/tools/tools/net80211/scripts/setup.wdsmain b/tools/tools/net80211/scripts/setup.wdsmain index 6123d83f73f..c25e06fb8a7 100644 --- a/tools/tools/net80211/scripts/setup.wdsmain +++ b/tools/tools/net80211/scripts/setup.wdsmain @@ -15,6 +15,13 @@ # otherwise frames transmitted from the WDS AP to the WDS STA # will not be encrypted. # +# * Because wlanwds is running on the physical interface (for now), +# and NOT the parent VAP, it will create cloned interfaces using +# the MAC address of the physical interface. So, until that +# whole setup is fixed, please only associate DWDS to the first +# VAP on a physical interface, which shares the MAC address of +# the physical NIC. +# # $FreeBSD$ # PATH=.:$PATH diff --git a/usr.bin/Makefile b/usr.bin/Makefile index db6b22c37e5..87affa429cd 100644 --- a/usr.bin/Makefile +++ b/usr.bin/Makefile @@ -301,6 +301,12 @@ SUBDIR.${MK_UTMPX}+= who SUBDIR.${MK_SVN}+= svn SUBDIR.${MK_SVNLITE}+= svn +# These are normally only handled for build-tools. +.if make(clean*) +SUBDIR+= mkcsmapper_static +SUBDIR+= mkesdb_static +.endif + .include SUBDIR:= ${SUBDIR:O:u} diff --git a/usr.bin/csplit/csplit.c b/usr.bin/csplit/csplit.c index a5e819f47c3..b23c85d23a6 100644 --- a/usr.bin/csplit/csplit.c +++ b/usr.bin/csplit/csplit.c @@ -195,7 +195,7 @@ main(int argc, char *argv[]) /* Copy the rest into a new file. */ if (!feof(infile)) { ofp = newfile(); - while ((p = get_line()) != NULL && fputs(p, ofp) == 0) + while ((p = get_line()) != NULL && fputs(p, ofp) != EOF) ; if (!sflag) printf("%jd\n", (intmax_t)ftello(ofp)); @@ -392,7 +392,7 @@ do_rexp(const char *expr) /* Read and output lines until we get a match. */ first = 1; while ((p = get_line()) != NULL) { - if (fputs(p, ofp) != 0) + if (fputs(p, ofp) == EOF) break; if (!first && regexec(&cre, p, 0, NULL, 0) == 0) break; @@ -453,7 +453,7 @@ do_lineno(const char *expr) while (lineno + 1 != lastline) { if ((p = get_line()) == NULL) errx(1, "%ld: out of range", lastline); - if (fputs(p, ofp) != 0) + if (fputs(p, ofp) == EOF) break; } if (!sflag) diff --git a/usr.bin/grep/Makefile b/usr.bin/grep/Makefile index c6b25f06182..758eac7f938 100644 --- a/usr.bin/grep/Makefile +++ b/usr.bin/grep/Makefile @@ -82,7 +82,7 @@ CFLAGS+= -DWITHOUT_BZIP2 .endif .if ${MK_GNU_GREP_COMPAT} != "no" -CFLAGS+= -I${DESTDIR}/usr/include/gnu +CFLAGS+= -I${DESTDIR}/usr/include/gnu -DWITH_GNU LIBADD+= gnuregex .endif diff --git a/usr.bin/grep/grep.c b/usr.bin/grep/grep.c index 20aec53f59c..3af9090d32c 100644 --- a/usr.bin/grep/grep.c +++ b/usr.bin/grep/grep.c @@ -74,13 +74,20 @@ const char *errstr[] = { /* 7*/ "\t[--null] [pattern] [file ...]\n", /* 8*/ "Binary file %s matches\n", /* 9*/ "%s (BSD grep) %s\n", +/* 10*/ "%s (BSD grep, GNU compatible) %s\n", }; /* Flags passed to regcomp() and regexec() */ int cflags = REG_NOSUB; int eflags = REG_STARTEND; -/* Shortcut for matching all cases like empty regex */ +/* XXX TODO: Get rid of this flag. + * matchall is a gross hack that means that an empty pattern was passed to us. + * It is a necessary evil at the moment because our regex(3) implementation + * does not allow for empty patterns, as supported by POSIX's definition of + * grammar for BREs/EREs. When libregex becomes available, it would be wise + * to remove this and let regex(3) handle the dirty details of empty patterns. + */ bool matchall; /* Searching patterns */ @@ -152,9 +159,6 @@ enum { static inline const char *init_color(const char *); /* Housekeeping */ -bool first = true; /* flag whether we are processing the first match */ -bool prev; /* flag whether or not the previous line matched */ -int tail; /* lines left to print */ bool file_err; /* file reading error */ /* @@ -596,7 +600,11 @@ main(int argc, char *argv[]) filebehave = FILE_MMAP; break; case 'V': +#ifdef WITH_GNU + printf(getstr(10), getprogname(), VERSION); +#else printf(getstr(9), getprogname(), VERSION); +#endif exit(0); case 'v': vflag = true; @@ -708,8 +716,13 @@ main(int argc, char *argv[]) case GREP_BASIC: break; case GREP_FIXED: - /* XXX: header mess, REG_LITERAL not defined in gnu/regex.h */ - cflags |= 0020; +#if defined(REG_NOSPEC) + cflags |= REG_NOSPEC; +#elif defined(REG_LITERAL) + cflags |= REG_LITERAL; +#else + errx(2, "literal expressions not supported at compile time"); +#endif break; case GREP_EXTENDED: cflags |= REG_EXTENDED; @@ -724,20 +737,25 @@ main(int argc, char *argv[]) #endif r_pattern = grep_calloc(patterns, sizeof(*r_pattern)); - /* Check if cheating is allowed (always is for fgrep). */ - for (i = 0; i < patterns; ++i) { + /* Don't process any patterns if we have a blank one */ + if (!matchall) { + /* Check if cheating is allowed (always is for fgrep). */ + for (i = 0; i < patterns; ++i) { #ifndef WITHOUT_FASTMATCH - /* Attempt compilation with fastmatch regex and fallback to - regex(3) if it fails. */ - if (fastncomp(&fg_pattern[i], pattern[i].pat, - pattern[i].len, cflags) == 0) - continue; + /* + * Attempt compilation with fastmatch regex and + * fallback to regex(3) if it fails. + */ + if (fastncomp(&fg_pattern[i], pattern[i].pat, + pattern[i].len, cflags) == 0) + continue; #endif - c = regcomp(&r_pattern[i], pattern[i].pat, cflags); - if (c != 0) { - regerror(c, &r_pattern[i], re_error, - RE_ERROR_BUF); - errx(2, "%s", re_error); + c = regcomp(&r_pattern[i], pattern[i].pat, cflags); + if (c != 0) { + regerror(c, &r_pattern[i], re_error, + RE_ERROR_BUF); + errx(2, "%s", re_error); + } } } diff --git a/usr.bin/grep/grep.h b/usr.bin/grep/grep.h index ea17af4099d..56ce456abb6 100644 --- a/usr.bin/grep/grep.h +++ b/usr.bin/grep/grep.h @@ -123,8 +123,7 @@ extern char *label; extern const char *color; extern int binbehave, devbehave, dirbehave, filebehave, grepbehave, linkbehave; -extern bool file_err, first, matchall, prev; -extern int tail; +extern bool file_err, matchall; extern unsigned int dpatterns, fpatterns, patterns; extern struct pat *pattern; extern struct epat *dpattern, *fpattern; @@ -145,10 +144,10 @@ void *grep_malloc(size_t size); void *grep_calloc(size_t nmemb, size_t size); void *grep_realloc(void *ptr, size_t size); char *grep_strdup(const char *str); -void printline(struct str *line, int sep, regmatch_t *matches, int m); +void grep_printline(struct str *line, int sep); /* queue.c */ -void enqueue(struct str *x); +bool enqueue(struct str *x); void printqueue(void); void clearqueue(void); diff --git a/usr.bin/grep/nls/C.msg b/usr.bin/grep/nls/C.msg index 6327b278072..a86bafa92fe 100644 --- a/usr.bin/grep/nls/C.msg +++ b/usr.bin/grep/nls/C.msg @@ -5,9 +5,10 @@ $quote " 1 "(standard input)" 2 "cannot read bzip2 compressed file" 3 "unknown %s option" -4 "usage: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZ] [-A num] [-B num] [-C[num]]\n" +4 "usage: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZz] [-A num] [-B num] [-C[num]]\n" 5 "\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n" 6 "\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n" 7 "\t[--null] [pattern] [file ...]\n" 8 "Binary file %s matches\n" 9 "%s (BSD grep) %s\n" +10 "%s (BSD grep, GNU compatible) %s\n" diff --git a/usr.bin/grep/nls/es_ES.ISO8859-1.msg b/usr.bin/grep/nls/es_ES.ISO8859-1.msg index 208e91d7987..fc65913d8c9 100644 --- a/usr.bin/grep/nls/es_ES.ISO8859-1.msg +++ b/usr.bin/grep/nls/es_ES.ISO8859-1.msg @@ -5,9 +5,10 @@ $quote " 1 "(entrada estándar)" 2 "no se puede leer el fichero comprimido bzip2" 3 "opción desconocida de %s" -4 "uso: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZ] [-A no] [-B no] [-C[no]]\n" +4 "uso: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZz] [-A no] [-B no] [-C[no]]\n" 5 "\t[-e pauta] [-f fichero] [--binary-files=valor] [--color=cuando]\n" 6 "\t[--context[=no]] [--directories=acción] [--label] [--line-buffered]\n" 7 "\t[--null] [pauta] [fichero ...]\n" 8 "fichero binario %s se ajusta\n" 9 "%s (BSD grep) %s\n" +10 "%s (BSD grep, GNU compatible) %s\n" diff --git a/usr.bin/grep/nls/gl_ES.ISO8859-1.msg b/usr.bin/grep/nls/gl_ES.ISO8859-1.msg index 9f3915a3dad..6de2798bbed 100644 --- a/usr.bin/grep/nls/gl_ES.ISO8859-1.msg +++ b/usr.bin/grep/nls/gl_ES.ISO8859-1.msg @@ -5,9 +5,10 @@ $quote " 1 "(entrada estándar)" 2 "non se pode ler o ficheiro comprimido bzip2" 3 "opción descoñecida de %s" -4 "uso: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZ] [-A no] [-B no] [-C[no]]\n" +4 "uso: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZz] [-A no] [-B no] [-C[no]]\n" 5 "\t[-e pauta] [-f ficheiro] [--binary-files=valor] [--color=cando]\n" 6 "\t[--context[=no]] [--directories=acción] [--label] [--line-buffered]\n" 7 "\t[--null] [pauta] [ficheiro ...]\n" 8 "ficheiro binario %s conforma\n" 9 "%s (BSD grep) %s\n" +10 "%s (BSD grep, GNU compatible) %s\n" diff --git a/usr.bin/grep/nls/hu_HU.ISO8859-2.msg b/usr.bin/grep/nls/hu_HU.ISO8859-2.msg index 6d3c1c91a83..c7740705947 100644 --- a/usr.bin/grep/nls/hu_HU.ISO8859-2.msg +++ b/usr.bin/grep/nls/hu_HU.ISO8859-2.msg @@ -5,9 +5,10 @@ $quote " 1 "(szabványos bemenet)" 2 "bzip2 tömörített fájl nem olvasható" 3 "ismeretlen %s opció" -4 "használat: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZ] [-A szám] [-B szám] [-C[szám]]\n" +4 "használat: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZz] [-A szám] [-B szám] [-C[szám]]\n" 5 "\t[-e minta] [-f fájl] [--binary-files=érték] [--color=mikor]\n" 6 "\t[--context[=szám]] [--directories=mûvelet] [--label] [--line-buffered]\n" 7 "\t[--null] [minta] [fájl ...]\n" 8 "%s bináris fájl illeszkedik\n" 9 "%s (BSD grep) %s\n" +10 "%s (BSD grep, GNU compatible) %s\n" diff --git a/usr.bin/grep/nls/ja_JP.SJIS.msg b/usr.bin/grep/nls/ja_JP.SJIS.msg index d18edd523c6..8f532c4881c 100644 --- a/usr.bin/grep/nls/ja_JP.SJIS.msg +++ b/usr.bin/grep/nls/ja_JP.SJIS.msg @@ -5,9 +5,10 @@ $quote " 1 "(•W€“ü—Í)" 2 "bzip2 ˆ³kƒtƒ@ƒCƒ‹‚ð“ǂݞ‚Þ‚±‚Æ‚ª‚Å‚«‚Ü‚¹‚ñ" 3 "%s ƒIƒvƒVƒ‡ƒ“‚ÌŽw’è’l‚ÉŒë‚肪‚ ‚è‚Ü‚·" -4 "Žg‚¢•û: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZ] [-A ”Žš] [-B ”Žš] [-C[”Žš]]\n" +4 "Žg‚¢•û: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZz] [-A ”Žš] [-B ”Žš] [-C[”Žš]]\n" 5 "\t[-e ƒpƒ^[ƒ“] [-f ƒtƒ@ƒCƒ‹–¼] [--binary-files=’l] [--color=’l]\n" 6 "\t[--context[=”Žš]] [--directories=“®ì] [--label] [--line-buffered]\n" 7 "\t[--null] [ƒpƒ^[ƒ“] [ƒtƒ@ƒCƒ‹–¼ ...]\n" 8 "ƒoƒCƒiƒŠƒtƒ@ƒCƒ‹ %s ‚Ƀ}ƒbƒ`‚µ‚Ü‚µ‚½\n" 9 "%s (BSD grep) %s\n" +10 "%s (BSD grep, GNU compatible) %s\n" diff --git a/usr.bin/grep/nls/ja_JP.UTF-8.msg b/usr.bin/grep/nls/ja_JP.UTF-8.msg index 84c6f450108..e59708bda7a 100644 --- a/usr.bin/grep/nls/ja_JP.UTF-8.msg +++ b/usr.bin/grep/nls/ja_JP.UTF-8.msg @@ -5,9 +5,10 @@ $quote " 1 "(標準入力)" 2 "bzip2 圧縮ファイルを読ã¿è¾¼ã‚€ã“ã¨ãŒã§ãã¾ã›ã‚“" 3 "%s ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã®æŒ‡å®šå€¤ã«èª¤ã‚ŠãŒã‚りã¾ã™" -4 "ä½¿ã„æ–¹: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZ] [-A æ•°å­—] [-B æ•°å­—] [-C[æ•°å­—]]\n" +4 "ä½¿ã„æ–¹: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZz] [-A æ•°å­—] [-B æ•°å­—] [-C[æ•°å­—]]\n" 5 "\t[-e パターン] [-f ファイルå] [--binary-files=値] [--color=値]\n" 6 "\t[--context[=æ•°å­—]] [--directories=動作] [--label] [--line-buffered]\n" 7 "\t[--null] [パターン] [ファイルå ...]\n" 8 "ãƒã‚¤ãƒŠãƒªãƒ•ァイル %s ã«ãƒžãƒƒãƒã—ã¾ã—ãŸ\n" 9 "%s (BSD grep) %s\n" +10 "%s (BSD grep, GNU compatible) %s\n" diff --git a/usr.bin/grep/nls/ja_JP.eucJP.msg b/usr.bin/grep/nls/ja_JP.eucJP.msg index e778c5f855a..8f2e97dcb90 100644 --- a/usr.bin/grep/nls/ja_JP.eucJP.msg +++ b/usr.bin/grep/nls/ja_JP.eucJP.msg @@ -5,9 +5,10 @@ $quote " 1 "(ɸ½àÆþÎÏ)" 2 "bzip2 °µ½Ì¥Õ¥¡¥¤¥ë¤òÆÉ¤ß¹þ¤à¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó" 3 "%s ¥ª¥×¥·¥ç¥ó¤Î»ØÄêÃͤ˸í¤ê¤¬¤¢¤ê¤Þ¤¹" -4 "»È¤¤Êý: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZ] [-A ¿ô»ú] [-B ¿ô»ú] [-C[¿ô»ú]]\n" +4 "»È¤¤Êý: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZz] [-A ¿ô»ú] [-B ¿ô»ú] [-C[¿ô»ú]]\n" 5 "\t[-e ¥Ñ¥¿¡¼¥ó] [-f ¥Õ¥¡¥¤¥ë̾] [--binary-files=ÃÍ] [--color=ÃÍ]\n" 6 "\t[--context[=¿ô»ú]] [--directories=ưºî] [--label] [--line-buffered]\n" 7 "\t[--null] [¥Ñ¥¿¡¼¥ó] [¥Õ¥¡¥¤¥ë̾ ...]\n" 8 "¥Ð¥¤¥Ê¥ê¥Õ¥¡¥¤¥ë %s ¤Ë¥Þ¥Ã¥Á¤·¤Þ¤·¤¿\n" 9 "%s (BSD grep) %s\n" +10 "%s (BSD grep, GNU compatible) %s\n" diff --git a/usr.bin/grep/nls/pt_BR.ISO8859-1.msg b/usr.bin/grep/nls/pt_BR.ISO8859-1.msg index 79c026ef5b7..15d777a3dd7 100644 --- a/usr.bin/grep/nls/pt_BR.ISO8859-1.msg +++ b/usr.bin/grep/nls/pt_BR.ISO8859-1.msg @@ -5,9 +5,10 @@ $quote " 1 "(entrada padrão)" 2 "não se posso ler o fichero comprimido bzip2" 3 "opcão não conhecida de %s" -4 "uso: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZ] [-A num] [-B num] [-C[num]]\n" +4 "uso: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZz] [-A num] [-B num] [-C[num]]\n" 5 "\t[-e padrão] [-f arquivo] [--binary-files=valor] [--color=quando]\n" 6 "\t[--context[=num]] [--directories=ação] [--label] [--line-buffered]\n" 7 "\t[--null] [padrão] [arquivo ...]\n" 8 "arquivo binário %s casa com o padrão\n" 9 "%s (BSD grep) %s\n" +10 "%s (BSD grep, GNU compatible) %s\n" diff --git a/usr.bin/grep/nls/ru_RU.KOI8-R.msg b/usr.bin/grep/nls/ru_RU.KOI8-R.msg index 6880d51016c..f12b1b64a1c 100644 --- a/usr.bin/grep/nls/ru_RU.KOI8-R.msg +++ b/usr.bin/grep/nls/ru_RU.KOI8-R.msg @@ -5,9 +5,10 @@ $quote " 1 "(ÓÔÁÎÄÁÒÔÎÙÊ ××ÏÄ)" 2 "ÎÅ ÍÏÇÕ ÐÒÏÞÉÔÁÔØ ÓÖÁÔÙÊ × bzip2 ÆÁÊÌ" 3 "ÎÅÉÚ×ÅÓÔÎÙÊ ËÌÀÞ %s" -4 "ÉÓÐÏÌØÚÏ×ÁÎÉÅ: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZ] [-A ÞÉÓ] [-B ÞÉÓ] [-C[ÞÉÓ]]\n" +4 "ÉÓÐÏÌØÚÏ×ÁÎÉÅ: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZz] [-A ÞÉÓ] [-B ÞÉÓ] [-C[ÞÉÓ]]\n" 5 "\t[-e ÛÁÂÌÏÎ] [-f ÆÁÊÌ] [--binary-files=ÚÎÁÞÅÎÉÅ] [--color=ËÏÇÄÁ]\n" 6 "\t[--context[=ÞÉÓ]] [--directories=ÄÅÊÓÔ×ÉÅ] [--label] [--line-buffered]\n" 7 "\t[--null] [ÛÁÂÌÏÎ] [ÆÁÊÌ ...]\n" 8 "Ä×ÏÉÞÎÙÊ ÆÁÊÌ %s ÓÏ×ÐÁÄÁÅÔ\n" 9 "%s (BSD grep) %s\n" +10 "%s (BSD grep, GNU compatible) %s\n" diff --git a/usr.bin/grep/nls/uk_UA.UTF-8.msg b/usr.bin/grep/nls/uk_UA.UTF-8.msg index 4492d317bbe..4564a59e755 100644 --- a/usr.bin/grep/nls/uk_UA.UTF-8.msg +++ b/usr.bin/grep/nls/uk_UA.UTF-8.msg @@ -4,9 +4,10 @@ $quote " 1 "(Ñтандартний ввід)" 2 "не можу прочитати ÑтиÑнутий bzip2 файл" 3 "невiдома Ð¾Ð¿Ñ†Ñ–Ñ %s" -4 "викориÑтаннÑ: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZ] [-A чиÑ] [-B чиÑ] [-C[чиÑ]]\n" +4 "викориÑтаннÑ: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZz] [-A чиÑ] [-B чиÑ] [-C[чиÑ]]\n" 5 "\t[-e шаблон] [-f файл] [--binary-files=значеннÑ] [--color=коли]\n" 6 "\t[--context[=чиÑ] [--directories=діÑ] [--label] [--line-buffered]\n" 7 "\t[--null] [шаблон] [файл ...]\n" 8 "двійковий файл %s Ñпівпадає\n" 9 "%s (BSD grep) %s\n" +10 "%s (BSD grep, GNU compatible) %s\n" diff --git a/usr.bin/grep/nls/zh_CN.UTF-8.msg b/usr.bin/grep/nls/zh_CN.UTF-8.msg index d5cd0c2ef66..b727316c8be 100644 --- a/usr.bin/grep/nls/zh_CN.UTF-8.msg +++ b/usr.bin/grep/nls/zh_CN.UTF-8.msg @@ -5,9 +5,10 @@ $quote " 1 "(标准输入)" 2 "è¯»å– bzip2 压缩文件时出错" 3 "选项 %s 无法识别" -4 "用法: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZ] [-A 行数] [-B 行数] [-C[行数]]\n" +4 "用法: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZz] [-A 行数] [-B 行数] [-C[行数]]\n" 5 "\t[-e 模å¼] [-f 文件] [--binary-files=值] [--color=何时]\n" 6 "\t[--context[=行数]] [--directories=动作] [--label] [--line-buffered]\n" 7 "\t[--null] [模å¼] [文件å ...]\n" 8 "二进制文件 %s åŒ…å«æ¨¡å¼\n" 9 "%s (BSD grep) %s\n" +10 "%s (BSD grep, GNU compatible) %s\n" diff --git a/usr.bin/grep/queue.c b/usr.bin/grep/queue.c index 18878880a36..453183367b8 100644 --- a/usr.bin/grep/queue.c +++ b/usr.bin/grep/queue.c @@ -53,7 +53,10 @@ static unsigned long long count; static struct qentry *dequeue(void); -void +/* + * Enqueue another line; return true if we've dequeued a line as a result + */ +bool enqueue(struct str *x) { struct qentry *item; @@ -72,7 +75,9 @@ enqueue(struct str *x) item = dequeue(); free(item->data.dat); free(item); + return (true); } + return (false); } static struct qentry * @@ -95,7 +100,7 @@ printqueue(void) struct qentry *item; while ((item = dequeue()) != NULL) { - printline(&item->data, '-', NULL, 0); + grep_printline(&item->data, '-'); free(item->data.dat); free(item); } diff --git a/usr.bin/grep/regex/tre-fastmatch.c b/usr.bin/grep/regex/tre-fastmatch.c index 3e5394caf95..bf59b9f8d55 100644 --- a/usr.bin/grep/regex/tre-fastmatch.c +++ b/usr.bin/grep/regex/tre-fastmatch.c @@ -98,6 +98,18 @@ static int fastcmp(const fastmatch_t *fg, const void *data, fg->pattern[siz] = '\0'; \ } \ +#define CONV_MBS_PAT(src, dest, destsz) \ + { \ + destsz = wcstombs(NULL, src, 0); \ + if (destsz == (size_t)-1) \ + return REG_BADPAT; \ + dest = malloc(destsz + 1); \ + if (dest == NULL) \ + return REG_ESPACE; \ + wcstombs(dest, src, destsz); \ + dest[destsz] = '\0'; \ + } \ + #define IS_OUT_OF_BOUNDS \ ((!fg->reversed \ ? ((type == STR_WIDE) ? ((j + fg->wlen) > len) \ @@ -630,7 +642,7 @@ tre_compile_fast(fastmatch_t *fg, const tre_char_t *pat, size_t n, if (escaped) { if (!_escmap) - _escmap = malloc(n * sizeof(bool)); + _escmap = calloc(n, sizeof(bool)); if (!_escmap) { free(tmp); @@ -714,8 +726,8 @@ badpat: { if (fg->wescmap != NULL) { - fg->escmap = malloc(fg->len * sizeof(bool)); - if (!fg->escmap) + fg->escmap = calloc(fg->len, sizeof(bool)); + if (fg->escmap == NULL) { tre_free_fast(fg); return REG_ESPACE; @@ -723,15 +735,29 @@ badpat: } escaped = false; - for (unsigned int i = 0; i < fg->len; i++) - if (fg->pattern[i] == '\\') - escaped = !escaped; - else if (fg->pattern[i] == '.' && fg->escmap && escaped) + char *_checkpat = NULL; + size_t _checklen = 0; + unsigned int escofs = 0; + /* + * Make a copy here of the original pattern, because fg->pattern has + * already been stripped of all escape sequences in the above processing. + * This is necessary if we wish to later treat fg->escmap as an actual, + * functional replacement of fg->wescmap. + */ + CONV_MBS_PAT(pat, _checkpat, _checklen); + for (unsigned int i = 0; i < n; i++) + if (_checkpat[i] == '\\') { - fg->escmap[i] = true; + escaped = !escaped; + if (escaped) + ++escofs; + } + else if (_checkpat[i] == '.' && fg->escmap != NULL && escaped) + { + fg->escmap[i - escofs] = true; escaped = false; } - else if (fg->pattern[i] == '.' && !escaped) + else if (_checkpat[i] == '.' && !escaped) { hasdot = i; if (firstdot == -1) @@ -739,6 +765,7 @@ badpat: } else escaped = false; + free(_checkpat); } #else SAVE_PATTERN(tmp, pos, fg->pattern, fg->len); diff --git a/usr.bin/grep/tests/Makefile b/usr.bin/grep/tests/Makefile index f383aa220ad..f0c0c86c6b4 100644 --- a/usr.bin/grep/tests/Makefile +++ b/usr.bin/grep/tests/Makefile @@ -20,9 +20,13 @@ ${PACKAGE}FILES+= d_context2_c.out ${PACKAGE}FILES+= d_context_a.in ${PACKAGE}FILES+= d_context_a.out ${PACKAGE}FILES+= d_context_b.in +${PACKAGE}FILES+= d_context_e.in ${PACKAGE}FILES+= d_context_b.out ${PACKAGE}FILES+= d_context_c.out ${PACKAGE}FILES+= d_context_d.out +${PACKAGE}FILES+= d_context_e.out +${PACKAGE}FILES+= d_context_f.out +${PACKAGE}FILES+= d_context_g.out ${PACKAGE}FILES+= d_egrep.out ${PACKAGE}FILES+= d_escmap.in ${PACKAGE}FILES+= d_f_file_empty.in diff --git a/usr.bin/grep/util.c b/usr.bin/grep/util.c index 8815d4f3422..bd2f8acf83a 100644 --- a/usr.bin/grep/util.c +++ b/usr.bin/grep/util.c @@ -54,11 +54,23 @@ __FBSDID("$FreeBSD$"); #endif #include "grep.h" -static int linesqueued; -static int procline(struct str *l, int); +static bool first_match = true; -static int lasta; -static bool ctxover; +/* + * Parsing context; used to hold things like matches made and + * other useful bits + */ +struct parsec { + regmatch_t matches[MAX_LINE_MATCHES]; /* Matches made */ + struct str ln; /* Current line */ + size_t matchidx; /* Latest used match index */ + bool binary; /* Binary file? */ +}; + + +static int procline(struct parsec *pc); +static void printline(struct parsec *pc, int sep); +static void printline_metadata(struct str *line, int sep); bool file_matching(const char *fname) @@ -183,13 +195,13 @@ grep_tree(char **argv) int procfile(const char *fn) { + struct parsec pc; struct file *f; struct stat sb; - struct str ln; + struct str *ln; mode_t s; - int c, t; - - mcount = mlimit; + int c, last_outed, t, tail; + bool doctx, same_file; if (strcmp(fn, "-") == 0) { fn = label != NULL ? label : getstr(1); @@ -213,57 +225,97 @@ procfile(const char *fn) return (0); } - ln.file = grep_malloc(strlen(fn) + 1); - strcpy(ln.file, fn); - ln.line_no = 0; - ln.len = 0; - ctxover = false; - linesqueued = 0; + /* Convenience */ + ln = &pc.ln; + pc.ln.file = grep_malloc(strlen(fn) + 1); + strcpy(pc.ln.file, fn); + pc.ln.line_no = 0; + pc.ln.len = 0; + pc.ln.off = -1; + pc.binary = f->binary; tail = 0; - lasta = 0; - ln.off = -1; + last_outed = 0; + same_file = false; + doctx = false; + if ((!pc.binary || binbehave != BINFILE_BIN) && !cflag && !qflag && + !lflag && !Lflag && (Aflag != 0 || Bflag != 0)) + doctx = true; + mcount = mlimit; + for (c = 0; c == 0 || !(lflag || qflag); ) { - ln.off += ln.len + 1; - if ((ln.dat = grep_fgetln(f, &ln.len)) == NULL || ln.len == 0) { - if (ln.line_no == 0 && matchall) - exit(0); + /* Reset match count for every line processed */ + pc.matchidx = 0; + pc.ln.off += pc.ln.len + 1; + if ((pc.ln.dat = grep_fgetln(f, &pc.ln.len)) == NULL || + pc.ln.len == 0) { + if (pc.ln.line_no == 0 && matchall) + /* + * An empty file with an empty pattern and the + * -w flag does not match + */ + exit(matchall && wflag ? 1 : 0); else break; } - if (ln.len > 0 && ln.dat[ln.len - 1] == fileeol) - --ln.len; - ln.line_no++; + + if (pc.ln.len > 0 && pc.ln.dat[pc.ln.len - 1] == fileeol) + --pc.ln.len; + pc.ln.line_no++; /* Return if we need to skip a binary file */ - if (f->binary && binbehave == BINFILE_SKIP) { + if (pc.binary && binbehave == BINFILE_SKIP) { grep_close(f); - free(ln.file); + free(pc.ln.file); free(f); return (0); } - /* Process the file line-by-line, enqueue non-matching lines */ - if ((t = procline(&ln, f->binary)) == 0 && Bflag > 0) { - /* Except don't enqueue lines that appear in -A ctx */ - if (ln.line_no == 0 || lasta != ln.line_no) { - /* queue is maxed to Bflag number of lines */ - enqueue(&ln); - linesqueued++; - ctxover = false; + if ((t = procline(&pc)) == 0) + ++c; + + /* Deal with any -B context or context separators */ + if (t == 0 && doctx) { + if (!first_match && (!same_file || last_outed > 0)) + printf("--\n"); + if (Bflag > 0) + printqueue(); + tail = Aflag; + } + /* Print the matching line, but only if not quiet/binary */ + if (t == 0 && !qflag && !pc.binary) { + printline(&pc, ':'); + first_match = false; + same_file = true; + last_outed = 0; + } + if (t != 0 && doctx) { + /* Deal with any -A context */ + if (tail > 0) { + printline(&pc, '-'); + tail--; + if (Bflag > 0) + clearqueue(); } else { /* - * Indicate to procline() that we have ctx - * overlap and make sure queue is empty. + * Enqueue non-matching lines for -B context. + * If we're not actually doing -B context or if + * the enqueue resulted in a line being rotated + * out, then go ahead and increment last_outed + * to signify a gap between context/match. */ - if (!ctxover) - clearqueue(); - ctxover = true; + if (Bflag == 0 || (Bflag > 0 && enqueue(ln))) + ++last_outed; } } - c += t; - if (mflag && mcount <= 0) - break; + + /* Count the matches if we have a match limit */ + if (t == 0 && mflag) { + --mcount; + if (mflag && mcount <= 0) + break; + } + } if (Bflag > 0) clearqueue(); @@ -271,7 +323,7 @@ procfile(const char *fn) if (cflag) { if (!hflag) - printf("%s:", ln.file); + printf("%s:", pc.ln.file); printf("%u\n", c); } if (lflag && !qflag && c != 0) @@ -282,7 +334,7 @@ procfile(const char *fn) binbehave == BINFILE_BIN && f->binary && !qflag) printf(getstr(8), fn); - free(ln.file); + free(pc.ln.file); free(f); return (c); } @@ -297,97 +349,132 @@ procfile(const char *fn) * appropriate output. */ static int -procline(struct str *l, int nottext) +procline(struct parsec *pc) { - regmatch_t matches[MAX_LINE_MATCHES]; - regmatch_t pmatch, lastmatch; + regmatch_t pmatch, lastmatch, chkmatch; + wchar_t wbegin, wend; size_t st = 0, nst = 0; unsigned int i; - int c = 0, m = 0, r = 0, lastmatches = 0, leflags = eflags; - int startm = 0; + int c = 0, r = 0, lastmatches = 0, leflags = eflags; + size_t startm = 0, matchidx; + int retry; + + matchidx = pc->matchidx; + + /* Special case: empty pattern with -w flag, check first character */ + if (matchall && wflag) { + if (pc->ln.len == 0) + return (0); + wend = L' '; + if (sscanf(&pc->ln.dat[0], "%lc", &wend) != 1 || iswword(wend)) + return (1); + else + return (0); + } else if (matchall) + return (0); /* Initialize to avoid a false positive warning from GCC. */ lastmatch.rm_so = lastmatch.rm_eo = 0; /* Loop to process the whole line */ - while (st <= l->len) { + while (st <= pc->ln.len) { lastmatches = 0; - startm = m; + startm = matchidx; + retry = 0; if (st > 0) leflags |= REG_NOTBOL; /* Loop to compare with all the patterns */ for (i = 0; i < patterns; i++) { pmatch.rm_so = st; - pmatch.rm_eo = l->len; + pmatch.rm_eo = pc->ln.len; #ifndef WITHOUT_FASTMATCH if (fg_pattern[i].pattern) r = fastexec(&fg_pattern[i], - l->dat, 1, &pmatch, leflags); + pc->ln.dat, 1, &pmatch, leflags); else #endif - r = regexec(&r_pattern[i], l->dat, 1, + r = regexec(&r_pattern[i], pc->ln.dat, 1, &pmatch, leflags); - r = (r == 0) ? 0 : REG_NOMATCH; - if (r == REG_NOMATCH) + if (r != 0) continue; /* Check for full match */ - if (r == 0 && xflag) - if (pmatch.rm_so != 0 || - (size_t)pmatch.rm_eo != l->len) - r = REG_NOMATCH; + if (xflag && (pmatch.rm_so != 0 || + (size_t)pmatch.rm_eo != pc->ln.len)) + continue; /* Check for whole word match */ #ifndef WITHOUT_FASTMATCH - if (r == 0 && (wflag || fg_pattern[i].word)) { + if (wflag || fg_pattern[i].word) { #else - if (r == 0 && wflag) { + if (wflag) { #endif - wchar_t wbegin, wend; - wbegin = wend = L' '; if (pmatch.rm_so != 0 && - sscanf(&l->dat[pmatch.rm_so - 1], + sscanf(&pc->ln.dat[pmatch.rm_so - 1], "%lc", &wbegin) != 1) r = REG_NOMATCH; else if ((size_t)pmatch.rm_eo != - l->len && - sscanf(&l->dat[pmatch.rm_eo], + pc->ln.len && + sscanf(&pc->ln.dat[pmatch.rm_eo], "%lc", &wend) != 1) r = REG_NOMATCH; else if (iswword(wbegin) || iswword(wend)) r = REG_NOMATCH; + /* + * If we're doing whole word matching and we + * matched once, then we should try the pattern + * again after advancing just past the start of + * the earliest match. This allows the pattern + * to match later on in the line and possibly + * still match a whole word. + */ + if (r == REG_NOMATCH && + (retry == 0 || pmatch.rm_so + 1 < retry)) + retry = pmatch.rm_so + 1; + if (r == REG_NOMATCH) + continue; } - if (r == 0) { - lastmatches++; - lastmatch = pmatch; - if (m == 0) - c++; - if (m < MAX_LINE_MATCHES) { - /* Replace previous match if the new one is earlier and/or longer */ - if (m > startm) { - if (pmatch.rm_so < matches[m-1].rm_so || - (pmatch.rm_so == matches[m-1].rm_so && (pmatch.rm_eo - pmatch.rm_so) > (matches[m-1].rm_eo - matches[m-1].rm_so))) { - matches[m-1] = pmatch; - nst = pmatch.rm_eo; - } - } else { - /* Advance as normal if not */ - matches[m++] = pmatch; - nst = pmatch.rm_eo; - } + lastmatches++; + lastmatch = pmatch; + + if (matchidx == 0) + c++; + + /* + * Replace previous match if the new one is earlier + * and/or longer. This will lead to some amount of + * extra work if -o/--color are specified, but it's + * worth it from a correctness point of view. + */ + if (matchidx > startm) { + chkmatch = pc->matches[matchidx - 1]; + if (pmatch.rm_so < chkmatch.rm_so || + (pmatch.rm_so == chkmatch.rm_so && + (pmatch.rm_eo - pmatch.rm_so) > + (chkmatch.rm_eo - chkmatch.rm_so))) { + pc->matches[matchidx - 1] = pmatch; + nst = pmatch.rm_eo; } - - /* matches - skip further patterns */ - if ((color == NULL && !oflag) || - qflag || lflag) - break; + } else { + /* Advance as normal if not */ + pc->matches[matchidx++] = pmatch; + nst = pmatch.rm_eo; } + /* avoid excessive matching - skip further patterns */ + if ((color == NULL && !oflag) || qflag || lflag || + matchidx >= MAX_LINE_MATCHES) + break; } - if (vflag) { - c = !c; - break; + /* + * Advance to just past the start of the earliest match, try + * again just in case we still have a chance to match later in + * the string. + */ + if (lastmatches == 0 && retry > 0) { + st = retry; + continue; } /* One pass if we are not recording matches */ @@ -396,7 +483,7 @@ procline(struct str *l, int nottext) /* If we didn't have any matches or REG_NOSUB set */ if (lastmatches == 0 || (cflags & REG_NOSUB)) - nst = l->len; + nst = pc->ln.len; if (lastmatches == 0) /* No matches */ @@ -409,42 +496,11 @@ procline(struct str *l, int nottext) st = nst; } - - /* Count the matches if we have a match limit */ - if (mflag) - mcount -= c; - - if (c && binbehave == BINFILE_BIN && nottext) - return (c); /* Binary file */ - - /* Dealing with the context */ - if ((tail || c) && !cflag && !qflag && !lflag && !Lflag) { - if (c) { - if (!first && !prev && !tail && (Bflag || Aflag) && - !ctxover) - printf("--\n"); - tail = Aflag; - if (Bflag > 0) { - printqueue(); - ctxover = false; - } - linesqueued = 0; - printline(l, ':', matches, m); - } else { - /* Print -A lines following matches */ - lasta = l->line_no; - printline(l, '-', matches, m); - tail--; - } - } - - if (c) { - prev = true; - first = false; - } else - prev = false; - - return (c); + /* Reflect the new matchidx in the context */ + pc->matchidx = matchidx; + if (vflag) + c = !c; + return (c ? 0 : 1); } /* @@ -499,69 +555,89 @@ grep_strdup(const char *str) } /* - * Prints a matching line according to the command line options. + * Print an entire line as-is, there are no inline matches to consider. This is + * used for printing context. */ -void -printline(struct str *line, int sep, regmatch_t *matches, int m) +void grep_printline(struct str *line, int sep) { + printline_metadata(line, sep); + fwrite(line->dat, line->len, 1, stdout); + putchar(fileeol); +} + +static void +printline_metadata(struct str *line, int sep) { - size_t a = 0; - int i, n = 0; - - /* If matchall, everything matches but don't actually print for -o */ - if (oflag && matchall) - return; + bool printsep; + printsep = false; if (!hflag) { if (!nullflag) { fputs(line->file, stdout); - ++n; + printsep = true; } else { printf("%s", line->file); putchar(0); } } if (nflag) { - if (n > 0) + if (printsep) putchar(sep); printf("%d", line->line_no); - ++n; + printsep = true; } if (bflag) { - if (n > 0) + if (printsep) putchar(sep); printf("%lld", (long long)line->off); - ++n; + printsep = true; } - if (n) + if (printsep) putchar(sep); +} + +/* + * Prints a matching line according to the command line options. + */ +static void +printline(struct parsec *pc, int sep) +{ + size_t a = 0; + size_t i, matchidx; + regmatch_t match; + + /* If matchall, everything matches but don't actually print for -o */ + if (oflag && matchall) + return; + + matchidx = pc->matchidx; + /* --color and -o */ - if ((oflag || color) && m > 0) { - for (i = 0; i < m; i++) { + if ((oflag || color) && matchidx > 0) { + printline_metadata(&pc->ln, sep); + for (i = 0; i < matchidx; i++) { + match = pc->matches[i]; /* Don't output zero length matches */ - if (matches[i].rm_so == matches[i].rm_eo) + if (match.rm_so == match.rm_eo) continue; if (!oflag) - fwrite(line->dat + a, matches[i].rm_so - a, 1, + fwrite(pc->ln.dat + a, match.rm_so - a, 1, stdout); - if (color) + if (color) fprintf(stdout, "\33[%sm\33[K", color); - - fwrite(line->dat + matches[i].rm_so, - matches[i].rm_eo - matches[i].rm_so, 1, - stdout); - if (color) + fwrite(pc->ln.dat + match.rm_so, + match.rm_eo - match.rm_so, 1, stdout); + if (color) fprintf(stdout, "\33[m\33[K"); - a = matches[i].rm_eo; + a = match.rm_eo; if (oflag) putchar('\n'); } if (!oflag) { - if (line->len - a > 0) - fwrite(line->dat + a, line->len - a, 1, stdout); + if (pc->ln.len - a > 0) + fwrite(pc->ln.dat + a, pc->ln.len - a, 1, + stdout); putchar('\n'); } - } else { - fwrite(line->dat, line->len, 1, stdout); - putchar(fileeol); - } + } else + grep_printline(&pc->ln, sep); } diff --git a/usr.bin/printf/printf.c b/usr.bin/printf/printf.c index f21a0152a47..62704416599 100644 --- a/usr.bin/printf/printf.c +++ b/usr.bin/printf/printf.c @@ -70,20 +70,15 @@ static const char rcsid[] = #endif #define PF(f, func) do { \ - char *b = NULL; \ if (havewidth) \ if (haveprec) \ - (void)asprintf(&b, f, fieldwidth, precision, func); \ + (void)printf(f, fieldwidth, precision, func); \ else \ - (void)asprintf(&b, f, fieldwidth, func); \ + (void)printf(f, fieldwidth, func); \ else if (haveprec) \ - (void)asprintf(&b, f, precision, func); \ + (void)printf(f, precision, func); \ else \ - (void)asprintf(&b, f, func); \ - if (b) { \ - (void)fputs(b, stdout); \ - free(b); \ - } \ + (void)printf(f, func); \ } while (0) static int asciicode(void); @@ -394,7 +389,8 @@ printf_doformat(char *fmt, int *rval) char p; p = getchr(); - PF(start, p); + if (p != '\0') + PF(start, p); break; } case 's': { diff --git a/usr.bin/proccontrol/Makefile b/usr.bin/proccontrol/Makefile index c11c412ee08..bca022f0c01 100644 --- a/usr.bin/proccontrol/Makefile +++ b/usr.bin/proccontrol/Makefile @@ -2,6 +2,6 @@ PROG= proccontrol WARNS?= 6 -MK_MAN=no +MAN= .include diff --git a/usr.bin/truss/syscall.h b/usr.bin/truss/syscall.h index 0ed08bde57d..46bef46b230 100644 --- a/usr.bin/truss/syscall.h +++ b/usr.bin/truss/syscall.h @@ -46,7 +46,8 @@ enum Argtype { None = 1, Hex, Octal, Int, UInt, LongHex, Name, Ptr, Stat, Ioctl, LinuxSockArgs, Umtxop, Atfd, Atflags, Timespec2, Accessmode, Long, Sysarch, ExecArgs, ExecEnv, PipeFds, QuadHex, Utrace, IntArray, Pipe2, CapFcntlRights, Fadvice, FileFlags, Flockop, Getfsstatmode, Kldsymcmd, - Kldunloadflags, Sizet, Madvice, + Kldunloadflags, Sizet, Madvice, Socklent, Sockprotocol, Sockoptlevel, + Sockoptname, Msgflags, CloudABIAdvice, CloudABIClockID, ClouduABIFDSFlags, CloudABIFDStat, CloudABIFileStat, CloudABIFileType, diff --git a/usr.bin/truss/syscalls.c b/usr.bin/truss/syscalls.c index bd8b932e9ef..ea70ac3efc0 100644 --- a/usr.bin/truss/syscalls.c +++ b/usr.bin/truss/syscalls.c @@ -86,7 +86,7 @@ static struct syscall decoded_syscalls[] = { { .name = "access", .ret_type = 1, .nargs = 2, .args = { { Name | IN, 0 }, { Accessmode, 1 } } }, { .name = "bind", .ret_type = 1, .nargs = 3, - .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } }, + .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Socklent, 2 } } }, { .name = "bindat", .ret_type = 1, .nargs = 4, .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 }, { Int, 3 } } }, @@ -114,7 +114,7 @@ static struct syscall decoded_syscalls[] = { { .name = "close", .ret_type = 1, .nargs = 1, .args = { { Int, 0 } } }, { .name = "connect", .ret_type = 1, .nargs = 3, - .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } }, + .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Socklent, 2 } } }, { .name = "connectat", .ret_type = 1, .nargs = 4, .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 }, { Int, 3 } } }, @@ -174,6 +174,9 @@ static struct syscall decoded_syscalls[] = { .args = { { Int, 0 } } }, { .name = "getsockname", .ret_type = 1, .nargs = 3, .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, + { .name = "getsockopt", .ret_type = 1, .nargs = 5, + .args = { { Int, 0 }, { Sockoptlevel, 1 }, { Sockoptname, 2 }, + { Ptr | OUT, 3 }, { Ptr | OUT, 4 } } }, { .name = "gettimeofday", .ret_type = 1, .nargs = 2, .args = { { Timeval | OUT, 0 }, { Ptr, 1 } } }, { .name = "ioctl", .ret_type = 1, .nargs = 3, @@ -212,7 +215,9 @@ static struct syscall decoded_syscalls[] = { { .name = "linkat", .ret_type = 1, .nargs = 5, .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 }, { Atflags, 4 } } }, - { .name = "lseek", .ret_type = 2, .nargs = 3, + { .name = "listen", .ret_type = 1, .nargs = 2, + .args = { { Int, 0 }, { Int, 1 } } }, + { .name = "lseek", .ret_type = 2, .nargs = 3, .args = { { Int, 0 }, { QuadHex, 1 }, { Whence, 2 } } }, { .name = "lstat", .ret_type = 1, .nargs = 2, .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } }, @@ -273,8 +278,11 @@ static struct syscall decoded_syscalls[] = { .args = { { Atfd, 0 }, { Name, 1 }, { Readlinkres | OUT, 2 }, { Sizet, 3 } } }, { .name = "recvfrom", .ret_type = 1, .nargs = 6, - .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 }, { Hex, 3 }, - { Sockaddr | OUT, 4 }, { Ptr | OUT, 5 } } }, + .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 }, + { Msgflags, 3 }, { Sockaddr | OUT, 4 }, + { Ptr | OUT, 5 } } }, + { .name = "recvmsg", .ret_type = 1, .nargs = 3, + .args = { { Int, 0 }, { Ptr, 1 }, { Msgflags, 2 } } }, { .name = "rename", .ret_type = 1, .nargs = 2, .args = { { Name, 0 }, { Name, 1 } } }, { .name = "renameat", .ret_type = 1, .nargs = 4, @@ -283,16 +291,30 @@ static struct syscall decoded_syscalls[] = { .args = { { Rforkflags, 0 } } }, { .name = "rmdir", .ret_type = 1, .nargs = 1, .args = { { Name, 0 } } }, + { .name = "sctp_generic_recvmsg", .ret_type = 1, .nargs = 7, + .args = { { Int, 0 }, { Ptr | IN, 1 }, { Int, 2 }, + { Sockaddr | OUT, 3 }, { Ptr | OUT, 4 }, { Ptr | OUT, 5 }, + { Ptr | OUT, 6 } } }, + { .name = "sctp_generic_sendmsg", .ret_type = 1, .nargs = 7, + .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 }, + { Sockaddr | IN, 3 }, { Socklent, 4 }, { Ptr | IN, 5 }, + { Msgflags, 6 } } }, { .name = "select", .ret_type = 1, .nargs = 5, .args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 }, { Timeval, 4 } } }, + { .name = "sendmsg", .ret_type = 1, .nargs = 3, + .args = { { Int, 0 }, { Ptr, 1 }, { Msgflags, 2 } } }, { .name = "sendto", .ret_type = 1, .nargs = 6, - .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 }, { Hex, 3 }, - { Sockaddr | IN, 4 }, { Int | IN, 5 } } }, + .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 }, + { Msgflags, 3 }, { Sockaddr | IN, 4 }, + { Socklent | IN, 5 } } }, { .name = "setitimer", .ret_type = 1, .nargs = 3, .args = { { Int, 0 }, { Itimerval, 1 }, { Itimerval | OUT, 2 } } }, { .name = "setrlimit", .ret_type = 1, .nargs = 2, .args = { { Resource, 0 }, { Rlimit | IN, 1 } } }, + { .name = "setsockopt", .ret_type = 1, .nargs = 5, + .args = { { Int, 0 }, { Sockoptlevel, 1 }, { Sockoptname, 2 }, + { Ptr | IN, 3 }, { Socklent, 4 } } }, { .name = "shutdown", .ret_type = 1, .nargs = 2, .args = { { Int, 0 }, { Shutdown, 1 } } }, { .name = "sigaction", .ret_type = 1, .nargs = 3, @@ -315,7 +337,7 @@ static struct syscall decoded_syscalls[] = { { .name = "sigwaitinfo", .ret_type = 1, .nargs = 2, .args = { { Sigset | IN, 0 }, { Ptr, 1 } } }, { .name = "socket", .ret_type = 1, .nargs = 3, - .args = { { Sockdomain, 0 }, { Socktype, 1 }, { Int, 2 } } }, + .args = { { Sockdomain, 0 }, { Socktype, 1 }, { Sockprotocol, 2 } } }, { .name = "stat", .ret_type = 1, .nargs = 2, .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } }, { .name = "statfs", .ret_type = 1, .nargs = 2, @@ -1912,6 +1934,41 @@ print_arg(struct syscall_args *sc, unsigned long *args, long *retval, case Madvice: print_integer_arg(sysdecode_madvice, fp, args[sc->offset]); break; + case Socklent: + fprintf(fp, "%u", (socklen_t)args[sc->offset]); + break; + case Sockprotocol: { + int protocol; + + protocol = args[sc->offset]; + if (protocol == 0) { + fputs("0", fp); + } else { + print_integer_arg(sysdecode_ipproto, fp, protocol); + } + break; + } + case Sockoptlevel: + print_integer_arg(sysdecode_sockopt_level, fp, + args[sc->offset]); + break; + case Sockoptname: { + const char *temp; + int level, name; + + level = args[sc->offset - 1]; + name = args[sc->offset]; + temp = sysdecode_sockopt_name(level, name); + if (temp) { + fputs(temp, fp); + } else { + fprintf(fp, "%d", name); + } + break; + } + case Msgflags: + print_mask_arg(sysdecode_msg_flags, fp, args[sc->offset]); + break; case CloudABIAdvice: fputs(xlookup(cloudabi_advice, args[sc->offset]), fp); diff --git a/usr.bin/unexpand/unexpand.c b/usr.bin/unexpand/unexpand.c index 33af8a2b076..df2f8bb9e43 100644 --- a/usr.bin/unexpand/unexpand.c +++ b/usr.bin/unexpand/unexpand.c @@ -132,8 +132,8 @@ tabify(const char *curfile) tabstops[0]; continue; } else { - for (n = 0; tabstops[n] - 1 < dcol && - n < nstops; n++) + for (n = 0; n < nstops && + tabstops[n] - 1 < dcol; n++) ; if (n < nstops - 1 && tabstops[n] - 1 < limit) { dcol = tabstops[n]; @@ -154,7 +154,7 @@ tabify(const char *curfile) tabstops[0]; } } else { - for (n = 0; tabstops[n] - 1 < ocol && n < nstops; n++) + for (n = 0; n < nstops && tabstops[n] - 1 < ocol; n++) ; while (ocol < dcol && n < nstops && ocol < limit) { putwchar('\t'); diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8 index e96ea5101b2..16b2245d031 100644 --- a/usr.sbin/bhyve/bhyve.8 +++ b/usr.sbin/bhyve/bhyve.8 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 27, 2017 +.Dd May 3, 2017 .Dt BHYVE 8 .Os .Sh NAME @@ -49,10 +49,13 @@ virtual machine. Parameters such as the number of virtual CPUs, amount of guest memory, and I/O connectivity can be specified with command-line parameters. .Pp -The guest operating system must be loaded with +If not using a boot ROM, the guest operating system must be loaded with .Xr bhyveload 8 or a similar boot loader before running -.Nm . +.Nm , +otherwise, it is enough to run +.Nm +with a boot ROM of choice. .Pp .Nm runs until the guest operating system reboots or an unhandled hypervisor @@ -188,6 +191,10 @@ PCI 16550 serial device. .It Li lpc LPC PCI-ISA bridge with COM1 and COM2 16550 serial ports and a boot ROM. The LPC bridge emulation can only be configured on bus 0. +.It Li fbuf +Raw framebuffer device attached to VNC server. +.It Li xhci +eXtensible Host Controller Interface (xHCI) USB controller. .El .It Op Ar conf This optional parameter describes the backend for device emulations. @@ -299,6 +306,77 @@ resize at present. Emergency write is advertised, but no-op at present. .El .El +.Pp +Framebuffer devices: +.Bl -tag -width 10n +.It Oo rfb= Ns Oo Ar IP: Oc Ns Ar port Oc Ns Oo ,w= Ns Ar width Oc Ns Oo ,h= Ns Ar height Oc Ns Oo ,vga= Ns Ar vgaconf Oc Ns Oo Ns ,wait Oc +.Bl -tag -width 8n +.It Ar IP:port +An +.Ar IP +address and a +.Ar port +VNC should listen on. +The default is to listen on localhost IPv4 address and default VNC port 5900. +Listening on an IPv6 address is not supported. +.It Ar width No and Ar height +A display resolution, width and height, respectively. +If not specified, a default resolution of 1024x768 pixels will be used. +Minimal supported resolution is 640x480 pixels, +and maximum is 1920x1200 pixels. +.It Ar vgaconf +Possible values for this option are +.Dq io +(default), +.Dq on +, and +.Dq off . +PCI graphics cards have a dual personality in that they are +standard PCI devices with BAR addressing, but may also +implicitly decode legacy VGA I/O space +.Pq Ad 0x3c0-3df +and memory space +.Pq 64KB at Ad 0xA0000 . +The default +.Dq io +option should be used for guests that attempt to issue BIOS +calls which result in I/O port queries, and fail to boot if I/O decode is disabled. +.Pp +The +.Dq on +option should be used along with the CSM BIOS capability in UEFI +to boot traditional BIOS guests that require the legacy VGA I/O and +memory regions to be available. +.Pp +The +.Dq off +option should be used for the UEFI guests that assume that +VGA adapter is present if they detect the I/O ports. +An example of such a guest is +.Ox +in UEFI mode. +.Pp +Please refer to the +.Nm +.Fx +wiki page +.Pq Lk https://wiki.freebsd.org/bhyve +for configuration notes of particular guests. +.It wait +Instruct +.Nm +to only boot upon the initiation of a VNC connection, simplifying the installation +of operating systems that require immediate keyboard input. +This can be removed for post-installation use. +.El +.El +.Pp +xHCI USB devices: +.Bl -tag -width 10n +.It Li tablet +A USB tablet device which provides precise cursor synchronization +when using VNC. +.El .El .It Fl S Wire guest memory. @@ -347,11 +425,12 @@ halted triple fault .El .Sh EXAMPLES -The guest operating system must have been loaded with +If not using a boot ROM, the guest operating system must have been loaded with .Xr bhyveload 8 or a similar boot loader before .Xr bhyve 4 can be run. +Otherwise, the boot loader is not needed. .Pp To run a virtual machine with 1GB of memory, two virtual CPUs, a virtio block device backed by the @@ -389,6 +468,21 @@ cd:/images/install.iso \\ -l com1,/dev/nmdm0A \\ -A -H -P -m 8G .Ed +.Pp +Run a UEFI virtual machine with a display resolution of 800 by 600 pixels +that can be accessed via VNC at: 0.0.0.0:5900. +.Bd -literal -offset indent +bhyve -c 2 -m 4G -w -H \\ + -s 0,hostbridge \\ + -s 3,ahci-cd,/path/to/uefi-OS-install.iso \\ + -s 4,ahci-hd,disk.img \\ + -s 5,virtio-net,tap0 \\ + -s 29,fbuf,tcp=0.0.0.0:5900,w=800,h=600,wait \\ + -s 30,xhci,tablet \\ + -s 31,lpc -l com1,stdio \\ + -l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd \\ + uefivm +.Ed .Sh SEE ALSO .Xr bhyve 4 , .Xr nmdm 4 , diff --git a/usr.sbin/bhyve/pci_fbuf.c b/usr.sbin/bhyve/pci_fbuf.c index c2de6221afb..67279d2162b 100644 --- a/usr.sbin/bhyve/pci_fbuf.c +++ b/usr.sbin/bhyve/pci_fbuf.c @@ -55,7 +55,7 @@ __FBSDID("$FreeBSD$"); * BAR0 points to the current mode information. * BAR1 is the 32-bit framebuffer address. * - * -s ,fbuf,wait,tcp=:port,w=width,h=height + * -s ,fbuf,wait,vga=on|io|off,rfb=:port,w=width,h=height */ static int fbuf_debug = 1; diff --git a/usr.sbin/bhyve/pci_xhci.c b/usr.sbin/bhyve/pci_xhci.c index d28a3e698c4..f178468108d 100644 --- a/usr.sbin/bhyve/pci_xhci.c +++ b/usr.sbin/bhyve/pci_xhci.c @@ -28,7 +28,7 @@ -s ,xhci,{devices} devices: - ums USB tablet mouse + tablet USB tablet mouse */ #include __FBSDID("$FreeBSD$"); diff --git a/usr.sbin/bhyve/rfb.c b/usr.sbin/bhyve/rfb.c index 78a3fa0945e..f3e30244b5d 100644 --- a/usr.sbin/bhyve/rfb.c +++ b/usr.sbin/bhyve/rfb.c @@ -897,11 +897,11 @@ rfb_init(char *hostname, int port, int wait) sin.sin_len = sizeof(sin); sin.sin_family = AF_INET; - sin.sin_port = htons(port); + sin.sin_port = port ? htons(port) : htons(5900); if (hostname && strlen(hostname) > 0) inet_pton(AF_INET, hostname, &(sin.sin_addr)); else - sin.sin_addr.s_addr = htonl(INADDR_ANY); + sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); if (bind(rc->sfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { perror("bind"); diff --git a/usr.sbin/bluetooth/hccontrol/node.c b/usr.sbin/bluetooth/hccontrol/node.c index f1f2694a228..2a08e0e89cb 100644 --- a/usr.sbin/bluetooth/hccontrol/node.c +++ b/usr.sbin/bluetooth/hccontrol/node.c @@ -208,12 +208,59 @@ hci_flush_neighbor_cache(int s, int argc, char **argv) return (OK); } /* hci_flush_neighbor_cache */ +#define MIN(a,b) (((a)>(b)) ? (b) :(a) ) + +static int hci_dump_adv(uint8_t *data, int length) +{ + int elemlen; + int type; + int i; + + while(length>0){ + elemlen = *data; + data++; + length --; + elemlen--; + if(length<=0) + break; + type = *data; + data++; + length --; + elemlen--; + if(length<=0) + break; + switch(type){ + case 0x1: + printf("NDflag:%x\n", *data); + break; + case 0x9: + printf("LocalName:"); + for(i = 0; i < MIN(length,elemlen); i++){ + putchar(data[i]); + } + printf("\n"); + break; + default: + printf("Type%d:", type); + for(i=0; i < MIN(length,elemlen); i++){ + printf("%02x ",data[i]); + } + printf("\n"); + break; + } + data += elemlen; + length -= elemlen; + } + return 0; +} +#undef MIN /* Send Read_Neighbor_Cache command to the node */ static int hci_read_neighbor_cache(int s, int argc, char **argv) { struct ng_btsocket_hci_raw_node_neighbor_cache r; int n, error = OK; + const char *addrtype2str[] = {"B", "P", "R", "E"}; memset(&r, 0, sizeof(r)); r.num_entries = NG_HCI_MAX_NEIGHBOR_NUM; @@ -231,6 +278,7 @@ hci_read_neighbor_cache(int s, int argc, char **argv) } fprintf(stdout, +"T " \ "BD_ADDR " \ "Features " \ "Clock offset " \ @@ -238,12 +286,16 @@ hci_read_neighbor_cache(int s, int argc, char **argv) "Rep. scan\n"); for (n = 0; n < r.num_entries; n++) { + uint8_t addrtype = r.entries[n].addrtype; + if(addrtype >= sizeof(addrtype2str)/sizeof(addrtype2str[0])) + addrtype = sizeof(addrtype2str)/sizeof(addrtype2str[0]) - 1; fprintf(stdout, -"%-17.17s " \ +"%1s %-17.17s " \ "%02x %02x %02x %02x %02x %02x %02x %02x " \ "%#12x " \ "%#9x " \ "%#9x\n", + addrtype2str[addrtype], hci_bdaddr2str(&r.entries[n].bdaddr), r.entries[n].features[0], r.entries[n].features[1], r.entries[n].features[2], r.entries[n].features[3], @@ -251,6 +303,9 @@ hci_read_neighbor_cache(int s, int argc, char **argv) r.entries[n].features[6], r.entries[n].features[7], r.entries[n].clock_offset, r.entries[n].page_scan_mode, r.entries[n].page_scan_rep_mode); + hci_dump_adv(r.entries[n].extinq_data, + r.entries[n].extinq_size); + fprintf(stdout,"\n"); } out: free(r.entries); diff --git a/usr.sbin/bsdconfig/share/device.subr b/usr.sbin/bsdconfig/share/device.subr index 97c3ecd9958..4662b81443c 100644 --- a/usr.sbin/bsdconfig/share/device.subr +++ b/usr.sbin/bsdconfig/share/device.subr @@ -1305,7 +1305,6 @@ f_network "disc%d" "Software discard network interface" f_network "ed%d" "Novell NE1000/2000; 3C503; NE2000-compatible PCMCIA" f_network "el%d" "3Com 3C501 Ethernet card" f_network "em%d" "Intel(R) PRO/1000 Ethernet card" -f_network "en%d" "Efficient Networks ATM PCI card" f_network "ep%d" "3Com 3C509 Ethernet card/3C589 PCMCIA" f_network "et%d" "Agere ET1310 based PCI Express Gigabit Ethernet card" f_network "ex%d" "Intel EtherExpress Pro/10 Ethernet card" diff --git a/usr.sbin/bsdinstall/partedit/gpart_ops.c b/usr.sbin/bsdinstall/partedit/gpart_ops.c index 9720b3363cd..466bae4e97d 100644 --- a/usr.sbin/bsdinstall/partedit/gpart_ops.c +++ b/usr.sbin/bsdinstall/partedit/gpart_ops.c @@ -99,14 +99,14 @@ newfs_command(const char *fstype, char *command, int use_default) if (!use_default) { int choice; choice = dlg_checklist("UFS Options", "", 0, 0, 0, - sizeof(items)/sizeof(items[0]), items, NULL, + nitems(items), items, NULL, FLAG_CHECK, &i); if (choice == 1) /* Cancel */ return; } strcpy(command, "newfs "); - for (i = 0; i < (int)(sizeof(items)/sizeof(items[0])); i++) { + for (i = 0; i < (int)nitems(items); i++) { if (items[i].state == 0) continue; if (strcmp(items[i].name, "UFS1") == 0) @@ -137,7 +137,7 @@ newfs_command(const char *fstype, char *command, int use_default) if (!use_default) { int choice; choice = dlg_checklist("ZFS Options", "", 0, 0, 0, - sizeof(items)/sizeof(items[0]), items, NULL, + nitems(items), items, NULL, FLAG_CHECK, &i); if (choice == 1) /* Cancel */ return; @@ -153,7 +153,7 @@ newfs_command(const char *fstype, char *command, int use_default) sprintf(command, "%s -o cachefile=%s/zpool.cache ", command, zfsboot_path); } - for (i = 0; i < (int)(sizeof(items)/sizeof(items[0])); i++) { + for (i = 0; i < (int)nitems(items); i++) { if (items[i].state == 0) continue; if (strcmp(items[i].name, "fletcher4") == 0) @@ -179,14 +179,14 @@ newfs_command(const char *fstype, char *command, int use_default) if (!use_default) { int choice; choice = dlg_checklist("FAT Options", "", 0, 0, 0, - sizeof(items)/sizeof(items[0]), items, NULL, + nitems(items), items, NULL, FLAG_RADIO, &i); if (choice == 1) /* Cancel */ return; } strcpy(command, "newfs_msdos "); - for (i = 0; i < (int)(sizeof(items)/sizeof(items[0])); i++) { + for (i = 0; i < (int)nitems(items); i++) { if (items[i].state == 0) continue; if (strcmp(items[i].name, "FAT32") == 0) @@ -227,7 +227,7 @@ parttypemenu: dialog_vars.default_item = __DECONST(char *, def_scheme); cancel = dlg_menu("Partition Scheme", "Select a partition scheme for this volume:", 0, 0, 0, - sizeof(items) / sizeof(items[0]), items, &choice, NULL); + nitems(items), items, &choice, NULL); dialog_vars.default_item = NULL; if (cancel) @@ -662,7 +662,7 @@ endedit: "freebsd") == 0) gpart_partition(pp->lg_name, "BSD"); - for (i = 0; i < (sizeof(items) / sizeof(items[0])); i++) + for (i = 0; i < nitems(items); i++) if (items[i].text_free) free(items[i].text); } @@ -1200,7 +1200,7 @@ addpartform: set_default_part_metadata(newpartname, scheme, items[0].text, items[2].text, newfs); - for (i = 0; i < (sizeof(items) / sizeof(items[0])); i++) + for (i = 0; i < nitems(items); i++) if (items[i].text_free) free(items[i].text); diff --git a/usr.sbin/fdread/fdread.c b/usr.sbin/fdread/fdread.c index f3c2d9147b9..a0cdd85336c 100644 --- a/usr.sbin/fdread/fdread.c +++ b/usr.sbin/fdread/fdread.c @@ -184,6 +184,7 @@ doread(int fd, FILE *of, const char *_devname) if (rv == 0) { /* EOF? */ warnx("premature EOF after %u bytes", nbytes); + free(trackbuf); return (EX_OK); } if ((unsigned)rv == tracksize) { @@ -215,6 +216,7 @@ doread(int fd, FILE *of, const char *_devname) if (!quiet) putc('\n', stderr); perror("non-IO error"); + free(trackbuf); return (EX_OSERR); } if (ioctl(fd, FD_GSTAT, &fdcs) == -1) @@ -233,6 +235,7 @@ doread(int fd, FILE *of, const char *_devname) if (!recover) { if (!quiet) putc('\n', stderr); + free(trackbuf); return (EX_IOERR); } memset(trackbuf, fillbyte, secsize); @@ -284,6 +287,7 @@ doread(int fd, FILE *of, const char *_devname) continue; } } + free(trackbuf); if (!quiet) { putc('\n', stderr); if (nerrs) diff --git a/usr.sbin/makefs/cd9660.c b/usr.sbin/makefs/cd9660.c index 785c3dc4cb8..1a0222184f4 100644 --- a/usr.sbin/makefs/cd9660.c +++ b/usr.sbin/makefs/cd9660.c @@ -186,8 +186,6 @@ cd9660_allocate_cd9660node(void) return temp; } -int cd9660_defaults_set = 0; - /** * Set default values for cd9660 extension to makefs */ @@ -234,8 +232,6 @@ cd9660_set_defaults(iso9660_disk *diskStructure) strcpy(diskStructure->primaryDescriptor.system_id, "FreeBSD"); - cd9660_defaults_set = 1; - /* Boot support: Initially disabled */ diskStructure->has_generic_bootimage = 0; diskStructure->generic_bootimage = NULL; @@ -1502,7 +1498,7 @@ cd9660_free_structure(cd9660node *root) * instead of having the TAILQ_ENTRY as part of the cd9660node, * just create a temporary structure */ -struct ptq_entry +static struct ptq_entry { TAILQ_ENTRY(ptq_entry) ptq; cd9660node *node; diff --git a/usr.sbin/makefs/ffs.c b/usr.sbin/makefs/ffs.c index 5e38f7ace6f..8c6d12b4f20 100644 --- a/usr.sbin/makefs/ffs.c +++ b/usr.sbin/makefs/ffs.c @@ -144,7 +144,6 @@ static void *ffs_build_dinode2(struct ufs2_dinode *, dirbuf_t *, fsnode *, -int sectorsize; /* XXX: for buf.c::getblk() */ /* publicly visible functions */ void @@ -427,8 +426,6 @@ ffs_validate(const char *dir, fsnode *root, fsinfo_t *fsopts) printf("ffs_validate: dir %s; %lld bytes, %lld inodes\n", dir, (long long)fsopts->size, (long long)fsopts->inodes); } - sectorsize = fsopts->sectorsize; /* XXX - see earlier */ - /* now check calculated sizes vs requested sizes */ if (fsopts->maxsize > 0 && fsopts->size > fsopts->maxsize) { errx(1, "`%s' size of %lld is larger than the maxsize of %lld.", diff --git a/usr.sbin/makefs/ffs/buf.c b/usr.sbin/makefs/ffs/buf.c index c2d561ae2b9..7b08d537d4b 100644 --- a/usr.sbin/makefs/ffs/buf.c +++ b/usr.sbin/makefs/ffs/buf.c @@ -50,16 +50,9 @@ __FBSDID("$FreeBSD$"); #include #include "makefs.h" +#include "buf.h" -#include -#include - -#include "ffs/buf.h" -#include "ffs/ufs_inode.h" - -extern int sectorsize; /* XXX: from ffs.c & mkfs.c */ - -TAILQ_HEAD(buftailhead,buf) buftail; +static TAILQ_HEAD(buftailhead,buf) buftail; int bread(struct vnode *vp, daddr_t blkno, int size, struct ucred *u1 __unused, @@ -67,16 +60,15 @@ bread(struct vnode *vp, daddr_t blkno, int size, struct ucred *u1 __unused, { off_t offset; ssize_t rv; - struct fs *fs = vp->fs; + fsinfo_t *fs = vp->fs; - assert (fs != NULL); assert (bpp != NULL); if (debug & DEBUG_BUF_BREAD) printf("%s: blkno %lld size %d\n", __func__, (long long)blkno, size); *bpp = getblk(vp, blkno, size, 0, 0, 0); - offset = (*bpp)->b_blkno * sectorsize; /* XXX */ + offset = (*bpp)->b_blkno * fs->sectorsize; if (debug & DEBUG_BUF_BREAD) printf("%s: blkno %lld offset %lld bcount %ld\n", __func__, (long long)(*bpp)->b_blkno, (long long) offset, @@ -133,9 +125,10 @@ bwrite(struct buf *bp) { off_t offset; ssize_t rv; + fsinfo_t *fs = bp->b_fs; assert (bp != NULL); - offset = bp->b_blkno * sectorsize; /* XXX */ + offset = bp->b_blkno * fs->sectorsize; if (debug & DEBUG_BUF_BWRITE) printf("bwrite: blkno %lld offset %lld bcount %ld\n", (long long)bp->b_blkno, (long long) offset, @@ -184,11 +177,7 @@ getblk(struct vnode *vp, daddr_t blkno, int size, int u1 __unused, static int buftailinitted; struct buf *bp; void *n; - int fd = vp->fd; - struct fs *fs = vp->fs; - blkno += vp->offset; - assert (fs != NULL); if (debug & DEBUG_BUF_GETBLK) printf("getblk: blkno %lld size %d\n", (long long)blkno, size); @@ -209,8 +198,8 @@ getblk(struct vnode *vp, daddr_t blkno, int size, int u1 __unused, bp = ecalloc(1, sizeof(*bp)); bp->b_bufsize = 0; bp->b_blkno = bp->b_lblkno = blkno; - bp->b_fd = fd; - bp->b_fs = fs; + bp->b_fd = vp->fd; + bp->b_fs = vp->fs; bp->b_data = NULL; TAILQ_INSERT_HEAD(&buftail, bp, b_tailq); } diff --git a/usr.sbin/makefs/ffs/buf.h b/usr.sbin/makefs/ffs/buf.h index b082f48650e..16149c67fbb 100644 --- a/usr.sbin/makefs/ffs/buf.h +++ b/usr.sbin/makefs/ffs/buf.h @@ -59,7 +59,7 @@ struct buf { daddr_t b_blkno; daddr_t b_lblkno; int b_fd; - struct fs * b_fs; + void * b_fs; TAILQ_ENTRY(buf) b_tailq; }; diff --git a/usr.sbin/makefs/ffs/mkfs.c b/usr.sbin/makefs/ffs/mkfs.c index 905a89d76ff..931007fb4f0 100644 --- a/usr.sbin/makefs/ffs/mkfs.c +++ b/usr.sbin/makefs/ffs/mkfs.c @@ -67,7 +67,7 @@ __FBSDID("$FreeBSD$"); #define BBSIZE 8192 /* size of boot area, with label */ #endif -static void initcg(int, time_t, const fsinfo_t *); +static void initcg(uint32_t, time_t, const fsinfo_t *); static int ilog2(int); static int count_digits(int); @@ -78,23 +78,22 @@ static int count_digits(int); #define UMASK 0755 #define POWEROF2(num) (((num) & ((num) - 1)) == 0) -union { +static union { struct fs fs; char pad[SBLOCKSIZE]; } fsun; #define sblock fsun.fs -struct csum *fscs; -union { +static union { struct cg cg; char pad[FFS_MAXBSIZE]; } cgun; #define acg cgun.cg -char *iobuf; -int iobufsize; +static char *iobuf; +static int iobufsize; -char writebuf[FFS_MAXBSIZE]; +static char writebuf[FFS_MAXBSIZE]; static int Oflag; /* format as an 4.3BSD file system */ static int64_t fssize; /* file system size */ @@ -117,7 +116,8 @@ struct fs * ffs_mkfs(const char *fsys, const fsinfo_t *fsopts, time_t tstamp) { int fragsperinode, optimalfpg, origdensity, minfpg, lastminfpg; - int32_t cylno, i, csfrags; + int32_t csfrags; + uint32_t i, cylno; long long sizepb; void *space; int size; @@ -537,7 +537,8 @@ ffs_mkfs(const char *fsys, const fsinfo_t *fsopts, time_t tstamp) void ffs_write_superblock(struct fs *fs, const fsinfo_t *fsopts) { - int cylno, size, blks, i, saveflag; + int size, blks, i, saveflag; + uint32_t cylno; void *space; char *wrbuf; @@ -579,10 +580,11 @@ ffs_write_superblock(struct fs *fs, const fsinfo_t *fsopts) * Initialize a cylinder group. */ static void -initcg(int cylno, time_t utime, const fsinfo_t *fsopts) +initcg(uint32_t cylno, time_t utime, const fsinfo_t *fsopts) { daddr_t cbase, dmax; - int32_t i, j, d, dlower, dupper, blkno; + int32_t blkno; + uint32_t i, j, d, dlower, dupper; struct ufs1_dinode *dp1; struct ufs2_dinode *dp2; int start; @@ -643,7 +645,7 @@ initcg(int cylno, time_t utime, const fsinfo_t *fsopts) acg.cg_nextfreeoff = acg.cg_clusteroff + howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT); } - if (acg.cg_nextfreeoff > sblock.fs_cgsize) { + if (acg.cg_nextfreeoff > (uint32_t)sblock.fs_cgsize) { printf("Panic: cylinder group too big\n"); exit(37); } diff --git a/usr.sbin/makefs/makefs.c b/usr.sbin/makefs/makefs.c index 3c53c2ba1dd..5e8268e0441 100644 --- a/usr.sbin/makefs/makefs.c +++ b/usr.sbin/makefs/makefs.c @@ -95,8 +95,8 @@ main(int argc, char *argv[]) fsinfo_t fsoptions; fsnode *root; int ch, i, len; - char *subtree; - char *specfile; + const char *subtree; + const char *specfile; setprogname(argv[0]); diff --git a/usr.sbin/mixer/mixer.c b/usr.sbin/mixer/mixer.c index be48a8ebbf5..591d42c9ebf 100644 --- a/usr.sbin/mixer/mixer.c +++ b/usr.sbin/mixer/mixer.c @@ -102,7 +102,7 @@ int main(int argc, char *argv[]) { char mixer[PATH_MAX] = "/dev/mixer"; - char lstr[5], rstr[5]; + char lstr[8], rstr[8]; char *name, *eptr; int devmask = 0, recmask = 0, recsrc = 0, orecsrc; int dusage = 0, drecsrc = 0, sflag = 0, Sflag = 0; diff --git a/usr.sbin/pkg/pkg.c b/usr.sbin/pkg/pkg.c index 13d02da5665..5e7072b722d 100644 --- a/usr.sbin/pkg/pkg.c +++ b/usr.sbin/pkg/pkg.c @@ -946,6 +946,7 @@ pkg_query_yes_no(void) { int ret, c; + fflush(stdout); c = getchar(); if (c == 'y' || c == 'Y') diff --git a/usr.sbin/tcpdrop/tcpdrop.c b/usr.sbin/tcpdrop/tcpdrop.c index 03667e4d810..721129f6898 100644 --- a/usr.sbin/tcpdrop/tcpdrop.c +++ b/usr.sbin/tcpdrop/tcpdrop.c @@ -321,7 +321,7 @@ tcpdropconn(const struct in_conninfo *inc) sizeof inc->inc6_faddr); foreign = (struct sockaddr *)&sin6[TCPDROP_FOREIGN]; } else { - memset(&sin4[TCPDROP_LOCAL], 0, sizeof sin4[TCPDROP_LOCAL]); + memset(sin4, 0, sizeof sin4); sin4[TCPDROP_LOCAL].sin_len = sizeof sin4[TCPDROP_LOCAL]; sin4[TCPDROP_LOCAL].sin_family = AF_INET;