diff --git a/bin/setfacl/setfacl.1 b/bin/setfacl/setfacl.1 index a310c6403da..b581dc4046c 100644 --- a/bin/setfacl/setfacl.1 +++ b/bin/setfacl/setfacl.1 @@ -26,7 +26,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 4, 2015 +.Dd January 23, 2016 .Dt SETFACL 1 .Os .Sh NAME @@ -62,8 +62,9 @@ starting at position counting from zero. This option is only applicable to NFSv4 ACLs. .It Fl b -Remove all ACL entries except for the three required entries -(POSIX.1e ACLs) or six "canonical" entries (NFSv4 ACLs). +Remove all ACL entries except for the ones synthesized +from the file mode - the three mandatory entries in case +of POSIX.1e ACL. If the POSIX.1e ACL contains a .Dq Li mask entry, the permissions of the diff --git a/bin/sh/cd.c b/bin/sh/cd.c index 88f03f57d73..d0348968c85 100644 --- a/bin/sh/cd.c +++ b/bin/sh/cd.c @@ -68,15 +68,13 @@ __FBSDID("$FreeBSD$"); static int cdlogical(char *); static int cdphysical(char *); static int docd(char *, int, int); -static char *getcomponent(void); +static char *getcomponent(char **); static char *findcwd(char *); static void updatepwd(char *); static char *getpwd(void); static char *getpwd2(void); static char *curdir = NULL; /* current working directory */ -static char *prevdir; /* previous working directory */ -static char *cdcomppath; int cdcmd(int argc __unused, char **argv __unused) @@ -112,11 +110,10 @@ cdcmd(int argc __unused, char **argv __unused) if (*dest == '\0') dest = "."; if (dest[0] == '-' && dest[1] == '\0') { - dest = prevdir ? prevdir : curdir; - if (dest) - print = 1; - else - dest = "."; + dest = bltinlookup("OLDPWD", 1); + if (dest == NULL) + error("OLDPWD not set"); + print = 1; } if (dest[0] == '/' || (dest[0] == '.' && (dest[1] == '/' || dest[1] == '\0')) || @@ -179,6 +176,7 @@ cdlogical(char *dest) char *p; char *q; char *component; + char *path; struct stat statb; int first; int badstat; @@ -189,14 +187,14 @@ cdlogical(char *dest) * next time we get the value of the current directory. */ badstat = 0; - cdcomppath = stsavestr(dest); + path = stsavestr(dest); STARTSTACKSTR(p); if (*dest == '/') { STPUTC('/', p); - cdcomppath++; + path++; } first = 1; - while ((q = getcomponent()) != NULL) { + while ((q = getcomponent(&path)) != NULL) { if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0')) continue; if (! first) @@ -245,25 +243,25 @@ cdphysical(char *dest) } /* - * Get the next component of the path name pointed to by cdcomppath. - * This routine overwrites the string pointed to by cdcomppath. + * Get the next component of the path name pointed to by *path. + * This routine overwrites *path and the string pointed to by it. */ static char * -getcomponent(void) +getcomponent(char **path) { char *p; char *start; - if ((p = cdcomppath) == NULL) + if ((p = *path) == NULL) return NULL; - start = cdcomppath; + start = *path; while (*p != '/' && *p != '\0') p++; if (*p == '\0') { - cdcomppath = NULL; + *path = NULL; } else { *p++ = '\0'; - cdcomppath = p; + *path = p; } return start; } @@ -274,6 +272,7 @@ findcwd(char *dir) { char *new; char *p; + char *path; /* * If our argument is NULL, we don't know the current directory @@ -282,14 +281,14 @@ findcwd(char *dir) */ if (dir == NULL || curdir == NULL) return getpwd2(); - cdcomppath = stsavestr(dir); + path = stsavestr(dir); STARTSTACKSTR(new); if (*dir != '/') { STPUTS(curdir, new); if (STTOPC(new) == '/') STUNPUTC(new); } - while ((p = getcomponent()) != NULL) { + while ((p = getcomponent(&path)) != NULL) { if (equal(p, "..")) { while (new > stackblock() && (STUNPUTC(new), *new) != '/'); } else if (*p != '\0' && ! equal(p, ".")) { @@ -311,14 +310,15 @@ findcwd(char *dir) static void updatepwd(char *dir) { + char *prevdir; + hashcd(); /* update command hash table */ - if (prevdir) - ckfree(prevdir); + setvar("PWD", dir, VEXPORT); + setvar("OLDPWD", curdir, VEXPORT); prevdir = curdir; curdir = dir ? savestr(dir) : NULL; - setvar("PWD", curdir, VEXPORT); - setvar("OLDPWD", prevdir, VEXPORT); + ckfree(prevdir); } int diff --git a/bin/sh/expand.c b/bin/sh/expand.c index c661541d491..6129bb6904c 100644 --- a/bin/sh/expand.c +++ b/bin/sh/expand.c @@ -91,13 +91,13 @@ struct worddest { static char *expdest; /* output of current string */ static struct nodelist *argbackq; /* list of back quote expressions */ -static char *argstr(char *, int, struct worddest *); -static char *exptilde(char *, int); -static char *expari(char *, int, struct worddest *); +static const char *argstr(const char *, int, struct worddest *); +static const char *exptilde(const char *, int); +static const char *expari(const char *, int, struct worddest *); static void expbackq(union node *, int, int, struct worddest *); -static void subevalvar_trim(char *, int, int, int); -static int subevalvar_misc(char *, const char *, int, int, int); -static char *evalvar(char *, int, struct worddest *); +static void subevalvar_trim(const char *, int, int, int); +static int subevalvar_misc(const char *, const char *, int, int, int); +static const char *evalvar(const char *, int, struct worddest *); static int varisset(const char *, int); static void strtodest(const char *, int, int, int, struct worddest *); static void reprocess(int, int, int, int, struct worddest *); @@ -262,8 +262,8 @@ expandarg(union node *arg, struct arglist *arglist, int flag) * * If EXP_SPLIT is set, dst receives any complete words produced. */ -static char * -argstr(char *p, int flag, struct worddest *dst) +static const char * +argstr(const char *p, int flag, struct worddest *dst) { char c; int quotes = flag & (EXP_GLOB | EXP_CASE); /* do CTLESC */ @@ -352,12 +352,15 @@ argstr(char *p, int flag, struct worddest *dst) * Perform tilde expansion, placing the result in the stack string and * returning the next position in the input string to process. */ -static char * -exptilde(char *p, int flag) +static const char * +exptilde(const char *p, int flag) { - char c, *startp = p; + char c; + const char *startp = p; + const char *user; struct passwd *pw; char *home; + int len; for (;;) { c = *p; @@ -377,14 +380,17 @@ exptilde(char *p, int flag) case '\0': case '/': case CTLENDVAR: - *p = '\0'; - if (*(startp+1) == '\0') { + len = p - startp - 1; + STPUTBIN(startp + 1, len, expdest); + STACKSTRNUL(expdest); + user = expdest - len; + if (*user == '\0') { home = lookupvar("HOME"); } else { - pw = getpwnam(startp+1); + pw = getpwnam(user); home = pw != NULL ? pw->pw_dir : NULL; } - *p = c; + STADJUST(-len, expdest); if (home == NULL || *home == '\0') return (startp); strtodest(home, flag, VSNORMAL, 1, NULL); @@ -398,8 +404,8 @@ exptilde(char *p, int flag) /* * Expand arithmetic expression. */ -static char * -expari(char *p, int flag, struct worddest *dst) +static const char * +expari(const char *p, int flag, struct worddest *dst) { char *q, *start; arith_t result; @@ -532,7 +538,7 @@ recordleft(const char *str, const char *loc, char *startp) } static void -subevalvar_trim(char *p, int strloc, int subtype, int startloc) +subevalvar_trim(const char *p, int strloc, int subtype, int startloc) { char *startp; char *loc = NULL; @@ -606,7 +612,7 @@ subevalvar_trim(char *p, int strloc, int subtype, int startloc) static int -subevalvar_misc(char *p, const char *var, int subtype, int startloc, +subevalvar_misc(const char *p, const char *var, int subtype, int startloc, int varflags) { char *startp; @@ -645,12 +651,12 @@ subevalvar_misc(char *p, const char *var, int subtype, int startloc, * input string. */ -static char * -evalvar(char *p, int flag, struct worddest *dst) +static const char * +evalvar(const char *p, int flag, struct worddest *dst) { int subtype; int varflags; - char *var; + const char *var; const char *val; int patloc; int c; diff --git a/cddl/lib/Makefile b/cddl/lib/Makefile index 9371865ca42..2bfc6c1e157 100644 --- a/cddl/lib/Makefile +++ b/cddl/lib/Makefile @@ -26,7 +26,7 @@ _libzpool= libzpool .endif .endif -.if ${MACHINE_CPUARCH} != "sparc64" +.if ${MACHINE_CPUARCH} != "sparc64" && ${MACHINE_CPUARCH} != "riscv" _drti= drti _libdtrace= libdtrace .endif diff --git a/contrib/elftoolchain/libelf/_libelf_config.h b/contrib/elftoolchain/libelf/_libelf_config.h index 1b8f35b2242..602eb89c566 100644 --- a/contrib/elftoolchain/libelf/_libelf_config.h +++ b/contrib/elftoolchain/libelf/_libelf_config.h @@ -97,6 +97,12 @@ #define LIBELF_BYTEORDER ELFDATA2MSB #define LIBELF_CLASS ELFCLASS32 +#elif defined(__riscv64) + +#define LIBELF_ARCH EM_RISCV +#define LIBELF_BYTEORDER ELFDATA2LSB +#define LIBELF_CLASS ELFCLASS64 + #elif defined(__sparc__) #define LIBELF_ARCH EM_SPARCV9 diff --git a/contrib/gcc/config/riscv64/freebsd.h b/contrib/gcc/config/riscv64/freebsd.h new file mode 100644 index 00000000000..7ce148742e7 --- /dev/null +++ b/contrib/gcc/config/riscv64/freebsd.h @@ -0,0 +1,6 @@ +/* $FreeBSD$ */ + +#undef INIT_SECTION_ASM_OP +#undef FINI_SECTION_ASM_OP +#define INIT_ARRAY_SECTION_ASM_OP "\t.section\t.init_array,\"aw\",%init_array" +#define FINI_ARRAY_SECTION_ASM_OP "\t.section\t.fini_array,\"aw\",%fini_array" diff --git a/contrib/gcc/config/riscv64/riscv64.h b/contrib/gcc/config/riscv64/riscv64.h new file mode 100644 index 00000000000..da23dbe43a4 --- /dev/null +++ b/contrib/gcc/config/riscv64/riscv64.h @@ -0,0 +1 @@ +/* $FreeBSD$ */ diff --git a/contrib/ofed/librdmacm/examples/build/rping/Makefile b/contrib/ofed/librdmacm/examples/build/rping/Makefile index b167a543c09..ee2efbd22b8 100644 --- a/contrib/ofed/librdmacm/examples/build/rping/Makefile +++ b/contrib/ofed/librdmacm/examples/build/rping/Makefile @@ -5,7 +5,8 @@ PROG= rping MAN= SRCS= rping.c -LDADD+= -libverbs -lrdmacm -lpthread -LDADD+= -lmlx4 +LIBADD+= ibverbs rdmacm pthread +LIBADD+= mlx4 +LIBADD+= cxgb4 .include diff --git a/etc/defaults/periodic.conf b/etc/defaults/periodic.conf index e9dac275bdc..2364d7fc0fa 100644 --- a/etc/defaults/periodic.conf +++ b/etc/defaults/periodic.conf @@ -134,6 +134,11 @@ daily_status_mail_rejects_enable="YES" # Check mail rejects daily_status_mail_rejects_logs=3 # How many logs to check daily_status_mail_rejects_shorten="NO" # Shorten output +# 480.leapfile-ntpd +daily_ntpd_leapfile_enable="NO" # Fetch NTP leapfile +daily_ntpd_avoid_congestion="YES" # Avoid congesting + # leapfile sources + # 480.status-ntpd daily_status_ntpd_enable="NO" # Check NTP status diff --git a/etc/defaults/rc.conf b/etc/defaults/rc.conf index 54facb84804..380f0d3b32f 100644 --- a/etc/defaults/rc.conf +++ b/etc/defaults/rc.conf @@ -362,6 +362,15 @@ ntpd_config="/etc/ntp.conf" # ntpd(8) configuration file ntpd_sync_on_start="NO" # Sync time on ntpd startup, even if offset is high ntpd_flags="-p /var/run/ntpd.pid -f /var/db/ntpd.drift" # Flags to ntpd (if enabled). +ntp_src_leapfile="/etc/ntp/leap-seconds" + # Initial source for ntpd leapfile +ntp_db_leapfile="/var/db/ntpd.leap-seconds.list" + # Working copy (updated weekly) leapfile +ntp_leapfile_sources="https://www.ietf.org/timezones/data/leap-seconds.list" + # Source from which to fetch leapfile +ntp_leapfile_expiry_days=30 # Check for new leapfile 30 days prior to + # expiry. +ntp_leapfile_fetch_verbose="NO" # Be verbose during NTP leapfile fetch # Network Information Services (NIS) options: All need rpcbind_enable="YES" ### nis_client_enable="NO" # We're an NIS client (or NO). diff --git a/etc/ntp.conf b/etc/ntp.conf index c4ad0aa1bde..64edd9377bc 100644 --- a/etc/ntp.conf +++ b/etc/ntp.conf @@ -81,4 +81,6 @@ restrict 127.127.1.0 # See http://support.ntp.org/bin/view/Support/ConfiguringNTP#Section_6.14. # for documentation regarding leapfile. Updates to the file can be obtained # from ftp://time.nist.gov/pub/ or ftp://tycho.usno.navy.mil/pub/ntp/. -leapfile "/etc/ntp/leap-seconds" +# Use either leapfile in /etc/ntp or weekly updated leapfile in /var/db. +#leapfile "/etc/ntp/leap-seconds" +leapfile "/var/db/ntpd.leap-seconds.list" diff --git a/etc/periodic/daily/480.leapfile-ntpd b/etc/periodic/daily/480.leapfile-ntpd new file mode 100755 index 00000000000..8429824f9b9 --- /dev/null +++ b/etc/periodic/daily/480.leapfile-ntpd @@ -0,0 +1,28 @@ +#!/bin/sh +# +# $FreeBSD$ +# + +# If there is a global system configuration file, suck it in. +# +if [ -r /etc/defaults/periodic.conf ] +then + . /etc/defaults/periodic.conf + source_periodic_confs +fi + +case "$daily_ntpd_leapfile_enable" in + [Yy][Ee][Ss]) + case "$daily_ntpd_avoid_congestion" in + [Yy][Ee][Ss]) + # Avoid dogpiling + (sleep $(jot -r 1 0 86400); service ntpd fetch) & + ;; + *) + service ntpd fetch + ;; + esac + ;; +esac + +exit $rc diff --git a/etc/periodic/daily/Makefile b/etc/periodic/daily/Makefile index 939dd150e4a..de0f8f2a907 100644 --- a/etc/periodic/daily/Makefile +++ b/etc/periodic/daily/Makefile @@ -35,7 +35,8 @@ FILES+= 130.clean-msgs .endif .if ${MK_NTP} != "no" -FILES+= 480.status-ntpd +FILES+= 480.status-ntpd \ + 480.leapfile-ntpd .endif .if ${MK_RCMDS} != "no" diff --git a/etc/rc.d/jail b/etc/rc.d/jail index a1b4bbcb35e..fa0bc46be6e 100755 --- a/etc/rc.d/jail +++ b/etc/rc.d/jail @@ -32,7 +32,7 @@ need_dad_wait= # Extract value from ${jail_$jv_$name} or ${jail_$name} and # set it to $param. If not defined, $defval is used. # When $num is [0-9]*, ${jail_$jv_$name$num} are looked up and -# $param is set by using +=. +# $param is set by using +=. $num=0 is optional (params may start at 1). # When $num is YN or NY, the value is interpret as boolean. extract_var() { @@ -72,7 +72,7 @@ extract_var() eval _tmpargs=\"\${$_name1:-\${$_name2:-$_def}}\" if [ -n "$_tmpargs" ]; then echo " $_param += \"$_tmpargs\";" - else + elif [ $i != 0 ]; then break; fi i=$(($i + 1)) @@ -202,7 +202,7 @@ parse_options() extract_var $_jv exec_poststop exec.poststop 0 "" echo " exec.start += \"$_exec_start\";" - extract_var $_jv exec_afterstart exec.start 1 "" + extract_var $_jv exec_afterstart exec.start 0 "" echo " exec.stop = \"$_exec_stop\";" extract_var $_jv consolelog exec.consolelog - \ diff --git a/etc/rc.d/ntpd b/etc/rc.d/ntpd index 3935b295ed4..f014110de81 100755 --- a/etc/rc.d/ntpd +++ b/etc/rc.d/ntpd @@ -14,6 +14,8 @@ name="ntpd" rcvar="ntpd_enable" command="/usr/sbin/${name}" pidfile="/var/run/${name}.pid" +extra_commands="fetch" +fetch_cmd="ntpd_fetch_leapfile" start_precmd="ntpd_precmd" load_rc_config $name @@ -30,6 +32,10 @@ ntpd_precmd() return 0; fi + if [ ! -f $ntp_db_leapfile ]; then + ntpd_fetch_leapfile + fi + # If running in a chroot cage, ensure that the appropriate files # exist inside the cage, as well as helper symlinks into the cage # from outside. @@ -44,10 +50,71 @@ ntpd_precmd() ( cd /dev ; /bin/pax -rw -pe clockctl "${ntpd_chrootdir}/dev" ) fi ln -fs "${ntpd_chrootdir}/var/db/ntp.drift" /var/db/ntp.drift + ln -fs "${ntpd_chrootdir}${ntp_tmp_leapfile}" ${ntp_tmp_leapfile} # Change run_rc_commands()'s internal copy of $ntpd_flags # rc_flags="-u ntpd:ntpd -i ${ntpd_chrootdir} $rc_flags" } +current_ntp_ts() { + # Seconds between 1900-01-01 and 1970-01-01 + # echo $(((70*365+17)*86400)) + ntp_to_unix=2208988800 + + echo $(($(date -u +%s)+$ntp_to_unix)) +} + +get_ntp_leapfile_ver() { + expr "$(awk '$1 == "#$" { print $2 }' "$1" 2>/dev/null)" : \ + '^\([1-9][0-9]*\)$' \| 0 +} + +get_ntp_leapfile_expiry() { + expr "$(awk '$1 == "#@" { print $2 }' "$1" 2>/dev/null)" : \ + '^\([1-9][0-9]*\)$' \| 0 +} + +ntpd_fetch_leapfile() { + local ntp_tmp_leapfile rc verbose + + if checkyesno ntp_leapfile_fetch_verbose; then + verbose=echo + else + verbose=: + fi + + ntp_tmp_leapfile="/var/run/ntpd.leap-seconds.list" + + ntp_ver_no_src=$(get_ntp_leapfile_ver $ntp_src_leapfile) + ntp_ver_no_db=$(get_ntp_leapfile_ver $ntp_db_leapfile) + $verbose ntp_src_leapfile version is $ntp_ver_no_src + $verbose ntp_db_leapfile version is $ntp_ver_no_db + + if [ "$ntp_ver_no_src" -gt "$ntp_ver_no_db" ]; then + $verbose replacing $ntp_db_leapfile with $ntp_src_leapfile + cp -p $ntp_src_leapfile $ntp_db_leapfile + ntp_ver_no_db=$ntp_ver_no_src + else + $verbose not replacing $ntp_db_leapfile with $ntp_src_leapfile + fi + ntp_leap_expiry=$(get_ntp_leapfile_expiry $ntp_db_leapfile) + ntp_leapfile_expiry_seconds=$((ntp_leapfile_expiry_days*86400)) + ntp_leap_fetch_date=$((ntp_leap_expiry-ntp_leapfile_expiry_seconds)) + if [ $(current_ntp_ts) -ge $ntp_leap_fetch_date ]; then + $verbose Within ntp leapfile expiry limit, initiating fetch + for url in $ntp_leapfile_sources ; do + $verbose fetching $url + fetch -mqo $ntp_tmp_leapfile $url && break + done + ntp_ver_no_tmp=$(get_ntp_leapfile_ver $ntp_tmp_leapfile) + if [ "$ntp_ver_no_tmp" -gt "$ntp_ver_no_db" ]; then + $verbose using $url as $ntp_db_leapfile + mv $ntp_tmp_leapfile $ntp_db_leapfile + else + $verbose using existing $ntp_db_leapfile + fi + fi +} + run_rc_command "$1" diff --git a/gnu/lib/libreadline/readline/Makefile b/gnu/lib/libreadline/readline/Makefile index 17c84ae8e61..1947b3e0bef 100644 --- a/gnu/lib/libreadline/readline/Makefile +++ b/gnu/lib/libreadline/readline/Makefile @@ -2,7 +2,7 @@ LIB= readline INTERNALLIB= yes -NO_MAN= yes +MAN= TILDESRC= tilde.c SRCS= readline.c vi_mode.c funmap.c keymaps.c parens.c search.c \ diff --git a/lib/Makefile b/lib/Makefile index 51532e76b0a..ccc6507ff56 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -264,7 +264,8 @@ _libproc= libproc _librtld_db= librtld_db .endif -.if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "arm" +.if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "arm" || \ + ${MACHINE_CPUARCH} == "riscv" _libproc= libproc _librtld_db= librtld_db .endif diff --git a/lib/libc/Makefile b/lib/libc/Makefile index d02c028f6e0..a48b3e5ca88 100644 --- a/lib/libc/Makefile +++ b/lib/libc/Makefile @@ -169,15 +169,15 @@ SUBDIR+= tests .if !defined(_SKIP_BUILD) # We need libutil.h, get it directly to avoid # recording a build dependency -CFLAGS+= -I${.CURDIR:H}/libutil +CFLAGS+= -I${SRCTOP}/lib/libutil # Same issue with libm -MSUN_ARCH_SUBDIR != ${MAKE} -B -C ${.CURDIR:H}/msun -V ARCH_SUBDIR +MSUN_ARCH_SUBDIR != ${MAKE} -B -C ${SRCTOP}/lib/msun -V ARCH_SUBDIR # unfortunately msun/src contains both private and public headers -CFLAGS+= -I${.CURDIR:H}/msun/${MSUN_ARCH_SUBDIR} +CFLAGS+= -I${SRCTOP}/lib/msun/${MSUN_ARCH_SUBDIR} .if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64" -CFLAGS+= -I${.CURDIR:H}/msun/x86 +CFLAGS+= -I${SRCTOP}/lib/msun/x86 .endif -CFLAGS+= -I${.CURDIR:H}/msun/src +CFLAGS+= -I${SRCTOP}/lib/msun/src # and we do not want to record a dependency on msun .if ${.MAKE.LEVEL} > 0 GENDIRDEPS_FILTER+= N${RELDIR:H}/msun diff --git a/lib/libc/gen/readpassphrase.c b/lib/libc/gen/readpassphrase.c index 60051a189e5..0961fbb35a8 100644 --- a/lib/libc/gen/readpassphrase.c +++ b/lib/libc/gen/readpassphrase.c @@ -46,7 +46,7 @@ char * readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) { ssize_t nr; - int input, output, save_errno, i, need_restart; + int input, output, save_errno, i, need_restart, input_is_tty; char ch, *p, *end; struct termios term, oterm; struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm; @@ -68,12 +68,20 @@ restart: * Read and write to /dev/tty if available. If not, read from * stdin and write to stderr unless a tty is required. */ - if ((flags & RPP_STDIN) || - (input = output = _open(_PATH_TTY, O_RDWR | O_CLOEXEC)) == -1) { - if (flags & RPP_REQUIRE_TTY) { - errno = ENOTTY; - return(NULL); + input_is_tty = 0; + if (!(flags & RPP_STDIN)) { + input = output = _open(_PATH_TTY, O_RDWR | O_CLOEXEC); + if (input == -1) { + if (flags & RPP_REQUIRE_TTY) { + errno = ENOTTY; + return(NULL); + } + input = STDIN_FILENO; + output = STDERR_FILENO; + } else { + input_is_tty = 1; } + } else { input = STDIN_FILENO; output = STDERR_FILENO; } @@ -83,7 +91,7 @@ restart: * If we are using a tty but are not the foreground pgrp this will * generate SIGTTOU, so do it *before* installing the signal handlers. */ - if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) { + if (input_is_tty && tcgetattr(input, &oterm) == 0) { memcpy(&term, &oterm, sizeof(term)); if (!(flags & RPP_ECHO_ON)) term.c_lflag &= ~(ECHO | ECHONL); @@ -152,7 +160,7 @@ restart: (void)__libc_sigaction(SIGTSTP, &savetstp, NULL); (void)__libc_sigaction(SIGTTIN, &savettin, NULL); (void)__libc_sigaction(SIGTTOU, &savettou, NULL); - if (input != STDIN_FILENO) + if (input_is_tty) (void)_close(input); /* diff --git a/lib/libc/net/sctp_sys_calls.c b/lib/libc/net/sctp_sys_calls.c index f07aa4321ca..dcbcee77576 100644 --- a/lib/libc/net/sctp_sys_calls.c +++ b/lib/libc/net/sctp_sys_calls.c @@ -700,14 +700,19 @@ sctp_sendx(int sd, const void *msg, size_t msg_len, #ifdef SYS_sctp_generic_sendmsg if (addrcnt == 1) { socklen_t l; + ssize_t ret; /* * Quick way, we don't need to do a connectx so lets use the * syscall directly. */ l = addrs->sa_len; - return (syscall(SYS_sctp_generic_sendmsg, sd, - msg, msg_len, addrs, l, sinfo, flags)); + ret = syscall(SYS_sctp_generic_sendmsg, sd, + msg, msg_len, addrs, l, sinfo, flags); + if ((ret >= 0) && (sinfo != NULL)) { + sinfo->sinfo_assoc_id = sctp_getassocid(sd, addrs); + } + return (ret); } #endif @@ -984,6 +989,7 @@ sctp_sendv(int sd, struct sockaddr *addr; struct sockaddr_in *addr_in; struct sockaddr_in6 *addr_in6; + sctp_assoc_t *assoc_id; if ((addrcnt < 0) || (iovcnt < 0) || @@ -1002,6 +1008,7 @@ sctp_sendv(int sd, errno = ENOMEM; return (-1); } + assoc_id = NULL; msg.msg_control = cmsgbuf; msg.msg_controllen = 0; cmsg = (struct cmsghdr *)cmsgbuf; @@ -1025,6 +1032,7 @@ sctp_sendv(int sd, memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_sndinfo)); msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo))); + assoc_id = &(((struct sctp_sndinfo *)info)->snd_assoc_id); break; case SCTP_SENDV_PRINFO: if ((info == NULL) || (infolen < sizeof(struct sctp_prinfo))) { @@ -1066,6 +1074,7 @@ sctp_sendv(int sd, memcpy(CMSG_DATA(cmsg), &spa_info->sendv_sndinfo, sizeof(struct sctp_sndinfo)); msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo))); + assoc_id = &(spa_info->sendv_sndinfo.snd_assoc_id); } if (spa_info->sendv_flags & SCTP_SEND_PRINFO_VALID) { cmsg->cmsg_level = IPPROTO_SCTP; @@ -1164,6 +1173,9 @@ sctp_sendv(int sd, msg.msg_flags = 0; ret = sendmsg(sd, &msg, flags); free(cmsgbuf); + if ((ret >= 0) && (addrs != NULL) && (assoc_id != NULL)) { + *assoc_id = sctp_getassocid(sd, addrs); + } return (ret); } diff --git a/lib/libelftc/Makefile b/lib/libelftc/Makefile index ccae1a55431..ed5c02a93cb 100644 --- a/lib/libelftc/Makefile +++ b/lib/libelftc/Makefile @@ -25,6 +25,6 @@ SRCS= elftc_bfdtarget.c \ INCS= libelftc.h CFLAGS+=-I${ELFTCDIR}/libelftc -I${ELFTCDIR}/common -NO_MAN= yes +MAN= .include diff --git a/lib/libproc/proc_bkpt.c b/lib/libproc/proc_bkpt.c index f0ff5c5d770..4a100cbbd4e 100644 --- a/lib/libproc/proc_bkpt.c +++ b/lib/libproc/proc_bkpt.c @@ -61,6 +61,9 @@ __FBSDID("$FreeBSD$"); #elif defined(__powerpc__) #define BREAKPOINT_INSTR 0x7fe00008 /* trap */ #define BREAKPOINT_INSTR_SZ 4 +#elif defined(__riscv__) +#define BREAKPOINT_INSTR 0x00100073 /* sbreak */ +#define BREAKPOINT_INSTR_SZ 4 #else #error "Add support for your architecture" #endif diff --git a/lib/libproc/proc_regs.c b/lib/libproc/proc_regs.c index aae43ba1710..745fa099a92 100644 --- a/lib/libproc/proc_regs.c +++ b/lib/libproc/proc_regs.c @@ -66,6 +66,8 @@ proc_regget(struct proc_handle *phdl, proc_reg_t reg, unsigned long *regvalue) *regvalue = regs.r_regs[PC]; #elif defined(__powerpc__) *regvalue = regs.pc; +#elif defined(__riscv__) + *regvalue = regs.sepc; #endif break; case REG_SP: @@ -81,6 +83,8 @@ proc_regget(struct proc_handle *phdl, proc_reg_t reg, unsigned long *regvalue) *regvalue = regs.r_regs[SP]; #elif defined(__powerpc__) *regvalue = regs.fixreg[1]; +#elif defined(__riscv__) + *regvalue = regs.sp; #endif break; default: @@ -117,6 +121,8 @@ proc_regset(struct proc_handle *phdl, proc_reg_t reg, unsigned long regvalue) regs.r_regs[PC] = regvalue; #elif defined(__powerpc__) regs.pc = regvalue; +#elif defined(__riscv__) + regs.sepc = regvalue; #endif break; case REG_SP: @@ -132,6 +138,8 @@ proc_regset(struct proc_handle *phdl, proc_reg_t reg, unsigned long regvalue) regs.r_regs[PC] = regvalue; #elif defined(__powerpc__) regs.fixreg[1] = regvalue; +#elif defined(__riscv__) + regs.sp = regvalue; #endif break; default: diff --git a/libexec/rtld-elf/riscv/rtld_machdep.h b/libexec/rtld-elf/riscv/rtld_machdep.h index aa370001b5c..660787f5d16 100644 --- a/libexec/rtld-elf/riscv/rtld_machdep.h +++ b/libexec/rtld-elf/riscv/rtld_machdep.h @@ -108,4 +108,6 @@ extern void *__tls_get_addr(tls_index* ti); #define RTLD_DEFAULT_STACK_PF_EXEC PF_X #define RTLD_DEFAULT_STACK_EXEC PROT_EXEC +#define md_abi_variant_hook(x) + #endif diff --git a/sbin/ifconfig/iflagg.c b/sbin/ifconfig/iflagg.c index 97b42e31e43..cbf58f7ba90 100644 --- a/sbin/ifconfig/iflagg.c +++ b/sbin/ifconfig/iflagg.c @@ -99,6 +99,19 @@ setlaggflowidshift(const char *val, int d, int s, const struct afswtch *afp) err(1, "SIOCSLAGGOPTS"); } +static void +setlaggrr_limit(const char *val, int d, int s, const struct afswtch *afp) +{ + struct lagg_reqopts ro; + + bzero(&ro, sizeof(ro)); + strlcpy(ro.ro_ifname, name, sizeof(ro.ro_ifname)); + ro.ro_bkt = (int)strtol(val, NULL, 10); + + if (ioctl(s, SIOCSLAGGOPTS, &ro) != 0) + err(1, "SIOCSLAGG"); +} + static void setlaggsetopt(const char *val, int d, int s, const struct afswtch *afp) { @@ -252,6 +265,8 @@ lagg_status(int s) printb("\t\tflags", ro.ro_opts, LAGG_OPT_BITS); putchar('\n'); printf("\t\tflowid_shift: %d\n", ro.ro_flowid_shift); + if (ra.ra_proto == LAGG_PROTO_ROUNDROBIN) + printf("\t\trr_limit: %d\n", ro.ro_bkt); printf("\tlagg statistics:\n"); printf("\t\tactive ports: %d\n", ro.ro_active); printf("\t\tflapping: %u\n", ro.ro_flapping); @@ -298,6 +313,7 @@ static struct cmd lagg_cmds[] = { DEF_CMD("lacp_fast_timeout", LAGG_OPT_LACP_TIMEOUT, setlaggsetopt), DEF_CMD("-lacp_fast_timeout", -LAGG_OPT_LACP_TIMEOUT, setlaggsetopt), DEF_CMD_ARG("flowid_shift", setlaggflowidshift), + DEF_CMD_ARG("rr_limit", setlaggrr_limit), }; static struct afswtch af_lagg = { .af_name = "af_lagg", diff --git a/sbin/kldstat/Makefile b/sbin/kldstat/Makefile index e4145d7c3c4..4bf022eb94d 100644 --- a/sbin/kldstat/Makefile +++ b/sbin/kldstat/Makefile @@ -29,4 +29,6 @@ PROG= kldstat MAN= kldstat.8 +LIBADD= util + .include diff --git a/sbin/kldstat/kldstat.8 b/sbin/kldstat/kldstat.8 index b892ef67829..2ea9ca44d4b 100644 --- a/sbin/kldstat/kldstat.8 +++ b/sbin/kldstat/kldstat.8 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd January 22, 2014 +.Dd January 19, 2016 .Dt KLDSTAT 8 .Os .Sh NAME @@ -33,6 +33,7 @@ .Nd display status of dynamic kernel linker .Sh SYNOPSIS .Nm +.Op Fl h .Op Fl q .Op Fl v .Op Fl i Ar id @@ -48,6 +49,9 @@ kernel. .Pp The following options are available: .Bl -tag -width indentXX +.It Fl h +Display the size field in a human-readable form, using unit suffixes +instead of hex values. .It Fl v Be more verbose. .It Fl i Ar id diff --git a/sbin/kldstat/kldstat.c b/sbin/kldstat/kldstat.c index 8785c00ee10..c48024f0d43 100644 --- a/sbin/kldstat/kldstat.c +++ b/sbin/kldstat/kldstat.c @@ -28,6 +28,7 @@ __FBSDID("$FreeBSD$"); #include +#include #include #include #include @@ -51,18 +52,27 @@ printmod(int modid) } static void -printfile(int fileid, int verbose) +printfile(int fileid, int verbose, int humanized) { struct kld_file_stat stat; int modid; + char buf[5]; stat.version = sizeof(struct kld_file_stat); - if (kldstat(fileid, &stat) < 0) + if (kldstat(fileid, &stat) < 0) { err(1, "can't stat file id %d", fileid); - else - printf("%2d %4d %p %-8zx %s", - stat.id, stat.refs, stat.address, stat.size, - stat.name); + } else { + if (humanized) { + humanize_number(buf, sizeof(buf), stat.size, + "", HN_AUTOSCALE, HN_DECIMAL | HN_NOSPACE); + + printf("%2d %4d %p %5s %s", + stat.id, stat.refs, stat.address, buf, stat.name); + } else { + printf("%2d %4d %p %-8zx %s", + stat.id, stat.refs, stat.address, stat.size, stat.name); + } + } if (verbose) { printf(" (%s)\n", stat.pathname); @@ -78,7 +88,7 @@ printfile(int fileid, int verbose) static void usage(void) { - fprintf(stderr, "usage: kldstat [-q] [-v] [-i id] [-n filename]\n"); + fprintf(stderr, "usage: kldstat [-h] [-q] [-v] [-i id] [-n filename]\n"); fprintf(stderr, " kldstat [-q] [-m modname]\n"); exit(1); } @@ -87,6 +97,7 @@ int main(int argc, char** argv) { int c; + int humanized = 0; int verbose = 0; int fileid = 0; int quiet = 0; @@ -94,8 +105,11 @@ main(int argc, char** argv) char* modname = NULL; char* p; - while ((c = getopt(argc, argv, "i:m:n:qv")) != -1) + while ((c = getopt(argc, argv, "hi:m:n:qv")) != -1) switch (c) { + case 'h': + humanized = 1; + break; case 'i': fileid = (int)strtoul(optarg, &p, 10); if (*p != '\0') @@ -155,12 +169,15 @@ main(int argc, char** argv) } } - printf("Id Refs Address%*c Size Name\n", POINTER_WIDTH - 7, ' '); + if (humanized) + printf("Id Refs Address%*c Size Name\n", POINTER_WIDTH - 7, ' '); + else + printf("Id Refs Address%*c Size Name\n", POINTER_WIDTH - 7, ' '); if (fileid != 0) - printfile(fileid, verbose); + printfile(fileid, verbose, humanized); else for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) - printfile(fileid, verbose); + printfile(fileid, verbose, humanized); return 0; } diff --git a/share/dtrace/watch_kill b/share/dtrace/watch_kill index b7a06f9a129..46f3cd8733f 100755 --- a/share/dtrace/watch_kill +++ b/share/dtrace/watch_kill @@ -1,6 +1,6 @@ #!/usr/sbin/dtrace -s /* - - * Copyright (c) 2014-2015 Devin Teske + * Copyright (c) 2014-2016 Devin Teske * All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/share/man/man4/lagg.4 b/share/man/man4/lagg.4 index da070f158d0..c1a1bef4d92 100644 --- a/share/man/man4/lagg.4 +++ b/share/man/man4/lagg.4 @@ -16,7 +16,7 @@ .\" .\" $FreeBSD$ .\" -.Dd November 6, 2015 +.Dd January 23, 2016 .Dt LAGG 4 .Os .Sh NAME @@ -110,6 +110,11 @@ available, the VLAN tag, and the IP source and destination address. Distributes outgoing traffic using a round-robin scheduler through all active ports and accepts incoming traffic from any active port. +Using +.Ic roundrobin +mode can cause unordered packet arrival at the client. +Throughput might be limited as the client performs CPU-intensive packet +reordering. .It Ic broadcast Sends frames to all ports of the LAG and receives frames on any port of the LAG. @@ -161,6 +166,19 @@ Gigabit Ethernet interfaces: 192.168.1.1 netmask 255.255.255.0 .Ed .Pp +Create a link aggregation using ROUNDROBIN with two +.Xr bge 4 +Gigabit Ethernet interfaces and set the limit of 500 packets +per interface: +.Bd -literal -offset indent +# ifconfig bge0 up +# ifconfig bge1 up +# ifconfig lagg0 create +# ifconfig lagg0 laggproto roundrobin laggport bge0 laggport bge1 \e + 192.168.1.1 netmask 255.255.255.0 +# ifconfig lagg0 rr_limit 500 +.Ed +.Pp The following example uses an active failover interface to set up roaming between wired and wireless networks using two network devices. Whenever the wired master interface is unplugged, the wireless failover diff --git a/share/man/man5/ext2fs.5 b/share/man/man5/ext2fs.5 index 00be16f750a..db792bb0c8c 100644 --- a/share/man/man5/ext2fs.5 +++ b/share/man/man5/ext2fs.5 @@ -26,12 +26,12 @@ .\" .\" $FreeBSD$ .\" -.Dd October 1, 2013 +.Dd January 23, 2016 .Dt EXT2FS 5 .Os .Sh NAME .Nm ext2fs -.Nd "Ext2fs file system" +.Nd "ext2/ext3/ext4 file system" .Sh SYNOPSIS To link into the kernel: .Bd -ragged -offset indent @@ -47,8 +47,14 @@ The driver will permit the .Fx kernel to access -.Tn Ext2 +.Tn ext2 , +.Tn ext3 , +and +.Tn ext4 file systems. +The +.Tn ext4 +support is read-only. .Sh EXAMPLES To mount a .Nm diff --git a/share/man/man9/hashinit.9 b/share/man/man9/hashinit.9 index b72cd755119..65ef10e5b6a 100644 --- a/share/man/man9/hashinit.9 +++ b/share/man/man9/hashinit.9 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd October 10, 2004 +.Dd January 23, 2016 .Dt HASHINIT 9 .Os .Sh NAME @@ -102,9 +102,11 @@ Any malloc performed by the .Fn hashinit_flags function will not be allowed to wait, and therefore may fail. .It Dv HASH_WAITOK -Any malloc performed by the +Any malloc performed by .Fn hashinit_flags function is allowed to wait for memory. +This is also the behavior of +.Fn hashinit . .El .Sh IMPLEMENTATION NOTES The largest prime hash value chosen by diff --git a/share/mk/auto.obj.mk b/share/mk/auto.obj.mk index 0c13ae53824..6bc8c50e6e9 100644 --- a/share/mk/auto.obj.mk +++ b/share/mk/auto.obj.mk @@ -1,5 +1,5 @@ # $FreeBSD$ -# $Id: auto.obj.mk,v 1.10 2015/04/16 16:59:00 sjg Exp $ +# $Id: auto.obj.mk,v 1.12 2015/12/16 01:57:06 sjg Exp $ # # @(#) Copyright (c) 2004, Simon J. Gerraty # @@ -41,12 +41,12 @@ MKOBJDIRS= auto .if !defined(NOOBJ) && !defined(NO_OBJ) && ${MKOBJDIRS:Uno} == auto # Use __objdir here so it is easier to tweak without impacting # the logic. -.if !empty(MAKEOBJDIRPREFIX) && exists(${MAKEOBJDIRPREFIX}) +.if !empty(MAKEOBJDIRPREFIX) __objdir?= ${MAKEOBJDIRPREFIX}${.CURDIR} .endif __objdir?= ${MAKEOBJDIR:Uobj} -__objdir:= ${__objdir:tA} -.if ${.OBJDIR} != ${__objdir} +__objdir:= ${__objdir} +.if ${.OBJDIR:tA} != ${__objdir:tA} # We need to chdir, make the directory if needed .if !exists(${__objdir}/) && \ (${.TARGETS} == "" || ${.TARGETS:Nclean*:N*clean:Ndestroy*} != "") @@ -54,11 +54,10 @@ __objdir:= ${__objdir:tA} __objdir_made != echo ${__objdir}/; umask ${OBJDIR_UMASK:U002}; \ ${ECHO_TRACE} "[Creating objdir ${__objdir}...]" >&2; \ ${Mkdirs}; Mkdirs ${__objdir} -__objdir:= ${__objdir:tA} .endif # This causes make to use the specified directory as .OBJDIR .OBJDIR: ${__objdir} -.if ${.OBJDIR} != ${__objdir} && ${__objdir_made:Uno:M${__objdir}/*} != "" +.if ${.OBJDIR:tA} != ${__objdir:tA} && ${__objdir_made:Uno:M${__objdir}/*} != "" .error could not use ${__objdir}: .OBJDIR=${.OBJDIR} .endif .endif diff --git a/share/mk/bsd.dep.mk b/share/mk/bsd.dep.mk index 95730afcaaf..d31dc8b5d96 100644 --- a/share/mk/bsd.dep.mk +++ b/share/mk/bsd.dep.mk @@ -56,6 +56,7 @@ _MKDEPCC+= ${DEPFLAGS} .endif MKDEPCMD?= CC='${_MKDEPCC}' mkdep DEPENDFILE?= .depend +.MAKE.DEPENDFILE= ${DEPENDFILE} DEPENDFILES= ${DEPENDFILE} # Keep `tags' here, before SRCS are mangled below for `depend'. @@ -129,25 +130,26 @@ CFLAGS+= -I${.OBJDIR} .endif .for _DSRC in ${SRCS:M*.d:N*/*} .for _D in ${_DSRC:R} -DHDRS+= ${_D}.h +SRCS+= ${_D}.h ${_D}.h: ${_DSRC} ${DTRACE} ${DTRACEFLAGS} -h -s ${.ALLSRC} SRCS:= ${SRCS:S/^${_DSRC}$//} OBJS+= ${_D}.o CLEANFILES+= ${_D}.h ${_D}.o ${_D}.o: ${_DSRC} ${OBJS:S/^${_D}.o$//} - ${DTRACE} ${DTRACEFLAGS} -G -o ${.TARGET} -s ${.ALLSRC} + @rm -f ${.TARGET} + ${DTRACE} ${DTRACEFLAGS} -G -o ${.TARGET} -s ${.ALLSRC:N*.h} .if defined(LIB) CLEANFILES+= ${_D}.So ${_D}.po ${_D}.So: ${_DSRC} ${SOBJS:S/^${_D}.So$//} - ${DTRACE} ${DTRACEFLAGS} -G -o ${.TARGET} -s ${.ALLSRC} + @rm -f ${.TARGET} + ${DTRACE} ${DTRACEFLAGS} -G -o ${.TARGET} -s ${.ALLSRC:N*.h} ${_D}.po: ${_DSRC} ${POBJS:S/^${_D}.po$//} - ${DTRACE} ${DTRACEFLAGS} -G -o ${.TARGET} -s ${.ALLSRC} + @rm -f ${.TARGET} + ${DTRACE} ${DTRACEFLAGS} -G -o ${.TARGET} -s ${.ALLSRC:N*.h} .endif .endfor .endfor -beforedepend: ${DHDRS} -beforebuild: ${DHDRS} .if ${MK_FAST_DEPEND} == "yes" && \ diff --git a/share/mk/gendirdeps.mk b/share/mk/gendirdeps.mk index f0c177d0a54..b4d1386b636 100644 --- a/share/mk/gendirdeps.mk +++ b/share/mk/gendirdeps.mk @@ -1,5 +1,5 @@ # $FreeBSD$ -# $Id: gendirdeps.mk,v 1.27 2015/06/08 20:55:11 sjg Exp $ +# $Id: gendirdeps.mk,v 1.29 2015/10/03 05:00:46 sjg Exp $ # Copyright (c) 2010-2013, Juniper Networks, Inc. # All rights reserved. @@ -158,7 +158,7 @@ M2D_OBJROOTS += ${SB_BACKING_SB}/${SB_OBJPREFIX} .endif # we are only interested in the dirs -# sepecifically those we read something from. +# specifically those we read something from. # we canonicalize them to keep things simple # if we are using a split-fs sandbox, it gets a little messier. _objtop := ${_OBJTOP:tA} diff --git a/share/mk/host-target.mk b/share/mk/host-target.mk index 754f1ece8cf..ef8cc80d658 100644 --- a/share/mk/host-target.mk +++ b/share/mk/host-target.mk @@ -1,6 +1,6 @@ # $FreeBSD$ # RCSid: -# $Id: host-target.mk,v 1.7 2014/05/16 17:54:52 sjg Exp $ +# $Id: host-target.mk,v 1.11 2015/10/25 00:07:20 sjg Exp $ # Host platform information; may be overridden .if !defined(_HOST_OSNAME) @@ -11,24 +11,33 @@ _HOST_OSNAME != uname -s _HOST_OSREL != uname -r .export _HOST_OSREL .endif +.if !defined(_HOST_MACHINE) +_HOST_MACHINE != uname -m +.export _HOST_MACHINE +.endif .if !defined(_HOST_ARCH) -_HOST_ARCH != uname -p 2>/dev/null || uname -m +# for NetBSD prefer $MACHINE (amd64 rather than x86_64) +.if ${_HOST_OSNAME:NNetBSD} == "" +_HOST_ARCH := ${_HOST_MACHINE} +.else +_HOST_ARCH != uname -p 2> /dev/null || uname -m # uname -p may produce garbage on linux -.if ${_HOST_ARCH:[\#]} > 1 -_HOST_ARCH != uname -m +.if ${_HOST_ARCH:[\#]} > 1 || ${_HOST_ARCH:Nunknown} == "" +_HOST_ARCH := ${_HOST_MACHINE} +.endif .endif .export _HOST_ARCH .endif .if !defined(HOST_MACHINE) -HOST_MACHINE != uname -m +HOST_MACHINE := ${_HOST_MACHINE} .export HOST_MACHINE .endif HOST_OSMAJOR := ${_HOST_OSREL:C/[^0-9].*//} -HOST_OSTYPE := ${_HOST_OSNAME}-${_HOST_OSREL:C/\([^\)]*\)//}-${_HOST_ARCH} +HOST_OSTYPE := ${_HOST_OSNAME:S,/,,g}-${_HOST_OSREL:C/\([^\)]*\)//}-${_HOST_ARCH} HOST_OS := ${_HOST_OSNAME} host_os := ${_HOST_OSNAME:tl} -HOST_TARGET := ${host_os}${HOST_OSMAJOR}-${_HOST_ARCH} +HOST_TARGET := ${host_os:S,/,,g}${HOST_OSMAJOR}-${_HOST_ARCH} # tr is insanely non-portable, accommodate the lowest common denominator TR ?= tr diff --git a/share/mk/meta.subdir.mk b/share/mk/meta.subdir.mk index 6a4db6379eb..966b6e0630f 100644 --- a/share/mk/meta.subdir.mk +++ b/share/mk/meta.subdir.mk @@ -1,5 +1,5 @@ # $FreeBSD$ -# $Id: meta.subdir.mk,v 1.10 2012/07/03 05:26:46 sjg Exp $ +# $Id: meta.subdir.mk,v 1.11 2015/11/24 22:26:51 sjg Exp $ # # @(#) Copyright (c) 2010, Simon J. Gerraty @@ -63,7 +63,7 @@ _subdeps != cd ${.CURDIR} && \ DIRDEPS = .else # clean up if needed -DIRDEPS := ${DIRDEPS:S,^./,,:S,/./,/,g:${SUBDIREPS_FILTER:Uu}} +DIRDEPS := ${DIRDEPS:S,^./,,:S,/./,/,g:${SUBDIRDEPS_FILTER:Uu}} .endif # we just dealt with it, if we leave it defined, # dirdeps.mk will compute some interesting combinations. diff --git a/sys/amd64/linux/linux.h b/sys/amd64/linux/linux.h index c4fe9aede7b..639499ab58d 100644 --- a/sys/amd64/linux/linux.h +++ b/sys/amd64/linux/linux.h @@ -530,8 +530,8 @@ struct l_pollfd { #define LINUX_ARCH_SET_GS 0x1001 #define LINUX_ARCH_SET_FS 0x1002 -#define LINUX_ARCH_GET_GS 0x1003 -#define LINUX_ARCH_GET_FS 0x1004 +#define LINUX_ARCH_GET_FS 0x1003 +#define LINUX_ARCH_GET_GS 0x1004 #define linux_copyout_rusage(r, u) copyout(r, u, sizeof(*r)) diff --git a/sys/amd64/linux/linux_machdep.c b/sys/amd64/linux/linux_machdep.c index 451e4b4bf25..376cce7932f 100644 --- a/sys/amd64/linux/linux_machdep.c +++ b/sys/amd64/linux/linux_machdep.c @@ -383,7 +383,6 @@ linux_sigaltstack(struct thread *td, struct linux_sigaltstack_args *uap) return (error); } -/* XXX do all */ int linux_arch_prctl(struct thread *td, struct linux_arch_prctl_args *args) { diff --git a/sys/arm/allwinner/a10_clk.c b/sys/arm/allwinner/a10_clk.c index 2f41d6f4479..eab95b0fe07 100644 --- a/sys/arm/allwinner/a10_clk.c +++ b/sys/arm/allwinner/a10_clk.c @@ -255,6 +255,57 @@ a10_clk_pll6_get_rate(void) return ((CCM_CLK_REF_FREQ * n * k) / 2); } +static int +a10_clk_pll2_set_rate(unsigned int freq) +{ + struct a10_ccm_softc *sc; + uint32_t reg_value; + unsigned int prediv, postdiv, n; + + sc = a10_ccm_sc; + if (sc == NULL) + return (ENXIO); + + reg_value = ccm_read_4(sc, CCM_PLL2_CFG); + reg_value &= ~(CCM_PLL2_CFG_PREDIV | CCM_PLL2_CFG_POSTDIV | + CCM_PLL_CFG_FACTOR_N); + + /* + * Audio Codec needs PLL2 to be either 24576000 Hz or 22579200 Hz + * + * PLL2 output frequency is 24MHz * n / prediv / postdiv. + * To get as close as possible to the desired rate, we use a + * pre-divider of 21 and a post-divider of 4. With these values, + * a multiplier of 86 or 79 gets us close to the target rates. + */ + prediv = 21; + postdiv = 4; + + switch (freq) { + case 24576000: + n = 86; + reg_value |= CCM_PLL_CFG_ENABLE; + break; + case 22579200: + n = 79; + reg_value |= CCM_PLL_CFG_ENABLE; + break; + case 0: + n = 1; + reg_value &= ~CCM_PLL_CFG_ENABLE; + break; + default: + return (EINVAL); + } + + reg_value |= (prediv << CCM_PLL2_CFG_PREDIV_SHIFT); + reg_value |= (postdiv << CCM_PLL2_CFG_POSTDIV_SHIFT); + reg_value |= (n << CCM_PLL_CFG_FACTOR_N_SHIFT); + ccm_write_4(sc, CCM_PLL2_CFG, reg_value); + + return (0); +} + int a10_clk_ahci_activate(void) { @@ -347,3 +398,46 @@ a10_clk_mmc_cfg(int devid, int freq) return (0); } + +int +a10_clk_dmac_activate(void) +{ + struct a10_ccm_softc *sc; + uint32_t reg_value; + + sc = a10_ccm_sc; + if (sc == NULL) + return (ENXIO); + + /* Gating AHB clock for DMA controller */ + reg_value = ccm_read_4(sc, CCM_AHB_GATING0); + reg_value |= CCM_AHB_GATING_DMA; + ccm_write_4(sc, CCM_AHB_GATING0, reg_value); + + return (0); +} + +int +a10_clk_codec_activate(unsigned int freq) +{ + struct a10_ccm_softc *sc; + uint32_t reg_value; + + sc = a10_ccm_sc; + if (sc == NULL) + return (ENXIO); + + a10_clk_pll2_set_rate(freq); + + /* Gating APB clock for ADDA */ + reg_value = ccm_read_4(sc, CCM_APB0_GATING); + reg_value |= CCM_APB0_GATING_ADDA; + ccm_write_4(sc, CCM_APB0_GATING, reg_value); + + /* Enable audio codec clock */ + reg_value = ccm_read_4(sc, CCM_AUDIO_CODEC_CLK); + reg_value |= CCM_AUDIO_CODEC_ENABLE; + ccm_write_4(sc, CCM_AUDIO_CODEC_CLK, reg_value); + + return (0); +} diff --git a/sys/arm/allwinner/a10_clk.h b/sys/arm/allwinner/a10_clk.h index e5aa8c27a2d..4df87cc21bf 100644 --- a/sys/arm/allwinner/a10_clk.h +++ b/sys/arm/allwinner/a10_clk.h @@ -106,10 +106,14 @@ #define CCM_GMAC_CLK_EXT_RGMII 0x1 #define CCM_GMAC_CLK_RGMII 0x2 +/* APB0_GATING */ +#define CCM_APB0_GATING_ADDA (1 << 0) + /* AHB_GATING_REG0 */ #define CCM_AHB_GATING_USB0 (1 << 0) #define CCM_AHB_GATING_EHCI0 (1 << 1) #define CCM_AHB_GATING_EHCI1 (1 << 3) +#define CCM_AHB_GATING_DMA (1 << 6) #define CCM_AHB_GATING_SDMMC0 (1 << 8) #define CCM_AHB_GATING_EMAC (1 << 17) #define CCM_AHB_GATING_SATA (1 << 25) @@ -132,6 +136,11 @@ #define CCM_PLL_CFG_FACTOR_K_SHIFT 4 #define CCM_PLL_CFG_FACTOR_M 0x3 +#define CCM_PLL2_CFG_POSTDIV 0x3c000000 +#define CCM_PLL2_CFG_POSTDIV_SHIFT 26 +#define CCM_PLL2_CFG_PREDIV 0x1f +#define CCM_PLL2_CFG_PREDIV_SHIFT 0 + #define CCM_PLL6_CFG_SATA_CLKEN (1U << 14) #define CCM_SD_CLK_SRC_SEL 0x3000000 @@ -146,6 +155,8 @@ #define CCM_SD_CLK_OPHASE_CTR_SHIFT 8 #define CCM_SD_CLK_DIV_RATIO_M 0xf +#define CCM_AUDIO_CODEC_ENABLE (1U << 31) + #define CCM_CLK_REF_FREQ 24000000U int a10_clk_usb_activate(void); @@ -155,5 +166,7 @@ int a10_clk_gmac_activate(phandle_t); int a10_clk_ahci_activate(void); int a10_clk_mmc_activate(int); int a10_clk_mmc_cfg(int, int); +int a10_clk_dmac_activate(void); +int a10_clk_codec_activate(unsigned int); #endif /* _A10_CLK_H_ */ diff --git a/sys/arm/allwinner/a10_common.c b/sys/arm/allwinner/a10_common.c index 3b5bf0efd0a..dacb97ede70 100644 --- a/sys/arm/allwinner/a10_common.c +++ b/sys/arm/allwinner/a10_common.c @@ -42,6 +42,8 @@ struct fdt_fixup_entry fdt_fixup_table[] = { { NULL, NULL } }; +#ifndef ARM_INTRNG + static int fdt_aintc_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig, int *pol) @@ -66,3 +68,5 @@ fdt_pic_decode_t fdt_pic_table[] = { &fdt_aintc_decode_ic, NULL }; + +#endif /* ARM_INTRNG */ diff --git a/sys/arm/allwinner/a10_machdep.c b/sys/arm/allwinner/allwinner_machdep.c similarity index 67% rename from sys/arm/allwinner/a10_machdep.c rename to sys/arm/allwinner/allwinner_machdep.c index 718ced77dba..5e8e842a2b1 100644 --- a/sys/arm/allwinner/a10_machdep.c +++ b/sys/arm/allwinner/allwinner_machdep.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2012 Ganbold Tsagaankhuu + * Copyright (c) 2015-2016 Emmanuel Vadot * All rights reserved. * * This code is derived from software written for Brini by Mark Brinicombe @@ -45,34 +46,43 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include +#include #include #include +#include -vm_offset_t -platform_lastaddr(void) +#include "platform_if.h" + +static u_int soc_type; +static u_int soc_family; + +static int +a10_attach(platform_t plat) +{ + soc_type = ALLWINNERSOC_A10; + soc_family = ALLWINNERSOC_SUN4I; + return (0); +} + +static int +a20_attach(platform_t plat) +{ + soc_type = ALLWINNERSOC_A20; + soc_family = ALLWINNERSOC_SUN7I; + + return (0); +} + + +static vm_offset_t +allwinner_lastaddr(platform_t plat) { return (arm_devmap_lastaddr()); } -void -platform_probe_and_attach(void) -{ -} - -void -platform_gpio_init(void) -{ -} - -void -platform_late_init(void) -{ -} - /* * Set up static device mappings. * @@ -83,8 +93,8 @@ platform_late_init(void) * shouldn't be device-mapped. The original code mapped a 4MB block, but * perhaps a 1MB block would be more appropriate. */ -int -platform_devmap_init(void) +static int +allwinner_devmap_init(platform_t plat) { arm_devmap_add_entry(0x01C00000, 0x00400000); /* 4MB */ @@ -111,3 +121,34 @@ cpu_reset() printf("Reset failed!\n"); while (1); } + +static platform_method_t a10_methods[] = { + PLATFORMMETHOD(platform_attach, a10_attach), + PLATFORMMETHOD(platform_lastaddr, allwinner_lastaddr), + PLATFORMMETHOD(platform_devmap_init, allwinner_devmap_init), + + PLATFORMMETHOD_END, +}; + +static platform_method_t a20_methods[] = { + PLATFORMMETHOD(platform_attach, a20_attach), + PLATFORMMETHOD(platform_lastaddr, allwinner_lastaddr), + PLATFORMMETHOD(platform_devmap_init, allwinner_devmap_init), + + PLATFORMMETHOD_END, +}; + +u_int +allwinner_soc_type(void) +{ + return (soc_type); +} + +u_int +allwinner_soc_family(void) +{ + return (soc_family); +} + +FDT_PLATFORM_DEF(a10, "a10", 0, "allwinner,sun4i-a10"); +FDT_PLATFORM_DEF(a20, "a20", 0, "allwinner,sun7i-a20"); diff --git a/sys/arm/allwinner/allwinner_machdep.h b/sys/arm/allwinner/allwinner_machdep.h new file mode 100644 index 00000000000..0edd090001b --- /dev/null +++ b/sys/arm/allwinner/allwinner_machdep.h @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2015 Emmanuel Vadot + * All rights reserved. + * + * This code is derived from software written for Brini by Mark Brinicombe + * + * 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 AW_MACHDEP_H +#define AW_MACHDEP_H + +#define ALLWINNERSOC_A10 0x10000000 +#define ALLWINNERSOC_A13 0x13000000 +#define ALLWINNERSOC_A10S 0x10000001 +#define ALLWINNERSOC_A20 0x20000000 + +#define ALLWINNERSOC_SUN4I 0x40000000 +#define ALLWINNERSOC_SUN5I 0x50000000 +#define ALLWINNERSOC_SUN7I 0x70000000 + +u_int allwinner_soc_type(void); +u_int allwinner_soc_family(void); + +#endif /* AW_MACHDEP_H */ diff --git a/sys/arm/allwinner/files.allwinner b/sys/arm/allwinner/files.allwinner index ea59bc27f8d..8606d914f4b 100644 --- a/sys/arm/allwinner/files.allwinner +++ b/sys/arm/allwinner/files.allwinner @@ -6,11 +6,11 @@ arm/allwinner/a10_clk.c standard arm/allwinner/a10_common.c standard arm/allwinner/a10_ehci.c optional ehci arm/allwinner/a10_gpio.c optional gpio -arm/allwinner/a10_machdep.c standard arm/allwinner/a10_mmc.c optional mmc arm/allwinner/a10_sramc.c standard arm/allwinner/a10_wdog.c standard arm/allwinner/a20/a20_cpu_cfg.c standard +arm/allwinner/allwinner_machdep.c standard arm/allwinner/if_emac.c optional emac arm/allwinner/timer.c standard #arm/allwinner/console.c standard diff --git a/sys/arm/arm/db_trace.c b/sys/arm/arm/db_trace.c index 96684f64223..846ad4e9915 100644 --- a/sys/arm/arm/db_trace.c +++ b/sys/arm/arm/db_trace.c @@ -28,6 +28,7 @@ * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ +#include "opt_ddb.h" #include __FBSDID("$FreeBSD$"); @@ -43,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -127,22 +129,25 @@ db_stack_trace_cmd(struct unwind_state *state) } } -/* XXX stubs */ void db_md_list_watchpoints() { + + dbg_show_watchpoint(); } int db_md_clr_watchpoint(db_expr_t addr, db_expr_t size) { - return (0); + + return (dbg_remove_watchpoint(addr, size)); } int db_md_set_watchpoint(db_expr_t addr, db_expr_t size) { - return (0); + + return (dbg_setup_watchpoint(addr, size, HW_WATCHPOINT_RW)); } int diff --git a/sys/arm/arm/debug_monitor.c b/sys/arm/arm/debug_monitor.c new file mode 100644 index 00000000000..7eba5959f8e --- /dev/null +++ b/sys/arm/arm/debug_monitor.c @@ -0,0 +1,943 @@ +/* + * Copyright (c) 2015 Juniper Networks Inc. + * All rights reserved. + * + * Developed by Semihalf. + * + * 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_ddb.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +enum dbg_t { + DBG_TYPE_BREAKPOINT = 0, + DBG_TYPE_WATCHPOINT = 1, +}; + +struct dbg_wb_conf { + enum dbg_t type; + enum dbg_access_t access; + db_addr_t address; + db_expr_t size; + u_int slot; +}; + +static int dbg_reset_state(void); +static int dbg_setup_breakpoint(db_expr_t, db_expr_t, u_int); +static int dbg_remove_breakpoint(u_int); +static u_int dbg_find_slot(enum dbg_t, db_expr_t); +static boolean_t dbg_check_slot_free(enum dbg_t, u_int); + +static int dbg_remove_xpoint(struct dbg_wb_conf *); +static int dbg_setup_xpoint(struct dbg_wb_conf *); + +static boolean_t dbg_capable; /* Indicates that machine is capable of using + HW watchpoints/breakpoints */ +static boolean_t dbg_ready[MAXCPU]; /* Debug arch. reset performed on this CPU */ + +static uint32_t dbg_model; /* Debug Arch. Model */ +static boolean_t dbg_ossr; /* OS Save and Restore implemented */ + +static uint32_t dbg_watchpoint_num; +static uint32_t dbg_breakpoint_num; + +static int dbg_ref_count_mme[MAXCPU]; /* Times monitor mode was enabled */ + +/* ID_DFR0 - Debug Feature Register 0 */ +#define ID_DFR0_CP_DEBUG_M_SHIFT 0 +#define ID_DFR0_CP_DEBUG_M_MASK (0xF << ID_DFR0_CP_DEBUG_M_SHIFT) +#define ID_DFR0_CP_DEBUG_M_NS (0x0) /* Not supported */ +#define ID_DFR0_CP_DEBUG_M_V6 (0x2) /* v6 Debug arch. CP14 access */ +#define ID_DFR0_CP_DEBUG_M_V6_1 (0x3) /* v6.1 Debug arch. CP14 access */ +#define ID_DFR0_CP_DEBUG_M_V7 (0x4) /* v7 Debug arch. CP14 access */ +#define ID_DFR0_CP_DEBUG_M_V7_1 (0x5) /* v7.1 Debug arch. CP14 access */ + +/* DBGDIDR - Debug ID Register */ +#define DBGDIDR_WRPS_SHIFT 28 +#define DBGDIDR_WRPS_MASK (0xF << DBGDIDR_WRPS_SHIFT) +#define DBGDIDR_WRPS_NUM(reg) \ + ((((reg) & DBGDIDR_WRPS_MASK) >> DBGDIDR_WRPS_SHIFT) + 1) + +#define DBGDIDR_BRPS_SHIFT 24 +#define DBGDIDR_BRPS_MASK (0xF << DBGDIDR_BRPS_SHIFT) +#define DBGDIDR_BRPS_NUM(reg) \ + ((((reg) & DBGDIDR_BRPS_MASK) >> DBGDIDR_BRPS_SHIFT) + 1) + +/* DBGPRSR - Device Powerdown and Reset Status Register */ +#define DBGPRSR_PU (1 << 0) /* Powerup status */ + +/* DBGOSLSR - OS Lock Status Register */ +#define DBGOSLSR_OSLM0 (1 << 0) + +/* DBGOSDLR - OS Double Lock Register */ +#define DBGPRSR_DLK (1 << 0) /* OS Double Lock set */ + +/* DBGDSCR - Debug Status and Control Register */ +#define DBGSCR_MDBG_EN (1 << 15) /* Monitor debug-mode enable */ + +/* DBGWVR - Watchpoint Value Register */ +#define DBGWVR_ADDR_MASK (~0x3U) + +/* Watchpoints/breakpoints control register bitfields */ +#define DBG_WB_CTRL_LEN_1 (0x1 << 5) +#define DBG_WB_CTRL_LEN_2 (0x3 << 5) +#define DBG_WB_CTRL_LEN_4 (0xf << 5) +#define DBG_WB_CTRL_LEN_8 (0xff << 5) +#define DBG_WB_CTRL_LEN_MASK(x) ((x) & (0xff << 5)) +#define DBG_WB_CTRL_EXEC (0x0 << 3) +#define DBG_WB_CTRL_LOAD (0x1 << 3) +#define DBG_WB_CTRL_STORE (0x2 << 3) +#define DBG_WB_CTRL_ACCESS_MASK(x) ((x) & (0x3 << 3)) + +/* Common for breakpoint and watchpoint */ +#define DBG_WB_CTRL_PL1 (0x1 << 1) +#define DBG_WB_CTRL_PL0 (0x2 << 1) +#define DBG_WB_CTRL_PLX_MASK(x) ((x) & (0x3 << 1)) +#define DBG_WB_CTRL_E (0x1 << 0) + +/* + * Watchpoint/breakpoint helpers + */ +#define DBG_BKPT_BT_SLOT 0 /* Slot for branch taken */ +#define DBG_BKPT_BNT_SLOT 1 /* Slot for branch not taken */ + +#define OP2_SHIFT 4 + +/* Opc2 numbers for coprocessor instructions */ +#define DBG_WB_BVR 4 +#define DBG_WB_BCR 5 +#define DBG_WB_WVR 6 +#define DBG_WB_WCR 7 + +#define DBG_REG_BASE_BVR (DBG_WB_BVR << OP2_SHIFT) +#define DBG_REG_BASE_BCR (DBG_WB_BCR << OP2_SHIFT) +#define DBG_REG_BASE_WVR (DBG_WB_WVR << OP2_SHIFT) +#define DBG_REG_BASE_WCR (DBG_WB_WCR << OP2_SHIFT) + +#define DBG_WB_READ(cn, cm, op2, val) do { \ + __asm __volatile("mrc p14, 0, %0, " #cn "," #cm "," #op2 : "=r" (val)); \ +} while (0) + +#define DBG_WB_WRITE(cn, cm, op2, val) do { \ + __asm __volatile("mcr p14, 0, %0, " #cn "," #cm "," #op2 :: "r" (val)); \ +} while (0) + +#define READ_WB_REG_CASE(op2, m, val) \ + case (((op2) << OP2_SHIFT) + m): \ + DBG_WB_READ(c0, c ## m, op2, val); \ + break + +#define WRITE_WB_REG_CASE(op2, m, val) \ + case (((op2) << OP2_SHIFT) + m): \ + DBG_WB_WRITE(c0, c ## m, op2, val); \ + break + +#define SWITCH_CASES_READ_WB_REG(op2, val) \ + READ_WB_REG_CASE(op2, 0, val); \ + READ_WB_REG_CASE(op2, 1, val); \ + READ_WB_REG_CASE(op2, 2, val); \ + READ_WB_REG_CASE(op2, 3, val); \ + READ_WB_REG_CASE(op2, 4, val); \ + READ_WB_REG_CASE(op2, 5, val); \ + READ_WB_REG_CASE(op2, 6, val); \ + READ_WB_REG_CASE(op2, 7, val); \ + READ_WB_REG_CASE(op2, 8, val); \ + READ_WB_REG_CASE(op2, 9, val); \ + READ_WB_REG_CASE(op2, 10, val); \ + READ_WB_REG_CASE(op2, 11, val); \ + READ_WB_REG_CASE(op2, 12, val); \ + READ_WB_REG_CASE(op2, 13, val); \ + READ_WB_REG_CASE(op2, 14, val); \ + READ_WB_REG_CASE(op2, 15, val) + +#define SWITCH_CASES_WRITE_WB_REG(op2, val) \ + WRITE_WB_REG_CASE(op2, 0, val); \ + WRITE_WB_REG_CASE(op2, 1, val); \ + WRITE_WB_REG_CASE(op2, 2, val); \ + WRITE_WB_REG_CASE(op2, 3, val); \ + WRITE_WB_REG_CASE(op2, 4, val); \ + WRITE_WB_REG_CASE(op2, 5, val); \ + WRITE_WB_REG_CASE(op2, 6, val); \ + WRITE_WB_REG_CASE(op2, 7, val); \ + WRITE_WB_REG_CASE(op2, 8, val); \ + WRITE_WB_REG_CASE(op2, 9, val); \ + WRITE_WB_REG_CASE(op2, 10, val); \ + WRITE_WB_REG_CASE(op2, 11, val); \ + WRITE_WB_REG_CASE(op2, 12, val); \ + WRITE_WB_REG_CASE(op2, 13, val); \ + WRITE_WB_REG_CASE(op2, 14, val); \ + WRITE_WB_REG_CASE(op2, 15, val) + +static uint32_t +dbg_wb_read_reg(int reg, int n) +{ + uint32_t val; + + val = 0; + + switch (reg + n) { + SWITCH_CASES_READ_WB_REG(DBG_WB_WVR, val); + SWITCH_CASES_READ_WB_REG(DBG_WB_WCR, val); + SWITCH_CASES_READ_WB_REG(DBG_WB_BVR, val); + SWITCH_CASES_READ_WB_REG(DBG_WB_BCR, val); + default: + db_printf( + "trying to read from CP14 reg. using wrong opc2 %d\n", + reg >> OP2_SHIFT); + } + + return (val); +} + +static void +dbg_wb_write_reg(int reg, int n, uint32_t val) +{ + + switch (reg + n) { + SWITCH_CASES_WRITE_WB_REG(DBG_WB_WVR, val); + SWITCH_CASES_WRITE_WB_REG(DBG_WB_WCR, val); + SWITCH_CASES_WRITE_WB_REG(DBG_WB_BVR, val); + SWITCH_CASES_WRITE_WB_REG(DBG_WB_BCR, val); + default: + db_printf( + "trying to write to CP14 reg. using wrong opc2 %d\n", + reg >> OP2_SHIFT); + } + isb(); +} + +boolean_t +kdb_cpu_pc_is_singlestep(db_addr_t pc) +{ + + if (dbg_find_slot(DBG_TYPE_BREAKPOINT, pc) != ~0U) + return (TRUE); + + return (FALSE); +} + +void +kdb_cpu_set_singlestep(void) +{ + db_expr_t inst; + db_addr_t pc, brpc; + uint32_t wcr; + u_int i; + + /* + * Disable watchpoints, e.g. stepping over watched instruction will + * trigger break exception instead of single-step exception and locks + * CPU on that instruction for ever. + */ + for (i = 0; i < dbg_watchpoint_num; i++) { + wcr = dbg_wb_read_reg(DBG_REG_BASE_WCR, i); + if ((wcr & DBG_WB_CTRL_E) != 0) { + dbg_wb_write_reg(DBG_REG_BASE_WCR, i, + (wcr & ~DBG_WB_CTRL_E)); + } + } + + pc = PC_REGS(); + + inst = db_get_value(pc, sizeof(pc), FALSE); + if (inst_branch(inst) || inst_call(inst) || inst_return(inst)) { + brpc = branch_taken(inst, pc); + dbg_setup_breakpoint(brpc, INSN_SIZE, DBG_BKPT_BT_SLOT); + } + pc = next_instr_address(pc, 0); + dbg_setup_breakpoint(pc, INSN_SIZE, DBG_BKPT_BNT_SLOT); +} + +void +kdb_cpu_clear_singlestep(void) +{ + uint32_t wvr, wcr; + u_int i; + + dbg_remove_breakpoint(DBG_BKPT_BT_SLOT); + dbg_remove_breakpoint(DBG_BKPT_BNT_SLOT); + + /* Restore all watchpoints */ + for (i = 0; i < dbg_watchpoint_num; i++) { + wcr = dbg_wb_read_reg(DBG_REG_BASE_WCR, i); + wvr = dbg_wb_read_reg(DBG_REG_BASE_WVR, i); + /* Watchpoint considered not empty if address value is not 0 */ + if ((wvr & DBGWVR_ADDR_MASK) != 0) { + dbg_wb_write_reg(DBG_REG_BASE_WCR, i, + (wcr | DBG_WB_CTRL_E)); + } + } +} + +int +dbg_setup_watchpoint(db_expr_t addr, db_expr_t size, enum dbg_access_t access) +{ + struct dbg_wb_conf conf; + + if (access == HW_BREAKPOINT_X) { + db_printf("Invalid access type for watchpoint: %d\n", access); + return (EINVAL); + } + + conf.address = addr; + conf.size = size; + conf.access = access; + conf.type = DBG_TYPE_WATCHPOINT; + + return (dbg_setup_xpoint(&conf)); +} + +int +dbg_remove_watchpoint(db_expr_t addr, db_expr_t size __unused) +{ + struct dbg_wb_conf conf; + + conf.address = addr; + conf.type = DBG_TYPE_WATCHPOINT; + + return (dbg_remove_xpoint(&conf)); +} + +static int +dbg_setup_breakpoint(db_expr_t addr, db_expr_t size, u_int slot) +{ + struct dbg_wb_conf conf; + + conf.address = addr; + conf.size = size; + conf.access = HW_BREAKPOINT_X; + conf.type = DBG_TYPE_BREAKPOINT; + conf.slot = slot; + + return (dbg_setup_xpoint(&conf)); +} + +static int +dbg_remove_breakpoint(u_int slot) +{ + struct dbg_wb_conf conf; + + /* Slot already cleared. Don't recurse */ + if (dbg_check_slot_free(DBG_TYPE_BREAKPOINT, slot)) + return (0); + + conf.slot = slot; + conf.type = DBG_TYPE_BREAKPOINT; + + return (dbg_remove_xpoint(&conf)); +} + +static const char * +dbg_watchtype_str(uint32_t type) +{ + + switch (type) { + case DBG_WB_CTRL_EXEC: + return ("execute"); + case DBG_WB_CTRL_STORE: + return ("write"); + case DBG_WB_CTRL_LOAD: + return ("read"); + case DBG_WB_CTRL_LOAD | DBG_WB_CTRL_STORE: + return ("read/write"); + default: + return ("invalid"); + } +} + +static int +dbg_watchtype_len(uint32_t len) +{ + + switch (len) { + case DBG_WB_CTRL_LEN_1: + return (1); + case DBG_WB_CTRL_LEN_2: + return (2); + case DBG_WB_CTRL_LEN_4: + return (4); + case DBG_WB_CTRL_LEN_8: + return (8); + default: + return (0); + } +} + +void +dbg_show_watchpoint(void) +{ + uint32_t wcr, len, type; + uint32_t addr; + boolean_t is_enabled; + int i; + + if (!dbg_capable) { + db_printf("Architecture does not support HW " + "breakpoints/watchpoints\n"); + return; + } + + db_printf("\nhardware watchpoints:\n"); + db_printf(" watch status type len address symbol\n"); + db_printf(" ----- -------- ---------- --- ---------- ------------------\n"); + for (i = 0; i < dbg_watchpoint_num; i++) { + wcr = dbg_wb_read_reg(DBG_REG_BASE_WCR, i); + if ((wcr & DBG_WB_CTRL_E) != 0) + is_enabled = TRUE; + else + is_enabled = FALSE; + + type = DBG_WB_CTRL_ACCESS_MASK(wcr); + len = DBG_WB_CTRL_LEN_MASK(wcr); + addr = dbg_wb_read_reg(DBG_REG_BASE_WVR, i) & DBGWVR_ADDR_MASK; + db_printf(" %-5d %-8s %10s %3d 0x%08x ", i, + is_enabled ? "enabled" : "disabled", + is_enabled ? dbg_watchtype_str(type) : "", + is_enabled ? dbg_watchtype_len(len) : 0, + addr); + db_printsym((db_addr_t)addr, DB_STGY_ANY); + db_printf("\n"); + } +} + +static boolean_t +dbg_check_slot_free(enum dbg_t type, u_int slot) +{ + uint32_t cr, vr; + uint32_t max; + + switch(type) { + case DBG_TYPE_BREAKPOINT: + max = dbg_breakpoint_num; + cr = DBG_REG_BASE_BCR; + vr = DBG_REG_BASE_BVR; + break; + case DBG_TYPE_WATCHPOINT: + max = dbg_watchpoint_num; + cr = DBG_REG_BASE_WCR; + vr = DBG_REG_BASE_WVR; + break; + default: + db_printf("%s: Unsupported event type %d\n", __func__, type); + return (FALSE); + } + + if (slot >= max) { + db_printf("%s: Invalid slot number %d, max %d\n", + __func__, slot, max - 1); + return (FALSE); + } + + if ((dbg_wb_read_reg(cr, slot) & DBG_WB_CTRL_E) == 0 && + (dbg_wb_read_reg(vr, slot) & DBGWVR_ADDR_MASK) == 0) + return (TRUE); + + return (FALSE); +} + +static u_int +dbg_find_free_slot(enum dbg_t type) +{ + u_int max, i; + + switch(type) { + case DBG_TYPE_BREAKPOINT: + max = dbg_breakpoint_num; + break; + case DBG_TYPE_WATCHPOINT: + max = dbg_watchpoint_num; + break; + default: + db_printf("Unsupported debug type\n"); + return (~0U); + } + + for (i = 0; i < max; i++) { + if (dbg_check_slot_free(type, i)) + return (i); + } + + return (~0U); +} + +static u_int +dbg_find_slot(enum dbg_t type, db_expr_t addr) +{ + uint32_t reg_addr, reg_ctrl; + u_int max, i; + + switch(type) { + case DBG_TYPE_BREAKPOINT: + max = dbg_breakpoint_num; + reg_addr = DBG_REG_BASE_BVR; + reg_ctrl = DBG_REG_BASE_BCR; + break; + case DBG_TYPE_WATCHPOINT: + max = dbg_watchpoint_num; + reg_addr = DBG_REG_BASE_WVR; + reg_ctrl = DBG_REG_BASE_WCR; + break; + default: + db_printf("Unsupported debug type\n"); + return (~0U); + } + + for (i = 0; i < max; i++) { + if ((dbg_wb_read_reg(reg_addr, i) == addr) && + ((dbg_wb_read_reg(reg_ctrl, i) & DBG_WB_CTRL_E) != 0)) + return (i); + } + + return (~0U); +} + +static __inline boolean_t +dbg_monitor_is_enabled(void) +{ + + return ((cp14_dbgdscrint_get() & DBGSCR_MDBG_EN) != 0); +} + +static int +dbg_enable_monitor(void) +{ + uint32_t dbg_dscr; + + /* Already enabled? Just increment reference counter and return */ + if (dbg_monitor_is_enabled()) { + dbg_ref_count_mme[PCPU_GET(cpuid)]++; + return (0); + } + + dbg_dscr = cp14_dbgdscrint_get(); + + switch (dbg_model) { + case ID_DFR0_CP_DEBUG_M_V6: + case ID_DFR0_CP_DEBUG_M_V6_1: /* fall through */ + cp14_dbgdscr_v6_set(dbg_dscr | DBGSCR_MDBG_EN); + break; + case ID_DFR0_CP_DEBUG_M_V7: /* fall through */ + case ID_DFR0_CP_DEBUG_M_V7_1: + cp14_dbgdscr_v7_set(dbg_dscr | DBGSCR_MDBG_EN); + break; + default: + break; + } + isb(); + + /* Verify that Monitor mode is set */ + if (dbg_monitor_is_enabled()) { + dbg_ref_count_mme[PCPU_GET(cpuid)]++; + return (0); + } + + return (ENXIO); +} + +static int +dbg_disable_monitor(void) +{ + uint32_t dbg_dscr; + + if (!dbg_monitor_is_enabled()) + return (0); + + if (--dbg_ref_count_mme[PCPU_GET(cpuid)] > 0) + return (0); + + dbg_dscr = cp14_dbgdscrint_get(); + switch (dbg_model) { + case ID_DFR0_CP_DEBUG_M_V6: + case ID_DFR0_CP_DEBUG_M_V6_1: /* fall through */ + dbg_dscr &= ~DBGSCR_MDBG_EN; + cp14_dbgdscr_v6_set(dbg_dscr); + break; + case ID_DFR0_CP_DEBUG_M_V7: /* fall through */ + case ID_DFR0_CP_DEBUG_M_V7_1: + dbg_dscr &= ~DBGSCR_MDBG_EN; + cp14_dbgdscr_v7_set(dbg_dscr); + break; + default: + return (ENXIO); + } + isb(); + + return (0); +} + +static int +dbg_setup_xpoint(struct dbg_wb_conf *conf) +{ + const char *typestr; + uint32_t cr_size, cr_priv, cr_access; + uint32_t reg_ctrl, reg_addr, ctrl, addr; + boolean_t is_bkpt; + u_int cpuid; + u_int i; + int err; + + if (!dbg_capable) + return (ENXIO); + + is_bkpt = (conf->type == DBG_TYPE_BREAKPOINT); + typestr = is_bkpt ? "breakpoint" : "watchpoint"; + + cpuid = PCPU_GET(cpuid); + if (!dbg_ready[cpuid]) { + err = dbg_reset_state(); + if (err != 0) + return (err); + dbg_ready[cpuid] = TRUE; + } + + if (is_bkpt) { + if (dbg_breakpoint_num == 0) { + db_printf("Breakpoints not supported on this architecture\n"); + return (ENXIO); + } + i = conf->slot; + if (!dbg_check_slot_free(DBG_TYPE_BREAKPOINT, i)) { + /* + * This should never happen. If it does it means that + * there is an erroneus scenario somewhere. Still, it can + * be done but let's inform the user. + */ + db_printf("ERROR: Breakpoint already set. Replacing...\n"); + } + } else { + i = dbg_find_free_slot(DBG_TYPE_WATCHPOINT); + if (i == ~0U) { + db_printf("Can not find slot for %s, max %d slots supported\n", + typestr, dbg_watchpoint_num); + return (ENXIO); + } + } + + /* Kernel access only */ + cr_priv = DBG_WB_CTRL_PL1; + + switch(conf->size) { + case 1: + cr_size = DBG_WB_CTRL_LEN_1; + break; + case 2: + cr_size = DBG_WB_CTRL_LEN_2; + break; + case 4: + cr_size = DBG_WB_CTRL_LEN_4; + break; + case 8: + cr_size = DBG_WB_CTRL_LEN_8; + break; + default: + db_printf("Unsupported address size for %s\n", typestr); + return (EINVAL); + } + + if (is_bkpt) { + cr_access = DBG_WB_CTRL_EXEC; + reg_ctrl = DBG_REG_BASE_BCR; + reg_addr = DBG_REG_BASE_BVR; + /* Always unlinked BKPT */ + ctrl = (cr_size | cr_access | cr_priv | DBG_WB_CTRL_E); + } else { + switch(conf->access) { + case HW_WATCHPOINT_R: + cr_access = DBG_WB_CTRL_LOAD; + break; + case HW_WATCHPOINT_W: + cr_access = DBG_WB_CTRL_STORE; + break; + case HW_WATCHPOINT_RW: + cr_access = DBG_WB_CTRL_LOAD | DBG_WB_CTRL_STORE; + break; + default: + db_printf("Unsupported exception level for %s\n", typestr); + return (EINVAL); + } + + reg_ctrl = DBG_REG_BASE_WCR; + reg_addr = DBG_REG_BASE_WVR; + ctrl = (cr_size | cr_access | cr_priv | DBG_WB_CTRL_E); + } + + addr = conf->address; + + dbg_wb_write_reg(reg_addr, i, addr); + dbg_wb_write_reg(reg_ctrl, i, ctrl); + + return (dbg_enable_monitor()); +} + +static int +dbg_remove_xpoint(struct dbg_wb_conf *conf) +{ + uint32_t reg_ctrl, reg_addr, addr; + u_int cpuid; + u_int i; + int err; + + if (!dbg_capable) + return (ENXIO); + + cpuid = PCPU_GET(cpuid); + if (!dbg_ready[cpuid]) { + err = dbg_reset_state(); + if (err != 0) + return (err); + dbg_ready[cpuid] = TRUE; + } + + addr = conf->address; + + if (conf->type == DBG_TYPE_BREAKPOINT) { + i = conf->slot; + reg_ctrl = DBG_REG_BASE_BCR; + reg_addr = DBG_REG_BASE_BVR; + } else { + i = dbg_find_slot(DBG_TYPE_WATCHPOINT, addr); + if (i == ~0U) { + db_printf("Can not find watchpoint for address 0%x\n", addr); + return (EINVAL); + } + reg_ctrl = DBG_REG_BASE_WCR; + reg_addr = DBG_REG_BASE_WVR; + } + + dbg_wb_write_reg(reg_ctrl, i, 0); + dbg_wb_write_reg(reg_addr, i, 0); + + return (dbg_disable_monitor()); +} + +static __inline uint32_t +dbg_get_debug_model(void) +{ + uint32_t dbg_m; + + dbg_m = ((cpuinfo.id_dfr0 & ID_DFR0_CP_DEBUG_M_MASK) >> + ID_DFR0_CP_DEBUG_M_SHIFT); + + return (dbg_m); +} + +static __inline boolean_t +dbg_get_ossr(void) +{ + + switch (dbg_model) { + case ID_DFR0_CP_DEBUG_M_V6_1: + if ((cp14_dbgoslsr_get() & DBGOSLSR_OSLM0) != 0) + return (TRUE); + + return (FALSE); + case ID_DFR0_CP_DEBUG_M_V7_1: + return (TRUE); + default: + return (FALSE); + } +} + +static __inline boolean_t +dbg_arch_supported(void) +{ + + switch (dbg_model) { + case ID_DFR0_CP_DEBUG_M_V6: + case ID_DFR0_CP_DEBUG_M_V6_1: + case ID_DFR0_CP_DEBUG_M_V7: + case ID_DFR0_CP_DEBUG_M_V7_1: /* fall through */ + return (TRUE); + default: + /* We only support valid v6.x/v7.x modes through CP14 */ + return (FALSE); + } +} + +static __inline uint32_t +dbg_get_wrp_num(void) +{ + uint32_t dbg_didr; + + dbg_didr = cp14_dbgdidr_get(); + + return (DBGDIDR_WRPS_NUM(dbg_didr)); +} + +static __inline uint32_t +dgb_get_brp_num(void) +{ + uint32_t dbg_didr; + + dbg_didr = cp14_dbgdidr_get(); + + return (DBGDIDR_BRPS_NUM(dbg_didr)); +} + +static int +dbg_reset_state(void) +{ + u_int cpuid; + size_t i; + int err; + + cpuid = PCPU_GET(cpuid); + err = 0; + + switch (dbg_model) { + case ID_DFR0_CP_DEBUG_M_V6: + /* v6 Debug logic reset upon power-up */ + return (0); + case ID_DFR0_CP_DEBUG_M_V6_1: + /* Is core power domain powered up? */ + if ((cp14_dbgprsr_get() & DBGPRSR_PU) == 0) + err = ENXIO; + + if (err != 0) + break; + + if (dbg_ossr) + goto vectr_clr; + break; + case ID_DFR0_CP_DEBUG_M_V7: + break; + case ID_DFR0_CP_DEBUG_M_V7_1: + /* Is double lock set? */ + if ((cp14_dbgosdlr_get() & DBGPRSR_DLK) != 0) + err = ENXIO; + + break; + default: + break; + } + + if (err != 0) { + db_printf("Debug facility locked (CPU%d)\n", cpuid); + return (err); + } + + /* + * DBGOSLAR is always implemented for v7.1 Debug Arch. however is + * optional for v7 (depends on OS save and restore support). + */ + if (((dbg_model & ID_DFR0_CP_DEBUG_M_V7_1) != 0) || dbg_ossr) { + /* + * Clear OS lock. + * Writing any other value than 0xC5ACCESS will unlock. + */ + cp14_dbgoslar_set(0); + isb(); + } + +vectr_clr: + /* + * After reset we must ensure that DBGVCR has a defined value. + * Disable all vector catch events. Safe to use - required in all + * implementations. + */ + cp14_dbgvcr_set(0); + isb(); + + /* + * We have limited number of {watch,break}points, each consists of + * two registers: + * - wcr/bcr regsiter configurates corresponding {watch,break}point + * behaviour + * - wvr/bvr register keeps address we are hunting for + * + * Reset all breakpoints and watchpoints. + */ + for (i = 0; i < dbg_watchpoint_num; ++i) { + dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 0); + dbg_wb_write_reg(DBG_REG_BASE_WVR, i, 0); + } + + for (i = 0; i < dbg_breakpoint_num; ++i) { + dbg_wb_write_reg(DBG_REG_BASE_BCR, i, 0); + dbg_wb_write_reg(DBG_REG_BASE_BVR, i, 0); + } + + return (0); +} + +void +dbg_monitor_init(void) +{ + int err; + + /* Fetch ARM Debug Architecture model */ + dbg_model = dbg_get_debug_model(); + + if (!dbg_arch_supported()) { + db_printf("ARM Debug Architecture not supported\n"); + return; + } + + if (bootverbose) { + db_printf("ARM Debug Architecture %s\n", + (dbg_model == ID_DFR0_CP_DEBUG_M_V6) ? "v6" : + (dbg_model == ID_DFR0_CP_DEBUG_M_V6_1) ? "v6.1" : + (dbg_model == ID_DFR0_CP_DEBUG_M_V7) ? "v7" : + (dbg_model == ID_DFR0_CP_DEBUG_M_V7_1) ? "v7.1" : "unknown"); + } + + /* Do we have OS Save and Restore mechanism? */ + dbg_ossr = dbg_get_ossr(); + + /* Find out many breakpoints and watchpoints we can use */ + dbg_watchpoint_num = dbg_get_wrp_num(); + dbg_breakpoint_num = dgb_get_brp_num(); + + if (bootverbose) { + db_printf("%d watchpoints and %d breakpoints supported\n", + dbg_watchpoint_num, dbg_breakpoint_num); + } + + err = dbg_reset_state(); + if (err == 0) { + dbg_capable = TRUE; + return; + } + + db_printf("HW Breakpoints/Watchpoints not enabled on CPU%d\n", + PCPU_GET(cpuid)); +} diff --git a/sys/arm/arm/elf_machdep.c b/sys/arm/arm/elf_machdep.c index 84b87f7822f..7dbdc912c82 100644 --- a/sys/arm/arm/elf_machdep.c +++ b/sys/arm/arm/elf_machdep.c @@ -256,7 +256,7 @@ elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data, } int -elf_cpu_load_file(linker_file_t lf __unused) +elf_cpu_load_file(linker_file_t lf) { /* @@ -265,13 +265,25 @@ elf_cpu_load_file(linker_file_t lf __unused) * that kernel memory allocations always have EXECUTABLE protection even * when the memory isn't going to hold executable code. The only time * kernel memory holding instructions does need a sync is after loading - * a kernel module, and that's when this function gets called. Normal - * data cache maintenance has already been done by the IO code, and TLB - * maintenance has been done by the pmap code, so all we have to do here - * is invalidate the instruction cache (which also invalidates the - * branch predictor cache on platforms that have one). + * a kernel module, and that's when this function gets called. + * + * This syncs data and instruction caches after loading a module. We + * don't worry about the kernel itself (lf->id is 1) as locore.S did + * that on entry. Even if data cache maintenance was done by IO code, + * the relocation fixup process creates dirty cache entries that we must + * write back before doing icache sync. The instruction cache sync also + * invalidates the branch predictor cache on platforms that have one. */ + if (lf->id == 1) + return (0); +#if __ARM_ARCH >= 6 + dcache_wb_pou((vm_offset_t)lf->address, (vm_size_t)lf->size); + icache_inv_all(); +#else + cpu_dcache_wb_range((vm_offset_t)lf->address, (vm_size_t)lf->size); + cpu_l2cache_wb_range((vm_offset_t)lf->address, (vm_size_t)lf->size); cpu_icache_sync_all(); +#endif return (0); } diff --git a/sys/arm/arm/machdep.c b/sys/arm/arm/machdep.c index b8e3ffd9c76..d1f8592d67d 100644 --- a/sys/arm/arm/machdep.c +++ b/sys/arm/arm/machdep.c @@ -96,6 +96,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -1710,6 +1711,7 @@ initarm(struct arm_boot_params *abp) arm_physmem_init_kernel_globals(); init_param2(physmem); + dbg_monitor_init(); kdb_init(); return ((void *)(kernelstack.pv_va + USPACE_SVC_STACK_TOP - @@ -1897,6 +1899,7 @@ initarm(struct arm_boot_params *abp) init_param2(physmem); /* Init message buffer. */ msgbufinit(msgbufp, msgbufsize); + dbg_monitor_init(); kdb_init(); return ((void *)STACKALIGN(thread0.td_pcb)); diff --git a/sys/arm/arm/minidump_machdep.c b/sys/arm/arm/minidump_machdep.c index 7a4abe46742..a351fb76095 100644 --- a/sys/arm/arm/minidump_machdep.c +++ b/sys/arm/arm/minidump_machdep.c @@ -1,4 +1,5 @@ /*- + * Copyright (c) 2006 Peter Wemm * Copyright (c) 2008 Semihalf, Grzegorz Bernacki * All rights reserved. * @@ -61,14 +62,12 @@ CTASSERT(sizeof(struct kerneldumpheader) == 512); uint32_t *vm_page_dump; int vm_page_dump_size; -#ifndef ARM_NEW_PMAP - static struct kerneldumpheader kdh; static off_t dumplo; /* Handle chunked writes. */ -static size_t fragsz, offset; +static size_t fragsz; static void *dump_va; static uint64_t counter, progress; @@ -96,10 +95,9 @@ blk_flush(struct dumperinfo *di) if (fragsz == 0) return (0); - error = dump_write(di, (char*)dump_va + offset, 0, dumplo, fragsz - offset); - dumplo += (fragsz - offset); + error = dump_write(di, dump_va, 0, dumplo, fragsz); + dumplo += fragsz; fragsz = 0; - offset = 0; return (error); } @@ -110,36 +108,36 @@ blk_write(struct dumperinfo *di, char *ptr, vm_paddr_t pa, size_t sz) int error, i, c; u_int maxdumpsz; - maxdumpsz = di->maxiosize; - + maxdumpsz = min(di->maxiosize, MAXDUMPPGS * PAGE_SIZE); if (maxdumpsz == 0) /* seatbelt */ maxdumpsz = PAGE_SIZE; - error = 0; - if (ptr != NULL && pa != 0) { printf("cant have both va and pa!\n"); return (EINVAL); } - + if (pa != 0) { + if ((sz % PAGE_SIZE) != 0) { + printf("size not page aligned\n"); + return (EINVAL); + } + if ((pa & PAGE_MASK) != 0) { + printf("address not page aligned\n"); + return (EINVAL); + } + } if (ptr != NULL) { - /* If we're doing a virtual dump, flush any pre-existing pa pages */ + /* Flush any pre-existing pa pages before a virtual dump. */ error = blk_flush(di); if (error) return (error); } - while (sz) { - if (fragsz == 0) { - offset = pa & PAGE_MASK; - fragsz += offset; - } len = maxdumpsz - fragsz; if (len > sz) len = sz; counter += len; progress -= len; - if (counter >> 22) { printf(" %lld", PG2MB(progress >> PAGE_SHIFT)); counter &= (1<<22) - 1; @@ -180,24 +178,9 @@ blk_write(struct dumperinfo *di, char *ptr, vm_paddr_t pa, size_t sz) return (0); } -static int -blk_write_cont(struct dumperinfo *di, vm_paddr_t pa, size_t sz) -{ - int error; - - error = blk_write(di, 0, pa, sz); - if (error) - return (error); - - error = blk_flush(di); - if (error) - return (error); - - return (0); -} - -/* A fake page table page, to avoid having to handle both 4K and 2M pages */ -static pt_entry_t fakept[NPTEPG]; +/* A buffer for general use. Its size must be one page at least. */ +static char dumpbuf[PAGE_SIZE]; +CTASSERT(sizeof(dumpbuf) % sizeof(pt2_entry_t) == 0); int minidumpsys(struct dumperinfo *di) @@ -208,9 +191,7 @@ minidumpsys(struct dumperinfo *di) uint32_t bits; uint32_t pa, prev_pa = 0, count = 0; vm_offset_t va; - pd_entry_t *pdp; - pt_entry_t *pt, *ptp; - int i, k, bit, error; + int i, bit, error; char *addr; /* @@ -228,48 +209,11 @@ minidumpsys(struct dumperinfo *di) counter = 0; /* Walk page table pages, set bits in vm_page_dump */ ptesize = 0; - for (va = KERNBASE; va < kernel_vm_end; va += NBPDR) { - /* - * We always write a page, even if it is zero. Each - * page written corresponds to 2MB of space - */ - ptesize += L2_TABLE_SIZE_REAL; - pmap_get_pde_pte(pmap_kernel(), va, &pdp, &ptp); - if (pmap_pde_v(pdp) && pmap_pde_section(pdp)) { - /* This is a section mapping 1M page. */ - pa = (*pdp & L1_S_ADDR_MASK) | (va & ~L1_S_ADDR_MASK); - for (k = 0; k < (L1_S_SIZE / PAGE_SIZE); k++) { - if (is_dumpable(pa)) - dump_add_page(pa); - pa += PAGE_SIZE; - } - continue; - } - if (pmap_pde_v(pdp) && pmap_pde_page(pdp)) { - /* Set bit for each valid page in this 1MB block */ - addr = pmap_kenter_temporary(*pdp & L1_C_ADDR_MASK, 0); - pt = (pt_entry_t*)(addr + - (((uint32_t)*pdp & L1_C_ADDR_MASK) & PAGE_MASK)); - for (k = 0; k < 256; k++) { - if ((pt[k] & L2_TYPE_MASK) == L2_TYPE_L) { - pa = (pt[k] & L2_L_FRAME) | - (va & L2_L_OFFSET); - for (i = 0; i < 16; i++) { - if (is_dumpable(pa)) - dump_add_page(pa); - k++; - pa += PAGE_SIZE; - } - } else if ((pt[k] & L2_TYPE_MASK) == L2_TYPE_S) { - pa = (pt[k] & L2_S_FRAME) | - (va & L2_S_OFFSET); - if (is_dumpable(pa)) - dump_add_page(pa); - } - } - } else { - /* Nothing, we're going to dump a null page */ - } + for (va = KERNBASE; va < kernel_vm_end; va += PAGE_SIZE) { + pa = pmap_dump_kextract(va, NULL); + if (pa != 0 && is_dumpable(pa)) + dump_add_page(pa); + ptesize += sizeof(pt2_entry_t); } /* Calculate dump size. */ @@ -331,14 +275,15 @@ minidumpsys(struct dumperinfo *di) dumplo += sizeof(kdh); /* Dump my header */ - bzero(&fakept, sizeof(fakept)); - bcopy(&mdhdr, &fakept, sizeof(mdhdr)); - error = blk_write(di, (char *)&fakept, 0, PAGE_SIZE); + bzero(dumpbuf, sizeof(dumpbuf)); + bcopy(&mdhdr, dumpbuf, sizeof(mdhdr)); + error = blk_write(di, dumpbuf, 0, PAGE_SIZE); if (error) goto fail; /* Dump msgbuf up front */ - error = blk_write(di, (char *)msgbufp->msg_ptr, 0, round_page(msgbufp->msg_size)); + error = blk_write(di, (char *)msgbufp->msg_ptr, 0, + round_page(msgbufp->msg_size)); if (error) goto fail; @@ -349,81 +294,21 @@ minidumpsys(struct dumperinfo *di) goto fail; /* Dump kernel page table pages */ - for (va = KERNBASE; va < kernel_vm_end; va += NBPDR) { - /* We always write a page, even if it is zero */ - pmap_get_pde_pte(pmap_kernel(), va, &pdp, &ptp); - - if (pmap_pde_v(pdp) && pmap_pde_section(pdp)) { - if (count) { - error = blk_write_cont(di, prev_pa, - count * L2_TABLE_SIZE_REAL); - if (error) - goto fail; - count = 0; - prev_pa = 0; - } - /* This is a single 2M block. Generate a fake PTP */ - pa = (*pdp & L1_S_ADDR_MASK) | (va & ~L1_S_ADDR_MASK); - for (k = 0; k < (L1_S_SIZE / PAGE_SIZE); k++) { - fakept[k] = L2_S_PROTO | (pa + (k * PAGE_SIZE)) | - L2_S_PROT(PTE_KERNEL, - VM_PROT_READ | VM_PROT_WRITE); - } - error = blk_write(di, (char *)&fakept, 0, - L2_TABLE_SIZE_REAL); - if (error) - goto fail; - /* Flush, in case we reuse fakept in the same block */ - error = blk_flush(di); - if (error) - goto fail; - continue; - } - if (pmap_pde_v(pdp) && pmap_pde_page(pdp)) { - pa = *pdp & L1_C_ADDR_MASK; - if (!count) { - prev_pa = pa; - count++; - } - else { - if (pa == (prev_pa + count * L2_TABLE_SIZE_REAL)) - count++; - else { - error = blk_write_cont(di, prev_pa, - count * L2_TABLE_SIZE_REAL); - if (error) - goto fail; - count = 1; - prev_pa = pa; - } - } - } else { - if (count) { - error = blk_write_cont(di, prev_pa, - count * L2_TABLE_SIZE_REAL); - if (error) - goto fail; - count = 0; - prev_pa = 0; - } - bzero(fakept, sizeof(fakept)); - error = blk_write(di, (char *)&fakept, 0, - L2_TABLE_SIZE_REAL); - if (error) - goto fail; - /* Flush, in case we reuse fakept in the same block */ - error = blk_flush(di); - if (error) + addr = dumpbuf; + for (va = KERNBASE; va < kernel_vm_end; va += PAGE_SIZE) { + pmap_dump_kextract(va, (pt2_entry_t *)addr); + addr += sizeof(pt2_entry_t); + if (addr == dumpbuf + sizeof(dumpbuf)) { + error = blk_write(di, dumpbuf, 0, sizeof(dumpbuf)); + if (error != 0) goto fail; + addr = dumpbuf; } } - - if (count) { - error = blk_write_cont(di, prev_pa, count * L2_TABLE_SIZE_REAL); - if (error) + if (addr != dumpbuf) { + error = blk_write(di, dumpbuf, 0, addr - dumpbuf); + if (error != 0) goto fail; - count = 0; - prev_pa = 0; } /* Dump memory chunks */ @@ -440,7 +325,7 @@ minidumpsys(struct dumperinfo *di) if (pa == (prev_pa + count * PAGE_SIZE)) count++; else { - error = blk_write_cont(di, prev_pa, + error = blk_write(di, NULL, prev_pa, count * PAGE_SIZE); if (error) goto fail; @@ -452,13 +337,17 @@ minidumpsys(struct dumperinfo *di) } } if (count) { - error = blk_write_cont(di, prev_pa, count * PAGE_SIZE); + error = blk_write(di, NULL, prev_pa, count * PAGE_SIZE); if (error) goto fail; count = 0; prev_pa = 0; } + error = blk_flush(di); + if (error) + goto fail; + /* Dump trailer */ error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh)); if (error) @@ -484,17 +373,6 @@ fail: return (0); } -#else /* ARM_NEW_PMAP */ - -int -minidumpsys(struct dumperinfo *di) -{ - - return (0); -} - -#endif - void dump_add_page(vm_paddr_t pa) { diff --git a/sys/arm/arm/physmem.c b/sys/arm/arm/physmem.c index 999d38c283c..d023905dacb 100644 --- a/sys/arm/arm/physmem.c +++ b/sys/arm/arm/physmem.c @@ -49,6 +49,8 @@ __FBSDID("$FreeBSD$"); #define MAX_HWCNT 10 #define MAX_EXCNT 10 +#define MAX_PHYS_ADDR 0xFFFFFFFFull + struct region { vm_paddr_t addr; vm_size_t size; @@ -273,14 +275,25 @@ insert_region(struct region *regions, size_t rcnt, vm_paddr_t addr, * Add a hardware memory region. */ void -arm_physmem_hardware_region(vm_paddr_t pa, vm_size_t sz) +arm_physmem_hardware_region(uint64_t pa, uint64_t sz) { vm_offset_t adj; /* * Filter out the page at PA 0x00000000. The VM can't handle it, as * pmap_extract() == 0 means failure. - * + */ + if (pa == 0) { + if (sz <= PAGE_SIZE) + return; + pa = PAGE_SIZE; + sz -= PAGE_SIZE; + } else if (pa > MAX_PHYS_ADDR) { + /* This range is past usable memory, ignore it */ + return; + } + + /* * Also filter out the page at the end of the physical address space -- * if addr is non-zero and addr+size is zero we wrapped to the next byte * beyond what vm_paddr_t can express. That leads to a NULL pointer @@ -291,12 +304,8 @@ arm_physmem_hardware_region(vm_paddr_t pa, vm_size_t sz) * pointer deref in _vm_map_lock_read(). Better to give up a megabyte * than leave some folks with an unusable system while we investigate. */ - if (pa == 0) { - if (sz <= PAGE_SIZE) - return; - pa = PAGE_SIZE; - sz -= PAGE_SIZE; - } else if (pa + sz == 0) { + if ((pa + sz) > (MAX_PHYS_ADDR - 1024 * 1024)) { + sz = MAX_PHYS_ADDR - pa + 1; if (sz <= 1024 * 1024) return; sz -= 1024 * 1024; diff --git a/sys/arm/arm/pmap-v6-new.c b/sys/arm/arm/pmap-v6-new.c index 9a756cfd94a..5c56f6c46ab 100644 --- a/sys/arm/arm/pmap-v6-new.c +++ b/sys/arm/arm/pmap-v6-new.c @@ -1049,6 +1049,36 @@ pmap_kextract(vm_offset_t va) return (pa); } +/* + * Extract from the kernel page table the physical address + * that is mapped by the given virtual address "va". Also + * return L2 page table entry which maps the address. + * + * This is only intended to be used for panic dumps. + */ +vm_paddr_t +pmap_dump_kextract(vm_offset_t va, pt2_entry_t *pte2p) +{ + vm_paddr_t pa; + pt1_entry_t pte1; + pt2_entry_t pte2; + + pte1 = pte1_load(kern_pte1(va)); + if (pte1_is_section(pte1)) { + pa = pte1_pa(pte1) | (va & PTE1_OFFSET); + pte2 = pa | ATTR_TO_L2(pte1) | PTE2_V; + } else if (pte1_is_link(pte1)) { + pte2 = pte2_load(pt2map_entry(va)); + pa = pte2_pa(pte2); + } else { + pte2 = 0; + pa = 0; + } + if (pte2p != NULL) + *pte2p = pte2; + return (pa); +} + /***************************************************************************** * * PMAP second stage initialization and utility functions diff --git a/sys/arm/arm/pmap-v6.c b/sys/arm/arm/pmap-v6.c index 4dbd9c46169..26a075db63d 100644 --- a/sys/arm/arm/pmap-v6.c +++ b/sys/arm/arm/pmap-v6.c @@ -3536,6 +3536,52 @@ retry: return (m); } +vm_paddr_t +pmap_dump_kextract(vm_offset_t va, pt2_entry_t *pte2p) +{ + struct l2_dtable *l2; + pd_entry_t l1pd; + pt_entry_t *ptep, pte; + vm_paddr_t pa; + u_int l1idx; + + l1idx = L1_IDX(va); + l1pd = kernel_pmap->pm_l1->l1_kva[l1idx]; + if (l1pte_section_p(l1pd)) { + if (l1pd & L1_S_SUPERSEC) + pa = (l1pd & L1_SUP_FRAME) | (va & L1_SUP_OFFSET); + else + pa = (l1pd & L1_S_FRAME) | (va & L1_S_OFFSET); + pte = L2_S_PROTO | pa | + L2_S_PROT(PTE_KERNEL, VM_PROT_READ | VM_PROT_WRITE); + } else { + l2 = kernel_pmap->pm_l2[L2_IDX(l1idx)]; + if (l2 == NULL || + (ptep = l2->l2_bucket[L2_BUCKET(l1idx)].l2b_kva) == NULL) { + pte = 0; + pa = 0; + goto out; + } + pte = ptep[l2pte_index(va)]; + if (pte == 0) { + pa = 0; + goto out; + } + switch (pte & L2_TYPE_MASK) { + case L2_TYPE_L: + pa = (pte & L2_L_FRAME) | (va & L2_L_OFFSET); + break; + default: + pa = (pte & L2_S_FRAME) | (va & L2_S_OFFSET); + break; + } + } +out: + if (pte2p != NULL) + *pte2p = pte; + return (pa); +} + /* * Initialize a preallocated and zeroed pmap structure, * such as one in a vmspace structure. diff --git a/sys/arm/arm/pmap.c b/sys/arm/arm/pmap.c index daaa0ee906e..e698f0e0885 100644 --- a/sys/arm/arm/pmap.c +++ b/sys/arm/arm/pmap.c @@ -3738,6 +3738,52 @@ retry: return (m); } +vm_paddr_t +pmap_dump_kextract(vm_offset_t va, pt2_entry_t *pte2p) +{ + struct l2_dtable *l2; + pd_entry_t l1pd; + pt_entry_t *ptep, pte; + vm_paddr_t pa; + u_int l1idx; + + l1idx = L1_IDX(va); + l1pd = kernel_pmap->pm_l1->l1_kva[l1idx]; + if (l1pte_section_p(l1pd)) { + if (l1pd & L1_S_SUPERSEC) + pa = (l1pd & L1_SUP_FRAME) | (va & L1_SUP_OFFSET); + else + pa = (l1pd & L1_S_FRAME) | (va & L1_S_OFFSET); + pte = L2_S_PROTO | pa | + L2_S_PROT(PTE_KERNEL, VM_PROT_READ | VM_PROT_WRITE); + } else { + l2 = kernel_pmap->pm_l2[L2_IDX(l1idx)]; + if (l2 == NULL || + (ptep = l2->l2_bucket[L2_BUCKET(l1idx)].l2b_kva) == NULL) { + pte = 0; + pa = 0; + goto out; + } + pte = ptep[l2pte_index(va)]; + if (pte == 0) { + pa = 0; + goto out; + } + switch (pte & L2_TYPE_MASK) { + case L2_TYPE_L: + pa = (pte & L2_L_FRAME) | (va & L2_L_OFFSET); + break; + default: + pa = (pte & L2_S_FRAME) | (va & L2_S_OFFSET); + break; + } + } +out: + if (pte2p != NULL) + *pte2p = pte; + return (pa); +} + /* * Initialize a preallocated and zeroed pmap structure, * such as one in a vmspace structure. diff --git a/sys/arm/arm/trap-v6.c b/sys/arm/arm/trap-v6.c index ea8ec0dbd5d..80cf793e731 100644 --- a/sys/arm/arm/trap-v6.c +++ b/sys/arm/arm/trap-v6.c @@ -259,7 +259,7 @@ abort_debug(struct trapframe *tf, u_int fsr, u_int prefetch, bool usermode, userret(td, tf); } else { #ifdef KDB - kdb_trap(T_BREAKPOINT, 0, tf); + kdb_trap((prefetch) ? T_BREAKPOINT : T_WATCHPOINT, 0, tf); #else printf("No debugger in kernel.\n"); #endif diff --git a/sys/arm/conf/A20 b/sys/arm/conf/A20 index 21ecd85d380..353c5ece820 100644 --- a/sys/arm/conf/A20 +++ b/sys/arm/conf/A20 @@ -23,9 +23,12 @@ ident A20 include "std.armv6" include "../allwinner/a20/std.a20" +options ARM_INTRNG + options HZ=100 options SCHED_ULE # ULE scheduler options SMP # Enable multiple cores +options PLATFORM # Debugging for use in -current makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols diff --git a/sys/arm/conf/CUBIEBOARD b/sys/arm/conf/CUBIEBOARD index 8102306d101..787c1775083 100644 --- a/sys/arm/conf/CUBIEBOARD +++ b/sys/arm/conf/CUBIEBOARD @@ -26,6 +26,7 @@ include "../allwinner/std.a10" options HZ=100 options SCHED_4BSD # 4BSD scheduler +options PLATFORM # Debugging for use in -current makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols diff --git a/sys/arm/include/cpu-v6.h b/sys/arm/include/cpu-v6.h index e7bf62de023..bb8649ab30b 100644 --- a/sys/arm/include/cpu-v6.h +++ b/sys/arm/include/cpu-v6.h @@ -138,6 +138,18 @@ _WF1(_CP15_ICIMVAU, CP15_ICIMVAU(%0)) /* Instruction cache invalidate */ * Publicly accessible functions */ +/* CP14 Debug Registers */ +_RF0(cp14_dbgdidr_get, CP14_DBGDIDR(%0)) +_RF0(cp14_dbgprsr_get, CP14_DBGPRSR(%0)) +_RF0(cp14_dbgoslsr_get, CP14_DBGOSLSR(%0)) +_RF0(cp14_dbgosdlr_get, CP14_DBGOSDLR(%0)) +_RF0(cp14_dbgdscrint_get, CP14_DBGDSCRint(%0)) + +_WF1(cp14_dbgdscr_v6_set, CP14_DBGDSCRext_V6(%0)) +_WF1(cp14_dbgdscr_v7_set, CP14_DBGDSCRext_V7(%0)) +_WF1(cp14_dbgvcr_set, CP14_DBGVCR(%0)) +_WF1(cp14_dbgoslar_set, CP14_DBGOSLAR(%0)) + /* Various control registers */ _RF0(cp15_cpacr_get, CP15_CPACR(%0)) diff --git a/sys/arm/include/db_machdep.h b/sys/arm/include/db_machdep.h index 42d31359933..0988fe30bdc 100644 --- a/sys/arm/include/db_machdep.h +++ b/sys/arm/include/db_machdep.h @@ -33,8 +33,10 @@ #include #include #include +#include #define T_BREAKPOINT (1) +#define T_WATCHPOINT (2) typedef vm_offset_t db_addr_t; typedef int db_expr_t; @@ -48,11 +50,16 @@ typedef int db_expr_t; kdb_frame->tf_pc += BKPT_SIZE; \ } while (0) -#define SOFTWARE_SSTEP 1 +#if __ARM_ARCH >= 6 +#define db_clear_single_step kdb_cpu_clear_singlestep +#define db_set_single_step kdb_cpu_set_singlestep +#define db_pc_is_singlestep kdb_cpu_pc_is_singlestep +#else +#define SOFTWARE_SSTEP 1 +#endif #define IS_BREAKPOINT_TRAP(type, code) (type == T_BREAKPOINT) -#define IS_WATCHPOINT_TRAP(type, code) (0) - +#define IS_WATCHPOINT_TRAP(type, code) (type == T_WATCHPOINT) #define inst_trap_return(ins) (0) /* ldmxx reg, {..., pc} diff --git a/sys/arm/include/debug_monitor.h b/sys/arm/include/debug_monitor.h new file mode 100644 index 00000000000..0cc8156ba44 --- /dev/null +++ b/sys/arm/include/debug_monitor.h @@ -0,0 +1,80 @@ +/*- + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Semihalf under + * the sponsorship of the FreeBSD Foundation. + * + * 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 _MACHINE_DEBUG_MONITOR_H_ +#define _MACHINE_DEBUG_MONITOR_H_ + +#ifdef DDB + +#include + +enum dbg_access_t { + HW_BREAKPOINT_X = 0, + HW_WATCHPOINT_R = 1, + HW_WATCHPOINT_W = 2, + HW_WATCHPOINT_RW = HW_WATCHPOINT_R | HW_WATCHPOINT_W, +}; + +#if __ARM_ARCH >= 6 +void dbg_monitor_init(void); +void dbg_show_watchpoint(void); +int dbg_setup_watchpoint(db_expr_t, db_expr_t, enum dbg_access_t); +int dbg_remove_watchpoint(db_expr_t, db_expr_t); +#else /* __ARM_ARCH >= 6 */ +static __inline void +dbg_show_watchpoint(void) +{ +} +static __inline int +dbg_setup_watchpoint(db_expr_t addr __unused, db_expr_t size __unused, + enum dbg_access_t access __unused) +{ + return (ENXIO); +} +static __inline int +dbg_remove_watchpoint(db_expr_t addr __unused, db_expr_t size __unused) +{ + return (ENXIO); +} +static __inline void +dbg_monitor_init(void) +{ +} +#endif /* __ARM_ARCH < 6 */ + +#else /* DDB */ +static __inline void +dbg_monitor_init(void) +{ +} +#endif + +#endif /* _MACHINE_DEBUG_MONITOR_H_ */ diff --git a/sys/arm/include/kdb.h b/sys/arm/include/kdb.h index 98099a35e1a..fb50c78ef94 100644 --- a/sys/arm/include/kdb.h +++ b/sys/arm/include/kdb.h @@ -32,9 +32,15 @@ #include #include #include +#include #define KDB_STOPPEDPCB(pc) &stoppcbs[pc->pc_cpuid] +#if __ARM_ARCH >= 6 +extern void kdb_cpu_clear_singlestep(void); +extern void kdb_cpu_set_singlestep(void); +boolean_t kdb_cpu_pc_is_singlestep(db_addr_t); +#else static __inline void kdb_cpu_clear_singlestep(void) { @@ -44,6 +50,7 @@ static __inline void kdb_cpu_set_singlestep(void) { } +#endif static __inline void kdb_cpu_sync_icache(unsigned char *addr, size_t size) diff --git a/sys/arm/include/ofw_machdep.h b/sys/arm/include/ofw_machdep.h index 54033eaa03b..941be82fd1c 100644 --- a/sys/arm/include/ofw_machdep.h +++ b/sys/arm/include/ofw_machdep.h @@ -40,8 +40,8 @@ typedef uint32_t cell_t; struct mem_region { - vm_offset_t mr_start; - vm_size_t mr_size; + uint64_t mr_start; + uint64_t mr_size; }; #endif /* _MACHINE_OFW_MACHDEP_H_ */ diff --git a/sys/arm/include/physmem.h b/sys/arm/include/physmem.h index ae6e4d0ab4c..5e5968d0696 100644 --- a/sys/arm/include/physmem.h +++ b/sys/arm/include/physmem.h @@ -52,7 +52,7 @@ extern vm_paddr_t arm_physmem_kernaddr; #define EXFLAG_NODUMP 0x01 #define EXFLAG_NOALLOC 0x02 -void arm_physmem_hardware_region(vm_paddr_t pa, vm_size_t sz); +void arm_physmem_hardware_region(uint64_t pa, uint64_t sz); void arm_physmem_exclude_region(vm_paddr_t pa, vm_size_t sz, uint32_t flags); void arm_physmem_init_kernel_globals(void); void arm_physmem_print_tables(void); diff --git a/sys/arm/include/pmap-v6.h b/sys/arm/include/pmap-v6.h index 2b254f072ba..beaf638a179 100644 --- a/sys/arm/include/pmap-v6.h +++ b/sys/arm/include/pmap-v6.h @@ -200,6 +200,8 @@ void pmap_tlb_flush_range(pmap_t , vm_offset_t , vm_size_t ); void pmap_dcache_wb_range(vm_paddr_t , vm_size_t , vm_memattr_t ); vm_paddr_t pmap_kextract(vm_offset_t ); +vm_paddr_t pmap_dump_kextract(vm_offset_t, pt2_entry_t *); + int pmap_fault(pmap_t , vm_offset_t , uint32_t , int , bool); #define vtophys(va) pmap_kextract((vm_offset_t)(va)) diff --git a/sys/arm/include/pmap.h b/sys/arm/include/pmap.h index 923301fa05a..a0b0d94255b 100644 --- a/sys/arm/include/pmap.h +++ b/sys/arm/include/pmap.h @@ -263,6 +263,7 @@ void pmap_kremove_device(vm_offset_t, vm_size_t); void *pmap_kenter_temporary(vm_paddr_t pa, int i); void pmap_kenter_user(vm_offset_t va, vm_paddr_t pa); vm_paddr_t pmap_kextract(vm_offset_t va); +vm_paddr_t pmap_dump_kextract(vm_offset_t, pt2_entry_t *); void pmap_kremove(vm_offset_t); void *pmap_mapdev(vm_offset_t, vm_size_t); void pmap_unmapdev(vm_offset_t, vm_size_t); diff --git a/sys/arm/include/pte.h b/sys/arm/include/pte.h index ef804ae9808..42e26ab6158 100644 --- a/sys/arm/include/pte.h +++ b/sys/arm/include/pte.h @@ -43,6 +43,7 @@ #ifndef LOCORE typedef uint32_t pd_entry_t; /* page directory entry */ typedef uint32_t pt_entry_t; /* page table entry */ +typedef pt_entry_t pt2_entry_t; /* compatibility with v6 */ #endif #define PG_FRAME 0xfffff000 diff --git a/sys/arm/include/sysreg.h b/sys/arm/include/sysreg.h index dc9386943d6..bbe6a29da65 100644 --- a/sys/arm/include/sysreg.h +++ b/sys/arm/include/sysreg.h @@ -41,6 +41,24 @@ #include +/* + * CP14 registers + */ +#if __ARM_ARCH >= 6 + +#define CP14_DBGDIDR(rr) p14, 0, rr, c0, c0, 0 /* Debug ID Register */ +#define CP14_DBGDSCRext_V6(rr) p14, 0, rr, c0, c1, 0 /* Debug Status and Ctrl Register v6 */ +#define CP14_DBGDSCRext_V7(rr) p14, 0, rr, c0, c2, 2 /* Debug Status and Ctrl Register v7 */ +#define CP14_DBGVCR(rr) p14, 0, rr, c0, c7, 0 /* Vector Catch Register */ +#define CP14_DBGOSLAR(rr) p14, 0, rr, c1, c0, 4 /* OS Lock Access Register */ +#define CP14_DBGOSLSR(rr) p14, 0, rr, c1, c1, 4 /* OS Lock Status Register */ +#define CP14_DBGOSDLR(rr) p14, 0, rr, c1, c3, 4 /* OS Double Lock Register */ +#define CP14_DBGPRSR(rr) p14, 0, rr, c1, c5, 4 /* Device Powerdown and Reset Status */ + +#define CP14_DBGDSCRint(rr) CP14_DBGDSCRext_V6(rr) /* Debug Status and Ctrl internal view */ + +#endif + /* * CP15 C0 registers */ diff --git a/sys/arm64/arm64/gic.c b/sys/arm64/arm64/gic.c index 812f64e2cba..823dd6110f3 100644 --- a/sys/arm64/arm64/gic.c +++ b/sys/arm64/arm64/gic.c @@ -355,22 +355,6 @@ DEFINE_CLASS_0(gic, arm_gic_driver, arm_gic_methods, #define GICv2M_MSI_SETSPI_NS 0x040 #define GICV2M_MSI_IIDR 0xFCC -struct gicv2m_softc { - struct resource *sc_mem; - struct mtx sc_mutex; - u_int sc_spi_start; - u_int sc_spi_count; - u_int sc_spi_offset; -}; - -static int -gicv2m_probe(device_t dev) -{ - - device_set_desc(dev, "ARM Generic Interrupt Controller MSI/MSIX"); - return (BUS_PROBE_DEFAULT); -} - static int gicv2m_attach(device_t dev) { @@ -478,7 +462,6 @@ gicv2m_map_msi(device_t dev, device_t pci_dev, int irq, uint64_t *addr, static device_method_t arm_gicv2m_methods[] = { /* Device interface */ - DEVMETHOD(device_probe, gicv2m_probe), DEVMETHOD(device_attach, gicv2m_attach), /* MSI/MSI-X */ @@ -489,9 +472,5 @@ static device_method_t arm_gicv2m_methods[] = { { 0, 0 } }; -static devclass_t arm_gicv2m_devclass; - DEFINE_CLASS_0(gicv2m, arm_gicv2m_driver, arm_gicv2m_methods, sizeof(struct gicv2m_softc)); -EARLY_DRIVER_MODULE(gicv2m, gic, arm_gicv2m_driver, arm_gicv2m_devclass, - 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); diff --git a/sys/arm64/arm64/gic.h b/sys/arm64/arm64/gic.h index a8f1c252046..d22d43ba272 100644 --- a/sys/arm64/arm64/gic.h +++ b/sys/arm64/arm64/gic.h @@ -51,6 +51,16 @@ struct arm_gic_softc { uint32_t nirqs; }; +DECLARE_CLASS(arm_gicv2m_driver); + +struct gicv2m_softc { + struct resource *sc_mem; + struct mtx sc_mutex; + u_int sc_spi_start; + u_int sc_spi_count; + u_int sc_spi_offset; +}; + int arm_gic_attach(device_t); #endif diff --git a/sys/arm64/arm64/gic_fdt.c b/sys/arm64/arm64/gic_fdt.c index 5160e5f245a..924a08b1cf6 100644 --- a/sys/arm64/arm64/gic_fdt.c +++ b/sys/arm64/arm64/gic_fdt.c @@ -290,3 +290,38 @@ EARLY_DRIVER_MODULE(gic, simplebus, arm_gic_fdt_driver, arm_gic_fdt_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); EARLY_DRIVER_MODULE(gic, ofwbus, arm_gic_fdt_driver, arm_gic_fdt_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); + +static struct ofw_compat_data gicv2m_compat_data[] = { + {"arm,gic-v2m-frame", true}, + {NULL, false} +}; + +static int +arm_gicv2m_fdt_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_search_compatible(dev, gicv2m_compat_data)->ocd_data) + return (ENXIO); + + device_set_desc(dev, "ARM Generic Interrupt Controller MSI/MSIX"); + return (BUS_PROBE_DEFAULT); +} + +static device_method_t arm_gicv2m_fdt_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, arm_gicv2m_fdt_probe), + + /* End */ + DEVMETHOD_END +}; + +DEFINE_CLASS_1(gicv2m, arm_gicv2m_fdt_driver, arm_gicv2m_fdt_methods, + sizeof(struct gicv2m_softc), arm_gicv2m_driver); + +static devclass_t arm_gicv2m_fdt_devclass; + +EARLY_DRIVER_MODULE(gicv2m, gic, arm_gicv2m_fdt_driver, + arm_gicv2m_fdt_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); diff --git a/sys/arm64/arm64/gic_v3.c b/sys/arm64/arm64/gic_v3.c index c0e939b1113..b74a56a9a4b 100644 --- a/sys/arm64/arm64/gic_v3.c +++ b/sys/arm64/arm64/gic_v3.c @@ -84,7 +84,7 @@ static device_method_t gic_v3_methods[] = { DEVMETHOD_END }; -DEFINE_CLASS_0(gic_v3, gic_v3_driver, gic_v3_methods, +DEFINE_CLASS_0(gic, gic_v3_driver, gic_v3_methods, sizeof(struct gic_v3_softc)); /* diff --git a/sys/arm64/arm64/gic_v3_fdt.c b/sys/arm64/arm64/gic_v3_fdt.c index 10bc524cf58..79075f2a423 100644 --- a/sys/arm64/arm64/gic_v3_fdt.c +++ b/sys/arm64/arm64/gic_v3_fdt.c @@ -78,7 +78,7 @@ static device_method_t gic_v3_fdt_methods[] = { DEVMETHOD_END }; -DEFINE_CLASS_1(gic_v3, gic_v3_fdt_driver, gic_v3_fdt_methods, +DEFINE_CLASS_1(gic, gic_v3_fdt_driver, gic_v3_fdt_methods, sizeof(struct gic_v3_softc), gic_v3_driver); static devclass_t gic_v3_fdt_devclass; @@ -287,12 +287,12 @@ static device_method_t gic_v3_its_fdt_methods[] = { DEVMETHOD_END }; -DEFINE_CLASS_1(gic_v3_its, gic_v3_its_fdt_driver, gic_v3_its_fdt_methods, +DEFINE_CLASS_1(its, gic_v3_its_fdt_driver, gic_v3_its_fdt_methods, sizeof(struct gic_v3_its_softc), gic_v3_its_driver); static devclass_t gic_v3_its_fdt_devclass; -EARLY_DRIVER_MODULE(gic_v3_its, gic_v3, gic_v3_its_fdt_driver, +EARLY_DRIVER_MODULE(its, gic, gic_v3_its_fdt_driver, gic_v3_its_fdt_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); static int diff --git a/sys/arm64/arm64/gic_v3_its.c b/sys/arm64/arm64/gic_v3_its.c index 1200f9c999e..7daeabe1348 100644 --- a/sys/arm64/arm64/gic_v3_its.c +++ b/sys/arm64/arm64/gic_v3_its.c @@ -82,7 +82,7 @@ static device_method_t gic_v3_its_methods[] = { DEVMETHOD_END }; -DEFINE_CLASS_0(gic_v3_its, gic_v3_its_driver, gic_v3_its_methods, +DEFINE_CLASS_0(its, gic_v3_its_driver, gic_v3_its_methods, sizeof(struct gic_v3_its_softc)); MALLOC_DEFINE(M_GIC_V3_ITS, "GICv3 ITS", GIC_V3_ITS_DEVSTR); diff --git a/sys/boot/arm/at91/boot2/boot2.c b/sys/boot/arm/at91/boot2/boot2.c index 1e17ab21c14..f7510a5a0fc 100644 --- a/sys/boot/arm/at91/boot2/boot2.c +++ b/sys/boot/arm/at91/boot2/boot2.c @@ -1,6 +1,6 @@ /*- * Copyright (c) 2008 John Hay - * Copyright (c) 2006 Warner Losh + * Copyright (c) 2006 M Warner Losh * Copyright (c) 1998 Robert Nordier * All rights reserved. * @@ -30,52 +30,16 @@ __FBSDID("$FreeBSD$"); #include "lib.h" #include "board.h" +#include "paths.h" +#include "rbx.h" -#define RBX_ASKNAME 0x0 /* -a */ -#define RBX_SINGLE 0x1 /* -s */ -/* 0x2 is reserved for log2(RB_NOSYNC). */ -/* 0x3 is reserved for log2(RB_HALT). */ -/* 0x4 is reserved for log2(RB_INITNAME). */ -#define RBX_DFLTROOT 0x5 /* -r */ -/* #define RBX_KDB 0x6 -d */ -/* 0x7 is reserved for log2(RB_RDONLY). */ -/* 0x8 is reserved for log2(RB_DUMP). */ -/* 0x9 is reserved for log2(RB_MINIROOT). */ -#define RBX_CONFIG 0xa /* -c */ -#define RBX_VERBOSE 0xb /* -v */ -/* #define RBX_SERIAL 0xc -h */ -/* #define RBX_CDROM 0xd -C */ -/* 0xe is reserved for log2(RB_POWEROFF). */ -#define RBX_GDB 0xf /* -g */ -/* #define RBX_MUTE 0x10 -m */ -/* 0x11 is reserved for log2(RB_SELFTEST). */ -/* 0x12 is reserved for boot programs. */ -/* 0x13 is reserved for boot programs. */ -/* #define RBX_PAUSE 0x14 -p */ -/* #define RBX_QUIET 0x15 -q */ -#define RBX_NOINTR 0x1c /* -n */ -/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */ -/* #define RBX_DUAL 0x1d -D */ -/* 0x1f is reserved for log2(RB_BOOTINFO). */ - -/* pass: -a, -s, -r, -v, -g */ -#define RBX_MASK (OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \ - OPT_SET(RBX_DFLTROOT) | \ - OPT_SET(RBX_VERBOSE) | \ - OPT_SET(RBX_GDB)) - -#define PATH_DOTCONFIG "/boot.config" -#define PATH_CONFIG "/boot/config" -//#define PATH_KERNEL "/boot/kernel/kernel" +#undef PATH_KERNEL #define PATH_KERNEL "/boot/kernel/kernel.gz.tramp" extern uint32_t _end; #define NOPT 6 -#define OPT_SET(opt) (1 << (opt)) -#define OPT_CHECK(opt) ((opts) & OPT_SET(opt)) - static const char optstr[NOPT] = "agnrsv"; static const unsigned char bootflags[NOPT] = { RBX_ASKNAME, diff --git a/sys/boot/arm/ixp425/boot2/boot2.c b/sys/boot/arm/ixp425/boot2/boot2.c index e5f49827394..93c4fe1aff5 100644 --- a/sys/boot/arm/ixp425/boot2/boot2.c +++ b/sys/boot/arm/ixp425/boot2/boot2.c @@ -28,51 +28,13 @@ __FBSDID("$FreeBSD$"); #include #include "lib.h" - -#define RBX_ASKNAME 0x0 /* -a */ -#define RBX_SINGLE 0x1 /* -s */ -/* 0x2 is reserved for log2(RB_NOSYNC). */ -/* 0x3 is reserved for log2(RB_HALT). */ -/* 0x4 is reserved for log2(RB_INITNAME). */ -#define RBX_DFLTROOT 0x5 /* -r */ -/* #define RBX_KDB 0x6 -d */ -/* 0x7 is reserved for log2(RB_RDONLY). */ -/* 0x8 is reserved for log2(RB_DUMP). */ -/* 0x9 is reserved for log2(RB_MINIROOT). */ -#define RBX_CONFIG 0xa /* -c */ -#define RBX_VERBOSE 0xb /* -v */ -/* #define RBX_SERIAL 0xc -h */ -/* #define RBX_CDROM 0xd -C */ -/* 0xe is reserved for log2(RB_POWEROFF). */ -#define RBX_GDB 0xf /* -g */ -/* #define RBX_MUTE 0x10 -m */ -/* 0x11 is reserved for log2(RB_SELFTEST). */ -/* 0x12 is reserved for boot programs. */ -/* 0x13 is reserved for boot programs. */ -/* #define RBX_PAUSE 0x14 -p */ -/* #define RBX_QUIET 0x15 -q */ -#define RBX_NOINTR 0x1c /* -n */ -/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */ -/* #define RBX_DUAL 0x1d -D */ -/* 0x1f is reserved for log2(RB_BOOTINFO). */ - -/* pass: -a, -s, -r, -v, -g */ -#define RBX_MASK (OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \ - OPT_SET(RBX_DFLTROOT) | \ - OPT_SET(RBX_VERBOSE) | \ - OPT_SET(RBX_GDB)) - -#define PATH_DOTCONFIG "/boot.config" -#define PATH_CONFIG "/boot/config" -#define PATH_KERNEL "/boot/kernel/kernel" +#include "paths.h" +#include "rbx.h" extern uint32_t _end; #define NOPT 6 -#define OPT_SET(opt) (1 << (opt)) -#define OPT_CHECK(opt) ((opts) & OPT_SET(opt)) - static const char optstr[NOPT] = "agnrsv"; static const unsigned char flags[NOPT] = { RBX_ASKNAME, diff --git a/sys/boot/common/paths.h b/sys/boot/common/paths.h new file mode 100644 index 00000000000..23f5d2160c6 --- /dev/null +++ b/sys/boot/common/paths.h @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 2016 M. Warner Losh + * 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 AUTHORS 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 AUTHORS 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 _PATHS_H_ +#define _PATHS_H_ + +#define PATH_DOTCONFIG "/boot.config" +#define PATH_CONFIG "/boot/config" +#define PATH_BOOT3 "/boot/loader" +#define PATH_LOADER "/boot/loader" +#define PATH_LOADER_EFI "/boot/loader.efi" +#define PATH_KERNEL "/boot/kernel/kernel" + +#endif /* _PATHS_H_ */ diff --git a/sys/boot/i386/common/rbx.h b/sys/boot/common/rbx.h similarity index 100% rename from sys/boot/i386/common/rbx.h rename to sys/boot/common/rbx.h diff --git a/sys/boot/efi/boot1/boot1.c b/sys/boot/efi/boot1/boot1.c index f04623562fb..c326c79d77a 100644 --- a/sys/boot/efi/boot1/boot1.c +++ b/sys/boot/efi/boot1/boot1.c @@ -31,8 +31,7 @@ __FBSDID("$FreeBSD$"); #include #include "boot_module.h" - -#define _PATH_LOADER "/boot/loader.efi" +#include "paths.h" static const boot_module_t *boot_modules[] = { @@ -92,20 +91,48 @@ Free(void *buf, const char *file __unused, int line __unused) void try_load(const boot_module_t *mod) { - size_t bufsize; + size_t bufsize, cmdsize; void *buf; + char *cmd; dev_info_t *dev; EFI_HANDLE loaderhandle; EFI_LOADED_IMAGE *loaded_image; EFI_STATUS status; - status = mod->load(_PATH_LOADER, &dev, &buf, &bufsize); + /* + * Read in and parse the command line from /boot.config or /boot/config, + * if present. We'll pass it the next stage via a simple ASCII + * string. loader.efi has a hack for ASCII strings, so we'll use that to + * keep the size down here. We only try to read the alternate file if + * we get EFI_NOT_FOUND because all other errors mean that the boot_module + * had troubles with the filesystem. We could return early, but we'll let + * loading the actual kernel sort all that out. Since these files are + * optional, we don't report errors in trying to read them. + */ + cmd = NULL; + cmdsize = 0; + status = mod->load(PATH_DOTCONFIG, &dev, &buf, &bufsize); + if (status == EFI_NOT_FOUND) + status = mod->load(PATH_CONFIG, &dev, &buf, &bufsize); + if (status == EFI_SUCCESS) { + cmdsize = bufsize + 1; + cmd = malloc(cmdsize); + if (cmd == NULL) { + free(buf); + return; + } + memcpy(cmd, buf, bufsize); + cmd[bufsize] = '\0'; + free(buf); + } + + status = mod->load(PATH_LOADER_EFI, &dev, &buf, &bufsize); if (status == EFI_NOT_FOUND) return; if (status != EFI_SUCCESS) { - printf("%s failed to load %s (%lu)\n", mod->name, _PATH_LOADER, - EFI_ERROR_CODE(status)); + printf("%s failed to load %s (%lu)\n", mod->name, + PATH_LOADER_EFI, EFI_ERROR_CODE(status)); return; } @@ -116,6 +143,9 @@ try_load(const boot_module_t *mod) return; } + if (cmd != NULL) + printf(" command args: %s\n", cmd); + if ((status = bs->HandleProtocol(loaderhandle, &LoadedImageGUID, (VOID**)&loaded_image)) != EFI_SUCCESS) { printf("Failed to query LoadedImage provided by %s (%lu)\n", @@ -124,11 +154,16 @@ try_load(const boot_module_t *mod) } loaded_image->DeviceHandle = dev->devhandle; + loaded_image->LoadOptionsSize = cmdsize; + loaded_image->LoadOptions = cmd; if ((status = bs->StartImage(loaderhandle, NULL, NULL)) != EFI_SUCCESS) { printf("Failed to start image provided by %s (%lu)\n", mod->name, EFI_ERROR_CODE(status)); + free(cmd); + loaded_image->LoadOptionsSize = 0; + loaded_image->LoadOptions = NULL; return; } } @@ -174,7 +209,7 @@ efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) conout->ClearScreen(conout); printf("\n>> FreeBSD EFI boot block\n"); - printf(" Loader path: %s\n\n", _PATH_LOADER); + printf(" Loader path: %s\n\n", PATH_LOADER_EFI); printf(" Initializing modules:"); for (i = 0; i < NUM_BOOT_MODULES; i++) { if (boot_modules[i] == NULL) diff --git a/sys/boot/efi/libefi/libefi.c b/sys/boot/efi/libefi/libefi.c index f87b89acb2b..c76bd6c9134 100644 --- a/sys/boot/efi/libefi/libefi.c +++ b/sys/boot/efi/libefi/libefi.c @@ -44,7 +44,7 @@ static CHAR16 * arg_skipsep(CHAR16 *argp) { - while (*argp == ' ' || *argp == '\t') + while (*argp == ' ' || *argp == '\t' || *argp == '\n') argp++; return (argp); } @@ -53,7 +53,7 @@ static CHAR16 * arg_skipword(CHAR16 *argp) { - while (*argp && *argp != ' ' && *argp != '\t') + while (*argp && *argp != ' ' && *argp != '\t' && *argp != '\n') argp++; return (argp); } diff --git a/sys/boot/efi/loader/main.c b/sys/boot/efi/loader/main.c index 0b9dcf6da09..4c3bc7aa3ef 100644 --- a/sys/boot/efi/loader/main.c +++ b/sys/boot/efi/loader/main.c @@ -29,6 +29,8 @@ __FBSDID("$FreeBSD$"); #include +#include +#include #include #include #include @@ -83,13 +85,22 @@ print_str16(const CHAR16 *str) printf("%c", (char)str[i]); } +static void +cp16to8(const CHAR16 *src, char *dst, size_t len) +{ + size_t i; + + for (i = 0; i < len && src[i]; i++) + dst[i] = (char)src[i]; +} + EFI_STATUS main(int argc, CHAR16 *argv[]) { char var[128]; EFI_LOADED_IMAGE *img; EFI_GUID *guid; - int i, j, vargood, unit; + int i, j, vargood, unit, howto; struct devsw *dev; uint64_t pool_guid; UINTN k; @@ -113,27 +124,97 @@ main(int argc, CHAR16 *argv[]) cons_probe(); /* + * Parse the args to set the console settings, etc + * boot1.efi passes these in, if it can read /boot.config or /boot/config + * or iPXE may be setup to pass these in. + * * Loop through the args, and for each one that contains an '=' that is * not the first character, add it to the environment. This allows * loader and kernel env vars to be passed on the command line. Convert * args from UCS-2 to ASCII (16 to 8 bit) as they are copied. */ + howto = 0; for (i = 1; i < argc; i++) { - vargood = 0; - for (j = 0; argv[i][j] != 0; j++) { - if (j == sizeof(var)) { - vargood = 0; - break; + if (argv[i][0] == '-') { + for (j = 1; argv[i][j] != 0; j++) { + int ch; + + ch = argv[i][j]; + switch (ch) { + case 'a': + howto |= RB_ASKNAME; + break; + case 'd': + howto |= RB_KDB; + break; + case 'D': + howto |= RB_MULTIPLE; + break; + case 'm': + howto |= RB_MUTE; + break; + case 'h': + howto |= RB_SERIAL; + break; + case 'p': + howto |= RB_PAUSE; + break; + case 'r': + howto |= RB_DFLTROOT; + break; + case 's': + howto |= RB_SINGLE; + break; + case 'S': + if (argv[i][j + 1] == 0) { + if (i + 1 == argc) { + setenv("comconsole_speed", "115200", 1); + } else { + cp16to8(&argv[i + 1][0], var, + sizeof(var)); + setenv("comconsole_speedspeed", var, 1); + } + i++; + break; + } else { + cp16to8(&argv[i][j + 1], var, + sizeof(var)); + setenv("comconsole_speed", var, 1); + break; + } + case 'v': + howto |= RB_VERBOSE; + break; + } + } + } else { + vargood = 0; + for (j = 0; argv[i][j] != 0; j++) { + if (j == sizeof(var)) { + vargood = 0; + break; + } + if (j > 0 && argv[i][j] == '=') + vargood = 1; + var[j] = (char)argv[i][j]; + } + if (vargood) { + var[j] = 0; + putenv(var); } - if (j > 0 && argv[i][j] == '=') - vargood = 1; - var[j] = (char)argv[i][j]; - } - if (vargood) { - var[j] = 0; - putenv(var); } } + for (i = 0; howto_names[i].ev != NULL; i++) + if (howto & howto_names[i].mask) + setenv(howto_names[i].ev, "YES", 1); + if (howto & RB_MULTIPLE) { + if (howto & RB_SERIAL) + setenv("console", "comconsole efi" , 1); + else + setenv("console", "efi comconsole" , 1); + } else if (howto & RB_SERIAL) { + setenv("console", "comconsole" , 1); + } if (efi_copy_init()) { printf("failed to allocate staging area\n"); diff --git a/sys/boot/i386/boot2/boot2.c b/sys/boot/i386/boot2/boot2.c index 101d2dad175..68d5de5198f 100644 --- a/sys/boot/i386/boot2/boot2.c +++ b/sys/boot/i386/boot2/boot2.c @@ -33,6 +33,8 @@ __FBSDID("$FreeBSD$"); #include "boot2.h" #include "lib.h" +#include "paths.h" +#include "rbx.h" /* Define to 0 to omit serial support */ #ifndef SERIAL @@ -52,46 +54,6 @@ __FBSDID("$FreeBSD$"); #define SECOND 18 /* Circa that many ticks in a second. */ -#define RBX_ASKNAME 0x0 /* -a */ -#define RBX_SINGLE 0x1 /* -s */ -/* 0x2 is reserved for log2(RB_NOSYNC). */ -/* 0x3 is reserved for log2(RB_HALT). */ -/* 0x4 is reserved for log2(RB_INITNAME). */ -#define RBX_DFLTROOT 0x5 /* -r */ -#define RBX_KDB 0x6 /* -d */ -/* 0x7 is reserved for log2(RB_RDONLY). */ -/* 0x8 is reserved for log2(RB_DUMP). */ -/* 0x9 is reserved for log2(RB_MINIROOT). */ -#define RBX_CONFIG 0xa /* -c */ -#define RBX_VERBOSE 0xb /* -v */ -#define RBX_SERIAL 0xc /* -h */ -#define RBX_CDROM 0xd /* -C */ -/* 0xe is reserved for log2(RB_POWEROFF). */ -#define RBX_GDB 0xf /* -g */ -#define RBX_MUTE 0x10 /* -m */ -/* 0x11 is reserved for log2(RB_SELFTEST). */ -/* 0x12 is reserved for boot programs. */ -/* 0x13 is reserved for boot programs. */ -#define RBX_PAUSE 0x14 /* -p */ -#define RBX_QUIET 0x15 /* -q */ -#define RBX_NOINTR 0x1c /* -n */ -/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */ -#define RBX_DUAL 0x1d /* -D */ -/* 0x1f is reserved for log2(RB_BOOTINFO). */ - -/* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -D */ -#define RBX_MASK (OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \ - OPT_SET(RBX_DFLTROOT) | OPT_SET(RBX_KDB ) | \ - OPT_SET(RBX_CONFIG) | OPT_SET(RBX_VERBOSE) | \ - OPT_SET(RBX_SERIAL) | OPT_SET(RBX_CDROM) | \ - OPT_SET(RBX_GDB ) | OPT_SET(RBX_MUTE) | \ - OPT_SET(RBX_PAUSE) | OPT_SET(RBX_DUAL)) - -#define PATH_DOTCONFIG "/boot.config" -#define PATH_CONFIG "/boot/config" -#define PATH_BOOT3 "/boot/loader" -#define PATH_KERNEL "/boot/kernel/kernel" - #define ARGS 0x900 #define NOPT 14 #define NDEV 3 @@ -106,9 +68,6 @@ __FBSDID("$FreeBSD$"); #define TYPE_MAXHARD TYPE_DA #define TYPE_FD 2 -#define OPT_SET(opt) (1 << (opt)) -#define OPT_CHECK(opt) ((opts) & OPT_SET(opt)) - extern uint32_t _end; static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ @@ -143,7 +102,7 @@ static struct dsk { } dsk; static char cmd[512], cmddup[512], knamebuf[1024]; static const char *kname; -static uint32_t opts; +uint32_t opts; static struct bootinfo bootinfo; #if SERIAL static int comspeed = SIOSPD; diff --git a/sys/boot/i386/gptboot/gptboot.c b/sys/boot/i386/gptboot/gptboot.c index 4fa52271a0b..96495d25ccb 100644 --- a/sys/boot/i386/gptboot/gptboot.c +++ b/sys/boot/i386/gptboot/gptboot.c @@ -37,11 +37,7 @@ __FBSDID("$FreeBSD$"); #include "util.h" #include "cons.h" #include "gpt.h" - -#define PATH_DOTCONFIG "/boot.config" -#define PATH_CONFIG "/boot/config" -#define PATH_BOOT3 "/boot/loader" -#define PATH_KERNEL "/boot/kernel/kernel" +#include "paths.h" #define ARGS 0x900 #define NOPT 14 diff --git a/sys/boot/i386/zfsboot/zfsboot.c b/sys/boot/i386/zfsboot/zfsboot.c index ca82c63afe2..51c9af15625 100644 --- a/sys/boot/i386/zfsboot/zfsboot.c +++ b/sys/boot/i386/zfsboot/zfsboot.c @@ -42,14 +42,10 @@ __FBSDID("$FreeBSD$"); #include "util.h" #include "cons.h" #include "bootargs.h" +#include "paths.h" #include "libzfs.h" -#define PATH_DOTCONFIG "/boot.config" -#define PATH_CONFIG "/boot/config" -#define PATH_BOOT3 "/boot/zfsloader" -#define PATH_KERNEL "/boot/kernel/kernel" - #define ARGS 0x900 #define NOPT 14 #define NDEV 3 diff --git a/sys/boot/mips/beri/boot2/boot2.c b/sys/boot/mips/beri/boot2/boot2.c index 0ee3109950f..9728a20b9bc 100644 --- a/sys/boot/mips/beri/boot2/boot2.c +++ b/sys/boot/mips/beri/boot2/boot2.c @@ -64,6 +64,9 @@ __FBSDID("$FreeBSD$"); #include #include +#include "paths.h" +#include "rbx.h" + static int beri_argc; static const char **beri_argv, **beri_envv; static uint64_t beri_memsize; @@ -73,46 +76,6 @@ static uint64_t beri_memsize; #define SECOND 1 /* Circa that many ticks in a second. */ -#define RBX_ASKNAME 0x0 /* -a */ -#define RBX_SINGLE 0x1 /* -s */ -/* 0x2 is reserved for log2(RB_NOSYNC). */ -/* 0x3 is reserved for log2(RB_HALT). */ -/* 0x4 is reserved for log2(RB_INITNAME). */ -#define RBX_DFLTROOT 0x5 /* -r */ -#define RBX_KDB 0x6 /* -d */ -/* 0x7 is reserved for log2(RB_RDONLY). */ -/* 0x8 is reserved for log2(RB_DUMP). */ -/* 0x9 is reserved for log2(RB_MINIROOT). */ -#define RBX_CONFIG 0xa /* -c */ -#define RBX_VERBOSE 0xb /* -v */ -#define RBX_SERIAL 0xc /* -h */ -#define RBX_CDROM 0xd /* -C */ -/* 0xe is reserved for log2(RB_POWEROFF). */ -#define RBX_GDB 0xf /* -g */ -#define RBX_MUTE 0x10 /* -m */ -/* 0x11 is reserved for log2(RB_SELFTEST). */ -/* 0x12 is reserved for boot programs. */ -/* 0x13 is reserved for boot programs. */ -#define RBX_PAUSE 0x14 /* -p */ -#define RBX_QUIET 0x15 /* -q */ -#define RBX_NOINTR 0x1c /* -n */ -/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */ -#define RBX_DUAL 0x1d /* -D */ -/* 0x1f is reserved for log2(RB_BOOTINFO). */ - -/* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -D */ -#define RBX_MASK (OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \ - OPT_SET(RBX_DFLTROOT) | OPT_SET(RBX_KDB ) | \ - OPT_SET(RBX_CONFIG) | OPT_SET(RBX_VERBOSE) | \ - OPT_SET(RBX_SERIAL) | OPT_SET(RBX_CDROM) | \ - OPT_SET(RBX_GDB ) | OPT_SET(RBX_MUTE) | \ - OPT_SET(RBX_PAUSE) | OPT_SET(RBX_DUAL)) - -#define PATH_DOTCONFIG "/boot.config" -#define PATH_CONFIG "/boot/config" -#define PATH_BOOT3 "/boot/loader" -#define PATH_KERNEL "/boot/kernel/kernel" - #define ARGS 0x900 #define NOPT 14 #define MEM_BASE 0x12 @@ -131,9 +94,6 @@ static uint64_t beri_memsize; /* Hard-coded assumption about location of JTAG-loaded kernel. */ #define DRAM_KERNEL_ADDR ((void *)mips_phys_to_cached(0x20000)) -#define OPT_SET(opt) (1 << (opt)) -#define OPT_CHECK(opt) ((opts) & OPT_SET(opt)) - extern uint32_t _end; static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ diff --git a/sys/boot/pc98/boot2/boot2.c b/sys/boot/pc98/boot2/boot2.c index 991cc533e98..aed07262f4a 100644 --- a/sys/boot/pc98/boot2/boot2.c +++ b/sys/boot/pc98/boot2/boot2.c @@ -35,6 +35,8 @@ __FBSDID("$FreeBSD$"); #include "boot2.h" #include "lib.h" +#include "paths.h" +#include "rbx.h" /* Define to 0 to omit serial support */ #ifndef SERIAL @@ -54,46 +56,6 @@ __FBSDID("$FreeBSD$"); #define SECOND 1 /* Circa that many ticks in a second. */ -#define RBX_ASKNAME 0x0 /* -a */ -#define RBX_SINGLE 0x1 /* -s */ -/* 0x2 is reserved for log2(RB_NOSYNC). */ -/* 0x3 is reserved for log2(RB_HALT). */ -/* 0x4 is reserved for log2(RB_INITNAME). */ -#define RBX_DFLTROOT 0x5 /* -r */ -#define RBX_KDB 0x6 /* -d */ -/* 0x7 is reserved for log2(RB_RDONLY). */ -/* 0x8 is reserved for log2(RB_DUMP). */ -/* 0x9 is reserved for log2(RB_MINIROOT). */ -#define RBX_CONFIG 0xa /* -c */ -#define RBX_VERBOSE 0xb /* -v */ -#define RBX_SERIAL 0xc /* -h */ -#define RBX_CDROM 0xd /* -C */ -/* 0xe is reserved for log2(RB_POWEROFF). */ -#define RBX_GDB 0xf /* -g */ -#define RBX_MUTE 0x10 /* -m */ -/* 0x11 is reserved for log2(RB_SELFTEST). */ -/* 0x12 is reserved for boot programs. */ -/* 0x13 is reserved for boot programs. */ -#define RBX_PAUSE 0x14 /* -p */ -#define RBX_QUIET 0x15 /* -q */ -#define RBX_NOINTR 0x1c /* -n */ -/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */ -#define RBX_DUAL 0x1d /* -D */ -/* 0x1f is reserved for log2(RB_BOOTINFO). */ - -/* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -D */ -#define RBX_MASK (OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \ - OPT_SET(RBX_DFLTROOT) | OPT_SET(RBX_KDB ) | \ - OPT_SET(RBX_CONFIG) | OPT_SET(RBX_VERBOSE) | \ - OPT_SET(RBX_SERIAL) | OPT_SET(RBX_CDROM) | \ - OPT_SET(RBX_GDB ) | OPT_SET(RBX_MUTE) | \ - OPT_SET(RBX_PAUSE) | OPT_SET(RBX_DUAL)) - -#define PATH_DOTCONFIG "/boot.config" -#define PATH_CONFIG "/boot/config" -#define PATH_BOOT3 "/boot/loader" -#define PATH_KERNEL "/boot/kernel/kernel" - #define ARGS 0x900 #define NOPT 14 #define NDEV 3 @@ -105,9 +67,6 @@ __FBSDID("$FreeBSD$"); #define TYPE_DA 1 #define TYPE_FD 2 -#define OPT_SET(opt) (1 << (opt)) -#define OPT_CHECK(opt) ((opts) & OPT_SET(opt)) - extern uint32_t _end; static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ diff --git a/sys/boot/powerpc/boot1.chrp/boot1.c b/sys/boot/powerpc/boot1.chrp/boot1.c index af22488a11e..9c50359ea06 100644 --- a/sys/boot/powerpc/boot1.chrp/boot1.c +++ b/sys/boot/powerpc/boot1.chrp/boot1.c @@ -23,8 +23,7 @@ __FBSDID("$FreeBSD$"); #include #include -#define _PATH_LOADER "/boot/loader" -#define _PATH_KERNEL "/boot/kernel/kernel" +#include "paths.h" #define BSIZEMAX 16384 @@ -396,7 +395,7 @@ main(int ac, char **av) char bootpath_full[255]; int i, len; - path = _PATH_LOADER; + path = PATH_LOADER; for (i = 0; i < ac; i++) { switch (av[i][0]) { case '-': diff --git a/sys/boot/sparc64/boot1/boot1.c b/sys/boot/sparc64/boot1/boot1.c index 6c43c9314f3..d0b738039b0 100644 --- a/sys/boot/sparc64/boot1/boot1.c +++ b/sys/boot/sparc64/boot1/boot1.c @@ -24,8 +24,8 @@ __FBSDID("$FreeBSD$"); #include #include -#define _PATH_LOADER "/boot/loader" -#define _PATH_KERNEL "/boot/kernel/kernel" +#include "paths.h" + #define READ_BUF_SIZE 8192 typedef int putc_func_t(char c, void *arg); @@ -324,7 +324,7 @@ main(int ac, char **av) const char *path; int i; - path = _PATH_LOADER; + path = PATH_LOADER; for (i = 0; i < ac; i++) { switch (av[i][0]) { case '-': diff --git a/sys/boot/usb/tools/Makefile b/sys/boot/usb/tools/Makefile index ae3259f98c3..64cf28ca75e 100644 --- a/sys/boot/usb/tools/Makefile +++ b/sys/boot/usb/tools/Makefile @@ -1,7 +1,7 @@ # $FreeBSD$ PROG= sysinit -NO_MAN= +MAN= CFLAGS+= -I${.CURDIR}/../../kshim diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu.c index ed3f19cac85..b60236f6ff1 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu.c @@ -1420,6 +1420,9 @@ dmu_assign_arcbuf(dmu_buf_t *handle, uint64_t offset, arc_buf_t *buf, */ if (offset == db->db.db_offset && blksz == db->db.db_size && DBUF_GET_BUFC_TYPE(db) == ARC_BUFC_DATA) { +#ifdef _KERNEL + curthread->td_ru.ru_oublock++; +#endif dbuf_assign_arcbuf(db, buf, tx); dbuf_rele(db, FTAG); } else { diff --git a/sys/conf/files b/sys/conf/files index ba8365f02e6..076b3ce3635 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1410,6 +1410,15 @@ dev/ex/if_ex.c optional ex dev/ex/if_ex_isa.c optional ex isa dev/ex/if_ex_pccard.c optional ex pccard dev/exca/exca.c optional cbb +dev/extres/clk/clk.c optional ext_resources clk +dev/extres/clk/clkdev_if.m optional ext_resources clk +dev/extres/clk/clknode_if.m optional ext_resources clk +dev/extres/clk/clk_div.c optional ext_resources clk +dev/extres/clk/clk_fixed.c optional ext_resources clk +dev/extres/clk/clk_gate.c optional ext_resources clk +dev/extres/clk/clk_mux.c optional ext_resources clk +dev/extres/hwreset/hwreset.c optional ext_resources hwreset +dev/extres/hwreset/hwreset_if.m optional ext_resources hwreset dev/fatm/if_fatm.c optional fatm pci dev/fb/fbd.c optional fbd | vt dev/fb/fb_if.m standard @@ -1419,7 +1428,7 @@ dev/fdt/fdt_clock_if.m optional fdt fdt_clock dev/fdt/fdt_common.c optional fdt dev/fdt/fdt_pinctrl.c optional fdt fdt_pinctrl dev/fdt/fdt_pinctrl_if.m optional fdt fdt_pinctrl -dev/fdt/fdt_slicer.c optional fdt cfi | fdt nand +dev/fdt/fdt_slicer.c optional fdt cfi | fdt nand | fdt mx25l dev/fdt/fdt_static_dtb.S optional fdt fdt_dtb_static \ dependency "$S/boot/fdt/dts/${MACHINE}/${FDT_DTS_FILE}" dev/fdt/simplebus.c optional fdt @@ -3010,7 +3019,7 @@ geom/geom_disk.c standard geom/geom_dump.c standard geom/geom_event.c standard geom/geom_fox.c optional geom_fox -geom/geom_flashmap.c optional fdt cfi | fdt nand +geom/geom_flashmap.c optional fdt cfi | fdt nand | fdt mx25l geom/geom_io.c standard geom/geom_kern.c standard geom/geom_map.c optional geom_map diff --git a/sys/conf/files.arm b/sys/conf/files.arm index b3b9ea303b0..33bdd94265c 100644 --- a/sys/conf/files.arm +++ b/sys/conf/files.arm @@ -29,6 +29,7 @@ arm/arm/cpu_asm-v6.S optional armv6 arm/arm/db_disasm.c optional ddb arm/arm/db_interface.c optional ddb arm/arm/db_trace.c optional ddb +arm/arm/debug_monitor.c optional ddb armv6 arm/arm/devmap.c standard arm/arm/disassem.c optional ddb arm/arm/dump_machdep.c standard diff --git a/sys/conf/options b/sys/conf/options index acded0522f1..c7cd58181e8 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -90,6 +90,7 @@ COMPAT_LINUXKPI opt_compat.h COMPILING_LINT opt_global.h CY_PCI_FASTINTR DEADLKRES opt_watchdog.h +EXT_RESOURCES opt_global.h DIRECTIO FILEMON opt_dontuse.h FFCLOCK diff --git a/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb.h b/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb.h index 9fd3e0cf92b..81f305fad5e 100644 --- a/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb.h +++ b/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb.h @@ -174,4 +174,5 @@ static inline void remove_handle(struct iwch_dev *rhp, struct idr *idr, u32 id) } void iwch_ev_dispatch(struct iwch_dev *, struct mbuf *); +void process_newconn(struct iw_cm_id *parent_cm_id, struct socket *child_so); #endif diff --git a/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb_cm.c b/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb_cm.c index b98caaedf21..9bcc1b0daea 100644 --- a/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb_cm.c +++ b/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb_cm.c @@ -260,7 +260,6 @@ alloc_ep(int size, int flags) void __free_ep(struct iwch_ep_common *epc) { CTR3(KTR_IW_CXGB, "%s ep %p state %s", __FUNCTION__, epc, states[state_read(epc)]); - KASSERT(!epc->so, ("%s warning ep->so %p \n", __FUNCTION__, epc->so)); KASSERT(!epc->entry.tqe_prev, ("%s epc %p still on req list!\n", __FUNCTION__, epc)); free(epc, M_DEVBUF); } @@ -1361,7 +1360,7 @@ out: } int -iwch_create_listen(struct iw_cm_id *cm_id, int backlog) +iwch_create_listen_ep(struct iw_cm_id *cm_id, int backlog) { int err = 0; struct iwch_listen_ep *ep; @@ -1381,35 +1380,22 @@ iwch_create_listen(struct iw_cm_id *cm_id, int backlog) state_set(&ep->com, LISTEN); ep->com.so = cm_id->so; - err = init_sock(&ep->com); - if (err) - goto fail; - - err = solisten(ep->com.so, ep->backlog, ep->com.thread); - if (!err) { - cm_id->provider_data = ep; - goto out; - } - close_socket(&ep->com, 0); -fail: - cm_id->rem_ref(cm_id); - put_ep(&ep->com); + cm_id->provider_data = ep; out: return err; } -int -iwch_destroy_listen(struct iw_cm_id *cm_id) +void +iwch_destroy_listen_ep(struct iw_cm_id *cm_id) { struct iwch_listen_ep *ep = to_listen_ep(cm_id); CTR2(KTR_IW_CXGB, "%s ep %p", __FUNCTION__, ep); state_set(&ep->com, DEAD); - close_socket(&ep->com, 0); cm_id->rem_ref(cm_id); put_ep(&ep->com); - return 0; + return; } int @@ -1526,54 +1512,32 @@ process_connected(struct iwch_ep *ep) } } -static struct socket * -dequeue_socket(struct socket *head, struct sockaddr_in **remote, struct iwch_ep *child_ep) +void +process_newconn(struct iw_cm_id *parent_cm_id, struct socket *child_so) { - struct socket *so; - - ACCEPT_LOCK(); - so = TAILQ_FIRST(&head->so_comp); - if (!so) { - ACCEPT_UNLOCK(); - return NULL; - } - TAILQ_REMOVE(&head->so_comp, so, so_list); - head->so_qlen--; - SOCK_LOCK(so); - so->so_qstate &= ~SQ_COMP; - so->so_head = NULL; - soref(so); - soupcall_set(so, SO_RCV, iwch_so_upcall, child_ep); - so->so_state |= SS_NBIO; - PANIC_IF(!(so->so_state & SS_ISCONNECTED)); - PANIC_IF(so->so_error); - SOCK_UNLOCK(so); - ACCEPT_UNLOCK(); - soaccept(so, (struct sockaddr **)remote); - return so; -} - -static void -process_newconn(struct iwch_ep *parent_ep) -{ - struct socket *child_so; struct iwch_ep *child_ep; + struct sockaddr_in *local; struct sockaddr_in *remote; + struct iwch_ep *parent_ep = parent_cm_id->provider_data; CTR3(KTR_IW_CXGB, "%s parent ep %p so %p", __FUNCTION__, parent_ep, parent_ep->com.so); + if (!child_so) { + log(LOG_ERR, "%s - invalid child socket!\n", __func__); + return; + } child_ep = alloc_ep(sizeof(*child_ep), M_NOWAIT); if (!child_ep) { log(LOG_ERR, "%s - failed to allocate ep entry!\n", __FUNCTION__); return; } - child_so = dequeue_socket(parent_ep->com.so, &remote, child_ep); - if (!child_so) { - log(LOG_ERR, "%s - failed to dequeue child socket!\n", - __FUNCTION__); - __free_ep(&child_ep->com); - return; - } + SOCKBUF_LOCK(&child_so->so_rcv); + soupcall_set(child_so, SO_RCV, iwch_so_upcall, child_ep); + SOCKBUF_UNLOCK(&child_so->so_rcv); + + in_getsockaddr(child_so, (struct sockaddr **)&local); + in_getpeeraddr(child_so, (struct sockaddr **)&remote); + CTR3(KTR_IW_CXGB, "%s remote addr %s port %d", __FUNCTION__, inet_ntoa(remote->sin_addr), ntohs(remote->sin_port)); child_ep->com.tdev = parent_ep->com.tdev; @@ -1590,9 +1554,9 @@ process_newconn(struct iwch_ep *parent_ep) child_ep->com.thread = parent_ep->com.thread; child_ep->parent_ep = parent_ep; + free(local, M_SONAME); free(remote, M_SONAME); get_ep(&parent_ep->com); - child_ep->parent_ep = parent_ep; callout_init(&child_ep->timer, 1); state_set(&child_ep->com, MPA_REQ_WAIT); start_ep_timer(child_ep); @@ -1630,7 +1594,10 @@ process_socket_event(struct iwch_ep *ep) } if (state == LISTEN) { - process_newconn(ep); + /* socket listening events are handled at IWCM */ + CTR3(KTR_IW_CXGB, "%s Invalid ep state:%u, ep:%p", __func__, + ep->com.state, ep); + BUG(); return; } diff --git a/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb_cm.h b/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb_cm.h index ef76729f452..241106bf7dc 100644 --- a/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb_cm.h +++ b/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb_cm.h @@ -231,8 +231,8 @@ iwch_wakeup(struct cv *cv, struct mtx *lock, int *rpl_done) /* CM prototypes */ int iwch_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param); -int iwch_create_listen(struct iw_cm_id *cm_id, int backlog); -int iwch_destroy_listen(struct iw_cm_id *cm_id); +int iwch_create_listen_ep(struct iw_cm_id *cm_id, int backlog); +void iwch_destroy_listen_ep(struct iw_cm_id *cm_id); int iwch_reject_cr(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len); int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param); int iwch_ep_disconnect(struct iwch_ep *ep, int abrupt, int flags); diff --git a/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb_provider.c b/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb_provider.c index f9d36b32c00..448b99348fb 100644 --- a/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb_provider.c +++ b/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb_provider.c @@ -1140,8 +1140,9 @@ int iwch_register_device(struct iwch_dev *dev) dev->ibdev.iwcm->connect = iwch_connect; dev->ibdev.iwcm->accept = iwch_accept_cr; dev->ibdev.iwcm->reject = iwch_reject_cr; - dev->ibdev.iwcm->create_listen = iwch_create_listen; - dev->ibdev.iwcm->destroy_listen = iwch_destroy_listen; + dev->ibdev.iwcm->create_listen_ep = iwch_create_listen_ep; + dev->ibdev.iwcm->destroy_listen_ep = iwch_destroy_listen_ep; + dev->ibdev.iwcm->newconn = process_newconn; dev->ibdev.iwcm->add_ref = iwch_qp_add_ref; dev->ibdev.iwcm->rem_ref = iwch_qp_rem_ref; dev->ibdev.iwcm->get_qp = iwch_get_qp; diff --git a/sys/dev/cxgbe/iw_cxgbe/cm.c b/sys/dev/cxgbe/iw_cxgbe/cm.c index c3c7f4b3d88..c884f5a58f9 100644 --- a/sys/dev/cxgbe/iw_cxgbe/cm.c +++ b/sys/dev/cxgbe/iw_cxgbe/cm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2013 Chelsio, Inc. All rights reserved. + * Copyright (c) 2009-2013, 2016 Chelsio, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -111,8 +111,6 @@ static void ep_timeout(unsigned long arg); static void init_sock(struct c4iw_ep_common *epc); static void process_data(struct c4iw_ep *ep); static void process_connected(struct c4iw_ep *ep); -static struct socket * dequeue_socket(struct socket *head, struct sockaddr_in **remote, struct c4iw_ep *child_ep); -static void process_newconn(struct c4iw_ep *parent_ep); static int c4iw_so_upcall(struct socket *so, void *arg, int waitflag); static void process_socket_event(struct c4iw_ep *ep); static void release_ep_resources(struct c4iw_ep *ep); @@ -623,40 +621,21 @@ process_connected(struct c4iw_ep *ep) } } -static struct socket * -dequeue_socket(struct socket *head, struct sockaddr_in **remote, - struct c4iw_ep *child_ep) +void +process_newconn(struct iw_cm_id *parent_cm_id, struct socket *child_so) { - struct socket *so; - - ACCEPT_LOCK(); - so = TAILQ_FIRST(&head->so_comp); - if (!so) { - ACCEPT_UNLOCK(); - return (NULL); - } - TAILQ_REMOVE(&head->so_comp, so, so_list); - head->so_qlen--; - SOCK_LOCK(so); - so->so_qstate &= ~SQ_COMP; - so->so_head = NULL; - soref(so); - soupcall_set(so, SO_RCV, c4iw_so_upcall, child_ep); - so->so_state |= SS_NBIO; - SOCK_UNLOCK(so); - ACCEPT_UNLOCK(); - soaccept(so, (struct sockaddr **)remote); - - return (so); -} - -static void -process_newconn(struct c4iw_ep *parent_ep) -{ - struct socket *child_so; struct c4iw_ep *child_ep; + struct sockaddr_in *local; struct sockaddr_in *remote; + struct c4iw_ep *parent_ep = parent_cm_id->provider_data; + if (!child_so) { + CTR4(KTR_IW_CXGBE, + "%s: parent so %p, parent ep %p, child so %p, invalid so", + __func__, parent_ep->com.so, parent_ep, child_so); + log(LOG_ERR, "%s: invalid child socket\n", __func__); + return; + } child_ep = alloc_ep(sizeof(*child_ep), M_NOWAIT); if (!child_ep) { CTR3(KTR_IW_CXGBE, "%s: parent so %p, parent ep %p, ENOMEM", @@ -664,23 +643,18 @@ process_newconn(struct c4iw_ep *parent_ep) log(LOG_ERR, "%s: failed to allocate ep entry\n", __func__); return; } - - child_so = dequeue_socket(parent_ep->com.so, &remote, child_ep); - if (!child_so) { - CTR4(KTR_IW_CXGBE, - "%s: parent so %p, parent ep %p, child ep %p, dequeue err", - __func__, parent_ep->com.so, parent_ep, child_ep); - log(LOG_ERR, "%s: failed to dequeue child socket\n", __func__); - __free_ep(&child_ep->com); - return; - - } + SOCKBUF_LOCK(&child_so->so_rcv); + soupcall_set(child_so, SO_RCV, c4iw_so_upcall, child_ep); + SOCKBUF_UNLOCK(&child_so->so_rcv); CTR5(KTR_IW_CXGBE, "%s: parent so %p, parent ep %p, child so %p, child ep %p", __func__, parent_ep->com.so, parent_ep, child_so, child_ep); - child_ep->com.local_addr = parent_ep->com.local_addr; + in_getsockaddr(child_so, (struct sockaddr **)&local); + in_getpeeraddr(child_so, (struct sockaddr **)&remote); + + child_ep->com.local_addr = *local; child_ep->com.remote_addr = *remote; child_ep->com.dev = parent_ep->com.dev; child_ep->com.so = child_so; @@ -688,15 +662,17 @@ process_newconn(struct c4iw_ep *parent_ep) child_ep->com.thread = parent_ep->com.thread; child_ep->parent_ep = parent_ep; + free(local, M_SONAME); free(remote, M_SONAME); + c4iw_get_ep(&parent_ep->com); - child_ep->parent_ep = parent_ep; init_timer(&child_ep->timer); state_set(&child_ep->com, MPA_REQ_WAIT); START_EP_TIMER(child_ep); /* maybe the request has already been queued up on the socket... */ process_mpa_request(child_ep); + return; } static int @@ -738,7 +714,10 @@ process_socket_event(struct c4iw_ep *ep) } if (state == LISTEN) { - process_newconn(ep); + /* socket listening events are handled at IWCM */ + CTR3(KTR_IW_CXGBE, "%s Invalid ep state:%u, ep:%p", __func__, + ep->com.state, ep); + BUG(); return; } @@ -919,7 +898,6 @@ void _c4iw_free_ep(struct kref *kref) ep = container_of(kref, struct c4iw_ep, com.kref); epc = &ep->com; - KASSERT(!epc->so, ("%s ep->so %p", __func__, epc->so)); KASSERT(!epc->entry.tqe_prev, ("%s epc %p still on req list", __func__, epc)); kfree(ep); @@ -2126,10 +2104,10 @@ out: } /* - * iwcm->create_listen. Returns -errno on failure. + * iwcm->create_listen_ep. Returns -errno on failure. */ int -c4iw_create_listen(struct iw_cm_id *cm_id, int backlog) +c4iw_create_listen_ep(struct iw_cm_id *cm_id, int backlog) { int rc; struct c4iw_dev *dev = to_c4iw_dev(cm_id->device); @@ -2154,17 +2132,6 @@ c4iw_create_listen(struct iw_cm_id *cm_id, int backlog) ep->com.thread = curthread; state_set(&ep->com, LISTEN); ep->com.so = so; - init_sock(&ep->com); - - rc = solisten(so, ep->backlog, ep->com.thread); - if (rc != 0) { - log(LOG_ERR, "%s: failed to start listener: %d\n", __func__, - rc); - close_socket(&ep->com, 0); - cm_id->rem_ref(cm_id); - c4iw_put_ep(&ep->com); - goto failed; - } cm_id->provider_data = ep; return (0); @@ -2174,21 +2141,19 @@ failed: return (-rc); } -int -c4iw_destroy_listen(struct iw_cm_id *cm_id) +void +c4iw_destroy_listen_ep(struct iw_cm_id *cm_id) { - int rc; struct c4iw_listen_ep *ep = to_listen_ep(cm_id); - CTR4(KTR_IW_CXGBE, "%s: cm_id %p, so %p, inp %p", __func__, cm_id, - cm_id->so, cm_id->so->so_pcb); + CTR4(KTR_IW_CXGBE, "%s: cm_id %p, so %p, state %s", __func__, cm_id, + cm_id->so, states[ep->com.state]); state_set(&ep->com, DEAD); - rc = close_socket(&ep->com, 0); cm_id->rem_ref(cm_id); c4iw_put_ep(&ep->com); - return (rc); + return; } int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp) diff --git a/sys/dev/cxgbe/iw_cxgbe/iw_cxgbe.h b/sys/dev/cxgbe/iw_cxgbe/iw_cxgbe.h index e6d70f42998..f6c8a593ab8 100644 --- a/sys/dev/cxgbe/iw_cxgbe/iw_cxgbe.h +++ b/sys/dev/cxgbe/iw_cxgbe/iw_cxgbe.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2013 Chelsio, Inc. All rights reserved. + * Copyright (c) 2009-2013, 2016 Chelsio, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -850,8 +850,8 @@ int c4iw_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, int c4iw_bind_mw(struct ib_qp *qp, struct ib_mw *mw, struct ib_mw_bind *mw_bind); int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param); -int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog); -int c4iw_destroy_listen(struct iw_cm_id *cm_id); +int c4iw_create_listen_ep(struct iw_cm_id *cm_id, int backlog); +void c4iw_destroy_listen_ep(struct iw_cm_id *cm_id); int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param); int c4iw_reject_cr(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len); void c4iw_qp_add_ref(struct ib_qp *qp); @@ -914,6 +914,8 @@ u32 c4iw_get_qpid(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx); void c4iw_put_qpid(struct c4iw_rdev *rdev, u32 qid, struct c4iw_dev_ucontext *uctx); void c4iw_ev_dispatch(struct c4iw_dev *dev, struct t4_cqe *err_cqe); +void process_newconn(struct iw_cm_id *parent_cm_id, + struct socket *child_so); extern struct cxgb4_client t4c_client; extern c4iw_handler_func c4iw_handlers[NUM_CPL_CMDS]; diff --git a/sys/dev/cxgbe/iw_cxgbe/provider.c b/sys/dev/cxgbe/iw_cxgbe/provider.c index d7ce07932c3..a21fb9cdc74 100644 --- a/sys/dev/cxgbe/iw_cxgbe/provider.c +++ b/sys/dev/cxgbe/iw_cxgbe/provider.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2013 Chelsio, Inc. All rights reserved. + * Copyright (c) 2009-2013, 2016 Chelsio, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -474,8 +474,9 @@ c4iw_register_device(struct c4iw_dev *dev) iwcm->connect = c4iw_connect; iwcm->accept = c4iw_accept_cr; iwcm->reject = c4iw_reject_cr; - iwcm->create_listen = c4iw_create_listen; - iwcm->destroy_listen = c4iw_destroy_listen; + iwcm->create_listen_ep = c4iw_create_listen_ep; + iwcm->destroy_listen_ep = c4iw_destroy_listen_ep; + iwcm->newconn = process_newconn; iwcm->add_ref = c4iw_qp_add_ref; iwcm->rem_ref = c4iw_qp_rem_ref; iwcm->get_qp = c4iw_get_qp; diff --git a/sys/dev/extres/clk/clk.c b/sys/dev/extres/clk/clk.c new file mode 100644 index 00000000000..f1ed0986f40 --- /dev/null +++ b/sys/dev/extres/clk/clk.c @@ -0,0 +1,1261 @@ +/*- + * Copyright 2016 Michal Meloun + * 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 "opt_platform.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef FDT +#include +#include +#include +#endif +#include + +MALLOC_DEFINE(M_CLOCK, "clocks", "Clock framework"); + +/* Forward declarations. */ +struct clk; +struct clknodenode; +struct clkdom; + +typedef TAILQ_HEAD(clknode_list, clknode) clknode_list_t; +typedef TAILQ_HEAD(clkdom_list, clkdom) clkdom_list_t; + +/* Default clock methods. */ +static int clknode_method_init(struct clknode *clk, device_t dev); +static int clknode_method_recalc_freq(struct clknode *clk, uint64_t *freq); +static int clknode_method_set_freq(struct clknode *clk, uint64_t fin, + uint64_t *fout, int flags, int *stop); +static int clknode_method_set_gate(struct clknode *clk, bool enable); +static int clknode_method_set_mux(struct clknode *clk, int idx); + +/* + * Clock controller methods. + */ +static clknode_method_t clknode_methods[] = { + CLKNODEMETHOD(clknode_init, clknode_method_init), + CLKNODEMETHOD(clknode_recalc_freq, clknode_method_recalc_freq), + CLKNODEMETHOD(clknode_set_freq, clknode_method_set_freq), + CLKNODEMETHOD(clknode_set_gate, clknode_method_set_gate), + CLKNODEMETHOD(clknode_set_mux, clknode_method_set_mux), + + CLKNODEMETHOD_END +}; +DEFINE_CLASS_0(clknode, clknode_class, clknode_methods, 0); + +/* + * Clock node - basic element for modeling SOC clock graph. It holds the clock + * provider's data about the clock, and the links for the clock's membership in + * various lists. + */ +struct clknode { + KOBJ_FIELDS; + + /* Clock nodes topology. */ + struct clkdom *clkdom; /* Owning clock domain */ + TAILQ_ENTRY(clknode) clkdom_link; /* Domain list entry */ + TAILQ_ENTRY(clknode) clklist_link; /* Global list entry */ + + /* String based parent list. */ + const char **parent_names; /* Array of parent names */ + int parent_cnt; /* Number of parents */ + int parent_idx; /* Parent index or -1 */ + + /* Cache for already resolved names. */ + struct clknode **parents; /* Array of potential parents */ + struct clknode *parent; /* Current parent */ + + /* Parent/child relationship links. */ + clknode_list_t children; /* List of our children */ + TAILQ_ENTRY(clknode) sibling_link; /* Our entry in parent's list */ + + /* Details of this device. */ + void *softc; /* Instance softc */ + const char *name; /* Globally unique name */ + intptr_t id; /* Per domain unique id */ + int flags; /* CLK_FLAG_* */ + struct sx lock; /* Lock for this clock */ + int ref_cnt; /* Reference counter */ + int enable_cnt; /* Enabled counter */ + + /* Cached values. */ + uint64_t freq; /* Actual frequency */ +}; + +/* + * Per consumer data, information about how a consumer is using a clock node. + * A pointer to this structure is used as a handle in the consumer interface. + */ +struct clk { + device_t dev; + struct clknode *clknode; + int enable_cnt; +}; + +/* + * Clock domain - a group of clocks provided by one clock device. + */ +struct clkdom { + device_t dev; /* Link to provider device */ + TAILQ_ENTRY(clkdom) link; /* Global domain list entry */ + clknode_list_t clknode_list; /* All clocks in the domain */ + +#ifdef FDT + clknode_ofw_mapper_func *ofw_mapper; /* Find clock using FDT xref */ +#endif +}; + +/* + * The system-wide list of clock domains. + */ +static clkdom_list_t clkdom_list = TAILQ_HEAD_INITIALIZER(clkdom_list); + +/* + * Each clock node is linked on a system-wide list and can be searched by name. + */ +static clknode_list_t clknode_list = TAILQ_HEAD_INITIALIZER(clknode_list); + +/* + * Locking - we use three levels of locking: + * - First, topology lock is taken. This one protect all lists. + * - Second level is per clknode lock. It protects clknode data. + * - Third level is outside of this file, it protect clock device registers. + * First two levels use sleepable locks; clock device can use mutex or sx lock. + */ +static struct sx clk_topo_lock; +SX_SYSINIT(clock_topology, &clk_topo_lock, "Clock topology lock"); + +#define CLK_TOPO_SLOCK() sx_slock(&clk_topo_lock) +#define CLK_TOPO_XLOCK() sx_xlock(&clk_topo_lock) +#define CLK_TOPO_UNLOCK() sx_unlock(&clk_topo_lock) +#define CLK_TOPO_ASSERT() sx_assert(&clk_topo_lock, SA_LOCKED) +#define CLK_TOPO_XASSERT() sx_assert(&clk_topo_lock, SA_XLOCKED) + +#define CLKNODE_SLOCK(_sc) sx_slock(&((_sc)->lock)) +#define CLKNODE_XLOCK(_sc) sx_xlock(&((_sc)->lock)) +#define CLKNODE_UNLOCK(_sc) sx_unlock(&((_sc)->lock)) + +static void clknode_adjust_parent(struct clknode *clknode, int idx); + +/* + * Default clock methods for base class. + */ +static int +clknode_method_init(struct clknode *clknode, device_t dev) +{ + + return (0); +} + +static int +clknode_method_recalc_freq(struct clknode *clknode, uint64_t *freq) +{ + + return (0); +} + +static int +clknode_method_set_freq(struct clknode *clknode, uint64_t fin, uint64_t *fout, + int flags, int *stop) +{ + + *stop = 0; + return (0); +} + +static int +clknode_method_set_gate(struct clknode *clk, bool enable) +{ + + return (0); +} + +static int +clknode_method_set_mux(struct clknode *clk, int idx) +{ + + return (0); +} + +/* + * Internal functions. + */ + +/* + * Duplicate an array of parent names. + * + * Compute total size and allocate a single block which holds both the array of + * pointers to strings and the copied strings themselves. Returns a pointer to + * the start of the block where the array of copied string pointers lives. + * + * XXX Revisit this, no need for the DECONST stuff. + */ +static const char ** +strdup_list(const char **names, int num) +{ + size_t len, slen; + const char **outptr, *ptr; + int i; + + len = sizeof(char *) * num; + for (i = 0; i < num; i++) { + if (names[i] == NULL) + continue; + slen = strlen(names[i]); + if (slen == 0) + panic("Clock parent names array have empty string"); + len += slen + 1; + } + outptr = malloc(len, M_CLOCK, M_WAITOK | M_ZERO); + ptr = (char *)(outptr + num); + for (i = 0; i < num; i++) { + if (names[i] == NULL) + continue; + outptr[i] = ptr; + slen = strlen(names[i]) + 1; + bcopy(names[i], __DECONST(void *, outptr[i]), slen); + ptr += slen; + } + return (outptr); +} + +/* + * Recompute the cached frequency for this node and all its children. + */ +static int +clknode_refresh_cache(struct clknode *clknode, uint64_t freq) +{ + int rv; + struct clknode *entry; + + CLK_TOPO_XASSERT(); + + /* Compute generated frequency. */ + rv = CLKNODE_RECALC_FREQ(clknode, &freq); + if (rv != 0) { + /* XXX If an error happens while refreshing children + * this leaves the world in a partially-updated state. + * Panic for now. + */ + panic("clknode_refresh_cache failed for '%s'\n", + clknode->name); + return (rv); + } + /* Refresh cache for this node. */ + clknode->freq = freq; + + /* Refresh cache for all children. */ + TAILQ_FOREACH(entry, &(clknode->children), sibling_link) { + rv = clknode_refresh_cache(entry, freq); + if (rv != 0) + return (rv); + } + return (0); +} + +/* + * Public interface. + */ + +struct clknode * +clknode_find_by_name(const char *name) +{ + struct clknode *entry; + + CLK_TOPO_ASSERT(); + + TAILQ_FOREACH(entry, &clknode_list, clklist_link) { + if (strcmp(entry->name, name) == 0) + return (entry); + } + return (NULL); +} + +struct clknode * +clknode_find_by_id(struct clkdom *clkdom, intptr_t id) +{ + struct clknode *entry; + + CLK_TOPO_ASSERT(); + + TAILQ_FOREACH(entry, &clkdom->clknode_list, clkdom_link) { + if (entry->id == id) + return (entry); + } + + return (NULL); +} + +/* -------------------------------------------------------------------------- */ +/* + * Clock domain functions + */ + +/* Find clock domain associated to device in global list. */ +struct clkdom * +clkdom_get_by_dev(const device_t dev) +{ + struct clkdom *entry; + + CLK_TOPO_ASSERT(); + + TAILQ_FOREACH(entry, &clkdom_list, link) { + if (entry->dev == dev) + return (entry); + } + return (NULL); +} + + +#ifdef FDT +/* Default DT mapper. */ +static int +clknode_default_ofw_map(struct clkdom *clkdom, uint32_t ncells, + phandle_t *cells, struct clknode **clk) +{ + + CLK_TOPO_ASSERT(); + + if (ncells == 0) + *clk = clknode_find_by_id(clkdom, 1); + else if (ncells == 1) + *clk = clknode_find_by_id(clkdom, cells[0]); + else + return (ERANGE); + + if (*clk == NULL) + return (ENXIO); + return (0); +} +#endif + +/* + * Create a clock domain. Returns with the topo lock held. + */ +struct clkdom * +clkdom_create(device_t dev) +{ + struct clkdom *clkdom; + + clkdom = malloc(sizeof(struct clkdom), M_CLOCK, M_WAITOK | M_ZERO); + clkdom->dev = dev; + TAILQ_INIT(&clkdom->clknode_list); +#ifdef FDT + clkdom->ofw_mapper = clknode_default_ofw_map; +#endif + + return (clkdom); +} + +void +clkdom_unlock(struct clkdom *clkdom) +{ + + CLK_TOPO_UNLOCK(); +} + +void +clkdom_xlock(struct clkdom *clkdom) +{ + + CLK_TOPO_XLOCK(); +} + +/* + * Finalize initialization of clock domain. Releases topo lock. + * + * XXX Revisit failure handling. + */ +int +clkdom_finit(struct clkdom *clkdom) +{ + struct clknode *clknode; + int i, rv; +#ifdef FDT + phandle_t node; + + + if ((node = ofw_bus_get_node(clkdom->dev)) == -1) { + device_printf(clkdom->dev, + "%s called on not ofw based device\n", __func__); + return (ENXIO); + } +#endif + rv = 0; + + /* Make clock domain globally visible. */ + CLK_TOPO_XLOCK(); + TAILQ_INSERT_TAIL(&clkdom_list, clkdom, link); +#ifdef FDT + OF_device_register_xref(OF_xref_from_node(node), clkdom->dev); +#endif + + /* Register all clock names into global list. */ + TAILQ_FOREACH(clknode, &clkdom->clknode_list, clkdom_link) { + TAILQ_INSERT_TAIL(&clknode_list, clknode, clklist_link); + } + /* + * At this point all domain nodes must be registered and all + * parents must be valid. + */ + TAILQ_FOREACH(clknode, &clkdom->clknode_list, clkdom_link) { + if (clknode->parent_cnt == 0) + continue; + for (i = 0; i < clknode->parent_cnt; i++) { + if (clknode->parents[i] != NULL) + continue; + if (clknode->parent_names[i] == NULL) + continue; + clknode->parents[i] = clknode_find_by_name( + clknode->parent_names[i]); + if (clknode->parents[i] == NULL) { + device_printf(clkdom->dev, + "Clock %s have unknown parent: %s\n", + clknode->name, clknode->parent_names[i]); + rv = ENODEV; + } + } + + /* If parent index is not set yet... */ + if (clknode->parent_idx == CLKNODE_IDX_NONE) { + device_printf(clkdom->dev, + "Clock %s have not set parent idx\n", + clknode->name); + rv = ENXIO; + continue; + } + if (clknode->parents[clknode->parent_idx] == NULL) { + device_printf(clkdom->dev, + "Clock %s have unknown parent(idx %d): %s\n", + clknode->name, clknode->parent_idx, + clknode->parent_names[clknode->parent_idx]); + rv = ENXIO; + continue; + } + clknode_adjust_parent(clknode, clknode->parent_idx); + } + CLK_TOPO_UNLOCK(); + return (rv); +} + +/* Dump clock domain. */ +void +clkdom_dump(struct clkdom * clkdom) +{ + struct clknode *clknode; + int rv; + uint64_t freq; + + CLK_TOPO_SLOCK(); + TAILQ_FOREACH(clknode, &clkdom->clknode_list, clkdom_link) { + rv = clknode_get_freq(clknode, &freq); + printf("Clock: %s, parent: %s(%d), freq: %llu\n", clknode->name, + clknode->parent == NULL ? "(NULL)" : clknode->parent->name, + clknode->parent_idx, + ((rv == 0) ? freq: rv)); + } + CLK_TOPO_UNLOCK(); +} + +/* + * Create and initialize clock object, but do not register it. + */ +struct clknode * +clknode_create(struct clkdom * clkdom, clknode_class_t clknode_class, + const struct clknode_init_def *def) +{ + struct clknode *clknode; + + KASSERT(def->name != NULL, ("clock name is NULL")); + KASSERT(def->name[0] != '\0', ("clock name is empty")); +#ifdef INVARIANTS + CLK_TOPO_SLOCK(); + if (clknode_find_by_name(def->name) != NULL) + panic("Duplicated clock registration: %s\n", def->name); + CLK_TOPO_UNLOCK(); +#endif + + /* Create object and initialize it. */ + clknode = malloc(sizeof(struct clknode), M_CLOCK, M_WAITOK | M_ZERO); + kobj_init((kobj_t)clknode, (kobj_class_t)clknode_class); + sx_init(&clknode->lock, "Clocknode lock"); + + /* Allocate softc if required. */ + if (clknode_class->size > 0) { + clknode->softc = malloc(clknode_class->size, + M_CLOCK, M_WAITOK | M_ZERO); + } + + /* Prepare array for ptrs to parent clocks. */ + clknode->parents = malloc(sizeof(struct clknode *) * def->parent_cnt, + M_CLOCK, M_WAITOK | M_ZERO); + + /* Copy all strings unless they're flagged as static. */ + if (def->flags & CLK_NODE_STATIC_STRINGS) { + clknode->name = def->name; + clknode->parent_names = def->parent_names; + } else { + clknode->name = strdup(def->name, M_CLOCK); + clknode->parent_names = + strdup_list(def->parent_names, def->parent_cnt); + } + + /* Rest of init. */ + clknode->id = def->id; + clknode->clkdom = clkdom; + clknode->flags = def->flags; + clknode->parent_cnt = def->parent_cnt; + clknode->parent = NULL; + clknode->parent_idx = CLKNODE_IDX_NONE; + TAILQ_INIT(&clknode->children); + + return (clknode); +} + +/* + * Register clock object into clock domain hierarchy. + */ +struct clknode * +clknode_register(struct clkdom * clkdom, struct clknode *clknode) +{ + int rv; + + rv = CLKNODE_INIT(clknode, clknode_get_device(clknode)); + if (rv != 0) { + printf(" CLKNODE_INIT failed: %d\n", rv); + return (NULL); + } + + TAILQ_INSERT_TAIL(&clkdom->clknode_list, clknode, clkdom_link); + + return (clknode); +} + +/* + * Clock providers interface. + */ + +/* + * Reparent clock node. + */ +static void +clknode_adjust_parent(struct clknode *clknode, int idx) +{ + + CLK_TOPO_XASSERT(); + + if (clknode->parent_cnt == 0) + return; + if ((idx == CLKNODE_IDX_NONE) || (idx >= clknode->parent_cnt)) + panic("Invalid clock parent index\n"); + + if (clknode->parents[idx] == NULL) + panic("%s: Attempt to set invalid parent %d for clock %s", + __func__, idx, clknode->name); + + /* Remove me from old children list. */ + if (clknode->parent != NULL) { + TAILQ_REMOVE(&clknode->parent->children, clknode, sibling_link); + } + + /* Insert into children list of new parent. */ + clknode->parent_idx = idx; + clknode->parent = clknode->parents[idx]; + TAILQ_INSERT_TAIL(&clknode->parent->children, clknode, sibling_link); +} + +/* + * Set parent index - init function. + */ +void +clknode_init_parent_idx(struct clknode *clknode, int idx) +{ + + if (clknode->parent_cnt == 0) { + clknode->parent_idx = CLKNODE_IDX_NONE; + clknode->parent = NULL; + return; + } + if ((idx == CLKNODE_IDX_NONE) || + (idx >= clknode->parent_cnt) || + (clknode->parent_names[idx] == NULL)) + panic("%s: Invalid clock parent index: %d\n", __func__, idx); + + clknode->parent_idx = idx; +} + +int +clknode_set_parent_by_idx(struct clknode *clknode, int idx) +{ + int rv; + uint64_t freq; + int oldidx; + + /* We have exclusive topology lock, node lock is not needed. */ + CLK_TOPO_XASSERT(); + + if (clknode->parent_cnt == 0) + return (0); + + if (clknode->parent_idx == idx) + return (0); + + oldidx = clknode->parent_idx; + clknode_adjust_parent(clknode, idx); + rv = CLKNODE_SET_MUX(clknode, idx); + if (rv != 0) { + clknode_adjust_parent(clknode, oldidx); + return (rv); + } + rv = clknode_get_freq(clknode->parent, &freq); + if (rv != 0) + return (rv); + rv = clknode_refresh_cache(clknode, freq); + return (rv); +} + +int +clknode_set_parent_by_name(struct clknode *clknode, const char *name) +{ + int rv; + uint64_t freq; + int oldidx, idx; + + /* We have exclusive topology lock, node lock is not needed. */ + CLK_TOPO_XASSERT(); + + if (clknode->parent_cnt == 0) + return (0); + + /* + * If this node doesnt have mux, then passthrough request to parent. + * This feature is used in clock domain initialization and allows us to + * set clock source and target frequency on the tail node of the clock + * chain. + */ + if (clknode->parent_cnt == 1) { + rv = clknode_set_parent_by_name(clknode->parent, name); + return (rv); + } + + for (idx = 0; idx < clknode->parent_cnt; idx++) { + if (clknode->parent_names[idx] == NULL) + continue; + if (strcmp(clknode->parent_names[idx], name) == 0) + break; + } + if (idx >= clknode->parent_cnt) { + return (ENXIO); + } + if (clknode->parent_idx == idx) + return (0); + + oldidx = clknode->parent_idx; + clknode_adjust_parent(clknode, idx); + rv = CLKNODE_SET_MUX(clknode, idx); + if (rv != 0) { + clknode_adjust_parent(clknode, oldidx); + CLKNODE_UNLOCK(clknode); + return (rv); + } + rv = clknode_get_freq(clknode->parent, &freq); + if (rv != 0) + return (rv); + rv = clknode_refresh_cache(clknode, freq); + return (rv); +} + +struct clknode * +clknode_get_parent(struct clknode *clknode) +{ + + return (clknode->parent); +} + +const char * +clknode_get_name(struct clknode *clknode) +{ + + return (clknode->name); +} + +const char ** +clknode_get_parent_names(struct clknode *clknode) +{ + + return (clknode->parent_names); +} + +int +clknode_get_parents_num(struct clknode *clknode) +{ + + return (clknode->parent_cnt); +} + +int +clknode_get_parent_idx(struct clknode *clknode) +{ + + return (clknode->parent_idx); +} + +int +clknode_get_flags(struct clknode *clknode) +{ + + return (clknode->flags); +} + + +void * +clknode_get_softc(struct clknode *clknode) +{ + + return (clknode->softc); +} + +device_t +clknode_get_device(struct clknode *clknode) +{ + + return (clknode->clkdom->dev); +} + +#ifdef FDT +void +clkdom_set_ofw_mapper(struct clkdom * clkdom, clknode_ofw_mapper_func *map) +{ + + clkdom->ofw_mapper = map; +} +#endif + +/* + * Real consumers executive + */ +int +clknode_get_freq(struct clknode *clknode, uint64_t *freq) +{ + int rv; + + CLK_TOPO_ASSERT(); + + /* Use cached value, if it exists. */ + *freq = clknode->freq; + if (*freq != 0) + return (0); + + /* Get frequency from parent, if the clock has a parent. */ + if (clknode->parent_cnt > 0) { + rv = clknode_get_freq(clknode->parent, freq); + if (rv != 0) { + return (rv); + } + } + + /* And recalculate my output frequency. */ + CLKNODE_XLOCK(clknode); + rv = CLKNODE_RECALC_FREQ(clknode, freq); + if (rv != 0) { + CLKNODE_UNLOCK(clknode); + printf("Cannot get frequency for clk: %s, error: %d\n", + clknode->name, rv); + return (rv); + } + + /* Save new frequency to cache. */ + clknode->freq = *freq; + CLKNODE_UNLOCK(clknode); + return (0); +} + +int +clknode_set_freq(struct clknode *clknode, uint64_t freq, int flags, + int enablecnt) +{ + int rv, done; + uint64_t parent_freq; + + /* We have exclusive topology lock, node lock is not needed. */ + CLK_TOPO_XASSERT(); + + parent_freq = 0; + + /* + * We can set frequency only if + * clock is disabled + * OR + * clock is glitch free and is enabled by calling consumer only + */ + if ((clknode->enable_cnt > 1) && + ((clknode->enable_cnt > enablecnt) || + !(clknode->flags & CLK_NODE_GLITCH_FREE))) { + return (EBUSY); + } + + /* Get frequency from parent, if the clock has a parent. */ + if (clknode->parent_cnt > 0) { + rv = clknode_get_freq(clknode->parent, &parent_freq); + if (rv != 0) { + return (rv); + } + } + + /* Set frequency for this clock. */ + rv = CLKNODE_SET_FREQ(clknode, parent_freq, &freq, flags, &done); + if (rv != 0) { + printf("Cannot set frequency for clk: %s, error: %d\n", + clknode->name, rv); + if ((flags & CLK_SET_DRYRUN) == 0) + clknode_refresh_cache(clknode, parent_freq); + return (rv); + } + + if (done) { + /* Success - invalidate frequency cache for all children. */ + clknode->freq = freq; + if ((flags & CLK_SET_DRYRUN) == 0) + clknode_refresh_cache(clknode, parent_freq); + } else if (clknode->parent != NULL) { + /* Nothing changed, pass request to parent. */ + rv = clknode_set_freq(clknode->parent, freq, flags, enablecnt); + } else { + /* End of chain without action. */ + printf("Cannot set frequency for clk: %s, end of chain\n", + clknode->name); + rv = ENXIO; + } + + return (rv); +} + +int +clknode_enable(struct clknode *clknode) +{ + int rv; + + CLK_TOPO_ASSERT(); + + /* Enable clock for each node in chain, starting from source. */ + if (clknode->parent_cnt > 0) { + rv = clknode_enable(clknode->parent); + if (rv != 0) { + return (rv); + } + } + + /* Handle this node */ + CLKNODE_XLOCK(clknode); + if (clknode->enable_cnt == 0) { + rv = CLKNODE_SET_GATE(clknode, 1); + if (rv != 0) { + CLKNODE_UNLOCK(clknode); + return (rv); + } + } + clknode->enable_cnt++; + CLKNODE_UNLOCK(clknode); + return (0); +} + +int +clknode_disable(struct clknode *clknode) +{ + int rv; + + CLK_TOPO_ASSERT(); + rv = 0; + + CLKNODE_XLOCK(clknode); + /* Disable clock for each node in chain, starting from consumer. */ + if ((clknode->enable_cnt == 1) && + ((clknode->flags & CLK_NODE_CANNOT_STOP) == 0)) { + rv = CLKNODE_SET_GATE(clknode, 0); + if (rv != 0) { + CLKNODE_UNLOCK(clknode); + return (rv); + } + } + clknode->enable_cnt--; + CLKNODE_UNLOCK(clknode); + + if (clknode->parent_cnt > 0) { + rv = clknode_disable(clknode->parent); + } + return (rv); +} + +int +clknode_stop(struct clknode *clknode, int depth) +{ + int rv; + + CLK_TOPO_ASSERT(); + rv = 0; + + CLKNODE_XLOCK(clknode); + /* The first node cannot be enabled. */ + if ((clknode->enable_cnt != 0) && (depth == 0)) { + CLKNODE_UNLOCK(clknode); + return (EBUSY); + } + /* Stop clock for each node in chain, starting from consumer. */ + if ((clknode->enable_cnt == 0) && + ((clknode->flags & CLK_NODE_CANNOT_STOP) == 0)) { + rv = CLKNODE_SET_GATE(clknode, 0); + if (rv != 0) { + CLKNODE_UNLOCK(clknode); + return (rv); + } + } + CLKNODE_UNLOCK(clknode); + + if (clknode->parent_cnt > 0) + rv = clknode_stop(clknode->parent, depth + 1); + return (rv); +} + +/* -------------------------------------------------------------------------- + * + * Clock consumers interface. + * + */ +/* Helper function for clk_get*() */ +static clk_t +clk_create(struct clknode *clknode, device_t dev) +{ + struct clk *clk; + + CLK_TOPO_ASSERT(); + + clk = malloc(sizeof(struct clk), M_CLOCK, M_WAITOK); + clk->dev = dev; + clk->clknode = clknode; + clk->enable_cnt = 0; + clknode->ref_cnt++; + + return (clk); +} + +int +clk_get_freq(clk_t clk, uint64_t *freq) +{ + int rv; + struct clknode *clknode; + + clknode = clk->clknode; + KASSERT(clknode->ref_cnt > 0, + ("Attempt to access unreferenced clock: %s\n", clknode->name)); + + CLK_TOPO_SLOCK(); + rv = clknode_get_freq(clknode, freq); + CLK_TOPO_UNLOCK(); + return (rv); +} + +int +clk_set_freq(clk_t clk, uint64_t freq, int flags) +{ + int rv; + struct clknode *clknode; + + flags &= CLK_SET_USER_MASK; + clknode = clk->clknode; + KASSERT(clknode->ref_cnt > 0, + ("Attempt to access unreferenced clock: %s\n", clknode->name)); + + CLK_TOPO_XLOCK(); + rv = clknode_set_freq(clknode, freq, flags, clk->enable_cnt); + CLK_TOPO_UNLOCK(); + return (rv); +} + +int +clk_test_freq(clk_t clk, uint64_t freq, int flags) +{ + int rv; + struct clknode *clknode; + + flags &= CLK_SET_USER_MASK; + clknode = clk->clknode; + KASSERT(clknode->ref_cnt > 0, + ("Attempt to access unreferenced clock: %s\n", clknode->name)); + + CLK_TOPO_XLOCK(); + rv = clknode_set_freq(clknode, freq, flags | CLK_SET_DRYRUN, 0); + CLK_TOPO_UNLOCK(); + return (rv); +} + +int +clk_get_parent(clk_t clk, clk_t *parent) +{ + struct clknode *clknode; + struct clknode *parentnode; + + clknode = clk->clknode; + KASSERT(clknode->ref_cnt > 0, + ("Attempt to access unreferenced clock: %s\n", clknode->name)); + + CLK_TOPO_SLOCK(); + parentnode = clknode_get_parent(clknode); + if (parentnode == NULL) { + CLK_TOPO_UNLOCK(); + return (ENODEV); + } + *parent = clk_create(parentnode, clk->dev); + CLK_TOPO_UNLOCK(); + return (0); +} + +int +clk_set_parent_by_clk(clk_t clk, clk_t parent) +{ + int rv; + struct clknode *clknode; + struct clknode *parentnode; + + clknode = clk->clknode; + parentnode = parent->clknode; + KASSERT(clknode->ref_cnt > 0, + ("Attempt to access unreferenced clock: %s\n", clknode->name)); + KASSERT(parentnode->ref_cnt > 0, + ("Attempt to access unreferenced clock: %s\n", clknode->name)); + CLK_TOPO_XLOCK(); + rv = clknode_set_parent_by_name(clknode, parentnode->name); + CLK_TOPO_UNLOCK(); + return (rv); +} + +int +clk_enable(clk_t clk) +{ + int rv; + struct clknode *clknode; + + clknode = clk->clknode; + KASSERT(clknode->ref_cnt > 0, + ("Attempt to access unreferenced clock: %s\n", clknode->name)); + CLK_TOPO_SLOCK(); + rv = clknode_enable(clknode); + if (rv == 0) + clk->enable_cnt++; + CLK_TOPO_UNLOCK(); + return (rv); +} + +int +clk_disable(clk_t clk) +{ + int rv; + struct clknode *clknode; + + clknode = clk->clknode; + KASSERT(clknode->ref_cnt > 0, + ("Attempt to access unreferenced clock: %s\n", clknode->name)); + KASSERT(clk->enable_cnt > 0, + ("Attempt to disable already disabled clock: %s\n", clknode->name)); + CLK_TOPO_SLOCK(); + rv = clknode_disable(clknode); + if (rv == 0) + clk->enable_cnt--; + CLK_TOPO_UNLOCK(); + return (rv); +} + +int +clk_stop(clk_t clk) +{ + int rv; + struct clknode *clknode; + + clknode = clk->clknode; + KASSERT(clknode->ref_cnt > 0, + ("Attempt to access unreferenced clock: %s\n", clknode->name)); + KASSERT(clk->enable_cnt == 0, + ("Attempt to stop already enabled clock: %s\n", clknode->name)); + + CLK_TOPO_SLOCK(); + rv = clknode_stop(clknode, 0); + CLK_TOPO_UNLOCK(); + return (rv); +} + +int +clk_release(clk_t clk) +{ + struct clknode *clknode; + + clknode = clk->clknode; + KASSERT(clknode->ref_cnt > 0, + ("Attempt to access unreferenced clock: %s\n", clknode->name)); + CLK_TOPO_SLOCK(); + while (clk->enable_cnt > 0) { + clknode_disable(clknode); + clk->enable_cnt--; + } + CLKNODE_XLOCK(clknode); + clknode->ref_cnt--; + CLKNODE_UNLOCK(clknode); + CLK_TOPO_UNLOCK(); + + free(clk, M_CLOCK); + return (0); +} + +const char * +clk_get_name(clk_t clk) +{ + const char *name; + struct clknode *clknode; + + clknode = clk->clknode; + KASSERT(clknode->ref_cnt > 0, + ("Attempt to access unreferenced clock: %s\n", clknode->name)); + name = clknode_get_name(clknode); + return (name); +} + +int +clk_get_by_name(device_t dev, const char *name, clk_t *clk) +{ + struct clknode *clknode; + + CLK_TOPO_SLOCK(); + clknode = clknode_find_by_name(name); + if (clknode == NULL) { + CLK_TOPO_UNLOCK(); + return (ENODEV); + } + *clk = clk_create(clknode, dev); + CLK_TOPO_UNLOCK(); + return (0); +} + +int +clk_get_by_id(device_t dev, struct clkdom *clkdom, intptr_t id, clk_t *clk) +{ + struct clknode *clknode; + + CLK_TOPO_SLOCK(); + + clknode = clknode_find_by_id(clkdom, id); + if (clknode == NULL) { + CLK_TOPO_UNLOCK(); + return (ENODEV); + } + *clk = clk_create(clknode, dev); + CLK_TOPO_UNLOCK(); + + return (0); +} + +#ifdef FDT + +int +clk_get_by_ofw_index(device_t dev, int idx, clk_t *clk) +{ + phandle_t cnode, parent, *cells; + device_t clockdev; + int ncells, rv; + struct clkdom *clkdom; + struct clknode *clknode; + + *clk = NULL; + + cnode = ofw_bus_get_node(dev); + if (cnode <= 0) { + device_printf(dev, "%s called on not ofw based device\n", + __func__); + return (ENXIO); + } + + rv = ofw_bus_parse_xref_list_alloc(cnode, "clocks", "#clock-cells", idx, + &parent, &ncells, &cells); + if (rv != 0) { + return (rv); + } + + clockdev = OF_device_from_xref(parent); + if (clockdev == NULL) { + rv = ENODEV; + goto done; + } + + CLK_TOPO_SLOCK(); + clkdom = clkdom_get_by_dev(clockdev); + if (clkdom == NULL){ + CLK_TOPO_UNLOCK(); + rv = ENXIO; + goto done; + } + + rv = clkdom->ofw_mapper(clkdom, ncells, cells, &clknode); + if (rv == 0) { + *clk = clk_create(clknode, dev); + } + CLK_TOPO_UNLOCK(); + +done: + if (cells != NULL) + free(cells, M_OFWPROP); + return (rv); +} + +int +clk_get_by_ofw_name(device_t dev, const char *name, clk_t *clk) +{ + int rv, idx; + phandle_t cnode; + + cnode = ofw_bus_get_node(dev); + if (cnode <= 0) { + device_printf(dev, "%s called on not ofw based device\n", + __func__); + return (ENXIO); + } + rv = ofw_bus_find_string_index(cnode, "clock-names", name, &idx); + if (rv != 0) + return (rv); + return (clk_get_by_ofw_index(dev, idx, clk)); +} +#endif diff --git a/sys/dev/extres/clk/clk.h b/sys/dev/extres/clk/clk.h new file mode 100644 index 00000000000..8547bae4a24 --- /dev/null +++ b/sys/dev/extres/clk/clk.h @@ -0,0 +1,136 @@ +/*- + * Copyright 2016 Michal Meloun + * 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$ + */ + +#ifndef _DEV_EXTRES_CLK_H_ +#define _DEV_EXTRES_CLK_H_ +#include "opt_platform.h" + +#include +#ifdef FDT +#include +#endif +#include "clknode_if.h" + +#define CLKNODE_IDX_NONE -1 /* Not-selected index */ + +/* clknode flags. */ +#define CLK_NODE_STATIC_STRINGS 0x00000001 /* Static name strings */ +#define CLK_NODE_GLITCH_FREE 0x00000002 /* Freq can change w/o stop */ +#define CLK_NODE_CANNOT_STOP 0x00000004 /* Clock cannot be disabled */ + +/* Flags passed to clk_set_freq() and clknode_set_freq(). */ +#define CLK_SET_ROUND_UP 0x00000001 +#define CLK_SET_ROUND_DOWN 0x00000002 +#define CLK_SET_USER_MASK 0x0000FFFF +#define CLK_SET_DRYRUN 0x00010000 + +typedef struct clk *clk_t; + +/* Initialization parameters for clocknode creation. */ +struct clknode_init_def { + const char *name; + intptr_t id; + const char **parent_names; + int parent_cnt; + int flags; +}; + +/* + * Shorthands for constructing method tables. + */ +#define CLKNODEMETHOD KOBJMETHOD +#define CLKNODEMETHOD_END KOBJMETHOD_END +#define clknode_method_t kobj_method_t +#define clknode_class_t kobj_class_t +DECLARE_CLASS(clknode_class); + +/* + * Clock domain functions. + */ +struct clkdom *clkdom_create(device_t dev); +int clkdom_finit(struct clkdom *clkdom); +void clkdom_dump(struct clkdom * clkdom); +void clkdom_unlock(struct clkdom *clkdom); +void clkdom_xlock(struct clkdom *clkdom); + +/* + * Clock providers interface. + */ +struct clkdom *clkdom_get_by_dev(const device_t dev); + +struct clknode *clknode_create(struct clkdom *clkdom, + clknode_class_t clknode_class, const struct clknode_init_def *def); +struct clknode *clknode_register(struct clkdom *cldom, struct clknode *clk); +#ifdef FDT +typedef int clknode_ofw_mapper_func(struct clkdom *clkdom, uint32_t ncells, + phandle_t *cells, struct clknode **clk); +void clkdom_set_ofw_mapper(struct clkdom *clkdom, clknode_ofw_mapper_func *cmp); +#endif + +void clknode_init_parent_idx(struct clknode *clknode, int idx); +int clknode_set_parent_by_idx(struct clknode *clk, int idx); +int clknode_set_parent_by_name(struct clknode *clk, const char *name); +const char *clknode_get_name(struct clknode *clk); +const char **clknode_get_parent_names(struct clknode *clk); +int clknode_get_parents_num(struct clknode *clk); +int clknode_get_parent_idx(struct clknode *clk); +struct clknode *clknode_get_parent(struct clknode *clk); +int clknode_get_flags(struct clknode *clk); +void *clknode_get_softc(struct clknode *clk); +device_t clknode_get_device(struct clknode *clk); +struct clknode *clknode_find_by_name(const char *name); +struct clknode *clknode_find_by_id(struct clkdom *clkdom, intptr_t id); +int clknode_get_freq(struct clknode *clknode, uint64_t *freq); +int clknode_set_freq(struct clknode *clknode, uint64_t freq, int flags, + int enablecnt); +int clknode_enable(struct clknode *clknode); +int clknode_disable(struct clknode *clknode); +int clknode_stop(struct clknode *clknode, int depth); + +/* + * Clock consumers interface. + */ +int clk_get_by_name(device_t dev, const char *name, clk_t *clk); +int clk_get_by_id(device_t dev, struct clkdom *clkdom, intptr_t id, clk_t *clk); +int clk_release(clk_t clk); +int clk_get_freq(clk_t clk, uint64_t *freq); +int clk_set_freq(clk_t clk, uint64_t freq, int flags); +int clk_test_freq(clk_t clk, uint64_t freq, int flags); +int clk_enable(clk_t clk); +int clk_disable(clk_t clk); +int clk_stop(clk_t clk); +int clk_get_parent(clk_t clk, clk_t *parent); +int clk_set_parent_by_clk(clk_t clk, clk_t parent); +const char *clk_get_name(clk_t clk); + +#ifdef FDT +int clk_get_by_ofw_index(device_t dev, int idx, clk_t *clk); +int clk_get_by_ofw_name(device_t dev, const char *name, clk_t *clk); +#endif + +#endif /* _DEV_EXTRES_CLK_H_ */ diff --git a/sys/dev/extres/clk/clk_div.c b/sys/dev/extres/clk/clk_div.c new file mode 100644 index 00000000000..fcb0a57c4f7 --- /dev/null +++ b/sys/dev/extres/clk/clk_div.c @@ -0,0 +1,209 @@ +/*- + * Copyright 2016 Michal Meloun + * 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 "clkdev_if.h" + +#define WR4(_clk, off, val) \ + CLKDEV_WRITE_4(clknode_get_device(_clk), off, val) +#define RD4(_clk, off, val) \ + CLKDEV_READ_4(clknode_get_device(_clk), off, val) +#define MD4(_clk, off, clr, set ) \ + CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set) + +static int clknode_div_init(struct clknode *clk, device_t dev); +static int clknode_div_recalc(struct clknode *clk, uint64_t *req); +static int clknode_div_set_freq(struct clknode *clknode, uint64_t fin, + uint64_t *fout, int flag, int *stop); + +struct clknode_div_sc { + struct mtx *mtx; + struct resource *mem_res; + uint32_t offset; + uint32_t i_shift; + uint32_t i_mask; + uint32_t i_width; + uint32_t f_shift; + uint32_t f_mask; + uint32_t f_width; + int div_flags; + uint32_t divider; /* in natural form */ +}; + +static clknode_method_t clknode_div_methods[] = { + /* Device interface */ + CLKNODEMETHOD(clknode_init, clknode_div_init), + CLKNODEMETHOD(clknode_recalc_freq, clknode_div_recalc), + CLKNODEMETHOD(clknode_set_freq, clknode_div_set_freq), + CLKNODEMETHOD_END +}; +DEFINE_CLASS_1(clknode_div, clknode_div_class, clknode_div_methods, + sizeof(struct clknode_div_sc), clknode_class); + +static int +clknode_div_init(struct clknode *clk, device_t dev) +{ + uint32_t reg; + struct clknode_div_sc *sc; + uint32_t i_div, f_div; + int rv; + + sc = clknode_get_softc(clk); + + rv = RD4(clk, sc->offset, ®); + if (rv != 0) + return (rv); + + i_div = (reg >> sc->i_shift) & sc->i_mask; + if (!(sc->div_flags & CLK_DIV_ZERO_BASED)) + i_div++; + f_div = (reg >> sc->f_shift) & sc->f_mask; + sc->divider = i_div << sc->f_width | f_div; + clknode_init_parent_idx(clk, 0); + return(0); +} + +static int +clknode_div_recalc(struct clknode *clk, uint64_t *freq) +{ + struct clknode_div_sc *sc; + + sc = clknode_get_softc(clk); + if (sc->divider == 0) { + printf("%s: %s divider is zero!\n", clknode_get_name(clk), + __func__); + *freq = 0; + return(EINVAL); + } + *freq = (*freq << sc->f_width) / sc->divider; + return (0); +} + +static int +clknode_div_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout, + int flags, int *stop) +{ + struct clknode_div_sc *sc; + uint64_t divider, _fin, _fout; + uint32_t reg, i_div, f_div, hw_i_div; + int rv; + + sc = clknode_get_softc(clk); + + /* For fractional divider. */ + _fin = fin << sc->f_width; + divider = (_fin + *fout / 2) / *fout; + _fout = _fin / divider; + + /* Rounding. */ + if ((flags & CLK_SET_ROUND_UP) && (*fout < _fout)) + divider--; + else if ((flags & CLK_SET_ROUND_DOWN) && (*fout > _fout)) + divider++; + + /* Break divider into integer and fractional parts. */ + i_div = divider >> sc->f_width; + f_div = divider & sc->f_mask; + + if (i_div == 0) { + printf("%s: %s integer divider is zero!\n", + clknode_get_name(clk), __func__); + return(EINVAL); + } + + hw_i_div = i_div; + if (!(sc->div_flags & CLK_DIV_ZERO_BASED)) + hw_i_div--; + + *stop = 1; + if (hw_i_div > sc->i_mask) { + /* XXX Or only return error? */ + printf("%s: %s integer divider is too big: %u\n", + clknode_get_name(clk), __func__, hw_i_div); + hw_i_div = sc->i_mask; + *stop = 0; + } + + i_div = hw_i_div; + if (!(sc->div_flags & CLK_DIV_ZERO_BASED)) + i_div++; + divider = i_div << sc->f_width | f_div; + + if ((flags & CLK_SET_DRYRUN) == 0) { + if ((*stop != 0) && + ((flags & (CLK_SET_ROUND_UP | CLK_SET_ROUND_DOWN)) == 0) && + (*fout != (_fin / divider))) + return (ERANGE); + + rv = MD4(clk, sc->offset, + (sc->i_mask << sc->i_shift) | (sc->f_mask << sc->f_shift), + (i_div << sc->i_shift) | (f_div << sc->f_shift)); + if (rv != 0) + return (rv); + RD4(clk, sc->offset, ®); + sc->divider = divider; + } + + *fout = _fin / divider; + return (0); +} + +int +clknode_div_register(struct clkdom *clkdom, struct clk_div_def *clkdef) +{ + struct clknode *clk; + struct clknode_div_sc *sc; + + clk = clknode_create(clkdom, &clknode_div_class, &clkdef->clkdef); + if (clk == NULL) + return (1); + + sc = clknode_get_softc(clk); + sc->offset = clkdef->offset; + sc->i_shift = clkdef->i_shift; + sc->i_width = clkdef->i_width; + sc->i_mask = (1 << clkdef->i_width) - 1; + sc->f_shift = clkdef->f_shift; + sc->f_width = clkdef->f_width; + sc->f_mask = (1 << clkdef->f_width) - 1; + sc->div_flags = clkdef->div_flags; + + clknode_register(clkdom, clk); + return (0); +} diff --git a/sys/dev/extres/clk/clk_div.h b/sys/dev/extres/clk/clk_div.h new file mode 100644 index 00000000000..85b8a0194eb --- /dev/null +++ b/sys/dev/extres/clk/clk_div.h @@ -0,0 +1,48 @@ +/*- + * Copyright 2016 Michal Meloun + * 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$ + */ + +#ifndef _DEV_EXTRES_CLK_DIV_H_ +#define _DEV_EXTRES_CLK_DIV_H_ + +#include + +#define CLK_DIV_ZERO_BASED 0x0001 /* Zero based divider. */ + +struct clk_div_def { + struct clknode_init_def clkdef; + uint32_t offset; /* Divider register offset */ + uint32_t i_shift; /* Pos of div bits in reg */ + uint32_t i_width; /* Width of div bit field */ + uint32_t f_shift; /* Fractional divide bits, */ + uint32_t f_width; /* set to 0 for int divider */ + int div_flags; /* Divider-specific flags */ +}; + +int clknode_div_register(struct clkdom *clkdom, struct clk_div_def *clkdef); + +#endif /*_DEV_EXTRES_CLK_DIV_H_*/ diff --git a/sys/dev/extres/clk/clk_fixed.c b/sys/dev/extres/clk/clk_fixed.c new file mode 100644 index 00000000000..4ddceae5a92 --- /dev/null +++ b/sys/dev/extres/clk/clk_fixed.c @@ -0,0 +1,114 @@ +/*- + * Copyright 2016 Michal Meloun + * 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 + +#include + +#define DEVICE_LOCK(_sc) mtx_lock((_sc)->mtx) +#define DEVICE_UNLOCK(_sc) mtx_unlock((_sc)->mtx) + +static int clknode_fixed_init(struct clknode *clk, device_t dev); +static int clknode_fixed_recalc(struct clknode *clk, uint64_t *freq); +struct clknode_fixed_sc { + struct mtx *mtx; + int fixed_flags; + uint64_t freq; + uint32_t mult; + uint32_t div; +}; + +static clknode_method_t clknode_fixed_methods[] = { + /* Device interface */ + CLKNODEMETHOD(clknode_init, clknode_fixed_init), + CLKNODEMETHOD(clknode_recalc_freq, clknode_fixed_recalc), + CLKNODEMETHOD_END +}; +DEFINE_CLASS_1(clknode_fixed, clknode_fixed_class, clknode_fixed_methods, + sizeof(struct clknode_fixed_sc), clknode_class); + +static int +clknode_fixed_init(struct clknode *clk, device_t dev) +{ + struct clknode_fixed_sc *sc; + + sc = clknode_get_softc(clk); + if (sc->freq == 0) + clknode_init_parent_idx(clk, 0); + return(0); +} +static int +clknode_fixed_recalc(struct clknode *clk, uint64_t *freq) +{ + struct clknode_fixed_sc *sc; + + sc = clknode_get_softc(clk); + if (sc->freq != 0) + *freq = sc->freq; + else if ((sc->mult != 0) && (sc->div != 0)) + *freq = (*freq / sc->div) * sc->mult; + else + *freq = 0; + return (0); +} + +int +clknode_fixed_register(struct clkdom *clkdom, struct clk_fixed_def *clkdef, + struct mtx *dev_mtx) +{ + struct clknode *clk; + struct clknode_fixed_sc *sc; + + if ((clkdef->freq == 0) && (clkdef->clkdef.parent_cnt == 0)) + panic("fixed clk: Frequency is not defined for clock source"); + clk = clknode_create(clkdom, &clknode_fixed_class, &clkdef->clkdef); + if (clk == NULL) + return (1); + + sc = clknode_get_softc(clk); + sc->mtx = dev_mtx; + sc->fixed_flags = clkdef->fixed_flags; + sc->freq = clkdef->freq; + sc->mult = clkdef->mult; + sc->div = clkdef->div; + + clknode_register(clkdom, clk); + return (0); +} diff --git a/sys/dev/extres/clk/clk_fixed.h b/sys/dev/extres/clk/clk_fixed.h new file mode 100644 index 00000000000..f57ee960d71 --- /dev/null +++ b/sys/dev/extres/clk/clk_fixed.h @@ -0,0 +1,53 @@ +/*- + * Copyright 2016 Michal Meloun + * 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$ + */ + +#ifndef _DEV_EXTRES_CLK_FIXED_H_ +#define _DEV_EXTRES_CLK_FIXED_H_ + +#include + +/* + * A fixed clock can represent several different real-world objects, including + * an oscillator with a fixed output frequency, a fixed divider (multiplier and + * divisor must both be > 0), or a phase-fractional divider within a PLL + * (however the code currently divides first, then multiplies, potentially + * leading to different roundoff errors than the hardware PLL). + */ + +struct clk_fixed_def { + struct clknode_init_def clkdef; + uint64_t freq; + uint32_t mult; + uint32_t div; + int fixed_flags; +}; + +int clknode_fixed_register(struct clkdom *clkdom, struct clk_fixed_def *clkdef, + struct mtx *dev_mtx); + +#endif /*_DEV_EXTRES_CLK_FIXED_H_*/ diff --git a/sys/dev/extres/clk/clk_gate.c b/sys/dev/extres/clk/clk_gate.c new file mode 100644 index 00000000000..2107450042b --- /dev/null +++ b/sys/dev/extres/clk/clk_gate.c @@ -0,0 +1,126 @@ +/*- + * Copyright 2016 Michal Meloun + * 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 "clkdev_if.h" + +#define WR4(_clk, off, val) \ + CLKDEV_WRITE_4(clknode_get_device(_clk), off, val) +#define RD4(_clk, off, val) \ + CLKDEV_READ_4(clknode_get_device(_clk), off, val) +#define MD4(_clk, off, clr, set ) \ + CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set) + + +static int clknode_gate_init(struct clknode *clk, device_t dev); +static int clknode_gate_set_gate(struct clknode *clk, bool enable); +struct clknode_gate_sc { + uint32_t offset; + uint32_t shift; + uint32_t mask; + uint32_t on_value; + uint32_t off_value; + int gate_flags; + bool ungated; +}; + +static clknode_method_t clknode_gate_methods[] = { + /* Device interface */ + CLKNODEMETHOD(clknode_init, clknode_gate_init), + CLKNODEMETHOD(clknode_set_gate, clknode_gate_set_gate), + CLKNODEMETHOD_END +}; +DEFINE_CLASS_1(clknode_gate, clknode_gate_class, clknode_gate_methods, + sizeof(struct clknode_gate_sc), clknode_class); + +static int +clknode_gate_init(struct clknode *clk, device_t dev) +{ + uint32_t reg; + struct clknode_gate_sc *sc; + int rv; + + sc = clknode_get_softc(clk); + rv = RD4(clk, sc->offset, ®); + if (rv != 0) + return (rv); + reg = (reg >> sc->shift) & sc->mask; + sc->ungated = reg == sc->on_value ? 1 : 0; + clknode_init_parent_idx(clk, 0); + return(0); +} + +static int +clknode_gate_set_gate(struct clknode *clk, bool enable) +{ + uint32_t reg; + struct clknode_gate_sc *sc; + int rv; + + sc = clknode_get_softc(clk); + sc->ungated = enable; + rv = MD4(clk, sc->offset, sc->mask << sc->shift, + (sc->ungated ? sc->on_value : sc->off_value) << sc->shift); + if (rv != 0) + return (rv); + RD4(clk, sc->offset, ®); + return(0); +} + +int +clknode_gate_register(struct clkdom *clkdom, struct clk_gate_def *clkdef) +{ + struct clknode *clk; + struct clknode_gate_sc *sc; + + clk = clknode_create(clkdom, &clknode_gate_class, &clkdef->clkdef); + if (clk == NULL) + return (1); + + sc = clknode_get_softc(clk); + sc->offset = clkdef->offset; + sc->shift = clkdef->shift; + sc->mask = clkdef->mask; + sc->on_value = clkdef->on_value; + sc->off_value = clkdef->off_value; + sc->gate_flags = clkdef->gate_flags; + + clknode_register(clkdom, clk); + return (0); +} diff --git a/sys/dev/extres/clk/clk_gate.h b/sys/dev/extres/clk/clk_gate.h new file mode 100644 index 00000000000..b6646c2f599 --- /dev/null +++ b/sys/dev/extres/clk/clk_gate.h @@ -0,0 +1,46 @@ +/*- + * Copyright 2016 Michal Meloun + * 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$ + */ + +#ifndef _DEV_EXTRES_CLK_GATE_H_ +#define _DEV_EXTRES_CLK_GATE_H_ + +#include + +struct clk_gate_def { + struct clknode_init_def clkdef; + uint32_t offset; + uint32_t shift; + uint32_t mask; + uint32_t on_value; + uint32_t off_value; + int gate_flags; +}; + +int clknode_gate_register(struct clkdom *clkdom, struct clk_gate_def *clkdef); + +#endif /* _DEV_EXTRES_CLK_GATE_H_ */ diff --git a/sys/dev/extres/clk/clk_mux.c b/sys/dev/extres/clk/clk_mux.c new file mode 100644 index 00000000000..54e0653cc05 --- /dev/null +++ b/sys/dev/extres/clk/clk_mux.c @@ -0,0 +1,122 @@ +/*- + * Copyright 2016 Michal Meloun + * 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 "clkdev_if.h" + +#define WR4(_clk, off, val) \ + CLKDEV_WRITE_4(clknode_get_device(_clk), off, val) +#define RD4(_clk, off, val) \ + CLKDEV_READ_4(clknode_get_device(_clk), off, val) +#define MD4(_clk, off, clr, set ) \ + CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set) + +static int clknode_mux_init(struct clknode *clk, device_t dev); +static int clknode_mux_set_mux(struct clknode *clk, int idx); + +struct clknode_mux_sc { + uint32_t offset; + uint32_t shift; + uint32_t mask; + int mux_flags; +}; + +static clknode_method_t clknode_mux_methods[] = { + /* Device interface */ + CLKNODEMETHOD(clknode_init, clknode_mux_init), + CLKNODEMETHOD(clknode_set_mux, clknode_mux_set_mux), + CLKNODEMETHOD_END +}; +DEFINE_CLASS_1(clknode_mux, clknode_mux_class, clknode_mux_methods, + sizeof(struct clknode_mux_sc), clknode_class); + + +static int +clknode_mux_init(struct clknode *clk, device_t dev) +{ + uint32_t reg; + struct clknode_mux_sc *sc; + int rv; + + sc = clknode_get_softc(clk); + + rv = RD4(clk, sc->offset, ®); + if (rv != 0) + return (rv); + reg = (reg >> sc->shift) & sc->mask; + clknode_init_parent_idx(clk, reg); + return(0); +} + +static int +clknode_mux_set_mux(struct clknode *clk, int idx) +{ + uint32_t reg; + struct clknode_mux_sc *sc; + int rv; + + sc = clknode_get_softc(clk); + + rv = MD4(clk, sc->offset, sc->mask << sc->shift, + (idx & sc->mask) << sc->shift); + if (rv != 0) + return (rv); + RD4(clk, sc->offset, ®); + return(0); +} + +int +clknode_mux_register(struct clkdom *clkdom, struct clk_mux_def *clkdef) +{ + struct clknode *clk; + struct clknode_mux_sc *sc; + + clk = clknode_create(clkdom, &clknode_mux_class, &clkdef->clkdef); + if (clk == NULL) + return (1); + + sc = clknode_get_softc(clk); + sc->offset = clkdef->offset; + sc->shift = clkdef->shift; + sc->mask = (1 << clkdef->width) - 1; + sc->mux_flags = clkdef->mux_flags; + + clknode_register(clkdom, clk); + return (0); +} diff --git a/sys/dev/extres/clk/clk_mux.h b/sys/dev/extres/clk/clk_mux.h new file mode 100644 index 00000000000..193a82fb035 --- /dev/null +++ b/sys/dev/extres/clk/clk_mux.h @@ -0,0 +1,43 @@ +/*- + * Copyright 2016 Michal Meloun + * 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$ + */ +#ifndef _DEV_EXTRESF_CLK_MUX_H_ +#define _DEV_EXTRESF_CLK_MUX_H_ + +#include + +struct clk_mux_def { + struct clknode_init_def clkdef; + uint32_t offset; + uint32_t shift; + uint32_t width; + int mux_flags; +}; + +int clknode_mux_register(struct clkdom *clkdom, struct clk_mux_def *clkdef); + +#endif /* _DEV_EXTRESF_CLK_MUX_H_ */ diff --git a/sys/dev/extres/clk/clkdev_if.m b/sys/dev/extres/clk/clkdev_if.m new file mode 100644 index 00000000000..b43d2058023 --- /dev/null +++ b/sys/dev/extres/clk/clkdev_if.m @@ -0,0 +1,59 @@ +#- +# Copyright 2016 Michal Meloun +# 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$ +# + +#include + +INTERFACE clkdev; + +# +# Write single register +# +METHOD int write_4 { + device_t dev; + bus_addr_t addr; + uint32_t val; +}; + +# +# Read single register +# +METHOD int read_4 { + device_t dev; + bus_addr_t addr; + uint32_t *val; +}; + +# +# Modify single register +# +METHOD int modify_4 { + device_t dev; + bus_addr_t addr; + uint32_t clear_mask; + uint32_t set_mask; +}; diff --git a/sys/dev/extres/clk/clknode_if.m b/sys/dev/extres/clk/clknode_if.m new file mode 100644 index 00000000000..80d67547b69 --- /dev/null +++ b/sys/dev/extres/clk/clknode_if.m @@ -0,0 +1,79 @@ +#- +# Copyright 2016 Michal Meloun +# 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$ +# + +INTERFACE clknode; + +HEADER { + struct clknode; +} + +# +# Initialize clock node, get shanpshot of cached values +# +METHOD int init { + struct clknode *clk; + device_t dev; +}; + +# +# Recalculate frequency +# req - in/out recalulated frequency +# +METHOD int recalc_freq { + struct clknode *clk; + uint64_t *freq; +}; + +# +# Set frequency +# fin - parent (input)frequency. +# fout - requested output freqency. If clock cannot change frequency, +# then must return new requested frequency for his parent +METHOD int set_freq { + struct clknode *clk; + uint64_t fin; + uint64_t *fout; + int flags; + int *done; +}; + +# +# Enable/disable clock +# +METHOD int set_gate { + struct clknode *clk; + bool enable; +}; + +# +# Set multiplexer +# +METHOD int set_mux { + struct clknode *clk; + int idx; +}; diff --git a/sys/dev/extres/hwreset/hwreset.c b/sys/dev/extres/hwreset/hwreset.c new file mode 100644 index 00000000000..b3493de883c --- /dev/null +++ b/sys/dev/extres/hwreset/hwreset.c @@ -0,0 +1,186 @@ +/*- + * Copyright 2016 Michal Meloun + * 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$ + */ +#include "opt_platform.h" +#include +#include +#include +#include +#include +#include + +#ifdef FDT +#include +#include +#endif + +#include + +#include "hwreset_if.h" + +struct hwreset { + device_t consumer_dev; /* consumer device*/ + device_t provider_dev; /* provider device*/ + int rst_id; /* reset id */ +}; + +MALLOC_DEFINE(M_HWRESET, "hwreset", "Reset framework"); + +int +hwreset_assert(hwreset_t rst) +{ + + return (HWRESET_ASSERT(rst->provider_dev, rst->rst_id, true)); +} + +int +hwreset_deassert(hwreset_t rst) +{ + + return (HWRESET_ASSERT(rst->provider_dev, rst->rst_id, false)); +} + +int +hwreset_is_asserted(hwreset_t rst, bool *value) +{ + + return (HWRESET_IS_ASSERTED(rst->provider_dev, rst->rst_id, value)); +} + +void +hwreset_release(hwreset_t rst) +{ + free(rst, M_HWRESET); +} + +int +hwreset_get_by_id(device_t consumer_dev, device_t provider_dev, intptr_t id, + hwreset_t *rst_out) +{ + hwreset_t rst; + + /* Create handle */ + rst = malloc(sizeof(struct hwreset), M_HWRESET, + M_WAITOK | M_ZERO); + rst->consumer_dev = consumer_dev; + rst->provider_dev = provider_dev; + rst->rst_id = id; + *rst_out = rst; + return (0); +} + +#ifdef FDT +int +hwreset_default_ofw_map(device_t provider_dev, phandle_t xref, int ncells, + pcell_t *cells, intptr_t *id) +{ + if (ncells == 0) + *id = 1; + else if (ncells == 1) + *id = cells[0]; + else + return (ERANGE); + + return (0); +} + +int +hwreset_get_by_ofw_idx(device_t consumer_dev, int idx, hwreset_t *rst) +{ + phandle_t cnode, xnode; + pcell_t *cells; + device_t rstdev; + int ncells, rv; + intptr_t id; + + cnode = ofw_bus_get_node(consumer_dev); + if (cnode <= 0) { + device_printf(consumer_dev, + "%s called on not ofw based device\n", __func__); + return (ENXIO); + } + + rv = ofw_bus_parse_xref_list_alloc(cnode, "resets", "#reset-cells", + idx, &xnode, &ncells, &cells); + if (rv != 0) + return (rv); + + /* Tranlate provider to device */ + rstdev = OF_device_from_xref(xnode); + if (rstdev == NULL) { + free(cells, M_OFWPROP); + return (ENODEV); + } + /* Map reset to number */ + rv = HWRESET_MAP(rstdev, xnode, ncells, cells, &id); + free(cells, M_OFWPROP); + if (rv != 0) + return (rv); + + return (hwreset_get_by_id(consumer_dev, rstdev, id, rst)); +} + +int +hwreset_get_by_ofw_name(device_t consumer_dev, char *name, hwreset_t *rst) +{ + int rv, idx; + phandle_t cnode; + + cnode = ofw_bus_get_node(consumer_dev); + if (cnode <= 0) { + device_printf(consumer_dev, + "%s called on not ofw based device\n", __func__); + return (ENXIO); + } + rv = ofw_bus_find_string_index(cnode, "reset-names", name, &idx); + if (rv != 0) + return (rv); + return (hwreset_get_by_ofw_idx(consumer_dev, idx, rst)); +} + +void +hwreset_register_ofw_provider(device_t provider_dev) +{ + phandle_t xref, node; + + node = ofw_bus_get_node(provider_dev); + if (node <= 0) + panic("%s called on not ofw based device.\n", __func__); + + xref = OF_xref_from_node(node); + OF_device_register_xref(xref, provider_dev); +} + +void +hwreset_unregister_ofw_provider(device_t provider_dev) +{ + phandle_t xref; + + xref = OF_xref_from_device(provider_dev); + OF_device_register_xref(xref, NULL); +} +#endif diff --git a/sys/dev/extres/hwreset/hwreset.h b/sys/dev/extres/hwreset/hwreset.h new file mode 100644 index 00000000000..75e653a5c2a --- /dev/null +++ b/sys/dev/extres/hwreset/hwreset.h @@ -0,0 +1,67 @@ +/*- + * Copyright 2016 Michal Meloun + * 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 ``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 DEV_EXTRES_HWRESET_HWRESET_H +#define DEV_EXTRES_HWRESET_HWRESET_H + +#include "opt_platform.h" +#include +#ifdef FDT +#include +#endif + +typedef struct hwreset *hwreset_t; + +/* + * Provider interface + */ +#ifdef FDT +int hwreset_default_ofw_map(device_t provider_dev, phandle_t xref, int ncells, + pcell_t *cells, intptr_t *id); +void hwreset_register_ofw_provider(device_t provider_dev); +void hwreset_unregister_ofw_provider(device_t provider_dev); +#endif + +/* + * Consumer interface + */ +int hwreset_get_by_id(device_t consumer_dev, device_t provider_dev, intptr_t id, + hwreset_t *rst); +void hwreset_release(hwreset_t rst); + +int hwreset_assert(hwreset_t rst); +int hwreset_deassert(hwreset_t rst); +int hwreset_is_asserted(hwreset_t rst, bool *value); + +#ifdef FDT +int hwreset_get_by_ofw_name(device_t consumer_dev, char *name, hwreset_t *rst); +int hwreset_get_by_ofw_idx(device_t consumer_dev, int idx, hwreset_t *rst); +#endif + + + +#endif /* DEV_EXTRES_HWRESET_HWRESET_H */ diff --git a/sys/dev/extres/hwreset/hwreset_if.m b/sys/dev/extres/hwreset/hwreset_if.m new file mode 100644 index 00000000000..f1816f9ef81 --- /dev/null +++ b/sys/dev/extres/hwreset/hwreset_if.m @@ -0,0 +1,72 @@ +#- +# Copyright 2016 Michal Meloun +# 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$ +# + +#ifdef FDT +#include +#include +#endif + +INTERFACE hwreset; + +#ifdef FDT +HEADER { +int hwreset_default_ofw_map(device_t , phandle_t, int, pcell_t *, intptr_t *); +} + +# +# map fdt property cells to reset id +# Returns 0 on success or a standard errno value. +# +METHOD int map { + device_t provider_dev; + phandle_t xref; + int ncells; + pcell_t *cells; + intptr_t *id; +} DEFAULT hwreset_default_ofw_map; +#endif + +# +# Assert/deassert given reset. +# Returns 0 on success or a standard errno value. +# +METHOD int assert { + device_t provider_dev; + intptr_t id; + bool value; +}; + +# +# Get actual status of given reset. +# Returns 0 on success or a standard errno value. +# +METHOD int is_asserted { + device_t provider_dev; + intptr_t id; + bool *value; +}; diff --git a/sys/dev/hyperv/netvsc/hv_net_vsc.c b/sys/dev/hyperv/netvsc/hv_net_vsc.c index 65913b5a76f..8bf34a85c78 100644 --- a/sys/dev/hyperv/netvsc/hv_net_vsc.c +++ b/sys/dev/hyperv/netvsc/hv_net_vsc.c @@ -1028,4 +1028,6 @@ hv_nv_on_channel_callback(void *context) if (bufferlen > NETVSC_PACKET_SIZE) free(buffer, M_NETVSC); + + hv_rf_channel_rollup(net_dev); } diff --git a/sys/dev/hyperv/netvsc/hv_net_vsc.h b/sys/dev/hyperv/netvsc/hv_net_vsc.h index 9157f918dbb..dbe546453e5 100644 --- a/sys/dev/hyperv/netvsc/hv_net_vsc.h +++ b/sys/dev/hyperv/netvsc/hv_net_vsc.h @@ -38,12 +38,16 @@ #ifndef __HV_NET_VSC_H__ #define __HV_NET_VSC_H__ -#include #include #include #include +#include #include +#include +#include +#include + #include #include @@ -984,6 +988,9 @@ typedef struct { hv_bool_uint8_t link_state; } netvsc_device_info; +struct hn_txdesc; +SLIST_HEAD(hn_txdesc_list, hn_txdesc); + /* * Device-specific softc structure */ @@ -1001,6 +1008,18 @@ typedef struct hn_softc { struct hv_device *hn_dev_obj; netvsc_dev *net_dev; + int hn_txdesc_cnt; + struct hn_txdesc *hn_txdesc; + bus_dma_tag_t hn_tx_data_dtag; + bus_dma_tag_t hn_tx_rndis_dtag; + int hn_tx_chimney_size; + int hn_tx_chimney_max; + + struct mtx hn_txlist_spin; + struct hn_txdesc_list hn_txlist; + int hn_txdesc_avail; + int hn_txeof; + struct lro_ctrl hn_lro; int hn_lro_hiwat; @@ -1012,6 +1031,11 @@ typedef struct hn_softc { u_long hn_csum_trusted; u_long hn_lro_tried; u_long hn_small_pkts; + u_long hn_no_txdescs; + u_long hn_send_failed; + u_long hn_txdma_failed; + u_long hn_tx_collapsed; + u_long hn_tx_chimney; } hn_softc_t; diff --git a/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c b/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c index 29ceb2ab01a..10e8adaaff9 100644 --- a/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c +++ b/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c @@ -129,6 +129,41 @@ __FBSDID("$FreeBSD$"); #define HV_NV_SC_PTR_OFFSET_IN_BUF 0 #define HV_NV_PACKET_OFFSET_IN_BUF 16 +/* YYY should get it from the underlying channel */ +#define HN_TX_DESC_CNT 512 + +#define HN_RNDIS_MSG_LEN \ + (sizeof(rndis_msg) + \ + RNDIS_VLAN_PPI_SIZE + \ + RNDIS_TSO_PPI_SIZE + \ + RNDIS_CSUM_PPI_SIZE) +#define HN_RNDIS_MSG_BOUNDARY PAGE_SIZE +#define HN_RNDIS_MSG_ALIGN CACHE_LINE_SIZE + +#define HN_TX_DATA_BOUNDARY PAGE_SIZE +#define HN_TX_DATA_MAXSIZE IP_MAXPACKET +#define HN_TX_DATA_SEGSIZE PAGE_SIZE +#define HN_TX_DATA_SEGCNT_MAX \ + (NETVSC_PACKET_MAXPAGE - HV_RF_NUM_TX_RESERVED_PAGE_BUFS) + +struct hn_txdesc { + SLIST_ENTRY(hn_txdesc) link; + struct mbuf *m; + struct hn_softc *sc; + int refs; + uint32_t flags; /* HN_TXD_FLAG_ */ + netvsc_packet netvsc_pkt; /* XXX to be removed */ + + bus_dmamap_t data_dmap; + + bus_addr_t rndis_msg_paddr; + rndis_msg *rndis_msg; + bus_dmamap_t rndis_msg_dmap; +}; + +#define HN_TXD_FLAG_ONLIST 0x1 +#define HN_TXD_FLAG_DMAMAP 0x2 + /* * A unified flag for all outbound check sum flags is useful, * and it helps avoiding unnecessary check sum calculation in @@ -171,9 +206,19 @@ __FBSDID("$FreeBSD$"); int hv_promisc_mode = 0; /* normal mode by default */ /* Trust tcp segements verification on host side. */ -static int hn_trust_hosttcp = 0; +static int hn_trust_hosttcp = 1; TUNABLE_INT("dev.hn.trust_hosttcp", &hn_trust_hosttcp); +#if __FreeBSD_version >= 1100045 +/* Limit TSO burst size */ +static int hn_tso_maxlen = 0; +TUNABLE_INT("dev.hn.tso_maxlen", &hn_tso_maxlen); +#endif + +/* Limit chimney send size */ +static int hn_tx_chimney_size = 0; +TUNABLE_INT("dev.hn.tx_chimney_size", &hn_tx_chimney_size); + /* * Forward declarations */ @@ -181,14 +226,17 @@ static void hn_stop(hn_softc_t *sc); static void hn_ifinit_locked(hn_softc_t *sc); static void hn_ifinit(void *xsc); static int hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); -static int hn_start_locked(struct ifnet *ifp); +static void hn_start_locked(struct ifnet *ifp); static void hn_start(struct ifnet *ifp); static int hn_ifmedia_upd(struct ifnet *ifp); static void hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr); #ifdef HN_LRO_HIWAT static int hn_lro_hiwat_sysctl(SYSCTL_HANDLER_ARGS); #endif +static int hn_tx_chimney_size_sysctl(SYSCTL_HANDLER_ARGS); static int hn_check_iplen(const struct mbuf *, int); +static int hn_create_tx_ring(struct hn_softc *sc); +static void hn_destroy_tx_ring(struct hn_softc *sc); static __inline void hn_set_lro_hiwat(struct hn_softc *sc, int hiwat) @@ -318,10 +366,13 @@ netvsc_attach(device_t dev) netvsc_device_info device_info; hn_softc_t *sc; int unit = device_get_unit(dev); - struct ifnet *ifp; + struct ifnet *ifp = NULL; struct sysctl_oid_list *child; struct sysctl_ctx_list *ctx; - int ret; + int error; +#if __FreeBSD_version >= 1100045 + int tso_maxlen; +#endif sc = device_get_softc(dev); if (sc == NULL) { @@ -334,6 +385,10 @@ netvsc_attach(device_t dev) sc->hn_lro_hiwat = HN_LRO_HIWAT_DEF; sc->hn_trust_hosttcp = hn_trust_hosttcp; + error = hn_create_tx_ring(sc); + if (error) + goto failed; + NV_LOCK_INIT(sc, "NetVSCLock"); sc->hn_dev_obj = device_ctx; @@ -381,12 +436,10 @@ netvsc_attach(device_t dev) else ifp->if_hwassist = CSUM_TCP | CSUM_TSO; - ret = hv_rf_on_device_add(device_ctx, &device_info); - if (ret != 0) { - if_free(ifp); + error = hv_rf_on_device_add(device_ctx, &device_info); + if (error) + goto failed; - return (ret); - } if (device_info.link_state == 0) { sc->hn_carrier = 1; } @@ -400,8 +453,30 @@ netvsc_attach(device_t dev) #endif #endif /* INET || INET6 */ +#if __FreeBSD_version >= 1100045 + tso_maxlen = hn_tso_maxlen; + if (tso_maxlen <= 0 || tso_maxlen > IP_MAXPACKET) + tso_maxlen = IP_MAXPACKET; + + ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX; + ifp->if_hw_tsomaxsegsize = PAGE_SIZE; + ifp->if_hw_tsomax = tso_maxlen - + (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN); +#endif + ether_ifattach(ifp, device_info.mac_addr); +#if __FreeBSD_version >= 1100045 + if_printf(ifp, "TSO: %u/%u/%u\n", ifp->if_hw_tsomax, + ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize); +#endif + + sc->hn_tx_chimney_max = sc->net_dev->send_section_size; + sc->hn_tx_chimney_size = sc->hn_tx_chimney_max; + if (hn_tx_chimney_size > 0 && + hn_tx_chimney_size < sc->hn_tx_chimney_max) + sc->hn_tx_chimney_size = hn_tx_chimney_size; + ctx = device_get_sysctl_ctx(dev); child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); @@ -429,6 +504,26 @@ netvsc_attach(device_t dev) "# of TCP segements that we trust host's csum verification"); SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "small_pkts", CTLFLAG_RW, &sc->hn_small_pkts, "# of small packets received"); + SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "no_txdescs", + CTLFLAG_RW, &sc->hn_no_txdescs, "# of times short of TX descs"); + SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "send_failed", + CTLFLAG_RW, &sc->hn_send_failed, "# of hyper-v sending failure"); + SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "txdma_failed", + CTLFLAG_RW, &sc->hn_txdma_failed, "# of TX DMA failure"); + SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "tx_collapsed", + CTLFLAG_RW, &sc->hn_tx_collapsed, "# of TX mbuf collapsed"); + SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "tx_chimney", + CTLFLAG_RW, &sc->hn_tx_chimney, "# of chimney send"); + SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt", + CTLFLAG_RD, &sc->hn_txdesc_cnt, 0, "# of total TX descs"); + SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail", + CTLFLAG_RD, &sc->hn_txdesc_avail, 0, "# of available TX descs"); + SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max", + CTLFLAG_RD, &sc->hn_tx_chimney_max, 0, + "Chimney send packet size upper boundary"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size", + CTLTYPE_INT | CTLFLAG_RW, sc, 0, hn_tx_chimney_size_sysctl, + "I", "Chimney send packet size limit"); if (unit == 0) { struct sysctl_ctx_list *dc_ctx; @@ -446,9 +541,21 @@ netvsc_attach(device_t dev) CTLFLAG_RD, &hn_trust_hosttcp, 0, "Trust tcp segement verification on host side, " "when csum info is missing (global setting)"); + SYSCTL_ADD_INT(dc_ctx, dc_child, OID_AUTO, "tx_chimney_size", + CTLFLAG_RD, &hn_tx_chimney_size, 0, + "Chimney send packet size limit"); +#if __FreeBSD_version >= 1100045 + SYSCTL_ADD_INT(dc_ctx, dc_child, OID_AUTO, "tso_maxlen", + CTLFLAG_RD, &hn_tso_maxlen, 0, "TSO burst limit"); +#endif } return (0); +failed: + hn_destroy_tx_ring(sc); + if (ifp != NULL) + if_free(ifp); + return (error); } /* @@ -480,6 +587,7 @@ netvsc_detach(device_t dev) #if defined(INET) || defined(INET6) tcp_lro_free(&sc->hn_lro); #endif + hn_destroy_tx_ring(sc); return (0); } @@ -493,6 +601,112 @@ netvsc_shutdown(device_t dev) return (0); } +static __inline int +hn_txdesc_dmamap_load(struct hn_softc *sc, struct hn_txdesc *txd, + struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs) +{ + struct mbuf *m = *m_head; + int error; + + error = bus_dmamap_load_mbuf_sg(sc->hn_tx_data_dtag, txd->data_dmap, + m, segs, nsegs, BUS_DMA_NOWAIT); + if (error == EFBIG) { + struct mbuf *m_new; + + m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX); + if (m_new == NULL) + return ENOBUFS; + else + *m_head = m = m_new; + sc->hn_tx_collapsed++; + + error = bus_dmamap_load_mbuf_sg(sc->hn_tx_data_dtag, + txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT); + } + if (!error) { + bus_dmamap_sync(sc->hn_tx_data_dtag, txd->data_dmap, + BUS_DMASYNC_PREWRITE); + txd->flags |= HN_TXD_FLAG_DMAMAP; + } + return error; +} + +static __inline void +hn_txdesc_dmamap_unload(struct hn_softc *sc, struct hn_txdesc *txd) +{ + + if (txd->flags & HN_TXD_FLAG_DMAMAP) { + bus_dmamap_sync(sc->hn_tx_data_dtag, + txd->data_dmap, BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->hn_tx_data_dtag, + txd->data_dmap); + txd->flags &= ~HN_TXD_FLAG_DMAMAP; + } +} + +static __inline int +hn_txdesc_put(struct hn_softc *sc, struct hn_txdesc *txd) +{ + + KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0, + ("put an onlist txd %#x", txd->flags)); + + KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs)); + if (atomic_fetchadd_int(&txd->refs, -1) != 1) + return 0; + + hn_txdesc_dmamap_unload(sc, txd); + if (txd->m != NULL) { + m_freem(txd->m); + txd->m = NULL; + } + + txd->flags |= HN_TXD_FLAG_ONLIST; + + mtx_lock_spin(&sc->hn_txlist_spin); + KASSERT(sc->hn_txdesc_avail >= 0 && + sc->hn_txdesc_avail < sc->hn_txdesc_cnt, + ("txdesc_put: invalid txd avail %d", sc->hn_txdesc_avail)); + sc->hn_txdesc_avail++; + SLIST_INSERT_HEAD(&sc->hn_txlist, txd, link); + mtx_unlock_spin(&sc->hn_txlist_spin); + + return 1; +} + +static __inline struct hn_txdesc * +hn_txdesc_get(struct hn_softc *sc) +{ + struct hn_txdesc *txd; + + mtx_lock_spin(&sc->hn_txlist_spin); + txd = SLIST_FIRST(&sc->hn_txlist); + if (txd != NULL) { + KASSERT(sc->hn_txdesc_avail > 0, + ("txdesc_get: invalid txd avail %d", sc->hn_txdesc_avail)); + sc->hn_txdesc_avail--; + SLIST_REMOVE_HEAD(&sc->hn_txlist, link); + } + mtx_unlock_spin(&sc->hn_txlist_spin); + + if (txd != NULL) { + KASSERT(txd->m == NULL && txd->refs == 0 && + (txd->flags & HN_TXD_FLAG_ONLIST), ("invalid txd")); + txd->flags &= ~HN_TXD_FLAG_ONLIST; + txd->refs = 1; + } + return txd; +} + +static __inline void +hn_txdesc_hold(struct hn_txdesc *txd) +{ + + /* 0->1 transition will never work */ + KASSERT(txd->refs > 0, ("invalid refs %d", txd->refs)); + atomic_add_int(&txd->refs, 1); +} + /* * Send completion processing * @@ -503,34 +717,44 @@ netvsc_shutdown(device_t dev) void netvsc_xmit_completion(void *context) { - netvsc_packet *packet = (netvsc_packet *)context; - struct mbuf *mb; - uint8_t *buf; + netvsc_packet *packet = context; + struct hn_txdesc *txd; + struct hn_softc *sc; - mb = (struct mbuf *)(uintptr_t)packet->compl.send.send_completion_tid; - buf = ((uint8_t *)packet) - HV_NV_PACKET_OFFSET_IN_BUF; + txd = (struct hn_txdesc *)(uintptr_t) + packet->compl.send.send_completion_tid; - free(buf, M_NETVSC); + sc = txd->sc; + sc->hn_txeof = 1; + hn_txdesc_put(sc, txd); +} - if (mb != NULL) { - m_freem(mb); - } +void +netvsc_channel_rollup(struct hv_device *device_ctx) +{ + struct hn_softc *sc = device_get_softc(device_ctx->device); + struct ifnet *ifp; + + if (!sc->hn_txeof) + return; + + sc->hn_txeof = 0; + ifp = sc->hn_ifp; + NV_LOCK(sc); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + hn_start_locked(ifp); + NV_UNLOCK(sc); } /* * Start a transmit of one or more packets */ -static int +static void hn_start_locked(struct ifnet *ifp) { hn_softc_t *sc = ifp->if_softc; struct hv_device *device_ctx = vmbus_get_devctx(sc->hn_dev); netvsc_dev *net_dev = sc->net_dev; - device_t dev = device_ctx->device; - uint8_t *buf; - netvsc_packet *packet; - struct mbuf *m_head, *m; - struct mbuf *mc_head = NULL; struct ether_vlan_header *eh; rndis_msg *rndis_mesg; rndis_packet *rndis_pkt; @@ -539,84 +763,36 @@ hn_start_locked(struct ifnet *ifp) rndis_tcp_ip_csum_info *csum_info; rndis_tcp_tso_info *tso_info; int ether_len; - int i; - int num_frags; - int len; - int retries = 0; - int ret = 0; uint32_t rndis_msg_size = 0; uint32_t trans_proto_type; - uint32_t send_buf_section_idx = - NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX; - while (!IFQ_DRV_IS_EMPTY(&sc->hn_ifp->if_snd)) { - IFQ_DRV_DEQUEUE(&sc->hn_ifp->if_snd, m_head); - if (m_head == NULL) { + if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != + IFF_DRV_RUNNING) + return; + + while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { + bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX]; + int error, nsegs, i, send_failed = 0; + struct hn_txdesc *txd; + netvsc_packet *packet; + struct mbuf *m_head; + + IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); + if (m_head == NULL) + break; + + txd = hn_txdesc_get(sc); + if (txd == NULL) { + sc->hn_no_txdescs++; + IF_PREPEND(&ifp->if_snd, m_head); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; break; } - len = 0; - num_frags = 0; - - /* Walk the mbuf list computing total length and num frags */ - for (m = m_head; m != NULL; m = m->m_next) { - if (m->m_len != 0) { - num_frags++; - len += m->m_len; - } - } - - /* - * Reserve the number of pages requested. Currently, - * one page is reserved for the message in the RNDIS - * filter packet - */ - num_frags += HV_RF_NUM_TX_RESERVED_PAGE_BUFS; - - /* If exceeds # page_buffers in netvsc_packet */ - if (num_frags > NETVSC_PACKET_MAXPAGE) { - device_printf(dev, "exceed max page buffers,%d,%d\n", - num_frags, NETVSC_PACKET_MAXPAGE); - m_freem(m_head); - if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); - return (EINVAL); - } - - /* - * Allocate a buffer with space for a netvsc packet plus a - * number of reserved areas. First comes a (currently 16 - * bytes, currently unused) reserved data area. Second is - * the netvsc_packet. Third is an area reserved for an - * rndis_filter_packet struct. Fourth (optional) is a - * rndis_per_packet_info struct. - * Changed malloc to M_NOWAIT to avoid sleep under spin lock. - * No longer reserving extra space for page buffers, as they - * are already part of the netvsc_packet. - */ - buf = malloc(HV_NV_PACKET_OFFSET_IN_BUF + - sizeof(netvsc_packet) + - sizeof(rndis_msg) + - RNDIS_VLAN_PPI_SIZE + - RNDIS_TSO_PPI_SIZE + - RNDIS_CSUM_PPI_SIZE, - M_NETVSC, M_ZERO | M_NOWAIT); - if (buf == NULL) { - device_printf(dev, "hn:malloc packet failed\n"); - m_freem(m_head); - if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); - return (ENOMEM); - } - - packet = (netvsc_packet *)(buf + HV_NV_PACKET_OFFSET_IN_BUF); - *(vm_offset_t *)buf = HV_NV_SC_PTR_OFFSET_IN_BUF; - + packet = &txd->netvsc_pkt; packet->is_data_pkt = TRUE; - - /* Set up the rndis header */ - packet->page_buf_count = num_frags; - /* Initialize it from the mbuf */ - packet->tot_data_buf_len = len; + packet->tot_data_buf_len = m_head->m_pkthdr.len; /* * extension points to the area reserved for the @@ -624,8 +800,9 @@ hn_start_locked(struct ifnet *ifp) * the netvsc_packet (and rppi struct, if present; * length is updated later). */ - packet->rndis_mesg = packet + 1; - rndis_mesg = (rndis_msg *)packet->rndis_mesg; + rndis_mesg = txd->rndis_msg; + /* XXX not necessary */ + memset(rndis_mesg, 0, HN_RNDIS_MSG_LEN); rndis_mesg->ndis_msg_type = REMOTE_NDIS_PACKET_MSG; rndis_pkt = &rndis_mesg->msg.packet; @@ -644,8 +821,6 @@ hn_start_locked(struct ifnet *ifp) * set up some additional fields so the Hyper-V infrastructure will stuff the VLAN tag * into the frame. */ - packet->vlan_tci = m_head->m_pkthdr.ether_vtag; - rndis_msg_size += RNDIS_VLAN_PPI_SIZE; rppi = hv_set_rppi_data(rndis_mesg, RNDIS_VLAN_PPI_SIZE, @@ -656,7 +831,7 @@ hn_start_locked(struct ifnet *ifp) rppi->per_packet_info_offset); /* FreeBSD does not support CFI or priority */ rppi_vlan_info->u1.s1.vlan_id = - packet->vlan_tci & 0xfff; + m_head->m_pkthdr.ether_vtag & 0xfff; } /* Only check the flags for outbound and ignore the ones for inbound */ @@ -758,58 +933,71 @@ pre_send: packet->tot_data_buf_len = rndis_mesg->msg_len; /* send packet with send buffer */ - if (packet->tot_data_buf_len < net_dev->send_section_size) { + if (packet->tot_data_buf_len < sc->hn_tx_chimney_size) { + uint32_t send_buf_section_idx; + send_buf_section_idx = hv_nv_get_next_send_section(net_dev); if (send_buf_section_idx != NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX) { - char *dest = ((char *)net_dev->send_buf + - send_buf_section_idx * - net_dev->send_section_size); + uint8_t *dest = ((uint8_t *)net_dev->send_buf + + (send_buf_section_idx * + net_dev->send_section_size)); memcpy(dest, rndis_mesg, rndis_msg_size); dest += rndis_msg_size; - for (m = m_head; m != NULL; m = m->m_next) { - if (m->m_len) { - memcpy(dest, - (void *)mtod(m, vm_offset_t), - m->m_len); - dest += m->m_len; - } - } + + m_copydata(m_head, 0, m_head->m_pkthdr.len, + dest); packet->send_buf_section_idx = send_buf_section_idx; packet->send_buf_section_size = packet->tot_data_buf_len; packet->page_buf_count = 0; + sc->hn_tx_chimney++; goto do_send; } } + error = hn_txdesc_dmamap_load(sc, txd, &m_head, segs, &nsegs); + if (error) { + int freed; + + /* + * This mbuf is not linked w/ the txd yet, so free + * it now. + */ + m_freem(m_head); + freed = hn_txdesc_put(sc, txd); + KASSERT(freed != 0, + ("fail to free txd upon txdma error")); + + sc->hn_txdma_failed++; + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + continue; + } + + packet->page_buf_count = nsegs + + HV_RF_NUM_TX_RESERVED_PAGE_BUFS; + /* send packet with page buffer */ - packet->page_buffers[0].pfn = - atop(hv_get_phys_addr(rndis_mesg)); + packet->page_buffers[0].pfn = atop(txd->rndis_msg_paddr); packet->page_buffers[0].offset = - (unsigned long)rndis_mesg & PAGE_MASK; + txd->rndis_msg_paddr & PAGE_MASK; packet->page_buffers[0].length = rndis_msg_size; /* * Fill the page buffers with mbuf info starting at index * HV_RF_NUM_TX_RESERVED_PAGE_BUFS. */ - i = HV_RF_NUM_TX_RESERVED_PAGE_BUFS; - for (m = m_head; m != NULL; m = m->m_next) { - if (m->m_len) { - vm_offset_t paddr = - vtophys(mtod(m, vm_offset_t)); - packet->page_buffers[i].pfn = - paddr >> PAGE_SHIFT; - packet->page_buffers[i].offset = - paddr & (PAGE_SIZE - 1); - packet->page_buffers[i].length = m->m_len; - i++; - } + for (i = 0; i < nsegs; ++i) { + hv_vmbus_page_buffer *pb = &packet->page_buffers[ + i + HV_RF_NUM_TX_RESERVED_PAGE_BUFS]; + + pb->pfn = atop(segs[i].ds_addr); + pb->offset = segs[i].ds_addr & PAGE_MASK; + pb->length = segs[i].ds_len; } packet->send_buf_section_idx = @@ -817,63 +1005,65 @@ pre_send: packet->send_buf_section_size = 0; do_send: + txd->m = m_head; - /* - * If bpf, copy the mbuf chain. This is less expensive than - * it appears; the mbuf clusters are not copied, only their - * reference counts are incremented. - * Needed to avoid a race condition where the completion - * callback is invoked, freeing the mbuf chain, before the - * bpf_mtap code has a chance to run. - */ - if (ifp->if_bpf) { - mc_head = m_copypacket(m_head, M_NOWAIT); - } -retry_send: /* Set the completion routine */ packet->compl.send.on_send_completion = netvsc_xmit_completion; packet->compl.send.send_completion_context = packet; - packet->compl.send.send_completion_tid = (uint64_t)(uintptr_t)m_head; + packet->compl.send.send_completion_tid = + (uint64_t)(uintptr_t)txd; - /* Removed critical_enter(), does not appear necessary */ - ret = hv_nv_on_send(device_ctx, packet); - if (ret == 0) { +again: + /* + * Make sure that txd is not freed before ETHER_BPF_MTAP. + */ + hn_txdesc_hold(txd); + error = hv_nv_on_send(device_ctx, packet); + if (!error) { + ETHER_BPF_MTAP(ifp, m_head); if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); - /* if bpf && mc_head, call bpf_mtap code */ - if (mc_head) { - ETHER_BPF_MTAP(ifp, mc_head); - } - } else { - retries++; - if (retries < 4) { - goto retry_send; - } + } + hn_txdesc_put(sc, txd); + if (__predict_false(error)) { + int freed; + + /* + * This should "really rarely" happen. + * + * XXX Too many RX to be acked or too many sideband + * commands to run? Ask netvsc_channel_rollup() + * to kick start later. + */ + sc->hn_txeof = 1; + if (!send_failed) { + sc->hn_send_failed++; + send_failed = 1; + /* + * Try sending again after set hn_txeof; + * in case that we missed the last + * netvsc_channel_rollup(). + */ + goto again; + } + if_printf(ifp, "send failed\n"); + + /* + * This mbuf will be prepended, don't free it + * in hn_txdesc_put(); only unload it from the + * DMA map in hn_txdesc_put(), if it was loaded. + */ + txd->m = NULL; + freed = hn_txdesc_put(sc, txd); + KASSERT(freed != 0, + ("fail to free txd upon send error")); + + sc->hn_send_failed++; IF_PREPEND(&ifp->if_snd, m_head); ifp->if_drv_flags |= IFF_DRV_OACTIVE; - - /* - * Null the mbuf pointer so the completion function - * does not free the mbuf chain. We just pushed the - * mbuf chain back on the if_snd queue. - */ - packet->compl.send.send_completion_tid = 0; - - /* - * Release the resources since we will not get any - * send completion - */ - netvsc_xmit_completion(packet); - if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); - } - - /* if bpf && mc_head, free the mbuf chain copy */ - if (mc_head) { - m_freem(mc_head); + break; } } - - return (ret); } /* @@ -1220,6 +1410,9 @@ hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; } + sc->hn_tx_chimney_max = sc->net_dev->send_section_size; + if (sc->hn_tx_chimney_size > sc->hn_tx_chimney_max) + sc->hn_tx_chimney_size = sc->hn_tx_chimney_max; hn_ifinit_locked(sc); NV_LOCK(sc); @@ -1476,6 +1669,25 @@ hn_lro_hiwat_sysctl(SYSCTL_HANDLER_ARGS) } #endif /* HN_LRO_HIWAT */ +static int +hn_tx_chimney_size_sysctl(SYSCTL_HANDLER_ARGS) +{ + struct hn_softc *sc = arg1; + int chimney_size, error; + + chimney_size = sc->hn_tx_chimney_size; + error = sysctl_handle_int(oidp, &chimney_size, 0, req); + if (error || req->newptr == NULL) + return error; + + if (chimney_size > sc->hn_tx_chimney_max || chimney_size <= 0) + return EINVAL; + + if (sc->hn_tx_chimney_size != chimney_size) + sc->hn_tx_chimney_size = chimney_size; + return 0; +} + static int hn_check_iplen(const struct mbuf *m, int hoff) { @@ -1551,6 +1763,150 @@ hn_check_iplen(const struct mbuf *m, int hoff) return ip->ip_p; } +static void +hn_dma_map_paddr(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + bus_addr_t *paddr = arg; + + if (error) + return; + + KASSERT(nseg == 1, ("too many segments %d!", nseg)); + *paddr = segs->ds_addr; +} + +static int +hn_create_tx_ring(struct hn_softc *sc) +{ + bus_dma_tag_t parent_dtag; + int error, i; + + sc->hn_txdesc_cnt = HN_TX_DESC_CNT; + sc->hn_txdesc = malloc(sizeof(struct hn_txdesc) * sc->hn_txdesc_cnt, + M_NETVSC, M_WAITOK | M_ZERO); + SLIST_INIT(&sc->hn_txlist); + mtx_init(&sc->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN); + + parent_dtag = bus_get_dma_tag(sc->hn_dev); + + /* DMA tag for RNDIS messages. */ + error = bus_dma_tag_create(parent_dtag, /* parent */ + HN_RNDIS_MSG_ALIGN, /* alignment */ + HN_RNDIS_MSG_BOUNDARY, /* boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + HN_RNDIS_MSG_LEN, /* maxsize */ + 1, /* nsegments */ + HN_RNDIS_MSG_LEN, /* maxsegsize */ + 0, /* flags */ + NULL, /* lockfunc */ + NULL, /* lockfuncarg */ + &sc->hn_tx_rndis_dtag); + if (error) { + device_printf(sc->hn_dev, "failed to create rndis dmatag\n"); + return error; + } + + /* DMA tag for data. */ + error = bus_dma_tag_create(parent_dtag, /* parent */ + 1, /* alignment */ + HN_TX_DATA_BOUNDARY, /* boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + HN_TX_DATA_MAXSIZE, /* maxsize */ + HN_TX_DATA_SEGCNT_MAX, /* nsegments */ + HN_TX_DATA_SEGSIZE, /* maxsegsize */ + 0, /* flags */ + NULL, /* lockfunc */ + NULL, /* lockfuncarg */ + &sc->hn_tx_data_dtag); + if (error) { + device_printf(sc->hn_dev, "failed to create data dmatag\n"); + return error; + } + + for (i = 0; i < sc->hn_txdesc_cnt; ++i) { + struct hn_txdesc *txd = &sc->hn_txdesc[i]; + + txd->sc = sc; + + /* + * Allocate and load RNDIS messages. + */ + error = bus_dmamem_alloc(sc->hn_tx_rndis_dtag, + (void **)&txd->rndis_msg, + BUS_DMA_WAITOK | BUS_DMA_COHERENT, + &txd->rndis_msg_dmap); + if (error) { + device_printf(sc->hn_dev, + "failed to allocate rndis_msg, %d\n", i); + return error; + } + + error = bus_dmamap_load(sc->hn_tx_rndis_dtag, + txd->rndis_msg_dmap, + txd->rndis_msg, HN_RNDIS_MSG_LEN, + hn_dma_map_paddr, &txd->rndis_msg_paddr, + BUS_DMA_NOWAIT); + if (error) { + device_printf(sc->hn_dev, + "failed to load rndis_msg, %d\n", i); + bus_dmamem_free(sc->hn_tx_rndis_dtag, + txd->rndis_msg, txd->rndis_msg_dmap); + return error; + } + + /* DMA map for TX data. */ + error = bus_dmamap_create(sc->hn_tx_data_dtag, 0, + &txd->data_dmap); + if (error) { + device_printf(sc->hn_dev, + "failed to allocate tx data dmamap\n"); + bus_dmamap_unload(sc->hn_tx_rndis_dtag, + txd->rndis_msg_dmap); + bus_dmamem_free(sc->hn_tx_rndis_dtag, + txd->rndis_msg, txd->rndis_msg_dmap); + return error; + } + + /* All set, put it to list */ + txd->flags |= HN_TXD_FLAG_ONLIST; + SLIST_INSERT_HEAD(&sc->hn_txlist, txd, link); + } + sc->hn_txdesc_avail = sc->hn_txdesc_cnt; + + return 0; +} + +static void +hn_destroy_tx_ring(struct hn_softc *sc) +{ + struct hn_txdesc *txd; + + while ((txd = SLIST_FIRST(&sc->hn_txlist)) != NULL) { + KASSERT(txd->m == NULL, ("still has mbuf installed")); + KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, + ("still dma mapped")); + SLIST_REMOVE_HEAD(&sc->hn_txlist, link); + + bus_dmamap_unload(sc->hn_tx_rndis_dtag, + txd->rndis_msg_dmap); + bus_dmamem_free(sc->hn_tx_rndis_dtag, + txd->rndis_msg, txd->rndis_msg_dmap); + + bus_dmamap_destroy(sc->hn_tx_data_dtag, txd->data_dmap); + } + + if (sc->hn_tx_data_dtag != NULL) + bus_dma_tag_destroy(sc->hn_tx_data_dtag); + if (sc->hn_tx_rndis_dtag != NULL) + bus_dma_tag_destroy(sc->hn_tx_rndis_dtag); + free(sc->hn_txdesc, M_NETVSC); + mtx_destroy(&sc->hn_txlist_spin); +} + static device_method_t netvsc_methods[] = { /* Device interface */ DEVMETHOD(device_probe, netvsc_probe), diff --git a/sys/dev/hyperv/netvsc/hv_rndis.h b/sys/dev/hyperv/netvsc/hv_rndis.h index fd032dea062..cd46ecc3b18 100644 --- a/sys/dev/hyperv/netvsc/hv_rndis.h +++ b/sys/dev/hyperv/netvsc/hv_rndis.h @@ -1050,6 +1050,7 @@ int netvsc_recv(struct hv_device *device_ctx, netvsc_packet *packet, rndis_tcp_ip_csum_info *csum_info); void netvsc_recv_rollup(struct hv_device *device_ctx); +void netvsc_channel_rollup(struct hv_device *device_ctx); void* hv_set_rppi_data(rndis_msg *rndis_mesg, uint32_t rppi_size, diff --git a/sys/dev/hyperv/netvsc/hv_rndis_filter.c b/sys/dev/hyperv/netvsc/hv_rndis_filter.c index 3e9502434f4..dfd0b472793 100644 --- a/sys/dev/hyperv/netvsc/hv_rndis_filter.c +++ b/sys/dev/hyperv/netvsc/hv_rndis_filter.c @@ -974,3 +974,21 @@ hv_rf_receive_rollup(netvsc_dev *net_dev) rndis_dev = (rndis_device *)net_dev->extension; netvsc_recv_rollup(rndis_dev->net_dev->dev); } + +void +hv_rf_channel_rollup(netvsc_dev *net_dev) +{ + rndis_device *rndis_dev; + + rndis_dev = (rndis_device *)net_dev->extension; + + /* + * This could be called pretty early, so we need + * to make sure everything has been setup. + */ + if (rndis_dev == NULL || + rndis_dev->net_dev == NULL || + rndis_dev->net_dev->dev == NULL) + return; + netvsc_channel_rollup(rndis_dev->net_dev->dev); +} diff --git a/sys/dev/hyperv/netvsc/hv_rndis_filter.h b/sys/dev/hyperv/netvsc/hv_rndis_filter.h index 2f3ebd8b58b..9d7a38dc18b 100644 --- a/sys/dev/hyperv/netvsc/hv_rndis_filter.h +++ b/sys/dev/hyperv/netvsc/hv_rndis_filter.h @@ -99,6 +99,7 @@ typedef struct rndis_device_ { int hv_rf_on_receive(netvsc_dev *net_dev, struct hv_device *device, netvsc_packet *pkt); void hv_rf_receive_rollup(netvsc_dev *net_dev); +void hv_rf_channel_rollup(netvsc_dev *net_dev); int hv_rf_on_device_add(struct hv_device *device, void *additl_info); int hv_rf_on_device_remove(struct hv_device *device, boolean_t destroy_channel); int hv_rf_on_open(struct hv_device *device); diff --git a/sys/dev/hyperv/vmbus/hv_channel.c b/sys/dev/hyperv/vmbus/hv_channel.c index 94137fbeb22..facddc271cb 100644 --- a/sys/dev/hyperv/vmbus/hv_channel.c +++ b/sys/dev/hyperv/vmbus/hv_channel.c @@ -665,11 +665,11 @@ hv_vmbus_channel_send_packet_pagebuffer( { int ret = 0; - int i = 0; boolean_t need_sig; uint32_t packet_len; + uint32_t page_buflen; uint32_t packetLen_aligned; - hv_vmbus_sg_buffer_list buffer_list[3]; + hv_vmbus_sg_buffer_list buffer_list[4]; hv_vmbus_channel_packet_page_buffer desc; uint32_t descSize; uint64_t alignedData = 0; @@ -681,36 +681,33 @@ hv_vmbus_channel_send_packet_pagebuffer( * Adjust the size down since hv_vmbus_channel_packet_page_buffer * is the largest size we support */ - descSize = sizeof(hv_vmbus_channel_packet_page_buffer) - - ((HV_MAX_PAGE_BUFFER_COUNT - page_count) * - sizeof(hv_vmbus_page_buffer)); - packet_len = descSize + buffer_len; + descSize = __offsetof(hv_vmbus_channel_packet_page_buffer, range); + page_buflen = sizeof(hv_vmbus_page_buffer) * page_count; + packet_len = descSize + page_buflen + buffer_len; packetLen_aligned = HV_ALIGN_UP(packet_len, sizeof(uint64_t)); /* Setup the descriptor */ desc.type = HV_VMBUS_PACKET_TYPE_DATA_USING_GPA_DIRECT; desc.flags = HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; - desc.data_offset8 = descSize >> 3; /* in 8-bytes granularity */ + /* in 8-bytes granularity */ + desc.data_offset8 = (descSize + page_buflen) >> 3; desc.length8 = (uint16_t) (packetLen_aligned >> 3); desc.transaction_id = request_id; desc.range_count = page_count; - for (i = 0; i < page_count; i++) { - desc.range[i].length = page_buffers[i].length; - desc.range[i].offset = page_buffers[i].offset; - desc.range[i].pfn = page_buffers[i].pfn; - } - buffer_list[0].data = &desc; buffer_list[0].length = descSize; - buffer_list[1].data = buffer; - buffer_list[1].length = buffer_len; + buffer_list[1].data = page_buffers; + buffer_list[1].length = page_buflen; - buffer_list[2].data = &alignedData; - buffer_list[2].length = packetLen_aligned - packet_len; + buffer_list[2].data = buffer; + buffer_list[2].length = buffer_len; - ret = hv_ring_buffer_write(&channel->outbound, buffer_list, 3, + buffer_list[3].data = &alignedData; + buffer_list[3].length = packetLen_aligned - packet_len; + + ret = hv_ring_buffer_write(&channel->outbound, buffer_list, 4, &need_sig); /* TODO: We should determine if this is optional */ diff --git a/sys/dev/ixgbe/ixgbe_osdep.h b/sys/dev/ixgbe/ixgbe_osdep.h index b767e737525..79d11665ee1 100644 --- a/sys/dev/ixgbe/ixgbe_osdep.h +++ b/sys/dev/ixgbe/ixgbe_osdep.h @@ -57,6 +57,15 @@ #define ASSERT(x) if(!(x)) panic("IXGBE: x") #define EWARN(H, W, S) printf(W) +enum { + IXGBE_ERROR_SOFTWARE, + IXGBE_ERROR_POLLING, + IXGBE_ERROR_INVALID_STATE, + IXGBE_ERROR_UNSUPPORTED, + IXGBE_ERROR_ARGUMENT, + IXGBE_ERROR_CAUTION, +}; + /* The happy-fun DELAY macro is defined in /usr/src/sys/i386/include/clock.h */ #define usec_delay(x) DELAY(x) #define msec_delay(x) DELAY(1000*(x)) @@ -73,9 +82,23 @@ #define DEBUGOUT5(S,A,B,C,D,E) printf(S "\n",A,B,C,D,E) #define DEBUGOUT6(S,A,B,C,D,E,F) printf(S "\n",A,B,C,D,E,F) #define DEBUGOUT7(S,A,B,C,D,E,F,G) printf(S "\n",A,B,C,D,E,F,G) - #define ERROR_REPORT1(S,A) printf(S "\n",A) - #define ERROR_REPORT2(S,A,B) printf(S "\n",A,B) - #define ERROR_REPORT3(S,A,B,C) printf(S "\n",A,B,C) + #define ERROR_REPORT1 ERROR_REPORT + #define ERROR_REPORT2 ERROR_REPORT + #define ERROR_REPORT3 ERROR_REPORT + #define ERROR_REPORT(level, format, arg...) do { \ + switch (level) { \ + case IXGBE_ERROR_SOFTWARE: \ + case IXGBE_ERROR_CAUTION: \ + case IXGBE_ERROR_POLLING: \ + case IXGBE_ERROR_INVALID_STATE: \ + case IXGBE_ERROR_UNSUPPORTED: \ + case IXGBE_ERROR_ARGUMENT: \ + device_printf(ixgbe_dev_from_hw(hw), format, ## arg); \ + break; \ + default: \ + break; \ + } \ + } while (0) #else #define DEBUGOUT(S) #define DEBUGOUT1(S,A) diff --git a/sys/dev/ofw/openfirm.c b/sys/dev/ofw/openfirm.c index b04dbc65247..d7adc96d317 100644 --- a/sys/dev/ofw/openfirm.c +++ b/sys/dev/ofw/openfirm.c @@ -394,6 +394,9 @@ OF_getencprop(phandle_t node, const char *propname, pcell_t *buf, size_t len) KASSERT(len % 4 == 0, ("Need a multiple of 4 bytes")); retval = OF_getprop(node, propname, buf, len); + if (retval <= 0) + return (retval); + for (i = 0; i < len/4; i++) buf[i] = be32toh(buf[i]); @@ -599,10 +602,9 @@ OF_xref_from_node(phandle_t node) return (xi->xref); } - if (OF_getencprop(node, "phandle", &xref, sizeof(xref)) == - -1 && OF_getencprop(node, "ibm,phandle", &xref, - sizeof(xref)) == -1 && OF_getencprop(node, - "linux,phandle", &xref, sizeof(xref)) == -1) + if (OF_getencprop(node, "phandle", &xref, sizeof(xref)) == -1 && + OF_getencprop(node, "ibm,phandle", &xref, sizeof(xref)) == -1 && + OF_getencprop(node, "linux,phandle", &xref, sizeof(xref)) == -1) return (node); return (xref); } diff --git a/sys/dev/sound/pci/hdspe.h b/sys/dev/sound/pci/hdspe.h index c7be775302e..c2654c8f492 100644 --- a/sys/dev/sound/pci/hdspe.h +++ b/sys/dev/sound/pci/hdspe.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2012 Ruslan Bukin + * Copyright (c) 2012-2016 Ruslan Bukin * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,71 +26,97 @@ * $FreeBSD$ */ -#define PCI_VENDOR_XILINX 0x10ee -#define PCI_DEVICE_XILINX_HDSPE 0x3fc6 /* AIO, MADI, AES, RayDAT */ -#define PCI_CLASS_REVISION 0x08 -#define PCI_REVISION_AIO 212 -#define PCI_REVISION_RAYDAT 211 +#define PCI_VENDOR_XILINX 0x10ee +#define PCI_DEVICE_XILINX_HDSPE 0x3fc6 /* AIO, MADI, AES, RayDAT */ +#define PCI_CLASS_REVISION 0x08 +#define PCI_REVISION_AIO 212 +#define PCI_REVISION_RAYDAT 211 -#define AIO 0 -#define RAYDAT 1 +#define AIO 0 +#define RAYDAT 1 /* Hardware mixer */ -#define HDSPE_OUT_ENABLE_BASE 512 -#define HDSPE_IN_ENABLE_BASE 768 -#define HDSPE_MIXER_BASE 32768 -#define HDSPE_MAX_GAIN 32768 +#define HDSPE_OUT_ENABLE_BASE 512 +#define HDSPE_IN_ENABLE_BASE 768 +#define HDSPE_MIXER_BASE 32768 +#define HDSPE_MAX_GAIN 32768 /* Buffer */ -#define HDSPE_PAGE_ADDR_BUF_OUT 8192 -#define HDSPE_PAGE_ADDR_BUF_IN (HDSPE_PAGE_ADDR_BUF_OUT + 64 * 16 * 4) -#define HDSPE_BUF_POSITION_MASK 0x000FFC0 +#define HDSPE_PAGE_ADDR_BUF_OUT 8192 +#define HDSPE_PAGE_ADDR_BUF_IN (HDSPE_PAGE_ADDR_BUF_OUT + 64 * 16 * 4) +#define HDSPE_BUF_POSITION_MASK 0x000FFC0 /* Frequency */ -#define HDSPE_FREQ_0 (1<<6) -#define HDSPE_FREQ_1 (1<<7) -#define HDSPE_FREQ_DOUBLE (1<<8) -#define HDSPE_FREQ_QUAD (1<<31) +#define HDSPE_FREQ_0 (1 << 6) +#define HDSPE_FREQ_1 (1 << 7) +#define HDSPE_FREQ_DOUBLE (1 << 8) +#define HDSPE_FREQ_QUAD (1 << 31) -#define HDSPE_FREQ_32000 HDSPE_FREQ_0 -#define HDSPE_FREQ_44100 HDSPE_FREQ_1 -#define HDSPE_FREQ_48000 (HDSPE_FREQ_0 | HDSPE_FREQ_1) -#define HDSPE_FREQ_MASK (HDSPE_FREQ_0 | HDSPE_FREQ_1 | \ +#define HDSPE_FREQ_32000 HDSPE_FREQ_0 +#define HDSPE_FREQ_44100 HDSPE_FREQ_1 +#define HDSPE_FREQ_48000 (HDSPE_FREQ_0 | HDSPE_FREQ_1) +#define HDSPE_FREQ_MASK (HDSPE_FREQ_0 | HDSPE_FREQ_1 | \ HDSPE_FREQ_DOUBLE | HDSPE_FREQ_QUAD) -#define HDSPE_FREQ_MASK_DEFAULT HDSPE_FREQ_48000 -#define HDSPE_FREQ_REG 256 -#define HDSPE_FREQ_AIO 104857600000000ULL +#define HDSPE_FREQ_MASK_DEFAULT HDSPE_FREQ_48000 +#define HDSPE_FREQ_REG 256 +#define HDSPE_FREQ_AIO 104857600000000ULL -#define HDSPE_SPEED_DEFAULT 48000 +#define HDSPE_SPEED_DEFAULT 48000 /* Latency */ -#define HDSPE_LAT_0 (1<<1) -#define HDSPE_LAT_1 (1<<2) -#define HDSPE_LAT_2 (1<<3) -#define HDSPE_LAT_MASK (HDSPE_LAT_0 | HDSPE_LAT_1 | HDSPE_LAT_2) -#define HDSPE_LAT_BYTES_MAX (4096 * 4) -#define HDSPE_LAT_BYTES_MIN (32 * 4) -#define hdspe_encode_latency(x) (((x)<<1) & HDSPE_LAT_MASK) +#define HDSPE_LAT_0 (1 << 1) +#define HDSPE_LAT_1 (1 << 2) +#define HDSPE_LAT_2 (1 << 3) +#define HDSPE_LAT_MASK (HDSPE_LAT_0 | HDSPE_LAT_1 | HDSPE_LAT_2) +#define HDSPE_LAT_BYTES_MAX (4096 * 4) +#define HDSPE_LAT_BYTES_MIN (32 * 4) +#define hdspe_encode_latency(x) (((x)<<1) & HDSPE_LAT_MASK) + +/* Gain */ +#define HDSP_ADGain0 (1 << 25) +#define HDSP_ADGain1 (1 << 26) +#define HDSP_DAGain0 (1 << 27) +#define HDSP_DAGain1 (1 << 28) +#define HDSP_PhoneGain0 (1 << 29) +#define HDSP_PhoneGain1 (1 << 30) + +#define HDSP_ADGainMask (HDSP_ADGain0 | HDSP_ADGain1) +#define HDSP_ADGainMinus10dBV (HDSP_ADGainMask) +#define HDSP_ADGainPlus4dBu (HDSP_ADGain0) +#define HDSP_ADGainLowGain 0 + +#define HDSP_DAGainMask (HDSP_DAGain0 | HDSP_DAGain1) +#define HDSP_DAGainHighGain (HDSP_DAGainMask) +#define HDSP_DAGainPlus4dBu (HDSP_DAGain0) +#define HDSP_DAGainMinus10dBV 0 + +#define HDSP_PhoneGainMask (HDSP_PhoneGain0|HDSP_PhoneGain1) +#define HDSP_PhoneGain0dB HDSP_PhoneGainMask +#define HDSP_PhoneGainMinus6dB (HDSP_PhoneGain0) +#define HDSP_PhoneGainMinus12dB 0 + +#define HDSPM_statusRegister 0 +#define HDSPM_statusRegister2 192 /* Settings */ -#define HDSPE_SETTINGS_REG 0 -#define HDSPE_CONTROL_REG 64 -#define HDSPE_STATUS_REG 0 -#define HDSPE_ENABLE (1<<0) -#define HDSPM_CLOCK_MODE_MASTER (1<<4) +#define HDSPE_SETTINGS_REG 0 +#define HDSPE_CONTROL_REG 64 +#define HDSPE_STATUS_REG 0 +#define HDSPE_ENABLE (1 << 0) +#define HDSPM_CLOCK_MODE_MASTER (1 << 4) /* Interrupts */ -#define HDSPE_AUDIO_IRQ_PENDING (1<<0) -#define HDSPE_AUDIO_INT_ENABLE (1<<5) -#define HDSPE_INTERRUPT_ACK 96 +#define HDSPE_AUDIO_IRQ_PENDING (1 << 0) +#define HDSPE_AUDIO_INT_ENABLE (1 << 5) +#define HDSPE_INTERRUPT_ACK 96 /* Channels */ -#define HDSPE_MAX_SLOTS 64 /* Mono channels */ -#define HDSPE_MAX_CHANS (HDSPE_MAX_SLOTS / 2) /* Stereo pairs */ +#define HDSPE_MAX_SLOTS 64 /* Mono channels */ +#define HDSPE_MAX_CHANS (HDSPE_MAX_SLOTS / 2) /* Stereo pairs */ -#define HDSPE_CHANBUF_SAMPLES (16 * 1024) -#define HDSPE_CHANBUF_SIZE (4 * HDSPE_CHANBUF_SAMPLES) -#define HDSPE_DMASEGSIZE (HDSPE_CHANBUF_SIZE * HDSPE_MAX_SLOTS) +#define HDSPE_CHANBUF_SAMPLES (16 * 1024) +#define HDSPE_CHANBUF_SIZE (4 * HDSPE_CHANBUF_SAMPLES) +#define HDSPE_DMASEGSIZE (HDSPE_CHANBUF_SIZE * HDSPE_MAX_SLOTS) struct hdspe_channel { uint32_t left; @@ -164,16 +190,16 @@ struct sc_info { uint32_t speed; }; -#define hdspe_read_1(sc, regno) \ +#define hdspe_read_1(sc, regno) \ bus_space_read_1((sc)->cst, (sc)->csh, (regno)) -#define hdspe_read_2(sc, regno) \ +#define hdspe_read_2(sc, regno) \ bus_space_read_2((sc)->cst, (sc)->csh, (regno)) -#define hdspe_read_4(sc, regno) \ +#define hdspe_read_4(sc, regno) \ bus_space_read_4((sc)->cst, (sc)->csh, (regno)) -#define hdspe_write_1(sc, regno, data) \ +#define hdspe_write_1(sc, regno, data) \ bus_space_write_1((sc)->cst, (sc)->csh, (regno), (data)) -#define hdspe_write_2(sc, regno, data) \ +#define hdspe_write_2(sc, regno, data) \ bus_space_write_2((sc)->cst, (sc)->csh, (regno), (data)) -#define hdspe_write_4(sc, regno, data) \ +#define hdspe_write_4(sc, regno, data) \ bus_space_write_4((sc)->cst, (sc)->csh, (regno), (data)) diff --git a/sys/dev/uart/uart_tty.c b/sys/dev/uart/uart_tty.c index 6b526aec410..27ceb5b1934 100644 --- a/sys/dev/uart/uart_tty.c +++ b/sys/dev/uart/uart_tty.c @@ -57,6 +57,16 @@ static cn_putc_t uart_cnputc; static cn_grab_t uart_cngrab; static cn_ungrab_t uart_cnungrab; +static tsw_open_t uart_tty_open; +static tsw_close_t uart_tty_close; +static tsw_outwakeup_t uart_tty_outwakeup; +static tsw_inwakeup_t uart_tty_inwakeup; +static tsw_ioctl_t uart_tty_ioctl; +static tsw_param_t uart_tty_param; +static tsw_modem_t uart_tty_modem; +static tsw_free_t uart_tty_free; +static tsw_busy_t uart_tty_busy; + CONSOLE_DRIVER(uart); static struct uart_devinfo uart_console; @@ -157,7 +167,7 @@ uart_tty_close(struct tty *tp) struct uart_softc *sc; sc = tty_softc(tp); - if (sc == NULL || sc->sc_leaving || !sc->sc_opened) + if (sc == NULL || sc->sc_leaving || !sc->sc_opened) return; if (sc->sc_hwiflow) @@ -169,7 +179,6 @@ uart_tty_close(struct tty *tp) wakeup(sc); sc->sc_opened = 0; - return; } static void @@ -215,7 +224,8 @@ uart_tty_inwakeup(struct tty *tp) } static int -uart_tty_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td) +uart_tty_ioctl(struct tty *tp, u_long cmd, caddr_t data, + struct thread *td __unused) { struct uart_softc *sc; @@ -256,8 +266,8 @@ uart_tty_param(struct tty *tp, struct termios *t) } stopbits = (t->c_cflag & CSTOPB) ? 2 : 1; if (t->c_cflag & PARENB) - parity = (t->c_cflag & PARODD) ? UART_PARITY_ODD - : UART_PARITY_EVEN; + parity = (t->c_cflag & PARODD) ? UART_PARITY_ODD : + UART_PARITY_EVEN; else parity = UART_PARITY_NONE; if (UART_PARAM(sc, t->c_ospeed, databits, stopbits, parity) != 0) @@ -285,7 +295,7 @@ uart_tty_modem(struct tty *tp, int biton, int bitoff) sc = tty_softc(tp); if (biton != 0 || bitoff != 0) - UART_SETSIG(sc, SER_DELTA(bitoff|biton) | biton); + UART_SETSIG(sc, SER_DELTA(bitoff | biton) | biton); return (sc->sc_hwsig); } @@ -344,7 +354,7 @@ uart_tty_intr(void *arg) } static void -uart_tty_free(void *arg) +uart_tty_free(void *arg __unused) { /* @@ -359,7 +369,7 @@ static bool uart_tty_busy(struct tty *tp) { struct uart_softc *sc; - + sc = tty_softc(tp); if (sc == NULL || sc->sc_leaving) return (FALSE); diff --git a/sys/fs/ext2fs/ext2_alloc.c b/sys/fs/ext2fs/ext2_alloc.c index 935cb0caeda..12067d2a9b2 100644 --- a/sys/fs/ext2fs/ext2_alloc.c +++ b/sys/fs/ext2fs/ext2_alloc.c @@ -393,6 +393,7 @@ ext2_valloc(struct vnode *pvp, int mode, struct ucred *cred, struct vnode **vpp) * Linux doesn't read the old inode in when it is allocating a * new one. I will set at least i_size and i_blocks to zero. */ + ip->i_flag = 0; ip->i_size = 0; ip->i_blocks = 0; ip->i_mode = 0; diff --git a/sys/fs/ext2fs/ext2_dinode.h b/sys/fs/ext2fs/ext2_dinode.h index 6ab6a84d91e..3f5ddefd755 100644 --- a/sys/fs/ext2fs/ext2_dinode.h +++ b/sys/fs/ext2fs/ext2_dinode.h @@ -51,8 +51,8 @@ /* * Inode flags * The system supports EXT2_IMMUTABLE, EXT2_APPEND and EXT2_NODUMP flags. - * The current implementation also uses EXT4_INDEX, EXT4_EXTENTS and - * EXT4_HUGE_FILE with some restrictions, imposed the lack of write + * The current implementation also uses EXT3_INDEX, EXT4_EXTENTS and + * EXT4_HUGE_FILE with some restrictions imposed by the lack of write * support. */ #define EXT2_SECRM 0x00000001 /* Secure deletion */ @@ -63,7 +63,7 @@ #define EXT2_APPEND 0x00000020 /* Writes to file may only append */ #define EXT2_NODUMP 0x00000040 /* Do not dump file */ #define EXT2_NOATIME 0x00000080 /* Do not update atime */ -#define EXT4_INDEX 0x00001000 /* Hash-indexed directory */ +#define EXT3_INDEX 0x00001000 /* Hash-indexed directory */ #define EXT4_IMAGIC 0x00002000 /* AFS directory */ #define EXT4_JOURNAL_DATA 0x00004000 /* File data should be journaled */ #define EXT4_NOTAIL 0x00008000 /* File tail should not be merged */ diff --git a/sys/fs/ext2fs/ext2_htree.c b/sys/fs/ext2fs/ext2_htree.c index ac506bdafee..a109224f2a4 100644 --- a/sys/fs/ext2fs/ext2_htree.c +++ b/sys/fs/ext2fs/ext2_htree.c @@ -90,7 +90,7 @@ int ext2_htree_has_idx(struct inode *ip) { if (EXT2_HAS_COMPAT_FEATURE(ip->i_e2fs, EXT2F_COMPAT_DIRHASHINDEX) && - ip->i_flag & IN_E4INDEX) + ip->i_flag & IN_E3INDEX) return (1); else return (0); @@ -653,7 +653,7 @@ ext2_htree_create_index(struct vnode *vp, struct componentname *cnp, ((char *)ep + ep->e2d_reclen); ep->e2d_reclen = buf1 + blksize - (char *)ep; - dp->i_flag |= IN_E4INDEX; + dp->i_flag |= IN_E3INDEX; /* * Initialize index root. diff --git a/sys/fs/ext2fs/ext2_inode_cnv.c b/sys/fs/ext2fs/ext2_inode_cnv.c index b69d4e5c8b6..78679cff0fd 100644 --- a/sys/fs/ext2fs/ext2_inode_cnv.c +++ b/sys/fs/ext2fs/ext2_inode_cnv.c @@ -110,7 +110,7 @@ ext2_ei2i(struct ext2fs_dinode *ei, struct inode *ip) ip->i_flags |= (ei->e2di_flags & EXT2_APPEND) ? SF_APPEND : 0; ip->i_flags |= (ei->e2di_flags & EXT2_IMMUTABLE) ? SF_IMMUTABLE : 0; ip->i_flags |= (ei->e2di_flags & EXT2_NODUMP) ? UF_NODUMP : 0; - ip->i_flag |= (ei->e2di_flags & EXT4_INDEX) ? IN_E4INDEX : 0; + ip->i_flag |= (ei->e2di_flags & EXT3_INDEX) ? IN_E3INDEX : 0; ip->i_flag |= (ei->e2di_flags & EXT4_EXTENTS) ? IN_E4EXTENTS : 0; ip->i_blocks = ei->e2di_nblock; if (E2DI_HAS_HUGE_FILE(ip)) { @@ -149,18 +149,16 @@ ext2_i2ei(struct inode *ip, struct ext2fs_dinode *ei) ei->e2di_atime = ip->i_atime; ei->e2di_mtime = ip->i_mtime; ei->e2di_ctime = ip->i_ctime; - if (E2DI_HAS_XTIME(ip)) { - ei->e2di_ctime_extra = NSEC_TO_XTIME(ip->i_ctimensec); - ei->e2di_mtime_extra = NSEC_TO_XTIME(ip->i_mtimensec); - ei->e2di_atime_extra = NSEC_TO_XTIME(ip->i_atimensec); - ei->e2di_crtime = ip->i_birthtime; - ei->e2di_crtime_extra = NSEC_TO_XTIME(ip->i_birthnsec); - } + ei->e2di_ctime_extra = NSEC_TO_XTIME(ip->i_ctimensec); + ei->e2di_mtime_extra = NSEC_TO_XTIME(ip->i_mtimensec); + ei->e2di_atime_extra = NSEC_TO_XTIME(ip->i_atimensec); + ei->e2di_crtime = ip->i_birthtime; + ei->e2di_crtime_extra = NSEC_TO_XTIME(ip->i_birthnsec); ei->e2di_flags = 0; ei->e2di_flags |= (ip->i_flags & SF_APPEND) ? EXT2_APPEND: 0; ei->e2di_flags |= (ip->i_flags & SF_IMMUTABLE) ? EXT2_IMMUTABLE: 0; ei->e2di_flags |= (ip->i_flags & UF_NODUMP) ? EXT2_NODUMP: 0; - ei->e2di_flags |= (ip->i_flag & IN_E4INDEX) ? EXT4_INDEX: 0; + ei->e2di_flags |= (ip->i_flag & IN_E3INDEX) ? EXT3_INDEX: 0; 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; diff --git a/sys/fs/ext2fs/ext2_lookup.c b/sys/fs/ext2fs/ext2_lookup.c index 309e383c0f8..5980c4b05ab 100644 --- a/sys/fs/ext2fs/ext2_lookup.c +++ b/sys/fs/ext2fs/ext2_lookup.c @@ -888,7 +888,7 @@ ext2_direnter(struct inode *ip, struct vnode *dvp, struct componentname *cnp) if (ext2_htree_has_idx(dp)) { error = ext2_htree_add_entry(dvp, &newdir, cnp); if (error) { - dp->i_flag &= ~IN_E4INDEX; + dp->i_flag &= ~IN_E3INDEX; dp->i_flag |= IN_CHANGE | IN_UPDATE; } return (error); diff --git a/sys/fs/ext2fs/inode.h b/sys/fs/ext2fs/inode.h index b1563e40be9..5222ba0f176 100644 --- a/sys/fs/ext2fs/inode.h +++ b/sys/fs/ext2fs/inode.h @@ -157,7 +157,7 @@ struct inode { * These are translation flags for some attributes that Ext4 * passes as inode flags but that we cannot pass directly. */ -#define IN_E4INDEX 0x010000 +#define IN_E3INDEX 0x010000 #define IN_E4EXTENTS 0x020000 #define i_devvp i_ump->um_devvp diff --git a/sys/geom/geom_flashmap.c b/sys/geom/geom_flashmap.c index 0383f69793d..76dd1fadd57 100644 --- a/sys/geom/geom_flashmap.c +++ b/sys/geom/geom_flashmap.c @@ -190,8 +190,12 @@ g_flashmap_taste(struct g_class *mp, struct g_provider *pp, int flags) size = sizeof(device_t); if (g_io_getattr("NAND::device", cp, &size, &dev)) { size = sizeof(device_t); - if (g_io_getattr("CFI::device", cp, &size, &dev)) - break; + if (g_io_getattr("CFI::device", cp, &size, &dev)) { + size = sizeof(device_t); + if (g_io_getattr("SPI::device", cp, &size, + &dev)) + break; + } } nslices = g_flashmap_load(dev, &head); diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c index 803951f2e28..f57cd588902 100644 --- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -166,6 +166,8 @@ sysctl_root_handler_locked(struct sysctl_oid *oid, void *arg1, intmax_t arg2, if (!(oid->oid_kind & CTLFLAG_MPSAFE)) mtx_unlock(&Giant); + KFAIL_POINT_ERROR(_debug_fail_point, sysctl_running, error); + if (tracker != NULL) SYSCTL_RLOCK(tracker); else @@ -1838,8 +1840,6 @@ sysctl_root(SYSCTL_HANDLER_ARGS) #endif error = sysctl_root_handler_locked(oid, arg1, arg2, req, &tracker); - KFAIL_POINT_ERROR(_debug_fail_point, sysctl_running, error); - out: SYSCTL_RUNLOCK(&tracker); return (error); diff --git a/sys/kern/tty.c b/sys/kern/tty.c index e28b303cefa..2d233270dea 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -175,6 +175,7 @@ tty_drain(struct tty *tp, int leaving) static __inline int ttydev_enter(struct tty *tp) { + tty_lock(tp); if (tty_gone(tp) || !tty_opened(tp)) { @@ -189,6 +190,7 @@ ttydev_enter(struct tty *tp) static void ttydev_leave(struct tty *tp) { + tty_lock_assert(tp, MA_OWNED); if (tty_opened(tp) || tp->t_flags & TF_OPENCLOSE) { @@ -234,7 +236,8 @@ ttydev_leave(struct tty *tp) * Operations that are exposed through the character device in /dev. */ static int -ttydev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) +ttydev_open(struct cdev *dev, int oflags, int devtype __unused, + struct thread *td) { struct tty *tp; int error; @@ -263,10 +266,10 @@ ttydev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) /* * Make sure the "tty" and "cua" device cannot be opened at the - * same time. + * same time. The console is a "tty" device. */ if (TTY_CALLOUT(tp, dev)) { - if (tp->t_flags & TF_OPENED_IN) { + if (tp->t_flags & (TF_OPENED_CONS | TF_OPENED_IN)) { error = EBUSY; goto done; } @@ -319,6 +322,8 @@ ttydev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) tp->t_flags |= TF_OPENED_OUT; else tp->t_flags |= TF_OPENED_IN; + MPASS((tp->t_flags & (TF_OPENED_CONS | TF_OPENED_IN)) == 0 || + (tp->t_flags & TF_OPENED_OUT) == 0); done: tp->t_flags &= ~TF_OPENCLOSE; cv_broadcast(&tp->t_dcdwait); @@ -328,7 +333,8 @@ done: tp->t_flags &= ~TF_OPENCLOSE; } static int -ttydev_close(struct cdev *dev, int fflag, int devtype, struct thread *td) +ttydev_close(struct cdev *dev, int fflag, int devtype __unused, + struct thread *td __unused) { struct tty *tp = dev->si_drv1; @@ -338,7 +344,8 @@ ttydev_close(struct cdev *dev, int fflag, int devtype, struct thread *td) * Don't actually close the device if it is being used as the * console. */ - MPASS((tp->t_flags & TF_OPENED) != TF_OPENED); + MPASS((tp->t_flags & (TF_OPENED_CONS | TF_OPENED_IN)) == 0 || + (tp->t_flags & TF_OPENED_OUT) == 0); if (dev == dev_console) tp->t_flags &= ~TF_OPENED_CONS; else @@ -369,6 +376,7 @@ ttydev_close(struct cdev *dev, int fflag, int devtype, struct thread *td) static __inline int tty_is_ctty(struct tty *tp, struct proc *p) { + tty_lock_assert(tp, MA_OWNED); return (p->p_session == tp->t_session && p->p_flag & P_CONTROLT); @@ -649,7 +657,7 @@ tty_kqops_read_detach(struct knote *kn) } static int -tty_kqops_read_event(struct knote *kn, long hint) +tty_kqops_read_event(struct knote *kn, long hint __unused) { struct tty *tp = kn->kn_hook; @@ -673,7 +681,7 @@ tty_kqops_write_detach(struct knote *kn) } static int -tty_kqops_write_event(struct knote *kn, long hint) +tty_kqops_write_event(struct knote *kn, long hint __unused) { struct tty *tp = kn->kn_hook; @@ -693,6 +701,7 @@ static struct filterops tty_kqops_read = { .f_detach = tty_kqops_read_detach, .f_event = tty_kqops_read_event, }; + static struct filterops tty_kqops_write = { .f_isfd = 1, .f_detach = tty_kqops_write_detach, @@ -748,7 +757,8 @@ static struct cdevsw ttydev_cdevsw = { */ static int -ttyil_open(struct cdev *dev, int oflags, int devtype, struct thread *td) +ttyil_open(struct cdev *dev, int oflags __unused, int devtype __unused, + struct thread *td) { struct tty *tp; int error; @@ -764,14 +774,18 @@ ttyil_open(struct cdev *dev, int oflags, int devtype, struct thread *td) } static int -ttyil_close(struct cdev *dev, int flag, int mode, struct thread *td) +ttyil_close(struct cdev *dev __unused, int flag __unused, int mode __unused, + struct thread *td __unused) { + return (0); } static int -ttyil_rdwr(struct cdev *dev, struct uio *uio, int ioflag) +ttyil_rdwr(struct cdev *dev __unused, struct uio *uio __unused, + int ioflag __unused) { + return (ENODEV); } @@ -868,45 +882,49 @@ tty_init_console(struct tty *tp, speed_t s) */ static int -ttydevsw_defopen(struct tty *tp) +ttydevsw_defopen(struct tty *tp __unused) { return (0); } static void -ttydevsw_defclose(struct tty *tp) +ttydevsw_defclose(struct tty *tp __unused) { + } static void -ttydevsw_defoutwakeup(struct tty *tp) +ttydevsw_defoutwakeup(struct tty *tp __unused) { panic("Terminal device has output, while not implemented"); } static void -ttydevsw_definwakeup(struct tty *tp) +ttydevsw_definwakeup(struct tty *tp __unused) { + } static int -ttydevsw_defioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td) +ttydevsw_defioctl(struct tty *tp __unused, u_long cmd __unused, + caddr_t data __unused, struct thread *td __unused) { return (ENOIOCTL); } static int -ttydevsw_defcioctl(struct tty *tp, int unit, u_long cmd, caddr_t data, struct thread *td) +ttydevsw_defcioctl(struct tty *tp __unused, int unit __unused, + u_long cmd __unused, caddr_t data __unused, struct thread *td __unused) { return (ENOIOCTL); } static int -ttydevsw_defparam(struct tty *tp, struct termios *t) +ttydevsw_defparam(struct tty *tp __unused, struct termios *t) { /* @@ -928,7 +946,8 @@ ttydevsw_defparam(struct tty *tp, struct termios *t) } static int -ttydevsw_defmodem(struct tty *tp, int sigon, int sigoff) +ttydevsw_defmodem(struct tty *tp __unused, int sigon __unused, + int sigoff __unused) { /* Simulate a carrier to make the TTY layer happy. */ @@ -936,20 +955,22 @@ ttydevsw_defmodem(struct tty *tp, int sigon, int sigoff) } static int -ttydevsw_defmmap(struct tty *tp, vm_ooffset_t offset, vm_paddr_t *paddr, - int nprot, vm_memattr_t *memattr) +ttydevsw_defmmap(struct tty *tp __unused, vm_ooffset_t offset __unused, + vm_paddr_t *paddr __unused, int nprot __unused, + vm_memattr_t *memattr __unused) { return (-1); } static void -ttydevsw_defpktnotify(struct tty *tp, char event) +ttydevsw_defpktnotify(struct tty *tp __unused, char event __unused) { + } static void -ttydevsw_deffree(void *softc) +ttydevsw_deffree(void *softc __unused) { panic("Terminal device freed without a free-handler"); @@ -1088,6 +1109,7 @@ tty_rel_free(struct tty *tp) void tty_rel_pgrp(struct tty *tp, struct pgrp *pg) { + MPASS(tp->t_sessioncnt > 0); tty_lock_assert(tp, MA_OWNED); @@ -1100,6 +1122,7 @@ tty_rel_pgrp(struct tty *tp, struct pgrp *pg) void tty_rel_sess(struct tty *tp, struct session *sess) { + MPASS(tp->t_sessioncnt > 0); /* Current session has left. */ @@ -1114,6 +1137,7 @@ tty_rel_sess(struct tty *tp, struct session *sess) void tty_rel_gone(struct tty *tp) { + MPASS(!tty_gone(tp)); /* Simulate carrier removal. */ @@ -1135,6 +1159,7 @@ tty_rel_gone(struct tty *tp) static void tty_to_xtty(struct tty *tp, struct xtty *xt) { + tty_lock_assert(tp, MA_OWNED); xt->xt_size = sizeof(struct xtty); @@ -1367,6 +1392,7 @@ tty_signal_pgrp(struct tty *tp, int sig) void tty_wakeup(struct tty *tp, int flags) { + if (tp->t_flags & TF_ASYNC && tp->t_sigio != NULL) pgsigio(&tp->t_sigio, SIGIO, (tp->t_session != NULL)); @@ -1429,6 +1455,7 @@ tty_timedwait(struct tty *tp, struct cv *cv, int hz) void tty_flush(struct tty *tp, int flags) { + if (flags & FWRITE) { tp->t_flags &= ~TF_HIWAT_OUT; ttyoutq_flush(&tp->t_outq); @@ -1819,10 +1846,11 @@ tty_ioctl(struct tty *tp, u_long cmd, void *data, int fflag, struct thread *td) dev_t tty_udev(struct tty *tp) { + if (tp->t_dev) - return dev2udev(tp->t_dev); + return (dev2udev(tp->t_dev)); else - return NODEV; + return (NODEV); } int @@ -1891,8 +1919,8 @@ ttyhook_defrint(struct tty *tp, char c, int flags) } int -ttyhook_register(struct tty **rtp, struct proc *p, int fd, - struct ttyhook *th, void *softc) +ttyhook_register(struct tty **rtp, struct proc *p, int fd, struct ttyhook *th, + void *softc) { struct tty *tp; struct file *fp; @@ -2043,7 +2071,7 @@ static struct cdevsw ttyconsdev_cdevsw = { }; static void -ttyconsdev_init(void *unused) +ttyconsdev_init(void *unused __unused) { dev_console = make_dev_credf(MAKEDEV_ETERNAL, &ttyconsdev_cdevsw, 0, @@ -2068,7 +2096,7 @@ ttyconsdev_select(const char *name) #include #include -static struct { +static const struct { int flag; char val; } ttystates[] = { @@ -2109,9 +2137,11 @@ static struct { }; #define TTY_FLAG_BITS \ - "\20\1NOPREFIX\2INITLOCK\3CALLOUT\4OPENED_IN\5OPENED_OUT\6GONE" \ - "\7OPENCLOSE\10ASYNC\11LITERAL\12HIWAT_IN\13HIWAT_OUT\14STOPPED" \ - "\15EXCLUDE\16BYPASS\17ZOMBIE\20HOOK" + "\20\1NOPREFIX\2INITLOCK\3CALLOUT\4OPENED_IN" \ + "\5OPENED_OUT\6OPENED_CONS\7GONE\10OPENCLOSE" \ + "\11ASYNC\12LITERAL\13HIWAT_IN\14HIWAT_OUT" \ + "\15STOPPED\16EXCLUDE\17BYPASS\20ZOMBIE" \ + "\21HOOK\22BUSY_IN\23BUSY_OUT" #define DB_PRINTSYM(name, addr) \ db_printf("%s " #name ": ", sep); \ @@ -2121,6 +2151,7 @@ static struct { static void _db_show_devsw(const char *sep, const struct ttydevsw *tsw) { + db_printf("%sdevsw: ", sep); db_printsym((db_addr_t)tsw, DB_STGY_ANY); db_printf(" (%p)\n", tsw); @@ -2135,9 +2166,11 @@ _db_show_devsw(const char *sep, const struct ttydevsw *tsw) DB_PRINTSYM(pktnotify, tsw->tsw_pktnotify); DB_PRINTSYM(free, tsw->tsw_free); } + static void _db_show_hooks(const char *sep, const struct ttyhook *th) { + db_printf("%shook: ", sep); db_printsym((db_addr_t)th, DB_STGY_ANY); db_printf(" (%p)\n", th); @@ -2174,9 +2207,9 @@ DB_SHOW_COMMAND(tty, db_show_tty) } tp = (struct tty *)addr; - db_printf("0x%p: %s\n", tp, tty_devname(tp)); + db_printf("%p: %s\n", tp, tty_devname(tp)); db_printf("\tmtx: %p\n", tp->t_mtx); - db_printf("\tflags: %b\n", tp->t_flags, TTY_FLAG_BITS); + db_printf("\tflags: 0x%b\n", tp->t_flags, TTY_FLAG_BITS); db_printf("\trevokecnt: %u\n", tp->t_revokecnt); /* Buffering mechanisms. */ @@ -2243,17 +2276,13 @@ DB_SHOW_ALL_COMMAND(ttys, db_show_all_ttys) isiz = tp->t_inq.ti_nblocks * TTYINQ_DATASIZE; osiz = tp->t_outq.to_nblocks * TTYOUTQ_DATASIZE; - db_printf("%p %10s %5zu %4u %4u %4zu %5zu %4u %4zu %5u %5d %5d ", - tp, - tty_devname(tp), - isiz, + db_printf("%p %10s %5zu %4u %4u %4zu %5zu %4u %4zu %5u %5d " + "%5d ", tp, tty_devname(tp), isiz, tp->t_inq.ti_linestart - tp->t_inq.ti_begin, tp->t_inq.ti_end - tp->t_inq.ti_linestart, - isiz - tp->t_inlow, - osiz, + isiz - tp->t_inlow, osiz, tp->t_outq.to_end - tp->t_outq.to_begin, - osiz - tp->t_outlow, - MIN(tp->t_column, 99999), + osiz - tp->t_outlow, MIN(tp->t_column, 99999), tp->t_session ? tp->t_session->s_sid : 0, tp->t_pgrp ? tp->t_pgrp->pg_id : 0); diff --git a/sys/kern/vfs_export.c b/sys/kern/vfs_export.c index 7524aab6c69..9be0ece53d9 100644 --- a/sys/kern/vfs_export.c +++ b/sys/kern/vfs_export.c @@ -199,7 +199,7 @@ vfs_hang_addrlist(struct mount *mp, struct netexport *nep, goto out; } RADIX_NODE_HEAD_LOCK(rnh); - rn = (*rnh->rnh_addaddr)(saddr, smask, rnh, np->netc_rnodes); + rn = (*rnh->rnh_addaddr)(saddr, smask, &rnh->rh, np->netc_rnodes); RADIX_NODE_HEAD_UNLOCK(rnh); if (rn == NULL || np != (struct netcred *)rn) { /* already exists */ error = EPERM; @@ -231,7 +231,7 @@ vfs_free_netcred(struct radix_node *rn, void *w) struct radix_node_head *rnh = (struct radix_node_head *) w; struct ucred *cred; - (*rnh->rnh_deladdr) (rn->rn_key, rn->rn_mask, rnh); + (*rnh->rnh_deladdr) (rn->rn_key, rn->rn_mask, &rnh->rh); cred = ((struct netcred *)rn)->netc_anon; if (cred != NULL) crfree(cred); @@ -256,7 +256,7 @@ vfs_free_addrlist_af(struct radix_node_head **prnh) rnh = *prnh; RADIX_NODE_HEAD_LOCK(rnh); - (*rnh->rnh_walktree) (rnh, vfs_free_netcred, rnh); + (*rnh->rnh_walktree)(&rnh->rh, vfs_free_netcred, &rnh->rh); RADIX_NODE_HEAD_UNLOCK(rnh); RADIX_NODE_HEAD_DESTROY(rnh); free(rnh, M_RTABLE); @@ -470,7 +470,7 @@ vfs_export_lookup(struct mount *mp, struct sockaddr *nam) if (rnh != NULL) { RADIX_NODE_HEAD_RLOCK(rnh); np = (struct netcred *) - (*rnh->rnh_matchaddr)(saddr, rnh); + (*rnh->rnh_matchaddr)(saddr, &rnh->rh); RADIX_NODE_HEAD_RUNLOCK(rnh); if (np && np->netc_rnodes->rn_flags & RNF_ROOT) np = NULL; diff --git a/sys/mips/conf/AR934X_BASE b/sys/mips/conf/AR934X_BASE index e55f4201d36..4faaf9e6be6 100644 --- a/sys/mips/conf/AR934X_BASE +++ b/sys/mips/conf/AR934X_BASE @@ -83,7 +83,6 @@ device ath_ahb # Atheros host bus glue options ATH_DEBUG options ATH_DIAGAPI option ATH_ENABLE_11N -option AH_DEBUG_ALQ #device ath_hal device ath_ar9300 # AR9330 HAL; no need for the others diff --git a/sys/net/if_lagg.c b/sys/net/if_lagg.c index 730a044a8f1..e1e1837f3d7 100644 --- a/sys/net/if_lagg.c +++ b/sys/net/if_lagg.c @@ -3,7 +3,7 @@ /* * Copyright (c) 2005, 2006 Reyk Floeter * Copyright (c) 2007 Andrew Thompson - * Copyright (c) 2014 Marcelo Araujo + * Copyright (c) 2014, 2016 Marcelo Araujo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -1291,10 +1291,17 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) ro->ro_active += LAGG_PORTACTIVE(lp); } + ro->ro_bkt = sc->sc_bkt; ro->ro_flapping = sc->sc_flapping; ro->ro_flowid_shift = sc->flowid_shift; break; case SIOCSLAGGOPTS: + if (sc->sc_proto == LAGG_PROTO_ROUNDROBIN) { + if (ro->ro_bkt == 0) + sc->sc_bkt = 1; // Minimum 1 packet per iface. + else + sc->sc_bkt = ro->ro_bkt; + } error = priv_check(td, PRIV_NET_LAGG); if (error) break; @@ -1329,6 +1336,7 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) } LAGG_WLOCK(sc); + if (valid == 0 || (lacp == 1 && sc->sc_proto != LAGG_PROTO_LACP)) { /* Invalid combination of options specified. */ @@ -1879,6 +1887,7 @@ lagg_rr_attach(struct lagg_softc *sc) { sc->sc_capabilities = IFCAP_LAGG_FULLDUPLEX; sc->sc_seq = 0; + sc->sc_bkt_count = sc->sc_bkt; } static int @@ -1887,9 +1896,21 @@ lagg_rr_start(struct lagg_softc *sc, struct mbuf *m) struct lagg_port *lp; uint32_t p; - p = atomic_fetchadd_32(&sc->sc_seq, 1); + if (sc->sc_bkt_count == 0 && sc->sc_bkt > 0) + sc->sc_bkt_count = sc->sc_bkt; + + if (sc->sc_bkt > 0) { + atomic_subtract_int(&sc->sc_bkt_count, 1); + if (atomic_cmpset_int(&sc->sc_bkt_count, 0, sc->sc_bkt)) + p = atomic_fetchadd_32(&sc->sc_seq, 1); + else + p = sc->sc_seq; + } else + p = atomic_fetchadd_32(&sc->sc_seq, 1); + p %= sc->sc_count; lp = SLIST_FIRST(&sc->sc_ports); + while (p--) lp = SLIST_NEXT(lp, lp_entries); diff --git a/sys/net/if_lagg.h b/sys/net/if_lagg.h index 195ac3a677a..334995e5c33 100644 --- a/sys/net/if_lagg.h +++ b/sys/net/if_lagg.h @@ -153,6 +153,7 @@ struct lagg_reqopts { u_int ro_active; /* active port count */ u_int ro_flapping; /* number of flapping */ int ro_flowid_shift; /* shift the flowid */ + uint32_t ro_bkt; /* packet bucket for roundrobin */ }; #define SIOCGLAGGOPTS _IOWR('i', 152, struct lagg_reqopts) @@ -243,6 +244,8 @@ struct lagg_softc { struct callout sc_callout; u_int sc_opts; int flowid_shift; /* shift the flowid */ + uint32_t sc_bkt; /* packates bucket for roundrobin */ + uint32_t sc_bkt_count; /* packates bucket count for roundrobin */ struct lagg_counters detached_counters; /* detached ports sum */ }; diff --git a/sys/net/radix.c b/sys/net/radix.c index d6db35ea3a9..2b4b9542b58 100644 --- a/sys/net/radix.c +++ b/sys/net/radix.c @@ -56,18 +56,15 @@ #include #endif /* !_KERNEL */ -static int rn_walktree_from(struct radix_node_head *h, void *a, void *m, - walktree_f_t *f, void *w); -static int rn_walktree(struct radix_node_head *, walktree_f_t *, void *); static struct radix_node - *rn_insert(void *, struct radix_node_head *, int *, + *rn_insert(void *, struct radix_head *, int *, struct radix_node [2]), *rn_newpair(void *, int, struct radix_node[2]), *rn_search(void *, struct radix_node *), *rn_search_m(void *, struct radix_node *, void *); +static struct radix_node *rn_addmask(void *, struct radix_mask_head *, int,int); -static void rn_detachhead_internal(void **head); -static int rn_inithead_internal(void **head, int off); +static void rn_detachhead_internal(struct radix_head *); #define RADIX_MAX_KEY_LEN 32 @@ -215,7 +212,7 @@ rn_refines(void *m_arg, void *n_arg) * from host routes. */ struct radix_node * -rn_lookup(void *v_arg, void *m_arg, struct radix_node_head *head) +rn_lookup(void *v_arg, void *m_arg, struct radix_head *head) { struct radix_node *x; caddr_t netmask; @@ -277,7 +274,7 @@ rn_satisfies_leaf(char *trial, struct radix_node *leaf, int skip) * Search for longest-prefix match in given @head */ struct radix_node * -rn_match(void *v_arg, struct radix_node_head *head) +rn_match(void *v_arg, struct radix_head *head) { caddr_t v = v_arg; struct radix_node *t = head->rnh_treetop, *x; @@ -426,7 +423,7 @@ rn_newpair(void *v, int b, struct radix_node nodes[2]) } static struct radix_node * -rn_insert(void *v_arg, struct radix_node_head *head, int *dupentry, +rn_insert(void *v_arg, struct radix_head *head, int *dupentry, struct radix_node nodes[2]) { caddr_t v = v_arg; @@ -490,7 +487,7 @@ on1: } struct radix_node * -rn_addmask(void *n_arg, struct radix_node_head *maskhead, int search, int skip) +rn_addmask(void *n_arg, struct radix_mask_head *maskhead, int search, int skip) { unsigned char *netmask = n_arg; unsigned char *cp, *cplim; @@ -505,7 +502,7 @@ rn_addmask(void *n_arg, struct radix_node_head *maskhead, int search, int skip) if (skip == 0) skip = 1; if (mlen <= skip) - return (maskhead->rnh_nodes); + return (maskhead->mask_nodes); bzero(addmask_key, RADIX_MAX_KEY_LEN); if (skip > 1) @@ -518,9 +515,9 @@ rn_addmask(void *n_arg, struct radix_node_head *maskhead, int search, int skip) cp--; mlen = cp - addmask_key; if (mlen <= skip) - return (maskhead->rnh_nodes); + return (maskhead->mask_nodes); *addmask_key = mlen; - x = rn_search(addmask_key, maskhead->rnh_treetop); + x = rn_search(addmask_key, maskhead->head.rnh_treetop); if (bcmp(addmask_key, x->rn_key, mlen) != 0) x = 0; if (x || search) @@ -530,7 +527,7 @@ rn_addmask(void *n_arg, struct radix_node_head *maskhead, int search, int skip) return (0); netmask = cp = (unsigned char *)(x + 2); bcopy(addmask_key, cp, mlen); - x = rn_insert(cp, maskhead, &maskduplicated, x); + x = rn_insert(cp, &maskhead->head, &maskduplicated, x); if (maskduplicated) { log(LOG_ERR, "rn_addmask: mask impossibly already in tree"); R_Free(saved_x); @@ -598,7 +595,7 @@ rn_new_radix_mask(struct radix_node *tt, struct radix_mask *next) } struct radix_node * -rn_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, +rn_addroute(void *v_arg, void *n_arg, struct radix_head *head, struct radix_node treenodes[2]) { caddr_t v = (caddr_t)v_arg, netmask = (caddr_t)n_arg; @@ -772,7 +769,7 @@ on2: } struct radix_node * -rn_delete(void *v_arg, void *netmask_arg, struct radix_node_head *head) +rn_delete(void *v_arg, void *netmask_arg, struct radix_head *head) { struct radix_node *t, *p, *x, *tt; struct radix_mask *m, *saved_m, **mp; @@ -959,8 +956,8 @@ out: * This is the same as rn_walktree() except for the parameters and the * exit. */ -static int -rn_walktree_from(struct radix_node_head *h, void *a, void *m, +int +rn_walktree_from(struct radix_head *h, void *a, void *m, walktree_f_t *f, void *w) { int error; @@ -1065,8 +1062,8 @@ rn_walktree_from(struct radix_node_head *h, void *a, void *m, return (0); } -static int -rn_walktree(struct radix_node_head *h, walktree_f_t *f, void *w) +int +rn_walktree(struct radix_head *h, walktree_f_t *f, void *w) { int error; struct radix_node *base, *next; @@ -1105,75 +1102,76 @@ rn_walktree(struct radix_node_head *h, walktree_f_t *f, void *w) } /* - * Allocate and initialize an empty tree. This has 3 nodes, which are - * part of the radix_node_head (in the order ) and are + * Initialize an empty tree. This has 3 nodes, which are passed + * via base_nodes (in the order ) and are * marked RNF_ROOT so they cannot be freed. * The leaves have all-zero and all-one keys, with significant * bits starting at 'off'. - * Return 1 on success, 0 on error. */ -static int -rn_inithead_internal(void **head, int off) +void +rn_inithead_internal(struct radix_head *rh, struct radix_node *base_nodes, int off) { - struct radix_node_head *rnh; struct radix_node *t, *tt, *ttt; - if (*head) - return (1); - R_Zalloc(rnh, struct radix_node_head *, sizeof (*rnh)); - if (rnh == 0) - return (0); - *head = rnh; - t = rn_newpair(rn_zeros, off, rnh->rnh_nodes); - ttt = rnh->rnh_nodes + 2; + + t = rn_newpair(rn_zeros, off, base_nodes); + ttt = base_nodes + 2; t->rn_right = ttt; t->rn_parent = t; - tt = t->rn_left; /* ... which in turn is rnh->rnh_nodes */ + tt = t->rn_left; /* ... which in turn is base_nodes */ tt->rn_flags = t->rn_flags = RNF_ROOT | RNF_ACTIVE; tt->rn_bit = -1 - off; *ttt = *tt; ttt->rn_key = rn_ones; + + rh->rnh_treetop = t; +} + +static void +rn_detachhead_internal(struct radix_head *head) +{ + + KASSERT((head != NULL), + ("%s: head already freed", __func__)); + + /* Free nodes. */ + R_Free(head); +} + +/* Functions used by 'struct radix_node_head' users */ + +int +rn_inithead(void **head, int off) +{ + struct radix_node_head *rnh; + struct radix_mask_head *rmh; + + rnh = *head; + rmh = NULL; + + if (*head != NULL) + return (1); + + R_Zalloc(rnh, struct radix_node_head *, sizeof (*rnh)); + R_Zalloc(rmh, struct radix_mask_head *, sizeof (*rmh)); + if (rnh == NULL || rmh == NULL) { + if (rnh != NULL) + R_Free(rnh); + return (0); + } + + /* Init trees */ + rn_inithead_internal(&rnh->rh, rnh->rnh_nodes, off); + rn_inithead_internal(&rmh->head, rmh->mask_nodes, 0); + *head = rnh; + rnh->rh.rnh_masks = rmh; + + /* Finally, set base callbacks */ rnh->rnh_addaddr = rn_addroute; rnh->rnh_deladdr = rn_delete; rnh->rnh_matchaddr = rn_match; rnh->rnh_lookup = rn_lookup; rnh->rnh_walktree = rn_walktree; rnh->rnh_walktree_from = rn_walktree_from; - rnh->rnh_treetop = t; - return (1); -} - -static void -rn_detachhead_internal(void **head) -{ - struct radix_node_head *rnh; - - KASSERT((head != NULL && *head != NULL), - ("%s: head already freed", __func__)); - rnh = *head; - - /* Free nodes. */ - R_Free(rnh); - - *head = NULL; -} - -int -rn_inithead(void **head, int off) -{ - struct radix_node_head *rnh; - - if (*head != NULL) - return (1); - - if (rn_inithead_internal(head, off) == 0) - return (0); - - rnh = (struct radix_node_head *)(*head); - - if (rn_inithead_internal((void **)&rnh->rnh_masks, 0) == 0) { - rn_detachhead_internal(head); - return (0); - } return (1); } @@ -1181,7 +1179,7 @@ rn_inithead(void **head, int off) static int rn_freeentry(struct radix_node *rn, void *arg) { - struct radix_node_head * const rnh = arg; + struct radix_head * const rnh = arg; struct radix_node *x; x = (struct radix_node *)rn_delete(rn + 2, NULL, rnh); @@ -1198,11 +1196,14 @@ rn_detachhead(void **head) KASSERT((head != NULL && *head != NULL), ("%s: head already freed", __func__)); - rnh = *head; + rnh = (struct radix_node_head *)(*head); + + rn_walktree(&rnh->rh.rnh_masks->head, rn_freeentry, rnh->rh.rnh_masks); + rn_detachhead_internal(&rnh->rh.rnh_masks->head); + rn_detachhead_internal(&rnh->rh); + + *head = NULL; - rn_walktree(rnh->rnh_masks, rn_freeentry, rnh->rnh_masks); - rn_detachhead_internal((void **)&rnh->rnh_masks); - rn_detachhead_internal(head); return (1); } diff --git a/sys/net/radix.h b/sys/net/radix.h index d4bb58a47ed..69aad831bd9 100644 --- a/sys/net/radix.h +++ b/sys/net/radix.h @@ -101,35 +101,53 @@ struct radix_mask { #define rm_mask rm_rmu.rmu_mask #define rm_leaf rm_rmu.rmu_leaf /* extra field would make 32 bytes */ +struct radix_head; + typedef int walktree_f_t(struct radix_node *, void *); +typedef struct radix_node *rn_matchaddr_f_t(void *v, + struct radix_head *head); +typedef struct radix_node *rn_addaddr_f_t(void *v, void *mask, + struct radix_head *head, struct radix_node nodes[]); +typedef struct radix_node *rn_deladdr_f_t(void *v, void *mask, + struct radix_head *head); +typedef struct radix_node *rn_lookup_f_t(void *v, void *mask, + struct radix_head *head); +typedef int rn_walktree_t(struct radix_head *head, walktree_f_t *f, + void *w); +typedef int rn_walktree_from_t(struct radix_head *head, + void *a, void *m, walktree_f_t *f, void *w); +typedef void rn_close_t(struct radix_node *rn, struct radix_head *head); + +struct radix_mask_head; + +struct radix_head { + struct radix_node *rnh_treetop; + struct radix_mask_head *rnh_masks; /* Storage for our masks */ +}; struct radix_node_head { - struct radix_node *rnh_treetop; - u_int rnh_gen; /* generation counter */ - int rnh_multipath; /* multipath capable ? */ - struct radix_node *(*rnh_addaddr) /* add based on sockaddr */ - (void *v, void *mask, - struct radix_node_head *head, struct radix_node nodes[]); - struct radix_node *(*rnh_deladdr) /* remove based on sockaddr */ - (void *v, void *mask, struct radix_node_head *head); - struct radix_node *(*rnh_matchaddr) /* longest match for sockaddr */ - (void *v, struct radix_node_head *head); - struct radix_node *(*rnh_lookup) /*exact match for sockaddr*/ - (void *v, void *mask, struct radix_node_head *head); - int (*rnh_walktree) /* traverse tree */ - (struct radix_node_head *head, walktree_f_t *f, void *w); - int (*rnh_walktree_from) /* traverse tree below a */ - (struct radix_node_head *head, void *a, void *m, - walktree_f_t *f, void *w); - void (*rnh_close) /* do something when the last ref drops */ - (struct radix_node *rn, struct radix_node_head *head); + struct radix_head rh; + rn_matchaddr_f_t *rnh_matchaddr; /* longest match for sockaddr */ + rn_addaddr_f_t *rnh_addaddr; /* add based on sockaddr*/ + rn_deladdr_f_t *rnh_deladdr; /* remove based on sockaddr */ + rn_lookup_f_t *rnh_lookup; /* exact match for sockaddr */ + rn_walktree_t *rnh_walktree; /* traverse tree */ + rn_walktree_from_t *rnh_walktree_from; /* traverse tree below a */ + rn_close_t *rnh_close; /*do something when the last ref drops*/ struct radix_node rnh_nodes[3]; /* empty tree for common case */ - struct radix_node_head *rnh_masks; /* Storage for our masks */ #ifdef _KERNEL struct rwlock rnh_lock; /* locks entire radix tree */ #endif }; +struct radix_mask_head { + struct radix_head head; + struct radix_node mask_nodes[3]; +}; + +void rn_inithead_internal(struct radix_head *rh, struct radix_node *base_nodes, + int off); + #ifndef _KERNEL #define R_Malloc(p, t, n) (p = (t) malloc((unsigned int)(n))) #define R_Zalloc(p, t, n) (p = (t) calloc(1,(unsigned int)(n))) @@ -156,13 +174,14 @@ struct radix_node_head { int rn_inithead(void **, int); int rn_detachhead(void **); int rn_refines(void *, void *); -struct radix_node - *rn_addmask(void *, struct radix_node_head *, int, int), - *rn_addroute (void *, void *, struct radix_node_head *, - struct radix_node [2]), - *rn_delete(void *, void *, struct radix_node_head *), - *rn_lookup (void *v_arg, void *m_arg, - struct radix_node_head *head), - *rn_match(void *, struct radix_node_head *); +struct radix_node *rn_addroute(void *, void *, struct radix_head *, + struct radix_node[2]); +struct radix_node *rn_delete(void *, void *, struct radix_head *); +struct radix_node *rn_lookup (void *v_arg, void *m_arg, + struct radix_head *head); +struct radix_node *rn_match(void *, struct radix_head *); +int rn_walktree_from(struct radix_head *h, void *a, void *m, + walktree_f_t *f, void *w); +int rn_walktree(struct radix_head *, walktree_f_t *, void *); #endif /* _RADIX_H_ */ diff --git a/sys/net/radix_mpath.c b/sys/net/radix_mpath.c index 5f40745f490..c02f0ff8550 100644 --- a/sys/net/radix_mpath.c +++ b/sys/net/radix_mpath.c @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -57,12 +58,19 @@ __FBSDID("$FreeBSD$"); static uint32_t hashjitter; int -rn_mpath_capable(struct radix_node_head *rnh) +rt_mpath_capable(struct rib_head *rnh) { return rnh->rnh_multipath; } +int +rn_mpath_capable(struct radix_head *rh) +{ + + return (rt_mpath_capable((struct rib_head *)rh)); +} + struct radix_node * rn_mpath_next(struct radix_node *rn) { @@ -159,14 +167,14 @@ rt_mpath_deldup(struct rtentry *headrt, struct rtentry *rt) * Assume @rt rt_key host bits are cleared according to @netmask */ int -rt_mpath_conflict(struct radix_node_head *rnh, struct rtentry *rt, +rt_mpath_conflict(struct rib_head *rnh, struct rtentry *rt, struct sockaddr *netmask) { struct radix_node *rn, *rn1; struct rtentry *rt1; rn = (struct radix_node *)rt; - rn1 = rnh->rnh_lookup(rt_key(rt), netmask, rnh); + rn1 = rnh->rnh_lookup(rt_key(rt), netmask, &rnh->head); if (!rn1 || rn1->rn_flags & RNF_ROOT) return (0); @@ -284,11 +292,11 @@ extern int in_inithead(void **head, int off); int rn4_mpath_inithead(void **head, int off) { - struct radix_node_head *rnh; + struct rib_head *rnh; hashjitter = arc4random(); if (in_inithead(head, off) == 1) { - rnh = (struct radix_node_head *)*head; + rnh = (struct rib_head *)*head; rnh->rnh_multipath = 1; return 1; } else @@ -300,11 +308,11 @@ rn4_mpath_inithead(void **head, int off) int rn6_mpath_inithead(void **head, int off) { - struct radix_node_head *rnh; + struct rib_head *rnh; hashjitter = arc4random(); if (in6_inithead(head, off) == 1) { - rnh = (struct radix_node_head *)*head; + rnh = (struct rib_head *)*head; rnh->rnh_multipath = 1; return 1; } else diff --git a/sys/net/radix_mpath.h b/sys/net/radix_mpath.h index fc6f7775a5f..2b0d442e5da 100644 --- a/sys/net/radix_mpath.h +++ b/sys/net/radix_mpath.h @@ -44,17 +44,16 @@ struct route; struct rtentry; struct sockaddr; -int rn_mpath_capable(struct radix_node_head *); +struct rib_head; +int rt_mpath_capable(struct rib_head *); +int rn_mpath_capable(struct radix_head *); struct radix_node *rn_mpath_next(struct radix_node *); u_int32_t rn_mpath_count(struct radix_node *); struct rtentry *rt_mpath_matchgate(struct rtentry *, struct sockaddr *); -int rt_mpath_conflict(struct radix_node_head *, struct rtentry *, +int rt_mpath_conflict(struct rib_head *, struct rtentry *, struct sockaddr *); void rtalloc_mpath_fib(struct route *, u_int32_t, u_int); -#define rtalloc_mpath(_route, _hash) rtalloc_mpath_fib((_route), (_hash), 0) struct rtentry *rt_mpath_select(struct rtentry *, uint32_t); -struct radix_node *rn_mpath_lookup(void *, void *, - struct radix_node_head *); int rt_mpath_deldup(struct rtentry *, struct rtentry *); int rn4_mpath_inithead(void **, int); int rn6_mpath_inithead(void **, int); diff --git a/sys/net/route.c b/sys/net/route.c index 001a15f6c8e..8ad0e24158c 100644 --- a/sys/net/route.c +++ b/sys/net/route.c @@ -57,6 +57,7 @@ #include #include #include +#include #include #include @@ -114,7 +115,7 @@ SYSCTL_UINT(_net, OID_AUTO, add_addr_allfibs, CTLFLAG_RWTUN | CTLFLAG_VNET, VNET_DEFINE(struct rtstat, rtstat); #define V_rtstat VNET(rtstat) -VNET_DEFINE(struct radix_node_head *, rt_tables); +VNET_DEFINE(struct rib_head *, rt_tables); #define V_rt_tables VNET(rt_tables) VNET_DEFINE(int, rttrash); /* routes not in table but not freed */ @@ -136,15 +137,15 @@ VNET_DEFINE(int, rttrash); /* routes not in table but not freed */ static VNET_DEFINE(uma_zone_t, rtzone); /* Routing table UMA zone. */ #define V_rtzone VNET(rtzone) -static int rtrequest1_fib_change(struct radix_node_head *, struct rt_addrinfo *, +static int rtrequest1_fib_change(struct rib_head *, struct rt_addrinfo *, struct rtentry **, u_int); static void rt_setmetrics(const struct rt_addrinfo *, struct rtentry *); static int rt_ifdelroute(const struct rtentry *rt, void *arg); -static struct rtentry *rt_unlinkrte(struct radix_node_head *rnh, +static struct rtentry *rt_unlinkrte(struct rib_head *rnh, struct rt_addrinfo *info, int *perror); static void rt_notifydelete(struct rtentry *rt, struct rt_addrinfo *info); #ifdef RADIX_MPATH -static struct radix_node *rt_mpath_unlink(struct radix_node_head *rnh, +static struct radix_node *rt_mpath_unlink(struct rib_head *rnh, struct rt_addrinfo *info, struct rtentry *rto, int *perror); #endif static int rt_exportinfo(struct rtentry *rt, struct rt_addrinfo *info, @@ -175,10 +176,10 @@ sysctl_my_fibnum(SYSCTL_HANDLER_ARGS) SYSCTL_PROC(_net, OID_AUTO, my_fibnum, CTLTYPE_INT|CTLFLAG_RD, NULL, 0, &sysctl_my_fibnum, "I", "default FIB of caller"); -static __inline struct radix_node_head ** +static __inline struct rib_head ** rt_tables_get_rnh_ptr(int table, int fam) { - struct radix_node_head **rnh; + struct rib_head **rnh; KASSERT(table >= 0 && table < rt_numfibs, ("%s: table out of bounds.", __func__)); @@ -186,14 +187,14 @@ rt_tables_get_rnh_ptr(int table, int fam) __func__)); /* rnh is [fib=0][af=0]. */ - rnh = (struct radix_node_head **)V_rt_tables; + rnh = (struct rib_head **)V_rt_tables; /* Get the offset to the requested table and fam. */ rnh += table * (AF_MAX+1) + fam; return (rnh); } -struct radix_node_head * +struct rib_head * rt_tables_get_rnh(int table, int fam) { @@ -263,12 +264,12 @@ static void vnet_route_init(const void *unused __unused) { struct domain *dom; - struct radix_node_head **rnh; + struct rib_head **rnh; int table; int fam; V_rt_tables = malloc(rt_numfibs * (AF_MAX+1) * - sizeof(struct radix_node_head *), M_RTABLE, M_WAITOK|M_ZERO); + sizeof(struct rib_head *), M_RTABLE, M_WAITOK|M_ZERO); V_rtzone = uma_zcreate("rtentry", sizeof(struct rtentry), rtentry_ctor, rtentry_dtor, @@ -299,7 +300,7 @@ vnet_route_uninit(const void *unused __unused) int table; int fam; struct domain *dom; - struct radix_node_head **rnh; + struct rib_head **rnh; for (dom = domains; dom; dom = dom->dom_next) { if (dom->dom_rtdetach == NULL) @@ -325,6 +326,43 @@ VNET_SYSUNINIT(vnet_route_uninit, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, vnet_route_uninit, 0); #endif +struct rib_head * +rt_table_init(int offset) +{ + struct rib_head *rh; + + rh = malloc(sizeof(struct rib_head), M_RTABLE, M_WAITOK | M_ZERO); + + /* TODO: These details should be hidded inside radix.c */ + /* Init masks tree */ + rn_inithead_internal(&rh->head, rh->rnh_nodes, offset); + rn_inithead_internal(&rh->rmhead.head, rh->rmhead.mask_nodes, 0); + rh->head.rnh_masks = &rh->rmhead; + + /* Init locks */ + rw_init(&rh->rib_lock, "rib head lock"); + + /* Finally, set base callbacks */ + rh->rnh_addaddr = rn_addroute; + rh->rnh_deladdr = rn_delete; + rh->rnh_matchaddr = rn_match; + rh->rnh_lookup = rn_lookup; + rh->rnh_walktree = rn_walktree; + rh->rnh_walktree_from = rn_walktree_from; + + return (rh); +} + +void +rt_table_destroy(struct rib_head *rh) +{ + + /* Assume table is already empty */ + rw_destroy(&rh->rib_lock); + free(rh, M_RTABLE); +} + + #ifndef _SYS_SYSPROTO_H_ struct setfib_args { int fibnum; @@ -375,32 +413,32 @@ struct rtentry * rtalloc1_fib(struct sockaddr *dst, int report, u_long ignflags, u_int fibnum) { - struct radix_node_head *rnh; + struct rib_head *rh; struct radix_node *rn; struct rtentry *newrt; struct rt_addrinfo info; int err = 0, msgtype = RTM_MISS; KASSERT((fibnum < rt_numfibs), ("rtalloc1_fib: bad fibnum")); - rnh = rt_tables_get_rnh(fibnum, dst->sa_family); + rh = rt_tables_get_rnh(fibnum, dst->sa_family); newrt = NULL; - if (rnh == NULL) + if (rh == NULL) goto miss; /* * Look up the address in the table for that Address Family */ - RADIX_NODE_HEAD_RLOCK(rnh); - rn = rnh->rnh_matchaddr(dst, rnh); + RIB_RLOCK(rh); + rn = rh->rnh_matchaddr(dst, &rh->head); if (rn && ((rn->rn_flags & RNF_ROOT) == 0)) { newrt = RNTORT(rn); RT_LOCK(newrt); RT_ADDREF(newrt); - RADIX_NODE_HEAD_RUNLOCK(rnh); + RIB_RUNLOCK(rh); return (newrt); } else - RADIX_NODE_HEAD_RUNLOCK(rnh); + RIB_RUNLOCK(rh); /* * Either we hit the root or couldn't find any match, @@ -430,7 +468,7 @@ miss: void rtfree(struct rtentry *rt) { - struct radix_node_head *rnh; + struct rib_head *rnh; KASSERT(rt != NULL,("%s: NULL rt", __func__)); rnh = rt_tables_get_rnh(rt->rt_fibnum, rt_key(rt)->sa_family); @@ -458,7 +496,7 @@ rtfree(struct rtentry *rt) * on the entry so that the code below reclaims the storage. */ if (rt->rt_refcnt == 0 && rnh->rnh_close) - rnh->rnh_close((struct radix_node *)rt, rnh); + rnh->rnh_close((struct radix_node *)rt, &rnh->head); /* * If we are no longer "up" (and ref == 0) @@ -522,7 +560,7 @@ rtredirect_fib(struct sockaddr *dst, short *stat = NULL; struct rt_addrinfo info; struct ifaddr *ifa; - struct radix_node_head *rnh; + struct rib_head *rnh; ifa = NULL; rnh = rt_tables_get_rnh(fibnum, dst->sa_family); @@ -608,10 +646,10 @@ rtredirect_fib(struct sockaddr *dst, * add the key and gateway (in one malloc'd chunk). */ RT_UNLOCK(rt); - RADIX_NODE_HEAD_LOCK(rnh); + RIB_WLOCK(rnh); RT_LOCK(rt); rt_setgate(rt, rt_key(rt), gateway); - RADIX_NODE_HEAD_UNLOCK(rnh); + RIB_WUNLOCK(rnh); } } else error = EHOSTUNREACH; @@ -853,7 +891,7 @@ int rib_lookup_info(uint32_t fibnum, const struct sockaddr *dst, uint32_t flags, uint32_t flowid, struct rt_addrinfo *info) { - struct radix_node_head *rh; + struct rib_head *rh; struct radix_node *rn; struct rtentry *rt; int error; @@ -863,20 +901,20 @@ rib_lookup_info(uint32_t fibnum, const struct sockaddr *dst, uint32_t flags, if (rh == NULL) return (ENOENT); - RADIX_NODE_HEAD_RLOCK(rh); - rn = rh->rnh_matchaddr(__DECONST(void *, dst), rh); + RIB_RLOCK(rh); + rn = rh->rnh_matchaddr(__DECONST(void *, dst), &rh->head); if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { rt = RNTORT(rn); /* Ensure route & ifp is UP */ if (RT_LINK_IS_UP(rt->rt_ifp)) { flags = (flags & NHR_REF) | NHR_COPY; error = rt_exportinfo(rt, info, flags); - RADIX_NODE_HEAD_RUNLOCK(rh); + RIB_RUNLOCK(rh); return (error); } } - RADIX_NODE_HEAD_RUNLOCK(rh); + RIB_RUNLOCK(rh); return (ENOENT); } @@ -903,7 +941,7 @@ void rt_foreach_fib_walk(int af, rt_setwarg_t *setwa_f, rt_walktree_f_t *wa_f, void *arg) { - struct radix_node_head *rnh; + struct rib_head *rnh; uint32_t fibnum; int i; @@ -916,9 +954,9 @@ rt_foreach_fib_walk(int af, rt_setwarg_t *setwa_f, rt_walktree_f_t *wa_f, if (setwa_f != NULL) setwa_f(rnh, fibnum, af, arg); - RADIX_NODE_HEAD_LOCK(rnh); - rnh->rnh_walktree(rnh, (walktree_f_t *)wa_f, arg); - RADIX_NODE_HEAD_UNLOCK(rnh); + RIB_WLOCK(rnh); + rnh->rnh_walktree(&rnh->head, (walktree_f_t *)wa_f,arg); + RIB_WUNLOCK(rnh); continue; } @@ -929,9 +967,9 @@ rt_foreach_fib_walk(int af, rt_setwarg_t *setwa_f, rt_walktree_f_t *wa_f, if (setwa_f != NULL) setwa_f(rnh, fibnum, i, arg); - RADIX_NODE_HEAD_LOCK(rnh); - rnh->rnh_walktree(rnh, (walktree_f_t *)wa_f, arg); - RADIX_NODE_HEAD_UNLOCK(rnh); + RIB_WLOCK(rnh); + rnh->rnh_walktree(&rnh->head, (walktree_f_t *)wa_f,arg); + RIB_WUNLOCK(rnh); } } } @@ -939,7 +977,7 @@ rt_foreach_fib_walk(int af, rt_setwarg_t *setwa_f, rt_walktree_f_t *wa_f, struct rt_delinfo { struct rt_addrinfo info; - struct radix_node_head *rnh; + struct rib_head *rnh; struct rtentry *head; }; @@ -987,7 +1025,7 @@ rt_checkdelroute(struct radix_node *rn, void *arg) void rt_foreach_fib_walk_del(int af, rt_filter_f_t *filter_f, void *arg) { - struct radix_node_head *rnh; + struct rib_head *rnh; struct rt_delinfo di; struct rtentry *rt; uint32_t fibnum; @@ -1013,9 +1051,9 @@ rt_foreach_fib_walk_del(int af, rt_filter_f_t *filter_f, void *arg) continue; di.rnh = rnh; - RADIX_NODE_HEAD_LOCK(rnh); - rnh->rnh_walktree(rnh, rt_checkdelroute, &di); - RADIX_NODE_HEAD_UNLOCK(rnh); + RIB_WLOCK(rnh); + rnh->rnh_walktree(&rnh->head, rt_checkdelroute, &di); + RIB_WUNLOCK(rnh); if (di.head == NULL) continue; @@ -1092,7 +1130,7 @@ rt_flushifroutes(struct ifnet *ifp) * ENOENT - if supplied filter function returned 0 (not matched). */ static struct rtentry * -rt_unlinkrte(struct radix_node_head *rnh, struct rt_addrinfo *info, int *perror) +rt_unlinkrte(struct rib_head *rnh, struct rt_addrinfo *info, int *perror) { struct sockaddr *dst, *netmask; struct rtentry *rt; @@ -1101,7 +1139,7 @@ rt_unlinkrte(struct radix_node_head *rnh, struct rt_addrinfo *info, int *perror) dst = info->rti_info[RTAX_DST]; netmask = info->rti_info[RTAX_NETMASK]; - rt = (struct rtentry *)rnh->rnh_lookup(dst, netmask, rnh); + rt = (struct rtentry *)rnh->rnh_lookup(dst, netmask, &rnh->head); if (rt == NULL) { *perror = ESRCH; return (NULL); @@ -1136,11 +1174,11 @@ rt_unlinkrte(struct radix_node_head *rnh, struct rt_addrinfo *info, int *perror) */ *perror = ESRCH; #ifdef RADIX_MPATH - if (rn_mpath_capable(rnh)) + if (rt_mpath_capable(rnh)) rn = rt_mpath_unlink(rnh, info, rt, perror); else #endif - rn = rnh->rnh_deladdr(dst, netmask, rnh); + rn = rnh->rnh_deladdr(dst, netmask, &rnh->head); if (rn == NULL) return (NULL); @@ -1273,7 +1311,7 @@ void rt_updatemtu(struct ifnet *ifp) { struct if_mtuinfo ifmtu; - struct radix_node_head *rnh; + struct rib_head *rnh; int i, j; ifmtu.ifp = ifp; @@ -1289,9 +1327,9 @@ rt_updatemtu(struct ifnet *ifp) rnh = rt_tables_get_rnh(j, i); if (rnh == NULL) continue; - RADIX_NODE_HEAD_LOCK(rnh); - rnh->rnh_walktree(rnh, if_updatemtu_cb, &ifmtu); - RADIX_NODE_HEAD_UNLOCK(rnh); + RIB_WLOCK(rnh); + rnh->rnh_walktree(&rnh->head, if_updatemtu_cb, &ifmtu); + RIB_WUNLOCK(rnh); } } } @@ -1357,7 +1395,7 @@ rt_print(char *buf, int buflen, struct rtentry *rt) * and sets @perror to ESRCH. */ static struct radix_node * -rt_mpath_unlink(struct radix_node_head *rnh, struct rt_addrinfo *info, +rt_mpath_unlink(struct rib_head *rnh, struct rt_addrinfo *info, struct rtentry *rto, int *perror) { /* @@ -1409,7 +1447,7 @@ rt_mpath_unlink(struct radix_node_head *rnh, struct rt_addrinfo *info, * use the normal delete code to remove * the first entry */ - rn = rnh->rnh_deladdr(dst, netmask, rnh); + rn = rnh->rnh_deladdr(dst, netmask, &rnh->head); *perror = 0; return (rn); } @@ -1427,7 +1465,7 @@ rt_mpath_unlink(struct radix_node_head *rnh, struct rt_addrinfo *info, #ifdef FLOWTABLE static struct rtentry * -rt_flowtable_check_route(struct radix_node_head *rnh, struct rt_addrinfo *info) +rt_flowtable_check_route(struct rib_head *rnh, struct rt_addrinfo *info) { #if defined(INET6) || defined(INET) struct radix_node *rn; @@ -1444,7 +1482,7 @@ rt_flowtable_check_route(struct radix_node_head *rnh, struct rt_addrinfo *info) case AF_INET: #endif #if defined(INET6) || defined(INET) - rn = rnh->rnh_matchaddr(dst, rnh); + rn = rnh->rnh_matchaddr(dst, &rnh->head); if (rn && ((rn->rn_flags & RNF_ROOT) == 0)) { struct sockaddr *mask; u_char *m, *n; @@ -1499,7 +1537,7 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt, struct rtentry *rt0; #endif struct radix_node *rn; - struct radix_node_head *rnh; + struct rib_head *rnh; struct ifaddr *ifa; struct sockaddr *ndst; struct sockaddr_storage mdst; @@ -1537,9 +1575,9 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt, dst = (struct sockaddr *)&mdst; } - RADIX_NODE_HEAD_LOCK(rnh); + RIB_WLOCK(rnh); rt = rt_unlinkrte(rnh, info, &error); - RADIX_NODE_HEAD_UNLOCK(rnh); + RIB_WUNLOCK(rnh); if (error != 0) return (error); @@ -1616,13 +1654,13 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt, rt_setmetrics(info, rt); - RADIX_NODE_HEAD_LOCK(rnh); + RIB_WLOCK(rnh); RT_LOCK(rt); #ifdef RADIX_MPATH /* do not permit exactly the same dst/mask/gw pair */ - if (rn_mpath_capable(rnh) && + if (rt_mpath_capable(rnh) && rt_mpath_conflict(rnh, rt, netmask)) { - RADIX_NODE_HEAD_UNLOCK(rnh); + RIB_WUNLOCK(rnh); ifa_free(rt->rt_ifa); R_Free(rt_key(rt)); @@ -1636,7 +1674,7 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt, #endif /* FLOWTABLE */ /* XXX mtu manipulation will be done in rnh_addaddr -- itojun */ - rn = rnh->rnh_addaddr(ndst, netmask, rnh, rt->rt_nodes); + rn = rnh->rnh_addaddr(ndst, netmask, &rnh->head, rt->rt_nodes); rt_old = NULL; if (rn == NULL && (info->rti_flags & RTF_PINNED) != 0) { @@ -1653,10 +1691,10 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt, info->rti_flags |= RTF_PINNED; info->rti_info[RTAX_DST] = info_dst; if (rt_old != NULL) - rn = rnh->rnh_addaddr(ndst, netmask, rnh, + rn = rnh->rnh_addaddr(ndst, netmask, &rnh->head, rt->rt_nodes); } - RADIX_NODE_HEAD_UNLOCK(rnh); + RIB_WUNLOCK(rnh); if (rt_old != NULL) RT_UNLOCK(rt_old); @@ -1705,9 +1743,9 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt, RT_UNLOCK(rt); break; case RTM_CHANGE: - RADIX_NODE_HEAD_LOCK(rnh); + RIB_WLOCK(rnh); error = rtrequest1_fib_change(rnh, info, ret_nrt, fibnum); - RADIX_NODE_HEAD_UNLOCK(rnh); + RIB_WUNLOCK(rnh); break; default: error = EOPNOTSUPP; @@ -1724,7 +1762,7 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt, #undef flags static int -rtrequest1_fib_change(struct radix_node_head *rnh, struct rt_addrinfo *info, +rtrequest1_fib_change(struct rib_head *rnh, struct rt_addrinfo *info, struct rtentry **ret_nrt, u_int fibnum) { struct rtentry *rt = NULL; @@ -1734,7 +1772,7 @@ rtrequest1_fib_change(struct radix_node_head *rnh, struct rt_addrinfo *info, struct if_mtuinfo ifmtu; rt = (struct rtentry *)rnh->rnh_lookup(info->rti_info[RTAX_DST], - info->rti_info[RTAX_NETMASK], rnh); + info->rti_info[RTAX_NETMASK], &rnh->head); if (rt == NULL) return (ESRCH); @@ -1744,7 +1782,7 @@ rtrequest1_fib_change(struct radix_node_head *rnh, struct rt_addrinfo *info, * If we got multipath routes, * we require users to specify a matching RTAX_GATEWAY. */ - if (rn_mpath_capable(rnh)) { + if (rt_mpath_capable(rnh)) { rt = rt_mpath_matchgate(rt, info->rti_info[RTAX_GATEWAY]); if (rt == NULL) return (ESRCH); @@ -1935,7 +1973,7 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum) int didwork = 0; int a_failure = 0; static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; - struct radix_node_head *rnh; + struct rib_head *rnh; if (flags & RTF_HOST) { dst = ifa->ifa_dstaddr; @@ -2003,10 +2041,10 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum) if (rnh == NULL) /* this table doesn't exist but others might */ continue; - RADIX_NODE_HEAD_RLOCK(rnh); - rn = rnh->rnh_lookup(dst, netmask, rnh); + RIB_RLOCK(rnh); + rn = rnh->rnh_lookup(dst, netmask, &rnh->head); #ifdef RADIX_MPATH - if (rn_mpath_capable(rnh)) { + if (rt_mpath_capable(rnh)) { if (rn == NULL) error = ESRCH; @@ -2029,7 +2067,7 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum) error = (rn == NULL || (rn->rn_flags & RNF_ROOT) || RNTORT(rn)->rt_ifa != ifa); - RADIX_NODE_HEAD_RUNLOCK(rnh); + RIB_RUNLOCK(rnh); if (error) { /* this is only an error if bad on ALL tables */ continue; diff --git a/sys/net/route.h b/sys/net/route.h index ed21a299b7e..6cc1e1cb24e 100644 --- a/sys/net/route.h +++ b/sys/net/route.h @@ -204,21 +204,6 @@ struct rtentry { /* Control plane route request flags */ #define NHR_COPY 0x100 /* Copy rte data */ -/* rte<>nhop translation */ -static inline uint16_t -fib_rte_to_nh_flags(int rt_flags) -{ - uint16_t res; - - res = (rt_flags & RTF_REJECT) ? NHF_REJECT : 0; - res |= (rt_flags & RTF_BLACKHOLE) ? NHF_BLACKHOLE : 0; - res |= (rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) ? NHF_REDIRECT : 0; - res |= (rt_flags & RTF_BROADCAST) ? NHF_BROADCAST : 0; - res |= (rt_flags & RTF_GATEWAY) ? NHF_GATEWAY : 0; - - return (res); -} - #ifdef _KERNEL /* rte<>ro_flags translation */ static inline void @@ -413,9 +398,8 @@ struct rt_addrinfo { } \ } while (0) -struct radix_node_head *rt_tables_get_rnh(int, int); - struct ifmultiaddr; +struct rib_head; void rt_ieee80211msg(struct ifnet *, int, void *, size_t); void rt_ifannouncemsg(struct ifnet *, int); @@ -429,6 +413,8 @@ int rt_routemsg(int, struct ifnet *ifp, int, struct rtentry *, int); void rt_newmaddrmsg(int, struct ifmultiaddr *); int rt_setgate(struct rtentry *, struct sockaddr *, struct sockaddr *); void rt_maskedcopy(struct sockaddr *, struct sockaddr *, struct sockaddr *); +struct rib_head *rt_table_init(int); +void rt_table_destroy(struct rib_head *); int rtsock_addrmsg(int, struct ifaddr *, int); int rtsock_routemsg(int, struct ifnet *ifp, int, struct rtentry *, int); @@ -447,7 +433,7 @@ void rtfree(struct rtentry *); void rt_updatemtu(struct ifnet *); typedef int rt_walktree_f_t(struct rtentry *, void *); -typedef void rt_setwarg_t(struct radix_node_head *, uint32_t, int, void *); +typedef void rt_setwarg_t(struct rib_head *, uint32_t, int, void *); void rt_foreach_fib_walk(int af, rt_setwarg_t *, rt_walktree_f_t *, void *); void rt_foreach_fib_walk_del(int af, rt_filter_f_t *filter_f, void *arg); void rt_flushifroutes(struct ifnet *ifp); diff --git a/sys/net/route_var.h b/sys/net/route_var.h new file mode 100644 index 00000000000..86fc8a99f5f --- /dev/null +++ b/sys/net/route_var.h @@ -0,0 +1,76 @@ +/*- + * Copyright (c) 2015-2016 + * Alexander V. Chernikov + * + * 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. + * 4. 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. + * + * $FreeBSD$ + */ + +#ifndef _NET_ROUTE_VAR_H_ +#define _NET_ROUTE_VAR_H_ + +struct rib_head { + struct radix_head head; + rn_matchaddr_f_t *rnh_matchaddr; /* longest match for sockaddr */ + rn_addaddr_f_t *rnh_addaddr; /* add based on sockaddr*/ + rn_deladdr_f_t *rnh_deladdr; /* remove based on sockaddr */ + rn_lookup_f_t *rnh_lookup; /* exact match for sockaddr */ + rn_walktree_t *rnh_walktree; /* traverse tree */ + rn_walktree_from_t *rnh_walktree_from; /* traverse tree below a */ + rn_close_t *rnh_close; /*do something when the last ref drops*/ + u_int rnh_gen; /* generation counter */ + int rnh_multipath; /* multipath capable ? */ + struct radix_node rnh_nodes[3]; /* empty tree for common case */ + struct rwlock rib_lock; /* config/data path lock */ + struct radix_mask_head rmhead; /* masks radix head */ +}; + +#define RIB_RLOCK(rh) rw_rlock(&(rh)->rib_lock) +#define RIB_RUNLOCK(rh) rw_runlock(&(rh)->rib_lock) +#define RIB_WLOCK(rh) rw_wlock(&(rh)->rib_lock) +#define RIB_WUNLOCK(rh) rw_wunlock(&(rh)->rib_lock) +#define RIB_LOCK_ASSERT(rh) rw_assert(&(rh)->rib_lock, RA_LOCKED) +#define RIB_WLOCK_ASSERT(rh) rw_assert(&(rh)->rib_lock, RA_WLOCKED) + +struct rib_head *rt_tables_get_rnh(int fib, int family); + +/* rte<>nhop translation */ +static inline uint16_t +fib_rte_to_nh_flags(int rt_flags) +{ + uint16_t res; + + res = (rt_flags & RTF_REJECT) ? NHF_REJECT : 0; + res |= (rt_flags & RTF_BLACKHOLE) ? NHF_BLACKHOLE : 0; + res |= (rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) ? NHF_REDIRECT : 0; + res |= (rt_flags & RTF_BROADCAST) ? NHF_BROADCAST : 0; + res |= (rt_flags & RTF_GATEWAY) ? NHF_GATEWAY : 0; + + return (res); +} + + +#endif diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c index a5ca9faf402..d59ef7055a7 100644 --- a/sys/net/rtsock.c +++ b/sys/net/rtsock.c @@ -59,6 +59,7 @@ #include #include #include +#include #include #include @@ -520,7 +521,7 @@ route_output(struct mbuf *m, struct socket *so, ...) { struct rt_msghdr *rtm = NULL; struct rtentry *rt = NULL; - struct radix_node_head *rnh; + struct rib_head *rnh; struct rt_addrinfo info; struct sockaddr_storage ss; #ifdef INET6 @@ -706,7 +707,7 @@ route_output(struct mbuf *m, struct socket *so, ...) if (rnh == NULL) senderr(EAFNOSUPPORT); - RADIX_NODE_HEAD_RLOCK(rnh); + RIB_RLOCK(rnh); if (info.rti_info[RTAX_NETMASK] == NULL && rtm->rtm_type == RTM_GET) { @@ -716,14 +717,14 @@ route_output(struct mbuf *m, struct socket *so, ...) * 'route -n get addr' */ rt = (struct rtentry *) rnh->rnh_matchaddr( - info.rti_info[RTAX_DST], rnh); + info.rti_info[RTAX_DST], &rnh->head); } else rt = (struct rtentry *) rnh->rnh_lookup( info.rti_info[RTAX_DST], - info.rti_info[RTAX_NETMASK], rnh); + info.rti_info[RTAX_NETMASK], &rnh->head); if (rt == NULL) { - RADIX_NODE_HEAD_RUNLOCK(rnh); + RIB_RUNLOCK(rnh); senderr(ESRCH); } #ifdef RADIX_MPATH @@ -735,11 +736,11 @@ route_output(struct mbuf *m, struct socket *so, ...) * if gate == NULL the first match is returned. * (no need to call rt_mpath_matchgate if gate == NULL) */ - if (rn_mpath_capable(rnh) && + if (rt_mpath_capable(rnh) && (rtm->rtm_type != RTM_GET || info.rti_info[RTAX_GATEWAY])) { rt = rt_mpath_matchgate(rt, info.rti_info[RTAX_GATEWAY]); if (!rt) { - RADIX_NODE_HEAD_RUNLOCK(rnh); + RIB_RUNLOCK(rnh); senderr(ESRCH); } } @@ -770,15 +771,16 @@ route_output(struct mbuf *m, struct socket *so, ...) /* * refactor rt and no lock operation necessary */ - rt = (struct rtentry *)rnh->rnh_matchaddr(&laddr, rnh); + rt = (struct rtentry *)rnh->rnh_matchaddr(&laddr, + &rnh->head); if (rt == NULL) { - RADIX_NODE_HEAD_RUNLOCK(rnh); + RIB_RUNLOCK(rnh); senderr(ESRCH); } } RT_LOCK(rt); RT_ADDREF(rt); - RADIX_NODE_HEAD_RUNLOCK(rnh); + RIB_RUNLOCK(rnh); report: RT_LOCK_ASSERT(rt); @@ -1803,7 +1805,7 @@ sysctl_rtsock(SYSCTL_HANDLER_ARGS) { int *name = (int *)arg1; u_int namelen = arg2; - struct radix_node_head *rnh = NULL; /* silence compiler. */ + struct rib_head *rnh = NULL; /* silence compiler. */ int i, lim, error = EINVAL; int fib = 0; u_char af; @@ -1872,10 +1874,10 @@ sysctl_rtsock(SYSCTL_HANDLER_ARGS) for (error = 0; error == 0 && i <= lim; i++) { rnh = rt_tables_get_rnh(fib, i); if (rnh != NULL) { - RADIX_NODE_HEAD_RLOCK(rnh); - error = rnh->rnh_walktree(rnh, + RIB_RLOCK(rnh); + error = rnh->rnh_walktree(&rnh->head, sysctl_dumpentry, &w); - RADIX_NODE_HEAD_RUNLOCK(rnh); + RIB_RUNLOCK(rnh); } else if (af != 0) error = EAFNOSUPPORT; } diff --git a/sys/net/vnet.c b/sys/net/vnet.c index 6dddd3da4d5..9c3d281910e 100644 --- a/sys/net/vnet.c +++ b/sys/net/vnet.c @@ -171,7 +171,6 @@ static MALLOC_DEFINE(M_VNET_DATA, "vnet_data", "VNET data"); */ #define VNET_MODMIN 8192 #define VNET_SIZE roundup2(VNET_BYTES, PAGE_SIZE) -#define VNET_MODSIZE (VNET_SIZE - (VNET_BYTES - VNET_MODMIN)) /* * Space to store virtualized global variables from loadable kernel modules, diff --git a/sys/net80211/ieee80211_ioctl.c b/sys/net80211/ieee80211_ioctl.c index 1ca3d45bde5..e78b8622112 100644 --- a/sys/net80211/ieee80211_ioctl.c +++ b/sys/net80211/ieee80211_ioctl.c @@ -68,7 +68,7 @@ static struct ieee80211_channel *findchannel(struct ieee80211com *, static int ieee80211_scanreq(struct ieee80211vap *, struct ieee80211_scan_req *); -static __noinline int +static int ieee80211_ioctl_getkey(struct ieee80211vap *vap, struct ieee80211req *ireq) { struct ieee80211com *ic = vap->iv_ic; @@ -124,7 +124,7 @@ ieee80211_ioctl_getkey(struct ieee80211vap *vap, struct ieee80211req *ireq) return copyout(&ik, ireq->i_data, sizeof(ik)); } -static __noinline int +static int ieee80211_ioctl_getchanlist(struct ieee80211vap *vap, struct ieee80211req *ireq) { struct ieee80211com *ic = vap->iv_ic; @@ -134,7 +134,7 @@ ieee80211_ioctl_getchanlist(struct ieee80211vap *vap, struct ieee80211req *ireq) return copyout(&ic->ic_chan_active, ireq->i_data, ireq->i_len); } -static __noinline int +static int ieee80211_ioctl_getchaninfo(struct ieee80211vap *vap, struct ieee80211req *ireq) { struct ieee80211com *ic = vap->iv_ic; @@ -148,36 +148,40 @@ ieee80211_ioctl_getchaninfo(struct ieee80211vap *vap, struct ieee80211req *ireq) return copyout(&ic->ic_nchans, ireq->i_data, space); } -static __noinline int +static int ieee80211_ioctl_getwpaie(struct ieee80211vap *vap, struct ieee80211req *ireq, int req) { struct ieee80211_node *ni; - struct ieee80211req_wpaie2 wpaie; + struct ieee80211req_wpaie2 *wpaie; int error; if (ireq->i_len < IEEE80211_ADDR_LEN) return EINVAL; - error = copyin(ireq->i_data, wpaie.wpa_macaddr, IEEE80211_ADDR_LEN); + wpaie = IEEE80211_MALLOC(sizeof(*wpaie), M_TEMP, + IEEE80211_M_NOWAIT | IEEE80211_M_ZERO); + if (wpaie == NULL) + return ENOMEM; + error = copyin(ireq->i_data, wpaie->wpa_macaddr, IEEE80211_ADDR_LEN); if (error != 0) - return error; - ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap, wpaie.wpa_macaddr); - if (ni == NULL) - return ENOENT; - memset(wpaie.wpa_ie, 0, sizeof(wpaie.wpa_ie)); + goto bad; + ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap, wpaie->wpa_macaddr); + if (ni == NULL) { + error = ENOENT; + goto bad; + } if (ni->ni_ies.wpa_ie != NULL) { int ielen = ni->ni_ies.wpa_ie[1] + 2; - if (ielen > sizeof(wpaie.wpa_ie)) - ielen = sizeof(wpaie.wpa_ie); - memcpy(wpaie.wpa_ie, ni->ni_ies.wpa_ie, ielen); + if (ielen > sizeof(wpaie->wpa_ie)) + ielen = sizeof(wpaie->wpa_ie); + memcpy(wpaie->wpa_ie, ni->ni_ies.wpa_ie, ielen); } if (req == IEEE80211_IOC_WPAIE2) { - memset(wpaie.rsn_ie, 0, sizeof(wpaie.rsn_ie)); if (ni->ni_ies.rsn_ie != NULL) { int ielen = ni->ni_ies.rsn_ie[1] + 2; - if (ielen > sizeof(wpaie.rsn_ie)) - ielen = sizeof(wpaie.rsn_ie); - memcpy(wpaie.rsn_ie, ni->ni_ies.rsn_ie, ielen); + if (ielen > sizeof(wpaie->rsn_ie)) + ielen = sizeof(wpaie->rsn_ie); + memcpy(wpaie->rsn_ie, ni->ni_ies.rsn_ie, ielen); } if (ireq->i_len > sizeof(struct ieee80211req_wpaie2)) ireq->i_len = sizeof(struct ieee80211req_wpaie2); @@ -186,18 +190,21 @@ ieee80211_ioctl_getwpaie(struct ieee80211vap *vap, /* XXX check ic_flags? */ if (ni->ni_ies.rsn_ie != NULL) { int ielen = ni->ni_ies.rsn_ie[1] + 2; - if (ielen > sizeof(wpaie.wpa_ie)) - ielen = sizeof(wpaie.wpa_ie); - memcpy(wpaie.wpa_ie, ni->ni_ies.rsn_ie, ielen); + if (ielen > sizeof(wpaie->wpa_ie)) + ielen = sizeof(wpaie->wpa_ie); + memcpy(wpaie->wpa_ie, ni->ni_ies.rsn_ie, ielen); } if (ireq->i_len > sizeof(struct ieee80211req_wpaie)) ireq->i_len = sizeof(struct ieee80211req_wpaie); } ieee80211_free_node(ni); - return copyout(&wpaie, ireq->i_data, ireq->i_len); + error = copyout(wpaie, ireq->i_data, ireq->i_len); +bad: + IEEE80211_FREE(wpaie, M_TEMP); + return error; } -static __noinline int +static int ieee80211_ioctl_getstastats(struct ieee80211vap *vap, struct ieee80211req *ireq) { struct ieee80211_node *ni; @@ -252,7 +259,7 @@ get_scan_space(void *arg, const struct ieee80211_scan_entry *se) req->space += scan_space(se, &ielen); } -static __noinline void +static void get_scan_result(void *arg, const struct ieee80211_scan_entry *se) { struct scanreq *req = arg; @@ -302,7 +309,7 @@ get_scan_result(void *arg, const struct ieee80211_scan_entry *se) req->sr = (struct ieee80211req_scan_result *)(((uint8_t *)sr) + len); } -static __noinline int +static int ieee80211_ioctl_getscanresults(struct ieee80211vap *vap, struct ieee80211req *ireq) { @@ -366,7 +373,7 @@ get_sta_space(void *arg, struct ieee80211_node *ni) req->space += sta_space(ni, &ielen); } -static __noinline void +static void get_sta_info(void *arg, struct ieee80211_node *ni) { struct stainforeq *req = arg; @@ -452,7 +459,7 @@ get_sta_info(void *arg, struct ieee80211_node *ni) req->space -= len; } -static __noinline int +static int getstainfo_common(struct ieee80211vap *vap, struct ieee80211req *ireq, struct ieee80211_node *ni, size_t off) { @@ -496,7 +503,7 @@ bad: return error; } -static __noinline int +static int ieee80211_ioctl_getstainfo(struct ieee80211vap *vap, struct ieee80211req *ireq) { uint8_t macaddr[IEEE80211_ADDR_LEN]; @@ -519,7 +526,7 @@ ieee80211_ioctl_getstainfo(struct ieee80211vap *vap, struct ieee80211req *ireq) return getstainfo_common(vap, ireq, ni, off); } -static __noinline int +static int ieee80211_ioctl_getstatxpow(struct ieee80211vap *vap, struct ieee80211req *ireq) { struct ieee80211_node *ni; @@ -540,7 +547,7 @@ ieee80211_ioctl_getstatxpow(struct ieee80211vap *vap, struct ieee80211req *ireq) return error; } -static __noinline int +static int ieee80211_ioctl_getwmeparam(struct ieee80211vap *vap, struct ieee80211req *ireq) { struct ieee80211com *ic = vap->iv_ic; @@ -583,7 +590,7 @@ ieee80211_ioctl_getwmeparam(struct ieee80211vap *vap, struct ieee80211req *ireq) return 0; } -static __noinline int +static int ieee80211_ioctl_getmaccmd(struct ieee80211vap *vap, struct ieee80211req *ireq) { const struct ieee80211_aclator *acl = vap->iv_acl; @@ -591,7 +598,7 @@ ieee80211_ioctl_getmaccmd(struct ieee80211vap *vap, struct ieee80211req *ireq) return (acl == NULL ? EINVAL : acl->iac_getioctl(vap, ireq)); } -static __noinline int +static int ieee80211_ioctl_getcurchan(struct ieee80211vap *vap, struct ieee80211req *ireq) { struct ieee80211com *ic = vap->iv_ic; @@ -648,7 +655,7 @@ ieee80211_ioctl_getappie(struct ieee80211vap *vap, struct ieee80211req *ireq) return EINVAL; } -static __noinline int +static int ieee80211_ioctl_getregdomain(struct ieee80211vap *vap, const struct ieee80211req *ireq) { @@ -660,7 +667,7 @@ ieee80211_ioctl_getregdomain(struct ieee80211vap *vap, sizeof(ic->ic_regdomain)); } -static __noinline int +static int ieee80211_ioctl_getroam(struct ieee80211vap *vap, const struct ieee80211req *ireq) { @@ -671,7 +678,7 @@ ieee80211_ioctl_getroam(struct ieee80211vap *vap, return copyout(vap->iv_roamparms, ireq->i_data, len); } -static __noinline int +static int ieee80211_ioctl_gettxparams(struct ieee80211vap *vap, const struct ieee80211req *ireq) { @@ -682,7 +689,7 @@ ieee80211_ioctl_gettxparams(struct ieee80211vap *vap, return copyout(vap->iv_txparms, ireq->i_data, len); } -static __noinline int +static int ieee80211_ioctl_getdevcaps(struct ieee80211com *ic, const struct ieee80211req *ireq) { @@ -716,7 +723,7 @@ ieee80211_ioctl_getdevcaps(struct ieee80211com *ic, return error; } -static __noinline int +static int ieee80211_ioctl_getstavlan(struct ieee80211vap *vap, struct ieee80211req *ireq) { struct ieee80211_node *ni; @@ -765,23 +772,7 @@ ieee80211_ioctl_getdefault(struct ieee80211vap *vap, struct ieee80211req *ireq) return EINVAL; } -/* - * When building the kernel with -O2 on the i386 architecture, gcc - * seems to want to inline this function into ieee80211_ioctl() - * (which is the only routine that calls it). When this happens, - * ieee80211_ioctl() ends up consuming an additional 2K of stack - * space. (Exactly why it needs so much is unclear.) The problem - * is that it's possible for ieee80211_ioctl() to invoke other - * routines (including driver init functions) which could then find - * themselves perilously close to exhausting the stack. - * - * To avoid this, we deliberately prevent gcc from inlining this - * routine. Another way to avoid this is to use less agressive - * optimization when compiling this file (i.e. -O instead of -O2) - * but special-casing the compilation of this one module in the - * build system would be awkward. - */ -static __noinline int +static int ieee80211_ioctl_get80211(struct ieee80211vap *vap, u_long cmd, struct ieee80211req *ireq) { @@ -932,8 +923,6 @@ ieee80211_ioctl_get80211(struct ieee80211vap *vap, u_long cmd, ireq->i_len); break; case IEEE80211_IOC_WPAIE: - error = ieee80211_ioctl_getwpaie(vap, ireq, ireq->i_type); - break; case IEEE80211_IOC_WPAIE2: error = ieee80211_ioctl_getwpaie(vap, ireq, ireq->i_type); break; @@ -1138,7 +1127,7 @@ ieee80211_ioctl_get80211(struct ieee80211vap *vap, u_long cmd, #undef MS } -static __noinline int +static int ieee80211_ioctl_setkey(struct ieee80211vap *vap, struct ieee80211req *ireq) { struct ieee80211req_key ik; @@ -1212,7 +1201,7 @@ ieee80211_ioctl_setkey(struct ieee80211vap *vap, struct ieee80211req *ireq) return error; } -static __noinline int +static int ieee80211_ioctl_delkey(struct ieee80211vap *vap, struct ieee80211req *ireq) { struct ieee80211req_del_key dk; @@ -1354,7 +1343,7 @@ setmlme_dropsta(struct ieee80211vap *vap, return error; } -static __noinline int +static int setmlme_common(struct ieee80211vap *vap, int op, const uint8_t mac[IEEE80211_ADDR_LEN], int reason) { @@ -1515,7 +1504,7 @@ mlmelookup(void *arg, const struct ieee80211_scan_entry *se) look->se = se; } -static __noinline int +static int setmlme_assoc_sta(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN], int ssid_len, const uint8_t ssid[IEEE80211_NWID_LEN]) @@ -1540,12 +1529,13 @@ setmlme_assoc_sta(struct ieee80211vap *vap, return 0; } -static __noinline int +static int setmlme_assoc_adhoc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN], int ssid_len, const uint8_t ssid[IEEE80211_NWID_LEN]) { - struct ieee80211_scan_req sr; + struct ieee80211_scan_req *sr; + int error; KASSERT(vap->iv_opmode == IEEE80211_M_IBSS || vap->iv_opmode == IEEE80211_M_AHDEMO, @@ -1555,23 +1545,30 @@ setmlme_assoc_adhoc(struct ieee80211vap *vap, if (ssid_len == 0) return EINVAL; + sr = IEEE80211_MALLOC(sizeof(*sr), M_TEMP, + IEEE80211_M_NOWAIT | IEEE80211_M_ZERO); + if (sr == NULL) + return ENOMEM; + /* NB: IEEE80211_IOC_SSID call missing for ap_scan=2. */ memset(vap->iv_des_ssid[0].ssid, 0, IEEE80211_NWID_LEN); vap->iv_des_ssid[0].len = ssid_len; memcpy(vap->iv_des_ssid[0].ssid, ssid, ssid_len); vap->iv_des_nssid = 1; - memset(&sr, 0, sizeof(sr)); - sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE | IEEE80211_IOC_SCAN_ONCE; - sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER; - memcpy(sr.sr_ssid[0].ssid, ssid, ssid_len); - sr.sr_ssid[0].len = ssid_len; - sr.sr_nssid = 1; + sr->sr_flags = IEEE80211_IOC_SCAN_ACTIVE | IEEE80211_IOC_SCAN_ONCE; + sr->sr_duration = IEEE80211_IOC_SCAN_FOREVER; + memcpy(sr->sr_ssid[0].ssid, ssid, ssid_len); + sr->sr_ssid[0].len = ssid_len; + sr->sr_nssid = 1; - return ieee80211_scanreq(vap, &sr); + error = ieee80211_scanreq(vap, sr); + + IEEE80211_FREE(sr, M_TEMP); + return error; } -static __noinline int +static int ieee80211_ioctl_setmlme(struct ieee80211vap *vap, struct ieee80211req *ireq) { struct ieee80211req_mlme mlme; @@ -1596,7 +1593,7 @@ ieee80211_ioctl_setmlme(struct ieee80211vap *vap, struct ieee80211req *ireq) mlme.im_macaddr, mlme.im_reason); } -static __noinline int +static int ieee80211_ioctl_macmac(struct ieee80211vap *vap, struct ieee80211req *ireq) { uint8_t mac[IEEE80211_ADDR_LEN]; @@ -1621,7 +1618,7 @@ ieee80211_ioctl_macmac(struct ieee80211vap *vap, struct ieee80211req *ireq) return 0; } -static __noinline int +static int ieee80211_ioctl_setmaccmd(struct ieee80211vap *vap, struct ieee80211req *ireq) { const struct ieee80211_aclator *acl = vap->iv_acl; @@ -1659,7 +1656,7 @@ ieee80211_ioctl_setmaccmd(struct ieee80211vap *vap, struct ieee80211req *ireq) return 0; } -static __noinline int +static int ieee80211_ioctl_setchanlist(struct ieee80211vap *vap, struct ieee80211req *ireq) { struct ieee80211com *ic = vap->iv_ic; @@ -1705,7 +1702,7 @@ ieee80211_ioctl_setchanlist(struct ieee80211vap *vap, struct ieee80211req *ireq) return ENETRESET; } -static __noinline int +static int ieee80211_ioctl_setstastats(struct ieee80211vap *vap, struct ieee80211req *ireq) { struct ieee80211_node *ni; @@ -1731,7 +1728,7 @@ ieee80211_ioctl_setstastats(struct ieee80211vap *vap, struct ieee80211req *ireq) return 0; } -static __noinline int +static int ieee80211_ioctl_setstatxpow(struct ieee80211vap *vap, struct ieee80211req *ireq) { struct ieee80211_node *ni; @@ -1751,7 +1748,7 @@ ieee80211_ioctl_setstatxpow(struct ieee80211vap *vap, struct ieee80211req *ireq) return error; } -static __noinline int +static int ieee80211_ioctl_setwmeparam(struct ieee80211vap *vap, struct ieee80211req *ireq) { struct ieee80211com *ic = vap->iv_ic; @@ -1977,7 +1974,7 @@ setcurchan(struct ieee80211vap *vap, struct ieee80211_channel *c) * Old api for setting the current channel; this is * deprecated because channel numbers are ambiguous. */ -static __noinline int +static int ieee80211_ioctl_setchannel(struct ieee80211vap *vap, const struct ieee80211req *ireq) { @@ -2056,7 +2053,7 @@ ieee80211_ioctl_setchannel(struct ieee80211vap *vap, * channel description is provide so there is no ambiguity in * identifying the channel. */ -static __noinline int +static int ieee80211_ioctl_setcurchan(struct ieee80211vap *vap, const struct ieee80211req *ireq) { @@ -2080,7 +2077,7 @@ ieee80211_ioctl_setcurchan(struct ieee80211vap *vap, return setcurchan(vap, c); } -static __noinline int +static int ieee80211_ioctl_setregdomain(struct ieee80211vap *vap, const struct ieee80211req *ireq) { @@ -2154,7 +2151,7 @@ checkmcs(int mcs) return (mcs & 0x7f) <= 15; /* XXX could search ht rate set */ } -static __noinline int +static int ieee80211_ioctl_settxparams(struct ieee80211vap *vap, const struct ieee80211req *ireq) { @@ -2275,7 +2272,7 @@ setwparsnie(struct ieee80211vap *vap, uint8_t *ie, int space) vap->iv_rsn_ie = ie; } -static __noinline int +static int ieee80211_ioctl_setappie_locked(struct ieee80211vap *vap, const struct ieee80211req *ireq, int fc0) { @@ -2353,7 +2350,7 @@ ieee80211_ioctl_setappie_locked(struct ieee80211vap *vap, return error; } -static __noinline int +static int ieee80211_ioctl_setappie(struct ieee80211vap *vap, const struct ieee80211req *ireq) { @@ -2371,7 +2368,7 @@ ieee80211_ioctl_setappie(struct ieee80211vap *vap, return error; } -static __noinline int +static int ieee80211_ioctl_chanswitch(struct ieee80211vap *vap, struct ieee80211req *ireq) { struct ieee80211com *ic = vap->iv_ic; @@ -2507,21 +2504,28 @@ ieee80211_scanreq(struct ieee80211vap *vap, struct ieee80211_scan_req *sr) #undef IEEE80211_IOC_SCAN_FLAGS } -static __noinline int +static int ieee80211_ioctl_scanreq(struct ieee80211vap *vap, struct ieee80211req *ireq) { - struct ieee80211_scan_req sr; /* XXX off stack? */ + struct ieee80211_scan_req *sr; int error; - if (ireq->i_len != sizeof(sr)) + if (ireq->i_len != sizeof(*sr)) return EINVAL; - error = copyin(ireq->i_data, &sr, sizeof(sr)); + sr = IEEE80211_MALLOC(sizeof(*sr), M_TEMP, + IEEE80211_M_NOWAIT | IEEE80211_M_ZERO); + if (sr == NULL) + return ENOMEM; + error = copyin(ireq->i_data, sr, sizeof(*sr)); if (error != 0) - return error; - return ieee80211_scanreq(vap, &sr); + goto bad; + error = ieee80211_scanreq(vap, sr); +bad: + IEEE80211_FREE(sr, M_TEMP); + return error; } -static __noinline int +static int ieee80211_ioctl_setstavlan(struct ieee80211vap *vap, struct ieee80211req *ireq) { struct ieee80211_node *ni; @@ -2585,7 +2589,7 @@ ieee80211_ioctl_setdefault(struct ieee80211vap *vap, struct ieee80211req *ireq) return EINVAL; } -static __noinline int +static int ieee80211_ioctl_set80211(struct ieee80211vap *vap, u_long cmd, struct ieee80211req *ireq) { struct ieee80211com *ic = vap->iv_ic; diff --git a/sys/netinet/in_fib.c b/sys/netinet/in_fib.c index 352c6d00efd..afd54180bd8 100644 --- a/sys/netinet/in_fib.c +++ b/sys/netinet/in_fib.c @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #ifdef RADIX_MPATH @@ -133,7 +134,7 @@ int fib4_lookup_nh_basic(uint32_t fibnum, struct in_addr dst, uint32_t flags, uint32_t flowid, struct nhop4_basic *pnh4) { - struct radix_node_head *rh; + struct rib_head *rh; struct radix_node *rn; struct sockaddr_in sin; struct rtentry *rte; @@ -148,19 +149,19 @@ fib4_lookup_nh_basic(uint32_t fibnum, struct in_addr dst, uint32_t flags, sin.sin_len = sizeof(struct sockaddr_in); sin.sin_addr = dst; - RADIX_NODE_HEAD_RLOCK(rh); - rn = rh->rnh_matchaddr((void *)&sin, rh); + RIB_RLOCK(rh); + rn = rh->rnh_matchaddr((void *)&sin, &rh->head); if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { rte = RNTORT(rn); /* Ensure route & ifp is UP */ if (RT_LINK_IS_UP(rte->rt_ifp)) { fib4_rte_to_nh_basic(rte, dst, flags, pnh4); - RADIX_NODE_HEAD_RUNLOCK(rh); + RIB_RUNLOCK(rh); return (0); } } - RADIX_NODE_HEAD_RUNLOCK(rh); + RIB_RUNLOCK(rh); return (ENOENT); } @@ -181,7 +182,7 @@ int fib4_lookup_nh_ext(uint32_t fibnum, struct in_addr dst, uint32_t flags, uint32_t flowid, struct nhop4_extended *pnh4) { - struct radix_node_head *rh; + struct rib_head *rh; struct radix_node *rn; struct sockaddr_in sin; struct rtentry *rte; @@ -196,14 +197,14 @@ fib4_lookup_nh_ext(uint32_t fibnum, struct in_addr dst, uint32_t flags, sin.sin_len = sizeof(struct sockaddr_in); sin.sin_addr = dst; - RADIX_NODE_HEAD_RLOCK(rh); - rn = rh->rnh_matchaddr((void *)&sin, rh); + RIB_RLOCK(rh); + rn = rh->rnh_matchaddr((void *)&sin, &rh->head); if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { rte = RNTORT(rn); #ifdef RADIX_MPATH rte = rt_mpath_select(rte, flowid); if (rte == NULL) { - RADIX_NODE_HEAD_RUNLOCK(rh); + RIB_RUNLOCK(rh); return (ENOENT); } #endif @@ -213,12 +214,12 @@ fib4_lookup_nh_ext(uint32_t fibnum, struct in_addr dst, uint32_t flags, if ((flags & NHR_REF) != 0) { /* TODO: lwref on egress ifp's ? */ } - RADIX_NODE_HEAD_RUNLOCK(rh); + RIB_RUNLOCK(rh); return (0); } } - RADIX_NODE_HEAD_RUNLOCK(rh); + RIB_RUNLOCK(rh); return (ENOENT); } diff --git a/sys/netinet/in_rmx.c b/sys/netinet/in_rmx.c index ced53816ada..c2a09e47479 100644 --- a/sys/netinet/in_rmx.c +++ b/sys/netinet/in_rmx.c @@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -57,13 +58,12 @@ extern int in_detachhead(void **head, int off); * Do what we need to do when inserting a route. */ static struct radix_node * -in_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, +in_addroute(void *v_arg, void *n_arg, struct radix_head *head, struct radix_node *treenodes) { struct rtentry *rt = (struct rtentry *)treenodes; struct sockaddr_in *sin = (struct sockaddr_in *)rt_key(rt); - RADIX_NODE_HEAD_WLOCK_ASSERT(head); /* * A little bit of help for both IP output and input: * For host routes, we make sure that RTF_BROADCAST @@ -113,15 +113,15 @@ static int _in_rt_was_here; int in_inithead(void **head, int off) { - struct radix_node_head *rnh; + struct rib_head *rh; - if (!rn_inithead(head, 32)) - return 0; + rh = rt_table_init(32); + if (rh == NULL) + return (0); - rnh = *head; - RADIX_NODE_HEAD_LOCK_INIT(rnh); + rh->rnh_addaddr = in_addroute; + *head = (void *)rh; - rnh->rnh_addaddr = in_addroute; if (_in_rt_was_here == 0 ) { _in_rt_was_here = 1; } diff --git a/sys/netinet/in_var.h b/sys/netinet/in_var.h index 121c6da1943..c5f27b000c7 100644 --- a/sys/netinet/in_var.h +++ b/sys/netinet/in_var.h @@ -351,7 +351,6 @@ inm_acquire_locked(struct in_multi *inm) struct rtentry; struct route; struct ip_moptions; -struct radix_node_head; struct in_multi *inm_lookup_locked(struct ifnet *, const struct in_addr); struct in_multi *inm_lookup(struct ifnet *, const struct in_addr); diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 7de745e27cc..0ef86935d20 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -69,6 +69,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -78,6 +79,7 @@ __FBSDID("$FreeBSD$"); #include #ifdef INET6 #include +#include #include #include #include @@ -2205,27 +2207,20 @@ tcp_mtudisc(struct inpcb *inp, int mtuoffer) u_long tcp_maxmtu(struct in_conninfo *inc, struct tcp_ifcap *cap) { - struct route sro; - struct sockaddr_in *dst; + struct nhop4_extended nh4; struct ifnet *ifp; u_long maxmtu = 0; KASSERT(inc != NULL, ("tcp_maxmtu with NULL in_conninfo pointer")); - bzero(&sro, sizeof(sro)); if (inc->inc_faddr.s_addr != INADDR_ANY) { - dst = (struct sockaddr_in *)&sro.ro_dst; - dst->sin_family = AF_INET; - dst->sin_len = sizeof(*dst); - dst->sin_addr = inc->inc_faddr; - in_rtalloc_ign(&sro, 0, inc->inc_fibnum); - } - if (sro.ro_rt != NULL) { - ifp = sro.ro_rt->rt_ifp; - if (sro.ro_rt->rt_mtu == 0) - maxmtu = ifp->if_mtu; - else - maxmtu = min(sro.ro_rt->rt_mtu, ifp->if_mtu); + + if (fib4_lookup_nh_ext(inc->inc_fibnum, inc->inc_faddr, + NHR_REF, 0, &nh4) != 0) + return (0); + + ifp = nh4.nh_ifp; + maxmtu = nh4.nh_mtu; /* Report additional interface capabilities. */ if (cap != NULL) { @@ -2237,7 +2232,7 @@ tcp_maxmtu(struct in_conninfo *inc, struct tcp_ifcap *cap) cap->tsomaxsegsize = ifp->if_hw_tsomaxsegsize; } } - RTFREE(sro.ro_rt); + fib4_free_nh_ext(inc->inc_fibnum, &nh4); } return (maxmtu); } @@ -2247,26 +2242,22 @@ tcp_maxmtu(struct in_conninfo *inc, struct tcp_ifcap *cap) u_long tcp_maxmtu6(struct in_conninfo *inc, struct tcp_ifcap *cap) { - struct route_in6 sro6; + struct nhop6_extended nh6; + struct in6_addr dst6; + uint32_t scopeid; struct ifnet *ifp; u_long maxmtu = 0; KASSERT(inc != NULL, ("tcp_maxmtu6 with NULL in_conninfo pointer")); - bzero(&sro6, sizeof(sro6)); if (!IN6_IS_ADDR_UNSPECIFIED(&inc->inc6_faddr)) { - sro6.ro_dst.sin6_family = AF_INET6; - sro6.ro_dst.sin6_len = sizeof(struct sockaddr_in6); - sro6.ro_dst.sin6_addr = inc->inc6_faddr; - in6_rtalloc_ign(&sro6, 0, inc->inc_fibnum); - } - if (sro6.ro_rt != NULL) { - ifp = sro6.ro_rt->rt_ifp; - if (sro6.ro_rt->rt_mtu == 0) - maxmtu = IN6_LINKMTU(sro6.ro_rt->rt_ifp); - else - maxmtu = min(sro6.ro_rt->rt_mtu, - IN6_LINKMTU(sro6.ro_rt->rt_ifp)); + in6_splitscope(&inc->inc6_faddr, &dst6, &scopeid); + if (fib6_lookup_nh_ext(inc->inc_fibnum, &dst6, scopeid, 0, + 0, &nh6) != 0) + return (0); + + ifp = nh6.nh_ifp; + maxmtu = nh6.nh_mtu; /* Report additional interface capabilities. */ if (cap != NULL) { @@ -2278,7 +2269,7 @@ tcp_maxmtu6(struct in_conninfo *inc, struct tcp_ifcap *cap) cap->tsomaxsegsize = ifp->if_hw_tsomaxsegsize; } } - RTFREE(sro6.ro_rt); + fib6_free_nh_ext(inc->inc_fibnum, &nh6); } return (maxmtu); diff --git a/sys/netinet6/in6_fib.c b/sys/netinet6/in6_fib.c index 96acfbbf679..b01e633c9b7 100644 --- a/sys/netinet6/in6_fib.c +++ b/sys/netinet6/in6_fib.c @@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #ifdef RADIX_MPATH @@ -170,7 +171,7 @@ int fib6_lookup_nh_basic(uint32_t fibnum, const struct in6_addr *dst, uint32_t scopeid, uint32_t flags, uint32_t flowid, struct nhop6_basic *pnh6) { - struct radix_node_head *rh; + struct rib_head *rh; struct radix_node *rn; struct sockaddr_in6 sin6; struct rtentry *rte; @@ -188,18 +189,18 @@ fib6_lookup_nh_basic(uint32_t fibnum, const struct in6_addr *dst, uint32_t scope if (IN6_IS_SCOPE_LINKLOCAL(dst)) sin6.sin6_addr.s6_addr16[1] = htons(scopeid & 0xffff); - RADIX_NODE_HEAD_RLOCK(rh); - rn = rh->rnh_matchaddr((void *)&sin6, rh); + RIB_RLOCK(rh); + rn = rh->rnh_matchaddr((void *)&sin6, &rh->head); if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { rte = RNTORT(rn); /* Ensure route & ifp is UP */ if (RT_LINK_IS_UP(rte->rt_ifp)) { fib6_rte_to_nh_basic(rte, &sin6.sin6_addr, flags, pnh6); - RADIX_NODE_HEAD_RUNLOCK(rh); + RIB_RUNLOCK(rh); return (0); } } - RADIX_NODE_HEAD_RUNLOCK(rh); + RIB_RUNLOCK(rh); return (ENOENT); } @@ -219,7 +220,7 @@ int fib6_lookup_nh_ext(uint32_t fibnum, const struct in6_addr *dst,uint32_t scopeid, uint32_t flags, uint32_t flowid, struct nhop6_extended *pnh6) { - struct radix_node_head *rh; + struct rib_head *rh; struct radix_node *rn; struct sockaddr_in6 sin6; struct rtentry *rte; @@ -237,14 +238,14 @@ fib6_lookup_nh_ext(uint32_t fibnum, const struct in6_addr *dst,uint32_t scopeid, if (IN6_IS_SCOPE_LINKLOCAL(dst)) sin6.sin6_addr.s6_addr16[1] = htons(scopeid & 0xffff); - RADIX_NODE_HEAD_RLOCK(rh); - rn = rh->rnh_matchaddr((void *)&sin6, rh); + RIB_RLOCK(rh); + rn = rh->rnh_matchaddr((void *)&sin6, &rh->head); if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { rte = RNTORT(rn); #ifdef RADIX_MPATH rte = rt_mpath_select(rte, flowid); if (rte == NULL) { - RADIX_NODE_HEAD_RUNLOCK(rh); + RIB_RUNLOCK(rh); return (ENOENT); } #endif @@ -255,12 +256,12 @@ fib6_lookup_nh_ext(uint32_t fibnum, const struct in6_addr *dst,uint32_t scopeid, if ((flags & NHR_REF) != 0) { /* TODO: Do lwref on egress ifp's */ } - RADIX_NODE_HEAD_RUNLOCK(rh); + RIB_RUNLOCK(rh); return (0); } } - RADIX_NODE_HEAD_RUNLOCK(rh); + RIB_RUNLOCK(rh); return (ENOENT); } diff --git a/sys/netinet6/in6_rmx.c b/sys/netinet6/in6_rmx.c index 93c786c7d7a..38b4bf2cc35 100644 --- a/sys/netinet6/in6_rmx.c +++ b/sys/netinet6/in6_rmx.c @@ -77,6 +77,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -102,13 +103,12 @@ extern int in6_detachhead(void **head, int off); * Do what we need to do when inserting a route. */ static struct radix_node * -in6_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, +in6_addroute(void *v_arg, void *n_arg, struct radix_head *head, struct radix_node *treenodes) { struct rtentry *rt = (struct rtentry *)treenodes; struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)rt_key(rt); - RADIX_NODE_HEAD_WLOCK_ASSERT(head); if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) rt->rt_flags |= RTF_MULTICAST; @@ -154,7 +154,7 @@ in6_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, * Age old PMTUs. */ struct mtuex_arg { - struct radix_node_head *rnh; + struct rib_head *rnh; time_t nextstop; }; static VNET_DEFINE(struct callout, rtq_mtutimer); @@ -179,7 +179,7 @@ in6_mtuexpire(struct rtentry *rt, void *rock) #define MTUTIMO_DEFAULT (60*1) static void -in6_mtutimo_setwa(struct radix_node_head *rnh, uint32_t fibum, int af, +in6_mtutimo_setwa(struct rib_head *rnh, uint32_t fibum, int af, void *_arg) { struct mtuex_arg *arg; @@ -213,15 +213,14 @@ static VNET_DEFINE(int, _in6_rt_was_here); int in6_inithead(void **head, int off) { - struct radix_node_head *rnh; + struct rib_head *rh; - if (!rn_inithead(head, offsetof(struct sockaddr_in6, sin6_addr) << 3)) + rh = rt_table_init(offsetof(struct sockaddr_in6, sin6_addr) << 3); + if (rh == NULL) return (0); - rnh = *head; - RADIX_NODE_HEAD_LOCK_INIT(rnh); - - rnh->rnh_addaddr = in6_addroute; + rh->rnh_addaddr = in6_addroute; + *head = (void *)rh; if (V__in6_rt_was_here == 0) { callout_init(&V_rtq_mtutimer, 1); diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c index b57cf157cda..ca649081368 100644 --- a/sys/netinet6/nd6_rtr.c +++ b/sys/netinet6/nd6_rtr.c @@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -1525,7 +1526,7 @@ static int nd6_prefix_onlink_rtrequest(struct nd_prefix *pr, struct ifaddr *ifa) { static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; - struct radix_node_head *rnh; + struct rib_head *rnh; struct rtentry *rt; struct sockaddr_in6 mask6; u_long rtflags; @@ -1554,7 +1555,7 @@ nd6_prefix_onlink_rtrequest(struct nd_prefix *pr, struct ifaddr *ifa) rnh = rt_tables_get_rnh(rt->rt_fibnum, AF_INET6); /* XXX what if rhn == NULL? */ - RADIX_NODE_HEAD_LOCK(rnh); + RIB_WLOCK(rnh); RT_LOCK(rt); if (rt_setgate(rt, rt_key(rt), (struct sockaddr *)&null_sdl) == 0) { @@ -1564,7 +1565,7 @@ nd6_prefix_onlink_rtrequest(struct nd_prefix *pr, struct ifaddr *ifa) dl->sdl_type = rt->rt_ifp->if_type; dl->sdl_index = rt->rt_ifp->if_index; } - RADIX_NODE_HEAD_UNLOCK(rnh); + RIB_WUNLOCK(rnh); nd6_rtmsg(RTM_ADD, rt); RT_UNLOCK(rt); pr->ndpr_stateflags |= NDPRF_ONLINK; diff --git a/sys/netpfil/ipfw/dn_sched_qfq.c b/sys/netpfil/ipfw/dn_sched_qfq.c index ea27b3ea7a3..b5f4bbad3bb 100644 --- a/sys/netpfil/ipfw/dn_sched_qfq.c +++ b/sys/netpfil/ipfw/dn_sched_qfq.c @@ -60,6 +60,10 @@ typedef unsigned long bitmap; /* * bitmaps ops are critical. Some linux versions have __fls * and the bitmap ops. Some machines have ffs + * NOTE: fls() returns 1 for the least significant bit, + * __fls() returns 0 for the same case. + * We use the base-0 version __fls() to match the description in + * the ToN QFQ paper */ #if defined(_WIN32) || (defined(__MIPSEL__) && defined(LINUX_24)) int fls(unsigned int n) @@ -409,8 +413,8 @@ qfq_make_eligible(struct qfq_sched *q, uint64_t old_V) old_vslot = old_V >> QFQ_MIN_SLOT_SHIFT; if (vslot != old_vslot) { - /* should be 1ULL not 2ULL */ - mask = (1ULL << (__fls(vslot ^ old_vslot))) - 1; + /* must be 2ULL, see ToN QFQ article fig.5, we use base-0 fls */ + mask = (2ULL << (__fls(vslot ^ old_vslot))) - 1; qfq_move_groups(q, mask, IR, ER); qfq_move_groups(q, mask, IB, EB); } diff --git a/sys/netpfil/ipfw/ip_fw_table_algo.c b/sys/netpfil/ipfw/ip_fw_table_algo.c index 2ce550ea841..c04ee86cf98 100644 --- a/sys/netpfil/ipfw/ip_fw_table_algo.c +++ b/sys/netpfil/ipfw/ip_fw_table_algo.c @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include /* ip_fw.h requires IFNAMSIZ */ #include #include +#include #include #include @@ -409,7 +410,7 @@ ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen, KEY_LEN(sa) = KEY_LEN_INET; sa.sin_addr.s_addr = *((in_addr_t *)key); rnh = (struct radix_node_head *)ti->state; - ent = (struct radix_addr_entry *)(rnh->rnh_matchaddr(&sa, rnh)); + ent = (struct radix_addr_entry *)(rnh->rnh_matchaddr(&sa, &rnh->rh)); if (ent != NULL) { *val = ent->value; return (1); @@ -420,7 +421,7 @@ ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen, KEY_LEN(sa6) = KEY_LEN_INET6; memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr)); rnh = (struct radix_node_head *)ti->xstate; - xent = (struct radix_addr_xentry *)(rnh->rnh_matchaddr(&sa6, rnh)); + xent = (struct radix_addr_xentry *)(rnh->rnh_matchaddr(&sa6, &rnh->rh)); if (xent != NULL) { *val = xent->value; return (1); @@ -461,7 +462,7 @@ flush_radix_entry(struct radix_node *rn, void *arg) struct radix_addr_entry *ent; ent = (struct radix_addr_entry *) - rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh); + rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, &rnh->rh); if (ent != NULL) free(ent, M_IPFW_TBL); return (0); @@ -476,11 +477,11 @@ ta_destroy_radix(void *ta_state, struct table_info *ti) cfg = (struct radix_cfg *)ta_state; rnh = (struct radix_node_head *)(ti->state); - rnh->rnh_walktree(rnh, flush_radix_entry, rnh); + rnh->rnh_walktree(&rnh->rh, flush_radix_entry, rnh); rn_detachhead(&ti->state); rnh = (struct radix_node_head *)(ti->xstate); - rnh->rnh_walktree(rnh, flush_radix_entry, rnh); + rnh->rnh_walktree(&rnh->rh, flush_radix_entry, rnh); rn_detachhead(&ti->xstate); free(cfg, M_IPFW); @@ -548,13 +549,13 @@ ta_find_radix_tentry(void *ta_state, struct table_info *ti, KEY_LEN(sa) = KEY_LEN_INET; sa.sin_addr.s_addr = tent->k.addr.s_addr; rnh = (struct radix_node_head *)ti->state; - e = rnh->rnh_matchaddr(&sa, rnh); + e = rnh->rnh_matchaddr(&sa, &rnh->rh); } else { struct sa_in6 sa6; KEY_LEN(sa6) = KEY_LEN_INET6; memcpy(&sa6.sin6_addr, &tent->k.addr6, sizeof(struct in6_addr)); rnh = (struct radix_node_head *)ti->xstate; - e = rnh->rnh_matchaddr(&sa6, rnh); + e = rnh->rnh_matchaddr(&sa6, &rnh->rh); } if (e != NULL) { @@ -572,10 +573,10 @@ ta_foreach_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f, struct radix_node_head *rnh; rnh = (struct radix_node_head *)(ti->state); - rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg); + rnh->rnh_walktree(&rnh->rh, (walktree_f_t *)f, arg); rnh = (struct radix_node_head *)(ti->xstate); - rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg); + rnh->rnh_walktree(&rnh->rh, (walktree_f_t *)f, arg); } @@ -722,7 +723,7 @@ ta_add_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei, } /* Search for an entry first */ - rn = rnh->rnh_lookup(tb->addr_ptr, tb->mask_ptr, rnh); + rn = rnh->rnh_lookup(tb->addr_ptr, tb->mask_ptr, &rnh->rh); if (rn != NULL) { if ((tei->flags & TEI_FLAGS_UPDATE) == 0) return (EEXIST); @@ -746,7 +747,7 @@ ta_add_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei, if ((tei->flags & TEI_FLAGS_DONTADD) != 0) return (EFBIG); - rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, rnh, tb->ent_ptr); + rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, &rnh->rh,tb->ent_ptr); if (rn == NULL) { /* Unknown error */ return (EINVAL); @@ -817,7 +818,7 @@ ta_del_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei, else rnh = ti->xstate; - rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, rnh); + rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, &rnh->rh); if (rn == NULL) return (ENOENT); @@ -4042,21 +4043,21 @@ static void ta_foreach_kfib(void *ta_state, struct table_info *ti, ta_foreach_f *f, void *arg) { - struct radix_node_head *rnh; + struct rib_head *rh; int error; - rnh = rt_tables_get_rnh(ti->data, AF_INET); - if (rnh != NULL) { - RADIX_NODE_HEAD_RLOCK(rnh); - error = rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg); - RADIX_NODE_HEAD_RUNLOCK(rnh); + rh = rt_tables_get_rnh(ti->data, AF_INET); + if (rh != NULL) { + RIB_RLOCK(rh); + error = rh->rnh_walktree(&rh->head, (walktree_f_t *)f, arg); + RIB_RUNLOCK(rh); } - rnh = rt_tables_get_rnh(ti->data, AF_INET6); - if (rnh != NULL) { - RADIX_NODE_HEAD_RLOCK(rnh); - error = rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg); - RADIX_NODE_HEAD_RUNLOCK(rnh); + rh = rt_tables_get_rnh(ti->data, AF_INET6); + if (rh != NULL) { + RIB_RLOCK(rh); + error = rh->rnh_walktree(&rh->head, (walktree_f_t *)f, arg); + RIB_RUNLOCK(rh); } } diff --git a/sys/netpfil/pf/pf_table.c b/sys/netpfil/pf/pf_table.c index b9f13b93de0..b9889b95733 100644 --- a/sys/netpfil/pf/pf_table.c +++ b/sys/netpfil/pf/pf_table.c @@ -559,10 +559,10 @@ pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size, w.pfrw_op = PFRW_GET_ADDRS; w.pfrw_addr = addr; w.pfrw_free = kt->pfrkt_cnt; - rv = kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w); + rv = kt->pfrkt_ip4->rnh_walktree(&kt->pfrkt_ip4->rh, pfr_walktree, &w); if (!rv) - rv = kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, - &w); + rv = kt->pfrkt_ip6->rnh_walktree(&kt->pfrkt_ip6->rh, + pfr_walktree, &w); if (rv) return (rv); @@ -601,10 +601,10 @@ pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size, w.pfrw_op = PFRW_GET_ASTATS; w.pfrw_astats = addr; w.pfrw_free = kt->pfrkt_cnt; - rv = kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w); + rv = kt->pfrkt_ip4->rnh_walktree(&kt->pfrkt_ip4->rh, pfr_walktree, &w); if (!rv) - rv = kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, - &w); + rv = kt->pfrkt_ip6->rnh_walktree(&kt->pfrkt_ip6->rh, + pfr_walktree, &w); if (!rv && (flags & PFR_FLAG_CLSTATS)) { pfr_enqueue_addrs(kt, &workq, NULL, 0); pfr_clstats_kentries(&workq, tzero, 0); @@ -710,12 +710,12 @@ pfr_enqueue_addrs(struct pfr_ktable *kt, struct pfr_kentryworkq *workq, w.pfrw_op = sweep ? PFRW_SWEEP : PFRW_ENQUEUE; w.pfrw_workq = workq; if (kt->pfrkt_ip4 != NULL) - if (kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, - &w)) + if (kt->pfrkt_ip4->rnh_walktree(&kt->pfrkt_ip4->rh, + pfr_walktree, &w)) printf("pfr_enqueue_addrs: IPv4 walktree failed.\n"); if (kt->pfrkt_ip6 != NULL) - if (kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, - &w)) + if (kt->pfrkt_ip6->rnh_walktree(&kt->pfrkt_ip6->rh, + pfr_walktree, &w)) printf("pfr_enqueue_addrs: IPv6 walktree failed.\n"); if (naddr != NULL) *naddr = w.pfrw_cnt; @@ -728,9 +728,9 @@ pfr_mark_addrs(struct pfr_ktable *kt) bzero(&w, sizeof(w)); w.pfrw_op = PFRW_MARK; - if (kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w)) + if (kt->pfrkt_ip4->rnh_walktree(&kt->pfrkt_ip4->rh, pfr_walktree, &w)) printf("pfr_mark_addrs: IPv4 walktree failed.\n"); - if (kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w)) + if (kt->pfrkt_ip6->rnh_walktree(&kt->pfrkt_ip6->rh, pfr_walktree, &w)) printf("pfr_mark_addrs: IPv6 walktree failed.\n"); } @@ -739,7 +739,7 @@ static struct pfr_kentry * pfr_lookup_addr(struct pfr_ktable *kt, struct pfr_addr *ad, int exact) { union sockaddr_union sa, mask; - struct radix_node_head *head = NULL; + struct radix_head *head = NULL; struct pfr_kentry *ke; PF_RULES_ASSERT(); @@ -747,10 +747,10 @@ pfr_lookup_addr(struct pfr_ktable *kt, struct pfr_addr *ad, int exact) bzero(&sa, sizeof(sa)); if (ad->pfra_af == AF_INET) { FILLIN_SIN(sa.sin, ad->pfra_ip4addr); - head = kt->pfrkt_ip4; + head = &kt->pfrkt_ip4->rh; } else if ( ad->pfra_af == AF_INET6 ) { FILLIN_SIN6(sa.sin6, ad->pfra_ip6addr); - head = kt->pfrkt_ip6; + head = &kt->pfrkt_ip6->rh; } if (ADDR_NETWORK(ad)) { pfr_prepare_network(&mask, ad->pfra_af, ad->pfra_net); @@ -929,15 +929,15 @@ pfr_route_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke) { union sockaddr_union mask; struct radix_node *rn; - struct radix_node_head *head = NULL; + struct radix_head *head = NULL; PF_RULES_WASSERT(); bzero(ke->pfrke_node, sizeof(ke->pfrke_node)); if (ke->pfrke_af == AF_INET) - head = kt->pfrkt_ip4; + head = &kt->pfrkt_ip4->rh; else if (ke->pfrke_af == AF_INET6) - head = kt->pfrkt_ip6; + head = &kt->pfrkt_ip6->rh; if (KENTRY_NETWORK(ke)) { pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net); @@ -953,12 +953,12 @@ pfr_unroute_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke) { union sockaddr_union mask; struct radix_node *rn; - struct radix_node_head *head = NULL; + struct radix_head *head = NULL; if (ke->pfrke_af == AF_INET) - head = kt->pfrkt_ip4; + head = &kt->pfrkt_ip4->rh; else if (ke->pfrke_af == AF_INET6) - head = kt->pfrkt_ip6; + head = &kt->pfrkt_ip6->rh; if (KENTRY_NETWORK(ke)) { pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net); @@ -1907,7 +1907,7 @@ pfr_match_addr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af) sin.sin_len = sizeof(sin); sin.sin_family = AF_INET; sin.sin_addr.s_addr = a->addr32[0]; - ke = (struct pfr_kentry *)rn_match(&sin, kt->pfrkt_ip4); + ke = (struct pfr_kentry *)rn_match(&sin, &kt->pfrkt_ip4->rh); if (ke && KENTRY_RNF_ROOT(ke)) ke = NULL; break; @@ -1922,7 +1922,7 @@ pfr_match_addr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af) sin6.sin6_len = sizeof(sin6); sin6.sin6_family = AF_INET6; bcopy(a, &sin6.sin6_addr, sizeof(sin6.sin6_addr)); - ke = (struct pfr_kentry *)rn_match(&sin6, kt->pfrkt_ip6); + ke = (struct pfr_kentry *)rn_match(&sin6, &kt->pfrkt_ip6->rh); if (ke && KENTRY_RNF_ROOT(ke)) ke = NULL; break; @@ -1958,7 +1958,7 @@ pfr_update_stats(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af, sin.sin_len = sizeof(sin); sin.sin_family = AF_INET; sin.sin_addr.s_addr = a->addr32[0]; - ke = (struct pfr_kentry *)rn_match(&sin, kt->pfrkt_ip4); + ke = (struct pfr_kentry *)rn_match(&sin, &kt->pfrkt_ip4->rh); if (ke && KENTRY_RNF_ROOT(ke)) ke = NULL; break; @@ -1973,7 +1973,7 @@ pfr_update_stats(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af, sin6.sin6_len = sizeof(sin6); sin6.sin6_family = AF_INET6; bcopy(a, &sin6.sin6_addr, sizeof(sin6.sin6_addr)); - ke = (struct pfr_kentry *)rn_match(&sin6, kt->pfrkt_ip6); + ke = (struct pfr_kentry *)rn_match(&sin6, &kt->pfrkt_ip6->rh); if (ke && KENTRY_RNF_ROOT(ke)) ke = NULL; break; @@ -2120,11 +2120,11 @@ _next_block: switch (af) { case AF_INET: ke2 = (struct pfr_kentry *)rn_match(&uaddr, - kt->pfrkt_ip4); + &kt->pfrkt_ip4->rh); break; case AF_INET6: ke2 = (struct pfr_kentry *)rn_match(&uaddr, - kt->pfrkt_ip6); + &kt->pfrkt_ip6->rh); break; } /* no need to check KENTRY_RNF_ROOT() here */ @@ -2162,12 +2162,12 @@ pfr_kentry_byidx(struct pfr_ktable *kt, int idx, int af) switch (af) { #ifdef INET case AF_INET: - kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w); + kt->pfrkt_ip4->rnh_walktree(&kt->pfrkt_ip4->rh, pfr_walktree, &w); return (w.pfrw_kentry); #endif /* INET */ #ifdef INET6 case AF_INET6: - kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w); + kt->pfrkt_ip6->rnh_walktree(&kt->pfrkt_ip6->rh, pfr_walktree, &w); return (w.pfrw_kentry); #endif /* INET6 */ default: @@ -2187,7 +2187,7 @@ pfr_dynaddr_update(struct pfr_ktable *kt, struct pfi_dynaddr *dyn) dyn->pfid_acnt4 = 0; dyn->pfid_acnt6 = 0; if (!dyn->pfid_af || dyn->pfid_af == AF_INET) - kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w); + kt->pfrkt_ip4->rnh_walktree(&kt->pfrkt_ip4->rh, pfr_walktree, &w); if (!dyn->pfid_af || dyn->pfid_af == AF_INET6) - kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w); + kt->pfrkt_ip6->rnh_walktree(&kt->pfrkt_ip6->rh, pfr_walktree, &w); } diff --git a/sys/nfs/bootp_subr.c b/sys/nfs/bootp_subr.c index c5bd4cb5fc7..dd76d7ed90b 100644 --- a/sys/nfs/bootp_subr.c +++ b/sys/nfs/bootp_subr.c @@ -65,6 +65,9 @@ __FBSDID("$FreeBSD$"); #include #include #include +#ifdef BOOTP_DEBUG +#include +#endif #include #include @@ -369,15 +372,15 @@ bootpboot_p_tree(struct radix_node *rn) void bootpboot_p_rtlist(void) { - struct radix_node_head *rnh; + struct rib_head *rnh; printf("Routing table:\n"); rnh = rt_tables_get_rnh(0, AF_INET); if (rnh == NULL) return; - RADIX_NODE_HEAD_RLOCK(rnh); /* could sleep XXX */ + RIB_RLOCK(rnh); /* could sleep XXX */ bootpboot_p_tree(rnh->rnh_treetop); - RADIX_NODE_HEAD_RUNLOCK(rnh); + RIB_RUNLOCK(rnh); } void diff --git a/sys/ofed/drivers/infiniband/core/cma.c b/sys/ofed/drivers/infiniband/core/cma.c index 40c4d82451a..1cafced985a 100644 --- a/sys/ofed/drivers/infiniband/core/cma.c +++ b/sys/ofed/drivers/infiniband/core/cma.c @@ -3,6 +3,7 @@ * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. * Copyright (c) 1999-2005, Mellanox Technologies, Inc. All rights reserved. * Copyright (c) 2005-2006 Intel Corporation. All rights reserved. + * Copyright (c) 2016 Chelsio Communications. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -407,6 +408,75 @@ static int find_gid_port(struct ib_device *device, union ib_gid *gid, u8 port_nu return -EAGAIN; } +int +rdma_find_cmid_laddr(struct sockaddr_in *local_addr, unsigned short dev_type, + void **cm_id) +{ + int ret; + u8 port; + int found_dev = 0, found_cmid = 0; + struct rdma_id_private *id_priv; + struct rdma_id_private *dev_id_priv; + struct cma_device *cma_dev; + struct rdma_dev_addr dev_addr; + union ib_gid gid; + enum rdma_link_layer dev_ll = dev_type == ARPHRD_INFINIBAND ? + IB_LINK_LAYER_INFINIBAND : IB_LINK_LAYER_ETHERNET; + + memset(&dev_addr, 0, sizeof(dev_addr)); + + ret = rdma_translate_ip((struct sockaddr *)local_addr, + &dev_addr, NULL); + if (ret) + goto err; + + /* find rdma device based on MAC address/gid */ + mutex_lock(&lock); + + memcpy(&gid, dev_addr.src_dev_addr + + rdma_addr_gid_offset(&dev_addr), sizeof(gid)); + + list_for_each_entry(cma_dev, &dev_list, list) + for (port = 1; port <= cma_dev->device->phys_port_cnt; ++port) + if ((rdma_port_get_link_layer(cma_dev->device, port) == + dev_ll) && + (rdma_node_get_transport(cma_dev->device->node_type) == + RDMA_TRANSPORT_IWARP)) { + ret = find_gid_port(cma_dev->device, + &gid, port); + if (!ret) { + found_dev = 1; + goto out; + } else if (ret == 1) { + mutex_unlock(&lock); + goto err; + } + } +out: + mutex_unlock(&lock); + + if (!found_dev) + goto err; + + /* Traverse through the list of listening cm_id's to find the + * desired cm_id based on rdma device & port number. + */ + list_for_each_entry(id_priv, &listen_any_list, list) + list_for_each_entry(dev_id_priv, &id_priv->listen_list, + listen_list) + if (dev_id_priv->cma_dev == cma_dev) + if (dev_id_priv->cm_id.iw->local_addr.sin_port + == local_addr->sin_port) { + *cm_id = (void *)dev_id_priv->cm_id.iw; + found_cmid = 1; + } + return found_cmid ? 0 : -ENODEV; + +err: + return -ENODEV; +} +EXPORT_SYMBOL(rdma_find_cmid_laddr); + static int cma_acquire_dev(struct rdma_id_private *id_priv) { struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; @@ -780,6 +850,12 @@ static inline int cma_any_addr(struct sockaddr *addr) { return cma_zero_addr(addr) || cma_loopback_addr(addr); } +int +rdma_cma_any_addr(struct sockaddr *addr) +{ + return cma_any_addr(addr); +} +EXPORT_SYMBOL(rdma_cma_any_addr); static int cma_addr_cmp(struct sockaddr *src, struct sockaddr *dst) { @@ -1707,6 +1783,7 @@ static void cma_listen_on_dev(struct rdma_id_private *id_priv, dev_id_priv = container_of(id, struct rdma_id_private, id); dev_id_priv->state = RDMA_CM_ADDR_BOUND; + dev_id_priv->sock = id_priv->sock; memcpy(&id->route.addr.src_addr, &id_priv->id.route.addr.src_addr, ip_addr_size((struct sockaddr *) &id_priv->id.route.addr.src_addr)); diff --git a/sys/ofed/drivers/infiniband/core/iwcm.c b/sys/ofed/drivers/infiniband/core/iwcm.c index 14d23cccb49..a90f907cb45 100644 --- a/sys/ofed/drivers/infiniband/core/iwcm.c +++ b/sys/ofed/drivers/infiniband/core/iwcm.c @@ -5,6 +5,7 @@ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. * Copyright (c) 2005 Network Appliance, Inc. All rights reserved. + * Copyright (c) 2016 Chelsio Communications. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -35,6 +36,8 @@ * SOFTWARE. * */ +#include "opt_inet.h" + #include #include #include @@ -47,7 +50,10 @@ #include #include #include +#include +#include +#include #include #include @@ -65,6 +71,85 @@ struct iwcm_work { struct iw_cm_event event; struct list_head free_list; }; +struct iwcm_listen_work { + struct work_struct work; + struct iw_cm_id *cm_id; +}; + +static LIST_HEAD(listen_port_list); + +static DEFINE_MUTEX(listen_port_mutex); +static DEFINE_MUTEX(dequeue_mutex); + +struct listen_port_info { + struct list_head list; + uint16_t port_num; + uint32_t refcnt; +}; + +static int32_t +add_port_to_listenlist(uint16_t port) +{ + struct listen_port_info *port_info; + int err = 0; + + mutex_lock(&listen_port_mutex); + + list_for_each_entry(port_info, &listen_port_list, list) + if (port_info->port_num == port) + goto found_port; + + port_info = kmalloc(sizeof(*port_info), GFP_KERNEL); + if (!port_info) { + err = -ENOMEM; + mutex_unlock(&listen_port_mutex); + goto out; + } + + port_info->port_num = port; + port_info->refcnt = 0; + + list_add(&port_info->list, &listen_port_list); + +found_port: + ++(port_info->refcnt); + mutex_unlock(&listen_port_mutex); + return port_info->refcnt; +out: + return err; +} + +static int32_t +rem_port_from_listenlist(uint16_t port) +{ + struct listen_port_info *port_info; + int ret, found_port = 0; + + mutex_lock(&listen_port_mutex); + + list_for_each_entry(port_info, &listen_port_list, list) + if (port_info->port_num == port) { + found_port = 1; + break; + } + + if (found_port) { + --(port_info->refcnt); + ret = port_info->refcnt; + if (port_info->refcnt == 0) { + /* Remove this entry from the list as there are no + * more listeners for this port_num. + */ + list_del(&port_info->list); + kfree(port_info); + } + } else { + ret = -EINVAL; + } + mutex_unlock(&listen_port_mutex); + return ret; + +} /* * The following services provide a mechanism for pre-allocating iwcm_work @@ -320,6 +405,167 @@ int iw_cm_disconnect(struct iw_cm_id *cm_id, int abrupt) } EXPORT_SYMBOL(iw_cm_disconnect); +static struct socket * +dequeue_socket(struct socket *head) +{ + struct socket *so; + struct sockaddr_in *remote; + + ACCEPT_LOCK(); + so = TAILQ_FIRST(&head->so_comp); + if (!so) { + ACCEPT_UNLOCK(); + return NULL; + } + + SOCK_LOCK(so); + /* + * Before changing the flags on the socket, we have to bump the + * reference count. Otherwise, if the protocol calls sofree(), + * the socket will be released due to a zero refcount. + */ + soref(so); + TAILQ_REMOVE(&head->so_comp, so, so_list); + head->so_qlen--; + so->so_qstate &= ~SQ_COMP; + so->so_head = NULL; + so->so_state |= SS_NBIO; + SOCK_UNLOCK(so); + ACCEPT_UNLOCK(); + soaccept(so, (struct sockaddr **)&remote); + + free(remote, M_SONAME); + return so; +} +static void +iw_so_event_handler(struct work_struct *_work) +{ +#ifdef INET + struct iwcm_listen_work *work = container_of(_work, + struct iwcm_listen_work, work); + struct iw_cm_id *listen_cm_id = work->cm_id; + struct iwcm_id_private *cm_id_priv; + struct iw_cm_id *real_cm_id; + struct sockaddr_in *local; + struct socket *so; + + cm_id_priv = container_of(listen_cm_id, struct iwcm_id_private, id); + + if (cm_id_priv->state != IW_CM_STATE_LISTEN) { + kfree(work); + return; + } + mutex_lock(&dequeue_mutex); + + /* Dequeue & process all new 'so' connection requests for this cmid */ + while ((so = dequeue_socket(work->cm_id->so)) != NULL) { + if (rdma_cma_any_addr((struct sockaddr *) + &listen_cm_id->local_addr)) { + in_getsockaddr(so, (struct sockaddr **)&local); + if (rdma_find_cmid_laddr(local, ARPHRD_ETHER, + (void **) &real_cm_id)) { + free(local, M_SONAME); + goto err; + } + free(local, M_SONAME); + + real_cm_id->device->iwcm->newconn(real_cm_id, so); + } else { + listen_cm_id->device->iwcm->newconn(listen_cm_id, so); + } + } +err: + mutex_unlock(&dequeue_mutex); + kfree(work); +#endif + return; +} +static int +iw_so_upcall(struct socket *parent_so, void *arg, int waitflag) +{ + struct iwcm_listen_work *work; + struct socket *so; + struct iw_cm_id *cm_id = arg; + + mutex_lock(&dequeue_mutex); + /* check whether iw_so_event_handler() already dequeued this 'so' */ + so = TAILQ_FIRST(&parent_so->so_comp); + if (!so) + return SU_OK; + work = kzalloc(sizeof(*work), M_NOWAIT); + if (!work) + return -ENOMEM; + work->cm_id = cm_id; + + INIT_WORK(&work->work, iw_so_event_handler); + queue_work(iwcm_wq, &work->work); + + mutex_unlock(&dequeue_mutex); + return SU_OK; +} + +static void +iw_init_sock(struct iw_cm_id *cm_id) +{ + struct sockopt sopt; + struct socket *so = cm_id->so; + int on = 1; + + SOCK_LOCK(so); + soupcall_set(so, SO_RCV, iw_so_upcall, cm_id); + so->so_state |= SS_NBIO; + SOCK_UNLOCK(so); + sopt.sopt_dir = SOPT_SET; + sopt.sopt_level = IPPROTO_TCP; + sopt.sopt_name = TCP_NODELAY; + sopt.sopt_val = (caddr_t)&on; + sopt.sopt_valsize = sizeof(on); + sopt.sopt_td = NULL; + sosetopt(so, &sopt); +} + +static int +iw_close_socket(struct iw_cm_id *cm_id, int close) +{ + struct socket *so = cm_id->so; + int rc; + + + SOCK_LOCK(so); + soupcall_clear(so, SO_RCV); + SOCK_UNLOCK(so); + + if (close) + rc = soclose(so); + else + rc = soshutdown(so, SHUT_WR | SHUT_RD); + + cm_id->so = NULL; + + return rc; +} + +static int +iw_create_listen(struct iw_cm_id *cm_id, int backlog) +{ + int rc; + + iw_init_sock(cm_id); + rc = solisten(cm_id->so, backlog, curthread); + if (rc != 0) + iw_close_socket(cm_id, 0); + return rc; +} + +static int +iw_destroy_listen(struct iw_cm_id *cm_id) +{ + int rc; + rc = iw_close_socket(cm_id, 0); + return rc; +} + + /* * CM_ID <-- DESTROYING * @@ -330,7 +576,7 @@ static void destroy_cm_id(struct iw_cm_id *cm_id) { struct iwcm_id_private *cm_id_priv; unsigned long flags; - int ret; + int ret = 0, refcnt; cm_id_priv = container_of(cm_id, struct iwcm_id_private, id); /* @@ -345,8 +591,18 @@ static void destroy_cm_id(struct iw_cm_id *cm_id) case IW_CM_STATE_LISTEN: cm_id_priv->state = IW_CM_STATE_DESTROYING; spin_unlock_irqrestore(&cm_id_priv->lock, flags); - /* destroy the listening endpoint */ - ret = cm_id->device->iwcm->destroy_listen(cm_id); + if (rdma_cma_any_addr((struct sockaddr *)&cm_id->local_addr)) { + refcnt = + rem_port_from_listenlist(cm_id->local_addr.sin_port); + + if (refcnt == 0) + ret = iw_destroy_listen(cm_id); + + cm_id->device->iwcm->destroy_listen_ep(cm_id); + } else { + ret = iw_destroy_listen(cm_id); + cm_id->device->iwcm->destroy_listen_ep(cm_id); + } spin_lock_irqsave(&cm_id_priv->lock, flags); break; case IW_CM_STATE_ESTABLISHED: @@ -418,7 +674,7 @@ int iw_cm_listen(struct iw_cm_id *cm_id, int backlog) { struct iwcm_id_private *cm_id_priv; unsigned long flags; - int ret; + int ret, refcnt; cm_id_priv = container_of(cm_id, struct iwcm_id_private, id); @@ -431,9 +687,33 @@ int iw_cm_listen(struct iw_cm_id *cm_id, int backlog) case IW_CM_STATE_IDLE: cm_id_priv->state = IW_CM_STATE_LISTEN; spin_unlock_irqrestore(&cm_id_priv->lock, flags); - ret = cm_id->device->iwcm->create_listen(cm_id, backlog); - if (ret) + + if (rdma_cma_any_addr((struct sockaddr *)&cm_id->local_addr)) { + refcnt = + add_port_to_listenlist(cm_id->local_addr.sin_port); + + if (refcnt == 1) { + ret = iw_create_listen(cm_id, backlog); + } else if (refcnt <= 0) { + ret = -EINVAL; + } else { + /* if refcnt > 1, a socket listener created + * already. And we need not create socket + * listener on other rdma devices/listen cm_id's + * due to TOE. That is when a socket listener is + * created with INADDR_ANY all registered TOE + * devices will get a call to start + * hardware listeners. + */ + } + } else { + ret = iw_create_listen(cm_id, backlog); + } + if (!ret) + cm_id->device->iwcm->create_listen_ep(cm_id, backlog); + else cm_id_priv->state = IW_CM_STATE_IDLE; + spin_lock_irqsave(&cm_id_priv->lock, flags); break; default: diff --git a/sys/ofed/include/rdma/iw_cm.h b/sys/ofed/include/rdma/iw_cm.h index 271c2f832ee..a246e6176c6 100644 --- a/sys/ofed/include/rdma/iw_cm.h +++ b/sys/ofed/include/rdma/iw_cm.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2005 Network Appliance, Inc. All rights reserved. * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. + * Copyright (c) 2016 Chelsio Communications. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -120,10 +121,13 @@ struct iw_cm_verbs { int (*reject)(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len); - int (*create_listen)(struct iw_cm_id *cm_id, + int (*create_listen_ep)(struct iw_cm_id *cm_id, int backlog); - int (*destroy_listen)(struct iw_cm_id *cm_id); + void (*destroy_listen_ep)(struct iw_cm_id *cm_id); + + void (*newconn)(struct iw_cm_id *parent_cm_id, + struct socket *so); }; /** diff --git a/sys/ofed/include/rdma/rdma_cm.h b/sys/ofed/include/rdma/rdma_cm.h index d6992617249..33be95784d5 100644 --- a/sys/ofed/include/rdma/rdma_cm.h +++ b/sys/ofed/include/rdma/rdma_cm.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2005 Voltaire Inc. All rights reserved. * Copyright (c) 2005 Intel Corporation. All rights reserved. + * Copyright (c) 2016 Chelsio Communications. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -400,5 +401,7 @@ int rdma_set_afonly(struct rdma_cm_id *id, int afonly); * @timeout: QP timeout */ void rdma_set_timeout(struct rdma_cm_id *id, int timeout); - +int rdma_cma_any_addr(struct sockaddr *addr); +int rdma_find_cmid_laddr(struct sockaddr_in *local_addr, + unsigned short dev_type, void **cm_id); #endif /* RDMA_CM_H */ diff --git a/sys/powerpc/booke/pmap.c b/sys/powerpc/booke/pmap.c index a5de4d68fcd..d0712b4de17 100644 --- a/sys/powerpc/booke/pmap.c +++ b/sys/powerpc/booke/pmap.c @@ -1305,8 +1305,8 @@ mmu_booke_bootstrap(mmu_t mmu, vm_offset_t start, vm_offset_t kernelend) debugf("Maxmem = 0x%08lx\n", Maxmem); debugf("phys_avail_count = %d\n", phys_avail_count); - debugf("physsz = 0x%08x physmem = %ld (0x%08lx)\n", physsz, physmem, - physmem); + debugf("physsz = 0x%09jx physmem = %jd (0x%09jx)\n", + (uintmax_t)physsz, (uintmax_t)physmem, (uintmax_t)physmem); /*******************************************************/ /* Initialize (statically allocated) kernel pmap. */ @@ -2254,7 +2254,7 @@ mmu_booke_zero_page(mmu_t mmu, vm_page_t m) mmu_booke_kenter(mmu, va, VM_PAGE_TO_PHYS(m)); for (off = 0; off < PAGE_SIZE; off += cacheline_size) - __asm __volatile("dcbzl 0,%0" :: "r"(va + off)); + __asm __volatile("dcbz 0,%0" :: "r"(va + off)); mmu_booke_kremove(mmu, va); mtx_unlock(&zero_page_mutex); diff --git a/sys/sys/ttydevsw.h b/sys/sys/ttydevsw.h index 876a3dd6d8d..98bebca724d 100644 --- a/sys/sys/ttydevsw.h +++ b/sys/sys/ttydevsw.h @@ -83,15 +83,17 @@ struct ttydevsw { static __inline int ttydevsw_open(struct tty *tp) { + tty_lock_assert(tp, MA_OWNED); MPASS(!tty_gone(tp)); - return tp->t_devsw->tsw_open(tp); + return (tp->t_devsw->tsw_open(tp)); } static __inline void ttydevsw_close(struct tty *tp) { + tty_lock_assert(tp, MA_OWNED); MPASS(!tty_gone(tp)); @@ -101,6 +103,7 @@ ttydevsw_close(struct tty *tp) static __inline void ttydevsw_outwakeup(struct tty *tp) { + tty_lock_assert(tp, MA_OWNED); MPASS(!tty_gone(tp)); @@ -114,6 +117,7 @@ ttydevsw_outwakeup(struct tty *tp) static __inline void ttydevsw_inwakeup(struct tty *tp) { + tty_lock_assert(tp, MA_OWNED); MPASS(!tty_gone(tp)); @@ -127,49 +131,56 @@ ttydevsw_inwakeup(struct tty *tp) static __inline int ttydevsw_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td) { + tty_lock_assert(tp, MA_OWNED); MPASS(!tty_gone(tp)); - return tp->t_devsw->tsw_ioctl(tp, cmd, data, td); + return (tp->t_devsw->tsw_ioctl(tp, cmd, data, td)); } static __inline int -ttydevsw_cioctl(struct tty *tp, int unit, u_long cmd, caddr_t data, struct thread *td) +ttydevsw_cioctl(struct tty *tp, int unit, u_long cmd, caddr_t data, + struct thread *td) { + tty_lock_assert(tp, MA_OWNED); MPASS(!tty_gone(tp)); - return tp->t_devsw->tsw_cioctl(tp, unit, cmd, data, td); + return (tp->t_devsw->tsw_cioctl(tp, unit, cmd, data, td)); } static __inline int ttydevsw_param(struct tty *tp, struct termios *t) { + MPASS(!tty_gone(tp)); - return tp->t_devsw->tsw_param(tp, t); + return (tp->t_devsw->tsw_param(tp, t)); } static __inline int ttydevsw_modem(struct tty *tp, int sigon, int sigoff) { + MPASS(!tty_gone(tp)); - return tp->t_devsw->tsw_modem(tp, sigon, sigoff); + return (tp->t_devsw->tsw_modem(tp, sigon, sigoff)); } static __inline int ttydevsw_mmap(struct tty *tp, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot, vm_memattr_t *memattr) { + MPASS(!tty_gone(tp)); - return tp->t_devsw->tsw_mmap(tp, offset, paddr, nprot, memattr); + return (tp->t_devsw->tsw_mmap(tp, offset, paddr, nprot, memattr)); } static __inline void ttydevsw_pktnotify(struct tty *tp, char event) { + tty_lock_assert(tp, MA_OWNED); MPASS(!tty_gone(tp)); @@ -179,6 +190,7 @@ ttydevsw_pktnotify(struct tty *tp, char event) static __inline void ttydevsw_free(struct tty *tp) { + MPASS(tty_gone(tp)); tp->t_devsw->tsw_free(tty_softc(tp)); diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index 5fdc62fe08b..5e22b3ef358 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -1553,7 +1553,7 @@ again: * * The map must be locked. * - * This routine guarentees that the passed entry remains valid (though + * This routine guarantees that the passed entry remains valid (though * possibly extended). When merging, this routine may delete one or * both neighbors. */ diff --git a/tools/regression/sockets/unix_cmsg/unix_cmsg.c b/tools/regression/sockets/unix_cmsg/unix_cmsg.c index d91cef496a0..7f6b45cf427 100644 --- a/tools/regression/sockets/unix_cmsg/unix_cmsg.c +++ b/tools/regression/sockets/unix_cmsg/unix_cmsg.c @@ -83,7 +83,13 @@ static int t_sockcred_2(void); static int t_cmsgcred_sockcred(void); static int t_timeval(void); static int t_bintime(void); +/* + * The testcase fails on 64-bit architectures (amd64), but passes on 32-bit + * architectures (i386); see bug 206543 + */ +#ifndef __LP64__ static int t_cmsg_len(void); +#endif static int t_peercred(void); struct test_func { @@ -120,10 +126,12 @@ static const struct test_func test_stream_tbl[] = { .func = t_bintime, .desc = "Sending, receiving bintime" }, +#ifndef __LP64__ { .func = t_cmsg_len, .desc = "Check cmsghdr.cmsg_len" }, +#endif { .func = t_peercred, .desc = "Check LOCAL_PEERCRED socket option" @@ -158,10 +166,12 @@ static const struct test_func test_dgram_tbl[] = { .func = t_bintime, .desc = "Sending, receiving bintime" }, +#ifndef __LP64__ { .func = t_cmsg_len, .desc = "Check cmsghdr.cmsg_len" } +#endif }; #define TEST_DGRAM_TBL_SIZE \ @@ -980,6 +990,8 @@ check_groups(const char *gid_arr_str, const gid_t *gid_arr, static int check_xucred(const struct xucred *xucred, socklen_t len) { + int rc; + if (len != sizeof(*xucred)) { logmsgx("option value size %zu != %zu", (size_t)len, sizeof(*xucred)); @@ -990,170 +1002,178 @@ check_xucred(const struct xucred *xucred, socklen_t len) dbgmsg("xucred.cr_uid %lu", (u_long)xucred->cr_uid); dbgmsg("xucred.cr_ngroups %d", xucred->cr_ngroups); + rc = 0; + if (xucred->cr_version != XUCRED_VERSION) { logmsgx("xucred.cr_version %u != %d", xucred->cr_version, XUCRED_VERSION); - return (-1); + rc = -1; } if (xucred->cr_uid != proc_cred.euid) { logmsgx("xucred.cr_uid %lu != %lu (EUID)", (u_long)xucred->cr_uid, (u_long)proc_cred.euid); - return (-1); + rc = -1; } if (xucred->cr_ngroups == 0) { logmsgx("xucred.cr_ngroups == 0"); - return (-1); + rc = -1; } if (xucred->cr_ngroups < 0) { logmsgx("xucred.cr_ngroups < 0"); - return (-1); + rc = -1; } if (xucred->cr_ngroups > XU_NGROUPS) { logmsgx("xucred.cr_ngroups %hu > %u (max)", xucred->cr_ngroups, XU_NGROUPS); - return (-1); + rc = -1; } if (xucred->cr_groups[0] != proc_cred.egid) { logmsgx("xucred.cr_groups[0] %lu != %lu (EGID)", (u_long)xucred->cr_groups[0], (u_long)proc_cred.egid); - return (-1); + rc = -1; } if (check_groups("xucred.cr_groups", xucred->cr_groups, "xucred.cr_ngroups", xucred->cr_ngroups, false) < 0) - return (-1); - return (0); + rc = -1; + return (rc); } static int check_scm_creds_cmsgcred(struct cmsghdr *cmsghdr) { - const struct cmsgcred *cmsgcred; + const struct cmsgcred *cmcred; + int rc; - if (check_cmsghdr(cmsghdr, SCM_CREDS, sizeof(*cmsgcred)) < 0) + if (check_cmsghdr(cmsghdr, SCM_CREDS, sizeof(struct cmsgcred)) < 0) return (-1); - cmsgcred = (struct cmsgcred *)CMSG_DATA(cmsghdr); + cmcred = (struct cmsgcred *)CMSG_DATA(cmsghdr); - dbgmsg("cmsgcred.cmcred_pid %ld", (long)cmsgcred->cmcred_pid); - dbgmsg("cmsgcred.cmcred_uid %lu", (u_long)cmsgcred->cmcred_uid); - dbgmsg("cmsgcred.cmcred_euid %lu", (u_long)cmsgcred->cmcred_euid); - dbgmsg("cmsgcred.cmcred_gid %lu", (u_long)cmsgcred->cmcred_gid); - dbgmsg("cmsgcred.cmcred_ngroups %d", cmsgcred->cmcred_ngroups); + dbgmsg("cmsgcred.cmcred_pid %ld", (long)cmcred->cmcred_pid); + dbgmsg("cmsgcred.cmcred_uid %lu", (u_long)cmcred->cmcred_uid); + dbgmsg("cmsgcred.cmcred_euid %lu", (u_long)cmcred->cmcred_euid); + dbgmsg("cmsgcred.cmcred_gid %lu", (u_long)cmcred->cmcred_gid); + dbgmsg("cmsgcred.cmcred_ngroups %d", cmcred->cmcred_ngroups); - if (cmsgcred->cmcred_pid != client_pid) { + rc = 0; + + if (cmcred->cmcred_pid != client_pid) { logmsgx("cmsgcred.cmcred_pid %ld != %ld", - (long)cmsgcred->cmcred_pid, (long)client_pid); - return (-1); + (long)cmcred->cmcred_pid, (long)client_pid); + rc = -1; } - if (cmsgcred->cmcred_uid != proc_cred.uid) { + if (cmcred->cmcred_uid != proc_cred.uid) { logmsgx("cmsgcred.cmcred_uid %lu != %lu", - (u_long)cmsgcred->cmcred_uid, (u_long)proc_cred.uid); - return (-1); + (u_long)cmcred->cmcred_uid, (u_long)proc_cred.uid); + rc = -1; } - if (cmsgcred->cmcred_euid != proc_cred.euid) { + if (cmcred->cmcred_euid != proc_cred.euid) { logmsgx("cmsgcred.cmcred_euid %lu != %lu", - (u_long)cmsgcred->cmcred_euid, (u_long)proc_cred.euid); - return (-1); + (u_long)cmcred->cmcred_euid, (u_long)proc_cred.euid); + rc = -1; } - if (cmsgcred->cmcred_gid != proc_cred.gid) { + if (cmcred->cmcred_gid != proc_cred.gid) { logmsgx("cmsgcred.cmcred_gid %lu != %lu", - (u_long)cmsgcred->cmcred_gid, (u_long)proc_cred.gid); - return (-1); + (u_long)cmcred->cmcred_gid, (u_long)proc_cred.gid); + rc = -1; } - if (cmsgcred->cmcred_ngroups == 0) { + if (cmcred->cmcred_ngroups == 0) { logmsgx("cmsgcred.cmcred_ngroups == 0"); - return (-1); + rc = -1; } - if (cmsgcred->cmcred_ngroups < 0) { + if (cmcred->cmcred_ngroups < 0) { logmsgx("cmsgcred.cmcred_ngroups %d < 0", - cmsgcred->cmcred_ngroups); - return (-1); + cmcred->cmcred_ngroups); + rc = -1; } - if (cmsgcred->cmcred_ngroups > CMGROUP_MAX) { + if (cmcred->cmcred_ngroups > CMGROUP_MAX) { logmsgx("cmsgcred.cmcred_ngroups %d > %d", - cmsgcred->cmcred_ngroups, CMGROUP_MAX); - return (-1); + cmcred->cmcred_ngroups, CMGROUP_MAX); + rc = -1; } - if (cmsgcred->cmcred_groups[0] != proc_cred.egid) { + if (cmcred->cmcred_groups[0] != proc_cred.egid) { logmsgx("cmsgcred.cmcred_groups[0] %lu != %lu (EGID)", - (u_long)cmsgcred->cmcred_groups[0], (u_long)proc_cred.egid); - return (-1); + (u_long)cmcred->cmcred_groups[0], (u_long)proc_cred.egid); + rc = -1; } - if (check_groups("cmsgcred.cmcred_groups", cmsgcred->cmcred_groups, - "cmsgcred.cmcred_ngroups", cmsgcred->cmcred_ngroups, false) < 0) - return (-1); - return (0); + if (check_groups("cmsgcred.cmcred_groups", cmcred->cmcred_groups, + "cmsgcred.cmcred_ngroups", cmcred->cmcred_ngroups, false) < 0) + rc = -1; + return (rc); } static int check_scm_creds_sockcred(struct cmsghdr *cmsghdr) { - const struct sockcred *sockcred; + const struct sockcred *sc; + int rc; if (check_cmsghdr(cmsghdr, SCM_CREDS, SOCKCREDSIZE(proc_cred.gid_num)) < 0) return (-1); - sockcred = (struct sockcred *)CMSG_DATA(cmsghdr); + sc = (struct sockcred *)CMSG_DATA(cmsghdr); - dbgmsg("sockcred.sc_uid %lu", (u_long)sockcred->sc_uid); - dbgmsg("sockcred.sc_euid %lu", (u_long)sockcred->sc_euid); - dbgmsg("sockcred.sc_gid %lu", (u_long)sockcred->sc_gid); - dbgmsg("sockcred.sc_egid %lu", (u_long)sockcred->sc_egid); - dbgmsg("sockcred.sc_ngroups %d", sockcred->sc_ngroups); + rc = 0; - if (sockcred->sc_uid != proc_cred.uid) { + dbgmsg("sockcred.sc_uid %lu", (u_long)sc->sc_uid); + dbgmsg("sockcred.sc_euid %lu", (u_long)sc->sc_euid); + dbgmsg("sockcred.sc_gid %lu", (u_long)sc->sc_gid); + dbgmsg("sockcred.sc_egid %lu", (u_long)sc->sc_egid); + dbgmsg("sockcred.sc_ngroups %d", sc->sc_ngroups); + + if (sc->sc_uid != proc_cred.uid) { logmsgx("sockcred.sc_uid %lu != %lu", - (u_long)sockcred->sc_uid, (u_long)proc_cred.uid); - return (-1); + (u_long)sc->sc_uid, (u_long)proc_cred.uid); + rc = -1; } - if (sockcred->sc_euid != proc_cred.euid) { + if (sc->sc_euid != proc_cred.euid) { logmsgx("sockcred.sc_euid %lu != %lu", - (u_long)sockcred->sc_euid, (u_long)proc_cred.euid); - return (-1); + (u_long)sc->sc_euid, (u_long)proc_cred.euid); + rc = -1; } - if (sockcred->sc_gid != proc_cred.gid) { + if (sc->sc_gid != proc_cred.gid) { logmsgx("sockcred.sc_gid %lu != %lu", - (u_long)sockcred->sc_gid, (u_long)proc_cred.gid); - return (-1); + (u_long)sc->sc_gid, (u_long)proc_cred.gid); + rc = -1; } - if (sockcred->sc_egid != proc_cred.egid) { + if (sc->sc_egid != proc_cred.egid) { logmsgx("sockcred.sc_egid %lu != %lu", - (u_long)sockcred->sc_egid, (u_long)proc_cred.egid); - return (-1); + (u_long)sc->sc_egid, (u_long)proc_cred.egid); + rc = -1; } - if (sockcred->sc_ngroups == 0) { + if (sc->sc_ngroups == 0) { logmsgx("sockcred.sc_ngroups == 0"); - return (-1); + rc = -1; } - if (sockcred->sc_ngroups < 0) { + if (sc->sc_ngroups < 0) { logmsgx("sockcred.sc_ngroups %d < 0", - sockcred->sc_ngroups); - return (-1); + sc->sc_ngroups); + rc = -1; } - if (sockcred->sc_ngroups != proc_cred.gid_num) { + if (sc->sc_ngroups != proc_cred.gid_num) { logmsgx("sockcred.sc_ngroups %d != %u", - sockcred->sc_ngroups, proc_cred.gid_num); - return (-1); + sc->sc_ngroups, proc_cred.gid_num); + rc = -1; } - if (check_groups("sockcred.sc_groups", sockcred->sc_groups, - "sockcred.sc_ngroups", sockcred->sc_ngroups, true) < 0) - return (-1); - return (0); + if (check_groups("sockcred.sc_groups", sc->sc_groups, + "sockcred.sc_ngroups", sc->sc_ngroups, true) < 0) + rc = -1; + return (rc); } static int check_scm_timestamp(struct cmsghdr *cmsghdr) { - const struct timeval *timeval; + const struct timeval *tv; if (check_cmsghdr(cmsghdr, SCM_TIMESTAMP, sizeof(struct timeval)) < 0) return (-1); - timeval = (struct timeval *)CMSG_DATA(cmsghdr); + tv = (struct timeval *)CMSG_DATA(cmsghdr); dbgmsg("timeval.tv_sec %"PRIdMAX", timeval.tv_usec %"PRIdMAX, - (intmax_t)timeval->tv_sec, (intmax_t)timeval->tv_usec); + (intmax_t)tv->tv_sec, (intmax_t)tv->tv_usec); return (0); } @@ -1161,15 +1181,15 @@ check_scm_timestamp(struct cmsghdr *cmsghdr) static int check_scm_bintime(struct cmsghdr *cmsghdr) { - const struct bintime *bintime; + const struct bintime *bt; if (check_cmsghdr(cmsghdr, SCM_BINTIME, sizeof(struct bintime)) < 0) return (-1); - bintime = (struct bintime *)CMSG_DATA(cmsghdr); + bt = (struct bintime *)CMSG_DATA(cmsghdr); dbgmsg("bintime.sec %"PRIdMAX", bintime.frac %"PRIu64, - (intmax_t)bintime->sec, bintime->frac); + (intmax_t)bt->sec, bt->frac); return (0); } @@ -1213,6 +1233,10 @@ msghdr_init_client(struct msghdr *msghdr, struct iovec *iov, msghdr_init_generic(msghdr, iov, cmsg_data); if (cmsg_data != NULL) { + if (send_array_flag) + dbgmsg("sending an array"); + else + dbgmsg("sending a scalar"); msghdr->msg_controllen = send_array_flag ? cmsg_size : CMSG_SPACE(0); cmsghdr = CMSG_FIRSTHDR(msghdr); @@ -1815,6 +1839,7 @@ t_bintime(void) return (t_generic(t_bintime_client, t_bintime_server)); } +#ifndef __LP64__ static int t_cmsg_len_client(int fd) { @@ -1853,8 +1878,11 @@ t_cmsg_len_client(int fd) (u_int)msghdr.msg_controllen); dbgmsg("send: cmsghdr.cmsg_len %u", (u_int)cmsghdr->cmsg_len); - if (sendmsg(fd, &msghdr, 0) < 0) + if (sendmsg(fd, &msghdr, 0) < 0) { + dbgmsg("sendmsg(2) failed: %s; retrying", + strerror(errno)); continue; + } logmsgx("sent message with cmsghdr.cmsg_len %u < %u", (u_int)cmsghdr->cmsg_len, (u_int)CMSG_LEN(0)); break; @@ -1904,6 +1932,7 @@ t_cmsg_len(void) { return (t_generic(t_cmsg_len_client, t_cmsg_len_server)); } +#endif static int t_peercred_client(int fd) diff --git a/tools/regression/sockets/zerosend/zerosend.c b/tools/regression/sockets/zerosend/zerosend.c index 5d29c0cd5b5..ac9542a9361 100644 --- a/tools/regression/sockets/zerosend/zerosend.c +++ b/tools/regression/sockets/zerosend/zerosend.c @@ -74,7 +74,7 @@ try_0write(const char *test, int fd) } static void -setup_udp(const char *test, int *fdp) +setup_udp(const char *test, int *fdp, int port1, int port2) { struct sockaddr_in sin; int sock1, sock2; @@ -84,14 +84,14 @@ setup_udp(const char *test, int *fdp) sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - sin.sin_port = htons(PORT1); + sin.sin_port = htons(port1); sock1 = socket(PF_INET, SOCK_DGRAM, 0); if (sock1 < 0) err(1, "%s: setup_udp: socket", test); if (bind(sock1, (struct sockaddr *)&sin, sizeof(sin)) < 0) err(1, "%s: setup_udp: bind(%s, %d)", test, inet_ntoa(sin.sin_addr), PORT1); - sin.sin_port = htons(PORT2); + sin.sin_port = htons(port2); if (connect(sock1, (struct sockaddr *)&sin, sizeof(sin)) < 0) err(1, "%s: setup_udp: connect(%s, %d)", test, inet_ntoa(sin.sin_addr), PORT2); @@ -102,7 +102,7 @@ setup_udp(const char *test, int *fdp) if (bind(sock2, (struct sockaddr *)&sin, sizeof(sin)) < 0) err(1, "%s: setup_udp: bind(%s, %d)", test, inet_ntoa(sin.sin_addr), PORT2); - sin.sin_port = htons(PORT1); + sin.sin_port = htons(port1); if (connect(sock2, (struct sockaddr *)&sin, sizeof(sin)) < 0) err(1, "%s: setup_udp: connect(%s, %d)", test, inet_ntoa(sin.sin_addr), PORT1); @@ -112,7 +112,7 @@ setup_udp(const char *test, int *fdp) } static void -setup_tcp(const char *test, int *fdp) +setup_tcp(const char *test, int *fdp, int port) { fd_set writefds, exceptfds; struct sockaddr_in sin; @@ -127,7 +127,7 @@ setup_tcp(const char *test, int *fdp) /* * First set up the listen socket. */ - sin.sin_port = htons(PORT1); + sin.sin_port = htons(port); sock1 = socket(PF_INET, SOCK_STREAM, 0); if (sock1 < 0) err(1, "%s: setup_tcp: socket", test); @@ -246,19 +246,19 @@ main(void) { int fd[2]; - setup_udp("udp_0send", fd); + setup_udp("udp_0send", fd, PORT1, PORT2); try_0send("udp_0send", fd[0]); close_both(fd); - setup_udp("udp_0write", fd); + setup_udp("udp_0write", fd, PORT1 + 10, PORT2 + 10); try_0write("udp_0write", fd[0]); close_both(fd); - setup_tcp("tcp_0send", fd); + setup_tcp("tcp_0send", fd, PORT1); try_0send("tcp_0send", fd[0]); close_both(fd); - setup_tcp("tcp_0write", fd); + setup_tcp("tcp_0write", fd, PORT1 + 10); try_0write("tcp_0write", fd[0]); close_both(fd); diff --git a/tools/tools/ath/ath_ee_v4k_print/v4k.c b/tools/tools/ath/ath_ee_v4k_print/v4k.c index a3a8e6d28b3..72dc142fcc0 100644 --- a/tools/tools/ath/ath_ee_v4k_print/v4k.c +++ b/tools/tools/ath/ath_ee_v4k_print/v4k.c @@ -26,12 +26,13 @@ * $FreeBSD$ */ +#include + +#include #include #include -#include #include -#include -#include +#include typedef enum { AH_FALSE = 0, /* NB: lots of code assumes false is zero */ @@ -128,12 +129,10 @@ eeprom_v4k_modal_print(uint16_t *buf) printf("| Modal Version: %.2x |\n", mh->version); - printf("| futureModal: 0x%.2x 0x%.2x 0x%.2x 0x%.2x |\n", - mh->futureModal[0], - mh->futureModal[1], - mh->futureModal[2], - mh->futureModal[3] - ); + printf("| tx_diversity: 0x%.2x |\n", mh->tx_diversity); + printf("| flc_pwr_thresh: 0x%.2x |\n", mh->flc_pwr_thresh); + printf("| bb_scale_smrt_antenna: 0x%.2x |\n", mh->bb_scale_smrt_antenna); + printf("| futureModal: 0x%.2x |\n", mh->futureModal[0]); /* and now, spur channels */ for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { diff --git a/tools/tools/nanobsd/embedded/qemu-amd64.cfg b/tools/tools/nanobsd/embedded/qemu-amd64.cfg index c405f04e9d9..f393f1fea0f 100644 --- a/tools/tools/nanobsd/embedded/qemu-amd64.cfg +++ b/tools/tools/nanobsd/embedded/qemu-amd64.cfg @@ -29,6 +29,6 @@ NANO_ARCH=amd64 NANO_NAME=qemu-amd64 -qemu_env +. common # Pull in common definitions -. common # Pull in common definitions, keep last +qemu_env diff --git a/tools/tools/nanobsd/embedded/qemu-i386.cfg b/tools/tools/nanobsd/embedded/qemu-i386.cfg index 642f19ae1b6..96ce026d48c 100644 --- a/tools/tools/nanobsd/embedded/qemu-i386.cfg +++ b/tools/tools/nanobsd/embedded/qemu-i386.cfg @@ -29,6 +29,6 @@ NANO_ARCH=i386 NANO_NAME=qemu-i386 -qemu_env +. common # Pull in common definitions -. common # Pull in common definitions, keep last +qemu_env diff --git a/tools/tools/nanobsd/embedded/qemu-mips.cfg b/tools/tools/nanobsd/embedded/qemu-mips.cfg index 1582fdf894e..9242b897491 100644 --- a/tools/tools/nanobsd/embedded/qemu-mips.cfg +++ b/tools/tools/nanobsd/embedded/qemu-mips.cfg @@ -31,6 +31,6 @@ NANO_KERNEL=MALTA NANO_DRIVE=ada0 NANO_NAME=qemu-mips -qemu_env +. common # Pull in common definitions -. common # Pull in common definitions, keep last +qemu_env diff --git a/tools/tools/nanobsd/embedded/qemu-mips64.cfg b/tools/tools/nanobsd/embedded/qemu-mips64.cfg index a6ad39e53d6..69fff3af394 100644 --- a/tools/tools/nanobsd/embedded/qemu-mips64.cfg +++ b/tools/tools/nanobsd/embedded/qemu-mips64.cfg @@ -31,6 +31,6 @@ NANO_KERNEL=MALTA64 NANO_DRIVE=ada0 NANO_NAME=qemu-mips64 -qemu_env +. common # Pull in common definitions -. common # Pull in common definitions, keep last +qemu_env diff --git a/tools/tools/nanobsd/embedded/qemu-powerpc.cfg b/tools/tools/nanobsd/embedded/qemu-powerpc.cfg index ac1efa1baa1..effdd4b6dac 100644 --- a/tools/tools/nanobsd/embedded/qemu-powerpc.cfg +++ b/tools/tools/nanobsd/embedded/qemu-powerpc.cfg @@ -32,6 +32,6 @@ NANO_KERNEL=GENERIC NANO_DRIVE=ada0 NANO_NAME=qemu-powerpc -qemu_env +. common # Pull in common definitions -. common # Pull in common definitions, keep last +qemu_env diff --git a/tools/tools/nanobsd/embedded/qemu-powerpc64.cfg b/tools/tools/nanobsd/embedded/qemu-powerpc64.cfg index 3789ee8098c..525afc6402c 100644 --- a/tools/tools/nanobsd/embedded/qemu-powerpc64.cfg +++ b/tools/tools/nanobsd/embedded/qemu-powerpc64.cfg @@ -31,6 +31,6 @@ NANO_KERNEL=GENERIC64 NANO_DRIVE=ada0 NANO_NAME=qemu-powerpc64 -NANO_DISKIMAGE_FORMAT=qcow2 +. common # Pull in common definitions -. common # Pull in common definitions, keep last +qemu_env diff --git a/tools/tools/nanobsd/embedded/qemu-sparc64.cfg b/tools/tools/nanobsd/embedded/qemu-sparc64.cfg index d497dd4e048..d5b565d9da2 100644 --- a/tools/tools/nanobsd/embedded/qemu-sparc64.cfg +++ b/tools/tools/nanobsd/embedded/qemu-sparc64.cfg @@ -31,6 +31,6 @@ NANO_KERNEL=GENERIC NANO_DRIVE=ada0 NANO_NAME=qemu-sparc64 -qemu_env +. common # Pull in common definitions -. common # Pull in common definitions, keep last +qemu_env diff --git a/usr.bin/Makefile b/usr.bin/Makefile index 86ea20980fc..474bee1091d 100644 --- a/usr.bin/Makefile +++ b/usr.bin/Makefile @@ -268,7 +268,8 @@ SUBDIR.${MK_TOOLCHAIN}+= ctags SUBDIR.${MK_TOOLCHAIN}+= cxxfilt SUBDIR.${MK_TOOLCHAIN}+= elfcopy SUBDIR.${MK_TOOLCHAIN}+= file2c -.if ${MACHINE_ARCH} != "aarch64" # ARM64TODO gprof does not build +.if ${MACHINE_ARCH} != "aarch64" && \ # ARM64TODO gprof does not build + ${MACHINE_CPUARCH} != "riscv" # RISCVTODO gprof does not build SUBDIR.${MK_TOOLCHAIN}+= gprof .endif SUBDIR.${MK_TOOLCHAIN}+= indent @@ -290,7 +291,9 @@ SUBDIR.${MK_VT}+= vtfontcvt SUBDIR.${MK_USB}+= usbhidaction SUBDIR.${MK_USB}+= usbhidctl SUBDIR.${MK_UTMPX}+= last +.if ${MACHINE_CPUARCH} != "riscv" # RISCVTODO users does not build SUBDIR.${MK_UTMPX}+= users +.endif SUBDIR.${MK_UTMPX}+= who SUBDIR.${MK_SVN}+= svn SUBDIR.${MK_SVNLITE}+= svn diff --git a/usr.bin/elfdump/elfdump.c b/usr.bin/elfdump/elfdump.c index 908c69964f0..e42727a44f8 100644 --- a/usr.bin/elfdump/elfdump.c +++ b/usr.bin/elfdump/elfdump.c @@ -408,9 +408,27 @@ static const char *sh_flags[] = { "SHF_WRITE|SHF_ALLOC|SHF_EXECINSTR" }; -static const char *st_types[] = { - "STT_NOTYPE", "STT_OBJECT", "STT_FUNC", "STT_SECTION", "STT_FILE" -}; +static const char * +st_type(unsigned int mach, unsigned int type) +{ + static char s_type[32]; + + switch (type) { + case STT_NOTYPE: return "STT_NOTYPE"; + case STT_OBJECT: return "STT_OBJECT"; + case STT_FUNC: return "STT_FUNC"; + case STT_SECTION: return "STT_SECTION"; + case STT_FILE: return "STT_FILE"; + case STT_COMMON: return "STT_COMMON"; + case STT_TLS: return "STT_TLS"; + case 13: + if (mach == EM_SPARCV9) + return "STT_SPARC_REGISTER"; + break; + } + snprintf(s_type, sizeof(s_type), "", type); + return (s_type); +} static const char *st_bindings[] = { "STB_LOCAL", "STB_GLOBAL", "STB_WEAK" @@ -824,6 +842,7 @@ elf_print_shdr(Elf32_Ehdr *e, void *sh) static void elf_print_symtab(Elf32_Ehdr *e, void *sh, char *str) { + u_int64_t machine; u_int64_t offset; u_int64_t entsize; u_int64_t size; @@ -835,6 +854,7 @@ elf_print_symtab(Elf32_Ehdr *e, void *sh, char *str) int len; int i; + machine = elf_get_quarter(e, e, E_MACHINE); offset = elf_get_off(e, sh, SH_OFFSET); entsize = elf_get_size(e, sh, SH_ENTSIZE); size = elf_get_size(e, sh, SH_SIZE); @@ -854,7 +874,7 @@ elf_print_symtab(Elf32_Ehdr *e, void *sh, char *str) fprintf(out, "\tst_value: %#jx\n", value); fprintf(out, "\tst_size: %jd\n", (intmax_t)size); fprintf(out, "\tst_info: %s %s\n", - st_types[ELF32_ST_TYPE(info)], + st_type(machine, ELF32_ST_TYPE(info)), st_bindings[ELF32_ST_BIND(info)]); fprintf(out, "\tst_shndx: %jd\n", (intmax_t)shndx); } diff --git a/usr.bin/ldd/ldd.c b/usr.bin/ldd/ldd.c index c8e0be3d455..cc3a7692b97 100644 --- a/usr.bin/ldd/ldd.c +++ b/usr.bin/ldd/ldd.c @@ -48,8 +48,8 @@ __FBSDID("$FreeBSD$"); #include "extern.h" -/* We don't support a.out executables on arm64 */ -#ifndef __aarch64__ +/* We don't support a.out executables on arm64 and riscv */ +#if !defined(__aarch64__) && !defined(__riscv__) #include #define AOUT_SUPPORTED #endif diff --git a/usr.bin/whois/whois.1 b/usr.bin/whois/whois.1 index bcc770ce962..0b74cc5bcf7 100644 --- a/usr.bin/whois/whois.1 +++ b/usr.bin/whois/whois.1 @@ -28,7 +28,7 @@ .\" From: @(#)whois.1 8.1 (Berkeley) 6/6/93 .\" $FreeBSD$ .\" -.Dd January 22, 2016 +.Dd January 23, 2016 .Dt WHOIS 1 .Os .Sh NAME @@ -49,31 +49,22 @@ Network Information Centers .Pp By default .Nm -automatically discovers the name of a whois server to use -from the top-level domain -.Pq Tn TLD -of the supplied (single) argument. -It tries -.Qq Va TLD Ns Li .whois-servers.net -and -.Qq Li whois.nic. Ns Va TLD -and if neither host exists it falls back to its default server. +starts by querying the Internet Assigned Numbers Authority (IANA) whois server, +and follows referrals to whois servers +that have more specific details about the query +.Ar name . +The IANA whois server knows about +IP address and AS numbers +as well as domain names. .Pp -If an IP address or AS number is specified, -the whois server will default to -the American Registry for Internet Numbers -.Pq Tn ARIN . -.Pp -If +There are a few special cases where referrals do not work, so .Nm -cannot automatically discover a server, -it will fall back to -the host specified in the -.Ev WHOIS_SERVER -or -.Ev RA_SERVER -environment variables, or if those are not set, it will use -.Pa whois.crsnic.net . +goes directly to the appropriate server. +These include point-of-contact handles for ARIN, +.Pa nic.at , +NORID, and RIPE, +and domain names under +.Pa ac.uk . .Pp The options are as follows: .Bl -tag -width indent @@ -85,17 +76,16 @@ It contains network numbers used in those parts of the world covered neither by .Tn APNIC , AfriNIC , LACNIC , nor by .Tn RIPE . -.Pp -(Hint: All point of contact handles in the -.Tn ARIN -whois database end with -.Qq Li -ARIN . ) +The query syntax is documented at +.Pa https://www.arin.net/resources/whoisrws/whois_api.html#nicname .It Fl A Use the Asia/Pacific Network Information Center .Pq Tn APNIC database. It contains network numbers used in East Asia, Australia, New Zealand, and the Pacific islands. +Get query syntax documentation using +.Ic whois -A help .It Fl b Use the Network Abuse Clearinghouse database. It contains addresses to which network abuse should be reported, @@ -111,6 +101,8 @@ Use the African Network Information Centre database. It contains network numbers used in Africa and the islands of the western Indian Ocean. +Get query syntax documentation using +.Ic whois -f help .It Fl g Use the US non-military federal government database, which contains points of contact for subdomains of @@ -119,14 +111,28 @@ contact for subdomains of Use the specified host instead of the default. Either a host name or an IP address may be specified. .It Fl i -Use the obsolete Network Solutions Registry for Internet Numbers -.Pq Pa whois.networksolutions.com +Use the traditional Network Information Center (InterNIC) +.Pq Pa whois.internic.net database. +This now contains only registrations for domain names under +.Pa .COM , +.Pa .NET , +.Pa .EDU . +You can specify the type of object to search for like +.Ic whois -i ' Ns Ar type Ar name Ns Ic ' +where +.Ar type +can be +.Nm domain , nameserver , registrar . +The +.Ar name +can contain +.Li * +wildcards. .It Fl I Use the Internet Assigned Numbers Authority .Pq Tn IANA database. -It contains network information for top-level domains. .It Fl k Use the National Internet Development Agency of Korea's .Pq Tn KRNIC @@ -160,7 +166,7 @@ Do a quick lookup; .Nm will not attempt to follow referrals to other whois servers. This is the default if a server is explicitly specified -using one of the other options. +using one of the other options or in an environment variable. See also the .Fl R option. @@ -170,6 +176,8 @@ Use the R\(aaeseaux IP Europ\(aaeens database. It contains network numbers and domain contact information for Europe. +Get query syntax documentation using +.Ic whois -r help .It Fl R Do a recursive lookup; .Nm @@ -179,19 +187,16 @@ See also the .Fl Q option. .It Fl S -By default, if the whois server is -.Pa whois.verisign-grs.com -(or a CNAME alias pointing at that name) -then +By default .Nm -will query for -.Dl domain Ar name -The +adjusts simple queries (without spaces) to produce more useful output +from certain whois servers, +and it suppresses some uninformative output. +With the .Fl S -option suppresses this behaviour, -allowing you to make a loose-matching query, -or query for host objects using the syntax -.Dl nameserver Ar name +option, +.Nm +sends the query and prints the output verbatim. .El .Pp The operands specified to @@ -212,22 +217,11 @@ The secondary default whois server. If this is unset, .Nm will use -.Pa whois.crsnic.net . +.Pa whois.iana.org . .El .Sh EXIT STATUS .Ex -std .Sh EXAMPLES -Most types of data, such as domain names and -.Tn IP -addresses, can be used as arguments to -.Nm -without any options, and -.Nm -will choose the correct whois server to query. -Some exceptions, where -.Nm -will not be able to handle data correctly, are detailed below. -.Pp To obtain contact information about an administrator located in the Russian .Tn TLD diff --git a/usr.bin/whois/whois.c b/usr.bin/whois/whois.c index 6be6c401c07..1630067f15c 100644 --- a/usr.bin/whois/whois.c +++ b/usr.bin/whois/whois.c @@ -61,31 +61,36 @@ __FBSDID("$FreeBSD$"); #define ABUSEHOST "whois.abuse.net" #define ANICHOST "whois.arin.net" -#define BNICHOST "whois.registro.br" +#define DENICHOST "whois.denic.de" +#define DKNICHOST "whois.dk-hostmaster.dk" #define FNICHOST "whois.afrinic.net" -#define GERMNICHOST "de" QNICHOST_TAIL #define GNICHOST "whois.nic.gov" #define IANAHOST "whois.iana.org" -#define INICHOST "whois.networksolutions.com" +#define INICHOST "whois.internic.net" #define KNICHOST "whois.krnic.net" #define LNICHOST "whois.lacnic.net" #define MNICHOST "whois.ra.net" -#define NICHOST "whois.crsnic.net" #define PDBHOST "whois.peeringdb.com" #define PNICHOST "whois.apnic.net" -#define QNICHOST_HEAD "whois.nic." #define QNICHOST_TAIL ".whois-servers.net" #define RNICHOST "whois.ripe.net" #define VNICHOST "whois.verisign-grs.com" #define DEFAULT_PORT "whois" -#define WHOIS_RECURSE 0x01 -#define WHOIS_QUICK 0x02 -#define WHOIS_SPAM_ME 0x04 +#define WHOIS_RECURSE 0x01 +#define WHOIS_QUICK 0x02 +#define WHOIS_SPAM_ME 0x04 + +#define CHOPSPAM ">>> Last update of WHOIS database:" #define ishost(h) (isalnum((unsigned char)h) || h == '.' || h == '-') +#define SCAN(p, end, check) \ + while ((p) < (end)) \ + if (check) ++(p); \ + else break + static struct { const char *suffix, *server; } whoiswhere[] = { @@ -96,7 +101,8 @@ static struct { { "-RIPE", RNICHOST }, /* Nominet's whois server doesn't return referrals to JANET */ { ".ac.uk", "ac.uk" QNICHOST_TAIL }, - { NULL, NULL } + { "", IANAHOST }, /* default */ + { NULL, NULL } /* safety belt */ }; #define WHOIS_REFERRAL(s) { s, sizeof(s) - 1 } @@ -104,18 +110,16 @@ static struct { const char *prefix; size_t len; } whois_referral[] = { - WHOIS_REFERRAL("Whois Server: "), - WHOIS_REFERRAL("WHOIS Server: "), - WHOIS_REFERRAL(" Whois Server: "), - WHOIS_REFERRAL("refer: "), - WHOIS_REFERRAL("Registrant Street1:Whois Server:"), - WHOIS_REFERRAL("ReferralServer: whois://"), + WHOIS_REFERRAL("whois:"), /* IANA */ + WHOIS_REFERRAL("Whois Server:"), + WHOIS_REFERRAL("Registrar WHOIS Server:"), /* corporatedomains.com */ + WHOIS_REFERRAL("ReferralServer: whois://"), /* ARIN */ { NULL, 0 } }; static const char *port = DEFAULT_PORT; -static char *choose_server(char *); +static const char *choose_server(char *); static struct addrinfo *gethostinfo(char const *host, int exitnoname); static void s_asprintf(char **ret, const char *format, ...) __printflike(2, 3); static void usage(void); @@ -125,15 +129,14 @@ int main(int argc, char *argv[]) { const char *country, *host; - char *qnichost; - int ch, flags, use_qnichost; + int ch, flags; #ifdef SOCKS SOCKSinit(argv[0]); #endif - country = host = qnichost = NULL; - flags = use_qnichost = 0; + country = host = NULL; + flags = 0; while ((ch = getopt(argc, argv, "aAbc:fgh:iIklmp:PQrRS")) != -1) { switch (ch) { case 'a': @@ -203,103 +206,43 @@ main(int argc, char *argv[]) usage(); /* - * If no host or country is specified, try to determine the top - * level domain from the query, or fall back to NICHOST. + * If no host or country is specified, rely on referrals from IANA. */ if (host == NULL && country == NULL) { if ((host = getenv("WHOIS_SERVER")) == NULL && (host = getenv("RA_SERVER")) == NULL) { - use_qnichost = 1; - host = NICHOST; if (!(flags & WHOIS_QUICK)) flags |= WHOIS_RECURSE; } } while (argc-- > 0) { if (country != NULL) { + char *qnichost; s_asprintf(&qnichost, "%s%s", country, QNICHOST_TAIL); whois(*argv, qnichost, flags); - } else if (use_qnichost) - if ((qnichost = choose_server(*argv)) != NULL) - whois(*argv, qnichost, flags); - if (qnichost == NULL) - whois(*argv, host, flags); - free(qnichost); - qnichost = NULL; + free(qnichost); + } else + whois(*argv, host != NULL ? host : + choose_server(*argv), flags); argv++; } exit(0); } -/* - * This function will remove any trailing periods from domain, after which it - * returns a pointer to newly allocated memory containing the whois server to - * be queried, or a NULL if the correct server couldn't be determined. The - * caller must remember to free(3) the allocated memory. - * - * If the domain is an IPv6 address or has a known suffix, that determines - * the server, else if the TLD is a number, query ARIN, else try a couple of - * formulaic server names. Fail if the domain does not contain '.'. - */ -static char * +static const char * choose_server(char *domain) { - char *pos, *retval; + size_t len = strlen(domain); int i; - struct addrinfo *res; - if (strchr(domain, ':')) { - s_asprintf(&retval, "%s", ANICHOST); - return (retval); - } - if (strncasecmp(domain, "AS", 2) == 0) { - size_t len = strspn(domain + 2, "0123456789"); - if (domain[len + 2] == '\0') { - s_asprintf(&retval, "%s", ANICHOST); - return (retval); - } - } - for (pos = strchr(domain, '\0'); pos > domain && pos[-1] == '.';) - *--pos = '\0'; - if (*domain == '\0') - errx(EX_USAGE, "can't search for a null string"); for (i = 0; whoiswhere[i].suffix != NULL; i++) { size_t suffix_len = strlen(whoiswhere[i].suffix); - if (domain + suffix_len < pos && - strcasecmp(pos - suffix_len, whoiswhere[i].suffix) == 0) { - s_asprintf(&retval, "%s", whoiswhere[i].server); - return (retval); - } - } - while (pos > domain && *pos != '.') - --pos; - if (pos <= domain) - return (NULL); - if (isdigit((unsigned char)*++pos)) { - s_asprintf(&retval, "%s", ANICHOST); - return (retval); - } - /* Try possible alternative whois server name formulae. */ - for (i = 0; ; ++i) { - switch (i) { - case 0: - s_asprintf(&retval, "%s%s", pos, QNICHOST_TAIL); - break; - case 1: - s_asprintf(&retval, "%s%s", QNICHOST_HEAD, pos); - break; - default: - return (NULL); - } - res = gethostinfo(retval, 0); - if (res) { - freeaddrinfo(res); - return (retval); - } else { - free(retval); - continue; - } + if (len > suffix_len && + strcasecmp(domain + len - suffix_len, + whoiswhere[i].suffix) == 0) + return (whoiswhere[i].server); } + errx(EX_SOFTWARE, "no default whois server"); } static struct addrinfo * @@ -341,7 +284,7 @@ whois(const char *query, const char *hostname, int flags) FILE *fp; struct addrinfo *hostres, *res; char *buf, *host, *nhost, *p; - int s = -1, f, antispam; + int s = -1, f; nfds_t i, j; size_t len, count; struct pollfd *fds; @@ -350,10 +293,6 @@ whois(const char *query, const char *hostname, int flags) hostres = gethostinfo(hostname, 1); for (res = hostres, count = 0; res; res = res->ai_next) count++; - - antispam = (flags & WHOIS_SPAM_ME) == 0 && - strcmp(hostres->ai_canonname, VNICHOST) == 0; - fds = calloc(count, sizeof(*fds)); if (fds == NULL) err(EX_OSERR, "calloc()"); @@ -420,8 +359,8 @@ whois(const char *query, const char *hostname, int flags) break; } else if (n < 0) { /* - * errno here can only be EINTR which we would want - * to clean up and bail out. + * errno here can only be EINTR which we would + * want to clean up and bail out. */ s = -1; goto done; @@ -455,66 +394,91 @@ whois(const char *query, const char *hostname, int flags) s = -1; if (count == 0) errno = ETIMEDOUT; - done: + if (s == -1) + err(EX_OSERR, "connect()"); + /* Close all watched fds except the succeeded one */ for (j = 0; j < i; j++) if (fds[j].fd != s && fds[j].fd != -1) close(fds[j].fd); - - if (s != -1) { - /* Restore default blocking behavior. */ - if ((f = fcntl(s, F_GETFL)) != -1) { - f &= ~O_NONBLOCK; - if (fcntl(s, F_SETFL, f) == -1) - err(EX_OSERR, "fcntl()"); - } else - err(EX_OSERR, "fcntl()"); - } - free(fds); - freeaddrinfo(hostres); - if (s == -1) - err(EX_OSERR, "connect()"); + + /* Restore default blocking behavior. */ + if ((f = fcntl(s, F_GETFL)) == -1) + err(EX_OSERR, "fcntl()"); + f &= ~O_NONBLOCK; + if (fcntl(s, F_SETFL, f) == -1) + err(EX_OSERR, "fcntl()"); fp = fdopen(s, "r+"); if (fp == NULL) err(EX_OSERR, "fdopen()"); - if (strcmp(hostname, GERMNICHOST) == 0) { - fprintf(fp, "-T dn,ace -C ISO-8859-1 %s\r\n", query); - } else if (strcmp(hostname, "dk" QNICHOST_TAIL) == 0) { + + if (!(flags & WHOIS_SPAM_ME) && + (strcasecmp(hostname, DENICHOST) == 0 || + strcasecmp(hostname, "de" QNICHOST_TAIL) == 0)) { + const char *q; + int idn = 0; + for (q = query; *q != '\0'; q++) + if (!isascii(*q)) + idn = 1; + fprintf(fp, "-T dn%s %s\r\n", idn ? "" : ",ace", query); + } else if (!(flags & WHOIS_SPAM_ME) && + (strcasecmp(hostname, DKNICHOST) == 0 || + strcasecmp(hostname, "dk" QNICHOST_TAIL) == 0)) fprintf(fp, "--show-handles %s\r\n", query); - } else if (antispam) { - fprintf(fp, "domain %s\r\n", query); - } else { + else if ((flags & WHOIS_SPAM_ME) || + strchr(query, ' ') != NULL) + fprintf(fp, "%s\r\n", query); + else if (strcasecmp(hostname, ANICHOST) == 0) + fprintf(fp, "+ %s\r\n", query); + else if (strcasecmp(hostres->ai_canonname, VNICHOST) == 0) + fprintf(fp, "domain %s\r\n", query); + else fprintf(fp, "%s\r\n", query); - } fflush(fp); + nhost = NULL; while ((buf = fgetln(fp, &len)) != NULL) { - while (len > 0 && isspace((unsigned char)buf[len - 1])) - buf[--len] = '\0'; - printf("%.*s\n", (int)len, buf); + /* Nominet */ + if (!(flags & WHOIS_SPAM_ME) && + len == 5 && strncmp(buf, "-- \r\n", 5) == 0) + break; + + printf("%.*s", (int)len, buf); if ((flags & WHOIS_RECURSE) && nhost == NULL) { for (i = 0; whois_referral[i].prefix != NULL; i++) { - if (strncmp(buf, - whois_referral[i].prefix, - whois_referral[i].len) != 0) + p = buf; + SCAN(p, buf+len, *p == ' '); + if (strncasecmp(p, whois_referral[i].prefix, + whois_referral[i].len) != 0) continue; - host = buf + whois_referral[i].len; - for (p = host; p < buf + len; p++) - if (!ishost(*p)) - break; - s_asprintf(&nhost, "%.*s", - (int)(p - host), host); + p += whois_referral[i].len; + SCAN(p, buf+len, *p == ' '); + host = p; + SCAN(p, buf+len, ishost(*p)); + /* avoid loops */ + if (strncmp(hostname, host, p - host) != 0) + s_asprintf(&nhost, "%.*s", + (int)(p - host), host); break; } } + /* Verisign etc. */ + if (!(flags & WHOIS_SPAM_ME) && + len >= sizeof(CHOPSPAM)-1 && + (strncasecmp(buf, CHOPSPAM, sizeof(CHOPSPAM)-1) == 0 || + strncasecmp(buf, CHOPSPAM+4, sizeof(CHOPSPAM)-5) == 0)) { + printf("\n"); + break; + } } fclose(fp); + freeaddrinfo(hostres); if (nhost != NULL) { - whois(query, nhost, 0); + whois(query, nhost, flags); free(nhost); } } diff --git a/usr.sbin/autofs/automount.c b/usr.sbin/autofs/automount.c index ce5d8614b13..c87d6c01510 100644 --- a/usr.sbin/autofs/automount.c +++ b/usr.sbin/autofs/automount.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -55,8 +56,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include - #include "common.h" #include "mntopts.h" diff --git a/usr.sbin/autofs/automountd.c b/usr.sbin/autofs/automountd.c index 2c9b1a9faf9..44eda6922dd 100644 --- a/usr.sbin/autofs/automountd.c +++ b/usr.sbin/autofs/automountd.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -55,8 +56,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include - #include "autofs_ioctl.h" #include "common.h" diff --git a/usr.sbin/autofs/autounmountd.c b/usr.sbin/autofs/autounmountd.c index b85f3ca453e..02971cf7241 100644 --- a/usr.sbin/autofs/autounmountd.c +++ b/usr.sbin/autofs/autounmountd.c @@ -37,13 +37,13 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include #include #include #include -#include #include "common.h" diff --git a/usr.sbin/autofs/common.c b/usr.sbin/autofs/common.c index eae118fae62..584c10b4696 100644 --- a/usr.sbin/autofs/common.c +++ b/usr.sbin/autofs/common.c @@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -58,8 +59,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include - #include "autofs_ioctl.h" #include "common.h" diff --git a/usr.sbin/autofs/defined.c b/usr.sbin/autofs/defined.c index eaaea280d83..f94b92d0de9 100644 --- a/usr.sbin/autofs/defined.c +++ b/usr.sbin/autofs/defined.c @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -60,8 +61,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include - #include "common.h" static TAILQ_HEAD(, defined_value) defined_values; diff --git a/usr.sbin/bhyve/block_if.c b/usr.sbin/bhyve/block_if.c index ef8e11e2755..b6cb4090e47 100644 --- a/usr.sbin/bhyve/block_if.c +++ b/usr.sbin/bhyve/block_if.c @@ -692,9 +692,7 @@ int blockif_close(struct blockif_ctxt *bc) { void *jval; - int err, i; - - err = 0; + int i; assert(bc->bc_magic == BLOCKIF_SIG); diff --git a/usr.sbin/bhyve/pci_ahci.c b/usr.sbin/bhyve/pci_ahci.c index 5c4743c41b3..d3122cb09aa 100644 --- a/usr.sbin/bhyve/pci_ahci.c +++ b/usr.sbin/bhyve/pci_ahci.c @@ -1201,10 +1201,9 @@ atapi_read_toc(struct ahci_port *p, int slot, uint8_t *cfis) { int msf, size; uint64_t sectors; - uint8_t start_track, *bp, buf[50]; + uint8_t *bp, buf[50]; msf = (acmd[1] >> 1) & 1; - start_track = acmd[6]; bp = buf + 2; *bp++ = 1; *bp++ = 1; @@ -1312,13 +1311,11 @@ atapi_read(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t done) struct ahci_cmd_hdr *hdr; struct ahci_prdt_entry *prdt; struct blockif_req *breq; - struct pci_ahci_softc *sc; uint8_t *acmd; uint64_t lba; uint32_t len; int err; - sc = p->pr_sc; acmd = cfis + 0x40; hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE); prdt = (struct ahci_prdt_entry *)(cfis + 0x80); diff --git a/usr.sbin/bsdconfig/share/strings.subr b/usr.sbin/bsdconfig/share/strings.subr index 487e0617453..e624fb5c7cd 100644 --- a/usr.sbin/bsdconfig/share/strings.subr +++ b/usr.sbin/bsdconfig/share/strings.subr @@ -110,7 +110,7 @@ f_sprintf() # Example 2: # # limit=12 format="%s %s" -# format_args=" 'doghouse' 'foxhound' " +# format_args=" 'doghouse' 'fox' " # # even more spaces added to illustrate escape-method # f_vsnprintf foo $limit "$format" "$format_args" # foo=[doghouse fox] # diff --git a/usr.sbin/iscsid/iscsid.c b/usr.sbin/iscsid/iscsid.c index c1c8b1b3a7c..72828ef572b 100644 --- a/usr.sbin/iscsid/iscsid.c +++ b/usr.sbin/iscsid/iscsid.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -51,8 +52,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include - #include "iscsid.h" static volatile bool sigalrm_received = false;