Index: projects/release-pkg/Makefile.inc1 =================================================================== --- projects/release-pkg/Makefile.inc1 (revision 289118) +++ projects/release-pkg/Makefile.inc1 (revision 289119) @@ -1,2385 +1,2387 @@ # # $FreeBSD$ # # Make command line options: # -DNO_CLEANDIR run ${MAKE} clean, instead of ${MAKE} cleandir # -DNO_CLEAN do not clean at all # -DDB_FROM_SRC use the user/group databases in src/etc instead of # the system database when installing. # -DNO_SHARE do not go into share subdir # -DKERNFAST define NO_KERNEL{CONFIG,CLEAN,DEPEND,OBJ} # -DNO_KERNELCONFIG do not run config in ${MAKE} buildkernel # -DNO_KERNELCLEAN do not run ${MAKE} clean in ${MAKE} buildkernel # -DNO_KERNELDEPEND do not run ${MAKE} depend in ${MAKE} buildkernel # -DNO_KERNELOBJ do not run ${MAKE} obj in ${MAKE} buildkernel # -DNO_PORTSUPDATE do not update ports in ${MAKE} update # -DNO_ROOT install without using root privilege # -DNO_DOCUPDATE do not update doc in ${MAKE} update # -DWITHOUT_CTF do not run the DTrace CTF conversion tools on built objects # LOCAL_DIRS="list of dirs" to add additional dirs to the SUBDIR list # LOCAL_ITOOLS="list of tools" to add additional tools to the ITOOLS list # LOCAL_LIB_DIRS="list of dirs" to add additional dirs to libraries target # LOCAL_MTREE="list of mtree files" to process to allow local directories # to be created before files are installed # LOCAL_TOOL_DIRS="list of dirs" to add additional dirs to the build-tools # list # METALOG="path to metadata log" to write permission and ownership # when NO_ROOT is set. (default: ${DESTDIR}/METALOG) # TARGET="machine" to crossbuild world for a different machine type # TARGET_ARCH= may be required when a TARGET supports multiple endians # BUILDENV_SHELL= shell to launch for the buildenv target (def:/bin/sh) # WORLD_FLAGS= additional flags to pass to make(1) during buildworld # KERNEL_FLAGS= additional flags to pass to make(1) during buildkernel # # The intended user-driven targets are: # buildworld - rebuild *everything*, including glue to help do upgrades # installworld- install everything built by "buildworld" # doxygen - build API documentation of the kernel # update - convenient way to update your source tree (eg: svn/svnup) # # Standard targets (not defined here) are documented in the makefiles in # /usr/share/mk. These include: # obj depend all install clean cleandepend cleanobj .if !defined(TARGET) || !defined(TARGET_ARCH) .error "Both TARGET and TARGET_ARCH must be defined." .endif .include "share/mk/src.opts.mk" .include .include # We must do lib/ and libexec/ before bin/, because if installworld # installs a new /bin/sh, the 'make' command will *immediately* # use that new version. And the new (dynamically-linked) /bin/sh # will expect to find appropriate libraries in /lib and /libexec. # SRCDIR?= ${.CURDIR} .if defined(SUBDIR_OVERRIDE) SUBDIR= ${SUBDIR_OVERRIDE} .else SUBDIR= lib libexec SUBDIR+=bin .if ${MK_CDDL} != "no" SUBDIR+=cddl .endif SUBDIR+=gnu include .if ${MK_KERBEROS} != "no" SUBDIR+=kerberos5 .endif .if ${MK_RESCUE} != "no" SUBDIR+=rescue .endif SUBDIR+=sbin .if ${MK_CRYPT} != "no" SUBDIR+=secure .endif .if !defined(NO_SHARE) SUBDIR+=share .endif SUBDIR+=sys usr.bin usr.sbin .if ${MK_TESTS} != "no" SUBDIR+= tests .endif .if ${MK_OFED} != "no" SUBDIR+=contrib/ofed .endif # # We must do etc/ last for install/distribute to work. # SUBDIR+=etc # Local directories are last, since it is nice to at least get the base # system rebuilt before you do them. .for _DIR in ${LOCAL_DIRS} .if exists(${.CURDIR}/${_DIR}/Makefile) SUBDIR+= ${_DIR} .endif .endfor # Add LOCAL_LIB_DIRS, but only if they will not be picked up as a SUBDIR # of a LOCAL_DIRS directory. This allows LOCAL_DIRS=foo and # LOCAL_LIB_DIRS=foo/lib to behave as expected. .for _DIR in ${LOCAL_DIRS:M*/} ${LOCAL_DIRS:N*/:S|$|/|} _REDUNDENT_LIB_DIRS+= ${LOCAL_LIB_DIRS:M${_DIR}*} .endfor .for _DIR in ${LOCAL_LIB_DIRS} .if empty(_REDUNDENT_LIB_DIRS:M${_DIR}) && exists(${.CURDIR}/${_DIR}/Makefile) SUBDIR+= ${_DIR} .else .warning ${_DIR} not added to SUBDIR list. See UPDATING 20141121. .endif .endfor .endif .if defined(NOCLEAN) NO_CLEAN= ${NOCLEAN} .endif .if defined(NO_CLEANDIR) CLEANDIR= clean cleandepend .else CLEANDIR= cleandir .endif LOCAL_TOOL_DIRS?= BUILDENV_SHELL?=/bin/sh SVN?= /usr/local/bin/svn SVNFLAGS?= -r HEAD MAKEOBJDIRPREFIX?= /usr/obj .if !defined(OSRELDATE) .if exists(/usr/include/osreldate.h) OSRELDATE!= awk '/^\#define[[:space:]]*__FreeBSD_version/ { print $$3 }' \ /usr/include/osreldate.h .else OSRELDATE= 0 .endif .endif .if !defined(VERSION) REVISION!= ${MAKE} -C ${SRCDIR}/release -V REVISION BRANCH!= ${MAKE} -C ${SRCDIR}/release -V BRANCH SRCRELDATE!= awk '/^\#define[[:space:]]*__FreeBSD_version/ { print $$3 }' \ ${SRCDIR}/sys/sys/param.h VERSION= FreeBSD ${REVISION}-${BRANCH:C/-p[0-9]+$//} ${TARGET_ARCH} ${SRCRELDATE} .endif .if !defined(PKG_VERSION) REVISION!= ${MAKE} -C ${SRCDIR}/release -V REVISION BRANCH!= ${MAKE} -C ${SRCDIR}/release -V BRANCH SRCRELDATE!= awk '/^\#define[[:space:]]*__FreeBSD_version/ { print $$3 }' \ ${SRCDIR}/sys/sys/param.h .if ${BRANCH:MSTABLE*} || ${BRANCH:MCURRENT*} TIMENOW= %Y%m%d%H%M%S EXTRA_REVISION= .s${TIMENOW:gmtime} .endif .if ${BRANCH:M*-p*} EXTRA_REVISION= _${BRANCH:C/.*-p([0-9]+$)/\1/} .endif PKG_VERSION= ${REVISION}${EXTRA_REVISION} .endif KNOWN_ARCHES?= aarch64/arm64 amd64 arm armeb/arm armv6/arm armv6hf/arm i386 i386/pc98 mips mipsel/mips mips64el/mips mips64/mips mipsn32el/mips mipsn32/mips powerpc powerpc64/powerpc sparc64 .if ${TARGET} == ${TARGET_ARCH} _t= ${TARGET} .else _t= ${TARGET_ARCH}/${TARGET} .endif .for _t in ${_t} .if empty(KNOWN_ARCHES:M${_t}) .error Unknown target ${TARGET_ARCH}:${TARGET}. .endif .endfor .if ${TARGET} == ${MACHINE} TARGET_CPUTYPE?=${CPUTYPE} .else TARGET_CPUTYPE?= .endif .if !empty(TARGET_CPUTYPE) _TARGET_CPUTYPE=${TARGET_CPUTYPE} .else _TARGET_CPUTYPE=dummy .endif _CPUTYPE!= MAKEFLAGS= CPUTYPE=${_TARGET_CPUTYPE} ${MAKE} \ -f /dev/null -m ${.CURDIR}/share/mk -V CPUTYPE .if ${_CPUTYPE} != ${_TARGET_CPUTYPE} .error CPUTYPE global should be set with ?=. .endif .if make(buildworld) BUILD_ARCH!= uname -p .if ${MACHINE_ARCH} != ${BUILD_ARCH} .error To cross-build, set TARGET_ARCH. .endif .endif .if ${MACHINE} == ${TARGET} && ${MACHINE_ARCH} == ${TARGET_ARCH} && !defined(CROSS_BUILD_TESTING) OBJTREE= ${MAKEOBJDIRPREFIX} .else OBJTREE= ${MAKEOBJDIRPREFIX}/${TARGET}.${TARGET_ARCH} .endif WORLDTMP= ${OBJTREE}${.CURDIR}/tmp BPATH= ${WORLDTMP}/legacy/usr/sbin:${WORLDTMP}/legacy/usr/bin:${WORLDTMP}/legacy/bin XPATH= ${WORLDTMP}/usr/sbin:${WORLDTMP}/usr/bin STRICTTMPPATH= ${BPATH}:${XPATH} TMPPATH= ${STRICTTMPPATH}:${PATH} # # Avoid running mktemp(1) unless actually needed. # It may not be functional, e.g., due to new ABI # when in the middle of installing over this system. # .if make(distributeworld) || make(installworld) || make(stageworld) INSTALLTMP!= /usr/bin/mktemp -d -u -t install .endif # # Building a world goes through the following stages # # 1. legacy stage [BMAKE] # This stage is responsible for creating compatibility # shims that are needed by the bootstrap-tools, # build-tools and cross-tools stages. These are generally # APIs that tools from one of those three stages need to # build that aren't present on the host. # 1. bootstrap-tools stage [BMAKE] # This stage is responsible for creating programs that # are needed for backward compatibility reasons. They # are not built as cross-tools. # 2. build-tools stage [TMAKE] # This stage is responsible for creating the object # tree and building any tools that are needed during # the build process. Some programs are listed during # this phase because they build binaries to generate # files needed to build these programs. This stage also # builds the 'build-tools' target rather than 'all'. # 3. cross-tools stage [XMAKE] # This stage is responsible for creating any tools that # are needed for building the system. A cross-compiler is one # of them. This differs from build tools in two ways: # 1. the 'all' target is built rather than 'build-tools' # 2. these tools are installed into TMPPATH for stage 4. # 4. world stage [WMAKE] # This stage actually builds the world. # 5. install stage (optional) [IMAKE] # This stage installs a previously built world. # BOOTSTRAPPING?= 0 # Common environment for world related stages CROSSENV= MAKEOBJDIRPREFIX=${OBJTREE} \ MACHINE_ARCH=${TARGET_ARCH} \ MACHINE=${TARGET} \ CPUTYPE=${TARGET_CPUTYPE} .if ${MK_GROFF} != "no" CROSSENV+= GROFF_BIN_PATH=${WORLDTMP}/legacy/usr/bin \ GROFF_FONT_PATH=${WORLDTMP}/legacy/usr/share/groff_font \ GROFF_TMAC_PATH=${WORLDTMP}/legacy/usr/share/tmac .endif .if defined(TARGET_CFLAGS) CROSSENV+= ${TARGET_CFLAGS} .endif # bootstrap-tools stage BMAKEENV= INSTALL="sh ${.CURDIR}/tools/install.sh" \ PATH=${BPATH}:${PATH} \ WORLDTMP=${WORLDTMP} \ VERSION="${VERSION}" \ MAKEFLAGS="-m ${.CURDIR}/tools/build/mk ${.MAKEFLAGS}" # need to keep this in sync with targets/pseudo/bootstrap-tools/Makefile BSARGS= DESTDIR= \ BOOTSTRAPPING=${OSRELDATE} \ SSP_CFLAGS= \ MK_HTML=no NO_LINT=yes MK_MAN=no \ -DNO_PIC MK_PROFILE=no -DNO_SHARED \ -DNO_CPU_CFLAGS MK_WARNS=no MK_CTF=no \ MK_CLANG_EXTRAS=no MK_CLANG_FULL=no \ MK_LLDB=no MK_TESTS=no \ MK_INCLUDES=yes BMAKE= MAKEOBJDIRPREFIX=${WORLDTMP} \ ${BMAKEENV} ${MAKE} ${WORLD_FLAGS} -f Makefile.inc1 \ ${BSARGS} # build-tools stage TMAKE= MAKEOBJDIRPREFIX=${OBJTREE} \ ${BMAKEENV} ${MAKE} ${WORLD_FLAGS} -f Makefile.inc1 \ TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ DESTDIR= \ BOOTSTRAPPING=${OSRELDATE} \ SSP_CFLAGS= \ -DNO_LINT \ -DNO_CPU_CFLAGS MK_WARNS=no MK_CTF=no \ MK_CLANG_EXTRAS=no MK_CLANG_FULL=no \ MK_LLDB=no MK_TESTS=no # cross-tools stage XMAKE= TOOLS_PREFIX=${WORLDTMP} ${BMAKE} \ TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ MK_GDB=no MK_TESTS=no # kernel-tools stage KTMAKEENV= INSTALL="sh ${.CURDIR}/tools/install.sh" \ PATH=${BPATH}:${PATH} \ WORLDTMP=${WORLDTMP} \ VERSION="${VERSION}" KTMAKE= TOOLS_PREFIX=${WORLDTMP} MAKEOBJDIRPREFIX=${WORLDTMP} \ ${KTMAKEENV} ${MAKE} ${WORLD_FLAGS} -f Makefile.inc1 \ DESTDIR= \ BOOTSTRAPPING=${OSRELDATE} \ SSP_CFLAGS= \ MK_HTML=no -DNO_LINT MK_MAN=no \ -DNO_PIC MK_PROFILE=no -DNO_SHARED \ -DNO_CPU_CFLAGS MK_WARNS=no MK_CTF=no # world stage WMAKEENV= ${CROSSENV} \ _LDSCRIPTROOT= \ VERSION="${VERSION}" \ INSTALL="sh ${.CURDIR}/tools/install.sh" \ PATH=${TMPPATH} # make hierarchy HMAKE= PATH=${TMPPATH} ${MAKE} LOCAL_MTREE=${LOCAL_MTREE:Q} .if defined(NO_ROOT) HMAKE+= PATH=${TMPPATH} METALOG=${METALOG} -DNO_ROOT .endif .if ${MK_CDDL} == "no" WMAKEENV+= MK_CTF=no .endif .if defined(CROSS_TOOLCHAIN) LOCALBASE?= /usr/local .include "${LOCALBASE}/share/toolchains/${CROSS_TOOLCHAIN}.mk" .endif .if defined(CROSS_TOOLCHAIN_PREFIX) CROSS_COMPILER_PREFIX?=${CROSS_TOOLCHAIN_PREFIX} CROSS_BINUTILS_PREFIX?=${CROSS_TOOLCHAIN_PREFIX} .endif # If we do not have a bootstrap binutils (because the in-tree one does not # support the target architecture), provide a default cross-binutils prefix. # This allows aarch64 builds, for example, to automatically use the # aarch64-binutils port or package. .if !make(showconfig) .if !empty(BROKEN_OPTIONS:MBINUTILS_BOOTSTRAP) && \ !defined(CROSS_BINUTILS_PREFIX) CROSS_BINUTILS_PREFIX=/usr/local/${TARGET_ARCH}-freebsd/bin/ .if !exists(${CROSS_BINUTILS_PREFIX}) .error In-tree binutils does not support the ${TARGET_ARCH} architecture. Install the ${TARGET_ARCH}-binutils port or package or set CROSS_BINUTILS_PREFIX. .endif .endif .endif XCOMPILERS= CC CXX CPP .for COMPILER in ${XCOMPILERS} .if defined(CROSS_COMPILER_PREFIX) X${COMPILER}?= ${CROSS_COMPILER_PREFIX}${${COMPILER}} .else X${COMPILER}?= ${${COMPILER}} .endif .endfor XBINUTILS= AS AR LD NM OBJCOPY OBJDUMP RANLIB SIZE STRINGS .for BINUTIL in ${XBINUTILS} .if defined(CROSS_BINUTILS_PREFIX) && \ exists(${CROSS_BINUTILS_PREFIX}${${BINUTIL}}) X${BINUTIL}?= ${CROSS_BINUTILS_PREFIX}${${BINUTIL}} .else X${BINUTIL}?= ${${BINUTIL}} .endif .endfor WMAKEENV+= CC="${XCC} ${XCFLAGS}" CXX="${XCXX} ${XCFLAGS} ${XCXXFLAGS}" \ DEPFLAGS="${DEPFLAGS}" \ CPP="${XCPP} ${XCFLAGS}" \ AS="${XAS}" AR="${XAR}" LD="${XLD}" NM=${XNM} \ OBJDUMP=${XOBJDUMP} OBJCOPY="${XOBJCOPY}" \ RANLIB=${XRANLIB} STRINGS=${XSTRINGS} \ SIZE="${XSIZE}" .if ${XCC:M/*} .if defined(CROSS_BINUTILS_PREFIX) # In the case of xdev-build tools, CROSS_BINUTILS_PREFIX won't be a # directory, but the compiler will look in the right place for it's # tools so we don't need to tell it where to look. .if exists(${CROSS_BINUTILS_PREFIX}) BFLAGS+= -B${CROSS_BINUTILS_PREFIX} .endif .else BFLAGS+= -B${WORLDTMP}/usr/bin .endif .if ${TARGET} == "arm" .if ${TARGET_ARCH:M*hf*} != "" TARGET_ABI= gnueabihf .else TARGET_ABI= gnueabi .endif .endif .if defined(X_COMPILER_TYPE) && ${X_COMPILER_TYPE} == gcc XCFLAGS+= -isystem ${WORLDTMP}/usr/include -L${WORLDTMP}/usr/lib XCXXFLAGS+= -I${WORLDTMP}/usr/include/c++/v1 -std=gnu++11 -L${WORLDTMP}/../lib/libc++ DEPFLAGS+= -I${WORLDTMP}/usr/include/c++/v1 .else TARGET_ABI?= unknown TARGET_TRIPLE?= ${TARGET_ARCH:C/amd64/x86_64/}-${TARGET_ABI}-freebsd11.0 XCFLAGS+= -target ${TARGET_TRIPLE} .endif XCFLAGS+= --sysroot=${WORLDTMP} ${BFLAGS} XCXXFLAGS+= --sysroot=${WORLDTMP} ${BFLAGS} .else .if defined(CROSS_BINUTILS_PREFIX) && exists(${CROSS_BINUTILS_PREFIX}) BFLAGS+= -B${CROSS_BINUTILS_PREFIX} XCFLAGS+= ${BFLAGS} XCXXFLAGS+= ${BFLAGS} .endif .endif # ${XCC:M/*} WMAKE= ${WMAKEENV} ${MAKE} ${WORLD_FLAGS} -f Makefile.inc1 DESTDIR=${WORLDTMP} .if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64" # 32 bit world LIB32_OBJTREE= ${OBJTREE}${.CURDIR}/world32 LIB32TMP= ${OBJTREE}${.CURDIR}/lib32 .if ${TARGET_ARCH} == "amd64" .if empty(TARGET_CPUTYPE) LIB32CPUFLAGS= -march=i686 -mmmx -msse -msse2 .else LIB32CPUFLAGS= -march=${TARGET_CPUTYPE} .endif LIB32WMAKEENV= MACHINE=i386 MACHINE_ARCH=i386 \ MACHINE_CPU="i686 mmx sse sse2" LIB32WMAKEFLAGS= \ AS="${XAS} --32" \ LD="${XLD} -m elf_i386_fbsd -Y P,${LIB32TMP}/usr/lib32" \ OBJCOPY="${XOBJCOPY}" .elif ${TARGET_ARCH} == "powerpc64" .if empty(TARGET_CPUTYPE) LIB32CPUFLAGS= -mcpu=powerpc .else LIB32CPUFLAGS= -mcpu=${TARGET_CPUTYPE} .endif LIB32WMAKEENV= MACHINE=powerpc MACHINE_ARCH=powerpc LIB32WMAKEFLAGS= \ LD="${XLD} -m elf32ppc_fbsd" \ OBJCOPY="${XOBJCOPY}" .endif LIB32FLAGS= -m32 ${LIB32CPUFLAGS} -DCOMPAT_32BIT \ -isystem ${LIB32TMP}/usr/include/ \ -L${LIB32TMP}/usr/lib32 \ -B${LIB32TMP}/usr/lib32 .if ${XCC:M/*} LIB32FLAGS+= --sysroot=${WORLDTMP} .endif # Yes, the flags are redundant. LIB32WMAKEENV+= MAKEOBJDIRPREFIX=${LIB32_OBJTREE} \ _LDSCRIPTROOT=${LIB32TMP} \ VERSION="${VERSION}" \ INSTALL="sh ${.CURDIR}/tools/install.sh" \ PATH=${TMPPATH} \ LIBDIR=/usr/lib32 \ SHLIBDIR=/usr/lib32 \ DTRACE="${DTRACE} -32" LIB32WMAKEFLAGS+= CC="${XCC} ${LIB32FLAGS}" \ CXX="${XCXX} ${LIB32FLAGS}" \ DESTDIR=${LIB32TMP} \ -DCOMPAT_32BIT \ -DLIBRARIES_ONLY \ -DNO_CPU_CFLAGS \ MK_CTF=no \ -DNO_LINT \ MK_TESTS=no LIB32WMAKE= ${LIB32WMAKEENV} ${MAKE} ${LIB32WMAKEFLAGS} \ MK_MAN=no MK_HTML=no LIB32IMAKE= ${LIB32WMAKE:NINSTALL=*:NDESTDIR=*:N_LDSCRIPTROOT=*} \ MK_TOOLCHAIN=no ${IMAKE_INSTALL} .endif IMAKEENV= ${CROSSENV:N_LDSCRIPTROOT=*} IMAKE= ${IMAKEENV} ${MAKE} -f Makefile.inc1 \ ${IMAKE_INSTALL} ${IMAKE_MTREE} .if empty(.MAKEFLAGS:M-n) IMAKEENV+= PATH=${STRICTTMPPATH}:${INSTALLTMP} \ LD_LIBRARY_PATH=${INSTALLTMP} \ PATH_LOCALE=${INSTALLTMP}/locale IMAKE+= __MAKE_SHELL=${INSTALLTMP}/sh .else IMAKEENV+= PATH=${TMPPATH}:${INSTALLTMP} .endif .if defined(DB_FROM_SRC) INSTALLFLAGS+= -N ${.CURDIR}/etc MTREEFLAGS+= -N ${.CURDIR}/etc .endif _INSTALL_DDIR= ${DESTDIR}/${DISTDIR} INSTALL_DDIR= ${_INSTALL_DDIR:S://:/:g:C:/$::} .if defined(NO_ROOT) METALOG?= ${DESTDIR}/${DISTDIR}/METALOG IMAKE+= -DNO_ROOT METALOG=${METALOG} INSTALLFLAGS+= -U -M ${METALOG} -D ${INSTALL_DDIR} MTREEFLAGS+= -W .endif .if defined(BUILD_PKGS) INSTALLFLAGS+= -h sha256 .endif .if defined(DB_FROM_SRC) || defined(NO_ROOT) IMAKE_INSTALL= INSTALL="install ${INSTALLFLAGS}" IMAKE_MTREE= MTREE_CMD="mtree ${MTREEFLAGS}" .endif # kernel stage KMAKEENV= ${WMAKEENV} KMAKE= ${KMAKEENV} ${MAKE} ${.MAKEFLAGS} ${KERNEL_FLAGS} KERNEL=${INSTKERNNAME} # # buildworld # # Attempt to rebuild the entire system, with reasonable chance of # success, regardless of how old your existing system is. # _worldtmp: .if ${.CURDIR:C/[^,]//g} != "" # The m4 build of sendmail files doesn't like it if ',' is used # anywhere in the path of it's files. @echo @echo "*** Error: path to source tree contains a comma ','" @echo false .endif @echo @echo "--------------------------------------------------------------" @echo ">>> Rebuilding the temporary build tree" @echo "--------------------------------------------------------------" .if !defined(NO_CLEAN) rm -rf ${WORLDTMP} .if defined(LIB32TMP) rm -rf ${LIB32TMP} .endif .else rm -rf ${WORLDTMP}/legacy/usr/include # XXX - These three can depend on any header file. rm -f ${OBJTREE}${.CURDIR}/usr.bin/kdump/ioctl.c rm -f ${OBJTREE}${.CURDIR}/usr.bin/kdump/kdump_subr.c rm -f ${OBJTREE}${.CURDIR}/usr.bin/truss/ioctl.c .endif .for _dir in \ lib usr legacy/bin legacy/usr mkdir -p ${WORLDTMP}/${_dir} .endfor mtree -deU -f ${.CURDIR}/etc/mtree/BSD.usr.dist \ -p ${WORLDTMP}/legacy/usr >/dev/null .if ${MK_GROFF} != "no" mtree -deU -f ${.CURDIR}/etc/mtree/BSD.groff.dist \ -p ${WORLDTMP}/legacy/usr >/dev/null .endif mtree -deU -f ${.CURDIR}/etc/mtree/BSD.usr.dist \ -p ${WORLDTMP}/usr >/dev/null mtree -deU -f ${.CURDIR}/etc/mtree/BSD.include.dist \ -p ${WORLDTMP}/usr/include >/dev/null ln -sf ${.CURDIR}/sys ${WORLDTMP} .if ${MK_DEBUG_FILES} != "no" # We could instead disable debug files for these build stages mtree -deU -f ${.CURDIR}/etc/mtree/BSD.debug.dist \ -p ${WORLDTMP}/legacy/usr/lib >/dev/null mtree -deU -f ${.CURDIR}/etc/mtree/BSD.debug.dist \ -p ${WORLDTMP}/usr/lib >/dev/null .endif .if ${MK_TESTS} != "no" mkdir -p ${WORLDTMP}${TESTSBASE} mtree -deU -f ${.CURDIR}/etc/mtree/BSD.tests.dist \ -p ${WORLDTMP}${TESTSBASE} >/dev/null .endif .for _mtree in ${LOCAL_MTREE} mtree -deU -f ${.CURDIR}/${_mtree} -p ${WORLDTMP} > /dev/null .endfor _legacy: @echo @echo "--------------------------------------------------------------" @echo ">>> stage 1.1: legacy release compatibility shims" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; ${BMAKE} legacy _bootstrap-tools: @echo @echo "--------------------------------------------------------------" @echo ">>> stage 1.2: bootstrap tools" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; ${BMAKE} bootstrap-tools _cleanobj: .if !defined(NO_CLEAN) @echo @echo "--------------------------------------------------------------" @echo ">>> stage 2.1: cleaning up the object tree" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; ${WMAKE} ${CLEANDIR:S/^/par-/} .if defined(LIB32TMP) ${_+_}cd ${.CURDIR}; ${LIB32WMAKE} -f Makefile.inc1 ${CLEANDIR:S/^/par-/} .endif .endif _obj: @echo @echo "--------------------------------------------------------------" @echo ">>> stage 2.2: rebuilding the object tree" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; ${WMAKE} par-obj _build-tools: @echo @echo "--------------------------------------------------------------" @echo ">>> stage 2.3: build tools" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; ${TMAKE} build-tools _cross-tools: @echo @echo "--------------------------------------------------------------" @echo ">>> stage 3: cross tools" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; ${XMAKE} cross-tools ${_+_}cd ${.CURDIR}; ${XMAKE} kernel-tools _includes: @echo @echo "--------------------------------------------------------------" @echo ">>> stage 4.1: building includes" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; ${WMAKE} SHARED=symlinks par-includes _libraries: @echo @echo "--------------------------------------------------------------" @echo ">>> stage 4.2: building libraries" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; \ ${WMAKE} -DNO_FSCHG MK_HTML=no -DNO_LINT MK_MAN=no \ MK_PROFILE=no MK_TESTS=no MK_TESTS_SUPPORT=${MK_TESTS} libraries _depend: @echo @echo "--------------------------------------------------------------" @echo ">>> stage 4.3: make dependencies" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; ${WMAKE} par-depend everything: @echo @echo "--------------------------------------------------------------" @echo ">>> stage 4.4: building everything" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; ${WMAKE} par-all .if defined(LIB32TMP) build32: @echo @echo "--------------------------------------------------------------" @echo ">>> stage 5.1: building 32 bit shim libraries" @echo "--------------------------------------------------------------" mkdir -p ${LIB32TMP}/usr/include mtree -deU -f ${.CURDIR}/etc/mtree/BSD.usr.dist \ -p ${LIB32TMP}/usr >/dev/null mtree -deU -f ${.CURDIR}/etc/mtree/BSD.include.dist \ -p ${LIB32TMP}/usr/include >/dev/null .if ${MK_DEBUG_FILES} != "no" mtree -deU -f ${.CURDIR}/etc/mtree/BSD.debug.dist \ -p ${LIB32TMP}/usr/lib >/dev/null .endif mkdir -p ${WORLDTMP} ln -sf ${.CURDIR}/sys ${WORLDTMP} .for _t in obj includes cd ${.CURDIR}/include; ${LIB32WMAKE} DIRPRFX=include/ ${_t} cd ${.CURDIR}/lib; ${LIB32WMAKE} DIRPRFX=lib/ ${_t} .if ${MK_CDDL} != "no" cd ${.CURDIR}/cddl/lib; ${LIB32WMAKE} DIRPRFX=cddl/lib/ ${_t} .endif cd ${.CURDIR}/gnu/lib; ${LIB32WMAKE} DIRPRFX=gnu/lib/ ${_t} .if ${MK_CRYPT} != "no" cd ${.CURDIR}/secure/lib; ${LIB32WMAKE} DIRPRFX=secure/lib/ ${_t} .endif .if ${MK_KERBEROS} != "no" cd ${.CURDIR}/kerberos5/lib; ${LIB32WMAKE} DIRPRFX=kerberos5/lib ${_t} .endif .endfor .for _dir in usr.bin/lex/lib cd ${.CURDIR}/${_dir}; ${LIB32WMAKE} DIRPRFX=${_dir}/ obj .endfor .for _dir in lib/ncurses/ncurses lib/ncurses/ncursesw lib/libmagic cd ${.CURDIR}/${_dir}; \ WORLDTMP=${WORLDTMP} \ MAKEFLAGS="-m ${.CURDIR}/tools/build/mk ${.MAKEFLAGS}" \ MAKEOBJDIRPREFIX=${LIB32_OBJTREE} ${MAKE} SSP_CFLAGS= DESTDIR= \ DIRPRFX=${_dir}/ -DNO_LINT -DNO_CPU_CFLAGS MK_WARNS=no MK_CTF=no \ build-tools .endfor cd ${.CURDIR}; \ ${LIB32WMAKE} -f Makefile.inc1 libraries .for _t in obj depend all cd ${.CURDIR}/libexec/rtld-elf; PROG=ld-elf32.so.1 ${LIB32WMAKE} \ DIRPRFX=libexec/rtld-elf/ ${_t} cd ${.CURDIR}/usr.bin/ldd; PROG=ldd32 ${LIB32WMAKE} \ DIRPRFX=usr.bin/ldd ${_t} .endfor distribute32 install32: cd ${.CURDIR}/lib; ${LIB32IMAKE} ${.TARGET:S/32$//} .if ${MK_CDDL} != "no" cd ${.CURDIR}/cddl/lib; ${LIB32IMAKE} ${.TARGET:S/32$//} .endif cd ${.CURDIR}/gnu/lib; ${LIB32IMAKE} ${.TARGET:S/32$//} .if ${MK_CRYPT} != "no" cd ${.CURDIR}/secure/lib; ${LIB32IMAKE} ${.TARGET:S/32$//} .endif .if ${MK_KERBEROS} != "no" cd ${.CURDIR}/kerberos5/lib; ${LIB32IMAKE} ${.TARGET:S/32$//} .endif cd ${.CURDIR}/libexec/rtld-elf; \ PROG=ld-elf32.so.1 ${LIB32IMAKE} ${.TARGET:S/32$//} cd ${.CURDIR}/usr.bin/ldd; PROG=ldd32 ${LIB32IMAKE} ${.TARGET:S/32$//} .endif WMAKE_TGTS= .if !defined(SUBDIR_OVERRIDE) WMAKE_TGTS+= _worldtmp _legacy _bootstrap-tools .endif WMAKE_TGTS+= _cleanobj _obj _build-tools .if !defined(SUBDIR_OVERRIDE) WMAKE_TGTS+= _cross-tools .endif WMAKE_TGTS+= _includes _libraries _depend everything .if defined(LIB32TMP) && ${MK_LIB32} != "no" WMAKE_TGTS+= build32 .endif buildworld: buildworld_prologue ${WMAKE_TGTS} buildworld_epilogue .ORDER: buildworld_prologue ${WMAKE_TGTS} buildworld_epilogue buildworld_prologue: @echo "--------------------------------------------------------------" @echo ">>> World build started on `LC_ALL=C date`" @echo "--------------------------------------------------------------" buildworld_epilogue: @echo @echo "--------------------------------------------------------------" @echo ">>> World build completed on `LC_ALL=C date`" @echo "--------------------------------------------------------------" # # We need to have this as a target because the indirection between Makefile # and Makefile.inc1 causes the correct PATH to be used, rather than a # modification of the current environment's PATH. In addition, we need # to quote multiword values. # buildenvvars: @echo ${WMAKEENV:Q} .if ${.TARGETS:Mbuildenv} .if ${.MAKEFLAGS:M-j} .error The buildenv target is incompatible with -j .endif .endif buildenv: @echo Entering world for ${TARGET_ARCH}:${TARGET} @cd ${.CURDIR} && env ${WMAKEENV} ${BUILDENV_SHELL} || true TOOLCHAIN_TGTS= ${WMAKE_TGTS:N_depend:Neverything:Nbuild32} toolchain: ${TOOLCHAIN_TGTS} kernel-toolchain: ${TOOLCHAIN_TGTS:N_includes:N_libraries} # # installcheck # # Checks to be sure system is ready for installworld/installkernel. # installcheck: _installcheck_world _installcheck_kernel _installcheck_world: _installcheck_kernel: # # Require DESTDIR to be set if installing for a different architecture or # using the user/group database in the source tree. # .if ${TARGET_ARCH} != ${MACHINE_ARCH} || ${TARGET} != ${MACHINE} || \ defined(DB_FROM_SRC) .if !make(distributeworld) _installcheck_world: __installcheck_DESTDIR _installcheck_kernel: __installcheck_DESTDIR __installcheck_DESTDIR: .if !defined(DESTDIR) || empty(DESTDIR) @echo "ERROR: Please set DESTDIR!"; \ false .endif .endif .endif .if !defined(DB_FROM_SRC) # # Check for missing UIDs/GIDs. # CHECK_UIDS= auditdistd CHECK_GIDS= audit .if ${MK_SENDMAIL} != "no" CHECK_UIDS+= smmsp CHECK_GIDS+= smmsp .endif .if ${MK_PF} != "no" CHECK_UIDS+= proxy CHECK_GIDS+= proxy authpf .endif .if ${MK_UNBOUND} != "no" CHECK_UIDS+= unbound CHECK_GIDS+= unbound .endif _installcheck_world: __installcheck_UGID __installcheck_UGID: .for uid in ${CHECK_UIDS} @if ! `id -u ${uid} >/dev/null 2>&1`; then \ echo "ERROR: Required ${uid} user is missing, see /usr/src/UPDATING."; \ false; \ fi .endfor .for gid in ${CHECK_GIDS} @if ! `find / -prune -group ${gid} >/dev/null 2>&1`; then \ echo "ERROR: Required ${gid} group is missing, see /usr/src/UPDATING."; \ false; \ fi .endfor .endif # # Required install tools to be saved in a scratch dir for safety. # .if ${MK_ZONEINFO} != "no" _zoneinfo= zic tzsetup .endif ITOOLS= [ awk cap_mkdb cat chflags chmod chown cmp cp \ date echo egrep find grep id install ${_install-info} \ ln lockf make mkdir mtree mv pwd_mkdb \ rm sed services_mkdb sh strip sysctl test true uname wc ${_zoneinfo} \ ${LOCAL_ITOOLS} # Needed for share/man .if ${MK_MAN} != "no" ITOOLS+=makewhatis .endif # # distributeworld # # Distributes everything compiled by a `buildworld'. # # installworld # # Installs everything compiled by a 'buildworld'. # # Non-base distributions produced by the base system EXTRA_DISTRIBUTIONS= doc .if defined(LIB32TMP) && ${MK_LIB32} != "no" EXTRA_DISTRIBUTIONS+= lib32 .endif .if ${MK_TESTS} != "no" EXTRA_DISTRIBUTIONS+= tests .endif DEBUG_DISTRIBUTIONS= .if ${MK_DEBUG_FILES} != "no" DEBUG_DISTRIBUTIONS+= base ${EXTRA_DISTRIBUTIONS:S,doc,,:S,tests,,} .endif MTREE_MAGIC?= mtree 2.0 distributeworld installworld stageworld: _installcheck_world mkdir -p ${INSTALLTMP} progs=$$(for prog in ${ITOOLS}; do \ if progpath=`which $$prog`; then \ echo $$progpath; \ else \ echo "Required tool $$prog not found in PATH." >&2; \ exit 1; \ fi; \ done); \ libs=$$(ldd -f "%o %p\n" -f "%o %p\n" $$progs 2>/dev/null | sort -u | \ while read line; do \ set -- $$line; \ if [ "$$2 $$3" != "not found" ]; then \ echo $$2; \ else \ echo "Required library $$1 not found." >&2; \ exit 1; \ fi; \ done); \ cp $$libs $$progs ${INSTALLTMP} cp -R $${PATH_LOCALE:-"/usr/share/locale"} ${INSTALLTMP}/locale .if defined(NO_ROOT) echo "#${MTREE_MAGIC}" > ${METALOG} .endif .if make(distributeworld) .for dist in ${EXTRA_DISTRIBUTIONS} -mkdir ${DESTDIR}/${DISTDIR}/${dist} mtree -deU -f ${.CURDIR}/etc/mtree/BSD.root.dist \ -p ${DESTDIR}/${DISTDIR}/${dist} >/dev/null mtree -deU -f ${.CURDIR}/etc/mtree/BSD.usr.dist \ -p ${DESTDIR}/${DISTDIR}/${dist}/usr >/dev/null mtree -deU -f ${.CURDIR}/etc/mtree/BSD.include.dist \ -p ${DESTDIR}/${DISTDIR}/${dist}/usr/include >/dev/null .if ${MK_DEBUG_FILES} != "no" mtree -deU -f ${.CURDIR}/etc/mtree/BSD.debug.dist \ -p ${DESTDIR}/${DISTDIR}/${dist}/usr/lib >/dev/null .endif .if ${MK_TESTS} != "no" && ${dist} == "tests" -mkdir -p ${DESTDIR}/${DISTDIR}/${dist}${TESTSBASE} mtree -deU -f ${.CURDIR}/etc/mtree/BSD.tests.dist \ -p ${DESTDIR}/${DISTDIR}/${dist}${TESTSBASE} >/dev/null .endif .if defined(NO_ROOT) ${IMAKEENV} mtree -C -f ${.CURDIR}/etc/mtree/BSD.root.dist | \ sed -e 's#^\./#./${dist}/#' >> ${METALOG} ${IMAKEENV} mtree -C -f ${.CURDIR}/etc/mtree/BSD.usr.dist | \ sed -e 's#^\./#./${dist}/usr/#' >> ${METALOG} ${IMAKEENV} mtree -C -f ${.CURDIR}/etc/mtree/BSD.include.dist | \ sed -e 's#^\./#./${dist}/usr/include/#' >> ${METALOG} .endif .endfor -mkdir ${DESTDIR}/${DISTDIR}/base cd ${.CURDIR}/etc; ${CROSSENV} PATH=${TMPPATH} ${MAKE} \ METALOG=${METALOG} ${IMAKE_INSTALL} ${IMAKE_MTREE} \ DISTBASE=/base DESTDIR=${DESTDIR}/${DISTDIR}/base \ LOCAL_MTREE=${LOCAL_MTREE:Q} distrib-dirs .endif ${_+_}cd ${.CURDIR}; ${IMAKE} re${.TARGET:S/world$//}; \ ${IMAKEENV} rm -rf ${INSTALLTMP} .if make(distributeworld) .for dist in ${EXTRA_DISTRIBUTIONS} find ${DESTDIR}/${DISTDIR}/${dist} -mindepth 1 -empty -delete .endfor .if defined(NO_ROOT) .for dist in base ${EXTRA_DISTRIBUTIONS} @# For each file that exists in this dist, print the corresponding @# line from the METALOG. This relies on the fact that @# a line containing only the filename will sort immediatly before @# the relevant mtree line. cd ${DESTDIR}/${DISTDIR}; \ find ./${dist} | sort -u ${METALOG} - | \ awk 'BEGIN { print "#${MTREE_MAGIC}" } !/ type=/ { file = $$1 } / type=/ { if ($$1 == file) { sub(/^\.\/${dist}\//, "./"); print } }' > \ ${DESTDIR}/${DISTDIR}/${dist}.meta .endfor .for dist in ${DEBUG_DISTRIBUTIONS} @# For each file that exists in this dist, print the corresponding @# line from the METALOG. This relies on the fact that @# a line containing only the filename will sort immediatly before @# the relevant mtree line. cd ${DESTDIR}/${DISTDIR}; \ find ./${dist}/usr/lib/debug | sort -u ${METALOG} - | \ awk 'BEGIN { print "#${MTREE_MAGIC}" } !/ type=/ { file = $$1 } / type=/ { if ($$1 == file) { sub(/^\.\/${dist}\//, "./"); print } }' > \ ${DESTDIR}/${DISTDIR}/${dist}.debug.meta .endfor .endif .endif packageworld: .for dist in base ${EXTRA_DISTRIBUTIONS} .if defined(NO_ROOT) ${_+_}cd ${DESTDIR}/${DISTDIR}/${dist}; \ tar cvf - --exclude usr/lib/debug \ @${DESTDIR}/${DISTDIR}/${dist}.meta | \ ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/${dist}.txz .else ${_+_}cd ${DESTDIR}/${DISTDIR}/${dist}; \ tar cvf - --exclude usr/lib/debug . | \ ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/${dist}.txz .endif .endfor .for dist in ${DEBUG_DISTRIBUTIONS} . if defined(NO_ROOT) ${_+_}cd ${DESTDIR}/${DISTDIR}/${dist}; \ tar cvf - @${DESTDIR}/${DISTDIR}/${dist}.debug.meta | \ ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/${dist}-dbg.txz . else ${_+_}cd ${DESTDIR}/${DISTDIR}/${dist}; \ tar cvLf - usr/lib/debug | \ ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/${dist}-dbg.txz . endif .endfor # # reinstall # # If you have a build server, you can NFS mount the source and obj directories # and do a 'make reinstall' on the *client* to install new binaries from the # most recent server build. # reinstall: .MAKE @echo "--------------------------------------------------------------" @echo ">>> Making hierarchy" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; ${MAKE} -f Makefile.inc1 \ LOCAL_MTREE=${LOCAL_MTREE:Q} hierarchy @echo @echo "--------------------------------------------------------------" @echo ">>> Installing everything" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; ${MAKE} -f Makefile.inc1 install .if defined(LIB32TMP) && ${MK_LIB32} != "no" ${_+_}cd ${.CURDIR}; ${MAKE} -f Makefile.inc1 install32 .endif restage: .MAKE @echo "--------------------------------------------------------------" @echo ">>> Making hierarchy" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; ${MAKE} -f Makefile.inc1 \ LOCAL_MTREE=${LOCAL_MTREE:Q} hierarchy distribution @echo @echo "--------------------------------------------------------------" @echo ">>> Installing everything" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; ${MAKE} -f Makefile.inc1 install .if defined(LIB32TMP) && ${MK_LIB32} != "no" ${_+_}cd ${.CURDIR}; ${MAKE} -f Makefile.inc1 install32 .endif redistribute: .MAKE @echo "--------------------------------------------------------------" @echo ">>> Distributing everything" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; ${MAKE} -f Makefile.inc1 distribute .if defined(LIB32TMP) && ${MK_LIB32} != "no" ${_+_}cd ${.CURDIR}; ${MAKE} -f Makefile.inc1 distribute32 \ DISTRIBUTION=lib32 .endif distrib-dirs: .MAKE cd ${.CURDIR}/etc; ${CROSSENV} PATH=${TMPPATH} ${MAKE} \ ${IMAKE_INSTALL} ${IMAKE_MTREE} METALOG=${METALOG} ${.TARGET} distribution: .MAKE cd ${.CURDIR}/etc; ${CROSSENV} PATH=${TMPPATH} ${MAKE} \ ${IMAKE_INSTALL} ${IMAKE_MTREE} METALOG=${METALOG} ${.TARGET} - ${_+_}cd ${.CURDIR}; ${MAKE} -f Makefile.inc1 installconfig + ${_+_}cd ${.CURDIR}; ${CROSSENV} PATH=${TMPPATH} \ + ${MAKE} -f Makefile.inc1 ${IMAKE_INSTALL} \ + METALOG=${METALOG} installconfig # # buildkernel and installkernel # # Which kernels to build and/or install is specified by setting # KERNCONF. If not defined a GENERIC kernel is built/installed. # Only the existing (depending TARGET) config files are used # for building kernels and only the first of these is designated # as the one being installed. # # Note that we have to use TARGET instead of TARGET_ARCH when # we're in kernel-land. Since only TARGET_ARCH is (expected) to # be set to cross-build, we have to make sure TARGET is set # properly. .if defined(KERNFAST) NO_KERNELCLEAN= t NO_KERNELCONFIG= t NO_KERNELDEPEND= t NO_KERNELOBJ= t # Shortcut for KERNCONF=Blah -DKERNFAST is now KERNFAST=Blah .if !defined(KERNCONF) && ${KERNFAST} != "1" KERNCONF=${KERNFAST} .endif .endif .if ${TARGET_ARCH} == "powerpc64" KERNCONF?= GENERIC64 .else KERNCONF?= GENERIC .endif INSTKERNNAME?= kernel KERNSRCDIR?= ${.CURDIR}/sys KRNLCONFDIR= ${KERNSRCDIR}/${TARGET}/conf KRNLOBJDIR= ${OBJTREE}${KERNSRCDIR} KERNCONFDIR?= ${KRNLCONFDIR} BUILDKERNELS= INSTALLKERNEL= .for _kernel in ${KERNCONF} .if exists(${KERNCONFDIR}/${_kernel}) BUILDKERNELS+= ${_kernel} .if empty(INSTALLKERNEL) INSTALLKERNEL= ${_kernel} .endif .endif .endfor buildkernel ${WMAKE_TGTS} ${.ALLTARGETS:M_*}: .MAKE # # buildkernel # # Builds all kernels defined by BUILDKERNELS. # buildkernel: .if empty(BUILDKERNELS) @echo "ERROR: Missing kernel configuration file(s) (${KERNCONF})."; \ false .endif @echo .for _kernel in ${BUILDKERNELS} @echo "--------------------------------------------------------------" @echo ">>> Kernel build for ${_kernel} started on `LC_ALL=C date`" @echo "--------------------------------------------------------------" @echo "===> ${_kernel}" mkdir -p ${KRNLOBJDIR} .if !defined(NO_KERNELCONFIG) @echo @echo "--------------------------------------------------------------" @echo ">>> stage 1: configuring the kernel" @echo "--------------------------------------------------------------" cd ${KRNLCONFDIR}; \ PATH=${TMPPATH} \ config ${CONFIGARGS} -d ${KRNLOBJDIR}/${_kernel} \ -I '${KERNCONFDIR}' '${KERNCONFDIR}/${_kernel}' .endif .if !defined(NO_CLEAN) && !defined(NO_KERNELCLEAN) @echo @echo "--------------------------------------------------------------" @echo ">>> stage 2.1: cleaning up the object tree" @echo "--------------------------------------------------------------" cd ${KRNLOBJDIR}/${_kernel}; ${KMAKE} ${CLEANDIR} .endif .if !defined(NO_KERNELOBJ) @echo @echo "--------------------------------------------------------------" @echo ">>> stage 2.2: rebuilding the object tree" @echo "--------------------------------------------------------------" cd ${KRNLOBJDIR}/${_kernel}; ${KMAKE} obj .endif @echo @echo "--------------------------------------------------------------" @echo ">>> stage 2.3: build tools" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; ${KTMAKE} kernel-tools .if !defined(NO_KERNELDEPEND) @echo @echo "--------------------------------------------------------------" @echo ">>> stage 3.1: making dependencies" @echo "--------------------------------------------------------------" cd ${KRNLOBJDIR}/${_kernel}; ${KMAKE} depend -DNO_MODULES_OBJ .endif @echo @echo "--------------------------------------------------------------" @echo ">>> stage 3.2: building everything" @echo "--------------------------------------------------------------" cd ${KRNLOBJDIR}/${_kernel}; ${KMAKE} all -DNO_MODULES_OBJ @echo "--------------------------------------------------------------" @echo ">>> Kernel build for ${_kernel} completed on `LC_ALL=C date`" @echo "--------------------------------------------------------------" .endfor # # installkernel, etc. # # Install the kernel defined by INSTALLKERNEL # installkernel installkernel.debug \ reinstallkernel reinstallkernel.debug: _installcheck_kernel .if empty(INSTALLKERNEL) @echo "ERROR: No kernel \"${KERNCONF}\" to install."; \ false .endif @echo "--------------------------------------------------------------" @echo ">>> Installing kernel ${INSTALLKERNEL}" @echo "--------------------------------------------------------------" cd ${KRNLOBJDIR}/${INSTALLKERNEL}; \ ${CROSSENV} PATH=${TMPPATH} \ ${MAKE} ${IMAKE_INSTALL} KERNEL=${INSTKERNNAME} ${.TARGET:S/kernel//} .if ${BUILDKERNELS:[#]} > 1 .for _kernel in ${BUILDKERNELS:[2..-1]} @echo "--------------------------------------------------------------" @echo ">>> Installing kernel ${_kernel}" @echo "--------------------------------------------------------------" cd ${KRNLOBJDIR}/${_kernel}; \ ${CROSSENV} PATH=${TMPPATH} \ ${MAKE} ${IMAKE_INSTALL} KERNEL=${INSTKERNNAME}.${_kernel} ${.TARGET:S/kernel//} .endfor .endif distributekernel distributekernel.debug: .if empty(INSTALLKERNEL) @echo "ERROR: No kernel \"${KERNCONF}\" to install."; \ false .endif mkdir -p ${DESTDIR}/${DISTDIR} .if defined(NO_ROOT) echo "#${MTREE_MAGIC}" > ${DESTDIR}/${DISTDIR}/kernel.premeta .endif cd ${KRNLOBJDIR}/${INSTALLKERNEL}; \ ${IMAKEENV} ${IMAKE_INSTALL:S/METALOG/kernel.premeta/} \ ${IMAKE_MTREE} PATH=${TMPPATH} ${MAKE} KERNEL=${INSTKERNNAME} \ DESTDIR=${INSTALL_DDIR}/kernel \ ${.TARGET:S/distributekernel/install/} .if defined(NO_ROOT) sed -e 's|^./kernel|.|' ${DESTDIR}/${DISTDIR}/kernel.premeta > \ ${DESTDIR}/${DISTDIR}/kernel.meta .endif .if ${BUILDKERNELS:[#]} > 1 .for _kernel in ${BUILDKERNELS:[2..-1]} .if defined(NO_ROOT) echo "#${MTREE_MAGIC}" > ${DESTDIR}/${DISTDIR}/kernel.${_kernel}.premeta .endif cd ${KRNLOBJDIR}/${_kernel}; \ ${IMAKEENV} ${IMAKE_INSTALL:S/METALOG/kernel.${_kernel}.premeta/} \ ${IMAKE_MTREE} PATH=${TMPPATH} ${MAKE} \ KERNEL=${INSTKERNNAME}.${_kernel} \ DESTDIR=${INSTALL_DDIR}/kernel.${_kernel} \ ${.TARGET:S/distributekernel/install/} .if defined(NO_ROOT) sed -e 's|^./kernel|.|' \ ${DESTDIR}/${DISTDIR}/kernel.${_kernel}.premeta > \ ${DESTDIR}/${DISTDIR}/kernel.${_kernel}.meta .endif .endfor .endif packagekernel: .if defined(NO_ROOT) cd ${DESTDIR}/${DISTDIR}/kernel; \ tar cvf - @${DESTDIR}/${DISTDIR}/kernel.meta | \ ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/kernel.txz .if ${BUILDKERNELS:[#]} > 1 .for _kernel in ${BUILDKERNELS:[2..-1]} cd ${DESTDIR}/${DISTDIR}/kernel.${_kernel}; \ tar cvf - @${DESTDIR}/${DISTDIR}/kernel.${_kernel}.meta | \ ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/kernel.${_kernel}.txz .endfor .endif .else cd ${DESTDIR}/${DISTDIR}/kernel; \ tar cvf - . | \ ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/kernel.txz .if ${BUILDKERNELS:[#]} > 1 .for _kernel in ${BUILDKERNELS:[2..-1]} cd ${DESTDIR}/${DISTDIR}/kernel.${_kernel}; \ tar cvf - . | \ ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/kernel.${_kernel}.txz .endfor .endif .endif create-world-packages: @rm -f ${DESTDIR}/*.plist 2>/dev/null || : @cd ${DESTDIR} ; \ awk -f ${SRCDIR}/release/scripts/mtree-to-plist.awk \ ${DESTDIR}/METALOG @for plist in ${DESTDIR}/*.plist; do \ plist=$${plist##*/} ; \ test -f ${SRCDIR}/release/packages/$${plist%.plist}.ucl || \ ( echo "Unkown package FreeBSD-$${plist%.plist}" ; false ) ; \ done @cap_arg=`cd ${SRCDIR}/etc ; ${MAKE} -VCAP_MKDB_ENDIAN` ; \ pwd_arg=`cd ${SRCDIR}/etc ; ${MAKE} -VPWD_MKDB_ENDIAN` ; \ for plist in ${DESTDIR}/*.plist; do \ plist=$${plist##*/} ; \ pkgname=$${plist%.plist} ; \ sed -e "s/%VERSION%/${PKG_VERSION}/" \ -e "s/%PKGNAME%/$${pkgname}/" \ -e "s/%COMMENT%/Generic comment for $${pkgname}/" \ -e "s/%DESC%/Generic description for $${pkgname}/" \ -e "s/%CAP_MKDB_ENDIAN%/$${cap_arg}/g" \ -e "s/%PWD_MKDB_ENDIAN%/$${pwd_arg}/g" \ ${SRCDIR}/release/packages/$${pkgname}.ucl \ > ${DESTDIR}/$${pkgname}.ucl ; \ awk -F\" '/name/ { printf("===> Creating %s-", $$2) } /version/ {print $$2 }' \ ${DESTDIR}/$${pkgname}.ucl ; \ pkg -o ABI_FILE=${DESTDIR}/bin/sh \ create -M ${DESTDIR}/$${pkgname}.ucl \ -p ${DESTDIR}/$${pkgname}.plist \ -r ${DESTDIR} -o ${DESTDIR} ; \ done STAGEDIR= ${MAKEOBJDIRPREFIX}${.CURDIR}/stage packages: @mkdir -p ${MAKEOBJDIRPREFIX}${.CURDIR}/stage ${_+_}@cd ${.CURDIR}; \ ${MAKE} buildworld ; \ ${MAKE} DESTDIR=${DESTDIR:U${STAGEDIR}} -DNO_ROOT stageworld ; \ ${MAKE} DESTDIR=${DESTDIR:U${STAGEDIR}} create-world-packages create-kernel-packages: .if !defined(NO_ROOT) @echo "ERROR: create-kernel-packages can only be done with -DNO_ROOT"; \ false .endif @cd ${DESTDIR}/${DISTDIR} ; \ awk -f ${SRCDIR}/release/scripts/mtree-to-plist.awk \ ${DESTDIR}/${DISTDIR}/kernel.meta .for flavor in release debug .if exists(${DESTDIR}/${DISTDIR}/${flavor}.plist) @rm -rf ${DESTDIR}/${DISTDIR}/${flavor}-manifestdir @cp -r ${SRCDIR}/release/packages/kernel \ ${DESTDIR}/${DISTDIR}/${flavor}-manifestdir @cd ${DESTDIR}/${DISTDIR} ; \ sed -i '' -e "s/%VERSION%/${PKG_VERSION}/" \ -e "s/%PKGNAME%/kernel-${flavor}/" \ -e "s/%COMMENT%/FreeBSD ${KERNCONF} kernel ${flavor}/" \ -e "s/%DESC%/FreeBSD ${KERNCONF} kernel ${flavor}/" \ ${DESTDIR}/${DISTDIR}/${flavor}-manifestdir/+MANIFEST @awk -F\" '/name/ { printf("===> Creating %s-", $$2) } /version/ {print $$2 }' \ ${DESTDIR}/${DISTDIR}/${flavor}-manifestdir/+MANIFEST @pkg create -m ${DESTDIR}/${DISTDIR}/${flavor}-manifestdir \ -p ${DESTDIR}/${DISTDIR}/${flavor}.plist \ -r ${DESTDIR}/${DISTDIR}/kernel \ -o ${DESTDIR} .endif .endfor .for _kernel in ${BUILDKERNELS:S/${INSTALLKERNEL}//} @cd ${DESTDIR}/${DISTDIR} ; \ awk -f ${SRCDIR}/release/scripts/mtree-to-plist.awk \ ${DESTDIR}/${DISTDIR}/kernel${_kernel}.meta .for flavor in release debug .if exists(${DESTDIR}/${DISTDIR}/${flavor}.plist) @rm -rf ${DESTDIR}/${DISTDIR}/${flavor}-manifestdir @cp -r ${SRCDIR}/release/packages/kernel \ ${DESTDIR}/${DISTDIR}/${flavor}-manifestdir @cd ${DESTDIR}/${DISTDIR} ; \ sed -i '' -e "s/%VERSION%/${PKG_VERSION}/" \ -e "s/%PKGNAME%/kernel-${flavor}/" \ -e "s/%COMMENT%/FreeBSD ${KERNCONF} kernel ${flavor}/" \ -e "s/%DESC%/FreeBSD ${KERNCONF} kernel ${flavor}/" \ ${DESTDIR}/${DISTDIR}/${flavor}-manifestdir/+MANIFEST @awk -F\" '/name/ { printf("===> Creating %s-", $$2) } /version/ {print $$2 }' \ ${DESTDIR}/${DISTDIR}/${flavor}-manifestdir/+MANIFEST @pkg create -m ${DESTDIR}/${DISTDIR}/${flavor}-manifestdir \ -p ${DESTDIR}/${DISTDIR}/${flavor}.plist \ -r ${DESTDIR}/${DISTDIR}/kernel.${_kernel} \ -o ${DESTDIR} .endif .endfor .endfor # # doxygen # # Build the API documentation with doxygen # doxygen: @if [ ! -x `/usr/bin/which doxygen` ]; then \ echo "You need doxygen (devel/doxygen) to generate the API documentation of the kernel." | /usr/bin/fmt; \ exit 1; \ fi cd ${.CURDIR}/tools/kerneldoc/subsys && ${MAKE} obj all # # update # # Update the source tree(s), by running svn/svnup to update to the # latest copy. # update: .if (defined(CVS_UPDATE) || defined(SUP_UPDATE)) && !defined(SVN_UPDATE) @echo "--------------------------------------------------------------" @echo "CVS_UPDATE and SUP_UPDATE are no longer supported." @echo "Please see: https://wiki.freebsd.org/CvsIsDeprecated" @echo "--------------------------------------------------------------" @exit 1 .endif .if defined(SVN_UPDATE) @echo "--------------------------------------------------------------" @echo ">>> Updating ${.CURDIR} using Subversion" @echo "--------------------------------------------------------------" @(cd ${.CURDIR} && ${SVN} update ${SVNFLAGS}) .endif # # ------------------------------------------------------------------------ # # From here onwards are utility targets used by the 'make world' and # related targets. If your 'world' breaks, you may like to try to fix # the problem and manually run the following targets to attempt to # complete the build. Beware, this is *not* guaranteed to work, you # need to have a pretty good grip on the current state of the system # to attempt to manually finish it. If in doubt, 'make world' again. # # # legacy: Build compatibility shims for the next three targets. This is a # minimal set of tools and shims necessary to compensate for older systems # which don't have the APIs required by the targets built in bootstrap-tools, # build-tools or cross-tools. # # ELF Tool Chain libraries are needed for ELF tools and dtrace tools. .if ${BOOTSTRAPPING} < 1100006 _elftoolchain_libs= lib/libelf lib/libdwarf .endif legacy: .if ${BOOTSTRAPPING} < 800107 && ${BOOTSTRAPPING} != 0 @echo "ERROR: Source upgrades from versions prior to 8.0 are not supported."; \ false .endif .for _tool in tools/build ${_elftoolchain_libs} ${_+_}@${ECHODIR} "===> ${_tool} (obj,includes,depend,all,install)"; \ cd ${.CURDIR}/${_tool} && \ ${MAKE} DIRPRFX=${_tool}/ obj && \ ${MAKE} DIRPRFX=${_tool}/ DESTDIR=${MAKEOBJDIRPREFIX}/legacy includes && \ ${MAKE} DIRPRFX=${_tool}/ depend && \ ${MAKE} DIRPRFX=${_tool}/ all && \ ${MAKE} DIRPRFX=${_tool}/ DESTDIR=${MAKEOBJDIRPREFIX}/legacy install .endfor # # bootstrap-tools: Build tools needed for compatibility. These are binaries that # are built to build other binaries in the system. However, the focus of these # binaries is usually quite narrow. Bootstrap tools use the host's compiler and # libraries, augmented by -legacy. # _bt= _bootstrap-tools .if ${MK_GAMES} != "no" _strfile= usr.bin/fortune/strfile .endif .if ${MK_GCC} != "no" && ${MK_CXX} != "no" _gperf= gnu/usr.bin/gperf .endif .if ${MK_GROFF} != "no" _groff= gnu/usr.bin/groff \ usr.bin/soelim .endif .if ${MK_VT} != "no" _vtfontcvt= usr.bin/vtfontcvt .endif .if ${BOOTSTRAPPING} < 900002 _sed= usr.bin/sed .endif .if ${BOOTSTRAPPING} < 1000002 _libohash= lib/libohash _m4= usr.bin/m4 ${_bt}-usr.bin/m4: ${_bt}-lib/libohash .endif .if ${BOOTSTRAPPING} < 1000026 _nmtree= lib/libnetbsd \ usr.sbin/nmtree ${_bt}-usr.sbin/nmtree: ${_bt}-lib/libnetbsd .endif .if ${BOOTSTRAPPING} < 1000027 _cat= bin/cat .endif .if ${BOOTSTRAPPING} < 1000033 _lex= usr.bin/lex ${_bt}-usr.bin/lex: ${_bt}-usr.bin/m4 .endif # r277259 crunchide: Correct 64-bit section header offset # r281674 crunchide: always include both 32- and 64-bit ELF support # r285986 crunchen: use STRIPBIN rather than STRIP .if ${BOOTSTRAPPING} < 1100078 _crunch= usr.sbin/crunch .endif .if ${BOOTSTRAPPING} >= 900040 && ${BOOTSTRAPPING} < 900041 _awk= usr.bin/awk .endif _yacc= lib/liby \ usr.bin/yacc ${_bt}-usr.bin/yacc: ${_bt}-lib/liby .if ${MK_BSNMP} != "no" _gensnmptree= usr.sbin/bsnmpd/gensnmptree .endif # We need to build tblgen when we're building clang either as # the bootstrap compiler, or as the part of the normal build. .if ${MK_CLANG_BOOTSTRAP} != "no" || ${MK_CLANG} != "no" _clang_tblgen= \ lib/clang/libllvmsupport \ lib/clang/libllvmtablegen \ usr.bin/clang/tblgen \ usr.bin/clang/clang-tblgen ${_bt}-usr.bin/clang/clang-tblgen: ${_bt}-lib/clang/libllvmtablegen ${_bt}-lib/clang/libllvmsupport ${_bt}-usr.bin/clang/tblgen: ${_bt}-lib/clang/libllvmtablegen ${_bt}-lib/clang/libllvmsupport .endif # Default to building the GPL DTC, but build the BSDL one if users explicitly # request it. _dtc= usr.bin/dtc .if ${MK_GPL_DTC} != "no" _dtc= gnu/usr.bin/dtc .endif .if ${MK_KERBEROS} != "no" _kerberos5_bootstrap_tools= \ kerberos5/tools/make-roken \ kerberos5/lib/libroken \ kerberos5/lib/libvers \ kerberos5/tools/asn1_compile \ kerberos5/tools/slc \ usr.bin/compile_et .ORDER: ${_kerberos5_bootstrap_tools:C/^/${_bt}-/g} .endif .if ${MK_MANDOCDB} != "no" _libohash?= lib/libohash _makewhatis= lib/libsqlite3 \ usr.bin/mandoc ${_bt}-usr.bin/mandoc: ${_bt}-lib/libohash ${_bt}-lib/libsqlite3 .else _makewhatis=usr.bin/makewhatis .endif # Rebuild up-to-date libmd for xinstall ${_bt}-usr.bin/xinstall: ${_bt}-lib/libmd bootstrap-tools: .PHONY # Please document (add comment) why something is in 'bootstrap-tools'. # Try to bound the building of the bootstrap-tool to just the # FreeBSD versions that need the tool built at this stage of the build. .for _tool in \ ${_clang_tblgen} \ ${_kerberos5_bootstrap_tools} \ ${_strfile} \ ${_gperf} \ ${_groff} \ ${_dtc} \ ${_awk} \ ${_cat} \ usr.bin/lorder \ ${_libohash} \ ${_makewhatis} \ usr.bin/rpcgen \ ${_sed} \ ${_yacc} \ ${_m4} \ ${_lex} \ lib/libmd \ usr.bin/xinstall \ ${_gensnmptree} \ usr.sbin/config \ ${_crunch} \ ${_nmtree} \ ${_vtfontcvt} ${_bt}-${_tool}: .PHONY .MAKE ${_+_}@${ECHODIR} "===> ${_tool} (obj,depend,all,install)"; \ cd ${.CURDIR}/${_tool} && \ ${MAKE} DIRPRFX=${_tool}/ obj && \ ${MAKE} DIRPRFX=${_tool}/ depend && \ ${MAKE} DIRPRFX=${_tool}/ all && \ ${MAKE} DIRPRFX=${_tool}/ DESTDIR=${MAKEOBJDIRPREFIX}/legacy install bootstrap-tools: ${_bt}-${_tool} .endfor # # build-tools: Build special purpose build tools # .if !defined(NO_SHARE) _share= share/syscons/scrnmaps .endif .if ${MK_GCC} != "no" _gcc_tools= gnu/usr.bin/cc/cc_tools .endif .if ${MK_RESCUE} != "no" # rescue includes programs that have build-tools targets _rescue=rescue/rescue .endif build-tools: .MAKE .for _tool in \ bin/csh \ bin/sh \ ${LOCAL_TOOL_DIRS} \ lib/ncurses/ncurses \ lib/ncurses/ncursesw \ ${_rescue} \ ${_share} \ usr.bin/awk \ lib/libmagic \ usr.bin/mkesdb_static \ usr.bin/mkcsmapper_static \ usr.bin/vi/catalog ${_+_}@${ECHODIR} "===> ${_tool} (obj,build-tools)"; \ cd ${.CURDIR}/${_tool} && \ ${MAKE} DIRPRFX=${_tool}/ obj && \ ${MAKE} DIRPRFX=${_tool}/ build-tools .endfor .for _tool in \ ${_gcc_tools} ${_+_}@${ECHODIR} "===> ${_tool} (obj,depend,all)"; \ cd ${.CURDIR}/${_tool} && \ ${MAKE} DIRPRFX=${_tool}/ obj && \ ${MAKE} DIRPRFX=${_tool}/ depend && \ ${MAKE} DIRPRFX=${_tool}/ all .endfor # # kernel-tools: Build kernel-building tools # kernel-tools: .MAKE mkdir -p ${MAKEOBJDIRPREFIX}/usr mtree -deU -f ${.CURDIR}/etc/mtree/BSD.usr.dist \ -p ${MAKEOBJDIRPREFIX}/usr >/dev/null # # cross-tools: All the tools needed to build the rest of the system after # we get done with the earlier stages. It is the last set of tools needed # to begin building the target binaries. # .if ${TARGET_ARCH} != ${MACHINE_ARCH} .if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "i386" _btxld= usr.sbin/btxld .endif .endif # Rebuild ctfconvert and ctfmerge to avoid difficult-to-diagnose failures # resulting from missing bug fixes or ELF Toolchain updates. .if ${MK_CDDL} != "no" _dtrace_tools= cddl/lib/libctf cddl/usr.bin/ctfconvert \ cddl/usr.bin/ctfmerge .endif # If we're given an XAS, don't build binutils. .if ${XAS:M/*} == "" .if ${MK_BINUTILS_BOOTSTRAP} != "no" _binutils= gnu/usr.bin/binutils .endif .if ${MK_ELFTOOLCHAIN_BOOTSTRAP} != "no" _elftctools= lib/libelftc \ usr.bin/elfcopy \ usr.bin/nm \ usr.bin/size \ usr.bin/strings # These are not required by the build, but can be useful for developers who # cross-build on a FreeBSD 10 host: _elftctools+= usr.bin/addr2line .endif .elif ${TARGET_ARCH} != ${MACHINE_ARCH} && ${MK_ELFTOOLCHAIN_BOOTSTRAP} != "no" # If cross-building with an external binutils we still need to build strip for # the target (for at least crunchide). _elftctools= lib/libelftc \ usr.bin/elfcopy .endif # If an full path to an external cross compiler is given, don't build # a cross compiler. .if ${XCC:M/*} == "" && ${MK_CROSS_COMPILER} != "no" .if ${MK_CLANG_BOOTSTRAP} != "no" _clang= usr.bin/clang _clang_libs= lib/clang .endif .if ${MK_GCC_BOOTSTRAP} != "no" _cc= gnu/usr.bin/cc .endif .endif .if ${MK_USB} != "no" _usb_tools= sys/boot/usb/tools .endif cross-tools: .MAKE .for _tool in \ ${_clang_libs} \ ${_clang} \ ${_binutils} \ ${_elftctools} \ ${_dtrace_tools} \ ${_cc} \ ${_btxld} \ ${_crunchide} \ ${_usb_tools} ${_+_}@${ECHODIR} "===> ${_tool} (obj,depend,all,install)"; \ cd ${.CURDIR}/${_tool} && \ ${MAKE} DIRPRFX=${_tool}/ obj && \ ${MAKE} DIRPRFX=${_tool}/ depend && \ ${MAKE} DIRPRFX=${_tool}/ all && \ ${MAKE} DIRPRFX=${_tool}/ DESTDIR=${MAKEOBJDIRPREFIX} install .endfor NXBENV= MAKEOBJDIRPREFIX=${OBJTREE}/nxb \ INSTALL="sh ${.CURDIR}/tools/install.sh" \ VERSION="${VERSION}" \ PATH=${PATH}:${OBJTREE}/gperf_for_gcc/usr/bin NXBMAKE= ${NXBENV} ${MAKE} \ TBLGEN=${OBJTREE}/nxb-bin/usr/bin/tblgen \ CLANG_TBLGEN=${OBJTREE}/nxb-bin/usr/bin/clang-tblgen \ MACHINE=${TARGET} MACHINE_ARCH=${TARGET_ARCH} \ MK_GDB=no MK_TESTS=no \ SSP_CFLAGS= \ MK_HTML=no NO_LINT=yes MK_MAN=no \ -DNO_PIC MK_PROFILE=no -DNO_SHARED \ -DNO_CPU_CFLAGS MK_WARNS=no MK_CTF=no \ MK_CLANG_EXTRAS=no MK_CLANG_FULL=no \ MK_LLDB=no # native-xtools is the current target for qemu-user cross builds of ports # via poudriere and the imgact_binmisc kernel module. # For non-clang enabled targets that are still using the in tree gcc # we must build a gperf binary for one instance of its Makefiles. On # clang-enabled systems, the gperf binary is obsolete. native-xtools: .MAKE .if ${MK_GCC_BOOTSTRAP} != "no" mkdir -p ${OBJTREE}/gperf_for_gcc/usr/bin ${_+_}@${ECHODIR} "===> ${_gperf} (obj,depend,all,install)"; \ cd ${.CURDIR}/${_gperf} && \ ${NXBMAKE} DIRPRFX=${_gperf}/ obj && \ ${NXBMAKE} DIRPRFX=${_gperf}/ depend && \ ${NXBMAKE} DIRPRFX=${_gperf}/ all && \ ${NXBMAKE} DIRPRFX=${_gperf}/ DESTDIR=${OBJTREE}/gperf_for_gcc install .endif mkdir -p ${OBJTREE}/nxb-bin/bin mkdir -p ${OBJTREE}/nxb-bin/sbin mkdir -p ${OBJTREE}/nxb-bin/usr mtree -deU -f ${.CURDIR}/etc/mtree/BSD.usr.dist \ -p ${OBJTREE}/nxb-bin/usr >/dev/null mtree -deU -f ${.CURDIR}/etc/mtree/BSD.include.dist \ -p ${OBJTREE}/nxb-bin/usr/include >/dev/null .for _tool in \ bin/cat \ bin/chmod \ bin/cp \ bin/csh \ bin/echo \ bin/expr \ bin/hostname \ bin/ln \ bin/ls \ bin/mkdir \ bin/mv \ bin/ps \ bin/realpath \ bin/rm \ bin/rmdir \ bin/sh \ bin/sleep \ ${_clang_tblgen} \ usr.bin/ar \ ${_binutils} \ ${_elftctools} \ ${_cc} \ ${_gcc_tools} \ ${_clang_libs} \ ${_clang} \ sbin/md5 \ sbin/sysctl \ gnu/usr.bin/diff \ usr.bin/awk \ usr.bin/basename \ usr.bin/bmake \ usr.bin/bzip2 \ usr.bin/cmp \ usr.bin/dirname \ usr.bin/env \ usr.bin/fetch \ usr.bin/find \ usr.bin/grep \ usr.bin/gzip \ usr.bin/id \ usr.bin/lex \ usr.bin/lorder \ usr.bin/mktemp \ usr.bin/mt \ usr.bin/patch \ usr.bin/sed \ usr.bin/sort \ usr.bin/tar \ usr.bin/touch \ usr.bin/tr \ usr.bin/true \ usr.bin/uniq \ usr.bin/unzip \ usr.bin/xargs \ usr.bin/xinstall \ usr.bin/xz \ usr.bin/yacc \ usr.sbin/chown ${_+_}@${ECHODIR} "===> ${_tool} (obj,depend,all,install)"; \ cd ${.CURDIR}/${_tool} && \ ${NXBMAKE} DIRPRFX=${_tool}/ obj && \ ${NXBMAKE} DIRPRFX=${_tool}/ depend && \ ${NXBMAKE} DIRPRFX=${_tool}/ all && \ ${NXBMAKE} DIRPRFX=${_tool}/ DESTDIR=${OBJTREE}/nxb-bin install .endfor # # hierarchy - ensure that all the needed directories are present # hierarchy hier: .MAKE cd ${.CURDIR}/etc && ${HMAKE} distrib-dirs # # libraries - build all libraries, and install them under ${DESTDIR}. # # The list of libraries with dependents (${_prebuild_libs}) and their # interdependencies (__L) are built automatically by the # ${.CURDIR}/tools/make_libdeps.sh script. # libraries: .MAKE cd ${.CURDIR} && \ ${MAKE} -f Makefile.inc1 _prereq_libs && \ ${MAKE} -f Makefile.inc1 _startup_libs && \ ${MAKE} -f Makefile.inc1 _prebuild_libs && \ ${MAKE} -f Makefile.inc1 _generic_libs # # static libgcc.a prerequisite for shared libc # _prereq_libs= gnu/lib/libssp/libssp_nonshared gnu/lib/libgcc lib/libcompiler_rt # These dependencies are not automatically generated: # # gnu/lib/csu, gnu/lib/libgcc, lib/csu and lib/libc must be built before # all shared libraries for ELF. # _startup_libs= gnu/lib/csu _startup_libs+= lib/csu _startup_libs+= gnu/lib/libgcc _startup_libs+= lib/libcompiler_rt _startup_libs+= lib/libc _startup_libs+= lib/libc_nonshared .if ${MK_LIBCPLUSPLUS} != "no" _startup_libs+= lib/libcxxrt .endif gnu/lib/libgcc__L: lib/libc__L gnu/lib/libgcc__L: lib/libc_nonshared__L .if ${MK_LIBCPLUSPLUS} != "no" lib/libcxxrt__L: gnu/lib/libgcc__L .endif _prebuild_libs= ${_kerberos5_lib_libasn1} \ ${_kerberos5_lib_libhdb} \ ${_kerberos5_lib_libheimbase} \ ${_kerberos5_lib_libheimntlm} \ ${_libsqlite3} \ ${_kerberos5_lib_libheimipcc} \ ${_kerberos5_lib_libhx509} ${_kerberos5_lib_libkrb5} \ ${_kerberos5_lib_libroken} \ ${_kerberos5_lib_libwind} \ lib/libbz2 ${_libcom_err} lib/libcrypt \ lib/libelf lib/libexpat \ lib/libfigpar \ ${_lib_libgssapi} \ lib/libkiconv lib/libkvm lib/liblzma lib/libmd lib/libnv \ ${_lib_libcapsicum} \ lib/ncurses/ncurses lib/ncurses/ncursesw \ lib/libopie lib/libpam ${_lib_libthr} \ ${_lib_libradius} lib/libsbuf lib/libtacplus \ lib/libgeom \ ${_cddl_lib_libumem} ${_cddl_lib_libnvpair} \ ${_cddl_lib_libuutil} \ ${_cddl_lib_libavl} \ ${_cddl_lib_libzfs_core} \ ${_cddl_lib_libctf} \ lib/libutil lib/libpjdlog ${_lib_libypclnt} lib/libz lib/msun \ ${_secure_lib_libcrypto} ${_lib_libldns} \ ${_secure_lib_libssh} ${_secure_lib_libssl} \ gnu/lib/libdialog .if ${MK_GNUCXX} != "no" _prebuild_libs+= gnu/lib/libstdc++ gnu/lib/libsupc++ gnu/lib/libstdc++__L: lib/msun__L gnu/lib/libsupc++__L: gnu/lib/libstdc++__L .endif .if ${MK_LIBCPLUSPLUS} != "no" _prebuild_libs+= lib/libc++ .endif lib/libgeom__L: lib/libexpat__L .if ${MK_LIBTHR} != "no" _lib_libthr= lib/libthr .endif .if ${MK_RADIUS_SUPPORT} != "no" _lib_libradius= lib/libradius .endif .if ${MK_OFED} != "no" _ofed_lib= contrib/ofed/usr.lib/ .endif .if ${MK_CASPER} != "no" _lib_libcapsicum=lib/libcapsicum .endif lib/libcapsicum__L: lib/libnv__L lib/libpjdlog__L: lib/libutil__L lib/liblzma__L: lib/libthr__L _generic_libs= ${_cddl_lib} gnu/lib ${_kerberos5_lib} lib ${_secure_lib} usr.bin/lex/lib ${_ofed_lib} .for _DIR in ${LOCAL_LIB_DIRS} .if exists(${.CURDIR}/${_DIR}/Makefile) _generic_libs+= ${_DIR} .endif .endfor lib/libopie__L lib/libtacplus__L: lib/libmd__L .if ${MK_CDDL} != "no" _cddl_lib_libumem= cddl/lib/libumem _cddl_lib_libnvpair= cddl/lib/libnvpair _cddl_lib_libavl= cddl/lib/libavl _cddl_lib_libuutil= cddl/lib/libuutil _cddl_lib_libzfs_core= cddl/lib/libzfs_core _cddl_lib_libctf= cddl/lib/libctf _cddl_lib= cddl/lib cddl/lib/libzfs_core__L: cddl/lib/libnvpair__L cddl/lib/libzfs__L: lib/libgeom__L cddl/lib/libctf__L: lib/libz__L .endif # cddl/lib/libdtrace requires lib/libproc and lib/librtld_db; it's only built # on select architectures though (see cddl/lib/Makefile) .if ${MACHINE_CPUARCH} != "sparc64" _prebuild_libs+= lib/libproc lib/librtld_db .endif .if ${MK_CRYPT} != "no" .if ${MK_OPENSSL} != "no" _secure_lib_libcrypto= secure/lib/libcrypto _secure_lib_libssl= secure/lib/libssl lib/libradius__L secure/lib/libssl__L: secure/lib/libcrypto__L .if ${MK_LDNS} != "no" _lib_libldns= lib/libldns lib/libldns__L: secure/lib/libcrypto__L .endif .if ${MK_OPENSSH} != "no" _secure_lib_libssh= secure/lib/libssh secure/lib/libssh__L: lib/libz__L secure/lib/libcrypto__L lib/libcrypt__L .if ${MK_LDNS} != "no" secure/lib/libssh__L: lib/libldns__L .endif .if ${MK_KERBEROS_SUPPORT} != "no" secure/lib/libssh__L: lib/libgssapi__L kerberos5/lib/libkrb5__L \ kerberos5/lib/libhx509__L kerberos5/lib/libasn1__L lib/libcom_err__L \ lib/libmd__L kerberos5/lib/libroken__L .endif .endif .endif _secure_lib= secure/lib .endif .if ${MK_KERBEROS} != "no" kerberos5/lib/libasn1__L: lib/libcom_err__L kerberos5/lib/libroken__L kerberos5/lib/libhdb__L: kerberos5/lib/libasn1__L lib/libcom_err__L \ kerberos5/lib/libkrb5__L kerberos5/lib/libroken__L \ kerberos5/lib/libwind__L lib/libsqlite3__L kerberos5/lib/libheimntlm__L: secure/lib/libcrypto__L kerberos5/lib/libkrb5__L \ kerberos5/lib/libroken__L lib/libcom_err__L kerberos5/lib/libhx509__L: kerberos5/lib/libasn1__L lib/libcom_err__L \ secure/lib/libcrypto__L kerberos5/lib/libroken__L kerberos5/lib/libwind__L kerberos5/lib/libkrb5__L: kerberos5/lib/libasn1__L lib/libcom_err__L \ lib/libcrypt__L secure/lib/libcrypto__L kerberos5/lib/libhx509__L \ kerberos5/lib/libroken__L kerberos5/lib/libwind__L \ kerberos5/lib/libheimbase__L kerberos5/lib/libheimipcc__L kerberos5/lib/libroken__L: lib/libcrypt__L kerberos5/lib/libwind__L: kerberos5/lib/libroken__L lib/libcom_err__L kerberos5/lib/libheimbase__L: lib/libthr__L kerberos5/lib/libheimipcc__L: kerberos5/lib/libroken__L kerberos5/lib/libheimbase__L lib/libthr__L .endif lib/libsqlite3__L: lib/libthr__L .if ${MK_GSSAPI} != "no" _lib_libgssapi= lib/libgssapi .endif .if ${MK_KERBEROS} != "no" _kerberos5_lib= kerberos5/lib _kerberos5_lib_libasn1= kerberos5/lib/libasn1 _kerberos5_lib_libhdb= kerberos5/lib/libhdb _kerberos5_lib_libheimbase= kerberos5/lib/libheimbase _kerberos5_lib_libkrb5= kerberos5/lib/libkrb5 _kerberos5_lib_libhx509= kerberos5/lib/libhx509 _kerberos5_lib_libroken= kerberos5/lib/libroken _kerberos5_lib_libheimntlm= kerberos5/lib/libheimntlm _libsqlite3= lib/libsqlite3 _kerberos5_lib_libheimipcc= kerberos5/lib/libheimipcc _kerberos5_lib_libwind= kerberos5/lib/libwind _libcom_err= lib/libcom_err .endif .if ${MK_NIS} != "no" _lib_libypclnt= lib/libypclnt .endif .if ${MK_OPENSSL} == "no" lib/libradius__L: lib/libmd__L .endif lib/libproc__L: \ ${_cddl_lib_libctf:D${_cddl_lib_libctf}__L} lib/libelf__L lib/librtld_db__L lib/libutil__L .if ${MK_CXX} != "no" .if ${MK_LIBCPLUSPLUS} != "no" lib/libproc__L: lib/libcxxrt__L .else # This implies MK_GNUCXX != "no"; see lib/libproc lib/libproc__L: gnu/lib/libsupc++__L .endif .endif gnu/lib/libdialog__L: lib/msun__L lib/ncurses/ncursesw__L .for _lib in ${_prereq_libs} ${_lib}__PL: .PHONY .MAKE .if exists(${.CURDIR}/${_lib}) ${_+_}@${ECHODIR} "===> ${_lib} (obj,depend,all,install)"; \ cd ${.CURDIR}/${_lib} && \ ${MAKE} MK_TESTS=no DIRPRFX=${_lib}/ obj && \ ${MAKE} MK_TESTS=no DIRPRFX=${_lib}/ depend && \ ${MAKE} MK_TESTS=no MK_PROFILE=no -DNO_PIC \ DIRPRFX=${_lib}/ all && \ ${MAKE} MK_TESTS=no MK_PROFILE=no -DNO_PIC \ DIRPRFX=${_lib}/ install .endif .endfor .for _lib in ${_startup_libs} ${_prebuild_libs:Nlib/libpam} ${_generic_libs} ${_lib}__L: .PHONY .MAKE .if exists(${.CURDIR}/${_lib}) ${_+_}@${ECHODIR} "===> ${_lib} (obj,depend,all,install)"; \ cd ${.CURDIR}/${_lib} && \ ${MAKE} MK_TESTS=no DIRPRFX=${_lib}/ obj && \ ${MAKE} MK_TESTS=no DIRPRFX=${_lib}/ depend && \ ${MAKE} MK_TESTS=no DIRPRFX=${_lib}/ all && \ ${MAKE} MK_TESTS=no DIRPRFX=${_lib}/ install .endif .endfor # libpam is special: we need to build static PAM modules before # static PAM library, and dynamic PAM library before dynamic PAM # modules. lib/libpam__L: .PHONY .MAKE ${_+_}@${ECHODIR} "===> lib/libpam (obj,depend,all,install)"; \ cd ${.CURDIR}/lib/libpam && \ ${MAKE} MK_TESTS=no DIRPRFX=lib/libpam/ obj && \ ${MAKE} MK_TESTS=no DIRPRFX=lib/libpam/ depend && \ ${MAKE} MK_TESTS=no DIRPRFX=lib/libpam/ \ -D_NO_LIBPAM_SO_YET all && \ ${MAKE} MK_TESTS=no DIRPRFX=lib/libpam/ \ -D_NO_LIBPAM_SO_YET install _prereq_libs: ${_prereq_libs:S/$/__PL/} _startup_libs: ${_startup_libs:S/$/__L/} _prebuild_libs: ${_prebuild_libs:S/$/__L/} _generic_libs: ${_generic_libs:S/$/__L/} .for __target in all clean cleandepend cleandir depend includes obj .for entry in ${SUBDIR} ${entry}.${__target}__D: .PHONY .MAKE ${_+_}@set -e; if test -d ${.CURDIR}/${entry}.${MACHINE_ARCH}; then \ ${ECHODIR} "===> ${DIRPRFX}${entry}.${MACHINE_ARCH} (${__target})"; \ edir=${entry}.${MACHINE_ARCH}; \ cd ${.CURDIR}/$${edir}; \ else \ ${ECHODIR} "===> ${DIRPRFX}${entry} (${__target})"; \ edir=${entry}; \ cd ${.CURDIR}/$${edir}; \ fi; \ ${MAKE} ${__target} DIRPRFX=${DIRPRFX}$${edir}/ .endfor par-${__target}: ${SUBDIR:S/$/.${__target}__D/} .endfor .include .if make(check-old) || make(check-old-dirs) || \ make(check-old-files) || make(check-old-libs) || \ make(delete-old) || make(delete-old-dirs) || \ make(delete-old-files) || make(delete-old-libs) # # check for / delete old files section # .include "ObsoleteFiles.inc" OLD_LIBS_MESSAGE="Please be sure no application still uses those libraries, \ else you can not start such an application. Consult UPDATING for more \ information regarding how to cope with the removal/revision bump of a \ specific library." .if !defined(BATCH_DELETE_OLD_FILES) RM_I=-i .else RM_I=-v .endif delete-old-files: @echo ">>> Removing old files (only deletes safe to delete libs)" # Ask for every old file if the user really wants to remove it. # It's annoying, but better safe than sorry. # NB: We cannot pass the list of OLD_FILES as a parameter because the # argument list will get too long. Using .for/.endfor make "loops" will make # the Makefile parser segfault. @exec 3<&0; \ cd ${.CURDIR}; \ ${MAKE} -f ${.CURDIR}/Makefile.inc1 ${.MAKEFLAGS} ${.TARGET} \ -V OLD_FILES -V "OLD_FILES:Musr/share/*.gz:R" | xargs -n1 | \ while read file; do \ if [ -f "${DESTDIR}/$${file}" -o -L "${DESTDIR}/$${file}" ]; then \ chflags noschg "${DESTDIR}/$${file}" 2>/dev/null || true; \ rm ${RM_I} "${DESTDIR}/$${file}" <&3; \ fi; \ done # Remove catpages without corresponding manpages. @exec 3<&0; \ find ${DESTDIR}/usr/share/man/cat* ! -type d | \ sed -ep -e's:${DESTDIR}/usr/share/man/cat:${DESTDIR}/usr/share/man/man:' | \ while read catpage; do \ read manpage; \ if [ ! -e "$${manpage}" ]; then \ rm ${RM_I} $${catpage} <&3; \ fi; \ done @echo ">>> Old files removed" check-old-files: @echo ">>> Checking for old files" @cd ${.CURDIR}; \ ${MAKE} -f ${.CURDIR}/Makefile.inc1 ${.MAKEFLAGS} ${.TARGET} \ -V OLD_FILES -V "OLD_FILES:Musr/share/*.gz:R" | xargs -n1 | \ while read file; do \ if [ -f "${DESTDIR}/$${file}" -o -L "${DESTDIR}/$${file}" ]; then \ echo "${DESTDIR}/$${file}"; \ fi; \ done # Check for catpages without corresponding manpages. @find ${DESTDIR}/usr/share/man/cat* ! -type d | \ sed -ep -e's:${DESTDIR}/usr/share/man/cat:${DESTDIR}/usr/share/man/man:' | \ while read catpage; do \ read manpage; \ if [ ! -e "$${manpage}" ]; then \ echo $${catpage}; \ fi; \ done delete-old-libs: @echo ">>> Removing old libraries" @echo "${OLD_LIBS_MESSAGE}" | fmt @exec 3<&0; \ cd ${.CURDIR}; \ ${MAKE} -f ${.CURDIR}/Makefile.inc1 ${.MAKEFLAGS} ${.TARGET} \ -V OLD_LIBS | xargs -n1 | \ while read file; do \ if [ -f "${DESTDIR}/$${file}" -o -L "${DESTDIR}/$${file}" ]; then \ chflags noschg "${DESTDIR}/$${file}" 2>/dev/null || true; \ rm ${RM_I} "${DESTDIR}/$${file}" <&3; \ fi; \ for ext in debug symbols; do \ if ! [ -e "${DESTDIR}/$${file}" ] && [ -f \ "${DESTDIR}${DEBUGDIR}/$${file}.$${ext}" ]; then \ rm ${RM_I} "${DESTDIR}${DEBUGDIR}/$${file}.$${ext}" \ <&3; \ fi; \ done; \ done @echo ">>> Old libraries removed" check-old-libs: @echo ">>> Checking for old libraries" @cd ${.CURDIR}; \ ${MAKE} -f ${.CURDIR}/Makefile.inc1 ${.MAKEFLAGS} ${.TARGET} \ -V OLD_LIBS | xargs -n1 | \ while read file; do \ if [ -f "${DESTDIR}/$${file}" -o -L "${DESTDIR}/$${file}" ]; then \ echo "${DESTDIR}/$${file}"; \ fi; \ for ext in debug symbols; do \ if [ -f "${DESTDIR}${DEBUGDIR}/$${file}.$${ext}" ]; then \ echo "${DESTDIR}${DEBUGDIR}/$${file}.$${ext}"; \ fi; \ done; \ done delete-old-dirs: @echo ">>> Removing old directories" @cd ${.CURDIR}; \ ${MAKE} -f ${.CURDIR}/Makefile.inc1 ${.MAKEFLAGS} ${.TARGET} \ -V OLD_DIRS | xargs -n1 | sort -r | \ while read dir; do \ if [ -d "${DESTDIR}/$${dir}" ]; then \ rmdir -v "${DESTDIR}/$${dir}" || true; \ elif [ -L "${DESTDIR}/$${dir}" ]; then \ echo "${DESTDIR}/$${dir} is a link, please remove everything manually."; \ fi; \ done @echo ">>> Old directories removed" check-old-dirs: @echo ">>> Checking for old directories" @cd ${.CURDIR}; \ ${MAKE} -f ${.CURDIR}/Makefile.inc1 ${.MAKEFLAGS} ${.TARGET} \ -V OLD_DIRS | xargs -n1 | \ while read dir; do \ if [ -d "${DESTDIR}/$${dir}" ]; then \ echo "${DESTDIR}/$${dir}"; \ elif [ -L "${DESTDIR}/$${dir}" ]; then \ echo "${DESTDIR}/$${dir} is a link, please remove everything manually."; \ fi; \ done delete-old: delete-old-files delete-old-dirs @echo "To remove old libraries run '${MAKE} delete-old-libs'." check-old: check-old-files check-old-libs check-old-dirs @echo "To remove old files and directories run '${MAKE} delete-old'." @echo "To remove old libraries run '${MAKE} delete-old-libs'." .endif # # showconfig - show build configuration. # showconfig: @(${MAKE} -n -f ${.CURDIR}/sys/conf/kern.opts.mk -V dummy -dg1; \ ${MAKE} -n -f ${.CURDIR}/share/mk/src.opts.mk -V dummy -dg1) 2>&1 | grep ^MK_ | sort -u .if !empty(KRNLOBJDIR) && !empty(KERNCONF) DTBOUTPUTPATH= ${KRNLOBJDIR}/${KERNCONF}/ .if !defined(FDT_DTS_FILE) || empty(FDT_DTS_FILE) .if exists(${KERNCONFDIR}/${KERNCONF}) FDT_DTS_FILE!= awk 'BEGIN {FS="="} /^makeoptions[[:space:]]+FDT_DTS_FILE/ {print $$2}' \ '${KERNCONFDIR}/${KERNCONF}' ; echo .endif .endif .endif .if !defined(DTBOUTPUTPATH) || !exists(${DTBOUTPUTPATH}) DTBOUTPUTPATH= ${.CURDIR} .endif # # Build 'standalone' Device Tree Blob # builddtb: @PATH=${TMPPATH} MACHINE=${TARGET} \ ${.CURDIR}/sys/tools/fdt/make_dtb.sh ${.CURDIR}/sys \ "${FDT_DTS_FILE}" ${DTBOUTPUTPATH} ############### .if defined(TARGET) && defined(TARGET_ARCH) .if ${TARGET} == ${MACHINE} && ${TARGET_ARCH} == ${MACHINE_ARCH} XDEV_CPUTYPE?=${CPUTYPE} .else XDEV_CPUTYPE?=${TARGET_CPUTYPE} .endif NOFUN=-DNO_FSCHG MK_HTML=no -DNO_LINT \ MK_MAN=no MK_NLS=no MK_PROFILE=no \ MK_KERBEROS=no MK_RESCUE=no MK_TESTS=no MK_WARNS=no \ TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ CPUTYPE=${XDEV_CPUTYPE} XDDIR=${TARGET_ARCH}-freebsd XDTP?=/usr/${XDDIR} .if ${XDTP:N/*} .error XDTP variable should be an absolute path .endif CDBENV=MAKEOBJDIRPREFIX=${MAKEOBJDIRPREFIX}/${XDDIR} \ INSTALL="sh ${.CURDIR}/tools/install.sh" CDENV= ${CDBENV} \ TOOLS_PREFIX=${XDTP} CD2CFLAGS=-isystem ${XDDESTDIR}/usr/include -L${XDDESTDIR}/usr/lib \ --sysroot=${XDDESTDIR}/ -B${XDDESTDIR}/usr/libexec \ -B${XDDESTDIR}/usr/bin -B${XDDESTDIR}/usr/lib CD2ENV=${CDENV} CC="${CC} ${CD2CFLAGS}" CXX="${CXX} ${CD2CFLAGS}" \ CPP="${CPP} ${CD2CFLAGS}" \ MACHINE=${TARGET} MACHINE_ARCH=${TARGET_ARCH} CDTMP= ${MAKEOBJDIRPREFIX}/${XDDIR}/${.CURDIR}/tmp CDMAKE=${CDENV} PATH=${CDTMP}/usr/bin:${PATH} ${MAKE} ${NOFUN} CD2MAKE=${CD2ENV} PATH=${CDTMP}/usr/bin:${XDDESTDIR}/usr/bin:${PATH} ${MAKE} ${NOFUN} XDDESTDIR=${DESTDIR}/${XDTP} .if !defined(OSREL) OSREL!= uname -r | sed -e 's/[-(].*//' .endif .ORDER: xdev-build xdev-install xdev-links xdev: xdev-build xdev-install .ORDER: _xb-worldtmp _xb-bootstrap-tools _xb-build-tools _xb-cross-tools xdev-build: _xb-worldtmp _xb-bootstrap-tools _xb-build-tools _xb-cross-tools _xb-worldtmp: mkdir -p ${CDTMP}/usr mtree -deU -f ${.CURDIR}/etc/mtree/BSD.usr.dist \ -p ${CDTMP}/usr >/dev/null _xb-bootstrap-tools: .for _tool in \ ${_clang_tblgen} \ ${_gperf} ${_+_}@${ECHODIR} "===> ${_tool} (obj,depend,all,install)"; \ cd ${.CURDIR}/${_tool} && \ ${CDMAKE} DIRPRFX=${_tool}/ obj && \ ${CDMAKE} DIRPRFX=${_tool}/ depend && \ ${CDMAKE} DIRPRFX=${_tool}/ all && \ ${CDMAKE} DIRPRFX=${_tool}/ DESTDIR=${CDTMP} install .endfor _xb-build-tools: ${_+_}@cd ${.CURDIR}; \ ${CDBENV} ${MAKE} -f Makefile.inc1 ${NOFUN} build-tools _xb-cross-tools: .for _tool in \ ${_binutils} \ ${_elftctools} \ usr.bin/ar \ ${_clang_libs} \ ${_clang} \ ${_cc} ${_+_}@${ECHODIR} "===> xdev ${_tool} (obj,depend,all)"; \ cd ${.CURDIR}/${_tool} && \ ${CDMAKE} DIRPRFX=${_tool}/ obj && \ ${CDMAKE} DIRPRFX=${_tool}/ depend && \ ${CDMAKE} DIRPRFX=${_tool}/ all .endfor _xi-mtree: ${_+_}@${ECHODIR} "mtree populating ${XDDESTDIR}" mkdir -p ${XDDESTDIR} mtree -deU -f ${.CURDIR}/etc/mtree/BSD.root.dist \ -p ${XDDESTDIR} >/dev/null mtree -deU -f ${.CURDIR}/etc/mtree/BSD.usr.dist \ -p ${XDDESTDIR}/usr >/dev/null mtree -deU -f ${.CURDIR}/etc/mtree/BSD.include.dist \ -p ${XDDESTDIR}/usr/include >/dev/null .if ${MK_TESTS} != "no" mkdir -p ${XDDESTDIR}${TESTSBASE} mtree -deU -f ${.CURDIR}/etc/mtree/BSD.tests.dist \ -p ${XDDESTDIR}${TESTSBASE} >/dev/null .endif .ORDER: xdev-build _xi-mtree _xi-cross-tools _xi-includes _xi-libraries xdev-install: xdev-build _xi-mtree _xi-cross-tools _xi-includes _xi-libraries _xi-cross-tools: @echo "_xi-cross-tools" .for _tool in \ ${_binutils} \ ${_elftctools} \ usr.bin/ar \ ${_clang_libs} \ ${_clang} \ ${_cc} ${_+_}@${ECHODIR} "===> xdev ${_tool} (install)"; \ cd ${.CURDIR}/${_tool}; \ ${CDMAKE} DIRPRFX=${_tool}/ install DESTDIR=${XDDESTDIR} .endfor _xi-includes: ${_+_}cd ${.CURDIR}; ${CD2MAKE} -f Makefile.inc1 par-includes \ DESTDIR=${XDDESTDIR} _xi-libraries: ${_+_}cd ${.CURDIR}; ${CD2MAKE} -f Makefile.inc1 libraries \ DESTDIR=${XDDESTDIR} xdev-links: ${_+_}cd ${XDDESTDIR}/usr/bin; \ mkdir -p ../../../../usr/bin; \ for i in *; do \ ln -sf ../../${XDTP}/usr/bin/$$i \ ../../../../usr/bin/${XDDIR}-$$i; \ ln -sf ../../${XDTP}/usr/bin/$$i \ ../../../../usr/bin/${XDDIR}${OSREL}-$$i; \ done .else xdev xdev-build xdev-install xdev-links: @echo "*** Error: Both TARGET and TARGET_ARCH must be defined for \"${.TARGET}\" target" .endif Index: projects/release-pkg/bin/ls/tests/ls_tests.sh =================================================================== --- projects/release-pkg/bin/ls/tests/ls_tests.sh (revision 289118) +++ projects/release-pkg/bin/ls/tests/ls_tests.sh (revision 289119) @@ -1,974 +1,964 @@ # # Copyright 2015 EMC Corp. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # $FreeBSD$ # create_test_dir() { [ -z "$ATF_TMPDIR" ] || return 0 export ATF_TMPDIR=$(pwd) # XXX: need to nest this because of how kyua creates $TMPDIR; otherwise # it will run into EPERM issues later TEST_INPUTS_DIR="${ATF_TMPDIR}/test/inputs" atf_check -e empty -s exit:0 mkdir -m 0777 -p $TEST_INPUTS_DIR cd $TEST_INPUTS_DIR } create_test_inputs() { create_test_dir atf_check -e empty -s exit:0 mkdir -m 0755 -p a/b/1 atf_check -e empty -s exit:0 ln -s a/b c atf_check -e empty -s exit:0 touch d atf_check -e empty -s exit:0 ln d e atf_check -e empty -s exit:0 touch .f atf_check -e empty -s exit:0 mkdir .g atf_check -e empty -s exit:0 mkfifo h atf_check -e ignore -s exit:0 dd if=/dev/zero of=i count=1000 bs=1 atf_check -e empty -s exit:0 touch klmn atf_check -e empty -s exit:0 touch opqr atf_check -e empty -s exit:0 touch stuv atf_check -e empty -s exit:0 install -m 0755 /dev/null wxyz atf_check -e empty -s exit:0 touch 0b00000001 atf_check -e empty -s exit:0 touch 0b00000010 atf_check -e empty -s exit:0 touch 0b00000011 atf_check -e empty -s exit:0 touch 0b00000100 atf_check -e empty -s exit:0 touch 0b00000101 atf_check -e empty -s exit:0 touch 0b00000110 atf_check -e empty -s exit:0 touch 0b00000111 atf_check -e empty -s exit:0 touch 0b00001000 atf_check -e empty -s exit:0 touch 0b00001001 atf_check -e empty -s exit:0 touch 0b00001010 atf_check -e empty -s exit:0 touch 0b00001011 atf_check -e empty -s exit:0 touch 0b00001100 atf_check -e empty -s exit:0 touch 0b00001101 atf_check -e empty -s exit:0 touch 0b00001110 atf_check -e empty -s exit:0 touch 0b00001111 - - atf_check -e empty -s exit:0 sync } KB=1024 MB=$(( 1024 * $KB )) GB=$(( 1024 * $MB )) TB=$(( 1024 * $GB )) PB=$(( 1024 * $TB )) create_test_inputs2() { create_test_dir for filesize in 1 512 $(( 2 * $KB )) $(( 10 * $KB )) $(( 512 * $KB )); \ do atf_check -e ignore -o empty -s exit:0 \ dd if=/dev/zero of=${filesize}.file bs=1 \ count=1 oseek=${filesize} conv=sparse files="${files} ${filesize}.file" done for filesize in $MB $GB $TB; do atf_check -e ignore -o empty -s exit:0 \ dd if=/dev/zero of=${filesize}.file bs=$MB \ count=1 oseek=$(( $filesize / $MB )) conv=sparse files="${files} ${filesize}.file" done - - atf_check -e empty -s exit:0 sync } atf_test_case A_flag A_flag_head() { atf_set "descr" "Verify -A support with unprivileged users" } A_flag_body() { create_test_dir atf_check -e empty -o empty -s exit:0 ls -A create_test_inputs WITH_A=$PWD/../with_A.out WITHOUT_A=$PWD/../without_A.out atf_check -e empty -o save:$WITH_A -s exit:0 ls -A atf_check -e empty -o save:$WITHOUT_A -s exit:0 ls echo "-A usage" cat $WITH_A echo "No -A usage" cat $WITHOUT_A for dot_path in '\.f' '\.g'; do atf_check -e empty -o not-empty -s exit:0 grep "${dot_path}" \ $WITH_A atf_check -e empty -o empty -s not-exit:0 grep "${dot_path}" \ $WITHOUT_A done } atf_test_case A_flag_implied_when_root A_flag_implied_when_root_head() { atf_set "descr" "Verify that -A is implied for root" atf_set "require.user" "root" } A_flag_implied_when_root_body() { create_test_dir atf_check -e empty -o empty -s exit:0 ls -A create_test_inputs WITH_EXPLICIT=$PWD/../with_explicit_A.out WITH_IMPLIED=$PWD/../with_implied_A.out atf_check -e empty -o save:$WITH_EXPLICIT -s exit:0 ls -A atf_check -e empty -o save:$WITH_IMPLIED -s exit:0 ls echo "Explicit -A usage" cat $WITH_EXPLICIT echo "Implicit -A usage" cat $WITH_IMPLIED atf_check_equal "$(cat $WITH_EXPLICIT)" "$(cat $WITH_IMPLIED)" } atf_test_case B_flag B_flag_head() { atf_set "descr" "Verify that the output from ls -B prints out non-printable characters" } B_flag_body() { atf_skip "kyua report-jenkins doesn't properly escape non-printable chars: https://github.com/jmmv/kyua/issues/136" atf_check -e empty -o empty -s exit:0 touch "$(printf "y\013z")" atf_check -e empty -o match:'y\\013z' -s exit:0 ls -B } atf_test_case C_flag C_flag_head() { atf_set "descr" "Verify that the output from ls -C is multi-column, sorted down" } print_index() { local i=1 local wanted_index=$1; shift while [ $i -le $wanted_index ]; do if [ $i -eq $wanted_index ]; then echo $1 return fi shift : $(( i += 1 )) done } C_flag_body() { create_test_inputs WITH_C=$PWD/../with_C.out export COLUMNS=40 atf_check -e empty -o save:$WITH_C -s exit:0 ls -C echo "With -C usage" cat $WITH_C paths=$(find -s . -mindepth 1 -maxdepth 1 \! -name '.*' -exec basename {} \; ) set -- $paths num_paths=$# num_columns=2 max_num_paths_per_column=$(( $(( $num_paths + 1 )) / $num_columns )) local i=1 while [ $i -le $max_num_paths_per_column ]; do column_1=$(print_index $i $paths) column_2=$(print_index $(( $i + $max_num_paths_per_column )) $paths) #echo "paths[$(( $i + $max_num_paths_per_column ))] = $column_2" expected_expr="$column_1" if [ -n "$column_2" ]; then expected_expr="$expected_expr[[:space:]]+$column_2" fi atf_check -e ignore -o not-empty -s exit:0 \ egrep "$expected_expr" $WITH_C : $(( i += 1 )) done } atf_test_case D_flag D_flag_head() { atf_set "descr" "Verify that the output from ls -D modifies the time format used with ls -l" } D_flag_body() { atf_check -e empty -o empty -s exit:0 touch a.file atf_check -e empty -o match:"$(stat -f '%c[[:space:]]+%N' a.file)" \ -s exit:0 ls -lD '%s' } atf_test_case F_flag F_flag_head() { atf_set "descr" "Verify that the output from ls -F prints out appropriate symbols after files" } F_flag_body() { create_test_inputs atf_check -e empty -s exit:0 \ sh -c "pid=${ATF_TMPDIR}/nc.pid; daemon -p \$pid nc -lU j; sleep 2; pkill -F \$pid" atf_check -e empty -o match:'a/' -s exit:0 ls -F atf_check -e empty -o match:'c@' -s exit:0 ls -F atf_check -e empty -o match:'h\|' -s exit:0 ls -F atf_check -e empty -o match:'j=' -s exit:0 ls -F #atf_check -e empty -o match:'%' -s exit:0 ls -F atf_check -e empty -o match:'stuv' -s exit:0 ls -F atf_check -e empty -o match:'wxyz\*' -s exit:0 ls -F } atf_test_case H_flag H_flag_head() { atf_set "descr" "Verify that ls -H follows symlinks" } H_flag_body() { create_test_inputs atf_check -e empty -o match:'1' -s exit:0 ls -H c } atf_test_case I_flag I_flag_head() { atf_set "descr" "Verify that the output from ls -I is the same as ls for an unprivileged user" } I_flag_body() { create_test_inputs WITH_I=$PWD/../with_I.out WITHOUT_I=$PWD/../without_I.out atf_check -e empty -o save:$WITH_I -s exit:0 ls -I atf_check -e empty -o save:$WITHOUT_I -s exit:0 ls echo "Explicit -I usage" cat $WITH_I echo "No -I usage" cat $WITHOUT_I atf_check_equal "$(cat $WITH_I)" "$(cat $WITHOUT_I)" } atf_test_case I_flag_voids_implied_A_flag_when_root I_flag_voids_implied_A_flag_when_root_head() { atf_set "descr" "Verify that -I voids out implied -A for root" atf_set "require.user" "root" } I_flag_voids_implied_A_flag_when_root_body() { create_test_inputs atf_check -o not-match:'\.f' -s exit:0 ls -I atf_check -o not-match:'\.g' -s exit:0 ls -I atf_check -o match:'\.f' -s exit:0 ls -A -I atf_check -o match:'\.g' -s exit:0 ls -A -I } atf_test_case L_flag L_flag_head() { atf_set "descr" "Verify that -L prints out the symbolic link and conversely -P prints out the target for the symbolic link" } L_flag_body() { atf_check -e empty -o empty -s exit:0 ln -s target1/target2 link1 atf_check -e empty -o match:link1 -s exit:0 ls -L atf_check -e empty -o not-match:target1/target2 -s exit:0 ls -L } atf_test_case R_flag R_flag_head() { atf_set "descr" "Verify that the output from ls -R prints out the directory contents recursively" } R_flag_body() { create_test_inputs WITH_R=$PWD/../with_R.out WITH_R_expected_output=$PWD/../with_R_expected.out atf_check -e empty -o save:$WITH_R -s exit:0 ls -R set -- . $(find -s . \! -name '.*' -type d) while [ $# -gt 0 ]; do dir=$1; shift [ "$dir" != "." ] && echo "$dir:" (cd $dir && ls -1A | sed -e '/^\./d') [ $# -ne 0 ] && echo done > $WITH_R_expected_output echo "-R usage" cat $WITH_R echo "-R expected output" cat $WITH_R_expected_output atf_check_equal "$(cat $WITH_R)" "$(cat $WITH_R_expected_output)" } atf_test_case S_flag S_flag_head() { atf_set "descr" "Verify that -S sorts by file size, then by filename lexicographically" } S_flag_body() { create_test_dir file_list_dir=$PWD/../files atf_check -e empty -o empty -s exit:0 mkdir -p $file_list_dir create_test_inputs create_test_inputs2 WITH_S=$PWD/../with_S.out WITHOUT_S=$PWD/../without_S.out atf_check -e empty -o save:$WITH_S ls -D '%s' -lS atf_check -e empty -o save:$WITHOUT_S ls -D '%s' -l WITH_S_parsed=$(awk '! /^total/ { print $7 }' $WITH_S) set -- $(awk '! /^total/ { print $5, $7 }' $WITHOUT_S) while [ $# -gt 0 ]; do size=$1; shift filename=$1; shift echo $filename >> $file_list_dir/${size} done file_lists=$(find $file_list_dir -type f -exec basename {} \; | sort -nr) WITHOUT_S_parsed=$(for file_list in $file_lists; do sort < $file_list_dir/$file_list; done) echo "-lS usage (parsed)" echo "$WITH_S_parsed" echo "-l usage (parsed)" echo "$WITHOUT_S_parsed" atf_check_equal "$WITHOUT_S_parsed" "$WITH_S_parsed" } atf_test_case T_flag T_flag_head() { atf_set "descr" "Verify -T support" } T_flag_body() { create_test_dir atf_check -e empty -o empty -s exit:0 touch a.file birthtime_in_secs=$(stat -f %B -t %s a.file) birthtime=$(date -j -f %s $birthtime_in_secs +"[[:space:]]+%b[[:space:]]+%e[[:space:]]+%H:%M:%S[[:space:]]+%Y") atf_check -e empty -o match:"$birthtime"'[[:space:]]+a\.file' \ -s exit:0 ls -lT a.file } atf_test_case a_flag a_flag_head() { atf_set "descr" "Verify -a support" } a_flag_body() { create_test_dir # Make sure "." and ".." show up with -a atf_check -e empty -o match:'\.[[:space:]]+\.\.' -s exit:0 ls -ax create_test_inputs WITH_a=$PWD/../with_a.out WITHOUT_a=$PWD/../without_a.out atf_check -e empty -o save:$WITH_a -s exit:0 ls -a atf_check -e empty -o save:$WITHOUT_a -s exit:0 ls echo "-a usage" cat $WITH_a echo "No -a usage" cat $WITHOUT_a for dot_path in '\.f' '\.g'; do atf_check -e empty -o not-empty -s exit:0 grep "${dot_path}" \ $WITH_a atf_check -e empty -o empty -s not-exit:0 grep "${dot_path}" \ $WITHOUT_a done } atf_test_case b_flag b_flag_head() { atf_set "descr" "Verify that the output from ls -b prints out non-printable characters" } b_flag_body() { atf_skip "kyua report-jenkins doesn't properly escape non-printable chars: https://github.com/jmmv/kyua/issues/136" atf_check -e empty -o empty -s exit:0 touch "$(printf "y\013z")" atf_check -e empty -o match:'y\\vz' -s exit:0 ls -b } atf_test_case d_flag d_flag_head() { atf_set "descr" "Verify that -d doesn't descend down directories" } d_flag_body() { create_test_dir output=$PWD/../output atf_check -e empty -o empty -s exit:0 mkdir -p a/b for path in . $PWD a; do atf_check -e empty -o save:$output -s exit:0 ls -d $path atf_check_equal "$(cat $output)" "$path" done } atf_test_case f_flag f_flag_head() { atf_set "descr" "Verify that -f prints out the contents of a directory unsorted" } f_flag_body() { create_test_inputs output=$PWD/../output # XXX: I don't have enough understanding of how the algorithm works yet # to determine more than the fact that all the entries printed out # exist paths=$(find -s . -mindepth 1 -maxdepth 1 \! -name '.*' -exec basename {} \; ) atf_check -e empty -o save:$output -s exit:0 ls -f for path in $paths; do atf_check -e ignore -o not-empty -s exit:0 \ egrep "^$path$" $output done } atf_test_case g_flag g_flag_head() { atf_set "descr" "Verify that -g does nothing (compatibility flag)" } g_flag_body() { create_test_inputs2 for file in $files; do atf_check -e empty -o match:"$(ls -a $file)" -s exit:0 \ ls -ag $file atf_check -e empty -o match:"$(ls -la $file)" -s exit:0 \ ls -alg $file done } atf_test_case h_flag h_flag_head() { atf_set "descr" "Verify that -h prints out the humanized units for file sizes with ls -l" atf_set "require.files" "/usr/bin/bc" } h_flag_body() { # XXX: this test doesn't currently show how 999 bytes will be 999B, # but 1000 bytes will be 1.0K, due to how humanize_number(3) works. create_test_inputs2 for file in $files; do file_size=$(stat -f '%z' "$file") || \ atf_fail "stat'ing $file failed" scale=2 if [ $file_size -lt $KB ]; then divisor=1 scale=0 suffix=B elif [ $file_size -lt $MB ]; then divisor=$KB suffix=K elif [ $file_size -lt $GB ]; then divisor=$MB suffix=M elif [ $file_size -lt $TB ]; then divisor=$GB suffix=G elif [ $file_size -lt $PB ]; then divisor=$TB suffix=T else divisor=$PB suffix=P fi bc_expr="$(printf "scale=%s\n%s/%s\nquit" $scale $file_size $divisor)" size_humanized=$(bc -e "$bc_expr" | tr '.' '\.' | sed -e 's,\.00,,') atf_check -e empty -o match:"$size_humanized.+$file" \ -s exit:0 ls -hl $file done } atf_test_case i_flag i_flag_head() { atf_set "descr" "Verify that -i prints out the inode for files" } i_flag_body() { create_test_inputs paths=$(find -L . -mindepth 1) [ -n "$paths" ] || atf_skip 'Could not find any paths to iterate over (!)' for path in $paths; do atf_check -e empty \ -o match:"$(stat -f '[[:space:]]*%i[[:space:]]+%N' $path)" \ -s exit:0 ls -d1i $path done } atf_test_case k_flag k_flag_head() { atf_set "descr" "Verify that -k prints out the size with a block size of 1kB" } k_flag_body() { create_test_inputs2 for file in $files; do atf_check -e empty \ -o match:"[[:space:]]+$(stat -f "%z" $file)[[:space:]]+.+[[:space:]]+$file" ls -lk $file done } atf_test_case l_flag l_flag_head() { atf_set "descr" "Verify that -l prints out the output in long format" } l_flag_body() { atf_check -e empty -o empty -s exit:0 touch a.file birthtime_in_secs=$(stat -f "%B" -t "%s" a.file) birthtime=$(date -j -f "%s" $birthtime_in_secs +"%b[[:space:]]+%e[[:space:]]+%H:%M") expected_output=$(stat -f "%Sp[[:space:]]+%l[[:space:]]+%Su[[:space:]]+%Sg[[:space:]]+%z[[:space:]]+$birthtime[[:space:]]+a\\.file" a.file) atf_check -e empty -o match:"$expected_output" -s exit:0 ls -l a.file } atf_test_case lcomma_flag lcomma_flag_head() { atf_set "descr" "Verify that -l, prints out the size with ',' delimiters" } lcomma_flag_body() { create_test_inputs atf_check \ -o match:'\-rw\-r\-\-r\-\-[[:space:]]+.+[[:space:]]+1,000[[:space:]]+.+i' \ env LC_ALL=en_US.ISO8859-1 ls -l, i } atf_test_case m_flag m_flag_head() { atf_set "descr" "Verify that the output from ls -m is comma-separated" } m_flag_body() { create_test_dir output=$PWD/../output atf_check -e empty -o empty -s exit:0 touch ,, "a,b " c d e atf_check -e empty -o save:$output -s exit:0 ls -m atf_check_equal "$(cat $output)" ",,, a,b , c, d, e" } atf_test_case n_flag n_flag_head() { atf_set "descr" "Verify that the output from ls -n prints out numeric GIDs/UIDs instead of symbolic GIDs/UIDs" atf_set "require.user" "root" } n_flag_body() { daemon_gid=$(id -g daemon) || atf_skip "could not resolve gid for daemon (!)" nobody_uid=$(id -u nobody) || atf_skip "could not resolve uid for nobody (!)" atf_check -e empty -o empty -s exit:0 touch a.file atf_check -e empty -o empty -s exit:0 chown $nobody_uid:$daemon_gid a.file atf_check -e empty \ -o match:'\-rw\-r\-\-r\-\-[[:space:]]+1[[:space:]]+'"$nobody_uid[[:space:]]+$daemon_gid"'[[:space:]]+.+a\.file' \ ls -ln a.file } atf_test_case o_flag o_flag_head() { atf_set "descr" "Verify that the output from ls -o prints out the chflag values or '-' if none are set" atf_set "require.user" "root" } o_flag_body() { local size=12345 create_test_dir atf_check -e ignore -o empty -s exit:0 dd if=/dev/zero of=a.file \ bs=$size count=1 atf_check -e ignore -o empty -s exit:0 dd if=/dev/zero of=b.file \ bs=$size count=1 atf_check -e empty -o empty -s exit:0 chflags uarch a.file atf_check -e empty -o match:"[[:space:]]+uarch[[:space:]]$size+.+a\\.file" \ -s exit:0 ls -lo a.file atf_check -e empty -o match:"[[:space:]]+\\-[[:space:]]$size+.+b\\.file" \ -s exit:0 ls -lo b.file } atf_test_case p_flag p_flag_head() { atf_set "descr" "Verify that the output from ls -p prints out '/' after directories" } p_flag_body() { create_test_inputs paths=$(find -L .) [ -n "$paths" ] || atf_skip 'Could not find any paths to iterate over (!)' for path in $paths; do suffix= # If path is not a symlink and is a directory, then the suffix # must be "/". if [ ! -L "${path}" -a -d "$path" ]; then suffix=/ fi atf_check -e empty -o match:"$path${suffix}" -s exit:0 \ ls -dp $path done } atf_test_case q_flag_and_w_flag q_flag_and_w_flag_head() { atf_set "descr" "Verify that the output from ls -q prints out '?' for ESC and ls -w prints out the escape character" } q_flag_and_w_flag_body() { atf_skip "kyua report-jenkins doesn't properly escape non-printable chars: https://github.com/jmmv/kyua/issues/136" create_test_dir test_file="$(printf "y\01z")" atf_check -e empty -o empty -s exit:0 touch "$test_file" atf_check -e empty -o match:'y\?z' -s exit:0 ls -q "$test_file" atf_check -e empty -o match:"$test_file" -s exit:0 ls -w "$test_file" } atf_test_case r_flag r_flag_head() { atf_set "descr" "Verify that the output from ls -r sorts the same way as reverse sorting with sort(1)" } r_flag_body() { create_test_inputs WITH_r=$PWD/../with_r.out WITH_sort=$PWD/../with_sort.out atf_check -e empty -o save:$WITH_r -s exit:0 ls -1r atf_check -e empty -o save:$WITH_sort -s exit:0 sh -c 'ls -1 | sort -r' echo "Sorted with -r" cat $WITH_r echo "Reverse sorted with sort(1)" cat $WITH_sort atf_check_equal "$(cat $WITH_r)" "$(cat $WITH_sort)" } atf_test_case s_flag s_flag_head() { atf_set "descr" "Verify that the output from ls -s matches the output from stat(1)" } s_flag_body() { create_test_inputs2 for file in $files; do atf_check -e empty \ -o match:"$(stat -f "%b" $file)[[:space:]]+$file" ls -s $file done } atf_test_case t_flag t_flag_head() { atf_set "descr" "Verify that the output from ls -t sorts by modification time" } t_flag_body() { create_test_dir atf_check -e empty -o empty -s exit:0 touch a.file atf_check -e empty -o empty -s exit:0 touch b.file - atf_check -e empty -s exit:0 sync - atf_check -e empty -o match:'a\.file' -s exit:0 sh -c 'ls -lt | tail -n 1' atf_check -e empty -o match:'b\.file.*a\.file' -s exit:0 ls -Ct atf_check -e empty -o empty -s exit:0 rm a.file atf_check -e empty -o empty -s exit:0 sh -c 'echo "i am a" > a.file' - atf_check -e empty -s exit:0 sync - atf_check -e empty -o match:'b\.file' -s exit:0 sh -c 'ls -lt | tail -n 1' atf_check -e empty -o match:'a\.file.*b\.file' -s exit:0 ls -Ct } atf_test_case u_flag u_flag_head() { atf_set "descr" "Verify that the output from ls -u sorts by last access" } u_flag_body() { create_test_dir atf_check -e empty -o empty -s exit:0 touch a.file atf_check -e empty -o empty -s exit:0 touch b.file - atf_check -e empty -s exit:0 sync atf_check -e empty -o match:'b\.file' -s exit:0 sh -c 'ls -lu | tail -n 1' atf_check -e empty -o match:'a\.file.*b\.file' -s exit:0 ls -Cu atf_check -e empty -o empty -s exit:0 sh -c 'echo "i am a" > a.file' atf_check -e empty -o match:'i am a' -s exit:0 cat a.file - atf_check -e empty -s exit:0 sync atf_check -e empty -o match:'b\.file' -s exit:0 sh -c 'ls -lu | tail -n 1' atf_check -e empty -o match:'a\.file.*b\.file' -s exit:0 ls -Cu } atf_test_case x_flag x_flag_head() { atf_set "descr" "Verify that the output from ls -x is multi-column, sorted across" } x_flag_body() { create_test_inputs WITH_x=$PWD/../with_x.out atf_check -e empty -o save:$WITH_x -s exit:0 ls -x echo "With -x usage" cat $WITH_x atf_check -e ignore -o not-empty -s exit:0 \ egrep "a[[:space:]]+c[[:space:]]+d[[:space:]]+e[[:space:]]+h" $WITH_x atf_check -e ignore -o not-empty -s exit:0 \ egrep "i[[:space:]]+klmn[[:space:]]+opqr[[:space:]]+stuv[[:space:]]+wxyz" $WITH_x } atf_test_case y_flag y_flag_head() { atf_set "descr" "Verify that the output from ls -y sorts the same way as sort(1)" } y_flag_body() { create_test_inputs WITH_sort=$PWD/../with_sort.out WITH_y=$PWD/../with_y.out atf_check -e empty -o save:$WITH_sort -s exit:0 sh -c 'ls -1 | sort' atf_check -e empty -o save:$WITH_y -s exit:0 ls -1y echo "Sorted with sort(1)" cat $WITH_sort echo "Sorted with -y" cat $WITH_y atf_check_equal "$(cat $WITH_sort)" "$(cat $WITH_y)" } atf_test_case 1_flag 1_flag_head() { atf_set "descr" "Verify that -1 prints out one item per line" } 1_flag_body() { create_test_inputs WITH_1=$PWD/../with_1.out WITHOUT_1=$PWD/../without_1.out atf_check -e empty -o save:$WITH_1 -s exit:0 ls -1 atf_check -e empty -o save:$WITHOUT_1 -s exit:0 \ sh -c 'for i in $(ls); do echo $i; done' echo "Explicit -1 usage" cat $WITH_1 echo "No -1 usage" cat $WITHOUT_1 atf_check_equal "$(cat $WITH_1)" "$(cat $WITHOUT_1)" } atf_init_test_cases() { export BLOCKSIZE=512 atf_add_test_case A_flag atf_add_test_case A_flag_implied_when_root atf_add_test_case B_flag atf_add_test_case C_flag atf_add_test_case D_flag atf_add_test_case F_flag #atf_add_test_case G_flag atf_add_test_case H_flag atf_add_test_case I_flag atf_add_test_case I_flag_voids_implied_A_flag_when_root atf_add_test_case L_flag #atf_add_test_case P_flag atf_add_test_case R_flag atf_add_test_case S_flag atf_add_test_case T_flag #atf_add_test_case U_flag #atf_add_test_case W_flag #atf_add_test_case Z_flag atf_add_test_case a_flag atf_add_test_case b_flag #atf_add_test_case c_flag atf_add_test_case d_flag atf_add_test_case f_flag atf_add_test_case g_flag atf_add_test_case h_flag atf_add_test_case i_flag atf_add_test_case k_flag atf_add_test_case l_flag atf_add_test_case lcomma_flag atf_add_test_case m_flag atf_add_test_case n_flag atf_add_test_case o_flag atf_add_test_case p_flag atf_add_test_case q_flag_and_w_flag atf_add_test_case r_flag atf_add_test_case s_flag atf_add_test_case t_flag atf_add_test_case u_flag atf_add_test_case x_flag atf_add_test_case y_flag atf_add_test_case 1_flag } Index: projects/release-pkg/etc/ppp/ppp.conf =================================================================== --- projects/release-pkg/etc/ppp/ppp.conf (revision 289118) +++ projects/release-pkg/etc/ppp/ppp.conf (nonexistent) @@ -1,37 +0,0 @@ -################################################################# -# PPP Sample Configuration File -# Originally written by Toshiharu OHNO -# Simplified 5/14/1999 by wself@cdrom.com -# -# See /usr/share/examples/ppp/ for some examples -# -# $FreeBSD$ -################################################################# - -default: - set log Phase Chat LCP IPCP CCP tun command - ident user-ppp VERSION - - # Ensure that "device" references the correct serial port - # for your modem. (cuau0 = COM1, cuau1 = COM2) - # - set device /dev/cuau1 - - set speed 115200 - set dial "ABORT BUSY ABORT NO\\sCARRIER TIMEOUT 5 \ - \"\" AT OK-AT-OK ATE1Q0 OK \\dATDT\\T TIMEOUT 40 CONNECT" - set timeout 180 # 3 minute idle timer (the default) - enable dns # request DNS info (for resolv.conf) - -papchap: - # - # edit the next three lines and replace the items in caps with - # the values which have been assigned by your ISP. - # - - set phone PHONE_NUM - set authname USERNAME - set authkey PASSWORD - - set ifaddr 10.0.0.1/0 10.0.0.2/0 255.255.255.0 0.0.0.0 - add default HISADDR # Add a (sticky) default route Property changes on: projects/release-pkg/etc/ppp/ppp.conf ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/release-pkg/etc/Makefile =================================================================== --- projects/release-pkg/etc/Makefile (revision 289118) +++ projects/release-pkg/etc/Makefile (revision 289119) @@ -1,429 +1,425 @@ # from: @(#)Makefile 5.11 (Berkeley) 5/21/91 # $FreeBSD$ .include SUBDIR= \ newsyslog.conf.d .if ${MK_SENDMAIL} != "no" SUBDIR+=sendmail .endif BIN1= crontab \ devd.conf \ devfs.conf \ ddb.conf \ dhclient.conf \ disktab \ fbtab \ gettytab \ group \ hosts \ hosts.allow \ hosts.equiv \ libalias.conf \ libmap.conf \ login.access \ login.conf \ mac.conf \ motd \ netconfig \ network.subr \ networks \ newsyslog.conf \ nsswitch.conf \ phones \ profile \ protocols \ rc \ rc.bsdextended \ rc.firewall \ rc.initdiskless \ rc.shutdown \ rc.subr \ remote \ rpc \ services \ shells \ sysctl.conf \ syslog.conf \ termcap.small .if exists(${.CURDIR}/etc.${MACHINE}/ttys) BIN1+= etc.${MACHINE}/ttys .elif exists(${.CURDIR}/etc.${MACHINE_ARCH}/ttys) BIN1+= etc.${MACHINE_ARCH}/ttys .elif exists(${.CURDIR}/etc.${MACHINE_CPUARCH}/ttys) BIN1+= etc.${MACHINE_CPUARCH}/ttys .else .error etc.MACHINE/ttys missing .endif OPENBSMDIR= ${.CURDIR}/../contrib/openbsm BSM_ETC_OPEN_FILES= ${OPENBSMDIR}/etc/audit_class \ ${OPENBSMDIR}/etc/audit_event BSM_ETC_RESTRICTED_FILES= ${OPENBSMDIR}/etc/audit_control \ ${OPENBSMDIR}/etc/audit_user BSM_ETC_EXEC_FILES= ${OPENBSMDIR}/etc/audit_warn BSM_ETC_DIR= ${DESTDIR}/etc/security # NB: keep these sorted by MK_* knobs .if ${MK_AMD} != "no" BIN1+= amd.map .endif .if ${MK_APM} != "no" BIN1+= apmd.conf .endif .if ${MK_AUTOFS} != "no" BIN1+= auto_master .endif .if ${MK_BSNMP} != "no" BIN1+= snmpd.config .endif .if ${MK_FREEBSD_UPDATE} != "no" BIN1+= freebsd-update.conf .endif .if ${MK_FTP} != "no" BIN1+= ftpusers .endif .if ${MK_INETD} != "no" BIN1+= inetd.conf .endif .if ${MK_LOCATE} != "no" BIN1+= ${.CURDIR}/../usr.bin/locate/locate/locate.rc .endif .if ${MK_LPR} != "no" BIN1+= hosts.lpd printcap .endif .if ${MK_MAIL} != "no" BIN1+= ${.CURDIR}/../usr.bin/mail/misc/mail.rc .endif .if ${MK_NTP} != "no" BIN1+= ntp.conf .endif .if ${MK_OPENSSH} != "no" SSH= ${.CURDIR}/../crypto/openssh/ssh_config \ ${.CURDIR}/../crypto/openssh/sshd_config \ ${.CURDIR}/../crypto/openssh/moduli .endif .if ${MK_OPENSSL} != "no" SSL= ${.CURDIR}/../crypto/openssl/apps/openssl.cnf .endif .if ${MK_NS_CACHING} != "no" BIN1+= nscd.conf .endif .if ${MK_PORTSNAP} != "no" BIN1+= portsnap.conf .endif .if ${MK_PF} != "no" BIN1+= pf.os .endif .if ${MK_SENDMAIL} != "no" BIN1+= rc.sendmail .endif .if ${MK_TCSH} != "no" BIN1+= csh.cshrc csh.login csh.logout .endif .if ${MK_WIRELESS} != "no" BIN1+= regdomain.xml .endif # -rwxr-xr-x root:wheel, for the new cron root:wheel BIN2= netstart pccard_ether rc.suspend rc.resume MTREE= BSD.debug.dist BSD.include.dist BSD.root.dist BSD.usr.dist BSD.var.dist .if ${MK_TESTS} != "no" MTREE+= BSD.tests.dist .endif .if ${MK_SENDMAIL} != "no" MTREE+= BSD.sendmail.dist .endif PPPCNF= ppp.conf .if ${MK_SENDMAIL} == "no" ETCMAIL=mailer.conf aliases .else ETCMAIL=Makefile README mailer.conf access.sample virtusertable.sample \ mailertable.sample aliases .endif # Special top level files for FreeBSD FREEBSD=COPYRIGHT # Sanitize DESTDIR DESTDIR:= ${DESTDIR:C://*:/:g} afterinstall: .if ${MK_MAN} != "no" ${_+_}cd ${.CURDIR}/../share/man; ${MAKE} makedb .endif distribute: # Avoid installing tests here; "make distribution" will do this and # correctly place them in the right location. ${_+_}cd ${.CURDIR} ; ${MAKE} MK_TESTS=no install \ DESTDIR=${DISTDIR}/${DISTRIBUTION} ${_+_}cd ${.CURDIR} ; ${MAKE} distribution DESTDIR=${DISTDIR}/${DISTRIBUTION} .include .if ${TARGET_ENDIANNESS} == "1234" CAP_MKDB_ENDIAN?= -l .elif ${TARGET_ENDIANNESS} == "4321" CAP_MKDB_ENDIAN?= -b .else CAP_MKDB_ENDIAN?= .endif .if defined(NO_ROOT) METALOG.add?= cat -l >> ${METALOG} .endif distribution: .if !defined(DESTDIR) @echo "set DESTDIR before running \"make ${.TARGET}\"" @false .endif cd ${.CURDIR}; \ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 \ ${BIN1} ${DESTDIR}/etc; \ cap_mkdb ${CAP_MKDB_ENDIAN} ${DESTDIR}/etc/login.conf; \ services_mkdb ${CAP_MKDB_ENDIAN} -q -o ${DESTDIR}/var/db/services.db \ ${DESTDIR}/etc/services; \ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 755 \ ${BIN2} ${DESTDIR}/etc; \ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 600 \ master.passwd nsmb.conf opieaccess ${DESTDIR}/etc; .if ${MK_AT} == "no" sed -i "" -e 's;.*/usr/libexec/atrun;#&;' ${DESTDIR}/etc/crontab .endif .if ${MK_TCSH} == "no" sed -i "" -e 's;/bin/csh;/bin/sh;' ${DESTDIR}/etc/master.passwd .endif pwd_mkdb -i -p -d ${DESTDIR}/etc ${DESTDIR}/etc/master.passwd .if defined(NO_ROOT) ( \ echo "./etc/login.conf.db type=file mode=0644 uname=root gname=wheel"; \ echo "./etc/passwd type=file mode=0644 uname=root gname=wheel"; \ echo "./etc/pwd.db type=file mode=0644 uname=root gname=wheel"; \ echo "./etc/spwd.db type=file mode=0600 uname=root gname=wheel"; \ ) | ${METALOG.add} .endif .if ${MK_AUTOFS} != "no" ${_+_}cd ${.CURDIR}/autofs; ${MAKE} install .endif .if ${MK_BLUETOOTH} != "no" ${_+_}cd ${.CURDIR}/bluetooth; ${MAKE} install .endif .if ${MK_CASPER} != "no" ${_+_}cd ${.CURDIR}/casper; ${MAKE} install .endif ${_+_}cd ${.CURDIR}/defaults; ${MAKE} install ${_+_}cd ${.CURDIR}/devd; ${MAKE} install ${_+_}cd ${.CURDIR}/gss; ${MAKE} install ${_+_}cd ${.CURDIR}/periodic; ${MAKE} install .if ${MK_PKGBOOTSTRAP} != "no" ${_+_}cd ${.CURDIR}/pkg; ${MAKE} install .endif ${_+_}cd ${.CURDIR}/rc.d; ${MAKE} install ${_+_}cd ${.CURDIR}/../share/termcap; ${MAKE} etc-termcap ${_+_}cd ${.CURDIR}/../usr.sbin/rmt; ${MAKE} etc-rmt ${_+_}cd ${.CURDIR}/pam.d; ${MAKE} install cd ${.CURDIR}; ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 0444 \ ${BSM_ETC_OPEN_FILES} ${BSM_ETC_DIR} cd ${.CURDIR}; ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 0600 \ ${BSM_ETC_RESTRICTED_FILES} ${BSM_ETC_DIR} cd ${.CURDIR}; ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 0500 \ ${BSM_ETC_EXEC_FILES} ${BSM_ETC_DIR} .if ${MK_UNBOUND} != "no" if [ ! -e ${DESTDIR}/etc/unbound ]; then \ ${INSTALL_SYMLINK} ../var/unbound ${DESTDIR}/etc/unbound; \ fi .endif .if ${MK_SENDMAIL} != "no" ${_+_}cd ${.CURDIR}/sendmail; ${MAKE} distribution .endif .if ${MK_OPENSSH} != "no" cd ${.CURDIR}; ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 \ ${SSH} ${DESTDIR}/etc/ssh .endif .if ${MK_OPENSSL} != "no" cd ${.CURDIR}; ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 \ ${SSL} ${DESTDIR}/etc/ssl .endif .if ${MK_KERBEROS} != "no" cd ${.CURDIR}/root; \ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 \ dot.k5login ${DESTDIR}/root/.k5login; .endif cd ${.CURDIR}/root; \ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 \ dot.profile ${DESTDIR}/root/.profile; \ rm -f ${DESTDIR}/.profile; \ ln ${DESTDIR}/root/.profile ${DESTDIR}/.profile .if ${MK_TCSH} != "no" cd ${.CURDIR}/root; \ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 \ dot.cshrc ${DESTDIR}/root/.cshrc; \ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 \ dot.login ${DESTDIR}/root/.login; \ rm -f ${DESTDIR}/.cshrc; \ ln ${DESTDIR}/root/.cshrc ${DESTDIR}/.cshrc .endif cd ${.CURDIR}/mtree; ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 444 \ ${MTREE} ${DESTDIR}/etc/mtree -.if ${MK_PPP} != "no" - cd ${.CURDIR}/ppp; ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 600 \ - ${PPPCNF} ${DESTDIR}/etc/ppp -.endif .if ${MK_MAIL} != "no" cd ${.CURDIR}/mail; ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 \ ${ETCMAIL} ${DESTDIR}/etc/mail if [ -d ${DESTDIR}/etc/mail -a -f ${DESTDIR}/etc/mail/aliases -a \ ! -f ${DESTDIR}/etc/aliases ]; then \ ln -s mail/aliases ${DESTDIR}/etc/aliases; \ fi .endif ${INSTALL} -o ${BINOWN} -g operator -m 664 /dev/null \ ${DESTDIR}/etc/dumpdates .if ${MK_LOCATE} != "no" ${INSTALL} -o nobody -g ${BINGRP} -m 644 /dev/null \ ${DESTDIR}/var/db/locate.database .endif ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 ${.CURDIR}/minfree \ ${DESTDIR}/var/crash cd ${.CURDIR}/..; ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 444 \ ${FREEBSD} ${DESTDIR}/ .if ${MK_BOOT} != "no" .if exists(${.CURDIR}/../sys/${MACHINE}/conf/GENERIC.hints) ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 444 \ ${.CURDIR}/../sys/${MACHINE}/conf/GENERIC.hints \ ${DESTDIR}/boot/device.hints .endif .endif .if ${MK_NIS} == "no" sed -i "" -e 's/.*_compat:/# &/' -e 's/compat$$/files/' \ ${DESTDIR}/etc/nsswitch.conf .endif MTREE_CMD?= mtree .if ${MK_INSTALL_AS_USER} == "yes" && ${_uid} != 0 MTREE_FILTER= sed -e 's,\([gu]\)name=,\1id=,g' \ -e 's,\(uid=\)[^ ]* ,\1${_uid} ,' \ -e 's,\(gid=\)[^ ]* ,\1${_gid} ,' \ -e 's,\(uid=\)[^ ]*$$,\1${_uid},' \ -e 's,\(gid=\)[^ ]*$$,\1${_gid},' .else MTREE_FILTER= cat .endif MTREES= mtree/BSD.root.dist / \ mtree/BSD.var.dist /var \ mtree/BSD.usr.dist /usr \ mtree/BSD.include.dist /usr/include \ mtree/BSD.debug.dist /usr/lib .if ${MK_GROFF} != "no" MTREES+= mtree/BSD.groff.dist /usr .endif .if ${MK_TESTS} != "no" MTREES+= mtree/BSD.tests.dist ${TESTSBASE} .endif .if ${MK_SENDMAIL} != "no" MTREES+= mtree/BSD.sendmail.dist / .endif .for mtree in ${LOCAL_MTREE} MTREES+= ../${mtree} / .endfor distrib-dirs: ${MTREES:N/*} @set ${MTREES}; \ while test $$# -ge 2; do \ m=${.CURDIR}/$$1; \ shift; \ d=${DESTDIR}$$1; \ shift; \ test -d $$d || mkdir -p $$d; \ ${ECHO} ${MTREE_CMD} -deU ${MTREE_FOLLOWS_SYMLINKS} \ -f $$m -p $$d; \ ${MTREE_FILTER} $$m | \ ${MTREE_CMD} -deU ${MTREE_FOLLOWS_SYMLINKS} -p $$d; \ done; true .if defined(NO_ROOT) @set ${MTREES}; \ while test $$# -ge 2; do \ m=${.CURDIR}/$$1; \ shift; \ d=$$1; \ test "$$d" == "/" && d=""; \ d=${DISTBASE}$$d; \ shift; \ test -d ${DESTDIR}/$$d || mkdir -p ${DESTDIR}/$$d; \ ${ECHO} "${MTREE_CMD:N-W} -C -f $$m -K uname,gname | " \ "sed s#^\.#.$$d# | ${METALOG.add}" ; \ ${MTREE_FILTER} $$m | \ ${MTREE_CMD:N-W} -C -K uname,gname | sed s#^\.#.$$d# | \ ${METALOG.add} ; \ done; true .endif ${INSTALL_SYMLINK} usr/src/sys ${DESTDIR}/sys .if ${MK_MAN} != "no" cd ${DESTDIR}/usr/share/man; \ for mandir in man*; do \ ${INSTALL_SYMLINK} ../$$mandir \ ${DESTDIR}/usr/share/man/en.ISO8859-1/; \ ${INSTALL_SYMLINK} ../$$mandir \ ${DESTDIR}/usr/share/man/en.UTF-8/; \ done .if ${MK_OPENSSL} != "no" cd ${DESTDIR}/usr/share/openssl/man; \ for mandir in man*; do \ ${INSTALL_SYMLINK} ../$$mandir \ ${DESTDIR}/usr/share/openssl/man/en.ISO8859-1/; \ done .endif set - `grep "^[a-zA-Z]" ${.CURDIR}/man.alias`; \ while [ $$# -gt 0 ] ; do \ ${INSTALL_SYMLINK} "$$2" "${DESTDIR}/usr/share/man/$$1"; \ if [ "${MK_OPENSSL}" != "no" ]; then \ ${INSTALL_SYMLINK} "$$2" \ "${DESTDIR}/usr/share/openssl/man/$$1"; \ fi; \ shift; shift; \ done .endif .if ${MK_NLS} != "no" set - `grep "^[a-zA-Z]" ${.CURDIR}/nls.alias`; \ while [ $$# -gt 0 ] ; do \ ${INSTALL_SYMLINK} "$$2" "${DESTDIR}/usr/share/nls/$$1"; \ shift; shift; \ done .endif etc-examples: cd ${.CURDIR}; ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 444 \ ${BIN1} ${BIN2} nsmb.conf opieaccess \ ${DESTDIR}/usr/share/examples/etc ${_+_}cd ${.CURDIR}/defaults; ${MAKE} install \ DESTDIR=${DESTDIR}/usr/share/examples .include Index: projects/release-pkg/lib/libc/sys/shmctl.2 =================================================================== --- projects/release-pkg/lib/libc/sys/shmctl.2 (revision 289118) +++ projects/release-pkg/lib/libc/sys/shmctl.2 (revision 289119) @@ -1,138 +1,141 @@ .\" .\" Copyright (c) 1995 David Hovemeyer .\" .\" 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 DEVELOPERS ``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 DEVELOPERS 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 July 17, 1995 +.Dd October 10, 2015 .Dt SHMCTL 2 .Os .Sh NAME .Nm shmctl .Nd shared memory control .Sh LIBRARY .Lb libc .Sh SYNOPSIS .In sys/types.h .In sys/ipc.h .In sys/shm.h .Ft int .Fn shmctl "int shmid" "int cmd" "struct shmid_ds *buf" .Sh DESCRIPTION Performs the action specified by .Fa cmd on the shared memory segment identified by .Fa shmid : .Bl -tag -width SHM_UNLOCKX .It Dv IPC_STAT Fetch the segment's .Fa "struct shmid_ds" , storing it in the memory pointed to by .Fa buf . .\" .\" XXX need to make sure that this is correct for FreeBSD .\" .It Dv IPC_SET Changes the .Fa shm_perm.uid , .Fa shm_perm.gid , and .Fa shm_perm.mode members of the segment's .Fa "struct shmid_ds" to match those of the struct pointed to by .Fa buf . The calling process's effective uid must match either .Fa shm_perm.uid or .Fa shm_perm.cuid , or it must have superuser privileges. .It Dv IPC_RMID Removes the segment from the system. The removal will not take -effect until all processes having attached the segment have exited; -however, once the IPC_RMID operation has taken place, no further -processes will be allowed to attach the segment. +effect until all processes having attached the segment have exited. For the operation to succeed, the calling process's effective uid must match .Fa shm_perm.uid or .Fa shm_perm.cuid , or the process must have superuser privileges. +If the +.Va kern.ipc.shm_allow_removed +.Xr sysctl 3 +variable is set to 0, once the IPC_RMID operation has taken place, +no further processes will be allowed to attach the segment. .\" .It Dv SHM_LOCK .\" Locks the segment in memory. The calling process must have .\" superuser privileges. Not implemented in FreeBSD. .\" .It Dv SHM_UNLOCK .\" Unlocks the segment from memory. The calling process must .\" have superuser privileges. Not implemented in FreeBSD. .El .Pp The .Vt shmid_ds structure is defined as follows: .\" .\" I fiddled with the spaces a bit to make it fit well when viewed .\" with nroff, but otherwise it is straight from sys/shm.h .\" .Bd -literal struct shmid_ds { struct ipc_perm shm_perm; /* operation permission structure */ size_t shm_segsz; /* size of segment in bytes */ pid_t shm_lpid; /* process ID of last shared memory op */ pid_t shm_cpid; /* process ID of creator */ int shm_nattch; /* number of current attaches */ time_t shm_atime; /* time of last shmat() */ time_t shm_dtime; /* time of last shmdt() */ time_t shm_ctime; /* time of last change by shmctl() */ }; .Ed .Sh RETURN VALUES .Rv -std shmctl .Sh ERRORS The .Fn shmctl system call will fail if: .Bl -tag -width Er .It Bq Er EINVAL Invalid operation, or no shared memory segment was found corresponding to .Fa shmid . .\" .\" XXX I think the following is right: ipcperm() only returns EPERM .\" when an attempt is made to modify (IPC_M) by a non-creator .\" non-owner .It Bq Er EPERM The calling process's effective uid does not match the uid of the shared memory segment's owner or creator. .It Bq Er EACCES Permission denied due to mismatch between operation and mode of shared memory segment. .El .Sh "SEE ALSO" .Xr shmat 2 , .Xr shmdt 2 , .Xr shmget 2 , .Xr ftok 3 Index: projects/release-pkg/lib/libc =================================================================== --- projects/release-pkg/lib/libc (revision 289118) +++ projects/release-pkg/lib/libc (revision 289119) Property changes on: projects/release-pkg/lib/libc ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/lib/libc:r289091-289118 Index: projects/release-pkg/libexec/dma/dma/mailer.conf =================================================================== --- projects/release-pkg/libexec/dma/dma/mailer.conf (revision 289118) +++ projects/release-pkg/libexec/dma/dma/mailer.conf (nonexistent) @@ -1,5 +0,0 @@ -# $FreeBSD$ - -sendmail /usr/libexec/dma -send-mail /usr/libexec/dma -mailq /usr/libexec/dma Property changes on: projects/release-pkg/libexec/dma/dma/mailer.conf ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: projects/release-pkg/libexec/dma/dma/Makefile =================================================================== --- projects/release-pkg/libexec/dma/dma/Makefile (revision 289118) +++ projects/release-pkg/libexec/dma/dma/Makefile (nonexistent) @@ -1,34 +0,0 @@ -# $FreeBSD$ - -LIBADD= ssl crypto - -PROG= dma -SRCS= aliases_parse.y \ - aliases_scan.l \ - base64.c \ - conf.c \ - crypto.c \ - dma.c \ - dns.c \ - local.c \ - mail.c \ - net.c \ - spool.c \ - util.c -MAN8= dma.8 -CONFS= dma.conf -CONFSDIR= ${ETCDIR}/dma -YFLAGS+= -i -CLEANFILES= aliases_parse.i -FILES= mailer.conf -FILESDIR= ${SHAREDIR}/examples/dma - -BINMODE= 2555 - -.include - -.if ${COMPILER_TYPE} == gcc -WARNS= 5 -.endif - -.include Property changes on: projects/release-pkg/libexec/dma/dma/Makefile ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: projects/release-pkg/libexec/dma/dma/dma.conf =================================================================== --- projects/release-pkg/libexec/dma/dma/dma.conf (revision 289118) +++ projects/release-pkg/libexec/dma/dma/dma.conf (nonexistent) @@ -1,64 +0,0 @@ -# $FreeBSD$ -# -# Your smarthost (also called relayhost). Leave blank if you don't want -# smarthost support. -#SMARTHOST - -# Use this SMTP port. Most users will be fine with the default (25) -#PORT 25 - -# Path to your alias file. Just stay with the default. -#ALIASES /etc/aliases - -# Path to your spooldir. Just stay with the default. -#SPOOLDIR /var/spool/dma - -# SMTP authentication -#AUTHPATH /etc/dma/auth.conf - -# Uncomment if yout want TLS/SSL support -#SECURETRANSFER - -# Uncomment if you want STARTTLS support (only used in combination with -# SECURETRANSFER) -#STARTTLS - -# Uncomment if you have specified STARTTLS above and it should be allowed -# to fail ("opportunistic TLS", use an encrypted connection when available -# but allow an unencrypted one to servers that do not support it) -#OPPORTUNISTIC_TLS - -# Path to your local SSL certificate -#CERTFILE - -# If you want to use plain text SMTP login without using encryption, change -# the SECURE entry below to INSECURE. Otherwise plain login will only work -# over a secure connection. Use this option with caution. -#SECURE - -# Uncomment if you want to defer your mails. This is useful if you are -# behind a dialup line. You have to submit your mails manually with dma -q -#DEFER - -# Uncomment if you want the bounce message to include the complete original -# message, not just the headers. -#FULLBOUNCE - -# The internet hostname dma uses to identify the host. -# If not set or empty, the result of gethostname(2) is used. -# If MAILNAME is an absolute path to a file, the first line of this file -# will be used as the hostname. -#MAILNAME mail.example.net - -# Masquerade envelope from addresses with this address/hostname. -# Use this if mails are not accepted by destination mail servers because -# your sender domain is invalid. -# By default, MASQUERADE is not set. -# Format: MASQUERADE [user@][host] -# Examples: -# MASQUERADE john@ on host "hamlet" will send all mails as john@hamlet -# MASQUERADE percolator will send mails as $username@percolator, e.g. fish@percolator -# MASQUERADE herb@ert will send all mails as herb@ert - -# Directly forward the mail to the SMARTHOST bypassing aliases and local delivery -#NULLCLIENT Property changes on: projects/release-pkg/libexec/dma/dma/dma.conf ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: projects/release-pkg/libexec/dma/Makefile =================================================================== --- projects/release-pkg/libexec/dma/Makefile (revision 289118) +++ projects/release-pkg/libexec/dma/Makefile (revision 289119) @@ -1,6 +1,6 @@ # $FreeBSD$ -SUBDIR= dma \ +SUBDIR= dmagent \ dma-mbox-create .include Index: projects/release-pkg/libexec/dma/dmagent/Makefile =================================================================== --- projects/release-pkg/libexec/dma/dmagent/Makefile (nonexistent) +++ projects/release-pkg/libexec/dma/dmagent/Makefile (revision 289119) @@ -0,0 +1,34 @@ +# $FreeBSD$ + +LIBADD= ssl crypto + +PROG= dma +SRCS= aliases_parse.y \ + aliases_scan.l \ + base64.c \ + conf.c \ + crypto.c \ + dma.c \ + dns.c \ + local.c \ + mail.c \ + net.c \ + spool.c \ + util.c +MAN8= dma.8 +CONFS= dma.conf +CONFSDIR= ${CONFIGDIR}/dma +YFLAGS+= -i +CLEANFILES= aliases_parse.i +FILES= mailer.conf +FILESDIR= ${SHAREDIR}/examples/dma + +BINMODE= 2555 + +.include + +.if ${COMPILER_TYPE} == gcc +WARNS= 5 +.endif + +.include Property changes on: projects/release-pkg/libexec/dma/dmagent/Makefile ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/release-pkg/libexec/dma/dmagent/dma.conf =================================================================== --- projects/release-pkg/libexec/dma/dmagent/dma.conf (nonexistent) +++ projects/release-pkg/libexec/dma/dmagent/dma.conf (revision 289119) @@ -0,0 +1,64 @@ +# $FreeBSD$ +# +# Your smarthost (also called relayhost). Leave blank if you don't want +# smarthost support. +#SMARTHOST + +# Use this SMTP port. Most users will be fine with the default (25) +#PORT 25 + +# Path to your alias file. Just stay with the default. +#ALIASES /etc/aliases + +# Path to your spooldir. Just stay with the default. +#SPOOLDIR /var/spool/dma + +# SMTP authentication +#AUTHPATH /etc/dma/auth.conf + +# Uncomment if yout want TLS/SSL support +#SECURETRANSFER + +# Uncomment if you want STARTTLS support (only used in combination with +# SECURETRANSFER) +#STARTTLS + +# Uncomment if you have specified STARTTLS above and it should be allowed +# to fail ("opportunistic TLS", use an encrypted connection when available +# but allow an unencrypted one to servers that do not support it) +#OPPORTUNISTIC_TLS + +# Path to your local SSL certificate +#CERTFILE + +# If you want to use plain text SMTP login without using encryption, change +# the SECURE entry below to INSECURE. Otherwise plain login will only work +# over a secure connection. Use this option with caution. +#SECURE + +# Uncomment if you want to defer your mails. This is useful if you are +# behind a dialup line. You have to submit your mails manually with dma -q +#DEFER + +# Uncomment if you want the bounce message to include the complete original +# message, not just the headers. +#FULLBOUNCE + +# The internet hostname dma uses to identify the host. +# If not set or empty, the result of gethostname(2) is used. +# If MAILNAME is an absolute path to a file, the first line of this file +# will be used as the hostname. +#MAILNAME mail.example.net + +# Masquerade envelope from addresses with this address/hostname. +# Use this if mails are not accepted by destination mail servers because +# your sender domain is invalid. +# By default, MASQUERADE is not set. +# Format: MASQUERADE [user@][host] +# Examples: +# MASQUERADE john@ on host "hamlet" will send all mails as john@hamlet +# MASQUERADE percolator will send mails as $username@percolator, e.g. fish@percolator +# MASQUERADE herb@ert will send all mails as herb@ert + +# Directly forward the mail to the SMARTHOST bypassing aliases and local delivery +#NULLCLIENT Property changes on: projects/release-pkg/libexec/dma/dmagent/dma.conf ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/release-pkg/libexec/dma/dmagent/mailer.conf =================================================================== --- projects/release-pkg/libexec/dma/dmagent/mailer.conf (nonexistent) +++ projects/release-pkg/libexec/dma/dmagent/mailer.conf (revision 289119) @@ -0,0 +1,5 @@ +# $FreeBSD$ + +sendmail /usr/libexec/dma +send-mail /usr/libexec/dma +mailq /usr/libexec/dma Property changes on: projects/release-pkg/libexec/dma/dmagent/mailer.conf ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/release-pkg/sbin/geom/class/nop/gnop.8 =================================================================== --- projects/release-pkg/sbin/geom/class/nop/gnop.8 (revision 289118) +++ projects/release-pkg/sbin/geom/class/nop/gnop.8 (revision 289119) @@ -1,185 +1,186 @@ .\" Copyright (c) 2004-2006 Pawel Jakub Dawidek .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" -.Dd September 15, 2015 +.Dd October 10, 2015 .Dt GNOP 8 .Os .Sh NAME .Nm gnop .Nd "control utility for NOP GEOM class" .Sh SYNOPSIS .Nm .Cm create .Op Fl v .Op Fl e Ar error .Op Fl o Ar offset .Op Fl p Ar stripesize .Op Fl P Ar stripeoffset .Op Fl r Ar rfailprob .Op Fl s Ar size .Op Fl S Ar secsize .Op Fl w Ar wfailprob .Ar dev ... .Nm .Cm configure .Op Fl v .Op Fl e Ar error .Op Fl r Ar rfailprob .Op Fl w Ar wfailprob .Ar prov ... .Nm .Cm destroy .Op Fl fv .Ar prov ... .Nm .Cm reset .Op Fl v .Ar prov ... .Nm .Cm list .Nm .Cm status .Nm .Cm load .Nm .Cm unload .Sh DESCRIPTION The .Nm utility is used for setting up transparent providers on existing ones. Its main purpose is testing other GEOM classes, as it allows forced provider removal and I/O error simulation with a given probability. -It also gathers the following statistics: number of read requests, number of -write requests, number of bytes read and number of bytes written. -In addition, it can be used as a good starting point for implementing new GEOM +It also gathers statistics on the number of read, write, delete, +getattr, flush, and other requests, and the number of bytes read and written. +.Nm +can also be used as a good starting point for implementing new GEOM classes. .Pp The first argument to .Nm indicates an action to be performed: .Bl -tag -width ".Cm configure" .It Cm create Set up a transparent provider on the given devices. If the operation succeeds, the new provider should appear with name .Pa /dev/ Ns Ao Ar dev Ac Ns Pa .nop . The kernel module .Pa geom_nop.ko will be loaded if it is not loaded already. .It Cm configure Configure existing transparent provider. At the moment it is only used for changing failure probability. .It Cm destroy Turn off the given transparent providers. .It Cm reset Reset statistics for the given transparent providers. .It Cm list See .Xr geom 8 . .It Cm status See .Xr geom 8 . .It Cm load See .Xr geom 8 . .It Cm unload See .Xr geom 8 . .El .Pp Additional options: .Bl -tag -width ".Fl r Ar rfailprob" .It Fl e Ar error Specifies the error number to return on failure. .It Fl f Force the removal of the specified provider. .It Fl o Ar offset Where to begin on the original provider. .It Fl p Ar stripesize Value of the stripesize property of the transparent provider. .It Fl P Ar stripeoffset Value of the stripeoffset property of the transparent provider. .It Fl r Ar rfailprob Specifies read failure probability in percent. .It Fl s Ar size Size of the transparent provider. .It Fl S Ar secsize Sector size of the transparent provider. .It Fl w Ar wfailprob Specifies write failure probability in percent. .It Fl v Be more verbose. .El .Sh SYSCTL VARIABLES The following .Xr sysctl 8 variables can be used to control the behavior of the .Nm NOP GEOM class. The default value is shown next to each variable. .Bl -tag -width indent .It Va kern.geom.nop.debug : No 0 Debug level of the .Nm NOP GEOM class. This can be set to a number between 0 and 2 inclusive. If set to 0, minimal debug information is printed. If set to 1, basic debug information is logged along with the I/O requests that were returned as errors. If set to 2, the maximum amount of debug information is printed including all I/O requests. .El .Sh EXIT STATUS Exit status is 0 on success, and 1 if the command fails. .Sh EXAMPLES The following example shows how to create a transparent provider for disk .Pa /dev/da0 with 50% write failure probability, and how to destroy it. .Bd -literal -offset indent gnop create -v -w 50 da0 gnop destroy -v da0.nop .Ed .Pp The traffic statistics for the given transparent providers can be obtained with the .Cm list command. The example below shows the number of bytes written with .Xr newfs 8 : .Bd -literal -offset indent gnop create da0 newfs /dev/da0.nop gnop list .Ed .Sh SEE ALSO .Xr geom 4 , .Xr geom 8 .Sh HISTORY The .Nm utility appeared in .Fx 5.3 . .Sh AUTHORS .An Pawel Jakub Dawidek Aq Mt pjd@FreeBSD.org Index: projects/release-pkg/sbin/mdconfig/mdconfig.8 =================================================================== --- projects/release-pkg/sbin/mdconfig/mdconfig.8 (revision 289118) +++ projects/release-pkg/sbin/mdconfig/mdconfig.8 (revision 289119) @@ -1,320 +1,320 @@ .\" Copyright (c) 1993 University of Utah. .\" Copyright (c) 1980, 1989, 1991, 1993 .\" The Regents of the University of California. All rights reserved. .\" Copyright (c) 2000 .\" Poul-Henning Kamp All rights reserved. .\" .\" This code is derived from software contributed to Berkeley by .\" the Systems Programming Group of the University of Utah Computer .\" Science Department. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" @(#)vnconfig.8 8.1 (Berkeley) 6/5/93 .\" from: src/usr.sbin/vnconfig/vnconfig.8,v 1.19 2000/12/27 15:30:29 .\" .\" $FreeBSD$ .\" -.Dd August 6, 2015 +.Dd October 10, 2015 .Dt MDCONFIG 8 .Os .Sh NAME .Nm mdconfig .Nd create and control memory disks .Sh SYNOPSIS .Nm .Fl a .Fl t Ar type .Op Fl n .Oo Fl o Oo Cm no Oc Ns Ar option Oc ... .Op Fl f Ar file .Op Fl s Ar size .Op Fl S Ar sectorsize .Op Fl u Ar unit .Op Fl x Ar sectors/track .Op Fl y Ar heads/cylinder .Nm .Fl d .Fl u Ar unit .Op Fl o Oo Cm no Oc Ns Ar force .Nm .Fl r .Fl u Ar unit .Fl s Ar size .Op Fl o Oo Cm no Oc Ns Ar force .Nm .Fl l .Op Fl n .Op Fl v .Op Fl f Ar file .Op Fl u Ar unit .Nm .Ar file .Sh DESCRIPTION The .Nm utility creates and controls .Xr md 4 devices. .Pp Options indicate an action to be performed: .Bl -tag -width indent .It Fl a Attach a memory disk. This will configure and attach a memory disk with the parameters specified and attach it to the system. If the .Fl u Ar unit option is not provided, the newly created device name will be printed on stdout. .It Fl d Detach a memory disk from the system and release all resources. .It Fl r Resize a memory disk. .It Fl t Ar type Select the type of the memory disk. .Bl -tag -width "malloc" .It Cm malloc Storage for this type of memory disk is allocated with .Xr malloc 9 . This limits the size to the malloc bucket limit in the kernel. If the .Fl o Cm reserve option is not set, creating and filling a large malloc-backed memory disk is a very easy way to panic the system. .It Cm vnode A file specified with .Fl f Ar file becomes the backing store for this memory disk. .It Cm swap Storage for this type of memory disk is allocated from buffer memory. Pages get pushed out to swap when the system is under memory pressure, otherwise they stay in the operating memory. Using .Cm swap backing is generally preferred instead of using .Cm malloc backing. .It Cm null Bitsink; all writes do nothing, all reads return zeroes. .El .It Fl f Ar file Filename to use for the vnode type memory disk. The .Fl a and .Fl t Ar vnode options are implied if not specified. .It Fl l List configured devices. If given with .Fl u , display details about that particular device. If given with .Fl f Ar file , display .Xr md 4 device names of which .Ar file is used as the backing store. If both of .Fl u and .Fl f options are specified, display devices which match the two conditions. If the .Fl v option is specified, show all details. .It Fl n When printing .Xr md 4 device names, print only the unit number without the .Xr md 4 prefix. .It Fl s Ar size Size of the memory disk. .Ar Size is the number of 512 byte sectors unless suffixed with a -.Cm b , k , m , g , +.Cm b , k , m , g , t , or -.Cm t +.Cm p which -denotes byte, kilobyte, megabyte, gigabyte and terabyte respectively. +denotes byte, kilobyte, megabyte, gigabyte, terabyte and petabyte respectively. When used without the .Fl r option, the .Fl a and .Fl t Ar swap options are implied if not specified. .It Fl S Ar sectorsize Sectorsize to use for the memory disk, in bytes. .It Fl x Ar sectors/track See the description of the .Fl y option below. .It Fl y Ar heads/cylinder For .Cm malloc or .Cm vnode backed devices, the .Fl x and .Fl y options can be used to specify a synthetic geometry. This is useful for constructing bootable images for later download to other devices. .It Fl o Oo Cm no Oc Ns Ar option Set or reset options. .Bl -tag -width indent .It Oo Cm no Oc Ns Cm async For .Cm vnode backed devices: avoid .Dv IO_SYNC for increased performance but at the risk of deadlocking the entire kernel. .It Oo Cm no Oc Ns Cm reserve Allocate and reserve all needed storage from the start, rather than as needed. .It Oo Cm no Oc Ns Cm cluster Enable clustering on this disk. .It Oo Cm no Oc Ns Cm compress Enable/disable compression features to reduce memory usage. .It Oo Cm no Oc Ns Cm force Disable/enable extra sanity checks to prevent the user from doing something that might adversely affect the system. This can be used with the .Fl d flag to forcibly destroy an .Xr md 4 disk that is still in use. .It Oo Cm no Oc Ns Cm readonly Enable/disable readonly mode. .El .It Fl u Ar unit Request a specific unit number or device name for the .Xr md 4 device instead of automatic allocation. If a device name is specified, it must be start with .Dq md followed by the unit number. .El .Pp The last form, .Nm .Ar file , is provided for convenience as an abbreviation of .Nm .Fl a .Fl t Ar vnode .Fl f Ar file . .Sh EXAMPLES Create a disk with .Pa /tmp/boot.flp as backing storage. The name of the allocated unit will be printed on stdout, such as .Dq Li md0 : .Bd -literal -offset indent mdconfig /tmp/boot.flp .Ed .Pp Create a 1 gigabyte swap backed memory disk named .Dq Li md3 : .Bd -literal -offset indent mdconfig -s 1g -u md3 .Ed .Pp Detach and free all resources used by .Pa /dev/md3 : .Bd -literal -offset indent mdconfig -du md3 .Ed .Pp Show detailed information on current memory disks: .Bd -literal -offset indent mdconfig -lv .Ed .Pp Resize the .Dq Li md3 memory disk to 2 gigabytes: .Bd -literal -offset indent mdconfig -rs 2g -u md3 .Ed .Pp Create a 1 gigabyte swap backed disk, initialize an .Xr ffs 7 file system on it, and mount it on .Pa /tmp : .Bd -literal -offset indent mdconfig -s 1g -u md10 newfs -U /dev/md10 mount /dev/md10 /tmp chmod 1777 /tmp .Ed .Pp Create a memory disk out of an ISO 9660 CD image file, using the first available .Xr md 4 device, and then mount it: .Bd -literal -offset indent mount -t cd9660 /dev/`mdconfig -f cdimage.iso` /mnt .Ed .Pp Create a file-backed device from a hard disk image that begins with 512K of raw header information. .Xr gnop 8 is used to skip over the header information, positioning .Pa md1.nop to the start of the filesystem in the image. .Bd -literal -offset indent mdconfig -u md1 -f diskimage.img gnop create -o 512K md1 mount /dev/md1.nop /mnt .Ed .Sh SEE ALSO .Xr md 4 , .Xr ffs 7 , .Xr gpart 8 , .Xr mdmfs 8 , .Xr malloc 9 .Sh HISTORY The .Nm utility first appeared in .Fx 5.0 as a cleaner replacement for the .Xr vn 4 and .Xr vnconfig 8 combo. .Sh AUTHORS The .Nm utility was written by .An Poul-Henning Kamp Aq Mt phk@FreeBSD.org . Index: projects/release-pkg/sbin/mdconfig/mdconfig.c =================================================================== --- projects/release-pkg/sbin/mdconfig/mdconfig.c (revision 289118) +++ projects/release-pkg/sbin/mdconfig/mdconfig.c (revision 289119) @@ -1,568 +1,571 @@ /*- * Copyright (c) 2000-2004 Poul-Henning Kamp * Copyright (c) 2012 The FreeBSD Foundation * All rights reserved. * * Portions of this software were developed by Edward Tomasz Napierala * 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 * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static struct md_ioctl mdio; static enum {UNSET, ATTACH, DETACH, RESIZE, LIST} action = UNSET; static int nflag; static void usage(void); static void md_set_file(const char *); static int md_find(const char *, const char *); static int md_query(const char *, const int, const char *); static int md_list(const char *, int, const char *); static char *geom_config_get(struct gconf *g, const char *name); static void md_prthumanval(char *length); #define OPT_VERBOSE 0x01 #define OPT_UNIT 0x02 #define OPT_DONE 0x04 #define OPT_LIST 0x10 #define CLASS_NAME_MD "MD" static void usage(void) { fprintf(stderr, "usage: mdconfig -a -t type [-n] [-o [no]option] ... [-f file]\n" " [-s size] [-S sectorsize] [-u unit]\n" " [-x sectors/track] [-y heads/cylinder]\n" " mdconfig -d -u unit [-o [no]force]\n" " mdconfig -r -u unit -s size [-o [no]force]\n" " mdconfig -l [-v] [-n] [-f file] [-u unit]\n" " mdconfig file\n"); fprintf(stderr, "\t\ttype = {malloc, vnode, swap}\n"); fprintf(stderr, "\t\toption = {cluster, compress, reserve}\n"); fprintf(stderr, "\t\tsize = %%d (512 byte blocks), %%db (B),\n"); - fprintf(stderr, "\t\t %%dk (kB), %%dm (MB), %%dg (GB) or\n"); - fprintf(stderr, "\t\t %%dt (TB)\n"); + fprintf(stderr, "\t\t %%dk (kB), %%dm (MB), %%dg (GB), \n"); + fprintf(stderr, "\t\t %%dt (TB), or %%dp (PB)\n"); exit(1); } int main(int argc, char **argv) { int ch, fd, i, vflag; char *p; char *fflag = NULL, *sflag = NULL, *tflag = NULL, *uflag = NULL; bzero(&mdio, sizeof(mdio)); mdio.md_file = malloc(PATH_MAX); if (mdio.md_file == NULL) err(1, "could not allocate memory"); vflag = 0; bzero(mdio.md_file, PATH_MAX); if (argc == 1) usage(); while ((ch = getopt(argc, argv, "ab:df:lno:rs:S:t:u:vx:y:")) != -1) { switch (ch) { case 'a': if (action != UNSET && action != ATTACH) errx(1, "-a is mutually exclusive " "with -d, -r, and -l"); action = ATTACH; break; case 'd': if (action != UNSET && action != DETACH) errx(1, "-d is mutually exclusive " "with -a, -r, and -l"); action = DETACH; mdio.md_options |= MD_AUTOUNIT; break; case 'r': if (action != UNSET && action != RESIZE) errx(1, "-r is mutually exclusive " "with -a, -d, and -l"); action = RESIZE; mdio.md_options |= MD_AUTOUNIT; break; case 'l': if (action != UNSET && action != LIST) errx(1, "-l is mutually exclusive " "with -a, -r, and -d"); action = LIST; mdio.md_options |= MD_AUTOUNIT; break; case 'n': nflag = 1; break; case 't': if (tflag != NULL) errx(1, "-t can be passed only once"); tflag = optarg; if (!strcmp(optarg, "malloc")) { mdio.md_type = MD_MALLOC; mdio.md_options |= MD_AUTOUNIT | MD_COMPRESS; } else if (!strcmp(optarg, "vnode")) { mdio.md_type = MD_VNODE; mdio.md_options |= MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS; } else if (!strcmp(optarg, "swap")) { mdio.md_type = MD_SWAP; mdio.md_options |= MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS; } else if (!strcmp(optarg, "null")) { mdio.md_type = MD_NULL; mdio.md_options |= MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS; } else errx(1, "unknown type: %s", optarg); break; case 'f': if (fflag != NULL) errx(1, "-f can be passed only once"); fflag = realpath(optarg, NULL); if (fflag == NULL) err(1, "realpath"); break; case 'o': if (!strcmp(optarg, "async")) mdio.md_options |= MD_ASYNC; else if (!strcmp(optarg, "noasync")) mdio.md_options &= ~MD_ASYNC; else if (!strcmp(optarg, "cluster")) mdio.md_options |= MD_CLUSTER; else if (!strcmp(optarg, "nocluster")) mdio.md_options &= ~MD_CLUSTER; else if (!strcmp(optarg, "compress")) mdio.md_options |= MD_COMPRESS; else if (!strcmp(optarg, "nocompress")) mdio.md_options &= ~MD_COMPRESS; else if (!strcmp(optarg, "force")) mdio.md_options |= MD_FORCE; else if (!strcmp(optarg, "noforce")) mdio.md_options &= ~MD_FORCE; else if (!strcmp(optarg, "readonly")) mdio.md_options |= MD_READONLY; else if (!strcmp(optarg, "noreadonly")) mdio.md_options &= ~MD_READONLY; else if (!strcmp(optarg, "reserve")) mdio.md_options |= MD_RESERVE; else if (!strcmp(optarg, "noreserve")) mdio.md_options &= ~MD_RESERVE; else errx(1, "unknown option: %s", optarg); break; case 'S': mdio.md_sectorsize = strtoul(optarg, &p, 0); break; case 's': if (sflag != NULL) errx(1, "-s can be passed only once"); sflag = optarg; mdio.md_mediasize = (off_t)strtoumax(optarg, &p, 0); if (p == NULL || *p == '\0') mdio.md_mediasize *= DEV_BSIZE; else if (*p == 'b' || *p == 'B') ; /* do nothing */ else if (*p == 'k' || *p == 'K') mdio.md_mediasize <<= 10; else if (*p == 'm' || *p == 'M') mdio.md_mediasize <<= 20; else if (*p == 'g' || *p == 'G') mdio.md_mediasize <<= 30; else if (*p == 't' || *p == 'T') { mdio.md_mediasize <<= 30; mdio.md_mediasize <<= 10; + } else if (*p == 'p' || *p == 'P') { + mdio.md_mediasize <<= 30; + mdio.md_mediasize <<= 20; } else errx(1, "unknown suffix on -s argument"); break; case 'u': if (!strncmp(optarg, _PATH_DEV, sizeof(_PATH_DEV) - 1)) optarg += sizeof(_PATH_DEV) - 1; if (!strncmp(optarg, MD_NAME, sizeof(MD_NAME) - 1)) optarg += sizeof(MD_NAME) - 1; uflag = optarg; break; case 'v': vflag = OPT_VERBOSE; break; case 'x': mdio.md_fwsectors = strtoul(optarg, &p, 0); break; case 'y': mdio.md_fwheads = strtoul(optarg, &p, 0); break; default: usage(); } } argc -= optind; argv += optind; if (action == UNSET) action = ATTACH; if (action == ATTACH) { if (tflag == NULL) { /* * Try to infer the type based on other arguments. */ if (fflag != NULL || argc > 0) { /* Imply ``-t vnode'' */ mdio.md_type = MD_VNODE; mdio.md_options |= MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS; } else if (sflag != NULL) { /* Imply ``-t swap'' */ mdio.md_type = MD_SWAP; mdio.md_options |= MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS; } else errx(1, "unable to determine type"); } if ((fflag != NULL || argc > 0) && mdio.md_type != MD_VNODE) errx(1, "only -t vnode can be used with file name"); if (mdio.md_type == MD_VNODE) { if (fflag != NULL) { if (argc != 0) usage(); md_set_file(fflag); } else { if (argc != 1) usage(); md_set_file(*argv); } if ((mdio.md_options & MD_READONLY) == 0 && access(mdio.md_file, W_OK) < 0 && (errno == EACCES || errno == EPERM || errno == EROFS)) { warnx("WARNING: opening backing store: %s " "readonly", mdio.md_file); mdio.md_options |= MD_READONLY; } } if ((mdio.md_type == MD_MALLOC || mdio.md_type == MD_SWAP || mdio.md_type == MD_NULL) && sflag == NULL) errx(1, "must specify -s for -t malloc, -t swap, " "or -t null"); if (mdio.md_type == MD_VNODE && mdio.md_file[0] == '\0') errx(1, "must specify -f for -t vnode"); } else { if (mdio.md_sectorsize != 0) errx(1, "-S can only be used with -a"); if (action != RESIZE && sflag != NULL) errx(1, "-s can only be used with -a and -r"); if (mdio.md_fwsectors != 0) errx(1, "-x can only be used with -a"); if (mdio.md_fwheads != 0) errx(1, "-y can only be used with -a"); if (fflag != NULL && action != LIST) errx(1, "-f can only be used with -a and -l"); if (tflag != NULL) errx(1, "-t can only be used with -a"); if (argc > 0) errx(1, "file can only be used with -a"); if ((action != DETACH && action != RESIZE) && (mdio.md_options & ~MD_AUTOUNIT) != 0) errx(1, "-o can only be used with -a, -d, and -r"); if (action == DETACH && (mdio.md_options & ~(MD_FORCE | MD_AUTOUNIT)) != 0) errx(1, "only -o [no]force can be used with -d"); if (action == RESIZE && (mdio.md_options & ~(MD_FORCE | MD_RESERVE | MD_AUTOUNIT)) != 0) errx(1, "only -o [no]force and -o [no]reserve can be used with -r"); } if (action == RESIZE && sflag == NULL) errx(1, "must specify -s for -r"); if (action != LIST && vflag == OPT_VERBOSE) errx(1, "-v can only be used with -l"); if (uflag != NULL) { mdio.md_unit = strtoul(uflag, &p, 0); if (mdio.md_unit == (unsigned)ULONG_MAX || *p != '\0') errx(1, "bad unit: %s", uflag); mdio.md_options &= ~MD_AUTOUNIT; } mdio.md_version = MDIOVERSION; if (!kld_isloaded("g_md") && kld_load("geom_md") == -1) err(1, "failed to load geom_md module"); fd = open(_PATH_DEV MDCTL_NAME, O_RDWR, 0); if (fd < 0) err(1, "open(%s%s)", _PATH_DEV, MDCTL_NAME); if (action == ATTACH) { i = ioctl(fd, MDIOCATTACH, &mdio); if (i < 0) err(1, "ioctl(%s%s)", _PATH_DEV, MDCTL_NAME); if (mdio.md_options & MD_AUTOUNIT) printf("%s%d\n", nflag ? "" : MD_NAME, mdio.md_unit); } else if (action == DETACH) { if (mdio.md_options & MD_AUTOUNIT) errx(1, "-d requires -u"); i = ioctl(fd, MDIOCDETACH, &mdio); if (i < 0) err(1, "ioctl(%s%s)", _PATH_DEV, MDCTL_NAME); } else if (action == RESIZE) { if (mdio.md_options & MD_AUTOUNIT) errx(1, "-r requires -u"); i = ioctl(fd, MDIOCRESIZE, &mdio); if (i < 0) err(1, "ioctl(%s%s)", _PATH_DEV, MDCTL_NAME); } else if (action == LIST) { if (mdio.md_options & MD_AUTOUNIT) { /* * Listing all devices. This is why we pass NULL * together with OPT_LIST. */ return (md_list(NULL, OPT_LIST | vflag, fflag)); } else return (md_query(uflag, vflag, fflag)); } else usage(); close(fd); return (0); } static void md_set_file(const char *fn) { struct stat sb; int fd; if (realpath(fn, mdio.md_file) == NULL) err(1, "could not find full path for %s", fn); fd = open(mdio.md_file, O_RDONLY); if (fd < 0) err(1, "could not open %s", fn); if (fstat(fd, &sb) == -1) err(1, "could not stat %s", fn); if (!S_ISREG(sb.st_mode)) errx(1, "%s is not a regular file", fn); if (mdio.md_mediasize == 0) mdio.md_mediasize = sb.st_size; close(fd); } /* * Lists md(4) disks. Is used also as a query routine, since it handles XML * interface. 'units' can be NULL for listing memory disks. It might be * coma-separated string containing md(4) disk names. 'opt' distinguished * between list and query mode. */ static int md_list(const char *units, int opt, const char *fflag) { struct gmesh gm; struct gprovider *pp; struct gconf *gc; struct gident *gid; struct devstat *gsp; struct ggeom *gg; struct gclass *gcl; void *sq; int retcode, ffound, ufound; char *type, *file, *length; type = file = length = NULL; retcode = geom_gettree(&gm); if (retcode != 0) return (-1); retcode = geom_stats_open(); if (retcode != 0) return (-1); sq = geom_stats_snapshot_get(); if (sq == NULL) return (-1); ffound = ufound = 0; while ((gsp = geom_stats_snapshot_next(sq)) != NULL) { gid = geom_lookupid(&gm, gsp->id); if (gid == NULL) continue; if (gid->lg_what == ISPROVIDER) { pp = gid->lg_ptr; gg = pp->lg_geom; gcl = gg->lg_class; if (strcmp(gcl->lg_name, CLASS_NAME_MD) != 0) continue; if ((opt & OPT_UNIT) && (units != NULL)) { retcode = md_find(units, pp->lg_name); if (retcode != 1) continue; else ufound = 1; } gc = &pp->lg_config; type = geom_config_get(gc, "type"); if (strcmp(type, "vnode") == 0) { file = geom_config_get(gc, "file"); if (fflag != NULL && strcmp(fflag, file) != 0) continue; else ffound = 1; } else if (fflag != NULL) continue; if (nflag && strncmp(pp->lg_name, MD_NAME, 2) == 0) printf("%s", pp->lg_name + 2); else printf("%s", pp->lg_name); if (opt & OPT_VERBOSE || ((opt & OPT_UNIT) && fflag == NULL)) { length = geom_config_get(gc, "length"); printf("\t%s\t", type); if (length != NULL) md_prthumanval(length); if (file != NULL) { printf("\t%s", file); file = NULL; } } opt |= OPT_DONE; if ((opt & OPT_LIST) && !(opt & OPT_VERBOSE)) printf(" "); else printf("\n"); } } if ((opt & OPT_LIST) && (opt & OPT_DONE) && !(opt & OPT_VERBOSE)) printf("\n"); /* XXX: Check if it's enough to clean everything. */ geom_stats_snapshot_free(sq); if (opt & OPT_UNIT) { if (((fflag == NULL) && ufound) || ((fflag == NULL) && (units != NULL) && ufound) || ((fflag != NULL) && ffound) || ((fflag != NULL) && (units != NULL) && ufound && ffound)) return (0); } else if (opt & OPT_LIST) { if ((fflag == NULL) || ((fflag != NULL) && ffound)) return (0); } return (-1); } /* * Returns value of 'name' from gconfig structure. */ static char * geom_config_get(struct gconf *g, const char *name) { struct gconfig *gce; LIST_FOREACH(gce, g, lg_config) { if (strcmp(gce->lg_name, name) == 0) return (gce->lg_val); } return (NULL); } /* * List is comma separated list of MD disks. name is a * device name we look for. Returns 1 if found and 0 * otherwise. */ static int md_find(const char *list, const char *name) { int ret; char num[PATH_MAX]; char *ptr, *p, *u; ret = 0; ptr = strdup(list); if (ptr == NULL) return (-1); for (p = ptr; (u = strsep(&p, ",")) != NULL;) { if (strncmp(u, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) u += sizeof(_PATH_DEV) - 1; /* Just in case user specified number instead of full name */ snprintf(num, sizeof(num), "%s%s", MD_NAME, u); if (strcmp(u, name) == 0 || strcmp(num, name) == 0) { ret = 1; break; } } free(ptr); return (ret); } static void md_prthumanval(char *length) { char buf[6]; uintmax_t bytes; char *endptr; errno = 0; bytes = strtoumax(length, &endptr, 10); if (errno != 0 || *endptr != '\0' || bytes > INT64_MAX) return; humanize_number(buf, sizeof(buf), (int64_t)bytes, "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); (void)printf("%6s", buf); } static int md_query(const char *name, const int opt, const char *fflag) { return (md_list(name, opt | OPT_UNIT, fflag)); } Index: projects/release-pkg/sbin =================================================================== --- projects/release-pkg/sbin (revision 289118) +++ projects/release-pkg/sbin (revision 289119) Property changes on: projects/release-pkg/sbin ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sbin:r289091-289118 Index: projects/release-pkg/share/man/man4/vtnet.4 =================================================================== --- projects/release-pkg/share/man/man4/vtnet.4 (revision 289118) +++ projects/release-pkg/share/man/man4/vtnet.4 (revision 289119) @@ -1,115 +1,115 @@ .\" Copyright (c) 2011 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 January 22, 2012 .Dt VTNET 4 .Os .Sh NAME .Nm vtnet .Nd VirtIO Ethernet 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 vtnet" .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 if_vtnet_load="YES" .Ed .Sh DESCRIPTION The .Nm device driver provides support for VirtIO Ethernet devices. .Pp If the hypervisor advertises the appreciate features, the .Nm driver supports TCP/UDP checksum offload for both transmit and receive, -TCP segmentation offload (TSO), TCP large receive offload (LRO), and -hardware VLAN tag stripping/insertion features, as well as a multicast -hash filter, as well as Jumbo Frames (up to 9216 bytes), which can be +TCP segmentation offload (TSO), TCP large receive offload (LRO), +hardware VLAN tag stripping/insertion features, a multicast hash filter, +as well as Jumbo Frames (up to 9216 bytes), which can be configured via the interface MTU setting. Selecting an MTU larger than 1500 bytes with the .Xr ifconfig 8 utility configures the adapter to receive and transmit Jumbo Frames. .Pp For more information on configuring this device, see .Xr ifconfig 8 . .Sh LOADER TUNABLES Tunables can be set at the .Xr loader 8 prompt before booting the kernel or stored in .Xr loader.conf 5 . .Bl -tag -width "xxxxxx" .It Va hw.vtnet.csum_disable .It Va hw.vtnet. Ns Ar X Ns Va .csum_disable This tunable disables receive and send checksum offload. The default value is 0. .It Va hw.vtnet.tso_disable .It Va hw.vtnet. Ns Ar X Ns Va .tso_disable This tunable disables TSO. The default value is 0. .It Va hw.vtnet.lro_disable .It Va hw.vtnet. Ns Ar X Ns Va .lro_disable This tunable disables LRO. The default value is 0. .It Va hw.vtnet.mq_disable .It Va hw.vtnet. Ns Ar X Ns Va .mq_disable This tunable disables multiqueue. The default value is 0. .It Va hw.vtnet.mq_max_pairs .It Va hw.vtnet. Ns Ar X Ns Va .mq_max_pairs This tunable sets the maximum number of transmit and receive queue pairs. Multiple queues are only supported when the Multiqueue feature is negotiated. This driver supports a maximum of 8 queue pairs. The number of queue pairs used is the lesser of the maximum supported by the driver and the hypervisor, the number of CPUs present in the guest, and this tunable if not zero. The default value is 0. .El .Sh SEE ALSO .Xr arp 4 , .Xr netintro 4 , .Xr ng_ether 4 , .Xr virtio 4 , .Xr vlan 4 , .Xr ifconfig 8 .Sh HISTORY The .Nm driver was written by .An Bryan Venteicher Aq Mt bryanv@FreeBSD.org . It first appeared in .Fx 9.0 . .Sh CAVEATS The .Nm driver only supports LRO when the hypervisor advertises the mergeable buffer feature. Index: projects/release-pkg/share/man/man4 =================================================================== --- projects/release-pkg/share/man/man4 (revision 289118) +++ projects/release-pkg/share/man/man4 (revision 289119) Property changes on: projects/release-pkg/share/man/man4 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/share/man/man4:r289091-289118 Index: projects/release-pkg/share/mk/Makefile =================================================================== --- projects/release-pkg/share/mk/Makefile (revision 289118) +++ projects/release-pkg/share/mk/Makefile (revision 289119) @@ -1,71 +1,72 @@ # $FreeBSD$ # @(#)Makefile 8.1 (Berkeley) 6/8/93 # Only parse this if executing make in this directory, not in other places # in src that lack a Makefile, such as sys/dev/*. Otherwise the MAKESYSPATH # will read this Makefile since it auto includes it into -I. .if ${.CURDIR} == ${.PARSEDIR} .include FILES= \ auto.obj.mk \ bsd.README \ bsd.arch.inc.mk \ bsd.compiler.mk \ + bsd.confs.mk \ bsd.cpu.mk \ bsd.crunchgen.mk \ bsd.dep.mk \ bsd.doc.mk \ bsd.dtb.mk \ bsd.endian.mk \ bsd.files.mk \ bsd.incs.mk \ bsd.info.mk \ bsd.init.mk \ bsd.kmod.mk \ bsd.lib.mk \ bsd.libnames.mk \ bsd.links.mk \ bsd.man.mk \ bsd.mkopt.mk \ bsd.nls.mk \ bsd.obj.mk \ bsd.opts.mk \ bsd.own.mk \ bsd.port.mk \ bsd.port.options.mk \ bsd.port.post.mk \ bsd.port.pre.mk \ bsd.port.subdir.mk \ bsd.prog.mk \ bsd.progs.mk \ bsd.snmpmod.mk \ bsd.subdir.mk \ bsd.symver.mk \ bsd.sys.mk \ bsd.test.mk \ dirdeps.mk \ gendirdeps.mk \ install-new.mk \ meta.autodep.mk \ meta.stage.mk \ meta.subdir.mk \ meta.sys.mk \ stage-install.sh \ sys.mk \ sys.dependfile.mk \ version_gen.awk NO_OBJ= FILESDIR= ${BINDIR}/mk .if ${MK_TESTS} != "no" FILES+= atf.test.mk FILES+= plain.test.mk FILES+= suite.test.mk FILES+= tap.test.mk .endif .include .endif # CURDIR == PARSEDIR Index: projects/release-pkg/share/mk/bsd.confs.mk =================================================================== --- projects/release-pkg/share/mk/bsd.confs.mk (revision 289118) +++ projects/release-pkg/share/mk/bsd.confs.mk (revision 289119) @@ -1,87 +1,87 @@ # $FreeBSD$ .if !target(____) .error bsd.conf.mk cannot be included directly. .endif .if ${MK_INCLUDES} != "no" CONFGROUPS?= CONFS .if !target(buildconfig) .for group in ${CONFSGROUPS} buildconfig: ${${group}} .endfor .endif all: buildconfig .if !target(installconfig) .for group in ${CONFGROUPS} .if defined(${group}) && !empty(${group}) ${group}OWN?= ${SHAREOWN} ${group}GRP?= ${SHAREGRP} ${group}MODE?= ${CONFMODE} -${group}DIR?= ${ETCDIR}/ +${group}DIR?= ${CONFIGDIR}/ STAGE_SETS+= ${group} STAGE_DIR.${group}= ${STAGE_OBJTOP}${${group}DIR} STAGE_SYMLINKS_DIR.${group}= ${STAGE_OBJTOP} _${group}CONFS= .for cnf in ${${group}} .if defined(${group}OWN_${cnf:T}) || defined(${group}GRP_${cnf:T}) || \ defined(${group}MODE_${cnf:T}) || defined(${group}DIR_${cnf:T}) || \ defined(${group}NAME_${cnf:T}) || defined(${group}NAME) ${group}OWN_${cnf:T}?= ${${group}OWN} ${group}GRP_${cnf:T}?= ${${group}GRP} ${group}MODE_${cnf:T}?= ${${group}MODE} ${group}DIR_${cnf:T}?= ${${group}DIR} .if defined(${group}NAME) ${group}NAME_${cnf:T}?= ${${group}NAME} .else ${group}NAME_${cnf:T}?= ${cnf:T} .endif STAGE_AS_SETS+= ${cnf:T} STAGE_AS_${cnf:T}= ${${group}NAME_${cnf:T}} # XXX {group}OWN,GRP,MODE STAGE_DIR.${cnf:T}= ${STAGE_OBJTOP}${${group}DIR_${cnf:T}} stage_as.${cnf:T}: ${cnf} stage_config: stage_as.${cnf:T} installconfig: _${group}INS_${cnf:T} _${group}INS_${cnf:T}: ${cnf} ${INSTALL} -C -o ${${group}OWN_${.ALLSRC:T}} \ -g ${${group}GRP_${.ALLSRC:T}} -m ${${group}MODE_${.ALLSRC:T}} \ ${.ALLSRC} \ ${DESTDIR}${${group}DIR_${.ALLSRC:T}}/${${group}NAME_${.ALLSRC:T}} .else _${group}CONFS+= ${cnf} .endif .endfor .if !empty(_${group}CONFS) stage_files.${group}: ${_${group}CONFS} stage_config: stage_files.${group} installconfig: _${group}INS _${group}INS: ${_${group}CONFS} .if defined(${group}NAME) ${INSTALL} -C -o ${${group}OWN} -g ${${group}GRP} -m ${${group}MODE} \ ${.ALLSRC} ${DESTDIR}${${group}DIR}/${${group}NAME} .else ${INSTALL} -C -o ${${group}OWN} -g ${${group}GRP} -m ${${group}MODE} \ ${.ALLSRC} ${DESTDIR}${${group}DIR} .endif .endif .endif # defined(${group}) && !empty(${group}) .endfor .endif # !target(installconfig) .if ${MK_STAGING} != "no" && !defined(_SKIP_BUILD) .if !defined(NO_STAGE_CONFIG) STAGE_TARGETS+= stage_config .endif .endif .endif # ${MK_TOOLCHAIN} != "no" Index: projects/release-pkg/share/mk/bsd.own.mk =================================================================== --- projects/release-pkg/share/mk/bsd.own.mk (revision 289118) +++ projects/release-pkg/share/mk/bsd.own.mk (revision 289119) @@ -1,256 +1,256 @@ # $FreeBSD$ # # The include file set common variables for owner, # group, mode, and directories. Defaults are in brackets. # # # +++ variables +++ # # DESTDIR Change the tree where the file gets installed. [not set] # # DISTDIR Change the tree where the file for a distribution # gets installed (see /usr/src/release/Makefile). [not set] # # COMPRESS_CMD Program to compress documents. # Output is to stdout. [gzip -cn] # # COMPRESS_EXT File name extension of ${COMPRESS_CMD} command. [.gz] # # BINOWN Binary owner. [root] # # BINGRP Binary group. [wheel] # # BINMODE Binary mode. [555] # # NOBINMODE Mode for non-executable files. [444] # # LIBDIR Base path for libraries. [/usr/lib] # # LIBCOMPATDIR Base path for compat libraries. [/usr/lib/compat] # # LIBDATADIR Base path for misc. utility data files. [/usr/libdata] # # LIBEXECDIR Base path for system daemons and utilities. [/usr/libexec] # # LINTLIBDIR Base path for lint libraries. [/usr/libdata/lint] # # SHLIBDIR Base path for shared libraries. [${LIBDIR}] # # LIBOWN Library owner. [${BINOWN}] # # LIBGRP Library group. [${BINGRP}] # # LIBMODE Library mode. [${NOBINMODE}] # # # DEBUGDIR Base path for standalone debug files. [/usr/lib/debug] # # DEBUGMODE Mode for debug files. [${NOBINMODE}] # # # KMODDIR Base path for loadable kernel modules # (see kld(4)). [/boot/kernel] # # KMODOWN Kernel and KLD owner. [${BINOWN}] # # KMODGRP Kernel and KLD group. [${BINGRP}] # # KMODMODE KLD mode. [${BINMODE}] # # # SHAREDIR Base path for architecture-independent ascii # text files. [/usr/share] # # SHAREOWN ASCII text file owner. [root] # # SHAREGRP ASCII text file group. [wheel] # # SHAREMODE ASCII text file mode. [${NOBINMODE}] # # # CONFDIR Base path for configuration files. [/etc] # # CONFOWN Configuration file owner. [root] # # CONFGRP Configuration file group. [wheel] # # CONFMODE Configuration file mode. [644] # # # DOCDIR Base path for system documentation (e.g. PSD, USD, # handbook, FAQ etc.). [${SHAREDIR}/doc] # # DOCOWN Documentation owner. [${SHAREOWN}] # # DOCGRP Documentation group. [${SHAREGRP}] # # DOCMODE Documentation mode. [${NOBINMODE}] # # # INFODIR Base path for GNU's hypertext system # called Info (see info(1)). [${SHAREDIR}/info] # # INFOOWN Info owner. [${SHAREOWN}] # # INFOGRP Info group. [${SHAREGRP}] # # INFOMODE Info mode. [${NOBINMODE}] # # # MANDIR Base path for manual installation. [${SHAREDIR}/man/man] # # MANOWN Manual owner. [${SHAREOWN}] # # MANGRP Manual group. [${SHAREGRP}] # # MANMODE Manual mode. [${NOBINMODE}] # # # NLSDIR Base path for National Language Support files # installation. [${SHAREDIR}/nls] # # NLSOWN National Language Support files owner. [${SHAREOWN}] # # NLSGRP National Language Support files group. [${SHAREGRP}] # # NLSMODE National Language Support files mode. [${NOBINMODE}] # # INCLUDEDIR Base path for standard C include files [/usr/include] .if !target(____) ____: .include # options now here or src.opts.mk .if !defined(_WITHOUT_SRCCONF) .if ${MK_CTF} != "no" CTFCONVERT_CMD= ${CTFCONVERT} ${CTFFLAGS} ${.TARGET} .elif defined(.PARSEDIR) || (defined(MAKE_VERSION) && ${MAKE_VERSION} >= 5201111300) CTFCONVERT_CMD= .else CTFCONVERT_CMD= @: .endif .if ${MK_INSTALL_AS_USER} != "no" _uid!= id -u .if ${_uid} != 0 .if !defined(USER) USER!= id -un .endif _gid!= id -g .for x in BIN CONF DOC DTB INFO KMOD LIB MAN NLS SHARE $xOWN= ${USER} $xGRP= ${_gid} .endfor .endif .endif .endif # !_WITHOUT_SRCCONF # Binaries BINOWN?= root BINGRP?= wheel BINMODE?= 555 NOBINMODE?= 444 .if defined(MODULES_WITH_WORLD) KMODDIR?= /boot/modules .else KMODDIR?= /boot/kernel .endif KMODOWN?= ${BINOWN} KMODGRP?= ${BINGRP} KMODMODE?= ${BINMODE} DTBDIR?= /boot/dtb DTBOWN?= root DTBGRP?= wheel DTBMODE?= 444 LIBDIR?= /usr/lib LIBCOMPATDIR?= /usr/lib/compat LIBDATADIR?= /usr/libdata LIBEXECDIR?= /usr/libexec LINTLIBDIR?= /usr/libdata/lint SHLIBDIR?= ${LIBDIR} LIBOWN?= ${BINOWN} LIBGRP?= ${BINGRP} LIBMODE?= ${NOBINMODE} DEBUGDIR?= /usr/lib/debug DEBUGMODE?= ${NOBINMODE} # Share files SHAREDIR?= /usr/share SHAREOWN?= root SHAREGRP?= wheel SHAREMODE?= ${NOBINMODE} CONFDIR?= /etc CONFOWN?= root CONFGRP?= wheel CONFMODE?= 644 MANDIR?= ${SHAREDIR}/man/man MANOWN?= ${SHAREOWN} MANGRP?= ${SHAREGRP} MANMODE?= ${NOBINMODE} DOCDIR?= ${SHAREDIR}/doc DOCOWN?= ${SHAREOWN} DOCGRP?= ${SHAREGRP} DOCMODE?= ${NOBINMODE} INFODIR?= ${SHAREDIR}/info INFOOWN?= ${SHAREOWN} INFOGRP?= ${SHAREGRP} INFOMODE?= ${NOBINMODE} NLSDIR?= ${SHAREDIR}/nls NLSOWN?= ${SHAREOWN} NLSGRP?= ${SHAREGRP} NLSMODE?= ${NOBINMODE} INCLUDEDIR?= /usr/include -ETCDIR?= /etc +CONFIGDIR?= /etc # # install(1) parameters. # HRDLINK?= -l h SYMLINK?= -l s RSYMLINK?= -l rs INSTALL_LINK?= ${INSTALL} ${HRDLINK} INSTALL_SYMLINK?= ${INSTALL} ${SYMLINK} INSTALL_RSYMLINK?= ${INSTALL} ${RSYMLINK} # Common variables .if !defined(DEBUG_FLAGS) STRIP?= -s .endif COMPRESS_CMD?= gzip -cn COMPRESS_EXT?= .gz # Set XZ_THREADS to 1 to disable multi-threading. XZ_THREADS?= 0 .if !empty(XZ_THREADS) XZ_CMD?= xz -T ${XZ_THREADS} .else XZ_CMD?= xz .endif # Pointer to the top directory into which tests are installed. Should not be # overriden by Makefiles, but the user may choose to set this in src.conf(5). TESTSBASE?= /usr/tests # Compat for the moment -- old bsd.own.mk only included this when _WITHOUT_SRCCONF # wasn't defined. bsd.ports.mk and friends depend on this behavior. Remove in 12. .if !defined(_WITHOUT_SRCCONF) .include .endif # !_WITHOUT_SRCCONF .endif # !target(____) Index: projects/release-pkg/share =================================================================== --- projects/release-pkg/share (revision 289118) +++ projects/release-pkg/share (revision 289119) Property changes on: projects/release-pkg/share ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/share:r289091-289118 Index: projects/release-pkg/sys/arm/freescale/imx/imx_i2c.c =================================================================== --- projects/release-pkg/sys/arm/freescale/imx/imx_i2c.c (revision 289118) +++ projects/release-pkg/sys/arm/freescale/imx/imx_i2c.c (revision 289119) @@ -1,531 +1,482 @@ /*- * Copyright (C) 2008-2009 Semihalf, Michal Hajduk * Copyright (c) 2012, 2013 The FreeBSD Foundation + * Copyright (c) 2015 Ian Lepore * All rights reserved. * * Portions of this software were developed by Oleksandr 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 * 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. */ +/* + * I2C driver for Freescale i.MX hardware. + * + * Note that the hardware is capable of running as both a master and a slave. + * This driver currently implements only master-mode operations. + * + * This driver supports multi-master i2c busses, by detecting bus arbitration + * loss and returning IIC_EBUSBSY status. Notably, it does not do any kind of + * retries if some other master jumps onto the bus and interrupts one of our + * transfer cycles resulting in arbitration loss in mid-transfer. The caller + * must handle retries in a way that makes sense for the slave being addressed. + */ + #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include -#include -#include - #include #include #include #include "iicbus_if.h" #include #include #include #include #define I2C_ADDR_REG 0x00 /* I2C slave address register */ #define I2C_FDR_REG 0x04 /* I2C frequency divider register */ #define I2C_CONTROL_REG 0x08 /* I2C control register */ #define I2C_STATUS_REG 0x0C /* I2C status register */ #define I2C_DATA_REG 0x10 /* I2C data register */ #define I2C_DFSRR_REG 0x14 /* I2C Digital Filter Sampling rate */ #define I2CCR_MEN (1 << 7) /* Module enable */ #define I2CCR_MSTA (1 << 5) /* Master/slave mode */ #define I2CCR_MTX (1 << 4) /* Transmit/receive mode */ #define I2CCR_TXAK (1 << 3) /* Transfer acknowledge */ #define I2CCR_RSTA (1 << 2) /* Repeated START */ #define I2CSR_MCF (1 << 7) /* Data transfer */ #define I2CSR_MASS (1 << 6) /* Addressed as a slave */ #define I2CSR_MBB (1 << 5) /* Bus busy */ #define I2CSR_MAL (1 << 4) /* Arbitration lost */ #define I2CSR_SRW (1 << 2) /* Slave read/write */ #define I2CSR_MIF (1 << 1) /* Module interrupt */ #define I2CSR_RXAK (1 << 0) /* Received acknowledge */ #define I2C_BAUD_RATE_FAST 0x31 #define I2C_BAUD_RATE_DEF 0x3F #define I2C_DFSSR_DIV 0x10 /* * A table of available divisors and the associated coded values to put in the * FDR register to achieve that divisor.. There is no algorithmic relationship I * can see between divisors and the codes that go into the register. The table * begins and ends with entries that handle insane configuration values. */ struct clkdiv { u_int divisor; u_int regcode; }; static struct clkdiv clkdiv_table[] = { { 0, 0x20 }, { 22, 0x20 }, { 24, 0x21 }, { 26, 0x22 }, { 28, 0x23 }, { 30, 0x00 }, { 32, 0x24 }, { 36, 0x25 }, { 40, 0x26 }, { 42, 0x03 }, { 44, 0x27 }, { 48, 0x28 }, { 52, 0x05 }, { 56, 0x29 }, { 60, 0x06 }, { 64, 0x2a }, { 72, 0x2b }, { 80, 0x2c }, { 88, 0x09 }, { 96, 0x2d }, { 104, 0x0a }, { 112, 0x2e }, { 128, 0x2f }, { 144, 0x0c }, { 160, 0x30 }, { 192, 0x31 }, { 224, 0x32 }, { 240, 0x0f }, { 256, 0x33 }, { 288, 0x10 }, { 320, 0x34 }, { 384, 0x35 }, { 448, 0x36 }, { 480, 0x13 }, { 512, 0x37 }, { 576, 0x14 }, { 640, 0x38 }, { 768, 0x39 }, { 896, 0x3a }, { 960, 0x17 }, { 1024, 0x3b }, { 1152, 0x18 }, { 1280, 0x3c }, { 1536, 0x3d }, { 1792, 0x3e }, { 1920, 0x1b }, { 2048, 0x3f }, { 2304, 0x1c }, { 2560, 0x1d }, { 3072, 0x1e }, { 3840, 0x1f }, {UINT_MAX, 0x1f} }; -#ifdef DEBUG -#define debugf(fmt, args...) do { printf("%s(): ", __func__); \ - printf(fmt,##args); } while (0) -#else -#define debugf(fmt, args...) -#endif - static struct ofw_compat_data compat_data[] = { {"fsl,imx6q-i2c", 1}, {"fsl,imx-i2c", 1}, {NULL, 0} }; struct i2c_softc { device_t dev; device_t iicbus; struct resource *res; - struct mtx mutex; int rid; - bus_space_handle_t bsh; - bus_space_tag_t bst; + sbintime_t byte_time_sbt; }; static phandle_t i2c_get_node(device_t, device_t); static int i2c_probe(device_t); static int i2c_attach(device_t); static int i2c_repeated_start(device_t, u_char, int); static int i2c_start(device_t, u_char, int); static int i2c_stop(device_t); static int i2c_reset(device_t, u_char, u_char, u_char *); static int i2c_read(device_t, char *, int, int *, int, int); static int i2c_write(device_t, const char *, int, int *, int); static device_method_t i2c_methods[] = { DEVMETHOD(device_probe, i2c_probe), DEVMETHOD(device_attach, i2c_attach), /* OFW methods */ DEVMETHOD(ofw_bus_get_node, i2c_get_node), DEVMETHOD(iicbus_callback, iicbus_null_callback), DEVMETHOD(iicbus_repeated_start, i2c_repeated_start), DEVMETHOD(iicbus_start, i2c_start), DEVMETHOD(iicbus_stop, i2c_stop), DEVMETHOD(iicbus_reset, i2c_reset), DEVMETHOD(iicbus_read, i2c_read), DEVMETHOD(iicbus_write, i2c_write), DEVMETHOD(iicbus_transfer, iicbus_transfer_gen), - { 0, 0 } + DEVMETHOD_END }; static driver_t i2c_driver = { "iichb", i2c_methods, sizeof(struct i2c_softc), }; static devclass_t i2c_devclass; DRIVER_MODULE(i2c, simplebus, i2c_driver, i2c_devclass, 0, 0); DRIVER_MODULE(iicbus, i2c, iicbus_driver, iicbus_devclass, 0, 0); static phandle_t i2c_get_node(device_t bus, device_t dev) { /* * Share controller node with iicbus device */ return ofw_bus_get_node(bus); } static __inline void i2c_write_reg(struct i2c_softc *sc, bus_size_t off, uint8_t val) { - bus_space_write_1(sc->bst, sc->bsh, off, val); + bus_write_1(sc->res, off, val); } static __inline uint8_t i2c_read_reg(struct i2c_softc *sc, bus_size_t off) { - return (bus_space_read_1(sc->bst, sc->bsh, off)); + return (bus_read_1(sc->res, off)); } static __inline void i2c_flag_set(struct i2c_softc *sc, bus_size_t off, uint8_t mask) { uint8_t status; status = i2c_read_reg(sc, off); status |= mask; i2c_write_reg(sc, off, status); } -/* Wait for transfer interrupt flag */ +/* Wait for bus to become busy or not-busy. */ static int -wait_for_iif(struct i2c_softc *sc) +wait_for_busbusy(struct i2c_softc *sc, int wantbusy) { - int retry; + int retry, srb; retry = 1000; while (retry --) { - if (i2c_read_reg(sc, I2C_STATUS_REG) & I2CSR_MIF) + srb = i2c_read_reg(sc, I2C_STATUS_REG) & I2CSR_MBB; + if ((srb && wantbusy) || (!srb && !wantbusy)) return (IIC_NOERR); - DELAY(10); + DELAY(1); } - return (IIC_ETIMEOUT); } -/* Wait for free bus */ +/* Wait for transfer to complete, optionally check RXAK. */ static int -wait_for_nibb(struct i2c_softc *sc) +wait_for_xfer(struct i2c_softc *sc, int checkack) { - int retry; + int retry, sr; - retry = 1000; + /* + * Sleep for about the time it takes to transfer a byte (with precision + * set to tolerate 5% oversleep). We calculate the approximate byte + * transfer time when we set the bus speed divisor. Slaves are allowed + * to do clock-stretching so the actual transfer time can be larger, but + * this gets the bulk of the waiting out of the way without tying up the + * processor the whole time. + */ + pause_sbt("imxi2c", sc->byte_time_sbt, sc->byte_time_sbt / 20, 0); + + retry = 10000; while (retry --) { - if ((i2c_read_reg(sc, I2C_STATUS_REG) & I2CSR_MBB) == 0) - return (IIC_NOERR); - DELAY(10); + sr = i2c_read_reg(sc, I2C_STATUS_REG); + if (sr & I2CSR_MIF) { + if (sr & I2CSR_MAL) + return (IIC_EBUSERR); + else if (checkack && (sr & I2CSR_RXAK)) + return (IIC_ENOACK); + else + return (IIC_NOERR); + } + DELAY(1); } - return (IIC_ETIMEOUT); } -/* Wait for transfer complete+interrupt flag */ +/* + * Implement the error handling shown in the state diagram of the imx6 reference + * manual. If there was an error, then: + * - Clear master mode (MSTA and MTX). + * - Wait for the bus to become free or for a timeout to happen. + * - Disable the controller. + */ static int -wait_for_icf(struct i2c_softc *sc) +i2c_error_handler(struct i2c_softc *sc, int error) { - int retry; - retry = 1000; - while (retry --) { - - if ((i2c_read_reg(sc, I2C_STATUS_REG) & - (I2CSR_MCF|I2CSR_MIF)) == (I2CSR_MCF|I2CSR_MIF)) - return (IIC_NOERR); - DELAY(10); + if (error != 0) { + i2c_write_reg(sc, I2C_STATUS_REG, 0); + i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN); + wait_for_busbusy(sc, false); + i2c_write_reg(sc, I2C_CONTROL_REG, 0); } - - return (IIC_ETIMEOUT); + return (error); } static int i2c_probe(device_t dev) { - struct i2c_softc *sc; if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); - sc = device_get_softc(dev); - sc->rid = 0; + device_set_desc(dev, "Freescale i.MX I2C"); - sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid, - RF_ACTIVE); - if (sc->res == NULL) { - device_printf(dev, "could not allocate resources\n"); - return (ENXIO); - } - - sc->bst = rman_get_bustag(sc->res); - sc->bsh = rman_get_bushandle(sc->res); - - /* Enable I2C */ - i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN); - bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res); - device_set_desc(dev, "Freescale i.MX I2C bus controller"); - return (BUS_PROBE_DEFAULT); } static int i2c_attach(device_t dev) { struct i2c_softc *sc; sc = device_get_softc(dev); sc->dev = dev; sc->rid = 0; - mtx_init(&sc->mutex, device_get_nameunit(dev), "I2C", MTX_DEF); - sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid, RF_ACTIVE); if (sc->res == NULL) { device_printf(dev, "could not allocate resources"); - mtx_destroy(&sc->mutex); return (ENXIO); } - sc->bst = rman_get_bustag(sc->res); - sc->bsh = rman_get_bushandle(sc->res); - sc->iicbus = device_add_child(dev, "iicbus", -1); if (sc->iicbus == NULL) { device_printf(dev, "could not add iicbus child"); - mtx_destroy(&sc->mutex); return (ENXIO); } bus_generic_attach(dev); - return (IIC_NOERR); + return (0); } static int i2c_repeated_start(device_t dev, u_char slave, int timeout) { struct i2c_softc *sc; int error; sc = device_get_softc(dev); - mtx_lock(&sc->mutex); - - i2c_write_reg(sc, I2C_ADDR_REG, slave); if ((i2c_read_reg(sc, I2C_STATUS_REG) & I2CSR_MBB) == 0) { - mtx_unlock(&sc->mutex); - return (IIC_EBUSBSY); + return (IIC_EBUSERR); } - /* Set repeated start condition */ - DELAY(10); + /* + * Set repeated start condition, delay (per reference manual, min 156nS) + * before writing slave address, wait for ack after write. + */ i2c_flag_set(sc, I2C_CONTROL_REG, I2CCR_RSTA); - DELAY(10); - /* Clear status */ + DELAY(1); i2c_write_reg(sc, I2C_STATUS_REG, 0x0); - /* Write target address - LSB is R/W bit */ i2c_write_reg(sc, I2C_DATA_REG, slave); - - error = wait_for_iif(sc); - - /* Clear status */ - i2c_write_reg(sc, I2C_STATUS_REG, 0x0); - - mtx_unlock(&sc->mutex); - - if (error) - return (error); - - return (IIC_NOERR); + error = wait_for_xfer(sc, true); + return (i2c_error_handler(sc, error)); } static int i2c_start(device_t dev, u_char slave, int timeout) { struct i2c_softc *sc; int error; sc = device_get_softc(dev); - mtx_lock(&sc->mutex); - i2c_write_reg(sc, I2C_ADDR_REG, slave); + i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN); + DELAY(10); /* Delay for controller to sample bus state. */ if (i2c_read_reg(sc, I2C_STATUS_REG) & I2CSR_MBB) { - mtx_unlock(&sc->mutex); - return (IIC_EBUSBSY); + return (i2c_error_handler(sc, IIC_EBUSERR)); } - - /* Set start condition */ - i2c_write_reg(sc, I2C_CONTROL_REG, - I2CCR_MEN | I2CCR_MSTA | I2CCR_TXAK); - DELAY(100); - i2c_write_reg(sc, I2C_CONTROL_REG, - I2CCR_MEN | I2CCR_MSTA | I2CCR_MTX | I2CCR_TXAK); - /* Clear status */ - i2c_write_reg(sc, I2C_STATUS_REG, 0x0); - /* Write target address - LSB is R/W bit */ + i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | I2CCR_MSTA | I2CCR_MTX); + if ((error = wait_for_busbusy(sc, true)) != IIC_NOERR) + return (i2c_error_handler(sc, error)); + i2c_write_reg(sc, I2C_STATUS_REG, 0); i2c_write_reg(sc, I2C_DATA_REG, slave); - - error = wait_for_iif(sc); - - mtx_unlock(&sc->mutex); - if (error) - return (error); - - return (IIC_NOERR); + error = wait_for_xfer(sc, true); + return (i2c_error_handler(sc, error)); } - static int i2c_stop(device_t dev) { struct i2c_softc *sc; sc = device_get_softc(dev); - mtx_lock(&sc->mutex); - i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | I2CCR_TXAK); - DELAY(100); - /* Reset controller if bus still busy after STOP */ - if (wait_for_nibb(sc) == IIC_ETIMEOUT) { - i2c_write_reg(sc, I2C_CONTROL_REG, 0); - DELAY(1000); - i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | I2CCR_TXAK); - i2c_write_reg(sc, I2C_STATUS_REG, 0x0); - } - mtx_unlock(&sc->mutex); - + i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN); + wait_for_busbusy(sc, false); + i2c_write_reg(sc, I2C_CONTROL_REG, 0); return (IIC_NOERR); } static int i2c_reset(device_t dev, u_char speed, u_char addr, u_char *oldadr) { struct i2c_softc *sc; u_int busfreq, div, i, ipgfreq; sc = device_get_softc(dev); /* * Look up the divisor that gives the nearest speed that doesn't exceed * the configured value for the bus. */ ipgfreq = imx_ccm_ipg_hz(); busfreq = IICBUS_GET_FREQUENCY(sc->iicbus, speed); div = (ipgfreq + busfreq - 1) / busfreq; for (i = 0; i < nitems(clkdiv_table); i++) { if (clkdiv_table[i].divisor >= div) break; } - div = clkdiv_table[i].regcode; - mtx_lock(&sc->mutex); - i2c_write_reg(sc, I2C_CONTROL_REG, 0x0); - i2c_write_reg(sc, I2C_STATUS_REG, 0x0); - DELAY(1000); + /* + * Calculate roughly how long it will take to transfer a byte (which + * requires 9 clock cycles) at the new bus speed. This value is used to + * pause() while waiting for transfer-complete. With a 66MHz IPG clock + * and the actual i2c bus speeds that leads to, for nominal 100KHz and + * 400KHz bus speeds the transfer times are roughly 104uS and 22uS. + */ + busfreq = ipgfreq / clkdiv_table[i].divisor; + sc->byte_time_sbt = SBT_1US * (9000000 / busfreq); - i2c_write_reg(sc, I2C_FDR_REG, (uint8_t)div); - i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN); - DELAY(1000); + /* + * Disable the controller (do the reset), and set the new clock divisor. + */ i2c_write_reg(sc, I2C_STATUS_REG, 0x0); - mtx_unlock(&sc->mutex); - + i2c_write_reg(sc, I2C_CONTROL_REG, 0x0); + i2c_write_reg(sc, I2C_FDR_REG, (uint8_t)clkdiv_table[i].regcode); return (IIC_NOERR); } static int i2c_read(device_t dev, char *buf, int len, int *read, int last, int delay) { struct i2c_softc *sc; int error, reg; sc = device_get_softc(dev); *read = 0; - mtx_lock(&sc->mutex); - if (len) { if (len == 1) i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | I2CCR_MSTA | I2CCR_TXAK); - else i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | I2CCR_MSTA); - - /* dummy read */ + /* Dummy read to prime the receiver. */ + i2c_write_reg(sc, I2C_STATUS_REG, 0x0); i2c_read_reg(sc, I2C_DATA_REG); - DELAY(1000); } + error = 0; + *read = 0; while (*read < len) { - error = wait_for_icf(sc); - if (error) { - mtx_unlock(&sc->mutex); - return (error); - } + if ((error = wait_for_xfer(sc, false)) != IIC_NOERR) + break; i2c_write_reg(sc, I2C_STATUS_REG, 0x0); - if ((*read == len - 2) && last) { - /* NO ACK on last byte */ - i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | - I2CCR_MSTA | I2CCR_TXAK); + if (last) { + if (*read == len - 2) { + /* NO ACK on last byte */ + i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | + I2CCR_MSTA | I2CCR_TXAK); + } else if (*read == len - 1) { + /* Transfer done, signal stop. */ + i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | + I2CCR_TXAK); + wait_for_busbusy(sc, false); + } } - - if ((*read == len - 1) && last) { - /* Transfer done, remove master bit */ - i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | - I2CCR_TXAK); - } - reg = i2c_read_reg(sc, I2C_DATA_REG); *buf++ = reg; (*read)++; } - mtx_unlock(&sc->mutex); - return (IIC_NOERR); + return (i2c_error_handler(sc, error)); } static int i2c_write(device_t dev, const char *buf, int len, int *sent, int timeout) { struct i2c_softc *sc; int error; sc = device_get_softc(dev); - *sent = 0; - mtx_lock(&sc->mutex); + error = 0; + *sent = 0; while (*sent < len) { i2c_write_reg(sc, I2C_STATUS_REG, 0x0); i2c_write_reg(sc, I2C_DATA_REG, *buf++); - - error = wait_for_iif(sc); - if (error) { - mtx_unlock(&sc->mutex); - return (error); - } - + if ((error = wait_for_xfer(sc, true)) != IIC_NOERR) + break; (*sent)++; } - mtx_unlock(&sc->mutex); - return (IIC_NOERR); + return (i2c_error_handler(sc, error)); } Index: projects/release-pkg/sys/arm/freescale/vybrid/vf_i2c.c =================================================================== --- projects/release-pkg/sys/arm/freescale/vybrid/vf_i2c.c (revision 289118) +++ projects/release-pkg/sys/arm/freescale/vybrid/vf_i2c.c (revision 289119) @@ -1,470 +1,470 @@ /*- * Copyright (c) 2014 Ruslan Bukin * 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. */ /* * Vybrid Family Inter-Integrated Circuit (I2C) * Chapter 48, Vybrid Reference Manual, Rev. 5, 07/2013 */ /* * This driver is based on the I2C driver for i.MX */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include "iicbus_if.h" #include #include #include #include #include #include #include #include #define I2C_IBAD 0x0 /* I2C Bus Address Register */ #define I2C_IBFD 0x1 /* I2C Bus Frequency Divider Register */ #define I2C_IBCR 0x2 /* I2C Bus Control Register */ #define IBCR_MDIS (1 << 7) /* Module disable. */ #define IBCR_IBIE (1 << 6) /* I-Bus Interrupt Enable. */ #define IBCR_MSSL (1 << 5) /* Master/Slave mode select. */ #define IBCR_TXRX (1 << 4) /* Transmit/Receive mode select. */ #define IBCR_NOACK (1 << 3) /* Data Acknowledge disable. */ #define IBCR_RSTA (1 << 2) /* Repeat Start. */ #define IBCR_DMAEN (1 << 1) /* DMA Enable. */ #define I2C_IBSR 0x3 /* I2C Bus Status Register */ #define IBSR_TCF (1 << 7) /* Transfer complete. */ #define IBSR_IAAS (1 << 6) /* Addressed as a slave. */ #define IBSR_IBB (1 << 5) /* Bus busy. */ #define IBSR_IBAL (1 << 4) /* Arbitration Lost. */ #define IBSR_SRW (1 << 2) /* Slave Read/Write. */ #define IBSR_IBIF (1 << 1) /* I-Bus Interrupt Flag. */ #define IBSR_RXAK (1 << 0) /* Received Acknowledge. */ #define I2C_IBDR 0x4 /* I2C Bus Data I/O Register */ #define I2C_IBIC 0x5 /* I2C Bus Interrupt Config Register */ #define IBIC_BIIE (1 << 7) /* Bus Idle Interrupt Enable bit. */ #define I2C_IBDBG 0x6 /* I2C Bus Debug Register */ #ifdef DEBUG #define vf_i2c_dbg(_sc, fmt, args...) \ device_printf((_sc)->dev, fmt, ##args) #else #define vf_i2c_dbg(_sc, fmt, args...) #endif static int i2c_repeated_start(device_t, u_char, int); static int i2c_start(device_t, u_char, int); static int i2c_stop(device_t); static int i2c_reset(device_t, u_char, u_char, u_char *); static int i2c_read(device_t, char *, int, int *, int, int); static int i2c_write(device_t, const char *, int, int *, int); struct i2c_softc { struct resource *res[2]; bus_space_tag_t bst; bus_space_handle_t bsh; device_t dev; device_t iicbus; struct mtx mutex; }; static struct resource_spec i2c_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { SYS_RES_IRQ, 0, RF_ACTIVE }, { -1, 0 } }; static int i2c_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_is_compatible(dev, "fsl,mvf600-i2c")) return (ENXIO); device_set_desc(dev, "Vybrid Family Inter-Integrated Circuit (I2C)"); return (BUS_PROBE_DEFAULT); } static int i2c_attach(device_t dev) { struct i2c_softc *sc; sc = device_get_softc(dev); sc->dev = dev; mtx_init(&sc->mutex, device_get_nameunit(dev), "I2C", MTX_DEF); if (bus_alloc_resources(dev, i2c_spec, sc->res)) { device_printf(dev, "could not allocate resources\n"); return (ENXIO); } /* Memory interface */ sc->bst = rman_get_bustag(sc->res[0]); sc->bsh = rman_get_bushandle(sc->res[0]); WRITE1(sc, I2C_IBIC, IBIC_BIIE); sc->iicbus = device_add_child(dev, "iicbus", -1); if (sc->iicbus == NULL) { device_printf(dev, "could not add iicbus child"); mtx_destroy(&sc->mutex); return (ENXIO); } bus_generic_attach(dev); return (0); } /* Wait for transfer interrupt flag */ static int wait_for_iif(struct i2c_softc *sc) { int retry; retry = 1000; while (retry --) { if (READ1(sc, I2C_IBSR) & IBSR_IBIF) { WRITE1(sc, I2C_IBSR, IBSR_IBIF); return (IIC_NOERR); } DELAY(10); } return (IIC_ETIMEOUT); } /* Wait for free bus */ static int wait_for_nibb(struct i2c_softc *sc) { int retry; retry = 1000; while (retry --) { if ((READ1(sc, I2C_IBSR) & IBSR_IBB) == 0) return (IIC_NOERR); DELAY(10); } return (IIC_ETIMEOUT); } /* Wait for transfer complete+interrupt flag */ static int wait_for_icf(struct i2c_softc *sc) { int retry; retry = 1000; while (retry --) { if (READ1(sc, I2C_IBSR) & IBSR_TCF) { if (READ1(sc, I2C_IBSR) & IBSR_IBIF) { WRITE1(sc, I2C_IBSR, IBSR_IBIF); return (IIC_NOERR); } } DELAY(10); } return (IIC_ETIMEOUT); } static int i2c_repeated_start(device_t dev, u_char slave, int timeout) { struct i2c_softc *sc; int error; int reg; sc = device_get_softc(dev); vf_i2c_dbg(sc, "i2c repeated start\n"); mtx_lock(&sc->mutex); WRITE1(sc, I2C_IBAD, slave); if ((READ1(sc, I2C_IBSR) & IBSR_IBB) == 0) { mtx_unlock(&sc->mutex); - return (IIC_EBUSBSY); + return (IIC_EBUSERR); } /* Set repeated start condition */ DELAY(10); reg = READ1(sc, I2C_IBCR); reg |= (IBCR_RSTA | IBCR_IBIE); WRITE1(sc, I2C_IBCR, reg); DELAY(10); /* Write target address - LSB is R/W bit */ WRITE1(sc, I2C_IBDR, slave); error = wait_for_iif(sc); mtx_unlock(&sc->mutex); if (error) return (error); return (IIC_NOERR); } static int i2c_start(device_t dev, u_char slave, int timeout) { struct i2c_softc *sc; int error; int reg; sc = device_get_softc(dev); vf_i2c_dbg(sc, "i2c start\n"); mtx_lock(&sc->mutex); WRITE1(sc, I2C_IBAD, slave); if (READ1(sc, I2C_IBSR) & IBSR_IBB) { mtx_unlock(&sc->mutex); vf_i2c_dbg(sc, "cant i2c start: IIC_EBUSBSY\n"); - return (IIC_EBUSBSY); + return (IIC_EBUSERR); } /* Set start condition */ reg = (IBCR_MSSL | IBCR_NOACK | IBCR_IBIE); WRITE1(sc, I2C_IBCR, reg); DELAY(100); reg |= (IBCR_TXRX); WRITE1(sc, I2C_IBCR, reg); /* Write target address - LSB is R/W bit */ WRITE1(sc, I2C_IBDR, slave); error = wait_for_iif(sc); mtx_unlock(&sc->mutex); if (error) { vf_i2c_dbg(sc, "cant i2c start: iif error\n"); return (error); } return (IIC_NOERR); } static int i2c_stop(device_t dev) { struct i2c_softc *sc; sc = device_get_softc(dev); vf_i2c_dbg(sc, "i2c stop\n"); mtx_lock(&sc->mutex); WRITE1(sc, I2C_IBCR, IBCR_NOACK | IBCR_IBIE); DELAY(100); /* Reset controller if bus still busy after STOP */ if (wait_for_nibb(sc) == IIC_ETIMEOUT) { WRITE1(sc, I2C_IBCR, IBCR_MDIS); DELAY(1000); WRITE1(sc, I2C_IBCR, IBCR_NOACK); } mtx_unlock(&sc->mutex); return (IIC_NOERR); } static int i2c_reset(device_t dev, u_char speed, u_char addr, u_char *oldadr) { struct i2c_softc *sc; sc = device_get_softc(dev); vf_i2c_dbg(sc, "i2c reset\n"); switch (speed) { case IIC_FAST: case IIC_SLOW: case IIC_UNKNOWN: case IIC_FASTEST: default: break; } mtx_lock(&sc->mutex); WRITE1(sc, I2C_IBCR, IBCR_MDIS); DELAY(1000); WRITE1(sc, I2C_IBFD, 20); WRITE1(sc, I2C_IBCR, 0x0); /* Enable i2c */ DELAY(1000); mtx_unlock(&sc->mutex); return (IIC_NOERR); } static int i2c_read(device_t dev, char *buf, int len, int *read, int last, int delay) { struct i2c_softc *sc; int error; sc = device_get_softc(dev); vf_i2c_dbg(sc, "i2c read\n"); *read = 0; mtx_lock(&sc->mutex); if (len) { if (len == 1) WRITE1(sc, I2C_IBCR, IBCR_IBIE | IBCR_MSSL | \ IBCR_NOACK); else WRITE1(sc, I2C_IBCR, IBCR_IBIE | IBCR_MSSL); /* dummy read */ READ1(sc, I2C_IBDR); DELAY(1000); } while (*read < len) { error = wait_for_icf(sc); if (error) { mtx_unlock(&sc->mutex); return (error); } if ((*read == len - 2) && last) { /* NO ACK on last byte */ WRITE1(sc, I2C_IBCR, IBCR_IBIE | IBCR_MSSL | \ IBCR_NOACK); } if ((*read == len - 1) && last) { /* Transfer done, remove master bit */ WRITE1(sc, I2C_IBCR, IBCR_IBIE | IBCR_NOACK); } *buf++ = READ1(sc, I2C_IBDR); (*read)++; } mtx_unlock(&sc->mutex); return (IIC_NOERR); } static int i2c_write(device_t dev, const char *buf, int len, int *sent, int timeout) { struct i2c_softc *sc; int error; sc = device_get_softc(dev); vf_i2c_dbg(sc, "i2c write\n"); *sent = 0; mtx_lock(&sc->mutex); while (*sent < len) { WRITE1(sc, I2C_IBDR, *buf++); error = wait_for_iif(sc); if (error) { mtx_unlock(&sc->mutex); return (error); } (*sent)++; } mtx_unlock(&sc->mutex); return (IIC_NOERR); } static device_method_t i2c_methods[] = { DEVMETHOD(device_probe, i2c_probe), DEVMETHOD(device_attach, i2c_attach), DEVMETHOD(iicbus_callback, iicbus_null_callback), DEVMETHOD(iicbus_repeated_start, i2c_repeated_start), DEVMETHOD(iicbus_start, i2c_start), DEVMETHOD(iicbus_stop, i2c_stop), DEVMETHOD(iicbus_reset, i2c_reset), DEVMETHOD(iicbus_read, i2c_read), DEVMETHOD(iicbus_write, i2c_write), DEVMETHOD(iicbus_transfer, iicbus_transfer_gen), { 0, 0 } }; static driver_t i2c_driver = { "i2c", i2c_methods, sizeof(struct i2c_softc), }; static devclass_t i2c_devclass; DRIVER_MODULE(i2c, simplebus, i2c_driver, i2c_devclass, 0, 0); DRIVER_MODULE(iicbus, i2c, iicbus_driver, iicbus_devclass, 0, 0); Index: projects/release-pkg/sys/arm/samsung/exynos/exynos5_i2c.c =================================================================== --- projects/release-pkg/sys/arm/samsung/exynos/exynos5_i2c.c (revision 289118) +++ projects/release-pkg/sys/arm/samsung/exynos/exynos5_i2c.c (revision 289119) @@ -1,481 +1,481 @@ /*- * Copyright (c) 2014 Ruslan Bukin * 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. */ /* * Samsung Exynos 5 Inter-Integrated Circuit (I2C) * Chapter 13, Exynos 5 Dual User's Manual Public Rev 1.00 */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include "iicbus_if.h" #include #include #include #include #include #include #include #define I2CCON 0x00 /* Control register */ #define ACKGEN (1 << 7) /* Acknowledge Enable */ /* * Source Clock of I2C-bus Transmit Clock Prescaler * * 0 = I2CCLK = fPCLK/16 * 1 = I2CCLK = fPCLK/512 */ #define I2CCLK (1 << 6) #define IRQ_EN (1 << 5) /* Tx/Rx Interrupt Enable/Disable */ #define IPEND (1 << 4) /* Tx/Rx Interrupt Pending Flag */ #define CLKVAL_M 0xf /* Transmit Clock Prescaler Mask */ #define CLKVAL_S 0 #define I2CSTAT 0x04 /* Control/status register */ #define I2CMODE_M 0x3 /* Master/Slave Tx/Rx Mode Select */ #define I2CMODE_S 6 #define I2CMODE_SR 0x0 /* Slave Receive Mode */ #define I2CMODE_ST 0x1 /* Slave Transmit Mode */ #define I2CMODE_MR 0x2 /* Master Receive Mode */ #define I2CMODE_MT 0x3 /* Master Transmit Mode */ #define I2CSTAT_BSY (1 << 5) /* Busy Signal Status bit */ #define I2C_START_STOP (1 << 5) /* Busy Signal Status bit */ #define RXTX_EN (1 << 4) /* Data Output Enable/Disable */ #define ARBST (1 << 3) /* Arbitration status flag */ #define ADDAS (1 << 2) /* Address-as-slave Status Flag */ #define ADDZERO (1 << 1) /* Address Zero Status Flag */ #define ACKRECVD (1 << 0) /* Last-received Bit Status Flag */ #define I2CADD 0x08 /* Address register */ #define I2CDS 0x0C /* Transmit/receive data shift */ #define I2CLC 0x10 /* Multi-master line control */ #define FILTER_EN (1 << 2) /* Filter Enable bit */ #define SDAOUT_DELAY_M 0x3 /* SDA Line Delay Length */ #define SDAOUT_DELAY_S 0 #ifdef DEBUG #define DPRINTF(fmt, args...) \ printf(fmt, ##args) #else #define DPRINTF(fmt, args...) #endif static int i2c_start(device_t, u_char, int); static int i2c_stop(device_t); static int i2c_reset(device_t, u_char, u_char, u_char *); static int i2c_read(device_t, char *, int, int *, int, int); static int i2c_write(device_t, const char *, int, int *, int); struct i2c_softc { struct resource *res[2]; bus_space_tag_t bst; bus_space_handle_t bsh; device_t dev; device_t iicbus; struct mtx mutex; void *ih; int intr; }; static struct resource_spec i2c_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { SYS_RES_IRQ, 0, RF_ACTIVE }, { -1, 0 } }; static int i2c_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_is_compatible(dev, "exynos,i2c")) return (ENXIO); device_set_desc(dev, "Samsung Exynos 5 I2C controller"); return (BUS_PROBE_DEFAULT); } static int clear_ipend(struct i2c_softc *sc) { int reg; reg = READ1(sc, I2CCON); reg &= ~(IPEND); WRITE1(sc, I2CCON, reg); return (0); } static int i2c_attach(device_t dev) { struct i2c_softc *sc; int reg; sc = device_get_softc(dev); sc->dev = dev; mtx_init(&sc->mutex, device_get_nameunit(dev), "I2C", MTX_DEF); if (bus_alloc_resources(dev, i2c_spec, sc->res)) { device_printf(dev, "could not allocate resources\n"); return (ENXIO); } /* Memory interface */ sc->bst = rman_get_bustag(sc->res[0]); sc->bsh = rman_get_bushandle(sc->res[0]); sc->iicbus = device_add_child(dev, "iicbus", -1); if (sc->iicbus == NULL) { device_printf(dev, "could not add iicbus child"); mtx_destroy(&sc->mutex); return (ENXIO); } WRITE1(sc, I2CSTAT, 0); WRITE1(sc, I2CADD, 0x00); /* Mode */ reg = (RXTX_EN); reg |= (I2CMODE_MT << I2CMODE_S); WRITE1(sc, I2CSTAT, reg); bus_generic_attach(dev); return (0); } static int wait_for_iif(struct i2c_softc *sc) { int retry; int reg; retry = 1000; while (retry --) { reg = READ1(sc, I2CCON); if (reg & IPEND) { return (IIC_NOERR); } DELAY(50); } return (IIC_ETIMEOUT); } static int wait_for_nibb(struct i2c_softc *sc) { int retry; retry = 1000; while (retry --) { if ((READ1(sc, I2CSTAT) & I2CSTAT_BSY) == 0) return (IIC_NOERR); DELAY(10); } return (IIC_ETIMEOUT); } static int is_ack(struct i2c_softc *sc) { int stat; stat = READ1(sc, I2CSTAT); if (!(stat & 1)) { /* ACK received */ return (1); } return (0); } static int i2c_start(device_t dev, u_char slave, int timeout) { struct i2c_softc *sc; int error; int reg; sc = device_get_softc(dev); DPRINTF("i2c start\n"); mtx_lock(&sc->mutex); #if 0 DPRINTF("I2CCON == 0x%08x\n", READ1(sc, I2CCON)); DPRINTF("I2CSTAT == 0x%08x\n", READ1(sc, I2CSTAT)); #endif if (slave & 1) { slave &= ~(1); slave <<= 1; slave |= 1; } else { slave <<= 1; } error = wait_for_nibb(sc); if (error) { mtx_unlock(&sc->mutex); - DPRINTF("cant i2c start: IIC_EBUSBSY\n"); - return (IIC_EBUSBSY); + DPRINTF("cant i2c start: IIC_EBUSERR\n"); + return (IIC_EBUSERR); } reg = READ1(sc, I2CCON); reg |= (IRQ_EN | ACKGEN); WRITE1(sc, I2CCON, reg); WRITE1(sc, I2CDS, slave); DELAY(50); reg = (RXTX_EN); reg |= I2C_START_STOP; reg |= (I2CMODE_MT << I2CMODE_S); WRITE1(sc, I2CSTAT, reg); error = wait_for_iif(sc); if (error) { DPRINTF("cant i2c start: iif error\n"); mtx_unlock(&sc->mutex); return (error); } if (!is_ack(sc)) { DPRINTF("cant i2c start: no ack\n"); mtx_unlock(&sc->mutex); return (IIC_ENOACK); }; mtx_unlock(&sc->mutex); return (IIC_NOERR); } static int i2c_stop(device_t dev) { struct i2c_softc *sc; int reg; int error; sc = device_get_softc(dev); DPRINTF("i2c stop\n"); mtx_lock(&sc->mutex); reg = READ1(sc, I2CSTAT); int mode = (reg >> I2CMODE_S) & I2CMODE_M; reg = (RXTX_EN); reg |= (mode << I2CMODE_S); WRITE1(sc, I2CSTAT, reg); clear_ipend(sc); error = wait_for_nibb(sc); if (error) { DPRINTF("cant i2c stop: nibb error\n"); return (error); } mtx_unlock(&sc->mutex); return (IIC_NOERR); } static int i2c_reset(device_t dev, u_char speed, u_char addr, u_char *oldadr) { struct i2c_softc *sc; sc = device_get_softc(dev); DPRINTF("i2c reset\n"); mtx_lock(&sc->mutex); /* TODO */ mtx_unlock(&sc->mutex); return (IIC_NOERR); } static int i2c_read(device_t dev, char *buf, int len, int *read, int last, int delay) { struct i2c_softc *sc; int error; int reg; uint8_t d; sc = device_get_softc(dev); DPRINTF("i2c read\n"); reg = (RXTX_EN); reg |= (I2CMODE_MR << I2CMODE_S); reg |= I2C_START_STOP; WRITE1(sc, I2CSTAT, reg); *read = 0; mtx_lock(&sc->mutex); /* dummy read */ clear_ipend(sc); error = wait_for_iif(sc); if (error) { DPRINTF("cant i2c read: iif error\n"); mtx_unlock(&sc->mutex); return (error); } READ1(sc, I2CDS); DPRINTF("Read "); while (*read < len) { /* Do not ack last read */ if (*read == (len - 1)) { reg = READ1(sc, I2CCON); reg &= ~(ACKGEN); WRITE1(sc, I2CCON, reg); }; clear_ipend(sc); error = wait_for_iif(sc); if (error) { DPRINTF("cant i2c read: iif error\n"); mtx_unlock(&sc->mutex); return (error); } d = READ1(sc, I2CDS); DPRINTF("0x%02x ", d); *buf++ = d; (*read)++; } DPRINTF("\n"); mtx_unlock(&sc->mutex); return (IIC_NOERR); } static int i2c_write(device_t dev, const char *buf, int len, int *sent, int timeout) { struct i2c_softc *sc; int error; sc = device_get_softc(dev); DPRINTF("i2c write\n"); *sent = 0; mtx_lock(&sc->mutex); DPRINTF("writing "); while (*sent < len) { uint8_t d = *buf++; DPRINTF("0x%02x ", d); WRITE1(sc, I2CDS, d); DELAY(50); clear_ipend(sc); error = wait_for_iif(sc); if (error) { DPRINTF("cant i2c write: iif error\n"); mtx_unlock(&sc->mutex); return (error); } if (!is_ack(sc)) { DPRINTF("cant i2c write: no ack\n"); mtx_unlock(&sc->mutex); return (IIC_ENOACK); }; (*sent)++; } DPRINTF("\n"); mtx_unlock(&sc->mutex); return (IIC_NOERR); } static device_method_t i2c_methods[] = { DEVMETHOD(device_probe, i2c_probe), DEVMETHOD(device_attach, i2c_attach), DEVMETHOD(iicbus_callback, iicbus_null_callback), DEVMETHOD(iicbus_start, i2c_start), DEVMETHOD(iicbus_stop, i2c_stop), DEVMETHOD(iicbus_reset, i2c_reset), DEVMETHOD(iicbus_read, i2c_read), DEVMETHOD(iicbus_write, i2c_write), DEVMETHOD(iicbus_transfer, iicbus_transfer_gen), { 0, 0 } }; static driver_t i2c_driver = { "i2c", i2c_methods, sizeof(struct i2c_softc), }; static devclass_t i2c_devclass; DRIVER_MODULE(i2c, simplebus, i2c_driver, i2c_devclass, 0, 0); DRIVER_MODULE(iicbus, i2c, iicbus_driver, iicbus_devclass, 0, 0); Index: projects/release-pkg/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_attach.c =================================================================== --- projects/release-pkg/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_attach.c (revision 289118) +++ projects/release-pkg/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_attach.c (revision 289119) @@ -1,4148 +1,4148 @@ /* * Copyright (c) 2013 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "opt_ah.h" #include "ah.h" #include "ah_internal.h" #include "ah_devid.h" #include "ar9300/ar9300desc.h" #include "ar9300/ar9300.h" #include "ar9300/ar9300reg.h" #include "ar9300/ar9300phy.h" #include "ar9300/ar9300paprd.h" #include "ar9300/ar9300_stub.h" #include "ar9300/ar9300_stub_funcs.h" /* Add static register initialization vectors */ #include "ar9300/ar9300_osprey22.ini" #include "ar9300/ar9330_11.ini" #include "ar9300/ar9330_12.ini" #include "ar9300/ar9340.ini" #include "ar9300/ar9485.ini" #include "ar9300/ar9485_1_1.ini" #include "ar9300/ar9300_jupiter10.ini" #include "ar9300/ar9300_jupiter20.ini" #include "ar9300/ar9580.ini" #include "ar9300/ar955x.ini" #include "ar9300/ar9300_aphrodite10.ini" /* Include various freebsd specific HAL methods */ #include "ar9300/ar9300_freebsd.h" /* XXX duplicate in ar9300_radio.c ? */ static HAL_BOOL ar9300_get_chip_power_limits(struct ath_hal *ah, struct ieee80211_channel *chan); static inline HAL_STATUS ar9300_init_mac_addr(struct ath_hal *ah); static inline HAL_STATUS ar9300_hw_attach(struct ath_hal *ah); static inline void ar9300_hw_detach(struct ath_hal *ah); static int16_t ar9300_get_nf_adjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c); #if 0 int ar9300_get_cal_intervals(struct ath_hal *ah, HAL_CALIBRATION_TIMER **timerp, HAL_CAL_QUERY query); #endif #if ATH_TRAFFIC_FAST_RECOVER unsigned long ar9300_get_pll3_sqsum_dvc(struct ath_hal *ah); #endif static int ar9300_init_offsets(struct ath_hal *ah, u_int16_t devid); static void ar9300_disable_pcie_phy(struct ath_hal *ah); static const HAL_PERCAL_DATA iq_cal_single_sample = {IQ_MISMATCH_CAL, MIN_CAL_SAMPLES, PER_MAX_LOG_COUNT, ar9300_iq_cal_collect, ar9300_iq_calibration}; #if 0 static HAL_CALIBRATION_TIMER ar9300_cals[] = { {IQ_MISMATCH_CAL, /* Cal type */ 1200000, /* Cal interval */ 0 /* Cal timestamp */ }, {TEMP_COMP_CAL, 5000, 0 }, }; #endif #if ATH_PCIE_ERROR_MONITOR int ar9300_start_pcie_error_monitor(struct ath_hal *ah, int b_auto_stop) { u_int32_t val; /* Clear the counters */ OS_REG_WRITE(ah, PCIE_CO_ERR_CTR_CTR0, 0); OS_REG_WRITE(ah, PCIE_CO_ERR_CTR_CTR1, 0); /* Read the previous value */ val = OS_REG_READ(ah, PCIE_CO_ERR_CTR_CTRL); /* Set auto_stop */ if (b_auto_stop) { val |= RCVD_ERR_CTR_AUTO_STOP | BAD_TLP_ERR_CTR_AUTO_STOP | BAD_DLLP_ERR_CTR_AUTO_STOP | RPLY_TO_ERR_CTR_AUTO_STOP | RPLY_NUM_RO_ERR_CTR_AUTO_STOP; } else { val &= ~( RCVD_ERR_CTR_AUTO_STOP | BAD_TLP_ERR_CTR_AUTO_STOP | BAD_DLLP_ERR_CTR_AUTO_STOP | RPLY_TO_ERR_CTR_AUTO_STOP | RPLY_NUM_RO_ERR_CTR_AUTO_STOP); } OS_REG_WRITE(ah, PCIE_CO_ERR_CTR_CTRL, val ); /* * Start to run. * This has to be done separately from the above auto_stop flag setting, * to avoid a HW race condition. */ val |= RCVD_ERR_CTR_RUN | BAD_TLP_ERR_CTR_RUN | BAD_DLLP_ERR_CTR_RUN | RPLY_TO_ERR_CTR_RUN | RPLY_NUM_RO_ERR_CTR_RUN; OS_REG_WRITE(ah, PCIE_CO_ERR_CTR_CTRL, val); return 0; } int ar9300_read_pcie_error_monitor(struct ath_hal *ah, void* p_read_counters) { u_int32_t val; ar_pcie_error_moniter_counters *p_counters = (ar_pcie_error_moniter_counters*) p_read_counters; val = OS_REG_READ(ah, PCIE_CO_ERR_CTR_CTR0); p_counters->uc_receiver_errors = MS(val, RCVD_ERR_MASK); p_counters->uc_bad_tlp_errors = MS(val, BAD_TLP_ERR_MASK); p_counters->uc_bad_dllp_errors = MS(val, BAD_DLLP_ERR_MASK); val = OS_REG_READ(ah, PCIE_CO_ERR_CTR_CTR1); p_counters->uc_replay_timeout_errors = MS(val, RPLY_TO_ERR_MASK); p_counters->uc_replay_number_rollover_errors= MS(val, RPLY_NUM_RO_ERR_MASK); return 0; } int ar9300_stop_pcie_error_monitor(struct ath_hal *ah) { u_int32_t val; /* Read the previous value */ val = OS_REG_READ(ah, PCIE_CO_ERR_CTR_CTRL); val &= ~( RCVD_ERR_CTR_RUN | BAD_TLP_ERR_CTR_RUN | BAD_DLLP_ERR_CTR_RUN | RPLY_TO_ERR_CTR_RUN | RPLY_NUM_RO_ERR_CTR_RUN); /* Start to stop */ OS_REG_WRITE(ah, PCIE_CO_ERR_CTR_CTRL, val ); return 0; } #endif /* ATH_PCIE_ERROR_MONITOR */ #if 0 /* WIN32 does not support C99 */ static const struct ath_hal_private ar9300hal = { { ar9300_get_rate_table, /* ah_get_rate_table */ ar9300_detach, /* ah_detach */ /* Reset Functions */ ar9300_reset, /* ah_reset */ ar9300_phy_disable, /* ah_phy_disable */ ar9300_disable, /* ah_disable */ ar9300_config_pci_power_save, /* ah_config_pci_power_save */ ar9300_set_pcu_config, /* ah_set_pcu_config */ ar9300_calibration, /* ah_per_calibration */ ar9300_reset_cal_valid, /* ah_reset_cal_valid */ ar9300_set_tx_power_limit, /* ah_set_tx_power_limit */ #if ATH_ANT_DIV_COMB ar9300_ant_ctrl_set_lna_div_use_bt_ant, /* ah_ant_ctrl_set_lna_div_use_bt_ant */ #endif /* ATH_ANT_DIV_COMB */ #ifdef ATH_SUPPORT_DFS ar9300_radar_wait, /* ah_radar_wait */ /* New DFS functions */ ar9300_check_dfs, /* ah_ar_check_dfs */ ar9300_dfs_found, /* ah_ar_dfs_found */ ar9300_enable_dfs, /* ah_ar_enable_dfs */ ar9300_get_dfs_thresh, /* ah_ar_get_dfs_thresh */ ar9300_get_dfs_radars, /* ah_ar_get_dfs_radars */ ar9300_adjust_difs, /* ah_adjust_difs */ ar9300_dfs_config_fft, /* ah_dfs_config_fft */ ar9300_dfs_cac_war, /* ah_dfs_cac_war */ ar9300_cac_tx_quiet, /* ah_cac_tx_quiet */ #endif ar9300_get_extension_channel, /* ah_get_extension_channel */ ar9300_is_fast_clock_enabled, /* ah_is_fast_clock_enabled */ /* Transmit functions */ ar9300_update_tx_trig_level, /* ah_update_tx_trig_level */ ar9300_get_tx_trig_level, /* ah_get_tx_trig_level */ ar9300_setup_tx_queue, /* ah_setup_tx_queue */ ar9300_set_tx_queue_props, /* ah_set_tx_queue_props */ ar9300_get_tx_queue_props, /* ah_get_tx_queue_props */ ar9300_release_tx_queue, /* ah_release_tx_queue */ ar9300_reset_tx_queue, /* ah_reset_tx_queue */ ar9300_get_tx_dp, /* ah_get_tx_dp */ ar9300_set_tx_dp, /* ah_set_tx_dp */ ar9300_num_tx_pending, /* ah_num_tx_pending */ ar9300_start_tx_dma, /* ah_start_tx_dma */ ar9300_stop_tx_dma, /* ah_stop_tx_dma */ ar9300_stop_tx_dma_indv_que, /* ah_stop_tx_dma_indv_que */ ar9300_abort_tx_dma, /* ah_abort_tx_dma */ ar9300_fill_tx_desc, /* ah_fill_tx_desc */ ar9300_set_desc_link, /* ah_set_desc_link */ ar9300_get_desc_link_ptr, /* ah_get_desc_link_ptr */ ar9300_clear_tx_desc_status, /* ah_clear_tx_desc_status */ #ifdef ATH_SWRETRY ar9300_clear_dest_mask, /* ah_clear_dest_mask */ #endif ar9300_proc_tx_desc, /* ah_proc_tx_desc */ ar9300_get_raw_tx_desc, /* ah_get_raw_tx_desc */ ar9300_get_tx_rate_code, /* ah_get_tx_rate_code */ AH_NULL, /* ah_get_tx_intr_queue */ ar9300_tx_req_intr_desc, /* ah_req_tx_intr_desc */ ar9300_calc_tx_airtime, /* ah_calc_tx_airtime */ ar9300_setup_tx_status_ring, /* ah_setup_tx_status_ring */ /* RX Functions */ ar9300_get_rx_dp, /* ah_get_rx_dp */ ar9300_set_rx_dp, /* ah_set_rx_dp */ ar9300_enable_receive, /* ah_enable_receive */ ar9300_stop_dma_receive, /* ah_stop_dma_receive */ ar9300_start_pcu_receive, /* ah_start_pcu_receive */ ar9300_stop_pcu_receive, /* ah_stop_pcu_receive */ ar9300_set_multicast_filter, /* ah_set_multicast_filter */ ar9300_get_rx_filter, /* ah_get_rx_filter */ ar9300_set_rx_filter, /* ah_set_rx_filter */ ar9300_set_rx_sel_evm, /* ah_set_rx_sel_evm */ ar9300_set_rx_abort, /* ah_set_rx_abort */ AH_NULL, /* ah_setup_rx_desc */ ar9300_proc_rx_desc, /* ah_proc_rx_desc */ ar9300_get_rx_key_idx, /* ah_get_rx_key_idx */ ar9300_proc_rx_desc_fast, /* ah_proc_rx_desc_fast */ ar9300_ani_ar_poll, /* ah_rx_monitor */ ar9300_process_mib_intr, /* ah_proc_mib_event */ /* Misc Functions */ ar9300_get_capability, /* ah_get_capability */ ar9300_set_capability, /* ah_set_capability */ ar9300_get_diag_state, /* ah_get_diag_state */ ar9300_get_mac_address, /* ah_get_mac_address */ ar9300_set_mac_address, /* ah_set_mac_address */ ar9300_get_bss_id_mask, /* ah_get_bss_id_mask */ ar9300_set_bss_id_mask, /* ah_set_bss_id_mask */ ar9300_set_regulatory_domain, /* ah_set_regulatory_domain */ ar9300_set_led_state, /* ah_set_led_state */ ar9300_set_power_led_state, /* ah_setpowerledstate */ ar9300_set_network_led_state, /* ah_setnetworkledstate */ ar9300_write_associd, /* ah_write_associd */ ar9300_force_tsf_sync, /* ah_force_tsf_sync */ ar9300_gpio_cfg_input, /* ah_gpio_cfg_input */ ar9300_gpio_cfg_output, /* ah_gpio_cfg_output */ ar9300_gpio_cfg_output_led_off, /* ah_gpio_cfg_output_led_off */ ar9300_gpio_get, /* ah_gpio_get */ ar9300_gpio_set, /* ah_gpio_set */ ar9300_gpio_get_intr, /* ah_gpio_get_intr */ ar9300_gpio_set_intr, /* ah_gpio_set_intr */ ar9300_gpio_get_polarity, /* ah_gpio_get_polarity */ ar9300_gpio_set_polarity, /* ah_gpio_set_polarity */ ar9300_gpio_get_mask, /* ah_gpio_get_mask */ ar9300_gpio_set_mask, /* ah_gpio_set_mask */ ar9300_get_tsf32, /* ah_get_tsf32 */ ar9300_get_tsf64, /* ah_get_tsf64 */ ar9300_get_tsf2_32, /* ah_get_tsf2_32 */ ar9300_reset_tsf, /* ah_reset_tsf */ ar9300_detect_card_present, /* ah_detect_card_present */ ar9300_update_mib_mac_stats, /* ah_update_mib_mac_stats */ ar9300_get_mib_mac_stats, /* ah_get_mib_mac_stats */ ar9300_get_rfgain, /* ah_get_rf_gain */ ar9300_get_def_antenna, /* ah_get_def_antenna */ ar9300_set_def_antenna, /* ah_set_def_antenna */ ar9300_set_slot_time, /* ah_set_slot_time */ ar9300_set_ack_timeout, /* ah_set_ack_timeout */ ar9300_get_ack_timeout, /* ah_get_ack_timeout */ ar9300_set_coverage_class, /* ah_set_coverage_class */ ar9300_set_quiet, /* ah_set_quiet */ ar9300_set_antenna_switch, /* ah_set_antenna_switch */ ar9300_get_desc_info, /* ah_get_desc_info */ ar9300_select_ant_config, /* ah_select_ant_config */ ar9300_ant_ctrl_common_get, /* ah_ant_ctrl_common_get */ ar9300_ant_swcom_sel, /* ah_ant_swcom_sel */ ar9300_enable_tpc, /* ah_enable_tpc */ AH_NULL, /* ah_olpc_temp_compensation */ #if ATH_SUPPORT_CRDC ar9300_chain_rssi_diff_compensation,/*ah_chain_rssi_diff_compensation*/ #endif ar9300_disable_phy_restart, /* ah_disable_phy_restart */ ar9300_enable_keysearch_always, ar9300_interference_is_present, /* ah_interference_is_present */ ar9300_disp_tpc_tables, /* ah_disp_tpc_tables */ ar9300_get_tpc_tables, /* ah_get_tpc_tables */ /* Key Cache Functions */ ar9300_get_key_cache_size, /* ah_get_key_cache_size */ ar9300_reset_key_cache_entry, /* ah_reset_key_cache_entry */ ar9300_is_key_cache_entry_valid, /* ah_is_key_cache_entry_valid */ ar9300_set_key_cache_entry, /* ah_set_key_cache_entry */ ar9300_set_key_cache_entry_mac, /* ah_set_key_cache_entry_mac */ ar9300_print_keycache, /* ah_print_key_cache */ #if ATH_SUPPORT_KEYPLUMB_WAR ar9300_check_key_cache_entry, /* ah_check_key_cache_entry */ #endif /* Power Management Functions */ ar9300_set_power_mode, /* ah_set_power_mode */ ar9300_set_sm_power_mode, /* ah_set_sm_ps_mode */ #if ATH_WOW ar9300_wow_apply_pattern, /* ah_wow_apply_pattern */ ar9300_wow_enable, /* ah_wow_enable */ ar9300_wow_wake_up, /* ah_wow_wake_up */ #if ATH_WOW_OFFLOAD ar9300_wowoffload_prep, /* ah_wow_offload_prep */ ar9300_wowoffload_post, /* ah_wow_offload_post */ ar9300_wowoffload_download_rekey_data, /* ah_wow_offload_download_rekey_data */ ar9300_wowoffload_retrieve_data, /* ah_wow_offload_retrieve_data */ ar9300_wowoffload_download_acer_magic, /* ah_wow_offload_download_acer_magic */ ar9300_wowoffload_download_acer_swka, /* ah_wow_offload_download_acer_swka */ ar9300_wowoffload_download_arp_info, /* ah_wow_offload_download_arp_info */ ar9300_wowoffload_download_ns_info, /* ah_wow_offload_download_ns_info */ #endif /* ATH_WOW_OFFLOAD */ #endif /* Get Channel Noise */ ath_hal_get_chan_noise, /* ah_get_chan_noise */ ar9300_chain_noise_floor, /* ah_get_chain_noise_floor */ ar9300_get_nf_from_reg, /* ah_get_nf_from_reg */ ar9300_get_rx_nf_offset, /* ah_get_rx_nf_offset */ /* Beacon Functions */ ar9300_beacon_init, /* ah_beacon_init */ ar9300_set_sta_beacon_timers, /* ah_set_station_beacon_timers */ /* Interrupt Functions */ ar9300_is_interrupt_pending, /* ah_is_interrupt_pending */ ar9300_get_pending_interrupts, /* ah_get_pending_interrupts */ ar9300_get_interrupts, /* ah_get_interrupts */ ar9300_set_interrupts, /* ah_set_interrupts */ ar9300_set_intr_mitigation_timer, /* ah_set_intr_mitigation_timer */ ar9300_get_intr_mitigation_timer, /* ah_get_intr_mitigation_timer */ ar9300ForceVCS, ar9300SetDfs3StreamFix, ar9300Get3StreamSignature, /* 11n specific functions (NOT applicable to ar9300) */ ar9300_set_11n_tx_desc, /* ah_set_11n_tx_desc */ /* Update rxchain */ ar9300_set_rx_chainmask, /*ah_set_rx_chainmask*/ /*Updating locationing register */ ar9300_update_loc_ctl_reg, /*ah_update_loc_ctl_reg*/ /* Start PAPRD functions */ ar9300_set_paprd_tx_desc, /* ah_set_paprd_tx_desc */ ar9300_paprd_init_table, /* ah_paprd_init_table */ ar9300_paprd_setup_gain_table, /* ah_paprd_setup_gain_table */ ar9300_paprd_create_curve, /* ah_paprd_create_curve */ ar9300_paprd_is_done, /* ah_paprd_is_done */ ar9300_enable_paprd, /* ah_PAPRDEnable */ ar9300_populate_paprd_single_table,/* ah_paprd_populate_table */ ar9300_is_tx_done, /* ah_is_tx_done */ ar9300_paprd_dec_tx_pwr, /* ah_paprd_dec_tx_pwr*/ ar9300_paprd_thermal_send, /* ah_paprd_thermal_send */ /* End PAPRD functions */ ar9300_set_11n_rate_scenario, /* ah_set_11n_rate_scenario */ ar9300_set_11n_aggr_first, /* ah_set_11n_aggr_first */ ar9300_set_11n_aggr_middle, /* ah_set_11n_aggr_middle */ ar9300_set_11n_aggr_last, /* ah_set_11n_aggr_last */ ar9300_clr_11n_aggr, /* ah_clr_11n_aggr */ ar9300_set_11n_rifs_burst_middle, /* ah_set_11n_rifs_burst_middle */ ar9300_set_11n_rifs_burst_last, /* ah_set_11n_rifs_burst_last */ ar9300_clr_11n_rifs_burst, /* ah_clr_11n_rifs_burst */ ar9300_set_11n_aggr_rifs_burst, /* ah_set_11n_aggr_rifs_burst */ ar9300_set_11n_rx_rifs, /* ah_set_11n_rx_rifs */ ar9300_set_smart_antenna, /* ah_setSmartAntenna */ ar9300_detect_bb_hang, /* ah_detect_bb_hang */ ar9300_detect_mac_hang, /* ah_detect_mac_hang */ ar9300_set_immunity, /* ah_immunity */ ar9300_get_hw_hangs, /* ah_get_hang_types */ ar9300_set_11n_burst_duration, /* ah_set_11n_burst_duration */ ar9300_set_11n_virtual_more_frag, /* ah_set_11n_virtual_more_frag */ ar9300_get_11n_ext_busy, /* ah_get_11n_ext_busy */ ar9300_set_11n_mac2040, /* ah_set_11n_mac2040 */ ar9300_get_11n_rx_clear, /* ah_get_11n_rx_clear */ ar9300_set_11n_rx_clear, /* ah_set_11n_rx_clear */ ar9300_get_mib_cycle_counts_pct, /* ah_get_mib_cycle_counts_pct */ ar9300_dma_reg_dump, /* ah_dma_reg_dump */ /* force_ppm specific functions */ ar9300_ppm_get_rssi_dump, /* ah_ppm_get_rssi_dump */ ar9300_ppm_arm_trigger, /* ah_ppm_arm_trigger */ ar9300_ppm_get_trigger, /* ah_ppm_get_trigger */ ar9300_ppm_force, /* ah_ppm_force */ ar9300_ppm_un_force, /* ah_ppm_un_force */ ar9300_ppm_get_force_state, /* ah_ppm_get_force_state */ ar9300_get_spur_info, /* ah_get_spur_info */ ar9300_set_spur_info, /* ah_get_spur_info */ ar9300_get_min_cca_pwr, /* ah_ar_get_noise_floor_val */ ar9300_green_ap_ps_on_off, /* ah_set_rx_green_ap_ps_on_off */ ar9300_is_single_ant_power_save_possible, /* ah_is_single_ant_power_save_possible */ /* radio measurement specific functions */ ar9300_get_mib_cycle_counts, /* ah_get_mib_cycle_counts */ ar9300_get_vow_stats, /* ah_get_vow_stats */ ar9300_clear_mib_counters, /* ah_clear_mib_counters */ #if ATH_GEN_RANDOMNESS ar9300_get_rssi_chain0, /* ah_get_rssi_chain0 */ #endif #ifdef ATH_BT_COEX /* Bluetooth Coexistence functions */ ar9300_set_bt_coex_info, /* ah_set_bt_coex_info */ ar9300_bt_coex_config, /* ah_bt_coex_config */ ar9300_bt_coex_set_qcu_thresh, /* ah_bt_coex_set_qcu_thresh */ ar9300_bt_coex_set_weights, /* ah_bt_coex_set_weights */ ar9300_bt_coex_setup_bmiss_thresh, /* ah_bt_coex_set_bmiss_thresh */ ar9300_bt_coex_set_parameter, /* ah_bt_coex_set_parameter */ ar9300_bt_coex_disable, /* ah_bt_coex_disable */ ar9300_bt_coex_enable, /* ah_bt_coex_enable */ ar9300_get_bt_active_gpio, /* ah_bt_coex_info*/ ar9300_get_wlan_active_gpio, /* ah__coex_wlan_info*/ #endif /* Generic Timer functions */ ar9300_alloc_generic_timer, /* ah_gentimer_alloc */ ar9300_free_generic_timer, /* ah_gentimer_free */ ar9300_start_generic_timer, /* ah_gentimer_start */ ar9300_stop_generic_timer, /* ah_gentimer_stop */ ar9300_get_gen_timer_interrupts, /* ah_gentimer_get_intr */ ar9300_set_dcs_mode, /* ah_set_dcs_mode */ ar9300_get_dcs_mode, /* ah_get_dcs_mode */ #if ATH_ANT_DIV_COMB ar9300_ant_div_comb_get_config, /* ah_get_ant_dvi_comb_conf */ ar9300_ant_div_comb_set_config, /* ah_set_ant_dvi_comb_conf */ #endif ar9300_get_bb_panic_info, /* ah_get_bb_panic_info */ ar9300_handle_radar_bb_panic, /* ah_handle_radar_bb_panic */ ar9300_set_hal_reset_reason, /* ah_set_hal_reset_reason */ #if ATH_PCIE_ERROR_MONITOR ar9300_start_pcie_error_monitor, /* ah_start_pcie_error_monitor */ ar9300_read_pcie_error_monitor, /* ah_read_pcie_error_monitor*/ ar9300_stop_pcie_error_monitor, /* ah_stop_pcie_error_monitor*/ #endif /* ATH_PCIE_ERROR_MONITOR */ #if ATH_SUPPORT_SPECTRAL /* Spectral scan */ ar9300_configure_spectral_scan, /* ah_ar_configure_spectral */ ar9300_get_spectral_params, /* ah_ar_get_spectral_config */ ar9300_start_spectral_scan, /* ah_ar_start_spectral_scan */ ar9300_stop_spectral_scan, /* ah_ar_stop_spectral_scan */ ar9300_is_spectral_enabled, /* ah_ar_is_spectral_enabled */ ar9300_is_spectral_active, /* ah_ar_is_spectral_active */ ar9300_get_ctl_chan_nf, /* ah_ar_get_ctl_nf */ ar9300_get_ext_chan_nf, /* ah_ar_get_ext_nf */ #endif /* ATH_SUPPORT_SPECTRAL */ ar9300_promisc_mode, /* ah_promisc_mode */ ar9300_read_pktlog_reg, /* ah_read_pktlog_reg */ ar9300_write_pktlog_reg, /* ah_write_pktlog_reg */ ar9300_set_proxy_sta, /* ah_set_proxy_sta */ ar9300_get_cal_intervals, /* ah_get_cal_intervals */ #if ATH_TRAFFIC_FAST_RECOVER ar9300_get_pll3_sqsum_dvc, /* ah_get_pll3_sqsum_dvc */ #endif #ifdef ATH_SUPPORT_HTC AH_NULL, #endif #ifdef ATH_TX99_DIAG /* Tx99 functions */ #ifdef ATH_SUPPORT_HTC AH_NULL, AH_NULL, AH_NULL, AH_NULL, AH_NULL, AH_NULL, AH_NULL, #else AH_NULL, AH_NULL, ar9300_tx99_channel_pwr_update, /* ah_tx99channelpwrupdate */ ar9300_tx99_start, /* ah_tx99start */ ar9300_tx99_stop, /* ah_tx99stop */ ar9300_tx99_chainmsk_setup, /* ah_tx99_chainmsk_setup */ ar9300_tx99_set_single_carrier, /* ah_tx99_set_single_carrier */ #endif #endif ar9300_chk_rssi_update_tx_pwr, ar9300_is_skip_paprd_by_greentx, /* ah_is_skip_paprd_by_greentx */ ar9300_hwgreentx_set_pal_spare, /* ah_hwgreentx_set_pal_spare */ #if ATH_SUPPORT_MCI /* MCI Coexistence Functions */ ar9300_mci_setup, /* ah_mci_setup */ ar9300_mci_send_message, /* ah_mci_send_message */ ar9300_mci_get_interrupt, /* ah_mci_get_interrupt */ ar9300_mci_state, /* ah_mci_state */ ar9300_mci_detach, /* ah_mci_detach */ #endif ar9300_reset_hw_beacon_proc_crc, /* ah_reset_hw_beacon_proc_crc */ ar9300_get_hw_beacon_rssi, /* ah_get_hw_beacon_rssi */ ar9300_set_hw_beacon_rssi_threshold,/*ah_set_hw_beacon_rssi_threshold*/ ar9300_reset_hw_beacon_rssi, /* ah_reset_hw_beacon_rssi */ ar9300_mat_enable, /* ah_mat_enable */ ar9300_dump_keycache, /* ah_dump_keycache */ ar9300_is_ani_noise_spur, /* ah_is_ani_noise_spur */ ar9300_set_hw_beacon_proc, /* ah_set_hw_beacon_proc */ ar9300_set_ctl_pwr, /* ah_set_ctl_pwr */ ar9300_set_txchainmaskopt, /* ah_set_txchainmaskopt */ }, ar9300_get_channel_edges, /* ah_get_channel_edges */ ar9300_get_wireless_modes, /* ah_get_wireless_modes */ ar9300_eeprom_read_word, /* ah_eeprom_read */ AH_NULL, ar9300_eeprom_dump_support, /* ah_eeprom_dump */ ar9300_get_chip_power_limits, /* ah_get_chip_power_limits */ ar9300_get_nf_adjust, /* ah_get_nf_adjust */ /* rest is zero'd by compiler */ }; #endif /* * Read MAC version/revision information from Chip registers and initialize * local data structures. */ void ar9300_read_revisions(struct ath_hal *ah) { u_int32_t val; /* XXX verify if this is the correct way to read revision on Osprey */ /* new SREV format for Sowl and later */ val = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_SREV)); if (AH_PRIVATE(ah)->ah_devid == AR9300_DEVID_AR9340) { /* XXX: AR_SREV register in Wasp reads 0 */ AH_PRIVATE(ah)->ah_macVersion = AR_SREV_VERSION_WASP; } else if(AH_PRIVATE(ah)->ah_devid == AR9300_DEVID_QCA955X) { /* XXX: AR_SREV register in Scorpion reads 0 */ AH_PRIVATE(ah)->ah_macVersion = AR_SREV_VERSION_SCORPION; } else { /* * Include 6-bit Chip Type (masked to 0) * to differentiate from pre-Sowl versions */ AH_PRIVATE(ah)->ah_macVersion = (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S; } #ifdef AH_SUPPORT_HORNET /* * EV74984, due to Hornet 1.1 didn't update WMAC revision, * so that have to read SoC's revision ID instead */ if (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_HORNET) { #define AR_SOC_RST_REVISION_ID 0xB8060090 #define REG_READ(_reg) *((volatile u_int32_t *)(_reg)) if ((REG_READ(AR_SOC_RST_REVISION_ID) & AR_SREV_REVISION_HORNET_11_MASK) == AR_SREV_REVISION_HORNET_11) { AH_PRIVATE(ah)->ah_macRev = AR_SREV_REVISION_HORNET_11; } else { AH_PRIVATE(ah)->ah_macRev = MS(val, AR_SREV_REVISION2); } #undef REG_READ #undef AR_SOC_RST_REVISION_ID } else #endif if (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_WASP) { #define AR_SOC_RST_REVISION_ID 0xB8060090 #define REG_READ(_reg) *((volatile u_int32_t *)(_reg)) AH_PRIVATE(ah)->ah_macRev = REG_READ(AR_SOC_RST_REVISION_ID) & AR_SREV_REVISION_WASP_MASK; #undef REG_READ #undef AR_SOC_RST_REVISION_ID } else AH_PRIVATE(ah)->ah_macRev = MS(val, AR_SREV_REVISION2); if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { AH_PRIVATE(ah)->ah_ispcie = AH_TRUE; } else { AH_PRIVATE(ah)->ah_ispcie = (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1; } } /* * Attach for an AR9300 part. */ struct ath_hal * ar9300_attach(u_int16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_OPS_CONFIG *ah_config, HAL_STATUS *status) { struct ath_hal_9300 *ahp; struct ath_hal *ah; struct ath_hal_private *ahpriv; HAL_STATUS ecode; HAL_NO_INTERSPERSED_READS; /* NB: memory is returned zero'd */ ahp = ar9300_new_state(devid, sc, st, sh, eepromdata, ah_config, status); if (ahp == AH_NULL) { return AH_NULL; } ah = &ahp->ah_priv.h; ar9300_init_offsets(ah, devid); ahpriv = AH_PRIVATE(ah); // AH_PRIVATE(ah)->ah_bustype = bustype; /* FreeBSD: to make OTP work for now, provide this.. */ AH9300(ah)->ah_cal_mem = ath_hal_malloc(HOST_CALDATA_SIZE); if (AH9300(ah)->ah_cal_mem == NULL) { ath_hal_printf(ah, "%s: caldata malloc failed!\n", __func__); ecode = HAL_EIO; goto bad; } /* * If eepromdata is not NULL, copy it it into ah_cal_mem. */ if (eepromdata != NULL) OS_MEMCPY(AH9300(ah)->ah_cal_mem, eepromdata, HOST_CALDATA_SIZE); /* XXX FreeBSD: enable RX mitigation */ ah->ah_config.ath_hal_intr_mitigation_rx = 1; /* interrupt mitigation */ #ifdef AR5416_INT_MITIGATION if (ah->ah_config.ath_hal_intr_mitigation_rx != 0) { ahp->ah_intr_mitigation_rx = AH_TRUE; } #else /* Enable Rx mitigation (default) */ ahp->ah_intr_mitigation_rx = AH_TRUE; ah->ah_config.ath_hal_intr_mitigation_rx = 1; #endif #ifdef HOST_OFFLOAD /* Reset default Rx mitigation values for Hornet */ if (AR_SREV_HORNET(ah)) { ahp->ah_intr_mitigation_rx = AH_FALSE; #ifdef AR5416_INT_MITIGATION ah->ah_config.ath_hal_intr_mitigation_rx = 0; #endif } #endif if (ah->ah_config.ath_hal_intr_mitigation_tx != 0) { ahp->ah_intr_mitigation_tx = AH_TRUE; } /* * Read back AR_WA into a permanent copy and set bits 14 and 17. * We need to do this to avoid RMW of this register. * Do this before calling ar9300_set_reset_reg. * If not, the AR_WA register which was inited via EEPROM * will get wiped out. */ ahp->ah_wa_reg_val = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_WA)); /* Set Bits 14 and 17 in the AR_WA register. */ ahp->ah_wa_reg_val |= AR_WA_D3_TO_L1_DISABLE | AR_WA_ASPM_TIMER_BASED_DISABLE; if (!ar9300_set_reset_reg(ah, HAL_RESET_POWER_ON)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_RESET, "%s: couldn't reset chip\n", __func__); ecode = HAL_EIO; goto bad; } if (AR_SREV_JUPITER(ah) #if ATH_WOW_OFFLOAD && !HAL_WOW_CTRL(ah, HAL_WOW_OFFLOAD_SET_4004_BIT14) #endif ) { /* Jupiter doesn't need bit 14 to be set. */ ahp->ah_wa_reg_val &= ~AR_WA_D3_TO_L1_DISABLE; OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), ahp->ah_wa_reg_val); } #if ATH_SUPPORT_MCI if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { #if 0 ah->ah_bt_coex_set_weights = ar9300_mci_bt_coex_set_weights; ah->ah_bt_coex_disable = ar9300_mci_bt_coex_disable; ah->ah_bt_coex_enable = ar9300_mci_bt_coex_enable; #endif ahp->ah_mci_ready = AH_FALSE; ahp->ah_mci_bt_state = MCI_BT_SLEEP; ahp->ah_mci_coex_major_version_wlan = MCI_GPM_COEX_MAJOR_VERSION_WLAN; ahp->ah_mci_coex_minor_version_wlan = MCI_GPM_COEX_MINOR_VERSION_WLAN; ahp->ah_mci_coex_major_version_bt = MCI_GPM_COEX_MAJOR_VERSION_DEFAULT; ahp->ah_mci_coex_minor_version_bt = MCI_GPM_COEX_MINOR_VERSION_DEFAULT; ahp->ah_mci_coex_bt_version_known = AH_FALSE; ahp->ah_mci_coex_2g5g_update = AH_TRUE; /* track if 2g5g status sent */ /* will be updated before boot up sequence */ ahp->ah_mci_coex_is_2g = AH_TRUE; ahp->ah_mci_coex_wlan_channels_update = AH_FALSE; ahp->ah_mci_coex_wlan_channels[0] = 0x00000000; ahp->ah_mci_coex_wlan_channels[1] = 0xffffffff; ahp->ah_mci_coex_wlan_channels[2] = 0xffffffff; ahp->ah_mci_coex_wlan_channels[3] = 0x7fffffff; ahp->ah_mci_query_bt = AH_TRUE; /* In case WLAN start after BT */ ahp->ah_mci_unhalt_bt_gpm = AH_TRUE; /* Send UNHALT at beginning */ ahp->ah_mci_halted_bt_gpm = AH_FALSE; /* Allow first HALT */ ahp->ah_mci_need_flush_btinfo = AH_FALSE; ahp->ah_mci_wlan_cal_seq = 0; ahp->ah_mci_wlan_cal_done = 0; } #endif /* ATH_SUPPORT_MCI */ #if ATH_WOW_OFFLOAD ahp->ah_mcast_filter_l32_set = 0; ahp->ah_mcast_filter_u32_set = 0; #endif if (AR_SREV_HORNET(ah)) { #ifdef AH_SUPPORT_HORNET if (!AR_SREV_HORNET_11(ah)) { /* * Do not check bootstrap register, which cannot be trusted * due to s26 switch issue on CUS164/AP121. */ ahp->clk_25mhz = 1; HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, "Bootstrap clock 25MHz\n"); } else { /* check bootstrap clock setting */ #define AR_SOC_SEL_25M_40M 0xB80600AC #define REG_WRITE(_reg, _val) *((volatile u_int32_t *)(_reg)) = (_val); #define REG_READ(_reg) (*((volatile u_int32_t *)(_reg))) if (REG_READ(AR_SOC_SEL_25M_40M) & 0x1) { ahp->clk_25mhz = 0; HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, "Bootstrap clock 40MHz\n"); } else { ahp->clk_25mhz = 1; HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, "Bootstrap clock 25MHz\n"); } #undef REG_READ #undef REG_WRITE #undef AR_SOC_SEL_25M_40M } #endif /* AH_SUPPORT_HORNET */ } if (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { /* check bootstrap clock setting */ #define AR9340_SOC_SEL_25M_40M 0xB80600B0 #define AR9340_REF_CLK_40 (1 << 4) /* 0 - 25MHz 1 - 40 MHz */ #define REG_READ(_reg) (*((volatile u_int32_t *)(_reg))) if (REG_READ(AR9340_SOC_SEL_25M_40M) & AR9340_REF_CLK_40) { ahp->clk_25mhz = 0; HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, "Bootstrap clock 40MHz\n"); } else { ahp->clk_25mhz = 1; HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, "Bootstrap clock 25MHz\n"); } #undef REG_READ #undef AR9340_SOC_SEL_25M_40M #undef AR9340_REF_CLK_40 } ar9300_init_pll(ah, AH_NULL); if (!ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE)) { HALDEBUG(ah, HAL_DEBUG_RESET, "%s: couldn't wakeup chip\n", __func__); ecode = HAL_EIO; goto bad; } /* No serialization of Register Accesses needed. */ ah->ah_config.ah_serialise_reg_war = SER_REG_MODE_OFF; HALDEBUG(ah, HAL_DEBUG_RESET, "%s: ah_serialise_reg_war is %d\n", __func__, ah->ah_config.ah_serialise_reg_war); /* * Add mac revision check when needed. * - Osprey 1.0 and 2.0 no longer supported. */ if (((ahpriv->ah_macVersion == AR_SREV_VERSION_OSPREY) && (ahpriv->ah_macRev <= AR_SREV_REVISION_OSPREY_20)) || (ahpriv->ah_macVersion != AR_SREV_VERSION_OSPREY && ahpriv->ah_macVersion != AR_SREV_VERSION_WASP && ahpriv->ah_macVersion != AR_SREV_VERSION_HORNET && ahpriv->ah_macVersion != AR_SREV_VERSION_POSEIDON && ahpriv->ah_macVersion != AR_SREV_VERSION_SCORPION && ahpriv->ah_macVersion != AR_SREV_VERSION_JUPITER && ahpriv->ah_macVersion != AR_SREV_VERSION_APHRODITE) ) { HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Mac Chip Rev 0x%02x.%x is not supported by this driver\n", __func__, ahpriv->ah_macVersion, ahpriv->ah_macRev); ecode = HAL_ENOTSUPP; goto bad; } AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIP_ID); /* Setup supported calibrations */ ahp->ah_iq_cal_data.cal_data = &iq_cal_single_sample; ahp->ah_supp_cals = IQ_MISMATCH_CAL; /* Enable ANI */ ahp->ah_ani_function = HAL_ANI_ALL; /* Enable RIFS */ ahp->ah_rifs_enabled = AH_TRUE; /* by default, stop RX also in abort txdma, due to "Unable to stop TxDMA" msg observed */ ahp->ah_abort_txdma_norx = AH_TRUE; /* do not use optional tx chainmask by default */ ahp->ah_tx_chainmaskopt = 0; ahp->ah_skip_rx_iq_cal = AH_FALSE; ahp->ah_rx_cal_complete = AH_FALSE; ahp->ah_rx_cal_chan = 0; ahp->ah_rx_cal_chan_flag = 0; HALDEBUG(ah, HAL_DEBUG_RESET, "%s: This Mac Chip Rev 0x%02x.%x is \n", __func__, ahpriv->ah_macVersion, ahpriv->ah_macRev); if (AR_SREV_HORNET_12(ah)) { /* mac */ INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_CORE], ar9331_hornet1_2_mac_core, ARRAY_LENGTH(ar9331_hornet1_2_mac_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_POST], ar9331_hornet1_2_mac_postamble, ARRAY_LENGTH(ar9331_hornet1_2_mac_postamble), 5); /* bb */ INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_CORE], ar9331_hornet1_2_baseband_core, ARRAY_LENGTH(ar9331_hornet1_2_baseband_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_POST], ar9331_hornet1_2_baseband_postamble, ARRAY_LENGTH(ar9331_hornet1_2_baseband_postamble), 5); /* radio */ INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_CORE], ar9331_hornet1_2_radio_core, ARRAY_LENGTH(ar9331_hornet1_2_radio_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_POST], NULL, 0, 0); /* soc */ INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_PRE], ar9331_hornet1_2_soc_preamble, ARRAY_LENGTH(ar9331_hornet1_2_soc_preamble), 2); INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_CORE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_POST], ar9331_hornet1_2_soc_postamble, ARRAY_LENGTH(ar9331_hornet1_2_soc_postamble), 2); /* rx/tx gain */ INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9331_common_rx_gain_hornet1_2, ARRAY_LENGTH(ar9331_common_rx_gain_hornet1_2), 2); INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9331_modes_lowest_ob_db_tx_gain_hornet1_2, ARRAY_LENGTH(ar9331_modes_lowest_ob_db_tx_gain_hornet1_2), 5); ah->ah_config.ath_hal_pcie_power_save_enable = 0; /* Japan 2484Mhz CCK settings */ INIT_INI_ARRAY(&ahp->ah_ini_japan2484, ar9331_hornet1_2_baseband_core_txfir_coeff_japan_2484, ARRAY_LENGTH( ar9331_hornet1_2_baseband_core_txfir_coeff_japan_2484), 2); #if 0 /* ATH_WOW */ /* SerDes values during WOW sleep */ INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_wow, ar9300_pcie_phy_awow, ARRAY_LENGTH(ar9300_pcie_phy_awow), 2); #endif /* additional clock settings */ if (AH9300(ah)->clk_25mhz) { INIT_INI_ARRAY(&ahp->ah_ini_modes_additional, ar9331_hornet1_2_xtal_25M, ARRAY_LENGTH(ar9331_hornet1_2_xtal_25M), 2); } else { INIT_INI_ARRAY(&ahp->ah_ini_modes_additional, ar9331_hornet1_2_xtal_40M, ARRAY_LENGTH(ar9331_hornet1_2_xtal_40M), 2); } } else if (AR_SREV_HORNET_11(ah)) { /* mac */ INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_CORE], ar9331_hornet1_1_mac_core, ARRAY_LENGTH(ar9331_hornet1_1_mac_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_POST], ar9331_hornet1_1_mac_postamble, ARRAY_LENGTH(ar9331_hornet1_1_mac_postamble), 5); /* bb */ INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_CORE], ar9331_hornet1_1_baseband_core, ARRAY_LENGTH(ar9331_hornet1_1_baseband_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_POST], ar9331_hornet1_1_baseband_postamble, ARRAY_LENGTH(ar9331_hornet1_1_baseband_postamble), 5); /* radio */ INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_CORE], ar9331_hornet1_1_radio_core, ARRAY_LENGTH(ar9331_hornet1_1_radio_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_POST], NULL, 0, 0); /* soc */ INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_PRE], ar9331_hornet1_1_soc_preamble, ARRAY_LENGTH(ar9331_hornet1_1_soc_preamble), 2); INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_CORE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_POST], ar9331_hornet1_1_soc_postamble, ARRAY_LENGTH(ar9331_hornet1_1_soc_postamble), 2); /* rx/tx gain */ INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9331_common_rx_gain_hornet1_1, ARRAY_LENGTH(ar9331_common_rx_gain_hornet1_1), 2); INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9331_modes_lowest_ob_db_tx_gain_hornet1_1, ARRAY_LENGTH(ar9331_modes_lowest_ob_db_tx_gain_hornet1_1), 5); ah->ah_config.ath_hal_pcie_power_save_enable = 0; /* Japan 2484Mhz CCK settings */ INIT_INI_ARRAY(&ahp->ah_ini_japan2484, ar9331_hornet1_1_baseband_core_txfir_coeff_japan_2484, ARRAY_LENGTH( ar9331_hornet1_1_baseband_core_txfir_coeff_japan_2484), 2); #if 0 /* ATH_WOW */ /* SerDes values during WOW sleep */ INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_wow, ar9300_pcie_phy_awow, N(ar9300_pcie_phy_awow), 2); #endif /* additional clock settings */ if (AH9300(ah)->clk_25mhz) { INIT_INI_ARRAY(&ahp->ah_ini_modes_additional, ar9331_hornet1_1_xtal_25M, ARRAY_LENGTH(ar9331_hornet1_1_xtal_25M), 2); } else { INIT_INI_ARRAY(&ahp->ah_ini_modes_additional, ar9331_hornet1_1_xtal_40M, ARRAY_LENGTH(ar9331_hornet1_1_xtal_40M), 2); } } else if (AR_SREV_POSEIDON_11_OR_LATER(ah)) { /* mac */ INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_CORE], ar9485_poseidon1_1_mac_core, ARRAY_LENGTH( ar9485_poseidon1_1_mac_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_POST], ar9485_poseidon1_1_mac_postamble, ARRAY_LENGTH(ar9485_poseidon1_1_mac_postamble), 5); /* bb */ INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_PRE], ar9485_poseidon1_1, ARRAY_LENGTH(ar9485_poseidon1_1), 2); INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_CORE], ar9485_poseidon1_1_baseband_core, ARRAY_LENGTH(ar9485_poseidon1_1_baseband_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_POST], ar9485_poseidon1_1_baseband_postamble, ARRAY_LENGTH(ar9485_poseidon1_1_baseband_postamble), 5); /* radio */ INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_CORE], ar9485_poseidon1_1_radio_core, ARRAY_LENGTH(ar9485_poseidon1_1_radio_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_POST], ar9485_poseidon1_1_radio_postamble, ARRAY_LENGTH(ar9485_poseidon1_1_radio_postamble), 2); /* soc */ INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_PRE], ar9485_poseidon1_1_soc_preamble, ARRAY_LENGTH(ar9485_poseidon1_1_soc_preamble), 2); INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_CORE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_POST], NULL, 0, 0); /* rx/tx gain */ INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9485_common_wo_xlna_rx_gain_poseidon1_1, ARRAY_LENGTH(ar9485_common_wo_xlna_rx_gain_poseidon1_1), 2); INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9485_modes_lowest_ob_db_tx_gain_poseidon1_1, ARRAY_LENGTH(ar9485_modes_lowest_ob_db_tx_gain_poseidon1_1), 5); /* Japan 2484Mhz CCK settings */ INIT_INI_ARRAY(&ahp->ah_ini_japan2484, ar9485_poseidon1_1_baseband_core_txfir_coeff_japan_2484, ARRAY_LENGTH( ar9485_poseidon1_1_baseband_core_txfir_coeff_japan_2484), 2); /* Load PCIE SERDES settings from INI */ if (ah->ah_config.ath_hal_pcie_clock_req) { /* Pci-e Clock Request = 1 */ if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_CONTROL) { /* Sleep Setting */ if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_ON_D3) { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9485_poseidon1_1_pcie_phy_clkreq_enable_L1, ARRAY_LENGTH( ar9485_poseidon1_1_pcie_phy_clkreq_enable_L1), 2); } else { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9485_poseidon1_1_pcie_phy_pll_on_clkreq_enable_L1, ARRAY_LENGTH( ar9485_poseidon1_1_pcie_phy_pll_on_clkreq_enable_L1), 2); } /* Awake Setting */ if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_ON_D0) { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9485_poseidon1_1_pcie_phy_clkreq_enable_L1, ARRAY_LENGTH( ar9485_poseidon1_1_pcie_phy_clkreq_enable_L1), 2); } else { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9485_poseidon1_1_pcie_phy_pll_on_clkreq_enable_L1, ARRAY_LENGTH( ar9485_poseidon1_1_pcie_phy_pll_on_clkreq_enable_L1), 2); } } else { /*Use driver default setting*/ /* Sleep Setting */ INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9485_poseidon1_1_pcie_phy_clkreq_enable_L1, ARRAY_LENGTH(ar9485_poseidon1_1_pcie_phy_clkreq_enable_L1), 2); /* Awake Setting */ INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9485_poseidon1_1_pcie_phy_clkreq_enable_L1, ARRAY_LENGTH(ar9485_poseidon1_1_pcie_phy_clkreq_enable_L1), 2); } } else { /* Pci-e Clock Request = 0 */ if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_CONTROL) { /* Sleep Setting */ if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_ON_D3) { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9485_poseidon1_1_pcie_phy_clkreq_disable_L1, ARRAY_LENGTH( ar9485_poseidon1_1_pcie_phy_clkreq_disable_L1), 2); } else { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9485_poseidon1_1_pcie_phy_pll_on_clkreq_disable_L1, ARRAY_LENGTH( ar9485_poseidon1_1_pcie_phy_pll_on_clkreq_disable_L1), 2); } /* Awake Setting */ if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_ON_D0) { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9485_poseidon1_1_pcie_phy_clkreq_disable_L1, ARRAY_LENGTH( ar9485_poseidon1_1_pcie_phy_clkreq_disable_L1), 2); } else { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9485_poseidon1_1_pcie_phy_pll_on_clkreq_disable_L1, ARRAY_LENGTH( ar9485_poseidon1_1_pcie_phy_pll_on_clkreq_disable_L1), 2); } } else { /*Use driver default setting*/ /* Sleep Setting */ INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9485_poseidon1_1_pcie_phy_clkreq_disable_L1, ARRAY_LENGTH(ar9485_poseidon1_1_pcie_phy_clkreq_disable_L1), 2); /* Awake Setting */ INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9485_poseidon1_1_pcie_phy_clkreq_disable_L1, ARRAY_LENGTH(ar9485_poseidon1_1_pcie_phy_clkreq_disable_L1), 2); } } /* pcie ps setting will honor registry setting, default is 0 */ //ah->ah_config.ath_hal_pciePowerSaveEnable = 0; } else if (AR_SREV_POSEIDON(ah)) { /* mac */ INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_CORE], ar9485_poseidon1_0_mac_core, ARRAY_LENGTH(ar9485_poseidon1_0_mac_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_POST], ar9485_poseidon1_0_mac_postamble, ARRAY_LENGTH(ar9485_poseidon1_0_mac_postamble), 5); /* bb */ INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_PRE], ar9485_poseidon1_0, ARRAY_LENGTH(ar9485_poseidon1_0), 2); INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_CORE], ar9485_poseidon1_0_baseband_core, ARRAY_LENGTH(ar9485_poseidon1_0_baseband_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_POST], ar9485_poseidon1_0_baseband_postamble, ARRAY_LENGTH(ar9485_poseidon1_0_baseband_postamble), 5); /* radio */ INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_CORE], ar9485_poseidon1_0_radio_core, ARRAY_LENGTH(ar9485_poseidon1_0_radio_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_POST], ar9485_poseidon1_0_radio_postamble, ARRAY_LENGTH(ar9485_poseidon1_0_radio_postamble), 2); /* soc */ INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_PRE], ar9485_poseidon1_0_soc_preamble, ARRAY_LENGTH(ar9485_poseidon1_0_soc_preamble), 2); INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_CORE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_POST], NULL, 0, 0); /* rx/tx gain */ INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9485Common_wo_xlna_rx_gain_poseidon1_0, ARRAY_LENGTH(ar9485Common_wo_xlna_rx_gain_poseidon1_0), 2); INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9485Modes_lowest_ob_db_tx_gain_poseidon1_0, ARRAY_LENGTH(ar9485Modes_lowest_ob_db_tx_gain_poseidon1_0), 5); /* Japan 2484Mhz CCK settings */ INIT_INI_ARRAY(&ahp->ah_ini_japan2484, ar9485_poseidon1_0_baseband_core_txfir_coeff_japan_2484, ARRAY_LENGTH( ar9485_poseidon1_0_baseband_core_txfir_coeff_japan_2484), 2); /* Load PCIE SERDES settings from INI */ if (ah->ah_config.ath_hal_pcie_clock_req) { /* Pci-e Clock Request = 1 */ if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_CONTROL) { /* Sleep Setting */ if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_ON_D3) { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9485_poseidon1_0_pcie_phy_clkreq_enable_L1, ARRAY_LENGTH( ar9485_poseidon1_0_pcie_phy_clkreq_enable_L1), 2); } else { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9485_poseidon1_0_pcie_phy_pll_on_clkreq_enable_L1, ARRAY_LENGTH( ar9485_poseidon1_0_pcie_phy_pll_on_clkreq_enable_L1), 2); } /* Awake Setting */ if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_ON_D0) { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9485_poseidon1_0_pcie_phy_clkreq_enable_L1, ARRAY_LENGTH( ar9485_poseidon1_0_pcie_phy_clkreq_enable_L1), 2); } else { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9485_poseidon1_0_pcie_phy_pll_on_clkreq_enable_L1, ARRAY_LENGTH( ar9485_poseidon1_0_pcie_phy_pll_on_clkreq_enable_L1), 2); } } else { /*Use driver default setting*/ /* Sleep Setting */ INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9485_poseidon1_0_pcie_phy_pll_on_clkreq_enable_L1, ARRAY_LENGTH( ar9485_poseidon1_0_pcie_phy_pll_on_clkreq_enable_L1), 2); /* Awake Setting */ INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9485_poseidon1_0_pcie_phy_pll_on_clkreq_enable_L1, ARRAY_LENGTH( ar9485_poseidon1_0_pcie_phy_pll_on_clkreq_enable_L1), 2); } } else { /* Pci-e Clock Request = 0 */ if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_CONTROL) { /* Sleep Setting */ if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_ON_D3) { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9485_poseidon1_0_pcie_phy_clkreq_disable_L1, ARRAY_LENGTH( ar9485_poseidon1_0_pcie_phy_clkreq_disable_L1), 2); } else { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9485_poseidon1_0_pcie_phy_pll_on_clkreq_disable_L1, ARRAY_LENGTH( ar9485_poseidon1_0_pcie_phy_pll_on_clkreq_disable_L1), 2); } /* Awake Setting */ if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_ON_D0) { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9485_poseidon1_0_pcie_phy_clkreq_disable_L1, ARRAY_LENGTH( ar9485_poseidon1_0_pcie_phy_clkreq_disable_L1), 2); } else { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9485_poseidon1_0_pcie_phy_pll_on_clkreq_disable_L1, ARRAY_LENGTH( ar9485_poseidon1_0_pcie_phy_pll_on_clkreq_disable_L1), 2); } } else { /*Use driver default setting*/ /* Sleep Setting */ INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9485_poseidon1_0_pcie_phy_pll_on_clkreq_disable_L1, ARRAY_LENGTH( ar9485_poseidon1_0_pcie_phy_pll_on_clkreq_disable_L1), 2); /* Awake Setting */ INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9485_poseidon1_0_pcie_phy_pll_on_clkreq_disable_L1, ARRAY_LENGTH( ar9485_poseidon1_0_pcie_phy_pll_on_clkreq_disable_L1), 2); } } /* pcie ps setting will honor registry setting, default is 0 */ /*ah->ah_config.ath_hal_pcie_power_save_enable = 0;*/ #if 0 /* ATH_WOW */ /* SerDes values during WOW sleep */ INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_wow, ar9300_pcie_phy_awow, ARRAY_LENGTH(ar9300_pcie_phy_awow), 2); #endif } else if (AR_SREV_WASP(ah)) { /* mac */ INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_CORE], ar9340_wasp_1p0_mac_core, ARRAY_LENGTH(ar9340_wasp_1p0_mac_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_POST], ar9340_wasp_1p0_mac_postamble, ARRAY_LENGTH(ar9340_wasp_1p0_mac_postamble), 5); /* bb */ INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_CORE], ar9340_wasp_1p0_baseband_core, ARRAY_LENGTH(ar9340_wasp_1p0_baseband_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_POST], ar9340_wasp_1p0_baseband_postamble, ARRAY_LENGTH(ar9340_wasp_1p0_baseband_postamble), 5); /* radio */ INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_CORE], ar9340_wasp_1p0_radio_core, ARRAY_LENGTH(ar9340_wasp_1p0_radio_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_POST], ar9340_wasp_1p0_radio_postamble, ARRAY_LENGTH(ar9340_wasp_1p0_radio_postamble), 5); /* soc */ INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_PRE], ar9340_wasp_1p0_soc_preamble, ARRAY_LENGTH(ar9340_wasp_1p0_soc_preamble), 2); INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_CORE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_POST], ar9340_wasp_1p0_soc_postamble, ARRAY_LENGTH(ar9340_wasp_1p0_soc_postamble), 5); /* rx/tx gain */ INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9340Common_wo_xlna_rx_gain_table_wasp_1p0, ARRAY_LENGTH(ar9340Common_wo_xlna_rx_gain_table_wasp_1p0), 2); INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9340Modes_high_ob_db_tx_gain_table_wasp_1p0, ARRAY_LENGTH(ar9340Modes_high_ob_db_tx_gain_table_wasp_1p0), 5); ah->ah_config.ath_hal_pcie_power_save_enable = 0; /* Fast clock modal settings */ INIT_INI_ARRAY(&ahp->ah_ini_modes_additional, ar9340Modes_fast_clock_wasp_1p0, ARRAY_LENGTH(ar9340Modes_fast_clock_wasp_1p0), 3); /* Additional setttings for 40Mhz */ INIT_INI_ARRAY(&ahp->ah_ini_modes_additional_40mhz, ar9340_wasp_1p0_radio_core_40M, ARRAY_LENGTH(ar9340_wasp_1p0_radio_core_40M), 2); /* DFS */ INIT_INI_ARRAY(&ahp->ah_ini_dfs, ar9340_wasp_1p0_baseband_postamble_dfs_channel, ARRAY_LENGTH(ar9340_wasp_1p0_baseband_postamble_dfs_channel), 3); } else if (AR_SREV_SCORPION(ah)) { /* mac */ INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_CORE], ar955x_scorpion_1p0_mac_core, ARRAY_LENGTH(ar955x_scorpion_1p0_mac_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_POST], ar955x_scorpion_1p0_mac_postamble, ARRAY_LENGTH(ar955x_scorpion_1p0_mac_postamble), 5); /* bb */ INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_CORE], ar955x_scorpion_1p0_baseband_core, ARRAY_LENGTH(ar955x_scorpion_1p0_baseband_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_POST], ar955x_scorpion_1p0_baseband_postamble, ARRAY_LENGTH(ar955x_scorpion_1p0_baseband_postamble), 5); /* radio */ INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_CORE], ar955x_scorpion_1p0_radio_core, ARRAY_LENGTH(ar955x_scorpion_1p0_radio_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_POST], ar955x_scorpion_1p0_radio_postamble, ARRAY_LENGTH(ar955x_scorpion_1p0_radio_postamble), 5); /* soc */ INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_PRE], ar955x_scorpion_1p0_soc_preamble, ARRAY_LENGTH(ar955x_scorpion_1p0_soc_preamble), 2); INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_CORE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_POST], ar955x_scorpion_1p0_soc_postamble, ARRAY_LENGTH(ar955x_scorpion_1p0_soc_postamble), 5); /* rx/tx gain */ INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar955xCommon_wo_xlna_rx_gain_table_scorpion_1p0, ARRAY_LENGTH(ar955xCommon_wo_xlna_rx_gain_table_scorpion_1p0), 2); INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain_bounds, ar955xCommon_wo_xlna_rx_gain_bounds_scorpion_1p0, ARRAY_LENGTH(ar955xCommon_wo_xlna_rx_gain_bounds_scorpion_1p0), 5); INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar955xModes_no_xpa_tx_gain_table_scorpion_1p0, ARRAY_LENGTH(ar955xModes_no_xpa_tx_gain_table_scorpion_1p0), 5); /*ath_hal_pciePowerSaveEnable should be 2 for OWL/Condor and 0 for merlin */ ah->ah_config.ath_hal_pcie_power_save_enable = 0; /* Fast clock modal settings */ INIT_INI_ARRAY(&ahp->ah_ini_modes_additional, ar955xModes_fast_clock_scorpion_1p0, ARRAY_LENGTH(ar955xModes_fast_clock_scorpion_1p0), 3); /* Additional setttings for 40Mhz */ //INIT_INI_ARRAY(&ahp->ah_ini_modes_additional_40M, // ar955x_scorpion_1p0_radio_core_40M, // ARRAY_LENGTH(ar955x_scorpion_1p0_radio_core_40M), 2); } else if (AR_SREV_JUPITER_10(ah)) { /* Jupiter: new INI format (pre, core, post arrays per subsystem) */ /* mac */ INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_CORE], ar9300_jupiter_1p0_mac_core, ARRAY_LENGTH(ar9300_jupiter_1p0_mac_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_POST], ar9300_jupiter_1p0_mac_postamble, ARRAY_LENGTH(ar9300_jupiter_1p0_mac_postamble), 5); /* bb */ INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_CORE], ar9300_jupiter_1p0_baseband_core, ARRAY_LENGTH(ar9300_jupiter_1p0_baseband_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_POST], ar9300_jupiter_1p0_baseband_postamble, ARRAY_LENGTH(ar9300_jupiter_1p0_baseband_postamble), 5); /* radio */ INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_CORE], ar9300_jupiter_1p0_radio_core, ARRAY_LENGTH(ar9300_jupiter_1p0_radio_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_POST], ar9300_jupiter_1p0_radio_postamble, ARRAY_LENGTH(ar9300_jupiter_1p0_radio_postamble), 5); /* soc */ INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_PRE], ar9300_jupiter_1p0_soc_preamble, ARRAY_LENGTH(ar9300_jupiter_1p0_soc_preamble), 2); INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_CORE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_POST], ar9300_jupiter_1p0_soc_postamble, ARRAY_LENGTH(ar9300_jupiter_1p0_soc_postamble), 5); /* rx/tx gain */ INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9300_common_rx_gain_table_jupiter_1p0, ARRAY_LENGTH(ar9300_common_rx_gain_table_jupiter_1p0), 2); /* Load PCIE SERDES settings from INI */ if (ah->ah_config.ath_hal_pcie_clock_req) { /* Pci-e Clock Request = 1 */ /* * PLL ON + clkreq enable is not a valid combination, * thus to ignore ath_hal_pll_pwr_save, use PLL OFF. */ { /*Use driver default setting*/ /* Awake -> Sleep Setting */ INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9300_pcie_phy_clkreq_enable_L1_jupiter_1p0, ARRAY_LENGTH(ar9300_pcie_phy_clkreq_enable_L1_jupiter_1p0), 2); /* Sleep -> Awake Setting */ INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9300_pcie_phy_clkreq_enable_L1_jupiter_1p0, ARRAY_LENGTH(ar9300_pcie_phy_clkreq_enable_L1_jupiter_1p0), 2); } } else { /* * Since Jupiter 1.0 and 2.0 share the same device id and will be * installed with same INF, but Jupiter 1.0 has issue with PLL OFF. * * Force Jupiter 1.0 to use ON/ON setting. */ ah->ah_config.ath_hal_pll_pwr_save = 0; /* Pci-e Clock Request = 0 */ if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_CONTROL) { /* Awake -> Sleep Setting */ if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_ON_D3) { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9300_pcie_phy_clkreq_disable_L1_jupiter_1p0, ARRAY_LENGTH( ar9300_pcie_phy_clkreq_disable_L1_jupiter_1p0), 2); } else { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9300_pcie_phy_pll_on_clkreq_disable_L1_jupiter_1p0, ARRAY_LENGTH( ar9300_pcie_phy_pll_on_clkreq_disable_L1_jupiter_1p0), 2); } /* Sleep -> Awake Setting */ if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_ON_D0) { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9300_pcie_phy_clkreq_disable_L1_jupiter_1p0, ARRAY_LENGTH( ar9300_pcie_phy_clkreq_disable_L1_jupiter_1p0), 2); } else { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9300_pcie_phy_pll_on_clkreq_disable_L1_jupiter_1p0, ARRAY_LENGTH( ar9300_pcie_phy_pll_on_clkreq_disable_L1_jupiter_1p0), 2); } } else { /*Use driver default setting*/ /* Awake -> Sleep Setting */ INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9300_pcie_phy_pll_on_clkreq_disable_L1_jupiter_1p0, ARRAY_LENGTH( ar9300_pcie_phy_pll_on_clkreq_disable_L1_jupiter_1p0), 2); /* Sleep -> Awake Setting */ INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9300_pcie_phy_pll_on_clkreq_disable_L1_jupiter_1p0, ARRAY_LENGTH( ar9300_pcie_phy_pll_on_clkreq_disable_L1_jupiter_1p0), 2); } } /* * ath_hal_pcie_power_save_enable should be 2 for OWL/Condor and * 0 for merlin */ ah->ah_config.ath_hal_pcie_power_save_enable = 0; #if 0 // ATH_WOW /* SerDes values during WOW sleep */ INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_wow, ar9300_pcie_phy_AWOW, ARRAY_LENGTH(ar9300_pcie_phy_AWOW), 2); #endif /* Fast clock modal settings */ INIT_INI_ARRAY(&ahp->ah_ini_modes_additional, ar9300_modes_fast_clock_jupiter_1p0, ARRAY_LENGTH(ar9300_modes_fast_clock_jupiter_1p0), 3); INIT_INI_ARRAY(&ahp->ah_ini_japan2484, ar9300_jupiter_1p0_baseband_core_txfir_coeff_japan_2484, ARRAY_LENGTH( ar9300_jupiter_1p0_baseband_core_txfir_coeff_japan_2484), 2); } else if (AR_SREV_JUPITER_20(ah)) { /* Jupiter: new INI format (pre, core, post arrays per subsystem) */ /* mac */ INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_CORE], ar9300_jupiter_2p0_mac_core, ARRAY_LENGTH(ar9300_jupiter_2p0_mac_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_POST], ar9300_jupiter_2p0_mac_postamble, ARRAY_LENGTH(ar9300_jupiter_2p0_mac_postamble), 5); /* bb */ INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_CORE], ar9300_jupiter_2p0_baseband_core, ARRAY_LENGTH(ar9300_jupiter_2p0_baseband_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_POST], ar9300_jupiter_2p0_baseband_postamble, ARRAY_LENGTH(ar9300_jupiter_2p0_baseband_postamble), 5); /* radio */ INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_CORE], ar9300_jupiter_2p0_radio_core, ARRAY_LENGTH(ar9300_jupiter_2p0_radio_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_POST], ar9300_jupiter_2p0_radio_postamble, ARRAY_LENGTH(ar9300_jupiter_2p0_radio_postamble), 5); INIT_INI_ARRAY(&ahp->ah_ini_radio_post_sys2ant, ar9300_jupiter_2p0_radio_postamble_sys2ant, ARRAY_LENGTH(ar9300_jupiter_2p0_radio_postamble_sys2ant), 5); /* soc */ INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_PRE], ar9300_jupiter_2p0_soc_preamble, ARRAY_LENGTH(ar9300_jupiter_2p0_soc_preamble), 2); INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_CORE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_POST], ar9300_jupiter_2p0_soc_postamble, ARRAY_LENGTH(ar9300_jupiter_2p0_soc_postamble), 5); /* rx/tx gain */ INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9300Common_rx_gain_table_jupiter_2p0, ARRAY_LENGTH(ar9300Common_rx_gain_table_jupiter_2p0), 2); /* BTCOEX */ INIT_INI_ARRAY(&ahp->ah_ini_BTCOEX_MAX_TXPWR, ar9300_jupiter_2p0_BTCOEX_MAX_TXPWR_table, ARRAY_LENGTH(ar9300_jupiter_2p0_BTCOEX_MAX_TXPWR_table), 2); /* Load PCIE SERDES settings from INI */ if (ah->ah_config.ath_hal_pcie_clock_req) { /* Pci-e Clock Request = 1 */ /* * PLL ON + clkreq enable is not a valid combination, * thus to ignore ath_hal_pll_pwr_save, use PLL OFF. */ { /*Use driver default setting*/ /* Awake -> Sleep Setting */ INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9300_PciePhy_clkreq_enable_L1_jupiter_2p0, ARRAY_LENGTH(ar9300_PciePhy_clkreq_enable_L1_jupiter_2p0), 2); /* Sleep -> Awake Setting */ INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9300_PciePhy_clkreq_enable_L1_jupiter_2p0, ARRAY_LENGTH(ar9300_PciePhy_clkreq_enable_L1_jupiter_2p0), 2); } } else { /* Pci-e Clock Request = 0 */ if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_CONTROL) { /* Awake -> Sleep Setting */ if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_ON_D3) { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9300_PciePhy_clkreq_disable_L1_jupiter_2p0, ARRAY_LENGTH( ar9300_PciePhy_clkreq_disable_L1_jupiter_2p0), 2); } else { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9300_PciePhy_pll_on_clkreq_disable_L1_jupiter_2p0, ARRAY_LENGTH( ar9300_PciePhy_pll_on_clkreq_disable_L1_jupiter_2p0), 2); } /* Sleep -> Awake Setting */ if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_ON_D0) { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9300_PciePhy_clkreq_disable_L1_jupiter_2p0, ARRAY_LENGTH( ar9300_PciePhy_clkreq_disable_L1_jupiter_2p0), 2); } else { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9300_PciePhy_pll_on_clkreq_disable_L1_jupiter_2p0, ARRAY_LENGTH( ar9300_PciePhy_pll_on_clkreq_disable_L1_jupiter_2p0), 2); } } else { /*Use driver default setting*/ /* Awake -> Sleep Setting */ INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9300_PciePhy_pll_on_clkreq_disable_L1_jupiter_2p0, ARRAY_LENGTH( ar9300_PciePhy_pll_on_clkreq_disable_L1_jupiter_2p0), 2); /* Sleep -> Awake Setting */ INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9300_PciePhy_pll_on_clkreq_disable_L1_jupiter_2p0, ARRAY_LENGTH( ar9300_PciePhy_pll_on_clkreq_disable_L1_jupiter_2p0), 2); } } /* * ath_hal_pcie_power_save_enable should be 2 for OWL/Condor and * 0 for merlin */ ah->ah_config.ath_hal_pcie_power_save_enable = 0; #if 0 // ATH_WOW /* SerDes values during WOW sleep */ INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_wow, ar9300_pcie_phy_AWOW, ARRAY_LENGTH(ar9300_pcie_phy_AWOW), 2); #endif /* Fast clock modal settings */ INIT_INI_ARRAY(&ahp->ah_ini_modes_additional, ar9300Modes_fast_clock_jupiter_2p0, ARRAY_LENGTH(ar9300Modes_fast_clock_jupiter_2p0), 3); INIT_INI_ARRAY(&ahp->ah_ini_japan2484, ar9300_jupiter_2p0_baseband_core_txfir_coeff_japan_2484, ARRAY_LENGTH( ar9300_jupiter_2p0_baseband_core_txfir_coeff_japan_2484), 2); } else if (AR_SREV_APHRODITE(ah)) { /* Aphrodite: new INI format (pre, core, post arrays per subsystem) */ /* mac */ INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_CORE], ar956X_aphrodite_1p0_mac_core, ARRAY_LENGTH(ar956X_aphrodite_1p0_mac_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_POST], ar956X_aphrodite_1p0_mac_postamble, ARRAY_LENGTH(ar956X_aphrodite_1p0_mac_postamble), 5); /* bb */ INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_CORE], ar956X_aphrodite_1p0_baseband_core, ARRAY_LENGTH(ar956X_aphrodite_1p0_baseband_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_POST], ar956X_aphrodite_1p0_baseband_postamble, ARRAY_LENGTH(ar956X_aphrodite_1p0_baseband_postamble), 5); //mark jupiter have but aphrodite don't have // /* radio */ // INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_PRE], NULL, 0, 0); // INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_CORE], // ar9300_aphrodite_1p0_radio_core, // ARRAY_LENGTH(ar9300_aphrodite_1p0_radio_core), 2); // INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_POST], // ar9300_aphrodite_1p0_radio_postamble, // ARRAY_LENGTH(ar9300_aphrodite_1p0_radio_postamble), 5); /* soc */ INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_PRE], ar956X_aphrodite_1p0_soc_preamble, ARRAY_LENGTH(ar956X_aphrodite_1p0_soc_preamble), 2); INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_CORE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_POST], ar956X_aphrodite_1p0_soc_postamble, ARRAY_LENGTH(ar956X_aphrodite_1p0_soc_postamble), 5); /* rx/tx gain */ INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar956XCommon_rx_gain_table_aphrodite_1p0, ARRAY_LENGTH(ar956XCommon_rx_gain_table_aphrodite_1p0), 2); //INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, // ar956XModes_lowest_ob_db_tx_gain_table_aphrodite_1p0, // ARRAY_LENGTH(ar956XModes_lowest_ob_db_tx_gain_table_aphrodite_1p0), // 5); /* * ath_hal_pcie_power_save_enable should be 2 for OWL/Condor and * 0 for merlin */ ah->ah_config.ath_hal_pcie_power_save_enable = 0; #if 0 // ATH_WOW /* SerDes values during WOW sleep */ INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_wow, ar9300_pcie_phy_AWOW, ARRAY_LENGTH(ar9300_pcie_phy_AWOW), 2); #endif /* Fast clock modal settings */ INIT_INI_ARRAY(&ahp->ah_ini_modes_additional, ar956XModes_fast_clock_aphrodite_1p0, ARRAY_LENGTH(ar956XModes_fast_clock_aphrodite_1p0), 3); } else if (AR_SREV_AR9580(ah)) { /* * AR9580/Peacock - * new INI format (pre, core, post arrays per subsystem) */ /* mac */ INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_CORE], ar9300_ar9580_1p0_mac_core, ARRAY_LENGTH(ar9300_ar9580_1p0_mac_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_POST], ar9300_ar9580_1p0_mac_postamble, ARRAY_LENGTH(ar9300_ar9580_1p0_mac_postamble), 5); /* bb */ INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_CORE], ar9300_ar9580_1p0_baseband_core, ARRAY_LENGTH(ar9300_ar9580_1p0_baseband_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_POST], ar9300_ar9580_1p0_baseband_postamble, ARRAY_LENGTH(ar9300_ar9580_1p0_baseband_postamble), 5); /* radio */ INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_CORE], ar9300_ar9580_1p0_radio_core, ARRAY_LENGTH(ar9300_ar9580_1p0_radio_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_POST], ar9300_ar9580_1p0_radio_postamble, ARRAY_LENGTH(ar9300_ar9580_1p0_radio_postamble), 5); /* soc */ INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_PRE], ar9300_ar9580_1p0_soc_preamble, ARRAY_LENGTH(ar9300_ar9580_1p0_soc_preamble), 2); INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_CORE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_POST], ar9300_ar9580_1p0_soc_postamble, ARRAY_LENGTH(ar9300_ar9580_1p0_soc_postamble), 5); /* rx/tx gain */ INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9300_common_rx_gain_table_ar9580_1p0, ARRAY_LENGTH(ar9300_common_rx_gain_table_ar9580_1p0), 2); INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9300Modes_lowest_ob_db_tx_gain_table_ar9580_1p0, ARRAY_LENGTH(ar9300Modes_lowest_ob_db_tx_gain_table_ar9580_1p0), 5); /* DFS */ INIT_INI_ARRAY(&ahp->ah_ini_dfs, ar9300_ar9580_1p0_baseband_postamble_dfs_channel, ARRAY_LENGTH(ar9300_ar9580_1p0_baseband_postamble_dfs_channel), 3); /* Load PCIE SERDES settings from INI */ /*D3 Setting */ if (ah->ah_config.ath_hal_pcie_clock_req) { if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_CONTROL) { //registry control if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_ON_D3) { //bit1, in to D3 INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9300PciePhy_clkreq_enable_L1_ar9580_1p0, ARRAY_LENGTH(ar9300PciePhy_clkreq_enable_L1_ar9580_1p0), 2); } else { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9300PciePhy_pll_on_clkreq_disable_L1_ar9580_1p0, ARRAY_LENGTH( ar9300PciePhy_pll_on_clkreq_disable_L1_ar9580_1p0), 2); } } else {//no registry control, default is pll on INIT_INI_ARRAY( &ahp->ah_ini_pcie_serdes, ar9300PciePhy_pll_on_clkreq_disable_L1_ar9580_1p0, ARRAY_LENGTH( ar9300PciePhy_pll_on_clkreq_disable_L1_ar9580_1p0), 2); } } else { if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_CONTROL) { //registry control if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_ON_D3) { //bit1, in to D3 INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9300PciePhy_clkreq_disable_L1_ar9580_1p0, ARRAY_LENGTH( ar9300PciePhy_clkreq_disable_L1_ar9580_1p0), 2); } else { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9300PciePhy_pll_on_clkreq_disable_L1_ar9580_1p0, ARRAY_LENGTH( ar9300PciePhy_pll_on_clkreq_disable_L1_ar9580_1p0), 2); } } else {//no registry control, default is pll on INIT_INI_ARRAY( &ahp->ah_ini_pcie_serdes, ar9300PciePhy_pll_on_clkreq_disable_L1_ar9580_1p0, ARRAY_LENGTH( ar9300PciePhy_pll_on_clkreq_disable_L1_ar9580_1p0), 2); } } /*D0 Setting */ if (ah->ah_config.ath_hal_pcie_clock_req) { if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_CONTROL) { //registry control if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_ON_D0) { //bit2, out of D3 INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9300PciePhy_clkreq_enable_L1_ar9580_1p0, ARRAY_LENGTH(ar9300PciePhy_clkreq_enable_L1_ar9580_1p0), 2); } else { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9300PciePhy_pll_on_clkreq_disable_L1_ar9580_1p0, ARRAY_LENGTH( ar9300PciePhy_pll_on_clkreq_disable_L1_ar9580_1p0), 2); } } else { //no registry control, default is pll on INIT_INI_ARRAY( &ahp->ah_ini_pcie_serdes_low_power, ar9300PciePhy_pll_on_clkreq_disable_L1_ar9580_1p0, ARRAY_LENGTH( ar9300PciePhy_pll_on_clkreq_disable_L1_ar9580_1p0), 2); } } else { if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_CONTROL) {//registry control if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_ON_D0) {//bit2, out of D3 INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9300PciePhy_clkreq_disable_L1_ar9580_1p0, ARRAY_LENGTH(ar9300PciePhy_clkreq_disable_L1_ar9580_1p0), 2); } else { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9300PciePhy_pll_on_clkreq_disable_L1_ar9580_1p0, ARRAY_LENGTH( ar9300PciePhy_pll_on_clkreq_disable_L1_ar9580_1p0), 2); } } else { //no registry control, default is pll on INIT_INI_ARRAY( &ahp->ah_ini_pcie_serdes_low_power, ar9300PciePhy_pll_on_clkreq_disable_L1_ar9580_1p0, ARRAY_LENGTH( ar9300PciePhy_pll_on_clkreq_disable_L1_ar9580_1p0), 2); } } ah->ah_config.ath_hal_pcie_power_save_enable = 0; #if 0 /* ATH_WOW */ /* SerDes values during WOW sleep */ INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_wow, ar9300_pcie_phy_awow, ARRAY_LENGTH(ar9300_pcie_phy_awow), 2); #endif /* Fast clock modal settings */ INIT_INI_ARRAY(&ahp->ah_ini_modes_additional, ar9300Modes_fast_clock_ar9580_1p0, ARRAY_LENGTH(ar9300Modes_fast_clock_ar9580_1p0), 3); INIT_INI_ARRAY(&ahp->ah_ini_japan2484, ar9300_ar9580_1p0_baseband_core_txfir_coeff_japan_2484, ARRAY_LENGTH( ar9300_ar9580_1p0_baseband_core_txfir_coeff_japan_2484), 2); } else { /* * Osprey 2.2 - new INI format (pre, core, post arrays per subsystem) */ /* mac */ INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_CORE], ar9300_osprey_2p2_mac_core, ARRAY_LENGTH(ar9300_osprey_2p2_mac_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_mac[ATH_INI_POST], ar9300_osprey_2p2_mac_postamble, ARRAY_LENGTH(ar9300_osprey_2p2_mac_postamble), 5); /* bb */ INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_CORE], ar9300_osprey_2p2_baseband_core, ARRAY_LENGTH(ar9300_osprey_2p2_baseband_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_bb[ATH_INI_POST], ar9300_osprey_2p2_baseband_postamble, ARRAY_LENGTH(ar9300_osprey_2p2_baseband_postamble), 5); /* radio */ INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_CORE], ar9300_osprey_2p2_radio_core, ARRAY_LENGTH(ar9300_osprey_2p2_radio_core), 2); INIT_INI_ARRAY(&ahp->ah_ini_radio[ATH_INI_POST], ar9300_osprey_2p2_radio_postamble, ARRAY_LENGTH(ar9300_osprey_2p2_radio_postamble), 5); /* soc */ INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_PRE], ar9300_osprey_2p2_soc_preamble, ARRAY_LENGTH(ar9300_osprey_2p2_soc_preamble), 2); INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_CORE], NULL, 0, 0); INIT_INI_ARRAY(&ahp->ah_ini_soc[ATH_INI_POST], ar9300_osprey_2p2_soc_postamble, ARRAY_LENGTH(ar9300_osprey_2p2_soc_postamble), 5); /* rx/tx gain */ INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9300_common_rx_gain_table_osprey_2p2, ARRAY_LENGTH(ar9300_common_rx_gain_table_osprey_2p2), 2); INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9300_modes_lowest_ob_db_tx_gain_table_osprey_2p2, ARRAY_LENGTH(ar9300_modes_lowest_ob_db_tx_gain_table_osprey_2p2), 5); /* DFS */ INIT_INI_ARRAY(&ahp->ah_ini_dfs, ar9300_osprey_2p2_baseband_postamble_dfs_channel, ARRAY_LENGTH(ar9300_osprey_2p2_baseband_postamble_dfs_channel), 3); /* Load PCIE SERDES settings from INI */ /*D3 Setting */ if (ah->ah_config.ath_hal_pcie_clock_req) { if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_CONTROL) { //registry control if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_ON_D3) { //bit1, in to D3 INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9300PciePhy_clkreq_enable_L1_osprey_2p2, ARRAY_LENGTH(ar9300PciePhy_clkreq_enable_L1_osprey_2p2), 2); } else { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9300PciePhy_pll_on_clkreq_disable_L1_osprey_2p2, ARRAY_LENGTH( ar9300PciePhy_pll_on_clkreq_disable_L1_osprey_2p2), 2); } } else {//no registry control, default is pll on #ifndef ATH_BUS_PM INIT_INI_ARRAY( &ahp->ah_ini_pcie_serdes, ar9300PciePhy_pll_on_clkreq_disable_L1_osprey_2p2, ARRAY_LENGTH( ar9300PciePhy_pll_on_clkreq_disable_L1_osprey_2p2), 2); #else //no registry control, default is pll off INIT_INI_ARRAY( &ahp->ah_ini_pcie_serdes, ar9300PciePhy_clkreq_disable_L1_osprey_2p2, ARRAY_LENGTH( ar9300PciePhy_clkreq_disable_L1_osprey_2p2), 2); #endif } } else { if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_CONTROL) { //registry control if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_ON_D3) { //bit1, in to D3 INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9300PciePhy_clkreq_disable_L1_osprey_2p2, ARRAY_LENGTH( ar9300PciePhy_clkreq_disable_L1_osprey_2p2), 2); } else { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9300PciePhy_pll_on_clkreq_disable_L1_osprey_2p2, ARRAY_LENGTH( ar9300PciePhy_pll_on_clkreq_disable_L1_osprey_2p2), 2); } } else { #ifndef ATH_BUS_PM //no registry control, default is pll on INIT_INI_ARRAY( &ahp->ah_ini_pcie_serdes, ar9300PciePhy_pll_on_clkreq_disable_L1_osprey_2p2, ARRAY_LENGTH( ar9300PciePhy_pll_on_clkreq_disable_L1_osprey_2p2), 2); #else //no registry control, default is pll off INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes, ar9300PciePhy_clkreq_disable_L1_osprey_2p2, ARRAY_LENGTH(ar9300PciePhy_clkreq_disable_L1_osprey_2p2), 2); #endif } } /*D0 Setting */ if (ah->ah_config.ath_hal_pcie_clock_req) { if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_CONTROL) { //registry control if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_ON_D0) { //bit2, out of D3 INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9300PciePhy_clkreq_enable_L1_osprey_2p2, ARRAY_LENGTH(ar9300PciePhy_clkreq_enable_L1_osprey_2p2), 2); } else { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9300PciePhy_pll_on_clkreq_disable_L1_osprey_2p2, ARRAY_LENGTH( ar9300PciePhy_pll_on_clkreq_disable_L1_osprey_2p2), 2); } } else { //no registry control, default is pll on INIT_INI_ARRAY( &ahp->ah_ini_pcie_serdes_low_power, ar9300PciePhy_pll_on_clkreq_disable_L1_osprey_2p2, ARRAY_LENGTH( ar9300PciePhy_pll_on_clkreq_disable_L1_osprey_2p2), 2); } } else { if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_CONTROL) {//registry control if (ah->ah_config.ath_hal_pll_pwr_save & AR_PCIE_PLL_PWRSAVE_ON_D0) {//bit2, out of D3 INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9300PciePhy_clkreq_disable_L1_osprey_2p2, ARRAY_LENGTH(ar9300PciePhy_clkreq_disable_L1_osprey_2p2), 2); } else { INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_low_power, ar9300PciePhy_pll_on_clkreq_disable_L1_osprey_2p2, ARRAY_LENGTH( ar9300PciePhy_pll_on_clkreq_disable_L1_osprey_2p2), 2); } } else { //no registry control, default is pll on INIT_INI_ARRAY( &ahp->ah_ini_pcie_serdes_low_power, ar9300PciePhy_pll_on_clkreq_disable_L1_osprey_2p2, ARRAY_LENGTH( ar9300PciePhy_pll_on_clkreq_disable_L1_osprey_2p2), 2); } } ah->ah_config.ath_hal_pcie_power_save_enable = 0; #ifdef ATH_BUS_PM /*Use HAL to config PCI powersave by writing into the SerDes Registers */ ah->ah_config.ath_hal_pcie_ser_des_write = 1; #endif #if 0 /* ATH_WOW */ /* SerDes values during WOW sleep */ INIT_INI_ARRAY(&ahp->ah_ini_pcie_serdes_wow, ar9300_pcie_phy_awow, ARRAY_LENGTH(ar9300_pcie_phy_awow), 2); #endif /* Fast clock modal settings */ INIT_INI_ARRAY(&ahp->ah_ini_modes_additional, ar9300Modes_fast_clock_osprey_2p2, ARRAY_LENGTH(ar9300Modes_fast_clock_osprey_2p2), 3); INIT_INI_ARRAY(&ahp->ah_ini_japan2484, ar9300_osprey_2p2_baseband_core_txfir_coeff_japan_2484, ARRAY_LENGTH( ar9300_osprey_2p2_baseband_core_txfir_coeff_japan_2484), 2); } if(AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { #define AR_SOC_RST_OTP_INTF 0xB80600B4 #define REG_READ(_reg) *((volatile u_int32_t *)(_reg)) ahp->ah_enterprise_mode = REG_READ(AR_SOC_RST_OTP_INTF); if (AR_SREV_SCORPION(ah)) { ahp->ah_enterprise_mode = ahp->ah_enterprise_mode << 12; } ath_hal_printf (ah, "Enterprise mode: 0x%08x\n", ahp->ah_enterprise_mode); #undef REG_READ #undef AR_SOC_RST_OTP_INTF } else { ahp->ah_enterprise_mode = OS_REG_READ(ah, AR_ENT_OTP); } if (ahpriv->ah_ispcie) { ar9300_config_pci_power_save(ah, 0, 0); } else { ar9300_disable_pcie_phy(ah); } ath_hal_printf(ah, "%s: calling ar9300_hw_attach\n", __func__); ecode = ar9300_hw_attach(ah); if (ecode != HAL_OK) { goto bad; } /* set gain table pointers according to values read from the eeprom */ ar9300_tx_gain_table_apply(ah); ar9300_rx_gain_table_apply(ah); /* ** ** Got everything we need now to setup the capabilities. */ if (!ar9300_fill_capability_info(ah)) { HALDEBUG(ah, HAL_DEBUG_RESET, "%s:failed ar9300_fill_capability_info\n", __func__); ecode = HAL_EEREAD; goto bad; } ecode = ar9300_init_mac_addr(ah); if (ecode != HAL_OK) { HALDEBUG(ah, HAL_DEBUG_RESET, "%s: failed initializing mac address\n", __func__); goto bad; } /* * Initialize receive buffer size to MAC default */ ahp->rx_buf_size = HAL_RXBUFSIZE_DEFAULT; #if ATH_WOW #if 0 /* * Needs to be removed once we stop using XB92 XXX * FIXME: Check with latest boards too - SriniK */ ar9300_wow_set_gpio_reset_low(ah); #endif /* * Clear the Wow Status. */ OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_PCIE_PM_CTRL), OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_PCIE_PM_CTRL)) | AR_PMCTRL_WOW_PME_CLR); OS_REG_WRITE(ah, AR_WOW_PATTERN_REG, AR_WOW_CLEAR_EVENTS(OS_REG_READ(ah, AR_WOW_PATTERN_REG))); #endif /* * Set the cur_trig_level to a value that works all modes - 11a/b/g or 11n * with aggregation enabled or disabled. */ ahp->ah_tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S); if (AR_SREV_HORNET(ah)) { ahp->nf_2GHz.nominal = AR_PHY_CCA_NOM_VAL_HORNET_2GHZ; ahp->nf_2GHz.max = AR_PHY_CCA_MAX_GOOD_VAL_OSPREY_2GHZ; ahp->nf_2GHz.min = AR_PHY_CCA_MIN_GOOD_VAL_OSPREY_2GHZ; ahp->nf_5GHz.nominal = AR_PHY_CCA_NOM_VAL_OSPREY_5GHZ; ahp->nf_5GHz.max = AR_PHY_CCA_MAX_GOOD_VAL_OSPREY_5GHZ; ahp->nf_5GHz.min = AR_PHY_CCA_MIN_GOOD_VAL_OSPREY_5GHZ; ahp->nf_cw_int_delta = AR_PHY_CCA_CW_INT_DELTA; } else if(AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)){ ahp->nf_2GHz.nominal = AR_PHY_CCA_NOM_VAL_JUPITER_2GHZ; ahp->nf_2GHz.max = AR_PHY_CCA_MAX_GOOD_VAL_OSPREY_2GHZ; ahp->nf_2GHz.min = AR_PHY_CCA_MIN_GOOD_VAL_JUPITER_2GHZ; ahp->nf_5GHz.nominal = AR_PHY_CCA_NOM_VAL_JUPITER_5GHZ; ahp->nf_5GHz.max = AR_PHY_CCA_MAX_GOOD_VAL_OSPREY_5GHZ; ahp->nf_5GHz.min = AR_PHY_CCA_MIN_GOOD_VAL_JUPITER_5GHZ; ahp->nf_cw_int_delta = AR_PHY_CCA_CW_INT_DELTA; } else { ahp->nf_2GHz.nominal = AR_PHY_CCA_NOM_VAL_OSPREY_2GHZ; ahp->nf_2GHz.max = AR_PHY_CCA_MAX_GOOD_VAL_OSPREY_2GHZ; ahp->nf_2GHz.min = AR_PHY_CCA_MIN_GOOD_VAL_OSPREY_2GHZ; if (AR_SREV_AR9580(ah) || AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { ahp->nf_5GHz.nominal = AR_PHY_CCA_NOM_VAL_PEACOCK_5GHZ; } else { ahp->nf_5GHz.nominal = AR_PHY_CCA_NOM_VAL_OSPREY_5GHZ; } ahp->nf_5GHz.max = AR_PHY_CCA_MAX_GOOD_VAL_OSPREY_5GHZ; ahp->nf_5GHz.min = AR_PHY_CCA_MIN_GOOD_VAL_OSPREY_5GHZ; ahp->nf_cw_int_delta = AR_PHY_CCA_CW_INT_DELTA; } /* init BB Panic Watchdog timeout */ if (AR_SREV_HORNET(ah)) { ahp->ah_bb_panic_timeout_ms = HAL_BB_PANIC_WD_TMO_HORNET; } else { ahp->ah_bb_panic_timeout_ms = HAL_BB_PANIC_WD_TMO; } /* * Determine whether tx IQ calibration HW should be enabled, * and whether tx IQ calibration should be performed during * AGC calibration, or separately. */ if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { /* * Register not initialized yet. This flag will be re-initialized * after INI loading following each reset. */ ahp->tx_iq_cal_enable = 1; /* if tx IQ cal is enabled, do it together with AGC cal */ ahp->tx_iq_cal_during_agc_cal = 1; } else if (AR_SREV_POSEIDON_OR_LATER(ah) && !AR_SREV_WASP(ah)) { ahp->tx_iq_cal_enable = 1; ahp->tx_iq_cal_during_agc_cal = 1; } else { /* osprey, hornet, wasp */ ahp->tx_iq_cal_enable = 1; ahp->tx_iq_cal_during_agc_cal = 0; } return ah; bad: if (ahp) { ar9300_detach((struct ath_hal *) ahp); } if (status) { *status = ecode; } return AH_NULL; } void ar9300_detach(struct ath_hal *ah) { HALASSERT(ah != AH_NULL); HALASSERT(ah->ah_magic == AR9300_MAGIC); /* Make sure that chip is awake before writing to it */ if (!ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE)) { HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s: failed to wake up chip\n", __func__); } ar9300_hw_detach(ah); ar9300_set_power_mode(ah, HAL_PM_FULL_SLEEP, AH_TRUE); // ath_hal_hdprintf_deregister(ah); if (AH9300(ah)->ah_cal_mem) ath_hal_free(AH9300(ah)->ah_cal_mem); AH9300(ah)->ah_cal_mem = AH_NULL; ath_hal_free(ah); } struct ath_hal_9300 * ar9300_new_state(u_int16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_OPS_CONFIG *ah_config, HAL_STATUS *status) { static const u_int8_t defbssidmask[IEEE80211_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; struct ath_hal_9300 *ahp; struct ath_hal *ah; /* NB: memory is returned zero'd */ ahp = ath_hal_malloc(sizeof(struct ath_hal_9300)); if (ahp == AH_NULL) { HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, "%s: cannot allocate memory for state block\n", __func__); *status = HAL_ENOMEM; return AH_NULL; } ah = &ahp->ah_priv.h; /* set initial values */ /* stub everything first */ ar9300_set_stub_functions(ah); /* setup the FreeBSD HAL methods */ ar9300_attach_freebsd_ops(ah); /* These are private to this particular file, so .. */ ah->ah_disablePCIE = ar9300_disable_pcie_phy; AH_PRIVATE(ah)->ah_getNfAdjust = ar9300_get_nf_adjust; AH_PRIVATE(ah)->ah_getChipPowerLimits = ar9300_get_chip_power_limits; #if 0 /* Attach Osprey structure as default hal structure */ OS_MEMCPY(&ahp->ah_priv.priv, &ar9300hal, sizeof(ahp->ah_priv.priv)); #endif #if 0 AH_PRIVATE(ah)->amem_handle = amem_handle; AH_PRIVATE(ah)->ah_osdev = osdev; #endif ah->ah_sc = sc; ah->ah_st = st; ah->ah_sh = sh; ah->ah_magic = AR9300_MAGIC; AH_PRIVATE(ah)->ah_devid = devid; AH_PRIVATE(ah)->ah_flags = 0; /* ** Initialize factory defaults in the private space */ // ath_hal_factory_defaults(AH_PRIVATE(ah), hal_conf_parm); ar9300_config_defaults_freebsd(ah, ah_config); /* XXX FreeBSD: cal is always in EEPROM */ #if 0 if (!hal_conf_parm->calInFlash) { AH_PRIVATE(ah)->ah_flags |= AH_USE_EEPROM; } #endif AH_PRIVATE(ah)->ah_flags |= AH_USE_EEPROM; #if 0 if (ar9300_eep_data_in_flash(ah)) { ahp->ah_priv.priv.ah_eeprom_read = ar9300_flash_read; ahp->ah_priv.priv.ah_eeprom_dump = AH_NULL; } else { ahp->ah_priv.priv.ah_eeprom_read = ar9300_eeprom_read_word; } #endif /* XXX FreeBSD - for now, just supports EEPROM reading */ ahp->ah_priv.ah_eepromRead = ar9300_eeprom_read_word; AH_PRIVATE(ah)->ah_powerLimit = MAX_RATE_POWER; AH_PRIVATE(ah)->ah_tpScale = HAL_TP_SCALE_MAX; /* no scaling */ ahp->ah_atim_window = 0; /* [0..1000] */ ahp->ah_diversity_control = ah->ah_config.ath_hal_diversity_control; ahp->ah_antenna_switch_swap = ah->ah_config.ath_hal_antenna_switch_swap; /* * Enable MIC handling. */ ahp->ah_sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE; ahp->ah_enable32k_hz_clock = DONT_USE_32KHZ;/* XXX */ ahp->ah_slot_time = (u_int) -1; ahp->ah_ack_timeout = (u_int) -1; OS_MEMCPY(&ahp->ah_bssid_mask, defbssidmask, IEEE80211_ADDR_LEN); /* * 11g-specific stuff */ ahp->ah_g_beacon_rate = 0; /* adhoc beacon fixed rate */ /* SM power mode: Attach time, disable any setting */ ahp->ah_sm_power_mode = HAL_SMPS_DEFAULT; return ahp; } HAL_BOOL ar9300_chip_test(struct ath_hal *ah) { /*u_int32_t reg_addr[2] = { AR_STA_ID0, AR_PHY_BASE+(8 << 2) };*/ u_int32_t reg_addr[2] = { AR_STA_ID0 }; u_int32_t reg_hold[2]; u_int32_t pattern_data[4] = { 0x55555555, 0xaaaaaaaa, 0x66666666, 0x99999999 }; int i, j; /* Test PHY & MAC registers */ for (i = 0; i < 1; i++) { u_int32_t addr = reg_addr[i]; u_int32_t wr_data, rd_data; reg_hold[i] = OS_REG_READ(ah, addr); for (j = 0; j < 0x100; j++) { wr_data = (j << 16) | j; OS_REG_WRITE(ah, addr, wr_data); rd_data = OS_REG_READ(ah, addr); if (rd_data != wr_data) { HALDEBUG(ah, HAL_DEBUG_REGIO, "%s: address test failed addr: " "0x%08x - wr:0x%08x != rd:0x%08x\n", __func__, addr, wr_data, rd_data); return AH_FALSE; } } for (j = 0; j < 4; j++) { wr_data = pattern_data[j]; OS_REG_WRITE(ah, addr, wr_data); rd_data = OS_REG_READ(ah, addr); if (wr_data != rd_data) { HALDEBUG(ah, HAL_DEBUG_REGIO, "%s: address test failed addr: " "0x%08x - wr:0x%08x != rd:0x%08x\n", __func__, addr, wr_data, rd_data); return AH_FALSE; } } OS_REG_WRITE(ah, reg_addr[i], reg_hold[i]); } OS_DELAY(100); return AH_TRUE; } /* * Store the channel edges for the requested operational mode */ HAL_BOOL ar9300_get_channel_edges(struct ath_hal *ah, u_int16_t flags, u_int16_t *low, u_int16_t *high) { struct ath_hal_private *ahpriv = AH_PRIVATE(ah); HAL_CAPABILITIES *p_cap = &ahpriv->ah_caps; if (flags & IEEE80211_CHAN_5GHZ) { *low = p_cap->halLow5GhzChan; *high = p_cap->halHigh5GhzChan; return AH_TRUE; } if ((flags & IEEE80211_CHAN_2GHZ)) { *low = p_cap->halLow2GhzChan; *high = p_cap->halHigh2GhzChan; return AH_TRUE; } return AH_FALSE; } HAL_BOOL ar9300_regulatory_domain_override(struct ath_hal *ah, u_int16_t regdmn) { AH_PRIVATE(ah)->ah_currentRD = regdmn; return AH_TRUE; } /* * Fill all software cached or static hardware state information. * Return failure if capabilities are to come from EEPROM and * cannot be read. */ HAL_BOOL ar9300_fill_capability_info(struct ath_hal *ah) { #define AR_KEYTABLE_SIZE 128 struct ath_hal_9300 *ahp = AH9300(ah); struct ath_hal_private *ahpriv = AH_PRIVATE(ah); HAL_CAPABILITIES *p_cap = &ahpriv->ah_caps; u_int16_t cap_field = 0, eeval; ahpriv->ah_devType = (u_int16_t)ar9300_eeprom_get(ahp, EEP_DEV_TYPE); eeval = ar9300_eeprom_get(ahp, EEP_REG_0); /* XXX record serial number */ AH_PRIVATE(ah)->ah_currentRD = eeval; /* Always enable fast clock; leave it up to EEPROM and channel */ p_cap->halSupportsFastClock5GHz = AH_TRUE; p_cap->halIntrMitigation = AH_TRUE; eeval = ar9300_eeprom_get(ahp, EEP_REG_1); AH_PRIVATE(ah)->ah_currentRDext = eeval | AR9300_RDEXT_DEFAULT; /* Read the capability EEPROM location */ cap_field = ar9300_eeprom_get(ahp, EEP_OP_CAP); /* Construct wireless mode from EEPROM */ p_cap->halWirelessModes = 0; eeval = ar9300_eeprom_get(ahp, EEP_OP_MODE); /* * XXX FreeBSD specific: for now, set ath_hal_ht_enable to 1, * or we won't have 11n support. */ ah->ah_config.ath_hal_ht_enable = 1; if (eeval & AR9300_OPFLAGS_11A) { p_cap->halWirelessModes |= HAL_MODE_11A | ((!ah->ah_config.ath_hal_ht_enable || (eeval & AR9300_OPFLAGS_N_5G_HT20)) ? 0 : (HAL_MODE_11NA_HT20 | ((eeval & AR9300_OPFLAGS_N_5G_HT40) ? 0 : (HAL_MODE_11NA_HT40PLUS | HAL_MODE_11NA_HT40MINUS)))); } if (eeval & AR9300_OPFLAGS_11G) { p_cap->halWirelessModes |= HAL_MODE_11B | HAL_MODE_11G | ((!ah->ah_config.ath_hal_ht_enable || (eeval & AR9300_OPFLAGS_N_2G_HT20)) ? 0 : (HAL_MODE_11NG_HT20 | ((eeval & AR9300_OPFLAGS_N_2G_HT40) ? 0 : (HAL_MODE_11NG_HT40PLUS | HAL_MODE_11NG_HT40MINUS)))); } /* Get chainamsks from eeprom */ p_cap->halTxChainMask = ar9300_eeprom_get(ahp, EEP_TX_MASK); p_cap->halRxChainMask = ar9300_eeprom_get(ahp, EEP_RX_MASK); #define owl_get_ntxchains(_txchainmask) \ (((_txchainmask >> 2) & 1) + ((_txchainmask >> 1) & 1) + (_txchainmask & 1)) /* FreeBSD: Update number of TX/RX streams */ p_cap->halTxStreams = owl_get_ntxchains(p_cap->halTxChainMask); p_cap->halRxStreams = owl_get_ntxchains(p_cap->halRxChainMask); /* * This being a newer chip supports TKIP non-splitmic mode. * */ ahp->ah_misc_mode |= AR_PCU_MIC_NEW_LOC_ENA; p_cap->halTkipMicTxRxKeySupport = AH_TRUE; p_cap->halLow2GhzChan = 2312; p_cap->halHigh2GhzChan = 2732; p_cap->halLow5GhzChan = 4920; p_cap->halHigh5GhzChan = 6100; p_cap->halCipherCkipSupport = AH_FALSE; p_cap->halCipherTkipSupport = AH_TRUE; p_cap->halCipherAesCcmSupport = AH_TRUE; p_cap->halMicCkipSupport = AH_FALSE; p_cap->halMicTkipSupport = AH_TRUE; p_cap->halMicAesCcmSupport = AH_TRUE; p_cap->halChanSpreadSupport = AH_TRUE; p_cap->halSleepAfterBeaconBroken = AH_TRUE; p_cap->halBurstSupport = AH_TRUE; p_cap->halChapTuningSupport = AH_TRUE; p_cap->halTurboPrimeSupport = AH_TRUE; - p_cap->halFastFramesSupport = AH_FALSE; + p_cap->halFastFramesSupport = AH_TRUE; p_cap->halTurboGSupport = p_cap->halWirelessModes & HAL_MODE_108G; // p_cap->hal_xr_support = AH_FALSE; p_cap->halHTSupport = ah->ah_config.ath_hal_ht_enable ? AH_TRUE : AH_FALSE; p_cap->halGTTSupport = AH_TRUE; p_cap->halPSPollBroken = AH_TRUE; /* XXX fixed in later revs? */ p_cap->halNumMRRetries = 4; /* Hardware supports 4 MRR */ p_cap->halHTSGI20Support = AH_TRUE; p_cap->halVEOLSupport = AH_TRUE; p_cap->halBssIdMaskSupport = AH_TRUE; /* Bug 26802, fixed in later revs? */ p_cap->halMcastKeySrchSupport = AH_TRUE; p_cap->halTsfAddSupport = AH_TRUE; if (cap_field & AR_EEPROM_EEPCAP_MAXQCU) { p_cap->halTotalQueues = MS(cap_field, AR_EEPROM_EEPCAP_MAXQCU); } else { p_cap->halTotalQueues = HAL_NUM_TX_QUEUES; } if (cap_field & AR_EEPROM_EEPCAP_KC_ENTRIES) { p_cap->halKeyCacheSize = 1 << MS(cap_field, AR_EEPROM_EEPCAP_KC_ENTRIES); } else { p_cap->halKeyCacheSize = AR_KEYTABLE_SIZE; } p_cap->halFastCCSupport = AH_TRUE; // p_cap->hal_num_mr_retries = 4; // ahp->hal_tx_trig_level_max = MAX_TX_FIFO_THRESHOLD; p_cap->halNumGpioPins = AR9382_MAX_GPIO_PIN_NUM; #if 0 /* XXX Verify support in Osprey */ if (AR_SREV_MERLIN_10_OR_LATER(ah)) { p_cap->halWowSupport = AH_TRUE; p_cap->hal_wow_match_pattern_exact = AH_TRUE; if (AR_SREV_MERLIN(ah)) { p_cap->hal_wow_pattern_match_dword = AH_TRUE; } } else { p_cap->halWowSupport = AH_FALSE; p_cap->hal_wow_match_pattern_exact = AH_FALSE; } #endif p_cap->halWowSupport = AH_TRUE; p_cap->halWowMatchPatternExact = AH_TRUE; if (AR_SREV_POSEIDON(ah)) { p_cap->halWowMatchPatternExact = AH_TRUE; } p_cap->halCSTSupport = AH_TRUE; p_cap->halRifsRxSupport = AH_TRUE; p_cap->halRifsTxSupport = AH_TRUE; #define IEEE80211_AMPDU_LIMIT_MAX (65536) p_cap->halRtsAggrLimit = IEEE80211_AMPDU_LIMIT_MAX; #undef IEEE80211_AMPDU_LIMIT_MAX p_cap->halMfpSupport = ah->ah_config.ath_hal_mfp_support; p_cap->halForcePpmSupport = AH_TRUE; p_cap->halHwBeaconProcSupport = AH_TRUE; /* ar9300 - has the HW UAPSD trigger support, * but it has the following limitations * The power state change from the following * frames are not put in High priority queue. * i) Mgmt frames * ii) NoN QoS frames * iii) QoS frames form the access categories for which * UAPSD is not enabled. * so we can not enable this feature currently. * could be enabled, if these limitations are fixed * in later versions of ar9300 chips */ p_cap->halHasUapsdSupport = AH_FALSE; /* Number of buffers that can be help in a single TxD */ p_cap->halNumTxMaps = 4; p_cap->halTxDescLen = sizeof(struct ar9300_txc); p_cap->halTxStatusLen = sizeof(struct ar9300_txs); p_cap->halRxStatusLen = sizeof(struct ar9300_rxs); p_cap->halRxHpFifoDepth = HAL_HP_RXFIFO_DEPTH; p_cap->halRxLpFifoDepth = HAL_LP_RXFIFO_DEPTH; /* Enable extension channel DFS support */ p_cap->halUseCombinedRadarRssi = AH_TRUE; p_cap->halExtChanDfsSupport = AH_TRUE; #if ATH_SUPPORT_SPECTRAL p_cap->halSpectralScanSupport = AH_TRUE; #endif ahpriv->ah_rfsilent = ar9300_eeprom_get(ahp, EEP_RF_SILENT); if (ahpriv->ah_rfsilent & EEP_RFSILENT_ENABLED) { ahp->ah_gpio_select = MS(ahpriv->ah_rfsilent, EEP_RFSILENT_GPIO_SEL); ahp->ah_polarity = MS(ahpriv->ah_rfsilent, EEP_RFSILENT_POLARITY); ath_hal_enable_rfkill(ah, AH_TRUE); p_cap->halRfSilentSupport = AH_TRUE; } /* XXX */ p_cap->halWpsPushButtonSupport = AH_FALSE; #ifdef ATH_BT_COEX p_cap->halBtCoexSupport = AH_TRUE; p_cap->halBtCoexApsmWar = AH_FALSE; #endif p_cap->halGenTimerSupport = AH_TRUE; ahp->ah_avail_gen_timers = ~((1 << AR_FIRST_NDP_TIMER) - 1); ahp->ah_avail_gen_timers &= (1 << AR_NUM_GEN_TIMERS) - 1; /* * According to Kyungwan, generic timer 0 and 8 are special * timers. Remove timer 8 from the available gen timer list. * Jupiter testing shows timer won't trigger with timer 8. */ ahp->ah_avail_gen_timers &= ~(1 << AR_GEN_TIMER_RESERVED); if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { #if ATH_SUPPORT_MCI if (ah->ah_config.ath_hal_mci_config & ATH_MCI_CONFIG_DISABLE_MCI) { p_cap->halMciSupport = AH_FALSE; } else #endif { p_cap->halMciSupport = (ahp->ah_enterprise_mode & AR_ENT_OTP_49GHZ_DISABLE) ? AH_FALSE: AH_TRUE; } HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, "%s: (MCI) MCI support = %d\n", __func__, p_cap->halMciSupport); } else { p_cap->halMciSupport = AH_FALSE; } if (AR_SREV_JUPITER_20(ah)) { p_cap->halRadioRetentionSupport = AH_TRUE; } else { p_cap->halRadioRetentionSupport = AH_FALSE; } p_cap->halAutoSleepSupport = AH_TRUE; p_cap->halMbssidAggrSupport = AH_TRUE; // p_cap->hal_proxy_sta_support = AH_TRUE; /* XXX Mark it true after it is verfied as fixed */ p_cap->hal4kbSplitTransSupport = AH_FALSE; /* Read regulatory domain flag */ if (AH_PRIVATE(ah)->ah_currentRDext & (1 << REG_EXT_JAPAN_MIDBAND)) { /* * If REG_EXT_JAPAN_MIDBAND is set, turn on U1 EVEN, U2, and MIDBAND. */ p_cap->halRegCap = AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN | AR_EEPROM_EEREGCAP_EN_KK_U2 | AR_EEPROM_EEREGCAP_EN_KK_MIDBAND; } else { p_cap->halRegCap = AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN; } /* For AR9300 and above, midband channels are always supported */ p_cap->halRegCap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND; p_cap->halNumAntCfg5GHz = ar9300_eeprom_get_num_ant_config(ahp, HAL_FREQ_BAND_5GHZ); p_cap->halNumAntCfg2GHz = ar9300_eeprom_get_num_ant_config(ahp, HAL_FREQ_BAND_2GHZ); /* STBC supported */ p_cap->halRxStbcSupport = 1; /* number of streams for STBC recieve. */ if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) { p_cap->halTxStbcSupport = 0; } else { p_cap->halTxStbcSupport = 1; } p_cap->halEnhancedDmaSupport = AH_TRUE; p_cap->halEnhancedDfsSupport = AH_TRUE; /* * EV61133 (missing interrupts due to AR_ISR_RAC). * Fixed in Osprey 2.0. */ p_cap->halIsrRacSupport = AH_TRUE; /* XXX FreeBSD won't support TKIP and WEP aggregation */ #if 0 p_cap->hal_wep_tkip_aggr_support = AH_TRUE; p_cap->hal_wep_tkip_aggr_num_tx_delim = 10; /* TBD */ p_cap->hal_wep_tkip_aggr_num_rx_delim = 10; /* TBD */ p_cap->hal_wep_tkip_max_ht_rate = 15; /* TBD */ #endif /* * XXX FreeBSD won't need these; but eventually add them * and add the WARs - AGGR extra delim WAR is useful to know * about. */ #if 0 p_cap->hal_cfend_fix_support = AH_FALSE; p_cap->hal_aggr_extra_delim_war = AH_FALSE; #endif p_cap->halHasLongRxDescTsf = AH_TRUE; // p_cap->hal_rx_desc_timestamp_bits = 32; p_cap->halRxTxAbortSupport = AH_TRUE; p_cap->hal_ani_poll_interval = AR9300_ANI_POLLINTERVAL; p_cap->hal_channel_switch_time_usec = AR9300_CHANNEL_SWITCH_TIME_USEC; /* Transmit Beamforming supported, fill capabilities */ p_cap->halPaprdEnabled = ar9300_eeprom_get(ahp, EEP_PAPRD_ENABLED); p_cap->halChanHalfRate = !(ahp->ah_enterprise_mode & AR_ENT_OTP_10MHZ_DISABLE); p_cap->halChanQuarterRate = !(ahp->ah_enterprise_mode & AR_ENT_OTP_5MHZ_DISABLE); if(AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)){ /* There is no AR_ENT_OTP_49GHZ_DISABLE feature in Jupiter, now the bit is used to disable BT. */ p_cap->hal49GhzSupport = 1; } else { p_cap->hal49GhzSupport = !(ahp->ah_enterprise_mode & AR_ENT_OTP_49GHZ_DISABLE); } if (AR_SREV_POSEIDON(ah) || AR_SREV_HORNET(ah) || AR_SREV_APHRODITE(ah)) { /* LDPC supported */ /* Poseidon doesn't support LDPC, or it will cause receiver CRC Error */ p_cap->halLDPCSupport = AH_FALSE; /* PCI_E LCR offset */ if (AR_SREV_POSEIDON(ah)) { p_cap->hal_pcie_lcr_offset = 0x80; /*for Poseidon*/ } /*WAR method for APSM L0s with Poseidon 1.0*/ if (AR_SREV_POSEIDON_10(ah)) { p_cap->hal_pcie_lcr_extsync_en = AH_TRUE; } } else { p_cap->halLDPCSupport = AH_TRUE; } /* XXX is this a flag, or a chainmask number? */ p_cap->halApmEnable = !! ar9300_eeprom_get(ahp, EEP_CHAIN_MASK_REDUCE); #if ATH_ANT_DIV_COMB if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON_11_OR_LATER(ah)) { if (ahp->ah_diversity_control == HAL_ANT_VARIABLE) { u_int8_t ant_div_control1 = ar9300_eeprom_get(ahp, EEP_ANTDIV_control); /* if enable_lnadiv is 0x1 and enable_fast_div is 0x1, * we enable the diversity-combining algorithm. */ if ((ant_div_control1 >> 0x6) == 0x3) { p_cap->halAntDivCombSupport = AH_TRUE; } p_cap->halAntDivCombSupportOrg = p_cap->halAntDivCombSupport; } } #endif /* ATH_ANT_DIV_COMB */ /* * FreeBSD: enable LNA mixing if the chip is Hornet or Poseidon. */ if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON_11_OR_LATER(ah)) { p_cap->halRxUsingLnaMixing = AH_TRUE; } /* * AR5416 and later NICs support MYBEACON filtering. */ p_cap->halRxDoMyBeacon = AH_TRUE; #if ATH_WOW_OFFLOAD if (AR_SREV_JUPITER_20_OR_LATER(ah) || AR_SREV_APHRODITE(ah)) { p_cap->hal_wow_gtk_offload_support = AH_TRUE; p_cap->hal_wow_arp_offload_support = AH_TRUE; p_cap->hal_wow_ns_offload_support = AH_TRUE; p_cap->hal_wow_4way_hs_wakeup_support = AH_TRUE; p_cap->hal_wow_acer_magic_support = AH_TRUE; p_cap->hal_wow_acer_swka_support = AH_TRUE; } else { p_cap->hal_wow_gtk_offload_support = AH_FALSE; p_cap->hal_wow_arp_offload_support = AH_FALSE; p_cap->hal_wow_ns_offload_support = AH_FALSE; p_cap->hal_wow_4way_hs_wakeup_support = AH_FALSE; p_cap->hal_wow_acer_magic_support = AH_FALSE; p_cap->hal_wow_acer_swka_support = AH_FALSE; } #endif /* ATH_WOW_OFFLOAD */ return AH_TRUE; #undef AR_KEYTABLE_SIZE } #if 0 static HAL_BOOL ar9300_get_chip_power_limits(struct ath_hal *ah, HAL_CHANNEL *chans, u_int32_t nchans) { struct ath_hal_9300 *ahp = AH9300(ah); return ahp->ah_rf_hal.get_chip_power_lim(ah, chans, nchans); } #endif /* XXX FreeBSD */ static HAL_BOOL ar9300_get_chip_power_limits(struct ath_hal *ah, struct ieee80211_channel *chan) { chan->ic_maxpower = AR9300_MAX_RATE_POWER; chan->ic_minpower = 0; return AH_TRUE; } /* * Disable PLL when in L0s as well as receiver clock when in L1. * This power saving option must be enabled through the Serdes. * * Programming the Serdes must go through the same 288 bit serial shift * register as the other analog registers. Hence the 9 writes. * * XXX Clean up the magic numbers. */ void ar9300_config_pci_power_save(struct ath_hal *ah, int restore, int power_off) { struct ath_hal_9300 *ahp = AH9300(ah); int i; if (AH_PRIVATE(ah)->ah_ispcie != AH_TRUE) { return; } /* * Increase L1 Entry Latency. Some WB222 boards don't have * this change in eeprom/OTP. */ if (AR_SREV_JUPITER(ah)) { u_int32_t val = ah->ah_config.ath_hal_war70c; if ((val & 0xff000000) == 0x17000000) { val &= 0x00ffffff; val |= 0x27000000; OS_REG_WRITE(ah, 0x570c, val); } } /* Do not touch SERDES registers */ if (ah->ah_config.ath_hal_pcie_power_save_enable == 2) { return; } /* Nothing to do on restore for 11N */ if (!restore) { /* set bit 19 to allow forcing of pcie core into L1 state */ OS_REG_SET_BIT(ah, AR_HOSTIF_REG(ah, AR_PCIE_PM_CTRL), AR_PCIE_PM_CTRL_ENA); /* * Set PCIE workaround config only if requested, else use the reset * value of this register. */ if (ah->ah_config.ath_hal_pcie_waen) { OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), ah->ah_config.ath_hal_pcie_waen); } else { /* Set Bits 17 and 14 in the AR_WA register. */ OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), ahp->ah_wa_reg_val); } } /* Configure PCIE after Ini init. SERDES values now come from ini file */ if (ah->ah_config.ath_hal_pcie_ser_des_write) { if (power_off) { for (i = 0; i < ahp->ah_ini_pcie_serdes.ia_rows; i++) { OS_REG_WRITE(ah, INI_RA(&ahp->ah_ini_pcie_serdes, i, 0), INI_RA(&ahp->ah_ini_pcie_serdes, i, 1)); } } else { for (i = 0; i < ahp->ah_ini_pcie_serdes_low_power.ia_rows; i++) { OS_REG_WRITE(ah, INI_RA(&ahp->ah_ini_pcie_serdes_low_power, i, 0), INI_RA(&ahp->ah_ini_pcie_serdes_low_power, i, 1)); } } } } /* * Recipe from charles to turn off PCIe PHY in PCI mode for power savings */ void ar9300_disable_pcie_phy(struct ath_hal *ah) { /* Osprey does not support PCI mode */ } static inline HAL_STATUS ar9300_init_mac_addr(struct ath_hal *ah) { u_int32_t sum; int i; u_int16_t eeval; struct ath_hal_9300 *ahp = AH9300(ah); u_int32_t EEP_MAC [] = { EEP_MAC_LSW, EEP_MAC_MID, EEP_MAC_MSW }; sum = 0; for (i = 0; i < 3; i++) { eeval = ar9300_eeprom_get(ahp, EEP_MAC[i]); sum += eeval; ahp->ah_macaddr[2*i] = eeval >> 8; ahp->ah_macaddr[2*i + 1] = eeval & 0xff; } if (sum == 0 || sum == 0xffff*3) { HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: mac address read failed: %s\n", __func__, ath_hal_ether_sprintf(ahp->ah_macaddr)); return HAL_EEBADMAC; } return HAL_OK; } /* * Code for the "real" chip i.e. non-emulation. Review and revisit * when actual hardware is at hand. */ static inline HAL_STATUS ar9300_hw_attach(struct ath_hal *ah) { HAL_STATUS ecode; if (!ar9300_chip_test(ah)) { HALDEBUG(ah, HAL_DEBUG_REGIO, "%s: hardware self-test failed\n", __func__); return HAL_ESELFTEST; } ath_hal_printf(ah, "%s: calling ar9300_eeprom_attach\n", __func__); ecode = ar9300_eeprom_attach(ah); ath_hal_printf(ah, "%s: ar9300_eeprom_attach returned %d\n", __func__, ecode); if (ecode != HAL_OK) { return ecode; } if (!ar9300_rf_attach(ah, &ecode)) { HALDEBUG(ah, HAL_DEBUG_RESET, "%s: RF setup failed, status %u\n", __func__, ecode); } if (ecode != HAL_OK) { return ecode; } ar9300_ani_attach(ah); return HAL_OK; } static inline void ar9300_hw_detach(struct ath_hal *ah) { /* XXX EEPROM allocated state */ ar9300_ani_detach(ah); } static int16_t ar9300_get_nf_adjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c) { return 0; } void ar9300_set_immunity(struct ath_hal *ah, HAL_BOOL enable) { struct ath_hal_9300 *ahp = AH9300(ah); u_int32_t m1_thresh_low = enable ? 127 : ahp->ah_immunity_vals[0], m2_thresh_low = enable ? 127 : ahp->ah_immunity_vals[1], m1_thresh = enable ? 127 : ahp->ah_immunity_vals[2], m2_thresh = enable ? 127 : ahp->ah_immunity_vals[3], m2_count_thr = enable ? 31 : ahp->ah_immunity_vals[4], m2_count_thr_low = enable ? 63 : ahp->ah_immunity_vals[5]; if (ahp->ah_immunity_on == enable) { return; } ahp->ah_immunity_on = enable; OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1_thresh_low); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2_thresh_low); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M1_THRESH, m1_thresh); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2_THRESH, m2_thresh); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2COUNT_THR, m2_count_thr); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2_count_thr_low); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1_thresh_low); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2_thresh_low); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH, m1_thresh); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH, m2_thresh); if (!enable) { OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); } else { OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); } } /* XXX FreeBSD: I'm not sure how to implement this.. */ #if 0 int ar9300_get_cal_intervals(struct ath_hal *ah, HAL_CALIBRATION_TIMER **timerp, HAL_CAL_QUERY query) { #define AR9300_IS_CHAIN_RX_IQCAL_INVALID(_ah, _reg) \ ((OS_REG_READ((_ah), _reg) & 0x3fff) == 0) #define AR9300_IS_RX_IQCAL_DISABLED(_ah) \ (!(OS_REG_READ((_ah), AR_PHY_RX_IQCAL_CORR_B0) & \ AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE)) /* Avoid comilation warnings. Variables are not used when EMULATION. */ struct ath_hal_9300 *ahp = AH9300(ah); u_int8_t rxchainmask = ahp->ah_rx_chainmask, i; int rx_iqcal_invalid = 0, num_chains = 0; static const u_int32_t offset_array[3] = { AR_PHY_RX_IQCAL_CORR_B0, AR_PHY_RX_IQCAL_CORR_B1, AR_PHY_RX_IQCAL_CORR_B2}; *timerp = ar9300_cals; switch (query) { case HAL_QUERY_CALS: return AR9300_NUM_CAL_TYPES; case HAL_QUERY_RERUN_CALS: for (i = 0; i < AR9300_MAX_CHAINS; i++) { if (rxchainmask & (1 << i)) { num_chains++; } } for (i = 0; i < num_chains; i++) { if (AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) { HALASSERT(num_chains == 0x1); } if (AR9300_IS_CHAIN_RX_IQCAL_INVALID(ah, offset_array[i])) { rx_iqcal_invalid = 1; } } if (AR9300_IS_RX_IQCAL_DISABLED(ah)) { rx_iqcal_invalid = 1; } return rx_iqcal_invalid; default: HALASSERT(0); } return 0; } #endif #if ATH_TRAFFIC_FAST_RECOVER #define PLL3 0x16188 #define PLL3_DO_MEAS_MASK 0x40000000 #define PLL4 0x1618c #define PLL4_MEAS_DONE 0x8 #define SQSUM_DVC_MASK 0x007ffff8 unsigned long ar9300_get_pll3_sqsum_dvc(struct ath_hal *ah) { if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { OS_REG_WRITE(ah, PLL3, (OS_REG_READ(ah, PLL3) & ~(PLL3_DO_MEAS_MASK))); OS_DELAY(100); OS_REG_WRITE(ah, PLL3, (OS_REG_READ(ah, PLL3) | PLL3_DO_MEAS_MASK)); while ( (OS_REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0) { OS_DELAY(100); } return (( OS_REG_READ(ah, PLL3) & SQSUM_DVC_MASK ) >> 3); } else { HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s: unable to get pll3_sqsum_dvc\n", __func__); return 0; } } #endif #define RX_GAIN_TABLE_LENGTH 128 // this will be called if rfGainCAP is enabled and rfGainCAP setting is changed, // or rxGainTable setting is changed HAL_BOOL ar9300_rf_gain_cap_apply(struct ath_hal *ah, int is_2GHz) { int i, done = 0, i_rx_gain = 32; u_int32_t rf_gain_cap; u_int32_t rx_gain_value, a_Byte, rx_gain_value_caped; static u_int32_t rx_gain_table[RX_GAIN_TABLE_LENGTH * 2][2]; ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; struct ath_hal_9300 *ahp = AH9300(ah); if ( !((eep->base_eep_header.misc_configuration & 0x80) >> 7) ) return AH_FALSE; if (is_2GHz) { rf_gain_cap = (u_int32_t) eep->modal_header_2g.rf_gain_cap; } else { rf_gain_cap = (u_int32_t) eep->modal_header_5g.rf_gain_cap; } if (rf_gain_cap == 0) return AH_FALSE; for (i = 0; i< RX_GAIN_TABLE_LENGTH * 2; i++) { if (AR_SREV_AR9580(ah)) { // BB_rx_ocgain2 i_rx_gain = 128 + 32; switch (ar9300_rx_gain_index_get(ah)) { case 0: rx_gain_table[i][0] = ar9300_common_rx_gain_table_ar9580_1p0[i][0]; rx_gain_table[i][1] = ar9300_common_rx_gain_table_ar9580_1p0[i][1]; break; case 1: rx_gain_table[i][0] = ar9300_common_wo_xlna_rx_gain_table_ar9580_1p0[i][0]; rx_gain_table[i][1] = ar9300_common_wo_xlna_rx_gain_table_ar9580_1p0[i][1]; break; } } else if (AR_SREV_OSPREY_22(ah)) { i_rx_gain = 128 + 32; switch (ar9300_rx_gain_index_get(ah)) { case 0: rx_gain_table[i][0] = ar9300_common_rx_gain_table_osprey_2p2[i][0]; rx_gain_table[i][1] = ar9300_common_rx_gain_table_osprey_2p2[i][1]; break; case 1: rx_gain_table[i][0] = ar9300Common_wo_xlna_rx_gain_table_osprey_2p2[i][0]; rx_gain_table[i][1] = ar9300Common_wo_xlna_rx_gain_table_osprey_2p2[i][1]; break; } } else { return AH_FALSE; } } while (1) { rx_gain_value = rx_gain_table[i_rx_gain][1]; rx_gain_value_caped = rx_gain_value; a_Byte = rx_gain_value & (0x000000FF); if (a_Byte>rf_gain_cap) { rx_gain_value_caped = (rx_gain_value_caped & (0xFFFFFF00)) + rf_gain_cap; } a_Byte = rx_gain_value & (0x0000FF00); if ( a_Byte > ( rf_gain_cap << 8 ) ) { rx_gain_value_caped = (rx_gain_value_caped & (0xFFFF00FF)) + (rf_gain_cap<<8); } a_Byte = rx_gain_value & (0x00FF0000); if ( a_Byte > ( rf_gain_cap << 16 ) ) { rx_gain_value_caped = (rx_gain_value_caped & (0xFF00FFFF)) + (rf_gain_cap<<16); } a_Byte = rx_gain_value & (0xFF000000); if ( a_Byte > ( rf_gain_cap << 24 ) ) { rx_gain_value_caped = (rx_gain_value_caped & (0x00FFFFFF)) + (rf_gain_cap<<24); } else { done = 1; } HALDEBUG(ah, HAL_DEBUG_RESET, "%s: rx_gain_address: %x, rx_gain_value: %x rx_gain_value_caped: %x\n", __func__, rx_gain_table[i_rx_gain][0], rx_gain_value, rx_gain_value_caped); if (rx_gain_value_caped != rx_gain_value) { rx_gain_table[i_rx_gain][1] = rx_gain_value_caped; } if (done == 1) break; i_rx_gain ++; } INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, rx_gain_table, ARRAY_LENGTH(rx_gain_table), 2); return AH_TRUE; } void ar9300_rx_gain_table_apply(struct ath_hal *ah) { struct ath_hal_9300 *ahp = AH9300(ah); //struct ath_hal_private *ahpriv = AH_PRIVATE(ah); u_int32_t xlan_gpio_cfg; u_int8_t i; if (AR_SREV_OSPREY(ah) || AR_SREV_AR9580(ah)) { // this will be called if rxGainTable setting is changed if (ar9300_rf_gain_cap_apply(ah, 1)) return; } switch (ar9300_rx_gain_index_get(ah)) { case 2: if (AR_SREV_JUPITER_10(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9300_common_mixed_rx_gain_table_jupiter_1p0, ARRAY_LENGTH(ar9300_common_mixed_rx_gain_table_jupiter_1p0), 2); break; } else if (AR_SREV_JUPITER_20(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9300Common_mixed_rx_gain_table_jupiter_2p0, ARRAY_LENGTH(ar9300Common_mixed_rx_gain_table_jupiter_2p0), 2); break; } case 0: default: if (AR_SREV_HORNET_12(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9331_common_rx_gain_hornet1_2, ARRAY_LENGTH(ar9331_common_rx_gain_hornet1_2), 2); } else if (AR_SREV_HORNET_11(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9331_common_rx_gain_hornet1_1, ARRAY_LENGTH(ar9331_common_rx_gain_hornet1_1), 2); } else if (AR_SREV_POSEIDON_11_OR_LATER(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9485_common_wo_xlna_rx_gain_poseidon1_1, ARRAY_LENGTH(ar9485_common_wo_xlna_rx_gain_poseidon1_1), 2); /* XXX FreeBSD: this needs to be revisited!! */ xlan_gpio_cfg = ah->ah_config.ath_hal_ext_lna_ctl_gpio; if (xlan_gpio_cfg) { for (i = 0; i < 32; i++) { if (xlan_gpio_cfg & (1 << i)) { /* * XXX FreeBSD: definitely make sure this * results in the correct value being written * to the hardware, or weird crap is very likely * to occur! */ ath_hal_gpioCfgOutput(ah, i, HAL_GPIO_OUTPUT_MUX_PCIE_ATTENTION_LED); } } } } else if (AR_SREV_POSEIDON(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9485Common_wo_xlna_rx_gain_poseidon1_0, ARRAY_LENGTH(ar9485Common_wo_xlna_rx_gain_poseidon1_0), 2); } else if (AR_SREV_JUPITER_10(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9300_common_rx_gain_table_jupiter_1p0, ARRAY_LENGTH(ar9300_common_rx_gain_table_jupiter_1p0), 2); } else if (AR_SREV_JUPITER_20(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9300Common_rx_gain_table_jupiter_2p0, ARRAY_LENGTH(ar9300Common_rx_gain_table_jupiter_2p0), 2); } else if (AR_SREV_AR9580(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9300_common_rx_gain_table_ar9580_1p0, ARRAY_LENGTH(ar9300_common_rx_gain_table_ar9580_1p0), 2); } else if (AR_SREV_WASP(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9340Common_rx_gain_table_wasp_1p0, ARRAY_LENGTH(ar9340Common_rx_gain_table_wasp_1p0), 2); } else if (AR_SREV_SCORPION(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar955xCommon_rx_gain_table_scorpion_1p0, ARRAY_LENGTH(ar955xCommon_rx_gain_table_scorpion_1p0), 2); INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain_bounds, ar955xCommon_rx_gain_bounds_scorpion_1p0, ARRAY_LENGTH(ar955xCommon_rx_gain_bounds_scorpion_1p0), 5); } else { INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9300_common_rx_gain_table_osprey_2p2, ARRAY_LENGTH(ar9300_common_rx_gain_table_osprey_2p2), 2); } break; case 1: if (AR_SREV_HORNET_12(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9331_common_wo_xlna_rx_gain_hornet1_2, ARRAY_LENGTH(ar9331_common_wo_xlna_rx_gain_hornet1_2), 2); } else if (AR_SREV_HORNET_11(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9331_common_wo_xlna_rx_gain_hornet1_1, ARRAY_LENGTH(ar9331_common_wo_xlna_rx_gain_hornet1_1), 2); } else if (AR_SREV_POSEIDON_11_OR_LATER(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9485_common_wo_xlna_rx_gain_poseidon1_1, ARRAY_LENGTH(ar9485_common_wo_xlna_rx_gain_poseidon1_1), 2); } else if (AR_SREV_POSEIDON(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9485Common_wo_xlna_rx_gain_poseidon1_0, ARRAY_LENGTH(ar9485Common_wo_xlna_rx_gain_poseidon1_0), 2); } else if (AR_SREV_JUPITER_10(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9300_common_wo_xlna_rx_gain_table_jupiter_1p0, ARRAY_LENGTH(ar9300_common_wo_xlna_rx_gain_table_jupiter_1p0), 2); } else if (AR_SREV_JUPITER_20(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9300Common_wo_xlna_rx_gain_table_jupiter_2p0, ARRAY_LENGTH(ar9300Common_wo_xlna_rx_gain_table_jupiter_2p0), 2); } else if (AR_SREV_APHRODITE(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar956XCommon_wo_xlna_rx_gain_table_aphrodite_1p0, ARRAY_LENGTH(ar956XCommon_wo_xlna_rx_gain_table_aphrodite_1p0), 2); } else if (AR_SREV_AR9580(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9300_common_wo_xlna_rx_gain_table_ar9580_1p0, ARRAY_LENGTH(ar9300_common_wo_xlna_rx_gain_table_ar9580_1p0), 2); } else if (AR_SREV_WASP(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9340Common_wo_xlna_rx_gain_table_wasp_1p0, ARRAY_LENGTH(ar9340Common_wo_xlna_rx_gain_table_wasp_1p0), 2); } else if (AR_SREV_SCORPION(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar955xCommon_wo_xlna_rx_gain_table_scorpion_1p0, ARRAY_LENGTH(ar955xCommon_wo_xlna_rx_gain_table_scorpion_1p0), 2); INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain_bounds, ar955xCommon_wo_xlna_rx_gain_bounds_scorpion_1p0, ARRAY_LENGTH(ar955xCommon_wo_xlna_rx_gain_bounds_scorpion_1p0), 5); } else { INIT_INI_ARRAY(&ahp->ah_ini_modes_rxgain, ar9300Common_wo_xlna_rx_gain_table_osprey_2p2, ARRAY_LENGTH(ar9300Common_wo_xlna_rx_gain_table_osprey_2p2), 2); } break; } } void ar9300_tx_gain_table_apply(struct ath_hal *ah) { struct ath_hal_9300 *ahp = AH9300(ah); switch (ar9300_tx_gain_index_get(ah)) { case 0: default: if (AR_SREV_HORNET_12(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9331_modes_lowest_ob_db_tx_gain_hornet1_2, ARRAY_LENGTH(ar9331_modes_lowest_ob_db_tx_gain_hornet1_2), 5); } else if (AR_SREV_HORNET_11(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9331_modes_lowest_ob_db_tx_gain_hornet1_1, ARRAY_LENGTH(ar9331_modes_lowest_ob_db_tx_gain_hornet1_1), 5); } else if (AR_SREV_POSEIDON_11_OR_LATER(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9485_modes_lowest_ob_db_tx_gain_poseidon1_1, ARRAY_LENGTH(ar9485_modes_lowest_ob_db_tx_gain_poseidon1_1), 5); } else if (AR_SREV_POSEIDON(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9485Modes_lowest_ob_db_tx_gain_poseidon1_0, ARRAY_LENGTH(ar9485Modes_lowest_ob_db_tx_gain_poseidon1_0), 5); } else if (AR_SREV_AR9580(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9300Modes_lowest_ob_db_tx_gain_table_ar9580_1p0, ARRAY_LENGTH(ar9300Modes_lowest_ob_db_tx_gain_table_ar9580_1p0), 5); } else if (AR_SREV_WASP(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9340Modes_lowest_ob_db_tx_gain_table_wasp_1p0, ARRAY_LENGTH(ar9340Modes_lowest_ob_db_tx_gain_table_wasp_1p0), 5); } else if (AR_SREV_SCORPION(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar955xModes_xpa_tx_gain_table_scorpion_1p0, ARRAY_LENGTH(ar955xModes_xpa_tx_gain_table_scorpion_1p0), 9); } else if (AR_SREV_JUPITER_10(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9300_modes_low_ob_db_tx_gain_table_jupiter_1p0, ARRAY_LENGTH(ar9300_modes_low_ob_db_tx_gain_table_jupiter_1p0), 5); } else if (AR_SREV_JUPITER_20(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9300Modes_low_ob_db_tx_gain_table_jupiter_2p0, ARRAY_LENGTH(ar9300Modes_low_ob_db_tx_gain_table_jupiter_2p0), 5); } else if (AR_SREV_APHRODITE(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar956XModes_low_ob_db_tx_gain_table_aphrodite_1p0, ARRAY_LENGTH(ar956XModes_low_ob_db_tx_gain_table_aphrodite_1p0), 5); } else { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9300_modes_lowest_ob_db_tx_gain_table_osprey_2p2, ARRAY_LENGTH(ar9300_modes_lowest_ob_db_tx_gain_table_osprey_2p2), 5); } break; case 1: if (AR_SREV_HORNET_12(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9331_modes_high_ob_db_tx_gain_hornet1_2, ARRAY_LENGTH(ar9331_modes_high_ob_db_tx_gain_hornet1_2), 5); } else if (AR_SREV_HORNET_11(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9331_modes_high_ob_db_tx_gain_hornet1_1, ARRAY_LENGTH(ar9331_modes_high_ob_db_tx_gain_hornet1_1), 5); } else if (AR_SREV_POSEIDON_11_OR_LATER(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9485_modes_high_ob_db_tx_gain_poseidon1_1, ARRAY_LENGTH(ar9485_modes_high_ob_db_tx_gain_poseidon1_1), 5); } else if (AR_SREV_POSEIDON(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9485Modes_high_ob_db_tx_gain_poseidon1_0, ARRAY_LENGTH(ar9485Modes_high_ob_db_tx_gain_poseidon1_0), 5); } else if (AR_SREV_AR9580(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9300Modes_high_ob_db_tx_gain_table_ar9580_1p0, ARRAY_LENGTH(ar9300Modes_high_ob_db_tx_gain_table_ar9580_1p0), 5); } else if (AR_SREV_WASP(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9340Modes_high_ob_db_tx_gain_table_wasp_1p0, ARRAY_LENGTH(ar9340Modes_high_ob_db_tx_gain_table_wasp_1p0), 5); } else if (AR_SREV_SCORPION(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar955xModes_no_xpa_tx_gain_table_scorpion_1p0, ARRAY_LENGTH(ar955xModes_no_xpa_tx_gain_table_scorpion_1p0), 9); } else if (AR_SREV_JUPITER_10(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9300_modes_high_ob_db_tx_gain_table_jupiter_1p0, ARRAY_LENGTH( ar9300_modes_high_ob_db_tx_gain_table_jupiter_1p0), 5); } else if (AR_SREV_JUPITER_20(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9300Modes_high_ob_db_tx_gain_table_jupiter_2p0, ARRAY_LENGTH( ar9300Modes_high_ob_db_tx_gain_table_jupiter_2p0), 5); } else if (AR_SREV_APHRODITE(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar956XModes_high_ob_db_tx_gain_table_aphrodite_1p0, ARRAY_LENGTH( ar956XModes_high_ob_db_tx_gain_table_aphrodite_1p0), 5); } else { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9300Modes_high_ob_db_tx_gain_table_osprey_2p2, ARRAY_LENGTH(ar9300Modes_high_ob_db_tx_gain_table_osprey_2p2), 5); } break; case 2: if (AR_SREV_HORNET_12(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9331_modes_low_ob_db_tx_gain_hornet1_2, ARRAY_LENGTH(ar9331_modes_low_ob_db_tx_gain_hornet1_2), 5); } else if (AR_SREV_HORNET_11(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9331_modes_low_ob_db_tx_gain_hornet1_1, ARRAY_LENGTH(ar9331_modes_low_ob_db_tx_gain_hornet1_1), 5); } else if (AR_SREV_POSEIDON_11_OR_LATER(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9485_modes_low_ob_db_tx_gain_poseidon1_1, ARRAY_LENGTH(ar9485_modes_low_ob_db_tx_gain_poseidon1_1), 5); } else if (AR_SREV_POSEIDON(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9485Modes_low_ob_db_tx_gain_poseidon1_0, ARRAY_LENGTH(ar9485Modes_low_ob_db_tx_gain_poseidon1_0), 5); } else if (AR_SREV_AR9580(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9300Modes_low_ob_db_tx_gain_table_ar9580_1p0, ARRAY_LENGTH(ar9300Modes_low_ob_db_tx_gain_table_ar9580_1p0), 5); } else if (AR_SREV_WASP(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9340Modes_low_ob_db_tx_gain_table_wasp_1p0, ARRAY_LENGTH(ar9340Modes_low_ob_db_tx_gain_table_wasp_1p0), 5); } else if (AR_SREV_APHRODITE(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar956XModes_low_ob_db_tx_gain_table_aphrodite_1p0, ARRAY_LENGTH(ar956XModes_low_ob_db_tx_gain_table_aphrodite_1p0), 5); } else { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9300Modes_low_ob_db_tx_gain_table_osprey_2p2, ARRAY_LENGTH(ar9300Modes_low_ob_db_tx_gain_table_osprey_2p2), 5); } break; case 3: if (AR_SREV_HORNET_12(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9331_modes_high_power_tx_gain_hornet1_2, ARRAY_LENGTH(ar9331_modes_high_power_tx_gain_hornet1_2), 5); } else if (AR_SREV_HORNET_11(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9331_modes_high_power_tx_gain_hornet1_1, ARRAY_LENGTH(ar9331_modes_high_power_tx_gain_hornet1_1), 5); } else if (AR_SREV_POSEIDON_11_OR_LATER(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9485_modes_high_power_tx_gain_poseidon1_1, ARRAY_LENGTH(ar9485_modes_high_power_tx_gain_poseidon1_1), 5); } else if (AR_SREV_POSEIDON(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9485Modes_high_power_tx_gain_poseidon1_0, ARRAY_LENGTH(ar9485Modes_high_power_tx_gain_poseidon1_0), 5); } else if (AR_SREV_AR9580(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9300Modes_high_power_tx_gain_table_ar9580_1p0, ARRAY_LENGTH(ar9300Modes_high_power_tx_gain_table_ar9580_1p0), 5); } else if (AR_SREV_WASP(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9340Modes_high_power_tx_gain_table_wasp_1p0, ARRAY_LENGTH(ar9340Modes_high_power_tx_gain_table_wasp_1p0), 5); } else if (AR_SREV_APHRODITE(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar956XModes_high_power_tx_gain_table_aphrodite_1p0, ARRAY_LENGTH(ar956XModes_high_power_tx_gain_table_aphrodite_1p0), 5); } else { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9300Modes_high_power_tx_gain_table_osprey_2p2, ARRAY_LENGTH(ar9300Modes_high_power_tx_gain_table_osprey_2p2), 5); } break; case 4: if (AR_SREV_WASP(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9340Modes_mixed_ob_db_tx_gain_table_wasp_1p0, ARRAY_LENGTH(ar9340Modes_mixed_ob_db_tx_gain_table_wasp_1p0), 5); } else if (AR_SREV_AR9580(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9300_modes_mixed_ob_db_tx_gain_table_ar9580_1p0, ARRAY_LENGTH(ar9300_modes_mixed_ob_db_tx_gain_table_ar9580_1p0), 5); } else { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9300Modes_mixed_ob_db_tx_gain_table_osprey_2p2, ARRAY_LENGTH(ar9300Modes_mixed_ob_db_tx_gain_table_osprey_2p2), 5); } break; case 5: /* HW Green TX */ if (AR_SREV_POSEIDON(ah)) { if (AR_SREV_POSEIDON_11_OR_LATER(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9485_modes_green_ob_db_tx_gain_poseidon1_1, sizeof(ar9485_modes_green_ob_db_tx_gain_poseidon1_1) / sizeof(ar9485_modes_green_ob_db_tx_gain_poseidon1_1[0]), 5); } else { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9485_modes_green_ob_db_tx_gain_poseidon1_0, sizeof(ar9485_modes_green_ob_db_tx_gain_poseidon1_0) / sizeof(ar9485_modes_green_ob_db_tx_gain_poseidon1_0[0]), 5); } ahp->ah_hw_green_tx_enable = 1; } else if (AR_SREV_WASP(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9340_modes_ub124_tx_gain_table_wasp_1p0, sizeof(ar9340_modes_ub124_tx_gain_table_wasp_1p0) / sizeof(ar9340_modes_ub124_tx_gain_table_wasp_1p0[0]), 5); } else if (AR_SREV_AR9580(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9300_modes_type5_tx_gain_table_ar9580_1p0, ARRAY_LENGTH( ar9300_modes_type5_tx_gain_table_ar9580_1p0), 5); } else if (AR_SREV_OSPREY_22(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9300_modes_number_5_tx_gain_table_osprey_2p2, ARRAY_LENGTH( ar9300_modes_number_5_tx_gain_table_osprey_2p2), 5); } break; case 6: if (AR_SREV_WASP(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9340_modes_low_ob_db_and_spur_tx_gain_table_wasp_1p0, sizeof(ar9340_modes_low_ob_db_and_spur_tx_gain_table_wasp_1p0) / sizeof(ar9340_modes_low_ob_db_and_spur_tx_gain_table_wasp_1p0[0]), 5); } /* HW Green TX */ else if (AR_SREV_POSEIDON(ah)) { if (AR_SREV_POSEIDON_11_OR_LATER(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9485_modes_green_spur_ob_db_tx_gain_poseidon1_1, sizeof(ar9485_modes_green_spur_ob_db_tx_gain_poseidon1_1) / sizeof(ar9485_modes_green_spur_ob_db_tx_gain_poseidon1_1[0]), 5); } ahp->ah_hw_green_tx_enable = 1; } else if (AR_SREV_AR9580(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9300_modes_type6_tx_gain_table_ar9580_1p0, ARRAY_LENGTH( ar9300_modes_type6_tx_gain_table_ar9580_1p0), 5); } break; case 7: if (AR_SREV_WASP(ah)) { INIT_INI_ARRAY(&ahp->ah_ini_modes_txgain, ar9340Modes_cus227_tx_gain_table_wasp_1p0, sizeof(ar9340Modes_cus227_tx_gain_table_wasp_1p0) / sizeof(ar9340Modes_cus227_tx_gain_table_wasp_1p0[0]), 5); } break; } } #if ATH_ANT_DIV_COMB void ar9300_ant_div_comb_get_config(struct ath_hal *ah, HAL_ANT_COMB_CONFIG *div_comb_conf) { u_int32_t reg_val = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL); div_comb_conf->main_lna_conf = MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__READ(reg_val); div_comb_conf->alt_lna_conf = MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__READ(reg_val); div_comb_conf->fast_div_bias = MULTICHAIN_GAIN_CTRL__ANT_FAST_DIV_BIAS__READ(reg_val); if (AR_SREV_HORNET_11(ah)) { div_comb_conf->antdiv_configgroup = HAL_ANTDIV_CONFIG_GROUP_1; } else if (AR_SREV_POSEIDON_11_OR_LATER(ah)) { div_comb_conf->antdiv_configgroup = HAL_ANTDIV_CONFIG_GROUP_2; } else { div_comb_conf->antdiv_configgroup = DEFAULT_ANTDIV_CONFIG_GROUP; } /* * XXX TODO: allow the HAL to override the rssithres and fast_div_bias * values (eg CUS198.) */ } void ar9300_ant_div_comb_set_config(struct ath_hal *ah, HAL_ANT_COMB_CONFIG *div_comb_conf) { u_int32_t reg_val; struct ath_hal_9300 *ahp = AH9300(ah); /* DO NOTHING when set to fixed antenna for manufacturing purpose */ if (AR_SREV_POSEIDON(ah) && ( ahp->ah_diversity_control == HAL_ANT_FIXED_A || ahp->ah_diversity_control == HAL_ANT_FIXED_B)) { return; } reg_val = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL); reg_val &= ~(MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__MASK | MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__MASK | MULTICHAIN_GAIN_CTRL__ANT_FAST_DIV_BIAS__MASK | MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_GAINTB__MASK | MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_GAINTB__MASK ); reg_val |= MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_GAINTB__WRITE( div_comb_conf->main_gaintb); reg_val |= MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_GAINTB__WRITE( div_comb_conf->alt_gaintb); reg_val |= MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__WRITE( div_comb_conf->main_lna_conf); reg_val |= MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__WRITE( div_comb_conf->alt_lna_conf); reg_val |= MULTICHAIN_GAIN_CTRL__ANT_FAST_DIV_BIAS__WRITE( div_comb_conf->fast_div_bias); OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, reg_val); } #endif /* ATH_ANT_DIV_COMB */ static void ar9300_init_hostif_offsets(struct ath_hal *ah) { AR_HOSTIF_REG(ah, AR_RC) = AR9300_HOSTIF_OFFSET(HOST_INTF_RESET_CONTROL); AR_HOSTIF_REG(ah, AR_WA) = AR9300_HOSTIF_OFFSET(HOST_INTF_WORK_AROUND); AR_HOSTIF_REG(ah, AR_PM_STATE) = AR9300_HOSTIF_OFFSET(HOST_INTF_PM_STATE); AR_HOSTIF_REG(ah, AR_H_INFOL) = AR9300_HOSTIF_OFFSET(HOST_INTF_CXPL_DEBUG_INFOL); AR_HOSTIF_REG(ah, AR_H_INFOH) = AR9300_HOSTIF_OFFSET(HOST_INTF_CXPL_DEBUG_INFOH); AR_HOSTIF_REG(ah, AR_PCIE_PM_CTRL) = AR9300_HOSTIF_OFFSET(HOST_INTF_PM_CTRL); AR_HOSTIF_REG(ah, AR_HOST_TIMEOUT) = AR9300_HOSTIF_OFFSET(HOST_INTF_TIMEOUT); AR_HOSTIF_REG(ah, AR_EEPROM) = AR9300_HOSTIF_OFFSET(HOST_INTF_EEPROM_CTRL); AR_HOSTIF_REG(ah, AR_SREV) = AR9300_HOSTIF_OFFSET(HOST_INTF_SREV); AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE) = AR9300_HOSTIF_OFFSET(HOST_INTF_INTR_SYNC_CAUSE); AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE_CLR) = AR9300_HOSTIF_OFFSET(HOST_INTF_INTR_SYNC_CAUSE); AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE) = AR9300_HOSTIF_OFFSET(HOST_INTF_INTR_SYNC_ENABLE); AR_HOSTIF_REG(ah, AR_INTR_ASYNC_MASK) = AR9300_HOSTIF_OFFSET(HOST_INTF_INTR_ASYNC_MASK); AR_HOSTIF_REG(ah, AR_INTR_SYNC_MASK) = AR9300_HOSTIF_OFFSET(HOST_INTF_INTR_SYNC_MASK); AR_HOSTIF_REG(ah, AR_INTR_ASYNC_CAUSE_CLR) = AR9300_HOSTIF_OFFSET(HOST_INTF_INTR_ASYNC_CAUSE); AR_HOSTIF_REG(ah, AR_INTR_ASYNC_CAUSE) = AR9300_HOSTIF_OFFSET(HOST_INTF_INTR_ASYNC_CAUSE); AR_HOSTIF_REG(ah, AR_INTR_ASYNC_ENABLE) = AR9300_HOSTIF_OFFSET(HOST_INTF_INTR_ASYNC_ENABLE); AR_HOSTIF_REG(ah, AR_PCIE_SERDES) = AR9300_HOSTIF_OFFSET(HOST_INTF_PCIE_PHY_RW); AR_HOSTIF_REG(ah, AR_PCIE_SERDES2) = AR9300_HOSTIF_OFFSET(HOST_INTF_PCIE_PHY_LOAD); AR_HOSTIF_REG(ah, AR_GPIO_OUT) = AR9300_HOSTIF_OFFSET(HOST_INTF_GPIO_OUT); AR_HOSTIF_REG(ah, AR_GPIO_IN) = AR9300_HOSTIF_OFFSET(HOST_INTF_GPIO_IN); AR_HOSTIF_REG(ah, AR_GPIO_OE_OUT) = AR9300_HOSTIF_OFFSET(HOST_INTF_GPIO_OE); AR_HOSTIF_REG(ah, AR_GPIO_OE1_OUT) = AR9300_HOSTIF_OFFSET(HOST_INTF_GPIO_OE1); AR_HOSTIF_REG(ah, AR_GPIO_INTR_POL) = AR9300_HOSTIF_OFFSET(HOST_INTF_GPIO_INTR_POLAR); AR_HOSTIF_REG(ah, AR_GPIO_INPUT_EN_VAL) = AR9300_HOSTIF_OFFSET(HOST_INTF_GPIO_INPUT_VALUE); AR_HOSTIF_REG(ah, AR_GPIO_INPUT_MUX1) = AR9300_HOSTIF_OFFSET(HOST_INTF_GPIO_INPUT_MUX1); AR_HOSTIF_REG(ah, AR_GPIO_INPUT_MUX2) = AR9300_HOSTIF_OFFSET(HOST_INTF_GPIO_INPUT_MUX2); AR_HOSTIF_REG(ah, AR_GPIO_OUTPUT_MUX1) = AR9300_HOSTIF_OFFSET(HOST_INTF_GPIO_OUTPUT_MUX1); AR_HOSTIF_REG(ah, AR_GPIO_OUTPUT_MUX2) = AR9300_HOSTIF_OFFSET(HOST_INTF_GPIO_OUTPUT_MUX2); AR_HOSTIF_REG(ah, AR_GPIO_OUTPUT_MUX3) = AR9300_HOSTIF_OFFSET(HOST_INTF_GPIO_OUTPUT_MUX3); AR_HOSTIF_REG(ah, AR_INPUT_STATE) = AR9300_HOSTIF_OFFSET(HOST_INTF_GPIO_INPUT_STATE); AR_HOSTIF_REG(ah, AR_SPARE) = AR9300_HOSTIF_OFFSET(HOST_INTF_SPARE); AR_HOSTIF_REG(ah, AR_PCIE_CORE_RESET_EN) = AR9300_HOSTIF_OFFSET(HOST_INTF_PCIE_CORE_RST_EN); AR_HOSTIF_REG(ah, AR_CLKRUN) = AR9300_HOSTIF_OFFSET(HOST_INTF_CLKRUN); AR_HOSTIF_REG(ah, AR_EEPROM_STATUS_DATA) = AR9300_HOSTIF_OFFSET(HOST_INTF_EEPROM_STS); AR_HOSTIF_REG(ah, AR_OBS) = AR9300_HOSTIF_OFFSET(HOST_INTF_OBS_CTRL); AR_HOSTIF_REG(ah, AR_RFSILENT) = AR9300_HOSTIF_OFFSET(HOST_INTF_RFSILENT); AR_HOSTIF_REG(ah, AR_GPIO_PDPU) = AR9300_HOSTIF_OFFSET(HOST_INTF_GPIO_PDPU); AR_HOSTIF_REG(ah, AR_GPIO_DS) = AR9300_HOSTIF_OFFSET(HOST_INTF_GPIO_DS); AR_HOSTIF_REG(ah, AR_MISC) = AR9300_HOSTIF_OFFSET(HOST_INTF_MISC); AR_HOSTIF_REG(ah, AR_PCIE_MSI) = AR9300_HOSTIF_OFFSET(HOST_INTF_PCIE_MSI); #if 0 /* Offsets are not defined in reg_map structure */ AR_HOSTIF_REG(ah, AR_TSF_SNAPSHOT_BT_ACTIVE) = AR9300_HOSTIF_OFFSET(HOST_INTF_TSF_SNAPSHOT_BT_ACTIVE); AR_HOSTIF_REG(ah, AR_TSF_SNAPSHOT_BT_PRIORITY) = AR9300_HOSTIF_OFFSET(HOST_INTF_TSF_SNAPSHOT_BT_PRIORITY); AR_HOSTIF_REG(ah, AR_TSF_SNAPSHOT_BT_CNTL) = AR9300_HOSTIF_OFFSET(HOST_INTF_MAC_TSF_SNAPSHOT_BT_CNTL); #endif AR_HOSTIF_REG(ah, AR_PCIE_PHY_LATENCY_NFTS_ADJ) = AR9300_HOSTIF_OFFSET(HOST_INTF_PCIE_PHY_LATENCY_NFTS_ADJ); AR_HOSTIF_REG(ah, AR_TDMA_CCA_CNTL) = AR9300_HOSTIF_OFFSET(HOST_INTF_MAC_TDMA_CCA_CNTL); AR_HOSTIF_REG(ah, AR_TXAPSYNC) = AR9300_HOSTIF_OFFSET(HOST_INTF_MAC_TXAPSYNC); AR_HOSTIF_REG(ah, AR_TXSYNC_INIT_SYNC_TMR) = AR9300_HOSTIF_OFFSET(HOST_INTF_MAC_TXSYNC_INITIAL_SYNC_TMR); AR_HOSTIF_REG(ah, AR_INTR_PRIO_SYNC_CAUSE) = AR9300_HOSTIF_OFFSET(HOST_INTF_INTR_PRIORITY_SYNC_CAUSE); AR_HOSTIF_REG(ah, AR_INTR_PRIO_SYNC_ENABLE) = AR9300_HOSTIF_OFFSET(HOST_INTF_INTR_PRIORITY_SYNC_ENABLE); AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_MASK) = AR9300_HOSTIF_OFFSET(HOST_INTF_INTR_PRIORITY_ASYNC_MASK); AR_HOSTIF_REG(ah, AR_INTR_PRIO_SYNC_MASK) = AR9300_HOSTIF_OFFSET(HOST_INTF_INTR_PRIORITY_SYNC_MASK); AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_CAUSE) = AR9300_HOSTIF_OFFSET(HOST_INTF_INTR_PRIORITY_ASYNC_CAUSE); AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_ENABLE) = AR9300_HOSTIF_OFFSET(HOST_INTF_INTR_PRIORITY_ASYNC_ENABLE); } static void ar9340_init_hostif_offsets(struct ath_hal *ah) { AR_HOSTIF_REG(ah, AR_RC) = AR9340_HOSTIF_OFFSET(HOST_INTF_RESET_CONTROL); AR_HOSTIF_REG(ah, AR_WA) = AR9340_HOSTIF_OFFSET(HOST_INTF_WORK_AROUND); AR_HOSTIF_REG(ah, AR_PCIE_PM_CTRL) = AR9340_HOSTIF_OFFSET(HOST_INTF_PM_CTRL); AR_HOSTIF_REG(ah, AR_HOST_TIMEOUT) = AR9340_HOSTIF_OFFSET(HOST_INTF_TIMEOUT); AR_HOSTIF_REG(ah, AR_SREV) = AR9340_HOSTIF_OFFSET(HOST_INTF_SREV); AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE) = AR9340_HOSTIF_OFFSET(HOST_INTF_INTR_SYNC_CAUSE); AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE_CLR) = AR9340_HOSTIF_OFFSET(HOST_INTF_INTR_SYNC_CAUSE); AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE) = AR9340_HOSTIF_OFFSET(HOST_INTF_INTR_SYNC_ENABLE); AR_HOSTIF_REG(ah, AR_INTR_ASYNC_MASK) = AR9340_HOSTIF_OFFSET(HOST_INTF_INTR_ASYNC_MASK); AR_HOSTIF_REG(ah, AR_INTR_SYNC_MASK) = AR9340_HOSTIF_OFFSET(HOST_INTF_INTR_SYNC_MASK); AR_HOSTIF_REG(ah, AR_INTR_ASYNC_CAUSE_CLR) = AR9340_HOSTIF_OFFSET(HOST_INTF_INTR_ASYNC_CAUSE); AR_HOSTIF_REG(ah, AR_INTR_ASYNC_CAUSE) = AR9340_HOSTIF_OFFSET(HOST_INTF_INTR_ASYNC_CAUSE); AR_HOSTIF_REG(ah, AR_INTR_ASYNC_ENABLE) = AR9340_HOSTIF_OFFSET(HOST_INTF_INTR_ASYNC_ENABLE); AR_HOSTIF_REG(ah, AR_GPIO_OUT) = AR9340_HOSTIF_OFFSET(HOST_INTF_GPIO_OUT); AR_HOSTIF_REG(ah, AR_GPIO_IN) = AR9340_HOSTIF_OFFSET(HOST_INTF_GPIO_IN); AR_HOSTIF_REG(ah, AR_GPIO_OE_OUT) = AR9340_HOSTIF_OFFSET(HOST_INTF_GPIO_OE); AR_HOSTIF_REG(ah, AR_GPIO_OE1_OUT) = AR9340_HOSTIF_OFFSET(HOST_INTF_GPIO_OE1); AR_HOSTIF_REG(ah, AR_GPIO_INTR_POL) = AR9340_HOSTIF_OFFSET(HOST_INTF_GPIO_INTR_POLAR); AR_HOSTIF_REG(ah, AR_GPIO_INPUT_EN_VAL) = AR9340_HOSTIF_OFFSET(HOST_INTF_GPIO_INPUT_VALUE); AR_HOSTIF_REG(ah, AR_GPIO_INPUT_MUX1) = AR9340_HOSTIF_OFFSET(HOST_INTF_GPIO_INPUT_MUX1); AR_HOSTIF_REG(ah, AR_GPIO_INPUT_MUX2) = AR9340_HOSTIF_OFFSET(HOST_INTF_GPIO_INPUT_MUX2); AR_HOSTIF_REG(ah, AR_GPIO_OUTPUT_MUX1) = AR9340_HOSTIF_OFFSET(HOST_INTF_GPIO_OUTPUT_MUX1); AR_HOSTIF_REG(ah, AR_GPIO_OUTPUT_MUX2) = AR9340_HOSTIF_OFFSET(HOST_INTF_GPIO_OUTPUT_MUX2); AR_HOSTIF_REG(ah, AR_GPIO_OUTPUT_MUX3) = AR9340_HOSTIF_OFFSET(HOST_INTF_GPIO_OUTPUT_MUX3); AR_HOSTIF_REG(ah, AR_INPUT_STATE) = AR9340_HOSTIF_OFFSET(HOST_INTF_GPIO_INPUT_STATE); AR_HOSTIF_REG(ah, AR_CLKRUN) = AR9340_HOSTIF_OFFSET(HOST_INTF_CLKRUN); AR_HOSTIF_REG(ah, AR_EEPROM_STATUS_DATA) = AR9340_HOSTIF_OFFSET(HOST_INTF_EEPROM_STS); AR_HOSTIF_REG(ah, AR_OBS) = AR9340_HOSTIF_OFFSET(HOST_INTF_OBS_CTRL); AR_HOSTIF_REG(ah, AR_RFSILENT) = AR9340_HOSTIF_OFFSET(HOST_INTF_RFSILENT); AR_HOSTIF_REG(ah, AR_MISC) = AR9340_HOSTIF_OFFSET(HOST_INTF_MISC); AR_HOSTIF_REG(ah, AR_PCIE_MSI) = AR9340_HOSTIF_OFFSET(HOST_INTF_PCIE_MSI); AR_HOSTIF_REG(ah, AR_TDMA_CCA_CNTL) = AR9340_HOSTIF_OFFSET(HOST_INTF_MAC_TDMA_CCA_CNTL); AR_HOSTIF_REG(ah, AR_TXAPSYNC) = AR9340_HOSTIF_OFFSET(HOST_INTF_MAC_TXAPSYNC); AR_HOSTIF_REG(ah, AR_TXSYNC_INIT_SYNC_TMR) = AR9340_HOSTIF_OFFSET(HOST_INTF_MAC_TXSYNC_INITIAL_SYNC_TMR); AR_HOSTIF_REG(ah, AR_INTR_PRIO_SYNC_CAUSE) = AR9340_HOSTIF_OFFSET(HOST_INTF_INTR_PRIORITY_SYNC_CAUSE); AR_HOSTIF_REG(ah, AR_INTR_PRIO_SYNC_ENABLE) = AR9340_HOSTIF_OFFSET(HOST_INTF_INTR_PRIORITY_SYNC_ENABLE); AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_MASK) = AR9340_HOSTIF_OFFSET(HOST_INTF_INTR_PRIORITY_ASYNC_MASK); AR_HOSTIF_REG(ah, AR_INTR_PRIO_SYNC_MASK) = AR9340_HOSTIF_OFFSET(HOST_INTF_INTR_PRIORITY_SYNC_MASK); AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_CAUSE) = AR9340_HOSTIF_OFFSET(HOST_INTF_INTR_PRIORITY_ASYNC_CAUSE); AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_ENABLE) = AR9340_HOSTIF_OFFSET(HOST_INTF_INTR_PRIORITY_ASYNC_ENABLE); } /* * Host interface register offsets are different for Osprey and Wasp * and hence store the offsets in hal structure */ static int ar9300_init_offsets(struct ath_hal *ah, u_int16_t devid) { if (devid == AR9300_DEVID_AR9340) { ar9340_init_hostif_offsets(ah); } else { ar9300_init_hostif_offsets(ah); } return 0; } static const char* ar9300_probe(uint16_t vendorid, uint16_t devid) { if (vendorid != ATHEROS_VENDOR_ID) return AH_NULL; switch (devid) { case AR9300_DEVID_AR9380_PCIE: /* PCIE (Osprey) */ return "Atheros AR938x"; case AR9300_DEVID_AR9340: /* Wasp */ return "Atheros AR934x"; case AR9300_DEVID_AR9485_PCIE: /* Poseidon */ return "Atheros AR9485"; case AR9300_DEVID_AR9580_PCIE: /* Peacock */ return "Atheros AR9580"; case AR9300_DEVID_AR946X_PCIE: /* AR9462, AR9463, AR9482 */ return "Atheros AR946x/AR948x"; case AR9300_DEVID_AR9330: /* Hornet */ return "Atheros AR933x"; case AR9300_DEVID_QCA955X: /* Scorpion */ return "Qualcomm Atheros QCA955x"; case AR9300_DEVID_QCA9565: /* Aphrodite */ return "Qualcomm Atheros AR9565"; case AR9300_DEVID_AR1111_PCIE: return "Atheros AR1111"; default: return AH_NULL; } return AH_NULL; } AH_CHIP(AR9300, ar9300_probe, ar9300_attach); Index: projects/release-pkg/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c =================================================================== --- projects/release-pkg/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c (revision 289118) +++ projects/release-pkg/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c (revision 289119) @@ -1,1081 +1,1075 @@ /* * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting * Copyright (c) 2002-2008 Atheros Communications, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $FreeBSD$ */ #include "opt_ah.h" #include "ah.h" #include "ah_internal.h" #include "ah_devid.h" #include "ah_eeprom_v14.h" #include "ar5416/ar5416.h" #include "ar5416/ar5416reg.h" #include "ar5416/ar5416phy.h" #include "ar5416/ar5416.ini" static void ar5416ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore, HAL_BOOL power_off); static void ar5416DisablePCIE(struct ath_hal *ah); static void ar5416WriteIni(struct ath_hal *ah, const struct ieee80211_channel *chan); static void ar5416SpurMitigate(struct ath_hal *ah, const struct ieee80211_channel *chan); static void ar5416AniSetup(struct ath_hal *ah) { static const struct ar5212AniParams aniparams = { .maxNoiseImmunityLevel = 4, /* levels 0..4 */ .totalSizeDesired = { -55, -55, -55, -55, -62 }, .coarseHigh = { -14, -14, -14, -14, -12 }, .coarseLow = { -64, -64, -64, -64, -70 }, .firpwr = { -78, -78, -78, -78, -80 }, .maxSpurImmunityLevel = 7, .cycPwrThr1 = { 2, 4, 6, 8, 10, 12, 14, 16 }, .maxFirstepLevel = 2, /* levels 0..2 */ .firstep = { 0, 4, 8 }, .ofdmTrigHigh = 500, .ofdmTrigLow = 200, .cckTrigHigh = 200, .cckTrigLow = 100, .rssiThrHigh = 40, .rssiThrLow = 7, .period = 100, }; /* NB: disable ANI noise immmunity for reliable RIFS rx */ AH5416(ah)->ah_ani_function &= ~(1 << HAL_ANI_NOISE_IMMUNITY_LEVEL); ar5416AniAttach(ah, &aniparams, &aniparams, AH_TRUE); } /* * AR5416 doesn't do OLC or temperature compensation. */ static void ar5416olcInit(struct ath_hal *ah) { } static void ar5416olcTempCompensation(struct ath_hal *ah) { } /* * Attach for an AR5416 part. */ void ar5416InitState(struct ath_hal_5416 *ahp5416, uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status) { struct ath_hal_5212 *ahp; struct ath_hal *ah; ahp = &ahp5416->ah_5212; ar5212InitState(ahp, devid, sc, st, sh, status); ah = &ahp->ah_priv.h; /* override 5212 methods for our needs */ ah->ah_magic = AR5416_MAGIC; ah->ah_getRateTable = ar5416GetRateTable; ah->ah_detach = ar5416Detach; /* Reset functions */ ah->ah_reset = ar5416Reset; ah->ah_phyDisable = ar5416PhyDisable; ah->ah_disable = ar5416Disable; ah->ah_configPCIE = ar5416ConfigPCIE; ah->ah_disablePCIE = ar5416DisablePCIE; ah->ah_perCalibration = ar5416PerCalibration; ah->ah_perCalibrationN = ar5416PerCalibrationN, ah->ah_resetCalValid = ar5416ResetCalValid, ah->ah_setTxPowerLimit = ar5416SetTxPowerLimit; ah->ah_setTxPower = ar5416SetTransmitPower; ah->ah_setBoardValues = ar5416SetBoardValues; /* Transmit functions */ ah->ah_stopTxDma = ar5416StopTxDma; ah->ah_setupTxDesc = ar5416SetupTxDesc; ah->ah_setupXTxDesc = ar5416SetupXTxDesc; ah->ah_fillTxDesc = ar5416FillTxDesc; ah->ah_procTxDesc = ar5416ProcTxDesc; ah->ah_getTxCompletionRates = ar5416GetTxCompletionRates; ah->ah_setupTxQueue = ar5416SetupTxQueue; ah->ah_resetTxQueue = ar5416ResetTxQueue; /* Receive Functions */ ah->ah_getRxFilter = ar5416GetRxFilter; ah->ah_setRxFilter = ar5416SetRxFilter; ah->ah_stopDmaReceive = ar5416StopDmaReceive; ah->ah_startPcuReceive = ar5416StartPcuReceive; ah->ah_stopPcuReceive = ar5416StopPcuReceive; ah->ah_setupRxDesc = ar5416SetupRxDesc; ah->ah_procRxDesc = ar5416ProcRxDesc; ah->ah_rxMonitor = ar5416RxMonitor; ah->ah_aniPoll = ar5416AniPoll; ah->ah_procMibEvent = ar5416ProcessMibIntr; /* Misc Functions */ ah->ah_getCapability = ar5416GetCapability; ah->ah_setCapability = ar5416SetCapability; ah->ah_getDiagState = ar5416GetDiagState; ah->ah_setLedState = ar5416SetLedState; ah->ah_gpioCfgOutput = ar5416GpioCfgOutput; ah->ah_gpioCfgInput = ar5416GpioCfgInput; ah->ah_gpioGet = ar5416GpioGet; ah->ah_gpioSet = ar5416GpioSet; ah->ah_gpioSetIntr = ar5416GpioSetIntr; ah->ah_getTsf64 = ar5416GetTsf64; ah->ah_setTsf64 = ar5416SetTsf64; ah->ah_resetTsf = ar5416ResetTsf; ah->ah_getRfGain = ar5416GetRfgain; ah->ah_setAntennaSwitch = ar5416SetAntennaSwitch; ah->ah_setDecompMask = ar5416SetDecompMask; ah->ah_setCoverageClass = ar5416SetCoverageClass; ah->ah_setQuiet = ar5416SetQuiet; ah->ah_getMibCycleCounts = ar5416GetMibCycleCounts; ah->ah_setChainMasks = ar5416SetChainMasks; ah->ah_resetKeyCacheEntry = ar5416ResetKeyCacheEntry; ah->ah_setKeyCacheEntry = ar5416SetKeyCacheEntry; /* DFS Functions */ ah->ah_enableDfs = ar5416EnableDfs; ah->ah_getDfsThresh = ar5416GetDfsThresh; ah->ah_getDfsDefaultThresh = ar5416GetDfsDefaultThresh; ah->ah_procRadarEvent = ar5416ProcessRadarEvent; ah->ah_isFastClockEnabled = ar5416IsFastClockEnabled; /* Spectral Scan Functions */ ah->ah_spectralConfigure = ar5416ConfigureSpectralScan; ah->ah_spectralGetConfig = ar5416GetSpectralParams; ah->ah_spectralStart = ar5416StartSpectralScan; ah->ah_spectralStop = ar5416StopSpectralScan; ah->ah_spectralIsEnabled = ar5416IsSpectralEnabled; ah->ah_spectralIsActive = ar5416IsSpectralActive; /* Power Management Functions */ ah->ah_setPowerMode = ar5416SetPowerMode; /* Beacon Management Functions */ ah->ah_setBeaconTimers = ar5416SetBeaconTimers; ah->ah_beaconInit = ar5416BeaconInit; ah->ah_setStationBeaconTimers = ar5416SetStaBeaconTimers; ah->ah_resetStationBeaconTimers = ar5416ResetStaBeaconTimers; ah->ah_getNextTBTT = ar5416GetNextTBTT; /* 802.11n Functions */ ah->ah_chainTxDesc = ar5416ChainTxDesc; ah->ah_setupFirstTxDesc = ar5416SetupFirstTxDesc; ah->ah_setupLastTxDesc = ar5416SetupLastTxDesc; ah->ah_set11nRateScenario = ar5416Set11nRateScenario; ah->ah_set11nAggrFirst = ar5416Set11nAggrFirst; ah->ah_set11nAggrMiddle = ar5416Set11nAggrMiddle; ah->ah_set11nAggrLast = ar5416Set11nAggrLast; ah->ah_clr11nAggr = ar5416Clr11nAggr; ah->ah_set11nBurstDuration = ar5416Set11nBurstDuration; ah->ah_get11nExtBusy = ar5416Get11nExtBusy; ah->ah_set11nMac2040 = ar5416Set11nMac2040; ah->ah_get11nRxClear = ar5416Get11nRxClear; ah->ah_set11nRxClear = ar5416Set11nRxClear; ah->ah_set11nVirtMoreFrag = ar5416Set11nVirtualMoreFrag; /* Interrupt functions */ ah->ah_isInterruptPending = ar5416IsInterruptPending; ah->ah_getPendingInterrupts = ar5416GetPendingInterrupts; ah->ah_setInterrupts = ar5416SetInterrupts; /* Bluetooth Coexistence functions */ ah->ah_btCoexSetInfo = ar5416SetBTCoexInfo; ah->ah_btCoexSetConfig = ar5416BTCoexConfig; ah->ah_btCoexSetQcuThresh = ar5416BTCoexSetQcuThresh; ah->ah_btCoexSetWeights = ar5416BTCoexSetWeights; ah->ah_btCoexSetBmissThresh = ar5416BTCoexSetupBmissThresh; ah->ah_btCoexSetParameter = ar5416BTCoexSetParameter; ah->ah_btCoexDisable = ar5416BTCoexDisable; ah->ah_btCoexEnable = ar5416BTCoexEnable; AH5416(ah)->ah_btCoexSetDiversity = ar5416BTCoexAntennaDiversity; ahp->ah_priv.ah_getWirelessModes= ar5416GetWirelessModes; ahp->ah_priv.ah_eepromRead = ar5416EepromRead; #ifdef AH_SUPPORT_WRITE_EEPROM ahp->ah_priv.ah_eepromWrite = ar5416EepromWrite; #endif ahp->ah_priv.ah_getChipPowerLimits = ar5416GetChipPowerLimits; /* Internal ops */ AH5416(ah)->ah_writeIni = ar5416WriteIni; AH5416(ah)->ah_spurMitigate = ar5416SpurMitigate; /* Internal baseband ops */ AH5416(ah)->ah_initPLL = ar5416InitPLL; /* Internal calibration ops */ AH5416(ah)->ah_cal_initcal = ar5416InitCalHardware; /* Internal TX power control related operations */ AH5416(ah)->ah_olcInit = ar5416olcInit; AH5416(ah)->ah_olcTempCompensation = ar5416olcTempCompensation; AH5416(ah)->ah_setPowerCalTable = ar5416SetPowerCalTable; /* * Start by setting all Owl devices to 2x2 */ AH5416(ah)->ah_rx_chainmask = AR5416_DEFAULT_RXCHAINMASK; AH5416(ah)->ah_tx_chainmask = AR5416_DEFAULT_TXCHAINMASK; /* Enable all ANI functions to begin with */ AH5416(ah)->ah_ani_function = 0xffffffff; /* Set overridable ANI methods */ AH5212(ah)->ah_aniControl = ar5416AniControl; /* * Default FIFO Trigger levels * * These define how filled the TX FIFO needs to be before * the baseband begins to be given some data. * * To be paranoid, we ensure that the TX trigger level always * has at least enough space for two TX DMA to occur. * The TX DMA size is currently hard-coded to AR_TXCFG_DMASZ_128B. * That means we need to leave at least 256 bytes available in * the TX DMA FIFO. */ #define AR_FTRIG_512B 0x00000080 // 5 bits total /* * AR9285/AR9271 have half the size TX FIFO compared to * other devices */ if (AR_SREV_KITE(ah) || AR_SREV_9271(ah)) { AH5212(ah)->ah_txTrigLev = (AR_FTRIG_256B >> AR_FTRIG_S); AH5212(ah)->ah_maxTxTrigLev = ((2048 / 64) - 1); } else { AH5212(ah)->ah_txTrigLev = (AR_FTRIG_512B >> AR_FTRIG_S); AH5212(ah)->ah_maxTxTrigLev = ((4096 / 64) - 1); } #undef AR_FTRIG_512B /* And now leave some headspace - 256 bytes */ AH5212(ah)->ah_maxTxTrigLev -= 4; } uint32_t ar5416GetRadioRev(struct ath_hal *ah) { uint32_t val; int i; /* Read Radio Chip Rev Extract */ OS_REG_WRITE(ah, AR_PHY(0x36), 0x00007058); for (i = 0; i < 8; i++) OS_REG_WRITE(ah, AR_PHY(0x20), 0x00010000); val = (OS_REG_READ(ah, AR_PHY(256)) >> 24) & 0xff; val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4); return ath_hal_reverseBits(val, 8); } /* * Attach for an AR5416 part. */ static struct ath_hal * ar5416Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_OPS_CONFIG *ah_config, HAL_STATUS *status) { struct ath_hal_5416 *ahp5416; struct ath_hal_5212 *ahp; struct ath_hal *ah; uint32_t val; HAL_STATUS ecode; HAL_BOOL rfStatus; HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", __func__, sc, (void*) st, (void*) sh); /* NB: memory is returned zero'd */ ahp5416 = ath_hal_malloc(sizeof (struct ath_hal_5416) + /* extra space for Owl 2.1/2.2 WAR */ sizeof(ar5416Addac) ); if (ahp5416 == AH_NULL) { HALDEBUG(AH_NULL, HAL_DEBUG_ANY, "%s: cannot allocate memory for state block\n", __func__); *status = HAL_ENOMEM; return AH_NULL; } ar5416InitState(ahp5416, devid, sc, st, sh, status); ahp = &ahp5416->ah_5212; ah = &ahp->ah_priv.h; if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't reset chip\n", __func__); ecode = HAL_EIO; goto bad; } if (!ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't wakeup chip\n", __func__); ecode = HAL_EIO; goto bad; } /* Read Revisions from Chips before taking out of reset */ val = OS_REG_READ(ah, AR_SREV) & AR_SREV_ID; AH_PRIVATE(ah)->ah_macVersion = val >> AR_SREV_ID_S; AH_PRIVATE(ah)->ah_macRev = val & AR_SREV_REVISION; AH_PRIVATE(ah)->ah_ispcie = (devid == AR5416_DEVID_PCIE); /* setup common ini data; rf backends handle remainder */ HAL_INI_INIT(&ahp->ah_ini_modes, ar5416Modes, 6); HAL_INI_INIT(&ahp->ah_ini_common, ar5416Common, 2); HAL_INI_INIT(&AH5416(ah)->ah_ini_bb_rfgain, ar5416BB_RfGain, 3); HAL_INI_INIT(&AH5416(ah)->ah_ini_bank0, ar5416Bank0, 2); HAL_INI_INIT(&AH5416(ah)->ah_ini_bank1, ar5416Bank1, 2); HAL_INI_INIT(&AH5416(ah)->ah_ini_bank2, ar5416Bank2, 2); HAL_INI_INIT(&AH5416(ah)->ah_ini_bank3, ar5416Bank3, 3); HAL_INI_INIT(&AH5416(ah)->ah_ini_bank6, ar5416Bank6, 3); HAL_INI_INIT(&AH5416(ah)->ah_ini_bank7, ar5416Bank7, 2); HAL_INI_INIT(&AH5416(ah)->ah_ini_addac, ar5416Addac, 2); if (! IS_5416V2_2(ah)) { /* Owl 2.1/2.0 */ ath_hal_printf(ah, "[ath] Enabling CLKDRV workaround for AR5416 < v2.2\n"); struct ini { uint32_t *data; /* NB: !const */ int rows, cols; }; /* override CLKDRV value */ OS_MEMCPY(&AH5416(ah)[1], ar5416Addac, sizeof(ar5416Addac)); AH5416(ah)->ah_ini_addac.data = (uint32_t *) &AH5416(ah)[1]; HAL_INI_VAL((struct ini *)&AH5416(ah)->ah_ini_addac, 31, 1) = 0; } HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, ar5416PciePhy, 2); ar5416AttachPCIE(ah); ecode = ath_hal_v14EepromAttach(ah); if (ecode != HAL_OK) goto bad; if (!ar5416ChipReset(ah, AH_NULL)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); ecode = HAL_EIO; goto bad; } AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIP_ID); if (!ar5212ChipTest(ah)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: hardware self-test failed\n", __func__); ecode = HAL_ESELFTEST; goto bad; } /* * Set correct Baseband to analog shift * setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); /* Read Radio Chip Rev Extract */ AH_PRIVATE(ah)->ah_analog5GhzRev = ar5416GetRadioRev(ah); switch (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { case AR_RAD5122_SREV_MAJOR: /* Fowl: 5G/2x2 */ case AR_RAD2122_SREV_MAJOR: /* Fowl: 2+5G/2x2 */ case AR_RAD2133_SREV_MAJOR: /* Fowl: 2G/3x3 */ case AR_RAD5133_SREV_MAJOR: /* Fowl: 2+5G/3x3 */ break; default: if (AH_PRIVATE(ah)->ah_analog5GhzRev == 0) { /* * When RF_Silen is used the analog chip is reset. * So when the system boots with radio switch off * the RF chip rev reads back as zero and we need * to use the mac+phy revs to set the radio rev. */ AH_PRIVATE(ah)->ah_analog5GhzRev = AR_RAD5133_SREV_MAJOR; break; } /* NB: silently accept anything in release code per Atheros */ #ifdef AH_DEBUG HALDEBUG(ah, HAL_DEBUG_ANY, "%s: 5G Radio Chip Rev 0x%02X is not supported by " "this driver\n", __func__, AH_PRIVATE(ah)->ah_analog5GhzRev); ecode = HAL_ENOTSUPP; goto bad; #endif } /* * Got everything we need now to setup the capabilities. */ if (!ar5416FillCapabilityInfo(ah)) { ecode = HAL_EEREAD; goto bad; } ecode = ath_hal_eepromGet(ah, AR_EEP_MACADDR, ahp->ah_macaddr); if (ecode != HAL_OK) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: error getting mac address from EEPROM\n", __func__); goto bad; } /* XXX How about the serial number ? */ /* Read Reg Domain */ AH_PRIVATE(ah)->ah_currentRD = ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, AH_NULL); AH_PRIVATE(ah)->ah_currentRDext = ath_hal_eepromGet(ah, AR_EEP_REGDMN_1, AH_NULL); /* * ah_miscMode is populated by ar5416FillCapabilityInfo() * starting from griffin. Set here to make sure that * AR_MISC_MODE_MIC_NEW_LOC_ENABLE is set before a GTK is * placed into hardware. */ if (ahp->ah_miscMode != 0) OS_REG_WRITE(ah, AR_MISC_MODE, OS_REG_READ(ah, AR_MISC_MODE) | ahp->ah_miscMode); rfStatus = ar2133RfAttach(ah, &ecode); if (!rfStatus) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RF setup failed, status %u\n", __func__, ecode); goto bad; } ar5416AniSetup(ah); /* Anti Noise Immunity */ AH5416(ah)->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_5416_2GHZ; AH5416(ah)->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_5416_2GHZ; AH5416(ah)->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_5416_2GHZ; AH5416(ah)->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_5416_5GHZ; AH5416(ah)->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_5416_5GHZ; AH5416(ah)->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_5416_5GHZ; ar5416InitNfHistBuff(AH5416(ah)->ah_cal.nfCalHist); HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__); return ah; bad: if (ahp) ar5416Detach((struct ath_hal *) ahp); if (status) *status = ecode; return AH_NULL; } void ar5416Detach(struct ath_hal *ah) { HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s:\n", __func__); HALASSERT(ah != AH_NULL); HALASSERT(ah->ah_magic == AR5416_MAGIC); /* Make sure that chip is awake before writing to it */ if (! ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s: failed to wake up chip\n", __func__); ar5416AniDetach(ah); ar5212RfDetach(ah); ah->ah_disable(ah); ar5416SetPowerMode(ah, HAL_PM_FULL_SLEEP, AH_TRUE); ath_hal_eepromDetach(ah); ath_hal_free(ah); } void ar5416AttachPCIE(struct ath_hal *ah) { if (AH_PRIVATE(ah)->ah_ispcie) ath_hal_configPCIE(ah, AH_FALSE, AH_FALSE); else ath_hal_disablePCIE(ah); } static void ar5416ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore, HAL_BOOL power_off) { /* This is only applicable for AR5418 (AR5416 PCIe) */ if (! AH_PRIVATE(ah)->ah_ispcie) return; if (! restore) { ath_hal_ini_write(ah, &AH5416(ah)->ah_ini_pcieserdes, 1, 0); OS_DELAY(1000); } if (power_off) { /* Power-off */ /* clear bit 19 to disable L1 */ OS_REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); } else { /* Power-on */ /* Set default WAR values for Owl */ OS_REG_WRITE(ah, AR_WA, AR_WA_DEFAULT); /* set bit 19 to allow forcing of pcie core into L1 state */ OS_REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); } } /* * Disable PCIe PHY if PCIe isn't used. */ static void ar5416DisablePCIE(struct ath_hal *ah) { /* PCIe? Don't */ if (AH_PRIVATE(ah)->ah_ispcie) return; /* .. Only applicable for AR5416v2 or later */ if (! (AR_SREV_OWL(ah) && AR_SREV_OWL_20_OR_LATER(ah))) return; OS_REG_WRITE_BUFFER_ENABLE(ah); /* * Disable the PCIe PHY. */ OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00); OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x28000029); OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x57160824); OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x25980579); OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x00000000); OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); OS_REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x000e1007); /* Load the new settings */ OS_REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); OS_REG_WRITE_BUFFER_FLUSH(ah); OS_REG_WRITE_BUFFER_DISABLE(ah); } static void ar5416WriteIni(struct ath_hal *ah, const struct ieee80211_channel *chan) { u_int modesIndex, freqIndex; int regWrites = 0; /* Setup the indices for the next set of register array writes */ /* XXX Ignore 11n dynamic mode on the AR5416 for the moment */ if (IEEE80211_IS_CHAN_2GHZ(chan)) { freqIndex = 2; if (IEEE80211_IS_CHAN_HT40(chan)) modesIndex = 3; else if (IEEE80211_IS_CHAN_108G(chan)) modesIndex = 5; else modesIndex = 4; } else { freqIndex = 1; if (IEEE80211_IS_CHAN_HT40(chan) || IEEE80211_IS_CHAN_TURBO(chan)) modesIndex = 2; else modesIndex = 1; } /* Set correct Baseband to analog shift setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); /* * Write addac shifts */ OS_REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO); /* NB: only required for Sowl */ if (AR_SREV_SOWL(ah)) ar5416EepromSetAddac(ah, chan); regWrites = ath_hal_ini_write(ah, &AH5416(ah)->ah_ini_addac, 1, regWrites); OS_REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC); regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_modes, modesIndex, regWrites); regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_common, 1, regWrites); /* XXX updated regWrites? */ AH5212(ah)->ah_rfHal->writeRegs(ah, modesIndex, freqIndex, regWrites); } /* * Convert to baseband spur frequency given input channel frequency * and compute register settings below. */ static void ar5416SpurMitigate(struct ath_hal *ah, const struct ieee80211_channel *chan) { uint16_t freq = ath_hal_gethwchannel(ah, chan); static const int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 }; static const int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 }; static const int inc[4] = { 0, 100, 0, 0 }; int bb_spur = AR_NO_SPUR; int bin, cur_bin; int spur_freq_sd; int spur_delta_phase; int denominator; int upper, lower, cur_vit_mask; int tmp, new; int i; int8_t mask_m[123]; int8_t mask_p[123]; int8_t mask_amt; int tmp_mask; int cur_bb_spur; HAL_BOOL is2GHz = IEEE80211_IS_CHAN_2GHZ(chan); OS_MEMZERO(mask_m, sizeof(mask_m)); OS_MEMZERO(mask_p, sizeof(mask_p)); /* * Need to verify range +/- 9.5 for static ht20, otherwise spur * is out-of-band and can be ignored. */ /* XXX ath9k changes */ for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { cur_bb_spur = ath_hal_getSpurChan(ah, i, is2GHz); if (AR_NO_SPUR == cur_bb_spur) break; cur_bb_spur = cur_bb_spur - (freq * 10); if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) { bb_spur = cur_bb_spur; break; } } if (AR_NO_SPUR == bb_spur) return; bin = bb_spur * 32; tmp = OS_REG_READ(ah, AR_PHY_TIMING_CTRL4_CHAIN(0)); new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); OS_REG_WRITE_BUFFER_ENABLE(ah); OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4_CHAIN(0), new); new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | AR_PHY_SPUR_REG_ENABLE_MASK_PPM | AR_PHY_SPUR_REG_MASK_RATE_SELECT | AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | SM(AR5416_SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); OS_REG_WRITE(ah, AR_PHY_SPUR_REG, new); /* * Should offset bb_spur by +/- 10 MHz for dynamic 2040 MHz * config, no offset for HT20. * spur_delta_phase = bb_spur/40 * 2**21 for static ht20, * /80 for dyn2040. */ spur_delta_phase = ((bb_spur * 524288) / 100) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; /* * in 11A mode the denominator of spur_freq_sd should be 40 and * it should be 44 in 11G */ denominator = IEEE80211_IS_CHAN_2GHZ(chan) ? 440 : 400; spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff; new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); OS_REG_WRITE(ah, AR_PHY_TIMING11, new); /* * ============================================ * pilot mask 1 [31:0] = +6..-26, no 0 bin * pilot mask 2 [19:0] = +26..+7 * * channel mask 1 [31:0] = +6..-26, no 0 bin * channel mask 2 [19:0] = +26..+7 */ //cur_bin = -26; cur_bin = -6000; upper = bin + 100; lower = bin - 100; for (i = 0; i < 4; i++) { int pilot_mask = 0; int chan_mask = 0; int bp = 0; for (bp = 0; bp < 30; bp++) { if ((cur_bin > lower) && (cur_bin < upper)) { pilot_mask = pilot_mask | 0x1 << bp; chan_mask = chan_mask | 0x1 << bp; } cur_bin += 100; } cur_bin += inc[i]; OS_REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); OS_REG_WRITE(ah, chan_mask_reg[i], chan_mask); } /* ================================================= * viterbi mask 1 based on channel magnitude * four levels 0-3 * - mask (-27 to 27) (reg 64,0x9900 to 67,0x990c) * [1 2 2 1] for -9.6 or [1 2 1] for +16 * - enable_mask_ppm, all bins move with freq * * - mask_select, 8 bits for rates (reg 67,0x990c) * - mask_rate_cntl, 8 bits for rates (reg 67,0x990c) * choose which mask to use mask or mask2 */ /* * viterbi mask 2 2nd set for per data rate puncturing * four levels 0-3 * - mask_select, 8 bits for rates (reg 67) * - mask (-27 to 27) (reg 98,0x9988 to 101,0x9994) * [1 2 2 1] for -9.6 or [1 2 1] for +16 */ cur_vit_mask = 6100; upper = bin + 120; lower = bin - 120; for (i = 0; i < 123; i++) { if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { if ((abs(cur_vit_mask - bin)) < 75) { mask_amt = 1; } else { mask_amt = 0; } if (cur_vit_mask < 0) { mask_m[abs(cur_vit_mask / 100)] = mask_amt; } else { mask_p[cur_vit_mask / 100] = mask_amt; } } cur_vit_mask -= 100; } tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) | (mask_m[48] << 26) | (mask_m[49] << 24) | (mask_m[50] << 22) | (mask_m[51] << 20) | (mask_m[52] << 18) | (mask_m[53] << 16) | (mask_m[54] << 14) | (mask_m[55] << 12) | (mask_m[56] << 10) | (mask_m[57] << 8) | (mask_m[58] << 6) | (mask_m[59] << 4) | (mask_m[60] << 2) | (mask_m[61] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); OS_REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); tmp_mask = (mask_m[31] << 28) | (mask_m[32] << 26) | (mask_m[33] << 24) | (mask_m[34] << 22) | (mask_m[35] << 20) | (mask_m[36] << 18) | (mask_m[37] << 16) | (mask_m[48] << 14) | (mask_m[39] << 12) | (mask_m[40] << 10) | (mask_m[41] << 8) | (mask_m[42] << 6) | (mask_m[43] << 4) | (mask_m[44] << 2) | (mask_m[45] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) | (mask_m[18] << 26) | (mask_m[18] << 24) | (mask_m[20] << 22) | (mask_m[20] << 20) | (mask_m[22] << 18) | (mask_m[22] << 16) | (mask_m[24] << 14) | (mask_m[24] << 12) | (mask_m[25] << 10) | (mask_m[26] << 8) | (mask_m[27] << 6) | (mask_m[28] << 4) | (mask_m[29] << 2) | (mask_m[30] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); tmp_mask = (mask_m[ 0] << 30) | (mask_m[ 1] << 28) | (mask_m[ 2] << 26) | (mask_m[ 3] << 24) | (mask_m[ 4] << 22) | (mask_m[ 5] << 20) | (mask_m[ 6] << 18) | (mask_m[ 7] << 16) | (mask_m[ 8] << 14) | (mask_m[ 9] << 12) | (mask_m[10] << 10) | (mask_m[11] << 8) | (mask_m[12] << 6) | (mask_m[13] << 4) | (mask_m[14] << 2) | (mask_m[15] << 0); OS_REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); tmp_mask = (mask_p[15] << 28) | (mask_p[14] << 26) | (mask_p[13] << 24) | (mask_p[12] << 22) | (mask_p[11] << 20) | (mask_p[10] << 18) | (mask_p[ 9] << 16) | (mask_p[ 8] << 14) | (mask_p[ 7] << 12) | (mask_p[ 6] << 10) | (mask_p[ 5] << 8) | (mask_p[ 4] << 6) | (mask_p[ 3] << 4) | (mask_p[ 2] << 2) | (mask_p[ 1] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); tmp_mask = (mask_p[30] << 28) | (mask_p[29] << 26) | (mask_p[28] << 24) | (mask_p[27] << 22) | (mask_p[26] << 20) | (mask_p[25] << 18) | (mask_p[24] << 16) | (mask_p[23] << 14) | (mask_p[22] << 12) | (mask_p[21] << 10) | (mask_p[20] << 8) | (mask_p[19] << 6) | (mask_p[18] << 4) | (mask_p[17] << 2) | (mask_p[16] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); tmp_mask = (mask_p[45] << 28) | (mask_p[44] << 26) | (mask_p[43] << 24) | (mask_p[42] << 22) | (mask_p[41] << 20) | (mask_p[40] << 18) | (mask_p[39] << 16) | (mask_p[38] << 14) | (mask_p[37] << 12) | (mask_p[36] << 10) | (mask_p[35] << 8) | (mask_p[34] << 6) | (mask_p[33] << 4) | (mask_p[32] << 2) | (mask_p[31] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) | (mask_p[59] << 26) | (mask_p[58] << 24) | (mask_p[57] << 22) | (mask_p[56] << 20) | (mask_p[55] << 18) | (mask_p[54] << 16) | (mask_p[53] << 14) | (mask_p[52] << 12) | (mask_p[51] << 10) | (mask_p[50] << 8) | (mask_p[49] << 6) | (mask_p[48] << 4) | (mask_p[47] << 2) | (mask_p[46] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); OS_REG_WRITE_BUFFER_FLUSH(ah); OS_REG_WRITE_BUFFER_DISABLE(ah); } /* * Fill all software cached or static hardware state information. * Return failure if capabilities are to come from EEPROM and * cannot be read. */ HAL_BOOL ar5416FillCapabilityInfo(struct ath_hal *ah) { struct ath_hal_private *ahpriv = AH_PRIVATE(ah); HAL_CAPABILITIES *pCap = &ahpriv->ah_caps; uint16_t val; /* Construct wireless mode from EEPROM */ pCap->halWirelessModes = 0; if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) { pCap->halWirelessModes |= HAL_MODE_11A | HAL_MODE_11NA_HT20 | HAL_MODE_11NA_HT40PLUS | HAL_MODE_11NA_HT40MINUS ; } if (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE)) { pCap->halWirelessModes |= HAL_MODE_11G | HAL_MODE_11NG_HT20 | HAL_MODE_11NG_HT40PLUS | HAL_MODE_11NG_HT40MINUS ; pCap->halWirelessModes |= HAL_MODE_11A | HAL_MODE_11NA_HT20 | HAL_MODE_11NA_HT40PLUS | HAL_MODE_11NA_HT40MINUS ; } pCap->halLow2GhzChan = 2312; pCap->halHigh2GhzChan = 2732; pCap->halLow5GhzChan = 4915; pCap->halHigh5GhzChan = 6100; pCap->halCipherCkipSupport = AH_FALSE; pCap->halCipherTkipSupport = AH_TRUE; pCap->halCipherAesCcmSupport = ath_hal_eepromGetFlag(ah, AR_EEP_AES); pCap->halMicCkipSupport = AH_FALSE; pCap->halMicTkipSupport = AH_TRUE; pCap->halMicAesCcmSupport = ath_hal_eepromGetFlag(ah, AR_EEP_AES); /* * Starting with Griffin TX+RX mic keys can be combined * in one key cache slot. */ pCap->halTkipMicTxRxKeySupport = AH_TRUE; pCap->halChanSpreadSupport = AH_TRUE; pCap->halSleepAfterBeaconBroken = AH_TRUE; pCap->halCompressSupport = AH_FALSE; pCap->halBurstSupport = AH_TRUE; - /* - * This is disabled for now; the net80211 layer needs to be - * taught when it is and isn't appropriate to enable FF processing - * with 802.11n NICs (it tries to enable both A-MPDU and - * fast frames, with very tragic crash-y results.) - */ - pCap->halFastFramesSupport = AH_FALSE; + pCap->halFastFramesSupport = AH_TRUE; pCap->halChapTuningSupport = AH_TRUE; pCap->halTurboPrimeSupport = AH_TRUE; pCap->halTurboGSupport = pCap->halWirelessModes & HAL_MODE_108G; pCap->halPSPollBroken = AH_TRUE; /* XXX fixed in later revs? */ pCap->halNumMRRetries = 4; /* Hardware supports 4 MRR */ pCap->halNumTxMaps = 1; /* Single TX ptr per descr */ pCap->halVEOLSupport = AH_TRUE; pCap->halBssIdMaskSupport = AH_TRUE; pCap->halMcastKeySrchSupport = AH_TRUE; /* Works on AR5416 and later */ pCap->halTsfAddSupport = AH_TRUE; pCap->hal4AddrAggrSupport = AH_FALSE; /* Broken in Owl */ pCap->halSpectralScanSupport = AH_FALSE; /* AR9280 and later */ if (ath_hal_eepromGet(ah, AR_EEP_MAXQCU, &val) == HAL_OK) pCap->halTotalQueues = val; else pCap->halTotalQueues = HAL_NUM_TX_QUEUES; if (ath_hal_eepromGet(ah, AR_EEP_KCENTRIES, &val) == HAL_OK) pCap->halKeyCacheSize = val; else pCap->halKeyCacheSize = AR5416_KEYTABLE_SIZE; /* XXX Which chips? */ pCap->halChanHalfRate = AH_TRUE; pCap->halChanQuarterRate = AH_TRUE; pCap->halTstampPrecision = 32; pCap->halHwPhyCounterSupport = AH_TRUE; pCap->halIntrMask = HAL_INT_COMMON | HAL_INT_RX | HAL_INT_TX | HAL_INT_FATAL | HAL_INT_BNR | HAL_INT_BMISC | HAL_INT_DTIMSYNC | HAL_INT_TSFOOR | HAL_INT_CST | HAL_INT_GTT ; pCap->halFastCCSupport = AH_TRUE; pCap->halNumGpioPins = 14; pCap->halWowSupport = AH_FALSE; pCap->halWowMatchPatternExact = AH_FALSE; pCap->halBtCoexSupport = AH_FALSE; /* XXX need support */ pCap->halAutoSleepSupport = AH_FALSE; pCap->hal4kbSplitTransSupport = AH_TRUE; /* Disable this so Block-ACK works correctly */ pCap->halHasRxSelfLinkedTail = AH_FALSE; #if 0 /* XXX not yet */ pCap->halNumAntCfg2GHz = ar5416GetNumAntConfig(ahp, HAL_FREQ_BAND_2GHZ); pCap->halNumAntCfg5GHz = ar5416GetNumAntConfig(ahp, HAL_FREQ_BAND_5GHZ); #endif pCap->halHTSupport = AH_TRUE; pCap->halTxChainMask = ath_hal_eepromGet(ah, AR_EEP_TXMASK, AH_NULL); /* XXX CB71 uses GPIO 0 to indicate 3 rx chains */ pCap->halRxChainMask = ath_hal_eepromGet(ah, AR_EEP_RXMASK, AH_NULL); /* AR5416 may have 3 antennas but is a 2x2 stream device */ pCap->halTxStreams = 2; pCap->halRxStreams = 2; /* * If the TX or RX chainmask has less than 2 chains active, * mark it as a 1-stream device for the relevant stream. */ if (owl_get_ntxchains(pCap->halTxChainMask) == 1) pCap->halTxStreams = 1; /* XXX Eww */ if (owl_get_ntxchains(pCap->halRxChainMask) == 1) pCap->halRxStreams = 1; pCap->halRtsAggrLimit = 8*1024; /* Owl 2.0 limit */ pCap->halMbssidAggrSupport = AH_FALSE; /* Broken on Owl */ pCap->halForcePpmSupport = AH_TRUE; pCap->halEnhancedPmSupport = AH_TRUE; pCap->halBssidMatchSupport = AH_TRUE; pCap->halGTTSupport = AH_TRUE; pCap->halCSTSupport = AH_TRUE; pCap->halEnhancedDfsSupport = AH_FALSE; /* Hardware supports 32 bit TSF values in the RX descriptor */ pCap->halHasLongRxDescTsf = AH_TRUE; /* * BB Read WAR: this is only for AR5008/AR9001 NICs * It is also set individually in the AR91xx attach functions. */ if (AR_SREV_OWL(ah)) pCap->halHasBBReadWar = AH_TRUE; if (ath_hal_eepromGetFlag(ah, AR_EEP_RFKILL) && ath_hal_eepromGet(ah, AR_EEP_RFSILENT, &ahpriv->ah_rfsilent) == HAL_OK) { /* NB: enabled by default */ ahpriv->ah_rfkillEnabled = AH_TRUE; pCap->halRfSilentSupport = AH_TRUE; } /* * The MAC will mark frames as RXed if there's a descriptor * to write them to. So if it hits a self-linked final descriptor, * it'll keep ACKing frames even though they're being silently * dropped. Thus, this particular feature of the driver can't * be used for 802.11n devices. */ ahpriv->ah_rxornIsFatal = AH_FALSE; /* * If it's a PCI NIC, ask the HAL OS layer to serialise * register access, or SMP machines may cause the hardware * to hang. This is applicable to AR5416 and AR9220; I'm not * sure about AR9160 or AR9227. */ if (! AH_PRIVATE(ah)->ah_ispcie) pCap->halSerialiseRegWar = 1; /* * AR5416 and later NICs support MYBEACON filtering. */ pCap->halRxDoMyBeacon = AH_TRUE; return AH_TRUE; } static const char* ar5416Probe(uint16_t vendorid, uint16_t devid) { if (vendorid == ATHEROS_VENDOR_ID) { if (devid == AR5416_DEVID_PCI) return "Atheros 5416"; if (devid == AR5416_DEVID_PCIE) return "Atheros 5418"; } return AH_NULL; } AH_CHIP(AR5416, ar5416Probe, ar5416Attach); Index: projects/release-pkg/sys/dev/cxgbe/iw_cxgbe/cm.c =================================================================== --- projects/release-pkg/sys/dev/cxgbe/iw_cxgbe/cm.c (revision 289118) +++ projects/release-pkg/sys/dev/cxgbe/iw_cxgbe/cm.c (revision 289119) @@ -1,2443 +1,2449 @@ /* * Copyright (c) 2009-2013 Chelsio, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include __FBSDID("$FreeBSD$"); #include "opt_inet.h" #ifdef TCP_OFFLOAD #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct sge_iq; struct rss_header; #include #include "offload.h" #include "tom/t4_tom.h" #define TOEPCB(so) ((struct toepcb *)(so_sototcpcb((so))->t_toe)) #include "iw_cxgbe.h" #include #include #include #include #include #include static spinlock_t req_lock; static TAILQ_HEAD(c4iw_ep_list, c4iw_ep_common) req_list; static struct work_struct c4iw_task; static struct workqueue_struct *c4iw_taskq; static LIST_HEAD(timeout_list); static spinlock_t timeout_lock; static void process_req(struct work_struct *ctx); static void start_ep_timer(struct c4iw_ep *ep); static void stop_ep_timer(struct c4iw_ep *ep); static int set_tcpinfo(struct c4iw_ep *ep); static enum c4iw_ep_state state_read(struct c4iw_ep_common *epc); static void __state_set(struct c4iw_ep_common *epc, enum c4iw_ep_state tostate); static void state_set(struct c4iw_ep_common *epc, enum c4iw_ep_state tostate); static void *alloc_ep(int size, gfp_t flags); void __free_ep(struct c4iw_ep_common *epc); static struct rtentry * find_route(__be32 local_ip, __be32 peer_ip, __be16 local_port, __be16 peer_port, u8 tos); static int close_socket(struct c4iw_ep_common *epc, int close); static int shutdown_socket(struct c4iw_ep_common *epc); static void abort_socket(struct c4iw_ep *ep); static void send_mpa_req(struct c4iw_ep *ep); static int send_mpa_reject(struct c4iw_ep *ep, const void *pdata, u8 plen); static int send_mpa_reply(struct c4iw_ep *ep, const void *pdata, u8 plen); static void close_complete_upcall(struct c4iw_ep *ep, int status); static int abort_connection(struct c4iw_ep *ep); static void peer_close_upcall(struct c4iw_ep *ep); static void peer_abort_upcall(struct c4iw_ep *ep); static void connect_reply_upcall(struct c4iw_ep *ep, int status); -static void connect_request_upcall(struct c4iw_ep *ep); +static int connect_request_upcall(struct c4iw_ep *ep); static void established_upcall(struct c4iw_ep *ep); static void process_mpa_reply(struct c4iw_ep *ep); static void process_mpa_request(struct c4iw_ep *ep); static void process_peer_close(struct c4iw_ep *ep); static void process_conn_error(struct c4iw_ep *ep); static void process_close_complete(struct c4iw_ep *ep); static void ep_timeout(unsigned long arg); static void init_sock(struct c4iw_ep_common *epc); static void process_data(struct c4iw_ep *ep); static void process_connected(struct c4iw_ep *ep); static struct socket * dequeue_socket(struct socket *head, struct sockaddr_in **remote, struct c4iw_ep *child_ep); static void process_newconn(struct c4iw_ep *parent_ep); static int c4iw_so_upcall(struct socket *so, void *arg, int waitflag); static void process_socket_event(struct c4iw_ep *ep); static void release_ep_resources(struct c4iw_ep *ep); #define START_EP_TIMER(ep) \ do { \ CTR3(KTR_IW_CXGBE, "start_ep_timer (%s:%d) ep %p", \ __func__, __LINE__, (ep)); \ start_ep_timer(ep); \ } while (0) #define STOP_EP_TIMER(ep) \ do { \ CTR3(KTR_IW_CXGBE, "stop_ep_timer (%s:%d) ep %p", \ __func__, __LINE__, (ep)); \ stop_ep_timer(ep); \ } while (0) #ifdef KTR static char *states[] = { "idle", "listen", "connecting", "mpa_wait_req", "mpa_req_sent", "mpa_req_rcvd", "mpa_rep_sent", "fpdu_mode", "aborting", "closing", "moribund", "dead", NULL, }; #endif static void process_req(struct work_struct *ctx) { struct c4iw_ep_common *epc; spin_lock(&req_lock); while (!TAILQ_EMPTY(&req_list)) { epc = TAILQ_FIRST(&req_list); TAILQ_REMOVE(&req_list, epc, entry); epc->entry.tqe_prev = NULL; spin_unlock(&req_lock); if (epc->so) process_socket_event((struct c4iw_ep *)epc); c4iw_put_ep(epc); spin_lock(&req_lock); } spin_unlock(&req_lock); } /* * XXX: doesn't belong here in the iWARP driver. * XXX: assumes that the connection was offloaded by cxgbe/t4_tom if TF_TOE is * set. Is this a valid assumption for active open? */ static int set_tcpinfo(struct c4iw_ep *ep) { struct socket *so = ep->com.so; struct inpcb *inp = sotoinpcb(so); struct tcpcb *tp; struct toepcb *toep; int rc = 0; INP_WLOCK(inp); tp = intotcpcb(inp); if ((tp->t_flags & TF_TOE) == 0) { rc = EINVAL; log(LOG_ERR, "%s: connection not offloaded (so %p, ep %p)\n", __func__, so, ep); goto done; } toep = TOEPCB(so); ep->hwtid = toep->tid; ep->snd_seq = tp->snd_nxt; ep->rcv_seq = tp->rcv_nxt; ep->emss = max(tp->t_maxseg, 128); done: INP_WUNLOCK(inp); return (rc); } static struct rtentry * find_route(__be32 local_ip, __be32 peer_ip, __be16 local_port, __be16 peer_port, u8 tos) { struct route iproute; struct sockaddr_in *dst = (struct sockaddr_in *)&iproute.ro_dst; CTR5(KTR_IW_CXGBE, "%s:frtB %x, %x, %d, %d", __func__, local_ip, peer_ip, ntohs(local_port), ntohs(peer_port)); bzero(&iproute, sizeof iproute); dst->sin_family = AF_INET; dst->sin_len = sizeof *dst; dst->sin_addr.s_addr = peer_ip; rtalloc(&iproute); CTR2(KTR_IW_CXGBE, "%s:frtE %p", __func__, (uint64_t)iproute.ro_rt); return iproute.ro_rt; } static int close_socket(struct c4iw_ep_common *epc, int close) { struct socket *so = epc->so; int rc; CTR4(KTR_IW_CXGBE, "%s: so %p, ep %p, state %s", __func__, epc, so, states[epc->state]); SOCK_LOCK(so); soupcall_clear(so, SO_RCV); SOCK_UNLOCK(so); if (close) rc = soclose(so); else rc = soshutdown(so, SHUT_WR | SHUT_RD); epc->so = NULL; return (rc); } static int shutdown_socket(struct c4iw_ep_common *epc) { CTR4(KTR_IW_CXGBE, "%s: so %p, ep %p, state %s", __func__, epc->so, epc, states[epc->state]); return (soshutdown(epc->so, SHUT_WR)); } static void abort_socket(struct c4iw_ep *ep) { struct sockopt sopt; int rc; struct linger l; CTR4(KTR_IW_CXGBE, "%s ep %p so %p state %s", __func__, ep, ep->com.so, states[ep->com.state]); l.l_onoff = 1; l.l_linger = 0; /* linger_time of 0 forces RST to be sent */ sopt.sopt_dir = SOPT_SET; sopt.sopt_level = SOL_SOCKET; sopt.sopt_name = SO_LINGER; sopt.sopt_val = (caddr_t)&l; sopt.sopt_valsize = sizeof l; sopt.sopt_td = NULL; rc = sosetopt(ep->com.so, &sopt); if (rc) { log(LOG_ERR, "%s: can't set linger to 0, no RST! err %d\n", __func__, rc); } } static void process_peer_close(struct c4iw_ep *ep) { struct c4iw_qp_attributes attrs; int disconnect = 1; int release = 0; CTR4(KTR_IW_CXGBE, "%s:ppcB ep %p so %p state %s", __func__, ep, ep->com.so, states[ep->com.state]); mutex_lock(&ep->com.mutex); switch (ep->com.state) { case MPA_REQ_WAIT: CTR2(KTR_IW_CXGBE, "%s:ppc1 %p MPA_REQ_WAIT CLOSING", __func__, ep); __state_set(&ep->com, CLOSING); break; case MPA_REQ_SENT: CTR2(KTR_IW_CXGBE, "%s:ppc2 %p MPA_REQ_SENT CLOSING", __func__, ep); __state_set(&ep->com, DEAD); connect_reply_upcall(ep, -ECONNABORTED); disconnect = 0; STOP_EP_TIMER(ep); close_socket(&ep->com, 0); ep->com.cm_id->rem_ref(ep->com.cm_id); ep->com.cm_id = NULL; ep->com.qp = NULL; release = 1; break; case MPA_REQ_RCVD: /* * We're gonna mark this puppy DEAD, but keep * the reference on it until the ULP accepts or * rejects the CR. */ CTR2(KTR_IW_CXGBE, "%s:ppc3 %p MPA_REQ_RCVD CLOSING", __func__, ep); __state_set(&ep->com, CLOSING); c4iw_get_ep(&ep->com); break; case MPA_REP_SENT: CTR2(KTR_IW_CXGBE, "%s:ppc4 %p MPA_REP_SENT CLOSING", __func__, ep); __state_set(&ep->com, CLOSING); break; case FPDU_MODE: CTR2(KTR_IW_CXGBE, "%s:ppc5 %p FPDU_MODE CLOSING", __func__, ep); START_EP_TIMER(ep); __state_set(&ep->com, CLOSING); attrs.next_state = C4IW_QP_STATE_CLOSING; c4iw_modify_qp(ep->com.dev, ep->com.qp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); peer_close_upcall(ep); break; case ABORTING: CTR2(KTR_IW_CXGBE, "%s:ppc6 %p ABORTING (disconn)", __func__, ep); disconnect = 0; break; case CLOSING: CTR2(KTR_IW_CXGBE, "%s:ppc7 %p CLOSING MORIBUND", __func__, ep); __state_set(&ep->com, MORIBUND); disconnect = 0; break; case MORIBUND: CTR2(KTR_IW_CXGBE, "%s:ppc8 %p MORIBUND DEAD", __func__, ep); STOP_EP_TIMER(ep); if (ep->com.cm_id && ep->com.qp) { attrs.next_state = C4IW_QP_STATE_IDLE; c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); } close_socket(&ep->com, 0); close_complete_upcall(ep, 0); __state_set(&ep->com, DEAD); release = 1; disconnect = 0; break; case DEAD: CTR2(KTR_IW_CXGBE, "%s:ppc9 %p DEAD (disconn)", __func__, ep); disconnect = 0; break; default: panic("%s: ep %p state %d", __func__, ep, ep->com.state); break; } mutex_unlock(&ep->com.mutex); if (disconnect) { CTR2(KTR_IW_CXGBE, "%s:ppca %p", __func__, ep); c4iw_ep_disconnect(ep, 0, M_NOWAIT); } if (release) { CTR2(KTR_IW_CXGBE, "%s:ppcb %p", __func__, ep); c4iw_put_ep(&ep->com); } CTR2(KTR_IW_CXGBE, "%s:ppcE %p", __func__, ep); return; } static void process_conn_error(struct c4iw_ep *ep) { struct c4iw_qp_attributes attrs; int ret; int state; state = state_read(&ep->com); CTR5(KTR_IW_CXGBE, "%s:pceB ep %p so %p so->so_error %u state %s", __func__, ep, ep->com.so, ep->com.so->so_error, states[ep->com.state]); switch (state) { case MPA_REQ_WAIT: STOP_EP_TIMER(ep); break; case MPA_REQ_SENT: STOP_EP_TIMER(ep); connect_reply_upcall(ep, -ECONNRESET); break; case MPA_REP_SENT: ep->com.rpl_err = ECONNRESET; CTR1(KTR_IW_CXGBE, "waking up ep %p", ep); break; case MPA_REQ_RCVD: /* * We're gonna mark this puppy DEAD, but keep * the reference on it until the ULP accepts or * rejects the CR. */ c4iw_get_ep(&ep->com); break; case MORIBUND: case CLOSING: STOP_EP_TIMER(ep); /*FALLTHROUGH*/ case FPDU_MODE: if (ep->com.cm_id && ep->com.qp) { attrs.next_state = C4IW_QP_STATE_ERROR; ret = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); if (ret) log(LOG_ERR, "%s - qp <- error failed!\n", __func__); } peer_abort_upcall(ep); break; case ABORTING: break; case DEAD: CTR2(KTR_IW_CXGBE, "%s so_error %d IN DEAD STATE!!!!", __func__, ep->com.so->so_error); return; default: panic("%s: ep %p state %d", __func__, ep, state); break; } if (state != ABORTING) { CTR2(KTR_IW_CXGBE, "%s:pce1 %p", __func__, ep); close_socket(&ep->com, 1); state_set(&ep->com, DEAD); c4iw_put_ep(&ep->com); } CTR2(KTR_IW_CXGBE, "%s:pceE %p", __func__, ep); return; } static void process_close_complete(struct c4iw_ep *ep) { struct c4iw_qp_attributes attrs; int release = 0; CTR4(KTR_IW_CXGBE, "%s:pccB ep %p so %p state %s", __func__, ep, ep->com.so, states[ep->com.state]); /* The cm_id may be null if we failed to connect */ mutex_lock(&ep->com.mutex); switch (ep->com.state) { case CLOSING: CTR2(KTR_IW_CXGBE, "%s:pcc1 %p CLOSING MORIBUND", __func__, ep); __state_set(&ep->com, MORIBUND); break; case MORIBUND: CTR2(KTR_IW_CXGBE, "%s:pcc1 %p MORIBUND DEAD", __func__, ep); STOP_EP_TIMER(ep); if ((ep->com.cm_id) && (ep->com.qp)) { CTR2(KTR_IW_CXGBE, "%s:pcc2 %p QP_STATE_IDLE", __func__, ep); attrs.next_state = C4IW_QP_STATE_IDLE; c4iw_modify_qp(ep->com.dev, ep->com.qp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); } if (ep->parent_ep) { CTR2(KTR_IW_CXGBE, "%s:pcc3 %p", __func__, ep); close_socket(&ep->com, 1); } else { CTR2(KTR_IW_CXGBE, "%s:pcc4 %p", __func__, ep); close_socket(&ep->com, 0); } close_complete_upcall(ep, 0); __state_set(&ep->com, DEAD); release = 1; break; case ABORTING: CTR2(KTR_IW_CXGBE, "%s:pcc5 %p ABORTING", __func__, ep); break; case DEAD: default: CTR2(KTR_IW_CXGBE, "%s:pcc6 %p DEAD", __func__, ep); panic("%s:pcc6 %p DEAD", __func__, ep); break; } mutex_unlock(&ep->com.mutex); if (release) { CTR2(KTR_IW_CXGBE, "%s:pcc7 %p", __func__, ep); c4iw_put_ep(&ep->com); } CTR2(KTR_IW_CXGBE, "%s:pccE %p", __func__, ep); return; } static void init_sock(struct c4iw_ep_common *epc) { int rc; struct sockopt sopt; struct socket *so = epc->so; int on = 1; SOCK_LOCK(so); soupcall_set(so, SO_RCV, c4iw_so_upcall, epc); so->so_state |= SS_NBIO; SOCK_UNLOCK(so); sopt.sopt_dir = SOPT_SET; sopt.sopt_level = IPPROTO_TCP; sopt.sopt_name = TCP_NODELAY; sopt.sopt_val = (caddr_t)&on; sopt.sopt_valsize = sizeof on; sopt.sopt_td = NULL; rc = sosetopt(so, &sopt); if (rc) { log(LOG_ERR, "%s: can't set TCP_NODELAY on so %p (%d)\n", __func__, so, rc); } } static void process_data(struct c4iw_ep *ep) { struct sockaddr_in *local, *remote; CTR5(KTR_IW_CXGBE, "%s: so %p, ep %p, state %s, sbused %d", __func__, ep->com.so, ep, states[ep->com.state], sbused(&ep->com.so->so_rcv)); switch (state_read(&ep->com)) { case MPA_REQ_SENT: process_mpa_reply(ep); break; case MPA_REQ_WAIT: in_getsockaddr(ep->com.so, (struct sockaddr **)&local); in_getpeeraddr(ep->com.so, (struct sockaddr **)&remote); ep->com.local_addr = *local; ep->com.remote_addr = *remote; free(local, M_SONAME); free(remote, M_SONAME); process_mpa_request(ep); break; default: if (sbused(&ep->com.so->so_rcv)) log(LOG_ERR, "%s: Unexpected streaming data. ep %p, " "state %d, so %p, so_state 0x%x, sbused %u\n", __func__, ep, state_read(&ep->com), ep->com.so, ep->com.so->so_state, sbused(&ep->com.so->so_rcv)); break; } } static void process_connected(struct c4iw_ep *ep) { if ((ep->com.so->so_state & SS_ISCONNECTED) && !ep->com.so->so_error) send_mpa_req(ep); else { connect_reply_upcall(ep, -ep->com.so->so_error); close_socket(&ep->com, 0); state_set(&ep->com, DEAD); c4iw_put_ep(&ep->com); } } static struct socket * dequeue_socket(struct socket *head, struct sockaddr_in **remote, struct c4iw_ep *child_ep) { struct socket *so; ACCEPT_LOCK(); so = TAILQ_FIRST(&head->so_comp); if (!so) { ACCEPT_UNLOCK(); return (NULL); } TAILQ_REMOVE(&head->so_comp, so, so_list); head->so_qlen--; SOCK_LOCK(so); so->so_qstate &= ~SQ_COMP; so->so_head = NULL; soref(so); soupcall_set(so, SO_RCV, c4iw_so_upcall, child_ep); so->so_state |= SS_NBIO; SOCK_UNLOCK(so); ACCEPT_UNLOCK(); soaccept(so, (struct sockaddr **)remote); return (so); } static void process_newconn(struct c4iw_ep *parent_ep) { struct socket *child_so; struct c4iw_ep *child_ep; struct sockaddr_in *remote; child_ep = alloc_ep(sizeof(*child_ep), M_NOWAIT); if (!child_ep) { CTR3(KTR_IW_CXGBE, "%s: parent so %p, parent ep %p, ENOMEM", __func__, parent_ep->com.so, parent_ep); log(LOG_ERR, "%s: failed to allocate ep entry\n", __func__); return; } child_so = dequeue_socket(parent_ep->com.so, &remote, child_ep); if (!child_so) { CTR4(KTR_IW_CXGBE, "%s: parent so %p, parent ep %p, child ep %p, dequeue err", __func__, parent_ep->com.so, parent_ep, child_ep); log(LOG_ERR, "%s: failed to dequeue child socket\n", __func__); __free_ep(&child_ep->com); return; } CTR5(KTR_IW_CXGBE, "%s: parent so %p, parent ep %p, child so %p, child ep %p", __func__, parent_ep->com.so, parent_ep, child_so, child_ep); child_ep->com.local_addr = parent_ep->com.local_addr; child_ep->com.remote_addr = *remote; child_ep->com.dev = parent_ep->com.dev; child_ep->com.so = child_so; child_ep->com.cm_id = NULL; child_ep->com.thread = parent_ep->com.thread; child_ep->parent_ep = parent_ep; free(remote, M_SONAME); c4iw_get_ep(&parent_ep->com); child_ep->parent_ep = parent_ep; init_timer(&child_ep->timer); state_set(&child_ep->com, MPA_REQ_WAIT); START_EP_TIMER(child_ep); /* maybe the request has already been queued up on the socket... */ process_mpa_request(child_ep); } static int c4iw_so_upcall(struct socket *so, void *arg, int waitflag) { struct c4iw_ep *ep = arg; spin_lock(&req_lock); CTR6(KTR_IW_CXGBE, "%s: so %p, so_state 0x%x, ep %p, ep_state %s, tqe_prev %p", __func__, so, so->so_state, ep, states[ep->com.state], ep->com.entry.tqe_prev); if (ep && ep->com.so && !ep->com.entry.tqe_prev) { KASSERT(ep->com.so == so, ("%s: XXX review.", __func__)); c4iw_get_ep(&ep->com); TAILQ_INSERT_TAIL(&req_list, &ep->com, entry); queue_work(c4iw_taskq, &c4iw_task); } spin_unlock(&req_lock); return (SU_OK); } static void process_socket_event(struct c4iw_ep *ep) { int state = state_read(&ep->com); struct socket *so = ep->com.so; CTR6(KTR_IW_CXGBE, "process_socket_event: so %p, so_state 0x%x, " "so_err %d, sb_state 0x%x, ep %p, ep_state %s", so, so->so_state, so->so_error, so->so_rcv.sb_state, ep, states[state]); if (state == CONNECTING) { process_connected(ep); return; } if (state == LISTEN) { process_newconn(ep); return; } /* connection error */ if (so->so_error) { process_conn_error(ep); return; } /* peer close */ if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) && state < CLOSING) { process_peer_close(ep); return; } /* close complete */ if (so->so_state & SS_ISDISCONNECTED) { process_close_complete(ep); return; } /* rx data */ process_data(ep); } SYSCTL_NODE(_hw, OID_AUTO, iw_cxgbe, CTLFLAG_RD, 0, "iw_cxgbe driver parameters"); int db_delay_usecs = 1; SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, db_delay_usecs, CTLFLAG_RWTUN, &db_delay_usecs, 0, "Usecs to delay awaiting db fifo to drain"); static int dack_mode = 1; SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, dack_mode, CTLFLAG_RWTUN, &dack_mode, 0, "Delayed ack mode (default = 1)"); int c4iw_max_read_depth = 8; SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, c4iw_max_read_depth, CTLFLAG_RWTUN, &c4iw_max_read_depth, 0, "Per-connection max ORD/IRD (default = 8)"); static int enable_tcp_timestamps; SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, enable_tcp_timestamps, CTLFLAG_RWTUN, &enable_tcp_timestamps, 0, "Enable tcp timestamps (default = 0)"); static int enable_tcp_sack; SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, enable_tcp_sack, CTLFLAG_RWTUN, &enable_tcp_sack, 0, "Enable tcp SACK (default = 0)"); static int enable_tcp_window_scaling = 1; SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, enable_tcp_window_scaling, CTLFLAG_RWTUN, &enable_tcp_window_scaling, 0, "Enable tcp window scaling (default = 1)"); int c4iw_debug = 1; SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, c4iw_debug, CTLFLAG_RWTUN, &c4iw_debug, 0, "Enable debug logging (default = 0)"); static int peer2peer; SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, peer2peer, CTLFLAG_RWTUN, &peer2peer, 0, "Support peer2peer ULPs (default = 0)"); static int p2p_type = FW_RI_INIT_P2PTYPE_READ_REQ; SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, p2p_type, CTLFLAG_RWTUN, &p2p_type, 0, "RDMAP opcode to use for the RTR message: 1 = RDMA_READ 0 = RDMA_WRITE (default 1)"); static int ep_timeout_secs = 60; SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, ep_timeout_secs, CTLFLAG_RWTUN, &ep_timeout_secs, 0, "CM Endpoint operation timeout in seconds (default = 60)"); static int mpa_rev = 1; #ifdef IW_CM_MPAV2 SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, mpa_rev, CTLFLAG_RWTUN, &mpa_rev, 0, "MPA Revision, 0 supports amso1100, 1 is RFC0544 spec compliant, 2 is IETF MPA Peer Connect Draft compliant (default = 1)"); #else SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, mpa_rev, CTLFLAG_RWTUN, &mpa_rev, 0, "MPA Revision, 0 supports amso1100, 1 is RFC0544 spec compliant (default = 1)"); #endif static int markers_enabled; SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, markers_enabled, CTLFLAG_RWTUN, &markers_enabled, 0, "Enable MPA MARKERS (default(0) = disabled)"); static int crc_enabled = 1; SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, crc_enabled, CTLFLAG_RWTUN, &crc_enabled, 0, "Enable MPA CRC (default(1) = enabled)"); static int rcv_win = 256 * 1024; SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, rcv_win, CTLFLAG_RWTUN, &rcv_win, 0, "TCP receive window in bytes (default = 256KB)"); static int snd_win = 128 * 1024; SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, snd_win, CTLFLAG_RWTUN, &snd_win, 0, "TCP send window in bytes (default = 128KB)"); int db_fc_threshold = 2000; SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, db_fc_threshold, CTLFLAG_RWTUN, &db_fc_threshold, 0, "QP count/threshold that triggers automatic"); static void start_ep_timer(struct c4iw_ep *ep) { if (timer_pending(&ep->timer)) { CTR2(KTR_IW_CXGBE, "%s: ep %p, already started", __func__, ep); printk(KERN_ERR "%s timer already started! ep %p\n", __func__, ep); return; } clear_bit(TIMEOUT, &ep->com.flags); c4iw_get_ep(&ep->com); ep->timer.expires = jiffies + ep_timeout_secs * HZ; ep->timer.data = (unsigned long)ep; ep->timer.function = ep_timeout; add_timer(&ep->timer); } static void stop_ep_timer(struct c4iw_ep *ep) { del_timer_sync(&ep->timer); if (!test_and_set_bit(TIMEOUT, &ep->com.flags)) { c4iw_put_ep(&ep->com); } } static enum c4iw_ep_state state_read(struct c4iw_ep_common *epc) { enum c4iw_ep_state state; mutex_lock(&epc->mutex); state = epc->state; mutex_unlock(&epc->mutex); return (state); } static void __state_set(struct c4iw_ep_common *epc, enum c4iw_ep_state new) { epc->state = new; } static void state_set(struct c4iw_ep_common *epc, enum c4iw_ep_state new) { mutex_lock(&epc->mutex); __state_set(epc, new); mutex_unlock(&epc->mutex); } static void * alloc_ep(int size, gfp_t gfp) { struct c4iw_ep_common *epc; epc = kzalloc(size, gfp); if (epc == NULL) return (NULL); kref_init(&epc->kref); mutex_init(&epc->mutex); c4iw_init_wr_wait(&epc->wr_wait); return (epc); } void __free_ep(struct c4iw_ep_common *epc) { CTR2(KTR_IW_CXGBE, "%s:feB %p", __func__, epc); KASSERT(!epc->so, ("%s warning ep->so %p \n", __func__, epc->so)); KASSERT(!epc->entry.tqe_prev, ("%s epc %p still on req list!\n", __func__, epc)); free(epc, M_DEVBUF); CTR2(KTR_IW_CXGBE, "%s:feE %p", __func__, epc); } void _c4iw_free_ep(struct kref *kref) { struct c4iw_ep *ep; struct c4iw_ep_common *epc; ep = container_of(kref, struct c4iw_ep, com.kref); epc = &ep->com; KASSERT(!epc->so, ("%s ep->so %p", __func__, epc->so)); KASSERT(!epc->entry.tqe_prev, ("%s epc %p still on req list", __func__, epc)); kfree(ep); } static void release_ep_resources(struct c4iw_ep *ep) { CTR2(KTR_IW_CXGBE, "%s:rerB %p", __func__, ep); set_bit(RELEASE_RESOURCES, &ep->com.flags); c4iw_put_ep(&ep->com); CTR2(KTR_IW_CXGBE, "%s:rerE %p", __func__, ep); } static void send_mpa_req(struct c4iw_ep *ep) { int mpalen; struct mpa_message *mpa; struct mpa_v2_conn_params mpa_v2_params; struct mbuf *m; char mpa_rev_to_use = mpa_rev; int err; if (ep->retry_with_mpa_v1) mpa_rev_to_use = 1; mpalen = sizeof(*mpa) + ep->plen; if (mpa_rev_to_use == 2) mpalen += sizeof(struct mpa_v2_conn_params); mpa = malloc(mpalen, M_CXGBE, M_NOWAIT); if (mpa == NULL) { failed: connect_reply_upcall(ep, -ENOMEM); return; } memset(mpa, 0, mpalen); memcpy(mpa->key, MPA_KEY_REQ, sizeof(mpa->key)); mpa->flags = (crc_enabled ? MPA_CRC : 0) | (markers_enabled ? MPA_MARKERS : 0) | (mpa_rev_to_use == 2 ? MPA_ENHANCED_RDMA_CONN : 0); mpa->private_data_size = htons(ep->plen); mpa->revision = mpa_rev_to_use; if (mpa_rev_to_use == 1) { ep->tried_with_mpa_v1 = 1; ep->retry_with_mpa_v1 = 0; } if (mpa_rev_to_use == 2) { mpa->private_data_size += htons(sizeof(struct mpa_v2_conn_params)); mpa_v2_params.ird = htons((u16)ep->ird); mpa_v2_params.ord = htons((u16)ep->ord); if (peer2peer) { mpa_v2_params.ird |= htons(MPA_V2_PEER2PEER_MODEL); if (p2p_type == FW_RI_INIT_P2PTYPE_RDMA_WRITE) { mpa_v2_params.ord |= htons(MPA_V2_RDMA_WRITE_RTR); } else if (p2p_type == FW_RI_INIT_P2PTYPE_READ_REQ) { mpa_v2_params.ord |= htons(MPA_V2_RDMA_READ_RTR); } } memcpy(mpa->private_data, &mpa_v2_params, sizeof(struct mpa_v2_conn_params)); if (ep->plen) { memcpy(mpa->private_data + sizeof(struct mpa_v2_conn_params), ep->mpa_pkt + sizeof(*mpa), ep->plen); } } else { if (ep->plen) memcpy(mpa->private_data, ep->mpa_pkt + sizeof(*mpa), ep->plen); CTR2(KTR_IW_CXGBE, "%s:smr7 %p", __func__, ep); } m = m_getm(NULL, mpalen, M_NOWAIT, MT_DATA); if (m == NULL) { free(mpa, M_CXGBE); goto failed; } m_copyback(m, 0, mpalen, (void *)mpa); free(mpa, M_CXGBE); err = sosend(ep->com.so, NULL, NULL, m, NULL, MSG_DONTWAIT, ep->com.thread); if (err) goto failed; START_EP_TIMER(ep); state_set(&ep->com, MPA_REQ_SENT); ep->mpa_attr.initiator = 1; } static int send_mpa_reject(struct c4iw_ep *ep, const void *pdata, u8 plen) { int mpalen ; struct mpa_message *mpa; struct mpa_v2_conn_params mpa_v2_params; struct mbuf *m; int err; CTR4(KTR_IW_CXGBE, "%s:smrejB %p %u %d", __func__, ep, ep->hwtid, ep->plen); mpalen = sizeof(*mpa) + plen; if (ep->mpa_attr.version == 2 && ep->mpa_attr.enhanced_rdma_conn) { mpalen += sizeof(struct mpa_v2_conn_params); CTR4(KTR_IW_CXGBE, "%s:smrej1 %p %u %d", __func__, ep, ep->mpa_attr.version, mpalen); } mpa = malloc(mpalen, M_CXGBE, M_NOWAIT); if (mpa == NULL) return (-ENOMEM); memset(mpa, 0, mpalen); memcpy(mpa->key, MPA_KEY_REP, sizeof(mpa->key)); mpa->flags = MPA_REJECT; mpa->revision = mpa_rev; mpa->private_data_size = htons(plen); if (ep->mpa_attr.version == 2 && ep->mpa_attr.enhanced_rdma_conn) { mpa->flags |= MPA_ENHANCED_RDMA_CONN; mpa->private_data_size += htons(sizeof(struct mpa_v2_conn_params)); mpa_v2_params.ird = htons(((u16)ep->ird) | (peer2peer ? MPA_V2_PEER2PEER_MODEL : 0)); mpa_v2_params.ord = htons(((u16)ep->ord) | (peer2peer ? (p2p_type == FW_RI_INIT_P2PTYPE_RDMA_WRITE ? MPA_V2_RDMA_WRITE_RTR : p2p_type == FW_RI_INIT_P2PTYPE_READ_REQ ? MPA_V2_RDMA_READ_RTR : 0) : 0)); memcpy(mpa->private_data, &mpa_v2_params, sizeof(struct mpa_v2_conn_params)); if (ep->plen) memcpy(mpa->private_data + sizeof(struct mpa_v2_conn_params), pdata, plen); CTR5(KTR_IW_CXGBE, "%s:smrej3 %p %d %d %d", __func__, ep, mpa_v2_params.ird, mpa_v2_params.ord, ep->plen); } else if (plen) memcpy(mpa->private_data, pdata, plen); m = m_getm(NULL, mpalen, M_NOWAIT, MT_DATA); if (m == NULL) { free(mpa, M_CXGBE); return (-ENOMEM); } m_copyback(m, 0, mpalen, (void *)mpa); free(mpa, M_CXGBE); err = -sosend(ep->com.so, NULL, NULL, m, NULL, MSG_DONTWAIT, ep->com.thread); if (!err) ep->snd_seq += mpalen; CTR4(KTR_IW_CXGBE, "%s:smrejE %p %u %d", __func__, ep, ep->hwtid, err); return err; } static int send_mpa_reply(struct c4iw_ep *ep, const void *pdata, u8 plen) { int mpalen; struct mpa_message *mpa; struct mbuf *m; struct mpa_v2_conn_params mpa_v2_params; int err; CTR2(KTR_IW_CXGBE, "%s:smrepB %p", __func__, ep); mpalen = sizeof(*mpa) + plen; if (ep->mpa_attr.version == 2 && ep->mpa_attr.enhanced_rdma_conn) { CTR3(KTR_IW_CXGBE, "%s:smrep1 %p %d", __func__, ep, ep->mpa_attr.version); mpalen += sizeof(struct mpa_v2_conn_params); } mpa = malloc(mpalen, M_CXGBE, M_NOWAIT); if (mpa == NULL) return (-ENOMEM); memset(mpa, 0, sizeof(*mpa)); memcpy(mpa->key, MPA_KEY_REP, sizeof(mpa->key)); mpa->flags = (ep->mpa_attr.crc_enabled ? MPA_CRC : 0) | (markers_enabled ? MPA_MARKERS : 0); mpa->revision = ep->mpa_attr.version; mpa->private_data_size = htons(plen); if (ep->mpa_attr.version == 2 && ep->mpa_attr.enhanced_rdma_conn) { mpa->flags |= MPA_ENHANCED_RDMA_CONN; mpa->private_data_size += htons(sizeof(struct mpa_v2_conn_params)); mpa_v2_params.ird = htons((u16)ep->ird); mpa_v2_params.ord = htons((u16)ep->ord); CTR5(KTR_IW_CXGBE, "%s:smrep3 %p %d %d %d", __func__, ep, ep->mpa_attr.version, mpa_v2_params.ird, mpa_v2_params.ord); if (peer2peer && (ep->mpa_attr.p2p_type != FW_RI_INIT_P2PTYPE_DISABLED)) { mpa_v2_params.ird |= htons(MPA_V2_PEER2PEER_MODEL); if (p2p_type == FW_RI_INIT_P2PTYPE_RDMA_WRITE) { mpa_v2_params.ord |= htons(MPA_V2_RDMA_WRITE_RTR); CTR5(KTR_IW_CXGBE, "%s:smrep4 %p %d %d %d", __func__, ep, p2p_type, mpa_v2_params.ird, mpa_v2_params.ord); } else if (p2p_type == FW_RI_INIT_P2PTYPE_READ_REQ) { mpa_v2_params.ord |= htons(MPA_V2_RDMA_READ_RTR); CTR5(KTR_IW_CXGBE, "%s:smrep5 %p %d %d %d", __func__, ep, p2p_type, mpa_v2_params.ird, mpa_v2_params.ord); } } memcpy(mpa->private_data, &mpa_v2_params, sizeof(struct mpa_v2_conn_params)); if (ep->plen) memcpy(mpa->private_data + sizeof(struct mpa_v2_conn_params), pdata, plen); } else if (plen) memcpy(mpa->private_data, pdata, plen); m = m_getm(NULL, mpalen, M_NOWAIT, MT_DATA); if (m == NULL) { free(mpa, M_CXGBE); return (-ENOMEM); } m_copyback(m, 0, mpalen, (void *)mpa); free(mpa, M_CXGBE); state_set(&ep->com, MPA_REP_SENT); ep->snd_seq += mpalen; err = -sosend(ep->com.so, NULL, NULL, m, NULL, MSG_DONTWAIT, ep->com.thread); CTR3(KTR_IW_CXGBE, "%s:smrepE %p %d", __func__, ep, err); return err; } static void close_complete_upcall(struct c4iw_ep *ep, int status) { struct iw_cm_event event; CTR2(KTR_IW_CXGBE, "%s:ccuB %p", __func__, ep); memset(&event, 0, sizeof(event)); event.event = IW_CM_EVENT_CLOSE; event.status = status; if (ep->com.cm_id) { CTR2(KTR_IW_CXGBE, "%s:ccu1 %1", __func__, ep); ep->com.cm_id->event_handler(ep->com.cm_id, &event); ep->com.cm_id->rem_ref(ep->com.cm_id); ep->com.cm_id = NULL; ep->com.qp = NULL; set_bit(CLOSE_UPCALL, &ep->com.history); } CTR2(KTR_IW_CXGBE, "%s:ccuE %p", __func__, ep); } static int abort_connection(struct c4iw_ep *ep) { int err; CTR2(KTR_IW_CXGBE, "%s:abB %p", __func__, ep); - close_complete_upcall(ep, -ECONNRESET); state_set(&ep->com, ABORTING); abort_socket(ep); err = close_socket(&ep->com, 0); set_bit(ABORT_CONN, &ep->com.history); CTR2(KTR_IW_CXGBE, "%s:abE %p", __func__, ep); return err; } static void peer_close_upcall(struct c4iw_ep *ep) { struct iw_cm_event event; CTR2(KTR_IW_CXGBE, "%s:pcuB %p", __func__, ep); memset(&event, 0, sizeof(event)); event.event = IW_CM_EVENT_DISCONNECT; if (ep->com.cm_id) { CTR2(KTR_IW_CXGBE, "%s:pcu1 %p", __func__, ep); ep->com.cm_id->event_handler(ep->com.cm_id, &event); set_bit(DISCONN_UPCALL, &ep->com.history); } CTR2(KTR_IW_CXGBE, "%s:pcuE %p", __func__, ep); } static void peer_abort_upcall(struct c4iw_ep *ep) { struct iw_cm_event event; CTR2(KTR_IW_CXGBE, "%s:pauB %p", __func__, ep); memset(&event, 0, sizeof(event)); event.event = IW_CM_EVENT_CLOSE; event.status = -ECONNRESET; if (ep->com.cm_id) { CTR2(KTR_IW_CXGBE, "%s:pau1 %p", __func__, ep); ep->com.cm_id->event_handler(ep->com.cm_id, &event); ep->com.cm_id->rem_ref(ep->com.cm_id); ep->com.cm_id = NULL; ep->com.qp = NULL; set_bit(ABORT_UPCALL, &ep->com.history); } CTR2(KTR_IW_CXGBE, "%s:pauE %p", __func__, ep); } static void connect_reply_upcall(struct c4iw_ep *ep, int status) { struct iw_cm_event event; CTR3(KTR_IW_CXGBE, "%s:cruB %p", __func__, ep, status); memset(&event, 0, sizeof(event)); event.event = IW_CM_EVENT_CONNECT_REPLY; event.status = (status ==-ECONNABORTED)?-ECONNRESET: status; event.local_addr = ep->com.local_addr; event.remote_addr = ep->com.remote_addr; if ((status == 0) || (status == -ECONNREFUSED)) { if (!ep->tried_with_mpa_v1) { CTR2(KTR_IW_CXGBE, "%s:cru1 %p", __func__, ep); /* this means MPA_v2 is used */ event.private_data_len = ep->plen - sizeof(struct mpa_v2_conn_params); event.private_data = ep->mpa_pkt + sizeof(struct mpa_message) + sizeof(struct mpa_v2_conn_params); } else { CTR2(KTR_IW_CXGBE, "%s:cru2 %p", __func__, ep); /* this means MPA_v1 is used */ event.private_data_len = ep->plen; event.private_data = ep->mpa_pkt + sizeof(struct mpa_message); } } if (ep->com.cm_id) { CTR2(KTR_IW_CXGBE, "%s:cru3 %p", __func__, ep); set_bit(CONN_RPL_UPCALL, &ep->com.history); ep->com.cm_id->event_handler(ep->com.cm_id, &event); } if(status == -ECONNABORTED) { CTR3(KTR_IW_CXGBE, "%s:cruE %p %d", __func__, ep, status); return; } if (status < 0) { CTR3(KTR_IW_CXGBE, "%s:cru4 %p %d", __func__, ep, status); ep->com.cm_id->rem_ref(ep->com.cm_id); ep->com.cm_id = NULL; ep->com.qp = NULL; } CTR2(KTR_IW_CXGBE, "%s:cruE %p", __func__, ep); } -static void connect_request_upcall(struct c4iw_ep *ep) +static int connect_request_upcall(struct c4iw_ep *ep) { struct iw_cm_event event; + int ret; CTR3(KTR_IW_CXGBE, "%s: ep %p, mpa_v1 %d", __func__, ep, ep->tried_with_mpa_v1); memset(&event, 0, sizeof(event)); event.event = IW_CM_EVENT_CONNECT_REQUEST; event.local_addr = ep->com.local_addr; event.remote_addr = ep->com.remote_addr; event.provider_data = ep; event.so = ep->com.so; if (!ep->tried_with_mpa_v1) { /* this means MPA_v2 is used */ #ifdef IW_CM_MPAV2 event.ord = ep->ord; event.ird = ep->ird; #endif event.private_data_len = ep->plen - sizeof(struct mpa_v2_conn_params); event.private_data = ep->mpa_pkt + sizeof(struct mpa_message) + sizeof(struct mpa_v2_conn_params); } else { /* this means MPA_v1 is used. Send max supported */ #ifdef IW_CM_MPAV2 event.ord = c4iw_max_read_depth; event.ird = c4iw_max_read_depth; #endif event.private_data_len = ep->plen; event.private_data = ep->mpa_pkt + sizeof(struct mpa_message); } c4iw_get_ep(&ep->com); - ep->parent_ep->com.cm_id->event_handler(ep->parent_ep->com.cm_id, + ret = ep->parent_ep->com.cm_id->event_handler(ep->parent_ep->com.cm_id, &event); + if(ret) + c4iw_put_ep(&ep->com); + set_bit(CONNREQ_UPCALL, &ep->com.history); c4iw_put_ep(&ep->parent_ep->com); + return ret; } static void established_upcall(struct c4iw_ep *ep) { struct iw_cm_event event; CTR2(KTR_IW_CXGBE, "%s:euB %p", __func__, ep); memset(&event, 0, sizeof(event)); event.event = IW_CM_EVENT_ESTABLISHED; #ifdef IW_CM_MPAV2 event.ird = ep->ird; event.ord = ep->ord; #endif if (ep->com.cm_id) { CTR2(KTR_IW_CXGBE, "%s:eu1 %p", __func__, ep); ep->com.cm_id->event_handler(ep->com.cm_id, &event); set_bit(ESTAB_UPCALL, &ep->com.history); } CTR2(KTR_IW_CXGBE, "%s:euE %p", __func__, ep); } static void process_mpa_reply(struct c4iw_ep *ep) { struct mpa_message *mpa; struct mpa_v2_conn_params *mpa_v2_params; u16 plen; u16 resp_ird, resp_ord; u8 rtr_mismatch = 0, insuff_ird = 0; struct c4iw_qp_attributes attrs; enum c4iw_qp_attr_mask mask; int err; struct mbuf *top, *m; int flags = MSG_DONTWAIT; struct uio uio; CTR2(KTR_IW_CXGBE, "%s:pmrB %p", __func__, ep); /* * Stop mpa timer. If it expired, then the state has * changed and we bail since ep_timeout already aborted * the connection. */ STOP_EP_TIMER(ep); if (state_read(&ep->com) != MPA_REQ_SENT) return; uio.uio_resid = 1000000; uio.uio_td = ep->com.thread; err = soreceive(ep->com.so, NULL, &uio, &top, NULL, &flags); if (err) { if (err == EWOULDBLOCK) { CTR2(KTR_IW_CXGBE, "%s:pmr1 %p", __func__, ep); START_EP_TIMER(ep); return; } err = -err; CTR2(KTR_IW_CXGBE, "%s:pmr2 %p", __func__, ep); goto err; } if (ep->com.so->so_rcv.sb_mb) { CTR2(KTR_IW_CXGBE, "%s:pmr3 %p", __func__, ep); printf("%s data after soreceive called! so %p sb_mb %p top %p\n", __func__, ep->com.so, ep->com.so->so_rcv.sb_mb, top); } m = top; do { CTR2(KTR_IW_CXGBE, "%s:pmr4 %p", __func__, ep); /* * If we get more than the supported amount of private data * then we must fail this connection. */ if (ep->mpa_pkt_len + m->m_len > sizeof(ep->mpa_pkt)) { CTR3(KTR_IW_CXGBE, "%s:pmr5 %p %d", __func__, ep, ep->mpa_pkt_len + m->m_len); err = (-EINVAL); goto err; } /* * copy the new data into our accumulation buffer. */ m_copydata(m, 0, m->m_len, &(ep->mpa_pkt[ep->mpa_pkt_len])); ep->mpa_pkt_len += m->m_len; if (!m->m_next) m = m->m_nextpkt; else m = m->m_next; } while (m); m_freem(top); /* * if we don't even have the mpa message, then bail. */ if (ep->mpa_pkt_len < sizeof(*mpa)) return; mpa = (struct mpa_message *) ep->mpa_pkt; /* Validate MPA header. */ if (mpa->revision > mpa_rev) { CTR4(KTR_IW_CXGBE, "%s:pmr6 %p %d %d", __func__, ep, mpa->revision, mpa_rev); printk(KERN_ERR MOD "%s MPA version mismatch. Local = %d, " " Received = %d\n", __func__, mpa_rev, mpa->revision); err = -EPROTO; goto err; } if (memcmp(mpa->key, MPA_KEY_REP, sizeof(mpa->key))) { CTR2(KTR_IW_CXGBE, "%s:pmr7 %p", __func__, ep); err = -EPROTO; goto err; } plen = ntohs(mpa->private_data_size); /* * Fail if there's too much private data. */ if (plen > MPA_MAX_PRIVATE_DATA) { CTR2(KTR_IW_CXGBE, "%s:pmr8 %p", __func__, ep); err = -EPROTO; goto err; } /* * If plen does not account for pkt size */ if (ep->mpa_pkt_len > (sizeof(*mpa) + plen)) { CTR2(KTR_IW_CXGBE, "%s:pmr9 %p", __func__, ep); err = -EPROTO; goto err; } ep->plen = (u8) plen; /* * If we don't have all the pdata yet, then bail. * We'll continue process when more data arrives. */ if (ep->mpa_pkt_len < (sizeof(*mpa) + plen)) { CTR2(KTR_IW_CXGBE, "%s:pmra %p", __func__, ep); return; } if (mpa->flags & MPA_REJECT) { CTR2(KTR_IW_CXGBE, "%s:pmrb %p", __func__, ep); err = -ECONNREFUSED; goto err; } /* * If we get here we have accumulated the entire mpa * start reply message including private data. And * the MPA header is valid. */ state_set(&ep->com, FPDU_MODE); ep->mpa_attr.crc_enabled = (mpa->flags & MPA_CRC) | crc_enabled ? 1 : 0; ep->mpa_attr.recv_marker_enabled = markers_enabled; ep->mpa_attr.xmit_marker_enabled = mpa->flags & MPA_MARKERS ? 1 : 0; ep->mpa_attr.version = mpa->revision; ep->mpa_attr.p2p_type = FW_RI_INIT_P2PTYPE_DISABLED; if (mpa->revision == 2) { CTR2(KTR_IW_CXGBE, "%s:pmrc %p", __func__, ep); ep->mpa_attr.enhanced_rdma_conn = mpa->flags & MPA_ENHANCED_RDMA_CONN ? 1 : 0; if (ep->mpa_attr.enhanced_rdma_conn) { CTR2(KTR_IW_CXGBE, "%s:pmrd %p", __func__, ep); mpa_v2_params = (struct mpa_v2_conn_params *) (ep->mpa_pkt + sizeof(*mpa)); resp_ird = ntohs(mpa_v2_params->ird) & MPA_V2_IRD_ORD_MASK; resp_ord = ntohs(mpa_v2_params->ord) & MPA_V2_IRD_ORD_MASK; /* * This is a double-check. Ideally, below checks are * not required since ird/ord stuff has been taken * care of in c4iw_accept_cr */ if ((ep->ird < resp_ord) || (ep->ord > resp_ird)) { CTR2(KTR_IW_CXGBE, "%s:pmre %p", __func__, ep); err = -ENOMEM; ep->ird = resp_ord; ep->ord = resp_ird; insuff_ird = 1; } if (ntohs(mpa_v2_params->ird) & MPA_V2_PEER2PEER_MODEL) { CTR2(KTR_IW_CXGBE, "%s:pmrf %p", __func__, ep); if (ntohs(mpa_v2_params->ord) & MPA_V2_RDMA_WRITE_RTR) { CTR2(KTR_IW_CXGBE, "%s:pmrg %p", __func__, ep); ep->mpa_attr.p2p_type = FW_RI_INIT_P2PTYPE_RDMA_WRITE; } else if (ntohs(mpa_v2_params->ord) & MPA_V2_RDMA_READ_RTR) { CTR2(KTR_IW_CXGBE, "%s:pmrh %p", __func__, ep); ep->mpa_attr.p2p_type = FW_RI_INIT_P2PTYPE_READ_REQ; } } } } else { CTR2(KTR_IW_CXGBE, "%s:pmri %p", __func__, ep); if (mpa->revision == 1) { CTR2(KTR_IW_CXGBE, "%s:pmrj %p", __func__, ep); if (peer2peer) { CTR2(KTR_IW_CXGBE, "%s:pmrk %p", __func__, ep); ep->mpa_attr.p2p_type = p2p_type; } } } if (set_tcpinfo(ep)) { CTR2(KTR_IW_CXGBE, "%s:pmrl %p", __func__, ep); printf("%s set_tcpinfo error\n", __func__); goto err; } CTR6(KTR_IW_CXGBE, "%s - crc_enabled = %d, recv_marker_enabled = %d, " "xmit_marker_enabled = %d, version = %d p2p_type = %d", __func__, ep->mpa_attr.crc_enabled, ep->mpa_attr.recv_marker_enabled, ep->mpa_attr.xmit_marker_enabled, ep->mpa_attr.version, ep->mpa_attr.p2p_type); /* * If responder's RTR does not match with that of initiator, assign * FW_RI_INIT_P2PTYPE_DISABLED in mpa attributes so that RTR is not * generated when moving QP to RTS state. * A TERM message will be sent after QP has moved to RTS state */ if ((ep->mpa_attr.version == 2) && peer2peer && (ep->mpa_attr.p2p_type != p2p_type)) { CTR2(KTR_IW_CXGBE, "%s:pmrm %p", __func__, ep); ep->mpa_attr.p2p_type = FW_RI_INIT_P2PTYPE_DISABLED; rtr_mismatch = 1; } //ep->ofld_txq = TOEPCB(ep->com.so)->ofld_txq; attrs.mpa_attr = ep->mpa_attr; attrs.max_ird = ep->ird; attrs.max_ord = ep->ord; attrs.llp_stream_handle = ep; attrs.next_state = C4IW_QP_STATE_RTS; mask = C4IW_QP_ATTR_NEXT_STATE | C4IW_QP_ATTR_LLP_STREAM_HANDLE | C4IW_QP_ATTR_MPA_ATTR | C4IW_QP_ATTR_MAX_IRD | C4IW_QP_ATTR_MAX_ORD; /* bind QP and TID with INIT_WR */ err = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, mask, &attrs, 1); if (err) { CTR2(KTR_IW_CXGBE, "%s:pmrn %p", __func__, ep); goto err; } /* * If responder's RTR requirement did not match with what initiator * supports, generate TERM message */ if (rtr_mismatch) { CTR2(KTR_IW_CXGBE, "%s:pmro %p", __func__, ep); printk(KERN_ERR "%s: RTR mismatch, sending TERM\n", __func__); attrs.layer_etype = LAYER_MPA | DDP_LLP; attrs.ecode = MPA_NOMATCH_RTR; attrs.next_state = C4IW_QP_STATE_TERMINATE; err = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 0); err = -ENOMEM; goto out; } /* * Generate TERM if initiator IRD is not sufficient for responder * provided ORD. Currently, we do the same behaviour even when * responder provided IRD is also not sufficient as regards to * initiator ORD. */ if (insuff_ird) { CTR2(KTR_IW_CXGBE, "%s:pmrp %p", __func__, ep); printk(KERN_ERR "%s: Insufficient IRD, sending TERM\n", __func__); attrs.layer_etype = LAYER_MPA | DDP_LLP; attrs.ecode = MPA_INSUFF_IRD; attrs.next_state = C4IW_QP_STATE_TERMINATE; err = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 0); err = -ENOMEM; goto out; } goto out; err: state_set(&ep->com, ABORTING); abort_connection(ep); out: connect_reply_upcall(ep, err); CTR2(KTR_IW_CXGBE, "%s:pmrE %p", __func__, ep); return; } static void process_mpa_request(struct c4iw_ep *ep) { struct mpa_message *mpa; u16 plen; int flags = MSG_DONTWAIT; int rc; struct iovec iov; struct uio uio; enum c4iw_ep_state state = state_read(&ep->com); CTR3(KTR_IW_CXGBE, "%s: ep %p, state %s", __func__, ep, states[state]); if (state != MPA_REQ_WAIT) return; iov.iov_base = &ep->mpa_pkt[ep->mpa_pkt_len]; iov.iov_len = sizeof(ep->mpa_pkt) - ep->mpa_pkt_len; uio.uio_iov = &iov; uio.uio_iovcnt = 1; uio.uio_offset = 0; uio.uio_resid = sizeof(ep->mpa_pkt) - ep->mpa_pkt_len; uio.uio_segflg = UIO_SYSSPACE; uio.uio_rw = UIO_READ; uio.uio_td = NULL; /* uio.uio_td = ep->com.thread; */ rc = soreceive(ep->com.so, NULL, &uio, NULL, NULL, &flags); if (rc == EAGAIN) return; else if (rc) { abort: STOP_EP_TIMER(ep); abort_connection(ep); return; } KASSERT(uio.uio_offset > 0, ("%s: sorecieve on so %p read no data", __func__, ep->com.so)); ep->mpa_pkt_len += uio.uio_offset; /* * If we get more than the supported amount of private data then we must * fail this connection. XXX: check so_rcv->sb_cc, or peek with another * soreceive, or increase the size of mpa_pkt by 1 and abort if the last * byte is filled by the soreceive above. */ /* Don't even have the MPA message. Wait for more data to arrive. */ if (ep->mpa_pkt_len < sizeof(*mpa)) return; mpa = (struct mpa_message *) ep->mpa_pkt; /* * Validate MPA Header. */ if (mpa->revision > mpa_rev) { log(LOG_ERR, "%s: MPA version mismatch. Local = %d," " Received = %d\n", __func__, mpa_rev, mpa->revision); goto abort; } if (memcmp(mpa->key, MPA_KEY_REQ, sizeof(mpa->key))) goto abort; /* * Fail if there's too much private data. */ plen = ntohs(mpa->private_data_size); if (plen > MPA_MAX_PRIVATE_DATA) goto abort; /* * If plen does not account for pkt size */ if (ep->mpa_pkt_len > (sizeof(*mpa) + plen)) goto abort; ep->plen = (u8) plen; /* * If we don't have all the pdata yet, then bail. */ if (ep->mpa_pkt_len < (sizeof(*mpa) + plen)) return; /* * If we get here we have accumulated the entire mpa * start reply message including private data. */ ep->mpa_attr.initiator = 0; ep->mpa_attr.crc_enabled = (mpa->flags & MPA_CRC) | crc_enabled ? 1 : 0; ep->mpa_attr.recv_marker_enabled = markers_enabled; ep->mpa_attr.xmit_marker_enabled = mpa->flags & MPA_MARKERS ? 1 : 0; ep->mpa_attr.version = mpa->revision; if (mpa->revision == 1) ep->tried_with_mpa_v1 = 1; ep->mpa_attr.p2p_type = FW_RI_INIT_P2PTYPE_DISABLED; if (mpa->revision == 2) { ep->mpa_attr.enhanced_rdma_conn = mpa->flags & MPA_ENHANCED_RDMA_CONN ? 1 : 0; if (ep->mpa_attr.enhanced_rdma_conn) { struct mpa_v2_conn_params *mpa_v2_params; u16 ird, ord; mpa_v2_params = (void *)&ep->mpa_pkt[sizeof(*mpa)]; ird = ntohs(mpa_v2_params->ird); ord = ntohs(mpa_v2_params->ord); ep->ird = ird & MPA_V2_IRD_ORD_MASK; ep->ord = ord & MPA_V2_IRD_ORD_MASK; if (ird & MPA_V2_PEER2PEER_MODEL && peer2peer) { if (ord & MPA_V2_RDMA_WRITE_RTR) { ep->mpa_attr.p2p_type = FW_RI_INIT_P2PTYPE_RDMA_WRITE; } else if (ord & MPA_V2_RDMA_READ_RTR) { ep->mpa_attr.p2p_type = FW_RI_INIT_P2PTYPE_READ_REQ; } } } } else if (mpa->revision == 1 && peer2peer) ep->mpa_attr.p2p_type = p2p_type; if (set_tcpinfo(ep)) goto abort; CTR5(KTR_IW_CXGBE, "%s: crc_enabled = %d, recv_marker_enabled = %d, " "xmit_marker_enabled = %d, version = %d", __func__, ep->mpa_attr.crc_enabled, ep->mpa_attr.recv_marker_enabled, ep->mpa_attr.xmit_marker_enabled, ep->mpa_attr.version); state_set(&ep->com, MPA_REQ_RCVD); STOP_EP_TIMER(ep); /* drive upcall */ mutex_lock(&ep->parent_ep->com.mutex); - if (ep->parent_ep->com.state != DEAD) - connect_request_upcall(ep); - else + if (ep->parent_ep->com.state != DEAD) { + if(connect_request_upcall(ep)) { + abort_connection(ep); + } + }else abort_connection(ep); mutex_unlock(&ep->parent_ep->com.mutex); } /* * Upcall from the adapter indicating data has been transmitted. * For us its just the single MPA request or reply. We can now free * the skb holding the mpa message. */ int c4iw_reject_cr(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len) { int err; struct c4iw_ep *ep = to_ep(cm_id); CTR2(KTR_IW_CXGBE, "%s:crcB %p", __func__, ep); if (state_read(&ep->com) == DEAD) { CTR2(KTR_IW_CXGBE, "%s:crc1 %p", __func__, ep); c4iw_put_ep(&ep->com); return -ECONNRESET; } set_bit(ULP_REJECT, &ep->com.history); BUG_ON(state_read(&ep->com) != MPA_REQ_RCVD); if (mpa_rev == 0) { CTR2(KTR_IW_CXGBE, "%s:crc2 %p", __func__, ep); abort_connection(ep); } else { CTR2(KTR_IW_CXGBE, "%s:crc3 %p", __func__, ep); err = send_mpa_reject(ep, pdata, pdata_len); err = soshutdown(ep->com.so, 3); } c4iw_put_ep(&ep->com); CTR2(KTR_IW_CXGBE, "%s:crc4 %p", __func__, ep); return 0; } int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) { int err; struct c4iw_qp_attributes attrs; enum c4iw_qp_attr_mask mask; struct c4iw_ep *ep = to_ep(cm_id); struct c4iw_dev *h = to_c4iw_dev(cm_id->device); struct c4iw_qp *qp = get_qhp(h, conn_param->qpn); CTR2(KTR_IW_CXGBE, "%s:cacB %p", __func__, ep); if (state_read(&ep->com) == DEAD) { CTR2(KTR_IW_CXGBE, "%s:cac1 %p", __func__, ep); err = -ECONNRESET; goto err; } BUG_ON(state_read(&ep->com) != MPA_REQ_RCVD); BUG_ON(!qp); set_bit(ULP_ACCEPT, &ep->com.history); if ((conn_param->ord > c4iw_max_read_depth) || (conn_param->ird > c4iw_max_read_depth)) { CTR2(KTR_IW_CXGBE, "%s:cac2 %p", __func__, ep); abort_connection(ep); err = -EINVAL; goto err; } if (ep->mpa_attr.version == 2 && ep->mpa_attr.enhanced_rdma_conn) { CTR2(KTR_IW_CXGBE, "%s:cac3 %p", __func__, ep); if (conn_param->ord > ep->ird) { CTR2(KTR_IW_CXGBE, "%s:cac4 %p", __func__, ep); ep->ird = conn_param->ird; ep->ord = conn_param->ord; send_mpa_reject(ep, conn_param->private_data, conn_param->private_data_len); abort_connection(ep); err = -ENOMEM; goto err; } if (conn_param->ird > ep->ord) { CTR2(KTR_IW_CXGBE, "%s:cac5 %p", __func__, ep); if (!ep->ord) { CTR2(KTR_IW_CXGBE, "%s:cac6 %p", __func__, ep); conn_param->ird = 1; } else { CTR2(KTR_IW_CXGBE, "%s:cac7 %p", __func__, ep); abort_connection(ep); err = -ENOMEM; goto err; } } } ep->ird = conn_param->ird; ep->ord = conn_param->ord; if (ep->mpa_attr.version != 2) { CTR2(KTR_IW_CXGBE, "%s:cac8 %p", __func__, ep); if (peer2peer && ep->ird == 0) { CTR2(KTR_IW_CXGBE, "%s:cac9 %p", __func__, ep); ep->ird = 1; } } cm_id->add_ref(cm_id); ep->com.cm_id = cm_id; ep->com.qp = qp; //ep->ofld_txq = TOEPCB(ep->com.so)->ofld_txq; /* bind QP to EP and move to RTS */ attrs.mpa_attr = ep->mpa_attr; attrs.max_ird = ep->ird; attrs.max_ord = ep->ord; attrs.llp_stream_handle = ep; attrs.next_state = C4IW_QP_STATE_RTS; /* bind QP and TID with INIT_WR */ mask = C4IW_QP_ATTR_NEXT_STATE | C4IW_QP_ATTR_LLP_STREAM_HANDLE | C4IW_QP_ATTR_MPA_ATTR | C4IW_QP_ATTR_MAX_IRD | C4IW_QP_ATTR_MAX_ORD; err = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, mask, &attrs, 1); if (err) { CTR2(KTR_IW_CXGBE, "%s:caca %p", __func__, ep); goto err1; } err = send_mpa_reply(ep, conn_param->private_data, conn_param->private_data_len); if (err) { CTR2(KTR_IW_CXGBE, "%s:caca %p", __func__, ep); goto err1; } state_set(&ep->com, FPDU_MODE); established_upcall(ep); c4iw_put_ep(&ep->com); CTR2(KTR_IW_CXGBE, "%s:cacE %p", __func__, ep); return 0; err1: ep->com.cm_id = NULL; ep->com.qp = NULL; cm_id->rem_ref(cm_id); err: c4iw_put_ep(&ep->com); CTR2(KTR_IW_CXGBE, "%s:cacE err %p", __func__, ep); return err; } int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) { int err = 0; struct c4iw_dev *dev = to_c4iw_dev(cm_id->device); struct c4iw_ep *ep = NULL; struct rtentry *rt; struct toedev *tdev; CTR2(KTR_IW_CXGBE, "%s:ccB %p", __func__, cm_id); if ((conn_param->ord > c4iw_max_read_depth) || (conn_param->ird > c4iw_max_read_depth)) { CTR2(KTR_IW_CXGBE, "%s:cc1 %p", __func__, cm_id); err = -EINVAL; goto out; } ep = alloc_ep(sizeof(*ep), M_NOWAIT); if (!ep) { CTR2(KTR_IW_CXGBE, "%s:cc2 %p", __func__, cm_id); printk(KERN_ERR MOD "%s - cannot alloc ep.\n", __func__); err = -ENOMEM; goto out; } init_timer(&ep->timer); ep->plen = conn_param->private_data_len; if (ep->plen) { CTR2(KTR_IW_CXGBE, "%s:cc3 %p", __func__, ep); memcpy(ep->mpa_pkt + sizeof(struct mpa_message), conn_param->private_data, ep->plen); } ep->ird = conn_param->ird; ep->ord = conn_param->ord; if (peer2peer && ep->ord == 0) { CTR2(KTR_IW_CXGBE, "%s:cc4 %p", __func__, ep); ep->ord = 1; } cm_id->add_ref(cm_id); ep->com.dev = dev; ep->com.cm_id = cm_id; ep->com.qp = get_qhp(dev, conn_param->qpn); if (!ep->com.qp) { CTR2(KTR_IW_CXGBE, "%s:cc5 %p", __func__, ep); err = -EINVAL; goto fail2; } ep->com.thread = curthread; ep->com.so = cm_id->so; init_sock(&ep->com); /* find a route */ rt = find_route( cm_id->local_addr.sin_addr.s_addr, cm_id->remote_addr.sin_addr.s_addr, cm_id->local_addr.sin_port, cm_id->remote_addr.sin_port, 0); if (!rt) { CTR2(KTR_IW_CXGBE, "%s:cc7 %p", __func__, ep); printk(KERN_ERR MOD "%s - cannot find route.\n", __func__); err = -EHOSTUNREACH; goto fail2; } if (!(rt->rt_ifp->if_capenable & IFCAP_TOE)) { CTR2(KTR_IW_CXGBE, "%s:cc8 %p", __func__, ep); printf("%s - interface not TOE capable.\n", __func__); close_socket(&ep->com, 0); err = -ENOPROTOOPT; goto fail3; } tdev = TOEDEV(rt->rt_ifp); if (tdev == NULL) { CTR2(KTR_IW_CXGBE, "%s:cc9 %p", __func__, ep); printf("%s - No toedev for interface.\n", __func__); goto fail3; } RTFREE(rt); state_set(&ep->com, CONNECTING); ep->tos = 0; ep->com.local_addr = cm_id->local_addr; ep->com.remote_addr = cm_id->remote_addr; err = soconnect(ep->com.so, (struct sockaddr *)&ep->com.remote_addr, ep->com.thread); if (!err) { CTR2(KTR_IW_CXGBE, "%s:cca %p", __func__, ep); goto out; } else { close_socket(&ep->com, 0); goto fail2; } fail3: CTR2(KTR_IW_CXGBE, "%s:ccb %p", __func__, ep); RTFREE(rt); fail2: cm_id->rem_ref(cm_id); c4iw_put_ep(&ep->com); out: CTR2(KTR_IW_CXGBE, "%s:ccE %p", __func__, ep); return err; } /* * iwcm->create_listen. Returns -errno on failure. */ int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog) { int rc; struct c4iw_dev *dev = to_c4iw_dev(cm_id->device); struct c4iw_listen_ep *ep; struct socket *so = cm_id->so; ep = alloc_ep(sizeof(*ep), GFP_KERNEL); CTR5(KTR_IW_CXGBE, "%s: cm_id %p, lso %p, ep %p, inp %p", __func__, cm_id, so, ep, so->so_pcb); if (ep == NULL) { log(LOG_ERR, "%s: failed to alloc memory for endpoint\n", __func__); rc = ENOMEM; goto failed; } cm_id->add_ref(cm_id); ep->com.cm_id = cm_id; ep->com.dev = dev; ep->backlog = backlog; ep->com.local_addr = cm_id->local_addr; ep->com.thread = curthread; state_set(&ep->com, LISTEN); ep->com.so = so; init_sock(&ep->com); rc = solisten(so, ep->backlog, ep->com.thread); if (rc != 0) { log(LOG_ERR, "%s: failed to start listener: %d\n", __func__, rc); close_socket(&ep->com, 0); cm_id->rem_ref(cm_id); c4iw_put_ep(&ep->com); goto failed; } cm_id->provider_data = ep; return (0); failed: CTR3(KTR_IW_CXGBE, "%s: cm_id %p, FAILED (%d)", __func__, cm_id, rc); return (-rc); } int c4iw_destroy_listen(struct iw_cm_id *cm_id) { int rc; struct c4iw_listen_ep *ep = to_listen_ep(cm_id); CTR4(KTR_IW_CXGBE, "%s: cm_id %p, so %p, inp %p", __func__, cm_id, cm_id->so, cm_id->so->so_pcb); state_set(&ep->com, DEAD); rc = close_socket(&ep->com, 0); cm_id->rem_ref(cm_id); c4iw_put_ep(&ep->com); return (rc); } int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp) { int ret = 0; int close = 0; int fatal = 0; struct c4iw_rdev *rdev; mutex_lock(&ep->com.mutex); CTR2(KTR_IW_CXGBE, "%s:cedB %p", __func__, ep); rdev = &ep->com.dev->rdev; if (c4iw_fatal_error(rdev)) { CTR2(KTR_IW_CXGBE, "%s:ced1 %p", __func__, ep); fatal = 1; - close_complete_upcall(ep, -EIO); + close_complete_upcall(ep, -ECONNRESET); ep->com.state = DEAD; } CTR3(KTR_IW_CXGBE, "%s:ced2 %p %s", __func__, ep, states[ep->com.state]); switch (ep->com.state) { case MPA_REQ_WAIT: case MPA_REQ_SENT: case MPA_REQ_RCVD: case MPA_REP_SENT: case FPDU_MODE: close = 1; if (abrupt) ep->com.state = ABORTING; else { ep->com.state = CLOSING; START_EP_TIMER(ep); } set_bit(CLOSE_SENT, &ep->com.flags); break; case CLOSING: if (!test_and_set_bit(CLOSE_SENT, &ep->com.flags)) { close = 1; if (abrupt) { STOP_EP_TIMER(ep); ep->com.state = ABORTING; } else ep->com.state = MORIBUND; } break; case MORIBUND: case ABORTING: case DEAD: CTR3(KTR_IW_CXGBE, "%s ignoring disconnect ep %p state %u", __func__, ep, ep->com.state); break; default: BUG(); break; } mutex_unlock(&ep->com.mutex); if (close) { CTR2(KTR_IW_CXGBE, "%s:ced3 %p", __func__, ep); if (abrupt) { CTR2(KTR_IW_CXGBE, "%s:ced4 %p", __func__, ep); set_bit(EP_DISC_ABORT, &ep->com.history); ret = abort_connection(ep); } else { CTR2(KTR_IW_CXGBE, "%s:ced5 %p", __func__, ep); set_bit(EP_DISC_CLOSE, &ep->com.history); if (!ep->parent_ep) __state_set(&ep->com, MORIBUND); ret = shutdown_socket(&ep->com); } if (ret) { fatal = 1; } } if (fatal) { release_ep_resources(ep); CTR2(KTR_IW_CXGBE, "%s:ced6 %p", __func__, ep); } CTR2(KTR_IW_CXGBE, "%s:cedE %p", __func__, ep); return ret; } #ifdef C4IW_EP_REDIRECT int c4iw_ep_redirect(void *ctx, struct dst_entry *old, struct dst_entry *new, struct l2t_entry *l2t) { struct c4iw_ep *ep = ctx; if (ep->dst != old) return 0; PDBG("%s ep %p redirect to dst %p l2t %p\n", __func__, ep, new, l2t); dst_hold(new); cxgb4_l2t_release(ep->l2t); ep->l2t = l2t; dst_release(old); ep->dst = new; return 1; } #endif static void ep_timeout(unsigned long arg) { struct c4iw_ep *ep = (struct c4iw_ep *)arg; int kickit = 0; CTR2(KTR_IW_CXGBE, "%s:etB %p", __func__, ep); spin_lock(&timeout_lock); if (!test_and_set_bit(TIMEOUT, &ep->com.flags)) { list_add_tail(&ep->entry, &timeout_list); kickit = 1; } spin_unlock(&timeout_lock); if (kickit) { CTR2(KTR_IW_CXGBE, "%s:et1 %p", __func__, ep); queue_work(c4iw_taskq, &c4iw_task); } CTR2(KTR_IW_CXGBE, "%s:etE %p", __func__, ep); } static int fw6_wr_rpl(struct adapter *sc, const __be64 *rpl) { uint64_t val = be64toh(*rpl); int ret; struct c4iw_wr_wait *wr_waitp; ret = (int)((val >> 8) & 0xff); wr_waitp = (struct c4iw_wr_wait *)rpl[1]; CTR3(KTR_IW_CXGBE, "%s wr_waitp %p ret %u", __func__, wr_waitp, ret); if (wr_waitp) c4iw_wake_up(wr_waitp, ret ? -ret : 0); return (0); } static int fw6_cqe_handler(struct adapter *sc, const __be64 *rpl) { struct t4_cqe cqe =*(const struct t4_cqe *)(&rpl[0]); CTR2(KTR_IW_CXGBE, "%s rpl %p", __func__, rpl); c4iw_ev_dispatch(sc->iwarp_softc, &cqe); return (0); } static int terminate(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) { struct adapter *sc = iq->adapter; const struct cpl_rdma_terminate *rpl = (const void *)(rss + 1); unsigned int tid = GET_TID(rpl); struct c4iw_qp_attributes attrs; struct toepcb *toep = lookup_tid(sc, tid); struct socket *so = inp_inpcbtosocket(toep->inp); struct c4iw_ep *ep = so->so_rcv.sb_upcallarg; CTR2(KTR_IW_CXGBE, "%s:tB %p %d", __func__, ep); if (ep && ep->com.qp) { printk(KERN_WARNING MOD "TERM received tid %u qpid %u\n", tid, ep->com.qp->wq.sq.qid); attrs.next_state = C4IW_QP_STATE_TERMINATE; c4iw_modify_qp(ep->com.dev, ep->com.qp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); } else printk(KERN_WARNING MOD "TERM received tid %u no ep/qp\n", tid); CTR2(KTR_IW_CXGBE, "%s:tE %p %d", __func__, ep); return 0; } void c4iw_cm_init_cpl(struct adapter *sc) { t4_register_cpl_handler(sc, CPL_RDMA_TERMINATE, terminate); t4_register_fw_msg_handler(sc, FW6_TYPE_WR_RPL, fw6_wr_rpl); t4_register_fw_msg_handler(sc, FW6_TYPE_CQE, fw6_cqe_handler); t4_register_an_handler(sc, c4iw_ev_handler); } void c4iw_cm_term_cpl(struct adapter *sc) { t4_register_cpl_handler(sc, CPL_RDMA_TERMINATE, NULL); t4_register_fw_msg_handler(sc, FW6_TYPE_WR_RPL, NULL); t4_register_fw_msg_handler(sc, FW6_TYPE_CQE, NULL); } int __init c4iw_cm_init(void) { TAILQ_INIT(&req_list); spin_lock_init(&req_lock); INIT_LIST_HEAD(&timeout_list); spin_lock_init(&timeout_lock); INIT_WORK(&c4iw_task, process_req); c4iw_taskq = create_singlethread_workqueue("iw_cxgbe"); if (!c4iw_taskq) return -ENOMEM; return 0; } void __exit c4iw_cm_term(void) { WARN_ON(!TAILQ_EMPTY(&req_list)); WARN_ON(!list_empty(&timeout_list)); flush_workqueue(c4iw_taskq); destroy_workqueue(c4iw_taskq); } #endif Index: projects/release-pkg/sys/dev/drm2/i915/i915_gem.c =================================================================== --- projects/release-pkg/sys/dev/drm2/i915/i915_gem.c (revision 289118) +++ projects/release-pkg/sys/dev/drm2/i915/i915_gem.c (revision 289119) @@ -1,4376 +1,4374 @@ /* * Copyright © 2008 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Authors: * Eric Anholt * * Copyright (c) 2011 The FreeBSD Foundation * All rights reserved. * * This software was developed by Konstantin Belousov 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 * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #define __user #define __force #define __iomem #define __must_check #define to_user_ptr(x) ((void *)(uintptr_t)(x)) #define offset_in_page(x) ((x) & PAGE_MASK) #define page_to_phys(x) VM_PAGE_TO_PHYS(x) static void i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj); static void i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj); static __must_check int i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, unsigned alignment, bool map_and_fenceable); static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_i915_gem_object *obj, struct drm_i915_gem_pwrite *args, struct drm_file *file); static void i915_gem_write_fence(struct drm_device *dev, int reg, struct drm_i915_gem_object *obj); static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, struct drm_i915_fence_reg *fence, bool enable); static void i915_gem_lowmem(void *arg); static void i915_gem_object_truncate(struct drm_i915_gem_object *obj); static int i915_gem_object_get_pages_range(struct drm_i915_gem_object *obj, off_t start, off_t end); static void i915_gem_object_put_pages_range(struct drm_i915_gem_object *obj, off_t start, off_t end); static vm_page_t i915_gem_wire_page(vm_object_t object, vm_pindex_t pindex, bool *fresh); MALLOC_DEFINE(DRM_I915_GEM, "i915gem", "Allocations from i915 gem"); long i915_gem_wired_pages_cnt; static bool cpu_cache_is_coherent(struct drm_device *dev, enum i915_cache_level level) { return HAS_LLC(dev) || level != I915_CACHE_NONE; } static bool cpu_write_needs_clflush(struct drm_i915_gem_object *obj) { if (!cpu_cache_is_coherent(obj->base.dev, obj->cache_level)) return true; return obj->pin_display; } static inline void i915_gem_object_fence_lost(struct drm_i915_gem_object *obj) { if (obj->tiling_mode) i915_gem_release_mmap(obj); /* As we do not have an associated fence register, we will force * a tiling change if we ever need to acquire one. */ obj->fence_dirty = false; obj->fence_reg = I915_FENCE_REG_NONE; } /* some bookkeeping */ static void i915_gem_info_add_obj(struct drm_i915_private *dev_priv, size_t size) { dev_priv->mm.object_count++; dev_priv->mm.object_memory += size; } static void i915_gem_info_remove_obj(struct drm_i915_private *dev_priv, size_t size) { dev_priv->mm.object_count--; dev_priv->mm.object_memory -= size; } static int i915_gem_wait_for_error(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int ret; if (!atomic_load_acq_int(&dev_priv->mm.wedged)) return (0); mtx_lock(&dev_priv->error_completion_lock); while (dev_priv->error_completion == 0) { ret = -msleep(&dev_priv->error_completion, &dev_priv->error_completion_lock, PCATCH, "915wco", 0); if (ret == -ERESTART) ret = -ERESTARTSYS; if (ret != 0) { mtx_unlock(&dev_priv->error_completion_lock); return (ret); } } mtx_unlock(&dev_priv->error_completion_lock); if (atomic_load_acq_int(&dev_priv->mm.wedged)) { /* GPU is hung, bump the completion count to account for * the token we just consumed so that we never hit zero and * end up waiting upon a subsequent completion event that * will never happen. */ mtx_lock(&dev_priv->error_completion_lock); dev_priv->error_completion++; mtx_unlock(&dev_priv->error_completion_lock); } return 0; } int i915_mutex_lock_interruptible(struct drm_device *dev) { int ret; ret = i915_gem_wait_for_error(dev); if (ret) return ret; /* * interruptible shall it be. might indeed be if dev_lock is * changed to sx */ ret = -sx_xlock_sig(&dev->dev_struct_lock); if (ret) return ret; return 0; } static inline bool i915_gem_object_is_inactive(struct drm_i915_gem_object *obj) { return !obj->active; } int i915_gem_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { struct drm_i915_gem_init *args = data; drm_i915_private_t *dev_priv = dev->dev_private; int ret; if (drm_core_check_feature(dev, DRIVER_MODESET)) return -ENODEV; if (args->gtt_start >= args->gtt_end || (args->gtt_end | args->gtt_start) & (PAGE_SIZE - 1)) return -EINVAL; if (mtx_initialized(&dev_priv->mm.gtt_space.unused_lock)) return -EBUSY; /* GEM with user mode setting was never supported on ilk and later. */ if (INTEL_INFO(dev)->gen >= 5) return -ENODEV; /* * XXXKIB. The second-time initialization should be guarded * against. */ DRM_LOCK(dev); ret = i915_gem_init_global_gtt(dev, args->gtt_start, args->gtt_end, args->gtt_end); DRM_UNLOCK(dev); return ret; } int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_get_aperture *args = data; struct drm_i915_gem_object *obj; size_t pinned; pinned = 0; DRM_LOCK(dev); list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) if (obj->pin_count) pinned += obj->gtt_space->size; DRM_UNLOCK(dev); args->aper_size = dev_priv->mm.gtt_total; args->aper_available_size = args->aper_size - pinned; return 0; } static int i915_gem_create(struct drm_file *file, struct drm_device *dev, uint64_t size, uint32_t *handle_p) { struct drm_i915_gem_object *obj; int ret; u32 handle; size = roundup(size, PAGE_SIZE); if (size == 0) return -EINVAL; /* Allocate the new object */ obj = i915_gem_alloc_object(dev, size); if (obj == NULL) return -ENOMEM; ret = drm_gem_handle_create(file, &obj->base, &handle); if (ret) { drm_gem_object_release(&obj->base); i915_gem_info_remove_obj(dev->dev_private, obj->base.size); free(obj, DRM_I915_GEM); return ret; } /* drop reference from allocate - handle holds it now */ drm_gem_object_unreference(&obj->base); CTR2(KTR_DRM, "object_create %p %x", obj, size); *handle_p = handle; return 0; } int i915_gem_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args) { /* have to work out size/pitch and return them */ args->pitch = roundup2(args->width * ((args->bpp + 7) / 8), 64); args->size = args->pitch * args->height; return i915_gem_create(file, dev, args->size, &args->handle); } int i915_gem_dumb_destroy(struct drm_file *file, struct drm_device *dev, uint32_t handle) { return drm_gem_handle_delete(file, handle); } /** * Creates a new mm object and returns a handle to it. */ int i915_gem_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { struct drm_i915_gem_create *args = data; return i915_gem_create(file, dev, args->size, &args->handle); } static int i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj) { drm_i915_private_t *dev_priv = obj->base.dev->dev_private; return dev_priv->mm.bit_6_swizzle_x == I915_BIT_6_SWIZZLE_9_10_17 && obj->tiling_mode != I915_TILING_NONE; } static inline int __copy_to_user_inatomic(void __user *to, const void *from, unsigned n) { return (copyout_nofault(from, to, n) != 0 ? n : 0); } static inline unsigned long __copy_from_user_inatomic_nocache(void *to, const void __user *from, unsigned long n) { /* * XXXKIB. Equivalent Linux function is implemented using * MOVNTI for aligned moves. For unaligned head and tail, * normal move is performed. As such, it is not incorrect, if * only somewhat slower, to use normal copyin. All uses * except shmem_pwrite_fast() have the destination mapped WC. */ return ((copyin_nofault(__DECONST(void *, from), to, n) != 0 ? n : 0)); } static inline int fault_in_multipages_readable(const char __user *uaddr, int size) { char c; int ret = 0; const char __user *end = uaddr + size - 1; if (unlikely(size == 0)) return ret; while (uaddr <= end) { ret = -copyin(uaddr, &c, 1); if (ret != 0) return -EFAULT; uaddr += PAGE_SIZE; } /* Check whether the range spilled into the next page. */ if (((unsigned long)uaddr & ~PAGE_MASK) == ((unsigned long)end & ~PAGE_MASK)) { ret = -copyin(end, &c, 1); } return ret; } static inline int fault_in_multipages_writeable(char __user *uaddr, int size) { int ret = 0; char __user *end = uaddr + size - 1; if (unlikely(size == 0)) return ret; /* * Writing zeroes into userspace here is OK, because we know that if * the zero gets there, we'll be overwriting it. */ while (uaddr <= end) { ret = subyte(uaddr, 0); if (ret != 0) return -EFAULT; uaddr += PAGE_SIZE; } /* Check whether the range spilled into the next page. */ if (((unsigned long)uaddr & ~PAGE_MASK) == ((unsigned long)end & ~PAGE_MASK)) ret = subyte(end, 0); return ret; } static inline int __copy_to_user_swizzled(char __user *cpu_vaddr, const char *gpu_vaddr, int gpu_offset, int length) { int ret, cpu_offset = 0; while (length > 0) { int cacheline_end = roundup2(gpu_offset + 1, 64); int this_length = min(cacheline_end - gpu_offset, length); int swizzled_gpu_offset = gpu_offset ^ 64; ret = __copy_to_user(cpu_vaddr + cpu_offset, gpu_vaddr + swizzled_gpu_offset, this_length); if (ret) return ret + length; cpu_offset += this_length; gpu_offset += this_length; length -= this_length; } return 0; } static inline int __copy_from_user_swizzled(char *gpu_vaddr, int gpu_offset, const char __user *cpu_vaddr, int length) { int ret, cpu_offset = 0; while (length > 0) { int cacheline_end = roundup2(gpu_offset + 1, 64); int this_length = min(cacheline_end - gpu_offset, length); int swizzled_gpu_offset = gpu_offset ^ 64; ret = __copy_from_user(gpu_vaddr + swizzled_gpu_offset, cpu_vaddr + cpu_offset, this_length); if (ret) return ret + length; cpu_offset += this_length; gpu_offset += this_length; length -= this_length; } return 0; } /* Per-page copy function for the shmem pread fastpath. * Flushes invalid cachelines before reading the target if * needs_clflush is set. */ static int shmem_pread_fast(vm_page_t page, int shmem_page_offset, int page_length, char __user *user_data, bool page_do_bit17_swizzling, bool needs_clflush) { char *vaddr; struct sf_buf *sf; int ret; if (unlikely(page_do_bit17_swizzling)) return -EINVAL; sched_pin(); sf = sf_buf_alloc(page, SFB_NOWAIT | SFB_CPUPRIVATE); if (sf == NULL) { sched_unpin(); return (-EFAULT); } vaddr = (char *)sf_buf_kva(sf); if (needs_clflush) drm_clflush_virt_range(vaddr + shmem_page_offset, page_length); ret = __copy_to_user_inatomic(user_data, vaddr + shmem_page_offset, page_length); sf_buf_free(sf); sched_unpin(); return ret ? -EFAULT : 0; } static void shmem_clflush_swizzled_range(char *addr, unsigned long length, bool swizzled) { if (unlikely(swizzled)) { unsigned long start = (unsigned long) addr; unsigned long end = (unsigned long) addr + length; /* For swizzling simply ensure that we always flush both * channels. Lame, but simple and it works. Swizzled * pwrite/pread is far from a hotpath - current userspace * doesn't use it at all. */ start = rounddown2(start, 128); end = roundup2(end, 128); drm_clflush_virt_range((void *)start, end - start); } else { drm_clflush_virt_range(addr, length); } } /* Only difference to the fast-path function is that this can handle bit17 * and uses non-atomic copy and kmap functions. */ static int shmem_pread_slow(vm_page_t page, int shmem_page_offset, int page_length, char __user *user_data, bool page_do_bit17_swizzling, bool needs_clflush) { char *vaddr; struct sf_buf *sf; int ret; sf = sf_buf_alloc(page, 0); vaddr = (char *)sf_buf_kva(sf); if (needs_clflush) shmem_clflush_swizzled_range(vaddr + shmem_page_offset, page_length, page_do_bit17_swizzling); if (page_do_bit17_swizzling) ret = __copy_to_user_swizzled(user_data, vaddr, shmem_page_offset, page_length); else ret = __copy_to_user(user_data, vaddr + shmem_page_offset, page_length); sf_buf_free(sf); return ret ? - EFAULT : 0; } static int i915_gem_shmem_pread(struct drm_device *dev, struct drm_i915_gem_object *obj, struct drm_i915_gem_pread *args, struct drm_file *file) { char __user *user_data; ssize_t remain, sremain; off_t offset, soffset; int shmem_page_offset, page_length, ret = 0; int obj_do_bit17_swizzling, page_do_bit17_swizzling; int prefaulted = 0; int needs_clflush = 0; user_data = to_user_ptr(args->data_ptr); sremain = remain = args->size; obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); if (!(obj->base.read_domains & I915_GEM_DOMAIN_CPU)) { /* If we're not in the cpu read domain, set ourself into the gtt * read domain and manually flush cachelines (if required). This * optimizes for the case when the gpu will dirty the data * anyway again before the next pread happens. */ needs_clflush = !cpu_cache_is_coherent(dev, obj->cache_level); ret = i915_gem_object_set_to_gtt_domain(obj, false); if (ret) return ret; } soffset = offset = args->offset; ret = i915_gem_object_get_pages_range(obj, soffset, soffset + sremain); if (ret) return ret; i915_gem_object_pin_pages(obj); VM_OBJECT_WLOCK(obj->base.vm_obj); for (vm_page_t page = vm_page_find_least(obj->base.vm_obj, OFF_TO_IDX(offset));; page = vm_page_next(page)) { VM_OBJECT_WUNLOCK(obj->base.vm_obj); if (remain <= 0) break; /* Operation in this page * * shmem_page_offset = offset within page in shmem file * page_length = bytes to copy for this page */ shmem_page_offset = offset_in_page(offset); page_length = remain; if ((shmem_page_offset + page_length) > PAGE_SIZE) page_length = PAGE_SIZE - shmem_page_offset; page_do_bit17_swizzling = obj_do_bit17_swizzling && (page_to_phys(page) & (1 << 17)) != 0; ret = shmem_pread_fast(page, shmem_page_offset, page_length, user_data, page_do_bit17_swizzling, needs_clflush); if (ret == 0) goto next_page; DRM_UNLOCK(dev); if (likely(!i915_prefault_disable) && !prefaulted) { ret = fault_in_multipages_writeable(user_data, remain); /* Userspace is tricking us, but we've already clobbered * its pages with the prefault and promised to write the * data up to the first fault. Hence ignore any errors * and just continue. */ (void)ret; prefaulted = 1; } ret = shmem_pread_slow(page, shmem_page_offset, page_length, user_data, page_do_bit17_swizzling, needs_clflush); DRM_LOCK(dev); next_page: vm_page_reference(page); if (ret) goto out; remain -= page_length; user_data += page_length; offset += page_length; VM_OBJECT_WLOCK(obj->base.vm_obj); } out: i915_gem_object_unpin_pages(obj); i915_gem_object_put_pages_range(obj, soffset, soffset + sremain); return ret; } /** * Reads data from the object referenced by handle. * * On error, the contents of *data are undefined. */ int i915_gem_pread_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { struct drm_i915_gem_pread *args = data; struct drm_i915_gem_object *obj; int ret = 0; if (args->size == 0) return 0; if (!useracc(to_user_ptr(args->data_ptr), args->size, VM_PROT_WRITE)) return -EFAULT; ret = i915_mutex_lock_interruptible(dev); if (ret) return ret; obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); if (&obj->base == NULL) { ret = -ENOENT; goto unlock; } /* Bounds check source. */ if (args->offset > obj->base.size || args->size > obj->base.size - args->offset) { ret = -EINVAL; goto out; } #if 1 KIB_NOTYET(); #else /* prime objects have no backing filp to GEM pread/pwrite * pages from. */ if (!obj->base.filp) { ret = -EINVAL; goto out; } #endif CTR3(KTR_DRM, "pread %p %jx %jx", obj, args->offset, args->size); ret = i915_gem_shmem_pread(dev, obj, args, file); out: drm_gem_object_unreference(&obj->base); unlock: DRM_UNLOCK(dev); return ret; } /* This is the fast write path which cannot handle * page faults in the source data */ static inline int fast_user_write(struct drm_device *dev, off_t page_base, int page_offset, char __user *user_data, int length) { void __iomem *vaddr_atomic; void *vaddr; unsigned long unwritten; vaddr_atomic = pmap_mapdev_attr(dev->agp->base + page_base, length, PAT_WRITE_COMBINING); /* We can use the cpu mem copy function because this is X86. */ vaddr = (char __force*)vaddr_atomic + page_offset; unwritten = __copy_from_user_inatomic_nocache(vaddr, user_data, length); pmap_unmapdev((vm_offset_t)vaddr_atomic, length); return unwritten; } /** * This is the fast pwrite path, where we copy the data directly from the * user into the GTT, uncached. */ static int i915_gem_gtt_pwrite_fast(struct drm_device *dev, struct drm_i915_gem_object *obj, struct drm_i915_gem_pwrite *args, struct drm_file *file) { ssize_t remain; off_t offset, page_base; char __user *user_data; int page_offset, page_length, ret; ret = i915_gem_object_pin(obj, 0, true); /* XXXKIB ret = i915_gem_obj_ggtt_pin(obj, 0, true, true); */ if (ret) goto out; ret = i915_gem_object_set_to_gtt_domain(obj, true); if (ret) goto out_unpin; ret = i915_gem_object_put_fence(obj); if (ret) goto out_unpin; user_data = to_user_ptr(args->data_ptr); remain = args->size; offset = obj->gtt_offset + args->offset; while (remain > 0) { /* Operation in this page * * page_base = page offset within aperture * page_offset = offset within page * page_length = bytes to copy for this page */ page_base = offset & ~PAGE_MASK; page_offset = offset_in_page(offset); page_length = remain; if ((page_offset + remain) > PAGE_SIZE) page_length = PAGE_SIZE - page_offset; /* If we get a fault while copying data, then (presumably) our * source page isn't available. Return the error and we'll * retry in the slow path. */ if (fast_user_write(dev, page_base, page_offset, user_data, page_length)) { ret = -EFAULT; goto out_unpin; } remain -= page_length; user_data += page_length; offset += page_length; } out_unpin: i915_gem_object_unpin(obj); out: return ret; } /* Per-page copy function for the shmem pwrite fastpath. * Flushes invalid cachelines before writing to the target if * needs_clflush_before is set and flushes out any written cachelines after * writing if needs_clflush is set. */ static int shmem_pwrite_fast(vm_page_t page, int shmem_page_offset, int page_length, char __user *user_data, bool page_do_bit17_swizzling, bool needs_clflush_before, bool needs_clflush_after) { char *vaddr; struct sf_buf *sf; int ret; if (unlikely(page_do_bit17_swizzling)) return -EINVAL; sched_pin(); sf = sf_buf_alloc(page, SFB_NOWAIT | SFB_CPUPRIVATE); if (sf == NULL) { sched_unpin(); return (-EFAULT); } vaddr = (char *)sf_buf_kva(sf); if (needs_clflush_before) drm_clflush_virt_range(vaddr + shmem_page_offset, page_length); ret = __copy_from_user_inatomic_nocache(vaddr + shmem_page_offset, user_data, page_length); if (needs_clflush_after) drm_clflush_virt_range(vaddr + shmem_page_offset, page_length); sf_buf_free(sf); sched_unpin(); return ret ? -EFAULT : 0; } /* Only difference to the fast-path function is that this can handle bit17 * and uses non-atomic copy and kmap functions. */ static int shmem_pwrite_slow(vm_page_t page, int shmem_page_offset, int page_length, char __user *user_data, bool page_do_bit17_swizzling, bool needs_clflush_before, bool needs_clflush_after) { char *vaddr; struct sf_buf *sf; int ret; sf = sf_buf_alloc(page, 0); vaddr = (char *)sf_buf_kva(sf); if (unlikely(needs_clflush_before || page_do_bit17_swizzling)) shmem_clflush_swizzled_range(vaddr + shmem_page_offset, page_length, page_do_bit17_swizzling); if (page_do_bit17_swizzling) ret = __copy_from_user_swizzled(vaddr, shmem_page_offset, user_data, page_length); else ret = __copy_from_user(vaddr + shmem_page_offset, user_data, page_length); if (needs_clflush_after) shmem_clflush_swizzled_range(vaddr + shmem_page_offset, page_length, page_do_bit17_swizzling); sf_buf_free(sf); return ret ? -EFAULT : 0; } static int i915_gem_shmem_pwrite(struct drm_device *dev, struct drm_i915_gem_object *obj, struct drm_i915_gem_pwrite *args, struct drm_file *file) { ssize_t remain, sremain; off_t offset, soffset; char __user *user_data; int shmem_page_offset, page_length, ret = 0; int obj_do_bit17_swizzling, page_do_bit17_swizzling; int hit_slowpath = 0; int needs_clflush_after = 0; int needs_clflush_before = 0; user_data = to_user_ptr(args->data_ptr); sremain = remain = args->size; obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); if (obj->base.write_domain != I915_GEM_DOMAIN_CPU) { /* If we're not in the cpu write domain, set ourself into the gtt * write domain and manually flush cachelines (if required). This * optimizes for the case when the gpu will use the data * right away and we therefore have to clflush anyway. */ needs_clflush_after = cpu_write_needs_clflush(obj); ret = i915_gem_object_set_to_gtt_domain(obj, true); if (ret) return ret; } /* Same trick applies to invalidate partially written cachelines read * before writing. */ if ((obj->base.read_domains & I915_GEM_DOMAIN_CPU) == 0) needs_clflush_before = !cpu_cache_is_coherent(dev, obj->cache_level); soffset = offset = args->offset; ret = i915_gem_object_get_pages_range(obj, soffset, soffset + sremain); if (ret) return ret; i915_gem_object_pin_pages(obj); obj->dirty = 1; VM_OBJECT_WLOCK(obj->base.vm_obj); for (vm_page_t page = vm_page_find_least(obj->base.vm_obj, OFF_TO_IDX(offset));; page = vm_page_next(page)) { VM_OBJECT_WUNLOCK(obj->base.vm_obj); int partial_cacheline_write; if (remain <= 0) break; /* Operation in this page * * shmem_page_offset = offset within page in shmem file * page_length = bytes to copy for this page */ shmem_page_offset = offset_in_page(offset); page_length = remain; if ((shmem_page_offset + page_length) > PAGE_SIZE) page_length = PAGE_SIZE - shmem_page_offset; /* If we don't overwrite a cacheline completely we need to be * careful to have up-to-date data by first clflushing. Don't * overcomplicate things and flush the entire patch. */ partial_cacheline_write = needs_clflush_before && ((shmem_page_offset | page_length) & (cpu_clflush_line_size - 1)); page_do_bit17_swizzling = obj_do_bit17_swizzling && (page_to_phys(page) & (1 << 17)) != 0; ret = shmem_pwrite_fast(page, shmem_page_offset, page_length, user_data, page_do_bit17_swizzling, partial_cacheline_write, needs_clflush_after); if (ret == 0) goto next_page; hit_slowpath = 1; DRM_UNLOCK(dev); ret = shmem_pwrite_slow(page, shmem_page_offset, page_length, user_data, page_do_bit17_swizzling, partial_cacheline_write, needs_clflush_after); DRM_LOCK(dev); next_page: vm_page_dirty(page); vm_page_reference(page); if (ret) goto out; remain -= page_length; user_data += page_length; offset += page_length; VM_OBJECT_WLOCK(obj->base.vm_obj); } out: i915_gem_object_unpin_pages(obj); i915_gem_object_put_pages_range(obj, soffset, soffset + sremain); if (hit_slowpath) { /* * Fixup: Flush cpu caches in case we didn't flush the dirty * cachelines in-line while writing and the object moved * out of the cpu write domain while we've dropped the lock. */ if (!needs_clflush_after && obj->base.write_domain != I915_GEM_DOMAIN_CPU) { i915_gem_clflush_object(obj); i915_gem_chipset_flush(dev); } } if (needs_clflush_after) i915_gem_chipset_flush(dev); return ret; } /** * Writes data to the object referenced by handle. * * On error, the contents of the buffer that were to be modified are undefined. */ int i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { struct drm_i915_gem_pwrite *args = data; struct drm_i915_gem_object *obj; int ret; if (args->size == 0) return 0; if (!useracc(to_user_ptr(args->data_ptr), args->size, VM_PROT_READ)) return -EFAULT; if (likely(!i915_prefault_disable)) { ret = fault_in_multipages_readable(to_user_ptr(args->data_ptr), args->size); if (ret) return -EFAULT; } ret = i915_mutex_lock_interruptible(dev); if (ret) return ret; obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); if (&obj->base == NULL) { ret = -ENOENT; goto unlock; } /* Bounds check destination. */ if (args->offset > obj->base.size || args->size > obj->base.size - args->offset) { ret = -EINVAL; goto out; } #if 1 KIB_NOTYET(); #else /* prime objects have no backing filp to GEM pread/pwrite * pages from. */ if (!obj->base.filp) { ret = -EINVAL; goto out; } #endif CTR3(KTR_DRM, "pwrite %p %jx %jx", obj, args->offset, args->size); ret = -EFAULT; /* We can only do the GTT pwrite on untiled buffers, as otherwise * it would end up going through the fenced access, and we'll get * different detiling behavior between reading and writing. * pread/pwrite currently are reading and writing from the CPU * perspective, requiring manual detiling by the client. */ if (obj->phys_obj) { ret = i915_gem_phys_pwrite(dev, obj, args, file); goto out; } if (obj->tiling_mode == I915_TILING_NONE && obj->base.write_domain != I915_GEM_DOMAIN_CPU && cpu_write_needs_clflush(obj)) { ret = i915_gem_gtt_pwrite_fast(dev, obj, args, file); /* Note that the gtt paths might fail with non-page-backed user * pointers (e.g. gtt mappings when moving data between * textures). Fallback to the shmem path in that case. */ } if (ret == -EFAULT || ret == -ENOSPC) ret = i915_gem_shmem_pwrite(dev, obj, args, file); out: drm_gem_object_unreference(&obj->base); unlock: DRM_UNLOCK(dev); return ret; } static int i915_gem_check_wedge(struct drm_i915_private *dev_priv) { DRM_LOCK_ASSERT(dev_priv->dev); if (atomic_load_acq_int(&dev_priv->mm.wedged) != 0) { bool recovery_complete; /* Give the error handler a chance to run. */ mtx_lock(&dev_priv->error_completion_lock); recovery_complete = (&dev_priv->error_completion) > 0; mtx_unlock(&dev_priv->error_completion_lock); return (recovery_complete ? -EIO : -EAGAIN); } return 0; } /* * Compare seqno against outstanding lazy request. Emit a request if they are * equal. */ static int i915_gem_check_olr(struct intel_ring_buffer *ring, u32 seqno) { int ret; DRM_LOCK_ASSERT(ring->dev); ret = 0; if (seqno == ring->outstanding_lazy_request) { struct drm_i915_gem_request *request; request = malloc(sizeof(*request), DRM_I915_GEM, M_WAITOK | M_ZERO); ret = i915_add_request(ring, NULL, request); if (ret != 0) { free(request, DRM_I915_GEM); return ret; } MPASS(seqno == request->seqno); } return ret; } static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, bool interruptible) { drm_i915_private_t *dev_priv = ring->dev->dev_private; int ret = 0, flags; if (i915_seqno_passed(ring->get_seqno(ring), seqno)) return 0; CTR2(KTR_DRM, "request_wait_begin %s %d", ring->name, seqno); mtx_lock(&dev_priv->irq_lock); if (!ring->irq_get(ring)) { mtx_unlock(&dev_priv->irq_lock); return -ENODEV; } flags = interruptible ? PCATCH : 0; while (!i915_seqno_passed(ring->get_seqno(ring), seqno) && !atomic_load_acq_int(&dev_priv->mm.wedged) && ret == 0) { ret = -msleep(ring, &dev_priv->irq_lock, flags, "915gwr", 0); if (ret == -ERESTART) ret = -ERESTARTSYS; } ring->irq_put(ring); mtx_unlock(&dev_priv->irq_lock); CTR3(KTR_DRM, "request_wait_end %s %d %d", ring->name, seqno, ret); return ret; } /** * Waits for a sequence number to be signaled, and cleans up the * request and object lists appropriately for that event. */ int i915_wait_request(struct intel_ring_buffer *ring, uint32_t seqno) { struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; int ret; KASSERT(seqno != 0, ("Zero seqno")); ret = i915_gem_check_wedge(dev_priv); if (ret) return ret; ret = i915_gem_check_olr(ring, seqno); if (ret) return ret; ret = __wait_seqno(ring, seqno, dev_priv->mm.interruptible); if (atomic_load_acq_int(&dev_priv->mm.wedged)) ret = -EAGAIN; return ret; } /** * Ensures that all rendering to the object has completed and the object is * safe to unbind from the GTT or access from the CPU. */ static __must_check int i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj) { int ret; KASSERT((obj->base.write_domain & I915_GEM_GPU_DOMAINS) == 0, ("In GPU write domain")); CTR5(KTR_DRM, "object_wait_rendering %p %s %x %d %d", obj, obj->ring != NULL ? obj->ring->name : "none", obj->gtt_offset, obj->active, obj->last_rendering_seqno); if (obj->active) { ret = i915_wait_request(obj->ring, obj->last_rendering_seqno); if (ret != 0) return (ret); i915_gem_retire_requests_ring(obj->ring); } return 0; } int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { struct drm_i915_gem_set_domain *args = data; struct drm_i915_gem_object *obj; uint32_t read_domains = args->read_domains; uint32_t write_domain = args->write_domain; int ret; /* Only handle setting domains to types used by the CPU. */ if (write_domain & I915_GEM_GPU_DOMAINS) return -EINVAL; if (read_domains & I915_GEM_GPU_DOMAINS) return -EINVAL; /* Having something in the write domain implies it's in the read * domain, and only that read domain. Enforce that in the request. */ if (write_domain != 0 && read_domains != write_domain) return -EINVAL; ret = i915_mutex_lock_interruptible(dev); if (ret) return ret; obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); if (&obj->base == NULL) { ret = -ENOENT; goto unlock; } if (read_domains & I915_GEM_DOMAIN_GTT) { ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0); /* Silently promote "you're not bound, there was nothing to do" * to success, since the client was just asking us to * make sure everything was done. */ if (ret == -EINVAL) ret = 0; } else { ret = i915_gem_object_set_to_cpu_domain(obj, write_domain != 0); } drm_gem_object_unreference(&obj->base); unlock: DRM_UNLOCK(dev); return ret; } /** * Called when user space has done writes to this buffer */ int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { struct drm_i915_gem_sw_finish *args = data; struct drm_i915_gem_object *obj; int ret = 0; ret = i915_mutex_lock_interruptible(dev); if (ret) return ret; obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); if (&obj->base == NULL) { ret = -ENOENT; goto unlock; } /* Pinned buffers may be scanout, so flush the cache */ if (obj->pin_count) i915_gem_object_flush_cpu_write_domain(obj); drm_gem_object_unreference(&obj->base); unlock: DRM_UNLOCK(dev); return ret; } /** * Maps the contents of an object, returning the address it is mapped * into. * * While the mapping holds a reference on the contents of the object, it doesn't * imply a ref on the object itself. */ int i915_gem_mmap_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { struct drm_i915_gem_mmap *args = data; struct drm_gem_object *obj; struct proc *p; vm_map_t map; vm_offset_t addr; vm_size_t size; int error, rv; obj = drm_gem_object_lookup(dev, file, args->handle); if (obj == NULL) return -ENOENT; error = 0; if (args->size == 0) goto out; p = curproc; map = &p->p_vmspace->vm_map; size = round_page(args->size); PROC_LOCK(p); if (map->size + size > lim_cur_proc(p, RLIMIT_VMEM)) { PROC_UNLOCK(p); error = -ENOMEM; goto out; } PROC_UNLOCK(p); addr = 0; vm_object_reference(obj->vm_obj); rv = vm_map_find(map, obj->vm_obj, args->offset, &addr, args->size, 0, VMFS_OPTIMAL_SPACE, VM_PROT_READ | VM_PROT_WRITE, VM_PROT_READ | VM_PROT_WRITE, MAP_INHERIT_SHARE); if (rv != KERN_SUCCESS) { vm_object_deallocate(obj->vm_obj); error = -vm_mmap_to_errno(rv); } else { args->addr_ptr = (uint64_t)addr; } out: drm_gem_object_unreference(obj); return (error); } static int i915_gem_pager_ctor(void *handle, vm_ooffset_t size, vm_prot_t prot, vm_ooffset_t foff, struct ucred *cred, u_short *color) { *color = 0; /* XXXKIB */ return (0); } /** * i915_gem_fault - fault a page into the GTT * vma: VMA in question * vmf: fault info * * The fault handler is set up by drm_gem_mmap() when a object is GTT mapped * from userspace. The fault handler takes care of binding the object to * the GTT (if needed), allocating and programming a fence register (again, * only if needed based on whether the old reg is still valid or the object * is tiled) and inserting a new PTE into the faulting process. * * Note that the faulting process may involve evicting existing objects * from the GTT and/or fence registers to make room. So performance may * suffer if the GTT working set is large or there are few fence registers * left. */ int i915_intr_pf; static int i915_gem_pager_fault(vm_object_t vm_obj, vm_ooffset_t offset, int prot, vm_page_t *mres) { struct drm_gem_object *gem_obj; struct drm_i915_gem_object *obj; struct drm_device *dev; drm_i915_private_t *dev_priv; vm_page_t page, oldpage; int cause, ret; bool write; gem_obj = vm_obj->handle; obj = to_intel_bo(gem_obj); dev = obj->base.dev; dev_priv = dev->dev_private; #if 0 write = (prot & VM_PROT_WRITE) != 0; #else write = true; #endif vm_object_pip_add(vm_obj, 1); /* * Remove the placeholder page inserted by vm_fault() from the * object before dropping the object lock. If * i915_gem_release_mmap() is active in parallel on this gem * object, then it owns the drm device sx and might find the * placeholder already. Then, since the page is busy, * i915_gem_release_mmap() sleeps waiting for the busy state * of the page cleared. We will be not able to acquire drm * device lock until i915_gem_release_mmap() is able to make a * progress. */ if (*mres != NULL) { oldpage = *mres; vm_page_lock(oldpage); vm_page_remove(oldpage); vm_page_unlock(oldpage); *mres = NULL; } else oldpage = NULL; VM_OBJECT_WUNLOCK(vm_obj); retry: cause = ret = 0; page = NULL; if (i915_intr_pf) { ret = i915_mutex_lock_interruptible(dev); if (ret != 0) { cause = 10; goto out; } } else DRM_LOCK(dev); /* * Since the object lock was dropped, other thread might have * faulted on the same GTT address and instantiated the * mapping for the page. Recheck. */ VM_OBJECT_WLOCK(vm_obj); page = vm_page_lookup(vm_obj, OFF_TO_IDX(offset)); if (page != NULL) { if (vm_page_busied(page)) { DRM_UNLOCK(dev); vm_page_lock(page); VM_OBJECT_WUNLOCK(vm_obj); vm_page_busy_sleep(page, "915pee"); goto retry; } goto have_page; } else VM_OBJECT_WUNLOCK(vm_obj); /* Now bind it into the GTT if needed */ if (!obj->map_and_fenceable) { ret = i915_gem_object_unbind(obj); if (ret != 0) { cause = 20; goto unlock; } } if (!obj->gtt_space) { ret = i915_gem_object_bind_to_gtt(obj, 0, true); if (ret != 0) { cause = 30; goto unlock; } ret = i915_gem_object_set_to_gtt_domain(obj, write); if (ret != 0) { cause = 40; goto unlock; } } if (!obj->has_global_gtt_mapping) i915_gem_gtt_bind_object(obj, obj->cache_level); ret = i915_gem_object_get_fence(obj); if (ret != 0) { cause = 50; goto unlock; } if (i915_gem_object_is_inactive(obj)) list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list); obj->fault_mappable = true; VM_OBJECT_WLOCK(vm_obj); page = PHYS_TO_VM_PAGE(dev->agp->base + obj->gtt_offset + offset); KASSERT((page->flags & PG_FICTITIOUS) != 0, ("physical address %#jx not fictitious", (uintmax_t)(dev->agp->base + obj->gtt_offset + offset))); if (page == NULL) { VM_OBJECT_WUNLOCK(vm_obj); cause = 60; ret = -EFAULT; goto unlock; } KASSERT((page->flags & PG_FICTITIOUS) != 0, ("not fictitious %p", page)); KASSERT(page->wire_count == 1, ("wire_count not 1 %p", page)); if (vm_page_busied(page)) { DRM_UNLOCK(dev); vm_page_lock(page); VM_OBJECT_WUNLOCK(vm_obj); vm_page_busy_sleep(page, "915pbs"); goto retry; } if (vm_page_insert(page, vm_obj, OFF_TO_IDX(offset))) { DRM_UNLOCK(dev); VM_OBJECT_WUNLOCK(vm_obj); VM_WAIT; goto retry; } page->valid = VM_PAGE_BITS_ALL; have_page: *mres = page; vm_page_xbusy(page); CTR4(KTR_DRM, "fault %p %jx %x phys %x", gem_obj, offset, prot, page->phys_addr); DRM_UNLOCK(dev); if (oldpage != NULL) { vm_page_lock(oldpage); vm_page_free(oldpage); vm_page_unlock(oldpage); } vm_object_pip_wakeup(vm_obj); return (VM_PAGER_OK); unlock: DRM_UNLOCK(dev); out: KASSERT(ret != 0, ("i915_gem_pager_fault: wrong return")); CTR5(KTR_DRM, "fault_fail %p %jx %x err %d %d", gem_obj, offset, prot, -ret, cause); if (ret == -EAGAIN || ret == -EIO || ret == -EINTR) { kern_yield(PRI_USER); goto retry; } VM_OBJECT_WLOCK(vm_obj); vm_object_pip_wakeup(vm_obj); return (VM_PAGER_ERROR); } static void i915_gem_pager_dtor(void *handle) { struct drm_gem_object *obj; struct drm_device *dev; obj = handle; dev = obj->dev; DRM_LOCK(dev); drm_gem_free_mmap_offset(obj); i915_gem_release_mmap(to_intel_bo(obj)); drm_gem_object_unreference(obj); DRM_UNLOCK(dev); } struct cdev_pager_ops i915_gem_pager_ops = { .cdev_pg_fault = i915_gem_pager_fault, .cdev_pg_ctor = i915_gem_pager_ctor, .cdev_pg_dtor = i915_gem_pager_dtor }; /** * i915_gem_release_mmap - remove physical page mappings * @obj: obj in question * * Preserve the reservation of the mmapping with the DRM core code, but * relinquish ownership of the pages back to the system. * * It is vital that we remove the page mapping if we have mapped a tiled * object through the GTT and then lose the fence register due to * resource pressure. Similarly if the object has been moved out of the * aperture, than pages mapped into userspace must be revoked. Removing the * mapping will then trigger a page fault on the next user access, allowing * fixup by i915_gem_fault(). */ void i915_gem_release_mmap(struct drm_i915_gem_object *obj) { vm_object_t devobj; vm_page_t page; int i, page_count; if (!obj->fault_mappable) return; CTR3(KTR_DRM, "release_mmap %p %x %x", obj, obj->gtt_offset, OFF_TO_IDX(obj->base.size)); devobj = cdev_pager_lookup(obj); if (devobj != NULL) { page_count = OFF_TO_IDX(obj->base.size); VM_OBJECT_WLOCK(devobj); retry: for (i = 0; i < page_count; i++) { page = vm_page_lookup(devobj, i); if (page == NULL) continue; if (vm_page_sleep_if_busy(page, "915unm")) goto retry; cdev_pager_free_page(devobj, page); } VM_OBJECT_WUNLOCK(devobj); vm_object_deallocate(devobj); } obj->fault_mappable = false; } static uint32_t i915_gem_get_gtt_size(struct drm_device *dev, uint32_t size, int tiling_mode) { uint32_t gtt_size; if (INTEL_INFO(dev)->gen >= 4 || tiling_mode == I915_TILING_NONE) return size; /* Previous chips need a power-of-two fence region when tiling */ if (INTEL_INFO(dev)->gen == 3) gtt_size = 1024*1024; else gtt_size = 512*1024; while (gtt_size < size) gtt_size <<= 1; return gtt_size; } /** * i915_gem_get_gtt_alignment - return required GTT alignment for an object * @obj: object to check * * Return the required GTT alignment for an object, taking into account * potential fence register mapping. */ static uint32_t i915_gem_get_gtt_alignment(struct drm_device *dev, uint32_t size, int tiling_mode) { /* * Minimum alignment is 4k (GTT page size), but might be greater * if a fence register is needed for the object. */ if (INTEL_INFO(dev)->gen >= 4 || tiling_mode == I915_TILING_NONE) return 4096; /* * Previous chips need to be aligned to the size of the smallest * fence register that can contain the object. */ return i915_gem_get_gtt_size(dev, size, tiling_mode); } /** * i915_gem_get_unfenced_gtt_alignment - return required GTT alignment for an * unfenced object * @dev: the device * @size: size of the object * @tiling_mode: tiling mode of the object * * Return the required GTT alignment for an object, only taking into account * unfenced tiled surface requirements. */ uint32_t i915_gem_get_unfenced_gtt_alignment(struct drm_device *dev, uint32_t size, int tiling_mode) { /* * Minimum alignment is 4k (GTT page size) for sane hw. */ if (INTEL_INFO(dev)->gen >= 4 || IS_G33(dev) || tiling_mode == I915_TILING_NONE) return 4096; /* Previous hardware however needs to be aligned to a power-of-two * tile height. The simplest method for determining this is to reuse * the power-of-tile object size. */ return i915_gem_get_gtt_size(dev, size, tiling_mode); } int i915_gem_mmap_gtt(struct drm_file *file, struct drm_device *dev, uint32_t handle, uint64_t *offset) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj; int ret; ret = i915_mutex_lock_interruptible(dev); if (ret) return ret; obj = to_intel_bo(drm_gem_object_lookup(dev, file, handle)); if (&obj->base == NULL) { ret = -ENOENT; goto unlock; } if (obj->base.size > dev_priv->mm.gtt_mappable_end) { ret = -E2BIG; goto out; } if (obj->madv != I915_MADV_WILLNEED) { DRM_ERROR("Attempting to mmap a purgeable buffer\n"); ret = -EINVAL; goto out; } ret = drm_gem_create_mmap_offset(&obj->base); if (ret) goto out; *offset = DRM_GEM_MAPPING_OFF(obj->base.map_list.key) | DRM_GEM_MAPPING_KEY; out: drm_gem_object_unreference(&obj->base); unlock: DRM_UNLOCK(dev); return ret; } /** * i915_gem_mmap_gtt_ioctl - prepare an object for GTT mmap'ing * @dev: DRM device * @data: GTT mapping ioctl data * @file: GEM object info * * Simply returns the fake offset to userspace so it can mmap it. * The mmap call will end up in drm_gem_mmap(), which will set things * up so we can get faults in the handler above. * * The fault handler will take care of binding the object into the GTT * (since it may have been evicted to make room for something), allocating * a fence register, and mapping the appropriate aperture address into * userspace. */ int i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { struct drm_i915_gem_mmap_gtt *args = data; return i915_gem_mmap_gtt(file, dev, args->handle, &args->offset); } /* Immediately discard the backing storage */ static void i915_gem_object_truncate(struct drm_i915_gem_object *obj) { vm_object_t vm_obj; vm_obj = obj->base.vm_obj; VM_OBJECT_WLOCK(vm_obj); vm_object_page_remove(vm_obj, 0, 0, false); VM_OBJECT_WUNLOCK(vm_obj); drm_gem_free_mmap_offset(&obj->base); obj->madv = I915_MADV_PURGED_INTERNAL; } static inline int i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj) { return obj->madv == I915_MADV_DONTNEED; } static void i915_gem_object_put_pages_range_locked(struct drm_i915_gem_object *obj, vm_pindex_t si, vm_pindex_t ei) { vm_object_t vm_obj; vm_page_t page; vm_pindex_t i; vm_obj = obj->base.vm_obj; VM_OBJECT_ASSERT_LOCKED(vm_obj); for (i = si, page = vm_page_lookup(vm_obj, i); i < ei; page = vm_page_next(page), i++) { KASSERT(page->pindex == i, ("pindex %jx %jx", (uintmax_t)page->pindex, (uintmax_t)i)); vm_page_lock(page); vm_page_unwire(page, PQ_INACTIVE); if (page->wire_count == 0) atomic_add_long(&i915_gem_wired_pages_cnt, -1); vm_page_unlock(page); } } #define GEM_PARANOID_CHECK_GTT 0 #if GEM_PARANOID_CHECK_GTT static void i915_gem_assert_pages_not_mapped(struct drm_device *dev, vm_page_t *ma, int page_count) { struct drm_i915_private *dev_priv; vm_paddr_t pa; unsigned long start, end; u_int i; int j; dev_priv = dev->dev_private; start = OFF_TO_IDX(dev_priv->mm.gtt_start); end = OFF_TO_IDX(dev_priv->mm.gtt_end); for (i = start; i < end; i++) { pa = intel_gtt_read_pte_paddr(i); for (j = 0; j < page_count; j++) { if (pa == VM_PAGE_TO_PHYS(ma[j])) { panic("Page %p in GTT pte index %d pte %x", ma[i], i, intel_gtt_read_pte(i)); } } } } #endif static void i915_gem_object_put_pages_range(struct drm_i915_gem_object *obj, off_t start, off_t end) { vm_object_t vm_obj; vm_obj = obj->base.vm_obj; VM_OBJECT_WLOCK(vm_obj); i915_gem_object_put_pages_range_locked(obj, OFF_TO_IDX(trunc_page(start)), OFF_TO_IDX(round_page(end))); VM_OBJECT_WUNLOCK(vm_obj); } static void i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj) { vm_page_t page; int page_count, i; KASSERT(obj->madv != I915_MADV_PURGED_INTERNAL, ("Purged object")); if (obj->tiling_mode != I915_TILING_NONE) i915_gem_object_save_bit_17_swizzle(obj); if (obj->madv == I915_MADV_DONTNEED) obj->dirty = 0; page_count = obj->base.size / PAGE_SIZE; VM_OBJECT_WLOCK(obj->base.vm_obj); #if GEM_PARANOID_CHECK_GTT i915_gem_assert_pages_not_mapped(obj->base.dev, obj->pages, page_count); #endif for (i = 0; i < page_count; i++) { page = obj->pages[i]; if (obj->dirty) vm_page_dirty(page); if (obj->madv == I915_MADV_WILLNEED) vm_page_reference(page); vm_page_lock(page); vm_page_unwire(obj->pages[i], PQ_ACTIVE); vm_page_unlock(page); atomic_add_long(&i915_gem_wired_pages_cnt, -1); } VM_OBJECT_WUNLOCK(obj->base.vm_obj); obj->dirty = 0; free(obj->pages, DRM_I915_GEM); obj->pages = NULL; } static int i915_gpu_is_active(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; return (!list_empty(&dev_priv->mm.flushing_list) || !list_empty(&dev_priv->mm.active_list)); } static void i915_gem_lowmem(void *arg) { struct drm_device *dev; struct drm_i915_private *dev_priv; struct drm_i915_gem_object *obj, *next; int cnt, cnt_fail, cnt_total; dev = arg; dev_priv = dev->dev_private; if (!sx_try_xlock(&dev->dev_struct_lock)) return; CTR0(KTR_DRM, "gem_lowmem"); rescan: /* first scan for clean buffers */ i915_gem_retire_requests(dev); cnt_total = cnt_fail = cnt = 0; list_for_each_entry_safe(obj, next, &dev_priv->mm.inactive_list, mm_list) { if (i915_gem_object_is_purgeable(obj)) { if (i915_gem_object_unbind(obj) != 0) cnt_total++; } else cnt_total++; } /* second pass, evict/count anything still on the inactive list */ list_for_each_entry_safe(obj, next, &dev_priv->mm.inactive_list, mm_list) { if (i915_gem_object_unbind(obj) == 0) cnt++; else cnt_fail++; } if (cnt_fail > cnt_total / 100 && i915_gpu_is_active(dev)) { /* * We are desperate for pages, so as a last resort, wait * for the GPU to finish and discard whatever we can. * This has a dramatic impact to reduce the number of * OOM-killer events whilst running the GPU aggressively. */ if (i915_gpu_idle(dev) == 0) goto rescan; } DRM_UNLOCK(dev); } static int i915_gem_object_get_pages_range(struct drm_i915_gem_object *obj, off_t start, off_t end) { vm_object_t vm_obj; vm_page_t page; vm_pindex_t si, ei, i; bool need_swizzle, fresh; need_swizzle = i915_gem_object_needs_bit17_swizzle(obj) != 0; vm_obj = obj->base.vm_obj; si = OFF_TO_IDX(trunc_page(start)); ei = OFF_TO_IDX(round_page(end)); VM_OBJECT_WLOCK(vm_obj); for (i = si; i < ei; i++) { page = i915_gem_wire_page(vm_obj, i, &fresh); if (page == NULL) goto failed; if (need_swizzle && fresh) i915_gem_object_do_bit_17_swizzle_page(obj, page); } VM_OBJECT_WUNLOCK(vm_obj); return (0); failed: i915_gem_object_put_pages_range_locked(obj, si, i); VM_OBJECT_WUNLOCK(vm_obj); return (-EIO); } static int i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj, int flags) { vm_object_t vm_obj; vm_page_t page; vm_pindex_t i, page_count; int res; KASSERT(obj->pages == NULL, ("Obj already has pages")); page_count = OFF_TO_IDX(obj->base.size); obj->pages = malloc(page_count * sizeof(vm_page_t), DRM_I915_GEM, M_WAITOK); res = i915_gem_object_get_pages_range(obj, 0, obj->base.size); if (res != 0) { free(obj->pages, DRM_I915_GEM); obj->pages = NULL; return (res); } vm_obj = obj->base.vm_obj; VM_OBJECT_WLOCK(vm_obj); for (i = 0, page = vm_page_lookup(vm_obj, 0); i < page_count; i++, page = vm_page_next(page)) { KASSERT(page->pindex == i, ("pindex %jx %jx", (uintmax_t)page->pindex, (uintmax_t)i)); obj->pages[i] = page; } VM_OBJECT_WUNLOCK(vm_obj); return (0); } void i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, struct intel_ring_buffer *ring, uint32_t seqno) { struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_fence_reg *reg; KASSERT(ring != NULL, ("NULL ring")); obj->ring = ring; /* Add a reference if we're newly entering the active list. */ if (!obj->active) { drm_gem_object_reference(&obj->base); obj->active = 1; } /* Move from whatever list we were on to the tail of execution. */ list_move_tail(&obj->mm_list, &dev_priv->mm.active_list); list_move_tail(&obj->ring_list, &ring->active_list); obj->last_rendering_seqno = seqno; if (obj->fenced_gpu_access) { obj->last_fenced_seqno = seqno; /* Bump MRU to take account of the delayed flush */ if (obj->fence_reg != I915_FENCE_REG_NONE) { reg = &dev_priv->fence_regs[obj->fence_reg]; list_move_tail(®->lru_list, &dev_priv->mm.fence_list); } } } static void i915_gem_object_move_off_active(struct drm_i915_gem_object *obj) { list_del_init(&obj->ring_list); obj->last_rendering_seqno = 0; obj->last_fenced_seqno = 0; } static void i915_gem_object_move_to_flushing(struct drm_i915_gem_object *obj) { struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; KASSERT(obj->active, ("Object not active")); list_move_tail(&obj->mm_list, &dev_priv->mm.flushing_list); i915_gem_object_move_off_active(obj); } static void i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) { struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list); KASSERT(list_empty(&obj->gpu_write_list), ("On gpu_write_list")); KASSERT(obj->active, ("Object not active")); obj->ring = NULL; i915_gem_object_move_off_active(obj); obj->fenced_gpu_access = false; obj->active = 0; obj->pending_gpu_write = false; drm_gem_object_unreference(&obj->base); #if 1 KIB_NOTYET(); #else WARN_ON(i915_verify_lists(dev)); #endif } static u32 i915_gem_get_seqno(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; u32 seqno = dev_priv->next_seqno; /* reserve 0 for non-seqno */ if (++dev_priv->next_seqno == 0) dev_priv->next_seqno = 1; return seqno; } u32 i915_gem_next_request_seqno(struct intel_ring_buffer *ring) { if (ring->outstanding_lazy_request == 0) ring->outstanding_lazy_request = i915_gem_get_seqno(ring->dev); return ring->outstanding_lazy_request; } int i915_add_request(struct intel_ring_buffer *ring, struct drm_file *file, struct drm_i915_gem_request *request) { drm_i915_private_t *dev_priv = ring->dev->dev_private; struct drm_i915_file_private *file_priv; uint32_t seqno; u32 request_ring_position; int was_empty; int ret; KASSERT(request != NULL, ("NULL request in add")); DRM_LOCK_ASSERT(ring->dev); seqno = i915_gem_next_request_seqno(ring); request_ring_position = intel_ring_get_tail(ring); ret = ring->add_request(ring, &seqno); if (ret != 0) return ret; CTR2(KTR_DRM, "request_add %s %d", ring->name, seqno); request->seqno = seqno; request->ring = ring; request->tail = request_ring_position; request->emitted_jiffies = ticks; was_empty = list_empty(&ring->request_list); list_add_tail(&request->list, &ring->request_list); if (file) { file_priv = file->driver_priv; mtx_lock(&file_priv->mm.lck); request->file_priv = file_priv; list_add_tail(&request->client_list, &file_priv->mm.request_list); mtx_unlock(&file_priv->mm.lck); } ring->outstanding_lazy_request = 0; if (!dev_priv->mm.suspended) { if (i915_enable_hangcheck) { callout_schedule(&dev_priv->hangcheck_timer, DRM_I915_HANGCHECK_PERIOD); } if (was_empty) taskqueue_enqueue_timeout(dev_priv->tq, &dev_priv->mm.retire_task, hz); } return 0; } static inline void i915_gem_request_remove_from_client(struct drm_i915_gem_request *request) { struct drm_i915_file_private *file_priv = request->file_priv; if (!file_priv) return; DRM_LOCK_ASSERT(request->ring->dev); mtx_lock(&file_priv->mm.lck); if (request->file_priv) { list_del(&request->client_list); request->file_priv = NULL; } mtx_unlock(&file_priv->mm.lck); } static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv, struct intel_ring_buffer *ring) { if (ring->dev != NULL) DRM_LOCK_ASSERT(ring->dev); while (!list_empty(&ring->request_list)) { struct drm_i915_gem_request *request; request = list_first_entry(&ring->request_list, struct drm_i915_gem_request, list); list_del(&request->list); i915_gem_request_remove_from_client(request); free(request, DRM_I915_GEM); } while (!list_empty(&ring->active_list)) { struct drm_i915_gem_object *obj; obj = list_first_entry(&ring->active_list, struct drm_i915_gem_object, ring_list); obj->base.write_domain = 0; list_del_init(&obj->gpu_write_list); i915_gem_object_move_to_inactive(obj); } } static void i915_gem_reset_fences(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int i; for (i = 0; i < dev_priv->num_fence_regs; i++) { struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i]; i915_gem_write_fence(dev, i, NULL); if (reg->obj) i915_gem_object_fence_lost(reg->obj); reg->pin_count = 0; reg->obj = NULL; INIT_LIST_HEAD(®->lru_list); } INIT_LIST_HEAD(&dev_priv->mm.fence_list); } void i915_gem_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj; struct intel_ring_buffer *ring; int i; for_each_ring(ring, dev_priv, i) i915_gem_reset_ring_lists(dev_priv, ring); /* Remove anything from the flushing lists. The GPU cache is likely * to be lost on reset along with the data, so simply move the * lost bo to the inactive list. */ while (!list_empty(&dev_priv->mm.flushing_list)) { obj = list_first_entry(&dev_priv->mm.flushing_list, struct drm_i915_gem_object, mm_list); obj->base.write_domain = 0; list_del_init(&obj->gpu_write_list); i915_gem_object_move_to_inactive(obj); } /* Move everything out of the GPU domains to ensure we do any * necessary invalidation upon reuse. */ list_for_each_entry(obj, &dev_priv->mm.inactive_list, mm_list) { obj->base.read_domains &= ~I915_GEM_GPU_DOMAINS; } /* The fence registers are invalidated so clear them out */ i915_gem_reset_fences(dev); } /** * This function clears the request list as sequence numbers are passed. */ void i915_gem_retire_requests_ring(struct intel_ring_buffer *ring) { uint32_t seqno; int i; if (list_empty(&ring->request_list)) return; seqno = ring->get_seqno(ring); CTR2(KTR_DRM, "retire_request_ring %s %d", ring->name, seqno); for (i = 0; i < ARRAY_SIZE(ring->sync_seqno); i++) if (seqno >= ring->sync_seqno[i]) ring->sync_seqno[i] = 0; while (!list_empty(&ring->request_list)) { struct drm_i915_gem_request *request; request = list_first_entry(&ring->request_list, struct drm_i915_gem_request, list); if (!i915_seqno_passed(seqno, request->seqno)) break; CTR2(KTR_DRM, "retire_request_seqno_passed %s %d", ring->name, seqno); ring->last_retired_head = request->tail; list_del(&request->list); i915_gem_request_remove_from_client(request); free(request, DRM_I915_GEM); } /* Move any buffers on the active list that are no longer referenced * by the ringbuffer to the flushing/inactive lists as appropriate. */ while (!list_empty(&ring->active_list)) { struct drm_i915_gem_object *obj; obj = list_first_entry(&ring->active_list, struct drm_i915_gem_object, ring_list); if (!i915_seqno_passed(seqno, obj->last_rendering_seqno)) break; if (obj->base.write_domain != 0) i915_gem_object_move_to_flushing(obj); else i915_gem_object_move_to_inactive(obj); } if (ring->trace_irq_seqno && i915_seqno_passed(seqno, ring->trace_irq_seqno)) { struct drm_i915_private *dev_priv = ring->dev->dev_private; mtx_lock(&dev_priv->irq_lock); ring->irq_put(ring); mtx_unlock(&dev_priv->irq_lock); ring->trace_irq_seqno = 0; } } void i915_gem_retire_requests(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; struct intel_ring_buffer *ring; int i; for_each_ring(ring, dev_priv, i) i915_gem_retire_requests_ring(ring); } static void i915_gem_process_flushing_list(struct intel_ring_buffer *ring, uint32_t flush_domains) { struct drm_i915_gem_object *obj, *next; uint32_t old_write_domain; list_for_each_entry_safe(obj, next, &ring->gpu_write_list, gpu_write_list) { if (obj->base.write_domain & flush_domains) { old_write_domain = obj->base.write_domain; obj->base.write_domain = 0; list_del_init(&obj->gpu_write_list); i915_gem_object_move_to_active(obj, ring, i915_gem_next_request_seqno(ring)); CTR3(KTR_DRM, "object_change_domain process_flush %p %x %x", obj, obj->base.read_domains, old_write_domain); } } } int i915_gem_flush_ring(struct intel_ring_buffer *ring, uint32_t invalidate_domains, uint32_t flush_domains) { int ret; if (((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) == 0) return 0; CTR3(KTR_DRM, "ring_flush %s %x %x", ring->name, invalidate_domains, flush_domains); ret = ring->flush(ring, invalidate_domains, flush_domains); if (ret) return ret; if (flush_domains & I915_GEM_GPU_DOMAINS) i915_gem_process_flushing_list(ring, flush_domains); return 0; } static void i915_gem_retire_task_handler(void *arg, int pending) { drm_i915_private_t *dev_priv; struct drm_device *dev; struct intel_ring_buffer *ring; bool idle; int i; dev_priv = arg; dev = dev_priv->dev; /* Come back later if the device is busy... */ if (!sx_try_xlock(&dev->dev_struct_lock)) { taskqueue_enqueue_timeout(dev_priv->tq, &dev_priv->mm.retire_task, hz); return; } CTR0(KTR_DRM, "retire_task"); i915_gem_retire_requests(dev); /* Send a periodic flush down the ring so we don't hold onto GEM * objects indefinitely. */ idle = true; for_each_ring(ring, dev_priv, i) { struct intel_ring_buffer *ring = &dev_priv->rings[i]; if (!list_empty(&ring->gpu_write_list)) { struct drm_i915_gem_request *request; int ret; ret = i915_gem_flush_ring(ring, 0, I915_GEM_GPU_DOMAINS); request = malloc(sizeof(*request), DRM_I915_GEM, M_WAITOK | M_ZERO); if (ret || request == NULL || i915_add_request(ring, NULL, request)) free(request, DRM_I915_GEM); } idle &= list_empty(&ring->request_list); } if (!dev_priv->mm.suspended && !idle) taskqueue_enqueue_timeout(dev_priv->tq, &dev_priv->mm.retire_task, hz); DRM_UNLOCK(dev); } int i915_gem_object_sync(struct drm_i915_gem_object *obj, struct intel_ring_buffer *to) { struct intel_ring_buffer *from = obj->ring; u32 seqno; int ret, idx; if (from == NULL || to == from) return 0; if (to == NULL || !i915_semaphore_is_enabled(obj->base.dev)) return i915_gem_object_wait_rendering(obj); idx = intel_ring_sync_index(from, to); seqno = obj->last_rendering_seqno; if (seqno <= from->sync_seqno[idx]) return 0; if (seqno == from->outstanding_lazy_request) { struct drm_i915_gem_request *request; request = malloc(sizeof(*request), DRM_I915_GEM, M_WAITOK | M_ZERO); ret = i915_add_request(from, NULL, request); if (ret) { free(request, DRM_I915_GEM); return ret; } seqno = request->seqno; } ret = to->sync_to(to, from, seqno); if (!ret) from->sync_seqno[idx] = seqno; return ret; } static void i915_gem_object_finish_gtt(struct drm_i915_gem_object *obj) { u32 old_write_domain, old_read_domains; /* Act a barrier for all accesses through the GTT */ mb(); /* Force a pagefault for domain tracking on next user access */ i915_gem_release_mmap(obj); if ((obj->base.read_domains & I915_GEM_DOMAIN_GTT) == 0) return; old_read_domains = obj->base.read_domains; old_write_domain = obj->base.write_domain; obj->base.read_domains &= ~I915_GEM_DOMAIN_GTT; obj->base.write_domain &= ~I915_GEM_DOMAIN_GTT; CTR3(KTR_DRM, "object_change_domain finish gtt %p %x %x", obj, old_read_domains, old_write_domain); } /** * Unbinds an object from the GTT aperture. */ int i915_gem_object_unbind(struct drm_i915_gem_object *obj) { drm_i915_private_t *dev_priv = obj->base.dev->dev_private; int ret = 0; if (obj->gtt_space == NULL) return 0; - if (obj->pin_count) { - DRM_ERROR("Attempting to unbind pinned buffer\n"); + if (obj->pin_count) return -EINVAL; - } ret = i915_gem_object_finish_gpu(obj); if (ret == -ERESTARTSYS || ret == -EINTR) return ret; i915_gem_object_finish_gtt(obj); if (ret == 0) ret = i915_gem_object_set_to_cpu_domain(obj, 1); if (ret == -ERESTARTSYS || ret == -EINTR) return ret; if (ret != 0) { i915_gem_clflush_object(obj); obj->base.read_domains = obj->base.write_domain = I915_GEM_DOMAIN_CPU; } /* release the fence reg _after_ flushing */ ret = i915_gem_object_put_fence(obj); if (ret) return ret; if (obj->has_global_gtt_mapping) i915_gem_gtt_unbind_object(obj); if (obj->has_aliasing_ppgtt_mapping) { i915_ppgtt_unbind_object(dev_priv->mm.aliasing_ppgtt, obj); obj->has_aliasing_ppgtt_mapping = 0; } i915_gem_gtt_finish_object(obj); i915_gem_object_put_pages_gtt(obj); list_del_init(&obj->gtt_list); list_del_init(&obj->mm_list); obj->map_and_fenceable = true; drm_mm_put_block(obj->gtt_space); obj->gtt_space = NULL; obj->gtt_offset = 0; if (i915_gem_object_is_purgeable(obj)) i915_gem_object_truncate(obj); CTR1(KTR_DRM, "object_unbind %p", obj); return ret; } static int i915_ring_idle(struct intel_ring_buffer *ring) { int ret; if (list_empty(&ring->gpu_write_list) && list_empty(&ring->active_list)) return 0; if (!list_empty(&ring->gpu_write_list)) { ret = i915_gem_flush_ring(ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); if (ret != 0) return ret; } return (i915_wait_request(ring, i915_gem_next_request_seqno(ring))); } int i915_gpu_idle(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; struct intel_ring_buffer *ring; int ret, i; /* Flush everything onto the inactive list. */ for_each_ring(ring, dev_priv, i) { ret = i915_switch_context(ring, NULL, DEFAULT_CONTEXT_ID); if (ret) return ret; ret = i915_ring_idle(ring); if (ret) return ret; /* Is the device fubar? */ if (!list_empty(&ring->gpu_write_list)) return -EBUSY; } return 0; } static void sandybridge_write_fence_reg(struct drm_device *dev, int reg, struct drm_i915_gem_object *obj) { drm_i915_private_t *dev_priv = dev->dev_private; uint64_t val; if (obj) { u32 size = obj->gtt_space->size; val = (uint64_t)((obj->gtt_offset + size - 4096) & 0xfffff000) << 32; val |= obj->gtt_offset & 0xfffff000; val |= (uint64_t)((obj->stride / 128) - 1) << SANDYBRIDGE_FENCE_PITCH_SHIFT; if (obj->tiling_mode == I915_TILING_Y) val |= 1 << I965_FENCE_TILING_Y_SHIFT; val |= I965_FENCE_REG_VALID; } else val = 0; I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + reg * 8, val); POSTING_READ(FENCE_REG_SANDYBRIDGE_0 + reg * 8); } static void i965_write_fence_reg(struct drm_device *dev, int reg, struct drm_i915_gem_object *obj) { drm_i915_private_t *dev_priv = dev->dev_private; uint64_t val; if (obj) { u32 size = obj->gtt_space->size; val = (uint64_t)((obj->gtt_offset + size - 4096) & 0xfffff000) << 32; val |= obj->gtt_offset & 0xfffff000; val |= ((obj->stride / 128) - 1) << I965_FENCE_PITCH_SHIFT; if (obj->tiling_mode == I915_TILING_Y) val |= 1 << I965_FENCE_TILING_Y_SHIFT; val |= I965_FENCE_REG_VALID; } else val = 0; I915_WRITE64(FENCE_REG_965_0 + reg * 8, val); POSTING_READ(FENCE_REG_965_0 + reg * 8); } static void i915_write_fence_reg(struct drm_device *dev, int reg, struct drm_i915_gem_object *obj) { drm_i915_private_t *dev_priv = dev->dev_private; u32 val; if (obj) { u32 size = obj->gtt_space->size; int pitch_val; int tile_width; if ((obj->gtt_offset & ~I915_FENCE_START_MASK) || (size & -size) != size || (obj->gtt_offset & (size - 1))) printf( "object 0x%08x [fenceable? %d] not 1M or pot-size (0x%08x) aligned\n", obj->gtt_offset, obj->map_and_fenceable, size); if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)) tile_width = 128; else tile_width = 512; /* Note: pitch better be a power of two tile widths */ pitch_val = obj->stride / tile_width; pitch_val = ffs(pitch_val) - 1; val = obj->gtt_offset; if (obj->tiling_mode == I915_TILING_Y) val |= 1 << I830_FENCE_TILING_Y_SHIFT; val |= I915_FENCE_SIZE_BITS(size); val |= pitch_val << I830_FENCE_PITCH_SHIFT; val |= I830_FENCE_REG_VALID; } else val = 0; if (reg < 8) reg = FENCE_REG_830_0 + reg * 4; else reg = FENCE_REG_945_8 + (reg - 8) * 4; I915_WRITE(reg, val); POSTING_READ(reg); } static void i830_write_fence_reg(struct drm_device *dev, int reg, struct drm_i915_gem_object *obj) { drm_i915_private_t *dev_priv = dev->dev_private; uint32_t val; if (obj) { u32 size = obj->gtt_space->size; uint32_t pitch_val; if ((obj->gtt_offset & ~I830_FENCE_START_MASK) || (size & -size) != size || (obj->gtt_offset & (size - 1))) printf( "object 0x%08x not 512K or pot-size 0x%08x aligned\n", obj->gtt_offset, size); pitch_val = obj->stride / 128; pitch_val = ffs(pitch_val) - 1; val = obj->gtt_offset; if (obj->tiling_mode == I915_TILING_Y) val |= 1 << I830_FENCE_TILING_Y_SHIFT; val |= I830_FENCE_SIZE_BITS(size); val |= pitch_val << I830_FENCE_PITCH_SHIFT; val |= I830_FENCE_REG_VALID; } else val = 0; I915_WRITE(FENCE_REG_830_0 + reg * 4, val); POSTING_READ(FENCE_REG_830_0 + reg * 4); } static void i915_gem_write_fence(struct drm_device *dev, int reg, struct drm_i915_gem_object *obj) { switch (INTEL_INFO(dev)->gen) { case 7: case 6: sandybridge_write_fence_reg(dev, reg, obj); break; case 5: case 4: i965_write_fence_reg(dev, reg, obj); break; case 3: i915_write_fence_reg(dev, reg, obj); break; case 2: i830_write_fence_reg(dev, reg, obj); break; default: break; } } static inline int fence_number(struct drm_i915_private *dev_priv, struct drm_i915_fence_reg *fence) { return fence - dev_priv->fence_regs; } static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, struct drm_i915_fence_reg *fence, bool enable) { struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; int fence_reg = fence_number(dev_priv, fence); i915_gem_write_fence(dev, fence_reg, enable ? obj : NULL); if (enable) { obj->fence_reg = fence_reg; fence->obj = obj; list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list); } else { obj->fence_reg = I915_FENCE_REG_NONE; fence->obj = NULL; list_del_init(&fence->lru_list); } } static int i915_gem_object_flush_fence(struct drm_i915_gem_object *obj) { int ret; if (obj->fenced_gpu_access) { if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) { ret = i915_gem_flush_ring(obj->ring, 0, obj->base.write_domain); if (ret) return ret; } obj->fenced_gpu_access = false; } if (obj->last_fenced_seqno) { ret = i915_wait_request(obj->ring, obj->last_fenced_seqno); if (ret) return ret; obj->last_fenced_seqno = 0; } /* Ensure that all CPU reads are completed before installing a fence * and all writes before removing the fence. */ if (obj->base.read_domains & I915_GEM_DOMAIN_GTT) mb(); return 0; } int i915_gem_object_put_fence(struct drm_i915_gem_object *obj) { struct drm_i915_private *dev_priv = obj->base.dev->dev_private; int ret; ret = i915_gem_object_flush_fence(obj); if (ret) return ret; if (obj->fence_reg == I915_FENCE_REG_NONE) return 0; i915_gem_object_update_fence(obj, &dev_priv->fence_regs[obj->fence_reg], false); i915_gem_object_fence_lost(obj); return 0; } static struct drm_i915_fence_reg * i915_find_fence_reg(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_fence_reg *reg, *avail; int i; /* First try to find a free reg */ avail = NULL; for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) { reg = &dev_priv->fence_regs[i]; if (!reg->obj) return reg; if (!reg->pin_count) avail = reg; } if (avail == NULL) return NULL; /* None available, try to steal one or wait for a user to finish */ list_for_each_entry(reg, &dev_priv->mm.fence_list, lru_list) { if (reg->pin_count) continue; return reg; } return NULL; } /** * i915_gem_object_get_fence - set up fencing for an object * @obj: object to map through a fence reg * * When mapping objects through the GTT, userspace wants to be able to write * to them without having to worry about swizzling if the object is tiled. * This function walks the fence regs looking for a free one for @obj, * stealing one if it can't find any. * * It then sets up the reg based on the object's properties: address, pitch * and tiling format. * * For an untiled surface, this removes any existing fence. */ int i915_gem_object_get_fence(struct drm_i915_gem_object *obj) { struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; bool enable = obj->tiling_mode != I915_TILING_NONE; struct drm_i915_fence_reg *reg; int ret; /* Have we updated the tiling parameters upon the object and so * will need to serialise the write to the associated fence register? */ if (obj->fence_dirty) { ret = i915_gem_object_flush_fence(obj); if (ret) return ret; } /* Just update our place in the LRU if our fence is getting reused. */ if (obj->fence_reg != I915_FENCE_REG_NONE) { reg = &dev_priv->fence_regs[obj->fence_reg]; if (!obj->fence_dirty) { list_move_tail(®->lru_list, &dev_priv->mm.fence_list); return 0; } } else if (enable) { reg = i915_find_fence_reg(dev); if (reg == NULL) return -EDEADLK; if (reg->obj) { struct drm_i915_gem_object *old = reg->obj; ret = i915_gem_object_flush_fence(old); if (ret) return ret; i915_gem_object_fence_lost(old); } } else return 0; i915_gem_object_update_fence(obj, reg, enable); obj->fence_dirty = false; return 0; } /** * Finds free space in the GTT aperture and binds the object there. */ static int i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, unsigned alignment, bool map_and_fenceable) { struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; struct drm_mm_node *free_space; u32 size, fence_size, fence_alignment, unfenced_alignment; bool mappable, fenceable; int ret; if (obj->madv != I915_MADV_WILLNEED) { DRM_ERROR("Attempting to bind a purgeable object\n"); return -EINVAL; } fence_size = i915_gem_get_gtt_size(dev, obj->base.size, obj->tiling_mode); fence_alignment = i915_gem_get_gtt_alignment(dev, obj->base.size, obj->tiling_mode); unfenced_alignment = i915_gem_get_unfenced_gtt_alignment(dev, obj->base.size, obj->tiling_mode); if (alignment == 0) alignment = map_and_fenceable ? fence_alignment : unfenced_alignment; if (map_and_fenceable && alignment & (fence_alignment - 1)) { DRM_ERROR("Invalid object alignment requested %u\n", alignment); return -EINVAL; } size = map_and_fenceable ? fence_size : obj->base.size; /* If the object is bigger than the entire aperture, reject it early * before evicting everything in a vain attempt to find space. */ if (obj->base.size > (map_and_fenceable ? dev_priv->mm.gtt_mappable_end : dev_priv->mm.gtt_total)) { DRM_ERROR("Attempting to bind an object larger than the aperture\n"); return -E2BIG; } search_free: if (map_and_fenceable) free_space = drm_mm_search_free_in_range( &dev_priv->mm.gtt_space, size, alignment, 0, dev_priv->mm.gtt_mappable_end, 0); else free_space = drm_mm_search_free(&dev_priv->mm.gtt_space, size, alignment, 0); if (free_space != NULL) { if (map_and_fenceable) obj->gtt_space = drm_mm_get_block_range_generic( free_space, size, alignment, 0, 0, dev_priv->mm.gtt_mappable_end, 1); else obj->gtt_space = drm_mm_get_block_generic(free_space, size, alignment, 0, 1); } if (obj->gtt_space == NULL) { ret = i915_gem_evict_something(dev, size, alignment, map_and_fenceable); if (ret != 0) return ret; goto search_free; } ret = i915_gem_object_get_pages_gtt(obj, 0); if (ret) { drm_mm_put_block(obj->gtt_space); obj->gtt_space = NULL; /* * i915_gem_object_get_pages_gtt() cannot return * ENOMEM, since we use vm_page_grab(). */ return ret; } ret = i915_gem_gtt_prepare_object(obj); if (ret) { i915_gem_object_put_pages_gtt(obj); drm_mm_put_block(obj->gtt_space); obj->gtt_space = NULL; if (i915_gem_evict_everything(dev, false)) return ret; goto search_free; } if (!dev_priv->mm.aliasing_ppgtt) i915_gem_gtt_bind_object(obj, obj->cache_level); list_add_tail(&obj->gtt_list, &dev_priv->mm.gtt_list); list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list); KASSERT((obj->base.read_domains & I915_GEM_GPU_DOMAINS) == 0, ("Object in gpu read domain")); KASSERT((obj->base.write_domain & I915_GEM_GPU_DOMAINS) == 0, ("Object in gpu write domain")); obj->gtt_offset = obj->gtt_space->start; fenceable = obj->gtt_space->size == fence_size && (obj->gtt_space->start & (fence_alignment - 1)) == 0; mappable = obj->gtt_offset + obj->base.size <= dev_priv->mm.gtt_mappable_end; obj->map_and_fenceable = mappable && fenceable; CTR4(KTR_DRM, "object_bind %p %x %x %d", obj, obj->gtt_offset, obj->base.size, map_and_fenceable); return 0; } void i915_gem_clflush_object(struct drm_i915_gem_object *obj) { /* If we don't have a page list set up, then we're not pinned * to GPU, and we can ignore the cache flush because it'll happen * again at bind time. */ if (obj->pages == NULL) return; /* If the GPU is snooping the contents of the CPU cache, * we do not need to manually clear the CPU cache lines. However, * the caches are only snooped when the render cache is * flushed/invalidated. As we always have to emit invalidations * and flushes when moving into and out of the RENDER domain, correct * snooping behaviour occurs naturally as the result of our domain * tracking. */ if (obj->cache_level != I915_CACHE_NONE) return; CTR1(KTR_DRM, "object_clflush %p", obj); drm_clflush_pages(obj->pages, obj->base.size / PAGE_SIZE); } /** Flushes the GTT write domain for the object if it's dirty. */ static void i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj) { uint32_t old_write_domain; if (obj->base.write_domain != I915_GEM_DOMAIN_GTT) return; /* No actual flushing is required for the GTT write domain. Writes * to it immediately go to main memory as far as we know, so there's * no chipset flush. It also doesn't land in render cache. * * However, we do have to enforce the order so that all writes through * the GTT land before any writes to the device, such as updates to * the GATT itself. */ wmb(); old_write_domain = obj->base.write_domain; obj->base.write_domain = 0; CTR3(KTR_DRM, "object_change_domain flush gtt_write %p %x %x", obj, obj->base.read_domains, old_write_domain); } /** Flushes the CPU write domain for the object if it's dirty. */ static void i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj) { uint32_t old_write_domain; if (obj->base.write_domain != I915_GEM_DOMAIN_CPU) return; i915_gem_clflush_object(obj); intel_gtt_chipset_flush(); old_write_domain = obj->base.write_domain; obj->base.write_domain = 0; CTR3(KTR_DRM, "object_change_domain flush_cpu_write %p %x %x", obj, obj->base.read_domains, old_write_domain); } static int i915_gem_object_flush_gpu_write_domain(struct drm_i915_gem_object *obj) { if ((obj->base.write_domain & I915_GEM_GPU_DOMAINS) == 0) return (0); return (i915_gem_flush_ring(obj->ring, 0, obj->base.write_domain)); } /** * Moves a single object to the GTT read, and possibly write domain. * * This function returns when the move is complete, including waiting on * flushes to occur. */ int i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) { drm_i915_private_t *dev_priv = obj->base.dev->dev_private; uint32_t old_write_domain, old_read_domains; int ret; /* Not valid to be called on unbound objects. */ if (obj->gtt_space == NULL) return -EINVAL; if (obj->base.write_domain == I915_GEM_DOMAIN_GTT) return 0; ret = i915_gem_object_flush_gpu_write_domain(obj); if (ret) return ret; if (obj->pending_gpu_write || write) { ret = i915_gem_object_wait_rendering(obj); if (ret) return (ret); } i915_gem_object_flush_cpu_write_domain(obj); old_write_domain = obj->base.write_domain; old_read_domains = obj->base.read_domains; /* It should now be out of any other write domains, and we can update * the domain values for our changes. */ KASSERT((obj->base.write_domain & ~I915_GEM_DOMAIN_GTT) == 0, ("In GTT write domain")); obj->base.read_domains |= I915_GEM_DOMAIN_GTT; if (write) { obj->base.read_domains = I915_GEM_DOMAIN_GTT; obj->base.write_domain = I915_GEM_DOMAIN_GTT; obj->dirty = 1; } CTR3(KTR_DRM, "object_change_domain set_to_gtt %p %x %x", obj, old_read_domains, old_write_domain); /* And bump the LRU for this access */ if (i915_gem_object_is_inactive(obj)) list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list); return 0; } int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, enum i915_cache_level cache_level) { struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; int ret; if (obj->cache_level == cache_level) return 0; if (obj->pin_count) { DRM_DEBUG("can not change the cache level of pinned objects\n"); return -EBUSY; } if (obj->gtt_space) { ret = i915_gem_object_finish_gpu(obj); if (ret) return ret; i915_gem_object_finish_gtt(obj); /* Before SandyBridge, you could not use tiling or fence * registers with snooped memory, so relinquish any fences * currently pointing to our region in the aperture. */ if (INTEL_INFO(obj->base.dev)->gen < 6) { ret = i915_gem_object_put_fence(obj); if (ret) return ret; } if (obj->has_global_gtt_mapping) i915_gem_gtt_bind_object(obj, cache_level); if (obj->has_aliasing_ppgtt_mapping) i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt, obj, cache_level); } if (cache_level == I915_CACHE_NONE) { u32 old_read_domains, old_write_domain; /* If we're coming from LLC cached, then we haven't * actually been tracking whether the data is in the * CPU cache or not, since we only allow one bit set * in obj->write_domain and have been skipping the clflushes. * Just set it to the CPU cache for now. */ KASSERT((obj->base.write_domain & ~I915_GEM_DOMAIN_CPU) == 0, ("obj %p in CPU write domain", obj)); KASSERT((obj->base.read_domains & ~I915_GEM_DOMAIN_CPU) == 0, ("obj %p in CPU read domain", obj)); old_read_domains = obj->base.read_domains; old_write_domain = obj->base.write_domain; obj->base.read_domains = I915_GEM_DOMAIN_CPU; obj->base.write_domain = I915_GEM_DOMAIN_CPU; CTR3(KTR_DRM, "object_change_domain set_cache_level %p %x %x", obj, old_read_domains, old_write_domain); } obj->cache_level = cache_level; return 0; } static bool is_pin_display(struct drm_i915_gem_object *obj) { /* There are 3 sources that pin objects: * 1. The display engine (scanouts, sprites, cursors); * 2. Reservations for execbuffer; * 3. The user. * * We can ignore reservations as we hold the struct_mutex and * are only called outside of the reservation path. The user * can only increment pin_count once, and so if after * subtracting the potential reference by the user, any pin_count * remains, it must be due to another use by the display engine. */ return obj->pin_count - !!obj->user_pin_count; } int i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, u32 alignment, struct intel_ring_buffer *pipelined) { u32 old_read_domains, old_write_domain; int ret; ret = i915_gem_object_flush_gpu_write_domain(obj); if (ret) return ret; if (pipelined != obj->ring) { ret = i915_gem_object_sync(obj, pipelined); if (ret) return ret; } /* Mark the pin_display early so that we account for the * display coherency whilst setting up the cache domains. */ obj->pin_display = true; /* The display engine is not coherent with the LLC cache on gen6. As * a result, we make sure that the pinning that is about to occur is * done with uncached PTEs. This is lowest common denominator for all * chipsets. * * However for gen6+, we could do better by using the GFDT bit instead * of uncaching, which would allow us to flush all the LLC-cached data * with that bit in the PTE to main memory with just one PIPE_CONTROL. */ ret = i915_gem_object_set_cache_level(obj, I915_CACHE_NONE); if (ret) goto err_unpin_display; /* As the user may map the buffer once pinned in the display plane * (e.g. libkms for the bootup splash), we have to ensure that we * always use map_and_fenceable for all scanout buffers. */ ret = i915_gem_object_pin(obj, alignment, true); if (ret) goto err_unpin_display; i915_gem_object_flush_cpu_write_domain(obj); old_write_domain = obj->base.write_domain; old_read_domains = obj->base.read_domains; KASSERT((obj->base.write_domain & ~I915_GEM_DOMAIN_GTT) == 0, ("obj %p in GTT write domain", obj)); obj->base.read_domains |= I915_GEM_DOMAIN_GTT; CTR3(KTR_DRM, "object_change_domain pin_to_display_plan %p %x %x", obj, old_read_domains, obj->base.write_domain); return 0; err_unpin_display: obj->pin_display = is_pin_display(obj); return ret; } void i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj) { i915_gem_object_unpin(obj); obj->pin_display = is_pin_display(obj); } int i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj) { int ret; if ((obj->base.read_domains & I915_GEM_GPU_DOMAINS) == 0) return 0; if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) { ret = i915_gem_flush_ring(obj->ring, 0, obj->base.write_domain); if (ret) return ret; } ret = i915_gem_object_wait_rendering(obj); if (ret) return ret; /* Ensure that we invalidate the GPU's caches and TLBs. */ obj->base.read_domains &= ~I915_GEM_GPU_DOMAINS; return 0; } /** * Moves a single object to the CPU read, and possibly write domain. * * This function returns when the move is complete, including waiting on * flushes to occur. */ int i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write) { uint32_t old_write_domain, old_read_domains; int ret; if (obj->base.write_domain == I915_GEM_DOMAIN_CPU) return 0; ret = i915_gem_object_flush_gpu_write_domain(obj); if (ret) return ret; if (write || obj->pending_gpu_write) { ret = i915_gem_object_wait_rendering(obj); if (ret) return ret; } i915_gem_object_flush_gtt_write_domain(obj); old_write_domain = obj->base.write_domain; old_read_domains = obj->base.read_domains; /* Flush the CPU cache if it's still invalid. */ if ((obj->base.read_domains & I915_GEM_DOMAIN_CPU) == 0) { i915_gem_clflush_object(obj); obj->base.read_domains |= I915_GEM_DOMAIN_CPU; } /* It should now be out of any other write domains, and we can update * the domain values for our changes. */ KASSERT((obj->base.write_domain & ~I915_GEM_DOMAIN_CPU) == 0, ("In cpu write domain")); /* If we're writing through the CPU, then the GPU read domains will * need to be invalidated at next use. */ if (write) { obj->base.read_domains = I915_GEM_DOMAIN_CPU; obj->base.write_domain = I915_GEM_DOMAIN_CPU; } CTR3(KTR_DRM, "object_change_domain set_to_cpu %p %x %x", obj, old_read_domains, old_write_domain); return 0; } /* Throttle our rendering by waiting until the ring has completed our requests * emitted over 20 msec ago. * * Note that if we were to use the current jiffies each time around the loop, * we wouldn't escape the function with any frames outstanding if the time to * render a frame was over 20ms. * * This should get us reasonable parallelism between CPU and GPU but also * relatively low latency when blocking on a particular request to finish. */ static int i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_file_private *file_priv = file->driver_priv; unsigned long recent_enough = ticks - (20 * hz / 1000); struct drm_i915_gem_request *request; struct intel_ring_buffer *ring = NULL; u32 seqno = 0; int ret; if (atomic_load_acq_int(&dev_priv->mm.wedged)) return -EIO; mtx_lock(&file_priv->mm.lck); list_for_each_entry(request, &file_priv->mm.request_list, client_list) { if (time_after_eq(request->emitted_jiffies, recent_enough)) break; ring = request->ring; seqno = request->seqno; } mtx_unlock(&file_priv->mm.lck); if (seqno == 0) return 0; ret = __wait_seqno(ring, seqno, true); if (ret == 0) taskqueue_enqueue_timeout(dev_priv->tq, &dev_priv->mm.retire_task, 0); return ret; } int i915_gem_object_pin(struct drm_i915_gem_object *obj, uint32_t alignment, bool map_and_fenceable) { int ret; if (obj->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT) return -EBUSY; if (obj->gtt_space != NULL) { if ((alignment && obj->gtt_offset & (alignment - 1)) || (map_and_fenceable && !obj->map_and_fenceable)) { DRM_DEBUG("bo is already pinned with incorrect alignment:" " offset=%x, req.alignment=%x, req.map_and_fenceable=%d," " obj->map_and_fenceable=%d\n", obj->gtt_offset, alignment, map_and_fenceable, obj->map_and_fenceable); ret = i915_gem_object_unbind(obj); if (ret) return ret; } } if (obj->gtt_space == NULL) { ret = i915_gem_object_bind_to_gtt(obj, alignment, map_and_fenceable); if (ret) return ret; } if (!obj->has_global_gtt_mapping && map_and_fenceable) i915_gem_gtt_bind_object(obj, obj->cache_level); obj->pin_count++; obj->pin_mappable |= map_and_fenceable; return 0; } void i915_gem_object_unpin(struct drm_i915_gem_object *obj) { KASSERT(obj->pin_count != 0, ("zero pin count")); KASSERT(obj->gtt_space != NULL, ("No gtt mapping")); if (--obj->pin_count == 0) obj->pin_mappable = false; } int i915_gem_pin_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { struct drm_i915_gem_pin *args = data; struct drm_i915_gem_object *obj; struct drm_gem_object *gobj; int ret; ret = i915_mutex_lock_interruptible(dev); if (ret) return ret; gobj = drm_gem_object_lookup(dev, file, args->handle); if (gobj == NULL) { ret = -ENOENT; goto unlock; } obj = to_intel_bo(gobj); if (obj->madv != I915_MADV_WILLNEED) { DRM_ERROR("Attempting to pin a purgeable buffer\n"); ret = -EINVAL; goto out; } if (obj->pin_filp != NULL && obj->pin_filp != file) { DRM_ERROR("Already pinned in i915_gem_pin_ioctl(): %d\n", args->handle); ret = -EINVAL; goto out; } obj->user_pin_count++; obj->pin_filp = file; if (obj->user_pin_count == 1) { ret = i915_gem_object_pin(obj, args->alignment, true); if (ret) goto out; } /* XXX - flush the CPU caches for pinned objects * as the X server doesn't manage domains yet */ i915_gem_object_flush_cpu_write_domain(obj); args->offset = obj->gtt_offset; out: drm_gem_object_unreference(&obj->base); unlock: DRM_UNLOCK(dev); return ret; } int i915_gem_unpin_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { struct drm_i915_gem_pin *args = data; struct drm_i915_gem_object *obj; int ret; ret = i915_mutex_lock_interruptible(dev); if (ret) return ret; obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); if (&obj->base == NULL) { ret = -ENOENT; goto unlock; } if (obj->pin_filp != file) { DRM_ERROR("Not pinned by caller in i915_gem_pin_ioctl(): %d\n", args->handle); ret = -EINVAL; goto out; } obj->user_pin_count--; if (obj->user_pin_count == 0) { obj->pin_filp = NULL; i915_gem_object_unpin(obj); } out: drm_gem_object_unreference(&obj->base); unlock: DRM_UNLOCK(dev); return ret; } int i915_gem_busy_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { struct drm_i915_gem_busy *args = data; struct drm_i915_gem_object *obj; int ret; ret = i915_mutex_lock_interruptible(dev); if (ret) return ret; obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); if (&obj->base == NULL) { ret = -ENOENT; goto unlock; } args->busy = obj->active; if (args->busy) { if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) { ret = i915_gem_flush_ring(obj->ring, 0, obj->base.write_domain); } else { ret = i915_gem_check_olr(obj->ring, obj->last_rendering_seqno); } i915_gem_retire_requests_ring(obj->ring); args->busy = obj->active; } drm_gem_object_unreference(&obj->base); unlock: DRM_UNLOCK(dev); return ret; } int i915_gem_throttle_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { return i915_gem_ring_throttle(dev, file_priv); } int i915_gem_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_i915_gem_madvise *args = data; struct drm_i915_gem_object *obj; int ret; switch (args->madv) { case I915_MADV_DONTNEED: case I915_MADV_WILLNEED: break; default: return -EINVAL; } ret = i915_mutex_lock_interruptible(dev); if (ret) return ret; obj = to_intel_bo(drm_gem_object_lookup(dev, file_priv, args->handle)); if (&obj->base == NULL) { ret = -ENOENT; goto unlock; } if (obj->pin_count) { ret = -EINVAL; goto out; } if (obj->madv != I915_MADV_PURGED_INTERNAL) obj->madv = args->madv; /* if the object is no longer attached, discard its backing storage */ if (i915_gem_object_is_purgeable(obj) && obj->gtt_space == NULL) i915_gem_object_truncate(obj); args->retained = obj->madv != I915_MADV_PURGED_INTERNAL; out: drm_gem_object_unreference(&obj->base); unlock: DRM_UNLOCK(dev); return ret; } struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev, size_t size) { struct drm_i915_private *dev_priv; struct drm_i915_gem_object *obj; dev_priv = dev->dev_private; obj = malloc(sizeof(*obj), DRM_I915_GEM, M_WAITOK | M_ZERO); if (drm_gem_object_init(dev, &obj->base, size) != 0) { free(obj, DRM_I915_GEM); return NULL; } obj->base.write_domain = I915_GEM_DOMAIN_CPU; obj->base.read_domains = I915_GEM_DOMAIN_CPU; if (HAS_LLC(dev)) { /* On some devices, we can have the GPU use the LLC (the CPU * cache) for about a 10% performance improvement * compared to uncached. Graphics requests other than * display scanout are coherent with the CPU in * accessing this cache. This means in this mode we * don't need to clflush on the CPU side, and on the * GPU side we only need to flush internal caches to * get data visible to the CPU. * * However, we maintain the display planes as UC, and so * need to rebind when first used as such. */ obj->cache_level = I915_CACHE_LLC; } else obj->cache_level = I915_CACHE_NONE; obj->base.driver_private = NULL; obj->fence_reg = I915_FENCE_REG_NONE; INIT_LIST_HEAD(&obj->mm_list); INIT_LIST_HEAD(&obj->gtt_list); INIT_LIST_HEAD(&obj->ring_list); INIT_LIST_HEAD(&obj->exec_list); INIT_LIST_HEAD(&obj->gpu_write_list); obj->madv = I915_MADV_WILLNEED; /* Avoid an unnecessary call to unbind on the first bind. */ obj->map_and_fenceable = true; i915_gem_info_add_obj(dev_priv, size); return obj; } int i915_gem_init_object(struct drm_gem_object *obj) { printf("i915_gem_init_object called\n"); return 0; } void i915_gem_free_object(struct drm_gem_object *gem_obj) { struct drm_i915_gem_object *obj = to_intel_bo(gem_obj); struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; CTR1(KTR_DRM, "object_destroy_tail %p", obj); if (obj->phys_obj) i915_gem_detach_phys_object(dev, obj); obj->pin_count = 0; if (i915_gem_object_unbind(obj) == -ERESTARTSYS) { bool was_interruptible; was_interruptible = dev_priv->mm.interruptible; dev_priv->mm.interruptible = false; if (i915_gem_object_unbind(obj)) printf("i915_gem_free_object: unbind\n"); dev_priv->mm.interruptible = was_interruptible; } drm_gem_free_mmap_offset(&obj->base); drm_gem_object_release(&obj->base); i915_gem_info_remove_obj(dev_priv, obj->base.size); free(obj->bit_17, DRM_I915_GEM); free(obj, DRM_I915_GEM); } int i915_gem_idle(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; int ret; DRM_LOCK(dev); if (dev_priv->mm.suspended) { DRM_UNLOCK(dev); return 0; } ret = i915_gpu_idle(dev); if (ret) { DRM_UNLOCK(dev); return ret; } i915_gem_retire_requests(dev); /* Under UMS, be paranoid and evict. */ if (!drm_core_check_feature(dev, DRIVER_MODESET)) { ret = i915_gem_evict_everything(dev, false); if (ret) { DRM_UNLOCK(dev); return ret; } } i915_gem_reset_fences(dev); /* Hack! Don't let anybody do execbuf while we don't control the chip. * We need to replace this with a semaphore, or something. * And not confound mm.suspended! */ dev_priv->mm.suspended = 1; callout_stop(&dev_priv->hangcheck_timer); i915_kernel_lost_context(dev); i915_gem_cleanup_ringbuffer(dev); DRM_UNLOCK(dev); /* Cancel the retire work handler, which should be idle now. */ taskqueue_cancel_timeout(dev_priv->tq, &dev_priv->mm.retire_task, NULL); return ret; } void i915_gem_init_swizzling(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; if (INTEL_INFO(dev)->gen < 5 || dev_priv->mm.bit_6_swizzle_x == I915_BIT_6_SWIZZLE_NONE) return; I915_WRITE(DISP_ARB_CTL, I915_READ(DISP_ARB_CTL) | DISP_TILE_SURFACE_SWIZZLING); if (IS_GEN5(dev)) return; I915_WRITE(TILECTL, I915_READ(TILECTL) | TILECTL_SWZCTL); if (IS_GEN6(dev)) I915_WRITE(ARB_MODE, _MASKED_BIT_ENABLE(ARB_MODE_SWIZZLE_SNB)); else I915_WRITE(ARB_MODE, _MASKED_BIT_ENABLE(ARB_MODE_SWIZZLE_IVB)); } int i915_gem_init_hw(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; int ret; i915_gem_init_swizzling(dev); ret = intel_init_render_ring_buffer(dev); if (ret) return ret; if (HAS_BSD(dev)) { ret = intel_init_bsd_ring_buffer(dev); if (ret) goto cleanup_render_ring; } if (HAS_BLT(dev)) { ret = intel_init_blt_ring_buffer(dev); if (ret) goto cleanup_bsd_ring; } dev_priv->next_seqno = 1; /* * XXX: There was some w/a described somewhere suggesting loading * contexts before PPGTT. */ i915_gem_context_init(dev); i915_gem_init_ppgtt(dev); return 0; cleanup_bsd_ring: intel_cleanup_ring_buffer(&dev_priv->rings[VCS]); cleanup_render_ring: intel_cleanup_ring_buffer(&dev_priv->rings[RCS]); return ret; } static bool intel_enable_ppgtt(struct drm_device *dev) { if (i915_enable_ppgtt >= 0) return i915_enable_ppgtt; /* Disable ppgtt on SNB if VT-d is on. */ if (INTEL_INFO(dev)->gen == 6 && intel_iommu_enabled) return false; return true; } int i915_gem_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; unsigned long gtt_size, mappable_size; int ret; gtt_size = dev_priv->mm.gtt.gtt_total_entries << PAGE_SHIFT; mappable_size = dev_priv->mm.gtt.gtt_mappable_entries << PAGE_SHIFT; DRM_LOCK(dev); if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) { /* PPGTT pdes are stolen from global gtt ptes, so shrink the * aperture accordingly when using aliasing ppgtt. */ gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE; i915_gem_init_global_gtt(dev, 0, mappable_size, gtt_size); ret = i915_gem_init_aliasing_ppgtt(dev); if (ret) { DRM_UNLOCK(dev); return ret; } } else { /* Let GEM Manage all of the aperture. * * However, leave one page at the end still bound to the scratch * page. There are a number of places where the hardware * apparently prefetches past the end of the object, and we've * seen multiple hangs with the GPU head pointer stuck in a * batchbuffer bound at the last page of the aperture. One page * should be enough to keep any prefetching inside of the * aperture. */ i915_gem_init_global_gtt(dev, 0, mappable_size, gtt_size); } ret = i915_gem_init_hw(dev); DRM_UNLOCK(dev); if (ret) { i915_gem_cleanup_aliasing_ppgtt(dev); return ret; } /* Allow hardware batchbuffers unless told otherwise, but not for KMS. */ if (!drm_core_check_feature(dev, DRIVER_MODESET)) dev_priv->dri1.allow_batchbuffer = 1; return 0; } void i915_gem_cleanup_ringbuffer(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; struct intel_ring_buffer *ring; int i; for_each_ring(ring, dev_priv, i) intel_cleanup_ring_buffer(ring); } int i915_gem_entervt_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_i915_private_t *dev_priv = dev->dev_private; int ret; if (drm_core_check_feature(dev, DRIVER_MODESET)) return 0; if (atomic_load_acq_int(&dev_priv->mm.wedged) != 0) { DRM_ERROR("Reenabling wedged hardware, good luck\n"); atomic_store_rel_int(&dev_priv->mm.wedged, 0); } DRM_LOCK(dev); dev_priv->mm.suspended = 0; ret = i915_gem_init_hw(dev); if (ret != 0) { DRM_UNLOCK(dev); return ret; } KASSERT(list_empty(&dev_priv->mm.active_list), ("active list")); KASSERT(list_empty(&dev_priv->mm.flushing_list), ("flushing list")); KASSERT(list_empty(&dev_priv->mm.inactive_list), ("inactive list")); DRM_UNLOCK(dev); ret = drm_irq_install(dev); if (ret) goto cleanup_ringbuffer; return 0; cleanup_ringbuffer: DRM_LOCK(dev); i915_gem_cleanup_ringbuffer(dev); dev_priv->mm.suspended = 1; DRM_UNLOCK(dev); return ret; } int i915_gem_leavevt_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { if (drm_core_check_feature(dev, DRIVER_MODESET)) return 0; drm_irq_uninstall(dev); return i915_gem_idle(dev); } void i915_gem_lastclose(struct drm_device *dev) { int ret; if (drm_core_check_feature(dev, DRIVER_MODESET)) return; ret = i915_gem_idle(dev); if (ret) DRM_ERROR("failed to idle hardware: %d\n", ret); } static void init_ring_lists(struct intel_ring_buffer *ring) { INIT_LIST_HEAD(&ring->active_list); INIT_LIST_HEAD(&ring->request_list); INIT_LIST_HEAD(&ring->gpu_write_list); } void i915_gem_load(struct drm_device *dev) { int i; drm_i915_private_t *dev_priv = dev->dev_private; INIT_LIST_HEAD(&dev_priv->mm.active_list); INIT_LIST_HEAD(&dev_priv->mm.flushing_list); INIT_LIST_HEAD(&dev_priv->mm.inactive_list); INIT_LIST_HEAD(&dev_priv->mm.fence_list); INIT_LIST_HEAD(&dev_priv->mm.gtt_list); for (i = 0; i < I915_NUM_RINGS; i++) init_ring_lists(&dev_priv->rings[i]); for (i = 0; i < I915_MAX_NUM_FENCES; i++) INIT_LIST_HEAD(&dev_priv->fence_regs[i].lru_list); TIMEOUT_TASK_INIT(dev_priv->tq, &dev_priv->mm.retire_task, 0, i915_gem_retire_task_handler, dev_priv); dev_priv->error_completion = 0; /* On GEN3 we really need to make sure the ARB C3 LP bit is set */ if (IS_GEN3(dev)) { I915_WRITE(MI_ARB_STATE, _MASKED_BIT_ENABLE(MI_ARB_C3_LP_WRITE_ENABLE)); } dev_priv->relative_constants_mode = I915_EXEC_CONSTANTS_REL_GENERAL; /* Old X drivers will take 0-2 for front, back, depth buffers */ if (!drm_core_check_feature(dev, DRIVER_MODESET)) dev_priv->fence_reg_start = 3; if (INTEL_INFO(dev)->gen >= 4 || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) dev_priv->num_fence_regs = 16; else dev_priv->num_fence_regs = 8; /* Initialize fence registers to zero */ i915_gem_reset_fences(dev); i915_gem_detect_bit_6_swizzle(dev); dev_priv->mm.interruptible = true; dev_priv->mm.i915_lowmem = EVENTHANDLER_REGISTER(vm_lowmem, i915_gem_lowmem, dev, EVENTHANDLER_PRI_ANY); } void i915_gem_unload(struct drm_device *dev) { struct drm_i915_private *dev_priv; dev_priv = dev->dev_private; EVENTHANDLER_DEREGISTER(vm_lowmem, dev_priv->mm.i915_lowmem); } /* * Create a physically contiguous memory object for this object * e.g. for cursor + overlay regs */ static int i915_gem_init_phys_object(struct drm_device *dev, int id, int size, int align) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_phys_object *phys_obj; int ret; if (dev_priv->mm.phys_objs[id - 1] || !size) return 0; phys_obj = malloc(sizeof(struct drm_i915_gem_phys_object), DRM_I915_GEM, M_WAITOK | M_ZERO); phys_obj->id = id; phys_obj->handle = drm_pci_alloc(dev, size, align, BUS_SPACE_MAXADDR); if (!phys_obj->handle) { ret = -ENOMEM; goto kfree_obj; } pmap_change_attr((vm_offset_t)phys_obj->handle->vaddr, size / PAGE_SIZE, PAT_WRITE_COMBINING); dev_priv->mm.phys_objs[id - 1] = phys_obj; return 0; kfree_obj: free(phys_obj, DRM_I915_GEM); return ret; } static void i915_gem_free_phys_object(struct drm_device *dev, int id) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_phys_object *phys_obj; if (!dev_priv->mm.phys_objs[id - 1]) return; phys_obj = dev_priv->mm.phys_objs[id - 1]; if (phys_obj->cur_obj) { i915_gem_detach_phys_object(dev, phys_obj->cur_obj); } drm_pci_free(dev, phys_obj->handle); free(phys_obj, DRM_I915_GEM); dev_priv->mm.phys_objs[id - 1] = NULL; } void i915_gem_free_all_phys_object(struct drm_device *dev) { int i; for (i = I915_GEM_PHYS_CURSOR_0; i <= I915_MAX_PHYS_OBJECT; i++) i915_gem_free_phys_object(dev, i); } void i915_gem_detach_phys_object(struct drm_device *dev, struct drm_i915_gem_object *obj) { vm_page_t page; struct sf_buf *sf; char *vaddr, *dst; int i, page_count; if (!obj->phys_obj) return; vaddr = obj->phys_obj->handle->vaddr; page_count = obj->base.size / PAGE_SIZE; VM_OBJECT_WLOCK(obj->base.vm_obj); for (i = 0; i < page_count; i++) { page = i915_gem_wire_page(obj->base.vm_obj, i, NULL); if (page == NULL) continue; /* XXX */ VM_OBJECT_WUNLOCK(obj->base.vm_obj); sf = sf_buf_alloc(page, 0); if (sf != NULL) { dst = (char *)sf_buf_kva(sf); memcpy(dst, vaddr + IDX_TO_OFF(i), PAGE_SIZE); sf_buf_free(sf); } drm_clflush_pages(&page, 1); VM_OBJECT_WLOCK(obj->base.vm_obj); vm_page_reference(page); vm_page_lock(page); vm_page_dirty(page); vm_page_unwire(page, PQ_INACTIVE); vm_page_unlock(page); atomic_add_long(&i915_gem_wired_pages_cnt, -1); } VM_OBJECT_WUNLOCK(obj->base.vm_obj); intel_gtt_chipset_flush(); obj->phys_obj->cur_obj = NULL; obj->phys_obj = NULL; } int i915_gem_attach_phys_object(struct drm_device *dev, struct drm_i915_gem_object *obj, int id, int align) { drm_i915_private_t *dev_priv = dev->dev_private; vm_page_t page; struct sf_buf *sf; char *dst, *src; int ret = 0; int page_count; int i; if (id > I915_MAX_PHYS_OBJECT) return -EINVAL; if (obj->phys_obj) { if (obj->phys_obj->id == id) return 0; i915_gem_detach_phys_object(dev, obj); } /* create a new object */ if (!dev_priv->mm.phys_objs[id - 1]) { ret = i915_gem_init_phys_object(dev, id, obj->base.size, align); if (ret) { DRM_ERROR("failed to init phys object %d size: %zu\n", id, obj->base.size); return ret; } } /* bind to the object */ obj->phys_obj = dev_priv->mm.phys_objs[id - 1]; obj->phys_obj->cur_obj = obj; page_count = obj->base.size / PAGE_SIZE; VM_OBJECT_WLOCK(obj->base.vm_obj); for (i = 0; i < page_count; i++) { page = i915_gem_wire_page(obj->base.vm_obj, i, NULL); if (page == NULL) { ret = -EIO; break; } VM_OBJECT_WUNLOCK(obj->base.vm_obj); sf = sf_buf_alloc(page, 0); src = (char *)sf_buf_kva(sf); dst = (char *)obj->phys_obj->handle->vaddr + IDX_TO_OFF(i); memcpy(dst, src, PAGE_SIZE); sf_buf_free(sf); VM_OBJECT_WLOCK(obj->base.vm_obj); vm_page_reference(page); vm_page_lock(page); vm_page_unwire(page, PQ_INACTIVE); vm_page_unlock(page); atomic_add_long(&i915_gem_wired_pages_cnt, -1); } VM_OBJECT_WUNLOCK(obj->base.vm_obj); return ret; } static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_i915_gem_object *obj, struct drm_i915_gem_pwrite *args, struct drm_file *file_priv) { void *vaddr = (char *)obj->phys_obj->handle->vaddr + args->offset; char __user *user_data = to_user_ptr(args->data_ptr); if (__copy_from_user_inatomic_nocache(vaddr, user_data, args->size)) { unsigned long unwritten; /* The physical object once assigned is fixed for the lifetime * of the obj, so we can safely drop the lock and continue * to access vaddr. */ DRM_UNLOCK(dev); unwritten = copy_from_user(vaddr, user_data, args->size); DRM_LOCK(dev); if (unwritten) return -EFAULT; } i915_gem_chipset_flush(dev); return 0; } void i915_gem_release(struct drm_device *dev, struct drm_file *file) { struct drm_i915_file_private *file_priv = file->driver_priv; /* Clean up our request list when the client is going away, so that * later retire_requests won't dereference our soon-to-be-gone * file_priv. */ mtx_lock(&file_priv->mm.lck); while (!list_empty(&file_priv->mm.request_list)) { struct drm_i915_gem_request *request; request = list_first_entry(&file_priv->mm.request_list, struct drm_i915_gem_request, client_list); list_del(&request->client_list); request->file_priv = NULL; } mtx_unlock(&file_priv->mm.lck); } static vm_page_t i915_gem_wire_page(vm_object_t object, vm_pindex_t pindex, bool *fresh) { vm_page_t page; int rv; VM_OBJECT_ASSERT_WLOCKED(object); page = vm_page_grab(object, pindex, VM_ALLOC_NORMAL); if (page->valid != VM_PAGE_BITS_ALL) { if (vm_pager_has_page(object, pindex, NULL, NULL)) { rv = vm_pager_get_pages(object, &page, 1, 0); if (rv != VM_PAGER_OK) { vm_page_lock(page); vm_page_free(page); vm_page_unlock(page); return (NULL); } if (fresh != NULL) *fresh = true; } else { pmap_zero_page(page); page->valid = VM_PAGE_BITS_ALL; page->dirty = 0; if (fresh != NULL) *fresh = false; } } else if (fresh != NULL) { *fresh = false; } vm_page_lock(page); vm_page_wire(page); vm_page_unlock(page); vm_page_xunbusy(page); atomic_add_long(&i915_gem_wired_pages_cnt, 1); return (page); } #undef __user #undef __force #undef __iomem #undef __must_check #undef to_user_ptr #undef offset_in_page #undef page_to_phys Index: projects/release-pkg/sys/dev/iicbus/icee.c =================================================================== --- projects/release-pkg/sys/dev/iicbus/icee.c (revision 289118) +++ projects/release-pkg/sys/dev/iicbus/icee.c (revision 289119) @@ -1,273 +1,278 @@ /*- * Copyright (c) 2006 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 ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * Generic IIC eeprom support, modeled after the AT24C family of products. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "iicbus_if.h" #define IIC_M_WR 0 /* write operation */ #define MAX_RD_SZ 256 /* Largest read size we support */ #define MAX_WR_SZ 256 /* Largest write size we support */ struct icee_softc { device_t sc_dev; /* Myself */ - struct sx sc_lock; /* basically a perimeter lock */ + device_t sc_busdev; /* Parent bus */ struct cdev *cdev; /* user interface */ int addr; int size; /* How big am I? */ int type; /* What type 8 or 16 bit? */ int rd_sz; /* What's the read page size */ int wr_sz; /* What's the write page size */ }; -#define ICEE_LOCK(_sc) sx_xlock(&(_sc)->sc_lock) -#define ICEE_UNLOCK(_sc) sx_xunlock(&(_sc)->sc_lock) -#define ICEE_LOCK_INIT(_sc) sx_init(&_sc->sc_lock, "icee") -#define ICEE_LOCK_DESTROY(_sc) sx_destroy(&_sc->sc_lock); -#define ICEE_ASSERT_LOCKED(_sc) sx_assert(&_sc->sc_lock, SA_XLOCKED); -#define ICEE_ASSERT_UNLOCKED(_sc) sx_assert(&_sc->sc_lock, SA_UNLOCKED); #define CDEV2SOFTC(dev) ((dev)->si_drv1) /* cdev routines */ static d_open_t icee_open; static d_close_t icee_close; static d_read_t icee_read; static d_write_t icee_write; static struct cdevsw icee_cdevsw = { .d_version = D_VERSION, .d_flags = D_TRACKCLOSE, .d_open = icee_open, .d_close = icee_close, .d_read = icee_read, .d_write = icee_write }; static int icee_probe(device_t dev) { device_set_desc(dev, "I2C EEPROM"); return (BUS_PROBE_NOWILDCARD); } static int icee_attach(device_t dev) { struct icee_softc *sc = device_get_softc(dev); const char *dname; int dunit, err; sc->sc_dev = dev; + sc->sc_busdev = device_get_parent(sc->sc_dev); sc->addr = iicbus_get_addr(dev); err = 0; dname = device_get_name(dev); dunit = device_get_unit(dev); resource_int_value(dname, dunit, "size", &sc->size); resource_int_value(dname, dunit, "type", &sc->type); resource_int_value(dname, dunit, "rd_sz", &sc->rd_sz); if (sc->rd_sz > MAX_RD_SZ) sc->rd_sz = MAX_RD_SZ; resource_int_value(dname, dunit, "wr_sz", &sc->wr_sz); if (bootverbose) device_printf(dev, "size: %d bytes bus_width: %d-bits\n", sc->size, sc->type); sc->cdev = make_dev(&icee_cdevsw, device_get_unit(dev), UID_ROOT, GID_WHEEL, 0600, "icee%d", device_get_unit(dev)); if (sc->cdev == NULL) { err = ENOMEM; goto out; } sc->cdev->si_drv1 = sc; - ICEE_LOCK_INIT(sc); out: return (err); } static int icee_open(struct cdev *dev, int oflags, int devtype, struct thread *td) { return (0); } static int icee_close(struct cdev *dev, int fflag, int devtype, struct thread *td) { return (0); } static int icee_read(struct cdev *dev, struct uio *uio, int ioflag) { struct icee_softc *sc; uint8_t addr[2]; uint8_t data[MAX_RD_SZ]; int error, i, len, slave; struct iic_msg msgs[2] = { { 0, IIC_M_WR, 1, addr }, { 0, IIC_M_RD, 0, data }, }; sc = CDEV2SOFTC(dev); if (uio->uio_offset == sc->size) return (0); if (uio->uio_offset > sc->size) return (EIO); if (sc->type != 8 && sc->type != 16) return (EINVAL); - ICEE_LOCK(sc); + error = iicbus_request_bus(sc->sc_busdev, sc->sc_dev, IIC_INTRWAIT); + if (error!= 0) + return (iic2errno(error)); slave = error = 0; while (uio->uio_resid > 0) { if (uio->uio_offset >= sc->size) break; len = MIN(sc->rd_sz - (uio->uio_offset & (sc->rd_sz - 1)), uio->uio_resid); switch (sc->type) { case 8: slave = (uio->uio_offset >> 7) | sc->addr; msgs[0].len = 1; msgs[1].len = len; addr[0] = uio->uio_offset & 0xff; break; case 16: slave = sc->addr | (uio->uio_offset >> 15); msgs[0].len = 2; msgs[1].len = len; addr[0] = (uio->uio_offset >> 8) & 0xff; addr[1] = uio->uio_offset & 0xff; break; } for (i = 0; i < 2; i++) msgs[i].slave = slave; error = iicbus_transfer(sc->sc_dev, msgs, 2); - if (error) + if (error) { + error = iic2errno(error); break; + } error = uiomove(data, len, uio); if (error) break; } - ICEE_UNLOCK(sc); + iicbus_release_bus(sc->sc_busdev, sc->sc_dev); return (error); } /* * Write to the part. We use three transfers here since we're actually * doing a write followed by a read to make sure that the write finished. * It is easier to encode the dummy read here than to break things up * into smaller chunks... */ static int icee_write(struct cdev *dev, struct uio *uio, int ioflag) { struct icee_softc *sc; int error, len, slave, waitlimit; uint8_t data[MAX_WR_SZ + 2]; struct iic_msg wr[1] = { { 0, IIC_M_WR, 0, data }, }; struct iic_msg rd[1] = { { 0, IIC_M_RD, 1, data }, }; sc = CDEV2SOFTC(dev); if (uio->uio_offset >= sc->size) return (EIO); if (sc->type != 8 && sc->type != 16) return (EINVAL); - ICEE_LOCK(sc); + + error = iicbus_request_bus(sc->sc_busdev, sc->sc_dev, IIC_INTRWAIT); + if (error!= 0) + return (iic2errno(error)); slave = error = 0; while (uio->uio_resid > 0) { if (uio->uio_offset >= sc->size) break; len = MIN(sc->wr_sz - (uio->uio_offset & (sc->wr_sz - 1)), uio->uio_resid); switch (sc->type) { case 8: slave = (uio->uio_offset >> 7) | sc->addr; wr[0].len = 1 + len; data[0] = uio->uio_offset & 0xff; break; case 16: slave = sc->addr | (uio->uio_offset >> 15); wr[0].len = 2 + len; data[0] = (uio->uio_offset >> 8) & 0xff; data[1] = uio->uio_offset & 0xff; break; } wr[0].slave = slave; error = uiomove(data + sc->type / 8, len, uio); if (error) break; error = iicbus_transfer(sc->sc_dev, wr, 1); - if (error) + if (error) { + error = iic2errno(error); break; + } /* Read after write to wait for write-done. */ waitlimit = 10000; rd[0].slave = slave; do { error = iicbus_transfer(sc->sc_dev, rd, 1); } while (waitlimit-- > 0 && error != 0); - if (error) + if (error) { + error = iic2errno(error); break; + } } - ICEE_UNLOCK(sc); + iicbus_release_bus(sc->sc_busdev, sc->sc_dev); return error; } static device_method_t icee_methods[] = { DEVMETHOD(device_probe, icee_probe), DEVMETHOD(device_attach, icee_attach), DEVMETHOD_END }; static driver_t icee_driver = { "icee", icee_methods, sizeof(struct icee_softc), }; static devclass_t icee_devclass; DRIVER_MODULE(icee, iicbus, icee_driver, icee_devclass, 0, 0); MODULE_VERSION(icee, 1); MODULE_DEPEND(icee, iicbus, 1, 1, 1); Index: projects/release-pkg/sys/dev/iicbus/iicoc.c =================================================================== --- projects/release-pkg/sys/dev/iicbus/iicoc.c (revision 289118) +++ projects/release-pkg/sys/dev/iicbus/iicoc.c (revision 289119) @@ -1,390 +1,390 @@ /*- * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "iicbus_if.h" static devclass_t iicoc_devclass; /* * Device methods */ static int iicoc_probe(device_t); static int iicoc_attach(device_t); static int iicoc_detach(device_t); static int iicoc_start(device_t dev, u_char slave, int timeout); static int iicoc_stop(device_t dev); static int iicoc_read(device_t dev, char *buf, int len, int *read, int last, int delay); static int iicoc_write(device_t dev, const char *buf, int len, int *sent, int timeout); static int iicoc_repeated_start(device_t dev, u_char slave, int timeout); struct iicoc_softc { device_t dev; /* Self */ u_int reg_shift; /* Chip specific */ u_int clockfreq; u_int i2cfreq; struct resource *mem_res; /* Memory resource */ int mem_rid; int sc_started; uint8_t i2cdev_addr; device_t iicbus; struct mtx sc_mtx; }; static void iicoc_dev_write(device_t dev, int reg, int value) { struct iicoc_softc *sc; sc = device_get_softc(dev); bus_write_1(sc->mem_res, reg<reg_shift, value); } static int iicoc_dev_read(device_t dev, int reg) { uint8_t val; struct iicoc_softc *sc; sc = device_get_softc(dev); val = bus_read_1(sc->mem_res, reg<reg_shift); return (val); } static int iicoc_wait_on_status(device_t dev, uint8_t bit) { int tries = I2C_TIMEOUT; uint8_t status; do { status = iicoc_dev_read(dev, OC_I2C_STATUS_REG); } while ((status & bit) != 0 && --tries > 0); return (tries == 0 ? -1: 0); } static int iicoc_rd_cmd(device_t dev, uint8_t cmd) { uint8_t data; iicoc_dev_write(dev, OC_I2C_CMD_REG, cmd); if (iicoc_wait_on_status(dev, OC_STATUS_TIP) < 0) { device_printf(dev, "read: Timeout waiting for TIP clear.\n"); return (-1); } data = iicoc_dev_read(dev, OC_I2C_DATA_REG); return (data); } static int iicoc_wr_cmd(device_t dev, uint8_t data, uint8_t cmd) { iicoc_dev_write(dev, OC_I2C_DATA_REG, data); iicoc_dev_write(dev, OC_I2C_CMD_REG, cmd); if (iicoc_wait_on_status(dev, OC_STATUS_TIP) < 0) { device_printf(dev, "write: Timeout waiting for TIP clear.\n"); return (-1); } return (0); } static int iicoc_wr_ack_cmd(device_t dev, uint8_t data, uint8_t cmd) { if (iicoc_wr_cmd(dev, data, cmd) < 0) return (-1); if (iicoc_dev_read(dev, OC_I2C_STATUS_REG) & OC_STATUS_NACK) { device_printf(dev, "write: I2C command ACK Error.\n"); return (IIC_ENOACK); } return (0); } static int iicoc_init(device_t dev) { struct iicoc_softc *sc; int value; sc = device_get_softc(dev); value = iicoc_dev_read(dev, OC_I2C_CTRL_REG); iicoc_dev_write(dev, OC_I2C_CTRL_REG, value & ~(OC_CONTROL_EN | OC_CONTROL_IEN)); value = (sc->clockfreq/(5 * sc->i2cfreq)) - 1; iicoc_dev_write(dev, OC_I2C_PRESCALE_LO_REG, value & 0xff); iicoc_dev_write(dev, OC_I2C_PRESCALE_HI_REG, value >> 8); value = iicoc_dev_read(dev, OC_I2C_CTRL_REG); iicoc_dev_write(dev, OC_I2C_CTRL_REG, value | OC_CONTROL_EN); value = iicoc_dev_read(dev, OC_I2C_CTRL_REG); /* return 0 on success, 1 on error */ return ((value & OC_CONTROL_EN) == 0); } static int iicoc_probe(device_t dev) { struct iicoc_softc *sc; sc = device_get_softc(dev); if ((pci_get_vendor(dev) == 0x184e) && (pci_get_device(dev) == 0x1011)) { sc->clockfreq = XLP_I2C_CLKFREQ; sc->i2cfreq = XLP_I2C_FREQ; sc->reg_shift = 2; device_set_desc(dev, "Netlogic XLP I2C Controller"); return (BUS_PROBE_DEFAULT); } return (ENXIO); } /* * We add all the devices which we know about. * The generic attach routine will attach them if they are alive. */ static int iicoc_attach(device_t dev) { int bus; struct iicoc_softc *sc; sc = device_get_softc(dev); bus = device_get_unit(dev); sc->dev = dev; mtx_init(&sc->sc_mtx, "iicoc", "iicoc", MTX_DEF); sc->mem_rid = 0; sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mem_rid, 0ul, ~0ul, 0x100, RF_ACTIVE); if (sc->mem_res == NULL) { device_printf(dev, "Could not allocate bus resource.\n"); return (-1); } iicoc_init(dev); sc->iicbus = device_add_child(dev, "iicbus", -1); if (sc->iicbus == NULL) { device_printf(dev, "Could not allocate iicbus instance.\n"); return (-1); } bus_generic_attach(dev); return (0); } static int iicoc_detach(device_t dev) { bus_generic_detach(dev); return (0); } static int iicoc_start(device_t dev, u_char slave, int timeout) { - int error = IIC_EBUSBSY; + int error = IIC_EBUSERR; struct iicoc_softc *sc; sc = device_get_softc(dev); mtx_lock(&sc->sc_mtx); sc->i2cdev_addr = (slave >> 1); /* Verify the bus is idle */ if (iicoc_wait_on_status(dev, OC_STATUS_BUSY) < 0) goto i2c_stx_error; /* Write Slave Address */ if (iicoc_wr_ack_cmd(dev, slave, OC_COMMAND_START)) { device_printf(dev, "I2C write slave address [0x%x] failed.\n", slave); error = IIC_ENOACK; goto i2c_stx_error; } /* Verify Arbitration is not Lost */ if (iicoc_dev_read(dev, OC_I2C_STATUS_REG) & OC_STATUS_AL) { device_printf(dev, "I2C Bus Arbitration Lost, Aborting.\n"); error = IIC_EBUSERR; goto i2c_stx_error; } error = IIC_NOERR; mtx_unlock(&sc->sc_mtx); return (error); i2c_stx_error: iicoc_dev_write(dev, OC_I2C_CMD_REG, OC_COMMAND_STOP); iicoc_wait_on_status(dev, OC_STATUS_BUSY); /* wait for idle */ mtx_unlock(&sc->sc_mtx); return (error); } static int iicoc_stop(device_t dev) { int error = 0; struct iicoc_softc *sc; sc = device_get_softc(dev); mtx_lock(&sc->sc_mtx); iicoc_dev_write(dev, OC_I2C_CMD_REG, OC_COMMAND_STOP); iicoc_wait_on_status(dev, OC_STATUS_BUSY); /* wait for idle */ mtx_unlock(&sc->sc_mtx); return (error); } static int iicoc_write(device_t dev, const char *buf, int len, int *sent, int timeout /* us */ ) { uint8_t value; int i; value = buf[0]; /* Write Slave Offset */ if (iicoc_wr_ack_cmd(dev, value, OC_COMMAND_WRITE)) { device_printf(dev, "I2C write slave offset failed.\n"); goto i2c_tx_error; } for (i = 1; i < len; i++) { /* Write data byte */ value = buf[i]; if (iicoc_wr_cmd(dev, value, OC_COMMAND_WRITE)) { device_printf(dev, "I2C write data byte %d failed.\n", i); goto i2c_tx_error; } } *sent = len; return (IIC_NOERR); i2c_tx_error: return (IIC_EBUSERR); } static int iicoc_read(device_t dev, char *buf, int len, int *read, int last, int delay) { int data, i; uint8_t cmd; for (i = 0; i < len; i++) { /* Read data byte */ cmd = (i == len - 1) ? OC_COMMAND_RDNACK : OC_COMMAND_READ; data = iicoc_rd_cmd(dev, cmd); if (data < 0) { device_printf(dev, "I2C read data byte %d failed.\n", i); goto i2c_rx_error; } buf[i] = (uint8_t)data; } *read = len; return (IIC_NOERR); i2c_rx_error: return (IIC_EBUSERR); } static int iicoc_reset(device_t dev, u_char speed, u_char addr, u_char *oldadr) { int error; struct iicoc_softc *sc; sc = device_get_softc(dev); mtx_lock(&sc->sc_mtx); error = iicoc_init(dev); mtx_unlock(&sc->sc_mtx); return (error); } static int iicoc_repeated_start(device_t dev, u_char slave, int timeout) { return 0; } static device_method_t iicoc_methods[] = { /* device interface */ DEVMETHOD(device_probe, iicoc_probe), DEVMETHOD(device_attach, iicoc_attach), DEVMETHOD(device_detach, iicoc_detach), /* iicbus interface */ DEVMETHOD(iicbus_callback, iicbus_null_callback), DEVMETHOD(iicbus_repeated_start, iicoc_repeated_start), DEVMETHOD(iicbus_start, iicoc_start), DEVMETHOD(iicbus_stop, iicoc_stop), DEVMETHOD(iicbus_reset, iicoc_reset), DEVMETHOD(iicbus_write, iicoc_write), DEVMETHOD(iicbus_read, iicoc_read), DEVMETHOD(iicbus_transfer, iicbus_transfer_gen), DEVMETHOD_END }; static driver_t iicoc_driver = { "iicoc", iicoc_methods, sizeof(struct iicoc_softc), }; DRIVER_MODULE(iicoc, pci, iicoc_driver, iicoc_devclass, 0, 0); DRIVER_MODULE(iicbus, iicoc, iicbus_driver, iicbus_devclass, 0, 0); Index: projects/release-pkg/sys/dev/iicbus/iiconf.c =================================================================== --- projects/release-pkg/sys/dev/iicbus/iiconf.c (revision 289118) +++ projects/release-pkg/sys/dev/iicbus/iiconf.c (revision 289119) @@ -1,423 +1,456 @@ /*- * Copyright (c) 1998 Nicolas Souchu * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include "iicbus_if.h" /* + * Translate IIC_Exxxxx status values to vaguely-equivelent errno values. + */ +int +iic2errno(int iic_status) +{ + switch (iic_status) { + case IIC_NOERR: return (0); + case IIC_EBUSERR: return (EALREADY); + case IIC_ENOACK: return (EIO); + case IIC_ETIMEOUT: return (ETIMEDOUT); + case IIC_EBUSBSY: return (EWOULDBLOCK); + case IIC_ESTATUS: return (EPROTO); + case IIC_EUNDERFLOW: return (EIO); + case IIC_EOVERFLOW: return (EOVERFLOW); + case IIC_ENOTSUPP: return (EOPNOTSUPP); + case IIC_ENOADDR: return (EADDRNOTAVAIL); + case IIC_ERESOURCE: return (ENOMEM); + default: return (EIO); + } +} + +/* * iicbus_intr() */ void iicbus_intr(device_t bus, int event, char *buf) { struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); /* call owner's intr routine */ if (sc->owner) IICBUS_INTR(sc->owner, event, buf); return; } static int iicbus_poll(struct iicbus_softc *sc, int how) { int error; IICBUS_ASSERT_LOCKED(sc); switch (how) { case IIC_WAIT | IIC_INTR: error = mtx_sleep(sc, &sc->lock, IICPRI|PCATCH, "iicreq", 0); break; case IIC_WAIT | IIC_NOINTR: error = mtx_sleep(sc, &sc->lock, IICPRI, "iicreq", 0); break; default: - return (EWOULDBLOCK); + return (IIC_EBUSBSY); } return (error); } /* * iicbus_request_bus() * * Allocate the device to perform transfers. * * how : IIC_WAIT or IIC_DONTWAIT */ int iicbus_request_bus(device_t bus, device_t dev, int how) { struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); int error = 0; IICBUS_LOCK(sc); while ((error == 0) && (sc->owner != NULL)) error = iicbus_poll(sc, how); if (error == 0) { sc->owner = dev; /* * Drop the lock around the call to the bus driver. * This call should be allowed to sleep in the IIC_WAIT case. * Drivers might also need to grab locks that would cause LOR * if our lock is held. */ IICBUS_UNLOCK(sc); /* Ask the underlying layers if the request is ok */ error = IICBUS_CALLBACK(device_get_parent(bus), IIC_REQUEST_BUS, (caddr_t)&how); IICBUS_LOCK(sc); if (error != 0) { sc->owner = NULL; wakeup_one(sc); } } IICBUS_UNLOCK(sc); return (error); } /* * iicbus_release_bus() * * Release the device allocated with iicbus_request_dev() */ int iicbus_release_bus(device_t bus, device_t dev) { struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); int error; IICBUS_LOCK(sc); if (sc->owner != dev) { IICBUS_UNLOCK(sc); - return (EACCES); + return (IIC_EBUSBSY); } /* * Drop the lock around the call to the bus driver. * This call should be allowed to sleep in the IIC_WAIT case. * Drivers might also need to grab locks that would cause LOR * if our lock is held. */ IICBUS_UNLOCK(sc); /* Ask the underlying layers if the release is ok */ error = IICBUS_CALLBACK(device_get_parent(bus), IIC_RELEASE_BUS, NULL); if (error == 0) { IICBUS_LOCK(sc); sc->owner = NULL; /* wakeup a waiting thread */ wakeup_one(sc); IICBUS_UNLOCK(sc); } return (error); } /* * iicbus_started() * * Test if the iicbus is started by the controller */ int iicbus_started(device_t bus) { struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); return (sc->started); } /* * iicbus_start() * * Send start condition to the slave addressed by 'slave' */ int iicbus_start(device_t bus, u_char slave, int timeout) { struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); int error = 0; if (sc->started) - return (EINVAL); /* bus already started */ + return (IIC_ESTATUS); /* protocol error, bus already started */ if (!(error = IICBUS_START(device_get_parent(bus), slave, timeout))) sc->started = slave; else sc->started = 0; return (error); } /* * iicbus_repeated_start() * * Send start condition to the slave addressed by 'slave' */ int iicbus_repeated_start(device_t bus, u_char slave, int timeout) { struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); int error = 0; if (!sc->started) - return (EINVAL); /* bus should have been already started */ + return (IIC_ESTATUS); /* protocol error, bus not started */ if (!(error = IICBUS_REPEATED_START(device_get_parent(bus), slave, timeout))) sc->started = slave; else sc->started = 0; return (error); } /* * iicbus_stop() * * Send stop condition to the bus */ int iicbus_stop(device_t bus) { struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); int error = 0; if (!sc->started) - return (EINVAL); /* bus not started */ + return (IIC_ESTATUS); /* protocol error, bus not started */ error = IICBUS_STOP(device_get_parent(bus)); /* refuse any further access */ sc->started = 0; return (error); } /* * iicbus_write() * * Write a block of data to the slave previously started by * iicbus_start() call */ int iicbus_write(device_t bus, const char *buf, int len, int *sent, int timeout) { struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); /* a slave must have been started for writing */ if (sc->started == 0 || (sc->strict != 0 && (sc->started & LSB) != 0)) - return (EINVAL); + return (IIC_ESTATUS); return (IICBUS_WRITE(device_get_parent(bus), buf, len, sent, timeout)); } /* * iicbus_read() * * Read a block of data from the slave previously started by * iicbus_read() call */ int iicbus_read(device_t bus, char *buf, int len, int *read, int last, int delay) { struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); /* a slave must have been started for reading */ if (sc->started == 0 || (sc->strict != 0 && (sc->started & LSB) == 0)) - return (EINVAL); + return (IIC_ESTATUS); return (IICBUS_READ(device_get_parent(bus), buf, len, read, last, delay)); } /* * iicbus_write_byte() * * Write a byte to the slave previously started by iicbus_start() call */ int iicbus_write_byte(device_t bus, char byte, int timeout) { + struct iicbus_softc *sc = device_get_softc(bus); char data = byte; int sent; + /* a slave must have been started for writing */ + if (sc->started == 0 || (sc->strict != 0 && (sc->started & LSB) != 0)) + return (IIC_ESTATUS); + return (iicbus_write(bus, &data, 1, &sent, timeout)); } /* * iicbus_read_byte() * * Read a byte from the slave previously started by iicbus_start() call */ int iicbus_read_byte(device_t bus, char *byte, int timeout) { + struct iicbus_softc *sc = device_get_softc(bus); int read; + /* a slave must have been started for reading */ + if (sc->started == 0 || (sc->strict != 0 && (sc->started & LSB) == 0)) + return (IIC_ESTATUS); + return (iicbus_read(bus, byte, 1, &read, IIC_LAST_READ, timeout)); } /* * iicbus_block_write() * * Write a block of data to slave ; start/stop protocol managed */ int iicbus_block_write(device_t bus, u_char slave, char *buf, int len, int *sent) { u_char addr = slave & ~LSB; int error; if ((error = iicbus_start(bus, addr, 0))) return (error); error = iicbus_write(bus, buf, len, sent, 0); iicbus_stop(bus); return (error); } /* * iicbus_block_read() * * Read a block of data from slave ; start/stop protocol managed */ int iicbus_block_read(device_t bus, u_char slave, char *buf, int len, int *read) { u_char addr = slave | LSB; int error; if ((error = iicbus_start(bus, addr, 0))) return (error); error = iicbus_read(bus, buf, len, read, IIC_LAST_READ, 0); iicbus_stop(bus); return (error); } /* * iicbus_transfer() * * Do an aribtrary number of transfers on the iicbus. We pass these * raw requests to the bridge driver. If the bridge driver supports * them directly, then it manages all the details. If not, it can use * the helper function iicbus_transfer_gen() which will do the * transfers at a low level. * * Pointers passed in as part of iic_msg must be kernel pointers. * Callers that have user addresses to manage must do so on their own. */ int iicbus_transfer(device_t bus, struct iic_msg *msgs, uint32_t nmsgs) { + return (IICBUS_TRANSFER(device_get_parent(bus), msgs, nmsgs)); } /* * Generic version of iicbus_transfer that calls the appropriate * routines to accomplish this. See note above about acceptable * buffer addresses. */ int iicbus_transfer_gen(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) { int i, error, lenread, lenwrote, nkid, rpstart, addr; device_t *children, bus; bool nostop; if ((error = device_get_children(dev, &children, &nkid)) != 0) - return (error); + return (IIC_ERESOURCE); if (nkid != 1) { free(children, M_TEMP); - return (EIO); + return (IIC_ENOTSUPP); } bus = children[0]; rpstart = 0; free(children, M_TEMP); nostop = iicbus_get_nostop(dev); for (i = 0, error = 0; i < nmsgs && error == 0; i++) { addr = msgs[i].slave; if (msgs[i].flags & IIC_M_RD) addr |= LSB; else addr &= ~LSB; if (!(msgs[i].flags & IIC_M_NOSTART)) { if (rpstart) error = iicbus_repeated_start(bus, addr, 0); else error = iicbus_start(bus, addr, 0); } if (error != 0) break; if (msgs[i].flags & IIC_M_RD) error = iicbus_read(bus, msgs[i].buf, msgs[i].len, &lenread, IIC_LAST_READ, 0); else error = iicbus_write(bus, msgs[i].buf, msgs[i].len, &lenwrote, 0); if (error != 0) break; if ((msgs[i].flags & IIC_M_NOSTOP) != 0 || (nostop && i + 1 < nmsgs)) { rpstart = 1; /* Next message gets repeated start */ } else { rpstart = 0; iicbus_stop(bus); } } if (error != 0 && !nostop) iicbus_stop(bus); return (error); } Index: projects/release-pkg/sys/dev/iicbus/iiconf.h =================================================================== --- projects/release-pkg/sys/dev/iicbus/iiconf.h (revision 289118) +++ projects/release-pkg/sys/dev/iicbus/iiconf.h (revision 289119) @@ -1,140 +1,147 @@ /*- * Copyright (c) 1998, 2001 Nicolas Souchu * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef __IICONF_H #define __IICONF_H #include #include #define IICPRI (PZERO+8) /* XXX sleep/wakeup queue priority */ #define LSB 0x1 /* * How tsleep() is called in iic_request_bus(). */ #define IIC_DONTWAIT 0 #define IIC_NOINTR 0 #define IIC_WAIT 0x1 #define IIC_INTR 0x2 +#define IIC_INTRWAIT (IIC_INTR | IIC_WAIT) /* * i2c modes */ #define IIC_MASTER 0x1 #define IIC_SLAVE 0x2 #define IIC_POLLED 0x4 /* * i2c speed */ #define IIC_UNKNOWN 0x0 #define IIC_SLOW 0x1 #define IIC_FAST 0x2 #define IIC_FASTEST 0x3 #define IIC_LAST_READ 0x1 /* * callback index */ #define IIC_REQUEST_BUS 0x1 #define IIC_RELEASE_BUS 0x2 /* * interrupt events */ #define INTR_GENERAL 0x1 /* general call received */ #define INTR_START 0x2 /* the I2C interface is addressed */ #define INTR_STOP 0x3 /* stop condition received */ #define INTR_RECEIVE 0x4 /* character received */ #define INTR_TRANSMIT 0x5 /* character to transmit */ #define INTR_ERROR 0x6 /* error */ #define INTR_NOACK 0x7 /* no ack from master receiver */ /* * adapter layer errors */ #define IIC_NOERR 0x0 /* no error occured */ -#define IIC_EBUSERR 0x1 /* bus error */ +#define IIC_EBUSERR 0x1 /* bus error (hardware not in expected state) */ #define IIC_ENOACK 0x2 /* ack not received until timeout */ #define IIC_ETIMEOUT 0x3 /* timeout */ -#define IIC_EBUSBSY 0x4 /* bus busy */ +#define IIC_EBUSBSY 0x4 /* bus busy (reserved by another client) */ #define IIC_ESTATUS 0x5 /* status error */ #define IIC_EUNDERFLOW 0x6 /* slave ready for more data */ #define IIC_EOVERFLOW 0x7 /* too much data */ #define IIC_ENOTSUPP 0x8 /* request not supported */ #define IIC_ENOADDR 0x9 /* no address assigned to the interface */ +#define IIC_ERESOURCE 0xa /* resources (memory, whatever) unavailable */ +/* + * Note that all iicbus functions return IIC_Exxxxx status values, + * except iic2errno() (obviously) and iicbus_started() (returns bool). + */ +extern int iic2errno(int); extern int iicbus_request_bus(device_t, device_t, int); extern int iicbus_release_bus(device_t, device_t); extern device_t iicbus_alloc_bus(device_t); extern void iicbus_intr(device_t, int, char *); extern int iicbus_null_repeated_start(device_t, u_char); extern int iicbus_null_callback(device_t, int, caddr_t); #define iicbus_reset(bus,speed,addr,oldaddr) \ (IICBUS_RESET(device_get_parent(bus), speed, addr, oldaddr)) /* basic I2C operations */ extern int iicbus_started(device_t); extern int iicbus_start(device_t, u_char, int); extern int iicbus_stop(device_t); extern int iicbus_repeated_start(device_t, u_char, int); extern int iicbus_write(device_t, const char *, int, int *, int); extern int iicbus_read(device_t, char *, int, int *, int, int); /* single byte read/write functions, start/stop not managed */ extern int iicbus_write_byte(device_t, char, int); extern int iicbus_read_byte(device_t, char *, int); /* Read/write operations with start/stop conditions managed */ extern int iicbus_block_write(device_t, u_char, char *, int, int *); extern int iicbus_block_read(device_t, u_char, char *, int, int *); /* vectors of iic operations to pass to bridge */ int iicbus_transfer(device_t bus, struct iic_msg *msgs, uint32_t nmsgs); int iicbus_transfer_gen(device_t bus, struct iic_msg *msgs, uint32_t nmsgs); #define IICBUS_MODVER 1 #define IICBUS_MINVER 1 #define IICBUS_MAXVER 1 #define IICBUS_PREFVER IICBUS_MODVER extern driver_t iicbb_driver; extern devclass_t iicbb_devclass; #define IICBB_MODVER 1 #define IICBB_MINVER 1 #define IICBB_MAXVER 1 #define IICBB_PREFVER IICBB_MODVER #endif Index: projects/release-pkg/sys/dev/pcf/pcf.c =================================================================== --- projects/release-pkg/sys/dev/pcf/pcf.c (revision 289118) +++ projects/release-pkg/sys/dev/pcf/pcf.c (revision 289119) @@ -1,485 +1,485 @@ /*- * Copyright (c) 1998 Nicolas Souchu, Marc Bouget * Copyright (c) 2004 Joerg Wunsch * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include "iicbus_if.h" /* Not so official debugging option. */ /* #define PCFDEBUG */ static int pcf_wait_byte(struct pcf_softc *pcf); static int pcf_noack(struct pcf_softc *pcf, int timeout); static void pcf_stop_locked(struct pcf_softc *pcf); /* * Polling mode for master operations wait for a new * byte incoming or outgoing */ static int pcf_wait_byte(struct pcf_softc *sc) { int counter = TIMEOUT; PCF_ASSERT_LOCKED(sc); while (counter--) { if ((pcf_get_S1(sc) & PIN) == 0) return (0); } #ifdef PCFDEBUG printf("pcf: timeout!\n"); #endif return (IIC_ETIMEOUT); } static void pcf_stop_locked(struct pcf_softc *sc) { PCF_ASSERT_LOCKED(sc); #ifdef PCFDEBUG device_printf(dev, " >> stop\n"); #endif /* * Send STOP condition iff the START condition was previously sent. * STOP is sent only once even if an iicbus_stop() is called after * an iicbus_read()... see pcf_read(): the PCF needs to send the stop * before the last char is read. */ if (sc->pcf_started) { /* set stop condition and enable IT */ pcf_set_S1(sc, PIN|ESO|ENI|STO|ACK); sc->pcf_started = 0; } } static int pcf_noack(struct pcf_softc *sc, int timeout) { int noack; int k = timeout/10; PCF_ASSERT_LOCKED(sc); do { noack = pcf_get_S1(sc) & LRB; if (!noack) break; DELAY(10); /* XXX wait 10 us */ } while (k--); return (noack); } int pcf_repeated_start(device_t dev, u_char slave, int timeout) { struct pcf_softc *sc = DEVTOSOFTC(dev); int error = 0; PCF_LOCK(sc); #ifdef PCFDEBUG device_printf(dev, " >> repeated start for slave %#x\n", (unsigned)slave); #endif /* repeated start */ pcf_set_S1(sc, ESO|STA|STO|ACK); /* set slave address to PCF. Last bit (LSB) must be set correctly * according to transfer direction */ pcf_set_S0(sc, slave); /* wait for address sent, polling */ if ((error = pcf_wait_byte(sc))) goto error; /* check for ack */ if (pcf_noack(sc, timeout)) { error = IIC_ENOACK; #ifdef PCFDEBUG printf("pcf: no ack on repeated_start!\n"); #endif goto error; } PCF_UNLOCK(sc); return (0); error: pcf_stop_locked(sc); PCF_UNLOCK(sc); return (error); } int pcf_start(device_t dev, u_char slave, int timeout) { struct pcf_softc *sc = DEVTOSOFTC(dev); int error = 0; PCF_LOCK(sc); #ifdef PCFDEBUG device_printf(dev, " >> start for slave %#x\n", (unsigned)slave); #endif if ((pcf_get_S1(sc) & nBB) == 0) { #ifdef PCFDEBUG printf("pcf: busy!\n"); #endif PCF_UNLOCK(sc); - return (IIC_EBUSBSY); + return (IIC_EBUSERR); } /* set slave address to PCF. Last bit (LSB) must be set correctly * according to transfer direction */ pcf_set_S0(sc, slave); /* START only */ pcf_set_S1(sc, PIN|ESO|STA|ACK); sc->pcf_started = 1; /* wait for address sent, polling */ if ((error = pcf_wait_byte(sc))) goto error; /* check for ACK */ if (pcf_noack(sc, timeout)) { error = IIC_ENOACK; #ifdef PCFDEBUG printf("pcf: no ack on start!\n"); #endif goto error; } PCF_UNLOCK(sc); return (0); error: pcf_stop_locked(sc); PCF_UNLOCK(sc); return (error); } int pcf_stop(device_t dev) { struct pcf_softc *sc = DEVTOSOFTC(dev); #ifdef PCFDEBUG device_printf(dev, " >> stop\n"); #endif PCF_LOCK(sc); pcf_stop_locked(sc); PCF_UNLOCK(sc); return (0); } void pcf_intr(void *arg) { struct pcf_softc *sc = arg; char data, status, addr; char error = 0; PCF_LOCK(sc); status = pcf_get_S1(sc); if (status & PIN) { printf("pcf: spurious interrupt, status=0x%x\n", status & 0xff); goto error; } if (status & LAB) printf("pcf: bus arbitration lost!\n"); if (status & BER) { error = IIC_EBUSERR; iicbus_intr(sc->iicbus, INTR_ERROR, &error); goto error; } do { status = pcf_get_S1(sc); switch(sc->pcf_slave_mode) { case SLAVE_TRANSMITTER: if (status & LRB) { /* ack interrupt line */ dummy_write(sc); /* no ack, don't send anymore */ sc->pcf_slave_mode = SLAVE_RECEIVER; iicbus_intr(sc->iicbus, INTR_NOACK, NULL); break; } /* get data from upper code */ iicbus_intr(sc->iicbus, INTR_TRANSMIT, &data); pcf_set_S0(sc, data); break; case SLAVE_RECEIVER: if (status & AAS) { addr = pcf_get_S0(sc); if (status & AD0) iicbus_intr(sc->iicbus, INTR_GENERAL, &addr); else iicbus_intr(sc->iicbus, INTR_START, &addr); if (addr & LSB) { sc->pcf_slave_mode = SLAVE_TRANSMITTER; /* get the first char from upper code */ iicbus_intr(sc->iicbus, INTR_TRANSMIT, &data); /* send first data byte */ pcf_set_S0(sc, data); } break; } /* stop condition received? */ if (status & STS) { /* ack interrupt line */ dummy_read(sc); /* emulate intr stop condition */ iicbus_intr(sc->iicbus, INTR_STOP, NULL); } else { /* get data, ack interrupt line */ data = pcf_get_S0(sc); /* deliver the character */ iicbus_intr(sc->iicbus, INTR_RECEIVE, &data); } break; default: panic("%s: unknown slave mode (%d)!", __func__, sc->pcf_slave_mode); } } while ((pcf_get_S1(sc) & PIN) == 0); PCF_UNLOCK(sc); return; error: /* unknown event on bus...reset PCF */ pcf_set_S1(sc, PIN|ESO|ENI|ACK); sc->pcf_slave_mode = SLAVE_RECEIVER; PCF_UNLOCK(sc); return; } int pcf_rst_card(device_t dev, u_char speed, u_char addr, u_char *oldaddr) { struct pcf_softc *sc = DEVTOSOFTC(dev); PCF_LOCK(sc); if (oldaddr) *oldaddr = sc->pcf_addr; /* retrieve own address from bus level */ if (!addr) sc->pcf_addr = PCF_DEFAULT_ADDR; else sc->pcf_addr = addr; pcf_set_S1(sc, PIN); /* initialize S1 */ /* own address S'O<>0 */ pcf_set_S0(sc, sc->pcf_addr >> 1); /* select clock register */ pcf_set_S1(sc, PIN|ES1); /* select bus speed : 18=90kb, 19=45kb, 1A=11kb, 1B=1.5kb */ switch (speed) { case IIC_SLOW: pcf_set_S0(sc, 0x1b); /* XXX Sun uses 0x1f */ break; case IIC_FAST: pcf_set_S0(sc, 0x19); /* XXX Sun: 0x1d */ break; case IIC_UNKNOWN: case IIC_FASTEST: default: pcf_set_S0(sc, 0x18); /* XXX Sun: 0x1c */ break; } /* set bus on, ack=yes, INT=yes */ pcf_set_S1(sc, PIN|ESO|ENI|ACK); sc->pcf_slave_mode = SLAVE_RECEIVER; PCF_UNLOCK(sc); return (0); } int pcf_write(device_t dev, const char *buf, int len, int *sent, int timeout /* us */) { struct pcf_softc *sc = DEVTOSOFTC(dev); int bytes, error = 0; #ifdef PCFDEBUG device_printf(dev, " >> writing %d bytes: %#x%s\n", len, (unsigned)buf[0], len > 1? "...": ""); #endif bytes = 0; PCF_LOCK(sc); while (len) { pcf_set_S0(sc, *buf++); /* wait for the byte to be send */ if ((error = pcf_wait_byte(sc))) goto error; /* check if ack received */ if (pcf_noack(sc, timeout)) { error = IIC_ENOACK; goto error; } len --; bytes ++; } error: *sent = bytes; PCF_UNLOCK(sc); #ifdef PCFDEBUG device_printf(dev, " >> %d bytes written (%d)\n", bytes, error); #endif return (error); } int pcf_read(device_t dev, char *buf, int len, int *read, int last, int delay /* us */) { struct pcf_softc *sc = DEVTOSOFTC(dev); int bytes, error = 0; #ifdef PCFDEBUG char *obuf = buf; device_printf(dev, " << reading %d bytes\n", len); #endif PCF_LOCK(sc); /* trig the bus to get the first data byte in S0 */ if (len) { if (len == 1 && last) /* just one byte to read */ pcf_set_S1(sc, ESO); /* no ack */ dummy_read(sc); } bytes = 0; while (len) { /* XXX delay needed here */ /* wait for trigged byte */ if ((error = pcf_wait_byte(sc))) { pcf_stop_locked(sc); goto error; } if (len == 1 && last) /* ok, last data byte already in S0, no I2C activity * on next pcf_get_S0() */ pcf_stop_locked(sc); else if (len == 2 && last) /* next trigged byte with no ack */ pcf_set_S1(sc, ESO); /* receive byte, trig next byte */ *buf++ = pcf_get_S0(sc); len --; bytes ++; }; error: *read = bytes; PCF_UNLOCK(sc); #ifdef PCFDEBUG device_printf(dev, " << %d bytes read (%d): %#x%s\n", bytes, error, (unsigned)obuf[0], bytes > 1? "...": ""); #endif return (error); } DRIVER_MODULE(iicbus, pcf, iicbus_driver, iicbus_devclass, 0, 0); MODULE_DEPEND(pcf, iicbus, PCF_MINVER, PCF_PREFVER, PCF_MAXVER); MODULE_VERSION(pcf, PCF_MODVER); Index: projects/release-pkg/sys/geom/nop/g_nop.c =================================================================== --- projects/release-pkg/sys/geom/nop/g_nop.c (revision 289118) +++ projects/release-pkg/sys/geom/nop/g_nop.c (revision 289119) @@ -1,668 +1,704 @@ /*- * Copyright (c) 2004-2006 Pawel Jakub Dawidek * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include SYSCTL_DECL(_kern_geom); static SYSCTL_NODE(_kern_geom, OID_AUTO, nop, CTLFLAG_RW, 0, "GEOM_NOP stuff"); static u_int g_nop_debug = 0; SYSCTL_UINT(_kern_geom_nop, OID_AUTO, debug, CTLFLAG_RW, &g_nop_debug, 0, "Debug level"); static int g_nop_destroy(struct g_geom *gp, boolean_t force); static int g_nop_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp); static void g_nop_config(struct gctl_req *req, struct g_class *mp, const char *verb); static void g_nop_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp); struct g_class g_nop_class = { .name = G_NOP_CLASS_NAME, .version = G_VERSION, .ctlreq = g_nop_config, .destroy_geom = g_nop_destroy_geom }; static void g_nop_orphan(struct g_consumer *cp) { g_topology_assert(); g_nop_destroy(cp->geom, 1); } static void g_nop_resize(struct g_consumer *cp) { struct g_nop_softc *sc; struct g_geom *gp; struct g_provider *pp; off_t size; g_topology_assert(); gp = cp->geom; sc = gp->softc; if (sc->sc_explicitsize != 0) return; if (cp->provider->mediasize < sc->sc_offset) { g_nop_destroy(gp, 1); return; } size = cp->provider->mediasize - sc->sc_offset; LIST_FOREACH(pp, &gp->provider, provider) g_resize_provider(pp, size); } static void g_nop_start(struct bio *bp) { struct g_nop_softc *sc; struct g_geom *gp; struct g_provider *pp; struct bio *cbp; u_int failprob = 0; gp = bp->bio_to->geom; sc = gp->softc; G_NOP_LOGREQ(bp, "Request received."); mtx_lock(&sc->sc_lock); switch (bp->bio_cmd) { case BIO_READ: sc->sc_reads++; sc->sc_readbytes += bp->bio_length; failprob = sc->sc_rfailprob; break; case BIO_WRITE: sc->sc_writes++; sc->sc_wrotebytes += bp->bio_length; failprob = sc->sc_wfailprob; break; + case BIO_DELETE: + sc->sc_deletes++; + break; + case BIO_GETATTR: + sc->sc_getattrs++; + break; + case BIO_FLUSH: + sc->sc_flushes++; + break; + case BIO_CMD0: + sc->sc_cmd0s++; + break; + case BIO_CMD1: + sc->sc_cmd1s++; + break; + case BIO_CMD2: + sc->sc_cmd2s++; + break; } mtx_unlock(&sc->sc_lock); if (failprob > 0) { u_int rval; rval = arc4random() % 100; if (rval < failprob) { G_NOP_LOGREQLVL(1, bp, "Returning error=%d.", sc->sc_error); g_io_deliver(bp, sc->sc_error); return; } } cbp = g_clone_bio(bp); if (cbp == NULL) { g_io_deliver(bp, ENOMEM); return; } cbp->bio_done = g_std_done; cbp->bio_offset = bp->bio_offset + sc->sc_offset; pp = LIST_FIRST(&gp->provider); KASSERT(pp != NULL, ("NULL pp")); cbp->bio_to = pp; G_NOP_LOGREQ(cbp, "Sending request."); g_io_request(cbp, LIST_FIRST(&gp->consumer)); } static int g_nop_access(struct g_provider *pp, int dr, int dw, int de) { struct g_geom *gp; struct g_consumer *cp; int error; gp = pp->geom; cp = LIST_FIRST(&gp->consumer); error = g_access(cp, dr, dw, de); return (error); } static int g_nop_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp, int ioerror, u_int rfailprob, u_int wfailprob, off_t offset, off_t size, u_int secsize, u_int stripesize, u_int stripeoffset) { struct g_nop_softc *sc; struct g_geom *gp; struct g_provider *newpp; struct g_consumer *cp; char name[64]; int error; off_t explicitsize; g_topology_assert(); gp = NULL; newpp = NULL; cp = NULL; if ((offset % pp->sectorsize) != 0) { gctl_error(req, "Invalid offset for provider %s.", pp->name); return (EINVAL); } if ((size % pp->sectorsize) != 0) { gctl_error(req, "Invalid size for provider %s.", pp->name); return (EINVAL); } if (offset >= pp->mediasize) { gctl_error(req, "Invalid offset for provider %s.", pp->name); return (EINVAL); } explicitsize = size; if (size == 0) size = pp->mediasize - offset; if (offset + size > pp->mediasize) { gctl_error(req, "Invalid size for provider %s.", pp->name); return (EINVAL); } if (secsize == 0) secsize = pp->sectorsize; else if ((secsize % pp->sectorsize) != 0) { gctl_error(req, "Invalid secsize for provider %s.", pp->name); return (EINVAL); } if (secsize > MAXPHYS) { gctl_error(req, "secsize is too big."); return (EINVAL); } size -= size % secsize; if ((stripesize % pp->sectorsize) != 0) { gctl_error(req, "Invalid stripesize for provider %s.", pp->name); return (EINVAL); } if ((stripeoffset % pp->sectorsize) != 0) { gctl_error(req, "Invalid stripeoffset for provider %s.", pp->name); return (EINVAL); } if (stripesize != 0 && stripeoffset >= stripesize) { gctl_error(req, "stripeoffset is too big."); return (EINVAL); } snprintf(name, sizeof(name), "%s%s", pp->name, G_NOP_SUFFIX); LIST_FOREACH(gp, &mp->geom, geom) { if (strcmp(gp->name, name) == 0) { gctl_error(req, "Provider %s already exists.", name); return (EEXIST); } } gp = g_new_geomf(mp, "%s", name); sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO); sc->sc_offset = offset; sc->sc_explicitsize = explicitsize; sc->sc_stripesize = stripesize; sc->sc_stripeoffset = stripeoffset; sc->sc_error = ioerror; sc->sc_rfailprob = rfailprob; sc->sc_wfailprob = wfailprob; sc->sc_reads = 0; sc->sc_writes = 0; + sc->sc_deletes = 0; + sc->sc_getattrs = 0; + sc->sc_flushes = 0; + sc->sc_cmd0s = 0; + sc->sc_cmd1s = 0; + sc->sc_cmd2s = 0; sc->sc_readbytes = 0; sc->sc_wrotebytes = 0; mtx_init(&sc->sc_lock, "gnop lock", NULL, MTX_DEF); gp->softc = sc; gp->start = g_nop_start; gp->orphan = g_nop_orphan; gp->resize = g_nop_resize; gp->access = g_nop_access; gp->dumpconf = g_nop_dumpconf; newpp = g_new_providerf(gp, "%s", gp->name); newpp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE; newpp->mediasize = size; newpp->sectorsize = secsize; newpp->stripesize = stripesize; newpp->stripeoffset = stripeoffset; cp = g_new_consumer(gp); cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; error = g_attach(cp, pp); if (error != 0) { gctl_error(req, "Cannot attach to provider %s.", pp->name); goto fail; } newpp->flags |= pp->flags & G_PF_ACCEPT_UNMAPPED; g_error_provider(newpp, 0); G_NOP_DEBUG(0, "Device %s created.", gp->name); return (0); fail: if (cp->provider != NULL) g_detach(cp); g_destroy_consumer(cp); g_destroy_provider(newpp); mtx_destroy(&sc->sc_lock); g_free(gp->softc); g_destroy_geom(gp); return (error); } static int g_nop_destroy(struct g_geom *gp, boolean_t force) { struct g_nop_softc *sc; struct g_provider *pp; g_topology_assert(); sc = gp->softc; if (sc == NULL) return (ENXIO); pp = LIST_FIRST(&gp->provider); if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) { if (force) { G_NOP_DEBUG(0, "Device %s is still open, so it " "can't be definitely removed.", pp->name); } else { G_NOP_DEBUG(1, "Device %s is still open (r%dw%de%d).", pp->name, pp->acr, pp->acw, pp->ace); return (EBUSY); } } else { G_NOP_DEBUG(0, "Device %s removed.", gp->name); } gp->softc = NULL; mtx_destroy(&sc->sc_lock); g_free(sc); g_wither_geom(gp, ENXIO); return (0); } static int g_nop_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp) { return (g_nop_destroy(gp, 0)); } static void g_nop_ctl_create(struct gctl_req *req, struct g_class *mp) { struct g_provider *pp; intmax_t *error, *rfailprob, *wfailprob, *offset, *secsize, *size, *stripesize, *stripeoffset; const char *name; char param[16]; int i, *nargs; g_topology_assert(); nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); if (nargs == NULL) { gctl_error(req, "No '%s' argument", "nargs"); return; } if (*nargs <= 0) { gctl_error(req, "Missing device(s)."); return; } error = gctl_get_paraml(req, "error", sizeof(*error)); if (error == NULL) { gctl_error(req, "No '%s' argument", "error"); return; } rfailprob = gctl_get_paraml(req, "rfailprob", sizeof(*rfailprob)); if (rfailprob == NULL) { gctl_error(req, "No '%s' argument", "rfailprob"); return; } if (*rfailprob < -1 || *rfailprob > 100) { gctl_error(req, "Invalid '%s' argument", "rfailprob"); return; } wfailprob = gctl_get_paraml(req, "wfailprob", sizeof(*wfailprob)); if (wfailprob == NULL) { gctl_error(req, "No '%s' argument", "wfailprob"); return; } if (*wfailprob < -1 || *wfailprob > 100) { gctl_error(req, "Invalid '%s' argument", "wfailprob"); return; } offset = gctl_get_paraml(req, "offset", sizeof(*offset)); if (offset == NULL) { gctl_error(req, "No '%s' argument", "offset"); return; } if (*offset < 0) { gctl_error(req, "Invalid '%s' argument", "offset"); return; } size = gctl_get_paraml(req, "size", sizeof(*size)); if (size == NULL) { gctl_error(req, "No '%s' argument", "size"); return; } if (*size < 0) { gctl_error(req, "Invalid '%s' argument", "size"); return; } secsize = gctl_get_paraml(req, "secsize", sizeof(*secsize)); if (secsize == NULL) { gctl_error(req, "No '%s' argument", "secsize"); return; } if (*secsize < 0) { gctl_error(req, "Invalid '%s' argument", "secsize"); return; } stripesize = gctl_get_paraml(req, "stripesize", sizeof(*stripesize)); if (stripesize == NULL) { gctl_error(req, "No '%s' argument", "stripesize"); return; } if (*stripesize < 0) { gctl_error(req, "Invalid '%s' argument", "stripesize"); return; } stripeoffset = gctl_get_paraml(req, "stripeoffset", sizeof(*stripeoffset)); if (stripeoffset == NULL) { gctl_error(req, "No '%s' argument", "stripeoffset"); return; } if (*stripeoffset < 0) { gctl_error(req, "Invalid '%s' argument", "stripeoffset"); return; } for (i = 0; i < *nargs; i++) { snprintf(param, sizeof(param), "arg%d", i); name = gctl_get_asciiparam(req, param); if (name == NULL) { gctl_error(req, "No 'arg%d' argument", i); return; } if (strncmp(name, "/dev/", strlen("/dev/")) == 0) name += strlen("/dev/"); pp = g_provider_by_name(name); if (pp == NULL) { G_NOP_DEBUG(1, "Provider %s is invalid.", name); gctl_error(req, "Provider %s is invalid.", name); return; } if (g_nop_create(req, mp, pp, *error == -1 ? EIO : (int)*error, *rfailprob == -1 ? 0 : (u_int)*rfailprob, *wfailprob == -1 ? 0 : (u_int)*wfailprob, (off_t)*offset, (off_t)*size, (u_int)*secsize, (u_int)*stripesize, (u_int)*stripeoffset) != 0) { return; } } } static void g_nop_ctl_configure(struct gctl_req *req, struct g_class *mp) { struct g_nop_softc *sc; struct g_provider *pp; intmax_t *error, *rfailprob, *wfailprob; const char *name; char param[16]; int i, *nargs; g_topology_assert(); nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); if (nargs == NULL) { gctl_error(req, "No '%s' argument", "nargs"); return; } if (*nargs <= 0) { gctl_error(req, "Missing device(s)."); return; } error = gctl_get_paraml(req, "error", sizeof(*error)); if (error == NULL) { gctl_error(req, "No '%s' argument", "error"); return; } rfailprob = gctl_get_paraml(req, "rfailprob", sizeof(*rfailprob)); if (rfailprob == NULL) { gctl_error(req, "No '%s' argument", "rfailprob"); return; } if (*rfailprob < -1 || *rfailprob > 100) { gctl_error(req, "Invalid '%s' argument", "rfailprob"); return; } wfailprob = gctl_get_paraml(req, "wfailprob", sizeof(*wfailprob)); if (wfailprob == NULL) { gctl_error(req, "No '%s' argument", "wfailprob"); return; } if (*wfailprob < -1 || *wfailprob > 100) { gctl_error(req, "Invalid '%s' argument", "wfailprob"); return; } for (i = 0; i < *nargs; i++) { snprintf(param, sizeof(param), "arg%d", i); name = gctl_get_asciiparam(req, param); if (name == NULL) { gctl_error(req, "No 'arg%d' argument", i); return; } if (strncmp(name, "/dev/", strlen("/dev/")) == 0) name += strlen("/dev/"); pp = g_provider_by_name(name); if (pp == NULL || pp->geom->class != mp) { G_NOP_DEBUG(1, "Provider %s is invalid.", name); gctl_error(req, "Provider %s is invalid.", name); return; } sc = pp->geom->softc; if (*error != -1) sc->sc_error = (int)*error; if (*rfailprob != -1) sc->sc_rfailprob = (u_int)*rfailprob; if (*wfailprob != -1) sc->sc_wfailprob = (u_int)*wfailprob; } } static struct g_geom * g_nop_find_geom(struct g_class *mp, const char *name) { struct g_geom *gp; LIST_FOREACH(gp, &mp->geom, geom) { if (strcmp(gp->name, name) == 0) return (gp); } return (NULL); } static void g_nop_ctl_destroy(struct gctl_req *req, struct g_class *mp) { int *nargs, *force, error, i; struct g_geom *gp; const char *name; char param[16]; g_topology_assert(); nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); if (nargs == NULL) { gctl_error(req, "No '%s' argument", "nargs"); return; } if (*nargs <= 0) { gctl_error(req, "Missing device(s)."); return; } force = gctl_get_paraml(req, "force", sizeof(*force)); if (force == NULL) { gctl_error(req, "No 'force' argument"); return; } for (i = 0; i < *nargs; i++) { snprintf(param, sizeof(param), "arg%d", i); name = gctl_get_asciiparam(req, param); if (name == NULL) { gctl_error(req, "No 'arg%d' argument", i); return; } if (strncmp(name, "/dev/", strlen("/dev/")) == 0) name += strlen("/dev/"); gp = g_nop_find_geom(mp, name); if (gp == NULL) { G_NOP_DEBUG(1, "Device %s is invalid.", name); gctl_error(req, "Device %s is invalid.", name); return; } error = g_nop_destroy(gp, *force); if (error != 0) { gctl_error(req, "Cannot destroy device %s (error=%d).", gp->name, error); return; } } } static void g_nop_ctl_reset(struct gctl_req *req, struct g_class *mp) { struct g_nop_softc *sc; struct g_provider *pp; const char *name; char param[16]; int i, *nargs; g_topology_assert(); nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); if (nargs == NULL) { gctl_error(req, "No '%s' argument", "nargs"); return; } if (*nargs <= 0) { gctl_error(req, "Missing device(s)."); return; } for (i = 0; i < *nargs; i++) { snprintf(param, sizeof(param), "arg%d", i); name = gctl_get_asciiparam(req, param); if (name == NULL) { gctl_error(req, "No 'arg%d' argument", i); return; } if (strncmp(name, "/dev/", strlen("/dev/")) == 0) name += strlen("/dev/"); pp = g_provider_by_name(name); if (pp == NULL || pp->geom->class != mp) { G_NOP_DEBUG(1, "Provider %s is invalid.", name); gctl_error(req, "Provider %s is invalid.", name); return; } sc = pp->geom->softc; sc->sc_reads = 0; sc->sc_writes = 0; + sc->sc_deletes = 0; + sc->sc_getattrs = 0; + sc->sc_flushes = 0; + sc->sc_cmd0s = 0; + sc->sc_cmd1s = 0; + sc->sc_cmd2s = 0; sc->sc_readbytes = 0; sc->sc_wrotebytes = 0; } } static void g_nop_config(struct gctl_req *req, struct g_class *mp, const char *verb) { uint32_t *version; g_topology_assert(); version = gctl_get_paraml(req, "version", sizeof(*version)); if (version == NULL) { gctl_error(req, "No '%s' argument.", "version"); return; } if (*version != G_NOP_VERSION) { gctl_error(req, "Userland and kernel parts are out of sync."); return; } if (strcmp(verb, "create") == 0) { g_nop_ctl_create(req, mp); return; } else if (strcmp(verb, "configure") == 0) { g_nop_ctl_configure(req, mp); return; } else if (strcmp(verb, "destroy") == 0) { g_nop_ctl_destroy(req, mp); return; } else if (strcmp(verb, "reset") == 0) { g_nop_ctl_reset(req, mp); return; } gctl_error(req, "Unknown verb."); } static void g_nop_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp) { struct g_nop_softc *sc; if (pp != NULL || cp != NULL) return; sc = gp->softc; sbuf_printf(sb, "%s%jd\n", indent, (intmax_t)sc->sc_offset); sbuf_printf(sb, "%s%u\n", indent, sc->sc_rfailprob); sbuf_printf(sb, "%s%u\n", indent, sc->sc_wfailprob); sbuf_printf(sb, "%s%d\n", indent, sc->sc_error); sbuf_printf(sb, "%s%ju\n", indent, sc->sc_reads); sbuf_printf(sb, "%s%ju\n", indent, sc->sc_writes); + sbuf_printf(sb, "%s%ju\n", indent, sc->sc_deletes); + sbuf_printf(sb, "%s%ju\n", indent, sc->sc_getattrs); + sbuf_printf(sb, "%s%ju\n", indent, sc->sc_flushes); + sbuf_printf(sb, "%s%ju\n", indent, sc->sc_cmd0s); + sbuf_printf(sb, "%s%ju\n", indent, sc->sc_cmd1s); + sbuf_printf(sb, "%s%ju\n", indent, sc->sc_cmd2s); sbuf_printf(sb, "%s%ju\n", indent, sc->sc_readbytes); sbuf_printf(sb, "%s%ju\n", indent, sc->sc_wrotebytes); } DECLARE_GEOM_CLASS(g_nop_class, g_nop); Index: projects/release-pkg/sys/geom/nop/g_nop.h =================================================================== --- projects/release-pkg/sys/geom/nop/g_nop.h (revision 289118) +++ projects/release-pkg/sys/geom/nop/g_nop.h (revision 289119) @@ -1,74 +1,80 @@ /*- * Copyright (c) 2004-2006 Pawel Jakub Dawidek * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _G_NOP_H_ #define _G_NOP_H_ #define G_NOP_CLASS_NAME "NOP" #define G_NOP_VERSION 4 #define G_NOP_SUFFIX ".nop" #ifdef _KERNEL #define G_NOP_DEBUG(lvl, ...) do { \ if (g_nop_debug >= (lvl)) { \ printf("GEOM_NOP"); \ if (g_nop_debug > 0) \ printf("[%u]", lvl); \ printf(": "); \ printf(__VA_ARGS__); \ printf("\n"); \ } \ } while (0) #define G_NOP_LOGREQ(bp, ...) G_NOP_LOGREQLVL(2, bp, __VA_ARGS__) #define G_NOP_LOGREQLVL(lvl, bp, ...) do { \ if (g_nop_debug >= (lvl)) { \ printf("GEOM_NOP[%d]: ", (lvl)); \ printf(__VA_ARGS__); \ printf(" "); \ g_print_bio(bp); \ printf("\n"); \ } \ } while (0) struct g_nop_softc { int sc_error; off_t sc_offset; off_t sc_explicitsize; off_t sc_stripesize; off_t sc_stripeoffset; u_int sc_rfailprob; u_int sc_wfailprob; uintmax_t sc_reads; uintmax_t sc_writes; + uintmax_t sc_deletes; + uintmax_t sc_getattrs; + uintmax_t sc_flushes; + uintmax_t sc_cmd0s; + uintmax_t sc_cmd1s; + uintmax_t sc_cmd2s; uintmax_t sc_readbytes; uintmax_t sc_wrotebytes; struct mtx sc_lock; }; #endif /* _KERNEL */ #endif /* _G_NOP_H_ */ Index: projects/release-pkg/sys/kern/kern_module.c =================================================================== --- projects/release-pkg/sys/kern/kern_module.c (revision 289118) +++ projects/release-pkg/sys/kern/kern_module.c (revision 289119) @@ -1,523 +1,519 @@ /*- * Copyright (c) 1997 Doug Rabson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "opt_compat.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include static MALLOC_DEFINE(M_MODULE, "module", "module data structures"); struct module { TAILQ_ENTRY(module) link; /* chain together all modules */ TAILQ_ENTRY(module) flink; /* all modules in a file */ struct linker_file *file; /* file which contains this module */ int refs; /* reference count */ int id; /* unique id number */ char *name; /* module name */ modeventhand_t handler; /* event handler */ void *arg; /* argument for handler */ modspecific_t data; /* module specific data */ }; #define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg) static TAILQ_HEAD(modulelist, module) modules; struct sx modules_sx; static int nextid = 1; static void module_shutdown(void *, int); static int modevent_nop(module_t mod, int what, void *arg) { switch(what) { case MOD_LOAD: return (0); case MOD_UNLOAD: return (EBUSY); default: return (EOPNOTSUPP); } } static void module_init(void *arg) { sx_init(&modules_sx, "module subsystem sx lock"); TAILQ_INIT(&modules); EVENTHANDLER_REGISTER(shutdown_final, module_shutdown, NULL, SHUTDOWN_PRI_DEFAULT); } SYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0); static void module_shutdown(void *arg1, int arg2) { module_t mod; if (arg2 & RB_NOSYNC) return; mtx_lock(&Giant); MOD_SLOCK; TAILQ_FOREACH_REVERSE(mod, &modules, modulelist, link) MOD_EVENT(mod, MOD_SHUTDOWN); MOD_SUNLOCK; mtx_unlock(&Giant); } void module_register_init(const void *arg) { const moduledata_t *data = (const moduledata_t *)arg; int error; module_t mod; mtx_lock(&Giant); MOD_SLOCK; mod = module_lookupbyname(data->name); if (mod == NULL) panic("module_register_init: module named %s not found\n", data->name); MOD_SUNLOCK; error = MOD_EVENT(mod, MOD_LOAD); if (error) { MOD_EVENT(mod, MOD_UNLOAD); MOD_XLOCK; module_release(mod); MOD_XUNLOCK; printf("module_register_init: MOD_LOAD (%s, %p, %p) error" " %d\n", data->name, (void *)data->evhand, data->priv, error); } else { MOD_XLOCK; if (mod->file) { /* * Once a module is successfully loaded, move * it to the head of the module list for this * linker file. This resorts the list so that * when the kernel linker iterates over the * modules to unload them, it will unload them * in the reverse order they were loaded. */ TAILQ_REMOVE(&mod->file->modules, mod, flink); TAILQ_INSERT_HEAD(&mod->file->modules, mod, flink); } MOD_XUNLOCK; } mtx_unlock(&Giant); } int module_register(const moduledata_t *data, linker_file_t container) { size_t namelen; module_t newmod; MOD_XLOCK; newmod = module_lookupbyname(data->name); if (newmod != NULL) { MOD_XUNLOCK; - printf("module_register: module %s already exists!\n", - data->name); + printf("%s: cannot register %s from %s; already loaded from %s\n", + __func__, data->name, container->filename, newmod->file->filename); return (EEXIST); } namelen = strlen(data->name) + 1; newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK); - if (newmod == NULL) { - MOD_XUNLOCK; - return (ENOMEM); - } newmod->refs = 1; newmod->id = nextid++; newmod->name = (char *)(newmod + 1); strcpy(newmod->name, data->name); newmod->handler = data->evhand ? data->evhand : modevent_nop; newmod->arg = data->priv; bzero(&newmod->data, sizeof(newmod->data)); TAILQ_INSERT_TAIL(&modules, newmod, link); if (container) TAILQ_INSERT_TAIL(&container->modules, newmod, flink); newmod->file = container; MOD_XUNLOCK; return (0); } void module_reference(module_t mod) { MOD_XLOCK_ASSERT; MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs)); mod->refs++; } void module_release(module_t mod) { MOD_XLOCK_ASSERT; if (mod->refs <= 0) panic("module_release: bad reference count"); MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs)); mod->refs--; if (mod->refs == 0) { TAILQ_REMOVE(&modules, mod, link); if (mod->file) TAILQ_REMOVE(&mod->file->modules, mod, flink); free(mod, M_MODULE); } } module_t module_lookupbyname(const char *name) { module_t mod; int err; MOD_LOCK_ASSERT; TAILQ_FOREACH(mod, &modules, link) { err = strcmp(mod->name, name); if (err == 0) return (mod); } return (NULL); } module_t module_lookupbyid(int modid) { module_t mod; MOD_LOCK_ASSERT; TAILQ_FOREACH(mod, &modules, link) if (mod->id == modid) return(mod); return (NULL); } int module_quiesce(module_t mod) { int error; mtx_lock(&Giant); error = MOD_EVENT(mod, MOD_QUIESCE); mtx_unlock(&Giant); if (error == EOPNOTSUPP || error == EINVAL) error = 0; return (error); } int module_unload(module_t mod) { int error; mtx_lock(&Giant); error = MOD_EVENT(mod, MOD_UNLOAD); mtx_unlock(&Giant); return (error); } int module_getid(module_t mod) { MOD_LOCK_ASSERT; return (mod->id); } module_t module_getfnext(module_t mod) { MOD_LOCK_ASSERT; return (TAILQ_NEXT(mod, flink)); } const char * module_getname(module_t mod) { MOD_LOCK_ASSERT; return (mod->name); } void module_setspecific(module_t mod, modspecific_t *datap) { MOD_XLOCK_ASSERT; mod->data = *datap; } linker_file_t module_file(module_t mod) { return (mod->file); } /* * Syscalls. */ int sys_modnext(struct thread *td, struct modnext_args *uap) { module_t mod; int error = 0; td->td_retval[0] = -1; MOD_SLOCK; if (uap->modid == 0) { mod = TAILQ_FIRST(&modules); if (mod) td->td_retval[0] = mod->id; else error = ENOENT; goto done2; } mod = module_lookupbyid(uap->modid); if (mod == NULL) { error = ENOENT; goto done2; } if (TAILQ_NEXT(mod, link)) td->td_retval[0] = TAILQ_NEXT(mod, link)->id; else td->td_retval[0] = 0; done2: MOD_SUNLOCK; return (error); } int sys_modfnext(struct thread *td, struct modfnext_args *uap) { module_t mod; int error; td->td_retval[0] = -1; MOD_SLOCK; mod = module_lookupbyid(uap->modid); if (mod == NULL) { error = ENOENT; } else { error = 0; if (TAILQ_NEXT(mod, flink)) td->td_retval[0] = TAILQ_NEXT(mod, flink)->id; else td->td_retval[0] = 0; } MOD_SUNLOCK; return (error); } struct module_stat_v1 { int version; /* set to sizeof(struct module_stat) */ char name[MAXMODNAME]; int refs; int id; }; int sys_modstat(struct thread *td, struct modstat_args *uap) { module_t mod; modspecific_t data; int error = 0; int id, namelen, refs, version; struct module_stat *stat; char *name; MOD_SLOCK; mod = module_lookupbyid(uap->modid); if (mod == NULL) { MOD_SUNLOCK; return (ENOENT); } id = mod->id; refs = mod->refs; name = mod->name; data = mod->data; MOD_SUNLOCK; stat = uap->stat; /* * Check the version of the user's structure. */ if ((error = copyin(&stat->version, &version, sizeof(version))) != 0) return (error); if (version != sizeof(struct module_stat_v1) && version != sizeof(struct module_stat)) return (EINVAL); namelen = strlen(mod->name) + 1; if (namelen > MAXMODNAME) namelen = MAXMODNAME; if ((error = copyout(name, &stat->name[0], namelen)) != 0) return (error); if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0) return (error); if ((error = copyout(&id, &stat->id, sizeof(int))) != 0) return (error); /* * >v1 stat includes module data. */ if (version == sizeof(struct module_stat)) if ((error = copyout(&data, &stat->data, sizeof(data))) != 0) return (error); td->td_retval[0] = 0; return (error); } int sys_modfind(struct thread *td, struct modfind_args *uap) { int error = 0; char name[MAXMODNAME]; module_t mod; if ((error = copyinstr(uap->name, name, sizeof name, 0)) != 0) return (error); MOD_SLOCK; mod = module_lookupbyname(name); if (mod == NULL) error = ENOENT; else td->td_retval[0] = module_getid(mod); MOD_SUNLOCK; return (error); } MODULE_VERSION(kernel, __FreeBSD_version); #ifdef COMPAT_FREEBSD32 #include #include #include #include #include typedef union modspecific32 { int intval; uint32_t uintval; int longval; uint32_t ulongval; } modspecific32_t; struct module_stat32 { int version; char name[MAXMODNAME]; int refs; int id; modspecific32_t data; }; int freebsd32_modstat(struct thread *td, struct freebsd32_modstat_args *uap) { module_t mod; modspecific32_t data32; int error = 0; int id, namelen, refs, version; struct module_stat32 *stat32; char *name; MOD_SLOCK; mod = module_lookupbyid(uap->modid); if (mod == NULL) { MOD_SUNLOCK; return (ENOENT); } id = mod->id; refs = mod->refs; name = mod->name; CP(mod->data, data32, intval); CP(mod->data, data32, uintval); CP(mod->data, data32, longval); CP(mod->data, data32, ulongval); MOD_SUNLOCK; stat32 = uap->stat; if ((error = copyin(&stat32->version, &version, sizeof(version))) != 0) return (error); if (version != sizeof(struct module_stat_v1) && version != sizeof(struct module_stat32)) return (EINVAL); namelen = strlen(mod->name) + 1; if (namelen > MAXMODNAME) namelen = MAXMODNAME; if ((error = copyout(name, &stat32->name[0], namelen)) != 0) return (error); if ((error = copyout(&refs, &stat32->refs, sizeof(int))) != 0) return (error); if ((error = copyout(&id, &stat32->id, sizeof(int))) != 0) return (error); /* * >v1 stat includes module data. */ if (version == sizeof(struct module_stat32)) if ((error = copyout(&data32, &stat32->data, sizeof(data32))) != 0) return (error); td->td_retval[0] = 0; return (error); } #endif Index: projects/release-pkg/sys/kern/sysv_shm.c =================================================================== --- projects/release-pkg/sys/kern/sysv_shm.c (revision 289118) +++ projects/release-pkg/sys/kern/sysv_shm.c (revision 289119) @@ -1,1364 +1,1364 @@ /* $NetBSD: sysv_shm.c,v 1.23 1994/07/04 23:25:12 glass Exp $ */ /*- * Copyright (c) 1994 Adam Glass and Charles Hannum. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Adam Glass and Charles * Hannum. * 4. The names of the authors may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHORS 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. */ /*- * Copyright (c) 2003-2005 McAfee, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project in part by McAfee * Research, the Security Research Division of McAfee, Inc under DARPA/SPAWAR * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS research * program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_compat.h" #include "opt_sysvipc.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include FEATURE(sysv_shm, "System V shared memory segments support"); static MALLOC_DEFINE(M_SHM, "shm", "SVID compatible shared memory segments"); static int shmget_allocate_segment(struct thread *td, struct shmget_args *uap, int mode); static int shmget_existing(struct thread *td, struct shmget_args *uap, int mode, int segnum); #define SHMSEG_FREE 0x0200 #define SHMSEG_REMOVED 0x0400 #define SHMSEG_ALLOCATED 0x0800 static int shm_last_free, shm_nused, shmalloced; vm_size_t shm_committed; static struct shmid_kernel *shmsegs; struct shmmap_state { vm_offset_t va; int shmid; }; static void shm_deallocate_segment(struct shmid_kernel *); static int shm_find_segment_by_key(key_t); static struct shmid_kernel *shm_find_segment(int, bool); static int shm_delete_mapping(struct vmspace *vm, struct shmmap_state *); static void shmrealloc(void); static int shminit(void); static int sysvshm_modload(struct module *, int, void *); static int shmunload(void); static void shmexit_myhook(struct vmspace *vm); static void shmfork_myhook(struct proc *p1, struct proc *p2); static int sysctl_shmsegs(SYSCTL_HANDLER_ARGS); /* * Tuneable values. */ #ifndef SHMMAXPGS #define SHMMAXPGS 131072 /* Note: sysv shared memory is swap backed. */ #endif #ifndef SHMMAX #define SHMMAX (SHMMAXPGS*PAGE_SIZE) #endif #ifndef SHMMIN #define SHMMIN 1 #endif #ifndef SHMMNI #define SHMMNI 192 #endif #ifndef SHMSEG #define SHMSEG 128 #endif #ifndef SHMALL #define SHMALL (SHMMAXPGS) #endif struct shminfo shminfo = { .shmmax = SHMMAX, .shmmin = SHMMIN, .shmmni = SHMMNI, .shmseg = SHMSEG, .shmall = SHMALL }; static int shm_use_phys; -static int shm_allow_removed; +static int shm_allow_removed = 1; SYSCTL_ULONG(_kern_ipc, OID_AUTO, shmmax, CTLFLAG_RWTUN, &shminfo.shmmax, 0, "Maximum shared memory segment size"); SYSCTL_ULONG(_kern_ipc, OID_AUTO, shmmin, CTLFLAG_RWTUN, &shminfo.shmmin, 0, "Minimum shared memory segment size"); SYSCTL_ULONG(_kern_ipc, OID_AUTO, shmmni, CTLFLAG_RDTUN, &shminfo.shmmni, 0, "Number of shared memory identifiers"); SYSCTL_ULONG(_kern_ipc, OID_AUTO, shmseg, CTLFLAG_RDTUN, &shminfo.shmseg, 0, "Number of segments per process"); SYSCTL_ULONG(_kern_ipc, OID_AUTO, shmall, CTLFLAG_RWTUN, &shminfo.shmall, 0, "Maximum number of pages available for shared memory"); SYSCTL_INT(_kern_ipc, OID_AUTO, shm_use_phys, CTLFLAG_RWTUN, &shm_use_phys, 0, "Enable/Disable locking of shared memory pages in core"); SYSCTL_INT(_kern_ipc, OID_AUTO, shm_allow_removed, CTLFLAG_RWTUN, &shm_allow_removed, 0, "Enable/Disable attachment to attached segments marked for removal"); SYSCTL_PROC(_kern_ipc, OID_AUTO, shmsegs, CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, sysctl_shmsegs, "", "Current number of shared memory segments allocated"); static struct sx sysvshmsx; #define SYSVSHM_LOCK() sx_xlock(&sysvshmsx) #define SYSVSHM_UNLOCK() sx_xunlock(&sysvshmsx) #define SYSVSHM_ASSERT_LOCKED() sx_assert(&sysvshmsx, SA_XLOCKED) static int shm_find_segment_by_key(key_t key) { int i; for (i = 0; i < shmalloced; i++) if ((shmsegs[i].u.shm_perm.mode & SHMSEG_ALLOCATED) && shmsegs[i].u.shm_perm.key == key) return (i); return (-1); } /* * Finds segment either by shmid if is_shmid is true, or by segnum if * is_shmid is false. */ static struct shmid_kernel * shm_find_segment(int arg, bool is_shmid) { struct shmid_kernel *shmseg; int segnum; segnum = is_shmid ? IPCID_TO_IX(arg) : arg; if (segnum < 0 || segnum >= shmalloced) return (NULL); shmseg = &shmsegs[segnum]; if ((shmseg->u.shm_perm.mode & SHMSEG_ALLOCATED) == 0 || (!shm_allow_removed && (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) != 0) || (is_shmid && shmseg->u.shm_perm.seq != IPCID_TO_SEQ(arg))) return (NULL); return (shmseg); } static void shm_deallocate_segment(struct shmid_kernel *shmseg) { vm_size_t size; SYSVSHM_ASSERT_LOCKED(); vm_object_deallocate(shmseg->object); shmseg->object = NULL; size = round_page(shmseg->u.shm_segsz); shm_committed -= btoc(size); shm_nused--; shmseg->u.shm_perm.mode = SHMSEG_FREE; #ifdef MAC mac_sysvshm_cleanup(shmseg); #endif racct_sub_cred(shmseg->cred, RACCT_NSHM, 1); racct_sub_cred(shmseg->cred, RACCT_SHMSIZE, size); crfree(shmseg->cred); shmseg->cred = NULL; } static int shm_delete_mapping(struct vmspace *vm, struct shmmap_state *shmmap_s) { struct shmid_kernel *shmseg; int segnum, result; vm_size_t size; SYSVSHM_ASSERT_LOCKED(); segnum = IPCID_TO_IX(shmmap_s->shmid); KASSERT(segnum >= 0 && segnum < shmalloced, ("segnum %d shmalloced %d", segnum, shmalloced)); shmseg = &shmsegs[segnum]; size = round_page(shmseg->u.shm_segsz); result = vm_map_remove(&vm->vm_map, shmmap_s->va, shmmap_s->va + size); if (result != KERN_SUCCESS) return (EINVAL); shmmap_s->shmid = -1; shmseg->u.shm_dtime = time_second; if ((--shmseg->u.shm_nattch <= 0) && (shmseg->u.shm_perm.mode & SHMSEG_REMOVED)) { shm_deallocate_segment(shmseg); shm_last_free = segnum; } return (0); } static int kern_shmdt_locked(struct thread *td, const void *shmaddr) { struct proc *p = td->td_proc; struct shmmap_state *shmmap_s; #ifdef MAC struct shmid_kernel *shmsegptr; int error; #endif int i; SYSVSHM_ASSERT_LOCKED(); if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) return (ENOSYS); shmmap_s = p->p_vmspace->vm_shm; if (shmmap_s == NULL) return (EINVAL); for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) { if (shmmap_s->shmid != -1 && shmmap_s->va == (vm_offset_t)shmaddr) { break; } } if (i == shminfo.shmseg) return (EINVAL); #ifdef MAC shmsegptr = &shmsegs[IPCID_TO_IX(shmmap_s->shmid)]; error = mac_sysvshm_check_shmdt(td->td_ucred, shmsegptr); if (error != 0) return (error); #endif return (shm_delete_mapping(p->p_vmspace, shmmap_s)); } #ifndef _SYS_SYSPROTO_H_ struct shmdt_args { const void *shmaddr; }; #endif int sys_shmdt(struct thread *td, struct shmdt_args *uap) { int error; SYSVSHM_LOCK(); error = kern_shmdt_locked(td, uap->shmaddr); SYSVSHM_UNLOCK(); return (error); } static int kern_shmat_locked(struct thread *td, int shmid, const void *shmaddr, int shmflg) { struct proc *p = td->td_proc; struct shmid_kernel *shmseg; struct shmmap_state *shmmap_s; vm_offset_t attach_va; vm_prot_t prot; vm_size_t size; int error, i, rv; SYSVSHM_ASSERT_LOCKED(); if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) return (ENOSYS); shmmap_s = p->p_vmspace->vm_shm; if (shmmap_s == NULL) { shmmap_s = malloc(shminfo.shmseg * sizeof(struct shmmap_state), M_SHM, M_WAITOK); for (i = 0; i < shminfo.shmseg; i++) shmmap_s[i].shmid = -1; KASSERT(p->p_vmspace->vm_shm == NULL, ("raced")); p->p_vmspace->vm_shm = shmmap_s; } shmseg = shm_find_segment(shmid, true); if (shmseg == NULL) return (EINVAL); error = ipcperm(td, &shmseg->u.shm_perm, (shmflg & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W); if (error != 0) return (error); #ifdef MAC error = mac_sysvshm_check_shmat(td->td_ucred, shmseg, shmflg); if (error != 0) return (error); #endif for (i = 0; i < shminfo.shmseg; i++) { if (shmmap_s->shmid == -1) break; shmmap_s++; } if (i >= shminfo.shmseg) return (EMFILE); size = round_page(shmseg->u.shm_segsz); prot = VM_PROT_READ; if ((shmflg & SHM_RDONLY) == 0) prot |= VM_PROT_WRITE; if (shmaddr != NULL) { if ((shmflg & SHM_RND) != 0) attach_va = (vm_offset_t)shmaddr & ~(SHMLBA-1); else if (((vm_offset_t)shmaddr & (SHMLBA-1)) == 0) attach_va = (vm_offset_t)shmaddr; else return (EINVAL); } else { /* * This is just a hint to vm_map_find() about where to * put it. */ attach_va = round_page((vm_offset_t)p->p_vmspace->vm_daddr + lim_max(td, RLIMIT_DATA)); } vm_object_reference(shmseg->object); rv = vm_map_find(&p->p_vmspace->vm_map, shmseg->object, 0, &attach_va, size, 0, shmaddr != NULL ? VMFS_NO_SPACE : VMFS_OPTIMAL_SPACE, prot, prot, MAP_INHERIT_SHARE | MAP_PREFAULT_PARTIAL); if (rv != KERN_SUCCESS) { vm_object_deallocate(shmseg->object); return (ENOMEM); } shmmap_s->va = attach_va; shmmap_s->shmid = shmid; shmseg->u.shm_lpid = p->p_pid; shmseg->u.shm_atime = time_second; shmseg->u.shm_nattch++; td->td_retval[0] = attach_va; return (error); } int kern_shmat(struct thread *td, int shmid, const void *shmaddr, int shmflg) { int error; SYSVSHM_LOCK(); error = kern_shmat_locked(td, shmid, shmaddr, shmflg); SYSVSHM_UNLOCK(); return (error); } #ifndef _SYS_SYSPROTO_H_ struct shmat_args { int shmid; const void *shmaddr; int shmflg; }; #endif int sys_shmat(struct thread *td, struct shmat_args *uap) { return (kern_shmat(td, uap->shmid, uap->shmaddr, uap->shmflg)); } static int kern_shmctl_locked(struct thread *td, int shmid, int cmd, void *buf, size_t *bufsz) { struct shmid_kernel *shmseg; struct shmid_ds *shmidp; struct shm_info shm_info; int error; SYSVSHM_ASSERT_LOCKED(); if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) return (ENOSYS); switch (cmd) { /* * It is possible that kern_shmctl is being called from the Linux ABI * layer, in which case, we will need to implement IPC_INFO. It should * be noted that other shmctl calls will be funneled through here for * Linix binaries as well. * * NB: The Linux ABI layer will convert this data to structure(s) more * consistent with the Linux ABI. */ case IPC_INFO: memcpy(buf, &shminfo, sizeof(shminfo)); if (bufsz) *bufsz = sizeof(shminfo); td->td_retval[0] = shmalloced; return (0); case SHM_INFO: { shm_info.used_ids = shm_nused; shm_info.shm_rss = 0; /*XXX where to get from ? */ shm_info.shm_tot = 0; /*XXX where to get from ? */ shm_info.shm_swp = 0; /*XXX where to get from ? */ shm_info.swap_attempts = 0; /*XXX where to get from ? */ shm_info.swap_successes = 0; /*XXX where to get from ? */ memcpy(buf, &shm_info, sizeof(shm_info)); if (bufsz != NULL) *bufsz = sizeof(shm_info); td->td_retval[0] = shmalloced; return (0); } } shmseg = shm_find_segment(shmid, cmd != SHM_STAT); if (shmseg == NULL) return (EINVAL); #ifdef MAC error = mac_sysvshm_check_shmctl(td->td_ucred, shmseg, cmd); if (error != 0) return (error); #endif switch (cmd) { case SHM_STAT: case IPC_STAT: error = ipcperm(td, &shmseg->u.shm_perm, IPC_R); if (error != 0) return (error); memcpy(buf, &shmseg->u, sizeof(struct shmid_ds)); if (bufsz != NULL) *bufsz = sizeof(struct shmid_ds); if (cmd == SHM_STAT) { td->td_retval[0] = IXSEQ_TO_IPCID(shmid, shmseg->u.shm_perm); } break; case IPC_SET: shmidp = (struct shmid_ds *)buf; error = ipcperm(td, &shmseg->u.shm_perm, IPC_M); if (error != 0) return (error); shmseg->u.shm_perm.uid = shmidp->shm_perm.uid; shmseg->u.shm_perm.gid = shmidp->shm_perm.gid; shmseg->u.shm_perm.mode = (shmseg->u.shm_perm.mode & ~ACCESSPERMS) | (shmidp->shm_perm.mode & ACCESSPERMS); shmseg->u.shm_ctime = time_second; break; case IPC_RMID: error = ipcperm(td, &shmseg->u.shm_perm, IPC_M); if (error != 0) return (error); shmseg->u.shm_perm.key = IPC_PRIVATE; shmseg->u.shm_perm.mode |= SHMSEG_REMOVED; if (shmseg->u.shm_nattch <= 0) { shm_deallocate_segment(shmseg); shm_last_free = IPCID_TO_IX(shmid); } break; #if 0 case SHM_LOCK: case SHM_UNLOCK: #endif default: error = EINVAL; break; } return (error); } int kern_shmctl(struct thread *td, int shmid, int cmd, void *buf, size_t *bufsz) { int error; SYSVSHM_LOCK(); error = kern_shmctl_locked(td, shmid, cmd, buf, bufsz); SYSVSHM_UNLOCK(); return (error); } #ifndef _SYS_SYSPROTO_H_ struct shmctl_args { int shmid; int cmd; struct shmid_ds *buf; }; #endif int sys_shmctl(struct thread *td, struct shmctl_args *uap) { int error; struct shmid_ds buf; size_t bufsz; /* * The only reason IPC_INFO, SHM_INFO, SHM_STAT exists is to support * Linux binaries. If we see the call come through the FreeBSD ABI, * return an error back to the user since we do not to support this. */ if (uap->cmd == IPC_INFO || uap->cmd == SHM_INFO || uap->cmd == SHM_STAT) return (EINVAL); /* IPC_SET needs to copyin the buffer before calling kern_shmctl */ if (uap->cmd == IPC_SET) { if ((error = copyin(uap->buf, &buf, sizeof(struct shmid_ds)))) goto done; } error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&buf, &bufsz); if (error) goto done; /* Cases in which we need to copyout */ switch (uap->cmd) { case IPC_STAT: error = copyout(&buf, uap->buf, bufsz); break; } done: if (error) { /* Invalidate the return value */ td->td_retval[0] = -1; } return (error); } static int shmget_existing(struct thread *td, struct shmget_args *uap, int mode, int segnum) { struct shmid_kernel *shmseg; #ifdef MAC int error; #endif SYSVSHM_ASSERT_LOCKED(); KASSERT(segnum >= 0 && segnum < shmalloced, ("segnum %d shmalloced %d", segnum, shmalloced)); shmseg = &shmsegs[segnum]; if ((uap->shmflg & (IPC_CREAT | IPC_EXCL)) == (IPC_CREAT | IPC_EXCL)) return (EEXIST); #ifdef MAC error = mac_sysvshm_check_shmget(td->td_ucred, shmseg, uap->shmflg); if (error != 0) return (error); #endif if (uap->size != 0 && uap->size > shmseg->u.shm_segsz) return (EINVAL); td->td_retval[0] = IXSEQ_TO_IPCID(segnum, shmseg->u.shm_perm); return (0); } static int shmget_allocate_segment(struct thread *td, struct shmget_args *uap, int mode) { struct ucred *cred = td->td_ucred; struct shmid_kernel *shmseg; vm_object_t shm_object; int i, segnum; size_t size; SYSVSHM_ASSERT_LOCKED(); if (uap->size < shminfo.shmmin || uap->size > shminfo.shmmax) return (EINVAL); if (shm_nused >= shminfo.shmmni) /* Any shmids left? */ return (ENOSPC); size = round_page(uap->size); if (shm_committed + btoc(size) > shminfo.shmall) return (ENOMEM); if (shm_last_free < 0) { shmrealloc(); /* Maybe expand the shmsegs[] array. */ for (i = 0; i < shmalloced; i++) if (shmsegs[i].u.shm_perm.mode & SHMSEG_FREE) break; if (i == shmalloced) return (ENOSPC); segnum = i; } else { segnum = shm_last_free; shm_last_free = -1; } KASSERT(segnum >= 0 && segnum < shmalloced, ("segnum %d shmalloced %d", segnum, shmalloced)); shmseg = &shmsegs[segnum]; #ifdef RACCT if (racct_enable) { PROC_LOCK(td->td_proc); if (racct_add(td->td_proc, RACCT_NSHM, 1)) { PROC_UNLOCK(td->td_proc); return (ENOSPC); } if (racct_add(td->td_proc, RACCT_SHMSIZE, size)) { racct_sub(td->td_proc, RACCT_NSHM, 1); PROC_UNLOCK(td->td_proc); return (ENOMEM); } PROC_UNLOCK(td->td_proc); } #endif /* * We make sure that we have allocated a pager before we need * to. */ shm_object = vm_pager_allocate(shm_use_phys ? OBJT_PHYS : OBJT_SWAP, 0, size, VM_PROT_DEFAULT, 0, cred); if (shm_object == NULL) { #ifdef RACCT if (racct_enable) { PROC_LOCK(td->td_proc); racct_sub(td->td_proc, RACCT_NSHM, 1); racct_sub(td->td_proc, RACCT_SHMSIZE, size); PROC_UNLOCK(td->td_proc); } #endif return (ENOMEM); } shm_object->pg_color = 0; VM_OBJECT_WLOCK(shm_object); vm_object_clear_flag(shm_object, OBJ_ONEMAPPING); vm_object_set_flag(shm_object, OBJ_COLORED | OBJ_NOSPLIT); VM_OBJECT_WUNLOCK(shm_object); shmseg->object = shm_object; shmseg->u.shm_perm.cuid = shmseg->u.shm_perm.uid = cred->cr_uid; shmseg->u.shm_perm.cgid = shmseg->u.shm_perm.gid = cred->cr_gid; shmseg->u.shm_perm.mode = (mode & ACCESSPERMS) | SHMSEG_ALLOCATED; shmseg->u.shm_perm.key = uap->key; shmseg->u.shm_perm.seq = (shmseg->u.shm_perm.seq + 1) & 0x7fff; shmseg->cred = crhold(cred); shmseg->u.shm_segsz = uap->size; shmseg->u.shm_cpid = td->td_proc->p_pid; shmseg->u.shm_lpid = shmseg->u.shm_nattch = 0; shmseg->u.shm_atime = shmseg->u.shm_dtime = 0; #ifdef MAC mac_sysvshm_create(cred, shmseg); #endif shmseg->u.shm_ctime = time_second; shm_committed += btoc(size); shm_nused++; td->td_retval[0] = IXSEQ_TO_IPCID(segnum, shmseg->u.shm_perm); return (0); } #ifndef _SYS_SYSPROTO_H_ struct shmget_args { key_t key; size_t size; int shmflg; }; #endif int sys_shmget(struct thread *td, struct shmget_args *uap) { int segnum, mode; int error; if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) return (ENOSYS); mode = uap->shmflg & ACCESSPERMS; SYSVSHM_LOCK(); if (uap->key == IPC_PRIVATE) { error = shmget_allocate_segment(td, uap, mode); } else { segnum = shm_find_segment_by_key(uap->key); if (segnum >= 0) error = shmget_existing(td, uap, mode, segnum); else if ((uap->shmflg & IPC_CREAT) == 0) error = ENOENT; else error = shmget_allocate_segment(td, uap, mode); } SYSVSHM_UNLOCK(); return (error); } static void shmfork_myhook(struct proc *p1, struct proc *p2) { struct shmmap_state *shmmap_s; size_t size; int i; SYSVSHM_LOCK(); size = shminfo.shmseg * sizeof(struct shmmap_state); shmmap_s = malloc(size, M_SHM, M_WAITOK); bcopy(p1->p_vmspace->vm_shm, shmmap_s, size); p2->p_vmspace->vm_shm = shmmap_s; for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) { if (shmmap_s->shmid != -1) { KASSERT(IPCID_TO_IX(shmmap_s->shmid) >= 0 && IPCID_TO_IX(shmmap_s->shmid) < shmalloced, ("segnum %d shmalloced %d", IPCID_TO_IX(shmmap_s->shmid), shmalloced)); shmsegs[IPCID_TO_IX(shmmap_s->shmid)].u.shm_nattch++; } } SYSVSHM_UNLOCK(); } static void shmexit_myhook(struct vmspace *vm) { struct shmmap_state *base, *shm; int i; base = vm->vm_shm; if (base != NULL) { vm->vm_shm = NULL; SYSVSHM_LOCK(); for (i = 0, shm = base; i < shminfo.shmseg; i++, shm++) { if (shm->shmid != -1) shm_delete_mapping(vm, shm); } SYSVSHM_UNLOCK(); free(base, M_SHM); } } static void shmrealloc(void) { struct shmid_kernel *newsegs; int i; SYSVSHM_ASSERT_LOCKED(); if (shmalloced >= shminfo.shmmni) return; newsegs = malloc(shminfo.shmmni * sizeof(*newsegs), M_SHM, M_WAITOK); for (i = 0; i < shmalloced; i++) bcopy(&shmsegs[i], &newsegs[i], sizeof(newsegs[0])); for (; i < shminfo.shmmni; i++) { newsegs[i].u.shm_perm.mode = SHMSEG_FREE; newsegs[i].u.shm_perm.seq = 0; #ifdef MAC mac_sysvshm_init(&newsegs[i]); #endif } free(shmsegs, M_SHM); shmsegs = newsegs; shmalloced = shminfo.shmmni; } static struct syscall_helper_data shm_syscalls[] = { SYSCALL_INIT_HELPER(shmat), SYSCALL_INIT_HELPER(shmctl), SYSCALL_INIT_HELPER(shmdt), SYSCALL_INIT_HELPER(shmget), #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) SYSCALL_INIT_HELPER_COMPAT(freebsd7_shmctl), #endif #if defined(__i386__) && (defined(COMPAT_FREEBSD4) || defined(COMPAT_43)) SYSCALL_INIT_HELPER(shmsys), #endif SYSCALL_INIT_LAST }; #ifdef COMPAT_FREEBSD32 #include #include #include #include #include #include static struct syscall_helper_data shm32_syscalls[] = { SYSCALL32_INIT_HELPER_COMPAT(shmat), SYSCALL32_INIT_HELPER_COMPAT(shmdt), SYSCALL32_INIT_HELPER_COMPAT(shmget), SYSCALL32_INIT_HELPER(freebsd32_shmsys), SYSCALL32_INIT_HELPER(freebsd32_shmctl), #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) SYSCALL32_INIT_HELPER(freebsd7_freebsd32_shmctl), #endif SYSCALL_INIT_LAST }; #endif static int shminit(void) { int i, error; #ifndef BURN_BRIDGES if (TUNABLE_ULONG_FETCH("kern.ipc.shmmaxpgs", &shminfo.shmall) != 0) printf("kern.ipc.shmmaxpgs is now called kern.ipc.shmall!\n"); #endif if (shminfo.shmmax == SHMMAX) { /* Initialize shmmax dealing with possible overflow. */ for (i = PAGE_SIZE; i != 0; i--) { shminfo.shmmax = shminfo.shmall * i; if ((shminfo.shmmax / shminfo.shmall) == (u_long)i) break; } } shmalloced = shminfo.shmmni; shmsegs = malloc(shmalloced * sizeof(shmsegs[0]), M_SHM, M_WAITOK); for (i = 0; i < shmalloced; i++) { shmsegs[i].u.shm_perm.mode = SHMSEG_FREE; shmsegs[i].u.shm_perm.seq = 0; #ifdef MAC mac_sysvshm_init(&shmsegs[i]); #endif } shm_last_free = 0; shm_nused = 0; shm_committed = 0; sx_init(&sysvshmsx, "sysvshmsx"); shmexit_hook = &shmexit_myhook; shmfork_hook = &shmfork_myhook; error = syscall_helper_register(shm_syscalls, SY_THR_STATIC_KLD); if (error != 0) return (error); #ifdef COMPAT_FREEBSD32 error = syscall32_helper_register(shm32_syscalls, SY_THR_STATIC_KLD); if (error != 0) return (error); #endif return (0); } static int shmunload(void) { int i; if (shm_nused > 0) return (EBUSY); #ifdef COMPAT_FREEBSD32 syscall32_helper_unregister(shm32_syscalls); #endif syscall_helper_unregister(shm_syscalls); for (i = 0; i < shmalloced; i++) { #ifdef MAC mac_sysvshm_destroy(&shmsegs[i]); #endif /* * Objects might be still mapped into the processes * address spaces. Actual free would happen on the * last mapping destruction. */ if (shmsegs[i].u.shm_perm.mode != SHMSEG_FREE) vm_object_deallocate(shmsegs[i].object); } free(shmsegs, M_SHM); shmexit_hook = NULL; shmfork_hook = NULL; sx_destroy(&sysvshmsx); return (0); } static int sysctl_shmsegs(SYSCTL_HANDLER_ARGS) { int error; SYSVSHM_LOCK(); error = SYSCTL_OUT(req, shmsegs, shmalloced * sizeof(shmsegs[0])); SYSVSHM_UNLOCK(); return (error); } #if defined(__i386__) && (defined(COMPAT_FREEBSD4) || defined(COMPAT_43)) struct oshmid_ds { struct ipc_perm_old shm_perm; /* operation perms */ int shm_segsz; /* size of segment (bytes) */ u_short shm_cpid; /* pid, creator */ u_short shm_lpid; /* pid, last operation */ short shm_nattch; /* no. of current attaches */ time_t shm_atime; /* last attach time */ time_t shm_dtime; /* last detach time */ time_t shm_ctime; /* last change time */ void *shm_handle; /* internal handle for shm segment */ }; struct oshmctl_args { int shmid; int cmd; struct oshmid_ds *ubuf; }; static int oshmctl(struct thread *td, struct oshmctl_args *uap) { #ifdef COMPAT_43 int error = 0; struct shmid_kernel *shmseg; struct oshmid_ds outbuf; if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) return (ENOSYS); if (uap->cmd != IPC_STAT) { return (freebsd7_shmctl(td, (struct freebsd7_shmctl_args *)uap)); } SYSVSHM_LOCK(); shmseg = shm_find_segment(uap->shmid, true); if (shmseg == NULL) { SYSVSHM_UNLOCK(); return (EINVAL); } error = ipcperm(td, &shmseg->u.shm_perm, IPC_R); if (error != 0) { SYSVSHM_UNLOCK(); return (error); } #ifdef MAC error = mac_sysvshm_check_shmctl(td->td_ucred, shmseg, uap->cmd); if (error != 0) { SYSVSHM_UNLOCK(); return (error); } #endif ipcperm_new2old(&shmseg->u.shm_perm, &outbuf.shm_perm); outbuf.shm_segsz = shmseg->u.shm_segsz; outbuf.shm_cpid = shmseg->u.shm_cpid; outbuf.shm_lpid = shmseg->u.shm_lpid; outbuf.shm_nattch = shmseg->u.shm_nattch; outbuf.shm_atime = shmseg->u.shm_atime; outbuf.shm_dtime = shmseg->u.shm_dtime; outbuf.shm_ctime = shmseg->u.shm_ctime; outbuf.shm_handle = shmseg->object; SYSVSHM_UNLOCK(); return (copyout(&outbuf, uap->ubuf, sizeof(outbuf))); #else return (EINVAL); #endif } /* XXX casting to (sy_call_t *) is bogus, as usual. */ static sy_call_t *shmcalls[] = { (sy_call_t *)sys_shmat, (sy_call_t *)oshmctl, (sy_call_t *)sys_shmdt, (sy_call_t *)sys_shmget, (sy_call_t *)freebsd7_shmctl }; #ifndef _SYS_SYSPROTO_H_ /* XXX actually varargs. */ struct shmsys_args { int which; int a2; int a3; int a4; }; #endif int sys_shmsys(struct thread *td, struct shmsys_args *uap) { if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) return (ENOSYS); if (uap->which < 0 || uap->which >= nitems(shmcalls)) return (EINVAL); return ((*shmcalls[uap->which])(td, &uap->a2)); } #endif /* i386 && (COMPAT_FREEBSD4 || COMPAT_43) */ #ifdef COMPAT_FREEBSD32 int freebsd32_shmsys(struct thread *td, struct freebsd32_shmsys_args *uap) { #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) switch (uap->which) { case 0: { /* shmat */ struct shmat_args ap; ap.shmid = uap->a2; ap.shmaddr = PTRIN(uap->a3); ap.shmflg = uap->a4; return (sysent[SYS_shmat].sy_call(td, &ap)); } case 2: { /* shmdt */ struct shmdt_args ap; ap.shmaddr = PTRIN(uap->a2); return (sysent[SYS_shmdt].sy_call(td, &ap)); } case 3: { /* shmget */ struct shmget_args ap; ap.key = uap->a2; ap.size = uap->a3; ap.shmflg = uap->a4; return (sysent[SYS_shmget].sy_call(td, &ap)); } case 4: { /* shmctl */ struct freebsd7_freebsd32_shmctl_args ap; ap.shmid = uap->a2; ap.cmd = uap->a3; ap.buf = PTRIN(uap->a4); return (freebsd7_freebsd32_shmctl(td, &ap)); } case 1: /* oshmctl */ default: return (EINVAL); } #else return (nosys(td, NULL)); #endif } #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) int freebsd7_freebsd32_shmctl(struct thread *td, struct freebsd7_freebsd32_shmctl_args *uap) { int error; union { struct shmid_ds shmid_ds; struct shm_info shm_info; struct shminfo shminfo; } u; union { struct shmid_ds32_old shmid_ds32; struct shm_info32 shm_info32; struct shminfo32 shminfo32; } u32; size_t sz; if (uap->cmd == IPC_SET) { if ((error = copyin(uap->buf, &u32.shmid_ds32, sizeof(u32.shmid_ds32)))) goto done; freebsd32_ipcperm_old_in(&u32.shmid_ds32.shm_perm, &u.shmid_ds.shm_perm); CP(u32.shmid_ds32, u.shmid_ds, shm_segsz); CP(u32.shmid_ds32, u.shmid_ds, shm_lpid); CP(u32.shmid_ds32, u.shmid_ds, shm_cpid); CP(u32.shmid_ds32, u.shmid_ds, shm_nattch); CP(u32.shmid_ds32, u.shmid_ds, shm_atime); CP(u32.shmid_ds32, u.shmid_ds, shm_dtime); CP(u32.shmid_ds32, u.shmid_ds, shm_ctime); } error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&u, &sz); if (error) goto done; /* Cases in which we need to copyout */ switch (uap->cmd) { case IPC_INFO: CP(u.shminfo, u32.shminfo32, shmmax); CP(u.shminfo, u32.shminfo32, shmmin); CP(u.shminfo, u32.shminfo32, shmmni); CP(u.shminfo, u32.shminfo32, shmseg); CP(u.shminfo, u32.shminfo32, shmall); error = copyout(&u32.shminfo32, uap->buf, sizeof(u32.shminfo32)); break; case SHM_INFO: CP(u.shm_info, u32.shm_info32, used_ids); CP(u.shm_info, u32.shm_info32, shm_rss); CP(u.shm_info, u32.shm_info32, shm_tot); CP(u.shm_info, u32.shm_info32, shm_swp); CP(u.shm_info, u32.shm_info32, swap_attempts); CP(u.shm_info, u32.shm_info32, swap_successes); error = copyout(&u32.shm_info32, uap->buf, sizeof(u32.shm_info32)); break; case SHM_STAT: case IPC_STAT: freebsd32_ipcperm_old_out(&u.shmid_ds.shm_perm, &u32.shmid_ds32.shm_perm); if (u.shmid_ds.shm_segsz > INT32_MAX) u32.shmid_ds32.shm_segsz = INT32_MAX; else CP(u.shmid_ds, u32.shmid_ds32, shm_segsz); CP(u.shmid_ds, u32.shmid_ds32, shm_lpid); CP(u.shmid_ds, u32.shmid_ds32, shm_cpid); CP(u.shmid_ds, u32.shmid_ds32, shm_nattch); CP(u.shmid_ds, u32.shmid_ds32, shm_atime); CP(u.shmid_ds, u32.shmid_ds32, shm_dtime); CP(u.shmid_ds, u32.shmid_ds32, shm_ctime); u32.shmid_ds32.shm_internal = 0; error = copyout(&u32.shmid_ds32, uap->buf, sizeof(u32.shmid_ds32)); break; } done: if (error) { /* Invalidate the return value */ td->td_retval[0] = -1; } return (error); } #endif int freebsd32_shmctl(struct thread *td, struct freebsd32_shmctl_args *uap) { int error; union { struct shmid_ds shmid_ds; struct shm_info shm_info; struct shminfo shminfo; } u; union { struct shmid_ds32 shmid_ds32; struct shm_info32 shm_info32; struct shminfo32 shminfo32; } u32; size_t sz; if (uap->cmd == IPC_SET) { if ((error = copyin(uap->buf, &u32.shmid_ds32, sizeof(u32.shmid_ds32)))) goto done; freebsd32_ipcperm_in(&u32.shmid_ds32.shm_perm, &u.shmid_ds.shm_perm); CP(u32.shmid_ds32, u.shmid_ds, shm_segsz); CP(u32.shmid_ds32, u.shmid_ds, shm_lpid); CP(u32.shmid_ds32, u.shmid_ds, shm_cpid); CP(u32.shmid_ds32, u.shmid_ds, shm_nattch); CP(u32.shmid_ds32, u.shmid_ds, shm_atime); CP(u32.shmid_ds32, u.shmid_ds, shm_dtime); CP(u32.shmid_ds32, u.shmid_ds, shm_ctime); } error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&u, &sz); if (error) goto done; /* Cases in which we need to copyout */ switch (uap->cmd) { case IPC_INFO: CP(u.shminfo, u32.shminfo32, shmmax); CP(u.shminfo, u32.shminfo32, shmmin); CP(u.shminfo, u32.shminfo32, shmmni); CP(u.shminfo, u32.shminfo32, shmseg); CP(u.shminfo, u32.shminfo32, shmall); error = copyout(&u32.shminfo32, uap->buf, sizeof(u32.shminfo32)); break; case SHM_INFO: CP(u.shm_info, u32.shm_info32, used_ids); CP(u.shm_info, u32.shm_info32, shm_rss); CP(u.shm_info, u32.shm_info32, shm_tot); CP(u.shm_info, u32.shm_info32, shm_swp); CP(u.shm_info, u32.shm_info32, swap_attempts); CP(u.shm_info, u32.shm_info32, swap_successes); error = copyout(&u32.shm_info32, uap->buf, sizeof(u32.shm_info32)); break; case SHM_STAT: case IPC_STAT: freebsd32_ipcperm_out(&u.shmid_ds.shm_perm, &u32.shmid_ds32.shm_perm); if (u.shmid_ds.shm_segsz > INT32_MAX) u32.shmid_ds32.shm_segsz = INT32_MAX; else CP(u.shmid_ds, u32.shmid_ds32, shm_segsz); CP(u.shmid_ds, u32.shmid_ds32, shm_lpid); CP(u.shmid_ds, u32.shmid_ds32, shm_cpid); CP(u.shmid_ds, u32.shmid_ds32, shm_nattch); CP(u.shmid_ds, u32.shmid_ds32, shm_atime); CP(u.shmid_ds, u32.shmid_ds32, shm_dtime); CP(u.shmid_ds, u32.shmid_ds32, shm_ctime); error = copyout(&u32.shmid_ds32, uap->buf, sizeof(u32.shmid_ds32)); break; } done: if (error) { /* Invalidate the return value */ td->td_retval[0] = -1; } return (error); } #endif #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) #ifndef CP #define CP(src, dst, fld) do { (dst).fld = (src).fld; } while (0) #endif #ifndef _SYS_SYSPROTO_H_ struct freebsd7_shmctl_args { int shmid; int cmd; struct shmid_ds_old *buf; }; #endif int freebsd7_shmctl(struct thread *td, struct freebsd7_shmctl_args *uap) { int error; struct shmid_ds_old old; struct shmid_ds buf; size_t bufsz; /* * The only reason IPC_INFO, SHM_INFO, SHM_STAT exists is to support * Linux binaries. If we see the call come through the FreeBSD ABI, * return an error back to the user since we do not to support this. */ if (uap->cmd == IPC_INFO || uap->cmd == SHM_INFO || uap->cmd == SHM_STAT) return (EINVAL); /* IPC_SET needs to copyin the buffer before calling kern_shmctl */ if (uap->cmd == IPC_SET) { if ((error = copyin(uap->buf, &old, sizeof(old)))) goto done; ipcperm_old2new(&old.shm_perm, &buf.shm_perm); CP(old, buf, shm_segsz); CP(old, buf, shm_lpid); CP(old, buf, shm_cpid); CP(old, buf, shm_nattch); CP(old, buf, shm_atime); CP(old, buf, shm_dtime); CP(old, buf, shm_ctime); } error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&buf, &bufsz); if (error) goto done; /* Cases in which we need to copyout */ switch (uap->cmd) { case IPC_STAT: ipcperm_new2old(&buf.shm_perm, &old.shm_perm); if (buf.shm_segsz > INT_MAX) old.shm_segsz = INT_MAX; else CP(buf, old, shm_segsz); CP(buf, old, shm_lpid); CP(buf, old, shm_cpid); if (buf.shm_nattch > SHRT_MAX) old.shm_nattch = SHRT_MAX; else CP(buf, old, shm_nattch); CP(buf, old, shm_atime); CP(buf, old, shm_dtime); CP(buf, old, shm_ctime); old.shm_internal = NULL; error = copyout(&old, uap->buf, sizeof(old)); break; } done: if (error) { /* Invalidate the return value */ td->td_retval[0] = -1; } return (error); } #endif /* COMPAT_FREEBSD4 || COMPAT_FREEBSD5 || COMPAT_FREEBSD6 || COMPAT_FREEBSD7 */ static int sysvshm_modload(struct module *module, int cmd, void *arg) { int error = 0; switch (cmd) { case MOD_LOAD: error = shminit(); if (error != 0) shmunload(); break; case MOD_UNLOAD: error = shmunload(); break; case MOD_SHUTDOWN: break; default: error = EINVAL; break; } return (error); } static moduledata_t sysvshm_mod = { "sysvshm", &sysvshm_modload, NULL }; DECLARE_MODULE(sysvshm, sysvshm_mod, SI_SUB_SYSV_SHM, SI_ORDER_FIRST); MODULE_VERSION(sysvshm, 1); Index: projects/release-pkg/sys/mips/conf/AP135.hints =================================================================== --- projects/release-pkg/sys/mips/conf/AP135.hints (revision 289118) +++ projects/release-pkg/sys/mips/conf/AP135.hints (revision 289119) @@ -1,178 +1,189 @@ # This is a placeholder until the hardware support is complete. # I'm assuming this is an AP135-020. The AP136-010 in openwrt has # the ethernet ports wired up to the switch in the reverse way. # $FreeBSD$ # QCA955X_ETH_CFG_RGMII_EN (1 << 0) hint.qca955x_gmac.0.gmac_cfg=0x1 # mdiobus0 on arge0 hint.argemdio.0.at="nexus0" hint.argemdio.0.maddr=0x19000000 hint.argemdio.0.msize=0x1000 hint.argemdio.0.order=0 # mdiobus1 on arge1 - required to bring up arge1? hint.argemdio.1.at="nexus0" hint.argemdio.1.maddr=0x1a000000 hint.argemdio.1.msize=0x1000 hint.argemdio.1.order=0 # AR8327 - connected via mdiobus0 on arge0 hint.arswitch.0.at="mdio0" hint.arswitch.0.is_7240=0 # definitely not the internal switch! hint.arswitch.0.is_9340=0 # not the internal switch! hint.arswitch.0.numphys=5 # all ports are PHYs hint.arswitch.0.phy4cpu=0 hint.arswitch.0.is_rgmii=0 # not needed hint.arswitch.0.is_gmii=0 # not needed # This is where it gets a bit odd. port 0 and port 6 are CPU ports. # The current code only supports one CPU port. So hm, what should # we do to hook PAD6 up to be RGMII but a PHY, not a MAC? # The other trick - how do we get arge1 (hooked up to GMAC0) to work? # That's currently supposed to be hooked up to CPU port 0. # Other AR8327 configuration parameters # AP136-020 parameters # GMAC0 AR8327 -> GMAC1 (arge1) SoC, SGMII # AR8327_PAD_MAC_SGMII hint.arswitch.0.pad.0.mode=3 #hint.arswitch.0.pad.0.rxclk_delay_sel=0 hint.arswitch.0.pad.0.sgmii_delay_en=1 # GMAC6 AR8327 -> GMAC0 (arge0) SoC, RGMII # AR8327_PAD_MAC_RGMII # XXX I think this hooks it up to the internal MAC6 hint.arswitch.0.pad.6.mode=6 hint.arswitch.0.pad.6.txclk_delay_en=1 hint.arswitch.0.pad.6.rxclk_delay_en=1 # AR8327_CLK_DELAY_SEL1 hint.arswitch.0.pad.6.txclk_delay_sel=1 # AR8327_CLK_DELAY_SEL2 hint.arswitch.0.pad.6.rxclk_delay_sel=2 # XXX there's no LED management just yet! hint.arswitch.0.led.ctrl0=0x00000000 hint.arswitch.0.led.ctrl1=0xc737c737 hint.arswitch.0.led.ctrl2=0x00000000 hint.arswitch.0.led.ctrl3=0x00c30c00 hint.arswitch.0.led.open_drain=1 # force_link=1 is required for the rest of the parameters # to be configured. hint.arswitch.0.port.0.force_link=1 hint.arswitch.0.port.0.speed=1000 hint.arswitch.0.port.0.duplex=1 hint.arswitch.0.port.0.txpause=1 hint.arswitch.0.port.0.rxpause=1 # force_link=1 is required for the rest of the parameters # to be configured. hint.arswitch.0.port.6.force_link=1 hint.arswitch.0.port.6.speed=1000 hint.arswitch.0.port.6.duplex=1 hint.arswitch.0.port.6.txpause=1 hint.arswitch.0.port.6.rxpause=1 # arge0 - hooked up to AR8327 GMAC6, RGMII # set at 1000/full to the switch. # so, lock both sides of this connect up to 1000/full; # if_arge thus wont change the PLL configuration # upon a link status change. hint.arge.0.phymask=0x0 hint.arge.0.miimode=3 # RGMII hint.arge.0.media=1000 hint.arge.0.fduplex=1 hint.arge.0.pll_1000=0x56000000 # MAC for arge0 is the first 6 bytes of the ART hint.arge.0.eeprommac=0x1fff0000 # arge1 - lock up to 1000/full hint.arge.1.phymask=0x0 hint.arge.1.media=1000 hint.arge.1.fduplex=1 hint.arge.1.miimode=5 # SGMII hint.arge.1.pll_1000=0x03000101 # MAC for arge1 is the second 6 bytes of the ART hint.arge.1.eeprommac=0x1fff0006 # ath0: Where the ART is - last 64k in the flash hint.ath.0.eepromaddr=0x1fff0000 hint.ath.0.eepromsize=16384 # ath1: it's different; it's a PCIe attached device, so # we instead need to teach the PCIe bridge code about it # (ie, the 'early pci fixup' stuff that programs the PCIe # host registers on the NIC) and then we teach ath where # to find it. # ath1 hint - pcie slot 0 # hint.pcib.0.bus.0.0.0.ath_fixup_addr=0x1fff4000 # hint.pcib.0.bus.0.0.0.ath_fixup_size=16384 # ath0 - eeprom comes from here # hint.ath.1.eeprom_firmware="pcib.0.bus.0.0.0.eeprom_firmware" # flash layout: # # bootargs=console=ttyS0,115200 root=31:02 rootfstype=jffs2 init=/sbin/init mtdparts=ath-nor0:256k(u-boot),64k(u-boot-env),6336k(rootfs),1408k(uImage),8256k(mib0),64k(ART) +# The default flash layout isn't enough to fit a freebsd kernel +# now, so the layout has been shuffled around. +# +# By default it's set to: +# 256KB uboot, 64KB uboot-env, 6336KB rootfs, 1344KB kernel, 64KB cfg, 8256MB mib0, 64KB ART +# With 'bootcmd=bootm 0x9f680000' in the environment. +# +# Instead, now let's make it: +# 256KB uboot, 64KB uboot-env, 2048MB kernel, 6144MB rootfs, 7644KB mib0, 64KB cfg, 64KB ART +# .. and then you change the boot env to be: +# 'bootcmd=bootm 0x9f050000' # 256KiB u-boot hint.map.0.at="flash/spi0" hint.map.0.start=0x00000000 hint.map.0.end=0x00040000 # 256k u-boot hint.map.0.name="u-boot" hint.map.0.readonly=1 # 64KiB u-boot-env hint.map.1.at="flash/spi0" hint.map.1.start=0x00040000 hint.map.1.end=0x00050000 # 64k u-boot-env hint.map.1.name="u-boot-env" hint.map.1.readonly=1 -# 6336KiB rootfs +# 2048KiB kernel hint.map.2.at="flash/spi0" hint.map.2.start=0x00050000 -hint.map.2.end=0x00680000 # 6336k rootfs -hint.map.2.name="rootfs" +hint.map.2.end=0x00250000 # 2048k rootfs +hint.map.2.name="kernel" hint.map.2.readonly=1 -# 1344KiB uImage +# 6144KiB rootfs hint.map.3.at="flash/spi0" -hint.map.3.start=0x00680000 -hint.map.3.end=0x007d0000 # 1408k uImage, 64k off the end.. -hint.map.3.name="uImage" +hint.map.3.start=0x00250000 +hint.map.3.end=0x00850000 +hint.map.3.name="rootfs" hint.map.3.readonly=1 -# 64KiB cfg +# 7644KiB mib0 hint.map.4.at="flash/spi0" -hint.map.4.start=0x007d0000 -hint.map.4.end=0x007e0000 -hint.map.4.name="cfg" +hint.map.4.start=0x00850000 +hint.map.4.end=0x00fe0000 +hint.map.4.name="mib0" hint.map.4.readonly=0 -# 8256 KiB mib0 +# 64KiB cfg hint.map.5.at="flash/spi0" -hint.map.5.start=0x007e0000 -hint.map.5.end=0x00ff0000 # 64k mib0 -hint.map.5.name="mib0" -hint.map.5.readonly=1 +hint.map.5.start=0x00fe0000 +hint.map.5.end=0x00ff0000 +hint.map.5.name="cfg" +hint.map.5.readonly=0 # 64KiB ART hint.map.6.at="flash/spi0" -hint.map.6.start=0x007f0000 +hint.map.6.start=0x00ff0000 hint.map.6.end=0x01000000 # 64k ART hint.map.6.name="ART" hint.map.6.readonly=1 Index: projects/release-pkg/sys/mips/conf/TP-MR3020 =================================================================== --- projects/release-pkg/sys/mips/conf/TP-MR3020 (revision 289118) +++ projects/release-pkg/sys/mips/conf/TP-MR3020 (revision 289119) @@ -1,65 +1,55 @@ # # TP Link MR3020 - an AR9331 based SoC wifi device. # # This is for the 32 RAM/4 flash part. There is little to no # chance that this will ever boot FreeBSD directly from the 3.5MB # of flash. The kernel can fit into the space, but userland is just # too big even when stripped down to its limits. # # * AR9331 SoC # * 32MB RAM # * 4MB flash # * Integrated 1x1 2GHz wifi and 10/100 bridge # * USB powered # * USB storage # # $FreeBSD$ # # Include the default AR933x parameters include "AR933X_BASE" ident TP-MR3020 # Override hints with board values hints "TP-MR3020.hints" # Board memory - 32MB options AR71XX_REALMEM=(32*1024*1024) # i2c GPIO bus device gpioiic device iicbb device iicbus device iic # Options required for miiproxy and mdiobus options ARGE_MDIO # Export an MDIO bus separate from arge device miiproxy # MDIO bus <-> MII PHY rendezvous device etherswitch device arswitch # Enable the uboot environment stuff rather then the # redboot stuff. options AR71XX_ENV_UBOOT # uzip - to boot natively from flash device geom_uncompress # Used for the static uboot partition map device geom_map -# Boot off of the rootfs, as defined in the geom_map setup. -# Probably, this should be a USB device as the memory available -# compressed rootfs is simply too small for FreeBSD -#options ROOTDEVNAME=\"ufs:map/rootfs.uncompress\" - -# Boot off of a uboot tftp ramdisk kernel image. Because the flash -# on this unit is so small, this is the only way to do dev work. -# For full deployment, you will *have* to use a usb storage device -# as a rootfs and use the flash to hold the kernel only. -options MD_ROOT # md device usable as a potential root device -options MD_ROOT_SIZE=10240 -#makeoptions MFS_IMAGE=/tftpboot/mfsroot-tl-mr3020.img.ulzma -options ROOTDEVNAME=\"ufs:md0.uncompress\" +# With only 4MB of flash, we are stuck using USB +# for the rootfs. +options ROOTDEVNAME=\"ufs:da0\" Index: projects/release-pkg/sys/powerpc/mpc85xx/i2c.c =================================================================== --- projects/release-pkg/sys/powerpc/mpc85xx/i2c.c (revision 289118) +++ projects/release-pkg/sys/powerpc/mpc85xx/i2c.c (revision 289119) @@ -1,427 +1,427 @@ /*- * Copyright (C) 2008-2009 Semihalf, Michal Hajduk * 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 #include #include #include #include #include #include #include #include #include #include "iicbus_if.h" #include #include #define I2C_ADDR_REG 0x00 /* I2C slave address register */ #define I2C_FDR_REG 0x04 /* I2C frequency divider register */ #define I2C_CONTROL_REG 0x08 /* I2C control register */ #define I2C_STATUS_REG 0x0C /* I2C status register */ #define I2C_DATA_REG 0x10 /* I2C data register */ #define I2C_DFSRR_REG 0x14 /* I2C Digital Filter Sampling rate */ #define I2C_ENABLE 0x80 /* Module enable - interrupt disable */ #define I2CSR_RXAK 0x01 /* Received acknowledge */ #define I2CSR_MCF (1<<7) /* Data transfer */ #define I2CSR_MASS (1<<6) /* Addressed as a slave */ #define I2CSR_MBB (1<<5) /* Bus busy */ #define I2CSR_MAL (1<<4) /* Arbitration lost */ #define I2CSR_SRW (1<<2) /* Slave read/write */ #define I2CSR_MIF (1<<1) /* Module interrupt */ #define I2CCR_MEN (1<<7) /* Module enable */ #define I2CCR_MSTA (1<<5) /* Master/slave mode */ #define I2CCR_MTX (1<<4) /* Transmit/receive mode */ #define I2CCR_TXAK (1<<3) /* Transfer acknowledge */ #define I2CCR_RSTA (1<<2) /* Repeated START */ #define I2C_BAUD_RATE_FAST 0x31 #define I2C_BAUD_RATE_DEF 0x3F #define I2C_DFSSR_DIV 0x10 #ifdef DEBUG #define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt,##args); } while (0) #else #define debugf(fmt, args...) #endif struct i2c_softc { device_t dev; device_t iicbus; struct resource *res; struct mtx mutex; int rid; bus_space_handle_t bsh; bus_space_tag_t bst; }; static int i2c_probe(device_t); static int i2c_attach(device_t); static int i2c_repeated_start(device_t dev, u_char slave, int timeout); static int i2c_start(device_t dev, u_char slave, int timeout); static int i2c_stop(device_t dev); static int i2c_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr); static int i2c_read(device_t dev, char *buf, int len, int *read, int last, int delay); static int i2c_write(device_t dev, const char *buf, int len, int *sent, int timeout); static device_method_t i2c_methods[] = { DEVMETHOD(device_probe, i2c_probe), DEVMETHOD(device_attach, i2c_attach), DEVMETHOD(iicbus_callback, iicbus_null_callback), DEVMETHOD(iicbus_repeated_start, i2c_repeated_start), DEVMETHOD(iicbus_start, i2c_start), DEVMETHOD(iicbus_stop, i2c_stop), DEVMETHOD(iicbus_reset, i2c_reset), DEVMETHOD(iicbus_read, i2c_read), DEVMETHOD(iicbus_write, i2c_write), DEVMETHOD(iicbus_transfer, iicbus_transfer_gen), { 0, 0 } }; static driver_t i2c_driver = { "i2c", i2c_methods, sizeof(struct i2c_softc), }; static devclass_t i2c_devclass; DRIVER_MODULE(i2c, simplebus, i2c_driver, i2c_devclass, 0, 0); DRIVER_MODULE(iicbus, i2c, iicbus_driver, iicbus_devclass, 0, 0); static __inline void i2c_write_reg(struct i2c_softc *sc, bus_size_t off, uint8_t val) { bus_space_write_1(sc->bst, sc->bsh, off, val); } static __inline uint8_t i2c_read_reg(struct i2c_softc *sc, bus_size_t off) { return (bus_space_read_1(sc->bst, sc->bsh, off)); } static __inline void i2c_flag_set(struct i2c_softc *sc, bus_size_t off, uint8_t mask) { uint8_t status; status = i2c_read_reg(sc, off); status |= mask; i2c_write_reg(sc, off, status); } static int i2c_do_wait(device_t dev, struct i2c_softc *sc, int write, int start) { int err; uint8_t status; status = i2c_read_reg(sc, I2C_STATUS_REG); if (status & I2CSR_MIF) { if (write && start && (status & I2CSR_RXAK)) { debugf("no ack %s", start ? "after sending slave address" : ""); err = IIC_ENOACK; goto error; } if (status & I2CSR_MAL) { debugf("arbitration lost"); err = IIC_EBUSERR; goto error; } if (!write && !(status & I2CSR_MCF)) { debugf("transfer unfinished"); err = IIC_EBUSERR; goto error; } } return (IIC_NOERR); error: i2c_write_reg(sc, I2C_STATUS_REG, 0x0); i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | I2CCR_TXAK); return (err); } static int i2c_probe(device_t dev) { struct i2c_softc *sc; if (!ofw_bus_is_compatible(dev, "fsl-i2c")) return (ENXIO); sc = device_get_softc(dev); sc->rid = 0; sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid, RF_ACTIVE); if (sc->res == NULL) { device_printf(dev, "could not allocate resources\n"); return (ENXIO); } sc->bst = rman_get_bustag(sc->res); sc->bsh = rman_get_bushandle(sc->res); /* Enable I2C */ i2c_write_reg(sc, I2C_CONTROL_REG, I2C_ENABLE); bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res); device_set_desc(dev, "I2C bus controller"); return (BUS_PROBE_DEFAULT); } static int i2c_attach(device_t dev) { struct i2c_softc *sc; sc = device_get_softc(dev); sc->dev = dev; sc->rid = 0; mtx_init(&sc->mutex, device_get_nameunit(dev), "I2C", MTX_DEF); sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid, RF_ACTIVE); if (sc->res == NULL) { device_printf(dev, "could not allocate resources"); mtx_destroy(&sc->mutex); return (ENXIO); } sc->bst = rman_get_bustag(sc->res); sc->bsh = rman_get_bushandle(sc->res); sc->iicbus = device_add_child(dev, "iicbus", -1); if (sc->iicbus == NULL) { device_printf(dev, "could not add iicbus child"); mtx_destroy(&sc->mutex); return (ENXIO); } bus_generic_attach(dev); return (IIC_NOERR); } static int i2c_repeated_start(device_t dev, u_char slave, int timeout) { struct i2c_softc *sc; int error; sc = device_get_softc(dev); mtx_lock(&sc->mutex); /* Set repeated start condition */ i2c_flag_set(sc, I2C_CONTROL_REG ,I2CCR_RSTA); /* Write target address - LSB is R/W bit */ i2c_write_reg(sc, I2C_DATA_REG, slave); DELAY(1250); error = i2c_do_wait(dev, sc, 1, 1); mtx_unlock(&sc->mutex); if (error) return (error); return (IIC_NOERR); } static int i2c_start(device_t dev, u_char slave, int timeout) { struct i2c_softc *sc; uint8_t status; int error; sc = device_get_softc(dev); DELAY(1000); mtx_lock(&sc->mutex); status = i2c_read_reg(sc, I2C_STATUS_REG); /* Check if bus is idle or busy */ if (status & I2CSR_MBB) { debugf("bus busy"); mtx_unlock(&sc->mutex); i2c_stop(dev); - return (IIC_EBUSBSY); + return (IIC_EBUSERR); } /* Set start condition */ i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | I2CCR_MSTA | I2CCR_MTX); /* Write target address - LSB is R/W bit */ i2c_write_reg(sc, I2C_DATA_REG, slave); DELAY(1250); error = i2c_do_wait(dev, sc, 1, 1); mtx_unlock(&sc->mutex); if (error) return (error); return (IIC_NOERR); } static int i2c_stop(device_t dev) { struct i2c_softc *sc; sc = device_get_softc(dev); mtx_lock(&sc->mutex); i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | I2CCR_TXAK); DELAY(1000); mtx_unlock(&sc->mutex); return (IIC_NOERR); } static int i2c_reset(device_t dev, u_char speed, u_char addr, u_char *oldadr) { struct i2c_softc *sc; uint8_t baud_rate; sc = device_get_softc(dev); switch (speed) { case IIC_FAST: baud_rate = I2C_BAUD_RATE_FAST; break; case IIC_SLOW: case IIC_UNKNOWN: case IIC_FASTEST: default: baud_rate = I2C_BAUD_RATE_DEF; break; } mtx_lock(&sc->mutex); i2c_write_reg(sc, I2C_CONTROL_REG, 0x0); i2c_write_reg(sc, I2C_STATUS_REG, 0x0); DELAY(1000); i2c_write_reg(sc, I2C_FDR_REG, baud_rate); i2c_write_reg(sc, I2C_DFSRR_REG, I2C_DFSSR_DIV); i2c_write_reg(sc, I2C_CONTROL_REG, I2C_ENABLE); DELAY(1000); mtx_unlock(&sc->mutex); return (IIC_NOERR); } static int i2c_read(device_t dev, char *buf, int len, int *read, int last, int delay) { struct i2c_softc *sc; int error; sc = device_get_softc(dev); *read = 0; mtx_lock(&sc->mutex); if (len) { if (len == 1) i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | I2CCR_MSTA | I2CCR_TXAK); else i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | I2CCR_MSTA); /* dummy read */ i2c_read_reg(sc, I2C_DATA_REG); DELAY(1000); } while (*read < len) { DELAY(1000); error = i2c_do_wait(dev, sc, 0, 0); if (error) { mtx_unlock(&sc->mutex); return (error); } if ((*read == len - 2) && last) { i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | I2CCR_MSTA | I2CCR_TXAK); } if ((*read == len - 1) && last) { i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | I2CCR_TXAK); } *buf++ = i2c_read_reg(sc, I2C_DATA_REG); (*read)++; DELAY(1250); } mtx_unlock(&sc->mutex); return (IIC_NOERR); } static int i2c_write(device_t dev, const char *buf, int len, int *sent, int timeout) { struct i2c_softc *sc; int error; sc = device_get_softc(dev); *sent = 0; mtx_lock(&sc->mutex); while (*sent < len) { i2c_write_reg(sc, I2C_DATA_REG, *buf++); DELAY(1250); error = i2c_do_wait(dev, sc, 1, 0); if (error) { mtx_unlock(&sc->mutex); return (error); } (*sent)++; } mtx_unlock(&sc->mutex); return (IIC_NOERR); } Index: projects/release-pkg/sys =================================================================== --- projects/release-pkg/sys (revision 289118) +++ projects/release-pkg/sys (revision 289119) Property changes on: projects/release-pkg/sys ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys:r289091-289118 Index: projects/release-pkg/usr.sbin/ppp/Makefile =================================================================== --- projects/release-pkg/usr.sbin/ppp/Makefile (revision 289118) +++ projects/release-pkg/usr.sbin/ppp/Makefile (revision 289119) @@ -1,111 +1,114 @@ # $FreeBSD$ .include PROG= ppp MAN= ppp.8 SRCS= acf.c arp.c async.c auth.c bundle.c cbcp.c ccp.c chap.c chat.c \ command.c datalink.c deflate.c defs.c exec.c filter.c fsm.c hdlc.c \ iface.c ip.c ipcp.c ipv6cp.c iplist.c lcp.c link.c log.c lqr.c main.c \ mbuf.c mp.c ncp.c ncpaddr.c pap.c physical.c pred.c probe.c prompt.c \ proto.c route.c server.c sig.c slcompress.c sync.c systems.c tcp.c \ tcpmss.c throughput.c timer.c tty.c tun.c udp.c vjcomp.c WARNS?= 3 .if defined(RELEASE_CRUNCH) CFLAGS+=-DRELEASE_CRUNCH PPP_NO_ATM= PPP_NO_DES= PPP_NO_KLDLOAD= PPP_NO_NAT= PPP_NO_PAM= PPP_NO_RADIUS= PPP_NO_SUID= .endif +CONFS= ppp.conf +CONFSDIR= ${CONFIGDIR}/ppp +CONFSMODE= 600 .if ${MK_ATM} == "no" PPP_NO_ATM= .endif .if ${MK_NETGRAPH} == "no" PPP_NO_NETGRAPH= .endif .if ${MK_PAM_SUPPORT} == "no" PPP_NO_PAM= .endif .if ${MK_RADIUS_SUPPORT} == "no" PPP_NO_RADIUS= .endif .if defined(PPP_NO_SUID) BINMODE=554 .else BINMODE=4554 BINOWN= root .endif BINGRP= network M4FLAGS= LIBADD= md util z .if defined(PPP_CONFDIR) && !empty(PPP_CONFDIR) CFLAGS+=-DPPP_CONFDIR=\"${PPP_CONFDIR}\" .endif .if defined(PPP_NO_KLDLOAD) CFLAGS+=-DNOKLDLOAD .endif .if ${MK_INET6_SUPPORT} == "no" CFLAGS+=-DNOINET6 .endif .if defined(PPP_NO_NAT) CFLAGS+=-DNONAT .else SRCS+= nat_cmd.c LIBADD+= alias .endif .if defined(PPP_NO_ATM) CFLAGS+=-DNOATM .else SRCS+= atm.c .endif .if defined(PPP_NO_SUID) CFLAGS+=-DNOSUID .else SRCS+= id.c .endif .if ${MK_OPENSSL} == "no" || defined(PPP_NO_DES) CFLAGS+=-DNODES .else SRCS+= chap_ms.c mppe.c LIBADD+= crypto .endif .if defined(PPP_NO_RADIUS) CFLAGS+=-DNORADIUS .else SRCS+= radius.c LIBADD+= radius .endif .if defined(PPP_NO_NETGRAPH) CFLAGS+=-DNONETGRAPH .else SRCS+= ether.c LIBADD+= netgraph .if defined(EXPERIMENTAL_NETGRAPH) CFLAGS+=-DEXPERIMENTAL_NETGRAPH SRCS+= netgraph.c .endif .endif .if defined(PPP_NO_PAM) CFLAGS+=-DNOPAM .else LIBADD+= pam .endif .include Index: projects/release-pkg/usr.sbin/ppp/ppp.conf =================================================================== --- projects/release-pkg/usr.sbin/ppp/ppp.conf (nonexistent) +++ projects/release-pkg/usr.sbin/ppp/ppp.conf (revision 289119) @@ -0,0 +1,37 @@ +################################################################# +# PPP Sample Configuration File +# Originally written by Toshiharu OHNO +# Simplified 5/14/1999 by wself@cdrom.com +# +# See /usr/share/examples/ppp/ for some examples +# +# $FreeBSD$ +################################################################# + +default: + set log Phase Chat LCP IPCP CCP tun command + ident user-ppp VERSION + + # Ensure that "device" references the correct serial port + # for your modem. (cuau0 = COM1, cuau1 = COM2) + # + set device /dev/cuau1 + + set speed 115200 + set dial "ABORT BUSY ABORT NO\\sCARRIER TIMEOUT 5 \ + \"\" AT OK-AT-OK ATE1Q0 OK \\dATDT\\T TIMEOUT 40 CONNECT" + set timeout 180 # 3 minute idle timer (the default) + enable dns # request DNS info (for resolv.conf) + +papchap: + # + # edit the next three lines and replace the items in caps with + # the values which have been assigned by your ISP. + # + + set phone PHONE_NUM + set authname USERNAME + set authkey PASSWORD + + set ifaddr 10.0.0.1/0 10.0.0.2/0 255.255.255.0 0.0.0.0 + add default HISADDR # Add a (sticky) default route Property changes on: projects/release-pkg/usr.sbin/ppp/ppp.conf ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: projects/release-pkg =================================================================== --- projects/release-pkg (revision 289118) +++ projects/release-pkg (revision 289119) Property changes on: projects/release-pkg ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,2 ## Merged /user/ngie/more-tests2:r288982 Merged /head:r289091-289118