diff --git a/bin/df/df.1 b/bin/df/df.1 index 85136a1e1042..85e1ab475203 100644 --- a/bin/df/df.1 +++ b/bin/df/df.1 @@ -29,7 +29,7 @@ .\" @(#)df.1 8.3 (Berkeley) 5/8/95 .\" $FreeBSD$ .\" -.Dd January 24, 2013 +.Dd January 16, 2014 .Dt DF 1 .Os .Sh NAME @@ -83,13 +83,13 @@ Use 1073741824 byte (1 Gibibyte) blocks rather than the default. This overrides any .Ev BLOCKSIZE specification from the environment. -.It Fl H +.It Fl h .Dq Human-readable output. Use unit suffixes: Byte, Kibibyte, Mebibyte, Gibibyte, Tebibyte and Pebibyte (based on powers of 1024) in order to reduce the number of digits to four or fewer. -.It Fl h +.It Fl H .Dq Human-readable output. Use unit suffixes: Byte, Kilobyte, Megabyte, diff --git a/cddl/contrib/opensolaris/cmd/zdb/zdb.c b/cddl/contrib/opensolaris/cmd/zdb/zdb.c index 4192812d512c..932687a8e33f 100644 --- a/cddl/contrib/opensolaris/cmd/zdb/zdb.c +++ b/cddl/contrib/opensolaris/cmd/zdb/zdb.c @@ -3012,6 +3012,7 @@ zdb_read_block(char *thing, spa_t *spa) free(dup); return; } + i += p - &flagstr[i + 1]; /* skip over the number */ } } diff --git a/cddl/contrib/opensolaris/cmd/zinject/zinject.c b/cddl/contrib/opensolaris/cmd/zinject/zinject.c index 994d6878cc85..ddcdb1ffd564 100644 --- a/cddl/contrib/opensolaris/cmd/zinject/zinject.c +++ b/cddl/contrib/opensolaris/cmd/zinject/zinject.c @@ -148,6 +148,7 @@ #include #include +#include #undef verify /* both libzfs.h and zfs_context.h want to define this */ diff --git a/cddl/usr.bin/zinject/Makefile b/cddl/usr.bin/zinject/Makefile index 8c5c141e582e..56251490bbda 100644 --- a/cddl/usr.bin/zinject/Makefile +++ b/cddl/usr.bin/zinject/Makefile @@ -16,6 +16,7 @@ CFLAGS+= -I${.CURDIR}/../../contrib/opensolaris/lib/libnvpair CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/fs/zfs CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/sys CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common +CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/common/zfs/ CFLAGS+= -I${.CURDIR}/../../contrib/opensolaris/head CFLAGS+= -I${.CURDIR}/../../lib/libumem diff --git a/contrib/gcc/cp/ChangeLog.apple b/contrib/gcc/cp/ChangeLog.apple index bd928a2ec612..a2cecaa79f49 100644 --- a/contrib/gcc/cp/ChangeLog.apple +++ b/contrib/gcc/cp/ChangeLog.apple @@ -302,15 +302,6 @@ (cp_parser_objc_declaration): Parses attribute list and passes it down to cp_parser_objc_class_interface/cp_parser_objc_protocol_declaration. -2007-07-24 Fariborz Jahanian - - Radar 5355344 - * cp-tree.h (cp_objc_protocol_id_list): New declaration - * cp-lang.c (cp_objc_protocol_id_list): New stub - * parser.c (cp_parser_type_name): Added code to disambiguate - conditional from a protocol type. - (cp_parser_objc_tentative_protocol_refs_opt): New - 2007-07-13 Fariborz Jahanian Radar 5277239 diff --git a/contrib/gcc/cp/parser.c b/contrib/gcc/cp/parser.c index 9bb66fad87e3..25cc2250f9f0 100644 --- a/contrib/gcc/cp/parser.c +++ b/contrib/gcc/cp/parser.c @@ -1827,10 +1827,6 @@ static tree cp_parser_objc_identifier_list /* APPLE LOCAL end radar 3803157 - objc attribute */ static tree cp_parser_objc_protocol_refs_opt (cp_parser *); -/* APPLE LOCAL begin radar 5355344 */ -static bool cp_parser_objc_tentative_protocol_refs_opt - (cp_parser *, tree *); -/* APPLE LOCAL end radar 5355344 */ static void cp_parser_objc_declaration (cp_parser *); static tree cp_parser_objc_statement @@ -17873,32 +17869,6 @@ cp_parser_objc_protocol_refs_opt (cp_parser* parser) return protorefs; } -/* APPLE LOCAL begin radar 5355344 */ -/* This routine also parses a list of Objective-C protocol references; except that - if list is not valid, it returns FALSE and back-tracks parsing. */ - -static bool -cp_parser_objc_tentative_protocol_refs_opt (cp_parser* parser, tree *protorefs) -{ - *protorefs = NULL_TREE; - if(cp_lexer_next_token_is (parser->lexer, CPP_LESS)) - { - cp_parser_parse_tentatively (parser); - cp_lexer_consume_token (parser->lexer); /* Eat '<'. */ - *protorefs = cp_parser_objc_identifier_list (parser); - if (!cp_objc_protocol_id_list (*protorefs)) - { - cp_parser_abort_tentative_parse (parser); - return false; - } - if (cp_parser_parse_definitely (parser)) - cp_parser_require (parser, CPP_GREATER, "`>'"); - } - - return true; -} -/* APPLE LOCAL end radar 5355344 */ - /* Parse a Objective-C visibility specification. */ static void diff --git a/gnu/lib/libgcc/Makefile b/gnu/lib/libgcc/Makefile index d9521d44b6e6..d186e7ef5921 100644 --- a/gnu/lib/libgcc/Makefile +++ b/gnu/lib/libgcc/Makefile @@ -34,9 +34,9 @@ OBJS= # added to below in various ways depending on TARGET_CPUARCH #--------------------------------------------------------------------------- # -# When upgrading GCC, get the following defintions straight from Makefile.in -# # Library members defined in libgcc2.c. +# When upgrading GCC, obtain the following list from mklibgcc.in +# LIB2FUNCS= _muldi3 _negdi2 _lshrdi3 _ashldi3 _ashrdi3 \ _cmpdi2 _ucmpdi2 \ _enable_execute_stack _trampoline __main _absvsi2 _absvdi2 _addvsi3 \ @@ -44,7 +44,7 @@ LIB2FUNCS= _muldi3 _negdi2 _lshrdi3 _ashldi3 _ashrdi3 \ _ffssi2 _ffsdi2 _clz _clzsi2 _clzdi2 _ctzsi2 _ctzdi2 _popcount_tab \ _popcountsi2 _popcountdi2 _paritysi2 _paritydi2 _powisf2 _powidf2 \ _powixf2 _powitf2 _mulsc3 _muldc3 _mulxc3 _multc3 _divsc3 _divdc3 \ - _divxc3 _divtc3 + _divxc3 _divtc3 _bswapsi2 _bswapdi2 .if ${COMPILER_TYPE} != "clang" || ${TARGET_CPUARCH} != "arm" LIB2FUNCS+= _clear_cache .endif @@ -119,8 +119,8 @@ LIB1ASMFUNCS = _dvmd_tls _bb_init_func .if ${MK_ARM_EABI} != "no" LIB2ADDEH = unwind-arm.c libunwind.S pr-support.c unwind-c.c # Some compilers generate __aeabi_ functions libgcc_s is missing -DPADD+= ${LIBGCC} -LDADD+= -lgcc +DPADD+= ${LIBCOMPILER_RT} +LDADD+= -lcompiler_rt .else LIB2FUNCS_EXTRA = floatunsidf.c floatunsisf.c .endif diff --git a/include/ttyent.h b/include/ttyent.h index 815d16844709..f2220ad73b94 100644 --- a/include/ttyent.h +++ b/include/ttyent.h @@ -37,6 +37,7 @@ #define _TTYS_OFF "off" #define _TTYS_ON "on" +#define _TTYS_ONIFCONSOLE "onifconsole" #define _TTYS_SECURE "secure" #define _TTYS_INSECURE "insecure" #define _TTYS_WINDOW "window" diff --git a/lib/libc/Makefile b/lib/libc/Makefile index 04235a255f3c..f4068ac6eb62 100644 --- a/lib/libc/Makefile +++ b/lib/libc/Makefile @@ -40,11 +40,11 @@ CFLAGS+=${CANCELPOINTS_CFLAGS} .endif # -# Only link with static libgcc.a (no libgcc_eh.a). +# Link with static libcompiler_rt.a. # -DPADD+= ${LIBGCC} +DPADD+= ${LIBCOMPILER_RT} LDFLAGS+= -nodefaultlibs -LDADD+= -lgcc +LDADD+= -lcompiler_rt .if ${MK_SSP} != "no" LDADD+= -lssp_nonshared diff --git a/lib/libc/gen/getttyent.c b/lib/libc/gen/getttyent.c index b82c30abe366..d10430524dac 100644 --- a/lib/libc/gen/getttyent.c +++ b/lib/libc/gen/getttyent.c @@ -39,6 +39,9 @@ __FBSDID("$FreeBSD$"); #include #include +#include +#include + static char zapchar; static FILE *tf; static size_t lbsize; @@ -64,6 +67,36 @@ getttynam(const char *tty) return (t); } +static int +auto_tty_status(const char *ty_name) +{ + size_t len; + char *buf, *cons, *nextcons; + + /* Check if this is an enabled kernel console line */ + buf = NULL; + if (sysctlbyname("kern.console", NULL, &len, NULL, 0) == -1) + return (0); /* Errors mean don't enable */ + buf = malloc(len); + if (sysctlbyname("kern.console", buf, &len, NULL, 0) == -1) + goto done; + + if ((cons = strchr(buf, '/')) == NULL) + goto done; + *cons = '\0'; + nextcons = buf; + while ((cons = strsep(&nextcons, ",")) != NULL && strlen(cons) != 0) { + if (strcmp(cons, ty_name) == 0) { + free(buf); + return (TTY_ON); + } + } + +done: + free(buf); + return (0); +} + struct ttyent * getttyent(void) { @@ -126,6 +159,8 @@ getttyent(void) tty.ty_status &= ~TTY_ON; else if (scmp(_TTYS_ON)) tty.ty_status |= TTY_ON; + else if (scmp(_TTYS_ONIFCONSOLE)) + tty.ty_status |= auto_tty_status(tty.ty_name); else if (scmp(_TTYS_SECURE)) tty.ty_status |= TTY_SECURE; else if (scmp(_TTYS_INSECURE)) diff --git a/lib/libfetch/common.c b/lib/libfetch/common.c index 49d268ce3761..fbacb0282a75 100644 --- a/lib/libfetch/common.c +++ b/lib/libfetch/common.c @@ -679,7 +679,7 @@ fetch_ssl_setup_transport_layer(SSL_CTX *ctx, int verbose) if (getenv("SSL_NO_TLS1") != NULL) ssl_ctx_options |= SSL_OP_NO_TLSv1; if (verbose) - fetch_info("SSL options: %x", ssl_ctx_options); + fetch_info("SSL options: %lx", ssl_ctx_options); SSL_CTX_set_options(ctx, ssl_ctx_options); } diff --git a/lib/libkvm/kvm_ia64.c b/lib/libkvm/kvm_ia64.c index 6456b6f42b1f..5db7e1e7ab09 100644 --- a/lib/libkvm/kvm_ia64.c +++ b/lib/libkvm/kvm_ia64.c @@ -371,5 +371,5 @@ _kvm_kvatop(kvm_t *kd, u_long va, off_t *ofs) size_t sz; sz = kd->vmst->kvatop(kd, va, ofs); - return (sz); + return ((sz > INT_MAX) ? INT_MAX : sz); } diff --git a/libexec/getty/ttys.5 b/libexec/getty/ttys.5 index 18151c9855fe..71a4b2b58072 100644 --- a/libexec/getty/ttys.5 +++ b/libexec/getty/ttys.5 @@ -102,8 +102,11 @@ ttys as a group. .Pp As flag values, the strings ``on'' and ``off'' specify that .Xr init 8 -should (should not) execute the command given in the second field, -while ``secure'' (if ``on'' is also specified) allows users with a +should (should not) execute the command given in the second field. +``onifconsole'' will cause this line to be enabled if and only if it is +an active kernel console device (it is equivalent to ``on'' in this +case). +The flag ``secure'' (if the console is enabled) allows users with a uid of 0 to login on this line. The flag ``dialin'' indicates that a tty entry describes a dialin diff --git a/libexec/rtld-elf/Makefile b/libexec/rtld-elf/Makefile index 31cbfdd449d7..2a0953c96dfa 100644 --- a/libexec/rtld-elf/Makefile +++ b/libexec/rtld-elf/Makefile @@ -43,11 +43,12 @@ DPADD= ${LIBC_PIC} LDADD= -lc_pic .if ${MACHINE_CPUARCH} == "arm" && ${MK_ARM_EABI} != "no" -# Some of the required math functions (div & mod) are implemented in libgcc -# on ARM. The library also needs to be placed first to be correctly linked. -# As some of the functions are used before we have shared libraries. -DPADD+= ${LIBGCC} -LDADD+= -lgcc +# Some of the required math functions (div & mod) are implemented in +# libcompiler_rt on ARM. The library also needs to be placed first to be +# correctly linked. As some of the functions are used before we have +# shared libraries. +DPADD+= ${LIBCOMPILER_RT} +LDADD+= -lcompiler_rt .endif diff --git a/release/Makefile b/release/Makefile index eb5abc99f407..c2c46de1f4e1 100644 --- a/release/Makefile +++ b/release/Makefile @@ -224,9 +224,9 @@ packagesystem: base.txz kernel.txz ${EXTRA_PACKAGES} touch ${.TARGET} pkg-stage: -.if !defined(NOPKG) && exists(${.CURDIR}/${TARGET}/pkg-stage.conf) - sh ${.CURDIR}/scripts/pkg-stage.sh ${.CURDIR}/${TARGET}/pkg-stage.conf \ - ${REVISION} +.if !defined(NOPKG) + env REPOS_DIR=${.CURDIR}/pkg_repos/ \ + sh ${.CURDIR}/scripts/pkg-stage.sh mkdir -p ${.OBJDIR}/dvd/packages/repos/ cp ${.CURDIR}/scripts/FreeBSD_install_cdrom.conf \ ${.OBJDIR}/dvd/packages/repos/ diff --git a/release/amd64/pkg-stage.conf b/release/amd64/pkg-stage.conf deleted file mode 100755 index 4ea7dc40e807..000000000000 --- a/release/amd64/pkg-stage.conf +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh -# -# $FreeBSD$ -# - -export PKG_ABI="freebsd:${REVISION%.[0-9]*}:x86:64" -export ASSUME_ALWAYS_YES=1 -export __PKG_CONF="/etc/pkg/FreeBSD.conf" -export PACKAGESITE="http://pkg.FreeBSD.org/${PKG_ABI}/latest" -export MIRROR_TYPE="SRV" -export REPO_AUTOUPDATE="NO" -export PKG_DBDIR="/tmp/pkg" -export PKG_CACHEDIR="dvd/packages/${PKG_ABI}" -export PERMISSIVE="YES" -export PKGCMD="/usr/sbin/pkg -d -C ${__PKG_CONF}" - -DVD_PACKAGES="archivers/unzip -devel/subversion -devel/subversion-static -emulators/linux_base-f10 -misc/freebsd-doc-all -net/mpd5 -net/rsync -ports-mgmt/pkg -ports-mgmt/portaudit -ports-mgmt/portmaster -shells/bash -shells/zsh -security/sudo -sysutils/screen -www/firefox -www/links -x11-drivers/xf86-video-vmware -x11/gnome2 -x11/kde4 -x11/xorg" diff --git a/release/doc/en_US.ISO8859-1/errata/article.xml b/release/doc/en_US.ISO8859-1/errata/article.xml index cad6fc7034b8..8fab95d92f16 100644 --- a/release/doc/en_US.ISO8859-1/errata/article.xml +++ b/release/doc/en_US.ISO8859-1/errata/article.xml @@ -1,45 +1,24 @@ + "http://www.FreeBSD.org/XML/share/xml/freebsd50.dtd" [ + %release; ]> - -
- &os; &release; Errata - - - - The &os; Project - + The &os; Project $FreeBSD$ - 2000 - 2001 - 2002 - 2003 - 2004 - 2005 - 2006 - 2007 - 2008 - 2009 - 2010 - 2011 - 2012 - 2013 + 2014 + The &os; Documentation Project @@ -50,20 +29,20 @@ &tm-attrib.general; - - This document lists errata items for &os; &release;, - containing significant information discovered after the release - or too late in the release cycle to be otherwise included in the - release documentation. - This information includes security advisories, as well as news - relating to the software or documentation that could affect its - operation or usability. An up-to-date version of this document - should always be consulted before installing this version of - &os;. + + This document lists errata items for &os; &release;, + containing significant information discovered after the release + or too late in the release cycle to be otherwise included in the + release documentation. + This information includes security advisories, as well as news + relating to the software or documentation that could affect its + operation or usability. An up-to-date version of this document + should always be consulted before installing this version of + &os;. - This errata document for &os; &release; - will be maintained until the release of &os; &release.next;. - + This errata document for &os; &release; + will be maintained until the release of &os; &release.next;. + @@ -80,44 +59,35 @@ out of date by definition, but other copies are kept updated on the Internet and should be consulted as the current errata for this release. These other copies of the - errata are located at http://www.FreeBSD.org/releases/, plus any sites + errata are located at + , + plus any sites which keep up-to-date mirrors of this location. Source and binary snapshots of &os; &release.branch; also contain up-to-date copies of this document (as of the time of the snapshot). - For a list of all &os; CERT security advisories, see http://www.FreeBSD.org/security/ or ftp://ftp.FreeBSD.org/pub/FreeBSD/CERT/. - + For a list of all &os; CERT security advisories, see + + or . Security Advisories - No advisories. - - No advisories. - - No advisories. + No advisory. Open Issues - No open issues. - - No open issues. - - No open issues. + No open issues. Late-Breaking News - No news. - - No news. - - No news. + No news.
diff --git a/release/doc/en_US.ISO8859-1/relnotes/article.xml b/release/doc/en_US.ISO8859-1/relnotes/article.xml index 1092590c8e89..e522a9d8bdd8 100644 --- a/release/doc/en_US.ISO8859-1/relnotes/article.xml +++ b/release/doc/en_US.ISO8859-1/relnotes/article.xml @@ -723,14 +723,13 @@ hv_vmbus_load="YES" Alternatively, the Hyper-V drivers can be Upgrading from previous releases of &os; - Beginning with &os; 6.2-RELEASE, - binary upgrades between RELEASE versions (and snapshots of the - various security branches) are supported using the - &man.freebsd-update.8; utility. The binary upgrade procedure will - update unmodified userland utilities, as well as unmodified GENERIC or - SMP kernels distributed as a part of an official &os; release. - The &man.freebsd-update.8; utility requires that the host being - upgraded have Internet connectivity. + Binary upgrades between RELEASE versions + (and snapshots of the various security branches) are supported + using the &man.freebsd-update.8; utility. The binary upgrade + procedure will update unmodified userland utilities, as well as + unmodified GENERIC kernels distributed as a part of an official + &os; release. The &man.freebsd-update.8; utility requires that + the host being upgraded have Internet connectivity. Source-based upgrades (those based on recompiling the &os; base system from source code) from previous versions are @@ -738,7 +737,7 @@ hv_vmbus_load="YES" Alternatively, the Hyper-V drivers can be /usr/src/UPDATING. - Upgrading &os; should, of course, only be attempted after + Upgrading &os; should only be attempted after backing up all data and configuration files. diff --git a/release/i386/pkg-stage.conf b/release/i386/pkg-stage.conf deleted file mode 100755 index 6d9e8efdd373..000000000000 --- a/release/i386/pkg-stage.conf +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh -# -# $FreeBSD$ -# - -export PKG_ABI="freebsd:${REVISION%.[0-9]*}:x86:32" -export ASSUME_ALWAYS_YES=1 -export __PKG_CONF="/etc/pkg/FreeBSD.conf" -export PACKAGESITE="http://pkg.FreeBSD.org/${PKG_ABI}/latest" -export MIRROR_TYPE="SRV" -export REPO_AUTOUPDATE="NO" -export PKG_DBDIR="/tmp/pkg" -export PKG_CACHEDIR="dvd/packages/${PKG_ABI}" -export PERMISSIVE="YES" -export PKGCMD="/usr/sbin/pkg -d -C ${__PKG_CONF}" - -DVD_PACKAGES="archivers/unzip -devel/subversion -devel/subversion-static -emulators/linux_base-f10 -misc/freebsd-doc-all -net/mpd5 -net/rsync -ports-mgmt/pkg -ports-mgmt/portaudit -ports-mgmt/portmaster -shells/bash -shells/zsh -security/sudo -sysutils/screen -www/firefox -www/links -x11-drivers/xf86-video-vmware -x11/gnome2 -x11/kde4 -x11/xorg" diff --git a/release/pkg_repos/release-dvd.conf b/release/pkg_repos/release-dvd.conf new file mode 100644 index 000000000000..95413592b719 --- /dev/null +++ b/release/pkg_repos/release-dvd.conf @@ -0,0 +1,8 @@ +# $FreeBSD$ +release: { + url: "pkg+http://pkg.FreeBSD.org/${ABI}/latest", + mirror_type: "srv", + signature_type: "fingerprints", + fingerprints: "/usr/share/keys/pkg", + enabled: yes +} diff --git a/release/scripts/pkg-stage.sh b/release/scripts/pkg-stage.sh index 3781f776656a..2281435aff45 100755 --- a/release/scripts/pkg-stage.sh +++ b/release/scripts/pkg-stage.sh @@ -5,24 +5,31 @@ set -e -usage() { - echo "$(basename ${0}) /path/to/pkg-stage.conf revision" - exit 1 -} +export ASSUME_ALWAYS_YES=1 +export PKG_DBDIR="/tmp/pkg" +export PERMISSIVE="YES" +export REPO_AUTOUPDATE="NO" +export PKGCMD="/usr/sbin/pkg -d" -if [ ! -e "${1}" ]; then - echo "Configuration file not specified." - echo - usage -fi - -if [ "$#" -lt 2 ]; then - usage -fi - -# Source config file for this architecture. -REVISION="${2}" -. "${1}" || exit 1 +DVD_PACKAGES="archivers/unzip +devel/subversion +devel/subversion-static +emulators/linux_base-f10 +misc/freebsd-doc-all +net/mpd5 +net/rsync +ports-mgmt/pkg +ports-mgmt/portmaster +shells/bash +shells/zsh +security/sudo +sysutils/screen +www/firefox +www/links +x11-drivers/xf86-video-vmware +x11/gnome2 +x11/kde4 +x11/xorg" # If NOPORTS is set for the release, do not attempt to build pkg(8). if [ ! -f /usr/ports/Makefile ]; then @@ -33,8 +40,13 @@ if [ ! -x /usr/local/sbin/pkg ]; then /usr/bin/make -C /usr/ports/ports-mgmt/pkg install clean fi +export PKG_ABI=$(pkg -vv | grep ^ABI | awk '{print $3}') +export PKG_CACHEDIR="dvd/packages/${PKG_ABI}" + /bin/mkdir -p ${PKG_CACHEDIR} +# Print pkg(8) information to make debugging easier. +${PKGCMD} -vv ${PKGCMD} update -f ${PKGCMD} fetch -d ${DVD_PACKAGES} diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index 3d5fd1208078..edfb41df3ecd 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -543,6 +543,7 @@ MAN= aac.4 \ ${_virtio.4} \ ${_virtio_balloon.4} \ ${_virtio_blk.4} \ + ${_virtio_random.4} \ ${_virtio_scsi.4} \ vkbd.4 \ vlan.4 \ @@ -787,6 +788,7 @@ _nxge.4= nxge.4 _virtio.4= virtio.4 _virtio_balloon.4=virtio_balloon.4 _virtio_blk.4= virtio_blk.4 +_virtio_random.4= virtio_random.4 _virtio_scsi.4= virtio_scsi.4 _vmx.4= vmx.4 _vtnet.4= vtnet.4 diff --git a/share/man/man4/virtio_random.4 b/share/man/man4/virtio_random.4 new file mode 100644 index 000000000000..a20e868d7441 --- /dev/null +++ b/share/man/man4/virtio_random.4 @@ -0,0 +1,61 @@ +.\" Copyright (c) 2013 Bryan Venteicher +.\" 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$ +.\" +.Dd December 28, 2013 +.Dt VIRTIO_RANDOM 4 +.Os +.Sh NAME +.Nm virtio_random +.Nd VirtIO Entropy driver +.Sh SYNOPSIS +To compile this driver into the kernel, +place the following lines in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device virtio_random" +.Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +virtio_random_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +device driver provides support for VirtIO entropy devices. +.Pp +The entropy device supplies high-quality randomness from the +hypervisor to the guest. +.Sh SEE ALSO +.Xr random 4 +.Xr virtio 4 +.Sh HISTORY +The +.Nm +driver was written by +.An Bryan Venteicher Aq bryanv@FreeBSD.org . diff --git a/share/man/man9/malloc.9 b/share/man/man9/malloc.9 index 9653b5827cdc..07fb7581d9bb 100644 --- a/share/man/man9/malloc.9 +++ b/share/man/man9/malloc.9 @@ -29,7 +29,7 @@ .\" $NetBSD: malloc.9,v 1.3 1996/11/11 00:05:11 lukem Exp $ .\" $FreeBSD$ .\" -.Dd November 15, 2012 +.Dd January 16, 2014 .Dt MALLOC 9 .Os .Sh NAME @@ -214,17 +214,6 @@ of two for requests up to the size of a page of memory. For larger requests, one or more pages is allocated. While it should not be relied upon, this information may be useful for optimizing the efficiency of memory use. -.Pp -Programmers should be careful not to confuse the malloc flags -.Dv M_NOWAIT -and -.Dv M_WAITOK -with the -.Xr mbuf 9 -flags -.Dv M_DONTWAIT -and -.Dv M_WAIT . .Sh CONTEXT .Fn malloc , .Fn realloc diff --git a/share/man/man9/mbuf.9 b/share/man/man9/mbuf.9 index eae17afa1576..4df1d6ab704d 100644 --- a/share/man/man9/mbuf.9 +++ b/share/man/man9/mbuf.9 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd December 20, 2013 +.Dd January 16, 2014 .Dt MBUF 9 .Os .\" @@ -381,17 +381,6 @@ A number of other functions and macros related to have the same argument because they may at some point need to allocate new .Vt mbufs . -.Pp -Historical -.Vt mbuf -allocator (See -.Sx HISTORY -section) used allocation flags -.Dv M_WAIT -and -.Dv M_DONTWAIT . -These constants are kept for compatibility -and their use in new code is discouraged. .It Fn MGETHDR mbuf how type Allocate an .Vt mbuf diff --git a/share/mk/bsd.libnames.mk b/share/mk/bsd.libnames.mk index 4f32e590fd6f..bca4f5e86c16 100644 --- a/share/mk/bsd.libnames.mk +++ b/share/mk/bsd.libnames.mk @@ -36,6 +36,7 @@ LIBCAPSICUM?= ${DESTDIR}${LIBDIR}/libcapsicum.a LIBCASPER?= ${DESTDIR}${LIBDIR}/libcasper.a LIBCOM_ERR?= ${DESTDIR}${LIBDIR}/libcom_err.a LIBCOMPAT?= ${DESTDIR}${LIBDIR}/libcompat.a +LIBCOMPILER_RT?=${DESTDIR}${LIBDIR}/libcompiler_rt.a LIBCRYPT?= ${DESTDIR}${LIBDIR}/libcrypt.a LIBCRYPTO?= ${DESTDIR}${LIBDIR}/libcrypto.a LIBCTF?= ${DESTDIR}${LIBDIR}/libctf.a @@ -53,8 +54,6 @@ LIBFETCH?= ${DESTDIR}${LIBDIR}/libfetch.a LIBFL?= "don't use LIBFL, use LIBL" LIBFORM?= ${DESTDIR}${LIBDIR}/libform.a LIBG2C?= ${DESTDIR}${LIBDIR}/libg2c.a -LIBGCC?= ${DESTDIR}${LIBDIR}/libgcc.a -LIBGCC_PIC?= ${DESTDIR}${LIBDIR}/libgcc_pic.a LIBGEOM?= ${DESTDIR}${LIBDIR}/libgeom.a LIBGNUREGEX?= ${DESTDIR}${LIBDIR}/libgnuregex.a LIBGSSAPI?= ${DESTDIR}${LIBDIR}/libgssapi.a diff --git a/sys/amd64/conf/NOTES b/sys/amd64/conf/NOTES index 28d68c816317..9333c1b51239 100644 --- a/sys/amd64/conf/NOTES +++ b/sys/amd64/conf/NOTES @@ -472,6 +472,7 @@ device vtnet # VirtIO Ethernet device device virtio_blk # VirtIO Block device device virtio_scsi # VirtIO SCSI device device virtio_balloon # VirtIO Memory Balloon device +device virtio_random # VirtIO Entropy device device hyperv # HyperV drivers diff --git a/sys/amd64/conf/VT b/sys/amd64/conf/VT new file mode 100644 index 000000000000..7d0547f11456 --- /dev/null +++ b/sys/amd64/conf/VT @@ -0,0 +1,14 @@ +# VT -- kernel config using the vt(9) system console instead of legacy syscons +# +# For more information see https://wiki.freebsd.org/Newcons +# +# $FreeBSD$ + +include GENERIC +ident VT + +nodevice sc +nodevice vga + +device vt +device vt_vga diff --git a/sys/amd64/vmm/intel/vmcs.h b/sys/amd64/vmm/intel/vmcs.h index fde93e522674..8c8231cd24d3 100644 --- a/sys/amd64/vmm/intel/vmcs.h +++ b/sys/amd64/vmm/intel/vmcs.h @@ -330,13 +330,19 @@ vmcs_write(uint32_t encoding, uint64_t val) #define EXIT_REASON_XSETBV 55 #define EXIT_REASON_APIC_WRITE 56 +/* + * NMI unblocking due to IRET. + * + * Applies to VM-exits due to hardware exception or EPT fault. + */ +#define EXIT_QUAL_NMIUDTI (1 << 12) /* * VMCS interrupt information fields */ -#define VMCS_INTR_INFO_VALID (1U << 31) -#define VMCS_INTR_INFO_TYPE(info) (((info) >> 8) & 0x7) -#define VMCS_INTR_INFO_HW_INTR (0 << 8) -#define VMCS_INTR_INFO_NMI (2 << 8) +#define VMCS_INTR_VALID (1U << 31) +#define VMCS_INTR_T_MASK 0x700 /* Interruption-info type */ +#define VMCS_INTR_T_HWINTR (0 << 8) +#define VMCS_INTR_T_NMI (2 << 8) /* * VMCS IDT-Vectoring information fields diff --git a/sys/amd64/vmm/intel/vmx.c b/sys/amd64/vmm/intel/vmx.c index a4e0a851e982..f7a2e5e9a546 100644 --- a/sys/amd64/vmm/intel/vmx.c +++ b/sys/amd64/vmm/intel/vmx.c @@ -146,21 +146,6 @@ static int vmx_initialized; SYSCTL_INT(_hw_vmm_vmx, OID_AUTO, initialized, CTLFLAG_RD, &vmx_initialized, 0, "Intel VMX initialized"); -/* - * Virtual NMI blocking conditions. - * - * Some processor implementations also require NMI to be blocked if - * the STI_BLOCKING bit is set. It is possible to detect this at runtime - * based on the (exit_reason,exit_qual) tuple being set to - * (EXIT_REASON_INVAL_VMCS, EXIT_QUAL_NMI_WHILE_STI_BLOCKING). - * - * We take the easy way out and also include STI_BLOCKING as one of the - * gating items for vNMI injection. - */ -static uint64_t nmi_blocking_bits = VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING | - VMCS_INTERRUPTIBILITY_NMI_BLOCKING | - VMCS_INTERRUPTIBILITY_STI_BLOCKING; - /* * Optional capabilities */ @@ -1020,121 +1005,149 @@ static void __inline vmx_set_int_window_exiting(struct vmx *vmx, int vcpu) { - vmx->cap[vcpu].proc_ctls |= PROCBASED_INT_WINDOW_EXITING; - vmcs_write(VMCS_PRI_PROC_BASED_CTLS, vmx->cap[vcpu].proc_ctls); + if ((vmx->cap[vcpu].proc_ctls & PROCBASED_INT_WINDOW_EXITING) == 0) { + vmx->cap[vcpu].proc_ctls |= PROCBASED_INT_WINDOW_EXITING; + vmcs_write(VMCS_PRI_PROC_BASED_CTLS, vmx->cap[vcpu].proc_ctls); + VCPU_CTR0(vmx->vm, vcpu, "Enabling interrupt window exiting"); + } } static void __inline vmx_clear_int_window_exiting(struct vmx *vmx, int vcpu) { + KASSERT((vmx->cap[vcpu].proc_ctls & PROCBASED_INT_WINDOW_EXITING) != 0, + ("intr_window_exiting not set: %#x", vmx->cap[vcpu].proc_ctls)); vmx->cap[vcpu].proc_ctls &= ~PROCBASED_INT_WINDOW_EXITING; vmcs_write(VMCS_PRI_PROC_BASED_CTLS, vmx->cap[vcpu].proc_ctls); + VCPU_CTR0(vmx->vm, vcpu, "Disabling interrupt window exiting"); } static void __inline vmx_set_nmi_window_exiting(struct vmx *vmx, int vcpu) { - vmx->cap[vcpu].proc_ctls |= PROCBASED_NMI_WINDOW_EXITING; - vmcs_write(VMCS_PRI_PROC_BASED_CTLS, vmx->cap[vcpu].proc_ctls); + if ((vmx->cap[vcpu].proc_ctls & PROCBASED_NMI_WINDOW_EXITING) == 0) { + vmx->cap[vcpu].proc_ctls |= PROCBASED_NMI_WINDOW_EXITING; + vmcs_write(VMCS_PRI_PROC_BASED_CTLS, vmx->cap[vcpu].proc_ctls); + VCPU_CTR0(vmx->vm, vcpu, "Enabling NMI window exiting"); + } } static void __inline vmx_clear_nmi_window_exiting(struct vmx *vmx, int vcpu) { + KASSERT((vmx->cap[vcpu].proc_ctls & PROCBASED_NMI_WINDOW_EXITING) != 0, + ("nmi_window_exiting not set %#x", vmx->cap[vcpu].proc_ctls)); vmx->cap[vcpu].proc_ctls &= ~PROCBASED_NMI_WINDOW_EXITING; vmcs_write(VMCS_PRI_PROC_BASED_CTLS, vmx->cap[vcpu].proc_ctls); + VCPU_CTR0(vmx->vm, vcpu, "Disabling NMI window exiting"); } -static int +#define NMI_BLOCKING (VMCS_INTERRUPTIBILITY_NMI_BLOCKING | \ + VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING) +#define HWINTR_BLOCKING (VMCS_INTERRUPTIBILITY_STI_BLOCKING | \ + VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING) + +static void vmx_inject_nmi(struct vmx *vmx, int vcpu) { - uint64_t info, interruptibility; + uint32_t gi, info; - /* Bail out if no NMI requested */ - if (!vm_nmi_pending(vmx->vm, vcpu)) - return (0); + gi = vmcs_read(VMCS_GUEST_INTERRUPTIBILITY); + KASSERT((gi & NMI_BLOCKING) == 0, ("vmx_inject_nmi: invalid guest " + "interruptibility-state %#x", gi)); - interruptibility = vmcs_read(VMCS_GUEST_INTERRUPTIBILITY); - if (interruptibility & nmi_blocking_bits) - goto nmiblocked; + info = vmcs_read(VMCS_ENTRY_INTR_INFO); + KASSERT((info & VMCS_INTR_VALID) == 0, ("vmx_inject_nmi: invalid " + "VM-entry interruption information %#x", info)); /* * Inject the virtual NMI. The vector must be the NMI IDT entry * or the VMCS entry check will fail. */ - info = VMCS_INTR_INFO_NMI | VMCS_INTR_INFO_VALID; - info |= IDT_NMI; + info = IDT_NMI | VMCS_INTR_T_NMI | VMCS_INTR_VALID; vmcs_write(VMCS_ENTRY_INTR_INFO, info); VCPU_CTR0(vmx->vm, vcpu, "Injecting vNMI"); /* Clear the request */ vm_nmi_clear(vmx->vm, vcpu); - return (1); - -nmiblocked: - /* - * Set the NMI Window Exiting execution control so we can inject - * the virtual NMI as soon as blocking condition goes away. - */ - vmx_set_nmi_window_exiting(vmx, vcpu); - - VCPU_CTR0(vmx->vm, vcpu, "Enabling NMI window exiting"); - return (1); } static void vmx_inject_interrupts(struct vmx *vmx, int vcpu, struct vlapic *vlapic) { - int vector; - uint64_t info, rflags, interruptibility; + int vector, need_nmi_exiting; + uint64_t rflags; + uint32_t gi, info; - const int HWINTR_BLOCKED = VMCS_INTERRUPTIBILITY_STI_BLOCKING | - VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING; + if (vm_nmi_pending(vmx->vm, vcpu)) { + /* + * If there are no conditions blocking NMI injection then + * inject it directly here otherwise enable "NMI window + * exiting" to inject it as soon as we can. + * + * We also check for STI_BLOCKING because some implementations + * don't allow NMI injection in this case. If we are running + * on a processor that doesn't have this restriction it will + * immediately exit and the NMI will be injected in the + * "NMI window exiting" handler. + */ + need_nmi_exiting = 1; + gi = vmcs_read(VMCS_GUEST_INTERRUPTIBILITY); + if ((gi & (HWINTR_BLOCKING | NMI_BLOCKING)) == 0) { + info = vmcs_read(VMCS_ENTRY_INTR_INFO); + if ((info & VMCS_INTR_VALID) == 0) { + vmx_inject_nmi(vmx, vcpu); + need_nmi_exiting = 0; + } else { + VCPU_CTR1(vmx->vm, vcpu, "Cannot inject NMI " + "due to VM-entry intr info %#x", info); + } + } else { + VCPU_CTR1(vmx->vm, vcpu, "Cannot inject NMI due to " + "Guest Interruptibility-state %#x", gi); + } - /* - * If there is already an interrupt pending then just return. - * - * This could happen if an interrupt was injected on a prior - * VM entry but the actual entry into guest mode was aborted - * because of a pending AST. - */ - info = vmcs_read(VMCS_ENTRY_INTR_INFO); - if (info & VMCS_INTR_INFO_VALID) - return; - - /* - * NMI injection has priority so deal with those first - */ - if (vmx_inject_nmi(vmx, vcpu)) - return; + if (need_nmi_exiting) + vmx_set_nmi_window_exiting(vmx, vcpu); + } if (virtual_interrupt_delivery) { vmx_inject_pir(vlapic); return; } + /* + * If there is already an interrupt pending then just return. This + * could happen for multiple reasons: + * - A vectoring VM-entry was aborted due to astpending or rendezvous. + * - A VM-exit happened during event injection. + * - A NMI was injected above or after "NMI window exiting" VM-exit. + */ + info = vmcs_read(VMCS_ENTRY_INTR_INFO); + if (info & VMCS_INTR_VALID) + return; + /* Ask the local apic for a vector to inject */ if (!vlapic_pending_intr(vlapic, &vector)) return; - if (vector < 32 || vector > 255) - panic("vmx_inject_interrupts: invalid vector %d\n", vector); + KASSERT(vector >= 32 && vector <= 255, ("invalid vector %d", vector)); /* Check RFLAGS.IF and the interruptibility state of the guest */ rflags = vmcs_read(VMCS_GUEST_RFLAGS); if ((rflags & PSL_I) == 0) goto cantinject; - interruptibility = vmcs_read(VMCS_GUEST_INTERRUPTIBILITY); - if (interruptibility & HWINTR_BLOCKED) + gi = vmcs_read(VMCS_GUEST_INTERRUPTIBILITY); + if (gi & HWINTR_BLOCKING) goto cantinject; /* Inject the interrupt */ - info = VMCS_INTR_INFO_HW_INTR | VMCS_INTR_INFO_VALID; + info = VMCS_INTR_T_HWINTR | VMCS_INTR_VALID; info |= vector; vmcs_write(VMCS_ENTRY_INTR_INFO, info); @@ -1151,8 +1164,37 @@ vmx_inject_interrupts(struct vmx *vmx, int vcpu, struct vlapic *vlapic) * the interrupt as soon as blocking condition goes away. */ vmx_set_int_window_exiting(vmx, vcpu); +} - VCPU_CTR0(vmx->vm, vcpu, "Enabling interrupt window exiting"); +/* + * If the Virtual NMIs execution control is '1' then the logical processor + * tracks virtual-NMI blocking in the Guest Interruptibility-state field of + * the VMCS. An IRET instruction in VMX non-root operation will remove any + * virtual-NMI blocking. + * + * This unblocking occurs even if the IRET causes a fault. In this case the + * hypervisor needs to restore virtual-NMI blocking before resuming the guest. + */ +static void +vmx_restore_nmi_blocking(struct vmx *vmx, int vcpuid) +{ + uint32_t gi; + + VCPU_CTR0(vmx->vm, vcpuid, "Restore Virtual-NMI blocking"); + gi = vmcs_read(VMCS_GUEST_INTERRUPTIBILITY); + gi |= VMCS_INTERRUPTIBILITY_NMI_BLOCKING; + vmcs_write(VMCS_GUEST_INTERRUPTIBILITY, gi); +} + +static void +vmx_clear_nmi_blocking(struct vmx *vmx, int vcpuid) +{ + uint32_t gi; + + VCPU_CTR0(vmx->vm, vcpuid, "Clear Virtual-NMI blocking"); + gi = vmcs_read(VMCS_GUEST_INTERRUPTIBILITY); + gi &= ~VMCS_INTERRUPTIBILITY_NMI_BLOCKING; + vmcs_write(VMCS_GUEST_INTERRUPTIBILITY, gi); } static int @@ -1448,6 +1490,8 @@ vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit) uint64_t qual, gpa; bool retu; + CTASSERT((PINBASED_CTLS_ONE_SETTING & PINBASED_VIRTUAL_NMI) != 0); + handled = 0; vmxctx = &vmx->ctx[vcpu]; @@ -1480,9 +1524,20 @@ vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit) vmcs_write(VMCS_ENTRY_EXCEPTION_ERROR, idtvec_err); } + /* + * If 'virtual NMIs' are being used and the VM-exit + * happened while injecting an NMI during the previous + * VM-entry, then clear "blocking by NMI" in the Guest + * Interruptibility-state. + */ + if ((idtvec_info & VMCS_INTR_T_MASK) == + VMCS_INTR_T_NMI) { + vmx_clear_nmi_blocking(vmx, vcpu); + } vmcs_write(VMCS_ENTRY_INST_LENGTH, vmexit->inst_length); } default: + idtvec_info = 0; break; } @@ -1543,7 +1598,6 @@ vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit) case EXIT_REASON_INTR_WINDOW: vmm_stat_incr(vmx->vm, vcpu, VMEXIT_INTR_WINDOW, 1); vmx_clear_int_window_exiting(vmx, vcpu); - VCPU_CTR0(vmx->vm, vcpu, "Disabling interrupt window exiting"); return (1); case EXIT_REASON_EXT_INTR: /* @@ -1556,8 +1610,8 @@ vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit) * this virtual interrupt during the subsequent VM enter. */ intr_info = vmcs_read(VMCS_EXIT_INTR_INFO); - KASSERT((intr_info & VMCS_INTR_INFO_VALID) != 0 && - VMCS_INTR_INFO_TYPE(intr_info) == 0, + KASSERT((intr_info & VMCS_INTR_VALID) != 0 && + (intr_info & VMCS_INTR_T_MASK) == VMCS_INTR_T_HWINTR, ("VM exit interruption info invalid: %#x", intr_info)); vmx_trigger_hostintr(intr_info & 0xff); @@ -1569,9 +1623,10 @@ vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit) return (1); case EXIT_REASON_NMI_WINDOW: /* Exit to allow the pending virtual NMI to be injected */ - vmm_stat_incr(vmx->vm, vcpu, VMEXIT_NMI_WINDOW, 1); + if (vm_nmi_pending(vmx->vm, vcpu)) + vmx_inject_nmi(vmx, vcpu); vmx_clear_nmi_window_exiting(vmx, vcpu); - VCPU_CTR0(vmx->vm, vcpu, "Disabling NMI window exiting"); + vmm_stat_incr(vmx->vm, vcpu, VMEXIT_NMI_WINDOW, 1); return (1); case EXIT_REASON_INOUT: vmm_stat_incr(vmx->vm, vcpu, VMEXIT_INOUT, 1); @@ -1587,6 +1642,23 @@ vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit) vmm_stat_incr(vmx->vm, vcpu, VMEXIT_CPUID, 1); handled = vmx_handle_cpuid(vmx->vm, vcpu, vmxctx); break; + case EXIT_REASON_EXCEPTION: + intr_info = vmcs_read(VMCS_EXIT_INTR_INFO); + KASSERT((intr_info & VMCS_INTR_VALID) != 0, + ("VM exit interruption info invalid: %#x", intr_info)); + /* + * If Virtual NMIs control is 1 and the VM-exit is due to a + * fault encountered during the execution of IRET then we must + * restore the state of "virtual-NMI blocking" before resuming + * the guest. + * + * See "Resuming Guest Software after Handling an Exception". + */ + if ((idtvec_info & VMCS_IDT_VEC_VALID) == 0 && + (intr_info & 0xff) != IDT_DF && + (intr_info & EXIT_QUAL_NMIUDTI) != 0) + vmx_restore_nmi_blocking(vmx, vcpu); + break; case EXIT_REASON_EPT_FAULT: vmm_stat_incr(vmx->vm, vcpu, VMEXIT_EPT_FAULT, 1); /* @@ -1605,6 +1677,17 @@ vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit) vmexit->u.inst_emul.gla = vmcs_gla(); vmexit->u.inst_emul.cr3 = vmcs_guest_cr3(); } + /* + * If Virtual NMIs control is 1 and the VM-exit is due to an + * EPT fault during the execution of IRET then we must restore + * the state of "virtual-NMI blocking" before resuming. + * + * See description of "NMI unblocking due to IRET" in + * "Exit Qualification for EPT Violations". + */ + if ((idtvec_info & VMCS_IDT_VEC_VALID) == 0 && + (qual & EXIT_QUAL_NMIUDTI) != 0) + vmx_restore_nmi_blocking(vmx, vcpu); break; case EXIT_REASON_APIC_ACCESS: handled = vmx_handle_apic_access(vmx, vcpu, vmexit); @@ -2039,11 +2122,11 @@ vmx_inject(void *arg, int vcpu, int type, int vector, uint32_t code, if (error) return (error); - if (info & VMCS_INTR_INFO_VALID) + if (info & VMCS_INTR_VALID) return (EAGAIN); info = vector | (type_map[type] << 8) | (code_valid ? 1 << 11 : 0); - info |= VMCS_INTR_INFO_VALID; + info |= VMCS_INTR_VALID; error = vmcs_setreg(vmcs, 0, VMCS_IDENT(VMCS_ENTRY_INTR_INFO), info); if (error != 0) return (error); diff --git a/sys/arm/at91/at91_gpio.h b/sys/arm/at91/at91_gpio.h new file mode 100644 index 000000000000..935e43733e2b --- /dev/null +++ b/sys/arm/at91/at91_gpio.h @@ -0,0 +1,296 @@ +/*- + * Copyright (c) 2014 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 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 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 ARM_AT91_AT91_GPIO_H +#define ARM_AT91_AT91_GPIO_H + +typedef uint32_t at91_pin_t; + +#define AT91_PIN_NONE 0xfffffffful /* No pin / Not GPIO controlled */ + +/* + * Map Atmel PIO pins to a unique number. They are just numbered sequentially. + */ + +#define AT91_PIN_PA0 (at91_pin_t)0 +#define AT91_PIN_PA1 (at91_pin_t)1 +#define AT91_PIN_PA2 (at91_pin_t)2 +#define AT91_PIN_PA3 (at91_pin_t)3 +#define AT91_PIN_PA4 (at91_pin_t)4 +#define AT91_PIN_PA5 (at91_pin_t)5 +#define AT91_PIN_PA6 (at91_pin_t)6 +#define AT91_PIN_PA7 (at91_pin_t)7 +#define AT91_PIN_PA8 (at91_pin_t)8 +#define AT91_PIN_PA9 (at91_pin_t)9 +#define AT91_PIN_PA10 (at91_pin_t)10 +#define AT91_PIN_PA11 (at91_pin_t)11 +#define AT91_PIN_PA12 (at91_pin_t)12 +#define AT91_PIN_PA13 (at91_pin_t)13 +#define AT91_PIN_PA14 (at91_pin_t)14 +#define AT91_PIN_PA15 (at91_pin_t)15 +#define AT91_PIN_PA16 (at91_pin_t)16 +#define AT91_PIN_PA17 (at91_pin_t)17 +#define AT91_PIN_PA18 (at91_pin_t)18 +#define AT91_PIN_PA19 (at91_pin_t)19 +#define AT91_PIN_PA20 (at91_pin_t)20 +#define AT91_PIN_PA21 (at91_pin_t)21 +#define AT91_PIN_PA22 (at91_pin_t)22 +#define AT91_PIN_PA23 (at91_pin_t)23 +#define AT91_PIN_PA24 (at91_pin_t)24 +#define AT91_PIN_PA25 (at91_pin_t)25 +#define AT91_PIN_PA26 (at91_pin_t)26 +#define AT91_PIN_PA27 (at91_pin_t)27 +#define AT91_PIN_PA28 (at91_pin_t)28 +#define AT91_PIN_PA29 (at91_pin_t)29 +#define AT91_PIN_PA30 (at91_pin_t)30 +#define AT91_PIN_PA31 (at91_pin_t)31 +#define AT91_PIN_PB0 (at91_pin_t)32 +#define AT91_PIN_PB1 (at91_pin_t)33 +#define AT91_PIN_PB2 (at91_pin_t)34 +#define AT91_PIN_PB3 (at91_pin_t)35 +#define AT91_PIN_PB4 (at91_pin_t)36 +#define AT91_PIN_PB5 (at91_pin_t)37 +#define AT91_PIN_PB6 (at91_pin_t)38 +#define AT91_PIN_PB7 (at91_pin_t)39 +#define AT91_PIN_PB8 (at91_pin_t)40 +#define AT91_PIN_PB9 (at91_pin_t)41 +#define AT91_PIN_PB10 (at91_pin_t)42 +#define AT91_PIN_PB11 (at91_pin_t)43 +#define AT91_PIN_PB12 (at91_pin_t)44 +#define AT91_PIN_PB13 (at91_pin_t)45 +#define AT91_PIN_PB14 (at91_pin_t)46 +#define AT91_PIN_PB15 (at91_pin_t)47 +#define AT91_PIN_PB16 (at91_pin_t)48 +#define AT91_PIN_PB17 (at91_pin_t)49 +#define AT91_PIN_PB18 (at91_pin_t)50 +#define AT91_PIN_PB19 (at91_pin_t)51 +#define AT91_PIN_PB20 (at91_pin_t)52 +#define AT91_PIN_PB21 (at91_pin_t)53 +#define AT91_PIN_PB22 (at91_pin_t)54 +#define AT91_PIN_PB23 (at91_pin_t)55 +#define AT91_PIN_PB24 (at91_pin_t)56 +#define AT91_PIN_PB25 (at91_pin_t)57 +#define AT91_PIN_PB26 (at91_pin_t)58 +#define AT91_PIN_PB27 (at91_pin_t)59 +#define AT91_PIN_PB28 (at91_pin_t)60 +#define AT91_PIN_PB29 (at91_pin_t)61 +#define AT91_PIN_PB30 (at91_pin_t)62 +#define AT91_PIN_PB31 (at91_pin_t)63 +#define AT91_PIN_PC0 (at91_pin_t)64 +#define AT91_PIN_PC1 (at91_pin_t)65 +#define AT91_PIN_PC2 (at91_pin_t)66 +#define AT91_PIN_PC3 (at91_pin_t)67 +#define AT91_PIN_PC4 (at91_pin_t)68 +#define AT91_PIN_PC5 (at91_pin_t)69 +#define AT91_PIN_PC6 (at91_pin_t)70 +#define AT91_PIN_PC7 (at91_pin_t)71 +#define AT91_PIN_PC8 (at91_pin_t)72 +#define AT91_PIN_PC9 (at91_pin_t)73 +#define AT91_PIN_PC10 (at91_pin_t)74 +#define AT91_PIN_PC11 (at91_pin_t)75 +#define AT91_PIN_PC12 (at91_pin_t)76 +#define AT91_PIN_PC13 (at91_pin_t)77 +#define AT91_PIN_PC14 (at91_pin_t)78 +#define AT91_PIN_PC15 (at91_pin_t)79 +#define AT91_PIN_PC16 (at91_pin_t)80 +#define AT91_PIN_PC17 (at91_pin_t)81 +#define AT91_PIN_PC18 (at91_pin_t)82 +#define AT91_PIN_PC19 (at91_pin_t)83 +#define AT91_PIN_PC20 (at91_pin_t)84 +#define AT91_PIN_PC21 (at91_pin_t)85 +#define AT91_PIN_PC22 (at91_pin_t)86 +#define AT91_PIN_PC23 (at91_pin_t)87 +#define AT91_PIN_PC24 (at91_pin_t)88 +#define AT91_PIN_PC25 (at91_pin_t)89 +#define AT91_PIN_PC26 (at91_pin_t)90 +#define AT91_PIN_PC27 (at91_pin_t)91 +#define AT91_PIN_PC28 (at91_pin_t)92 +#define AT91_PIN_PC29 (at91_pin_t)93 +#define AT91_PIN_PC30 (at91_pin_t)94 +#define AT91_PIN_PC31 (at91_pin_t)95 +#define AT91_PIN_PD0 (at91_pin_t)96 +#define AT91_PIN_PD1 (at91_pin_t)97 +#define AT91_PIN_PD2 (at91_pin_t)98 +#define AT91_PIN_PD3 (at91_pin_t)99 +#define AT91_PIN_PD4 (at91_pin_t)100 +#define AT91_PIN_PD5 (at91_pin_t)101 +#define AT91_PIN_PD6 (at91_pin_t)102 +#define AT91_PIN_PD7 (at91_pin_t)103 +#define AT91_PIN_PD8 (at91_pin_t)104 +#define AT91_PIN_PD9 (at91_pin_t)105 +#define AT91_PIN_PD10 (at91_pin_t)106 +#define AT91_PIN_PD11 (at91_pin_t)107 +#define AT91_PIN_PD12 (at91_pin_t)108 +#define AT91_PIN_PD13 (at91_pin_t)109 +#define AT91_PIN_PD14 (at91_pin_t)110 +#define AT91_PIN_PD15 (at91_pin_t)111 +#define AT91_PIN_PD16 (at91_pin_t)112 +#define AT91_PIN_PD17 (at91_pin_t)113 +#define AT91_PIN_PD18 (at91_pin_t)114 +#define AT91_PIN_PD19 (at91_pin_t)115 +#define AT91_PIN_PD20 (at91_pin_t)116 +#define AT91_PIN_PD21 (at91_pin_t)117 +#define AT91_PIN_PD22 (at91_pin_t)118 +#define AT91_PIN_PD23 (at91_pin_t)119 +#define AT91_PIN_PD24 (at91_pin_t)120 +#define AT91_PIN_PD25 (at91_pin_t)121 +#define AT91_PIN_PD26 (at91_pin_t)122 +#define AT91_PIN_PD27 (at91_pin_t)123 +#define AT91_PIN_PD28 (at91_pin_t)124 +#define AT91_PIN_PD29 (at91_pin_t)125 +#define AT91_PIN_PD30 (at91_pin_t)126 +#define AT91_PIN_PD31 (at91_pin_t)127 +#define AT91_PIN_PE0 (at91_pin_t)128 +#define AT91_PIN_PE1 (at91_pin_t)129 +#define AT91_PIN_PE2 (at91_pin_t)130 +#define AT91_PIN_PE3 (at91_pin_t)131 +#define AT91_PIN_PE4 (at91_pin_t)132 +#define AT91_PIN_PE5 (at91_pin_t)133 +#define AT91_PIN_PE6 (at91_pin_t)134 +#define AT91_PIN_PE7 (at91_pin_t)135 +#define AT91_PIN_PE8 (at91_pin_t)136 +#define AT91_PIN_PE9 (at91_pin_t)137 +#define AT91_PIN_PE10 (at91_pin_t)138 +#define AT91_PIN_PE11 (at91_pin_t)139 +#define AT91_PIN_PE12 (at91_pin_t)140 +#define AT91_PIN_PE13 (at91_pin_t)141 +#define AT91_PIN_PE14 (at91_pin_t)142 +#define AT91_PIN_PE15 (at91_pin_t)143 +#define AT91_PIN_PE16 (at91_pin_t)144 +#define AT91_PIN_PE17 (at91_pin_t)145 +#define AT91_PIN_PE18 (at91_pin_t)146 +#define AT91_PIN_PE19 (at91_pin_t)147 +#define AT91_PIN_PE20 (at91_pin_t)148 +#define AT91_PIN_PE21 (at91_pin_t)149 +#define AT91_PIN_PE22 (at91_pin_t)150 +#define AT91_PIN_PE23 (at91_pin_t)151 +#define AT91_PIN_PE24 (at91_pin_t)152 +#define AT91_PIN_PE25 (at91_pin_t)153 +#define AT91_PIN_PE26 (at91_pin_t)154 +#define AT91_PIN_PE27 (at91_pin_t)155 +#define AT91_PIN_PE28 (at91_pin_t)156 +#define AT91_PIN_PE29 (at91_pin_t)157 +#define AT91_PIN_PE30 (at91_pin_t)158 +#define AT91_PIN_PE31 (at91_pin_t)159 +#define AT91_PIN_PF0 (at91_pin_t)160 +#define AT91_PIN_PF1 (at91_pin_t)161 +#define AT91_PIN_PF2 (at91_pin_t)162 +#define AT91_PIN_PF3 (at91_pin_t)163 +#define AT91_PIN_PF4 (at91_pin_t)164 +#define AT91_PIN_PF5 (at91_pin_t)165 +#define AT91_PIN_PF6 (at91_pin_t)166 +#define AT91_PIN_PF7 (at91_pin_t)167 +#define AT91_PIN_PF8 (at91_pin_t)168 +#define AT91_PIN_PF9 (at91_pin_t)169 +#define AT91_PIN_PF10 (at91_pin_t)170 +#define AT91_PIN_PF11 (at91_pin_t)171 +#define AT91_PIN_PF12 (at91_pin_t)172 +#define AT91_PIN_PF13 (at91_pin_t)173 +#define AT91_PIN_PF14 (at91_pin_t)174 +#define AT91_PIN_PF15 (at91_pin_t)175 +#define AT91_PIN_PF16 (at91_pin_t)176 +#define AT91_PIN_PF17 (at91_pin_t)177 +#define AT91_PIN_PF18 (at91_pin_t)178 +#define AT91_PIN_PF19 (at91_pin_t)179 +#define AT91_PIN_PF20 (at91_pin_t)180 +#define AT91_PIN_PF21 (at91_pin_t)181 +#define AT91_PIN_PF22 (at91_pin_t)182 +#define AT91_PIN_PF23 (at91_pin_t)183 +#define AT91_PIN_PF24 (at91_pin_t)184 +#define AT91_PIN_PF25 (at91_pin_t)185 +#define AT91_PIN_PF26 (at91_pin_t)186 +#define AT91_PIN_PF27 (at91_pin_t)187 +#define AT91_PIN_PF28 (at91_pin_t)188 +#define AT91_PIN_PF29 (at91_pin_t)189 +#define AT91_PIN_PF30 (at91_pin_t)190 +#define AT91_PIN_PF31 (at91_pin_t)191 +#define AT91_PIN_PG0 (at91_pin_t)192 +#define AT91_PIN_PG1 (at91_pin_t)193 +#define AT91_PIN_PG2 (at91_pin_t)194 +#define AT91_PIN_PG3 (at91_pin_t)195 +#define AT91_PIN_PG4 (at91_pin_t)196 +#define AT91_PIN_PG5 (at91_pin_t)197 +#define AT91_PIN_PG6 (at91_pin_t)198 +#define AT91_PIN_PG7 (at91_pin_t)199 +#define AT91_PIN_PG8 (at91_pin_t)200 +#define AT91_PIN_PG9 (at91_pin_t)201 +#define AT91_PIN_PG10 (at91_pin_t)202 +#define AT91_PIN_PG11 (at91_pin_t)203 +#define AT91_PIN_PG12 (at91_pin_t)204 +#define AT91_PIN_PG13 (at91_pin_t)205 +#define AT91_PIN_PG14 (at91_pin_t)206 +#define AT91_PIN_PG15 (at91_pin_t)207 +#define AT91_PIN_PG16 (at91_pin_t)208 +#define AT91_PIN_PG17 (at91_pin_t)209 +#define AT91_PIN_PG18 (at91_pin_t)210 +#define AT91_PIN_PG19 (at91_pin_t)211 +#define AT91_PIN_PG20 (at91_pin_t)212 +#define AT91_PIN_PG21 (at91_pin_t)213 +#define AT91_PIN_PG22 (at91_pin_t)214 +#define AT91_PIN_PG23 (at91_pin_t)215 +#define AT91_PIN_PG24 (at91_pin_t)216 +#define AT91_PIN_PG25 (at91_pin_t)217 +#define AT91_PIN_PG26 (at91_pin_t)218 +#define AT91_PIN_PG27 (at91_pin_t)219 +#define AT91_PIN_PG28 (at91_pin_t)220 +#define AT91_PIN_PG29 (at91_pin_t)221 +#define AT91_PIN_PG30 (at91_pin_t)222 +#define AT91_PIN_PG31 (at91_pin_t)223 +#define AT91_PIN_PH0 (at91_pin_t)224 +#define AT91_PIN_PH1 (at91_pin_t)225 +#define AT91_PIN_PH2 (at91_pin_t)226 +#define AT91_PIN_PH3 (at91_pin_t)227 +#define AT91_PIN_PH4 (at91_pin_t)228 +#define AT91_PIN_PH5 (at91_pin_t)229 +#define AT91_PIN_PH6 (at91_pin_t)230 +#define AT91_PIN_PH7 (at91_pin_t)231 +#define AT91_PIN_PH8 (at91_pin_t)232 +#define AT91_PIN_PH9 (at91_pin_t)233 +#define AT91_PIN_PH10 (at91_pin_t)234 +#define AT91_PIN_PH11 (at91_pin_t)235 +#define AT91_PIN_PH12 (at91_pin_t)236 +#define AT91_PIN_PH13 (at91_pin_t)237 +#define AT91_PIN_PH14 (at91_pin_t)238 +#define AT91_PIN_PH15 (at91_pin_t)239 +#define AT91_PIN_PH16 (at91_pin_t)240 +#define AT91_PIN_PH17 (at91_pin_t)241 +#define AT91_PIN_PH18 (at91_pin_t)242 +#define AT91_PIN_PH19 (at91_pin_t)243 +#define AT91_PIN_PH20 (at91_pin_t)244 +#define AT91_PIN_PH21 (at91_pin_t)245 +#define AT91_PIN_PH22 (at91_pin_t)246 +#define AT91_PIN_PH23 (at91_pin_t)247 +#define AT91_PIN_PH24 (at91_pin_t)248 +#define AT91_PIN_PH25 (at91_pin_t)249 +#define AT91_PIN_PH26 (at91_pin_t)250 +#define AT91_PIN_PH27 (at91_pin_t)251 +#define AT91_PIN_PH28 (at91_pin_t)252 +#define AT91_PIN_PH29 (at91_pin_t)253 +#define AT91_PIN_PH30 (at91_pin_t)254 +#define AT91_PIN_PH31 (at91_pin_t)255 + +#endif /* ARM_AT91_AT91_GPIO_H */ diff --git a/sys/arm/at91/at91_smc.c b/sys/arm/at91/at91_smc.c new file mode 100644 index 000000000000..2d59d169a76d --- /dev/null +++ b/sys/arm/at91/at91_smc.c @@ -0,0 +1,91 @@ +/*- + * Copyright (c) 2014 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 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 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 + +/* + * RD4HW()/WR4HW() read and write at91 hardware register space directly. They + * serve the same purpose as the RD4()/WR4() idiom you see in many drivers, + * except that those translate to bus_space calls, but in this code we need to + * access some devices before bus_space is ready to use. Of course for this to + * work the appropriate static device mappings need to be made in machdep.c. + */ +static inline uint32_t +RD4HW(uint32_t devbase, uint32_t regoff) +{ + + return *(volatile uint32_t *)(AT91_BASE + devbase + regoff); +} + + +static inline void +WR4HW(uint32_t devbase, uint32_t regoff, uint32_t val) +{ + + *(volatile uint32_t *)(AT91_BASE + devbase + regoff) = val; +} + + +void +at91_smc_setup(int id, int cs, const struct at91_smc_init *smc) +{ + // Need a generic way to get this address for all SoCs... Assume 9260 for now... + uint32_t base = AT91SAM9260_SMC_BASE + SMC_CS_OFF(cs); + + WR4HW(base, SMC_SETUP, SMC_SETUP_NCS_RD_SETUP(smc->ncs_rd_setup) | + SMC_SETUP_NRD_SETUP(smc->nrd_setup) | + SMC_SETUP_NCS_WR_SETUP(smc->ncs_wr_setup) | + SMC_SETUP_NWE_SETUP(smc->nwe_setup)); + WR4HW(base, SMC_PULSE, SMC_PULSE_NCS_RD_PULSE(smc->ncs_rd_pulse) | + SMC_PULSE_NRD_PULSE(smc->nrd_pulse) | + SMC_PULSE_NCS_WR_PULSE(smc->ncs_wr_pulse) | + SMC_PULSE_NWE_PULSE(smc->nwe_pulse)); + WR4HW(base, SMC_CYCLE, SMC_CYCLE_NRD_CYCLE(smc->nrd_cycle) | + SMC_CYCLE_NWE_CYCLE(smc->nwe_cycle)); + WR4HW(base, SMC_MODE, smc->mode | SMC_MODE_TDF_CYCLES(smc->tdf_cycles)); +} + +void +at91_ebi_enable(int bank) +{ + + WR4HW(AT91SAM9260_MATRIX_BASE, AT91SAM9260_EBICSA, (1 << bank) | + RD4HW(AT91SAM9260_MATRIX_BASE, AT91SAM9260_EBICSA)); +} + +void +at91_ebi_disable(int bank) +{ + + WR4HW(AT91SAM9260_MATRIX_BASE, AT91SAM9260_EBICSA, ~(1 << bank) & + RD4HW(AT91SAM9260_MATRIX_BASE, AT91SAM9260_EBICSA)); +} diff --git a/sys/arm/at91/at91_smc.h b/sys/arm/at91/at91_smc.h new file mode 100644 index 000000000000..f571c46b1862 --- /dev/null +++ b/sys/arm/at91/at91_smc.h @@ -0,0 +1,116 @@ +/*- + * Copyright (c) 2014 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 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 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 ARM_AT91_AT91_SMC_H +#define ARM_AT91_AT91_SMC_H + +/* Registers */ +#define SMC_SETUP 0x00 +#define SMC_PULSE 0x04 +#define SMC_CYCLE 0x08 +#define SMC_MODE 0x0C + +#define SMC_CS_OFF(cs) (0x10 * (cs)) + +/* Setup */ +#define SMC_SETUP_NCS_RD_SETUP(x) ((x) << 24) +#define SMC_SETUP_NRD_SETUP(x) ((x) << 16) +#define SMC_SETUP_NCS_WR_SETUP(x) ((x) << 8) +#define SMC_SETUP_NWE_SETUP(x) (x) + +/* Pulse */ +#define SMC_PULSE_NCS_RD_PULSE(x) ((x) << 24) +#define SMC_PULSE_NRD_PULSE(x) ((x) << 16) +#define SMC_PULSE_NCS_WR_PULSE(x) ((x) << 8) +#define SMC_PULSE_NWE_PULSE(x) (x) + +/* Cycle */ +#define SMC_CYCLE_NRD_CYCLE(x) ((x) << 16) +#define SMC_CYCLE_NWE_CYCLE(x) (x) + +/* Mode */ +#define SMC_MODE_READ (1 << 0) +#define SMC_MODE_WRITE (1 << 1) +#define SMC_MODE_EXNW_DISABLED (0 << 4) +#define SMC_MODE_EXNW_FROZEN_MODE (2 << 4) +#define SMC_MODE_EXNW_READY_MODE (3 << 4) +#define SMC_MODE_BAT (1 << 8) +#define SMC_MODE_DBW_8BIT (0 << 12) +#define SMC_MODE_DBW_16BIT (1 << 12) +#define SMC_MODE_DBW_32_BIT (2 << 12) +#define SMC_MODE_TDF_CYCLES(x) ((x) << 16) +#define SMC_MODE_TDF_MODE (1 << 20) +#define SMC_MODE_PMEN (1 << 24) +#define SMC_PS_4BYTE (0 << 28) +#define SMC_PS_8BYTE (1 << 28) +#define SMC_PS_16BYTE (2 << 28) +#define SMC_PS_32BYTE (3 << 28) + +/* + * structure to ease init. See the SMC chapter in the datasheet for + * the appropriate SoC you are using for details. + */ +struct at91_smc_init +{ + /* Setup register */ + uint8_t ncs_rd_setup; + uint8_t nrd_setup; + uint8_t ncs_wr_setup; + uint8_t nwe_setup; + + /* Pulse register */ + uint8_t ncs_rd_pulse; + uint8_t nrd_pulse; + uint8_t ncs_wr_pulse; + uint8_t nwe_pulse; + + /* Cycle register */ + uint16_t nrd_cycle; + uint16_t nwe_cycle; + + /* Mode register */ + uint8_t mode; /* Combo of READ/WRITE/EXNW fields */ + uint8_t bat; + uint8_t dwb; + uint8_t tdf_cycles; + uint8_t tdf_mode; + uint8_t pmen; + uint8_t ps; +}; + +/* + * Convenience routine to fill in SMC registers for a given chip select. + */ +void at91_smc_setup(int id, int cs, const struct at91_smc_init *smc); + +/* + * Disable/Enable different External Bus Interfaces (EBI) + */ +void at91_ebi_enable(int cs); +void at91_ebi_disable(int cs); + +#endif /* ARM_AT91_AT91_SMC_H */ diff --git a/sys/arm/at91/at91rm9200.c b/sys/arm/at91/at91rm9200.c index 2c6073c3186c..f2ee45060f4e 100644 --- a/sys/arm/at91/at91rm9200.c +++ b/sys/arm/at91/at91rm9200.c @@ -88,6 +88,13 @@ static const int at91_irq_prio[32] = 0 /* Advanced Interrupt Controller (IRQ6) */ }; +static const uint32_t at91_pio_base[] = { + AT91RM92_PIOA_BASE, + AT91RM92_PIOB_BASE, + AT91RM92_PIOC_BASE, + AT91RM92_PIOD_BASE, +}; + #define DEVICE(_name, _id, _unit) \ { \ _name, _unit, \ @@ -195,6 +202,8 @@ static struct at91_soc_data soc_data = { .soc_clock_init = at91_clock_init, .soc_irq_prio = at91_irq_prio, .soc_children = at91_devs, + .soc_pio_base = at91_pio_base, + .soc_pio_count = nitems(at91_pio_base), }; AT91_SOC(AT91_T_RM9200, &soc_data); diff --git a/sys/arm/at91/at91sam9260.c b/sys/arm/at91/at91sam9260.c index 013c9e4f50e2..03ad462f81ac 100644 --- a/sys/arm/at91/at91sam9260.c +++ b/sys/arm/at91/at91sam9260.c @@ -87,6 +87,12 @@ static const int at91_irq_prio[32] = 0, /* Advanced Interrupt Controller IRQ2 */ }; +static const uint32_t at91_pio_base[] = { + AT91SAM9260_PIOA_BASE, + AT91SAM9260_PIOB_BASE, + AT91SAM9260_PIOC_BASE, +}; + #define DEVICE(_name, _id, _unit) \ { \ _name, _unit, \ @@ -204,6 +210,8 @@ static struct at91_soc_data soc_data = { .soc_clock_init = at91_clock_init, .soc_irq_prio = at91_irq_prio, .soc_children = at91_devs, + .soc_pio_base = at91_pio_base, + .soc_pio_count = nitems(at91_pio_base), }; AT91_SOC(AT91_T_SAM9260, &soc_data); diff --git a/sys/arm/at91/at91sam9g20.c b/sys/arm/at91/at91sam9g20.c index 4d9907cdd69f..d4e6347a8312 100644 --- a/sys/arm/at91/at91sam9g20.c +++ b/sys/arm/at91/at91sam9g20.c @@ -87,6 +87,12 @@ static const int at91_irq_prio[32] = 0, /* Advanced Interrupt Controller IRQ2 */ }; +static const uint32_t at91_pio_base[] = { + AT91SAM9G20_PIOA_BASE, + AT91SAM9G20_PIOB_BASE, + AT91SAM9G20_PIOC_BASE, +}; + #define DEVICE(_name, _id, _unit) \ { \ _name, _unit, \ @@ -169,6 +175,8 @@ static struct at91_soc_data soc_data = { .soc_clock_init = at91_clock_init, .soc_irq_prio = at91_irq_prio, .soc_children = at91_devs, + .soc_pio_base = at91_pio_base, + .soc_pio_count = nitems(at91_pio_base), }; AT91_SOC(AT91_T_SAM9G20, &soc_data); diff --git a/sys/arm/at91/at91sam9g45.c b/sys/arm/at91/at91sam9g45.c index dedc7ceba2ea..c3a26d58f499 100644 --- a/sys/arm/at91/at91sam9g45.c +++ b/sys/arm/at91/at91sam9g45.c @@ -88,6 +88,14 @@ static const int at91_irq_prio[32] = 0, /* Advanced Interrupt Controller IRQ0 */ }; +static const uint32_t at91_pio_base[] = { + AT91SAM9G45_PIOA_BASE, + AT91SAM9G45_PIOB_BASE, + AT91SAM9G45_PIOC_BASE, + AT91SAM9G45_PIOD_BASE, + AT91SAM9G45_PIOE_BASE, +}; + #define DEVICE(_name, _id, _unit) \ { \ _name, _unit, \ @@ -155,6 +163,8 @@ static struct at91_soc_data soc_data = { .soc_clock_init = at91_clock_init, .soc_irq_prio = at91_irq_prio, .soc_children = at91_devs, + .soc_pio_base = at91_pio_base, + .soc_pio_count = nitems(at91_pio_base), }; AT91_SOC(AT91_T_SAM9G45, &soc_data); diff --git a/sys/arm/at91/at91sam9x5.c b/sys/arm/at91/at91sam9x5.c index dedd1353dd2f..4e8c3f43c96c 100644 --- a/sys/arm/at91/at91sam9x5.c +++ b/sys/arm/at91/at91sam9x5.c @@ -87,6 +87,13 @@ static const int at91_irq_prio[32] = 0, /* Advanced Interrupt Controller (IRQ0) */ }; +static const uint32_t at91_pio_base[] = { + AT91SAM9X25_PIOA_BASE, + AT91SAM9X25_PIOB_BASE, + AT91SAM9X25_PIOC_BASE, + AT91SAM9X25_PIOD_BASE, +}; + #define DEVICE(_name, _id, _unit) \ { \ _name, _unit, \ @@ -172,6 +179,8 @@ static struct at91_soc_data soc_data = { .soc_clock_init = at91_clock_init, .soc_irq_prio = at91_irq_prio, .soc_children = at91_devs, + .soc_pio_base = at91_pio_base, + .soc_pio_count = nitems(at91_pio_base), }; AT91_SOC_SUB(AT91_T_SAM9X5, AT91_ST_SAM9X25, &soc_data); diff --git a/sys/arm/at91/at91var.h b/sys/arm/at91/at91var.h index b14946563986..240eb74831b7 100644 --- a/sys/arm/at91/at91var.h +++ b/sys/arm/at91/at91var.h @@ -107,11 +107,13 @@ typedef void (*cpu_reset_t)(void); typedef void (*clk_init_t)(void); struct at91_soc_data { - DELAY_t soc_delay; - cpu_reset_t soc_reset; - clk_init_t soc_clock_init; - const int *soc_irq_prio; - const struct cpu_devs *soc_children; + DELAY_t soc_delay; /* SoC specific delay function */ + cpu_reset_t soc_reset; /* SoC specific reset function */ + clk_init_t soc_clock_init; /* SoC specific clock init function */ + const int *soc_irq_prio; /* SoC specific IRQ priorities */ + const struct cpu_devs *soc_children; /* SoC specific children list */ + const uint32_t *soc_pio_base; /* SoC specific PIO base registers */ + size_t soc_pio_count; /* Count of PIO units (not pins) in SoC */ }; struct at91_soc_info { diff --git a/sys/arm/at91/board_hl201.c b/sys/arm/at91/board_hl201.c index 8ba69804456d..66dbf368f4b6 100644 --- a/sys/arm/at91/board_hl201.c +++ b/sys/arm/at91/board_hl201.c @@ -34,6 +34,36 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include +#include + +static struct at91_smc_init nand_smc = { + .ncs_rd_setup = 0, + .nrd_setup = 2, + .ncs_wr_setup = 0, + .nwe_setup = 2, + + .ncs_rd_pulse = 4, + .nrd_pulse = 4, + .ncs_wr_pulse = 4, + .nwe_pulse = 4, + + .nrd_cycle = 7, + .nwe_cycle = 7, + + .mode = SMC_MODE_READ | SMC_MODE_WRITE | SMC_MODE_EXNW_DISABLED, + .tdf_cycles = 3, +}; + +static struct at91_nand_params nand_param = { + .ale = 1u << 21, + .cle = 1u << 22, + .width = 8, + .rnb_pin = AT91_PIN_PC13, /* Note: These pins not confirmed */ + .nce_pin = AT91_PIN_PC14, + .cs = 3, +}; BOARD_INIT long board_init(void) @@ -64,6 +94,27 @@ board_init(void) at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA24, 0); /* ETX3 */ at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA22, 0); /* ETXER */ + /* Setup Static Memory Controller */ + at91_smc_setup(0, 3, &nand_smc); + at91_enable_nand(&nand_param); + + /* + * This assumes + * - RNB is on pin PC13 + * - CE is on pin PC14 + * + * Nothing actually uses RNB right now. + * + * For CE, this currently asserts it during board setup and leaves it + * that way forever. + * + * All this can go away when the gpio pin-renumbering happens... + */ + at91_pio_use_gpio(AT91SAM9G20_PIOC_BASE, AT91C_PIO_PC13 | AT91C_PIO_PC14); + at91_pio_gpio_input(AT91SAM9G20_PIOC_BASE, AT91C_PIO_PC13); /* RNB */ + at91_pio_gpio_output(AT91SAM9G20_PIOC_BASE, AT91C_PIO_PC14, 0); /* nCS */ + at91_pio_gpio_clear(AT91SAM9G20_PIOC_BASE, AT91C_PIO_PC14); /* Assert nCS */ + return (at91_ramsize()); } diff --git a/sys/arm/at91/board_sam9260ek.c b/sys/arm/at91/board_sam9260ek.c index 61b9cbde3e56..96c822fc43b5 100644 --- a/sys/arm/at91/board_sam9260ek.c +++ b/sys/arm/at91/board_sam9260ek.c @@ -38,9 +38,39 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include +#include -BOARD_INIT long -board_init(void) +static struct at91_smc_init nand_smc = { + .ncs_rd_setup = 0, + .nrd_setup = 1, + .ncs_wr_setup = 0, + .nwe_setup = 1, + + .ncs_rd_pulse = 3, + .nrd_pulse = 3, + .ncs_wr_pulse = 3, + .nwe_pulse = 3, + + .nrd_cycle = 5, + .nwe_cycle = 5, + + .mode = SMC_MODE_READ | SMC_MODE_WRITE | SMC_MODE_EXNW_DISABLED, + .tdf_cycles = 2, +}; + +static struct at91_nand_params nand_param = { + .ale = 1u << 21, + .cle = 1u << 22, + .width = 8, + .rnb_pin = AT91_PIN_PC13, + .nce_pin = AT91_PIN_PC14, + .cs = 3, +}; + +static void +bi_dbgu(void) { /* @@ -50,6 +80,11 @@ board_init(void) at91_pio_use_periph_a(AT91SAM9260_PIOB_BASE, AT91C_PIO_PB14, 0); /* DTXD */ at91_pio_use_periph_a(AT91SAM9260_PIOB_BASE, AT91C_PIO_PB15, 1); +} + +static void +bi_emac() +{ /* * EMAC @@ -91,7 +126,11 @@ board_init(void) at91_pio_use_periph_b(AT91SAM9260_PIOA_BASE, AT91C_PIO_PA28, 0); /* ECOL */ at91_pio_use_periph_b(AT91SAM9260_PIOA_BASE, AT91C_PIO_PA29, 0); +} +static void +bi_mmc(void) +{ /* * MMC, wired to socket B. @@ -114,11 +153,11 @@ board_init(void) * don't support the dataflash. But if you did, you'd have to * use CS0 and CS1. */ +} - /* - * SPI1 is wired to a audio CODEC that we don't support, so - * give it a pass. - */ +static void +bi_iic(void) +{ /* * TWI. Only one child on the iic bus, which we take care of @@ -128,6 +167,11 @@ board_init(void) at91_pio_use_periph_a(AT91SAM9260_PIOA_BASE, AT91C_PIO_PA23, 1); /* TWCK */ at91_pio_use_periph_a(AT91SAM9260_PIOA_BASE, AT91C_PIO_PA24, 1); +} + +static void +bi_usart0(void) +{ /* * USART0 @@ -148,7 +192,11 @@ board_init(void) at91_pio_use_periph_a(AT91SAM9260_PIOB_BASE, AT91C_PIO_PB26, 1); /* CTS0 */ at91_pio_use_periph_a(AT91SAM9260_PIOB_BASE, AT91C_PIO_PB27, 0); +} +static void +bi_usart1(void) +{ /* * USART1 */ @@ -160,9 +208,54 @@ board_init(void) at91_pio_use_periph_a(AT91SAM9260_PIOB_BASE, AT91C_PIO_PB6, 1); /* RXD1 */ at91_pio_use_periph_a(AT91SAM9260_PIOB_BASE, AT91C_PIO_PB7, 0); +} +static void +bi_nand(void) +{ + /* Samsung 256MB SLC Flash */ + + /* Setup Static Memory Controller */ + at91_smc_setup(0, 3, &nand_smc); + at91_enable_nand(&nand_param); + + /* + * This assumes + * - RNB is on pin PC13 + * - CE is on pin PC14 + * + * Nothing actually uses RNB right now. + * + * For CE, this currently asserts it during board setup and leaves it + * that way forever. + * + * All this can go away when the gpio pin-renumbering happens... + */ + at91_pio_use_gpio(AT91SAM9260_PIOC_BASE, AT91C_PIO_PC13 | AT91C_PIO_PC14); + at91_pio_gpio_input(AT91SAM9260_PIOC_BASE, AT91C_PIO_PC13); /* RNB */ + at91_pio_gpio_output(AT91SAM9260_PIOC_BASE, AT91C_PIO_PC14, 0); /* nCS */ + at91_pio_gpio_clear(AT91SAM9260_PIOC_BASE, AT91C_PIO_PC14); /* Assert nCS */ +} + +BOARD_INIT long +board_init(void) +{ + bi_dbgu(); + bi_emac(); + bi_mmc(); + + /* + * SPI1 is wired to a audio CODEC that we don't support, so + * give it a pass. + */ + + bi_iic(); + bi_usart0(); + bi_usart1(); /* USART2 - USART5 aren't wired up, except via PIO pins, ignore them. */ + bi_nand(); + return (at91_ramsize()); } diff --git a/sys/arm/at91/files.at91 b/sys/arm/at91/files.at91 index a83aa7a7b2c5..5533594da887 100644 --- a/sys/arm/at91/files.at91 +++ b/sys/arm/at91/files.at91 @@ -12,6 +12,7 @@ arm/at91/at91_pit.c optional at91sam9 arm/at91/at91_reset.S optional at91sam9 arm/at91/at91_rst.c optional at91sam9 arm/at91/at91_rtc.c optional at91_rtc +arm/at91/at91_smc.c standard arm/at91/at91_spi.c optional at91_spi \ dependency "spibus_if.h" arm/at91/at91_ssc.c optional at91_ssc diff --git a/sys/arm/at91/uart_dev_at91usart.c b/sys/arm/at91/uart_dev_at91usart.c index 43655b6e6cd0..6ba7736a749b 100644 --- a/sys/arm/at91/uart_dev_at91usart.c +++ b/sys/arm/at91/uart_dev_at91usart.c @@ -219,20 +219,6 @@ at91_usart_param(struct uart_bas *bas, int baudrate, int databits, return (0); } -static void -at91_usart_grab(struct uart_bas *bas) -{ - - WR4(bas, USART_IDR, USART_CSR_RXRDY); -} - -static void -at91_usart_ungrab(struct uart_bas *bas) -{ - - WR4(bas, USART_IER, USART_CSR_RXRDY); -} - static struct uart_ops at91_usart_ops = { .probe = at91_usart_probe, .init = at91_usart_init, @@ -240,8 +226,6 @@ static struct uart_ops at91_usart_ops = { .putc = at91_usart_putc, .rxready = at91_usart_rxready, .getc = at91_usart_getc, - .grab = at91_usart_grab, - .ungrab = at91_usart_ungrab, }; static int @@ -331,6 +315,8 @@ static int at91_usart_bus_param(struct uart_softc *, int, int, int, int); static int at91_usart_bus_receive(struct uart_softc *); static int at91_usart_bus_setsig(struct uart_softc *, int); static int at91_usart_bus_transmit(struct uart_softc *); +static void at91_usart_bus_grab(struct uart_softc *); +static void at91_usart_bus_ungrab(struct uart_softc *); static kobj_method_t at91_usart_methods[] = { KOBJMETHOD(uart_probe, at91_usart_bus_probe), @@ -343,6 +329,8 @@ static kobj_method_t at91_usart_methods[] = { KOBJMETHOD(uart_receive, at91_usart_bus_receive), KOBJMETHOD(uart_setsig, at91_usart_bus_setsig), KOBJMETHOD(uart_transmit, at91_usart_bus_transmit), + KOBJMETHOD(uart_grab, at91_usart_bus_grab), + KOBJMETHOD(uart_ungrab, at91_usart_bus_ungrab), KOBJMETHOD_END }; @@ -815,6 +803,25 @@ at91_usart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) return (EINVAL); } + +static void +at91_usart_bus_grab(struct uart_softc *sc) +{ + + uart_lock(sc->sc_hwmtx); + WR4(&sc->sc_bas, USART_IDR, USART_CSR_RXRDY); + uart_unlock(sc->sc_hwmtx); +} + +static void +at91_usart_bus_ungrab(struct uart_softc *sc) +{ + + uart_lock(sc->sc_hwmtx); + WR4(&sc->sc_bas, USART_IER, USART_CSR_RXRDY); + uart_unlock(sc->sc_hwmtx); +} + struct uart_class at91_usart_class = { "at91_usart", at91_usart_methods, diff --git a/sys/arm/conf/ATMEL b/sys/arm/conf/ATMEL index 82bc9cc4e4bd..74871eb5dbd2 100644 --- a/sys/arm/conf/ATMEL +++ b/sys/arm/conf/ATMEL @@ -175,3 +175,6 @@ device at91_wdt # Atmel AT91 Watchdog Timer device at91_rtc device at91_ssc #device at91_tc # missing? + +# NAND Flash - Reference design has Samsung 256MB but others possible +device nand # NAND interface on CS3 diff --git a/sys/arm/conf/HL201 b/sys/arm/conf/HL201 index a02d3dfa933c..7a4e2df3d167 100644 --- a/sys/arm/conf/HL201 +++ b/sys/arm/conf/HL201 @@ -37,7 +37,8 @@ options FFS #Berkeley Fast Filesystem #options UFS_ACL #Support for access control lists #options UFS_DIRHASH #Improve performance on big directories #options MD_ROOT #MD is a potential root device -#options MD_ROOT_SIZE=4096 # 3MB ram disk +#options MD_ROOT_SIZE=4096 # 4MB ram disk +options NANDFS # NAND file system #options ROOTDEVNAME=\"ufs:/dev/mmcsd0s1a\" options NFSCL #New Network Filesystem Client #options NFSD #New Network Filesystem Server @@ -131,3 +132,5 @@ device pass # Passthrough device (direct SCSI access) #device wlan_amrr # AMRR transmit rate control algorithm options ROOTDEVNAME=\"ufs:da0s1a\" +# NAND Flash - my board as 128MB Samsung part +device nand # NAND interface on CS3 diff --git a/sys/arm/conf/SAM9260EK b/sys/arm/conf/SAM9260EK index 12b5c8a1ee79..9d6962d13daa 100644 --- a/sys/arm/conf/SAM9260EK +++ b/sys/arm/conf/SAM9260EK @@ -1,4 +1,4 @@ -# Kernel configuration for Ethernut 5 boards +# Kernel configuration for Atmel SAM9260-EK eval board # # For more information on this file, please read the config(5) manual page, # and/or the handbook section on Kernel Configuration Files: @@ -37,6 +37,7 @@ options SOFTUPDATES # Enable FFS soft updates support options UFS_DIRHASH # Improve performance on big directories #options UFS_GJOURNAL # Enable gjournal-based UFS journaling #options MD_ROOT # MD is a potential root device +options NANDFS # NAND file system options NFSCL # New Network Filesystem Client #options NFSD # New Network Filesystem Server options NFSLOCKD # Network Lock Manager @@ -165,3 +166,6 @@ device umass # Disks/Mass storage - Requires scbus and da # watchdog device at91_wdt # Atmel AT91 Watchdog Timer + +# NAND Flash - Reference design has Samsung 256MB but others possible +device nand # NAND interface on CS3 diff --git a/sys/arm/freescale/imx/imx51_ipuv3_fbd.c b/sys/arm/freescale/imx/imx51_ipuv3_fbd.c index 5295cd760ed9..8756ba326a6f 100644 --- a/sys/arm/freescale/imx/imx51_ipuv3_fbd.c +++ b/sys/arm/freescale/imx/imx51_ipuv3_fbd.c @@ -57,6 +57,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include diff --git a/sys/arm/s3c2xx0/uart_dev_s3c2410.c b/sys/arm/s3c2xx0/uart_dev_s3c2410.c index 0f9f79861ea2..aadd835dcbec 100644 --- a/sys/arm/s3c2xx0/uart_dev_s3c2410.c +++ b/sys/arm/s3c2xx0/uart_dev_s3c2410.c @@ -203,7 +203,6 @@ s3c2410_getc(struct uart_bas *bas, struct mtx *mtx) return sscom_getc(bas->bst, bas->bsh); } - static int s3c2410_bus_probe(struct uart_softc *sc); static int s3c2410_bus_attach(struct uart_softc *sc); static int s3c2410_bus_flush(struct uart_softc *, int); @@ -214,6 +213,8 @@ static int s3c2410_bus_param(struct uart_softc *, int, int, int, int); static int s3c2410_bus_receive(struct uart_softc *); static int s3c2410_bus_setsig(struct uart_softc *, int); static int s3c2410_bus_transmit(struct uart_softc *); +static void s3c2410_bus_grab(struct uart_softc *); +static void s3c2410_bus_ungrab(struct uart_softc *); static kobj_method_t s3c2410_methods[] = { KOBJMETHOD(uart_probe, s3c2410_bus_probe), @@ -226,6 +227,8 @@ static kobj_method_t s3c2410_methods[] = { KOBJMETHOD(uart_receive, s3c2410_bus_receive), KOBJMETHOD(uart_setsig, s3c2410_bus_setsig), KOBJMETHOD(uart_transmit, s3c2410_bus_transmit), + KOBJMETHOD(uart_grab, s3c2410_bus_grab), + KOBJMETHOD(uart_ungrab, s3c2410_bus_ungrab), {0, 0 } }; @@ -373,6 +376,25 @@ s3c2410_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) return (EINVAL); } + +static void +s3c2410_bus_grab(struct uart_softc *sc) +{ + uintptr_t irq; + + irq = rman_get_start(sc->sc_ires); + arm_mask_irq(get_sub_irq(irq, RX_OFF)); +} + +static void +s3c2410_bus_ungrab(struct uart_softc *sc) +{ + uintptr_t irq; + + irq = rman_get_start(sc->sc_ires); + arm_unmask_irq(get_sub_irq(irq, RX_OFF)); +} + struct uart_class uart_s3c2410_class = { "s3c2410 class", s3c2410_methods, diff --git a/sys/arm/sa11x0/uart_dev_sa1110.c b/sys/arm/sa11x0/uart_dev_sa1110.c index 6765cf289025..1df1009a4bd6 100644 --- a/sys/arm/sa11x0/uart_dev_sa1110.c +++ b/sys/arm/sa11x0/uart_dev_sa1110.c @@ -137,6 +137,8 @@ static int sa1110_bus_param(struct uart_softc *, int, int, int, int); static int sa1110_bus_receive(struct uart_softc *); static int sa1110_bus_setsig(struct uart_softc *, int); static int sa1110_bus_transmit(struct uart_softc *); +static void sa1110_bus_grab(struct uart_softc *); +static void sa1110_bus_ungrab(struct uart_softc *); static kobj_method_t sa1110_methods[] = { KOBJMETHOD(uart_probe, sa1110_bus_probe), @@ -149,6 +151,8 @@ static kobj_method_t sa1110_methods[] = { KOBJMETHOD(uart_receive, sa1110_bus_receive), KOBJMETHOD(uart_setsig, sa1110_bus_setsig), KOBJMETHOD(uart_transmit, sa1110_bus_transmit), + KOBJMETHOD(uart_grab, sa1110_bus_grab), + KOBJMETHOD(uart_ungrab, sa1110_bus_ungrab), {0, 0 } }; @@ -164,10 +168,10 @@ sa1110_bus_probe(struct uart_softc *sc) static int sa1110_bus_attach(struct uart_softc *sc) { - bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas)); + bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas)); - sc->sc_hwiflow = 0; - uart_setreg(&sc->sc_bas, SACOM_CR3, CR3_RXE | CR3_TXE | CR3_RIE | CR3_TIE); + sc->sc_hwiflow = 0; + uart_setreg(&sc->sc_bas, SACOM_CR3, CR3_RXE | CR3_TXE | CR3_RIE | CR3_TIE); return (0); } static int @@ -273,6 +277,26 @@ sa1110_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) return (EINVAL); } +static void +sa1110_bus_grab(struct uart_softc *sc) +{ + + /* Turn off Rx interrupts */ + uart_lock(sc->sc_hwmtx); + uart_setreg(&sc->sc_bas, SACOM_CR3, CR3_TXE | CR3_TIE); + uart_unlock(sc->sc_hwmtx); +} + +static void +sa1110_bus_ungrab(struct uart_softc *sc) +{ + + /* Turn on Rx interrupts */ + uart_lock(sc->sc_hwmtx); + uart_setreg(&sc->sc_bas, SACOM_CR3, CR3_RXE | CR3_TXE | CR3_RIE | CR3_TIE); + uart_unlock(sc->sc_hwmtx); +} + struct uart_class uart_sa1110_class = { "sa1110", sa1110_methods, diff --git a/sys/arm/xilinx/uart_dev_cdnc.c b/sys/arm/xilinx/uart_dev_cdnc.c index a0088532ea54..6224503f7542 100644 --- a/sys/arm/xilinx/uart_dev_cdnc.c +++ b/sys/arm/xilinx/uart_dev_cdnc.c @@ -398,6 +398,8 @@ static int cdnc_uart_bus_param(struct uart_softc *, int, int, int, int); static int cdnc_uart_bus_receive(struct uart_softc *); static int cdnc_uart_bus_setsig(struct uart_softc *, int); static int cdnc_uart_bus_transmit(struct uart_softc *); +static void cdnc_uart_bus_grab(struct uart_softc *); +static void cdnc_uart_bus_ungrab(struct uart_softc *); static kobj_method_t cdnc_uart_bus_methods[] = { KOBJMETHOD(uart_probe, cdnc_uart_bus_probe), @@ -410,6 +412,8 @@ static kobj_method_t cdnc_uart_bus_methods[] = { KOBJMETHOD(uart_receive, cdnc_uart_bus_receive), KOBJMETHOD(uart_setsig, cdnc_uart_bus_setsig), KOBJMETHOD(uart_transmit, cdnc_uart_bus_transmit), + KOBJMETHOD(uart_grab, cdnc_uart_bus_grab), + KOBJMETHOD(uart_ungrab, cdnc_uart_bus_ungrab), KOBJMETHOD_END }; @@ -675,6 +679,27 @@ cdnc_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) return (error); } +static void +cdnc_uart_bus_grab(struct uart_softc *sc) +{ + + /* Enable interrupts. */ + WR4(&sc->sc_bas, CDNC_UART_IEN_REG, + CDNC_UART_INT_TXOVR | CDNC_UART_INT_RXOVR | + CDNC_UART_INT_DMSI); +} + +static void +cdnc_uart_bus_ungrab(struct uart_softc *sc) +{ + + /* Enable interrupts. */ + WR4(&sc->sc_bas, CDNC_UART_IEN_REG, + CDNC_UART_INT_RXTRIG | CDNC_UART_INT_RXTMOUT | + CDNC_UART_INT_TXOVR | CDNC_UART_INT_RXOVR | + CDNC_UART_INT_DMSI); +} + struct uart_class uart_cdnc_class = { "cdnc_uart", cdnc_uart_bus_methods, diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c index 6b6370dbebe2..05529050c2fc 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013 by Delphix. All rights reserved. - * Copyright (c) 2013 by Saso Kiselkov. All rights reserved. + * Copyright (c) 2014 by Saso Kiselkov. All rights reserved. * Copyright 2013 Nexenta Systems, Inc. All rights reserved. */ @@ -4597,6 +4597,13 @@ l2arc_write_done(zio_t *zio) */ for (ab = list_prev(buflist, head); ab; ab = ab_prev) { ab_prev = list_prev(buflist, ab); + abl2 = ab->b_l2hdr; + + /* + * Release the temporary compressed buffer as soon as possible. + */ + if (abl2->b_compress != ZIO_COMPRESS_OFF) + l2arc_release_cdata_buf(ab); hash_lock = HDR_LOCK(ab); if (!mutex_tryenter(hash_lock)) { @@ -4609,14 +4616,6 @@ l2arc_write_done(zio_t *zio) continue; } - abl2 = ab->b_l2hdr; - - /* - * Release the temporary compressed buffer as soon as possible. - */ - if (abl2->b_compress != ZIO_COMPRESS_OFF) - l2arc_release_cdata_buf(ab); - if (zio->io_error != 0) { /* * Error - drop L2ARC entry. diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_traverse.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_traverse.c index 146aad1fbc0f..1f64d73acdd2 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_traverse.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_traverse.c @@ -351,9 +351,9 @@ traverse_visitbp(traverse_data_t *td, const dnode_phys_t *dnp, prefetch_dnode_metadata(td, dnp, zb->zb_objset, DMU_META_DNODE_OBJECT); if (arc_buf_size(buf) >= sizeof (objset_phys_t)) { - prefetch_dnode_metadata(td, &osp->os_userused_dnode, - zb->zb_objset, DMU_USERUSED_OBJECT); prefetch_dnode_metadata(td, &osp->os_groupused_dnode, + zb->zb_objset, DMU_GROUPUSED_OBJECT); + prefetch_dnode_metadata(td, &osp->os_userused_dnode, zb->zb_objset, DMU_USERUSED_OBJECT); } @@ -364,18 +364,18 @@ traverse_visitbp(traverse_data_t *td, const dnode_phys_t *dnp, err = 0; } if (err == 0 && arc_buf_size(buf) >= sizeof (objset_phys_t)) { - dnp = &osp->os_userused_dnode; + dnp = &osp->os_groupused_dnode; err = traverse_dnode(td, dnp, zb->zb_objset, - DMU_USERUSED_OBJECT); + DMU_GROUPUSED_OBJECT); } if (err && hard) { lasterr = err; err = 0; } if (err == 0 && arc_buf_size(buf) >= sizeof (objset_phys_t)) { - dnp = &osp->os_groupused_dnode; + dnp = &osp->os_userused_dnode; err = traverse_dnode(td, dnp, zb->zb_objset, - DMU_GROUPUSED_OBJECT); + DMU_USERUSED_OBJECT); } } diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_mirror.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_mirror.c index 1ffd1de2731f..0b8d449f4aa1 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_mirror.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_mirror.c @@ -313,13 +313,16 @@ vdev_mirror_scrub_done(zio_t *zio) * single-copy data. */ static int -vdev_mirror_dva_select(zio_t *zio, int preferred) +vdev_mirror_dva_select(zio_t *zio, int p) { dva_t *dva = zio->io_bp->blk_dva; mirror_map_t *mm = zio->io_vsd; + int preferred; int c; - for (c = preferred - 1; c >= 0; c--) { + preferred = mm->mm_preferred[p]; + for (p-- ; p >= 0; p--) { + c = mm->mm_preferred[p]; if (DVA_GET_VDEV(&dva[c]) == DVA_GET_VDEV(&dva[preferred])) preferred = c; } @@ -334,7 +337,7 @@ vdev_mirror_preferred_child_randomize(zio_t *zio) if (mm->mm_root) { p = spa_get_random(mm->mm_preferred_cnt); - return (vdev_mirror_dva_select(zio, mm->mm_preferred[p])); + return (vdev_mirror_dva_select(zio, p)); } /* diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_dir.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_dir.c index 1f7fee29a950..be96da91c43d 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_dir.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_dir.c @@ -951,6 +951,8 @@ zfs_make_xattrdir(znode_t *zp, vattr_t *vap, vnode_t **xvpp, cred_t *cr) return (SET_ERROR(EDQUOT)); } + getnewvnode_reserve(1); + tx = dmu_tx_create(zfsvfs->z_os); dmu_tx_hold_sa_create(tx, acl_ids.z_aclp->z_acl_bytes + ZFS_SA_BASE_ATTR_SIZE); @@ -985,6 +987,8 @@ zfs_make_xattrdir(znode_t *zp, vattr_t *vap, vnode_t **xvpp, cred_t *cr) zfs_acl_ids_free(&acl_ids); dmu_tx_commit(tx); + getnewvnode_drop_reserve(); + *xvpp = ZTOV(xzp); return (0); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c index 033980114559..3e43b4888da8 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c @@ -1625,6 +1625,9 @@ zfs_create(vnode_t *dvp, char *name, vattr_t *vap, int excl, int mode, return (error); } } + + getnewvnode_reserve(1); + top: *vpp = NULL; @@ -1653,6 +1656,7 @@ zfs_create(vnode_t *dvp, char *name, vattr_t *vap, int excl, int mode, zfs_acl_ids_free(&acl_ids); if (strcmp(name, "..") == 0) error = SET_ERROR(EISDIR); + getnewvnode_drop_reserve(); ZFS_EXIT(zfsvfs); return (error); } @@ -1721,6 +1725,7 @@ zfs_create(vnode_t *dvp, char *name, vattr_t *vap, int excl, int mode, } zfs_acl_ids_free(&acl_ids); dmu_tx_abort(tx); + getnewvnode_drop_reserve(); ZFS_EXIT(zfsvfs); return (error); } @@ -1787,6 +1792,7 @@ zfs_create(vnode_t *dvp, char *name, vattr_t *vap, int excl, int mode, } } out: + getnewvnode_drop_reserve(); if (dl) zfs_dirent_unlock(dl); @@ -2130,6 +2136,9 @@ zfs_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp, cred_t *cr, ZFS_EXIT(zfsvfs); return (error); } + + getnewvnode_reserve(1); + /* * First make sure the new directory doesn't exist. * @@ -2143,6 +2152,7 @@ zfs_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp, cred_t *cr, if (error = zfs_dirent_lock(&dl, dzp, dirname, &zp, zf, NULL, NULL)) { zfs_acl_ids_free(&acl_ids); + getnewvnode_drop_reserve(); ZFS_EXIT(zfsvfs); return (error); } @@ -2150,6 +2160,7 @@ zfs_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp, cred_t *cr, if (error = zfs_zaccess(dzp, ACE_ADD_SUBDIRECTORY, 0, B_FALSE, cr)) { zfs_acl_ids_free(&acl_ids); zfs_dirent_unlock(dl); + getnewvnode_drop_reserve(); ZFS_EXIT(zfsvfs); return (error); } @@ -2157,6 +2168,7 @@ zfs_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp, cred_t *cr, if (zfs_acl_ids_overquota(zfsvfs, &acl_ids)) { zfs_acl_ids_free(&acl_ids); zfs_dirent_unlock(dl); + getnewvnode_drop_reserve(); ZFS_EXIT(zfsvfs); return (SET_ERROR(EDQUOT)); } @@ -2189,6 +2201,7 @@ zfs_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp, cred_t *cr, } zfs_acl_ids_free(&acl_ids); dmu_tx_abort(tx); + getnewvnode_drop_reserve(); ZFS_EXIT(zfsvfs); return (error); } @@ -2218,6 +2231,8 @@ zfs_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp, cred_t *cr, dmu_tx_commit(tx); + getnewvnode_drop_reserve(); + zfs_dirent_unlock(dl); if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS) @@ -4109,6 +4124,9 @@ zfs_symlink(vnode_t *dvp, vnode_t **vpp, char *name, vattr_t *vap, char *link, ZFS_EXIT(zfsvfs); return (error); } + + getnewvnode_reserve(1); + top: /* * Attempt to lock directory; fail if entry already exists. @@ -4116,6 +4134,7 @@ zfs_symlink(vnode_t *dvp, vnode_t **vpp, char *name, vattr_t *vap, char *link, error = zfs_dirent_lock(&dl, dzp, name, &zp, zflg, NULL, NULL); if (error) { zfs_acl_ids_free(&acl_ids); + getnewvnode_drop_reserve(); ZFS_EXIT(zfsvfs); return (error); } @@ -4123,6 +4142,7 @@ zfs_symlink(vnode_t *dvp, vnode_t **vpp, char *name, vattr_t *vap, char *link, if (error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr)) { zfs_acl_ids_free(&acl_ids); zfs_dirent_unlock(dl); + getnewvnode_drop_reserve(); ZFS_EXIT(zfsvfs); return (error); } @@ -4130,6 +4150,7 @@ zfs_symlink(vnode_t *dvp, vnode_t **vpp, char *name, vattr_t *vap, char *link, if (zfs_acl_ids_overquota(zfsvfs, &acl_ids)) { zfs_acl_ids_free(&acl_ids); zfs_dirent_unlock(dl); + getnewvnode_drop_reserve(); ZFS_EXIT(zfsvfs); return (SET_ERROR(EDQUOT)); } @@ -4157,6 +4178,7 @@ zfs_symlink(vnode_t *dvp, vnode_t **vpp, char *name, vattr_t *vap, char *link, } zfs_acl_ids_free(&acl_ids); dmu_tx_abort(tx); + getnewvnode_drop_reserve(); ZFS_EXIT(zfsvfs); return (error); } @@ -4195,6 +4217,8 @@ zfs_symlink(vnode_t *dvp, vnode_t **vpp, char *name, vattr_t *vap, char *link, dmu_tx_commit(tx); + getnewvnode_drop_reserve(); + zfs_dirent_unlock(dl); if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS) @@ -6750,14 +6774,16 @@ vop_deleteextattr { UIO_SYSSPACE, attrname, xvp, td); error = namei(&nd); vp = nd.ni_vp; - NDFREE(&nd, NDF_ONLY_PNBUF); if (error != 0) { ZFS_EXIT(zfsvfs); + NDFREE(&nd, NDF_ONLY_PNBUF); if (error == ENOENT) error = ENOATTR; return (error); } + error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd); + NDFREE(&nd, NDF_ONLY_PNBUF); vput(nd.ni_dvp); if (vp == nd.ni_dvp) diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c index 5c18671e2f59..e78b13ba3a08 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c @@ -624,6 +624,8 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz, zp = kmem_cache_alloc(znode_cache, KM_SLEEP); + KASSERT(curthread->td_vp_reserv > 0, + ("zfs_znode_alloc: getnewvnode without any vnodes reserved")); error = getnewvnode("zfs", zfsvfs->z_parent->z_vfs, &zfs_vnodeops, &vp); if (error != 0) { kmem_cache_free(znode_cache, zp); @@ -830,7 +832,6 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr, } } - getnewvnode_reserve(1); ZFS_OBJ_HOLD_ENTER(zfsvfs, obj); VERIFY(0 == sa_buf_hold(zfsvfs->z_os, obj, NULL, &db)); @@ -1016,7 +1017,6 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr, KASSERT(err == 0, ("insmntque() failed: error %d", err)); } ZFS_OBJ_HOLD_EXIT(zfsvfs, obj); - getnewvnode_drop_reserve(); } /* diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c index c8681c6e3f8b..719a0573cb5d 100644 --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -1644,18 +1644,28 @@ struct sf_hdtr32 { int trl_cnt; }; +struct sf_hdtr_kq32 { + int kq_fd; + uint32_t kq_flags; + uint32_t kq_udata; /* 32-bit void ptr */ + uint32_t kq_ident; /* 32-bit uintptr_t */ +}; + static int freebsd32_do_sendfile(struct thread *td, struct freebsd32_sendfile_args *uap, int compat) { struct sf_hdtr32 hdtr32; struct sf_hdtr hdtr; + struct sf_hdtr_kq32 hdtr_kq32; + struct sf_hdtr_kq hdtr_kq; struct uio *hdr_uio, *trl_uio; struct iovec32 *iov32; off_t offset; int error; off_t sbytes; struct sendfile_sync *sfs; + int do_kqueue = 0; offset = PAIR32TO64(off_t, uap->offset); if (offset < 0) @@ -1687,10 +1697,32 @@ freebsd32_do_sendfile(struct thread *td, if (error) goto out; } + + /* + * If SF_KQUEUE is set, then we need to also copy in + * the kqueue data after the normal hdtr set and set do_kqueue=1. + */ + if (uap->flags & SF_KQUEUE) { + error = copyin(((char *) uap->hdtr) + sizeof(hdtr32), + &hdtr_kq32, + sizeof(hdtr_kq32)); + if (error != 0) + goto out; + + /* 32->64 bit fields */ + CP(hdtr_kq32, hdtr_kq, kq_fd); + CP(hdtr_kq32, hdtr_kq, kq_flags); + PTRIN_CP(hdtr_kq32, hdtr_kq, kq_udata); + CP(hdtr_kq32, hdtr_kq, kq_ident); + do_kqueue = 1; + } } + + /* Call sendfile */ + /* XXX stack depth! */ error = _do_sendfile(td, uap->fd, uap->s, uap->flags, compat, - offset, uap->nbytes, &sbytes, hdr_uio, trl_uio); + offset, uap->nbytes, &sbytes, hdr_uio, trl_uio, &hdtr_kq); if (uap->sbytes != NULL) copyout(&sbytes, uap->sbytes, sizeof(off_t)); diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64 index d1bdcd97bfb5..3937823383ac 100644 --- a/sys/conf/files.amd64 +++ b/sys/conf/files.amd64 @@ -448,6 +448,7 @@ dev/virtio/network/if_vtnet.c optional vtnet dev/virtio/block/virtio_blk.c optional virtio_blk dev/virtio/balloon/virtio_balloon.c optional virtio_balloon dev/virtio/scsi/virtio_scsi.c optional virtio_scsi +dev/virtio/random/virtio_random.c optional virtio_random isa/syscons_isa.c optional sc isa/vga_isa.c optional vga kern/kern_clocksource.c standard diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index eb8697cd9d70..77b556542e22 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -414,6 +414,7 @@ dev/virtio/network/if_vtnet.c optional vtnet dev/virtio/block/virtio_blk.c optional virtio_blk dev/virtio/balloon/virtio_balloon.c optional virtio_balloon dev/virtio/scsi/virtio_scsi.c optional virtio_scsi +dev/virtio/random/virtio_random.c optional virtio_random i386/acpica/acpi_machdep.c optional acpi acpi_wakecode.o optional acpi \ dependency "$S/i386/acpica/acpi_wakecode.S assym.s" \ diff --git a/sys/contrib/ipfilter/netinet/ip_compat.h b/sys/contrib/ipfilter/netinet/ip_compat.h index 3dbaee266edd..d0b26af2aa8e 100644 --- a/sys/contrib/ipfilter/netinet/ip_compat.h +++ b/sys/contrib/ipfilter/netinet/ip_compat.h @@ -543,7 +543,7 @@ MALLOC_DECLARE(M_IPFILTER); # ifndef ALLOC_MB_T # ifdef MGETHDR # define ALLOC_MB_T(m,l) do { \ - MGETHDR((m), M_DONTWAIT, MT_HEADER); \ + MGETHDR((m), M_NOWAIT, MT_HEADER); \ if ((m) != NULL) { \ (m)->m_len = (l); \ (m)->m_pkthdr.len = (l); \ @@ -551,7 +551,7 @@ MALLOC_DECLARE(M_IPFILTER); } while (0) # else # define ALLOC_MB_T(m,l) do { \ - MGET((m), M_DONTWAIT, MT_HEADER); \ + MGET((m), M_NOWAIT, MT_HEADER); \ if ((m) != NULL) { \ (m)->m_len = (l); \ (m)->m_pkthdr.len = (l); \ diff --git a/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c b/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c index 898869a797c7..3466c7ce969f 100644 --- a/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c +++ b/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c @@ -368,14 +368,14 @@ ipf_send_reset(fin) hlen = sizeof(ip_t); #endif #ifdef MGETHDR - MGETHDR(m, M_DONTWAIT, MT_HEADER); + MGETHDR(m, M_NOWAIT, MT_HEADER); #else - MGET(m, M_DONTWAIT, MT_HEADER); + MGET(m, M_NOWAIT, MT_HEADER); #endif if (m == NULL) return -1; if (sizeof(*tcp2) + hlen > MLEN) { - MCLGET(m, M_DONTWAIT); + MCLGET(m, M_NOWAIT); if ((m->m_flags & M_EXT) == 0) { FREE_MB_T(m); return -1; @@ -543,9 +543,9 @@ ipf_send_icmp_err(type, fin, dst) if (ipf_checkl4sum(fin) == -1) return -1; #ifdef MGETHDR - MGETHDR(m, M_DONTWAIT, MT_HEADER); + MGETHDR(m, M_NOWAIT, MT_HEADER); #else - MGET(m, M_DONTWAIT, MT_HEADER); + MGET(m, M_NOWAIT, MT_HEADER); #endif if (m == NULL) return -1; @@ -599,7 +599,7 @@ ipf_send_icmp_err(type, fin, dst) code = icmptoicmp6unreach[code]; if (iclen + max_linkhdr + fin->fin_plen > avail) { - MCLGET(m, M_DONTWAIT); + MCLGET(m, M_NOWAIT); if ((m->m_flags & M_EXT) == 0) { FREE_MB_T(m); return -1; @@ -730,7 +730,7 @@ ipf_fastroute(m0, mpp, fin, fdp) * problem. */ if (M_WRITABLE(m) == 0) { - m0 = m_dup(m, M_DONTWAIT); + m0 = m_dup(m, M_NOWAIT); if (m0 != 0) { FREE_MB_T(m); m = m0; @@ -878,9 +878,9 @@ ipf_fastroute(m0, mpp, fin, fdp) mhlen = sizeof (struct ip); for (off = hlen + len; off < ntohs(ip->ip_len); off += len) { #ifdef MGETHDR - MGETHDR(m, M_DONTWAIT, MT_HEADER); + MGETHDR(m, M_NOWAIT, MT_HEADER); #else - MGET(m, M_DONTWAIT, MT_HEADER); + MGET(m, M_NOWAIT, MT_HEADER); #endif if (m == 0) { m = m0; diff --git a/sys/dev/aha/aha.c b/sys/dev/aha/aha.c index ee9cc72b7f10..4efbb32d159f 100644 --- a/sys/dev/aha/aha.c +++ b/sys/dev/aha/aha.c @@ -207,9 +207,9 @@ aha_free(struct aha_softc *aha) case 7: bus_dmamap_unload(aha->ccb_dmat, aha->ccb_dmamap); case 6: - bus_dmamap_destroy(aha->ccb_dmat, aha->ccb_dmamap); bus_dmamem_free(aha->ccb_dmat, aha->aha_ccb_array, aha->ccb_dmamap); + bus_dmamap_destroy(aha->ccb_dmat, aha->ccb_dmamap); case 5: bus_dma_tag_destroy(aha->ccb_dmat); case 4: diff --git a/sys/dev/ahci/ahci.c b/sys/dev/ahci/ahci.c index 05d5f7ad0aa9..ad7188cdd51e 100644 --- a/sys/dev/ahci/ahci.c +++ b/sys/dev/ahci/ahci.c @@ -146,6 +146,7 @@ static struct { {0x78021022, 0x00, "AMD Hudson-2", 0}, {0x78031022, 0x00, "AMD Hudson-2", 0}, {0x78041022, 0x00, "AMD Hudson-2", 0}, + {0x06111b21, 0x00, "ASMedia ASM2106", 0}, {0x06121b21, 0x00, "ASMedia ASM1061", 0}, {0x26528086, 0x00, "Intel ICH6", AHCI_Q_NOFORCE}, {0x26538086, 0x00, "Intel ICH6M", AHCI_Q_NOFORCE}, diff --git a/sys/dev/altera/atse/if_atse.c b/sys/dev/altera/atse/if_atse.c index f6ed625f76aa..d49df5a31507 100644 --- a/sys/dev/altera/atse/if_atse.c +++ b/sys/dev/altera/atse/if_atse.c @@ -1174,7 +1174,7 @@ atse_rx_locked(struct atse_softc *sc) sc->atse_rx_cycles--; if (sc->atse_rx_m == NULL) { - m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); + m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); if (m == NULL) return (rx_npkts); m->m_len = m->m_pkthdr.len = MCLBYTES; diff --git a/sys/dev/bxe/bxe.c b/sys/dev/bxe/bxe.c index 31f7a0515bc4..37d1680e1397 100644 --- a/sys/dev/bxe/bxe.c +++ b/sys/dev/bxe/bxe.c @@ -5443,7 +5443,7 @@ bxe_tx_encap(struct bxe_fastpath *fp, struct mbuf **m_head) } else if (error == EFBIG) { /* possibly recoverable with defragmentation */ fp->eth_q_stats.mbuf_defrag_attempts++; - m0 = m_defrag(*m_head, M_DONTWAIT); + m0 = m_defrag(*m_head, M_NOWAIT); if (m0 == NULL) { fp->eth_q_stats.mbuf_defrag_failures++; rc = ENOBUFS; @@ -5504,7 +5504,7 @@ bxe_tx_encap(struct bxe_fastpath *fp, struct mbuf **m_head) /* lets try to defragment this mbuf */ fp->eth_q_stats.mbuf_defrag_attempts++; - m0 = m_defrag(*m_head, M_DONTWAIT); + m0 = m_defrag(*m_head, M_NOWAIT); if (m0 == NULL) { fp->eth_q_stats.mbuf_defrag_failures++; /* Ugh, just drop the frame... :( */ @@ -6564,7 +6564,7 @@ bxe_alloc_rx_bd_mbuf(struct bxe_fastpath *fp, rc = 0; /* allocate the new RX BD mbuf */ - m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, fp->mbuf_alloc_size); + m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, fp->mbuf_alloc_size); if (__predict_false(m == NULL)) { fp->eth_q_stats.mbuf_rx_bd_alloc_failed++; return (ENOBUFS); @@ -6645,7 +6645,7 @@ bxe_alloc_rx_tpa_mbuf(struct bxe_fastpath *fp, int rc = 0; /* allocate the new TPA mbuf */ - m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, fp->mbuf_alloc_size); + m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, fp->mbuf_alloc_size); if (__predict_false(m == NULL)) { fp->eth_q_stats.mbuf_rx_tpa_alloc_failed++; return (ENOBUFS); @@ -6707,7 +6707,7 @@ bxe_alloc_rx_sge_mbuf(struct bxe_fastpath *fp, int rc = 0; /* allocate a new SGE mbuf */ - m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, SGE_PAGE_SIZE); + m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, SGE_PAGE_SIZE); if (__predict_false(m == NULL)) { fp->eth_q_stats.mbuf_rx_sge_alloc_failed++; return (ENOMEM); @@ -6769,7 +6769,7 @@ bxe_alloc_fp_buffers(struct bxe_softc *sc) #if __FreeBSD_version >= 800000 fp->tx_br = buf_ring_alloc(BXE_BR_SIZE, M_DEVBUF, - M_DONTWAIT, &fp->tx_mtx); + M_NOWAIT, &fp->tx_mtx); if (fp->tx_br == NULL) { BLOGE(sc, "buf_ring alloc fail for fp[%02d]\n", i); goto bxe_alloc_fp_buffers_error; diff --git a/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c b/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c index f0df87b948da..674db231e052 100644 --- a/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c +++ b/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c @@ -485,7 +485,7 @@ hn_start_locked(struct ifnet *ifp) * bpf_mtap code has a chance to run. */ if (ifp->if_bpf) { - mc_head = m_copypacket(m_head, M_DONTWAIT); + mc_head = m_copypacket(m_head, M_NOWAIT); } retry_send: /* Set the completion routine */ @@ -594,7 +594,7 @@ hv_m_append(struct mbuf *m0, int len, c_caddr_t cp) * Allocate a new mbuf; could check space * and allocate a cluster instead. */ - n = m_getjcl(M_DONTWAIT, m->m_type, 0, MJUMPAGESIZE); + n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE); if (n == NULL) break; n->m_len = min(MJUMPAGESIZE, remainder); @@ -658,7 +658,7 @@ netvsc_recv(struct hv_device *device_ctx, netvsc_packet *packet) size = MJUMPAGESIZE; } - m_new = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, size); + m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size); if (m_new == NULL) return (0); diff --git a/sys/dev/nand/nfc_at91.c b/sys/dev/nand/nfc_at91.c index cdf85249e550..7357cdbd31dc 100644 --- a/sys/dev/nand/nfc_at91.c +++ b/sys/dev/nand/nfc_at91.c @@ -54,23 +54,29 @@ __FBSDID("$FreeBSD$"); #include #include "nfc_if.h" +#include +#include + /* * Data cycles are triggered by access to any address within the EBI CS3 region * that has A21 and A22 clear. Command cycles are any access with bit A21 - * asserted. Address cycles are any access with bit A22 asserted. - * - * XXX The atmel docs say that any address bits can be used instead of A21 and - * A22; these values should be configurable. + * asserted. Address cycles are any access with bit A22 asserted. Or vice versa. + * We get these parameters from the nand_param that the board is required to + * call at91_enable_nand, and enable the GPIO lines properly (that will be moved + * into at91_enable_nand when the great GPIO pin renumbering happens). We use + * ale (Address Latch Enable) and cle (Comand Latch Enable) to match the hardware + * names used in NAND. */ #define AT91_NAND_DATA 0 -#define AT91_NAND_COMMAND (1 << 21) -#define AT91_NAND_ADDRESS (1 << 22) struct at91_nand_softc { struct nand_softc nand_sc; struct resource *res; + struct at91_nand_params *nand_param; }; +static struct at91_nand_params nand_param; + static int at91_nand_attach(device_t); static int at91_nand_probe(device_t); static uint8_t at91_nand_read_byte(device_t); @@ -81,6 +87,12 @@ static int at91_nand_send_command(device_t, uint8_t); static int at91_nand_send_address(device_t, uint8_t); static void at91_nand_write_buf(device_t, void *, uint32_t); +void +at91_enable_nand(const struct at91_nand_params *np) +{ + nand_param = *np; +} + static inline u_int8_t dev_read_1(struct at91_nand_softc *sc, bus_size_t offset) { @@ -108,6 +120,14 @@ at91_nand_attach(device_t dev) int err, rid; sc = device_get_softc(dev); + sc->nand_param = &nand_param; + if (sc->nand_param->width != 8 && sc->nand_param->width != 16) { + device_printf(dev, "Bad bus width (%d) defaulting to 8 bits\n", + sc->nand_param->width); + sc->nand_param->width = 8; + } + at91_ebi_enable(sc->nand_param->cs); + rid = 0; sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); @@ -128,10 +148,10 @@ at91_nand_send_command(device_t dev, uint8_t command) { struct at91_nand_softc *sc; - /* nand_debug(NDBG_DRV,"at91_nand_send_command: 0x%02x", command); */ + nand_debug(NDBG_DRV,"at91_nand_send_command: 0x%02x", command); sc = device_get_softc(dev); - dev_write_1(sc, AT91_NAND_COMMAND, command); + dev_write_1(sc, sc->nand_param->cle, command); return (0); } @@ -140,10 +160,10 @@ at91_nand_send_address(device_t dev, uint8_t addr) { struct at91_nand_softc *sc; - /* nand_debug(NDBG_DRV,"at91_nand_send_address: x%02x", addr); */ + nand_debug(NDBG_DRV,"at91_nand_send_address: x%02x", addr); sc = device_get_softc(dev); - dev_write_1(sc, AT91_NAND_ADDRESS, addr); + dev_write_1(sc, sc->nand_param->ale, addr); return (0); } @@ -156,7 +176,7 @@ at91_nand_read_byte(device_t dev) sc = device_get_softc(dev); data = dev_read_1(sc, AT91_NAND_DATA); - /* nand_debug(NDBG_DRV,"at91_nand_read_byte: 0x%02x", data); */ + nand_debug(NDBG_DRV,"at91_nand_read_byte: 0x%02x", data); return (data); } diff --git a/sys/dev/nand/nfc_at91.h b/sys/dev/nand/nfc_at91.h new file mode 100644 index 000000000000..ae06e69cb72f --- /dev/null +++ b/sys/dev/nand/nfc_at91.h @@ -0,0 +1,50 @@ +/*- + * Copyright (C) 2014 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 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$ + */ + +/* + * Atmel at91-family integrated NAND controller driver. + * + * Interface to board setup code to set parameters. + */ + +#ifndef DEV_NAND_NFC_AT91_H +#define DEV_NAND_NFC_AT91_H 1 + +struct at91_nand_params +{ + uint32_t ale; /* Address for ALE (address) NAND cycles */ + uint32_t cle; /* Address for CLE (command) NAND cycles */ + uint32_t width; /* 8 or 16 bits (specify in bits) */ + uint32_t cs; /* Chip Select NAND is connected to */ + uint32_t rnb_pin; /* GPIO pin # for Read/notBusy */ + uint32_t nce_pin; /* GPIO pin # for CE (active low) */ +}; + +void at91_enable_nand(const struct at91_nand_params *); + +#endif /* DEV_NAND_NFC_AT91_H */ diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c index 70f82cee8a0f..fdd368a346fe 100644 --- a/sys/dev/netmap/netmap.c +++ b/sys/dev/netmap/netmap.c @@ -1052,7 +1052,7 @@ netmap_get_hw_na(struct ifnet *ifp, struct netmap_adapter **na) * to use generic adapters, we cannot satisfy the request. */ if (!NETMAP_CAPABLE(ifp) && i == NETMAP_ADMODE_NATIVE) - return EINVAL; + return EOPNOTSUPP; /* Otherwise, create a generic adapter and return it, * saving the previously used netmap adapter, if any. @@ -1090,22 +1090,19 @@ netmap_get_hw_na(struct ifnet *ifp, struct netmap_adapter **na) /* * MUST BE CALLED UNDER NMG_LOCK() * - * get a refcounted reference to an interface. + * Get a refcounted reference to a netmap adapter attached + * to the interface specified by nmr. * This is always called in the execution of an ioctl(). * - * Return ENXIO if the interface does not exist, EINVAL if netmap - * is not supported by the interface. - * If successful, hold a reference. + * Return ENXIO if the interface specified by the request does + * not exist, ENOTSUP if netmap is not supported by the interface, + * EBUSY if the interface is already attached to a bridge, + * EINVAL if parameters are invalid, ENOMEM if needed resources + * could not be allocated. + * If successful, hold a reference to the netmap adapter. * - * When the NIC is attached to a bridge, reference is managed - * at na->na_bdg_refcount using ADD/DROP_BDG_REF() as well as - * virtual ports. Hence, on the final DROP_BDG_REF(), the NIC - * is detached from the bridge, then ifp's refcount is dropped (this - * is equivalent to that ifp is destroyed in case of virtual ports. - * - * This function uses if_rele() when we want to prevent the NIC from - * being detached from the bridge in error handling. But once refcount - * is acquired by this function, it must be released using nm_if_rele(). + * No reference is kept on the real interface, which may then + * disappear at any time. */ int netmap_get_na(struct nmreq *nmr, struct netmap_adapter **na, int create) @@ -1135,7 +1132,7 @@ netmap_get_na(struct nmreq *nmr, struct netmap_adapter **na, int create) if (ret != NULL) { /* Users cannot use the NIC attached to a bridge directly */ if (NETMAP_OWNED_BY_KERN(ret)) { - error = EINVAL; + error = EBUSY; goto out; } error = 0; diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c index 109a734cac9f..e695fcbd29f8 100644 --- a/sys/dev/netmap/netmap_generic.c +++ b/sys/dev/netmap/netmap_generic.c @@ -261,7 +261,7 @@ generic_netmap_register(struct netmap_adapter *na, int enable) /* Prepare to intercept incoming traffic. */ error = netmap_catch_rx(na, 1); if (error) { - D("netdev_rx_handler_register() failed"); + D("netdev_rx_handler_register() failed (%d)", error); goto register_handler; } ifp->if_capenable |= IFCAP_NETMAP; @@ -283,7 +283,11 @@ generic_netmap_register(struct netmap_adapter *na, int enable) rate_ctx.refcount++; #endif /* RATE */ - } else { /* Disable netmap mode. */ + } else if (na->tx_rings[0].tx_pool) { + /* Disable netmap mode. We enter here only if the previous + generic_netmap_register(na, 1) was successfull. + If it was not, na->tx_rings[0].tx_pool was set to NULL by the + error handling code below. */ rtnl_lock(); ifp->if_capenable &= ~IFCAP_NETMAP; @@ -322,7 +326,7 @@ generic_netmap_register(struct netmap_adapter *na, int enable) #ifdef REG_RESET error = ifp->netdev_ops->ndo_open(ifp); if (error) { - goto alloc_tx_pool; + goto free_tx_pools; } #endif @@ -338,6 +342,11 @@ generic_netmap_register(struct netmap_adapter *na, int enable) if (na->tx_rings[r].tx_pool[i]) m_freem(na->tx_rings[r].tx_pool[i]); free(na->tx_rings[r].tx_pool, M_DEVBUF); + na->tx_rings[r].tx_pool = NULL; + } + netmap_mitigation_cleanup(gna); + for (r=0; rnum_rx_rings; r++) { + mbq_safe_destroy(&na->rx_rings[r].rx_queue); } return error; diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c index cec2ac15a7e9..13a725378c28 100644 --- a/sys/dev/netmap/netmap_vale.c +++ b/sys/dev/netmap/netmap_vale.c @@ -515,7 +515,7 @@ netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na, int create) b = nm_find_bridge(name, create); if (b == NULL) { D("no bridges available for '%s'", name); - return (ENXIO); + return (create ? ENOMEM : ENXIO); } /* Now we are sure that name starts with the bridge's name, @@ -547,7 +547,7 @@ netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na, int create) needed = 2; /* in some cases we only need 1 */ if (b->bdg_active_ports + needed >= NM_BDG_MAXPORTS) { D("bridge full %d, cannot create new port", b->bdg_active_ports); - return EINVAL; + return ENOMEM; } /* record the next two ports available, but do not allocate yet */ cand = b->bdg_port_index[b->bdg_active_ports]; @@ -594,7 +594,7 @@ netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na, int create) if (NETMAP_OWNED_BY_ANY(ret)) { D("NIC %s busy, cannot attach to bridge", NM_IFPNAME(ifp)); - error = EINVAL; + error = EBUSY; goto out; } /* create a fake interface */ @@ -658,11 +658,13 @@ nm_bdg_attach(struct nmreq *nmr) npriv = malloc(sizeof(*npriv), M_DEVBUF, M_NOWAIT|M_ZERO); if (npriv == NULL) return ENOMEM; + NMG_LOCK(); - /* XXX probably netmap_get_bdg_na() */ + error = netmap_get_bdg_na(nmr, &na, 1 /* create if not exists */); if (error) /* no device, or another bridge or user owns the device */ goto unlock_exit; + if (na == NULL) { /* VALE prefix missing */ error = EINVAL; goto unlock_exit; @@ -707,6 +709,7 @@ nm_bdg_detach(struct nmreq *nmr) if (error) { /* no device, or another bridge or user owns the device */ goto unlock_exit; } + if (na == NULL) { /* VALE prefix missing */ error = EINVAL; goto unlock_exit; @@ -1945,7 +1948,7 @@ netmap_bwrap_notify(struct netmap_adapter *na, u_int ring_n, enum txrx tx, int f int error = 0; if (tx == NR_TX) - return ENXIO; + return EINVAL; kring = &na->rx_rings[ring_n]; hw_kring = &hwna->tx_rings[ring_n]; @@ -1999,7 +2002,7 @@ netmap_bwrap_host_notify(struct netmap_adapter *na, u_int ring_n, enum txrx tx, struct netmap_bwrap_adapter *bna = na->na_private; struct netmap_adapter *port_na = &bna->up.up; if (tx == NR_TX || ring_n != 0) - return ENXIO; + return EINVAL; return netmap_bwrap_notify(port_na, port_na->num_rx_rings, NR_RX, flags); } diff --git a/sys/dev/qlxge/qls_os.c b/sys/dev/qlxge/qls_os.c index 8b34d23bde52..509bfe2c5fc9 100644 --- a/sys/dev/qlxge/qls_os.c +++ b/sys/dev/qlxge/qls_os.c @@ -1158,7 +1158,7 @@ qls_send(qla_host_t *ha, struct mbuf **m_headp) QL_DPRINT8((ha->pci_dev, "%s: EFBIG [%d]\n", __func__, m_head->m_pkthdr.len)); - m = m_defrag(m_head, M_DONTWAIT); + m = m_defrag(m_head, M_NOWAIT); if (m == NULL) { ha->err_tx_defrag++; m_freem(m_head); @@ -1413,7 +1413,7 @@ qls_get_mbuf(qla_host_t *ha, qla_rx_buf_t *rxb, struct mbuf *nmp) if (mp == NULL) { - mp = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, ha->msize); + mp = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, ha->msize); if (mp == NULL) { diff --git a/sys/dev/uart/uart_core.c b/sys/dev/uart/uart_core.c index 17dabd7d8017..eea2d8ce80a1 100644 --- a/sys/dev/uart/uart_core.c +++ b/sys/dev/uart/uart_core.c @@ -411,6 +411,13 @@ uart_bus_attach(device_t dev) } else sc = sc0; + /* + * Now that we know the softc for this device, connect the back + * pointer from the sysdev for this device, if any + */ + if (sc->sc_sysdev != NULL) + sc->sc_sysdev->sc = sc; + /* * Protect ourselves against interrupts while we're not completely * finished attaching and initializing. We don't expect interrupts @@ -617,3 +624,19 @@ uart_bus_resume(device_t dev) sc = device_get_softc(dev); return (UART_ATTACH(sc)); } + +void +uart_grab(struct uart_devinfo *di) +{ + + if (di->sc) + UART_GRAB(di->sc); +} + +void +uart_ungrab(struct uart_devinfo *di) +{ + + if (di->sc) + UART_UNGRAB(di->sc); +} diff --git a/sys/dev/uart/uart_cpu.h b/sys/dev/uart/uart_cpu.h index 99ced1a2c0c3..2db04123ad0e 100644 --- a/sys/dev/uart/uart_cpu.h +++ b/sys/dev/uart/uart_cpu.h @@ -33,6 +33,8 @@ #include #include +struct uart_softc; + /* * Low-level operations for use by console and/or debug port support. */ @@ -43,8 +45,6 @@ struct uart_ops { void (*putc)(struct uart_bas *, int); int (*rxready)(struct uart_bas *); int (*getc)(struct uart_bas *, struct mtx *); - void (*grab)(struct uart_bas *); - void (*ungrab)(struct uart_bas *); }; extern bus_space_tag_t uart_bus_space_io; @@ -53,7 +53,6 @@ extern bus_space_tag_t uart_bus_space_mem; /* * Console and debug port device info. */ -struct uart_softc; struct uart_devinfo { SLIST_ENTRY(uart_devinfo) next; struct uart_ops *ops; @@ -70,6 +69,7 @@ struct uart_devinfo { int (*detach)(struct uart_softc*); void *cookie; /* Type dependent use. */ struct mtx *hwmtx; + struct uart_softc *sc; /* valid only from start of attach */ }; int uart_cpu_eqres(struct uart_bas *, struct uart_bas *); @@ -137,27 +137,6 @@ uart_putc(struct uart_devinfo *di, int c) uart_unlock(di->hwmtx); } -static __inline void -uart_grab(struct uart_devinfo *di) -{ - - uart_lock(di->hwmtx); - if (di->ops->grab) - di->ops->grab(&di->bas); - uart_unlock(di->hwmtx); -} - -static __inline void -uart_ungrab(struct uart_devinfo *di) -{ - - uart_lock(di->hwmtx); - if (di->ops->ungrab) - di->ops->ungrab(&di->bas); - uart_unlock(di->hwmtx); -} - - static __inline int uart_rxready(struct uart_devinfo *di) { @@ -190,4 +169,7 @@ uart_getc(struct uart_devinfo *di) return (di->ops->getc(&di->bas, di->hwmtx)); } +void uart_grab(struct uart_devinfo *di); +void uart_ungrab(struct uart_devinfo *di); + #endif /* _DEV_UART_CPU_H_ */ diff --git a/sys/dev/uart/uart_dev_imx.c b/sys/dev/uart/uart_dev_imx.c index 22ee8ccc83de..e99cf774e3d5 100644 --- a/sys/dev/uart/uart_dev_imx.c +++ b/sys/dev/uart/uart_dev_imx.c @@ -140,6 +140,8 @@ static int imx_uart_bus_probe(struct uart_softc *); static int imx_uart_bus_receive(struct uart_softc *); static int imx_uart_bus_setsig(struct uart_softc *, int); static int imx_uart_bus_transmit(struct uart_softc *); +static void imx_uart_bus_grab(struct uart_softc *); +static void imx_uart_bus_ungrab(struct uart_softc *); static kobj_method_t imx_uart_methods[] = { KOBJMETHOD(uart_attach, imx_uart_bus_attach), @@ -153,6 +155,8 @@ static kobj_method_t imx_uart_methods[] = { KOBJMETHOD(uart_receive, imx_uart_bus_receive), KOBJMETHOD(uart_setsig, imx_uart_bus_setsig), KOBJMETHOD(uart_transmit, imx_uart_bus_transmit), + KOBJMETHOD(uart_grab, imx_uart_bus_grab), + KOBJMETHOD(uart_ungrab, imx_uart_bus_ungrab), { 0, 0 } }; @@ -189,12 +193,7 @@ imx_uart_bus_attach(struct uart_softc *sc) (void)imx_uart_bus_getsig(sc); - /* XXX workaround to have working console on mount prompt */ - if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE){ - DIS(bas, UCR4, DREN); - } else { - ENA(bas, UCR4, DREN); - } + ENA(bas, UCR4, DREN); DIS(bas, UCR1, RRDYEN); DIS(bas, UCR1, IDEN); DIS(bas, UCR3, RXDSEN); @@ -402,13 +401,6 @@ static int imx_uart_bus_setsig(struct uart_softc *sc, int sig) { - /* TODO: implement (?) */ - - /* XXX workaround to have working console on mount prompt */ - /* Enable RX interrupt */ - if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) - if (!IS(&sc->sc_bas, UCR4, DREN)) - ENA(&sc->sc_bas, UCR4, DREN); return (0); } @@ -434,3 +426,25 @@ imx_uart_bus_transmit(struct uart_softc *sc) return (0); } + +static void +imx_uart_bus_grab(struct uart_softc *sc) +{ + struct uart_bas *bas = &sc->sc_bas; + + bas = &sc->sc_bas; + uart_lock(sc->sc_hwmtx); + DIS(bas, UCR4, DREN); + uart_unlock(sc->sc_hwmtx); +} + +static void +imx_uart_bus_ungrab(struct uart_softc *sc) +{ + struct uart_bas *bas = &sc->sc_bas; + + bas = &sc->sc_bas; + uart_lock(sc->sc_hwmtx); + ENA(bas, UCR4, DREN); + uart_unlock(sc->sc_hwmtx); +} diff --git a/sys/dev/uart/uart_dev_lpc.c b/sys/dev/uart/uart_dev_lpc.c index 708d343b76f4..08cebc9cdff0 100644 --- a/sys/dev/uart/uart_dev_lpc.c +++ b/sys/dev/uart/uart_dev_lpc.c @@ -401,6 +401,8 @@ static int lpc_ns8250_bus_probe(struct uart_softc *); static int lpc_ns8250_bus_receive(struct uart_softc *); static int lpc_ns8250_bus_setsig(struct uart_softc *, int); static int lpc_ns8250_bus_transmit(struct uart_softc *); +static void lpc_ns8250_bus_grab(struct uart_softc *); +static void lpc_ns8250_bus_ungrab(struct uart_softc *); static kobj_method_t lpc_ns8250_methods[] = { KOBJMETHOD(uart_attach, lpc_ns8250_bus_attach), @@ -414,6 +416,8 @@ static kobj_method_t lpc_ns8250_methods[] = { KOBJMETHOD(uart_receive, lpc_ns8250_bus_receive), KOBJMETHOD(uart_setsig, lpc_ns8250_bus_setsig), KOBJMETHOD(uart_transmit, lpc_ns8250_bus_transmit), + KOBJMETHOD(uart_grab, lpc_ns8250_bus_grab), + KOBJMETHOD(uart_ungrab, lpc_ns8250_bus_ungrab), { 0, 0 } }; @@ -890,3 +894,34 @@ lpc_ns8250_bus_transmit(struct uart_softc *sc) uart_unlock(sc->sc_hwmtx); return (0); } + +void +lpc_ns8250_bus_grab(struct uart_softc *sc) +{ + struct uart_bas *bas = &sc->sc_bas; + + /* + * turn off all interrupts to enter polling mode. Leave the + * saved mask alone. We'll restore whatever it was in ungrab. + * All pending interupt signals are reset when IER is set to 0. + */ + uart_lock(sc->sc_hwmtx); + uart_setreg(bas, REG_IER, 0); + uart_barrier(bas); + uart_unlock(sc->sc_hwmtx); +} + +void +lpc_ns8250_bus_ungrab(struct uart_softc *sc) +{ + struct lpc_ns8250_softc *lpc_ns8250 = (struct lpc_ns8250_softc*)sc; + struct uart_bas *bas = &sc->sc_bas; + + /* + * Restore previous interrupt mask + */ + uart_lock(sc->sc_hwmtx); + uart_setreg(bas, REG_IER, lpc_ns8250->ier); + uart_barrier(bas); + uart_unlock(sc->sc_hwmtx); +} diff --git a/sys/dev/uart/uart_dev_ns8250.c b/sys/dev/uart/uart_dev_ns8250.c index 249be4ce0e33..47a61bfa6014 100644 --- a/sys/dev/uart/uart_dev_ns8250.c +++ b/sys/dev/uart/uart_dev_ns8250.c @@ -365,6 +365,8 @@ static kobj_method_t ns8250_methods[] = { KOBJMETHOD(uart_receive, ns8250_bus_receive), KOBJMETHOD(uart_setsig, ns8250_bus_setsig), KOBJMETHOD(uart_transmit, ns8250_bus_transmit), + KOBJMETHOD(uart_grab, ns8250_bus_grab), + KOBJMETHOD(uart_ungrab, ns8250_bus_ungrab), { 0, 0 } }; @@ -922,3 +924,34 @@ ns8250_bus_transmit(struct uart_softc *sc) uart_sched_softih(sc, SER_INT_TXIDLE); return (0); } + +void +ns8250_bus_grab(struct uart_softc *sc) +{ + struct uart_bas *bas = &sc->sc_bas; + + /* + * turn off all interrupts to enter polling mode. Leave the + * saved mask alone. We'll restore whatever it was in ungrab. + * All pending interupt signals are reset when IER is set to 0. + */ + uart_lock(sc->sc_hwmtx); + uart_setreg(bas, REG_IER, 0); + uart_barrier(bas); + uart_unlock(sc->sc_hwmtx); +} + +void +ns8250_bus_ungrab(struct uart_softc *sc) +{ + struct ns8250_softc *ns8250 = (struct ns8250_softc*)sc; + struct uart_bas *bas = &sc->sc_bas; + + /* + * Restore previous interrupt mask + */ + uart_lock(sc->sc_hwmtx); + uart_setreg(bas, REG_IER, ns8250->ier); + uart_barrier(bas); + uart_unlock(sc->sc_hwmtx); +} diff --git a/sys/dev/uart/uart_dev_ns8250.h b/sys/dev/uart/uart_dev_ns8250.h index 39f4a0f27803..0046dfefd875 100644 --- a/sys/dev/uart/uart_dev_ns8250.h +++ b/sys/dev/uart/uart_dev_ns8250.h @@ -56,5 +56,7 @@ int ns8250_bus_probe(struct uart_softc *); int ns8250_bus_receive(struct uart_softc *); int ns8250_bus_setsig(struct uart_softc *, int); int ns8250_bus_transmit(struct uart_softc *); +void ns8250_bus_grab(struct uart_softc *); +void ns8250_bus_ungrab(struct uart_softc *); #endif /* _DEV_UART_DEV_NS8250_H_ */ diff --git a/sys/dev/uart/uart_dev_pl011.c b/sys/dev/uart/uart_dev_pl011.c index 82e8b03654d0..3253cd14a2e0 100644 --- a/sys/dev/uart/uart_dev_pl011.c +++ b/sys/dev/uart/uart_dev_pl011.c @@ -242,6 +242,8 @@ static int uart_pl011_bus_probe(struct uart_softc *); static int uart_pl011_bus_receive(struct uart_softc *); static int uart_pl011_bus_setsig(struct uart_softc *, int); static int uart_pl011_bus_transmit(struct uart_softc *); +static void uart_pl011_bus_grab(struct uart_softc *); +static void uart_pl011_bus_ungrab(struct uart_softc *); static kobj_method_t uart_pl011_methods[] = { KOBJMETHOD(uart_attach, uart_pl011_bus_attach), @@ -255,6 +257,9 @@ static kobj_method_t uart_pl011_methods[] = { KOBJMETHOD(uart_receive, uart_pl011_bus_receive), KOBJMETHOD(uart_setsig, uart_pl011_bus_setsig), KOBJMETHOD(uart_transmit, uart_pl011_bus_transmit), + KOBJMETHOD(uart_grab, uart_pl011_bus_grab), + KOBJMETHOD(uart_ungrab, uart_pl011_bus_ungrab), + { 0, 0 } }; @@ -441,3 +446,27 @@ uart_pl011_bus_transmit(struct uart_softc *sc) return (0); } + +static void +uart_pl011_bus_grab(struct uart_softc *sc) +{ + struct uart_bas *bas; + + bas = &sc->sc_bas; + uart_lock(sc->sc_hwmtx); + __uart_setreg(bas, UART_IMSC, /* Switch to RX polling while grabbed */ + ~UART_RXREADY & __uart_getreg(bas, UART_IMSC)); + uart_unlock(sc->sc_hwmtx); +} + +static void +uart_pl011_bus_ungrab(struct uart_softc *sc) +{ + struct uart_bas *bas; + + bas = &sc->sc_bas; + uart_lock(sc->sc_hwmtx); + __uart_setreg(bas, UART_IMSC, /* Switch to RX interrupts while not grabbed */ + UART_RXREADY | __uart_getreg(bas, UART_IMSC)); + uart_unlock(sc->sc_hwmtx); +} diff --git a/sys/dev/uart/uart_dev_quicc.c b/sys/dev/uart/uart_dev_quicc.c index 337591e8ec90..bbbc3bd0f5df 100644 --- a/sys/dev/uart/uart_dev_quicc.c +++ b/sys/dev/uart/uart_dev_quicc.c @@ -245,6 +245,8 @@ static int quicc_bus_probe(struct uart_softc *); static int quicc_bus_receive(struct uart_softc *); static int quicc_bus_setsig(struct uart_softc *, int); static int quicc_bus_transmit(struct uart_softc *); +static void quicc_bus_grab(struct uart_softc *); +static void quicc_bus_ungrab(struct uart_softc *); static kobj_method_t quicc_methods[] = { KOBJMETHOD(uart_attach, quicc_bus_attach), @@ -258,6 +260,8 @@ static kobj_method_t quicc_methods[] = { KOBJMETHOD(uart_receive, quicc_bus_receive), KOBJMETHOD(uart_setsig, quicc_bus_setsig), KOBJMETHOD(uart_transmit, quicc_bus_transmit), + KOBJMETHOD(uart_grab, quicc_bus_grab), + KOBJMETHOD(uart_ungrab, quicc_bus_ungrab), { 0, 0 } }; @@ -485,3 +489,34 @@ quicc_bus_transmit(struct uart_softc *sc) uart_unlock(sc->sc_hwmtx); return (0); } + +static void +quicc_bus_grab(struct uart_softc *sc) +{ + struct uart_bas *bas; + uint16_t st, rb; + + /* Disable interrupts on the receive buffer. */ + bas = &sc->sc_bas; + uart_lock(sc->sc_hwmtx); + rb = quicc_read2(bas, QUICC_PRAM_SCC_RBASE(bas->chan - 1)); + st = quicc_read2(bas, rb); + quicc_write2(bas, rb, st & ~0x9000); + uart_unlock(sc->sc_hwmtx); +} + +static void +quicc_bus_ungrab(struct uart_softc *sc) +{ + struct uart_bas *bas; + uint16_t st, rb; + + /* Enable interrupts on the receive buffer. */ + bas = &sc->sc_bas; + uart_lock(sc->sc_hwmtx); + rb = quicc_read2(bas, QUICC_PRAM_SCC_RBASE(bas->chan - 1)); + st = quicc_read2(bas, rb); + quicc_write2(bas, rb, st | 0x9000); + uart_unlock(sc->sc_hwmtx); +} + diff --git a/sys/dev/uart/uart_dev_sab82532.c b/sys/dev/uart/uart_dev_sab82532.c index e2ec22766eac..8caa7a7f1234 100644 --- a/sys/dev/uart/uart_dev_sab82532.c +++ b/sys/dev/uart/uart_dev_sab82532.c @@ -365,6 +365,8 @@ static int sab82532_bus_probe(struct uart_softc *); static int sab82532_bus_receive(struct uart_softc *); static int sab82532_bus_setsig(struct uart_softc *, int); static int sab82532_bus_transmit(struct uart_softc *); +static void sab82532_bus_grab(struct uart_softc *); +static void sab82532_bus_ungrab(struct uart_softc *); static kobj_method_t sab82532_methods[] = { KOBJMETHOD(uart_attach, sab82532_bus_attach), @@ -378,6 +380,8 @@ static kobj_method_t sab82532_methods[] = { KOBJMETHOD(uart_receive, sab82532_bus_receive), KOBJMETHOD(uart_setsig, sab82532_bus_setsig), KOBJMETHOD(uart_transmit, sab82532_bus_transmit), + KOBJMETHOD(uart_grab, sab82532_bus_grab), + KOBJMETHOD(uart_ungrab, sab82532_bus_ungrab), { 0, 0 } }; @@ -724,3 +728,32 @@ sab82532_bus_transmit(struct uart_softc *sc) uart_unlock(sc->sc_hwmtx); return (0); } + +static void +sab82532_bus_grab(struct uart_softc *sc) +{ + struct uart_bas *bas; + uint8_t imr0; + + bas = &sc->sc_bas; + imr0 = SAB_IMR0_TIME|SAB_IMR0_CDSC|SAB_IMR0_RFO; /* No TCD or RPF */ + uart_lock(sc->sc_hwmtx); + uart_setreg(bas, SAB_IMR0, 0xff & ~imr0); + uart_barrier(bas); + uart_unlock(sc->sc_hwmtx); +} + +static void +sab82532_bus_ungrab(struct uart_softc *sc) +{ + struct uart_bas *bas; + uint8_t imr0; + + bas = &sc->sc_bas; + imr0 = SAB_IMR0_TCD|SAB_IMR0_TIME|SAB_IMR0_CDSC|SAB_IMR0_RFO| + SAB_IMR0_RPF; + uart_lock(sc->sc_hwmtx); + uart_setreg(bas, SAB_IMR0, 0xff & ~imr0); + uart_barrier(bas); + uart_unlock(sc->sc_hwmtx); +} diff --git a/sys/dev/uart/uart_dev_z8530.c b/sys/dev/uart/uart_dev_z8530.c index f948b26fa2fa..5cc24a80bd62 100644 --- a/sys/dev/uart/uart_dev_z8530.c +++ b/sys/dev/uart/uart_dev_z8530.c @@ -281,6 +281,8 @@ static int z8530_bus_probe(struct uart_softc *); static int z8530_bus_receive(struct uart_softc *); static int z8530_bus_setsig(struct uart_softc *, int); static int z8530_bus_transmit(struct uart_softc *); +static void z8530_bus_grab(struct uart_softc *); +static void z8530_bus_ungrab(struct uart_softc *); static kobj_method_t z8530_methods[] = { KOBJMETHOD(uart_attach, z8530_bus_attach), @@ -294,6 +296,8 @@ static kobj_method_t z8530_methods[] = { KOBJMETHOD(uart_receive, z8530_bus_receive), KOBJMETHOD(uart_setsig, z8530_bus_setsig), KOBJMETHOD(uart_transmit, z8530_bus_transmit), + KOBJMETHOD(uart_grab, z8530_bus_grab), + KOBJMETHOD(uart_ungrab, z8530_bus_ungrab), { 0, 0 } }; @@ -621,3 +625,27 @@ z8530_bus_transmit(struct uart_softc *sc) uart_unlock(sc->sc_hwmtx); return (0); } + +static void +z8530_bus_grab(struct uart_softc *sc) +{ + struct uart_bas *bas; + + bas = &sc->sc_bas; + uart_lock(sc->sc_hwmtx); + uart_setmreg(bas, WR_IDT, IDT_XIE | IDT_TIE); + uart_barrier(bas); + uart_unlock(sc->sc_hwmtx); +} + +static void +z8530_bus_ungrab(struct uart_softc *sc) +{ + struct uart_bas *bas; + + bas = &sc->sc_bas; + uart_lock(sc->sc_hwmtx); + uart_setmreg(bas, WR_IDT, IDT_XIE | IDT_TIE | IDT_RIA); + uart_barrier(bas); + uart_unlock(sc->sc_hwmtx); +} diff --git a/sys/dev/uart/uart_if.m b/sys/dev/uart/uart_if.m index bfac07134486..aab777172fb0 100644 --- a/sys/dev/uart/uart_if.m +++ b/sys/dev/uart/uart_if.m @@ -141,3 +141,19 @@ METHOD int setsig { METHOD int transmit { struct uart_softc *this; }; + +# grab() - Up call from the console to the upper layers of the driver when +# the kernel asks to grab the console. This is valid only for console +# drivers. This method is responsible for transitioning the hardware +# from an interrupt driven state to a polled state that works with the +# low-level console interface defined for this device. The kernel +# currently only calls this when it wants to grab input from the +# console. Output can still happen asyncrhonously to these calls. +METHOD void grab { + struct uart_softc *this; +}; + +# ungrab() - Undoes the effects of grab(). +METHOD void ungrab { + struct uart_softc *this; +}; diff --git a/sys/dev/usb/net/uhso.c b/sys/dev/usb/net/uhso.c index 2e50d7a1970d..ec84b0fdc944 100644 --- a/sys/dev/usb/net/uhso.c +++ b/sys/dev/usb/net/uhso.c @@ -817,6 +817,8 @@ uhso_probe_iface_auto(struct usb_device *udev, int index) UHSO_PORT_SERIAL | UHSO_PORT_NETWORK, port)); case UHSO_PORT_TYPE_DIAG: case UHSO_PORT_TYPE_DIAG2: + case UHSO_PORT_TYPE_GPS: + case UHSO_PORT_TYPE_GPSCTL: case UHSO_PORT_TYPE_CTL: case UHSO_PORT_TYPE_APP: case UHSO_PORT_TYPE_APP2: diff --git a/sys/dev/usb/usb_dev.c b/sys/dev/usb/usb_dev.c index 9e3cef5220a7..6a3080f1fccc 100644 --- a/sys/dev/usb/usb_dev.c +++ b/sys/dev/usb/usb_dev.c @@ -207,6 +207,11 @@ usb_ref_device(struct usb_cdev_privdata *cpd, DPRINTFN(2, "no device at %u\n", cpd->dev_index); goto error; } + if (cpd->udev->state == USB_STATE_DETACHED && + (need_uref != 2)) { + DPRINTFN(2, "device is detached\n"); + goto error; + } if (cpd->udev->refcount == USB_DEV_REF_MAX) { DPRINTFN(2, "no dev ref\n"); goto error; @@ -597,6 +602,13 @@ usb_fifo_free(struct usb_fifo *f) mtx_unlock(f->priv_mtx); mtx_lock(&usb_ref_lock); + /* + * Check if the "f->refcount" variable reached zero + * during the unlocked time before entering wait: + */ + if (f->refcount == 0) + break; + /* wait for sync */ cv_wait(&f->cv_drain, &usb_ref_lock); } @@ -915,23 +927,12 @@ usb_close(void *arg) DPRINTFN(2, "cpd=%p\n", cpd); - err = usb_ref_device(cpd, &refs, 0); - if (err) + err = usb_ref_device(cpd, &refs, + 2 /* uref and allow detached state */); + if (err) { + DPRINTFN(0, "Cannot grab USB reference when " + "closing USB file handle\n"); goto done; - - /* - * If this function is not called directly from the root HUB - * thread, there is usually a need to lock the enumeration - * lock. Check this. - */ - if (!usbd_enum_is_locked(cpd->udev)) { - - DPRINTFN(2, "Locking enumeration\n"); - - /* reference device */ - err = usb_usb_ref_device(cpd, &refs); - if (err) - goto done; } if (cpd->fflags & FREAD) { usb_fifo_close(refs.rxfifo, cpd->fflags); diff --git a/sys/dev/usb/usb_device.c b/sys/dev/usb/usb_device.c index 08c3cd08db32..0e9176c0aa4d 100644 --- a/sys/dev/usb/usb_device.c +++ b/sys/dev/usb/usb_device.c @@ -2070,6 +2070,8 @@ usb_free_device(struct usb_device *udev, uint8_t flag) DPRINTFN(4, "udev=%p port=%d\n", udev, udev->port_no); bus = udev->bus; + + /* set DETACHED state to prevent any further references */ usb_set_device_state(udev, USB_STATE_DETACHED); #if USB_HAVE_DEVCTL @@ -2085,16 +2087,7 @@ usb_free_device(struct usb_device *udev, uint8_t flag) usb_free_symlink(udev->ugen_symlink); udev->ugen_symlink = NULL; } -#endif - /* - * Unregister our device first which will prevent any further - * references: - */ - usb_bus_port_set_device(bus, udev->parent_hub ? - udev->parent_hub->hub->ports + udev->port_index : NULL, - NULL, USB_ROOT_HUB_ADDR); -#if USB_HAVE_UGEN /* wait for all pending references to go away: */ mtx_lock(&usb_ref_lock); udev->refcount--; @@ -2114,6 +2107,11 @@ usb_free_device(struct usb_device *udev, uint8_t flag) /* the following will get the device unconfigured in software */ usb_unconfigure(udev, USB_UNCFG_FLAG_FREE_EP0); + /* final device unregister after all character devices are closed */ + usb_bus_port_set_device(bus, udev->parent_hub ? + udev->parent_hub->hub->ports + udev->port_index : NULL, + NULL, USB_ROOT_HUB_ADDR); + /* unsetup any leftover default USB transfers */ usbd_transfer_unsetup(udev->ctrl_xfer, USB_CTRL_XFER_MAX); @@ -2647,8 +2645,14 @@ usb_set_device_state(struct usb_device *udev, enum usb_dev_state state) DPRINTF("udev %p state %s -> %s\n", udev, usb_statestr(udev->state), usb_statestr(state)); - udev->state = state; +#if USB_HAVE_UGEN + mtx_lock(&usb_ref_lock); +#endif + udev->state = state; +#if USB_HAVE_UGEN + mtx_unlock(&usb_ref_lock); +#endif if (udev->bus->methods->device_state_change != NULL) (udev->bus->methods->device_state_change) (udev); } diff --git a/sys/dev/virtio/random/virtio_random.c b/sys/dev/virtio/random/virtio_random.c new file mode 100644 index 000000000000..f44878f21897 --- /dev/null +++ b/sys/dev/virtio/random/virtio_random.c @@ -0,0 +1,231 @@ +/*- + * Copyright (c) 2013, Bryan Venteicher + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Driver for VirtIO entropy device. */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +struct vtrnd_softc { + device_t vtrnd_dev; + uint64_t vtrnd_features; + struct callout vtrnd_callout; + struct virtqueue *vtrnd_vq; +}; + +static int vtrnd_modevent(module_t, int, void *); + +static int vtrnd_probe(device_t); +static int vtrnd_attach(device_t); +static int vtrnd_detach(device_t); + +static void vtrnd_negotiate_features(struct vtrnd_softc *); +static int vtrnd_alloc_virtqueue(struct vtrnd_softc *); +static void vtrnd_harvest(struct vtrnd_softc *); +static void vtrnd_timer(void *); + +#define VTRND_FEATURES 0 + +static struct virtio_feature_desc vtrnd_feature_desc[] = { + { 0, NULL } +}; + +static device_method_t vtrnd_methods[] = { + /* Device methods. */ + DEVMETHOD(device_probe, vtrnd_probe), + DEVMETHOD(device_attach, vtrnd_attach), + DEVMETHOD(device_detach, vtrnd_detach), + + DEVMETHOD_END +}; + +static driver_t vtrnd_driver = { + "vtrnd", + vtrnd_methods, + sizeof(struct vtrnd_softc) +}; +static devclass_t vtrnd_devclass; + +DRIVER_MODULE(virtio_random, virtio_pci, vtrnd_driver, vtrnd_devclass, + vtrnd_modevent, 0); +MODULE_VERSION(virtio_random, 1); +MODULE_DEPEND(virtio_random, virtio, 1, 1, 1); + +static int +vtrnd_modevent(module_t mod, int type, void *unused) +{ + int error; + + switch (type) { + case MOD_LOAD: + case MOD_QUIESCE: + case MOD_UNLOAD: + case MOD_SHUTDOWN: + error = 0; + break; + default: + error = EOPNOTSUPP; + break; + } + + return (error); +} + +static int +vtrnd_probe(device_t dev) +{ + + if (virtio_get_device_type(dev) != VIRTIO_ID_ENTROPY) + return (ENXIO); + + device_set_desc(dev, "VirtIO Entropy Adapter"); + + return (BUS_PROBE_DEFAULT); +} + +static int +vtrnd_attach(device_t dev) +{ + struct vtrnd_softc *sc; + int error; + + sc = device_get_softc(dev); + sc->vtrnd_dev = dev; + + callout_init(&sc->vtrnd_callout, CALLOUT_MPSAFE); + + virtio_set_feature_desc(dev, vtrnd_feature_desc); + vtrnd_negotiate_features(sc); + + error = vtrnd_alloc_virtqueue(sc); + if (error) { + device_printf(dev, "cannot allocate virtqueue\n"); + goto fail; + } + + callout_reset(&sc->vtrnd_callout, 5 * hz, vtrnd_timer, sc); + +fail: + if (error) + vtrnd_detach(dev); + + return (error); +} + +static int +vtrnd_detach(device_t dev) +{ + struct vtrnd_softc *sc; + + sc = device_get_softc(dev); + + callout_stop(&sc->vtrnd_callout); + + return (0); +} + +static void +vtrnd_negotiate_features(struct vtrnd_softc *sc) +{ + device_t dev; + uint64_t features; + + dev = sc->vtrnd_dev; + features = VTRND_FEATURES; + + sc->vtrnd_features = virtio_negotiate_features(dev, features); +} + +static int +vtrnd_alloc_virtqueue(struct vtrnd_softc *sc) +{ + device_t dev; + struct vq_alloc_info vq_info; + + dev = sc->vtrnd_dev; + + VQ_ALLOC_INFO_INIT(&vq_info, 0, NULL, sc, &sc->vtrnd_vq, + "%s request", device_get_nameunit(dev)); + + return (virtio_alloc_virtqueues(dev, 0, 1, &vq_info)); +} + +static void +vtrnd_harvest(struct vtrnd_softc *sc) +{ + struct sglist_seg segs[1]; + struct sglist sg; + struct virtqueue *vq; + uint32_t value; + int error; + + vq = sc->vtrnd_vq; + + sglist_init(&sg, 1, segs); + error = sglist_append(&sg, &value, sizeof(value)); + KASSERT(error == 0 && sg.sg_nseg == 1, + ("%s: error %d adding buffer to sglist", __func__, error)); + + if (!virtqueue_empty(vq)) + return; + if (virtqueue_enqueue(vq, &value, &sg, 0, 1) != 0) + return; + + /* + * Poll for the response, but the command is likely already + * done when we return from the notify. + */ + virtqueue_notify(vq); + virtqueue_poll(vq, NULL); + + random_harvest(&value, sizeof(value), sizeof(value) * NBBY / 2, + RANDOM_PURE_VIRTIO); +} + +static void +vtrnd_timer(void *xsc) +{ + struct vtrnd_softc *sc; + + sc = xsc; + + vtrnd_harvest(sc); + callout_schedule(&sc->vtrnd_callout, 5 * hz); +} diff --git a/sys/dev/vt/hw/xboxfb/xboxfb.c b/sys/dev/vt/hw/xboxfb/xboxfb.c index ae26d736781a..8186f5e6bf69 100644 --- a/sys/dev/vt/hw/xboxfb/xboxfb.c +++ b/sys/dev/vt/hw/xboxfb/xboxfb.c @@ -1,12 +1,9 @@ /*- - * Copyright (c) 2005 Rink Springer + * Copyright (c) 2013 The FreeBSD Foundation * All rights reserved. * - * Copyright (c) 2009 The FreeBSD Foundation - * All rights reserved. - * - * Portions of this software were developed by Ed Schouten - * under sponsorship from the FreeBSD Foundation. + * This software was developed by Aleksandr Rybalko under sponsorship from the + * FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,16 +25,23 @@ * 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 __FBSDID("$FreeBSD$"); #include -#include #include +#include +#include + +#include "opt_platform.h" #include +#include +#include #include #include @@ -47,110 +51,32 @@ __FBSDID("$FreeBSD$"); #include #include -struct xbox_softc { - bus_space_tag_t xbox_fb_tag; - bus_space_handle_t xbox_fb_handle; -}; - -/* Convenience macros. */ -#define MEM_WRITE4(sc, ofs, val) \ - bus_space_write_4(sc->xbox_fb_tag, sc->xbox_fb_handle, ofs, val) - #define VT_XBOX_WIDTH 640 #define VT_XBOX_HEIGHT 480 -static vd_init_t xbox_init; -static vd_blank_t xbox_blank; -static vd_bitbltchr_t xbox_bitbltchr; +static vd_init_t xboxfb_init; -static const struct vt_driver vt_xbox_driver = { - .vd_init = xbox_init, - .vd_blank = xbox_blank, - .vd_bitbltchr = xbox_bitbltchr, - .vd_priority = VD_PRIORITY_GENERIC+1, +static struct vt_driver xboxfb_driver = { + .vd_init = xboxfb_init, + .vd_blank = vt_fb_blank, + .vd_bitbltchr = vt_fb_bitbltchr, + .vd_priority = VD_PRIORITY_GENERIC, }; -static struct xbox_softc xbox_conssoftc; -VT_CONSDEV_DECLARE(vt_xbox_driver, PIXEL_WIDTH(VT_XBOX_WIDTH), - PIXEL_HEIGHT(VT_XBOX_HEIGHT), &xbox_conssoftc); +static struct fb_info xboxfb_info; +VT_CONSDEV_DECLARE(xboxfb_driver, PIXEL_WIDTH(VT_XBOX_WIDTH), + PIXEL_HEIGHT(VT_XBOX_HEIGHT), &xboxfb_info); -static const uint32_t colormap[] = { - 0x00000000, /* Black */ - 0x00ff0000, /* Red */ - 0x0000ff00, /* Green */ - 0x00c0c000, /* Brown */ - 0x000000ff, /* Blue */ - 0x00c000c0, /* Magenta */ - 0x0000c0c0, /* Cyan */ - 0x00c0c0c0, /* Light grey */ - 0x00808080, /* Dark grey */ - 0x00ff8080, /* Light red */ - 0x0080ff80, /* Light green */ - 0x00ffff80, /* Yellow */ - 0x008080ff, /* Light blue */ - 0x00ff80ff, /* Light magenta */ - 0x0080ffff, /* Light cyan */ - 0x00ffffff, /* White */ -}; - -static void -xbox_blank(struct vt_device *vd, term_color_t color) -{ - struct xbox_softc *sc = vd->vd_softc; - u_int ofs; - uint32_t c; - - c = colormap[color]; - for (ofs = 0; ofs < (VT_XBOX_WIDTH * VT_XBOX_HEIGHT) * 4; ofs += 4) - MEM_WRITE4(sc, ofs, c); -} - -static void -xbox_bitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask, - int bpl, vt_axis_t top, vt_axis_t left, unsigned int width, - unsigned int height, term_color_t fg, term_color_t bg) -{ - struct xbox_softc *sc = vd->vd_softc; - u_long line; - uint32_t fgc, bgc; - int c; - uint8_t b, m; - - fgc = colormap[fg]; - bgc = colormap[bg]; - - /* Don't try to put off screen pixels */ - if (((left + width) > info->fb_width) || ((top + height) > - info->fb_height)) - return; - - line = (VT_XBOX_WIDTH * top + left) * 4; - for (; height > 0; height--) { - for (c = 0; c < width; c++) { - if (c % 8 == 0) - b = *src++; - else - b <<= 1; - if (mask != NULL) { - if (c % 8 == 0) - m = *mask++; - else - m <<= 1; - /* Skip pixel write, if mask has no bit set. */ - if ((m & 0x80) == 0) - continue; - } - MEM_WRITE4(sc, line + c * 4, b & 0x80 ? fgc : bgc); - } - line += VT_XBOX_WIDTH * 4; - } -} - -static void -xbox_initialize(struct vt_device *vd) +static int +xboxfb_init(struct vt_device *vd) { + struct fb_info *info; int i; + if (!arch_i386_is_xbox) + return (CN_DEAD); + + info = &xboxfb_info; /* * We must make a mapping from video framebuffer memory * to real. This is very crude: we map the entire @@ -175,25 +101,27 @@ xbox_initialize(struct vt_device *vd) *(uint32_t *)((i + 1) * PAGE_SIZE + XBOX_FB_START_PTR % PAGE_SIZE) = XBOX_FB_START; - /* Clear the screen. */ - xbox_blank(vd, TC_BLACK); -} + /* Initialize fb_info. */ + info = vd->vd_softc; -static int -xbox_init(struct vt_device *vd) -{ - struct xbox_softc *sc = vd->vd_softc; + info->fb_width = VT_XBOX_WIDTH; + info->fb_height = VT_XBOX_HEIGHT; - if (!arch_i386_is_xbox) - return (CN_DEAD); + info->fb_size = XBOX_FB_SIZE; + info->fb_stride = VT_XBOX_WIDTH * 4; /* 32bits per pixel. */ - sc->xbox_fb_tag = X86_BUS_SPACE_MEM; - sc->xbox_fb_handle = PAGE_SIZE; + info->fb_vbase = PAGE_SIZE; + info->fb_pbase = XBOX_FB_START_PTR; - vd->vd_width = VT_XBOX_WIDTH; - vd->vd_height = VT_XBOX_HEIGHT; + /* Get pixel storage size. */ + info->fb_bpp = 32; + /* Get color depth. */ + info->fb_depth = 24; - xbox_initialize(vd); + vt_generate_vga_palette(info->fb_cmap, COLOR_FORMAT_RGB, 255, 0, 255, + 8, 255, 16); + fb_probe(info); + vt_fb_init(vd); return (CN_INTERNAL); } @@ -201,12 +129,13 @@ xbox_init(struct vt_device *vd) static void xbox_remap(void *unused) { + struct fb_info *info; if (!arch_i386_is_xbox) return; - xbox_conssoftc.xbox_fb_handle = - (bus_space_handle_t)pmap_mapdev(XBOX_FB_START, XBOX_FB_SIZE); + info = &xboxfb_info; + info->fb_vbase = (intptr_t)pmap_mapdev(info->fb_pbase, info->fb_size); } SYSINIT(xboxfb, SI_SUB_DRIVERS, SI_ORDER_ANY, xbox_remap, NULL); diff --git a/sys/geom/multipath/g_multipath.c b/sys/geom/multipath/g_multipath.c index 88e65f8b2021..7593ccaa238a 100644 --- a/sys/geom/multipath/g_multipath.c +++ b/sys/geom/multipath/g_multipath.c @@ -1089,7 +1089,6 @@ g_multipath_ctl_create(struct gctl_req *req, struct g_class *mp) gctl_error(req, "Device %s already exist", mpname); return; } - sc = gp->softc; memset(&md, 0, sizeof(md)); strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic)); diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES index 212dbd9a17bf..2325124cdec3 100644 --- a/sys/i386/conf/NOTES +++ b/sys/i386/conf/NOTES @@ -800,6 +800,7 @@ device vtnet # VirtIO Ethernet device device virtio_blk # VirtIO Block device device virtio_scsi # VirtIO SCSI device device virtio_balloon # VirtIO Memory Balloon device +device virtio_random # VirtIO Entropy device device hyperv # HyperV drivers diff --git a/sys/i386/conf/VT b/sys/i386/conf/VT new file mode 100644 index 000000000000..7d0547f11456 --- /dev/null +++ b/sys/i386/conf/VT @@ -0,0 +1,14 @@ +# VT -- kernel config using the vt(9) system console instead of legacy syscons +# +# For more information see https://wiki.freebsd.org/Newcons +# +# $FreeBSD$ + +include GENERIC +ident VT + +nodevice sc +nodevice vga + +device vt +device vt_vga diff --git a/sys/ia64/conf/GENERIC b/sys/ia64/conf/GENERIC index 82008431a493..0a16b877980d 100644 --- a/sys/ia64/conf/GENERIC +++ b/sys/ia64/conf/GENERIC @@ -192,7 +192,9 @@ options AH_SUPPORT_AR5416 # Various (pseudo) devices device ether # Ethernet support device faith # IPv6-to-IPv4 relaying (translation) +device firmware # firmware assist module device gif # IPv6 and IPv4 tunneling +device kbdmux # keyboard multiplexer device loop # Network loopback device md # Memory "disks" device puc # Multi I/O cards and multi-channel UARTs @@ -200,7 +202,8 @@ device random # Entropy device device tun # Packet tunnel. device uart # Serial port (UART) device vlan # 802.1Q VLAN support -device firmware # firmware assist module +device vt # Virtual terminals +device vt_vga # VGA terminal device # The `bpf' device enables the Berkeley Packet Filter. # Be aware of the administrative consequences of enabling this! diff --git a/sys/ia64/ia64/pmap.c b/sys/ia64/ia64/pmap.c index dbddb5fa9adf..038725fcfd88 100644 --- a/sys/ia64/ia64/pmap.c +++ b/sys/ia64/ia64/pmap.c @@ -1303,6 +1303,8 @@ pmap_set_pte(struct ia64_lpte *pte, vm_offset_t va, vm_offset_t pa, pte->itir = PAGE_SHIFT << 2; + ia64_mf(); + pte->tag = ia64_ttag(va); } @@ -1321,8 +1323,8 @@ pmap_remove_pte(pmap_t pmap, struct ia64_lpte *pte, vm_offset_t va, * First remove from the VHPT. */ error = pmap_remove_vhpt(va); - if (error) - return (error); + KASSERT(error == 0, ("%s: pmap_remove_vhpt returned %d", + __func__, error)); pmap_invalidate_page(va); diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c index f24032551604..72386e0ff438 100644 --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -294,6 +294,7 @@ static struct { { &fs_filtops }, /* EVFILT_FS */ { &null_filtops }, /* EVFILT_LIO */ { &user_filtops }, /* EVFILT_USER */ + { &null_filtops }, /* EVFILT_SENDFILE */ }; /* diff --git a/sys/kern/subr_witness.c b/sys/kern/subr_witness.c index 9315133c083d..d2ba7a9944d2 100644 --- a/sys/kern/subr_witness.c +++ b/sys/kern/subr_witness.c @@ -132,7 +132,7 @@ __FBSDID("$FreeBSD$"); /* Define this to check for blessed mutexes */ #undef BLESSING -#define WITNESS_COUNT 1024 +#define WITNESS_COUNT 1536 #define WITNESS_CHILDCOUNT (WITNESS_COUNT * 4) #define WITNESS_HASH_SIZE 251 /* Prime, gives load factor < 2 */ #define WITNESS_PENDLIST 1024 diff --git a/sys/kern/uipc_mbuf.c b/sys/kern/uipc_mbuf.c index a16af57a85b3..99092cfce37e 100644 --- a/sys/kern/uipc_mbuf.c +++ b/sys/kern/uipc_mbuf.c @@ -554,7 +554,7 @@ m_dup_pkthdr(struct mbuf *to, struct mbuf *from, int how) to->m_data = to->m_pktdat; to->m_pkthdr = from->m_pkthdr; SLIST_INIT(&to->m_pkthdr.tags); - return (m_tag_copy_chain(to, from, MBTOM(how))); + return (m_tag_copy_chain(to, from, how)); } /* diff --git a/sys/kern/uipc_sockbuf.c b/sys/kern/uipc_sockbuf.c index c23995f72c69..8e99f3e3899d 100644 --- a/sys/kern/uipc_sockbuf.c +++ b/sys/kern/uipc_sockbuf.c @@ -813,7 +813,7 @@ sbflush_internal(struct sockbuf *sb) while (sb->sb_mbcnt) { /* - * Don't call sbdrop(sb, 0) if the leading mbuf is non-empty: + * Don't call sbcut(sb, 0) if the leading mbuf is non-empty: * we would loop forever. Panic instead. */ if (!sb->sb_cc && (sb->sb_mb == NULL || sb->sb_mb->m_len)) diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index 9da42057f9e9..52c244e97aa2 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -1723,28 +1723,27 @@ soreceive_generic(struct socket *so, struct sockaddr **psa, struct uio *uio, moff += len; else { if (mp != NULL) { - int copy_flag; - - if (flags & MSG_DONTWAIT) - copy_flag = M_NOWAIT; - else - copy_flag = M_WAIT; - if (copy_flag == M_WAITOK) + if (flags & MSG_DONTWAIT) { + *mp = m_copym(m, 0, len, + M_NOWAIT); + if (*mp == NULL) { + /* + * m_copym() couldn't + * allocate an mbuf. + * Adjust uio_resid back + * (it was adjusted + * down by len bytes, + * which we didn't end + * up "copying" over). + */ + uio->uio_resid += len; + break; + } + } else { SOCKBUF_UNLOCK(&so->so_rcv); - *mp = m_copym(m, 0, len, copy_flag); - if (copy_flag == M_WAITOK) + *mp = m_copym(m, 0, len, + M_WAITOK); SOCKBUF_LOCK(&so->so_rcv); - if (*mp == NULL) { - /* - * m_copym() couldn't - * allocate an mbuf. Adjust - * uio_resid back (it was - * adjusted down by len - * bytes, which we didn't end - * up "copying" over). - */ - uio->uio_resid += len; - break; } } m->m_data += len; diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index 6dbdd522a2d1..9420dfda5800 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -123,6 +123,10 @@ static int getpeername1(struct thread *td, struct getpeername_args *uap, counter_u64_t sfstat[sizeof(struct sfstat) / sizeof(uint64_t)]; +static int filt_sfsync_attach(struct knote *kn); +static void filt_sfsync_detach(struct knote *kn); +static int filt_sfsync(struct knote *kn, long hint); + /* * sendfile(2)-related variables and associated sysctls */ @@ -132,8 +136,28 @@ static int sfreadahead = 1; SYSCTL_INT(_kern_ipc_sendfile, OID_AUTO, readahead, CTLFLAG_RW, &sfreadahead, 0, "Number of sendfile(2) read-ahead MAXBSIZE blocks"); +#ifdef SFSYNC_DEBUG +static int sf_sync_debug = 0; +SYSCTL_INT(_debug, OID_AUTO, sf_sync_debug, CTLFLAG_RW, + &sf_sync_debug, 0, "Output debugging during sf_sync lifecycle"); +#define SFSYNC_DPRINTF(s, ...) \ + do { \ + if (sf_sync_debug) \ + printf((s), ##__VA_ARGS__); \ + } while (0) +#else +#define SFSYNC_DPRINTF(c, ...) +#endif + static uma_zone_t zone_sfsync; +static struct filterops sendfile_filtops = { + .f_isfd = 0, + .f_attach = filt_sfsync_attach, + .f_detach = filt_sfsync_detach, + .f_event = filt_sfsync, +}; + static void sfstat_init(const void *unused) { @@ -152,6 +176,7 @@ sf_sync_init(const void *unused) NULL, NULL, UMA_ALIGN_CACHE, 0); + kqueue_add_filteropts(EVFILT_SENDFILE, &sendfile_filtops); } SYSINIT(sf_sync, SI_SUB_MBUF, SI_ORDER_FIRST, sf_sync_init, NULL); @@ -1860,6 +1885,118 @@ getsockaddr(namp, uaddr, len) return (error); } +static int +filt_sfsync_attach(struct knote *kn) +{ + struct sendfile_sync *sfs = (struct sendfile_sync *) kn->kn_sdata; + struct knlist *knl = &sfs->klist; + + SFSYNC_DPRINTF("%s: kn=%p, sfs=%p\n", __func__, kn, sfs); + + /* + * Validate that we actually received this via the kernel API. + */ + if ((kn->kn_flags & EV_FLAG1) == 0) + return (EPERM); + + kn->kn_ptr.p_v = sfs; + kn->kn_flags &= ~EV_FLAG1; + + knl->kl_lock(knl->kl_lockarg); + /* + * If we're in the "freeing" state, + * don't allow the add. That way we don't + * end up racing with some other thread that + * is trying to finish some setup. + */ + if (sfs->state == SF_STATE_FREEING) { + knl->kl_unlock(knl->kl_lockarg); + return (EINVAL); + } + knlist_add(&sfs->klist, kn, 1); + knl->kl_unlock(knl->kl_lockarg); + + return (0); +} + +/* + * Called when a knote is being detached. + */ +static void +filt_sfsync_detach(struct knote *kn) +{ + struct knlist *knl; + struct sendfile_sync *sfs; + int do_free = 0; + + sfs = kn->kn_ptr.p_v; + knl = &sfs->klist; + + SFSYNC_DPRINTF("%s: kn=%p, sfs=%p\n", __func__, kn, sfs); + + knl->kl_lock(knl->kl_lockarg); + if (!knlist_empty(knl)) + knlist_remove(knl, kn, 1); + + /* + * If the list is empty _AND_ the refcount is 0 + * _AND_ we've finished the setup phase and now + * we're in the running phase, we can free the + * underlying sendfile_sync. + * + * But we shouldn't do it before finishing the + * underlying divorce from the knote. + * + * So, we have the sfsync lock held; transition + * it to "freeing", then unlock, then free + * normally. + */ + if (knlist_empty(knl)) { + if (sfs->state == SF_STATE_COMPLETED && sfs->count == 0) { + SFSYNC_DPRINTF("%s: (%llu) sfs=%p; completed, " + "count==0, empty list: time to free!\n", + __func__, + (unsigned long long) curthread->td_tid, + sfs); + sf_sync_set_state(sfs, SF_STATE_FREEING, 1); + do_free = 1; + } + } + knl->kl_unlock(knl->kl_lockarg); + + /* + * Only call free if we're the one who has transitioned things + * to free. Otherwise we could race with another thread that + * is currently tearing things down. + */ + if (do_free == 1) { + SFSYNC_DPRINTF("%s: (%llu) sfs=%p, %s:%d\n", + __func__, + (unsigned long long) curthread->td_tid, + sfs, + __FILE__, + __LINE__); + sf_sync_free(sfs); + } +} + +static int +filt_sfsync(struct knote *kn, long hint) +{ + struct sendfile_sync *sfs = (struct sendfile_sync *) kn->kn_ptr.p_v; + int ret; + + SFSYNC_DPRINTF("%s: kn=%p, sfs=%p\n", __func__, kn, sfs); + + /* + * XXX add a lock assertion here! + */ + ret = (sfs->count == 0 && sfs->state == SF_STATE_COMPLETED); + + return (ret); +} + + /* * Detach mapped page and release resources back to the system. */ @@ -1885,21 +2022,97 @@ sf_buf_mext(struct mbuf *mb, void *addr, void *args) sfs = addr; sf_sync_deref(sfs); } + /* + * sfs may be invalid at this point, don't use it! + */ return (EXT_FREE_OK); } +/* + * Called to remove a reference to a sf_sync object. + * + * This is generally done during the mbuf free path to signify + * that one of the mbufs in the transaction has been completed. + * + * If we're doing SF_SYNC and the refcount is zero then we'll wake + * up any waiters. + * + * IF we're doing SF_KQUEUE and the refcount is zero then we'll + * fire off the knote. + */ void sf_sync_deref(struct sendfile_sync *sfs) { + int do_free = 0; if (sfs == NULL) return; mtx_lock(&sfs->mtx); KASSERT(sfs->count> 0, ("Sendfile sync botchup count == 0")); - if (--sfs->count == 0) - cv_signal(&sfs->cv); + sfs->count --; + + /* + * Only fire off the wakeup / kqueue notification if + * we are in the running state. + */ + if (sfs->count == 0 && sfs->state == SF_STATE_COMPLETED) { + if (sfs->flags & SF_SYNC) + cv_signal(&sfs->cv); + + if (sfs->flags & SF_KQUEUE) { + SFSYNC_DPRINTF("%s: (%llu) sfs=%p: knote!\n", + __func__, + (unsigned long long) curthread->td_tid, + sfs); + KNOTE_LOCKED(&sfs->klist, 1); + } + + /* + * If we're not waiting around for a sync, + * check if the knote list is empty. + * If it is, we transition to free. + * + * XXX I think it's about time I added some state + * or flag that says whether we're supposed to be + * waiting around until we've done a signal. + * + * XXX Ie, the reason that I don't free it here + * is because the caller will free the last reference, + * not us. That should be codified in some flag + * that indicates "self-free" rather than checking + * for SF_SYNC all the time. + */ + if ((sfs->flags & SF_SYNC) == 0 && knlist_empty(&sfs->klist)) { + SFSYNC_DPRINTF("%s: (%llu) sfs=%p; completed, " + "count==0, empty list: time to free!\n", + __func__, + (unsigned long long) curthread->td_tid, + sfs); + sf_sync_set_state(sfs, SF_STATE_FREEING, 1); + do_free = 1; + } + + } mtx_unlock(&sfs->mtx); + + /* + * Attempt to do a free here. + * + * We do this outside of the lock because it may destroy the + * lock in question as it frees things. We can optimise this + * later. + * + * XXX yes, we should make it a requirement to hold the + * lock across sf_sync_free(). + */ + if (do_free == 1) { + SFSYNC_DPRINTF("%s: (%llu) sfs=%p\n", + __func__, + (unsigned long long) curthread->td_tid, + sfs); + sf_sync_free(sfs); + } } /* @@ -1917,6 +2130,10 @@ sf_sync_alloc(uint32_t flags) mtx_init(&sfs->mtx, "sendfile", NULL, MTX_DEF); cv_init(&sfs->cv, "sendfile"); sfs->flags = flags; + sfs->state = SF_STATE_SETUP; + knlist_init_mtx(&sfs->klist, &sfs->mtx); + + SFSYNC_DPRINTF("%s: sfs=%p, flags=0x%08x\n", __func__, sfs, sfs->flags); return (sfs); } @@ -1946,13 +2163,49 @@ sf_sync_syscall_wait(struct sendfile_sync *sfs) if (sfs == NULL) return; - mtx_lock(&sfs->mtx); + KASSERT(mtx_owned(&sfs->mtx), ("%s: sfs=%p: not locked but should be!", + __func__, + sfs)); + + /* + * If we're not requested to wait during the syscall, + * don't bother waiting. + */ + if ((sfs->flags & SF_SYNC) == 0) + goto out; + + /* + * This is a bit suboptimal and confusing, so bear with me. + * + * Ideally sf_sync_syscall_wait() will wait until + * all pending mbuf transmit operations are done. + * This means that when sendfile becomes async, it'll + * run in the background and will transition from + * RUNNING to COMPLETED when it's finished acquiring + * new things to send. Then, when the mbufs finish + * sending, COMPLETED + sfs->count == 0 is enough to + * know that no further work is being done. + * + * So, we will sleep on both RUNNING and COMPLETED. + * It's up to the (in progress) async sendfile loop + * to transition the sf_sync from RUNNING to + * COMPLETED so the wakeup above will actually + * do the cv_signal() call. + */ + if (sfs->state != SF_STATE_COMPLETED && sfs->state != SF_STATE_RUNNING) + goto out; + if (sfs->count != 0) cv_wait(&sfs->cv, &sfs->mtx); KASSERT(sfs->count == 0, ("sendfile sync still busy")); - mtx_unlock(&sfs->mtx); + +out: + return; } +/* + * Free an sf_sync if it's appropriate to. + */ void sf_sync_free(struct sendfile_sync *sfs) { @@ -1960,17 +2213,157 @@ sf_sync_free(struct sendfile_sync *sfs) if (sfs == NULL) return; - /* - * XXX we should ensure that nothing else has this - * locked before freeing. - */ + SFSYNC_DPRINTF("%s: (%lld) sfs=%p; called; state=%d, flags=0x%08x " + "count=%d\n", + __func__, + (long long) curthread->td_tid, + sfs, + sfs->state, + sfs->flags, + sfs->count); + mtx_lock(&sfs->mtx); + + /* + * We keep the sf_sync around if the state is active, + * we are doing kqueue notification and we have active + * knotes. + * + * If the caller wants to free us right this second it + * should transition this to the freeing state. + * + * So, complain loudly if they break this rule. + */ + if (sfs->state != SF_STATE_FREEING) { + printf("%s: (%llu) sfs=%p; not freeing; let's wait!\n", + __func__, + (unsigned long long) curthread->td_tid, + sfs); + mtx_unlock(&sfs->mtx); + return; + } + KASSERT(sfs->count == 0, ("sendfile sync still busy")); cv_destroy(&sfs->cv); + /* + * This doesn't call knlist_detach() on each knote; it just frees + * the entire list. + */ + knlist_delete(&sfs->klist, curthread, 1); mtx_destroy(&sfs->mtx); + SFSYNC_DPRINTF("%s: (%llu) sfs=%p; freeing\n", + __func__, + (unsigned long long) curthread->td_tid, + sfs); uma_zfree(zone_sfsync, sfs); } +/* + * Setup a sf_sync to post a kqueue notification when things are complete. + */ +int +sf_sync_kqueue_setup(struct sendfile_sync *sfs, struct sf_hdtr_kq *sfkq) +{ + struct kevent kev; + int error; + + sfs->flags |= SF_KQUEUE; + + /* Check the flags are valid */ + if ((sfkq->kq_flags & ~(EV_CLEAR | EV_DISPATCH | EV_ONESHOT)) != 0) + return (EINVAL); + + SFSYNC_DPRINTF("%s: sfs=%p: kqfd=%d, flags=0x%08x, ident=%p, udata=%p\n", + __func__, + sfs, + sfkq->kq_fd, + sfkq->kq_flags, + (void *) sfkq->kq_ident, + (void *) sfkq->kq_udata); + + /* Setup and register a knote on the given kqfd. */ + kev.ident = (uintptr_t) sfkq->kq_ident; + kev.filter = EVFILT_SENDFILE; + kev.flags = EV_ADD | EV_ENABLE | EV_FLAG1 | sfkq->kq_flags; + kev.data = (intptr_t) sfs; + kev.udata = sfkq->kq_udata; + + error = kqfd_register(sfkq->kq_fd, &kev, curthread, 1); + if (error != 0) { + SFSYNC_DPRINTF("%s: returned %d\n", __func__, error); + } + return (error); +} + +void +sf_sync_set_state(struct sendfile_sync *sfs, sendfile_sync_state_t state, + int islocked) +{ + sendfile_sync_state_t old_state; + + if (! islocked) + mtx_lock(&sfs->mtx); + + /* + * Update our current state. + */ + old_state = sfs->state; + sfs->state = state; + SFSYNC_DPRINTF("%s: (%llu) sfs=%p; going from %d to %d\n", + __func__, + (unsigned long long) curthread->td_tid, + sfs, + old_state, + state); + + /* + * If we're transitioning from RUNNING to COMPLETED and the count is + * zero, then post the knote. The caller may have completed the + * send before we updated the state to COMPLETED and we need to make + * sure this is communicated. + */ + if (old_state == SF_STATE_RUNNING + && state == SF_STATE_COMPLETED + && sfs->count == 0 + && sfs->flags & SF_KQUEUE) { + SFSYNC_DPRINTF("%s: (%llu) sfs=%p: triggering knote!\n", + __func__, + (unsigned long long) curthread->td_tid, + sfs); + KNOTE_LOCKED(&sfs->klist, 1); + } + + if (! islocked) + mtx_unlock(&sfs->mtx); +} + +/* + * Set the retval/errno for the given transaction. + * + * This will eventually/ideally be used when the KNOTE is fired off + * to signify the completion of this transaction. + * + * The sfsync lock should be held before entering this function. + */ +void +sf_sync_set_retval(struct sendfile_sync *sfs, off_t retval, int xerrno) +{ + + KASSERT(mtx_owned(&sfs->mtx), ("%s: sfs=%p: not locked but should be!", + __func__, + sfs)); + + SFSYNC_DPRINTF("%s: (%llu) sfs=%p: errno=%d, retval=%jd\n", + __func__, + (unsigned long long) curthread->td_tid, + sfs, + xerrno, + (intmax_t) retval); + + sfs->retval = retval; + sfs->xerrno = xerrno; +} + /* * sendfile(2) * @@ -1992,15 +2385,21 @@ sys_sendfile(struct thread *td, struct sendfile_args *uap) int _do_sendfile(struct thread *td, int src_fd, int sock_fd, int flags, int compat, off_t offset, size_t nbytes, off_t *sbytes, - struct uio *hdr_uio, struct uio *trl_uio) + struct uio *hdr_uio, + struct uio *trl_uio, struct sf_hdtr_kq *hdtr_kq) { cap_rights_t rights; struct sendfile_sync *sfs = NULL; struct file *fp; int error; + int do_kqueue = 0; + int do_free = 0; AUDIT_ARG_FD(src_fd); + if (hdtr_kq != NULL) + do_kqueue = 1; + /* * sendfile(2) can start at any offset within a file so we require * CAP_READ+CAP_SEEK = CAP_PREAD. @@ -2010,21 +2409,122 @@ _do_sendfile(struct thread *td, int src_fd, int sock_fd, int flags, goto out; } + /* + * IF SF_KQUEUE is set but we haven't copied in anything for + * kqueue data, error out. + */ + if (flags & SF_KQUEUE && do_kqueue == 0) { + SFSYNC_DPRINTF("%s: SF_KQUEUE but no KQUEUE data!\n", __func__); + goto out; + } + /* * If we need to wait for completion, initialise the sfsync * state here. */ - if (flags & SF_SYNC) - sfs = sf_sync_alloc(flags & SF_SYNC); + if (flags & (SF_SYNC | SF_KQUEUE)) + sfs = sf_sync_alloc(flags & (SF_SYNC | SF_KQUEUE)); + if (flags & SF_KQUEUE) { + error = sf_sync_kqueue_setup(sfs, hdtr_kq); + if (error) { + SFSYNC_DPRINTF("%s: (%llu) error; sfs=%p\n", + __func__, + (unsigned long long) curthread->td_tid, + sfs); + sf_sync_set_state(sfs, SF_STATE_FREEING, 0); + sf_sync_free(sfs); + goto out; + } + } + + /* + * Do the sendfile call. + * + * If this fails, it'll free the mbuf chain which will free up the + * sendfile_sync references. + */ error = fo_sendfile(fp, sock_fd, hdr_uio, trl_uio, offset, nbytes, sbytes, flags, compat ? SFK_COMPAT : 0, sfs, td); /* - * If appropriate, do the wait and free here. + * If the sendfile call succeeded, transition the sf_sync state + * to RUNNING, then COMPLETED. + * + * If the sendfile call failed, then the sendfile call may have + * actually sent some data first - so we check to see whether + * any data was sent. If some data was queued (ie, count > 0) + * then we can't call free; we have to wait until the partial + * transaction completes before we continue along. + * + * This has the side effect of firing off the knote + * if the refcount has hit zero by the time we get here. */ if (sfs != NULL) { + mtx_lock(&sfs->mtx); + if (error == 0 || sfs->count > 0) { + /* + * When it's time to do async sendfile, the transition + * to RUNNING signifies that we're actually actively + * adding and completing mbufs. When the last disk + * buffer is read (ie, when we're not doing any + * further read IO and all subsequent stuff is mbuf + * transmissions) we'll transition to COMPLETED + * and when the final mbuf is freed, the completion + * will be signaled. + */ + sf_sync_set_state(sfs, SF_STATE_RUNNING, 1); + + /* + * Set the retval before we signal completed. + * If we do it the other way around then transitioning to + * COMPLETED may post the knote before you set the return + * status! + * + * XXX for now, errno is always 0, as we don't post + * knotes if sendfile failed. Maybe that'll change later. + */ + sf_sync_set_retval(sfs, *sbytes, error); + + /* + * And now transition to completed, which will kick off + * the knote if required. + */ + sf_sync_set_state(sfs, SF_STATE_COMPLETED, 1); + } else { + /* + * Error isn't zero, sfs_count is zero, so we + * won't have some other thing to wake things up. + * Thus free. + */ + sf_sync_set_state(sfs, SF_STATE_FREEING, 1); + do_free = 1; + } + + /* + * Next - wait if appropriate. + */ sf_sync_syscall_wait(sfs); + + /* + * If we're not doing kqueue notifications, we can + * transition this immediately to the freeing state. + */ + if ((sfs->flags & SF_KQUEUE) == 0) { + sf_sync_set_state(sfs, SF_STATE_FREEING, 1); + do_free = 1; + } + + mtx_unlock(&sfs->mtx); + } + + /* + * If do_free is set, free here. + * + * If we're doing no-kqueue notification and it's just sleep notification, + * we also do free; it's the only chance we have. + */ + if (sfs != NULL && do_free == 1) { sf_sync_free(sfs); } @@ -2036,16 +2536,20 @@ _do_sendfile(struct thread *td, int src_fd, int sock_fd, int flags, fdrop(fp, td); out: + /* Return error */ return (error); } + static int do_sendfile(struct thread *td, struct sendfile_args *uap, int compat) { struct sf_hdtr hdtr; + struct sf_hdtr_kq hdtr_kq; struct uio *hdr_uio, *trl_uio; int error; off_t sbytes; + int do_kqueue = 0; /* * File offset must be positive. If it goes beyond EOF @@ -2070,10 +2574,25 @@ do_sendfile(struct thread *td, struct sendfile_args *uap, int compat) if (error != 0) goto out; } + + /* + * If SF_KQUEUE is set, then we need to also copy in + * the kqueue data after the normal hdtr set and set + * do_kqueue=1. + */ + if (uap->flags & SF_KQUEUE) { + error = copyin(((char *) uap->hdtr) + sizeof(hdtr), + &hdtr_kq, + sizeof(hdtr_kq)); + if (error != 0) + goto out; + do_kqueue = 1; + } } + /* Call sendfile */ error = _do_sendfile(td, uap->fd, uap->s, uap->flags, compat, - uap->offset, uap->nbytes, &sbytes, hdr_uio, trl_uio); + uap->offset, uap->nbytes, &sbytes, hdr_uio, trl_uio, &hdtr_kq); if (uap->sbytes != NULL) { copyout(&sbytes, uap->sbytes, sizeof(off_t)); diff --git a/sys/mips/adm5120/uart_dev_adm5120.c b/sys/mips/adm5120/uart_dev_adm5120.c index 9f2dc029a740..5ec18c88f0e6 100644 --- a/sys/mips/adm5120/uart_dev_adm5120.c +++ b/sys/mips/adm5120/uart_dev_adm5120.c @@ -149,6 +149,8 @@ static int adm5120_uart_bus_probe(struct uart_softc *); static int adm5120_uart_bus_receive(struct uart_softc *); static int adm5120_uart_bus_setsig(struct uart_softc *, int); static int adm5120_uart_bus_transmit(struct uart_softc *); +static void adm5120_uart_bus_grab(struct uart_softc *); +static void adm5120_uart_bus_ungrab(struct uart_softc *); static kobj_method_t adm5120_uart_methods[] = { KOBJMETHOD(uart_attach, adm5120_uart_bus_attach), @@ -162,6 +164,8 @@ static kobj_method_t adm5120_uart_methods[] = { KOBJMETHOD(uart_receive, adm5120_uart_bus_receive), KOBJMETHOD(uart_setsig, adm5120_uart_bus_setsig), KOBJMETHOD(uart_transmit, adm5120_uart_bus_transmit), + KOBJMETHOD(uart_grab, adm5120_uart_bus_grab), + KOBJMETHOD(uart_ungrab, adm5120_uart_bus_ungrab), { 0, 0 } }; @@ -450,3 +454,26 @@ adm5120_uart_bus_transmit(struct uart_softc *sc) uart_unlock(sc->sc_hwmtx); return (0); } + +static void +adm5120_uart_bus_grab(struct uart_softc *sc) +{ + + /* Enable interrupts - no RX_INT or RX_TIMEOUT */ + uart_lock(sc->sc_hwmtx); + uart_setreg(&sc->sc_bas, UART_CR_REG, + UART_CR_PORT_EN | UART_CR_MODEM_STATUS_INT_EN); + uart_unlock(sc->sc_hwmtx); +} + +static void +adm5120_uart_bus_ungrab(struct uart_softc *sc) +{ + + /* Enable interrupts */ + uart_lock(sc->sc_hwmtx); + uart_setreg(&sc->sc_bas, UART_CR_REG, + UART_CR_PORT_EN|UART_CR_RX_INT_EN|UART_CR_RX_TIMEOUT_INT_EN| + UART_CR_MODEM_STATUS_INT_EN); + uart_unlock(sc->sc_hwmtx); +} diff --git a/sys/mips/atheros/uart_dev_ar933x.c b/sys/mips/atheros/uart_dev_ar933x.c index 30f05babe8a3..f719805dde2c 100644 --- a/sys/mips/atheros/uart_dev_ar933x.c +++ b/sys/mips/atheros/uart_dev_ar933x.c @@ -325,6 +325,8 @@ static int ar933x_bus_probe(struct uart_softc *); static int ar933x_bus_receive(struct uart_softc *); static int ar933x_bus_setsig(struct uart_softc *, int); static int ar933x_bus_transmit(struct uart_softc *); +static void ar933x_bus_grab(struct uart_softc *); +static void ar933x_bus_ungrab(struct uart_softc *); static kobj_method_t ar933x_methods[] = { KOBJMETHOD(uart_attach, ar933x_bus_attach), @@ -338,6 +340,8 @@ static kobj_method_t ar933x_methods[] = { KOBJMETHOD(uart_receive, ar933x_bus_receive), KOBJMETHOD(uart_setsig, ar933x_bus_setsig), KOBJMETHOD(uart_transmit, ar933x_bus_transmit), + KOBJMETHOD(uart_grab, ar933x_bus_grab), + KOBJMETHOD(uart_ungrab, ar933x_bus_ungrab), { 0, 0 } }; @@ -752,3 +756,31 @@ ar933x_bus_transmit(struct uart_softc *sc) return (0); } + +static void +ar933x_bus_grab(struct uart_softc *sc) +{ + struct uart_bas *bas = &sc->sc_bas; + uint32_t reg; + + /* Disable the host interrupt now */ + uart_lock(sc->sc_hwmtx); + reg = ar933x_getreg(bas, AR933X_UART_CS_REG); + reg &= ~AR933X_UART_CS_HOST_INT_EN; + ar933x_setreg(bas, AR933X_UART_CS_REG, reg); + uart_unlock(sc->sc_hwmtx); +} + +static void +ar933x_bus_ungrab(struct uart_softc *sc) +{ + struct uart_bas *bas = &sc->sc_bas; + uint32_t reg; + + /* Enable the host interrupt now */ + uart_lock(sc->sc_hwmtx); + reg = ar933x_getreg(bas, AR933X_UART_CS_REG); + reg |= AR933X_UART_CS_HOST_INT_EN; + ar933x_setreg(bas, AR933X_UART_CS_REG, reg); + uart_unlock(sc->sc_hwmtx); +} diff --git a/sys/mips/cavium/ciu.c b/sys/mips/cavium/ciu.c index a9b1f988f6b0..87895bb4960b 100644 --- a/sys/mips/cavium/ciu.c +++ b/sys/mips/cavium/ciu.c @@ -433,7 +433,6 @@ ciu_intr(void *arg) if (en0_sum == 0 && en1_sum == 0) return (FILTER_STRAY); - irq_index = 0; for (irq_index = 0; en0_sum != 0; irq_index++, en0_sum >>= 1) { if ((en0_sum & 1) == 0) continue; @@ -445,7 +444,6 @@ ciu_intr(void *arg) printf("%s: stray en0 irq%d\n", __func__, irq_index); } - irq_index = 0; for (irq_index = 0; en1_sum != 0; irq_index++, en1_sum >>= 1) { if ((en1_sum & 1) == 0) continue; diff --git a/sys/mips/cavium/uart_dev_oct16550.c b/sys/mips/cavium/uart_dev_oct16550.c index 753559ff7a92..f3d47ca9ef56 100644 --- a/sys/mips/cavium/uart_dev_oct16550.c +++ b/sys/mips/cavium/uart_dev_oct16550.c @@ -398,6 +398,8 @@ static int oct16550_bus_probe(struct uart_softc *); static int oct16550_bus_receive(struct uart_softc *); static int oct16550_bus_setsig(struct uart_softc *, int); static int oct16550_bus_transmit(struct uart_softc *); +static void oct16550_bus_grab(struct uart_softc *); +static void oct16550_bus_ungrab(struct uart_softc *); static kobj_method_t oct16550_methods[] = { KOBJMETHOD(uart_attach, oct16550_bus_attach), @@ -411,6 +413,8 @@ static kobj_method_t oct16550_methods[] = { KOBJMETHOD(uart_receive, oct16550_bus_receive), KOBJMETHOD(uart_setsig, oct16550_bus_setsig), KOBJMETHOD(uart_transmit, oct16550_bus_transmit), + KOBJMETHOD(uart_grab, oct16550_bus_grab), + KOBJMETHOD(uart_ungrab, oct16550_bus_ungrab), { 0, 0 } }; @@ -810,3 +814,34 @@ oct16550_bus_transmit (struct uart_softc *sc) uart_unlock(sc->sc_hwmtx); return (0); } + +static void +oct16550_bus_grab(struct uart_softc *sc) +{ + struct uart_bas *bas = &sc->sc_bas; + + /* + * turn off all interrupts to enter polling mode. Leave the + * saved mask alone. We'll restore whatever it was in ungrab. + * All pending interupt signals are reset when IER is set to 0. + */ + uart_lock(sc->sc_hwmtx); + uart_setreg(bas, REG_IER, 0); + uart_barrier(bas); + uart_unlock(sc->sc_hwmtx); +} + +static void +oct16550_bus_ungrab(struct uart_softc *sc) +{ + struct oct16550_softc *oct16550 = (struct oct16550_softc*)sc; + struct uart_bas *bas = &sc->sc_bas; + + /* + * Restore previous interrupt mask + */ + uart_lock(sc->sc_hwmtx); + uart_setreg(bas, REG_IER, oct16550->ier); + uart_barrier(bas); + uart_unlock(sc->sc_hwmtx); +} diff --git a/sys/mips/rt305x/uart_dev_rt305x.c b/sys/mips/rt305x/uart_dev_rt305x.c index 94d0386cb421..3154cb97437f 100644 --- a/sys/mips/rt305x/uart_dev_rt305x.c +++ b/sys/mips/rt305x/uart_dev_rt305x.c @@ -195,6 +195,8 @@ static int rt305x_uart_bus_probe(struct uart_softc *); static int rt305x_uart_bus_receive(struct uart_softc *); static int rt305x_uart_bus_setsig(struct uart_softc *, int); static int rt305x_uart_bus_transmit(struct uart_softc *); +static void rt305x_uart_bus_grab(struct uart_softc *); +static void rt305x_uart_bus_ungrab(struct uart_softc *); static kobj_method_t rt305x_uart_methods[] = { KOBJMETHOD(uart_attach, rt305x_uart_bus_attach), @@ -208,6 +210,8 @@ static kobj_method_t rt305x_uart_methods[] = { KOBJMETHOD(uart_receive, rt305x_uart_bus_receive), KOBJMETHOD(uart_setsig, rt305x_uart_bus_setsig), KOBJMETHOD(uart_transmit, rt305x_uart_bus_transmit), + KOBJMETHOD(uart_grab, rt305x_uart_bus_grab), + KOBJMETHOD(uart_ungrab, rt305x_uart_bus_ungrab), { 0, 0 } }; @@ -278,7 +282,7 @@ rt305x_uart_bus_attach(struct uart_softc *sc) uart_setreg(bas, UART_FCR_REG, uart_getreg(bas, UART_FCR_REG) | UART_FCR_FIFOEN | UART_FCR_TXTGR_1 | UART_FCR_RXTGR_1); - uart_barrier(bas); + uart_barrier(bas); /* Enable interrupts */ uart_setreg(bas, UART_IER_REG, UART_IER_EDSSI | UART_IER_ELSI | UART_IER_ERBFI); @@ -505,3 +509,28 @@ rt305x_uart_bus_transmit(struct uart_softc *sc) uart_unlock(sc->sc_hwmtx); return (0); } + +static void +rt305x_uart_bus_grab(struct uart_softc *sc) +{ + struct uart_bas *bas = &sc->sc_bas; + + /* disable interrupts -- XXX not sure which one is RX, so kill them all */ + uart_lock(sc->sc_hwmtx); + uart_setreg(bas, UART_IER_REG, 0); + uart_barrier(bas); + uart_unlock(sc->sc_hwmtx); +} + +static void +rt305x_uart_bus_ungrab(struct uart_softc *sc) +{ + struct uart_bas *bas = &sc->sc_bas; + + /* Enable interrupts */ + uart_lock(sc->sc_hwmtx); + uart_setreg(bas, UART_IER_REG, + UART_IER_EDSSI | UART_IER_ELSI | UART_IER_ERBFI); + uart_barrier(bas); + uart_unlock(sc->sc_hwmtx); +} diff --git a/sys/modules/virtio/Makefile b/sys/modules/virtio/Makefile index 12846b2b8066..ecf9441fe081 100644 --- a/sys/modules/virtio/Makefile +++ b/sys/modules/virtio/Makefile @@ -23,6 +23,6 @@ # SUCH DAMAGE. # -SUBDIR= virtio pci network block balloon scsi +SUBDIR= virtio pci network block balloon scsi random .include diff --git a/sys/modules/virtio/random/Makefile b/sys/modules/virtio/random/Makefile new file mode 100644 index 000000000000..fb5b9b0cb22e --- /dev/null +++ b/sys/modules/virtio/random/Makefile @@ -0,0 +1,36 @@ +# +# $FreeBSD$ +# +# 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. +# + +.PATH: ${.CURDIR}/../../../dev/virtio/random + +KMOD= virtio_random +SRCS= virtio_random.c +SRCS+= virtio_bus_if.h virtio_if.h +SRCS+= bus_if.h device_if.h + +MFILES= kern/bus_if.m kern/device_if.m \ + dev/virtio/virtio_bus_if.m dev/virtio/virtio_if.m + +.include diff --git a/sys/net/ieee8023ad_lacp.c b/sys/net/ieee8023ad_lacp.c index 1042de6ab819..b023c6caa119 100644 --- a/sys/net/ieee8023ad_lacp.c +++ b/sys/net/ieee8023ad_lacp.c @@ -522,11 +522,7 @@ lacp_port_create(struct lagg_port *lgp) boolean_t active = TRUE; /* XXX should be configurable */ boolean_t fast = FALSE; /* XXX should be configurable */ - bzero((char *)&sdl, sizeof(sdl)); - sdl.sdl_len = sizeof(sdl); - sdl.sdl_family = AF_LINK; - sdl.sdl_index = ifp->if_index; - sdl.sdl_type = IFT_ETHER; + link_init_sdl(ifp, (struct sockaddr *)&sdl, IFT_ETHER); sdl.sdl_alen = ETHER_ADDR_LEN; bcopy(ðermulticastaddr_slowprotocols, diff --git a/sys/net/if.c b/sys/net/if.c index 75c8e3ff4eb2..cef3dd35f6a9 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -1888,6 +1888,38 @@ link_rtrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info) } } +struct sockaddr_dl * +link_alloc_sdl(size_t size, int flags) +{ + + return (malloc(size, M_TEMP, flags)); +} + +void +link_free_sdl(struct sockaddr *sa) +{ + free(sa, M_TEMP); +} + +/* + * Fills in given sdl with interface basic info. + * Returns pointer to filled sdl. + */ +struct sockaddr_dl * +link_init_sdl(struct ifnet *ifp, struct sockaddr *paddr, u_char iftype) +{ + struct sockaddr_dl *sdl; + + sdl = (struct sockaddr_dl *)paddr; + memset(sdl, 0, sizeof(struct sockaddr_dl)); + sdl->sdl_len = sizeof(struct sockaddr_dl); + sdl->sdl_family = AF_LINK; + sdl->sdl_index = ifp->if_index; + sdl->sdl_type = iftype; + + return (sdl); +} + /* * Mark an interface down and notify protocols of * the transition. @@ -2938,6 +2970,7 @@ if_addmulti(struct ifnet *ifp, struct sockaddr *sa, { struct ifmultiaddr *ifma, *ll_ifma; struct sockaddr *llsa; + struct sockaddr_dl sdl; int error; /* @@ -2957,12 +2990,18 @@ if_addmulti(struct ifnet *ifp, struct sockaddr *sa, /* * The address isn't already present; resolve the protocol address * into a link layer address, and then look that up, bump its - * refcount or allocate an ifma for that also. If 'llsa' was - * returned, we will need to free it later. + * refcount or allocate an ifma for that also. + * Most link layer resolving functions returns address data which + * fits inside default sockaddr_dl structure. However callback + * can allocate another sockaddr structure, in that case we need to + * free it later. */ llsa = NULL; ll_ifma = NULL; if (ifp->if_resolvemulti != NULL) { + /* Provide called function with buffer size information */ + sdl.sdl_len = sizeof(sdl); + llsa = (struct sockaddr *)&sdl; error = ifp->if_resolvemulti(ifp, &llsa, sa); if (error) goto unlock_out; @@ -3026,14 +3065,14 @@ if_addmulti(struct ifnet *ifp, struct sockaddr *sa, (void) (*ifp->if_ioctl)(ifp, SIOCADDMULTI, 0); } - if (llsa != NULL) - free(llsa, M_IFMADDR); + if ((llsa != NULL) && (llsa != (struct sockaddr *)&sdl)) + link_free_sdl(llsa); return (0); free_llsa_out: - if (llsa != NULL) - free(llsa, M_IFMADDR); + if ((llsa != NULL) && (llsa != (struct sockaddr *)&sdl)) + link_free_sdl(llsa); unlock_out: IF_ADDR_WUNLOCK(ifp); diff --git a/sys/net/if_arcsubr.c b/sys/net/if_arcsubr.c index 49c2dd3de685..6cec6d959d37 100644 --- a/sys/net/if_arcsubr.c +++ b/sys/net/if_arcsubr.c @@ -786,14 +786,7 @@ arc_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa, sin = (struct sockaddr_in *)sa; if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) return EADDRNOTAVAIL; - sdl = malloc(sizeof *sdl, M_IFMADDR, - M_NOWAIT | M_ZERO); - if (sdl == NULL) - return ENOMEM; - sdl->sdl_len = sizeof *sdl; - sdl->sdl_family = AF_LINK; - sdl->sdl_index = ifp->if_index; - sdl->sdl_type = IFT_ARCNET; + sdl = link_init_sdl(ifp, *llsa, IFT_ETHER); sdl->sdl_alen = ARC_ADDR_LEN; *LLADDR(sdl) = 0; *llsa = (struct sockaddr *)sdl; @@ -814,14 +807,7 @@ arc_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa, } if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) return EADDRNOTAVAIL; - sdl = malloc(sizeof *sdl, M_IFMADDR, - M_NOWAIT | M_ZERO); - if (sdl == NULL) - return ENOMEM; - sdl->sdl_len = sizeof *sdl; - sdl->sdl_family = AF_LINK; - sdl->sdl_index = ifp->if_index; - sdl->sdl_type = IFT_ARCNET; + sdl = link_init_sdl(ifp, *llsa, IFT_ETHER); sdl->sdl_alen = ARC_ADDR_LEN; *LLADDR(sdl) = 0; *llsa = (struct sockaddr *)sdl; diff --git a/sys/net/if_dl.h b/sys/net/if_dl.h index 64f4b56d76e6..8b4e00790eb6 100644 --- a/sys/net/if_dl.h +++ b/sys/net/if_dl.h @@ -69,6 +69,12 @@ struct sockaddr_dl { #define LLADDR(s) ((caddr_t)((s)->sdl_data + (s)->sdl_nlen)) #define LLINDEX(s) ((s)->sdl_index) + +struct ifnet; +struct sockaddr_dl *link_alloc_sdl(size_t, int); +void link_free_sdl(struct sockaddr *sa); +struct sockaddr_dl *link_init_sdl(struct ifnet *, struct sockaddr *, u_char); + #ifndef _KERNEL #include diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 04b94defc956..ec29b693d7e4 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -1168,14 +1168,7 @@ ether_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa, sin = (struct sockaddr_in *)sa; if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) return EADDRNOTAVAIL; - sdl = malloc(sizeof *sdl, M_IFMADDR, - M_NOWAIT|M_ZERO); - if (sdl == NULL) - return ENOMEM; - sdl->sdl_len = sizeof *sdl; - sdl->sdl_family = AF_LINK; - sdl->sdl_index = ifp->if_index; - sdl->sdl_type = IFT_ETHER; + sdl = link_init_sdl(ifp, *llsa, IFT_ETHER); sdl->sdl_alen = ETHER_ADDR_LEN; e_addr = LLADDR(sdl); ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); @@ -1197,14 +1190,7 @@ ether_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa, } if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) return EADDRNOTAVAIL; - sdl = malloc(sizeof *sdl, M_IFMADDR, - M_NOWAIT|M_ZERO); - if (sdl == NULL) - return (ENOMEM); - sdl->sdl_len = sizeof *sdl; - sdl->sdl_family = AF_LINK; - sdl->sdl_index = ifp->if_index; - sdl->sdl_type = IFT_ETHER; + sdl = link_init_sdl(ifp, *llsa, IFT_ETHER); sdl->sdl_alen = ETHER_ADDR_LEN; e_addr = LLADDR(sdl); ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); diff --git a/sys/net/if_fddisubr.c b/sys/net/if_fddisubr.c index 2f03bb7e5feb..2bb818bd702e 100644 --- a/sys/net/if_fddisubr.c +++ b/sys/net/if_fddisubr.c @@ -729,14 +729,7 @@ fddi_resolvemulti(ifp, llsa, sa) sin = (struct sockaddr_in *)sa; if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) return (EADDRNOTAVAIL); - sdl = malloc(sizeof *sdl, M_IFMADDR, - M_NOWAIT | M_ZERO); - if (sdl == NULL) - return (ENOMEM); - sdl->sdl_len = sizeof *sdl; - sdl->sdl_family = AF_LINK; - sdl->sdl_index = ifp->if_index; - sdl->sdl_type = IFT_FDDI; + sdl = link_init_sdl(ifp, *llsa, IFT_FDDI); sdl->sdl_nlen = 0; sdl->sdl_alen = FDDI_ADDR_LEN; sdl->sdl_slen = 0; @@ -760,14 +753,7 @@ fddi_resolvemulti(ifp, llsa, sa) } if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) return (EADDRNOTAVAIL); - sdl = malloc(sizeof *sdl, M_IFMADDR, - M_NOWAIT | M_ZERO); - if (sdl == NULL) - return (ENOMEM); - sdl->sdl_len = sizeof *sdl; - sdl->sdl_family = AF_LINK; - sdl->sdl_index = ifp->if_index; - sdl->sdl_type = IFT_FDDI; + sdl = link_init_sdl(ifp, *llsa, IFT_FDDI); sdl->sdl_nlen = 0; sdl->sdl_alen = FDDI_ADDR_LEN; sdl->sdl_slen = 0; diff --git a/sys/net/if_iso88025subr.c b/sys/net/if_iso88025subr.c index 825b220a1311..593c5ab4bd83 100644 --- a/sys/net/if_iso88025subr.c +++ b/sys/net/if_iso88025subr.c @@ -721,14 +721,7 @@ iso88025_resolvemulti (ifp, llsa, sa) if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { return (EADDRNOTAVAIL); } - sdl = malloc(sizeof *sdl, M_IFMADDR, - M_NOWAIT|M_ZERO); - if (sdl == NULL) - return (ENOMEM); - sdl->sdl_len = sizeof *sdl; - sdl->sdl_family = AF_LINK; - sdl->sdl_index = ifp->if_index; - sdl->sdl_type = IFT_ISO88025; + sdl = link_init_sdl(ifp, *llsa, IFT_ISO88025); sdl->sdl_alen = ISO88025_ADDR_LEN; e_addr = LLADDR(sdl); ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); @@ -751,14 +744,7 @@ iso88025_resolvemulti (ifp, llsa, sa) if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { return (EADDRNOTAVAIL); } - sdl = malloc(sizeof *sdl, M_IFMADDR, - M_NOWAIT|M_ZERO); - if (sdl == NULL) - return (ENOMEM); - sdl->sdl_len = sizeof *sdl; - sdl->sdl_family = AF_LINK; - sdl->sdl_index = ifp->if_index; - sdl->sdl_type = IFT_ISO88025; + sdl = link_init_sdl(ifp, *llsa, IFT_ISO88025); sdl->sdl_alen = ISO88025_ADDR_LEN; e_addr = LLADDR(sdl); ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); diff --git a/sys/net/if_lagg.c b/sys/net/if_lagg.c index beae0b616b20..c9000640e4e2 100644 --- a/sys/net/if_lagg.c +++ b/sys/net/if_lagg.c @@ -1214,12 +1214,8 @@ lagg_ether_cmdmulti(struct lagg_port *lp, int set) LAGG_WLOCK_ASSERT(sc); - bzero((char *)&sdl, sizeof(sdl)); - sdl.sdl_len = sizeof(sdl); - sdl.sdl_family = AF_LINK; - sdl.sdl_type = IFT_ETHER; + link_init_sdl(ifp, (struct sockaddr *)&sdl, IFT_ETHER); sdl.sdl_alen = ETHER_ADDR_LEN; - sdl.sdl_index = ifp->if_index; if (set) { TAILQ_FOREACH(ifma, &scifp->if_multiaddrs, ifma_link) { diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h index 72882b08a2a3..1bb337cf0ef7 100644 --- a/sys/net/netmap_user.h +++ b/sys/net/netmap_user.h @@ -139,11 +139,8 @@ nm_ring_space(struct netmap_ring *ring) #include /* EINVAL */ #include /* O_RDWR */ #include /* close() */ -#ifdef __FreeBSD__ +#include #include -#else -#include /* on FreeBSD it is stdlib.h */ -#endif struct nm_hdr_t { /* same as pcap_pkthdr */ struct timeval ts; @@ -151,15 +148,43 @@ struct nm_hdr_t { /* same as pcap_pkthdr */ uint32_t len; }; +struct nm_stat_t { // pcap_stat + u_int ps_recv; + u_int ps_drop; + u_int ps_ifdrop; +#ifdef WIN32 + u_int bs_capt; +#endif /* WIN32 */ +}; + +#define NM_ERRBUF_SIZE 512 + struct nm_desc_t { struct nm_desc_t *self; int fd; void *mem; int memsize; struct netmap_if *nifp; - uint16_t first_ring, last_ring, cur_ring; - struct nmreq req; + uint16_t first_tx_ring, last_tx_ring, cur_tx_ring; + uint16_t first_rx_ring, last_rx_ring, cur_rx_ring; + struct nmreq req; /* also contains the nr_name = ifname */ struct nm_hdr_t hdr; + + struct netmap_ring *tx, *rx; /* shortcuts to base hw/sw rings */ + + /* parameters from pcap_open_live */ + int snaplen; + int promisc; + int to_ms; + char *errbuf; + + /* save flags so we can restore them on close */ + uint32_t if_flags; + uint32_t if_reqcap; + uint32_t if_curcap; + + struct nm_stat_t st; + char msg[NM_ERRBUF_SIZE]; }; /* @@ -248,7 +273,8 @@ static struct nm_desc_t * nm_open(const char *ifname, const char *ring_name, int flags, int ring_flags) { struct nm_desc_t *d; - u_int n; + u_int n, namelen; + char *port = NULL; if (strncmp(ifname, "netmap:", 7) && strncmp(ifname, "vale", 4)) { errno = 0; /* name not recognised */ @@ -256,6 +282,20 @@ nm_open(const char *ifname, const char *ring_name, int flags, int ring_flags) } if (ifname[0] == 'n') ifname += 7; + port = strchr(ifname, '-'); + if (!port) { + namelen = strlen(ifname); + } else { + namelen = port - ifname; + flags &= ~(NETMAP_SW_RING | NETMAP_HW_RING | NETMAP_RING_MASK); + if (port[1] == 's') + flags |= NETMAP_SW_RING; + else + ring_name = port; + } + if (namelen >= sizeof(d->req.nr_name)) + namelen = sizeof(d->req.nr_name) - 1; + d = (struct nm_desc_t *)calloc(1, sizeof(*d)); if (d == NULL) { errno = ENOMEM; @@ -279,9 +319,11 @@ nm_open(const char *ifname, const char *ring_name, int flags, int ring_flags) } d->req.nr_ringid |= (flags & ~NETMAP_RING_MASK); d->req.nr_version = NETMAP_API; - strncpy(d->req.nr_name, ifname, sizeof(d->req.nr_name)); - if (ioctl(d->fd, NIOCREGIF, &d->req)) + memcpy(d->req.nr_name, ifname, namelen); + d->req.nr_name[namelen] = '\0'; + if (ioctl(d->fd, NIOCREGIF, &d->req)) { goto fail; + } d->memsize = d->req.nr_memsize; d->mem = mmap(0, d->memsize, PROT_WRITE | PROT_READ, MAP_SHARED, @@ -290,18 +332,27 @@ nm_open(const char *ifname, const char *ring_name, int flags, int ring_flags) goto fail; d->nifp = NETMAP_IF(d->mem, d->req.nr_offset); if (d->req.nr_ringid & NETMAP_SW_RING) { - d->first_ring = d->last_ring = d->req.nr_rx_rings; + d->first_tx_ring = d->last_tx_ring = d->req.nr_tx_rings; + d->first_rx_ring = d->last_rx_ring = d->req.nr_rx_rings; } else if (d->req.nr_ringid & NETMAP_HW_RING) { - d->first_ring = d->last_ring = + /* XXX check validity */ + d->first_tx_ring = d->last_tx_ring = + d->first_rx_ring = d->last_rx_ring = d->req.nr_ringid & NETMAP_RING_MASK; } else { - d->first_ring = 0; - d->last_ring = d->req.nr_rx_rings - 1; + d->first_tx_ring = d->last_rx_ring = 0; + d->last_tx_ring = d->req.nr_tx_rings - 1; + d->last_rx_ring = d->req.nr_rx_rings - 1; } - d->cur_ring = d->first_ring; - for (n = d->first_ring; n <= d->last_ring; n++) { - struct netmap_ring *ring = NETMAP_RXRING(d->nifp, n); - ring->flags |= ring_flags; + d->tx = NETMAP_TXRING(d->nifp, 0); + d->rx = NETMAP_RXRING(d->nifp, 0); + d->cur_tx_ring = d->first_tx_ring; + d->cur_rx_ring = d->first_rx_ring; + for (n = d->first_tx_ring; n <= d->last_tx_ring; n++) { + d->tx[n].flags |= ring_flags; + } + for (n = d->first_rx_ring; n <= d->last_rx_ring; n++) { + d->rx[n].flags |= ring_flags; } return d; @@ -340,30 +391,25 @@ nm_close(struct nm_desc_t *d) static int nm_inject(struct nm_desc_t *d, const void *buf, size_t size) { - u_int c, n = d->last_ring - d->first_ring + 1; + u_int c, n = d->last_tx_ring - d->first_tx_ring + 1; - if (0) fprintf(stderr, "%s rings %d %d %d\n", __FUNCTION__, - d->first_ring, d->cur_ring, d->last_ring); for (c = 0; c < n ; c++) { /* compute current ring to use */ struct netmap_ring *ring; uint32_t i, idx; - uint32_t ri = d->cur_ring + c; + uint32_t ri = d->cur_tx_ring + c; - if (ri > d->last_ring) - ri = d->first_ring; + if (ri > d->last_tx_ring) + ri = d->first_tx_ring; ring = NETMAP_TXRING(d->nifp, ri); if (nm_ring_empty(ring)) { - if (0) fprintf(stderr, "%s ring %d cur %d tail %d\n", - __FUNCTION__, - ri, ring->cur, ring->tail); continue; } i = ring->cur; idx = ring->slot[i].buf_idx; ring->slot[i].len = size; pkt_copy(buf, NETMAP_BUF(ring, idx), size); - d->cur_ring = ri; + d->cur_tx_ring = ri; ring->head = ring->cur = nm_ring_next(ring, i); return size; } @@ -377,8 +423,8 @@ nm_inject(struct nm_desc_t *d, const void *buf, size_t size) static int nm_dispatch(struct nm_desc_t *d, int cnt, nm_cb_t cb, u_char *arg) { - int n = d->last_ring - d->first_ring + 1; - int c, got = 0, ri = d->cur_ring; + int n = d->last_rx_ring - d->first_rx_ring + 1; + int c, got = 0, ri = d->cur_rx_ring; if (cnt == 0) cnt = -1; @@ -390,30 +436,30 @@ nm_dispatch(struct nm_desc_t *d, int cnt, nm_cb_t cb, u_char *arg) /* compute current ring to use */ struct netmap_ring *ring; - ri = d->cur_ring + c; - if (ri > d->last_ring) - ri = d->first_ring; + ri = d->cur_rx_ring + c; + if (ri > d->last_rx_ring) + ri = d->first_rx_ring; ring = NETMAP_RXRING(d->nifp, ri); for ( ; !nm_ring_empty(ring) && cnt != got; got++) { u_int i = ring->cur; u_int idx = ring->slot[i].buf_idx; u_char *buf = (u_char *)NETMAP_BUF(ring, idx); - // XXX should check valid buf - // prefetch(buf); + + // __builtin_prefetch(buf); d->hdr.len = d->hdr.caplen = ring->slot[i].len; d->hdr.ts = ring->ts; cb(arg, &d->hdr, buf); ring->head = ring->cur = nm_ring_next(ring, i); } } - d->cur_ring = ri; + d->cur_rx_ring = ri; return got; } static u_char * nm_nextpkt(struct nm_desc_t *d, struct nm_hdr_t *hdr) { - int ri = d->cur_ring; + int ri = d->cur_rx_ring; do { /* compute current ring to use */ @@ -422,8 +468,8 @@ nm_nextpkt(struct nm_desc_t *d, struct nm_hdr_t *hdr) u_int i = ring->cur; u_int idx = ring->slot[i].buf_idx; u_char *buf = (u_char *)NETMAP_BUF(ring, idx); - // XXX should check valid buf - // prefetch(buf); + + // __builtin_prefetch(buf); hdr->ts = ring->ts; hdr->len = hdr->caplen = ring->slot[i].len; ring->cur = nm_ring_next(ring, i); @@ -432,13 +478,13 @@ nm_nextpkt(struct nm_desc_t *d, struct nm_hdr_t *hdr) * the future. */ ring->head = ring->cur; - d->cur_ring = ri; + d->cur_rx_ring = ri; return buf; } ri++; - if (ri > d->last_ring) - ri = d->first_ring; - } while (ri != d->cur_ring); + if (ri > d->last_rx_ring) + ri = d->first_rx_ring; + } while (ri != d->cur_rx_ring); return NULL; /* nothing found */ } diff --git a/sys/net80211/ieee80211_mesh.c b/sys/net80211/ieee80211_mesh.c index 4aff6bd51689..51db327d9fad 100644 --- a/sys/net80211/ieee80211_mesh.c +++ b/sys/net80211/ieee80211_mesh.c @@ -2693,7 +2693,7 @@ mesh_send_action(struct ieee80211_node *ni, return EIO; /* XXX */ } - M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); + M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT); if (m == NULL) { ieee80211_free_node(ni); return ENOMEM; diff --git a/sys/netinet/in.c b/sys/netinet/in.c index 6624c1ac5557..e4a54b2716de 100644 --- a/sys/netinet/in.c +++ b/sys/netinet/in.c @@ -408,7 +408,7 @@ in_aifaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, struct thread *td) if (ifp->if_flags & IFF_LOOPBACK) ia->ia_dstaddr = ia->ia_addr; - ifa_ref(ifa); /* if_addrhead */ + /* if_addrhead is already referenced by ifa_alloc() */ IF_ADDR_WLOCK(ifp); TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); IF_ADDR_WUNLOCK(ifp); @@ -495,13 +495,13 @@ in_aifaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, struct thread *td) IF_ADDR_WLOCK(ifp); TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); IF_ADDR_WUNLOCK(ifp); - ifa_free(&ia->ia_ifa); + ifa_free(&ia->ia_ifa); /* if_addrhead */ IN_IFADDR_WLOCK(); TAILQ_REMOVE(&V_in_ifaddrhead, ia, ia_link); LIST_REMOVE(ia, ia_hash); IN_IFADDR_WUNLOCK(); - ifa_free(&ia->ia_ifa); + ifa_free(&ia->ia_ifa); /* in_ifaddrhead */ return (error); } @@ -565,7 +565,6 @@ in_difaddr_ioctl(caddr_t data, struct ifnet *ifp, struct thread *td) TAILQ_REMOVE(&V_in_ifaddrhead, ia, ia_link); LIST_REMOVE(ia, ia_hash); IN_IFADDR_WUNLOCK(); - ifa_free(&ia->ia_ifa); /* in_ifaddrhead */ /* * in_scrubprefix() kills the interface route. @@ -601,6 +600,7 @@ in_difaddr_ioctl(caddr_t data, struct ifnet *ifp, struct thread *td) } EVENTHANDLER_INVOKE(ifaddr_event, ifp); + ifa_free(&ia->ia_ifa); /* in_ifaddrhead */ return (0); } diff --git a/sys/netinet/in_mcast.c b/sys/netinet/in_mcast.c index 621957ea3315..d996bd189281 100644 --- a/sys/netinet/in_mcast.c +++ b/sys/netinet/in_mcast.c @@ -1496,7 +1496,7 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) error = inm_merge(inm, imf); if (error) { CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); - goto out_imf_rollback; + goto out_in_multi_locked; } CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); @@ -1504,6 +1504,8 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) if (error) CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__); +out_in_multi_locked: + IN_MULTI_UNLOCK(); out_imf_rollback: @@ -2172,8 +2174,12 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) if (is_new) { error = in_joingroup_locked(ifp, &gsa->sin.sin_addr, imf, &inm); - if (error) + if (error) { + CTR1(KTR_IGMPV3, "%s: in_joingroup_locked failed", + __func__); + IN_MULTI_UNLOCK(); goto out_imo_free; + } imo->imo_membership[idx] = inm; } else { CTR1(KTR_IGMPV3, "%s: merge inm state", __func__); @@ -2181,20 +2187,21 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) if (error) { CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); - goto out_imf_rollback; + goto out_in_multi_locked; } CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); error = igmp_change_state(inm); if (error) { CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__); - goto out_imf_rollback; + goto out_in_multi_locked; } } +out_in_multi_locked: + IN_MULTI_UNLOCK(); -out_imf_rollback: INP_WLOCK_ASSERT(inp); if (error) { imf_rollback(imf); @@ -2398,7 +2405,7 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) if (error) { CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); - goto out_imf_rollback; + goto out_in_multi_locked; } CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); @@ -2409,9 +2416,10 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) } } +out_in_multi_locked: + IN_MULTI_UNLOCK(); -out_imf_rollback: if (error) imf_rollback(imf); else @@ -2645,7 +2653,7 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) error = inm_merge(inm, imf); if (error) { CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); - goto out_imf_rollback; + goto out_in_multi_locked; } CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); @@ -2653,6 +2661,8 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) if (error) CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__); +out_in_multi_locked: + IN_MULTI_UNLOCK(); out_imf_rollback: diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index 5b92b8cd70d4..b6931a0a1235 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -964,7 +964,7 @@ carp_ifa_addroute(struct ifaddr *ifa) case AF_INET6: ifa_add_loopback_route(ifa, (struct sockaddr *)&ifatoia6(ifa)->ia_addr); - in6_ifaddloop(ifa); + nd6_add_ifa_lle(ifatoia6(ifa)); break; #endif } @@ -995,7 +995,7 @@ carp_ifa_delroute(struct ifaddr *ifa) case AF_INET6: ifa_del_loopback_route(ifa, (struct sockaddr *)&ifatoia6(ifa)->ia_addr); - in6_ifremloop(ifa); + nd6_rem_ifa_lle(ifatoia6(ifa)); break; #endif } diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index e3da758fc72d..ee10fdc32ab3 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -123,9 +123,6 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags, struct mbuf *m0; int hlen = sizeof (struct ip); int mtu; -#if 0 - int n; /* scratchpad */ -#endif int error = 0; struct sockaddr_in *dst; const struct sockaddr_in *gw; @@ -158,7 +155,7 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags, #ifdef FLOWTABLE if (ro->ro_rt == NULL) { struct flentry *fle; - + /* * The flow table returns route entries valid for up to 30 * seconds; we rely on the remainder of ip_output() taking no @@ -202,15 +199,21 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags, hlen = ip->ip_hl << 2; } + /* + * dst/gw handling: + * + * dst can be rewritten but always points to &ro->ro_dst. + * gw is readonly but can point either to dst OR rt_gateway, + * therefore we need restore gw if we're redoing lookup. + */ gw = dst = (struct sockaddr_in *)&ro->ro_dst; again: ia = NULL; /* - * If there is a cached route, - * check that it is to the same destination - * and is still up. If not, free it and try again. - * The address family should also be checked in case of sharing the - * cache with IPv6. + * If there is a cached route, check that it is to the same + * destination and is still up. If not, free it and try again. + * The address family should also be checked in case of sharing + * the cache with IPv6. */ rte = ro->ro_rt; if (rte && ((rte->rt_flags & RTF_UP) == 0 || @@ -221,6 +224,7 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags, RO_RTFREE(ro); ro->ro_lle = NULL; rte = NULL; + gw = dst; } if (rte == NULL && fwd_tag == NULL) { bzero(dst, sizeof(*dst)); @@ -762,10 +766,10 @@ ip_fragment(struct ip *ip, struct mbuf **m_frag, int mtu, } #endif if (len > PAGE_SIZE) { - /* - * Fragment large datagrams such that each segment - * contains a multiple of PAGE_SIZE amount of data, - * plus headers. This enables a receiver to perform + /* + * Fragment large datagrams such that each segment + * contains a multiple of PAGE_SIZE amount of data, + * plus headers. This enables a receiver to perform * page-flipping zero-copy optimizations. * * XXX When does this help given that sender and receiver @@ -779,7 +783,7 @@ ip_fragment(struct ip *ip, struct mbuf **m_frag, int mtu, off += m->m_len; /* - * firstlen (off - hlen) must be aligned on an + * firstlen (off - hlen) must be aligned on an * 8-byte boundary */ if (off < hlen) @@ -1164,7 +1168,7 @@ ip_ctloutput(struct socket *so, struct sockopt *sopt) case IP_OPTIONS: case IP_RETOPTS: if (inp->inp_options) - error = sooptcopyout(sopt, + error = sooptcopyout(sopt, mtod(inp->inp_options, char *), inp->inp_options->m_len); diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c index 29d9d5310124..af30ad14e847 100644 --- a/sys/netinet/tcp_syncache.c +++ b/sys/netinet/tcp_syncache.c @@ -721,6 +721,16 @@ syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m) } #endif + /* + * If there's an mbuf and it has a flowid, then let's initialise the + * inp with that particular flowid. + */ + if (m != NULL && m->m_flags & M_FLOWID) { + inp->inp_flags |= INP_HW_FLOWID; + inp->inp_flags &= ~INP_SW_FLOWID; + inp->inp_flowid = m->m_pkthdr.flowid; + } + /* * Install in the reservation hash table for now, but don't yet * install a connection group since the full 4-tuple isn't yet diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index 405a2619da54..f17c4a08d7cc 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -133,74 +133,31 @@ const struct in6_addr in6mask128 = IN6MASK128; const struct sockaddr_in6 sa6_any = { sizeof(sa6_any), AF_INET6, 0, 0, IN6ADDR_ANY_INIT, 0 }; -static int in6_ifinit(struct ifnet *, struct in6_ifaddr *, - struct sockaddr_in6 *, int); +static int in6_notify_ifa(struct ifnet *, struct in6_ifaddr *, + struct in6_aliasreq *, int); static void in6_unlink_ifa(struct in6_ifaddr *, struct ifnet *); int (*faithprefix_p)(struct in6_addr *); +static int in6_validate_ifra(struct ifnet *, struct in6_aliasreq *, + struct in6_ifaddr *, int); +static struct in6_ifaddr *in6_alloc_ifa(struct ifnet *, + struct in6_aliasreq *, int flags); +static int in6_update_ifa_internal(struct ifnet *, struct in6_aliasreq *, + struct in6_ifaddr *, int, int); +static int in6_broadcast_ifa(struct ifnet *, struct in6_aliasreq *, + struct in6_ifaddr *, int); + #define ifa2ia6(ifa) ((struct in6_ifaddr *)(ifa)) #define ia62ifa(ia6) (&((ia6)->ia_ifa)) + void -in6_ifaddloop(struct ifaddr *ifa) +in6_newaddrmsg(struct in6_ifaddr *ia, int cmd) { struct sockaddr_dl gateway; struct sockaddr_in6 mask, addr; struct rtentry rt; - struct in6_ifaddr *ia; - struct ifnet *ifp; - struct llentry *ln; - - ia = ifa2ia6(ifa); - ifp = ifa->ifa_ifp; - IF_AFDATA_LOCK(ifp); - ifa->ifa_rtrequest = nd6_rtrequest; - ln = lla_lookup(LLTABLE6(ifp), (LLE_CREATE | LLE_IFADDR | - LLE_EXCLUSIVE), (struct sockaddr *)&ia->ia_addr); - IF_AFDATA_UNLOCK(ifp); - if (ln != NULL) { - ln->la_expire = 0; /* for IPv6 this means permanent */ - ln->ln_state = ND6_LLINFO_REACHABLE; - /* - * initialize for rtmsg generation - */ - bzero(&gateway, sizeof(gateway)); - gateway.sdl_len = sizeof(gateway); - gateway.sdl_family = AF_LINK; - gateway.sdl_nlen = 0; - gateway.sdl_alen = 6; - memcpy(gateway.sdl_data, &ln->ll_addr.mac_aligned, - sizeof(ln->ll_addr)); - LLE_WUNLOCK(ln); - } - - bzero(&rt, sizeof(rt)); - rt.rt_gateway = (struct sockaddr *)&gateway; - memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask)); - memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr)); - rt_mask(&rt) = (struct sockaddr *)&mask; - rt_key(&rt) = (struct sockaddr *)&addr; - rt.rt_flags = RTF_UP | RTF_HOST | RTF_STATIC; - /* Announce arrival of local address to all FIBs. */ - rt_newaddrmsg(RTM_ADD, ifa, 0, &rt); -} - -void -in6_ifremloop(struct ifaddr *ifa) -{ - struct sockaddr_dl gateway; - struct sockaddr_in6 mask, addr; - struct rtentry rt0; - struct in6_ifaddr *ia; - struct ifnet *ifp; - - ia = ifa2ia6(ifa); - ifp = ifa->ifa_ifp; - memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr)); - memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask)); - lltable_prefix_free(AF_INET6, (struct sockaddr *)&addr, - (struct sockaddr *)&mask, LLE_STATIC); /* * initialize for rtmsg generation @@ -208,15 +165,18 @@ in6_ifremloop(struct ifaddr *ifa) bzero(&gateway, sizeof(gateway)); gateway.sdl_len = sizeof(gateway); gateway.sdl_family = AF_LINK; - gateway.sdl_nlen = 0; - gateway.sdl_alen = ifp->if_addrlen; - bzero(&rt0, sizeof(rt0)); - rt0.rt_gateway = (struct sockaddr *)&gateway; - rt_mask(&rt0) = (struct sockaddr *)&mask; - rt_key(&rt0) = (struct sockaddr *)&addr; - rt0.rt_flags = RTF_HOST | RTF_STATIC; - /* Announce removal of local address to all FIBs. */ - rt_newaddrmsg(RTM_DELETE, ifa, 0, &rt0); + + bzero(&rt, sizeof(rt)); + rt.rt_gateway = (struct sockaddr *)&gateway; + memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask)); + memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr)); + rt_mask(&rt) = (struct sockaddr *)&mask; + rt_key(&rt) = (struct sockaddr *)&addr; + rt.rt_flags = RTF_HOST | RTF_STATIC; + if (cmd == RTM_ADD) + rt.rt_flags |= RTF_UP; + /* Announce arrival of local address to all FIBs. */ + rt_newaddrmsg(cmd, &ia->ia_ifa, 0, &rt); } int @@ -1001,11 +961,60 @@ int in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, struct in6_ifaddr *ia, int flags) { - int error = 0, hostIsNew = 0, plen = -1; + int error, hostIsNew = 0; + + if ((error = in6_validate_ifra(ifp, ifra, ia, flags)) != 0) + return (error); + + if (ia == NULL) { + hostIsNew = 1; + if ((ia = in6_alloc_ifa(ifp, ifra, flags)) == NULL) + return (ENOBUFS); + } + + error = in6_update_ifa_internal(ifp, ifra, ia, hostIsNew, flags); + if (error != 0) { + if (hostIsNew != 0) { + in6_unlink_ifa(ia, ifp); + ifa_free(&ia->ia_ifa); + } + return (error); + } + + if (hostIsNew) + error = in6_broadcast_ifa(ifp, ifra, ia, flags); + + return (error); +} + +/* + * Fill in basic IPv6 address request info. + */ +void +in6_prepare_ifra(struct in6_aliasreq *ifra, const struct in6_addr *addr, + const struct in6_addr *mask) +{ + + memset(ifra, 0, sizeof(struct in6_aliasreq)); + + ifra->ifra_addr.sin6_family = AF_INET6; + ifra->ifra_addr.sin6_len = sizeof(struct sockaddr_in6); + if (addr != NULL) + ifra->ifra_addr.sin6_addr = *addr; + + ifra->ifra_prefixmask.sin6_family = AF_INET6; + ifra->ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); + if (mask != NULL) + ifra->ifra_prefixmask.sin6_addr = *mask; +} + +static int +in6_validate_ifra(struct ifnet *ifp, struct in6_aliasreq *ifra, + struct in6_ifaddr *ia, int flags) +{ + int plen = -1; struct sockaddr_in6 dst6; struct in6_addrlifetime *lt; - struct in6_multi *in6m_sol; - int delay; char ip6buf[INET6_ADDRSTRLEN]; /* Validate parameters */ @@ -1020,6 +1029,14 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, ifra->ifra_dstaddr.sin6_family != AF_INET6 && ifra->ifra_dstaddr.sin6_family != AF_UNSPEC) return (EAFNOSUPPORT); + + /* + * Validate address + */ + if (ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6) || + ifra->ifra_addr.sin6_family != AF_INET6) + return (EINVAL); + /* * validate ifra_prefixmask. don't check sin6_family, netmask * does not carry fields other than sin6_len. @@ -1072,6 +1089,9 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, if (sa6_embedscope(&dst6, 0)) return (EINVAL); /* XXX: should be impossible */ } + /* Modify original ifra_dstaddr to reflect changes */ + ifra->ifra_dstaddr = dst6; + /* * The destination address can be specified only for a p2p or a * loopback interface. If specified, the corresponding prefix length @@ -1107,94 +1127,102 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, return (0); /* there's nothing to do */ } - /* - * If this is a new address, allocate a new ifaddr and link it - * into chains. - */ - if (ia == NULL) { - hostIsNew = 1; - /* - * When in6_update_ifa() is called in a process of a received - * RA, it is called under an interrupt context. So, we should - * call malloc with M_NOWAIT. - */ - ia = (struct in6_ifaddr *)ifa_alloc(sizeof(*ia), M_NOWAIT); - if (ia == NULL) - return (ENOBUFS); - LIST_INIT(&ia->ia6_memberships); - /* Initialize the address and masks, and put time stamp */ - ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; - ia->ia_addr.sin6_family = AF_INET6; - ia->ia_addr.sin6_len = sizeof(ia->ia_addr); - ia->ia6_createtime = time_uptime; - if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) != 0) { - /* - * XXX: some functions expect that ifa_dstaddr is not - * NULL for p2p interfaces. - */ - ia->ia_ifa.ifa_dstaddr = - (struct sockaddr *)&ia->ia_dstaddr; - } else { - ia->ia_ifa.ifa_dstaddr = NULL; - } - ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask; - ia->ia_ifp = ifp; - ifa_ref(&ia->ia_ifa); /* if_addrhead */ - IF_ADDR_WLOCK(ifp); - TAILQ_INSERT_TAIL(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); - IF_ADDR_WUNLOCK(ifp); - - ifa_ref(&ia->ia_ifa); /* in6_ifaddrhead */ - IN6_IFADDR_WLOCK(); - TAILQ_INSERT_TAIL(&V_in6_ifaddrhead, ia, ia_link); - LIST_INSERT_HEAD(IN6ADDR_HASH(&ifra->ifra_addr.sin6_addr), - ia, ia6_hash); - IN6_IFADDR_WUNLOCK(); - } - - /* update timestamp */ - ia->ia6_updatetime = time_uptime; - - /* set prefix mask */ - if (ifra->ifra_prefixmask.sin6_len) { + /* Check prefix mask */ + if (ia != NULL && ifra->ifra_prefixmask.sin6_len != 0) { /* * We prohibit changing the prefix length of an existing * address, because * + such an operation should be rare in IPv6, and * + the operation would confuse prefix management. */ - if (ia->ia_prefixmask.sin6_len && + if (ia->ia_prefixmask.sin6_len != 0 && in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL) != plen) { - nd6log((LOG_INFO, "in6_update_ifa: the prefix length of an" - " existing (%s) address should not be changed\n", + nd6log((LOG_INFO, "in6_validate_ifa: the prefix length " + "of an existing %s address should not be changed\n", ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr))); - error = EINVAL; - goto unlink; + + return (EINVAL); } - ia->ia_prefixmask = ifra->ifra_prefixmask; - ia->ia_prefixmask.sin6_family = AF_INET6; } + return (0); +} + + +/* + * Allocate a new ifaddr and link it into chains. + */ +static struct in6_ifaddr * +in6_alloc_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, int flags) +{ + struct in6_ifaddr *ia; + /* - * If a new destination address is specified, scrub the old one and - * install the new destination. Note that the interface must be - * p2p or loopback (see the check above.) + * When in6_alloc_ifa() is called in a process of a received + * RA, it is called under an interrupt context. So, we should + * call malloc with M_NOWAIT. */ - if (dst6.sin6_family == AF_INET6 && - !IN6_ARE_ADDR_EQUAL(&dst6.sin6_addr, &ia->ia_dstaddr.sin6_addr)) { - int e; - - if ((ia->ia_flags & IFA_ROUTE) != 0 && - (e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST)) != 0) { - nd6log((LOG_ERR, "in6_update_ifa: failed to remove " - "a route to the old destination: %s\n", - ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr))); - /* proceed anyway... */ - } else - ia->ia_flags &= ~IFA_ROUTE; - ia->ia_dstaddr = dst6; + ia = (struct in6_ifaddr *)ifa_alloc(sizeof(*ia), M_NOWAIT); + if (ia == NULL) + return (NULL); + LIST_INIT(&ia->ia6_memberships); + /* Initialize the address and masks, and put time stamp */ + ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; + ia->ia_addr.sin6_family = AF_INET6; + ia->ia_addr.sin6_len = sizeof(ia->ia_addr); + /* XXX: Can we assign ,sin6_addr and skip the rest? */ + ia->ia_addr = ifra->ifra_addr; + ia->ia6_createtime = time_uptime; + if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) != 0) { + /* + * Some functions expect that ifa_dstaddr is not + * NULL for p2p interfaces. + */ + ia->ia_ifa.ifa_dstaddr = + (struct sockaddr *)&ia->ia_dstaddr; + } else { + ia->ia_ifa.ifa_dstaddr = NULL; } + /* set prefix mask if any */ + ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask; + if (ifra->ifra_prefixmask.sin6_len != 0) { + ia->ia_prefixmask.sin6_family = AF_INET6; + ia->ia_prefixmask.sin6_len = ifra->ifra_prefixmask.sin6_len; + ia->ia_prefixmask.sin6_addr = ifra->ifra_prefixmask.sin6_addr; + } + + ia->ia_ifp = ifp; + ifa_ref(&ia->ia_ifa); /* if_addrhead */ + IF_ADDR_WLOCK(ifp); + TAILQ_INSERT_TAIL(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); + IF_ADDR_WUNLOCK(ifp); + + ifa_ref(&ia->ia_ifa); /* in6_ifaddrhead */ + IN6_IFADDR_WLOCK(); + TAILQ_INSERT_TAIL(&V_in6_ifaddrhead, ia, ia_link); + LIST_INSERT_HEAD(IN6ADDR_HASH(&ia->ia_addr.sin6_addr), ia, ia6_hash); + IN6_IFADDR_WUNLOCK(); + + return (ia); +} + +/* + * Update/configure interface address parameters: + * + * 1) Update lifetime + * 2) Update interface metric ad flags + * 3) Notify other subsystems + */ +static int +in6_update_ifa_internal(struct ifnet *ifp, struct in6_aliasreq *ifra, + struct in6_ifaddr *ia, int hostIsNew, int flags) +{ + int error; + + /* update timestamp */ + ia->ia6_updatetime = time_uptime; + /* * Set lifetimes. We do not refer to ia6t_expire and ia6t_preferred * to see if the address is deprecated or invalidated, but initialize @@ -1212,14 +1240,6 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, } else ia->ia6_lifetime.ia6t_preferred = 0; - /* reset the interface and routing table appropriately. */ - if ((error = in6_ifinit(ifp, ia, &ifra->ifra_addr, hostIsNew)) != 0) - goto unlink; - - /* - * configure address flags. - */ - ia->ia6_flags = ifra->ifra_flags; /* * backward compatibility - if IN6_IFF_DEPRECATED is set from the * userland, make it deprecated. @@ -1228,6 +1248,15 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, ia->ia6_lifetime.ia6t_pltime = 0; ia->ia6_lifetime.ia6t_preferred = time_uptime; } + + /* Update metric */ + ia->ia_ifa.ifa_metric = ifp->if_metric; + + /* + * configure address flags. + */ + ia->ia6_flags = ifra->ifra_flags; + /* * Make the address tentative before joining multicast addresses, * so that corresponding MLD responses would not have a tentative @@ -1241,23 +1270,42 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) ia->ia6_flags |= IN6_IFF_TENTATIVE; - /* - * We are done if we have simply modified an existing address. - */ - if (!hostIsNew) - return (error); + /* notify other subsystems */ + error = in6_notify_ifa(ifp, ia, ifra, hostIsNew); - /* - * Beyond this point, we should call in6_purgeaddr upon an error, - * not just go to unlink. - */ + return (error); +} + +/* + * Do link-level ifa job: + * 1) Add lle entry for added address + * 2) Notifies routing socket users about new address + * 3) join appropriate multicast group + * 4) start DAD if enabled + */ +static int +in6_broadcast_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, + struct in6_ifaddr *ia, int flags) +{ + struct in6_multi *in6m_sol; + int error = 0; + + /* Add local address to lltable, if necessary (ex. on p2p link). */ + if ((error = nd6_add_ifa_lle(ia)) != 0) { + in6_purgeaddr(&ia->ia_ifa); + ifa_free(&ia->ia_ifa); + return (error); + } /* Join necessary multicast groups. */ in6m_sol = NULL; if ((ifp->if_flags & IFF_MULTICAST) != 0) { error = in6_update_ifa_join_mc(ifp, ifra, ia, flags, &in6m_sol); - if (error) - goto cleanup; + if (error != 0) { + in6_purgeaddr(&ia->ia_ifa); + ifa_free(&ia->ia_ifa); + return (error); + } } /* @@ -1267,7 +1315,7 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, if (in6if_do_dad(ifp) && ((ifra->ifra_flags & IN6_IFF_NODAD) == 0) && (ia->ia6_flags & IN6_IFF_TENTATIVE)) { - int mindelay, maxdelay; + int delay, mindelay, maxdelay; delay = 0; if ((flags & IN6_IFAUPDATE_DADDELAY)) { @@ -1298,26 +1346,8 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, nd6_dad_start((struct ifaddr *)ia, delay); } - KASSERT(hostIsNew, ("in6_update_ifa: !hostIsNew")); ifa_free(&ia->ia_ifa); return (error); - - unlink: - /* - * XXX: if a change of an existing address failed, keep the entry - * anyway. - */ - if (hostIsNew) { - in6_unlink_ifa(ia, ifp); - ifa_free(&ia->ia_ifa); - } - return (error); - - cleanup: - KASSERT(hostIsNew, ("in6_update_ifa: cleanup: !hostIsNew")); - ifa_free(&ia->ia_ifa); - in6_purgeaddr(&ia->ia_ifa); - return error; } /* @@ -1498,7 +1528,7 @@ in6_purgeaddr(struct ifaddr *ifa) nd6_dad_stop(ifa); /* Remove local address entry from lltable. */ - in6_ifremloop(ifa); + nd6_rem_ifa_lle(ia); /* Leave multicast groups. */ error = in6_purgeaddr_mc(ifp, ia, ifa0); @@ -1577,29 +1607,33 @@ in6_purgeif(struct ifnet *ifp) } /* - * Initialize an interface's IPv6 address and routing table entry. + * Notifies other other subsystems about address change/arrival: + * 1) Notifies device handler on first IPv6 address assignment + * 2) Handle routing table changes for P2P links and route + * 3) Handle routing table changes for address host route */ static int -in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia, - struct sockaddr_in6 *sin6, int newhost) +in6_notify_ifa(struct ifnet *ifp, struct in6_ifaddr *ia, + struct in6_aliasreq *ifra, int hostIsNew) { int error = 0, plen, ifacount = 0; struct ifaddr *ifa; + struct sockaddr_in6 *pdst; + char ip6buf[INET6_ADDRSTRLEN]; /* * Give the interface a chance to initialize * if this is its first address, - * and to validate the address if necessary. */ - IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { - if (ifa->ifa_addr->sa_family != AF_INET6) - continue; - ifacount++; + if (hostIsNew != 0) { + IF_ADDR_RLOCK(ifp); + TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + ifacount++; + } + IF_ADDR_RUNLOCK(ifp); } - IF_ADDR_RUNLOCK(ifp); - - ia->ia_addr = *sin6; if (ifacount <= 1 && ifp->if_ioctl) { error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia); @@ -1607,12 +1641,26 @@ in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia, return (error); } - ia->ia_ifa.ifa_metric = ifp->if_metric; - - /* we could do in(6)_socktrim here, but just omit it at this moment. */ + /* + * If a new destination address is specified, scrub the old one and + * install the new destination. Note that the interface must be + * p2p or loopback. + */ + pdst = &ifra->ifra_dstaddr; + if (pdst->sin6_family == AF_INET6 && + !IN6_ARE_ADDR_EQUAL(&pdst->sin6_addr, &ia->ia_dstaddr.sin6_addr)) { + if ((ia->ia_flags & IFA_ROUTE) != 0 && + (rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST) != 0)) { + nd6log((LOG_ERR, "in6_update_ifa_internal: failed to " + "remove a route to the old destination: %s\n", + ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr))); + /* proceed anyway... */ + } else + ia->ia_flags &= ~IFA_ROUTE; + ia->ia_dstaddr = *pdst; + } /* - * Special case: * If a new destination address is specified for a point-to-point * interface, install a route to the destination as an interface * direct route. @@ -1623,19 +1671,19 @@ in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia, if (!(ia->ia_flags & IFA_ROUTE) && plen == 128 && ia->ia_dstaddr.sin6_family == AF_INET6) { int rtflags = RTF_UP | RTF_HOST; - error = rtinit(&ia->ia_ifa, RTM_ADD, ia->ia_flags | rtflags); - if (error) - return (error); - ia->ia_flags |= IFA_ROUTE; /* * Handle the case for ::1 . */ if (ifp->if_flags & IFF_LOOPBACK) ia->ia_flags |= IFA_RTSELF; + error = rtinit(&ia->ia_ifa, RTM_ADD, ia->ia_flags | rtflags); + if (error) + return (error); + ia->ia_flags |= IFA_ROUTE; } /* - * add a loopback route to self + * add a loopback route to self if not exists */ if (!(ia->ia_flags & IFA_RTSELF) && V_nd6_useloopback) { error = ifa_add_loopback_route((struct ifaddr *)ia, @@ -1644,10 +1692,6 @@ in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia, ia->ia_flags |= IFA_RTSELF; } - /* Add local address to lltable, if necessary (ex. on p2p link). */ - if (newhost) - in6_ifaddloop(&(ia->ia_ifa)); - return (error); } diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c index b1c5b23e3d57..94a7ee4352e0 100644 --- a/sys/netinet6/in6_ifattach.c +++ b/sys/netinet6/in6_ifattach.c @@ -460,16 +460,8 @@ in6_ifattach_linklocal(struct ifnet *ifp, struct ifnet *altifp) /* * configure link-local address. */ - bzero(&ifra, sizeof(ifra)); + in6_prepare_ifra(&ifra, NULL, &in6mask64); - /* - * in6_update_ifa() does not use ifra_name, but we accurately set it - * for safety. - */ - strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); - - ifra.ifra_addr.sin6_family = AF_INET6; - ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); ifra.ifra_addr.sin6_addr.s6_addr32[0] = htonl(0xfe800000); ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0; if ((ifp->if_flags & IFF_LOOPBACK) != 0) { @@ -485,9 +477,6 @@ in6_ifattach_linklocal(struct ifnet *ifp, struct ifnet *altifp) if (in6_setscope(&ifra.ifra_addr.sin6_addr, ifp, NULL)) return (-1); - ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); - ifra.ifra_prefixmask.sin6_family = AF_INET6; - ifra.ifra_prefixmask.sin6_addr = in6mask64; /* link-local addresses should NEVER expire. */ ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; @@ -565,17 +554,7 @@ in6_ifattach_loopback(struct ifnet *ifp) struct in6_aliasreq ifra; int error; - bzero(&ifra, sizeof(ifra)); - - /* - * in6_update_ifa() does not use ifra_name, but we accurately set it - * for safety. - */ - strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); - - ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); - ifra.ifra_prefixmask.sin6_family = AF_INET6; - ifra.ifra_prefixmask.sin6_addr = in6mask128; + in6_prepare_ifra(&ifra, &in6addr_loopback, &in6mask128); /* * Always initialize ia_dstaddr (= broadcast address) to loopback @@ -585,10 +564,6 @@ in6_ifattach_loopback(struct ifnet *ifp) ifra.ifra_dstaddr.sin6_family = AF_INET6; ifra.ifra_dstaddr.sin6_addr = in6addr_loopback; - ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); - ifra.ifra_addr.sin6_family = AF_INET6; - ifra.ifra_addr.sin6_addr = in6addr_loopback; - /* the loopback address should NEVER expire. */ ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h index fca10686f6a8..70e3a94025ba 100644 --- a/sys/netinet6/in6_var.h +++ b/sys/netinet6/in6_var.h @@ -799,6 +799,8 @@ int in6_control(struct socket *, u_long, caddr_t, struct ifnet *, struct thread *); int in6_update_ifa(struct ifnet *, struct in6_aliasreq *, struct in6_ifaddr *, int); +void in6_prepare_ifra(struct in6_aliasreq *, const struct in6_addr *, + const struct in6_addr *); void in6_purgeaddr(struct ifaddr *); int in6if_do_dad(struct ifnet *); void in6_purgeif(struct ifnet *); @@ -820,12 +822,11 @@ int in6_prefix_ioctl(struct socket *, u_long, caddr_t, int in6_prefix_add_ifid(int, struct in6_ifaddr *); void in6_prefix_remove_ifid(int, struct in6_ifaddr *); void in6_purgeprefix(struct ifnet *); -void in6_ifremloop(struct ifaddr *); -void in6_ifaddloop(struct ifaddr *); int in6_is_addr_deprecated(struct sockaddr_in6 *); int in6_src_ioctl(u_long, caddr_t); +void in6_newaddrmsg(struct in6_ifaddr *, int); /* * Extended API for IPv6 FIB support. */ diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index 1e1016561fae..5308d79e1b42 100644 --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -133,6 +133,7 @@ static int regen_tmpaddr(struct in6_ifaddr *); static struct llentry *nd6_free(struct llentry *, int); static void nd6_llinfo_timer(void *); static void clear_llinfo_pqueue(struct llentry *); +static void nd6_rtrequest(int, struct rtentry *, struct rt_addrinfo *); static VNET_DEFINE(struct callout, nd6_slowtimo_ch); #define V_nd6_slowtimo_ch VNET(nd6_slowtimo_ch) @@ -2176,6 +2177,62 @@ nd6_need_cache(struct ifnet *ifp) } } +/* + * Add pernament ND6 link-layer record for given + * interface address. + * + * Very similar to IPv4 arp_ifinit(), but: + * 1) IPv6 DAD is performed in different place + * 2) It is called by IPv6 protocol stack in contrast to + * arp_ifinit() which is typically called in SIOCSIFADDR + * driver ioctl handler. + * + */ +int +nd6_add_ifa_lle(struct in6_ifaddr *ia) +{ + struct ifnet *ifp; + struct llentry *ln; + + ifp = ia->ia_ifa.ifa_ifp; + IF_AFDATA_LOCK(ifp); + ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; + ln = lla_lookup(LLTABLE6(ifp), (LLE_CREATE | LLE_IFADDR | + LLE_EXCLUSIVE), (struct sockaddr *)&ia->ia_addr); + IF_AFDATA_UNLOCK(ifp); + if (ln != NULL) { + ln->la_expire = 0; /* for IPv6 this means permanent */ + ln->ln_state = ND6_LLINFO_REACHABLE; + LLE_WUNLOCK(ln); + in6_newaddrmsg(ia, RTM_ADD); + return (0); + } + + return (ENOBUFS); +} + +/* + * Removes ALL lle records for interface address prefix. + * XXXME: That's probably not we really want to do, we need + * to remove address record only and keep other records + * until we determine if given prefix is really going + * to be removed. + */ +void +nd6_rem_ifa_lle(struct in6_ifaddr *ia) +{ + struct sockaddr_in6 mask, addr; + struct ifnet *ifp; + + in6_newaddrmsg(ia, RTM_DELETE); + + ifp = ia->ia_ifa.ifa_ifp; + memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr)); + memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask)); + lltable_prefix_free(AF_INET6, (struct sockaddr *)&addr, + (struct sockaddr *)&mask, LLE_STATIC); +} + /* * the callers of this function need to be re-worked to drop * the lle lock, drop here for now diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h index 25d8c5d1f6ba..a23a4f608c48 100644 --- a/sys/netinet6/nd6.h +++ b/sys/netinet6/nd6.h @@ -404,7 +404,6 @@ void nd6_purge(struct ifnet *); void nd6_nud_hint(struct rtentry *, struct in6_addr *, int); int nd6_resolve(struct ifnet *, struct rtentry *, struct mbuf *, struct sockaddr *, u_char *); -void nd6_rtrequest(int, struct rtentry *, struct rt_addrinfo *); int nd6_ioctl(u_long, caddr_t, struct ifnet *); struct llentry *nd6_cache_lladdr(struct ifnet *, struct in6_addr *, char *, int, int, int); @@ -416,6 +415,8 @@ int nd6_output_lle(struct ifnet *, struct ifnet *, struct mbuf *, int nd6_output_flush(struct ifnet *, struct ifnet *, struct mbuf *, struct sockaddr_in6 *, struct route *); int nd6_need_cache(struct ifnet *); +int nd6_add_ifa_lle(struct in6_ifaddr *); +void nd6_rem_ifa_lle(struct in6_ifaddr *); int nd6_storelladdr(struct ifnet *, struct mbuf *, const struct sockaddr *, u_char *, struct llentry **); diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c index 36cdac465ab0..19c5f8d53474 100644 --- a/sys/netinet6/nd6_rtr.c +++ b/sys/netinet6/nd6_rtr.c @@ -1829,19 +1829,9 @@ in6_ifadd(struct nd_prefixctl *pr, int mcast) } /* make ifaddr */ + in6_prepare_ifra(&ifra, &pr->ndpr_prefix.sin6_addr, &mask); - bzero(&ifra, sizeof(ifra)); - /* - * in6_update_ifa() does not use ifra_name, but we accurately set it - * for safety. - */ - strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); - ifra.ifra_addr.sin6_family = AF_INET6; - ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); - /* prefix */ - ifra.ifra_addr.sin6_addr = pr->ndpr_prefix.sin6_addr; IN6_MASK_ADDR(&ifra.ifra_addr.sin6_addr, &mask); - /* interface ID */ ifra.ifra_addr.sin6_addr.s6_addr32[0] |= (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]); @@ -1853,12 +1843,6 @@ in6_ifadd(struct nd_prefixctl *pr, int mcast) (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]); ifa_free(ifa); - /* new prefix mask. */ - ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); - ifra.ifra_prefixmask.sin6_family = AF_INET6; - bcopy(&mask, &ifra.ifra_prefixmask.sin6_addr, - sizeof(ifra.ifra_prefixmask.sin6_addr)); - /* lifetimes. */ ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime; ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime; @@ -1915,7 +1899,7 @@ int in6_tmpifadd(const struct in6_ifaddr *ia0, int forcegen, int delay) { struct ifnet *ifp = ia0->ia_ifa.ifa_ifp; - struct in6_ifaddr *newia, *ia; + struct in6_ifaddr *newia; struct in6_aliasreq ifra; int error; int trylimit = 3; /* XXX: adhoc value */ @@ -1923,11 +1907,10 @@ in6_tmpifadd(const struct in6_ifaddr *ia0, int forcegen, int delay) u_int32_t randid[2]; time_t vltime0, pltime0; - bzero(&ifra, sizeof(ifra)); - strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); - ifra.ifra_addr = ia0->ia_addr; - /* copy prefix mask */ - ifra.ifra_prefixmask = ia0->ia_prefixmask; + in6_prepare_ifra(&ifra, &ia0->ia_addr.sin6_addr, + &ia0->ia_prefixmask.sin6_addr); + + ifra.ifra_addr = ia0->ia_addr; /* XXX: do we need this ? */ /* clear the old IFID */ IN6_MASK_ADDR(&ifra.ifra_addr.sin6_addr, &ifra.ifra_prefixmask.sin6_addr); @@ -1950,26 +1933,18 @@ in6_tmpifadd(const struct in6_ifaddr *ia0, int forcegen, int delay) * there may be a time lag between generation of the ID and generation * of the address. So, we'll do one more sanity check. */ - IN6_IFADDR_RLOCK(); - TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) { - if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, - &ifra.ifra_addr.sin6_addr)) { - if (trylimit-- == 0) { - IN6_IFADDR_RUNLOCK(); - /* - * Give up. Something strange should have - * happened. - */ - nd6log((LOG_NOTICE, "in6_tmpifadd: failed to " - "find a unique random IFID\n")); - return (EEXIST); - } - IN6_IFADDR_RUNLOCK(); + + if (in6_localip(&ifra.ifra_addr.sin6_addr) != 0) { + if (trylimit-- > 0) { forcegen = 1; goto again; } + + /* Give up. Something strange should have happened. */ + nd6log((LOG_NOTICE, "in6_tmpifadd: failed to " + "find a unique random IFID\n")); + return (EEXIST); } - IN6_IFADDR_RUNLOCK(); /* * The Valid Lifetime is the lower of the Valid Lifetime of the diff --git a/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c index bae1740ae7bd..52a03d2a7913 100644 --- a/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1490,14 +1490,7 @@ ipoib_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa, sin = (struct sockaddr_in *)sa; if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) return EADDRNOTAVAIL; - sdl = malloc(sizeof *sdl, M_IFMADDR, - M_NOWAIT|M_ZERO); - if (sdl == NULL) - return ENOMEM; - sdl->sdl_len = sizeof *sdl; - sdl->sdl_family = AF_LINK; - sdl->sdl_index = ifp->if_index; - sdl->sdl_type = IFT_INFINIBAND; + sdl = link_init_sdl(ifp, *llsa, IFT_INFINIBAND); sdl->sdl_alen = INFINIBAND_ALEN; e_addr = LLADDR(sdl); ip_ib_mc_map(sin->sin_addr.s_addr, ifp->if_broadcastaddr, @@ -1517,14 +1510,7 @@ ipoib_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa, return EADDRNOTAVAIL; if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) return EADDRNOTAVAIL; - sdl = malloc(sizeof *sdl, M_IFMADDR, - M_NOWAIT|M_ZERO); - if (sdl == NULL) - return (ENOMEM); - sdl->sdl_len = sizeof *sdl; - sdl->sdl_family = AF_LINK; - sdl->sdl_index = ifp->if_index; - sdl->sdl_type = IFT_INFINIBAND; + sdl = link_init_sdl(ifp, *llsa, IFT_INFINIBAND); sdl->sdl_alen = INFINIBAND_ALEN; e_addr = LLADDR(sdl); ipv6_ib_mc_map(&sin6->sin6_addr, ifp->if_broadcastaddr, e_addr); diff --git a/sys/powerpc/powermac/pmu.c b/sys/powerpc/powermac/pmu.c index ca979d8c9238..c6bd1b053ae2 100644 --- a/sys/powerpc/powermac/pmu.c +++ b/sys/powerpc/powermac/pmu.c @@ -378,7 +378,7 @@ pmu_attach(device_t dev) pmu_write_reg(sc, vIER, 0x94); /* make sure VIA interrupts are on */ pmu_send(sc, PMU_SYSTEM_READY, 1, cmd, 16, resp); - pmu_send(sc, PMU_GET_VERSION, 1, cmd, 16, resp); + pmu_send(sc, PMU_GET_VERSION, 0, cmd, 16, resp); /* Initialize child buses (ADB) */ node = ofw_bus_get_node(dev); diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h index bc2924ad6560..e8caa3897e39 100644 --- a/sys/sys/mbuf.h +++ b/sys/sys/mbuf.h @@ -465,14 +465,6 @@ struct mbuf { #define MT_NOINIT 255 /* Not a type but a flag to allocate a non-initialized mbuf */ -/* - * Compatibility with historic mbuf allocator. - */ -#define MBTOM(how) (how) -#define M_DONTWAIT M_NOWAIT -#define M_TRYWAIT M_WAITOK -#define M_WAIT M_WAITOK - /* * String names of mbuf-related UMA(9) and malloc(9) types. Exposed to * !_KERNEL so that monitoring tools can look up the zones with diff --git a/sys/sys/random.h b/sys/sys/random.h index 9fee143751b8..8bb262ab446a 100644 --- a/sys/sys/random.h +++ b/sys/sys/random.h @@ -56,6 +56,7 @@ enum esource { RANDOM_PURE_RDRAND, RANDOM_PURE_NEHEMIAH, RANDOM_PURE_RNDTEST, + RANDOM_PURE_VIRTIO, ENTROPYSOURCE }; void random_harvest(const void *, u_int, u_int, enum esource); diff --git a/sys/sys/sf_base.h b/sys/sys/sf_base.h index 1c03ef447259..7c8d49cde4fe 100644 --- a/sys/sys/sf_base.h +++ b/sys/sys/sf_base.h @@ -31,6 +31,7 @@ extern int _do_sendfile(struct thread *, int src_fd, int sock_fd, int flags, int compat, off_t offset, size_t nbytes, off_t *sbytes, - struct uio *hdr_uio, struct uio *trl_uio); + struct uio *hdr_uio, struct uio *trl_uio, + struct sf_hdtr_kq *hdtr_kq); #endif /* _SYS_SF_BASE_H_ */ diff --git a/sys/sys/sf_sync.h b/sys/sys/sf_sync.h index c66f4d99f162..04dee3801a5e 100644 --- a/sys/sys/sf_sync.h +++ b/sys/sys/sf_sync.h @@ -29,17 +29,36 @@ #ifndef _SYS_SF_SYNC_H_ #define _SYS_SF_SYNC_H_ +typedef enum { + SF_STATE_NONE, + SF_STATE_SETUP, + SF_STATE_RUNNING, + SF_STATE_COMPLETED, + SF_STATE_FREEING +} sendfile_sync_state_t; + struct sendfile_sync { - uint32_t flags; struct mtx mtx; struct cv cv; - unsigned count; + struct knlist klist; + uint32_t flags; + uint32_t count; + int32_t xerrno; /* Completion errno, if retval < 0 */ + off_t retval; /* Completion retval (eg written bytes) */ + sendfile_sync_state_t state; }; +/* XXX pollution */ +struct sf_hdtr_kq; + extern struct sendfile_sync * sf_sync_alloc(uint32_t flags); extern void sf_sync_syscall_wait(struct sendfile_sync *); extern void sf_sync_free(struct sendfile_sync *); +extern void sf_sync_try_free(struct sendfile_sync *); extern void sf_sync_ref(struct sendfile_sync *); extern void sf_sync_deref(struct sendfile_sync *); +extern int sf_sync_kqueue_setup(struct sendfile_sync *, struct sf_hdtr_kq *); +extern void sf_sync_set_state(struct sendfile_sync *, sendfile_sync_state_t, int); +extern void sf_sync_set_retval(struct sendfile_sync *, off_t, int); #endif /* !_SYS_SF_BUF_H_ */ diff --git a/sys/sys/socket.h b/sys/sys/socket.h index 952454aea003..25ff9bf3ef28 100644 --- a/sys/sys/socket.h +++ b/sys/sys/socket.h @@ -84,6 +84,16 @@ typedef __uid_t uid_t; #endif #endif +#ifndef _UINT32_T_DECLARED +typedef __uint32_t uint32_t; +#define _UINT32_T_DECLARED +#endif + +#ifndef _UINTPTR_T_DECLARED +typedef __uintptr_t uintptr_t; +#define _UINTPTR_T_DECLARED +#endif + /* * Types */ @@ -576,12 +586,28 @@ struct sf_hdtr { int trl_cnt; /* number of trailer iovec's */ }; +/* + * sendfile(2) kqueue information + */ +struct sf_hdtr_kq { + uintptr_t kq_ident; /* ident (from userland?) */ + void *kq_udata; /* user data pointer */ + uint32_t kq_flags; /* extra flags to pass in */ + int kq_fd; /* kq fd to post completion events on */ +}; + +struct sf_hdtr_all { + struct sf_hdtr hdtr; + struct sf_hdtr_kq kq; +}; + /* * Sendfile-specific flag(s) */ #define SF_NODISKIO 0x00000001 #define SF_MNOWAIT 0x00000002 #define SF_SYNC 0x00000004 +#define SF_KQUEUE 0x00000008 #ifdef _KERNEL #define SFK_COMPAT 0x00000001 diff --git a/sys/vm/vm_pageout.c b/sys/vm/vm_pageout.c index d2ccfa0f16d8..517491fe7efb 100644 --- a/sys/vm/vm_pageout.c +++ b/sys/vm/vm_pageout.c @@ -1047,11 +1047,11 @@ vm_pageout_scan(struct vm_domain *vmd, int pass) * level VM system not knowing anything about existing * references. */ - act_delta = 0; if ((m->aflags & PGA_REFERENCED) != 0) { vm_page_aflag_clear(m, PGA_REFERENCED); act_delta = 1; - } + } else + act_delta = 0; if (object->ref_count != 0) { act_delta += pmap_ts_referenced(m); } else { @@ -1064,7 +1064,7 @@ vm_pageout_scan(struct vm_domain *vmd, int pass) * references, we reactivate the page or requeue it. */ if (act_delta != 0) { - if (object->ref_count) { + if (object->ref_count != 0) { vm_page_activate(m); m->act_count += act_delta + ACT_ADVANCE; } else { @@ -1361,11 +1361,12 @@ vm_pageout_scan(struct vm_domain *vmd, int pass) /* * Check to see "how much" the page has been used. */ - act_delta = 0; - if (m->aflags & PGA_REFERENCED) { + if ((m->aflags & PGA_REFERENCED) != 0) { vm_page_aflag_clear(m, PGA_REFERENCED); - act_delta += 1; - } + act_delta = 1; + } else + act_delta = 0; + /* * Unlocked object ref count check. Two races are possible. * 1) The ref was transitioning to zero and we saw non-zero, @@ -1380,20 +1381,18 @@ vm_pageout_scan(struct vm_domain *vmd, int pass) /* * Advance or decay the act_count based on recent usage. */ - if (act_delta) { + if (act_delta != 0) { m->act_count += ACT_ADVANCE + act_delta; if (m->act_count > ACT_MAX) m->act_count = ACT_MAX; - } else { + } else m->act_count -= min(m->act_count, ACT_DECLINE); - act_delta = m->act_count; - } /* * Move this page to the tail of the active or inactive * queue depending on usage. */ - if (act_delta == 0) { + if (m->act_count == 0) { /* Dequeue to avoid later lock recursion. */ vm_page_dequeue_locked(m); vm_page_deactivate(m); diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c index 2e3d2c0095b9..5e509797b1be 100644 --- a/sys/vm/vnode_pager.c +++ b/sys/vm/vnode_pager.c @@ -244,8 +244,7 @@ vnode_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot, * The object must be locked. */ static void -vnode_pager_dealloc(object) - vm_object_t object; +vnode_pager_dealloc(vm_object_t object) { struct vnode *vp; int refs; @@ -280,11 +279,8 @@ vnode_pager_dealloc(object) } static boolean_t -vnode_pager_haspage(object, pindex, before, after) - vm_object_t object; - vm_pindex_t pindex; - int *before; - int *after; +vnode_pager_haspage(vm_object_t object, vm_pindex_t pindex, int *before, + int *after) { struct vnode *vp = object->handle; daddr_t bn; @@ -363,9 +359,7 @@ vnode_pager_haspage(object, pindex, before, after) * operation (possibly at object termination time), so we must be careful. */ void -vnode_pager_setsize(vp, nsize) - struct vnode *vp; - vm_ooffset_t nsize; +vnode_pager_setsize(struct vnode *vp, vm_ooffset_t nsize) { vm_object_t object; vm_page_t m; @@ -490,9 +484,7 @@ vnode_pager_addr(struct vnode *vp, vm_ooffset_t address, daddr_t *rtaddress, * small block filesystem vnode pager input */ static int -vnode_pager_input_smlfs(object, m) - vm_object_t object; - vm_page_t m; +vnode_pager_input_smlfs(vm_object_t object, vm_page_t m) { struct vnode *vp; struct bufobj *bo; @@ -584,9 +576,7 @@ vnode_pager_input_smlfs(object, m) * old style vnode pager input routine */ static int -vnode_pager_input_old(object, m) - vm_object_t object; - vm_page_t m; +vnode_pager_input_old(vm_object_t object, vm_page_t m) { struct uio auio; struct iovec aiov; @@ -659,11 +649,7 @@ vnode_pager_input_old(object, m) * backing vp's VOP_GETPAGES. */ static int -vnode_pager_getpages(object, m, count, reqpage) - vm_object_t object; - vm_page_t *m; - int count; - int reqpage; +vnode_pager_getpages(vm_object_t object, vm_page_t *m, int count, int reqpage) { int rtval; struct vnode *vp; @@ -683,11 +669,8 @@ vnode_pager_getpages(object, m, count, reqpage) * own vnodes if they fail to implement VOP_GETPAGES. */ int -vnode_pager_generic_getpages(vp, m, bytecount, reqpage) - struct vnode *vp; - vm_page_t *m; - int bytecount; - int reqpage; +vnode_pager_generic_getpages(struct vnode *vp, vm_page_t *m, int bytecount, + int reqpage) { vm_object_t object; vm_offset_t kva; @@ -1024,12 +1007,8 @@ vnode_pager_generic_getpages(vp, m, bytecount, reqpage) * backing vp's VOP_PUTPAGES. */ static void -vnode_pager_putpages(object, m, count, sync, rtvals) - vm_object_t object; - vm_page_t *m; - int count; - boolean_t sync; - int *rtvals; +vnode_pager_putpages(vm_object_t object, vm_page_t *m, int count, + boolean_t sync, int *rtvals) { int rtval; struct vnode *vp; diff --git a/sys/x86/x86/nexus.c b/sys/x86/x86/nexus.c index 9ead8c842cae..f74299cf4351 100644 --- a/sys/x86/x86/nexus.c +++ b/sys/x86/x86/nexus.c @@ -368,12 +368,13 @@ nexus_alloc_resource(device_t bus, device_t child, int type, int *rid, int needactivate = flags & RF_ACTIVE; /* - * If this is an allocation of the "default" range for a given RID, and - * we know what the resources for this device are (ie. they aren't maintained - * by a child bus), then work out the start/end values. + * If this is an allocation of the "default" range for a given + * RID, and we know what the resources for this device are + * (ie. they aren't maintained by a child bus), then work out + * the start/end values. */ if ((start == 0UL) && (end == ~0UL) && (count == 1)) { - if (ndev == NULL) + if (device_get_parent(child) != bus || ndev == NULL) return(NULL); rle = resource_list_find(&ndev->nx_resources, type, *rid); if (rle == NULL) @@ -492,6 +493,7 @@ static int nexus_release_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { + if (rman_get_flags(r) & RF_ACTIVE) { int error = bus_deactivate_resource(child, type, rid, r); if (error) diff --git a/tools/tools/mcgrab/mcgrab.cc b/tools/tools/mcgrab/mcgrab.cc index 5522f303004b..35687b8d42ce 100644 --- a/tools/tools/mcgrab/mcgrab.cc +++ b/tools/tools/mcgrab/mcgrab.cc @@ -88,7 +88,7 @@ void usage(string message) // // @return 0 for 0K, -1 for error, sets errno // -void grab(char *interface, struct in_addr *group, int number) { +void grab(char *interface, struct in_addr *group, int number, int block) { int sock; @@ -138,8 +138,10 @@ void grab(char *interface, struct in_addr *group, int number) { group->s_addr = htonl(ntohl(group->s_addr) + 1); } - printf("Press Control-C to exit.\n"); - sleep(INT_MAX); + if (block > 0) { + printf("Press Control-C to exit.\n"); + sleep(INT_MAX); + } } @@ -160,11 +162,12 @@ int main(int argc, char**argv) char* interface = 0; ///< Name of the interface struct in_addr *group = NULL; ///< the multicast group address int number = 0; ///< Number of addresses to grab + int block = 1; ///< Do we block or just return? - if (argc != 7) + if ((argc < 7) || (argc > 8)) usage(); - while ((ch = getopt(argc, argv, "g:i:n:h")) != -1) { + while ((ch = getopt(argc, argv, "g:i:n:bh")) != -1) { switch (ch) { case 'g': group = new (struct in_addr ); @@ -178,12 +181,15 @@ int main(int argc, char**argv) case 'n': number = atoi(optarg); break; + case 'b': + block = 0; + break; case 'h': usage(string("Help\n")); break; } } - grab(interface, group, number); + grab(interface, group, number, block); } diff --git a/tools/tools/netmap/Makefile b/tools/tools/netmap/Makefile index d737bac71939..e873389c7179 100644 --- a/tools/tools/netmap/Makefile +++ b/tools/tools/netmap/Makefile @@ -10,7 +10,12 @@ NO_MAN= CFLAGS += -Werror -Wall -nostdinc -I/usr/include -I../../../sys CFLAGS += -Wextra -LDFLAGS += -lpthread -lpcap +LDFLAGS += -lpthread +.ifdef WITHOUT_PCAP +CFLAGS += -DNO_PCAP +.else +LDFLAGS += -lpcap +.endif .include .include diff --git a/tools/tools/netmap/bridge.c b/tools/tools/netmap/bridge.c index 6dc77e438273..cab545bfc919 100644 --- a/tools/tools/netmap/bridge.c +++ b/tools/tools/netmap/bridge.c @@ -96,16 +96,16 @@ process_rings(struct netmap_ring *rxring, struct netmap_ring *txring, /* move packts from src to destination */ static int -move(struct my_ring *src, struct my_ring *dst, u_int limit) +move(struct nm_desc_t *src, struct nm_desc_t *dst, u_int limit) { struct netmap_ring *txring, *rxring; - u_int m = 0, si = src->begin, di = dst->begin; - const char *msg = (src->queueid & NETMAP_SW_RING) ? + u_int m = 0, si = src->first_rx_ring, di = dst->first_tx_ring; + const char *msg = (src->req.nr_ringid & NETMAP_SW_RING) ? "host->net" : "net->host"; - while (si < src->end && di < dst->end) { - rxring = NETMAP_RXRING(src->nifp, si); - txring = NETMAP_TXRING(dst->nifp, di); + while (si <= src->last_rx_ring && di <= dst->last_tx_ring) { + rxring = src->tx + si; + txring = dst->tx + di; ND("txring %p rxring %p", txring, rxring); if (nm_ring_empty(rxring)) { si++; @@ -121,28 +121,6 @@ move(struct my_ring *src, struct my_ring *dst, u_int limit) return (m); } -/* - * how many packets on this set of queues ? - */ -static int -pkt_queued(struct my_ring *me, int tx) -{ - u_int i, tot = 0; - - ND("me %p begin %d end %d", me, me->begin, me->end); - for (i = me->begin; i < me->end; i++) { - struct netmap_ring *ring = tx ? - NETMAP_TXRING(me->nifp, i) : NETMAP_RXRING(me->nifp, i); - tot += nm_ring_space(ring); - } - if (0 && verbose && tot && !tx) - D("ring %s %s %s has %d avail at %d", - me->ifname, tx ? "tx": "rx", - me->end >= me->nifp->ni_tx_rings ? // XXX who comes first ? - "host":"net", - tot, NETMAP_TXRING(me->nifp, me->begin)->cur); - return tot; -} static void usage(void) @@ -165,14 +143,12 @@ main(int argc, char **argv) struct pollfd pollfd[2]; int i, ch; u_int burst = 1024, wait_link = 4; - struct my_ring me[2]; + struct nm_desc_t *pa = NULL, *pb = NULL; char *ifa = NULL, *ifb = NULL; fprintf(stderr, "%s %s built %s %s\n", argv[0], version, __DATE__, __TIME__); - bzero(me, sizeof(me)); - while ( (ch = getopt(argc, argv, "b:i:vw:")) != -1) { switch (ch) { default: @@ -224,9 +200,6 @@ main(int argc, char **argv) D("invalid wait_link %d, set to 4", wait_link); wait_link = 4; } - /* setup netmap interface #1. */ - me[0].ifname = ifa; - me[1].ifname = ifb; if (!strcmp(ifa, ifb)) { D("same interface, endpoint 0 goes to host"); i = NETMAP_SW_RING; @@ -234,24 +207,26 @@ main(int argc, char **argv) /* two different interfaces. Take all rings on if1 */ i = 0; // all hw rings } - if (netmap_open(me, i, 1)) + pa = netmap_open(ifa, i, 1); + if (pa == NULL) return (1); - me[1].mem = me[0].mem; /* copy the pointer, so only one mmap */ - if (netmap_open(me+1, 0, 1)) + // XXX use a single mmap ? + pb = netmap_open(ifb, 0, 1); + if (pb == NULL) { + nm_close(pa); return (1); + } /* setup poll(2) variables. */ memset(pollfd, 0, sizeof(pollfd)); - for (i = 0; i < 2; i++) { - pollfd[i].fd = me[i].fd; - pollfd[i].events = (POLLIN); - } + pollfd[0].fd = pa->fd; + pollfd[1].fd = pb->fd; D("Wait %d secs for link to come up...", wait_link); sleep(wait_link); D("Ready to go, %s 0x%x/%d <-> %s 0x%x/%d.", - me[0].ifname, me[0].queueid, me[0].nifp->ni_rx_rings, - me[1].ifname, me[1].queueid, me[1].nifp->ni_rx_rings); + pa->req.nr_name, pa->first_rx_ring, pa->req.nr_rx_rings, + pb->req.nr_name, pb->first_rx_ring, pb->req.nr_rx_rings); /* main loop */ signal(SIGINT, sigint_h); @@ -259,8 +234,8 @@ main(int argc, char **argv) int n0, n1, ret; pollfd[0].events = pollfd[1].events = 0; pollfd[0].revents = pollfd[1].revents = 0; - n0 = pkt_queued(me, 0); - n1 = pkt_queued(me + 1, 0); + n0 = pkt_queued(pa, 0); + n1 = pkt_queued(pb, 0); if (n0) pollfd[1].events |= POLLOUT; else @@ -276,39 +251,39 @@ main(int argc, char **argv) ret <= 0 ? "timeout" : "ok", pollfd[0].events, pollfd[0].revents, - pkt_queued(me, 0), - me[0].rx->cur, - pkt_queued(me, 1), + pkt_queued(pa, 0), + pa->rx->cur, + pkt_queued(pa, 1), pollfd[1].events, pollfd[1].revents, - pkt_queued(me+1, 0), - me[1].rx->cur, - pkt_queued(me+1, 1) + pkt_queued(pb, 0), + pb->rx->cur, + pkt_queued(pb, 1) ); if (ret < 0) continue; if (pollfd[0].revents & POLLERR) { D("error on fd0, rx [%d,%d)", - me[0].rx->cur, me[0].rx->tail); + pa->rx->cur, pa->rx->tail); } if (pollfd[1].revents & POLLERR) { D("error on fd1, rx [%d,%d)", - me[1].rx->cur, me[1].rx->tail); + pb->rx->cur, pb->rx->tail); } if (pollfd[0].revents & POLLOUT) { - move(me + 1, me, burst); + move(pb, pa, burst); // XXX we don't need the ioctl */ // ioctl(me[0].fd, NIOCTXSYNC, NULL); } if (pollfd[1].revents & POLLOUT) { - move(me, me + 1, burst); + move(pa, pb, burst); // XXX we don't need the ioctl */ // ioctl(me[1].fd, NIOCTXSYNC, NULL); } } D("exiting"); - netmap_close(me + 1); - netmap_close(me + 0); + nm_close(pb); + nm_close(pa); return (0); } diff --git a/tools/tools/netmap/nm_util.c b/tools/tools/netmap/nm_util.c index 1268840cd868..deb52bbc87e4 100644 --- a/tools/tools/netmap/nm_util.c +++ b/tools/tools/netmap/nm_util.c @@ -37,16 +37,21 @@ extern int verbose; int -nm_do_ioctl(struct my_ring *me, u_long what, int subcmd) +nm_do_ioctl(struct nm_desc_t *me, u_long what, int subcmd) { struct ifreq ifr; int error; + int fd; + #if defined( __FreeBSD__ ) || defined (__APPLE__) - int fd = me->fd; + (void)subcmd; // only used on Linux + fd = me->fd; #endif + #ifdef linux struct ethtool_value eval; - int fd; + + bzero(&eval, sizeof(eval)); fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { printf("Error: cannot get device control socket.\n"); @@ -54,9 +59,8 @@ nm_do_ioctl(struct my_ring *me, u_long what, int subcmd) } #endif /* linux */ - (void)subcmd; // unused bzero(&ifr, sizeof(ifr)); - strncpy(ifr.ifr_name, me->ifname, sizeof(ifr.ifr_name)); + strncpy(ifr.ifr_name, me->req.nr_name, sizeof(ifr.ifr_name)); switch (what) { case SIOCSIFFLAGS: #ifndef __APPLE__ @@ -71,6 +75,7 @@ nm_do_ioctl(struct my_ring *me, u_long what, int subcmd) ifr.ifr_curcap = me->if_curcap; break; #endif + #ifdef linux case SIOCETHTOOL: eval.cmd = subcmd; @@ -115,108 +120,47 @@ nm_do_ioctl(struct my_ring *me, u_long what, int subcmd) * Returns the file descriptor. * The extra flag checks configures promisc mode. */ -int -netmap_open(struct my_ring *me, int ringid, int promisc) +struct nm_desc_t * +netmap_open(const char *name, int ringid, int promisc) { - int fd, err, l; - struct nmreq req; + struct nm_desc_t *d = nm_open(name, NULL, ringid, 0); + + if (d == NULL) + return d; - me->fd = fd = open("/dev/netmap", O_RDWR); - if (fd < 0) { - D("Unable to open /dev/netmap"); - return (-1); - } - bzero(&req, sizeof(req)); - req.nr_version = NETMAP_API; - strncpy(req.nr_name, me->ifname, sizeof(req.nr_name)); - req.nr_ringid = ringid; - err = ioctl(fd, NIOCREGIF, &req); - if (err) { - D("Unable to register %s", me->ifname); - goto error; - } - me->memsize = l = req.nr_memsize; if (verbose) - D("memsize is %d MB", l>>20); - - if (me->mem == NULL) { - me->mem = mmap(0, l, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0); - if (me->mem == MAP_FAILED) { - D("Unable to mmap"); - me->mem = NULL; - goto error; - } - } - + D("memsize is %d MB", d->req.nr_memsize>>20); /* Set the operating mode. */ if (ringid != NETMAP_SW_RING) { - nm_do_ioctl(me, SIOCGIFFLAGS, 0); - if ((me[0].if_flags & IFF_UP) == 0) { - D("%s is down, bringing up...", me[0].ifname); - me[0].if_flags |= IFF_UP; + nm_do_ioctl(d, SIOCGIFFLAGS, 0); + if ((d->if_flags & IFF_UP) == 0) { + D("%s is down, bringing up...", name); + d->if_flags |= IFF_UP; } if (promisc) { - me[0].if_flags |= IFF_PPROMISC; - nm_do_ioctl(me, SIOCSIFFLAGS, 0); + d->if_flags |= IFF_PPROMISC; + nm_do_ioctl(d, SIOCSIFFLAGS, 0); } + /* disable GSO, TSO, RXCSUM, TXCSUM... + * TODO: set them back when done. + */ #ifdef __FreeBSD__ - /* also disable checksums etc. */ - nm_do_ioctl(me, SIOCGIFCAP, 0); - me[0].if_reqcap = me[0].if_curcap; - me[0].if_reqcap &= ~(IFCAP_HWCSUM | IFCAP_TSO | IFCAP_TOE); - nm_do_ioctl(me+0, SIOCSIFCAP, 0); + nm_do_ioctl(d, SIOCGIFCAP, 0); + d->if_reqcap = d->if_curcap; + d->if_reqcap &= ~(IFCAP_HWCSUM | IFCAP_TSO | IFCAP_TOE); + nm_do_ioctl(d, SIOCSIFCAP, 0); #endif #ifdef linux - /* disable: - * - generic-segmentation-offload - * - tcp-segmentation-offload - * - rx-checksumming - * - tx-checksumming - * XXX check how to set back the caps. - */ - nm_do_ioctl(me, SIOCETHTOOL, ETHTOOL_SGSO); - nm_do_ioctl(me, SIOCETHTOOL, ETHTOOL_STSO); - nm_do_ioctl(me, SIOCETHTOOL, ETHTOOL_SRXCSUM); - nm_do_ioctl(me, SIOCETHTOOL, ETHTOOL_STXCSUM); + nm_do_ioctl(d, SIOCETHTOOL, ETHTOOL_SGSO); + nm_do_ioctl(d, SIOCETHTOOL, ETHTOOL_STSO); + nm_do_ioctl(d, SIOCETHTOOL, ETHTOOL_SRXCSUM); + nm_do_ioctl(d, SIOCETHTOOL, ETHTOOL_STXCSUM); #endif /* linux */ } - me->nifp = NETMAP_IF(me->mem, req.nr_offset); - me->queueid = ringid; - if (ringid & NETMAP_SW_RING) { - me->begin = req.nr_rx_rings; - me->end = me->begin + 1; - me->tx = NETMAP_TXRING(me->nifp, req.nr_tx_rings); - me->rx = NETMAP_RXRING(me->nifp, req.nr_rx_rings); - } else if (ringid & NETMAP_HW_RING) { - D("XXX check multiple threads"); - me->begin = ringid & NETMAP_RING_MASK; - me->end = me->begin + 1; - me->tx = NETMAP_TXRING(me->nifp, me->begin); - me->rx = NETMAP_RXRING(me->nifp, me->begin); - } else { - me->begin = 0; - me->end = req.nr_rx_rings; // XXX max of the two - me->tx = NETMAP_TXRING(me->nifp, 0); - me->rx = NETMAP_RXRING(me->nifp, 0); - } - return (0); -error: - close(me->fd); - return -1; -} - - -int -netmap_close(struct my_ring *me) -{ - D(""); - if (me->mem) - munmap(me->mem, me->memsize); - close(me->fd); - return (0); + return d; } @@ -224,22 +168,18 @@ netmap_close(struct my_ring *me) * how many packets on this set of queues ? */ int -pkt_queued(struct my_ring *me, int tx) +pkt_queued(struct nm_desc_t *d, int tx) { u_int i, tot = 0; ND("me %p begin %d end %d", me, me->begin, me->end); - for (i = me->begin; i < me->end; i++) { - struct netmap_ring *ring = tx ? - NETMAP_TXRING(me->nifp, i) : NETMAP_RXRING(me->nifp, i); - tot += nm_ring_space(ring); + if (tx) { + for (i = d->first_tx_ring; i <= d->last_tx_ring; i++) + tot += nm_ring_space(d->tx + i); + } else { + for (i = d->first_rx_ring; i <= d->last_rx_ring; i++) + tot += nm_ring_space(d->rx + i); } - if (0 && verbose && tot && !tx) - D("ring %s %s %s has %d avail at %d", - me->ifname, tx ? "tx": "rx", - me->end >= me->nifp->ni_tx_rings ? // XXX who comes first ? - "host":"net", - tot, NETMAP_TXRING(me->nifp, me->begin)->cur); return tot; } @@ -258,7 +198,7 @@ Helper routines for multiple readers from the same queue In particular we have a shared head+tail pointers that work together with cur and available ON RETURN FROM THE SYSCALL: - shadow->head = ring->cur + shadow->cur = ring->cur shadow->tail = ring->tail shadow->link[i] = i for all slots // mark invalid @@ -267,7 +207,7 @@ Helper routines for multiple readers from the same queue struct nm_q_arg { u_int want; /* Input */ u_int have; /* Output, 0 on error */ - u_int head; + u_int cur; u_int tail; struct netmap_ring *ring; }; @@ -280,24 +220,26 @@ my_grab(struct nm_q_arg q) { const u_int ns = q.ring->num_slots; + // lock(ring); for (;;) { - q.head = (volatile u_int)q.ring->head; + q.cur = (volatile u_int)q.ring->head; q.have = ns + q.head - (volatile u_int)q.ring->tail; if (q.have >= ns) q.have -= ns; - if (q.have == 0) /* no space */ + if (q.have == 0) /* no space; caller may ioctl/retry */ break; if (q.want < q.have) q.have = q.want; - q.tail = q.head + q.have; + q.tail = q.cur + q.have; if (q.tail >= ns) q.tail -= ns; - if (atomic_cmpset_int(&q.ring->head, q.head, q.tail) + if (atomic_cmpset_int(&q.ring->cur, q.cur, q.tail) break; /* success */ } + // unlock(ring); D("returns %d out of %d at %d,%d", - q.have, q.want, q.head, q.tail); + q.have, q.want, q.cur, q.tail); /* the last one can clear avail ? */ return q; } @@ -306,16 +248,18 @@ my_grab(struct nm_q_arg q) int my_release(struct nm_q_arg q) { - u_int head = q.head, tail = q.tail, i; + u_int cur = q.cur, tail = q.tail, i; struct netmap_ring *r = q.ring; /* link the block to the next one. * there is no race here because the location is mine. */ - r->slot[head].ptr = tail; /* this is mine */ + r->slot[cur].ptr = tail; /* this is mine */ + r->slot[cur].flags |= NM_SLOT_PTR; // points to next block // memory barrier - if (r->head != head) - return; /* not my turn to release */ + // lock(ring); + if (r->head != cur) + goto done; for (;;) { // advance head r->head = head = r->slot[head].ptr; @@ -327,5 +271,8 @@ my_release(struct nm_q_arg q) * further down. */ // do an ioctl/poll to flush. +done: + // unlock(ring); + return; /* not my turn to release */ } #endif /* unused */ diff --git a/tools/tools/netmap/nm_util.h b/tools/tools/netmap/nm_util.h index d8f8f94fd162..0ab2e2e81984 100644 --- a/tools/tools/netmap/nm_util.h +++ b/tools/tools/netmap/nm_util.h @@ -35,60 +35,31 @@ #define _GNU_SOURCE /* for CPU_SET() */ -#include -#include /* signal */ -#include -#include +#include /* fprintf */ +#include /* POLLIN */ #include /* PRI* macros */ -#include /* strcmp */ -#include /* open */ -#include /* close */ -#include /* getifaddrs */ +#include /* u_char */ -#include /* PROT_* */ -#include /* ioctl */ -#include -#include /* sockaddr.. */ #include /* ntohs */ -#include #include /* sysctl */ -#include /* timersub */ +#include /* getifaddrs */ +#include /* ETHERTYPE_IP */ +#include /* IPPROTO_* */ +#include /* struct ip */ +#include /* struct udp */ -#include -#include /* ifreq */ -#include -#include -#include - -#include +#define NETMAP_WITH_LIBS #include -#ifndef MY_PCAP /* use the system's pcap if available */ - -#ifdef NO_PCAP -#define PCAP_ERRBUF_SIZE 512 -typedef void pcap_t; -struct pcap_pkthdr; -#define pcap_inject(a,b,c) ((void)a, (void)b, (void)c, -1) -#define pcap_dispatch(a, b, c, d) (void)c -#define pcap_open_live(a, b, c, d, e) ((void)e, NULL) -#else /* !NO_PCAP */ -#include // XXX do we need it ? -#endif /* !NO_PCAP */ - -#endif // XXX hack - #include /* pthread_* */ #ifdef linux #define cpuset_t cpu_set_t -#define ifr_flagshigh ifr_flags -#define ifr_curcap ifr_flags -#define ifr_reqcap ifr_flags -#define IFF_PPROMISC IFF_PROMISC +#define ifr_flagshigh ifr_flags /* only the low 16 bits here */ +#define IFF_PPROMISC IFF_PROMISC /* IFF_PPROMISC does not exist */ #include #include @@ -107,6 +78,20 @@ struct pcap_pkthdr; #endif /* __FreeBSD__ */ #ifdef __APPLE__ + +#define cpuset_t uint64_t // XXX +static inline void CPU_ZERO(cpuset_t *p) +{ + *p = 0; +} + +static inline void CPU_SET(uint32_t i, cpuset_t *p) +{ + *p |= 1<< (i & 0x3f); +} + +#define pthread_setaffinity_np(a, b, c) ((void)a, 0) + #define ifr_flagshigh ifr_flags // XXX #define IFF_PPROMISC IFF_PROMISC #include /* LLADDR */ @@ -136,54 +121,7 @@ extern int time_second; -// XXX does it work on 32-bit machines ? -static inline void prefetch (const void *x) -{ - __asm volatile("prefetcht0 %0" :: "m" (*(const unsigned long *)x)); -} - -// XXX only for multiples of 64 bytes, non overlapped. -static inline void -pkt_copy(const void *_src, void *_dst, int l) -{ - const uint64_t *src = _src; - uint64_t *dst = _dst; -#define likely(x) __builtin_expect(!!(x), 1) -#define unlikely(x) __builtin_expect(!!(x), 0) - if (unlikely(l >= 1024)) { - bcopy(src, dst, l); - return; - } - for (; l > 0; l-=64) { - *dst++ = *src++; - *dst++ = *src++; - *dst++ = *src++; - *dst++ = *src++; - *dst++ = *src++; - *dst++ = *src++; - *dst++ = *src++; - *dst++ = *src++; - } -} - -/* - * info on a ring we handle - */ -struct my_ring { - const char *ifname; - int fd; - char *mem; /* userspace mmap address */ - u_int memsize; - u_int queueid; - u_int begin, end; /* first..last+1 rings to check */ - struct netmap_if *nifp; - struct netmap_ring *tx, *rx; /* shortcuts */ - - uint32_t if_flags; - uint32_t if_reqcap; - uint32_t if_curcap; -}; -int netmap_open(struct my_ring *me, int ringid, int promisc); -int netmap_close(struct my_ring *me); -int nm_do_ioctl(struct my_ring *me, u_long what, int subcmd); +struct nm_desc_t * netmap_open(const char *name, int ringid, int promisc); +int nm_do_ioctl(struct nm_desc_t *me, u_long what, int subcmd); +int pkt_queued(struct nm_desc_t *d, int tx); #endif /* _NM_UTIL_H */ diff --git a/tools/tools/netmap/pcap.c b/tools/tools/netmap/pcap.c index dd87c4a1b00e..b3c2be5d23ff 100644 --- a/tools/tools/netmap/pcap.c +++ b/tools/tools/netmap/pcap.c @@ -65,7 +65,7 @@ struct pcap_stat { #endif /* WIN32 */ }; -typedef void pcap_t; +typedef struct nm_desc_t pcap_t; typedef enum { PCAP_D_INOUT = 0, PCAP_D_IN, @@ -107,41 +107,6 @@ struct eproto { char pcap_version[] = "libnetmap version 0.3"; -/* - * Our equivalent of pcap_t - */ -struct pcap_ring { - struct my_ring me; -#if 0 - const char *ifname; - - //struct nmreq nmr; - - int fd; - char *mem; /* userspace mmap address */ - u_int memsize; - u_int queueid; - u_int begin, end; /* first..last+1 rings to check */ - struct netmap_if *nifp; - - uint32_t if_flags; - uint32_t if_reqcap; - uint32_t if_curcap; -#endif - int snaplen; - char *errbuf; - int promisc; - int to_ms; - - struct pcap_pkthdr hdr; - - - struct pcap_stat st; - - char msg[PCAP_ERRBUF_SIZE]; -}; - - /* * There is a set of functions that tcpdump expects even if probably @@ -279,7 +244,7 @@ pcap_can_set_rfmon(pcap_t *p) int pcap_set_snaplen(pcap_t *p, int snaplen) { - struct pcap_ring *me = p; + struct nm_desc_t *me = p; D("len %d", snaplen); me->snaplen = snaplen; @@ -289,7 +254,7 @@ pcap_set_snaplen(pcap_t *p, int snaplen) int pcap_snapshot(pcap_t *p) { - struct pcap_ring *me = p; + struct nm_desc_t *me = p; D("len %d", me->snaplen); return me->snaplen; @@ -310,17 +275,15 @@ pcap_lookupnet(const char *device, uint32_t *netp, int pcap_set_promisc(pcap_t *p, int promisc) { - struct pcap_ring *me = p; - D("promisc %d", promisc); - if (nm_do_ioctl(&me->me, SIOCGIFFLAGS, 0)) + if (nm_do_ioctl(p, SIOCGIFFLAGS, 0)) D("SIOCGIFFLAGS failed"); if (promisc) { - me->me.if_flags |= IFF_PPROMISC; + p->if_flags |= IFF_PPROMISC; } else { - me->me.if_flags &= ~IFF_PPROMISC; + p->if_flags &= ~IFF_PPROMISC; } - if (nm_do_ioctl(&me->me, SIOCSIFFLAGS, 0)) + if (nm_do_ioctl(p, SIOCSIFFLAGS, 0)) D("SIOCSIFFLAGS failed"); return 0; } @@ -328,10 +291,8 @@ pcap_set_promisc(pcap_t *p, int promisc) int pcap_set_timeout(pcap_t *p, int to_ms) { - struct pcap_ring *me = p; - D("%d ms", to_ms); - me->to_ms = to_ms; + p->to_ms = to_ms; return 0; } @@ -384,31 +345,24 @@ struct pcap_stat; int pcap_stats(pcap_t *p, struct pcap_stat *ps) { - struct pcap_ring *me = p; - ND(""); - - *ps = me->st; + *ps = *(struct pcap_stat *)(void *)&(p->st); return 0; /* accumulate from pcap_dispatch() */ }; char * pcap_geterr(pcap_t *p) { - struct pcap_ring *me = p; - D(""); - return me->msg; + return p->msg; } pcap_t * pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, char *errbuf) { - struct pcap_ring *me; + struct nm_desc_t *d; int l; - (void)snaplen; /* UNUSED */ - (void)errbuf; /* UNUSED */ if (!device) { D("missing device name"); return NULL; @@ -417,54 +371,40 @@ pcap_open_live(const char *device, int snaplen, l = strlen(device) + 1; D("request to open %s snaplen %d promisc %d timeout %dms", device, snaplen, promisc, to_ms); - me = calloc(1, sizeof(*me) + l); - if (me == NULL) { - D("failed to allocate struct for %s", device); - return NULL; - } - me->me.ifname = (char *)(me + 1); - strcpy((char *)me->me.ifname, device); - if (netmap_open(&me->me, 0, promisc)) { + d = nm_open(device, NULL, 0, 0); + if (d == NULL) { D("error opening %s", device); - free(me); return NULL; } - me->to_ms = to_ms; + d->to_ms = to_ms; + d->snaplen = snaplen; + d->errbuf = errbuf; + d->promisc = promisc; - return (pcap_t *)me; + return d; } void pcap_close(pcap_t *p) { - struct my_ring *me = p; - - D(""); - if (!me) - return; - if (me->mem) - munmap(me->mem, me->memsize); + nm_close(p); /* restore original flags ? */ - close(me->fd); - bzero(me, sizeof(*me)); - free(me); } int pcap_fileno(pcap_t *p) { - struct my_ring *me = p; - D("returns %d", me->fd); - return me->fd; + struct nm_desc_t *d = p; + D("returns %d", d->fd); + return d->fd; } int pcap_get_selectable_fd(pcap_t *p) { - struct my_ring *me = p; + struct nm_desc_t *d = p; - ND(""); - return me->fd; + return d->fd; } int @@ -488,94 +428,32 @@ pcap_setdirection(pcap_t *p, pcap_direction_t d) int pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { - struct pcap_ring *pme = p; - struct my_ring *me = &pme->me; - int got = 0; - u_int si; - - ND("cnt %d", cnt); - if (cnt == 0) - cnt = -1; - /* scan all rings */ - for (si = me->begin; si < me->end; si++) { - struct netmap_ring *ring = NETMAP_RXRING(me->nifp, si); - if (nm_ring_empty(ring)) - continue; - pme->hdr.ts = ring->ts; - /* - * XXX a proper prefetch should be done as - * prefetch(i); callback(i-1); ... - */ - while ((cnt == -1 || cnt != got) && !nm_ring_empty(ring)) { - u_int i = ring->cur; - u_int idx = ring->slot[i].buf_idx; - if (idx < 2) { - D("%s bogus RX index %d at offset %d", - me->nifp->ni_name, idx, i); - sleep(2); - } - u_char *buf = (u_char *)NETMAP_BUF(ring, idx); - prefetch(buf); - pme->hdr.len = pme->hdr.caplen = ring->slot[i].len; - // D("call %p len %d", p, me->hdr.len); - callback(user, &pme->hdr, buf); - ring->head = ring->cur = nm_ring_next(ring, i); - got++; - } - } - pme->st.ps_recv += got; - return got; + return nm_dispatch(p, cnt, (void *)callback, user); } int pcap_inject(pcap_t *p, const void *buf, size_t size) { - struct my_ring *me = p; - u_int si; - - ND("cnt %d", cnt); - /* scan all rings */ - for (si = me->begin; si < me->end; si++) { - struct netmap_ring *ring = NETMAP_TXRING(me->nifp, si); - - if (nm_ring_empty(ring)) - continue; - u_int i = ring->cur; - u_int idx = ring->slot[i].buf_idx; - if (idx < 2) { - D("%s bogus TX index %d at offset %d", - me->nifp->ni_name, idx, i); - sleep(2); - } - u_char *dst = (u_char *)NETMAP_BUF(ring, idx); - ring->slot[i].len = size; - pkt_copy(buf, dst, size); - ring->head = ring->cur = nm_ring_next(ring, i); - // if (ring->cur == ring->tail) ioctl(me->fd, NIOCTXSYNC, NULL); - return size; - } - errno = ENOBUFS; - return -1; + return nm_inject(p, buf, size); } int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { - struct pcap_ring *me = p; struct pollfd fds[1]; int i; ND("cnt %d", cnt); memset(fds, 0, sizeof(fds)); - fds[0].fd = me->me.fd; + fds[0].fd = p->fd; fds[0].events = (POLLIN); while (cnt == -1 || cnt > 0) { - if (poll(fds, 1, me->to_ms) <= 0) { + if (poll(fds, 1, p->to_ms) <= 0) { D("poll error/timeout"); continue; } - i = pcap_dispatch(p, cnt, callback, user); + i = nm_dispatch(p, cnt, (void *)callback, user); if (cnt > 0) cnt -= i; } @@ -640,9 +518,9 @@ main(int argc, char **argv) if (ret < 0) continue; if (pollfd[0].revents & POLLIN) - pcap_dispatch(p0, burst, do_send, p1); + pcap_dispatch(p0, burst, do_send, (void *)p1); if (pollfd[1].revents & POLLIN) - pcap_dispatch(p1, burst, do_send, p0); + pcap_dispatch(p1, burst, do_send, (void *)p0); } return (0); diff --git a/tools/tools/netmap/pkt-gen.c b/tools/tools/netmap/pkt-gen.c index c1d084028d93..3fb7702083fd 100644 --- a/tools/tools/netmap/pkt-gen.c +++ b/tools/tools/netmap/pkt-gen.c @@ -37,10 +37,15 @@ * */ +#define MY_PCAP #include "nm_util.h" +// #include #include // isprint() +#ifndef NO_PCAP +#include +#endif const char *default_payload="netmap pkt-gen DIRECT payload\n" "http://info.iet.unipi.it/~luigi/netmap/ "; @@ -105,14 +110,16 @@ struct glob_arg { #define OPT_INDIRECT 32 /* use indirect buffers, tx only */ #define OPT_DUMP 64 /* dump rx/tx traffic */ int dev_type; +#ifndef NO_PCAP pcap_t *p; +#endif int tx_rate; struct timespec tx_period; int affinity; int main_fd; - int report_interval; + int report_interval; /* milliseconds between prints */ void *(*td_body)(void *); void *mmap_addr; int mmap_size; @@ -486,17 +493,18 @@ update_addresses(struct pkt *pkt, struct glob_arg *g) struct ip *ip = &pkt->ip; struct udphdr *udp = &pkt->udp; + do { p = ntohs(udp->uh_sport); if (p < g->src_ip.port1) { /* just inc, no wrap */ udp->uh_sport = htons(p + 1); - return; + break; } udp->uh_sport = htons(g->src_ip.port0); a = ntohl(ip->ip_src.s_addr); if (a < g->src_ip.end) { /* just inc, no wrap */ ip->ip_src.s_addr = htonl(a + 1); - return; + break; } ip->ip_src.s_addr = htonl(g->src_ip.start); @@ -504,17 +512,18 @@ update_addresses(struct pkt *pkt, struct glob_arg *g) p = ntohs(udp->uh_dport); if (p < g->dst_ip.port1) { /* just inc, no wrap */ udp->uh_dport = htons(p + 1); - return; + break; } udp->uh_dport = htons(g->dst_ip.port0); a = ntohl(ip->ip_dst.s_addr); if (a < g->dst_ip.end) { /* just inc, no wrap */ ip->ip_dst.s_addr = htonl(a + 1); - return; + break; } ip->ip_dst.s_addr = htonl(g->dst_ip.start); - + } while (0); + // update checksum } /* @@ -531,13 +540,13 @@ initialize_packet(struct targ *targ) uint16_t paylen = targ->g->pkt_size - sizeof(*eh) - sizeof(struct ip); const char *payload = targ->g->options & OPT_INDIRECT ? indirect_payload : default_payload; - int i, l, l0 = strlen(payload); + int i, l0 = strlen(payload); /* create a nice NUL-terminated string */ - for (i = 0; i < paylen;) { - l = min(l0, paylen - i); - bcopy(payload, pkt->body + i, l); - i += l; + for (i = 0; i < paylen; i += l0) { + if (l0 > paylen - i) + l0 = paylen - i; // last round + bcopy(payload, pkt->body + i, l0); } pkt->body[i-1] = '\0'; ip = &pkt->ip; @@ -593,7 +602,7 @@ send_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame, u_int nfrags) { u_int n, sent, cur = ring->cur; - int fcnt; + u_int fcnt; n = nm_ring_space(ring); if (n < count) @@ -608,7 +617,7 @@ send_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame, struct netmap_slot *slot = &ring->slot[cur]; char *p = NETMAP_BUF(ring, slot->buf_idx); - prefetch(p); + __builtin_prefetch(p); cur = nm_ring_next(ring, cur); } cur = ring->cur; @@ -624,14 +633,14 @@ send_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame, slot->ptr = (uint64_t)frame; } else if (options & OPT_COPY) { pkt_copy(frame, p, size); - if (fcnt == 1) + if (fcnt == nfrags) update_addresses(pkt, g); } else if (options & OPT_MEMCPY) { memcpy(p, frame, size); - if (fcnt == 1) + if (fcnt == nfrags) update_addresses(pkt, g); } else if (options & OPT_PREFETCH) { - prefetch(p); + __builtin_prefetch(p); } if (options & OPT_DUMP) dump_payload(p, size, ring, cur); @@ -947,19 +956,7 @@ sender_body(void *data) wait_time(targ->tic); nexttime = targ->tic; } - if (targ->g->dev_type == DEV_PCAP) { - pcap_t *p = targ->g->p; - - for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) { - if (pcap_inject(p, frame, size) != -1) - sent++; - update_addresses(pkt, targ->g); - if (i > 10000) { - targ->count = sent; - i = 0; - } - } - } else if (targ->g->dev_type == DEV_TAP) { /* tap */ + if (targ->g->dev_type == DEV_TAP) { D("writing to file desc %d", targ->g->main_fd); for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) { @@ -971,6 +968,20 @@ sender_body(void *data) i = 0; } } +#ifndef NO_PCAP + } else if (targ->g->dev_type == DEV_PCAP) { + pcap_t *p = targ->g->p; + + for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) { + if (pcap_inject(p, frame, size) != -1) + sent++; + update_addresses(pkt, targ->g); + if (i > 10000) { + targ->count = sent; + i = 0; + } + } +#endif /* NO_PCAP */ } else { int tosend = 0; int frags = targ->g->frags; @@ -1016,8 +1027,8 @@ sender_body(void *data) m = send_packets(txring, pkt, frame, size, targ->g, limit, options, frags); - ND("limit %d avail %d frags %d m %d", - limit, txring->avail, frags, m); + ND("limit %d tail %d frags %d m %d", + limit, txring->tail, frags, m); sent += m; targ->count = sent; if (rate_limit) { @@ -1038,7 +1049,7 @@ sender_body(void *data) usleep(1); /* wait 1 tick */ } } - } + } /* end DEV_NETMAP */ clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); targ->completed = 1; @@ -1052,6 +1063,7 @@ sender_body(void *data) } +#ifndef NO_PCAP static void receive_pcap(u_char *user, const struct pcap_pkthdr * h, const u_char * bytes) @@ -1061,6 +1073,7 @@ receive_pcap(u_char *user, const struct pcap_pkthdr * h, (void)bytes; /* UNUSED */ (*count)++; } +#endif /* !NO_PCAP */ static int receive_packets(struct netmap_ring *ring, u_int limit, int dump) @@ -1113,12 +1126,7 @@ receiver_body(void *data) /* main loop, exit after 1s silence */ clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic); - if (targ->g->dev_type == DEV_PCAP) { - while (!targ->cancel) { - /* XXX should we poll ? */ - pcap_dispatch(targ->g->p, targ->g->burst, receive_pcap, NULL); - } - } else if (targ->g->dev_type == DEV_TAP) { + if (targ->g->dev_type == DEV_TAP) { D("reading from %s fd %d", targ->g->ifname, targ->g->main_fd); while (!targ->cancel) { char buf[2048]; @@ -1126,6 +1134,13 @@ receiver_body(void *data) if (read(targ->g->main_fd, buf, sizeof(buf)) > 0) targ->count++; } +#ifndef NO_PCAP + } else if (targ->g->dev_type == DEV_PCAP) { + while (!targ->cancel) { + /* XXX should we poll ? */ + pcap_dispatch(targ->g->p, targ->g->burst, receive_pcap, NULL); + } +#endif /* !NO_PCAP */ } else { int dump = targ->g->options & OPT_DUMP; while (!targ->cancel) { @@ -1533,7 +1548,7 @@ main(int arc, char **argv) g.virt_header = 0; while ( (ch = getopt(arc, argv, - "a:f:F:n:i:It:r:l:d:s:D:S:b:c:o:p:PT:w:WvR:XC:H:h")) != -1) { + "a:f:F:n:i:It:r:l:d:s:D:S:b:c:o:p:T:w:WvR:XC:H:h")) != -1) { struct sf *fn; switch(ch) { @@ -1575,13 +1590,28 @@ main(int arc, char **argv) break; case 'i': /* interface */ + /* a prefix of tap: netmap: or pcap: forces the mode. + * otherwise we guess + */ + D("interface is %s", optarg); g.ifname = optarg; - if (!strncmp(optarg, "tap", 3)) - g.dev_type = DEV_TAP; - else + if (!strcmp(optarg, "null")) { g.dev_type = DEV_NETMAP; - if (!strcmp(g.ifname, "null")) g.dummy_send = 1; + } else if (!strncmp(optarg, "tap:", 4)) { + g.dev_type = DEV_TAP; + g.ifname = optarg + 4; + } else if (!strncmp(optarg, "pcap:", 5)) { + g.dev_type = DEV_PCAP; + g.ifname = optarg + 5; + } else if (!strncmp(optarg, "netmap:", 7)) { + g.dev_type = DEV_NETMAP; + g.ifname = optarg + 7; + } else if (!strncmp(optarg, "tap", 3)) { + g.dev_type = DEV_TAP; + } else { + g.dev_type = DEV_NETMAP; + } break; case 'I': @@ -1634,10 +1664,6 @@ main(int arc, char **argv) g.nthreads = atoi(optarg); break; - case 'P': - g.dev_type = DEV_PCAP; - break; - case 'D': /* destination mac */ g.dst_mac.name = optarg; break; @@ -1659,8 +1685,10 @@ main(int arc, char **argv) break; case 'H': g.virt_header = atoi(optarg); + break; case 'h': g.host_ring = 1; + break; } } @@ -1697,6 +1725,12 @@ main(int arc, char **argv) extract_mac_range(&g.src_mac); extract_mac_range(&g.dst_mac); + if (g.src_ip.start != g.src_ip.end || + g.src_ip.port0 != g.src_ip.port1 || + g.dst_ip.start != g.dst_ip.end || + g.dst_ip.port0 != g.dst_ip.port1) + g.options |= OPT_COPY; + if (g.virt_header != 0 && g.virt_header != VIRT_HDR_1 && g.virt_header != VIRT_HDR_2) { D("bad virtio-net-header length"); @@ -1710,7 +1744,8 @@ main(int arc, char **argv) D("cannot open tap %s", g.ifname); usage(); } - } else if (g.dev_type > DEV_NETMAP) { +#ifndef NO_PCAP + } else if (g.dev_type == DEV_PCAP) { char pcap_errbuf[PCAP_ERRBUF_SIZE]; D("using pcap on %s", g.ifname); @@ -1720,7 +1755,8 @@ main(int arc, char **argv) D("cannot open pcap on %s", g.ifname); usage(); } - } else if (g.dummy_send) { +#endif /* !NO_PCAP */ + } else if (g.dummy_send) { /* but DEV_NETMAP */ D("using a dummy send routine"); } else { bzero(&nmr, sizeof(nmr)); @@ -1758,9 +1794,6 @@ main(int arc, char **argv) ND("%s: txr %d txd %d rxr %d rxd %d", g.ifname, nmr.nr_tx_rings, nmr.nr_tx_slots, nmr.nr_rx_rings, nmr.nr_rx_slots); - if ((ioctl(g.main_fd, NIOCGINFO, &nmr)) == -1) { - D("Unable to get if info for %s: %s", g.ifname, strerror(errno)); - } devqueues = nmr.nr_rx_rings; /* validate provided nthreads. */ @@ -1784,7 +1817,21 @@ main(int arc, char **argv) // continue, fail later } + if (verbose) { + struct netmap_if *nifp = NETMAP_IF(g.mmap_addr, nmr.nr_offset); + D("nifp at offset %d, %d tx %d rx rings %s", + nmr.nr_offset, nmr.nr_tx_rings, nmr.nr_rx_rings, + nmr.nr_ringid & NETMAP_PRIV_MEM ? "PRIVATE" : "common" ); + for (i = 0; i <= nmr.nr_tx_rings; i++) { + D(" TX%d at 0x%lx", i, + (char *)NETMAP_TXRING(nifp, i) - (char *)nifp); + } + for (i = 0; i <= nmr.nr_rx_rings; i++) { + D(" RX%d at 0x%lx", i, + (char *)NETMAP_RXRING(nifp, i) - (char *)nifp); + } + } /* Print some debug information. */ fprintf(stdout, @@ -1846,16 +1893,6 @@ main(int arc, char **argv) global_nthreads = g.nthreads; signal(SIGINT, sigint_h); -#if 0 // XXX this is not needed, i believe - if (g.dev_type > DEV_NETMAP) { - g.p = pcap_open_live(g.ifname, 0, 1, 100, NULL); - if (g.p == NULL) { - D("cannot open pcap on %s", g.ifname); - usage(); - } else - D("using pcap %p on %s", g.p, g.ifname); - } -#endif // XXX start_threads(&g); main_thread(&g); return 0; diff --git a/tools/tools/netmap/vale-ctl.c b/tools/tools/netmap/vale-ctl.c index c0cf574986b6..eb6c48d15a04 100644 --- a/tools/tools/netmap/vale-ctl.c +++ b/tools/tools/netmap/vale-ctl.c @@ -69,20 +69,22 @@ bdg_ctl(const char *name, int nr_cmd, int nr_arg) nr_arg = 0; nmr.nr_arg1 = nr_arg; error = ioctl(fd, NIOCREGIF, &nmr); - if (error == -1) - D("Unable to %s %s to the bridge", nr_cmd == + if (error == -1) { + ND("Unable to %s %s to the bridge", nr_cmd == NETMAP_BDG_DETACH?"detach":"attach", name); - else - D("Success to %s %s to the bridge\n", nr_cmd == + perror(name); + } else + ND("Success to %s %s to the bridge", nr_cmd == NETMAP_BDG_DETACH?"detach":"attach", name); break; case NETMAP_BDG_LIST: if (strlen(nmr.nr_name)) { /* name to bridge/port info */ error = ioctl(fd, NIOCGINFO, &nmr); - if (error) - D("Unable to obtain info for %s", name); - else + if (error) { + ND("Unable to obtain info for %s", name); + perror(name); + } else D("%s at bridge:%d port:%d", name, nmr.nr_arg1, nmr.nr_arg2); break; @@ -101,9 +103,10 @@ bdg_ctl(const char *name, int nr_cmd, int nr_arg) default: /* GINFO */ nmr.nr_cmd = nmr.nr_arg1 = nmr.nr_arg2 = 0; error = ioctl(fd, NIOCGINFO, &nmr); - if (error) - D("Unable to get if info for %s", name); - else + if (error) { + ND("Unable to get if info for %s", name); + perror(name); + } else D("%s: %d queues.", name, nmr.nr_rx_rings); break; } @@ -164,6 +167,5 @@ main(int argc, char *argv[]) } if (argc == 1) nr_cmd = NETMAP_BDG_LIST; - bdg_ctl(name, nr_cmd, nr_arg); - return 0; + return bdg_ctl(name, nr_cmd, nr_arg) ? 1 : 0; } diff --git a/usr.bin/killall/killall.c b/usr.bin/killall/killall.c index dd22a83e6f22..b171630d6b9b 100644 --- a/usr.bin/killall/killall.c +++ b/usr.bin/killall/killall.c @@ -90,6 +90,7 @@ nosig(char *name) int main(int ac, char **av) { + char **saved_av; struct kinfo_proc *procs, *newprocs; struct stat sb; struct passwd *pw; @@ -144,9 +145,6 @@ main(int ac, char **av) if (**av == '-') { ++*av; switch (**av) { - case 'I': - Iflag = 1; - break; case 'j': ++*av; if (**av == '\0') { @@ -214,6 +212,7 @@ main(int ac, char **av) zflag++; break; default: + saved_av = av; if (isalpha((unsigned char)**av)) { if (strncasecmp(*av, "SIG", 3) == 0) *av += 3; @@ -223,8 +222,14 @@ main(int ac, char **av) sig = p - sys_signame; break; } - if (!sig) - nosig(*av); + if (!sig) { + if (**saved_av == 'I') { + av = saved_av; + Iflag = 1; + break; + } else + nosig(*av); + } } else if (isdigit((unsigned char)**av)) { sig = strtol(*av, &ep, 10); if (!*av || *ep) diff --git a/usr.bin/ktrdump/ktrdump.c b/usr.bin/ktrdump/ktrdump.c index 77ae522e9b12..5f3e7cad9eab 100644 --- a/usr.bin/ktrdump/ktrdump.c +++ b/usr.bin/ktrdump/ktrdump.c @@ -236,7 +236,7 @@ main(int ac, char **av) next: if ((c = *p++) == '\0') break; if (parm == KTR_PARMS) - errx(1, "too many parameters"); + errx(1, "too many parameters in \"%s\"", desc); switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': diff --git a/usr.bin/script/script.c b/usr.bin/script/script.c index 1396d3d1f383..72814fbe17ad 100644 --- a/usr.bin/script/script.c +++ b/usr.bin/script/script.c @@ -238,12 +238,15 @@ main(int argc, char *argv[]) FD_SET(master, &rfd); if (readstdin) FD_SET(STDIN_FILENO, &rfd); - if ((!readstdin && ttyflg) || flushtime > 0) { - tv.tv_sec = !readstdin && ttyflg ? 1 : - flushtime - (tvec - start); + if (!readstdin && ttyflg) { + tv.tv_sec = 1; tv.tv_usec = 0; tvp = &tv; readstdin = 1; + } else if (flushtime > 0) { + tv.tv_sec = flushtime - (tvec - start); + tv.tv_usec = 0; + tvp = &tv; } else { tvp = NULL; } diff --git a/usr.sbin/bsdconfig/share/strings.subr b/usr.sbin/bsdconfig/share/strings.subr index 9b0014fc7e19..1bb42e3620db 100644 --- a/usr.sbin/bsdconfig/share/strings.subr +++ b/usr.sbin/bsdconfig/share/strings.subr @@ -369,17 +369,14 @@ f_shell_unescape() f_expand_number() { local __string="$1" __var_to_set="$2" - local __cp __num __bshift __maxinput + local __cp __number __bshift __maxinput - # Remove any leading non-digits - while :; do - __cp="$__string" - __string="${__cp#[!0-9]}" - [ "$__string" = "$__cp" ] && break - done + # Remove any leading non-digits and store numbers (sans suffix) + __string="${__string#${__string%%[0-9]*}}" + __number="${__string%%[!0-9]*}" # Produce `-1' if string didn't contain any digits - if [ ! "$__string" ]; then + if [ ! "$__number" ]; then if [ "$__var_to_set" ]; then setvar "$__var_to_set" -1 else @@ -388,25 +385,8 @@ f_expand_number() return 1 # 1 = "Given $string contains no digits" fi - # Store the numbers - __num="${__string%%[!0-9]*}" - - # Shortcut - if [ $__num -eq 0 ]; then - if [ "$__var_to_set" ]; then - setvar "$__var_to_set" 0 - else - echo 0 - fi - return $SUCCESS - fi - # Remove all the leading numbers from the string to get at the prefix - while :; do - __cp="$__string" - __string="${__cp#[0-9]}" - [ "$__string" = "$__cp" ] && break - done + __string="${__string#"$__number"}" # # Test for invalid prefix (and determine bitshift length) @@ -414,9 +394,9 @@ f_expand_number() case "$__string" in ""|[[:space:]]*) # Shortcut if [ "$__var_to_set" ]; then - setvar "$__var_to_set" $__num + setvar "$__var_to_set" $__number else - echo $__num + echo $__number fi return $SUCCESS ;; [Kk]*) __bshift=10 ;; @@ -437,7 +417,7 @@ f_expand_number() # Determine if the wheels fall off __maxinput=$(( 0x7fffffffffffffff >> $__bshift )) - if [ $__num -gt $__maxinput ]; then + if [ $__number -gt $__maxinput ]; then # Input (before expanding) would exceed 64-bit signed int if [ "$__var_to_set" ]; then setvar "$__var_to_set" -1 @@ -448,11 +428,11 @@ f_expand_number() fi # Shift the number out and produce it - __num=$(( $__num << $__bshift )) + __number=$(( $__number << $__bshift )) if [ "$__var_to_set" ]; then - setvar "$__var_to_set" $__num + setvar "$__var_to_set" $__number else - echo $__num + echo $__number fi } diff --git a/usr.sbin/bsdinstall/scripts/services b/usr.sbin/bsdinstall/scripts/services index 3297407e1110..54c5018610e2 100755 --- a/usr.sbin/bsdinstall/scripts/services +++ b/usr.sbin/bsdinstall/scripts/services @@ -29,7 +29,8 @@ : ${DIALOG_OK=0} if [ -f $BSDINSTALL_TMPETC/rc.conf.services ]; then - eval `sed -e s/YES/on/i -e s/NO/off/i $BSDINSTALL_TMPETC/rc.conf.services` + eval $( sed -e s/YES/on/i -e s/NO/off/i \ + $BSDINSTALL_TMPETC/rc.conf.services ) else # Default service states. Everything is off if not enabled. sshd_enable="on" @@ -38,30 +39,29 @@ fi echo -n > $BSDINSTALL_TMPETC/rc.conf.services exec 3>&1 -DAEMONS=$(dialog --backtitle "FreeBSD Installer" \ +DAEMONS=$( dialog --backtitle "FreeBSD Installer" \ --title "System Configuration" --nocancel --separate-output \ --checklist "Choose the services you would like to be started at boot:" \ 0 0 0 \ sshd "Secure shell daemon" ${sshd_enable:-off} \ moused "PS/2 mouse pointer on console" ${moused_enable:-off} \ ntpd "Synchronize system and network time" ${ntpd_enable:-off} \ - powerd "Adjust CPU frequency dynamically if supported" ${powerd_enable:-off} \ + powerd "Adjust CPU frequency dynamically if supported" \ + ${powerd_enable:-off} \ dumpdev "Enable kernel crash dumps to /var/crash" ${dumpdev:-on} \ -2>&1 1>&3) +2>&1 1>&3 ) exec 3>&- havedump= for daemon in $DAEMONS; do - if [ "$daemon" == "dumpdev" ]; then - havedump=1 - echo '# Set dumpdev to "AUTO" to enable crash dumps, "NO"' \ - 'to disable' >> $BSDINSTALL_TMPETC/rc.conf.services - echo dumpdev=\"AUTO\" >> $BSDINSTALL_TMPETC/rc.conf.services - continue - fi + [ "$daemon" = "dumpdev" ] && havedump=1 continue echo ${daemon}_enable=\"YES\" >> $BSDINSTALL_TMPETC/rc.conf.services done -if [ ! "$havedump" ]; then +echo '# Set dumpdev to "AUTO" to enable crash dumps, "NO"' \ + 'to disable' >> $BSDINSTALL_TMPETC/rc.conf.services +if [ "$havedump" ]; then + echo dumpdev=\"AUTO\" >> $BSDINSTALL_TMPETC/rc.conf.services +else echo dumpdev=\"NO\" >> $BSDINSTALL_TMPETC/rc.conf.services fi diff --git a/usr.sbin/pciconf/pciconf.8 b/usr.sbin/pciconf/pciconf.8 index b416abc54096..7eacfaba841b 100644 --- a/usr.sbin/pciconf/pciconf.8 +++ b/usr.sbin/pciconf/pciconf.8 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 1, 2012 +.Dd January 20, 2014 .Dt PCICONF 8 .Os .Sh NAME @@ -33,13 +33,13 @@ .Nd diagnostic utility for the PCI bus .Sh SYNOPSIS .Nm -.Fl l Op Fl bcev +.Fl l Oo Fl bcev Oc Op Ar device .Nm -.Fl a Ar selector +.Fl a Ar device .Nm -.Fl r Oo Fl b | h Oc Ar selector addr Ns Op : Ns Ar addr2 +.Fl r Oo Fl b | h Oc Ar device addr Ns Op : Ns Ar addr2 .Nm -.Fl w Oo Fl b | h Oc Ar selector addr value +.Fl w Oo Fl b | h Oc Ar device addr value .Sh DESCRIPTION The .Nm @@ -54,7 +54,9 @@ normally only the super-user. .Pp With the .Fl l -option, it lists all devices found by the boot probe in the following format: +option, +.Nm +lists PCI devices in the following format: .Bd -literal foo0@pci0:0:4:0: class=0x010000 card=0x00000000 chip=0x000f1000 rev=0x01 \ hdr=0x00 @@ -65,16 +67,14 @@ hdr=0x00 .Ed .Pp The first column gives the -device name, unit number, and -.Ar selector . -If there is no device configured in the kernel for the +driver name, unit number, and selector . +If there is no driver attached to the .Tn PCI -device in question, the device name will be +device in question, the driver name will be .Dq none . -Unit numbers for unconfigured devices start at zero and are incremented for -each unconfigured device that is encountered. -The -.Ar selector +Unit numbers for detached devices start at zero and are incremented for +each detached device that is encountered. +The selector is in a form which may directly be used for the other forms of the command. The second column is the class code, with the class byte printed as two hex digits, followed by the sub-class and the interface bytes. @@ -182,18 +182,36 @@ option is supplied, will attempt to load the vendor/device information database, and print vendor, device, class and subclass identification strings for each device. .Pp +If the optional +.Ar device +argument is given with the +.Fl l +flag, +.Nm +will only list details about a single device instead of all devices. +.Pp All invocations of .Nm except for .Fl l require a -.Ar selector -of the form +.Ar device . +The device can be identified either by a device name if the device is +attached to a driver or by a selector. +Selectors identify a PCI device by its address in PCI config space and +can take one of the following forms: +.Pp +.Bl -bullet -offset indent -compact +.It .Li pci Ns Va domain Ns \&: Ns Va bus Ns \&: Ns Va device Ns \&: \ -Ns Va function Ns , -.Li pci Ns Va bus Ns \&: Ns Va device Ns \&: Ns Va function Ns , or -.Li pci Ns Va bus Ns \&: Ns Va device Ns . -In case of an abridged form, omitted selector components are assumed to be 0. +Ns Va function Ns +.It +.Li pci Ns Va bus Ns \&: Ns Va device Ns \&: Ns Va function Ns +.It +.Li pci Ns Va bus Ns \&: Ns Va device Ns +.El +.Pp +In the case of an abridged form, omitted selector components are assumed to be 0. An optional leading device name followed by @ and an optional final colon will be ignored; this is so that the first column in the output of .Nm diff --git a/usr.sbin/pciconf/pciconf.c b/usr.sbin/pciconf/pciconf.c index 58ffddd9cfab..0d1bbde382bc 100644 --- a/usr.sbin/pciconf/pciconf.c +++ b/usr.sbin/pciconf/pciconf.c @@ -35,6 +35,7 @@ static const char rcsid[] = #include #include +#include #include #include #include @@ -67,8 +68,10 @@ struct pci_vendor_info TAILQ_HEAD(,pci_vendor_info) pci_vendors; +static struct pcisel getsel(const char *str); static void list_bars(int fd, struct pci_conf *p); -static void list_devs(int verbose, int bars, int caps, int errors); +static void list_devs(const char *name, int verbose, int bars, int caps, + int errors); static void list_verbose(struct pci_conf *p); static const char *guess_class(struct pci_conf *p); static const char *guess_subclass(struct pci_conf *p); @@ -83,10 +86,10 @@ static void usage(void) { fprintf(stderr, "%s\n%s\n%s\n%s\n", - "usage: pciconf -l [-bcev]", - " pciconf -a selector", - " pciconf -r [-b | -h] selector addr[:addr2]", - " pciconf -w [-b | -h] selector addr value"); + "usage: pciconf -l [-bcev] [device]", + " pciconf -a device", + " pciconf -r [-b | -h] device addr[:addr2]", + " pciconf -w [-b | -h] device addr value"); exit (1); } @@ -145,14 +148,15 @@ main(int argc, char **argv) } } - if ((listmode && optind != argc) + if ((listmode && optind >= argc + 1) || (writemode && optind + 3 != argc) || (readmode && optind + 2 != argc) || (attachedmode && optind + 1 != argc)) usage(); if (listmode) { - list_devs(verbose, bars, caps, errors); + list_devs(optind + 1 == argc ? argv[optind] : NULL, verbose, + bars, caps, errors); } else if (attachedmode) { chkattached(argv[optind]); } else if (readmode) { @@ -169,11 +173,12 @@ main(int argc, char **argv) } static void -list_devs(int verbose, int bars, int caps, int errors) +list_devs(const char *name, int verbose, int bars, int caps, int errors) { int fd; struct pci_conf_io pc; struct pci_conf conf[255], *p; + struct pci_match_conf patterns[1]; int none_count = 0; if (verbose) @@ -186,6 +191,16 @@ list_devs(int verbose, int bars, int caps, int errors) bzero(&pc, sizeof(struct pci_conf_io)); pc.match_buf_len = sizeof(conf); pc.matches = conf; + if (name != NULL) { + bzero(&patterns, sizeof(patterns)); + patterns[0].pc_sel = getsel(name); + patterns[0].flags = PCI_GETCONF_MATCH_DOMAIN | + PCI_GETCONF_MATCH_BUS | PCI_GETCONF_MATCH_DEV | + PCI_GETCONF_MATCH_FUNC; + pc.num_patterns = 1; + pc.pat_buf_len = sizeof(patterns); + pc.patterns = patterns; + } do { if (ioctl(fd, PCIOCGETCONF, &pc) == -1) @@ -557,7 +572,61 @@ read_config(int fd, struct pcisel *sel, long reg, int width) } static struct pcisel -getsel(const char *str) +getdevice(const char *name) +{ + struct pci_conf_io pc; + struct pci_conf conf[1]; + struct pci_match_conf patterns[1]; + char *cp; + int fd; + + fd = open(_PATH_DEVPCI, O_RDONLY, 0); + if (fd < 0) + err(1, "%s", _PATH_DEVPCI); + + bzero(&pc, sizeof(struct pci_conf_io)); + pc.match_buf_len = sizeof(conf); + pc.matches = conf; + + bzero(&patterns, sizeof(patterns)); + + /* + * The pattern structure requires the unit to be split out from + * the driver name. Walk backwards from the end of the name to + * find the start of the unit. + */ + if (name[0] == '\0') + err(1, "Empty device name"); + cp = strchr(name, '\0'); + assert(cp != NULL && cp != name); + cp--; + while (cp != name && isdigit(cp[-1])) + cp--; + if (cp == name) + errx(1, "Invalid device name"); + if ((size_t)(cp - name) + 1 > sizeof(patterns[0].pd_name)) + errx(1, "Device name i2s too long"); + memcpy(patterns[0].pd_name, name, cp - name); + patterns[0].pd_unit = strtol(cp, &cp, 10); + assert(*cp == '\0'); + patterns[0].flags = PCI_GETCONF_MATCH_NAME | PCI_GETCONF_MATCH_UNIT; + pc.num_patterns = 1; + pc.pat_buf_len = sizeof(patterns); + pc.patterns = patterns; + + if (ioctl(fd, PCIOCGETCONF, &pc) == -1) + err(1, "ioctl(PCIOCGETCONF)"); + if (pc.status != PCI_GETCONF_LAST_DEVICE && + pc.status != PCI_GETCONF_MORE_DEVS) + errx(1, "error returned from PCIOCGETCONF ioctl"); + close(fd); + if (pc.num_matches == 0) + errx(1, "Device not found"); + return (conf[0].pc_sel); +} + +static struct pcisel +parsesel(const char *str) { char *ep = strchr(str, '@'); char *epbase; @@ -595,6 +664,20 @@ getsel(const char *str) return sel; } +static struct pcisel +getsel(const char *str) +{ + + /* + * No device names contain colons and selectors always contain + * at least one colon. + */ + if (strchr(str, ':') == NULL) + return (getdevice(str)); + else + return (parsesel(str)); +} + static void readone(int fd, struct pcisel *sel, long reg, int width) {