From 7925f73aa967b7bbdb4eeeeb7ac3102cbe42b1e0 Mon Sep 17 00:00:00 2001 From: gjb Date: Tue, 14 Oct 2014 12:04:50 +0000 Subject: [PATCH 001/258] Clear VM_RC_LIST. Sponsored by: The FreeBSD Foundation --- release/tools/azure.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/tools/azure.conf b/release/tools/azure.conf index da205bb1d307..8f16acc0d279 100644 --- a/release/tools/azure.conf +++ b/release/tools/azure.conf @@ -11,4 +11,4 @@ export VM_EXTRA_PACKAGES= # Set to a list of third-party software to enable in rc.conf(5). # Example: #export VM_RC_LIST="apache24" -export VM_RC_LIST="apache24" +export VM_RC_LIST= From 53cd002a855491bd9c9242e22022c686575b5b7b Mon Sep 17 00:00:00 2001 From: gjb Date: Tue, 14 Oct 2014 12:13:43 +0000 Subject: [PATCH 002/258] Fix signal list to trigger umount(8). Sponsored by: The FreeBSD Foundation --- release/amd64/mk-azure.sh | 2 +- release/i386/mk-azure.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/release/amd64/mk-azure.sh b/release/amd64/mk-azure.sh index b691d54f6a69..4ba0bfae0e1b 100755 --- a/release/amd64/mk-azure.sh +++ b/release/amd64/mk-azure.sh @@ -67,7 +67,7 @@ vm_create_azure() { usage fi - trap "umount ${DESTDIR}/dev ${DESTDIR}" EXIT + trap "umount ${DESTDIR}/dev ${DESTDIR}" INT QUIT TRAP ABRT TERM i=0 mkdir -p ${DESTDIR} diff --git a/release/i386/mk-azure.sh b/release/i386/mk-azure.sh index b691d54f6a69..4ba0bfae0e1b 100755 --- a/release/i386/mk-azure.sh +++ b/release/i386/mk-azure.sh @@ -67,7 +67,7 @@ vm_create_azure() { usage fi - trap "umount ${DESTDIR}/dev ${DESTDIR}" EXIT + trap "umount ${DESTDIR}/dev ${DESTDIR}" INT QUIT TRAP ABRT TERM i=0 mkdir -p ${DESTDIR} From 8521a45a5518d0da7ec2b53f2abb0f433d612a61 Mon Sep 17 00:00:00 2001 From: gjb Date: Tue, 14 Oct 2014 15:18:22 +0000 Subject: [PATCH 003/258] Output an informational message when mkimg(1) runs, so it does not appear that the process has stopped while waiting for a 'y/n' response when waagent is deprovisioned. Sponsored by: The FreeBSD Foundation --- release/amd64/mk-azure.sh | 2 ++ release/i386/mk-azure.sh | 2 ++ 2 files changed, 4 insertions(+) diff --git a/release/amd64/mk-azure.sh b/release/amd64/mk-azure.sh index 4ba0bfae0e1b..45b70ae73a1d 100755 --- a/release/amd64/mk-azure.sh +++ b/release/amd64/mk-azure.sh @@ -130,6 +130,8 @@ vm_create_azure() { sleep 1 done + echo "Creating image... Please wait." + mkimg -f vhdf -s gpt \ -b /boot/pmbr -p freebsd-boot/bootfs:=/boot/gptboot \ -p freebsd-swap/swapfs::1G \ diff --git a/release/i386/mk-azure.sh b/release/i386/mk-azure.sh index 4ba0bfae0e1b..45b70ae73a1d 100755 --- a/release/i386/mk-azure.sh +++ b/release/i386/mk-azure.sh @@ -130,6 +130,8 @@ vm_create_azure() { sleep 1 done + echo "Creating image... Please wait." + mkimg -f vhdf -s gpt \ -b /boot/pmbr -p freebsd-boot/bootfs:=/boot/gptboot \ -p freebsd-swap/swapfs::1G \ From a44964f2220df0202e792c5f037dc4843dd1ce20 Mon Sep 17 00:00:00 2001 From: gjb Date: Wed, 29 Oct 2014 14:57:30 +0000 Subject: [PATCH 004/258] Move virtual machine / cloud provider targets and options from release/Makefile to their own Makefile. Sponsored by: The FreeBSD Foundation --- release/Makefile | 51 +--------------------------------------- release/Makefile.vm | 57 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 50 deletions(-) create mode 100644 release/Makefile.vm diff --git a/release/Makefile b/release/Makefile index 8a517f810243..5c425e48f0af 100644 --- a/release/Makefile +++ b/release/Makefile @@ -97,12 +97,6 @@ IMAGES+= memstick.img IMAGES+= mini-memstick.img .endif -VMTARGETS= vm-base vm-image -VMFORMATS?= vhd vmdk qcow2 raw -VMSIZE?= 20G -VMBASE?= vm -AZURECONF?= ${.CURDIR}/tools/azure.conf - CLEANFILES= packagesystem *.txz MANIFEST system ${IMAGES} .if defined(WITH_COMPRESSED_IMAGES) && !empty(WITH_COMPRESSED_IMAGES) . for I in ${IMAGES} @@ -112,22 +106,7 @@ CLEANFILES+= ${I}.xz .if defined(WITH_DVD) && !empty(WITH_DVD) CLEANFILES+= pkg-stage .endif -.if defined(WITH_VMIMAGES) && !empty(WITH_VMIMAGES) -CLEANFILES+= ${VMBASE}.img -. for FORMAT in ${VMFORMATS} -CLEANFILES+= ${VMBASE}.${FORMAT} -. endfor -.endif CLEANDIRS= dist ftp release bootonly dvd -.if defined(WITH_VMIMAGES) && !empty(WITH_VMIMAGES) -CLEANDIRS+= ${VMTARGETS} -.endif -.if exists(${.CURDIR}/${TARGET}/mk-azure.sh) -CLEANFILES+= ${OSRELEASE}.vhd \ - ${OSRELEASE}.vhd.raw \ - azure.img -CLEANDIRS+= vm-azure -.endif beforeclean: chflags -R noschg . .include @@ -324,32 +303,4 @@ install: ${DESTDIR}/vmimages/CHECKSUM.MD5 .endif -vm-base: -.if defined(WITH_VMIMAGES) && !empty(WITH_VMIMAGES) -. if exists(${.CURDIR}/${TARGET}/mk-vmimage.sh) - env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ - ${.CURDIR}/${TARGET}/mk-vmimage.sh ${.TARGET} \ - ${VMBASE}.img ${WORLDDIR} ${.OBJDIR}/${.TARGET} ${VMSIZE} -. endif -.endif - touch ${.TARGET} - -vm-image: vm-base -.if defined(WITH_VMIMAGES) && !empty(WITH_VMIMAGES) -. if exists(${.CURDIR}/${TARGET}/mk-vmimage.sh) -. for FORMAT in ${VMFORMATS} - env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ - ${.CURDIR}/${TARGET}/mk-vmimage.sh ${.TARGET} \ - ${VMBASE}.img ${FORMAT} ${VMBASE}.${FORMAT} -. endfor -. endif -.endif - touch ${.TARGET} - -vm-azure: -.if exists(${.CURDIR}/${TARGET}/mk-azure.sh) - env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} AZURECONF=${AZURECONF} \ - ${.CURDIR}/${TARGET}/mk-azure.sh ${.TARGET} azure.img \ - ${WORLDDIR} ${.TARGET} ${VMSIZE} ${OSRELEASE}.vhd -.endif - touch ${.TARGET} +.include "${.CURDIR}/Makefile.vm" diff --git a/release/Makefile.vm b/release/Makefile.vm new file mode 100644 index 000000000000..1d1f64223f53 --- /dev/null +++ b/release/Makefile.vm @@ -0,0 +1,57 @@ +# +# $FreeBSD$ +# +# +# Makefile for building virtual machine and cloud provider disk images. +# + +VMTARGETS= vm-base vm-image +VMFORMATS?= vhd vmdk qcow2 raw +VMSIZE?= 20G +VMBASE?= vm +AZURECONF?= ${.CURDIR}/tools/azure.conf + +.if defined(WITH_VMIMAGES) && !empty(WITH_VMIMAGES) +CLEANDIRS+= ${VMTARGETS} +CLEANFILES+= ${VMBASE}.img +. for FORMAT in ${VMFORMATS} +CLEANFILES+= ${VMBASE}.${FORMAT} +. endfor +.endif + +.if exists(${.CURDIR}/${TARGET}/mk-azure.sh) +CLEANFILES+= ${OSRELEASE}.vhd \ + ${OSRELEASE}.vhd.raw \ + azure.img +CLEANDIRS+= vm-azure +.endif + +vm-base: +.if defined(WITH_VMIMAGES) && !empty(WITH_VMIMAGES) +. if exists(${.CURDIR}/${TARGET}/mk-vmimage.sh) + env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ + ${.CURDIR}/${TARGET}/mk-vmimage.sh ${.TARGET} \ + ${VMBASE}.img ${WORLDDIR} ${.OBJDIR}/${.TARGET} ${VMSIZE} +. endif +.endif + touch ${.TARGET} + +vm-image: vm-base +.if defined(WITH_VMIMAGES) && !empty(WITH_VMIMAGES) +. if exists(${.CURDIR}/${TARGET}/mk-vmimage.sh) +. for FORMAT in ${VMFORMATS} + env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ + ${.CURDIR}/${TARGET}/mk-vmimage.sh ${.TARGET} \ + ${VMBASE}.img ${FORMAT} ${VMBASE}.${FORMAT} +. endfor +. endif +.endif + touch ${.TARGET} + +vm-azure: +.if exists(${.CURDIR}/${TARGET}/mk-azure.sh) + env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} AZURECONF=${AZURECONF} \ + ${.CURDIR}/${TARGET}/mk-azure.sh ${.TARGET} azure.img \ + ${WORLDDIR} ${.TARGET} ${VMSIZE} ${OSRELEASE}.vhd +.endif + touch ${.TARGET} From 312c939c86a5d14589ab78630e9aff85d0e79cdb Mon Sep 17 00:00:00 2001 From: gjb Date: Wed, 29 Oct 2014 15:52:17 +0000 Subject: [PATCH 005/258] Add glue to allow enabling building cloud provider VM images by default. When WITH_CLOUDWARE is not empty, add CLOUDTARGETS to the release/Makefile 'release' target. CLOUDTARGETS is generated from the contents of CLOUDWARE, which should be a list of all supported target providers. Sponsored by: The FreeBSD Foundation --- release/Makefile | 3 +++ release/Makefile.vm | 24 ++++++++++++++++-------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/release/Makefile b/release/Makefile index 5c425e48f0af..5edd4d0f4f68 100644 --- a/release/Makefile +++ b/release/Makefile @@ -269,6 +269,9 @@ release: .if defined(WITH_VMIMAGES) && !empty(WITH_VMIMAGES) ${MAKE} -C ${.CURDIR} ${.MAKEFLAGS} ${VMTARGETS} .endif +.if defined(WITH_CLOUDWARE) && !empty(WITH_CLOUDWARE) && !empty(CLOUDWARE) + ${MAKE} -C ${.CURDIR} ${.MAKEFLAGS} ${CLOUDTARGETS} +.endif install: .if defined(DESTDIR) && !empty(DESTDIR) diff --git a/release/Makefile.vm b/release/Makefile.vm index 1d1f64223f53..82eb7d4ece45 100644 --- a/release/Makefile.vm +++ b/release/Makefile.vm @@ -9,7 +9,22 @@ VMTARGETS= vm-base vm-image VMFORMATS?= vhd vmdk qcow2 raw VMSIZE?= 20G VMBASE?= vm -AZURECONF?= ${.CURDIR}/tools/azure.conf + +CLOUDWARE?= AZURE +AZURE_FORMAT= vhd + +.if defined(WITH_CLOUDWARE) && !empty(WITH_CLOUDWARE) && !empty(CLOUDWARE) +. for _CW in ${CLOUDWARE} +CLOUDTARGETS+= vm-${_CW:tl} +CLEANDIRS+= vm-${_CW:tl} +CLEANFILES+= ${_CW:tl}.img \ + ${_CW:tl}.${${_CW:tu}_FORMAT} \ + ${_CW:tl}.${${_CW:tu}_FORMAT}.raw +. if exists(${.CURDIR}/tools/${_CW:tl}.conf) && !defined(${_CW:tu}CONF) +${_CW:tu}CONF?= ${.CURDIR}/tools/${_CW:tl}.conf +. endif +. endfor +.endif .if defined(WITH_VMIMAGES) && !empty(WITH_VMIMAGES) CLEANDIRS+= ${VMTARGETS} @@ -19,13 +34,6 @@ CLEANFILES+= ${VMBASE}.${FORMAT} . endfor .endif -.if exists(${.CURDIR}/${TARGET}/mk-azure.sh) -CLEANFILES+= ${OSRELEASE}.vhd \ - ${OSRELEASE}.vhd.raw \ - azure.img -CLEANDIRS+= vm-azure -.endif - vm-base: .if defined(WITH_VMIMAGES) && !empty(WITH_VMIMAGES) . if exists(${.CURDIR}/${TARGET}/mk-vmimage.sh) From b2f4325812859a3c741c1c51a4a01eb697361b95 Mon Sep 17 00:00:00 2001 From: gjb Date: Wed, 29 Oct 2014 16:18:29 +0000 Subject: [PATCH 006/258] Avoid hard-coding the Azure image file format. While here, avoid using OSRELEASE for the output file name. Sponsored by: The FreeBSD Foundation --- release/Makefile.vm | 6 ++++-- release/amd64/mk-azure.sh | 2 +- release/i386/mk-azure.sh | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/release/Makefile.vm b/release/Makefile.vm index 82eb7d4ece45..ce7f0eab922c 100644 --- a/release/Makefile.vm +++ b/release/Makefile.vm @@ -11,7 +11,7 @@ VMSIZE?= 20G VMBASE?= vm CLOUDWARE?= AZURE -AZURE_FORMAT= vhd +AZURE_FORMAT= vhdf .if defined(WITH_CLOUDWARE) && !empty(WITH_CLOUDWARE) && !empty(CLOUDWARE) . for _CW in ${CLOUDWARE} @@ -20,6 +20,7 @@ CLEANDIRS+= vm-${_CW:tl} CLEANFILES+= ${_CW:tl}.img \ ${_CW:tl}.${${_CW:tu}_FORMAT} \ ${_CW:tl}.${${_CW:tu}_FORMAT}.raw +${_CW:tu}IMAGE= ${_CW:tl}.${${_CW:tu}_FORMAT} . if exists(${.CURDIR}/tools/${_CW:tl}.conf) && !defined(${_CW:tu}CONF) ${_CW:tu}CONF?= ${.CURDIR}/tools/${_CW:tl}.conf . endif @@ -59,7 +60,8 @@ vm-image: vm-base vm-azure: .if exists(${.CURDIR}/${TARGET}/mk-azure.sh) env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} AZURECONF=${AZURECONF} \ + AZURE_FORMAT=${AZURE_FORMAT} \ ${.CURDIR}/${TARGET}/mk-azure.sh ${.TARGET} azure.img \ - ${WORLDDIR} ${.TARGET} ${VMSIZE} ${OSRELEASE}.vhd + ${WORLDDIR} ${.TARGET} ${VMSIZE} ${AZUREIMAGE} .endif touch ${.TARGET} diff --git a/release/amd64/mk-azure.sh b/release/amd64/mk-azure.sh index 45b70ae73a1d..43c92040ed35 100755 --- a/release/amd64/mk-azure.sh +++ b/release/amd64/mk-azure.sh @@ -132,7 +132,7 @@ vm_create_azure() { echo "Creating image... Please wait." - mkimg -f vhdf -s gpt \ + mkimg -f ${AZURE_FORMAT} -s gpt \ -b /boot/pmbr -p freebsd-boot/bootfs:=/boot/gptboot \ -p freebsd-swap/swapfs::1G \ -p freebsd-ufs/rootfs:=${VMBASE} \ diff --git a/release/i386/mk-azure.sh b/release/i386/mk-azure.sh index 45b70ae73a1d..43c92040ed35 100755 --- a/release/i386/mk-azure.sh +++ b/release/i386/mk-azure.sh @@ -132,7 +132,7 @@ vm_create_azure() { echo "Creating image... Please wait." - mkimg -f vhdf -s gpt \ + mkimg -f ${AZURE_FORMAT} -s gpt \ -b /boot/pmbr -p freebsd-boot/bootfs:=/boot/gptboot \ -p freebsd-swap/swapfs::1G \ -p freebsd-ufs/rootfs:=${VMBASE} \ From a452e67d0444028810849a32f47e3267b5d9560a Mon Sep 17 00:00:00 2001 From: gjb Date: Wed, 29 Oct 2014 16:20:49 +0000 Subject: [PATCH 007/258] Remove a few vestiges of passing an exit code to panic(). Sponsored by: The FreeBSD Foundation --- release/amd64/mk-azure.sh | 4 ++-- release/i386/mk-azure.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/release/amd64/mk-azure.sh b/release/amd64/mk-azure.sh index 43c92040ed35..ac89258996f4 100755 --- a/release/amd64/mk-azure.sh +++ b/release/amd64/mk-azure.sh @@ -78,7 +78,7 @@ vm_create_azure() { mount /dev/${mddev} ${DESTDIR} make -C ${WORLDDIR} DESTDIR=$(realpath ${DESTDIR}) \ installworld installkernel distribution || \ - panic 1 "\n\nCannot install the base system to ${DESTDIR}." + panic "\n\nCannot install the base system to ${DESTDIR}." mount -t devfs devfs ${DESTDIR}/dev chroot ${DESTDIR} /usr/bin/newaliases echo '# Custom /etc/fstab for FreeBSD VM images' \ @@ -125,7 +125,7 @@ vm_create_azure() { # This should never happen. But, it has happened. msg="Cannot umount(8) ${DESTDIR}\n" msg="${msg}Something has gone horribly wrong." - panic 1 "${msg}" + panic "${msg}" fi sleep 1 done diff --git a/release/i386/mk-azure.sh b/release/i386/mk-azure.sh index 43c92040ed35..ac89258996f4 100755 --- a/release/i386/mk-azure.sh +++ b/release/i386/mk-azure.sh @@ -78,7 +78,7 @@ vm_create_azure() { mount /dev/${mddev} ${DESTDIR} make -C ${WORLDDIR} DESTDIR=$(realpath ${DESTDIR}) \ installworld installkernel distribution || \ - panic 1 "\n\nCannot install the base system to ${DESTDIR}." + panic "\n\nCannot install the base system to ${DESTDIR}." mount -t devfs devfs ${DESTDIR}/dev chroot ${DESTDIR} /usr/bin/newaliases echo '# Custom /etc/fstab for FreeBSD VM images' \ @@ -125,7 +125,7 @@ vm_create_azure() { # This should never happen. But, it has happened. msg="Cannot umount(8) ${DESTDIR}\n" msg="${msg}Something has gone horribly wrong." - panic 1 "${msg}" + panic "${msg}" fi sleep 1 done From be176f72fe4aae01058f956718665299e1604d4e Mon Sep 17 00:00:00 2001 From: gjb Date: Wed, 29 Oct 2014 17:04:09 +0000 Subject: [PATCH 008/258] Initial commit providing a mechanism to create openstack images as part of the release build. This mimics the way Microsoft Azure images are built, with the addition of installing the net/cloud-init package and adding a (commented) rc.conf(5) entry for cloudinit. Sponsored by: The FreeBSD Foundation --- release/Makefile.vm | 14 +++- release/amd64/mk-openstack.sh | 153 ++++++++++++++++++++++++++++++++++ release/i386/mk-openstack.sh | 153 ++++++++++++++++++++++++++++++++++ release/tools/openstack.conf | 10 +++ 4 files changed, 329 insertions(+), 1 deletion(-) create mode 100755 release/amd64/mk-openstack.sh create mode 100755 release/i386/mk-openstack.sh create mode 100644 release/tools/openstack.conf diff --git a/release/Makefile.vm b/release/Makefile.vm index ce7f0eab922c..0ef7fc8ef2e7 100644 --- a/release/Makefile.vm +++ b/release/Makefile.vm @@ -10,8 +10,10 @@ VMFORMATS?= vhd vmdk qcow2 raw VMSIZE?= 20G VMBASE?= vm -CLOUDWARE?= AZURE +CLOUDWARE?= AZURE \ + OPENSTACK AZURE_FORMAT= vhdf +OPENSTACK_FORMAT=qcow2 .if defined(WITH_CLOUDWARE) && !empty(WITH_CLOUDWARE) && !empty(CLOUDWARE) . for _CW in ${CLOUDWARE} @@ -65,3 +67,13 @@ vm-azure: ${WORLDDIR} ${.TARGET} ${VMSIZE} ${AZUREIMAGE} .endif touch ${.TARGET} + +vm-openstack: +.if exists(${.CURDIR}/${TARGET}/mk-openstack.sh) + env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ + OPENSTACKCONF=${OPENSTACKCONF} + OPENSTACK_FORMAT=${OPENSTACK_FORMAT} \ + ${.CURDIR}/${TARGET}/mk-openstack.sh ${.TARGET} openstack.img \ + ${WORLDDIR} ${.TARGET} ${VMSIZE} ${OPENSTACKIMAGE} +.endif + touch ${.TARGET} diff --git a/release/amd64/mk-openstack.sh b/release/amd64/mk-openstack.sh new file mode 100755 index 000000000000..32e0f4cbb5fe --- /dev/null +++ b/release/amd64/mk-openstack.sh @@ -0,0 +1,153 @@ +#!/bin/sh +#- +# Copyright (c) 2014 The FreeBSD Foundation +# All rights reserved. +# +# This software was developed by Glen Barber 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. +# +# mk-openstack.sh: Create virtual machine disk images for Openstack +# +# $FreeBSD$ +# + +export PATH="/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin" + +usage() { + echo "Usage:" + echo -n "$(basename ${0}) vm-openstack " + echo " " + exit 1 +} + +panic() { + msg="${@}" + printf "${msg}\n" + if [ ! -z "${mddev}" ]; then + mdconfig -d -u ${mddev} + fi + # Do not allow one failure case to chain through any remaining image + # builds. + exit 0 +} + +vm_create_openstack() { + # Arguments: + # vm-openstack + # + + VMBASE="${1}" + WORLDDIR="${2}" + DESTDIR="${3}" + VMSIZE="${4}" + VMIMAGE="${5}" + + if [ -z "${VMBASE}" -o -z "${WORLDDIR}" -o -z "${DESTDIR}" \ + -o -z "${VMSIZE}" -o -z "${VMIMAGE}" ]; then + usage + fi + + trap "umount ${DESTDIR}/dev ${DESTDIR}" INT QUIT TRAP ABRT TERM + + i=0 + mkdir -p ${DESTDIR} + truncate -s ${VMSIZE} ${VMBASE} + mddev=$(mdconfig -f ${VMBASE}) + newfs -j /dev/${mddev} + mkdir -p ${DESTDIR} + mount /dev/${mddev} ${DESTDIR} + make -C ${WORLDDIR} DESTDIR=$(realpath ${DESTDIR}) \ + installworld installkernel distribution || \ + panic "\n\nCannot install the base system to ${DESTDIR}." + mount -t devfs devfs ${DESTDIR}/dev + chroot ${DESTDIR} /usr/bin/newaliases + echo '# Custom /etc/fstab for FreeBSD VM images' \ + > ${DESTDIR}/etc/fstab + echo '/dev/gpt/rootfs / ufs rw 2 2' \ + >> ${DESTDIR}/etc/fstab + echo '/dev/gpt/swapfs none swap sw 0 0' \ + >> ${DESTDIR}/etc/fstab + + chroot ${DESTDIR} /etc/rc.d/ldconfig forcestart + chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes /usr/sbin/pkg bootstrap -y + if [ ! -z "${VM_EXTRA_PACKAGES}" ]; then + chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes /usr/sbin/pkg install -y \ + ${VM_EXTRA_PACKAGES} + fi + + rm -f ${DESTDIR}/etc/resolv.conf + echo 'sshd_enable="YES"' > ${DESTDIR}/etc/rc.conf + echo 'ifconfig_DEFAULT="SYNCDHCP"' >> ${DESTDIR}/etc/rc.conf + + if [ ! -z "${VM_RC_LIST}" ]; then + for _rcvar in ${VM_RC_LIST}; do + echo ${_rcvar}_enable="YES" >> ${DESTDIR}/etc/rc.conf + done + fi + + sync + + while ! umount ${DESTDIR}/dev ${DESTDIR}; do + i=$(( $i + 1 )) + if [ $i -ge 10 ]; then + # This should never happen. But, it has happened. + msg="Cannot umount(8) ${DESTDIR}\n" + msg="${msg}Something has gone horribly wrong." + panic "${msg}" + fi + sleep 1 + done + + echo "Creating image... Please wait." + + mkimg -f ${OPENSTACK_FORMAT} -s gpt \ + -b /boot/pmbr -p freebsd-boot/bootfs:=/boot/gptboot \ + -p freebsd-swap/swapfs::1G \ + -p freebsd-ufs/rootfs:=${VMBASE} \ + -o ${VMIMAGE}.raw + + return 0 +} + +main() { + cmd="${1}" + shift 1 + + if [ -e "${OPENSTACKCONF}" -a ! -c "${OPENSTACKCONF}" ]; then + . ${OPENSTACKCONF} + fi + + case ${cmd} in + vm-openstack) + eval vm_create_openstack "$@" || return 0 + ;; + *|\?) + usage + ;; + esac + + return 0 +} + +main "$@" diff --git a/release/i386/mk-openstack.sh b/release/i386/mk-openstack.sh new file mode 100755 index 000000000000..32e0f4cbb5fe --- /dev/null +++ b/release/i386/mk-openstack.sh @@ -0,0 +1,153 @@ +#!/bin/sh +#- +# Copyright (c) 2014 The FreeBSD Foundation +# All rights reserved. +# +# This software was developed by Glen Barber 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. +# +# mk-openstack.sh: Create virtual machine disk images for Openstack +# +# $FreeBSD$ +# + +export PATH="/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin" + +usage() { + echo "Usage:" + echo -n "$(basename ${0}) vm-openstack " + echo " " + exit 1 +} + +panic() { + msg="${@}" + printf "${msg}\n" + if [ ! -z "${mddev}" ]; then + mdconfig -d -u ${mddev} + fi + # Do not allow one failure case to chain through any remaining image + # builds. + exit 0 +} + +vm_create_openstack() { + # Arguments: + # vm-openstack + # + + VMBASE="${1}" + WORLDDIR="${2}" + DESTDIR="${3}" + VMSIZE="${4}" + VMIMAGE="${5}" + + if [ -z "${VMBASE}" -o -z "${WORLDDIR}" -o -z "${DESTDIR}" \ + -o -z "${VMSIZE}" -o -z "${VMIMAGE}" ]; then + usage + fi + + trap "umount ${DESTDIR}/dev ${DESTDIR}" INT QUIT TRAP ABRT TERM + + i=0 + mkdir -p ${DESTDIR} + truncate -s ${VMSIZE} ${VMBASE} + mddev=$(mdconfig -f ${VMBASE}) + newfs -j /dev/${mddev} + mkdir -p ${DESTDIR} + mount /dev/${mddev} ${DESTDIR} + make -C ${WORLDDIR} DESTDIR=$(realpath ${DESTDIR}) \ + installworld installkernel distribution || \ + panic "\n\nCannot install the base system to ${DESTDIR}." + mount -t devfs devfs ${DESTDIR}/dev + chroot ${DESTDIR} /usr/bin/newaliases + echo '# Custom /etc/fstab for FreeBSD VM images' \ + > ${DESTDIR}/etc/fstab + echo '/dev/gpt/rootfs / ufs rw 2 2' \ + >> ${DESTDIR}/etc/fstab + echo '/dev/gpt/swapfs none swap sw 0 0' \ + >> ${DESTDIR}/etc/fstab + + chroot ${DESTDIR} /etc/rc.d/ldconfig forcestart + chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes /usr/sbin/pkg bootstrap -y + if [ ! -z "${VM_EXTRA_PACKAGES}" ]; then + chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes /usr/sbin/pkg install -y \ + ${VM_EXTRA_PACKAGES} + fi + + rm -f ${DESTDIR}/etc/resolv.conf + echo 'sshd_enable="YES"' > ${DESTDIR}/etc/rc.conf + echo 'ifconfig_DEFAULT="SYNCDHCP"' >> ${DESTDIR}/etc/rc.conf + + if [ ! -z "${VM_RC_LIST}" ]; then + for _rcvar in ${VM_RC_LIST}; do + echo ${_rcvar}_enable="YES" >> ${DESTDIR}/etc/rc.conf + done + fi + + sync + + while ! umount ${DESTDIR}/dev ${DESTDIR}; do + i=$(( $i + 1 )) + if [ $i -ge 10 ]; then + # This should never happen. But, it has happened. + msg="Cannot umount(8) ${DESTDIR}\n" + msg="${msg}Something has gone horribly wrong." + panic "${msg}" + fi + sleep 1 + done + + echo "Creating image... Please wait." + + mkimg -f ${OPENSTACK_FORMAT} -s gpt \ + -b /boot/pmbr -p freebsd-boot/bootfs:=/boot/gptboot \ + -p freebsd-swap/swapfs::1G \ + -p freebsd-ufs/rootfs:=${VMBASE} \ + -o ${VMIMAGE}.raw + + return 0 +} + +main() { + cmd="${1}" + shift 1 + + if [ -e "${OPENSTACKCONF}" -a ! -c "${OPENSTACKCONF}" ]; then + . ${OPENSTACKCONF} + fi + + case ${cmd} in + vm-openstack) + eval vm_create_openstack "$@" || return 0 + ;; + *|\?) + usage + ;; + esac + + return 0 +} + +main "$@" diff --git a/release/tools/openstack.conf b/release/tools/openstack.conf new file mode 100644 index 000000000000..faa6ee245410 --- /dev/null +++ b/release/tools/openstack.conf @@ -0,0 +1,10 @@ +#!/bin/sh +# +# $FreeBSD$ +# + +# Set to a list of packages to install. +export VM_EXTRA_PACKAGES="net/cloud-init" + +# Set to a list of third-party software to enable in rc.conf(5). +export VM_RC_LIST="#cloudinit" From 0b5eea342c049437134cf6dafccf9ff694cc8831 Mon Sep 17 00:00:00 2001 From: gjb Date: Wed, 29 Oct 2014 19:44:34 +0000 Subject: [PATCH 009/258] Fix output file name for openstack images. No further conversion is necessary for this VM file target, so there is no need to append the '.raw' suffix here. Sponsored by: The FreeBSD Foundation --- release/amd64/mk-openstack.sh | 2 +- release/i386/mk-openstack.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/release/amd64/mk-openstack.sh b/release/amd64/mk-openstack.sh index 32e0f4cbb5fe..863860b520e4 100755 --- a/release/amd64/mk-openstack.sh +++ b/release/amd64/mk-openstack.sh @@ -125,7 +125,7 @@ vm_create_openstack() { -b /boot/pmbr -p freebsd-boot/bootfs:=/boot/gptboot \ -p freebsd-swap/swapfs::1G \ -p freebsd-ufs/rootfs:=${VMBASE} \ - -o ${VMIMAGE}.raw + -o ${VMIMAGE} return 0 } diff --git a/release/i386/mk-openstack.sh b/release/i386/mk-openstack.sh index 32e0f4cbb5fe..863860b520e4 100755 --- a/release/i386/mk-openstack.sh +++ b/release/i386/mk-openstack.sh @@ -125,7 +125,7 @@ vm_create_openstack() { -b /boot/pmbr -p freebsd-boot/bootfs:=/boot/gptboot \ -p freebsd-swap/swapfs::1G \ -p freebsd-ufs/rootfs:=${VMBASE} \ - -o ${VMIMAGE}.raw + -o ${VMIMAGE} return 0 } From e7b2345984cbf9e8c6b24e219567c2ae918fef30 Mon Sep 17 00:00:00 2001 From: gjb Date: Sat, 1 Nov 2014 20:41:47 +0000 Subject: [PATCH 010/258] Uncomment the cloudinit rc.conf(5) line. Sponsored by: The FreeBSD Foundation --- release/tools/openstack.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/tools/openstack.conf b/release/tools/openstack.conf index faa6ee245410..b43ad76b6da2 100644 --- a/release/tools/openstack.conf +++ b/release/tools/openstack.conf @@ -7,4 +7,4 @@ export VM_EXTRA_PACKAGES="net/cloud-init" # Set to a list of third-party software to enable in rc.conf(5). -export VM_RC_LIST="#cloudinit" +export VM_RC_LIST="cloudinit" From a3e21a00c8108c6ab3b51bc1f6aaa5560cd6f337 Mon Sep 17 00:00:00 2001 From: gjb Date: Mon, 3 Nov 2014 23:47:00 +0000 Subject: [PATCH 011/258] Add line continuation so OPENSTACKCONF is actually included in the env(1). Sponsored by: The FreeBSD Foundation --- release/Makefile.vm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/Makefile.vm b/release/Makefile.vm index 0ef7fc8ef2e7..db3ac541654d 100644 --- a/release/Makefile.vm +++ b/release/Makefile.vm @@ -71,7 +71,7 @@ vm-azure: vm-openstack: .if exists(${.CURDIR}/${TARGET}/mk-openstack.sh) env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ - OPENSTACKCONF=${OPENSTACKCONF} + OPENSTACKCONF=${OPENSTACKCONF} \ OPENSTACK_FORMAT=${OPENSTACK_FORMAT} \ ${.CURDIR}/${TARGET}/mk-openstack.sh ${.TARGET} openstack.img \ ${WORLDDIR} ${.TARGET} ${VMSIZE} ${OPENSTACKIMAGE} From 7e4ec2d94365d65fc6f0b5d61588109f352a7012 Mon Sep 17 00:00:00 2001 From: gjb Date: Mon, 3 Nov 2014 23:59:53 +0000 Subject: [PATCH 012/258] Add a 'vm-cloudware' target, used to drive all targets in CLOUDTARGETS. Sponsored by: The FreeBSD Foundation --- release/Makefile.vm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/release/Makefile.vm b/release/Makefile.vm index db3ac541654d..73042f72bf23 100644 --- a/release/Makefile.vm +++ b/release/Makefile.vm @@ -59,6 +59,8 @@ vm-image: vm-base .endif touch ${.TARGET} +vm-cloudware: ${CLOUDTARGETS} + vm-azure: .if exists(${.CURDIR}/${TARGET}/mk-azure.sh) env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} AZURECONF=${AZURECONF} \ From 47dc31278a9555f9cf19e395d87a0950344ea008 Mon Sep 17 00:00:00 2001 From: gjb Date: Tue, 4 Nov 2014 00:02:23 +0000 Subject: [PATCH 013/258] Add examples for WITH_CLOUDWARE to release.conf.sample. Add WITH_CLOUDWARE evaluation to RELEASE_RMAKEFLAGS. Sponsored by: The FreeBSD Foundation --- release/release.conf.sample | 8 ++++++++ release/release.sh | 7 ++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/release/release.conf.sample b/release/release.conf.sample index c79ed9f87003..f6cfadc6c85c 100644 --- a/release/release.conf.sample +++ b/release/release.conf.sample @@ -98,3 +98,11 @@ PORTBRANCH="ports/head@rHEAD" ## image formats to create. Valid values are listed in the mkimg(1) ## manual page, as well as 'mkimg --formats' output. #VMFORMATS="vhdf vmdk qcow2 raw" + +## Set to a non-empty value to build virtual machine images for various +## cloud providers as part of the release build. +#WITH_CLOUDWARE= + +## If WITH_CLOUDWARE is set to a non-empty value, this is a list of providers +## to create disk images. +#CLOUDWARE="AZURE OPENSTACK" diff --git a/release/release.sh b/release/release.sh index 87b36974070a..616ae96df7ae 100755 --- a/release/release.sh +++ b/release/release.sh @@ -94,6 +94,10 @@ WITH_COMPRESSED_IMAGES= WITH_VMIMAGES= WITH_COMPRESSED_VMIMAGES= +# Set to non-empty value to build virtual machine images for various +# cloud providers as part of the release. +WITH_CLOUDWARE= + usage() { echo "Usage: $0 [-c release.conf]" exit 1 @@ -174,7 +178,8 @@ CHROOT_DMAKEFLAGS="${CONF_FILES}" RELEASE_WMAKEFLAGS="${MAKE_FLAGS} ${WORLD_FLAGS} ${ARCH_FLAGS} ${CONF_FILES}" RELEASE_KMAKEFLAGS="${MAKE_FLAGS} ${KERNEL_FLAGS} KERNCONF=\"${KERNEL}\" ${ARCH_FLAGS} ${CONF_FILES}" RELEASE_RMAKEFLAGS="${ARCH_FLAGS} KERNCONF=\"${KERNEL}\" ${CONF_FILES} \ - ${DOCPORTS} WITH_DVD=${WITH_DVD} WITH_VMIMAGES=${WITH_VMIMAGES}" + ${DOCPORTS} WITH_DVD=${WITH_DVD} WITH_VMIMAGES=${WITH_VMIMAGES} \ + WITH_CLOUDWARE=${WITH_CLOUDWARE}" # Force src checkout if configured FORCE_SRC_KEY= From b70ef7c982f0509a990aca256050a1d5ef721431 Mon Sep 17 00:00:00 2001 From: gjb Date: Wed, 5 Nov 2014 13:22:19 +0000 Subject: [PATCH 014/258] Initial rewrite to consolidate VM image build scripts into one. There may be some very sharp edges here while refactoring. - Move amd64/mk-vmimage.sh -> scripts/mk-vmimage.sh. - Remove vm-base target from Makefile.vm. - In vm-image target, use getopts flags for argument passing. - Create tools/vmimage.subr, containing default and prototype for the following functions that are used to drive the build, run in this order: vm_install_base() vm_extra_install_base() vm_extra_install_packages() vm_extra_install_ports() vm_extra_enable_services() vm_extra_pre_umount() vm_create_disk() vm_extra_create_disk() - In tools/azure.conf, override: vm_extra_install_base() vm_extra_pre_umount() vm_extra_create_disk() - In tools/openstack.conf, override: vm_extra_install_base() vm_extra_pre_umount() Sponsored by: The FreeBSD Foundation --- release/Makefile.vm | 41 ++++--- release/amd64/mk-openstack.sh | 153 -------------------------- release/amd64/mk-vmimage.sh | 197 ---------------------------------- release/i386/mk-azure.sh | 173 ----------------------------- release/i386/mk-openstack.sh | 153 -------------------------- release/i386/mk-vmimage.sh | 197 ---------------------------------- release/scripts/mk-vmimage.sh | 102 ++++++++++++++++++ release/tools/azure.conf | 37 +++++++ release/tools/openstack.conf | 16 +++ release/tools/vmimage.subr | 150 ++++++++++++++++++++++++++ 10 files changed, 323 insertions(+), 896 deletions(-) delete mode 100755 release/amd64/mk-openstack.sh delete mode 100755 release/amd64/mk-vmimage.sh delete mode 100755 release/i386/mk-azure.sh delete mode 100755 release/i386/mk-openstack.sh delete mode 100755 release/i386/mk-vmimage.sh create mode 100755 release/scripts/mk-vmimage.sh create mode 100644 release/tools/vmimage.subr diff --git a/release/Makefile.vm b/release/Makefile.vm index 73042f72bf23..c37a4ad759d6 100644 --- a/release/Makefile.vm +++ b/release/Makefile.vm @@ -5,7 +5,7 @@ # Makefile for building virtual machine and cloud provider disk images. # -VMTARGETS= vm-base vm-image +VMTARGETS= vm-image VMFORMATS?= vhd vmdk qcow2 raw VMSIZE?= 20G VMBASE?= vm @@ -37,23 +37,17 @@ CLEANFILES+= ${VMBASE}.${FORMAT} . endfor .endif -vm-base: -.if defined(WITH_VMIMAGES) && !empty(WITH_VMIMAGES) -. if exists(${.CURDIR}/${TARGET}/mk-vmimage.sh) - env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ - ${.CURDIR}/${TARGET}/mk-vmimage.sh ${.TARGET} \ - ${VMBASE}.img ${WORLDDIR} ${.OBJDIR}/${.TARGET} ${VMSIZE} -. endif -.endif - touch ${.TARGET} +vm-base: vm-image -vm-image: vm-base +vm-image: .if defined(WITH_VMIMAGES) && !empty(WITH_VMIMAGES) . if exists(${.CURDIR}/${TARGET}/mk-vmimage.sh) . for FORMAT in ${VMFORMATS} env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ - ${.CURDIR}/${TARGET}/mk-vmimage.sh ${.TARGET} \ - ${VMBASE}.img ${FORMAT} ${VMBASE}.${FORMAT} + ${.CURDIR}/${TARGET}/mk-vmimage.sh \ + -C ${.CURDIR}/tools/vmimage.subr -d ${.TARGET} \ + -i ${VMBASE}.img -s ${VMSIZE} -f ${FORMAT} \ + -S ${WORLDDIR} -o ${VMBASE}.${FORMAT} . endfor . endif .endif @@ -62,20 +56,21 @@ vm-image: vm-base vm-cloudware: ${CLOUDTARGETS} vm-azure: -.if exists(${.CURDIR}/${TARGET}/mk-azure.sh) - env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} AZURECONF=${AZURECONF} \ - AZURE_FORMAT=${AZURE_FORMAT} \ - ${.CURDIR}/${TARGET}/mk-azure.sh ${.TARGET} azure.img \ - ${WORLDDIR} ${.TARGET} ${VMSIZE} ${AZUREIMAGE} +.if exists(${.CURDIR}/${TARGET}/mk-vmimage.sh) + env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ + ${.CURDIR}/${TARGET}/mk-vmimage.sh \ + -C ${.CURDIR}/tools/vmimage.subr -d ${.TARGET} \ + -i azure.img -s ${VMSIZE} -f ${AZURE_FORMAT} \ + -S ${WORLDDIR} -o ${AZUREIMAGE} -c ${AZURECONF} .endif touch ${.TARGET} vm-openstack: -.if exists(${.CURDIR}/${TARGET}/mk-openstack.sh) +.if exists(${.CURDIR}/${TARGET}/mk-vmimage.sh) env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ - OPENSTACKCONF=${OPENSTACKCONF} \ - OPENSTACK_FORMAT=${OPENSTACK_FORMAT} \ - ${.CURDIR}/${TARGET}/mk-openstack.sh ${.TARGET} openstack.img \ - ${WORLDDIR} ${.TARGET} ${VMSIZE} ${OPENSTACKIMAGE} + ${.CURDIR}/${TARGET}/mk-vmimage.sh \ + -C ${.CURDIR}/tools/vmimage.subr -d ${.TARGET} \ + -i openstack.img -s ${VMSIZE} -f ${OPENSTACK_FORMAT} \ + -S ${WORLDDIR} -o ${OPENSTACKIMAGE} -c ${OPENSTACKCONF} .endif touch ${.TARGET} diff --git a/release/amd64/mk-openstack.sh b/release/amd64/mk-openstack.sh deleted file mode 100755 index 863860b520e4..000000000000 --- a/release/amd64/mk-openstack.sh +++ /dev/null @@ -1,153 +0,0 @@ -#!/bin/sh -#- -# Copyright (c) 2014 The FreeBSD Foundation -# All rights reserved. -# -# This software was developed by Glen Barber 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. -# -# mk-openstack.sh: Create virtual machine disk images for Openstack -# -# $FreeBSD$ -# - -export PATH="/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin" - -usage() { - echo "Usage:" - echo -n "$(basename ${0}) vm-openstack " - echo " " - exit 1 -} - -panic() { - msg="${@}" - printf "${msg}\n" - if [ ! -z "${mddev}" ]; then - mdconfig -d -u ${mddev} - fi - # Do not allow one failure case to chain through any remaining image - # builds. - exit 0 -} - -vm_create_openstack() { - # Arguments: - # vm-openstack - # - - VMBASE="${1}" - WORLDDIR="${2}" - DESTDIR="${3}" - VMSIZE="${4}" - VMIMAGE="${5}" - - if [ -z "${VMBASE}" -o -z "${WORLDDIR}" -o -z "${DESTDIR}" \ - -o -z "${VMSIZE}" -o -z "${VMIMAGE}" ]; then - usage - fi - - trap "umount ${DESTDIR}/dev ${DESTDIR}" INT QUIT TRAP ABRT TERM - - i=0 - mkdir -p ${DESTDIR} - truncate -s ${VMSIZE} ${VMBASE} - mddev=$(mdconfig -f ${VMBASE}) - newfs -j /dev/${mddev} - mkdir -p ${DESTDIR} - mount /dev/${mddev} ${DESTDIR} - make -C ${WORLDDIR} DESTDIR=$(realpath ${DESTDIR}) \ - installworld installkernel distribution || \ - panic "\n\nCannot install the base system to ${DESTDIR}." - mount -t devfs devfs ${DESTDIR}/dev - chroot ${DESTDIR} /usr/bin/newaliases - echo '# Custom /etc/fstab for FreeBSD VM images' \ - > ${DESTDIR}/etc/fstab - echo '/dev/gpt/rootfs / ufs rw 2 2' \ - >> ${DESTDIR}/etc/fstab - echo '/dev/gpt/swapfs none swap sw 0 0' \ - >> ${DESTDIR}/etc/fstab - - chroot ${DESTDIR} /etc/rc.d/ldconfig forcestart - chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes /usr/sbin/pkg bootstrap -y - if [ ! -z "${VM_EXTRA_PACKAGES}" ]; then - chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes /usr/sbin/pkg install -y \ - ${VM_EXTRA_PACKAGES} - fi - - rm -f ${DESTDIR}/etc/resolv.conf - echo 'sshd_enable="YES"' > ${DESTDIR}/etc/rc.conf - echo 'ifconfig_DEFAULT="SYNCDHCP"' >> ${DESTDIR}/etc/rc.conf - - if [ ! -z "${VM_RC_LIST}" ]; then - for _rcvar in ${VM_RC_LIST}; do - echo ${_rcvar}_enable="YES" >> ${DESTDIR}/etc/rc.conf - done - fi - - sync - - while ! umount ${DESTDIR}/dev ${DESTDIR}; do - i=$(( $i + 1 )) - if [ $i -ge 10 ]; then - # This should never happen. But, it has happened. - msg="Cannot umount(8) ${DESTDIR}\n" - msg="${msg}Something has gone horribly wrong." - panic "${msg}" - fi - sleep 1 - done - - echo "Creating image... Please wait." - - mkimg -f ${OPENSTACK_FORMAT} -s gpt \ - -b /boot/pmbr -p freebsd-boot/bootfs:=/boot/gptboot \ - -p freebsd-swap/swapfs::1G \ - -p freebsd-ufs/rootfs:=${VMBASE} \ - -o ${VMIMAGE} - - return 0 -} - -main() { - cmd="${1}" - shift 1 - - if [ -e "${OPENSTACKCONF}" -a ! -c "${OPENSTACKCONF}" ]; then - . ${OPENSTACKCONF} - fi - - case ${cmd} in - vm-openstack) - eval vm_create_openstack "$@" || return 0 - ;; - *|\?) - usage - ;; - esac - - return 0 -} - -main "$@" diff --git a/release/amd64/mk-vmimage.sh b/release/amd64/mk-vmimage.sh deleted file mode 100755 index b3ffd232f848..000000000000 --- a/release/amd64/mk-vmimage.sh +++ /dev/null @@ -1,197 +0,0 @@ -#!/bin/sh -#- -# Copyright (c) 2014 The FreeBSD Foundation -# All rights reserved. -# -# This software was developed by Glen Barber 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. -# -# mk-vmimage.sh: Create virtual machine disk images in various formats. -# -# $FreeBSD$ -# - -PATH="/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin" -export PATH - -usage_vm_base() { - echo -n "$(basename ${0}) vm-base " - echo " " - return 0 -} - -usage_vm_image() { - echo -n "$(basename ${0}) vm-image " - echo " " - return 0 -} - -usage() { - echo "Usage:" - echo "$(basename ${0}) [vm-base|vm-image] [...]" - echo - usage_vm_base - echo - usage_vm_image - exit 1 -} - -panic() { - msg="${@}" - printf "${msg}\n" - if [ ! -z "${mddev}" ]; then - mdconfig -d -u ${mddev} - fi - case ${cmd} in - vm-base) - # If the vm-base target fails, the vm-image target - # cannot possibly succeed. Touch the .TARGET file - # so it is not attempted. - touch vm-image - ;; - *) - # FALLTHROUGH - ;; - esac - # Do not allow one failure case to chain through any remaining image - # builds. - return 1 -} - -vm_create_baseimage() { - # Creates the UFS root filesystem for the virtual machine disk, - # written to the formatted disk image with mkimg(1). - # - # Arguments: - # vm-base - - VMBASE="${1}" - WORLDDIR="${2}" - DESTDIR="${3}" - VMSIZE="${4}" - - if [ -z "${VMBASE}" -o -z "${WORLDDIR}" -o -z "${DESTDIR}" \ - -o -z "${VMSIZE}" ]; then - usage - fi - - i=0 - mkdir -p ${DESTDIR} - truncate -s ${VMSIZE} ${VMBASE} - mddev=$(mdconfig -f ${VMBASE}) - newfs -j /dev/${mddev} - mount /dev/${mddev} ${DESTDIR} - cd ${WORLDDIR} && \ - make DESTDIR=${DESTDIR} \ - installworld installkernel distribution || \ - panic "\n\nCannot install the base system to ${DESTDIR}." - chroot ${DESTDIR} /usr/bin/newaliases - echo '# Custom /etc/fstab for FreeBSD VM images' \ - > ${DESTDIR}/etc/fstab - echo '/dev/gpt/rootfs / ufs rw 2 2' \ - >> ${DESTDIR}/etc/fstab - echo '/dev/gpt/swapfs none swap sw 0 0' \ - >> ${DESTDIR}/etc/fstab - sync - while ! umount ${DESTDIR}; do - i=$(( $i + 1 )) - if [ $i -ge 10 ]; then - # This should never happen. But, it has happened. - msg="Cannot umount(8) ${DESTDIR}\n" - msg="${msg}Something has gone horribly wrong." - panic "${msg}" - fi - sleep 1 - done - - return 0 -} - -vm_create_vmdisk() { - # Creates the virtual machine disk image from the raw disk image. - # - # Arguments: - # vm-image " - - VMBASE="${1}" - FORMAT="${2}" - VMIMAGE="${3}" - - if [ -z "${VMBASE}" -o -z "${FORMAT}" -o -z "${VMIMAGE}" ]; then - usage - fi - - mkimg_version=$(mkimg --version 2>/dev/null | awk '{print $2}') - - # We need mkimg(1) '--version' output, at minimum, to be able to - # tell what virtual machine disk image formats are available. - # Bail if mkimg(1) reports an empty '--version' value. - if [ -z "${mkimg_version}" ]; then - msg="Cannot determine mkimg(1) version.\n" - msg="${msg}Cannot continue without a known mkimg(1) version." - panic "${msg}" - fi - - if ! mkimg --formats 2>/dev/null | grep -q ${FORMAT}; then - panic "'${FORMAT}' is not supported by this mkimg(1).\n" - fi - - case ${FORMAT} in - vhd) - mkimg_format=vhdf - ;; - *) - mkimg_format=${FORMAT} - ;; - esac - - mkimg -f ${mkimg_format} -s gpt \ - -b /boot/pmbr -p freebsd-boot/bootfs:=/boot/gptboot \ - -p freebsd-swap/swapfs::1G \ - -p freebsd-ufs/rootfs:=${VMBASE} \ - -o ${VMIMAGE} - - return 0 -} - -main() { - cmd="${1}" - shift 1 - - case ${cmd} in - vm-base) - eval vm_create_baseimage "$@" || return 0 - ;; - vm-image) - eval vm_create_vmdisk "$@" || return 0 - ;; - *|\?) - usage - ;; - esac - - return 0 -} - -main "$@" diff --git a/release/i386/mk-azure.sh b/release/i386/mk-azure.sh deleted file mode 100755 index ac89258996f4..000000000000 --- a/release/i386/mk-azure.sh +++ /dev/null @@ -1,173 +0,0 @@ -#!/bin/sh -#- -# Copyright (c) 2014 The FreeBSD Foundation -# All rights reserved. -# -# This software was developed by Glen Barber 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. -# -# mk-azure.sh: Create virtual machine disk images for Microsoft Azure -# -# $FreeBSD$ -# - -export PATH="/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin" - -usage() { - echo "Usage:" - echo -n "$(basename ${0}) vm-azure " - echo " " - exit 1 -} - -panic() { - msg="${@}" - printf "${msg}\n" - if [ ! -z "${mddev}" ]; then - mdconfig -d -u ${mddev} - fi - # Do not allow one failure case to chain through any remaining image - # builds. - exit 0 -} - -vm_create_azure() { - # Arguments: - # vm-azure - - VMBASE="${1}" - WORLDDIR="${2}" - DESTDIR="${3}" - VMSIZE="${4}" - VMIMAGE="${5}" - - if [ -z "${VMBASE}" -o -z "${WORLDDIR}" -o -z "${DESTDIR}" \ - -o -z "${VMSIZE}" -o -z "${VMIMAGE}" ]; then - usage - fi - - trap "umount ${DESTDIR}/dev ${DESTDIR}" INT QUIT TRAP ABRT TERM - - i=0 - mkdir -p ${DESTDIR} - truncate -s ${VMSIZE} ${VMBASE} - mddev=$(mdconfig -f ${VMBASE}) - newfs -j /dev/${mddev} - mkdir -p ${DESTDIR} - mount /dev/${mddev} ${DESTDIR} - make -C ${WORLDDIR} DESTDIR=$(realpath ${DESTDIR}) \ - installworld installkernel distribution || \ - panic "\n\nCannot install the base system to ${DESTDIR}." - mount -t devfs devfs ${DESTDIR}/dev - chroot ${DESTDIR} /usr/bin/newaliases - echo '# Custom /etc/fstab for FreeBSD VM images' \ - > ${DESTDIR}/etc/fstab - echo '/dev/gpt/rootfs / ufs rw 2 2' \ - >> ${DESTDIR}/etc/fstab - # Although a swap partition is created, it is not used in Azure. - echo '#/dev/gpt/swapfs none swap sw 0 0' \ - >> ${DESTDIR}/etc/fstab - - chroot ${DESTDIR} /etc/rc.d/ldconfig forcestart - chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes /usr/sbin/pkg bootstrap -y - chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes /usr/sbin/pkg install -y \ - python python2 python27 py27-asn1 sudo bash - if [ ! -z "${VM_EXTRA_PACKAGES}" ]; then - chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes /usr/sbin/pkg install -y \ - ${VM_EXTRA_PACKAGES} - fi - - fetch -o ${DESTDIR}/usr/sbin/waagent \ - http://people.freebsd.org/~gjb/waagent - chmod +x ${DESTDIR}/usr/sbin/waagent - rm -f ${DESTDIR}/etc/resolv.conf - chroot ${DESTDIR} /usr/sbin/waagent -verbose -install - yes | chroot ${DESTDIR} /usr/sbin/waagent -deprovision - echo 'sshd_enable="YES"' > ${DESTDIR}/etc/rc.conf - echo 'ifconfig_hn0="SYNCDHCP"' >> ${DESTDIR}/etc/rc.conf - echo 'waagent_enable="YES"' >> ${DESTDIR}/etc/rc.conf - - echo 'console="comconsole vidconsole"' >> ${DESTDIR}/boot/loader.conf - echo 'comconsole_speed="115200"' >> ${DESTDIR}/boot/loader.conf - - if [ ! -z "${VM_RC_LIST}" ]; then - for _rcvar in ${VM_RC_LIST}; do - echo ${_rcvar}_enable="YES" >> ${DESTDIR}/etc/rc.conf - done - fi - - sync - - while ! umount ${DESTDIR}/dev ${DESTDIR}; do - i=$(( $i + 1 )) - if [ $i -ge 10 ]; then - # This should never happen. But, it has happened. - msg="Cannot umount(8) ${DESTDIR}\n" - msg="${msg}Something has gone horribly wrong." - panic "${msg}" - fi - sleep 1 - done - - echo "Creating image... Please wait." - - mkimg -f ${AZURE_FORMAT} -s gpt \ - -b /boot/pmbr -p freebsd-boot/bootfs:=/boot/gptboot \ - -p freebsd-swap/swapfs::1G \ - -p freebsd-ufs/rootfs:=${VMBASE} \ - -o ${VMIMAGE}.raw - - if [ ! -x "/usr/local/bin/qemu-img" ]; then - env ASSUME_ALWAYS_YES=yes pkg install -y emulators/qemu-devel - fi - - size=$(qemu-img info -f raw --output json ${VMIMAGE}.raw | awk '/virtual-size/ {print $2}' | tr -d ',') - size=$(( ( ${size} / ( 1024 * 1024 ) + 1 ) * ( 1024 * 1024 ) )) - qemu-img resize ${VMIMAGE}.raw ${size} - qemu-img convert -f raw -o subformat=fixed -O vpc ${VMIMAGE}.raw ${VMIMAGE} - - return 0 -} - -main() { - cmd="${1}" - shift 1 - - if [ -e "${AZURECONF}" -a ! -c "${AZURECONF}" ]; then - . ${AZURECONF} - fi - - case ${cmd} in - vm-azure) - eval vm_create_azure "$@" || return 0 - ;; - *|\?) - usage - ;; - esac - - return 0 -} - -main "$@" diff --git a/release/i386/mk-openstack.sh b/release/i386/mk-openstack.sh deleted file mode 100755 index 863860b520e4..000000000000 --- a/release/i386/mk-openstack.sh +++ /dev/null @@ -1,153 +0,0 @@ -#!/bin/sh -#- -# Copyright (c) 2014 The FreeBSD Foundation -# All rights reserved. -# -# This software was developed by Glen Barber 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. -# -# mk-openstack.sh: Create virtual machine disk images for Openstack -# -# $FreeBSD$ -# - -export PATH="/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin" - -usage() { - echo "Usage:" - echo -n "$(basename ${0}) vm-openstack " - echo " " - exit 1 -} - -panic() { - msg="${@}" - printf "${msg}\n" - if [ ! -z "${mddev}" ]; then - mdconfig -d -u ${mddev} - fi - # Do not allow one failure case to chain through any remaining image - # builds. - exit 0 -} - -vm_create_openstack() { - # Arguments: - # vm-openstack - # - - VMBASE="${1}" - WORLDDIR="${2}" - DESTDIR="${3}" - VMSIZE="${4}" - VMIMAGE="${5}" - - if [ -z "${VMBASE}" -o -z "${WORLDDIR}" -o -z "${DESTDIR}" \ - -o -z "${VMSIZE}" -o -z "${VMIMAGE}" ]; then - usage - fi - - trap "umount ${DESTDIR}/dev ${DESTDIR}" INT QUIT TRAP ABRT TERM - - i=0 - mkdir -p ${DESTDIR} - truncate -s ${VMSIZE} ${VMBASE} - mddev=$(mdconfig -f ${VMBASE}) - newfs -j /dev/${mddev} - mkdir -p ${DESTDIR} - mount /dev/${mddev} ${DESTDIR} - make -C ${WORLDDIR} DESTDIR=$(realpath ${DESTDIR}) \ - installworld installkernel distribution || \ - panic "\n\nCannot install the base system to ${DESTDIR}." - mount -t devfs devfs ${DESTDIR}/dev - chroot ${DESTDIR} /usr/bin/newaliases - echo '# Custom /etc/fstab for FreeBSD VM images' \ - > ${DESTDIR}/etc/fstab - echo '/dev/gpt/rootfs / ufs rw 2 2' \ - >> ${DESTDIR}/etc/fstab - echo '/dev/gpt/swapfs none swap sw 0 0' \ - >> ${DESTDIR}/etc/fstab - - chroot ${DESTDIR} /etc/rc.d/ldconfig forcestart - chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes /usr/sbin/pkg bootstrap -y - if [ ! -z "${VM_EXTRA_PACKAGES}" ]; then - chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes /usr/sbin/pkg install -y \ - ${VM_EXTRA_PACKAGES} - fi - - rm -f ${DESTDIR}/etc/resolv.conf - echo 'sshd_enable="YES"' > ${DESTDIR}/etc/rc.conf - echo 'ifconfig_DEFAULT="SYNCDHCP"' >> ${DESTDIR}/etc/rc.conf - - if [ ! -z "${VM_RC_LIST}" ]; then - for _rcvar in ${VM_RC_LIST}; do - echo ${_rcvar}_enable="YES" >> ${DESTDIR}/etc/rc.conf - done - fi - - sync - - while ! umount ${DESTDIR}/dev ${DESTDIR}; do - i=$(( $i + 1 )) - if [ $i -ge 10 ]; then - # This should never happen. But, it has happened. - msg="Cannot umount(8) ${DESTDIR}\n" - msg="${msg}Something has gone horribly wrong." - panic "${msg}" - fi - sleep 1 - done - - echo "Creating image... Please wait." - - mkimg -f ${OPENSTACK_FORMAT} -s gpt \ - -b /boot/pmbr -p freebsd-boot/bootfs:=/boot/gptboot \ - -p freebsd-swap/swapfs::1G \ - -p freebsd-ufs/rootfs:=${VMBASE} \ - -o ${VMIMAGE} - - return 0 -} - -main() { - cmd="${1}" - shift 1 - - if [ -e "${OPENSTACKCONF}" -a ! -c "${OPENSTACKCONF}" ]; then - . ${OPENSTACKCONF} - fi - - case ${cmd} in - vm-openstack) - eval vm_create_openstack "$@" || return 0 - ;; - *|\?) - usage - ;; - esac - - return 0 -} - -main "$@" diff --git a/release/i386/mk-vmimage.sh b/release/i386/mk-vmimage.sh deleted file mode 100755 index b3ffd232f848..000000000000 --- a/release/i386/mk-vmimage.sh +++ /dev/null @@ -1,197 +0,0 @@ -#!/bin/sh -#- -# Copyright (c) 2014 The FreeBSD Foundation -# All rights reserved. -# -# This software was developed by Glen Barber 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. -# -# mk-vmimage.sh: Create virtual machine disk images in various formats. -# -# $FreeBSD$ -# - -PATH="/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin" -export PATH - -usage_vm_base() { - echo -n "$(basename ${0}) vm-base " - echo " " - return 0 -} - -usage_vm_image() { - echo -n "$(basename ${0}) vm-image " - echo " " - return 0 -} - -usage() { - echo "Usage:" - echo "$(basename ${0}) [vm-base|vm-image] [...]" - echo - usage_vm_base - echo - usage_vm_image - exit 1 -} - -panic() { - msg="${@}" - printf "${msg}\n" - if [ ! -z "${mddev}" ]; then - mdconfig -d -u ${mddev} - fi - case ${cmd} in - vm-base) - # If the vm-base target fails, the vm-image target - # cannot possibly succeed. Touch the .TARGET file - # so it is not attempted. - touch vm-image - ;; - *) - # FALLTHROUGH - ;; - esac - # Do not allow one failure case to chain through any remaining image - # builds. - return 1 -} - -vm_create_baseimage() { - # Creates the UFS root filesystem for the virtual machine disk, - # written to the formatted disk image with mkimg(1). - # - # Arguments: - # vm-base - - VMBASE="${1}" - WORLDDIR="${2}" - DESTDIR="${3}" - VMSIZE="${4}" - - if [ -z "${VMBASE}" -o -z "${WORLDDIR}" -o -z "${DESTDIR}" \ - -o -z "${VMSIZE}" ]; then - usage - fi - - i=0 - mkdir -p ${DESTDIR} - truncate -s ${VMSIZE} ${VMBASE} - mddev=$(mdconfig -f ${VMBASE}) - newfs -j /dev/${mddev} - mount /dev/${mddev} ${DESTDIR} - cd ${WORLDDIR} && \ - make DESTDIR=${DESTDIR} \ - installworld installkernel distribution || \ - panic "\n\nCannot install the base system to ${DESTDIR}." - chroot ${DESTDIR} /usr/bin/newaliases - echo '# Custom /etc/fstab for FreeBSD VM images' \ - > ${DESTDIR}/etc/fstab - echo '/dev/gpt/rootfs / ufs rw 2 2' \ - >> ${DESTDIR}/etc/fstab - echo '/dev/gpt/swapfs none swap sw 0 0' \ - >> ${DESTDIR}/etc/fstab - sync - while ! umount ${DESTDIR}; do - i=$(( $i + 1 )) - if [ $i -ge 10 ]; then - # This should never happen. But, it has happened. - msg="Cannot umount(8) ${DESTDIR}\n" - msg="${msg}Something has gone horribly wrong." - panic "${msg}" - fi - sleep 1 - done - - return 0 -} - -vm_create_vmdisk() { - # Creates the virtual machine disk image from the raw disk image. - # - # Arguments: - # vm-image " - - VMBASE="${1}" - FORMAT="${2}" - VMIMAGE="${3}" - - if [ -z "${VMBASE}" -o -z "${FORMAT}" -o -z "${VMIMAGE}" ]; then - usage - fi - - mkimg_version=$(mkimg --version 2>/dev/null | awk '{print $2}') - - # We need mkimg(1) '--version' output, at minimum, to be able to - # tell what virtual machine disk image formats are available. - # Bail if mkimg(1) reports an empty '--version' value. - if [ -z "${mkimg_version}" ]; then - msg="Cannot determine mkimg(1) version.\n" - msg="${msg}Cannot continue without a known mkimg(1) version." - panic "${msg}" - fi - - if ! mkimg --formats 2>/dev/null | grep -q ${FORMAT}; then - panic "'${FORMAT}' is not supported by this mkimg(1).\n" - fi - - case ${FORMAT} in - vhd) - mkimg_format=vhdf - ;; - *) - mkimg_format=${FORMAT} - ;; - esac - - mkimg -f ${mkimg_format} -s gpt \ - -b /boot/pmbr -p freebsd-boot/bootfs:=/boot/gptboot \ - -p freebsd-swap/swapfs::1G \ - -p freebsd-ufs/rootfs:=${VMBASE} \ - -o ${VMIMAGE} - - return 0 -} - -main() { - cmd="${1}" - shift 1 - - case ${cmd} in - vm-base) - eval vm_create_baseimage "$@" || return 0 - ;; - vm-image) - eval vm_create_vmdisk "$@" || return 0 - ;; - *|\?) - usage - ;; - esac - - return 0 -} - -main "$@" diff --git a/release/scripts/mk-vmimage.sh b/release/scripts/mk-vmimage.sh new file mode 100755 index 000000000000..b5065b66ab2d --- /dev/null +++ b/release/scripts/mk-vmimage.sh @@ -0,0 +1,102 @@ +#!/bin/sh +#- +# Copyright (c) 2014 The FreeBSD Foundation +# All rights reserved. +# +# This software was developed by Glen Barber 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. +# +# mk-vmimage.sh: Create virtual machine disk images in various formats. +# +# $FreeBSD$ +# + +main() { + local arg + while getopts "C:c:d:f:i:o:s:S:" arg; do + case "${arg}" in + C) + VMBUILDCONF="${OPTARG}" + ;; + c) + VMCONFIG="${OPTARG}" + ;; + d) + DESTDIR="${OPTARG}" + ;; + f) + VMFORMAT="${OPTARG}" + ;; + i) + VMBASE="${VMBASE}" + ;; + o) + VMIMAGE="${OPTARG}" + ;; + s) + VMSIZE="${OPTARG}" + ;; + S) + WORLDDIR="${OPTARG}" + ;; + *) + ;; + esac + done + shift $(( ${OPTIND} - 1)) + + if [ -z "${VMBASE}" -o \ + -z "${WORLDDIR}" -o \ + -z "${DESTDIR}" -o \ + -z "${VMSIZE}" -o \ + -z "${VMIMAGE}" -o \ + -z "${VMCONFIG}" ]; + then + usage + fi + + if [ -z "${VMBUILDCONF}" ] || [ ! -e "${VMBUILDCONF}" ]; then + echo "Must provide the path to vmimage.subr." + return 1 + fi + + . "${VMBUILDCONF}" + + if [ ! -z "${VMCONFIG}" ] && [ -e "${VMCONFIG}" ]; then + . "${VMCONFIG}" + fi + + vm_install_base + vm_extra_install_base + vm_extra_install_packages + vm_extra_install_ports + vm_extra_enable_services + vm_extra_pre_umount + vm_create_disk + vm_extra_create_disk + + return 0 +} + +main "$@" diff --git a/release/tools/azure.conf b/release/tools/azure.conf index 8f16acc0d279..16c207da3240 100644 --- a/release/tools/azure.conf +++ b/release/tools/azure.conf @@ -12,3 +12,40 @@ export VM_EXTRA_PACKAGES= # Example: #export VM_RC_LIST="apache24" export VM_RC_LIST= + +vm_extra_install_base() { + fetch -o ${DESTDIR}/usr/sbin/waagent \ + http://people.freebsd.org/~gjb/waagent + chmod +x ${DESTDIR}/usr/sbin/waagent + rm -f ${DESTDIR}/etc/resolv.conf + + return 0 +} + +vm_extra_pre_umount() { + chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes /usr/sbin/pkg install -y \ + python python2 python27 py27-asn1 sudo bash + chroot ${DESTDIR} /usr/sbin/waagent -verbose -install + yes | chroot ${DESTDIR} /usr/sbin/waagent -deprovision + echo 'sshd_enable="YES"' >> ${DESTDIR}/etc/rc.conf + echo 'ifconfig_hn0="SYNCDHCP"' >> ${DESTDIR}/etc/rc.conf + echo 'waagent_enable="YES"' >> ${DESTDIR}/etc/rc.conf + echo 'console="comconsole vidconsole"' >> ${DESTDIR}/boot/loader.conf + echo 'comconsole_speed="115200"' >> ${DESTDIR}/boot/loader.conf + + return 0 +} + +vm_extra_create_disk() { + if [ ! -x "/usr/local/bin/qemu-img" ]; then + env ASSUME_ALWAYS_YES=yes pkg install -y emulators/qemu-devel + fi + + mv ${VMIMAGE} ${VMIMAGE}.raw + size=$(qemu-img info -f raw --output json ${VMIMAGE}.raw | awk '/virtual-size/ {print $2}' | tr -d ',') + size=$(( ( ${size} / ( 1024 * 1024 ) + 1 ) * ( 1024 * 1024 ) )) + qemu-img resize ${VMIMAGE}.raw ${size} + qemu-img convert -f raw -o subformat=fixed -O vpc ${VMIMAGE}.raw ${VMIMAGE} + + return 0 +} diff --git a/release/tools/openstack.conf b/release/tools/openstack.conf index b43ad76b6da2..6aa17493f974 100644 --- a/release/tools/openstack.conf +++ b/release/tools/openstack.conf @@ -8,3 +8,19 @@ export VM_EXTRA_PACKAGES="net/cloud-init" # Set to a list of third-party software to enable in rc.conf(5). export VM_RC_LIST="cloudinit" + +vm_extra_install_base() { + fetch -o ${DESTDIR}/usr/sbin/waagent \ + http://people.freebsd.org/~gjb/waagent + chmod +x ${DESTDIR}/usr/sbin/waagent + rm -f ${DESTDIR}/etc/resolv.conf + + return 0 +} + +vm_extra_pre_umount() { + echo 'sshd_enable="YES"' >> ${DESTDIR}/etc/rc.conf + echo 'ifconfig_DEFAULT="SYNCDHCP"' >> ${DESTDIR}/etc/rc.conf + + return 0 +} diff --git a/release/tools/vmimage.subr b/release/tools/vmimage.subr new file mode 100644 index 000000000000..622e0fc967ec --- /dev/null +++ b/release/tools/vmimage.subr @@ -0,0 +1,150 @@ +#!/bin/sh +# +# $FreeBSD$ +# +# +# Common functions for virtual machine image build scripts. +# + +export PATH="/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin" +trap "cleanup" INT QUIT TRAP ABRT TERM + +mkimg_bootcode="/boot/pmbr" +mkimg_partitions="-p freebsd-boot/bootfs:=/boot/gptboot" +mkimg_partitions="${mkimg_partitions} -p freebsd-swap/swapfs::1G" +mkimg_partitions="${mkimg_partitions} freebsd-ufs/rootfs:=${VMBASE}" + +usage() { + echo "${0} usage:" + echo "${@}" + return 1 +} + +err() { + printf "${@}\n" + cleanup + return 1 +} + +cleanup() { + if [ ! -z "${mddev}" ]; then + mdconfig -d -u ${mddev} + fi + umount ${DESTDIR}/dev + umount ${DESTDIR} + + return 0 +} + +vm_create_base() { + # Creates the UFS root filesystem for the virtual machine disk, + # written to the formatted disk image with mkimg(1). + + mkdir -p ${DESTDIR} + truncate -s ${VMSIZE} ${VMBASE} + mddev=$(mdconfig -f ${VMBASE}) + newfs -j /dev/${mddev} + mount /dev/${mddev} ${DESTDIR} + + return 0 +} + +vm_install_base() { + # Installs the FreeBSD userland/kernel to the virtual machine disk. + + cd ${WORLDDIR} && \ + make DESTDIR=${DESTDIR} \ + installworld installkernel distribution || \ + err "\n\nCannot install the base system to ${DESTDIR}." + + echo '# Custom /etc/fstab for FreeBSD VM images' \ + > ${DESTDIR}/etc/fstab + echo '/dev/gpt/rootfs / ufs rw 1 1' \ + >> ${DESTDIR}/etc/fstab + echo '/dev/gpt/swapfs none swap sw 0 0' \ + >> ${DESTDIR}/etc/fstab + + chroot ${DESTDIR} /usr/bin/newaliases + chroot ${DESTDIR} /etc/rc.d/ldconfig forcestart + + return 0 +} + +vm_extra_install_base() { + # Prototype. When overridden, runs extra post-installworld commands + # as needed, based on the target virtual machine image or cloud + # provider image target. + + return 0 +} + +vm_extra_enable_services() { + if [ ! -z "${VM_RC_LIST}" ]; then + for _rcvar in ${VM_RC_LIST}; do + echo ${_rcvar}_enable="YES" >> ${DESTDIR}/etc/rc.conf + done + fi + + return 0 +} + +vm_extra_install_packages() { + chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes \ + /usr/sbin/pkg bootstrap -y + if [ ! -z "${VM_EXTRA_PACKAGES}" ]; then + chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes \ + /usr/sbin/pkg install -y ${VM_EXTRA_PACKAGES} + fi + + return 0 +} + +vm_extra_install_ports() { + # Prototype. When overridden, installs additional ports within the + # virtual machine environment. + + return 0 +} + +vm_umount_base() { + i=0 + sync + while ! umount ${DESTDIR}/dev ${DESTDIR}; do + i=$(( $i + 1 )) + if [ $i -ge 10 ]; then + # This should never happen. But, it has happened. + msg="Cannot umount(8) ${DESTDIR}\n" + msg="${msg}Something has gone horribly wrong." + err "${msg}" + fi + sleep 1 + done + + return 0 +} + +vm_create_disk() { + if [ -z "${mkimg_paritions}" ]; then + err "No partition types specified. Skipping." + return 1 + fi + echo "Creating image... Please wait." + echo + mkimg -f ${mkimg_format} -s ${mkimg_scheme} \ + ${mkimg_bootcode} \ + ${mkimg_partitions} \ + ${mkimg_outfile} + + mkimg -b /boot/pmbr -p freebsd-boot/bootfs:=/boot/gptboot \ + -p freebsd-swap/swapfs::1G \ + -p freebsd-ufs/rootfs:=${VMBASE} \ + -o ${VMIMAGE}.raw + + return 0 +} + +vm_extra_create_disk() { + + return 0 +} + From 922d9bb47089a6a610b6428a2dea00fb7e18b90d Mon Sep 17 00:00:00 2001 From: gjb Date: Fri, 7 Nov 2014 01:48:12 +0000 Subject: [PATCH 015/258] Add write_partition_layout() used to populate the final image. Fix duplicated mkimg(1) call in vm_create_disk(). Add primitive (untested) PowerPC/PowerPC64 VM image support. Note: As it is currently written, the /boot/pmbr and /boot/{gptboot,boot1.hfs} use the build host and not the target build. Fixing this is likely going to be a hack in itself. Sponsored by: The FreeBSD Foundation --- release/tools/vmimage.subr | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/release/tools/vmimage.subr b/release/tools/vmimage.subr index 622e0fc967ec..3cf19ff360ec 100644 --- a/release/tools/vmimage.subr +++ b/release/tools/vmimage.subr @@ -9,10 +9,31 @@ export PATH="/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin" trap "cleanup" INT QUIT TRAP ABRT TERM -mkimg_bootcode="/boot/pmbr" -mkimg_partitions="-p freebsd-boot/bootfs:=/boot/gptboot" -mkimg_partitions="${mkimg_partitions} -p freebsd-swap/swapfs::1G" -mkimg_partitions="${mkimg_partitions} freebsd-ufs/rootfs:=${VMBASE}" +write_partition_layout() { + + case "${TARGET}:${TARGET_ARCH}" in + amd64:amd64 | i386:i386) + mkimg -f gpt -b /boot/pmbr \ + -p freebsd-boot/bootfs:=/boot/gptboot \ + -p freebsd-swap/swapfs::1G \ + -p freebsd-ufs/rootfs:=${VMBASE} + -o ${VMIMAGE} + ;; + powerpc:powerpc*) + mkimg -f apm \ + -p freebsd-boot/bootfs:=/boot/boot1.hfs \ + -p freebsd-swap/swapfs::1G \ + -p freebsd-ufs/rootfs:=${VMBASE} + -o ${VMIMAGE} + ;; + *) + # ENOTSUPP + return 1 + ;; + esac + + return 0 +} usage() { echo "${0} usage:" @@ -130,15 +151,8 @@ vm_create_disk() { fi echo "Creating image... Please wait." echo - mkimg -f ${mkimg_format} -s ${mkimg_scheme} \ - ${mkimg_bootcode} \ - ${mkimg_partitions} \ - ${mkimg_outfile} - mkimg -b /boot/pmbr -p freebsd-boot/bootfs:=/boot/gptboot \ - -p freebsd-swap/swapfs::1G \ - -p freebsd-ufs/rootfs:=${VMBASE} \ - -o ${VMIMAGE}.raw + write_partition_layout || return 1 return 0 } From 78882d335bd4e3636c0d9b440bcc091b6d763949 Mon Sep 17 00:00:00 2001 From: gjb Date: Sat, 8 Nov 2014 12:23:50 +0000 Subject: [PATCH 016/258] Return if vm_create_disk() is unsuccessful. Sponsored by: The FreeBSD Foundation --- release/scripts/mk-vmimage.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/scripts/mk-vmimage.sh b/release/scripts/mk-vmimage.sh index b5065b66ab2d..27c48b72b915 100755 --- a/release/scripts/mk-vmimage.sh +++ b/release/scripts/mk-vmimage.sh @@ -93,7 +93,7 @@ main() { vm_extra_install_ports vm_extra_enable_services vm_extra_pre_umount - vm_create_disk + vm_create_disk || return 0 vm_extra_create_disk return 0 From bc139c5c53585e7c4ad799a98bdcf4d193b1b929 Mon Sep 17 00:00:00 2001 From: gjb Date: Sat, 8 Nov 2014 12:40:59 +0000 Subject: [PATCH 017/258] Add CLEANFILES entry for VM targets Sponsored by: The FreeBSD Foundation --- release/Makefile.vm | 1 + 1 file changed, 1 insertion(+) diff --git a/release/Makefile.vm b/release/Makefile.vm index c37a4ad759d6..30f38682b46a 100644 --- a/release/Makefile.vm +++ b/release/Makefile.vm @@ -20,6 +20,7 @@ OPENSTACK_FORMAT=qcow2 CLOUDTARGETS+= vm-${_CW:tl} CLEANDIRS+= vm-${_CW:tl} CLEANFILES+= ${_CW:tl}.img \ + vm-${_CW:tl} \ ${_CW:tl}.${${_CW:tu}_FORMAT} \ ${_CW:tl}.${${_CW:tu}_FORMAT}.raw ${_CW:tu}IMAGE= ${_CW:tl}.${${_CW:tu}_FORMAT} From c424c032b8fe3123fcb4c92b4ad145fd83bd99a1 Mon Sep 17 00:00:00 2001 From: gjb Date: Sat, 8 Nov 2014 12:45:02 +0000 Subject: [PATCH 018/258] Add vm_extra_pre_umount() prototype to vmimage.subr. Sponsored by: The FreeBSD Foundation --- release/tools/vmimage.subr | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/release/tools/vmimage.subr b/release/tools/vmimage.subr index 3cf19ff360ec..7e54a7f3311c 100644 --- a/release/tools/vmimage.subr +++ b/release/tools/vmimage.subr @@ -127,6 +127,13 @@ vm_extra_install_ports() { return 0 } +vm_extra_pre_umount() { + # Prototype. When overridden, installs additional ports within the + # virtual machine environment. + + return 0 +} + vm_umount_base() { i=0 sync From 1da292027f8e035f0aa318f919fa9dff0c0dcd14 Mon Sep 17 00:00:00 2001 From: gjb Date: Sat, 8 Nov 2014 12:45:35 +0000 Subject: [PATCH 019/258] Fix DESTDIR for installworld, and make sure it is created before use. Sponsored by: The FreeBSD Foundation --- release/Makefile.vm | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/release/Makefile.vm b/release/Makefile.vm index 30f38682b46a..eb167defa5fc 100644 --- a/release/Makefile.vm +++ b/release/Makefile.vm @@ -44,9 +44,10 @@ vm-image: .if defined(WITH_VMIMAGES) && !empty(WITH_VMIMAGES) . if exists(${.CURDIR}/${TARGET}/mk-vmimage.sh) . for FORMAT in ${VMFORMATS} + mkdir -p ${.OBJDIR}/${.TARGET} env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ ${.CURDIR}/${TARGET}/mk-vmimage.sh \ - -C ${.CURDIR}/tools/vmimage.subr -d ${.TARGET} \ + -C ${.CURDIR}/tools/vmimage.subr -d ${.OBJDIR}/${.TARGET} \ -i ${VMBASE}.img -s ${VMSIZE} -f ${FORMAT} \ -S ${WORLDDIR} -o ${VMBASE}.${FORMAT} . endfor @@ -58,9 +59,10 @@ vm-cloudware: ${CLOUDTARGETS} vm-azure: .if exists(${.CURDIR}/${TARGET}/mk-vmimage.sh) + mkdir -p ${.OBJDIR}/${.TARGET} env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ ${.CURDIR}/${TARGET}/mk-vmimage.sh \ - -C ${.CURDIR}/tools/vmimage.subr -d ${.TARGET} \ + -C ${.CURDIR}/tools/vmimage.subr -d ${.OBJDIR}/${.TARGET} \ -i azure.img -s ${VMSIZE} -f ${AZURE_FORMAT} \ -S ${WORLDDIR} -o ${AZUREIMAGE} -c ${AZURECONF} .endif @@ -68,9 +70,10 @@ vm-azure: vm-openstack: .if exists(${.CURDIR}/${TARGET}/mk-vmimage.sh) + mkdir -p ${.OBJDIR}/${.TARGET} env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ ${.CURDIR}/${TARGET}/mk-vmimage.sh \ - -C ${.CURDIR}/tools/vmimage.subr -d ${.TARGET} \ + -C ${.CURDIR}/tools/vmimage.subr -d ${.OBJDIR}/${.TARGET} \ -i openstack.img -s ${VMSIZE} -f ${OPENSTACK_FORMAT} \ -S ${WORLDDIR} -o ${OPENSTACKIMAGE} -c ${OPENSTACKCONF} .endif From c4727c6932cc8fcd5f05a4f93c08fcf5dc9ebce0 Mon Sep 17 00:00:00 2001 From: gjb Date: Sat, 8 Nov 2014 12:47:21 +0000 Subject: [PATCH 020/258] Move usage() from vmimage.subr to mk-vmimage.sh, in case vmimage.subr has not been sourced. Sponsored by: The FreeBSD Foundation --- release/scripts/mk-vmimage.sh | 6 ++++++ release/tools/vmimage.subr | 6 ------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/release/scripts/mk-vmimage.sh b/release/scripts/mk-vmimage.sh index 27c48b72b915..0dd330fa98d9 100755 --- a/release/scripts/mk-vmimage.sh +++ b/release/scripts/mk-vmimage.sh @@ -32,6 +32,12 @@ # $FreeBSD$ # +usage() { + echo "${0} usage:" + echo "${@}" + return 1 +} + main() { local arg while getopts "C:c:d:f:i:o:s:S:" arg; do diff --git a/release/tools/vmimage.subr b/release/tools/vmimage.subr index 7e54a7f3311c..62273a528f12 100644 --- a/release/tools/vmimage.subr +++ b/release/tools/vmimage.subr @@ -35,12 +35,6 @@ write_partition_layout() { return 0 } -usage() { - echo "${0} usage:" - echo "${@}" - return 1 -} - err() { printf "${@}\n" cleanup From 987e4720872ab85486b66e3d1edc33550e9186c3 Mon Sep 17 00:00:00 2001 From: gjb Date: Sat, 8 Nov 2014 12:59:32 +0000 Subject: [PATCH 021/258] Spell 'OPTARG' correctly. Actually call vm_create_base(). Sponsored by: The FreeBSD Foundation --- release/scripts/mk-vmimage.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/release/scripts/mk-vmimage.sh b/release/scripts/mk-vmimage.sh index 0dd330fa98d9..7df7e3d10fb1 100755 --- a/release/scripts/mk-vmimage.sh +++ b/release/scripts/mk-vmimage.sh @@ -55,7 +55,7 @@ main() { VMFORMAT="${OPTARG}" ;; i) - VMBASE="${VMBASE}" + VMBASE="${OPTARG}" ;; o) VMIMAGE="${OPTARG}" @@ -93,6 +93,7 @@ main() { . "${VMCONFIG}" fi + vm_create_base vm_install_base vm_extra_install_base vm_extra_install_packages From 9a076ad6f79b98290bcf134ffe132223de5509e7 Mon Sep 17 00:00:00 2001 From: gjb Date: Sat, 8 Nov 2014 13:49:18 +0000 Subject: [PATCH 022/258] Fix line continuation in write_partition_layout(). Remove variable test that is no longer needed. Sponsored by: The FreeBSD Foundation --- release/tools/vmimage.subr | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/release/tools/vmimage.subr b/release/tools/vmimage.subr index 62273a528f12..b6a91daa5fb4 100644 --- a/release/tools/vmimage.subr +++ b/release/tools/vmimage.subr @@ -16,14 +16,14 @@ write_partition_layout() { mkimg -f gpt -b /boot/pmbr \ -p freebsd-boot/bootfs:=/boot/gptboot \ -p freebsd-swap/swapfs::1G \ - -p freebsd-ufs/rootfs:=${VMBASE} + -p freebsd-ufs/rootfs:=${VMBASE} \ -o ${VMIMAGE} ;; powerpc:powerpc*) mkimg -f apm \ -p freebsd-boot/bootfs:=/boot/boot1.hfs \ -p freebsd-swap/swapfs::1G \ - -p freebsd-ufs/rootfs:=${VMBASE} + -p freebsd-ufs/rootfs:=${VMBASE} \ -o ${VMIMAGE} ;; *) @@ -146,10 +146,6 @@ vm_umount_base() { } vm_create_disk() { - if [ -z "${mkimg_paritions}" ]; then - err "No partition types specified. Skipping." - return 1 - fi echo "Creating image... Please wait." echo From 4a2bc310f45178ac5a7243304f5ee194c2094acb Mon Sep 17 00:00:00 2001 From: gjb Date: Sat, 8 Nov 2014 13:49:59 +0000 Subject: [PATCH 023/258] Fix scheme flag to mkimg(1). Sponsored by: The FreeBSD Foundation --- release/tools/vmimage.subr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release/tools/vmimage.subr b/release/tools/vmimage.subr index b6a91daa5fb4..498299429932 100644 --- a/release/tools/vmimage.subr +++ b/release/tools/vmimage.subr @@ -13,14 +13,14 @@ write_partition_layout() { case "${TARGET}:${TARGET_ARCH}" in amd64:amd64 | i386:i386) - mkimg -f gpt -b /boot/pmbr \ + mkimg -s gpt -b /boot/pmbr \ -p freebsd-boot/bootfs:=/boot/gptboot \ -p freebsd-swap/swapfs::1G \ -p freebsd-ufs/rootfs:=${VMBASE} \ -o ${VMIMAGE} ;; powerpc:powerpc*) - mkimg -f apm \ + mkimg -s apm \ -p freebsd-boot/bootfs:=/boot/boot1.hfs \ -p freebsd-swap/swapfs::1G \ -p freebsd-ufs/rootfs:=${VMBASE} \ From fd404f418bc40af9a67ed29bdab2af505b0b055f Mon Sep 17 00:00:00 2001 From: gjb Date: Sat, 8 Nov 2014 16:26:17 +0000 Subject: [PATCH 024/258] mount(8) and umount(8) devfs(5) as needed. Sponsored by: The FreeBSD Foundation --- release/tools/vmimage.subr | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/release/tools/vmimage.subr b/release/tools/vmimage.subr index 498299429932..64015b470610 100644 --- a/release/tools/vmimage.subr +++ b/release/tools/vmimage.subr @@ -79,8 +79,11 @@ vm_install_base() { echo '/dev/gpt/swapfs none swap sw 0 0' \ >> ${DESTDIR}/etc/fstab + mkdir -p ${DESTDIR}/dev + mount -t devfs devfs ${DESTDIR}/dev chroot ${DESTDIR} /usr/bin/newaliases chroot ${DESTDIR} /etc/rc.d/ldconfig forcestart + umount ${DESTDIR}/dev return 0 } @@ -104,12 +107,15 @@ vm_extra_enable_services() { } vm_extra_install_packages() { + mkdir -p ${DESTDIR}/dev + mount -t devfs devfs ${DESTDIR}/dev chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes \ /usr/sbin/pkg bootstrap -y if [ ! -z "${VM_EXTRA_PACKAGES}" ]; then chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes \ /usr/sbin/pkg install -y ${VM_EXTRA_PACKAGES} fi + umount ${DESTDIR}/dev return 0 } From 1eccb480289d05c002743bb59a9cd351caf268bb Mon Sep 17 00:00:00 2001 From: gjb Date: Sat, 8 Nov 2014 16:44:45 +0000 Subject: [PATCH 025/258] Change path for mk-vmimage.sh from ${TARGET}/ to scripts/ now that it is consolidated into one file. Fix paths for the base image and output disk image files. Sponsored by: The FreeBSD Foundation --- release/Makefile.vm | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/release/Makefile.vm b/release/Makefile.vm index eb167defa5fc..d7fc18f941d8 100644 --- a/release/Makefile.vm +++ b/release/Makefile.vm @@ -42,39 +42,33 @@ vm-base: vm-image vm-image: .if defined(WITH_VMIMAGES) && !empty(WITH_VMIMAGES) -. if exists(${.CURDIR}/${TARGET}/mk-vmimage.sh) -. for FORMAT in ${VMFORMATS} +. for FORMAT in ${VMFORMATS} mkdir -p ${.OBJDIR}/${.TARGET} env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ - ${.CURDIR}/${TARGET}/mk-vmimage.sh \ + ${.CURDIR}/scripts/mk-vmimage.sh \ -C ${.CURDIR}/tools/vmimage.subr -d ${.OBJDIR}/${.TARGET} \ - -i ${VMBASE}.img -s ${VMSIZE} -f ${FORMAT} \ - -S ${WORLDDIR} -o ${VMBASE}.${FORMAT} -. endfor -. endif + -i ${.OBJDIR}/${VMBASE}.img -s ${VMSIZE} -f ${FORMAT} \ + -S ${WORLDDIR} -o ${.OBJDIR}/${VMBASE}.${FORMAT} +. endfor .endif touch ${.TARGET} vm-cloudware: ${CLOUDTARGETS} vm-azure: -.if exists(${.CURDIR}/${TARGET}/mk-vmimage.sh) mkdir -p ${.OBJDIR}/${.TARGET} env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ - ${.CURDIR}/${TARGET}/mk-vmimage.sh \ + ${.CURDIR}/scripts/mk-vmimage.sh \ -C ${.CURDIR}/tools/vmimage.subr -d ${.OBJDIR}/${.TARGET} \ - -i azure.img -s ${VMSIZE} -f ${AZURE_FORMAT} \ - -S ${WORLDDIR} -o ${AZUREIMAGE} -c ${AZURECONF} -.endif + -i ${.OBJDIR}/azure.img -s ${VMSIZE} -f ${AZURE_FORMAT} \ + -S ${WORLDDIR} -o ${.OBJDIR}/${AZUREIMAGE} -c ${AZURECONF} touch ${.TARGET} vm-openstack: -.if exists(${.CURDIR}/${TARGET}/mk-vmimage.sh) mkdir -p ${.OBJDIR}/${.TARGET} env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ - ${.CURDIR}/${TARGET}/mk-vmimage.sh \ + ${.CURDIR}/scripts/mk-vmimage.sh \ -C ${.CURDIR}/tools/vmimage.subr -d ${.OBJDIR}/${.TARGET} \ - -i openstack.img -s ${VMSIZE} -f ${OPENSTACK_FORMAT} \ - -S ${WORLDDIR} -o ${OPENSTACKIMAGE} -c ${OPENSTACKCONF} -.endif + -i ${.OBJDIR}/openstack.img -s ${VMSIZE} -f ${OPENSTACK_FORMAT} \ + -S ${WORLDDIR} -o ${.OBJDIR}/${OPENSTACKIMAGE} -c ${OPENSTACKCONF} touch ${.TARGET} From 102d6a49cadee1eec91f95417755b0e29f92b800 Mon Sep 17 00:00:00 2001 From: gjb Date: Sat, 8 Nov 2014 16:52:07 +0000 Subject: [PATCH 026/258] Call cleanup() after everything is done. Sponsored by: The FreeBSD Foundation --- release/scripts/mk-vmimage.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/release/scripts/mk-vmimage.sh b/release/scripts/mk-vmimage.sh index 7df7e3d10fb1..05a64cc3f92b 100755 --- a/release/scripts/mk-vmimage.sh +++ b/release/scripts/mk-vmimage.sh @@ -102,6 +102,7 @@ main() { vm_extra_pre_umount vm_create_disk || return 0 vm_extra_create_disk + cleanup return 0 } From ef1cbbf54c33d254238d1756f545d50e7bd66704 Mon Sep 17 00:00:00 2001 From: gjb Date: Mon, 10 Nov 2014 21:10:50 +0000 Subject: [PATCH 027/258] Remove a stray directory from CLEANFILES. Sponsored by: The FreeBSD Foundation --- release/Makefile.vm | 1 - 1 file changed, 1 deletion(-) diff --git a/release/Makefile.vm b/release/Makefile.vm index d7fc18f941d8..d362324379f7 100644 --- a/release/Makefile.vm +++ b/release/Makefile.vm @@ -20,7 +20,6 @@ OPENSTACK_FORMAT=qcow2 CLOUDTARGETS+= vm-${_CW:tl} CLEANDIRS+= vm-${_CW:tl} CLEANFILES+= ${_CW:tl}.img \ - vm-${_CW:tl} \ ${_CW:tl}.${${_CW:tu}_FORMAT} \ ${_CW:tl}.${${_CW:tu}_FORMAT}.raw ${_CW:tu}IMAGE= ${_CW:tl}.${${_CW:tu}_FORMAT} From 5b019b36049cac593f05800112642dffee4799ed Mon Sep 17 00:00:00 2001 From: gjb Date: Fri, 14 Nov 2014 22:29:33 +0000 Subject: [PATCH 028/258] Set the boot partition type to 'apple-boot' for powerpc. Submitted by: jhibbits Sponsored by: The FreeBSD Foundation --- release/tools/vmimage.subr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/tools/vmimage.subr b/release/tools/vmimage.subr index 64015b470610..bc2a7fb1f50f 100644 --- a/release/tools/vmimage.subr +++ b/release/tools/vmimage.subr @@ -21,7 +21,7 @@ write_partition_layout() { ;; powerpc:powerpc*) mkimg -s apm \ - -p freebsd-boot/bootfs:=/boot/boot1.hfs \ + -p apple-boot/bootfs:=/boot/boot1.hfs \ -p freebsd-swap/swapfs::1G \ -p freebsd-ufs/rootfs:=${VMBASE} \ -o ${VMIMAGE} From ee5ba5e498b6fa4e91c95853282ab74f4359adac Mon Sep 17 00:00:00 2001 From: gjb Date: Wed, 19 Nov 2014 20:19:53 +0000 Subject: [PATCH 029/258] In vm_install_base(), copy the host resolv.conf into the build chroot before attempting to do anything that requires working DNS (i.e., pkg bootstrap). In vm_extra_pre_umount(), remove the resolv.conf before the disk image is unmounted from the backing md(4). Reported by: cperciva Sponsored by: The FreeBSD Foundation --- release/tools/azure.conf | 2 ++ release/tools/openstack.conf | 2 ++ release/tools/vmimage.subr | 4 ++++ 3 files changed, 8 insertions(+) diff --git a/release/tools/azure.conf b/release/tools/azure.conf index 16c207da3240..3e4a4864adfe 100644 --- a/release/tools/azure.conf +++ b/release/tools/azure.conf @@ -33,6 +33,8 @@ vm_extra_pre_umount() { echo 'console="comconsole vidconsole"' >> ${DESTDIR}/boot/loader.conf echo 'comconsole_speed="115200"' >> ${DESTDIR}/boot/loader.conf + rm -f ${DESTDIR}/etc/resolv.conf + return 0 } diff --git a/release/tools/openstack.conf b/release/tools/openstack.conf index 6aa17493f974..3e0e857e9d89 100644 --- a/release/tools/openstack.conf +++ b/release/tools/openstack.conf @@ -22,5 +22,7 @@ vm_extra_pre_umount() { echo 'sshd_enable="YES"' >> ${DESTDIR}/etc/rc.conf echo 'ifconfig_DEFAULT="SYNCDHCP"' >> ${DESTDIR}/etc/rc.conf + rm -f ${DESTDIR}/etc/resolv.conf + return 0 } diff --git a/release/tools/vmimage.subr b/release/tools/vmimage.subr index bc2a7fb1f50f..00a0a2e23da3 100644 --- a/release/tools/vmimage.subr +++ b/release/tools/vmimage.subr @@ -85,6 +85,8 @@ vm_install_base() { chroot ${DESTDIR} /etc/rc.d/ldconfig forcestart umount ${DESTDIR}/dev + cp /etc/resolv.conf ${DESTDIR}/etc/resolv.conf + return 0 } @@ -131,6 +133,8 @@ vm_extra_pre_umount() { # Prototype. When overridden, installs additional ports within the # virtual machine environment. + rm -f ${DESTDIR}/etc/resolv.conf + return 0 } From 9e2769f85a5fa8890bf5b8379ee70c83f05b9661 Mon Sep 17 00:00:00 2001 From: cperciva Date: Wed, 19 Nov 2014 22:17:22 +0000 Subject: [PATCH 030/258] Silence errors when umounting the chroot's /dev, since it probably doesn't exist when we're running this. Unmount filesystems before attempting to destroy the md which holds them. --- release/tools/vmimage.subr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release/tools/vmimage.subr b/release/tools/vmimage.subr index 00a0a2e23da3..3e1ddce66b14 100644 --- a/release/tools/vmimage.subr +++ b/release/tools/vmimage.subr @@ -42,11 +42,11 @@ err() { } cleanup() { + umount ${DESTDIR}/dev 2>/dev/null + umount ${DESTDIR} if [ ! -z "${mddev}" ]; then mdconfig -d -u ${mddev} fi - umount ${DESTDIR}/dev - umount ${DESTDIR} return 0 } From 5d6c87f034dfb472153503733292f86cd7e93156 Mon Sep 17 00:00:00 2001 From: cperciva Date: Thu, 20 Nov 2014 00:16:55 +0000 Subject: [PATCH 031/258] Unmount filesystem and destroy md before we read the vnode from disk and package it into a disk image. Otherwise we end up packaging an unclean filesystem. --- release/scripts/mk-vmimage.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/scripts/mk-vmimage.sh b/release/scripts/mk-vmimage.sh index 05a64cc3f92b..bf0e1325dde7 100755 --- a/release/scripts/mk-vmimage.sh +++ b/release/scripts/mk-vmimage.sh @@ -100,9 +100,9 @@ main() { vm_extra_install_ports vm_extra_enable_services vm_extra_pre_umount + cleanup vm_create_disk || return 0 vm_extra_create_disk - cleanup return 0 } From 38536134a537e0bdb40e60d84c17bb691424480d Mon Sep 17 00:00:00 2001 From: cperciva Date: Thu, 20 Nov 2014 03:46:35 +0000 Subject: [PATCH 032/258] Merge duplicative vm-CLOUDTYPE targets before additional duplication gets added by the impending arrival of ec2 and gcloud. --- release/Makefile.vm | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/release/Makefile.vm b/release/Makefile.vm index d362324379f7..bb5311fdc66c 100644 --- a/release/Makefile.vm +++ b/release/Makefile.vm @@ -26,6 +26,15 @@ ${_CW:tu}IMAGE= ${_CW:tl}.${${_CW:tu}_FORMAT} . if exists(${.CURDIR}/tools/${_CW:tl}.conf) && !defined(${_CW:tu}CONF) ${_CW:tu}CONF?= ${.CURDIR}/tools/${_CW:tl}.conf . endif + +vm-${_CW:tl}: + mkdir -p ${.OBJDIR}/${.TARGET} + env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ + ${.CURDIR}/scripts/mk-vmimage.sh \ + -C ${.CURDIR}/tools/vmimage.subr -d ${.OBJDIR}/${.TARGET} \ + -i ${.OBJDIR}/${_CW:tl}.img -s ${VMSIZE} -f ${${_CW}_FORMAT} \ + -S ${WORLDDIR} -o ${.OBJDIR}/${${_CW}IMAGE} -c ${${_CW}CONF} + touch ${.TARGET} . endfor .endif @@ -53,21 +62,3 @@ vm-image: touch ${.TARGET} vm-cloudware: ${CLOUDTARGETS} - -vm-azure: - mkdir -p ${.OBJDIR}/${.TARGET} - env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ - ${.CURDIR}/scripts/mk-vmimage.sh \ - -C ${.CURDIR}/tools/vmimage.subr -d ${.OBJDIR}/${.TARGET} \ - -i ${.OBJDIR}/azure.img -s ${VMSIZE} -f ${AZURE_FORMAT} \ - -S ${WORLDDIR} -o ${.OBJDIR}/${AZUREIMAGE} -c ${AZURECONF} - touch ${.TARGET} - -vm-openstack: - mkdir -p ${.OBJDIR}/${.TARGET} - env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ - ${.CURDIR}/scripts/mk-vmimage.sh \ - -C ${.CURDIR}/tools/vmimage.subr -d ${.OBJDIR}/${.TARGET} \ - -i ${.OBJDIR}/openstack.img -s ${VMSIZE} -f ${OPENSTACK_FORMAT} \ - -S ${WORLDDIR} -o ${.OBJDIR}/${OPENSTACKIMAGE} -c ${OPENSTACKCONF} - touch ${.TARGET} From cb036cbe50cf25bdcc6642eb5f0810af8e4d58db Mon Sep 17 00:00:00 2001 From: cperciva Date: Fri, 21 Nov 2014 01:53:40 +0000 Subject: [PATCH 033/258] Add NOSWAP option which can be set by a vmimage.conf file to specify that no swap space should be created in the image. This will be used by EC2 builds, since FreeBSD/EC2 allocates swap space on "ephemeral" disks which are physically attached to the Xen host node. --- release/tools/vmimage.subr | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/release/tools/vmimage.subr b/release/tools/vmimage.subr index 3e1ddce66b14..c7805721d2a5 100644 --- a/release/tools/vmimage.subr +++ b/release/tools/vmimage.subr @@ -10,19 +10,22 @@ export PATH="/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin" trap "cleanup" INT QUIT TRAP ABRT TERM write_partition_layout() { + if [ -z "${NOSWAP}" ]; then + SWAPOPT="-p freebsd-swap/swapfs::1G" + fi case "${TARGET}:${TARGET_ARCH}" in amd64:amd64 | i386:i386) mkimg -s gpt -b /boot/pmbr \ -p freebsd-boot/bootfs:=/boot/gptboot \ - -p freebsd-swap/swapfs::1G \ + ${SWAPOPT} \ -p freebsd-ufs/rootfs:=${VMBASE} \ -o ${VMIMAGE} ;; powerpc:powerpc*) mkimg -s apm \ -p apple-boot/bootfs:=/boot/boot1.hfs \ - -p freebsd-swap/swapfs::1G \ + ${SWAPOPT} \ -p freebsd-ufs/rootfs:=${VMBASE} \ -o ${VMIMAGE} ;; @@ -76,8 +79,10 @@ vm_install_base() { > ${DESTDIR}/etc/fstab echo '/dev/gpt/rootfs / ufs rw 1 1' \ >> ${DESTDIR}/etc/fstab - echo '/dev/gpt/swapfs none swap sw 0 0' \ - >> ${DESTDIR}/etc/fstab + if [ -z "${NOSWAP}" ]; then + echo '/dev/gpt/swapfs none swap sw 0 0' \ + >> ${DESTDIR}/etc/fstab + fi mkdir -p ${DESTDIR}/dev mount -t devfs devfs ${DESTDIR}/dev From 8b1726e8cc096e375dec775efc8fec7ce1e3dc84 Mon Sep 17 00:00:00 2001 From: cperciva Date: Fri, 21 Nov 2014 02:13:12 +0000 Subject: [PATCH 034/258] Change how packages are installed into VM images: Rather than chrooting into the image and running 'pkg install' from there, use 'pkg fetch' to download packages into a temporary location and then 'pkg add' to install them into the image. This simplifies the code by avoiding the need to copy /etc/resolv.conf into the image and then delete it later, and makes it possible to cross build (e.g., to create an amd64 image when running on i386 hardware; or in the future for building disk images for embedded platforms). Because pkg was implicitly installed when VM_EXTRA_PACKAGES was non-empty, add it to VM_EXTRA_PACKAGES in azure.conf and openstack.conf to maintain the current behaviour. By default repo-FreeBSD.sqlite is copied into the image, (a) to match previous behaviour, where the file would be downloaded by the chrooted pkg invocation; and (b) because it may be useful for testing purposes, e.g., to see why a package didn't get installed. Because this file is large (46 MB) and not likely to be useful in -RELEASE images which are being launched into Clouds several months later, it can be disabled by setting NOREPOSQLITE. As far as I know this commit does not change the disk images produced in any filesystem-visible way. --- release/tools/azure.conf | 5 +---- release/tools/openstack.conf | 5 +---- release/tools/vmimage.subr | 21 ++++++++++----------- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/release/tools/azure.conf b/release/tools/azure.conf index 3e4a4864adfe..46b678cd5c25 100644 --- a/release/tools/azure.conf +++ b/release/tools/azure.conf @@ -5,7 +5,7 @@ # Set to a list of packages to install. # Example: -#export VM_EXTRA_PACKAGES="www/apache24" +#export VM_EXTRA_PACKAGES="www/apache24 ports-mgmt/pkg" export VM_EXTRA_PACKAGES= # Set to a list of third-party software to enable in rc.conf(5). @@ -17,7 +17,6 @@ vm_extra_install_base() { fetch -o ${DESTDIR}/usr/sbin/waagent \ http://people.freebsd.org/~gjb/waagent chmod +x ${DESTDIR}/usr/sbin/waagent - rm -f ${DESTDIR}/etc/resolv.conf return 0 } @@ -33,8 +32,6 @@ vm_extra_pre_umount() { echo 'console="comconsole vidconsole"' >> ${DESTDIR}/boot/loader.conf echo 'comconsole_speed="115200"' >> ${DESTDIR}/boot/loader.conf - rm -f ${DESTDIR}/etc/resolv.conf - return 0 } diff --git a/release/tools/openstack.conf b/release/tools/openstack.conf index 3e0e857e9d89..ed88ae2972fb 100644 --- a/release/tools/openstack.conf +++ b/release/tools/openstack.conf @@ -4,7 +4,7 @@ # # Set to a list of packages to install. -export VM_EXTRA_PACKAGES="net/cloud-init" +export VM_EXTRA_PACKAGES="net/cloud-init ports-mgmt/pkg" # Set to a list of third-party software to enable in rc.conf(5). export VM_RC_LIST="cloudinit" @@ -13,7 +13,6 @@ vm_extra_install_base() { fetch -o ${DESTDIR}/usr/sbin/waagent \ http://people.freebsd.org/~gjb/waagent chmod +x ${DESTDIR}/usr/sbin/waagent - rm -f ${DESTDIR}/etc/resolv.conf return 0 } @@ -22,7 +21,5 @@ vm_extra_pre_umount() { echo 'sshd_enable="YES"' >> ${DESTDIR}/etc/rc.conf echo 'ifconfig_DEFAULT="SYNCDHCP"' >> ${DESTDIR}/etc/rc.conf - rm -f ${DESTDIR}/etc/resolv.conf - return 0 } diff --git a/release/tools/vmimage.subr b/release/tools/vmimage.subr index c7805721d2a5..63e39066fea2 100644 --- a/release/tools/vmimage.subr +++ b/release/tools/vmimage.subr @@ -90,8 +90,6 @@ vm_install_base() { chroot ${DESTDIR} /etc/rc.d/ldconfig forcestart umount ${DESTDIR}/dev - cp /etc/resolv.conf ${DESTDIR}/etc/resolv.conf - return 0 } @@ -114,15 +112,18 @@ vm_extra_enable_services() { } vm_extra_install_packages() { - mkdir -p ${DESTDIR}/dev - mount -t devfs devfs ${DESTDIR}/dev - chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes \ - /usr/sbin/pkg bootstrap -y if [ ! -z "${VM_EXTRA_PACKAGES}" ]; then - chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes \ - /usr/sbin/pkg install -y ${VM_EXTRA_PACKAGES} + PKGSDIR=`mktemp -d` + ABI=`/usr/sbin/pkg -c ${DESTDIR} config abi` + /usr/sbin/pkg -o ABI=${ABI} fetch -o ${PKGSDIR} -d -y ${VM_EXTRA_PACKAGES} + for PKG in ${PKGSDIR}/All/*; do + /usr/sbin/pkg -c ${DESTDIR} add -M - < ${PKG} + done + rm -r ${PKGSDIR} + if [ -z "${NOREPOSQLITE}" ]; then + cp /var/db/pkg/repo-FreeBSD.sqlite ${DESTDIR}/var/db/pkg + fi fi - umount ${DESTDIR}/dev return 0 } @@ -138,8 +139,6 @@ vm_extra_pre_umount() { # Prototype. When overridden, installs additional ports within the # virtual machine environment. - rm -f ${DESTDIR}/etc/resolv.conf - return 0 } From 5074f8a73ef15d33d0e142de9376bc34ec07dbdf Mon Sep 17 00:00:00 2001 From: gjb Date: Fri, 21 Nov 2014 02:30:37 +0000 Subject: [PATCH 035/258] Revert r274773, after I *specifically* objected to this change numerous times. Sponsored by: The FreeBSD Foundation --- release/tools/azure.conf | 5 ++++- release/tools/openstack.conf | 5 ++++- release/tools/vmimage.subr | 21 +++++++++++---------- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/release/tools/azure.conf b/release/tools/azure.conf index 46b678cd5c25..3e4a4864adfe 100644 --- a/release/tools/azure.conf +++ b/release/tools/azure.conf @@ -5,7 +5,7 @@ # Set to a list of packages to install. # Example: -#export VM_EXTRA_PACKAGES="www/apache24 ports-mgmt/pkg" +#export VM_EXTRA_PACKAGES="www/apache24" export VM_EXTRA_PACKAGES= # Set to a list of third-party software to enable in rc.conf(5). @@ -17,6 +17,7 @@ vm_extra_install_base() { fetch -o ${DESTDIR}/usr/sbin/waagent \ http://people.freebsd.org/~gjb/waagent chmod +x ${DESTDIR}/usr/sbin/waagent + rm -f ${DESTDIR}/etc/resolv.conf return 0 } @@ -32,6 +33,8 @@ vm_extra_pre_umount() { echo 'console="comconsole vidconsole"' >> ${DESTDIR}/boot/loader.conf echo 'comconsole_speed="115200"' >> ${DESTDIR}/boot/loader.conf + rm -f ${DESTDIR}/etc/resolv.conf + return 0 } diff --git a/release/tools/openstack.conf b/release/tools/openstack.conf index ed88ae2972fb..3e0e857e9d89 100644 --- a/release/tools/openstack.conf +++ b/release/tools/openstack.conf @@ -4,7 +4,7 @@ # # Set to a list of packages to install. -export VM_EXTRA_PACKAGES="net/cloud-init ports-mgmt/pkg" +export VM_EXTRA_PACKAGES="net/cloud-init" # Set to a list of third-party software to enable in rc.conf(5). export VM_RC_LIST="cloudinit" @@ -13,6 +13,7 @@ vm_extra_install_base() { fetch -o ${DESTDIR}/usr/sbin/waagent \ http://people.freebsd.org/~gjb/waagent chmod +x ${DESTDIR}/usr/sbin/waagent + rm -f ${DESTDIR}/etc/resolv.conf return 0 } @@ -21,5 +22,7 @@ vm_extra_pre_umount() { echo 'sshd_enable="YES"' >> ${DESTDIR}/etc/rc.conf echo 'ifconfig_DEFAULT="SYNCDHCP"' >> ${DESTDIR}/etc/rc.conf + rm -f ${DESTDIR}/etc/resolv.conf + return 0 } diff --git a/release/tools/vmimage.subr b/release/tools/vmimage.subr index 63e39066fea2..c7805721d2a5 100644 --- a/release/tools/vmimage.subr +++ b/release/tools/vmimage.subr @@ -90,6 +90,8 @@ vm_install_base() { chroot ${DESTDIR} /etc/rc.d/ldconfig forcestart umount ${DESTDIR}/dev + cp /etc/resolv.conf ${DESTDIR}/etc/resolv.conf + return 0 } @@ -112,18 +114,15 @@ vm_extra_enable_services() { } vm_extra_install_packages() { + mkdir -p ${DESTDIR}/dev + mount -t devfs devfs ${DESTDIR}/dev + chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes \ + /usr/sbin/pkg bootstrap -y if [ ! -z "${VM_EXTRA_PACKAGES}" ]; then - PKGSDIR=`mktemp -d` - ABI=`/usr/sbin/pkg -c ${DESTDIR} config abi` - /usr/sbin/pkg -o ABI=${ABI} fetch -o ${PKGSDIR} -d -y ${VM_EXTRA_PACKAGES} - for PKG in ${PKGSDIR}/All/*; do - /usr/sbin/pkg -c ${DESTDIR} add -M - < ${PKG} - done - rm -r ${PKGSDIR} - if [ -z "${NOREPOSQLITE}" ]; then - cp /var/db/pkg/repo-FreeBSD.sqlite ${DESTDIR}/var/db/pkg - fi + chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes \ + /usr/sbin/pkg install -y ${VM_EXTRA_PACKAGES} fi + umount ${DESTDIR}/dev return 0 } @@ -139,6 +138,8 @@ vm_extra_pre_umount() { # Prototype. When overridden, installs additional ports within the # virtual machine environment. + rm -f ${DESTDIR}/etc/resolv.conf + return 0 } From 14b8fb23980471b417fd74d0aabf4df363e9da54 Mon Sep 17 00:00:00 2001 From: gjb Date: Mon, 24 Nov 2014 02:34:01 +0000 Subject: [PATCH 036/258] In vm_extra_install_packages(), only bootstrap pkg(8) if VM_EXTRA_PACKAGES is empty. In vm_extra_pre_umount(), cleanup downloaded packages if pkg(8) was bootstrapped earlier. Inspired by: cperciva Sponsored by: The FreeBSD Foundation --- release/tools/vmimage.subr | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/release/tools/vmimage.subr b/release/tools/vmimage.subr index c7805721d2a5..3ea505619bef 100644 --- a/release/tools/vmimage.subr +++ b/release/tools/vmimage.subr @@ -114,14 +114,15 @@ vm_extra_enable_services() { } vm_extra_install_packages() { + if [ -z "${VM_EXTRA_PACKAGES}" ]; then + return 0 + fi mkdir -p ${DESTDIR}/dev mount -t devfs devfs ${DESTDIR}/dev chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes \ /usr/sbin/pkg bootstrap -y - if [ ! -z "${VM_EXTRA_PACKAGES}" ]; then chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes \ /usr/sbin/pkg install -y ${VM_EXTRA_PACKAGES} - fi umount ${DESTDIR}/dev return 0 @@ -138,6 +139,10 @@ vm_extra_pre_umount() { # Prototype. When overridden, installs additional ports within the # virtual machine environment. + if [ -e ${DESTDIR}/usr/local/sbin/pkg ]; then + chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes \ + /usr/local/sbin/pkg clean -y -a + fi rm -f ${DESTDIR}/etc/resolv.conf return 0 From 7f08d7ffb1a5607d815a518dada617cec8b841b4 Mon Sep 17 00:00:00 2001 From: gjb Date: Mon, 24 Nov 2014 02:36:43 +0000 Subject: [PATCH 037/258] Fix indentation nit. Sponsored by: The FreeBSD Foundation --- release/tools/vmimage.subr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release/tools/vmimage.subr b/release/tools/vmimage.subr index 3ea505619bef..2fd70fffea5c 100644 --- a/release/tools/vmimage.subr +++ b/release/tools/vmimage.subr @@ -121,8 +121,8 @@ vm_extra_install_packages() { mount -t devfs devfs ${DESTDIR}/dev chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes \ /usr/sbin/pkg bootstrap -y - chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes \ - /usr/sbin/pkg install -y ${VM_EXTRA_PACKAGES} + chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes \ + /usr/sbin/pkg install -y ${VM_EXTRA_PACKAGES} umount ${DESTDIR}/dev return 0 From f0d9ad0c8593615af8fe52950188ad6ba33044a5 Mon Sep 17 00:00:00 2001 From: gjb Date: Wed, 14 Jan 2015 14:49:05 +0000 Subject: [PATCH 038/258] In vm_extra_install_base(), do not install waagent in the openstack image, because it is not used. This appears to be a copy mistake. Remove vm_extra_install_base() from the openstack.conf entirely, since it does not need to be overridden. Sponsored by: The FreeBSD Foundation --- release/tools/openstack.conf | 9 --------- 1 file changed, 9 deletions(-) diff --git a/release/tools/openstack.conf b/release/tools/openstack.conf index 3e0e857e9d89..a88e0f8e37de 100644 --- a/release/tools/openstack.conf +++ b/release/tools/openstack.conf @@ -9,15 +9,6 @@ export VM_EXTRA_PACKAGES="net/cloud-init" # Set to a list of third-party software to enable in rc.conf(5). export VM_RC_LIST="cloudinit" -vm_extra_install_base() { - fetch -o ${DESTDIR}/usr/sbin/waagent \ - http://people.freebsd.org/~gjb/waagent - chmod +x ${DESTDIR}/usr/sbin/waagent - rm -f ${DESTDIR}/etc/resolv.conf - - return 0 -} - vm_extra_pre_umount() { echo 'sshd_enable="YES"' >> ${DESTDIR}/etc/rc.conf echo 'ifconfig_DEFAULT="SYNCDHCP"' >> ${DESTDIR}/etc/rc.conf From 5107643b94d616de8402a3bfdcf5c4c9fca0901e Mon Sep 17 00:00:00 2001 From: gjb Date: Wed, 14 Jan 2015 15:23:58 +0000 Subject: [PATCH 039/258] Enable the textmode console by default for VM images, since there is no way to tell if the environment will be able to use the graphics-mode console. Sponsored by: The FreeBSD Foundation --- release/tools/vmimage.subr | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/release/tools/vmimage.subr b/release/tools/vmimage.subr index 2fd70fffea5c..52530e8397f2 100644 --- a/release/tools/vmimage.subr +++ b/release/tools/vmimage.subr @@ -84,6 +84,12 @@ vm_install_base() { >> ${DESTDIR}/etc/fstab fi + # Set hw.vga.textmode=1, with the assumption that the hypervisor + # will not be capable of using the graphics console mode. + echo '# Comment the next line to enable graphical console mode' \ + >> ${DESTDIR}/boot/loader.conf + echo 'hw.vga.textmode=1' >> ${DESTDIR}/boot/loader.conf + mkdir -p ${DESTDIR}/dev mount -t devfs devfs ${DESTDIR}/dev chroot ${DESTDIR} /usr/bin/newaliases From 64286bf832c873a4fd62113d3329836ae6ee2c68 Mon Sep 17 00:00:00 2001 From: gjb Date: Wed, 14 Jan 2015 15:45:18 +0000 Subject: [PATCH 040/258] Enable password-less sudo for openstack images. Sponsored by: The FreeBSD Foundation --- release/tools/openstack.conf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/release/tools/openstack.conf b/release/tools/openstack.conf index a88e0f8e37de..3eb7b1d31991 100644 --- a/release/tools/openstack.conf +++ b/release/tools/openstack.conf @@ -13,6 +13,10 @@ vm_extra_pre_umount() { echo 'sshd_enable="YES"' >> ${DESTDIR}/etc/rc.conf echo 'ifconfig_DEFAULT="SYNCDHCP"' >> ${DESTDIR}/etc/rc.conf + # Openstack wants sudo(8) usable by default without a password. + echo 'ALL ALL=(ALL) NOPASSWD:ALL' >> \ + ${DESTDIR}/usr/local/etc/sudoers.d/cloud-init + rm -f ${DESTDIR}/etc/resolv.conf return 0 From 57dffb5c40e2e989b05663115570a76de6b852da Mon Sep 17 00:00:00 2001 From: gjb Date: Wed, 14 Jan 2015 16:27:43 +0000 Subject: [PATCH 041/258] Update the VM_EXTRA_PACKAGES list for the openstack images. The documentation suggests doing a "just fetch this and run it"-style bootstrap, from which the list of dependencies was obtained (in github, at: pellaeon/bsd-cloudinit-installer) There is one Python dependency unmet, oslo.config, which is not in the Ports Collection. Sponsored by: The FreeBSD Foundation --- release/tools/openstack.conf | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/release/tools/openstack.conf b/release/tools/openstack.conf index 3eb7b1d31991..e5bfd4187048 100644 --- a/release/tools/openstack.conf +++ b/release/tools/openstack.conf @@ -4,7 +4,9 @@ # # Set to a list of packages to install. -export VM_EXTRA_PACKAGES="net/cloud-init" +export VM_EXTRA_PACKAGES="net/cloud-init devel/py-pbr devel/py-iso8601 \ +net/py-eventlet net/py-netaddr comms/py-serial devel/py-six \ +devel/py-babel net/py-oauth net/py-netifaces" # Set to a list of third-party software to enable in rc.conf(5). export VM_RC_LIST="cloudinit" From 8bf2cea4c97e61d36323362dd55e1fb300c7e562 Mon Sep 17 00:00:00 2001 From: gjb Date: Wed, 14 Jan 2015 16:42:54 +0000 Subject: [PATCH 042/258] Add a comment to note that setting hw.vga.textmode=1 is temporary. Sponsored by: The FreeBSD Foundation --- release/tools/vmimage.subr | 1 + 1 file changed, 1 insertion(+) diff --git a/release/tools/vmimage.subr b/release/tools/vmimage.subr index 52530e8397f2..e200d0af6ff3 100644 --- a/release/tools/vmimage.subr +++ b/release/tools/vmimage.subr @@ -86,6 +86,7 @@ vm_install_base() { # Set hw.vga.textmode=1, with the assumption that the hypervisor # will not be capable of using the graphics console mode. + # XXX: Revert this before merging to head. echo '# Comment the next line to enable graphical console mode' \ >> ${DESTDIR}/boot/loader.conf echo 'hw.vga.textmode=1' >> ${DESTDIR}/boot/loader.conf From 0d86658a18173622e67d50e85f1d133e1c87e12c Mon Sep 17 00:00:00 2001 From: gjb Date: Fri, 16 Jan 2015 15:37:07 +0000 Subject: [PATCH 043/258] Remove vm_extra_install_base() for the Azure image, now that the waagent exists in the ports tree. Add sysutils/azure-agent to the VM_EXTRA_PACKAGES list. In vm_extra_pre_umount(), remove the explicit pkg(8) install list, as dependencies are resolved by sysutils/azure-agent. Sponsored by: The FreeBSD Foundation --- release/tools/azure.conf | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/release/tools/azure.conf b/release/tools/azure.conf index 3e4a4864adfe..922f8d9d406f 100644 --- a/release/tools/azure.conf +++ b/release/tools/azure.conf @@ -6,25 +6,14 @@ # Set to a list of packages to install. # Example: #export VM_EXTRA_PACKAGES="www/apache24" -export VM_EXTRA_PACKAGES= +export VM_EXTRA_PACKAGES="sysutils/azure-agent" # Set to a list of third-party software to enable in rc.conf(5). # Example: #export VM_RC_LIST="apache24" export VM_RC_LIST= -vm_extra_install_base() { - fetch -o ${DESTDIR}/usr/sbin/waagent \ - http://people.freebsd.org/~gjb/waagent - chmod +x ${DESTDIR}/usr/sbin/waagent - rm -f ${DESTDIR}/etc/resolv.conf - - return 0 -} - vm_extra_pre_umount() { - chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes /usr/sbin/pkg install -y \ - python python2 python27 py27-asn1 sudo bash chroot ${DESTDIR} /usr/sbin/waagent -verbose -install yes | chroot ${DESTDIR} /usr/sbin/waagent -deprovision echo 'sshd_enable="YES"' >> ${DESTDIR}/etc/rc.conf From 17c10aaadc2530475f707d7445539e373094175c Mon Sep 17 00:00:00 2001 From: gjb Date: Fri, 16 Jan 2015 17:05:35 +0000 Subject: [PATCH 044/258] Add a 'list-cloudware' target to print the list of supported CLOUDWARE values and a description. Add the AZURE_DESC and OPENSTACK_DESC descriptions. Sponsored by: The FreeBSD Foundation --- release/Makefile.vm | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/release/Makefile.vm b/release/Makefile.vm index bb5311fdc66c..f28881eca7ae 100644 --- a/release/Makefile.vm +++ b/release/Makefile.vm @@ -13,7 +13,9 @@ VMBASE?= vm CLOUDWARE?= AZURE \ OPENSTACK AZURE_FORMAT= vhdf +AZURE_DESC= Microsoft Azure platform image OPENSTACK_FORMAT=qcow2 +OPENSTACK_DESC= OpenStack platform image .if defined(WITH_CLOUDWARE) && !empty(WITH_CLOUDWARE) && !empty(CLOUDWARE) . for _CW in ${CLOUDWARE} @@ -62,3 +64,10 @@ vm-image: touch ${.TARGET} vm-cloudware: ${CLOUDTARGETS} + +list-cloudware: +.if !empty(CLOUDWARE) +. for _CW in ${CLOUDWARE} + @${ECHO} "${_CW:tu}: ${${_CW:tu}_DESC}" +. endfor +.endif From e3fed9e5b144dea4410e3896243f905712869346 Mon Sep 17 00:00:00 2001 From: gjb Date: Fri, 16 Jan 2015 17:07:35 +0000 Subject: [PATCH 045/258] Update release(7): - Add a "CLOUD HOSTING MACHINE IMAGES" section, documenting the CLOUDWARE and WITH_CLOUDWARE make(1) environment variables. - Document the vm-cloudware and list-cloudware targets. - Add release/Makefile.vm, release/tools/*.conf and release/tools/vmimage.subr to FILES. Sponsored by: The FreeBSD Foundation --- share/man/man7/release.7 | 57 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/share/man/man7/release.7 b/share/man/man7/release.7 index 93aec89618a9..1284915de693 100644 --- a/share/man/man7/release.7 +++ b/share/man/man7/release.7 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd October 2, 2014 +.Dd January 16, 2015 .Dt RELEASE 7 .Os .Sh NAME @@ -406,6 +406,47 @@ See for valid format values .Pq requires version 20140927 or later . .El +.Sh CLOUD HOSTING MACHINE IMAGES +The +.Fx +release build tools support building virtual machine images for various +cloud hosting providers, each with their own specific configuration to +include support for each hosting provider by default. +.Pp +The following +.Xr make 1 +environment variables are supported: +.Pp +.Bl -tag -width Ev +.It Va CLOUDWARE +Set to a list of one or more cloud hosting providers, enclosed in quotes. +Requires +.Va WITH_CLOUDWARE +to also be set. +.It Va WITH_CLOUDWARE +Set to a non-empty value to enable building virtual machine images +for various cloud hosting providers. +Requires +.Va CLOUDWARE +to also be set. +.El +.Pp +Additionally, the +.Va CLOUDWARE +and +.Va WITH_CLOUDWARE +variables can be added to +.Pa release.conf , +and used in conjunction with +.Pa release.sh . +.Pp +For a list of supported +.Va CLOUDWARE +values, run: +.Bd -literal -offset indent +cd /usr/src +make -C release list-cloudware +.Ed .Sh MAKEFILE TARGETS The release makefile .Pq Pa src/release/Makefile @@ -470,6 +511,17 @@ target requires the .Va WITH_VMIMAGES .Xr make 1 envirionment variable to be set to a non-null value. +.It Cm vm-cloudware +Builds +.Fx +virtual machine images for various cloud hosting providers. +See +.Qq CLOUD HOSTING MACHINE IMAGES +for implementation details. +.It Cm list-cloudware +Displays the list of valid +.Va CLOUDWARE +values. .El .Pp Major subtargets called by targets above: @@ -576,8 +628,11 @@ Typically, one only needs to set .It Pa /usr/src/Makefile .It Pa /usr/src/Makefile.inc1 .It Pa /usr/src/release/Makefile +.It Pa /usr/src/release/Makefile.vm .It Pa /usr/src/release/release.sh .It Pa /usr/src/release/release.conf.sample +.It Pa /usr/src/release/tools/*.conf +.It Pa /usr/src/release/tools/vmimage.subr .El .Sh EXAMPLES The following sequence of commands can be used to build a From 2b1b7bc3e77dfa2b6d4fd800029ee16f77e2c40c Mon Sep 17 00:00:00 2001 From: gjb Date: Fri, 16 Jan 2015 17:40:30 +0000 Subject: [PATCH 046/258] Add 'list-vmtargets' target, which produces a list of all supported VM and cloud provider images. Add VHD_DESC, VMDK_DESC, QCOW2_DESC, RAW_DESC image descriptions. Format the output to make a bit more readable. Update release(7) to document the list-vmtargets target. Sponsored by: The FreeBSD Foundation --- release/Makefile.vm | 16 +++++++++++++++- share/man/man7/release.7 | 16 ++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/release/Makefile.vm b/release/Makefile.vm index f28881eca7ae..4652c164a76f 100644 --- a/release/Makefile.vm +++ b/release/Makefile.vm @@ -10,6 +10,11 @@ VMFORMATS?= vhd vmdk qcow2 raw VMSIZE?= 20G VMBASE?= vm +VHD_DESC= Azure, VirtualPC, Hyper-V, Xen disk image +VMDK_DESC= VMWare, VirtualBox disk image +QCOW2_DESC= Qemu, KVM disk image +RAW_DESC= Unformatted raw disk image + CLOUDWARE?= AZURE \ OPENSTACK AZURE_FORMAT= vhdf @@ -65,9 +70,18 @@ vm-image: vm-cloudware: ${CLOUDTARGETS} +list-vmtargets: list-cloudware + @${ECHO} + @${ECHO} "Supported virtual machine disk image formats:" +.for FORMAT in ${VMFORMATS:tu} + @${ECHO} " ${FORMAT:tl}: ${${FORMAT}_DESC}" +.endfor + list-cloudware: .if !empty(CLOUDWARE) + @${ECHO} + @${ECHO} "Supported cloud hosting provider images:" . for _CW in ${CLOUDWARE} - @${ECHO} "${_CW:tu}: ${${_CW:tu}_DESC}" + @${ECHO} " ${_CW:tu}: ${${_CW:tu}_DESC}" . endfor .endif diff --git a/share/man/man7/release.7 b/share/man/man7/release.7 index 1284915de693..5cd91b68285c 100644 --- a/share/man/man7/release.7 +++ b/share/man/man7/release.7 @@ -406,6 +406,16 @@ See for valid format values .Pq requires version 20140927 or later . .El +.Pp +For a list of supported +.Va VMFORMATS +values +.Pq including cloud hosting provider formats +along with a brief description, run: +.Bd -literal -offset indent +cd /usr/src +make -C release list-vmtargets +.Ed .Sh CLOUD HOSTING MACHINE IMAGES The .Fx @@ -522,6 +532,12 @@ for implementation details. Displays the list of valid .Va CLOUDWARE values. +.It Cm list-vmtargets +Displays the list of valid +.Va VMFORMAT +and +.Va CLOUDWARE +values. .El .Pp Major subtargets called by targets above: From 2f6be49b3a077b469a27a8c97ee1f3d24334468d Mon Sep 17 00:00:00 2001 From: gjb Date: Fri, 16 Jan 2015 19:27:19 +0000 Subject: [PATCH 047/258] Add initial support for the GCE (Google Compute Engine) cloud hosting provider image. Many thanks to swills@ for his work on getting this to this point. Submitted by: swills Sponsored by: The FreeBSD Foundation --- release/Makefile.vm | 3 ++ release/tools/gce.conf | 96 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 release/tools/gce.conf diff --git a/release/Makefile.vm b/release/Makefile.vm index 4652c164a76f..5c052fa04e7c 100644 --- a/release/Makefile.vm +++ b/release/Makefile.vm @@ -16,9 +16,12 @@ QCOW2_DESC= Qemu, KVM disk image RAW_DESC= Unformatted raw disk image CLOUDWARE?= AZURE \ + GCE \ OPENSTACK AZURE_FORMAT= vhdf AZURE_DESC= Microsoft Azure platform image +GCE_FORMAT= raw +GCE_DESC= Google Compute Engine image OPENSTACK_FORMAT=qcow2 OPENSTACK_DESC= OpenStack platform image diff --git a/release/tools/gce.conf b/release/tools/gce.conf new file mode 100644 index 000000000000..bccf1f45fa88 --- /dev/null +++ b/release/tools/gce.conf @@ -0,0 +1,96 @@ +#!/bin/sh +# +# $FreeBSD$ +# + +# Set to a list of packages to install. +export VM_EXTRA_PACKAGES="firstboot-freebsd-update firstboot-pkgs google-cloud-sdk google-daemon panicmail sudo firstboot-growfs google-startup-scripts" + +# Set to a list of third-party software to enable in rc.conf(5). +export VM_RC_LIST="google_accounts_manager ntpd" + +vm_extra_install_base() { + echo 'search google.internal' > ${DESTDIR}/etc/resolv.conf + echo 'nameserver 169.254.169.254' >> ${DESTDIR}/etc/resolv.conf + echo 'nameserver 8.8.8.8' >> ${DESTDIR}/etc/resolv.conf +} + +vm_extra_pre_umount() { + cat << EOF >> ${DESTDIR}/etc/rc.conf +console="comconsole" +dumpdev="AUTO" +ifconfig_vtnet0="SYNCDHCP mtu 1460" +ntpd_sync_on_start="YES" +ntpd_enable="YES" +sshd_enable="YES" +google_accounts_manager_enable="YES" +#disabled until I can figure out why the reboot for updates is hanging +#firstboot_freebsd_update_enable="YES" +#firstboot_pkgs_enable="YES" +# need to fill in something here +#firstboot_pkgs_list="" +panicmail_autosubmit="YES" +firstboot_growfs_enable="YES" +google_startup_enable="YES" +EOF + + cat << EOF >> ${DESTDIR}/boot/loader.conf +autoboot_delay="-1" +beastie_disable="YES" +loader_logo="none" +hw.memtest.tests="0" +console="comconsole" +hw.vtnet.mq_disable=1 +kern.timecounter.hardware=ACPI-safe +aesni_load="YES" +nvme_load="YES" +EOF + + echo '169.254.169.254 metadata.google.internal metadata' > \ + ${DESTDIR}/etc/hosts + + # overwrite ntp.conf + cat << EOF > ${DESTDIR}/etc/ntp.conf +server metadata.google.internal iburst + +restrict default kod nomodify notrap nopeer noquery +restrict -6 default kod nomodify notrap nopeer noquery + +restrict 127.0.0.1 +restrict -6 ::1 +restrict 127.127.1.0 +EOF + + cat << EOF >> ${DESTDIR}/etc/syslog.conf +*.err;kern.warning;auth.notice;mail.crit /dev/console +EOF + + cat << EOF >> ${DESTDIR}/etc/ssh/sshd_config +ChallengeResponseAuthentication no +X11Forwarding no +AcceptEnv LANG +Ciphers aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-cbc,3des-cbc +AllowAgentForwarding no +ClientAliveInterval 420 +EOF + + cat << EOF >> ${DESTDIR}/etc/crontab +0 3 * * * root /usr/sbin/freebsd-update cron +EOF + + cat << EOF >> ${DESTDIR}/etc/sysctl.conf +net.inet.icmp.drop_redirect=1 +net.inet.ip.redirect=0 +net.inet.tcp.blackhole=2 +net.inet.udp.blackhole=1 +kern.ipc.somaxconn=1024 +debug.trace_on_panic=1 +debug.debugger_on_panic=0 +EOF + + sed -E -i '' 's/^([^#].*[[:space:]])on/\1off/' ${DESTDIR}/etc/ttys + + touch ${DESTDIR}/firstboot + + return 0 +} From 79660291fb82626d215166111e5653a3a9ee4d53 Mon Sep 17 00:00:00 2001 From: allanjude Date: Sun, 18 Jan 2015 17:25:41 +0000 Subject: [PATCH 048/258] Fix minor syntax and grammar errors in the markup of the ee(1) man page Differential Revision: https://reviews.freebsd.org/D1552 Submitted by: bcallah@openbsd.org (original) Approved by: wblock (mentor) MFC after: 1 week Sponsored by: ScaleEngine Inc. --- contrib/ee/ee.1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/ee/ee.1 b/contrib/ee/ee.1 index b66c8aae17aa..d6558a14c6fc 100644 --- a/contrib/ee/ee.1 +++ b/contrib/ee/ee.1 @@ -329,8 +329,8 @@ A window showing the keyboard operations that can be performed can be displayed or not. .IP "\fBemacs keys\fR" Control keys may be given bindings similar to emacs, or not. -.IP "\f16 bit characters\fR" -Toggles whether sixteen bit characters are handled as one 16-bit quantities or +.IP "\fB16 bit characters\fR" +Toggles whether sixteen bit characters are handled as one 16-bit quantity or two 8-bit quantities. This works primarily with the Chinese Big 5 code set. .RE .PP @@ -461,7 +461,7 @@ Turns off display of eight bit characters (they are displayed as their decimal value inside angle brackets, e.g., "<220>"). .IP \fB16bit\fR Turns on handling of 16-bit characters. -.IP \fbno16bit\fR +.IP \fBno16bit\fR Turns off handling of 16-bit characters. .IP \fBemacs\fR Turns on emacs key bindings. From 33d33ed0ad23b7885673bd9f26fd280aa15d1c88 Mon Sep 17 00:00:00 2001 From: adrian Date: Sun, 18 Jan 2015 17:43:00 +0000 Subject: [PATCH 049/258] Oops - use the correct argument order for ar9300_set_beacon(). (It's only an issue in AP/adhoc modes. But, still. Grr.) --- sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.c index 3846dcb2bce7..315086c2d42e 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.c +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.c @@ -606,8 +606,8 @@ ar9300_freebsd_beacon_init(struct ath_hal *ah, uint32_t next_beacon, uint32_t beacon_period) { - ar9300_beacon_init(ah, AH_PRIVATE(ah)->ah_opmode, - next_beacon, beacon_period); + ar9300_beacon_init(ah, next_beacon, beacon_period, + AH_PRIVATE(ah)->ah_opmode); } HAL_BOOL From f1c9d3f332580379ca3a231c238944ef36934596 Mon Sep 17 00:00:00 2001 From: adrian Date: Sun, 18 Jan 2015 18:06:40 +0000 Subject: [PATCH 050/258] Refactor / restructure the RSS code into generic, IPv4 and IPv6 specific bits. The motivation here is to eventually teach netisr and potentially other networking subsystems a bit more about how RSS work queues / buckets are configured so things have a hope of auto-configuring in the future. * net/rss_config.[ch] takes care of the generic bits for doing configuration, hash function selection, etc; * topelitz.[ch] is now in net/ rather than netinet/; * (and would be in libkern if it didn't directly include RSS_KEYSIZE; that's a later thing to fix up.) * netinet/in_rss.[ch] now just contains the IPv4 specific methods; * and netinet/in6_rss.[ch] now just contains the IPv6 specific methods. This should have no functional impact on anyone currently using the RSS support. Differential Revision: D1383 Reviewed by: gnn, jfv (intel driver bits) --- sys/conf/files | 6 +- sys/dev/e1000/if_igb.c | 6 +- sys/dev/ixgbe/ixgbe.c | 2 +- sys/dev/ixl/ixl_txrx.c | 2 +- sys/net/if_ethersubr.c | 2 +- sys/net/rss_config.c | 558 +++++++++++++++++++++++++++++++ sys/net/rss_config.h | 123 +++++++ sys/{netinet => net}/toeplitz.c | 4 +- sys/{netinet => net}/toeplitz.h | 0 sys/netinet/in_pcb.c | 2 +- sys/netinet/in_pcbgroup.c | 3 + sys/netinet/in_rss.c | 570 +------------------------------- sys/netinet/in_rss.h | 85 ----- sys/netinet/ip_input.c | 1 + sys/netinet/ip_output.c | 1 + sys/netinet/tcp_timer.c | 1 + sys/netinet/udp_usrreq.c | 1 + sys/netinet6/in6_pcbgroup.c | 4 +- sys/netinet6/in6_rss.c | 103 ++++++ sys/netinet6/in6_rss.h | 45 +++ sys/netinet6/ip6_output.c | 3 +- sys/netinet6/udp6_usrreq.c | 3 +- 22 files changed, 870 insertions(+), 655 deletions(-) create mode 100644 sys/net/rss_config.c create mode 100644 sys/net/rss_config.h rename sys/{netinet => net}/toeplitz.c (97%) rename sys/{netinet => net}/toeplitz.h (100%) create mode 100644 sys/netinet6/in6_rss.c create mode 100644 sys/netinet6/in6_rss.h diff --git a/sys/conf/files b/sys/conf/files index 22a20d88e1a1..5895cce88ab7 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -3270,9 +3270,11 @@ net/radix_mpath.c standard net/raw_cb.c standard net/raw_usrreq.c standard net/route.c standard +net/rss_config.c optional inet rss | inet6 rss net/rtsock.c standard net/slcompress.c optional netgraph_vjc | sppp | \ netgraph_sppp +net/toeplitz.c optional inet rss | inet6 rss net/vnet.c optional vimage net/zlib.c optional crypto | geom_uzip | ipsec | \ mxge | netgraph_deflate | \ @@ -3422,7 +3424,7 @@ netinet/in_pcb.c optional inet | inet6 netinet/in_pcbgroup.c optional inet pcbgroup | inet6 pcbgroup netinet/in_proto.c optional inet | inet6 netinet/in_rmx.c optional inet -netinet/in_rss.c optional inet rss | inet6 rss +netinet/in_rss.c optional inet rss netinet/ip_divert.c optional inet ipdivert ipfirewall netinet/ip_ecn.c optional inet | inet6 netinet/ip_encap.c optional inet | inet6 @@ -3465,7 +3467,6 @@ netinet/tcp_syncache.c optional inet | inet6 netinet/tcp_timer.c optional inet | inet6 netinet/tcp_timewait.c optional inet | inet6 netinet/tcp_usrreq.c optional inet | inet6 -netinet/toeplitz.c optional inet rss | inet6 rss netinet/udp_usrreq.c optional inet | inet6 netinet/libalias/alias.c optional libalias inet | netgraph_nat inet netinet/libalias/alias_db.c optional libalias inet | netgraph_nat inet @@ -3485,6 +3486,7 @@ netinet6/in6_pcb.c optional inet6 netinet6/in6_pcbgroup.c optional inet6 pcbgroup netinet6/in6_proto.c optional inet6 netinet6/in6_rmx.c optional inet6 +netinet6/in6_rss.c optional inet6 rss netinet6/in6_src.c optional inet6 netinet6/ip6_forward.c optional inet6 netinet6/ip6_gre.c optional gre inet6 diff --git a/sys/dev/e1000/if_igb.c b/sys/dev/e1000/if_igb.c index 6e598c4bba60..c875945845f9 100644 --- a/sys/dev/e1000/if_igb.c +++ b/sys/dev/e1000/if_igb.c @@ -73,6 +73,9 @@ #include #include #include +#ifdef RSS +#include +#endif #include #include @@ -85,9 +88,6 @@ #include #include #include -#ifdef RSS -#include -#endif #include #include diff --git a/sys/dev/ixgbe/ixgbe.c b/sys/dev/ixgbe/ixgbe.c index bd9407e3a7a6..7231c560b34c 100644 --- a/sys/dev/ixgbe/ixgbe.c +++ b/sys/dev/ixgbe/ixgbe.c @@ -39,7 +39,7 @@ #include "ixgbe.h" #ifdef RSS -#include +#include #endif /********************************************************************* diff --git a/sys/dev/ixl/ixl_txrx.c b/sys/dev/ixl/ixl_txrx.c index 0ba9685a07a9..6a6ab7c9ccc1 100755 --- a/sys/dev/ixl/ixl_txrx.c +++ b/sys/dev/ixl/ixl_txrx.c @@ -1378,7 +1378,7 @@ static inline int ixl_ptype_to_hash(u8 ptype) { struct i40e_rx_ptype_decoded decoded; - u8 ex = 0 + u8 ex = 0; decoded = decode_rx_desc_ptype(ptype); ex = decoded.outer_frag; diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 9ba1f636063f..7227788ac084 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -63,6 +63,7 @@ #include #include #include +#include #include #include @@ -71,7 +72,6 @@ #include #include #include -#include #include #include #endif diff --git a/sys/net/rss_config.c b/sys/net/rss_config.c new file mode 100644 index 000000000000..55f4952fbec2 --- /dev/null +++ b/sys/net/rss_config.c @@ -0,0 +1,558 @@ +/*- + * Copyright (c) 2010-2011 Juniper Networks, Inc. + * All rights reserved. + * + * This software was developed by Robert N. M. Watson under contract + * to Juniper Networks, Inc. + * + * 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_inet6.h" +#include "opt_pcbgroup.h" + +#ifndef PCBGROUP +#error "options RSS depends on options PCBGROUP" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if 0 +#include +#include +#include +#include + +/* for software rss hash support */ +#include +#include +#include +#endif + +/*- + * Operating system parts of receiver-side scaling (RSS), which allows + * network cards to direct flows to particular receive queues based on hashes + * of header tuples. This implementation aligns RSS buckets with connection + * groups at the TCP/IP layer, so each bucket is associated with exactly one + * group. As a result, the group lookup structures (and lock) should have an + * effective affinity with exactly one CPU. + * + * Network device drivers needing to configure RSS will query this framework + * for parameters, such as the current RSS key, hashing policies, number of + * bits, and indirection table mapping hashes to buckets and CPUs. They may + * provide their own supplementary information, such as queue<->CPU bindings. + * It is the responsibility of the network device driver to inject packets + * into the stack on as close to the right CPU as possible, if playing by RSS + * rules. + * + * TODO: + * + * - Synchronization for rss_key and other future-configurable parameters. + * - Event handler drivers can register to pick up RSS configuration changes. + * - Should we allow rss_basecpu to be configured? + * - Randomize key on boot. + * - IPv6 support. + * - Statistics on how often there's a misalignment between hardware + * placement and pcbgroup expectations. + */ + +SYSCTL_DECL(_net_inet); +SYSCTL_NODE(_net_inet, OID_AUTO, rss, CTLFLAG_RW, 0, "Receive-side steering"); + +/* + * Toeplitz is the only required hash function in the RSS spec, so use it by + * default. + */ +static u_int rss_hashalgo = RSS_HASH_TOEPLITZ; +SYSCTL_INT(_net_inet_rss, OID_AUTO, hashalgo, CTLFLAG_RDTUN, &rss_hashalgo, 0, + "RSS hash algorithm"); + +/* + * Size of the indirection table; at most 128 entries per the RSS spec. We + * size it to at least 2 times the number of CPUs by default to allow useful + * rebalancing. If not set explicitly with a loader tunable, we tune based + * on the number of CPUs present. + * + * XXXRW: buckets might be better to use for the tunable than bits. + */ +static u_int rss_bits; +SYSCTL_INT(_net_inet_rss, OID_AUTO, bits, CTLFLAG_RDTUN, &rss_bits, 0, + "RSS bits"); + +static u_int rss_mask; +SYSCTL_INT(_net_inet_rss, OID_AUTO, mask, CTLFLAG_RD, &rss_mask, 0, + "RSS mask"); + +static const u_int rss_maxbits = RSS_MAXBITS; +SYSCTL_INT(_net_inet_rss, OID_AUTO, maxbits, CTLFLAG_RD, + __DECONST(int *, &rss_maxbits), 0, "RSS maximum bits"); + +/* + * RSS's own count of the number of CPUs it could be using for processing. + * Bounded to 64 by RSS constants. + */ +static u_int rss_ncpus; +SYSCTL_INT(_net_inet_rss, OID_AUTO, ncpus, CTLFLAG_RD, &rss_ncpus, 0, + "Number of CPUs available to RSS"); + +#define RSS_MAXCPUS (1 << (RSS_MAXBITS - 1)) +static const u_int rss_maxcpus = RSS_MAXCPUS; +SYSCTL_INT(_net_inet_rss, OID_AUTO, maxcpus, CTLFLAG_RD, + __DECONST(int *, &rss_maxcpus), 0, "RSS maximum CPUs that can be used"); + +/* + * Variable exists just for reporting rss_bits in a user-friendly way. + */ +static u_int rss_buckets; +SYSCTL_INT(_net_inet_rss, OID_AUTO, buckets, CTLFLAG_RD, &rss_buckets, 0, + "RSS buckets"); + +/* + * Base CPU number; devices will add this to all CPU numbers returned by the + * RSS indirection table. Currently unmodifable in FreeBSD. + */ +static const u_int rss_basecpu; +SYSCTL_INT(_net_inet_rss, OID_AUTO, basecpu, CTLFLAG_RD, + __DECONST(int *, &rss_basecpu), 0, "RSS base CPU"); + +/* + * RSS secret key, intended to prevent attacks on load-balancing. Its + * effectiveness may be limited by algorithm choice and available entropy + * during the boot. + * + * XXXRW: And that we don't randomize it yet! + * + * This is the default Microsoft RSS specification key which is also + * the Chelsio T5 firmware default key. + */ +static uint8_t rss_key[RSS_KEYSIZE] = { + 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2, + 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0, + 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4, + 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c, + 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa, +}; + +/* + * RSS hash->CPU table, which maps hashed packet headers to particular CPUs. + * Drivers may supplement this table with a seperate CPU<->queue table when + * programming devices. + */ +struct rss_table_entry { + uint8_t rte_cpu; /* CPU affinity of bucket. */ +}; +static struct rss_table_entry rss_table[RSS_TABLE_MAXLEN]; + +static void +rss_init(__unused void *arg) +{ + u_int i; + u_int cpuid; + + /* + * Validate tunables, coerce to sensible values. + */ + switch (rss_hashalgo) { + case RSS_HASH_TOEPLITZ: + case RSS_HASH_NAIVE: + break; + + default: + printf("%s: invalid RSS hashalgo %u, coercing to %u", + __func__, rss_hashalgo, RSS_HASH_TOEPLITZ); + rss_hashalgo = RSS_HASH_TOEPLITZ; + } + + /* + * Count available CPUs. + * + * XXXRW: Note incorrect assumptions regarding contiguity of this set + * elsewhere. + */ + rss_ncpus = 0; + for (i = 0; i <= mp_maxid; i++) { + if (CPU_ABSENT(i)) + continue; + rss_ncpus++; + } + if (rss_ncpus > RSS_MAXCPUS) + rss_ncpus = RSS_MAXCPUS; + + /* + * Tune RSS table entries to be no less than 2x the number of CPUs + * -- unless we're running uniprocessor, in which case there's not + * much point in having buckets to rearrange for load-balancing! + */ + if (rss_ncpus > 1) { + if (rss_bits == 0) + rss_bits = fls(rss_ncpus - 1) + 1; + + /* + * Microsoft limits RSS table entries to 128, so apply that + * limit to both auto-detected CPU counts and user-configured + * ones. + */ + if (rss_bits == 0 || rss_bits > RSS_MAXBITS) { + printf("%s: RSS bits %u not valid, coercing to %u", + __func__, rss_bits, RSS_MAXBITS); + rss_bits = RSS_MAXBITS; + } + + /* + * Figure out how many buckets to use; warn if less than the + * number of configured CPUs, although this is not a fatal + * problem. + */ + rss_buckets = (1 << rss_bits); + if (rss_buckets < rss_ncpus) + printf("%s: WARNING: rss_buckets (%u) less than " + "rss_ncpus (%u)\n", __func__, rss_buckets, + rss_ncpus); + rss_mask = rss_buckets - 1; + } else { + rss_bits = 0; + rss_buckets = 1; + rss_mask = 0; + } + + /* + * Set up initial CPU assignments: round-robin by default. + */ + cpuid = CPU_FIRST(); + for (i = 0; i < rss_buckets; i++) { + rss_table[i].rte_cpu = cpuid; + cpuid = CPU_NEXT(cpuid); + } + + /* + * Randomize rrs_key. + * + * XXXRW: Not yet. If nothing else, will require an rss_isbadkey() + * loop to check for "bad" RSS keys. + */ +} +SYSINIT(rss_init, SI_SUB_SOFTINTR, SI_ORDER_SECOND, rss_init, NULL); + +static uint32_t +rss_naive_hash(u_int keylen, const uint8_t *key, u_int datalen, + const uint8_t *data) +{ + uint32_t v; + u_int i; + + v = 0; + for (i = 0; i < keylen; i++) + v += key[i]; + for (i = 0; i < datalen; i++) + v += data[i]; + return (v); +} + +uint32_t +rss_hash(u_int datalen, const uint8_t *data) +{ + + switch (rss_hashalgo) { + case RSS_HASH_TOEPLITZ: + return (toeplitz_hash(sizeof(rss_key), rss_key, datalen, + data)); + + case RSS_HASH_NAIVE: + return (rss_naive_hash(sizeof(rss_key), rss_key, datalen, + data)); + + default: + panic("%s: unsupported/unknown hashalgo %d", __func__, + rss_hashalgo); + } +} + +/* + * Query the number of RSS bits in use. + */ +u_int +rss_getbits(void) +{ + + return (rss_bits); +} + +/* + * Query the RSS bucket associated with an RSS hash. + */ +u_int +rss_getbucket(u_int hash) +{ + + return (hash & rss_mask); +} + +/* + * Query the RSS layer bucket associated with the given + * entry in the RSS hash space. + * + * The RSS indirection table is 0 .. rss_buckets-1, + * covering the low 'rss_bits' of the total 128 slot + * RSS indirection table. So just mask off rss_bits and + * return that. + * + * NIC drivers can then iterate over the 128 slot RSS + * indirection table and fetch which RSS bucket to + * map it to. This will typically be a CPU queue + */ +u_int +rss_get_indirection_to_bucket(u_int index) +{ + + return (index & rss_mask); +} + +/* + * Query the RSS CPU associated with an RSS bucket. + */ +u_int +rss_getcpu(u_int bucket) +{ + + return (rss_table[bucket].rte_cpu); +} + +/* + * netisr CPU affinity lookup given just the hash and hashtype. + */ +u_int +rss_hash2cpuid(uint32_t hash_val, uint32_t hash_type) +{ + + switch (hash_type) { + case M_HASHTYPE_RSS_IPV4: + case M_HASHTYPE_RSS_TCP_IPV4: + case M_HASHTYPE_RSS_UDP_IPV4: + case M_HASHTYPE_RSS_IPV6: + case M_HASHTYPE_RSS_TCP_IPV6: + case M_HASHTYPE_RSS_UDP_IPV6: + return (rss_getcpu(rss_getbucket(hash_val))); + default: + return (NETISR_CPUID_NONE); + } +} + +/* + * Query the RSS bucket associated with the given hash value and + * type. + */ +int +rss_hash2bucket(uint32_t hash_val, uint32_t hash_type, uint32_t *bucket_id) +{ + + switch (hash_type) { + case M_HASHTYPE_RSS_IPV4: + case M_HASHTYPE_RSS_TCP_IPV4: + case M_HASHTYPE_RSS_UDP_IPV4: + case M_HASHTYPE_RSS_IPV6: + case M_HASHTYPE_RSS_TCP_IPV6: + case M_HASHTYPE_RSS_UDP_IPV6: + *bucket_id = rss_getbucket(hash_val); + return (0); + default: + return (-1); + } +} + +/* + * netisr CPU affinity lookup routine for use by protocols. + */ +struct mbuf * +rss_m2cpuid(struct mbuf *m, uintptr_t source, u_int *cpuid) +{ + + M_ASSERTPKTHDR(m); + *cpuid = rss_hash2cpuid(m->m_pkthdr.flowid, M_HASHTYPE_GET(m)); + return (m); +} + +int +rss_m2bucket(struct mbuf *m, uint32_t *bucket_id) +{ + + M_ASSERTPKTHDR(m); + + return(rss_hash2bucket(m->m_pkthdr.flowid, M_HASHTYPE_GET(m), + bucket_id)); +} + +/* + * Query the RSS hash algorithm. + */ +u_int +rss_gethashalgo(void) +{ + + return (rss_hashalgo); +} + +/* + * Query the current RSS key; likely to be used by device drivers when + * configuring hardware RSS. Caller must pass an array of size RSS_KEYSIZE. + * + * XXXRW: Perhaps we should do the accept-a-length-and-truncate thing? + */ +void +rss_getkey(uint8_t *key) +{ + + bcopy(rss_key, key, sizeof(rss_key)); +} + +/* + * Query the number of buckets; this may be used by both network device + * drivers, which will need to populate hardware shadows of the software + * indirection table, and the network stack itself (such as when deciding how + * many connection groups to allocate). + */ +u_int +rss_getnumbuckets(void) +{ + + return (rss_buckets); +} + +/* + * Query the number of CPUs in use by RSS; may be useful to device drivers + * trying to figure out how to map a larger number of CPUs into a smaller + * number of receive queues. + */ +u_int +rss_getnumcpus(void) +{ + + return (rss_ncpus); +} + +/* + * Return the supported RSS hash configuration. + * + * NICs should query this to determine what to configure in their redirection + * matching table. + */ +inline u_int +rss_gethashconfig(void) +{ + + /* Return 4-tuple for TCP; 2-tuple for others */ + /* + * UDP may fragment more often than TCP and thus we'll end up with + * NICs returning 2-tuple fragments. + * udp_init() and udplite_init() both currently initialise things + * as 2-tuple. + * So for now disable UDP 4-tuple hashing until all of the other + * pieces are in place. + */ + return ( + RSS_HASHTYPE_RSS_IPV4 + | RSS_HASHTYPE_RSS_TCP_IPV4 + | RSS_HASHTYPE_RSS_IPV6 + | RSS_HASHTYPE_RSS_TCP_IPV6 + | RSS_HASHTYPE_RSS_IPV6_EX + | RSS_HASHTYPE_RSS_TCP_IPV6_EX +#if 0 + | RSS_HASHTYPE_RSS_UDP_IPV4 + | RSS_HASHTYPE_RSS_UDP_IPV4_EX + | RSS_HASHTYPE_RSS_UDP_IPV6 + | RSS_HASHTYPE_RSS_UDP_IPV6_EX +#endif + ); +} + +/* + * XXXRW: Confirm that sysctl -a won't dump this keying material, don't want + * it appearing in debugging output unnecessarily. + */ +static int +sysctl_rss_key(SYSCTL_HANDLER_ARGS) +{ + uint8_t temp_rss_key[RSS_KEYSIZE]; + int error; + + error = priv_check(req->td, PRIV_NETINET_HASHKEY); + if (error) + return (error); + + bcopy(rss_key, temp_rss_key, sizeof(temp_rss_key)); + error = sysctl_handle_opaque(oidp, temp_rss_key, + sizeof(temp_rss_key), req); + if (error) + return (error); + if (req->newptr != NULL) { + /* XXXRW: Not yet. */ + return (EINVAL); + } + return (0); +} +SYSCTL_PROC(_net_inet_rss, OID_AUTO, key, + CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, sysctl_rss_key, + "", "RSS keying material"); + +static int +sysctl_rss_bucket_mapping(SYSCTL_HANDLER_ARGS) +{ + struct sbuf *sb; + int error; + int i; + + error = 0; + error = sysctl_wire_old_buffer(req, 0); + if (error != 0) + return (error); + sb = sbuf_new_for_sysctl(NULL, NULL, 512, req); + if (sb == NULL) + return (ENOMEM); + for (i = 0; i < rss_buckets; i++) { + sbuf_printf(sb, "%s%d:%d", i == 0 ? "" : " ", + i, + rss_getcpu(i)); + } + error = sbuf_finish(sb); + sbuf_delete(sb); + + return (error); +} +SYSCTL_PROC(_net_inet_rss, OID_AUTO, bucket_mapping, + CTLTYPE_STRING | CTLFLAG_RD, NULL, 0, + sysctl_rss_bucket_mapping, "", "RSS bucket -> CPU mapping"); diff --git a/sys/net/rss_config.h b/sys/net/rss_config.h new file mode 100644 index 000000000000..37d82ae15426 --- /dev/null +++ b/sys/net/rss_config.h @@ -0,0 +1,123 @@ +/*- + * Copyright (c) 2010-2011 Juniper Networks, Inc. + * All rights reserved. + * + * This software was developed by Robert N. M. Watson under contract + * to Juniper Networks, Inc. + * + * 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 _NET_RSS_CONFIG_H_ +#define _NET_RSS_CONFIG_H_ + +#include /* in_addr_t */ + +/* + * Supported RSS hash functions. + */ +#define RSS_HASH_NAIVE 0x00000001 /* Poor but fast hash. */ +#define RSS_HASH_TOEPLITZ 0x00000002 /* Required by RSS. */ +#define RSS_HASH_CRC32 0x00000004 /* Future; some NICs do it. */ + +#define RSS_HASH_MASK (RSS_HASH_NAIVE | RSS_HASH_TOEPLITZ) + +/* + * Instances of struct inpcbinfo declare an RSS hash type indicating what + * header fields are covered. + */ +#define RSS_HASHFIELDS_NONE 0 +#define RSS_HASHFIELDS_4TUPLE 1 +#define RSS_HASHFIELDS_2TUPLE 2 + +/* + * Define RSS representations of the M_HASHTYPE_* values, representing + * which particular bits are supported. The NICs can then use this to + * calculate which hash types to enable and which not to enable. + * + * The fact that these line up with M_HASHTYPE_* is not to be relied + * upon. + */ +#define RSS_HASHTYPE_RSS_IPV4 (1 << 1) /* IPv4 2-tuple */ +#define RSS_HASHTYPE_RSS_TCP_IPV4 (1 << 2) /* TCPv4 4-tuple */ +#define RSS_HASHTYPE_RSS_IPV6 (1 << 3) /* IPv6 2-tuple */ +#define RSS_HASHTYPE_RSS_TCP_IPV6 (1 << 4) /* TCPv6 4-tuple */ +#define RSS_HASHTYPE_RSS_IPV6_EX (1 << 5) /* IPv6 2-tuple + ext hdrs */ +#define RSS_HASHTYPE_RSS_TCP_IPV6_EX (1 << 6) /* TCPv6 4-tiple + ext hdrs */ +#define RSS_HASHTYPE_RSS_UDP_IPV4 (1 << 7) /* IPv4 UDP 4-tuple */ +#define RSS_HASHTYPE_RSS_UDP_IPV4_EX (1 << 8) /* IPv4 UDP 4-tuple + ext hdrs */ +#define RSS_HASHTYPE_RSS_UDP_IPV6 (1 << 9) /* IPv6 UDP 4-tuple */ +#define RSS_HASHTYPE_RSS_UDP_IPV6_EX (1 << 10) /* IPv6 UDP 4-tuple + ext hdrs */ + +/* + * Compile-time limits on the size of the indirection table. + */ +#define RSS_MAXBITS 7 +#define RSS_TABLE_MAXLEN (1 << RSS_MAXBITS) + +/* + * Maximum key size used throughout. It's OK for hardware to use only the + * first 16 bytes, which is all that's required for IPv4. + */ +#define RSS_KEYSIZE 40 + +/* + * For RSS hash methods that do a software hash on an mbuf, the packet + * direction (ingress / egress) is required. + * + * The default direction (INGRESS) is the "receive into the NIC" - ie, + * what the hardware is hashing on. + */ +#define RSS_HASH_PKT_INGRESS 0 +#define RSS_HASH_PKT_EGRESS 1 + +/* + * Device driver interfaces to query RSS properties that must be programmed + * into hardware. + */ +u_int rss_getbits(void); +u_int rss_getbucket(u_int hash); +u_int rss_get_indirection_to_bucket(u_int index); +u_int rss_getcpu(u_int bucket); +void rss_getkey(uint8_t *key); +u_int rss_gethashalgo(void); +u_int rss_getnumbuckets(void); +u_int rss_getnumcpus(void); +u_int rss_gethashconfig(void); + +/* + * Hash calculation functions. + */ +uint32_t rss_hash(u_int datalen, const uint8_t *data); + +/* + * Network stack interface to query desired CPU affinity of a packet. + */ +struct mbuf * rss_m2cpuid(struct mbuf *m, uintptr_t source, u_int *cpuid); +u_int rss_hash2cpuid(uint32_t hash_val, uint32_t hash_type); +int rss_hash2bucket(uint32_t hash_val, uint32_t hash_type, + uint32_t *bucket_id); +int rss_m2bucket(struct mbuf *m, uint32_t *bucket_id); + +#endif /* !_NET_RSS_CONFIG_H_ */ diff --git a/sys/netinet/toeplitz.c b/sys/net/toeplitz.c similarity index 97% rename from sys/netinet/toeplitz.c rename to sys/net/toeplitz.c index 84d3a5955a7b..4328ec4468aa 100644 --- a/sys/netinet/toeplitz.c +++ b/sys/net/toeplitz.c @@ -29,8 +29,8 @@ __FBSDID("$FreeBSD$"); #include -#include -#include +#include +#include #include diff --git a/sys/netinet/toeplitz.h b/sys/net/toeplitz.h similarity index 100% rename from sys/netinet/toeplitz.h rename to sys/net/toeplitz.h diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 6bec7efc256c..f8f290558ba6 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -71,12 +71,12 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #if defined(INET) || defined(INET6) #include #include -#include #include #include #include diff --git a/sys/netinet/in_pcbgroup.c b/sys/netinet/in_pcbgroup.c index 4157290382d7..2d3c1366afde 100644 --- a/sys/netinet/in_pcbgroup.c +++ b/sys/netinet/in_pcbgroup.c @@ -42,7 +42,10 @@ __FBSDID("$FreeBSD$"); #include #include +#include + #include + #include #include #ifdef INET6 diff --git a/sys/netinet/in_rss.c b/sys/netinet/in_rss.c index 336c64f57c76..087d8467686b 100644 --- a/sys/netinet/in_rss.c +++ b/sys/netinet/in_rss.c @@ -50,257 +50,18 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include #include -#include /* for software rss hash support */ #include #include #include -/*- - * Operating system parts of receiver-side scaling (RSS), which allows - * network cards to direct flows to particular receive queues based on hashes - * of header tuples. This implementation aligns RSS buckets with connection - * groups at the TCP/IP layer, so each bucket is associated with exactly one - * group. As a result, the group lookup structures (and lock) should have an - * effective affinity with exactly one CPU. - * - * Network device drivers needing to configure RSS will query this framework - * for parameters, such as the current RSS key, hashing policies, number of - * bits, and indirection table mapping hashes to buckets and CPUs. They may - * provide their own supplementary information, such as queue<->CPU bindings. - * It is the responsibility of the network device driver to inject packets - * into the stack on as close to the right CPU as possible, if playing by RSS - * rules. - * - * TODO: - * - * - Synchronization for rss_key and other future-configurable parameters. - * - Event handler drivers can register to pick up RSS configuration changes. - * - Should we allow rss_basecpu to be configured? - * - Randomize key on boot. - * - IPv6 support. - * - Statistics on how often there's a misalignment between hardware - * placement and pcbgroup expectations. - */ - -SYSCTL_NODE(_net_inet, OID_AUTO, rss, CTLFLAG_RW, 0, "Receive-side steering"); - -/* - * Toeplitz is the only required hash function in the RSS spec, so use it by - * default. - */ -static u_int rss_hashalgo = RSS_HASH_TOEPLITZ; -SYSCTL_INT(_net_inet_rss, OID_AUTO, hashalgo, CTLFLAG_RDTUN, &rss_hashalgo, 0, - "RSS hash algorithm"); - -/* - * Size of the indirection table; at most 128 entries per the RSS spec. We - * size it to at least 2 times the number of CPUs by default to allow useful - * rebalancing. If not set explicitly with a loader tunable, we tune based - * on the number of CPUs present. - * - * XXXRW: buckets might be better to use for the tunable than bits. - */ -static u_int rss_bits; -SYSCTL_INT(_net_inet_rss, OID_AUTO, bits, CTLFLAG_RDTUN, &rss_bits, 0, - "RSS bits"); - -static u_int rss_mask; -SYSCTL_INT(_net_inet_rss, OID_AUTO, mask, CTLFLAG_RD, &rss_mask, 0, - "RSS mask"); - -static const u_int rss_maxbits = RSS_MAXBITS; -SYSCTL_INT(_net_inet_rss, OID_AUTO, maxbits, CTLFLAG_RD, - __DECONST(int *, &rss_maxbits), 0, "RSS maximum bits"); - -/* - * RSS's own count of the number of CPUs it could be using for processing. - * Bounded to 64 by RSS constants. - */ -static u_int rss_ncpus; -SYSCTL_INT(_net_inet_rss, OID_AUTO, ncpus, CTLFLAG_RD, &rss_ncpus, 0, - "Number of CPUs available to RSS"); - -#define RSS_MAXCPUS (1 << (RSS_MAXBITS - 1)) -static const u_int rss_maxcpus = RSS_MAXCPUS; -SYSCTL_INT(_net_inet_rss, OID_AUTO, maxcpus, CTLFLAG_RD, - __DECONST(int *, &rss_maxcpus), 0, "RSS maximum CPUs that can be used"); - -/* - * Variable exists just for reporting rss_bits in a user-friendly way. - */ -static u_int rss_buckets; -SYSCTL_INT(_net_inet_rss, OID_AUTO, buckets, CTLFLAG_RD, &rss_buckets, 0, - "RSS buckets"); - -/* - * Base CPU number; devices will add this to all CPU numbers returned by the - * RSS indirection table. Currently unmodifable in FreeBSD. - */ -static const u_int rss_basecpu; -SYSCTL_INT(_net_inet_rss, OID_AUTO, basecpu, CTLFLAG_RD, - __DECONST(int *, &rss_basecpu), 0, "RSS base CPU"); - -/* - * RSS secret key, intended to prevent attacks on load-balancing. Its - * effectiveness may be limited by algorithm choice and available entropy - * during the boot. - * - * XXXRW: And that we don't randomize it yet! - * - * This is the default Microsoft RSS specification key which is also - * the Chelsio T5 firmware default key. - */ -static uint8_t rss_key[RSS_KEYSIZE] = { - 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2, - 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0, - 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4, - 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c, - 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa, -}; - -/* - * RSS hash->CPU table, which maps hashed packet headers to particular CPUs. - * Drivers may supplement this table with a seperate CPU<->queue table when - * programming devices. - */ -struct rss_table_entry { - uint8_t rte_cpu; /* CPU affinity of bucket. */ -}; -static struct rss_table_entry rss_table[RSS_TABLE_MAXLEN]; - -static inline u_int rss_gethashconfig_local(void); - -static void -rss_init(__unused void *arg) -{ - u_int i; - u_int cpuid; - - /* - * Validate tunables, coerce to sensible values. - */ - switch (rss_hashalgo) { - case RSS_HASH_TOEPLITZ: - case RSS_HASH_NAIVE: - break; - - default: - printf("%s: invalid RSS hashalgo %u, coercing to %u", - __func__, rss_hashalgo, RSS_HASH_TOEPLITZ); - rss_hashalgo = RSS_HASH_TOEPLITZ; - } - - /* - * Count available CPUs. - * - * XXXRW: Note incorrect assumptions regarding contiguity of this set - * elsewhere. - */ - rss_ncpus = 0; - for (i = 0; i <= mp_maxid; i++) { - if (CPU_ABSENT(i)) - continue; - rss_ncpus++; - } - if (rss_ncpus > RSS_MAXCPUS) - rss_ncpus = RSS_MAXCPUS; - - /* - * Tune RSS table entries to be no less than 2x the number of CPUs - * -- unless we're running uniprocessor, in which case there's not - * much point in having buckets to rearrange for load-balancing! - */ - if (rss_ncpus > 1) { - if (rss_bits == 0) - rss_bits = fls(rss_ncpus - 1) + 1; - - /* - * Microsoft limits RSS table entries to 128, so apply that - * limit to both auto-detected CPU counts and user-configured - * ones. - */ - if (rss_bits == 0 || rss_bits > RSS_MAXBITS) { - printf("%s: RSS bits %u not valid, coercing to %u", - __func__, rss_bits, RSS_MAXBITS); - rss_bits = RSS_MAXBITS; - } - - /* - * Figure out how many buckets to use; warn if less than the - * number of configured CPUs, although this is not a fatal - * problem. - */ - rss_buckets = (1 << rss_bits); - if (rss_buckets < rss_ncpus) - printf("%s: WARNING: rss_buckets (%u) less than " - "rss_ncpus (%u)\n", __func__, rss_buckets, - rss_ncpus); - rss_mask = rss_buckets - 1; - } else { - rss_bits = 0; - rss_buckets = 1; - rss_mask = 0; - } - - /* - * Set up initial CPU assignments: round-robin by default. - */ - cpuid = CPU_FIRST(); - for (i = 0; i < rss_buckets; i++) { - rss_table[i].rte_cpu = cpuid; - cpuid = CPU_NEXT(cpuid); - } - - /* - * Randomize rrs_key. - * - * XXXRW: Not yet. If nothing else, will require an rss_isbadkey() - * loop to check for "bad" RSS keys. - */ -} -SYSINIT(rss_init, SI_SUB_SOFTINTR, SI_ORDER_SECOND, rss_init, NULL); - -static uint32_t -rss_naive_hash(u_int keylen, const uint8_t *key, u_int datalen, - const uint8_t *data) -{ - uint32_t v; - u_int i; - - v = 0; - for (i = 0; i < keylen; i++) - v += key[i]; - for (i = 0; i < datalen; i++) - v += data[i]; - return (v); -} - -static uint32_t -rss_hash(u_int datalen, const uint8_t *data) -{ - - switch (rss_hashalgo) { - case RSS_HASH_TOEPLITZ: - return (toeplitz_hash(sizeof(rss_key), rss_key, datalen, - data)); - - case RSS_HASH_NAIVE: - return (rss_naive_hash(sizeof(rss_key), rss_key, datalen, - data)); - - default: - panic("%s: unsupported/unknown hashalgo %d", __func__, - rss_hashalgo); - } -} - /* * Hash an IPv4 2-tuple. */ @@ -341,162 +102,6 @@ rss_hash_ip4_4tuple(struct in_addr src, u_short srcport, struct in_addr dst, return (rss_hash(datalen, data)); } -#ifdef INET6 -/* - * Hash an IPv6 2-tuple. - */ -uint32_t -rss_hash_ip6_2tuple(const struct in6_addr *src, const struct in6_addr *dst) -{ - uint8_t data[sizeof(*src) + sizeof(*dst)]; - u_int datalen; - - datalen = 0; - bcopy(src, &data[datalen], sizeof(*src)); - datalen += sizeof(*src); - bcopy(dst, &data[datalen], sizeof(*dst)); - datalen += sizeof(*dst); - return (rss_hash(datalen, data)); -} - -/* - * Hash an IPv6 4-tuple. - */ -uint32_t -rss_hash_ip6_4tuple(const struct in6_addr *src, u_short srcport, - const struct in6_addr *dst, u_short dstport) -{ - uint8_t data[sizeof(*src) + sizeof(*dst) + sizeof(srcport) + - sizeof(dstport)]; - u_int datalen; - - datalen = 0; - bcopy(src, &data[datalen], sizeof(*src)); - datalen += sizeof(*src); - bcopy(dst, &data[datalen], sizeof(*dst)); - datalen += sizeof(*dst); - bcopy(&srcport, &data[datalen], sizeof(srcport)); - datalen += sizeof(srcport); - bcopy(&dstport, &data[datalen], sizeof(dstport)); - datalen += sizeof(dstport); - return (rss_hash(datalen, data)); -} -#endif /* INET6 */ - -/* - * Query the number of RSS bits in use. - */ -u_int -rss_getbits(void) -{ - - return (rss_bits); -} - -/* - * Query the RSS bucket associated with an RSS hash. - */ -u_int -rss_getbucket(u_int hash) -{ - - return (hash & rss_mask); -} - -/* - * Query the RSS layer bucket associated with the given - * entry in the RSS hash space. - * - * The RSS indirection table is 0 .. rss_buckets-1, - * covering the low 'rss_bits' of the total 128 slot - * RSS indirection table. So just mask off rss_bits and - * return that. - * - * NIC drivers can then iterate over the 128 slot RSS - * indirection table and fetch which RSS bucket to - * map it to. This will typically be a CPU queue - */ -u_int -rss_get_indirection_to_bucket(u_int index) -{ - - return (index & rss_mask); -} - -/* - * Query the RSS CPU associated with an RSS bucket. - */ -u_int -rss_getcpu(u_int bucket) -{ - - return (rss_table[bucket].rte_cpu); -} - -/* - * netisr CPU affinity lookup given just the hash and hashtype. - */ -u_int -rss_hash2cpuid(uint32_t hash_val, uint32_t hash_type) -{ - - switch (hash_type) { - case M_HASHTYPE_RSS_IPV4: - case M_HASHTYPE_RSS_TCP_IPV4: - case M_HASHTYPE_RSS_UDP_IPV4: - case M_HASHTYPE_RSS_IPV6: - case M_HASHTYPE_RSS_TCP_IPV6: - case M_HASHTYPE_RSS_UDP_IPV6: - return (rss_getcpu(rss_getbucket(hash_val))); - default: - return (NETISR_CPUID_NONE); - } -} - -/* - * Query the RSS bucket associated with the given hash value and - * type. - */ -int -rss_hash2bucket(uint32_t hash_val, uint32_t hash_type, uint32_t *bucket_id) -{ - - switch (hash_type) { - case M_HASHTYPE_RSS_IPV4: - case M_HASHTYPE_RSS_TCP_IPV4: - case M_HASHTYPE_RSS_UDP_IPV4: - case M_HASHTYPE_RSS_IPV6: - case M_HASHTYPE_RSS_TCP_IPV6: - case M_HASHTYPE_RSS_UDP_IPV6: - *bucket_id = rss_getbucket(hash_val); - return (0); - default: - return (-1); - } -} - -/* - * netisr CPU affinity lookup routine for use by protocols. - */ -struct mbuf * -rss_m2cpuid(struct mbuf *m, uintptr_t source, u_int *cpuid) -{ - - M_ASSERTPKTHDR(m); - *cpuid = rss_hash2cpuid(m->m_pkthdr.flowid, M_HASHTYPE_GET(m)); - return (m); -} - -int -rss_m2bucket(struct mbuf *m, uint32_t *bucket_id) -{ - - M_ASSERTPKTHDR(m); - - return(rss_hash2bucket(m->m_pkthdr.flowid, M_HASHTYPE_GET(m), - bucket_id)); -} - /* * Calculate an appropriate ipv4 2-tuple or 4-tuple given the given * IPv4 source/destination address, UDP or TCP source/destination ports @@ -522,18 +127,18 @@ rss_proto_software_hash_v4(struct in_addr s, struct in_addr d, * identifier. */ if ((proto == IPPROTO_TCP) && - (rss_gethashconfig_local() & RSS_HASHTYPE_RSS_TCP_IPV4)) { + (rss_gethashconfig() & RSS_HASHTYPE_RSS_TCP_IPV4)) { hash = rss_hash_ip4_4tuple(s, sp, d, dp); *hashval = hash; *hashtype = M_HASHTYPE_RSS_TCP_IPV4; return (0); } else if ((proto == IPPROTO_UDP) && - (rss_gethashconfig_local() & RSS_HASHTYPE_RSS_UDP_IPV4)) { + (rss_gethashconfig() & RSS_HASHTYPE_RSS_UDP_IPV4)) { hash = rss_hash_ip4_4tuple(s, sp, d, dp); *hashval = hash; *hashtype = M_HASHTYPE_RSS_UDP_IPV4; return (0); - } else if (rss_gethashconfig_local() & RSS_HASHTYPE_RSS_IPV4) { + } else if (rss_gethashconfig() & RSS_HASHTYPE_RSS_IPV4) { /* RSS doesn't hash on other protocols like SCTP; so 2-tuple */ hash = rss_hash_ip4_2tuple(s, d); *hashval = hash; @@ -625,7 +230,7 @@ rss_mbuf_software_hash_v4(const struct mbuf *m, int dir, uint32_t *hashval, if (flowtype != M_HASHTYPE_NONE) { switch (proto) { case IPPROTO_UDP: - if ((rss_gethashconfig_local() & RSS_HASHTYPE_RSS_UDP_IPV4) && + if ((rss_gethashconfig() & RSS_HASHTYPE_RSS_UDP_IPV4) && (flowtype == M_HASHTYPE_RSS_UDP_IPV4) && (is_frag == 0)) { return (1); @@ -634,14 +239,14 @@ rss_mbuf_software_hash_v4(const struct mbuf *m, int dir, uint32_t *hashval, * Only allow 2-tuple for UDP frames if we don't also * support 4-tuple for UDP. */ - if ((rss_gethashconfig_local() & RSS_HASHTYPE_RSS_IPV4) && - ((rss_gethashconfig_local() & RSS_HASHTYPE_RSS_UDP_IPV4) == 0) && + if ((rss_gethashconfig() & RSS_HASHTYPE_RSS_IPV4) && + ((rss_gethashconfig() & RSS_HASHTYPE_RSS_UDP_IPV4) == 0) && flowtype == M_HASHTYPE_RSS_IPV4) { return (1); } break; case IPPROTO_TCP: - if ((rss_gethashconfig_local() & RSS_HASHTYPE_RSS_TCP_IPV4) && + if ((rss_gethashconfig() & RSS_HASHTYPE_RSS_TCP_IPV4) && (flowtype == M_HASHTYPE_RSS_TCP_IPV4) && (is_frag == 0)) { return (1); @@ -650,14 +255,14 @@ rss_mbuf_software_hash_v4(const struct mbuf *m, int dir, uint32_t *hashval, * Only allow 2-tuple for TCP frames if we don't also * support 2-tuple for TCP. */ - if ((rss_gethashconfig_local() & RSS_HASHTYPE_RSS_IPV4) && - ((rss_gethashconfig_local() & RSS_HASHTYPE_RSS_TCP_IPV4) == 0) && + if ((rss_gethashconfig() & RSS_HASHTYPE_RSS_IPV4) && + ((rss_gethashconfig() & RSS_HASHTYPE_RSS_TCP_IPV4) == 0) && flowtype == M_HASHTYPE_RSS_IPV4) { return (1); } break; default: - if ((rss_gethashconfig_local() & RSS_HASHTYPE_RSS_IPV4) && + if ((rss_gethashconfig() & RSS_HASHTYPE_RSS_IPV4) && flowtype == M_HASHTYPE_RSS_IPV4) { return (1); } @@ -671,7 +276,7 @@ rss_mbuf_software_hash_v4(const struct mbuf *m, int dir, uint32_t *hashval, * XXX TODO: does the hardware hash on 4-tuple if IP * options are present? */ - if ((rss_gethashconfig_local() & RSS_HASHTYPE_RSS_TCP_IPV4) && + if ((rss_gethashconfig() & RSS_HASHTYPE_RSS_TCP_IPV4) && (proto == IPPROTO_TCP) && (is_frag == 0)) { if (m->m_len < iphlen + sizeof(struct tcphdr)) { @@ -685,7 +290,7 @@ rss_mbuf_software_hash_v4(const struct mbuf *m, int dir, uint32_t *hashval, proto, hashval, hashtype); - } else if ((rss_gethashconfig_local() & RSS_HASHTYPE_RSS_UDP_IPV4) && + } else if ((rss_gethashconfig() & RSS_HASHTYPE_RSS_UDP_IPV4) && (proto == IPPROTO_UDP) && (is_frag == 0)) { uh = (struct udphdr *)((caddr_t)ip + iphlen); @@ -699,7 +304,7 @@ rss_mbuf_software_hash_v4(const struct mbuf *m, int dir, uint32_t *hashval, proto, hashval, hashtype); - } else if (rss_gethashconfig_local() & RSS_HASHTYPE_RSS_IPV4) { + } else if (rss_gethashconfig() & RSS_HASHTYPE_RSS_IPV4) { /* Default to 2-tuple hash */ return rss_proto_software_hash_v4(ip->ip_src, ip->ip_dst, 0, /* source port */ @@ -750,150 +355,3 @@ rss_soft_m2cpuid(struct mbuf *m, uintptr_t source, u_int *cpuid) } return (m); } - -/* - * Query the RSS hash algorithm. - */ -u_int -rss_gethashalgo(void) -{ - - return (rss_hashalgo); -} - -/* - * Query the current RSS key; likely to be used by device drivers when - * configuring hardware RSS. Caller must pass an array of size RSS_KEYSIZE. - * - * XXXRW: Perhaps we should do the accept-a-length-and-truncate thing? - */ -void -rss_getkey(uint8_t *key) -{ - - bcopy(rss_key, key, sizeof(rss_key)); -} - -/* - * Query the number of buckets; this may be used by both network device - * drivers, which will need to populate hardware shadows of the software - * indirection table, and the network stack itself (such as when deciding how - * many connection groups to allocate). - */ -u_int -rss_getnumbuckets(void) -{ - - return (rss_buckets); -} - -/* - * Query the number of CPUs in use by RSS; may be useful to device drivers - * trying to figure out how to map a larger number of CPUs into a smaller - * number of receive queues. - */ -u_int -rss_getnumcpus(void) -{ - - return (rss_ncpus); -} - -static inline u_int -rss_gethashconfig_local(void) -{ - - /* Return 4-tuple for TCP; 2-tuple for others */ - /* - * UDP may fragment more often than TCP and thus we'll end up with - * NICs returning 2-tuple fragments. - * udp_init() and udplite_init() both currently initialise things - * as 2-tuple. - * So for now disable UDP 4-tuple hashing until all of the other - * pieces are in place. - */ - return ( - RSS_HASHTYPE_RSS_IPV4 - | RSS_HASHTYPE_RSS_TCP_IPV4 - | RSS_HASHTYPE_RSS_IPV6 - | RSS_HASHTYPE_RSS_TCP_IPV6 - | RSS_HASHTYPE_RSS_IPV6_EX - | RSS_HASHTYPE_RSS_TCP_IPV6_EX -#if 0 - | RSS_HASHTYPE_RSS_UDP_IPV4 - | RSS_HASHTYPE_RSS_UDP_IPV4_EX - | RSS_HASHTYPE_RSS_UDP_IPV6 - | RSS_HASHTYPE_RSS_UDP_IPV6_EX -#endif - ); -} - -/* - * Return the supported RSS hash configuration. - * - * NICs should query this to determine what to configure in their redirection - * matching table. - */ -u_int -rss_gethashconfig(void) -{ - - return (rss_gethashconfig_local()); -} - -/* - * XXXRW: Confirm that sysctl -a won't dump this keying material, don't want - * it appearing in debugging output unnecessarily. - */ -static int -sysctl_rss_key(SYSCTL_HANDLER_ARGS) -{ - uint8_t temp_rss_key[RSS_KEYSIZE]; - int error; - - error = priv_check(req->td, PRIV_NETINET_HASHKEY); - if (error) - return (error); - - bcopy(rss_key, temp_rss_key, sizeof(temp_rss_key)); - error = sysctl_handle_opaque(oidp, temp_rss_key, - sizeof(temp_rss_key), req); - if (error) - return (error); - if (req->newptr != NULL) { - /* XXXRW: Not yet. */ - return (EINVAL); - } - return (0); -} -SYSCTL_PROC(_net_inet_rss, OID_AUTO, key, - CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, sysctl_rss_key, - "", "RSS keying material"); - -static int -sysctl_rss_bucket_mapping(SYSCTL_HANDLER_ARGS) -{ - struct sbuf *sb; - int error; - int i; - - error = 0; - error = sysctl_wire_old_buffer(req, 0); - if (error != 0) - return (error); - sb = sbuf_new_for_sysctl(NULL, NULL, 512, req); - if (sb == NULL) - return (ENOMEM); - for (i = 0; i < rss_buckets; i++) { - sbuf_printf(sb, "%s%d:%d", i == 0 ? "" : " ", - i, - rss_getcpu(i)); - } - error = sbuf_finish(sb); - sbuf_delete(sb); - - return (error); -} -SYSCTL_PROC(_net_inet_rss, OID_AUTO, bucket_mapping, - CTLTYPE_STRING | CTLFLAG_RD, NULL, 0, - sysctl_rss_bucket_mapping, "", "RSS bucket -> CPU mapping"); diff --git a/sys/netinet/in_rss.h b/sys/netinet/in_rss.h index 90d28ed53099..f493eab9a469 100644 --- a/sys/netinet/in_rss.h +++ b/sys/netinet/in_rss.h @@ -34,97 +34,12 @@ #include /* in_addr_t */ -/* - * Supported RSS hash functions. - */ -#define RSS_HASH_NAIVE 0x00000001 /* Poor but fast hash. */ -#define RSS_HASH_TOEPLITZ 0x00000002 /* Required by RSS. */ -#define RSS_HASH_CRC32 0x00000004 /* Future; some NICs do it. */ - -#define RSS_HASH_MASK (RSS_HASH_NAIVE | RSS_HASH_TOEPLITZ) - -/* - * Instances of struct inpcbinfo declare an RSS hash type indicating what - * header fields are covered. - */ -#define RSS_HASHFIELDS_NONE 0 -#define RSS_HASHFIELDS_4TUPLE 1 -#define RSS_HASHFIELDS_2TUPLE 2 - -/* - * Define RSS representations of the M_HASHTYPE_* values, representing - * which particular bits are supported. The NICs can then use this to - * calculate which hash types to enable and which not to enable. - * - * The fact that these line up with M_HASHTYPE_* is not to be relied - * upon. - */ -#define RSS_HASHTYPE_RSS_IPV4 (1 << 1) /* IPv4 2-tuple */ -#define RSS_HASHTYPE_RSS_TCP_IPV4 (1 << 2) /* TCPv4 4-tuple */ -#define RSS_HASHTYPE_RSS_IPV6 (1 << 3) /* IPv6 2-tuple */ -#define RSS_HASHTYPE_RSS_TCP_IPV6 (1 << 4) /* TCPv6 4-tuple */ -#define RSS_HASHTYPE_RSS_IPV6_EX (1 << 5) /* IPv6 2-tuple + ext hdrs */ -#define RSS_HASHTYPE_RSS_TCP_IPV6_EX (1 << 6) /* TCPv6 4-tiple + ext hdrs */ -#define RSS_HASHTYPE_RSS_UDP_IPV4 (1 << 7) /* IPv4 UDP 4-tuple */ -#define RSS_HASHTYPE_RSS_UDP_IPV4_EX (1 << 8) /* IPv4 UDP 4-tuple + ext hdrs */ -#define RSS_HASHTYPE_RSS_UDP_IPV6 (1 << 9) /* IPv6 UDP 4-tuple */ -#define RSS_HASHTYPE_RSS_UDP_IPV6_EX (1 << 10) /* IPv6 UDP 4-tuple + ext hdrs */ - -/* - * Compile-time limits on the size of the indirection table. - */ -#define RSS_MAXBITS 7 -#define RSS_TABLE_MAXLEN (1 << RSS_MAXBITS) - -/* - * Maximum key size used throughout. It's OK for hardware to use only the - * first 16 bytes, which is all that's required for IPv4. - */ -#define RSS_KEYSIZE 40 - -/* - * For RSS hash methods that do a software hash on an mbuf, the packet - * direction (ingress / egress) is required. - * - * The default direction (INGRESS) is the "receive into the NIC" - ie, - * what the hardware is hashing on. - */ -#define RSS_HASH_PKT_INGRESS 0 -#define RSS_HASH_PKT_EGRESS 1 - -/* - * Device driver interfaces to query RSS properties that must be programmed - * into hardware. - */ -u_int rss_getbits(void); -u_int rss_getbucket(u_int hash); -u_int rss_get_indirection_to_bucket(u_int index); -u_int rss_getcpu(u_int bucket); -void rss_getkey(uint8_t *key); -u_int rss_gethashalgo(void); -u_int rss_getnumbuckets(void); -u_int rss_getnumcpus(void); -u_int rss_gethashconfig(void); - /* * Network stack interface to generate a hash for a protocol tuple. */ uint32_t rss_hash_ip4_4tuple(struct in_addr src, u_short srcport, struct in_addr dst, u_short dstport); uint32_t rss_hash_ip4_2tuple(struct in_addr src, struct in_addr dst); -uint32_t rss_hash_ip6_4tuple(const struct in6_addr *src, u_short srcport, - const struct in6_addr *dst, u_short dstport); -uint32_t rss_hash_ip6_2tuple(const struct in6_addr *src, - const struct in6_addr *dst); - -/* - * Network stack interface to query desired CPU affinity of a packet. - */ -struct mbuf *rss_m2cpuid(struct mbuf *m, uintptr_t source, u_int *cpuid); -u_int rss_hash2cpuid(uint32_t hash_val, uint32_t hash_type); -int rss_hash2bucket(uint32_t hash_val, uint32_t hash_type, - uint32_t *bucket_id); -int rss_m2bucket(struct mbuf *m, uint32_t *bucket_id); /* * Functions to calculate a software RSS hash for a given mbuf or diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index adbc449de071..9ca6f700099c 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 275c29d1ea49..ccd5e898da9e 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -65,6 +65,7 @@ __FBSDID("$FreeBSD$"); #ifdef RADIX_MPATH #include #endif +#include #include #include diff --git a/sys/netinet/tcp_timer.c b/sys/netinet/tcp_timer.c index 5d379ea38dfd..6cd0ffd239ca 100644 --- a/sys/netinet/tcp_timer.c +++ b/sys/netinet/tcp_timer.c @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index 482ee1510385..d13821fbb5c3 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -70,6 +70,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include diff --git a/sys/netinet6/in6_pcbgroup.c b/sys/netinet6/in6_pcbgroup.c index 45773ed055e4..694de99f3129 100644 --- a/sys/netinet6/in6_pcbgroup.c +++ b/sys/netinet6/in6_pcbgroup.c @@ -37,11 +37,13 @@ __FBSDID("$FreeBSD$"); #include #include +#include + #include #include -#include #ifdef INET6 #include +#include #endif /* INET6 */ /* diff --git a/sys/netinet6/in6_rss.c b/sys/netinet6/in6_rss.c new file mode 100644 index 000000000000..40d54d94c9ec --- /dev/null +++ b/sys/netinet6/in6_rss.c @@ -0,0 +1,103 @@ +/*- + * Copyright (c) 2010-2011 Juniper Networks, Inc. + * All rights reserved. + * + * This software was developed by Robert N. M. Watson under contract + * to Juniper Networks, Inc. + * + * 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_inet6.h" +#include "opt_pcbgroup.h" + +#ifndef PCBGROUP +#error "options RSS depends on options PCBGROUP" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +/* for software rss hash support */ +#include +#include +#include + +/* + * Hash an IPv6 2-tuple. + */ +uint32_t +rss_hash_ip6_2tuple(const struct in6_addr *src, const struct in6_addr *dst) +{ + uint8_t data[sizeof(*src) + sizeof(*dst)]; + u_int datalen; + + datalen = 0; + bcopy(src, &data[datalen], sizeof(*src)); + datalen += sizeof(*src); + bcopy(dst, &data[datalen], sizeof(*dst)); + datalen += sizeof(*dst); + return (rss_hash(datalen, data)); +} + +/* + * Hash an IPv6 4-tuple. + */ +uint32_t +rss_hash_ip6_4tuple(const struct in6_addr *src, u_short srcport, + const struct in6_addr *dst, u_short dstport) +{ + uint8_t data[sizeof(*src) + sizeof(*dst) + sizeof(srcport) + + sizeof(dstport)]; + u_int datalen; + + datalen = 0; + bcopy(src, &data[datalen], sizeof(*src)); + datalen += sizeof(*src); + bcopy(dst, &data[datalen], sizeof(*dst)); + datalen += sizeof(*dst); + bcopy(&srcport, &data[datalen], sizeof(srcport)); + datalen += sizeof(srcport); + bcopy(&dstport, &data[datalen], sizeof(dstport)); + datalen += sizeof(dstport); + return (rss_hash(datalen, data)); +} diff --git a/sys/netinet6/in6_rss.h b/sys/netinet6/in6_rss.h new file mode 100644 index 000000000000..b215b5b80a0c --- /dev/null +++ b/sys/netinet6/in6_rss.h @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 2010-2011 Juniper Networks, Inc. + * All rights reserved. + * + * This software was developed by Robert N. M. Watson under contract + * to Juniper Networks, Inc. + * + * 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 _NETINET6_IN6_RSS_H_ +#define _NETINET6_IN6_RSS_H_ + +#include /* in_addr_t */ + +/* + * Network stack interface to generate a hash for a protocol tuple. + */ +uint32_t rss_hash_ip6_4tuple(const struct in6_addr *src, u_short srcport, + const struct in6_addr *dst, u_short dstport); +uint32_t rss_hash_ip6_2tuple(const struct in6_addr *src, + const struct in6_addr *dst); + +#endif /* !_NETINET6_IN6_RSS_H_ */ diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index 32308e49fde5..a3474d34dc35 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -91,6 +91,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -103,7 +104,7 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include +#include #ifdef IPSEC #include diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c index fc6b6a0a810a..ab4dc7a8ce3b 100644 --- a/sys/netinet6/udp6_usrreq.c +++ b/sys/netinet6/udp6_usrreq.c @@ -97,6 +97,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -112,11 +113,11 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include #include +#include #include #include From 1ac50c4c33db8aa0a2923a7f2a0e25cbdee3a40b Mon Sep 17 00:00:00 2001 From: smh Date: Sun, 18 Jan 2015 18:25:12 +0000 Subject: [PATCH 051/258] Fix bsdinstall when working with geli boot disks PR: 196790 Differential Revision: https://reviews.freebsd.org/D566 Submitted by: Michael Gmelin MFC after: 2 weeks Sponsored by: Multiplay --- usr.sbin/bsdinstall/scripts/zfsboot | 3 +++ 1 file changed, 3 insertions(+) diff --git a/usr.sbin/bsdinstall/scripts/zfsboot b/usr.sbin/bsdinstall/scripts/zfsboot index 673961aef980..5bdf94fa0a98 100755 --- a/usr.sbin/bsdinstall/scripts/zfsboot +++ b/usr.sbin/bsdinstall/scripts/zfsboot @@ -1077,6 +1077,9 @@ zfs_create_boot() boot_vdevs="$boot_vdevs $disk$bootpart" fi zroot_vdevs="$zroot_vdevs $disk$targetpart" + if [ "$ZFSBOOT_GELI_ENCRYPTION" ]; then + zroot_vdevs="$zroot_vdevs.eli" + fi n=$(( $n + 1 )) done # disks From 3511827a804deda5b4a1e167acbf8c3086c173c7 Mon Sep 17 00:00:00 2001 From: nwhitehorn Date: Sun, 18 Jan 2015 18:32:43 +0000 Subject: [PATCH 052/258] Refactor PowerPC (especially AIM) init sequence to be less baroque. MFC after: 2 months --- sys/conf/ldscript.powerpc | 1 + sys/conf/ldscript.powerpc64 | 3 +- sys/powerpc/aim/locore32.S | 56 ++----------- sys/powerpc/aim/locore64.S | 124 +++++++++-------------------- sys/powerpc/aim/machdep.c | 18 +++-- sys/powerpc/aim/trap_subr64.S | 15 ++-- sys/powerpc/booke/locore.S | 22 +---- sys/powerpc/include/trap.h | 3 + sys/powerpc/ofw/ofw_machdep.c | 16 +++- sys/powerpc/powerpc/intr_machdep.c | 5 ++ sys/powerpc/powerpc/vm_machdep.c | 7 +- 11 files changed, 92 insertions(+), 178 deletions(-) diff --git a/sys/conf/ldscript.powerpc b/sys/conf/ldscript.powerpc index efc0dfdf1273..b190dc193b02 100644 --- a/sys/conf/ldscript.powerpc +++ b/sys/conf/ldscript.powerpc @@ -11,6 +11,7 @@ SECTIONS /* Read-only sections, merged into text segment: */ . = kernbase + SIZEOF_HEADERS; + PROVIDE (begin = . - SIZEOF_HEADERS); .text : { diff --git a/sys/conf/ldscript.powerpc64 b/sys/conf/ldscript.powerpc64 index ce235516f0d5..dba745538be7 100644 --- a/sys/conf/ldscript.powerpc64 +++ b/sys/conf/ldscript.powerpc64 @@ -11,6 +11,7 @@ SECTIONS /* Read-only sections, merged into text segment: */ . = kernbase + SIZEOF_HEADERS; + PROVIDE (begin = . - SIZEOF_HEADERS); .text : { @@ -68,7 +69,7 @@ SECTIONS .toc1 : ALIGN(8) { *(.toc1) } .opd : ALIGN(8) { KEEP (*(.opd)) } .branch_lt : ALIGN(8) { *(.branch_lt) } - .got : ALIGN(8) { *(.got .toc) } + .got : ALIGN(8) { __tocbase = .; *(.got .toc) } .dynamic : { *(.dynamic) } /* Put .ctors and .dtors next to the .got2 section, so that the pointers diff --git a/sys/powerpc/aim/locore32.S b/sys/powerpc/aim/locore32.S index 8cee6654b2e0..6e462a05d33b 100644 --- a/sys/powerpc/aim/locore32.S +++ b/sys/powerpc/aim/locore32.S @@ -76,29 +76,19 @@ .globl kernbase .set kernbase, KERNBASE -#define TMPSTKSZ 8192 /* 8K temporary stack */ - /* * Globals */ .data + .align 3 +GLOBAL(__startkernel) + .long begin +GLOBAL(__endkernel) + .long end .align 4 +#define TMPSTKSZ 8192 /* 8K temporary stack */ GLOBAL(tmpstk) .space TMPSTKSZ -GLOBAL(esym) - .long 0 /* end of symbol table */ - -#define INTRCNT_COUNT 256 /* max(HROWPIC_IRQMAX,OPENPIC_IRQMAX) */ -GLOBAL(intrnames) - .space INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 -GLOBAL(sintrnames) - .long INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 - - .align 4 -GLOBAL(intrcnt) - .space INTRCNT_COUNT * 4 * 2 -GLOBAL(sintrcnt) - .long INTRCNT_COUNT * 4 * 2 .text .globl btext @@ -142,43 +132,9 @@ __start: cmplw 8,9 blt 2b - /* Save the argument pointer and length */ - mr 20,6 - mr 21,7 - - lis 8,openfirmware_entry@ha - stw 5,openfirmware_entry@l(8) /* save client interface handler */ - lis 1,(tmpstk+TMPSTKSZ-16)@ha addi 1,1,(tmpstk+TMPSTKSZ-16)@l - mfmsr 0 - lis 9,ofmsr@ha - stwu 0,ofmsr@l(9) - - mfsprg0 0 /* save SPRG0-3 */ - stw 0,4(9) /* ofmsr[1] = sprg0 */ - mfsprg1 0 - stw 0,8(9) /* ofmsr[2] = sprg1 */ - mfsprg2 0 - stw 0,12(9) /* ofmsr[3] = sprg2 */ - mfsprg3 0 - stw 0,16(9) /* ofmsr[4] = sprg3 */ - - bl OF_initial_setup - - lis 3,kernel_text@ha - addi 3,3,kernel_text@l - - lis 4,end@ha - addi 4,4,end@l - add 4,4,3 - mr 5,4 - - /* Restore the argument pointer and length */ - mr 6,20 - mr 7,21 - bl powerpc_init mr %r1, %r3 li %r3, 0 diff --git a/sys/powerpc/aim/locore64.S b/sys/powerpc/aim/locore64.S index 0c26e01125b3..4865e75dc18d 100644 --- a/sys/powerpc/aim/locore64.S +++ b/sys/powerpc/aim/locore64.S @@ -68,36 +68,28 @@ /* Locate the per-CPU data structure */ #define GET_CPUINFO(r) \ mfsprg0 r +#define GET_TOCBASE(r) \ + li r,TRAP_TOCBASE; /* Magic address for TOC */ \ + ld r,0(r) -/* - * Compiled KERNBASE location and the kernel load address - */ - .globl kernbase - .set kernbase, KERNBASE - -#define TMPSTKSZ 16384 /* 16K temporary stack */ +/* Glue for linker script */ +.globl kernbase +.set kernbase, KERNBASE /* * Globals */ .data + .align 3 +GLOBAL(__startkernel) + .llong begin +GLOBAL(__endkernel) + .llong end + .align 4 +#define TMPSTKSZ 16384 /* 16K temporary stack */ GLOBAL(tmpstk) .space TMPSTKSZ -GLOBAL(esym) - .llong 0 /* end of symbol table */ - -#define INTRCNT_COUNT 256 /* max(HROWPIC_IRQMAX,OPENPIC_IRQMAX) */ -GLOBAL(intrnames) - .space INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 -GLOBAL(sintrnames) - .quad INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 - - .align 4 -GLOBAL(intrcnt) - .space INTRCNT_COUNT * 4 * 2 -GLOBAL(sintrcnt) - .quad INTRCNT_COUNT * 4 * 2 .text .globl btext @@ -113,89 +105,51 @@ kernel_text: /* * Startup entry. Note, this must be the first thing in the text * segment! + * + * Calling convention: + * r3: Flattened Device Tree pointer (or zero) + * r4: ignored + * r5: OF client interface pointer (or zero) + * r6: Loader metadata pointer (or zero) */ .text ASENTRY_NOPROF(__start) - li 8,0 - li 9,0x100 - mtctr 9 -1: - dcbf 0,8 - icbi 0,8 - addi 8,8,0x20 - bdnz 1b - sync - isync - - /* Save the argument pointer and length */ - mr 20,6 - mr 21,7 - - lis 8,openfirmware_entry@ha - std 5,openfirmware_entry@l(8) /* save client interface handler */ + /* Set up the TOC pointer */ + b 0f + .align 3 +0: nop + bl 1f + .llong __tocbase + 0x8000 +1: mflr %r2 + ld %r2,0(%r2) /* Set up the stack pointer */ - lis 1,(tmpstk+TMPSTKSZ-48)@ha - addi 1,1,(tmpstk+TMPSTKSZ-48)@l - - /* Set up the TOC pointer */ - lis 2,tocbase@ha - ld 2,tocbase@l(2) - - mfmsr 0 - lis 9,ofmsr@ha - stdu 0,ofmsr@l(9) - - mfsprg0 0 /* save SPRG0-3 */ - std 0,8(9) /* ofmsr[1] = sprg0 */ - mfsprg1 0 - std 0,16(9) /* ofmsr[2] = sprg1 */ - mfsprg2 0 - std 0,24(9) /* ofmsr[3] = sprg2 */ - mfsprg3 0 - std 0,32(9) /* ofmsr[4] = sprg3 */ + lis %r1,(tmpstk+TMPSTKSZ-48)@ha + addi %r1,%r1,(tmpstk+TMPSTKSZ-48)@l /* Switch to 64-bit mode */ - mfmsr 9 - li 8,1 - insrdi 9,8,1,0 - mtmsrd 9 + mfmsr %r9 + li %r8,1 + insrdi %r9,%r8,1,0 + mtmsrd %r9 isync - bl OF_initial_setup - nop - - lis 3,kernbase@ha - addi 3,3,kernbase@l - - lis 4,end@ha - addi 4,4,end@l - add 4,4,3 - mr 5,4 - - /* Restore the argument pointer and length */ - mr 6,20 - mr 7,21 - + /* Begin CPU init */ + mr %r4,%r2 /* Replace ignored r4 with tocbase for trap handlers */ bl powerpc_init nop + + /* Set stack pointer to new value and branch to mi_startup */ mr %r1, %r3 li %r3, 0 std %r3, 0(%r1) bl mi_startup nop + + /* If this returns (it won't), go back to firmware */ b OF_exit nop -/* - * PPC64 ABI TOC base - */ - - .align 3 - .globl tocbase -tocbase: - .llong .TOC.@tocbase - /* * int setfault() * diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c index d1413a2c4aba..fdbe48b4b54f 100644 --- a/sys/powerpc/aim/machdep.c +++ b/sys/powerpc/aim/machdep.c @@ -223,7 +223,7 @@ cpu_startup(void *dummy) vm_pager_bufferinit(); } -extern char kernel_text[], _end[]; +extern vm_offset_t __startkernel, __endkernel; #ifndef __powerpc64__ /* Bits for running on 64-bit systems in 32-bit mode. */ @@ -244,13 +244,12 @@ extern void *dblow, *dbsize; extern void *imisstrap, *imisssize; extern void *dlmisstrap, *dlmisssize; extern void *dsmisstrap, *dsmisssize; -char save_trap_init[0x2f00]; /* EXC_LAST */ uintptr_t -powerpc_init(vm_offset_t startkernel, vm_offset_t endkernel, - vm_offset_t basekernel, void *mdp) +powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp) { struct pcpu *pc; + vm_offset_t startkernel, endkernel; void *generictrap; size_t trap_offset; void *kmdp; @@ -273,8 +272,12 @@ powerpc_init(vm_offset_t startkernel, vm_offset_t endkernel, trap_offset = 0; cacheline_warn = 0; - /* Save trap vectors. */ - ofw_save_trap_vec(save_trap_init); + /* Store boot environment state */ + OF_initial_setup((void *)fdt, NULL, (int (*)(void *))ofentry); + + /* First guess at start/end kernel positions */ + startkernel = __startkernel; + endkernel = __endkernel; #ifdef WII /* @@ -490,6 +493,9 @@ powerpc_init(vm_offset_t startkernel, vm_offset_t endkernel, #else /* powerpc64 */ cpu_features |= PPC_FEATURE_64; generictrap = &trapcode; + + /* Set TOC base so that the interrupt code can get at it */ + *((register_t *)TRAP_TOCBASE) = toc; #endif bcopy(&rstcode, (void *)(EXC_RST + trap_offset), (size_t)&rstsize); diff --git a/sys/powerpc/aim/trap_subr64.S b/sys/powerpc/aim/trap_subr64.S index 0dc46b34e866..ec3c92579117 100644 --- a/sys/powerpc/aim/trap_subr64.S +++ b/sys/powerpc/aim/trap_subr64.S @@ -310,8 +310,7 @@ cpu_reset: lis %r1,(tmpstk+TMPSTKSZ-48)@ha /* get new SP */ addi %r1,%r1,(tmpstk+TMPSTKSZ-48)@l - lis %r3,tocbase@ha - ld %r2,tocbase@l(%r3) + GET_TOCBASE(%r2) bl CNAME(cpudep_ap_early_bootstrap) /* Set PCPU */ nop lis %r3,1@l @@ -445,8 +444,7 @@ kern_slbtrap: addi %r1,%r1,PC_SLBSTACK-48+1024 li %r2,~15 and %r1,%r1,%r2 - lis %r3,tocbase@ha - ld %r2,tocbase@l(%r3) + GET_TOCBASE(%r2) mflr %r3 andi. %r3,%r3,0xff80 mfdar %r4 @@ -683,8 +681,7 @@ k_trap: FRAME_SETUP(PC_TEMPSAVE) /* Call C interrupt dispatcher: */ trapagain: - lis %r3,tocbase@ha - ld %r2,tocbase@l(%r3) + GET_TOCBASE(%r2) addi %r3,%r1,48 bl CNAME(powerpc_interrupt) nop @@ -711,8 +708,7 @@ CNAME(trapexit): ori %r3,%r3,PSL_EE@l mtmsr %r3 isync - lis %r3,tocbase@ha - ld %r2,tocbase@l(%r3) + GET_TOCBASE(%r2) addi %r3,%r1,48 bl CNAME(ast) nop @@ -760,8 +756,7 @@ dbtrap: FRAME_SETUP(PC_DBSAVE) /* Call C trap code: */ - lis %r3,tocbase@ha - ld %r2,tocbase@l(%r3) + GET_TOCBASE(%r2) addi %r3,%r1,48 bl CNAME(db_trap_glue) nop diff --git a/sys/powerpc/booke/locore.S b/sys/powerpc/booke/locore.S index 514afa66be71..0fcca91c36e0 100644 --- a/sys/powerpc/booke/locore.S +++ b/sys/powerpc/booke/locore.S @@ -207,7 +207,7 @@ done_mapping: */ lis %r1, tmpstack@ha addi %r1, %r1, tmpstack@l - addi %r1, %r1, (TMPSTACKSZ - 8) + addi %r1, %r1, (TMPSTACKSZ - 16) /* * Initialise exception vector offsets @@ -367,7 +367,7 @@ bp_tlb1_end: */ lis %r1, tmpstack@ha addi %r1, %r1, tmpstack@l - addi %r1, %r1, (TMPSTACKSZ - 8) + addi %r1, %r1, (TMPSTACKSZ - 16) /* * Initialise exception vector offsets @@ -757,6 +757,8 @@ setfault: .align 4 tmpstack: .space TMPSTACKSZ +tmpstackbound: + .space 10240 /* XXX: this really should not be necessary */ /* * Compiled KERNBASE locations @@ -764,20 +766,4 @@ tmpstack: .globl kernbase .set kernbase, KERNBASE -/* - * Globals - */ -#define INTRCNT_COUNT 256 /* max(HROWPIC_IRQMAX,OPENPIC_IRQMAX) */ - -GLOBAL(intrnames) - .space INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 -GLOBAL(sintrnames) - .long INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 - - .align 4 -GLOBAL(intrcnt) - .space INTRCNT_COUNT * 4 * 2 -GLOBAL(sintrcnt) - .long INTRCNT_COUNT * 4 * 2 - #include diff --git a/sys/powerpc/include/trap.h b/sys/powerpc/include/trap.h index 211afcf78225..3b1ade582e10 100644 --- a/sys/powerpc/include/trap.h +++ b/sys/powerpc/include/trap.h @@ -123,6 +123,9 @@ /* DTrace trap opcode. */ #define EXC_DTRACE 0x7c810808 +/* Magic pointer to store TOC base for trap handlers on ppc64 */ +#define TRAP_TOCBASE 0x1f8 + #ifndef LOCORE struct trapframe; struct pcb; diff --git a/sys/powerpc/ofw/ofw_machdep.c b/sys/powerpc/ofw/ofw_machdep.c index cc44847fa932..1c02fa3e90d3 100644 --- a/sys/powerpc/ofw/ofw_machdep.c +++ b/sys/powerpc/ofw/ofw_machdep.c @@ -66,8 +66,8 @@ extern register_t ofmsr[5]; extern void *openfirmware_entry; static void *fdt; int ofw_real_mode; -extern char save_trap_init[0x2f00]; /* EXC_LAST */ -char save_trap_of[0x2f00]; /* EXC_LAST */ +char save_trap_init[0x2f00]; /* EXC_LAST */ +char save_trap_of[0x2f00]; /* EXC_LAST */ int ofwcall(void *); static int openfirmware(void *args); @@ -257,18 +257,30 @@ ofw_mem_regions(struct mem_region *memp, int *memsz, void OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *)) { + ofmsr[0] = mfmsr(); + #ifdef __powerpc64__ + ofmsr[0] &= ~PSL_SF; + #endif + __asm __volatile("mfsprg0 %0" : "=&r"(ofmsr[1])); + __asm __volatile("mfsprg1 %0" : "=&r"(ofmsr[2])); + __asm __volatile("mfsprg2 %0" : "=&r"(ofmsr[3])); + __asm __volatile("mfsprg3 %0" : "=&r"(ofmsr[4])); + if (ofmsr[0] & PSL_DR) ofw_real_mode = 0; else ofw_real_mode = 1; fdt = fdt_ptr; + openfirmware_entry = openfirm; #ifdef FDT_DTB_STATIC /* Check for a statically included blob */ if (fdt == NULL) fdt = &fdt_static_dtb; #endif + + ofw_save_trap_vec(save_trap_init); } boolean_t diff --git a/sys/powerpc/powerpc/intr_machdep.c b/sys/powerpc/powerpc/intr_machdep.c index cc7624f61e4d..b481279d657d 100644 --- a/sys/powerpc/powerpc/intr_machdep.c +++ b/sys/powerpc/powerpc/intr_machdep.c @@ -127,6 +127,11 @@ static u_int nirqs = 0; /* Allocated IRQs. */ #endif static u_int stray_count; +u_long intrcnt[INTR_VECTORS]; +char intrnames[INTR_VECTORS * MAXCOMLEN]; +size_t sintrcnt = sizeof(intrcnt); +size_t sintrnames = sizeof(intrnames); + device_t root_pic; #ifdef SMP diff --git a/sys/powerpc/powerpc/vm_machdep.c b/sys/powerpc/powerpc/vm_machdep.c index d6840947f0f8..c816e32cc2b4 100644 --- a/sys/powerpc/powerpc/vm_machdep.c +++ b/sys/powerpc/powerpc/vm_machdep.c @@ -99,11 +99,6 @@ #include #include -#ifdef __powerpc64__ -extern uintptr_t tocbase; -#endif - - /* * Finish a fork operation, with process p2 nearly set up. * Copy and update the pcb, set up the stack so that the child @@ -149,7 +144,7 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) cf = (struct callframe *)tf - 1; memset(cf, 0, sizeof(struct callframe)); #ifdef __powerpc64__ - cf->cf_toc = tocbase; + cf->cf_toc = ((register_t *)fork_return)[1]; #endif cf->cf_func = (register_t)fork_return; cf->cf_arg0 = (register_t)td2; From 27bc0854ecd49b77662051a3c62acdf33671517f Mon Sep 17 00:00:00 2001 From: nwhitehorn Date: Sun, 18 Jan 2015 20:00:33 +0000 Subject: [PATCH 053/258] Use TOC to look up all kernel globals on powerpc64 instead of doing the non-relocatable lis @ha, ori @l dance and hoping they are below 4 GB. MFC after: 2 months --- sys/powerpc/aim/locore64.S | 6 ++++-- sys/powerpc/aim/trap_subr64.S | 13 ++++++++----- sys/powerpc/include/asm.h | 6 ++++++ sys/powerpc/ofw/ofwcall64.S | 36 ++++++++++++++++++++++------------- sys/powerpc/powerpc/swtch64.S | 5 +++-- 5 files changed, 44 insertions(+), 22 deletions(-) diff --git a/sys/powerpc/aim/locore64.S b/sys/powerpc/aim/locore64.S index 4865e75dc18d..30ee3a95dc9f 100644 --- a/sys/powerpc/aim/locore64.S +++ b/sys/powerpc/aim/locore64.S @@ -91,6 +91,8 @@ GLOBAL(__endkernel) GLOBAL(tmpstk) .space TMPSTKSZ +TOC_ENTRY(tmpstk) + .text .globl btext btext: @@ -124,8 +126,8 @@ ASENTRY_NOPROF(__start) ld %r2,0(%r2) /* Set up the stack pointer */ - lis %r1,(tmpstk+TMPSTKSZ-48)@ha - addi %r1,%r1,(tmpstk+TMPSTKSZ-48)@l + ld %r1,TOC_REF(tmpstk)(%r2) + addi %r1,%r1,TMPSTKSZ-48 /* Switch to 64-bit mode */ mfmsr %r9 diff --git a/sys/powerpc/aim/trap_subr64.S b/sys/powerpc/aim/trap_subr64.S index ec3c92579117..63ca50a4bfe3 100644 --- a/sys/powerpc/aim/trap_subr64.S +++ b/sys/powerpc/aim/trap_subr64.S @@ -307,10 +307,11 @@ CNAME(rstcode): CNAME(rstsize) = . - CNAME(rstcode) cpu_reset: - lis %r1,(tmpstk+TMPSTKSZ-48)@ha /* get new SP */ - addi %r1,%r1,(tmpstk+TMPSTKSZ-48)@l - GET_TOCBASE(%r2) + + ld %r1,TOC_REF(tmpstk)(%r2) /* get new SP */ + addi %r1,%r1,(TMPSTKSZ-48) + bl CNAME(cpudep_ap_early_bootstrap) /* Set PCPU */ nop lis %r3,1@l @@ -751,8 +752,10 @@ dbtrap: andi. %r1,%r1,0xff00 mtsprg3 %r1 - lis %r1,(tmpstk+TMPSTKSZ-48)@ha /* get new SP */ - addi %r1,%r1,(tmpstk+TMPSTKSZ-48)@l + li %r1,TRAP_TOCBASE /* get new SP */ + ld %r1,0(%r1) + ld %r1,TOC_REF(tmpstk)(%r1) + addi %r1,%r1,(TMPSTKSZ-48) FRAME_SETUP(PC_DBSAVE) /* Call C trap code: */ diff --git a/sys/powerpc/include/asm.h b/sys/powerpc/include/asm.h index e571316d15ea..c04cbc2f78ec 100644 --- a/sys/powerpc/include/asm.h +++ b/sys/powerpc/include/asm.h @@ -80,6 +80,12 @@ name: #ifdef __powerpc64__ +#define TOC_REF(name) __CONCAT(.L,name) +#define TOC_ENTRY(name) \ + .section ".toc","aw"; \ + TOC_REF(name): \ + .tc name[TC],name + #define _ENTRY(name) \ .section ".text"; \ .p2align 2; \ diff --git a/sys/powerpc/ofw/ofwcall64.S b/sys/powerpc/ofw/ofwcall64.S index beb6bdc70731..c1778cc82934 100644 --- a/sys/powerpc/ofw/ofwcall64.S +++ b/sys/powerpc/ofw/ofwcall64.S @@ -52,6 +52,13 @@ GLOBAL(openfirmware_entry) GLOBAL(rtas_entry) .llong 0 /* RTAS entry point */ +TOC_ENTRY(ofmsr) +TOC_ENTRY(ofwstk) +TOC_ENTRY(rtasmsr) +TOC_ENTRY(openfirmware_entry) +TOC_ENTRY(rtas_entry) +TOC_ENTRY(rtas_regsave) + /* * Open Firmware Real-mode Entry Point. This is a huge pain. */ @@ -94,16 +101,20 @@ ASENTRY_NOPROF(ofwcall) mfmsr %r6 /* read client interface handler */ - lis %r4,openfirmware_entry@ha - ld %r4,openfirmware_entry@l(%r4) + ld %r4,TOC_REF(openfirmware_entry)(%r2) + ld %r4,0(%r4) + + /* Get OF stack pointer */ + ld %r7,TOC_REF(ofwstk)(%r2) + addi %r7,%r7,OFWSTKSZ-32 /* * Set the MSR to the OF value. This has the side effect of disabling * exceptions, which is important for the next few steps. */ - lis %r5,ofmsr@ha - ld %r5,ofmsr@l(%r5) + ld %r5,TOC_REF(ofmsr)(%r2) + ld %r5,0(%r5) mtmsrd %r5 isync @@ -114,8 +125,7 @@ ASENTRY_NOPROF(ofwcall) * the old MSR so we can get them back later. */ mr %r5,%r1 - lis %r1,(ofwstk+OFWSTKSZ-32)@ha - addi %r1,%r1,(ofwstk+OFWSTKSZ-32)@l + mr %r1,%r7 std %r5,8(%r1) /* Save real stack pointer */ std %r2,16(%r1) /* Save old TOC */ std %r6,24(%r1) /* Save old MSR */ @@ -212,17 +222,18 @@ ASENTRY_NOPROF(rtascall) /* Record the old MSR */ mfmsr %r6 - /* read client interface handler */ - lis %r5,rtas_entry@ha - ld %r5,rtas_entry@l(%r5) + /* Read RTAS entry and reg save area pointers */ + ld %r5,TOC_REF(rtas_entry)(%r2) + ld %r5,0(%r5) + ld %r8,TOC_REF(rtas_regsave)(%r2) /* * Set the MSR to the RTAS value. This has the side effect of disabling * exceptions, which is important for the next few steps. */ - lis %r7,rtasmsr@ha - ld %r7,rtasmsr@l(%r7) + ld %r7,TOC_REF(rtasmsr)(%r2) + ld %r7,0(%r7) mtmsrd %r7 isync @@ -233,8 +244,7 @@ ASENTRY_NOPROF(rtascall) * are below 4 GB, so this is safe. */ mr %r7,%r1 - lis %r1,rtas_regsave@ha - addi %r1,%r1,rtas_regsave@l + mr %r1,%r8 std %r7,0(%r1) /* Save 64-bit stack pointer */ std %r2,8(%r1) /* Save TOC */ std %r6,16(%r1) /* Save MSR */ diff --git a/sys/powerpc/powerpc/swtch64.S b/sys/powerpc/powerpc/swtch64.S index ab6f53278952..6722bb642135 100644 --- a/sys/powerpc/powerpc/swtch64.S +++ b/sys/powerpc/powerpc/swtch64.S @@ -65,6 +65,8 @@ #include #include +TOC_ENTRY(blocked_lock) + /* * void cpu_throw(struct thread *old, struct thread *new) */ @@ -145,8 +147,7 @@ ENTRY(cpu_switch) cpu_switchin: #if defined(SMP) && defined(SCHED_ULE) /* Wait for the new thread to become unblocked */ - lis %r6,blocked_lock@ha - addi %r6,%r6,blocked_lock@l + ld %r6,TOC_REF(blocked_lock)(%r2) blocked_loop: ld %r7,TD_LOCK(%r13) cmpd %r6,%r7 From 45a01cbee3755f2c3364b4d297d1c8ac287d6907 Mon Sep 17 00:00:00 2001 From: tuexen Date: Sun, 18 Jan 2015 20:20:27 +0000 Subject: [PATCH 054/258] Remove an unused variable. Reported by: Coverity CID: 750999 MFC after: 1 week --- sys/netinet/sctp_usrreq.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index 95955dedcb90..b1d85f51eb3b 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -4720,7 +4720,6 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, case SCTP_CONNECT_X_COMPLETE: { struct sockaddr *sa; - struct sctp_nets *net; /* FIXME MT: check correct? */ SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize); @@ -4731,7 +4730,6 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, stcb = LIST_FIRST(&inp->sctp_asoc_list); if (stcb) { SCTP_TCB_LOCK(stcb); - net = sctp_findnet(stcb, sa); } SCTP_INP_RUNLOCK(inp); } else { @@ -4743,7 +4741,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, * TCB.. aka NULL. */ SCTP_INP_INCR_REF(inp); - stcb = sctp_findassociation_ep_addr(&inp, sa, &net, NULL, NULL); + stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL); if (stcb == NULL) { SCTP_INP_DECR_REF(inp); } From f71f36cb87e96b61d25f546fbbf6ee016bffb239 Mon Sep 17 00:00:00 2001 From: pfg Date: Sun, 18 Jan 2015 20:26:27 +0000 Subject: [PATCH 055/258] Remove dead code. After the ext2 variant of the "orlov allocator" was implemented, the case for a negative or zero dirsize disappeared. Drop the dead code and unsign dirsize given that it can't be negative anyways. CID: 1008669 MFC after: 1 week --- sys/fs/ext2fs/ext2_alloc.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sys/fs/ext2fs/ext2_alloc.c b/sys/fs/ext2fs/ext2_alloc.c index e2bb138793b5..935cb0caedac 100644 --- a/sys/fs/ext2fs/ext2_alloc.c +++ b/sys/fs/ext2fs/ext2_alloc.c @@ -443,11 +443,11 @@ static u_long ext2_dirpref(struct inode *pip) { struct m_ext2fs *fs; - int cg, prefcg, dirsize, cgsize; + int cg, prefcg, cgsize; u_int avgifree, avgbfree, avgndir, curdirsize; u_int minifree, minbfree, maxndir; u_int mincg, minndir; - u_int maxcontigdirs; + u_int dirsize, maxcontigdirs; mtx_assert(EXT2_MTX(pip->i_ump), MA_OWNED); fs = pip->i_e2fs; @@ -498,10 +498,7 @@ ext2_dirpref(struct inode *pip) curdirsize = avgndir ? (cgsize - avgbfree * fs->e2fs_bsize) / avgndir : 0; if (dirsize < curdirsize) dirsize = curdirsize; - if (dirsize <= 0) - maxcontigdirs = 0; /* dirsize overflowed */ - else - maxcontigdirs = min((avgbfree * fs->e2fs_bsize) / dirsize, 255); + maxcontigdirs = min((avgbfree * fs->e2fs_bsize) / dirsize, 255); maxcontigdirs = min(maxcontigdirs, fs->e2fs_ipg / AFPDIR); if (maxcontigdirs == 0) maxcontigdirs = 1; From 8b663cb83f547cc7b4033a7c8d8cbca1c344fe52 Mon Sep 17 00:00:00 2001 From: ian Date: Sun, 18 Jan 2015 20:47:21 +0000 Subject: [PATCH 056/258] Save the command-and-flags value into the shadow register when it is written. This doesn't actually change any behavior, because it just allows a 16-bit read of the command register to return the correct value, and nothing actually does a 16-bit read of that register. --- sys/arm/broadcom/bcm2835/bcm2835_sdhci.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c b/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c index 7e1ad1988ebb..5f31478266e3 100644 --- a/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c +++ b/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c @@ -399,8 +399,11 @@ bcm_sdhci_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint16_ val32 |= (val << (off & 3)*8); if (off == SDHCI_TRANSFER_MODE) sc->cmd_and_mode = val32; - else + else { WR4(sc, off & ~3, val32); + if (off == SDHCI_COMMAND_FLAGS) + sc->cmd_and_mode = val32; + } } static void From 632195efc50deb0daca7ef06d995bb2b44de680c Mon Sep 17 00:00:00 2001 From: tuexen Date: Sun, 18 Jan 2015 20:53:20 +0000 Subject: [PATCH 057/258] Add protection code to free memory in case of processing an address which is neither IPv4 or IPv6. Reported by: Coverity CID: 749311 MFC after: 1 week --- sys/netinet/sctp_asconf.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sys/netinet/sctp_asconf.c b/sys/netinet/sctp_asconf.c index 069d4536a17a..456990019c2f 100644 --- a/sys/netinet/sctp_asconf.c +++ b/sys/netinet/sctp_asconf.c @@ -3346,6 +3346,11 @@ sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb, TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next); break; #endif + default: + SCTPDBG(SCTP_DEBUG_ASCONF1, + "sctp_asconf_send_nat_state_update: unknown address family\n"); + SCTP_FREE(aa, SCTP_M_ASC_ADDR); + return; } SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa), SCTP_M_ASC_ADDR); @@ -3379,6 +3384,11 @@ sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb, TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next); break; #endif + default: + SCTPDBG(SCTP_DEBUG_ASCONF1, + "sctp_asconf_send_nat_state_update: unknown address family\n"); + SCTP_FREE(aa, SCTP_M_ASC_ADDR); + return; } /* Now we must hunt the addresses and add all global addresses */ if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { From d9a8f0535a192520c49486e9886f573413a264c8 Mon Sep 17 00:00:00 2001 From: tuexen Date: Sun, 18 Jan 2015 21:16:22 +0000 Subject: [PATCH 058/258] Remove an unnecessary check. Reported by: Coverity CID: 749576 MFC after: 1 week --- sys/netinet/sctp_input.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c index ab64435364f7..feb7b892ecac 100644 --- a/sys/netinet/sctp_input.c +++ b/sys/netinet/sctp_input.c @@ -3108,7 +3108,6 @@ sctp_handle_ecn_cwr(struct sctp_cwr_chunk *cp, struct sctp_tcb *stcb, struct sct uint32_t cwr_tsn; cwr_tsn = ntohl(cp->tsn); - override = cp->ch.chunk_flags & SCTP_CWR_REDUCE_OVERRIDE; TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) { if (chk->rec.chunk_id.id != SCTP_ECN_ECHO) { @@ -3124,10 +3123,8 @@ sctp_handle_ecn_cwr(struct sctp_cwr_chunk *cp, struct sctp_tcb *stcb, struct sct stcb->asoc.ecn_echo_cnt_onq--; TAILQ_REMOVE(&stcb->asoc.control_send_queue, chk, sctp_next); - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } + sctp_m_freem(chk->data); + chk->data = NULL; stcb->asoc.ctrl_queue_cnt--; sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); if (override == 0) { From 142fb530ca2eafe21af1e49ba8a92d6aa71530ee Mon Sep 17 00:00:00 2001 From: pfg Date: Sun, 18 Jan 2015 21:18:28 +0000 Subject: [PATCH 059/258] ext2: fix for uninitialized pointer read. path.ep_bp was being used uninitialized in ext4_ext_find_extent(). CID: 1062344 MFC after: 1 week --- sys/fs/ext2fs/ext2_bmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/fs/ext2fs/ext2_bmap.c b/sys/fs/ext2fs/ext2_bmap.c index ce6485860977..12f9560d93b0 100644 --- a/sys/fs/ext2fs/ext2_bmap.c +++ b/sys/fs/ext2fs/ext2_bmap.c @@ -94,7 +94,7 @@ ext4_bmapext(struct vnode *vp, int32_t bn, int64_t *bnp, int *runp, int *runb) struct inode *ip; struct m_ext2fs *fs; struct ext4_extent *ep; - struct ext4_extent_path path; + struct ext4_extent_path path = { .ep_bp = NULL }; daddr_t lbn; ip = VTOI(vp); From 51e92f331975b4ef1a007b05d3266697edab8381 Mon Sep 17 00:00:00 2001 From: tuexen Date: Sun, 18 Jan 2015 22:00:39 +0000 Subject: [PATCH 060/258] Fix a bug which only shows up when an mbuf allocation failed. Therefore chances are low that we hit this. Reported by: Coverity CID: 1018886 MFC after: 1 week --- sys/netinet/sctp_output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index 86aa3afdeab5..8e8157499d4c 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -7420,7 +7420,7 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, SCTP_TCB_SEND_LOCK(stcb); send_lock_up = 1; } - if (chk->data == NULL) { + if (sp->data == NULL) { /* unsteal the data */ sp->data = chk->data; sp->tail_mbuf = chk->last_mbuf; From 3d07512cea65fe9d6ebf2e47235c5d3b0577fbb5 Mon Sep 17 00:00:00 2001 From: smh Date: Sun, 18 Jan 2015 23:15:49 +0000 Subject: [PATCH 061/258] Clean ZFS spa config before syncing A number of entries that can be present in the spa config shouldn't be saved to disk so add a method to ensure this is case. Without this if the last caller to vdev_config_generate requested stats then we can end up in the cache file. Also only skip a none writable pool in the cache file generation if its active. This prevents unavailable pools incorrectly getting removed from cache file. Tested by: delphij MFC after: 2 weeks Sponsored by: Multiplay --- .../uts/common/fs/zfs/spa_config.c | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa_config.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa_config.c index c4ee741e9a70..be1e528f7f42 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa_config.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa_config.c @@ -140,6 +140,26 @@ spa_config_load(void) kobj_close_file(file); } +static void +spa_config_clean(nvlist_t *nvl) +{ + nvlist_t **child; + nvlist_t *nvroot = NULL; + uint_t c, children; + + if (nvlist_lookup_nvlist_array(nvl, ZPOOL_CONFIG_CHILDREN, &child, + &children) == 0) { + for (c = 0; c < children; c++) + spa_config_clean(child[c]); + } + + if (nvlist_lookup_nvlist(nvl, ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0) + spa_config_clean(nvroot); + + nvlist_remove(nvl, ZPOOL_CONFIG_VDEV_STATS, DATA_TYPE_UINT64_ARRAY); + nvlist_remove(nvl, ZPOOL_CONFIG_SCAN_STATS, DATA_TYPE_UINT64_ARRAY); +} + static int spa_config_write(spa_config_dirent_t *dp, nvlist_t *nvl) { @@ -233,6 +253,7 @@ spa_config_sync(spa_t *target, boolean_t removing, boolean_t postsysevent) */ nvl = NULL; while ((spa = spa_next(spa)) != NULL) { + nvlist_t *nvroot = NULL; /* * Skip over our own pool if we're about to remove * ourselves from the spa namespace or any pool that @@ -241,7 +262,8 @@ spa_config_sync(spa_t *target, boolean_t removing, boolean_t postsysevent) * we don't allow them to be written to the cache file. */ if ((spa == target && removing) || - !spa_writeable(spa)) + (spa_state(spa) == POOL_STATE_ACTIVE && + !spa_writeable(spa))) continue; mutex_enter(&spa->spa_props_lock); @@ -260,6 +282,9 @@ spa_config_sync(spa_t *target, boolean_t removing, boolean_t postsysevent) VERIFY(nvlist_add_nvlist(nvl, spa->spa_name, spa->spa_config) == 0); mutex_exit(&spa->spa_props_lock); + + if (nvlist_lookup_nvlist(nvl, spa->spa_name, &nvroot) == 0) + spa_config_clean(nvroot); } error = spa_config_write(dp, nvl); From cb3a27ad28c1f0dde8ed5051245175152b16ce26 Mon Sep 17 00:00:00 2001 From: rstone Date: Mon, 19 Jan 2015 00:33:32 +0000 Subject: [PATCH 062/258] When mountd is creating sockets, it iterates over all addresses specified in the "hosts" array and eventually looks up the network address with getaddrinfo(). At one point it checks for a numeric address and if it sees one, it sets a hint parameter to force getaddrinfo to interpret the host as a numeric address. However that hint is not cleared for subsequent iterations of the loop and if any hosts seen after this point are host names, getaddrinfo will fail on the name. The result of this bug is that you cannot pass a host name to the -h flag. Unfortunately, the first iteration will either process ::1 or 127.0.0.1, so the flag is set on the first iteration and all host names will fail to be processed. The same bug applies to rpc.lockd and rpc.statd, so fix them too. Differential Revision: https://reviews.freebsd.org/D1507 Reported by: Dylan Martin MFC after: 1 week Sponsored by: Sandvine Inc. --- usr.sbin/mountd/mountd.c | 3 ++- usr.sbin/rpc.lockd/lockd.c | 2 +- usr.sbin/rpc.statd/statd.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/usr.sbin/mountd/mountd.c b/usr.sbin/mountd/mountd.c index 6e4085c85aa0..87794c3ce6db 100644 --- a/usr.sbin/mountd/mountd.c +++ b/usr.sbin/mountd/mountd.c @@ -627,7 +627,6 @@ create_service(struct netconfig *nconf) /* Get mountd's address on this transport */ memset(&hints, 0, sizeof hints); - hints.ai_flags = AI_PASSIVE; hints.ai_family = si.si_af; hints.ai_socktype = si.si_socktype; hints.ai_protocol = si.si_proto; @@ -644,6 +643,8 @@ create_service(struct netconfig *nconf) sock_fd[sock_fdcnt++] = -1; /* Set invalid for now. */ mallocd_res = 0; + hints.ai_flags = AI_PASSIVE; + /* * XXX - using RPC library internal functions. */ diff --git a/usr.sbin/rpc.lockd/lockd.c b/usr.sbin/rpc.lockd/lockd.c index 2974acb6ca4b..4f1347ef924b 100644 --- a/usr.sbin/rpc.lockd/lockd.c +++ b/usr.sbin/rpc.lockd/lockd.c @@ -518,7 +518,6 @@ create_service(struct netconfig *nconf) /* Get rpc.statd's address on this transport */ memset(&hints, 0, sizeof hints); - hints.ai_flags = AI_PASSIVE; hints.ai_family = si.si_af; hints.ai_socktype = si.si_socktype; hints.ai_protocol = si.si_proto; @@ -534,6 +533,7 @@ create_service(struct netconfig *nconf) out_of_mem(); sock_fd[sock_fdcnt++] = -1; /* Set invalid for now. */ mallocd_res = 0; + hints.ai_flags = AI_PASSIVE; /* * XXX - using RPC library internal functions. diff --git a/usr.sbin/rpc.statd/statd.c b/usr.sbin/rpc.statd/statd.c index ff537f84b535..faa8513ba59a 100644 --- a/usr.sbin/rpc.statd/statd.c +++ b/usr.sbin/rpc.statd/statd.c @@ -343,7 +343,6 @@ create_service(struct netconfig *nconf) /* Get rpc.statd's address on this transport */ memset(&hints, 0, sizeof hints); - hints.ai_flags = AI_PASSIVE; hints.ai_family = si.si_af; hints.ai_socktype = si.si_socktype; hints.ai_protocol = si.si_proto; @@ -359,6 +358,7 @@ create_service(struct netconfig *nconf) out_of_mem(); sock_fd[sock_fdcnt++] = -1; /* Set invalid for now. */ mallocd_res = 0; + hints.ai_flags = AI_PASSIVE; /* * XXX - using RPC library internal functions. From ea59bea59330a848548ce834189e97959e8ebae4 Mon Sep 17 00:00:00 2001 From: marcel Date: Mon, 19 Jan 2015 02:22:03 +0000 Subject: [PATCH 063/258] Upgrade libxo to 0.2.0. Obtained from: https://github.com/Juniper/libxo Requested by: Phil Shafer Revisions 276253 & 276273 were incorporated into 0.2.0. Revision 276260 has been merged-in. --- contrib/libxo/Makefile.am | 24 +- contrib/libxo/bin/Zaliases | 2 +- contrib/libxo/configure.ac | 6 +- contrib/libxo/doc/libxo.txt | 293 ++++- contrib/libxo/libxo/libxo.3 | 257 +++- contrib/libxo/libxo/libxo.c | 1129 ++++++++++++++--- contrib/libxo/libxo/xo.h | 81 +- contrib/libxo/libxo/xo_attr.3 | 4 + contrib/libxo/libxo/xo_create.3 | 42 +- contrib/libxo/libxo/xo_emit.3 | 15 +- contrib/libxo/libxo/xo_err.3 | 23 +- contrib/libxo/libxo/xo_error.3 | 64 + contrib/libxo/libxo/xo_finish.3 | 20 +- contrib/libxo/libxo/xo_flush.3 | 23 +- contrib/libxo/libxo/xo_format.5 | 333 +++-- contrib/libxo/libxo/xo_no_setlocale.3 | 37 +- contrib/libxo/libxo/xo_open_container.3 | 58 +- contrib/libxo/libxo/xo_open_list.3 | 55 +- contrib/libxo/libxo/xo_parse_args.3 | 88 +- contrib/libxo/libxo/xo_set_allocator.3 | 21 +- contrib/libxo/libxo/xo_set_flags.3 | 106 +- contrib/libxo/libxo/xo_set_info.3 | 51 +- contrib/libxo/libxo/xo_set_options.3 | 19 +- contrib/libxo/libxo/xo_set_style.3 | 21 +- contrib/libxo/libxo/xo_set_writer.3 | 30 +- contrib/libxo/libxo/xoconfig.h | 12 +- contrib/libxo/libxo/xoconfig.h.in | 6 + contrib/libxo/libxo/xoversion.h | 6 +- contrib/libxo/packaging/libxo.rb.base.in | 20 + contrib/libxo/tests/core/Makefile.am | 6 +- contrib/libxo/tests/core/saved/test_01.H.out | 2 +- .../libxo/tests/core/saved/test_01.HIPx.out | 58 + contrib/libxo/tests/core/saved/test_01.HP.out | 58 + contrib/libxo/tests/core/saved/test_01.J.out | 2 +- contrib/libxo/tests/core/saved/test_01.JP.out | 9 +- contrib/libxo/tests/core/saved/test_01.T.out | 8 + contrib/libxo/tests/core/saved/test_01.X.out | 2 +- contrib/libxo/tests/core/saved/test_01.XP.out | 23 +- contrib/libxo/tests/core/saved/test_02.J.out | 2 +- contrib/libxo/tests/core/saved/test_02.JP.out | 5 +- contrib/libxo/tests/core/saved/test_07.J.out | 2 +- contrib/libxo/tests/core/saved/test_07.JP.out | 2 +- contrib/libxo/tests/core/saved/test_08.H.err | 18 + contrib/libxo/tests/core/saved/test_08.H.out | 1 + .../libxo/tests/core/saved/test_08.HIPx.err | 18 + .../libxo/tests/core/saved/test_08.HIPx.out | 264 ++++ contrib/libxo/tests/core/saved/test_08.HP.err | 18 + contrib/libxo/tests/core/saved/test_08.HP.out | 264 ++++ contrib/libxo/tests/core/saved/test_08.J.err | 18 + contrib/libxo/tests/core/saved/test_08.J.out | 2 + contrib/libxo/tests/core/saved/test_08.JP.err | 18 + contrib/libxo/tests/core/saved/test_08.JP.out | 185 +++ contrib/libxo/tests/core/saved/test_08.T.err | 18 + contrib/libxo/tests/core/saved/test_08.T.out | 52 + contrib/libxo/tests/core/saved/test_08.X.err | 18 + contrib/libxo/tests/core/saved/test_08.X.out | 1 + contrib/libxo/tests/core/saved/test_08.XP.err | 18 + contrib/libxo/tests/core/saved/test_08.XP.out | 165 +++ contrib/libxo/tests/core/saved/test_09.H.err | 0 contrib/libxo/tests/core/saved/test_09.H.out | 1 + .../libxo/tests/core/saved/test_09.HIPx.err | 0 .../libxo/tests/core/saved/test_09.HIPx.out | 93 ++ contrib/libxo/tests/core/saved/test_09.HP.err | 0 contrib/libxo/tests/core/saved/test_09.HP.out | 93 ++ contrib/libxo/tests/core/saved/test_09.J.err | 0 contrib/libxo/tests/core/saved/test_09.J.out | 2 + contrib/libxo/tests/core/saved/test_09.JP.err | 0 contrib/libxo/tests/core/saved/test_09.JP.out | 27 + contrib/libxo/tests/core/saved/test_09.T.err | 0 contrib/libxo/tests/core/saved/test_09.T.out | 25 + contrib/libxo/tests/core/saved/test_09.X.err | 0 contrib/libxo/tests/core/saved/test_09.X.out | 1 + contrib/libxo/tests/core/saved/test_09.XP.err | 0 contrib/libxo/tests/core/saved/test_09.XP.out | 29 + contrib/libxo/tests/core/test_01.c | 28 + contrib/libxo/tests/core/test_07.c | 3 +- contrib/libxo/tests/core/test_08.c | 157 +++ contrib/libxo/tests/core/test_09.c | 114 ++ contrib/libxo/xo/xo.1 | 52 +- contrib/libxo/xo/xo.c | 3 +- contrib/libxo/xolint/Makefile.am | 2 +- contrib/libxo/xolint/xolint.1 | 53 +- lib/libxo/Makefile | 1 + 83 files changed, 4077 insertions(+), 710 deletions(-) create mode 100644 contrib/libxo/libxo/xo_error.3 create mode 100644 contrib/libxo/packaging/libxo.rb.base.in create mode 100644 contrib/libxo/tests/core/saved/test_08.H.err create mode 100644 contrib/libxo/tests/core/saved/test_08.H.out create mode 100644 contrib/libxo/tests/core/saved/test_08.HIPx.err create mode 100644 contrib/libxo/tests/core/saved/test_08.HIPx.out create mode 100644 contrib/libxo/tests/core/saved/test_08.HP.err create mode 100644 contrib/libxo/tests/core/saved/test_08.HP.out create mode 100644 contrib/libxo/tests/core/saved/test_08.J.err create mode 100644 contrib/libxo/tests/core/saved/test_08.J.out create mode 100644 contrib/libxo/tests/core/saved/test_08.JP.err create mode 100644 contrib/libxo/tests/core/saved/test_08.JP.out create mode 100644 contrib/libxo/tests/core/saved/test_08.T.err create mode 100644 contrib/libxo/tests/core/saved/test_08.T.out create mode 100644 contrib/libxo/tests/core/saved/test_08.X.err create mode 100644 contrib/libxo/tests/core/saved/test_08.X.out create mode 100644 contrib/libxo/tests/core/saved/test_08.XP.err create mode 100644 contrib/libxo/tests/core/saved/test_08.XP.out create mode 100644 contrib/libxo/tests/core/saved/test_09.H.err create mode 100644 contrib/libxo/tests/core/saved/test_09.H.out create mode 100644 contrib/libxo/tests/core/saved/test_09.HIPx.err create mode 100644 contrib/libxo/tests/core/saved/test_09.HIPx.out create mode 100644 contrib/libxo/tests/core/saved/test_09.HP.err create mode 100644 contrib/libxo/tests/core/saved/test_09.HP.out create mode 100644 contrib/libxo/tests/core/saved/test_09.J.err create mode 100644 contrib/libxo/tests/core/saved/test_09.J.out create mode 100644 contrib/libxo/tests/core/saved/test_09.JP.err create mode 100644 contrib/libxo/tests/core/saved/test_09.JP.out create mode 100644 contrib/libxo/tests/core/saved/test_09.T.err create mode 100644 contrib/libxo/tests/core/saved/test_09.T.out create mode 100644 contrib/libxo/tests/core/saved/test_09.X.err create mode 100644 contrib/libxo/tests/core/saved/test_09.X.out create mode 100644 contrib/libxo/tests/core/saved/test_09.XP.err create mode 100644 contrib/libxo/tests/core/saved/test_09.XP.out create mode 100644 contrib/libxo/tests/core/test_08.c create mode 100644 contrib/libxo/tests/core/test_09.c diff --git a/contrib/libxo/Makefile.am b/contrib/libxo/Makefile.am index f1fc9997b8ac..4ff2aad892d6 100644 --- a/contrib/libxo/Makefile.am +++ b/contrib/libxo/Makefile.am @@ -35,6 +35,7 @@ docs: DIST_FILES_DIR = ~/Dropbox/dist-files/ GH_PAGES_DIR = gh-pages/ +GH_PAGES_DIR_VER = gh-pages/${PACKAGE_VERSION} PACKAGE_FILE = ${PACKAGE_TARNAME}-${PACKAGE_VERSION}.tar.gz upload: dist upload-docs @@ -45,10 +46,14 @@ upload-docs: docs @echo "Uploading libxo-manual.html ... " @-[ -d ${GH_PAGES_DIR} ] \ && echo "Updating manual on gh-pages ..." \ + && mkdir -p ${GH_PAGES_DIR_VER} \ && cp doc/libxo-manual.html ${GH_PAGES_DIR} \ + && cp doc/libxo-manual.html ${GH_PAGES_DIR_VER} \ && (cd ${GH_PAGES_DIR} \ + && git add ${PACKAGE_VERSION} \ + && git add libxo-manual.html \ && git commit -m 'new docs' \ - libxo-manual.html \ + libxo-manual.html ${PACKAGE_VERSION} \ && git push origin gh-pages ) ; true pkgconfigdir=$(libdir)/pkgconfig @@ -66,7 +71,7 @@ UPDATE_PACKAGE_FILE = \ -e "s;__SHA256__;SHA256 (textproc/${PACKAGE_FILE}) = $$SHA256;" \ -e "s;__SIZE__;SIZE (textproc/${PACKAGE_FILE}) = $$SIZE;" -GH_PACKAGING_DIR = packaging/${PACKAGE_VERSION} +GH_PACKAGING_DIR = ${PACKAGE_VERSION}/packaging GH_PAGES_PACKAGE_DIR = ${GH_PAGES_DIR}/${GH_PACKAGING_DIR} packages: @@ -75,7 +80,6 @@ packages: && SHA1="`openssl sha1 ${PACKAGE_FILE} | awk '{print $$2}'`" \ && SHA256="`openssl sha256 ${PACKAGE_FILE} | awk '{print $$2}'`" \ && SIZE="`ls -l ${PACKAGE_FILE} | awk '{print $$5}'`" \ - && mkdir -p ${GH_PAGES_PACKAGE_DIR}/freebsd \ && echo "... ${GH_PAGES_PACKAGE_DIR}/${PACKAGE_NAME}.rb ..." \ && sed ${UPDATE_PACKAGE_FILE} \ packaging/${PACKAGE_NAME}.rb.base \ @@ -83,20 +87,10 @@ packages: && echo "... ${GH_PAGES_PACKAGE_DIR}/${PACKAGE_NAME}.spec ..." \ && cp packaging/${PACKAGE_NAME}.spec \ ${GH_PAGES_PACKAGE_DIR}/${PACKAGE_NAME}.spec \ - && echo "... ${GH_PAGES_PACKAGE_DIR}/freebsd ..." \ - && sed ${UPDATE_PACKAGE_FILE} \ - ${srcdir}/packaging/freebsd/distinfo.base \ - > ${GH_PAGES_PACKAGE_DIR}/freebsd/distinfo \ - && cp ${srcdir}/packaging/freebsd/pkg-descr \ - ${GH_PAGES_PACKAGE_DIR}/freebsd/pkg-descr \ - && cp ${srcdir}/packaging/freebsd/pkg-plist \ - ${GH_PAGES_PACKAGE_DIR}/freebsd/pkg-plist \ - && cp ${srcdir}/packaging/freebsd/pkg-plist \ - ${GH_PAGES_PACKAGE_DIR}/freebsd/pkg-plist \ - && cp packaging/freebsd/port-Makefile \ - ${GH_PAGES_PACKAGE_DIR}/freebsd/Makefile \ && (cd ${GH_PAGES_DIR} \ && git add ${GH_PACKAGING_DIR} \ + && git add ${GH_PACKAGING_DIR}/libxo.rb \ + ${GH_PACKAGING_DIR}/libxo.spec \ && git commit -m 'new packaging data' \ ${GH_PACKAGING_DIR} \ && git push origin gh-pages ) ; true diff --git a/contrib/libxo/bin/Zaliases b/contrib/libxo/bin/Zaliases index a24d33e7a522..b8fb5dbe5220 100644 --- a/contrib/libxo/bin/Zaliases +++ b/contrib/libxo/bin/Zaliases @@ -1,5 +1,5 @@ set top_src=`pwd` -alias Zautoreconf "(cd $top_src ; autoreconf --install)" +alias Zautoreconf "(cd $top_src ; autoreconf)" set opts=' \ --with-libslax-prefix=/Users/phil/work/root \ diff --git a/contrib/libxo/configure.ac b/contrib/libxo/configure.ac index 904af12bf687..b2553b89ac5b 100644 --- a/contrib/libxo/configure.ac +++ b/contrib/libxo/configure.ac @@ -12,7 +12,7 @@ # AC_PREREQ(2.2) -AC_INIT([libxo], [0.1.6], [phil@juniper.net]) +AC_INIT([libxo], [0.2.0], [phil@juniper.net]) AM_INIT_AUTOMAKE([-Wall -Werror foreign -Wno-portability]) # Support silent build rules. Requires at least automake-1.11. @@ -57,8 +57,10 @@ AC_CHECK_FUNCS([getpass]) AC_CHECK_FUNCS([sysctlbyname]) AC_CHECK_FUNCS([flock]) AC_CHECK_FUNCS([asprintf]) +AC_CHECK_FUNCS([__flbf]) AC_CHECK_HEADERS([dlfcn.h]) +AC_CHECK_HEADERS([stdio_ext.h]) AC_CHECK_HEADERS([tzfile.h]) AC_CHECK_HEADERS([stdtime/tzfile.h]) AC_CHECK_FUNCS([dlfunc]) @@ -164,7 +166,6 @@ AC_ARG_ENABLE([libxo-options], AC_MSG_RESULT([$LIBXO_OPTS]) AM_CONDITIONAL([NO_LIBXO_OPTIONS], [test "$LIBXO_OPTS" != "yes"]) - case $host_os in darwin*) LIBTOOL=glibtool @@ -238,6 +239,7 @@ AC_CONFIG_FILES([ tests/core/Makefile tests/xo/Makefile packaging/libxo.spec + packaging/libxo.rb.base ]) AC_OUTPUT diff --git a/contrib/libxo/doc/libxo.txt b/contrib/libxo/doc/libxo.txt index 5148de0f74a9..31aec5333b51 100644 --- a/contrib/libxo/doc/libxo.txt +++ b/contrib/libxo/doc/libxo.txt @@ -12,14 +12,15 @@ libxo - A Library for Generating Text, XML, JSON, and HTML Output -You live in the present, but you want to live in the future. You'd -love a flying car, but need to get to work today. You want to support -features like XML, JSON, and HTML rendering to allow integration with -NETCONF, REST, and web browsers, but you need to make text output for -command line users. And you don't want multiple code paths that can't -help but get out of sync. None of this "if (xml) {... } else {...}" -logic. And ifdefs are right out. But you'd really, really like all -the fancy features that modern encoding formats can provide. +You want to prepare for the future, but you need to live in the +present. You'd love a flying car, but need to get to work today. You +want to support features like XML, JSON, and HTML rendering to allow +integration with NETCONF, REST, and web browsers, but you need to make +text output for command line users. And you don't want multiple code +paths that can't help but get out of sync. None of this "if (xml) +{... } else {...}" logic. And ifdefs are right out. But you'd +really, really like all the fancy features that modern encoding +formats can provide. libxo can help. The libxo library allows an application to generate text, XML, JSON, and HTML output using a common set of function calls. The application @@ -83,31 +84,37 @@ The latest release of libxo is available at: https://github.com/Juniper/libxo/releases -We are following the branching scheme from -^http://nvie.com/posts/a-successful-git-branching-model/^ -which means we will do development under the "develop" branch, and -release from the master. To clone a developer tree, run the following +We are following the branching scheme from +^http://nvie.com/posts/a-successful-git-branching-model/^ which means +we will do development under the "develop" branch, and release from +the "master" branch. To clone a developer tree, run the following command: git clone https://github.com/Juniper/libxo.git -b develop -We're using semantic release numbering. +We're using semantic release numbering, as defined in +^http://semver.org/spec/v2.0.0.html^. + +libxo is open source, distributed under the BSD license. It +is shipped as part of FreeBSD 11.0. * Overview Most unix commands emit text output aimed at humans. It is designed -to be parsed and understood by a user. Humans are gifted at extracted -details and pattern matching. Often programmers need to extract -information from this human-oriented output. Programmers use tools -like grep, awk, and regular expressions to ferret out the pieces of -information they need. Such solutions are fragile and require -updates when output contents change or evolve, requiring testing and -validation. +to be parsed and understood by a user. Humans are gifted at +extracting details and pattern matching in such output. Often +programmers need to extract information from this human-oriented +output. Programmers use tools like grep, awk, and regular expressions +to ferret out the pieces of information they need. Such solutions are +fragile and require maintenance when output contents change or evolve, +along with testing and validation. -Modern tool developers favors encoding schemes like XML and JSON, +Modern tool developers favor encoding schemes like XML and JSON, which allow trivial parsing and extraction of data. Such formats are simple, well understood, hierarchical, easily parsed, and often -integrate easier with common tools and environments. +integrate easier with common tools and environments. Changes to +content can be done in ways that do not break existing users of the +data, which can reduce maintenance costs and increase feature velocity. In addition, modern reality means that more output ends up in web browsers than in terminals, making HTML output valuable. @@ -278,7 +285,7 @@ content. The roles are listed below; only one role is permitted: |---+--------------+-------------------------------------------------| | M | Name | Description | |---+--------------+-------------------------------------------------| -| D | decoration | Field is non-text (e.g. colon, comma) | +| D | decoration | Field is non-text (e.g., colon, comma) | | E | error | Field is an error message | | L | label | Field is text that prefixes a value | | N | note | Field is text that follows a value | @@ -321,7 +328,7 @@ the field descriptor, or a printf-style format descriptor can be used, if preceded by a slash ("/"): xo_emit("{P: }{Lwc:Cost}{:cost/%u}\n", cost); - xo_emit("{P:/30s}{Lwc:Cost}{:cost/%u}\n", "", cost); + xo_emit("{P:/%30s}{Lwc:Cost}{:cost/%u}\n", "", cost); **** The Title Role ({T:}) @@ -333,6 +340,16 @@ if preceded by a slash ("/"): xo_emit("{T:Interface Statistics}\n"); xo_emit("{T:/%20.20s}{T:/%6.6s}\n", "Item Name", "Cost"); +Title fields have an extra convenience feature; if both content and +format are specified, instead of looking to the argument list for a +value, the content is used, allowing a mixture of format and content +within the field descriptor: + + xo_emit("{T:Name/%20s}{T:Count/%6s}\n"); + +Since the incoming argument is a string, the format must be "%s" or +something suitable. + **** The Units Role ({U:}) Units are the dimension by which values are measured, such as degrees, @@ -412,6 +429,7 @@ content emitted for some output styles: | d | display | Only emit field for display styles (text/HTML) | | e | encoding | Only emit for encoding styles (XML/JSON) | | k | key | Field is a key, suitable for XPath predicates | +| l | leaf-list | Field is a leaf-list | n | no-quotes | Do not quote the field when using JSON style | | q | quotes | Quote the field when using JSON style | | w | white space | A blank (" ") is appended after the label | @@ -433,7 +451,7 @@ The colon modifier appends a single colon to the data value: Name:phil The colon modifier is only used for the TEXT and HTML output -styles. It is commonly combined with the space modifier ('{w:'). +styles. It is commonly combined with the space modifier ('{w:}'). It is purely a convenience feature. **** The Display Modifier ({d:}) @@ -485,6 +503,24 @@ Currently the key modifier is only used when generating XPath value for the HTML output style when XOF_XPATH is set, but other uses are likely in the near future. +**** The Leaf-List Modifier ({l:}) + +The leaf-list modifier is used to distinguish lists where each +instance consists of only a single value. In XML, these are +rendered as single elements, where JSON renders them as arrays. + + EXAMPLE: + for (i = 0; i < num_users; i++) { + xo_emit("Member {l:user}\n", user[i].u_name); + } + XML: + phil + pallavi + JSON: + "user": [ "phil", "pallavi" ] + +The name of the field must match the name of the leaf list. + **** The No-Quotes Modifier ({n:}) The no-quotes modifier (and its twin, the 'quotes' modifier) affect @@ -522,7 +558,7 @@ The white space modifier appends a single space to the data value: Name phil The white space modifier is only used for the TEXT and HTML output -styles. It is commonly combined with the colon modifier ('{c:'). +styles. It is commonly combined with the colon modifier ('{c:}'). It is purely a convenience feature. Note that the sense of the 'w' modifier is reversed for the units role @@ -530,14 +566,15 @@ Note that the sense of the 'w' modifier is reversed for the units role *** Field Formatting -The field format is similar to the format string for printf(3). It's -used varies based on the role of the field, but generally is used to +The field format is similar to the format string for printf(3). Its +use varies based on the role of the field, but generally is used to format the field's contents. -If not provided, the format string defaults to "%s". +If the format string is not provided for a value field, it defaults to +"%s". Note a field definition can contain zero or more printf-style -'directives', which are sequences that start with a '%' and end with a +'directives', which are sequences that start with a '%' and end with one of following characters: "diouxXDOUeEfFgGaAcCsSp". Each directive is matched by one of more arguments to the xo_emit function. @@ -557,7 +594,7 @@ argument. If the width in columns of the output value is less that the minumum width, the value will be padded to reach the minimum. - a period followed by one or more digits indicating the maximum number of bytes which will be examined for a string argument, or the maximum -width for a non-string argument. When handling ASCII strings this is +width for a non-string argument. When handling ASCII strings this functions as the field width but for multi-byte characters, a single character may be composed of multiple bytes. xo_emit will never dereference memory beyond the given number of bytes. @@ -630,8 +667,8 @@ ASCII data, a normal 7-bit ASCII string can be used. '%ls' expects a Unicode values. '%hs' expects a 'char *' pointer to a multi-byte string encoded with the current locale, as given by the LC_CTYPE, LANG, or LC_ALL environment varibles. The first of this list of -variables is used and if none of the variables, the locale defaults to -"UTF-8". +variables is used and if none of the variables are set, the locale +defaults to "UTF-8". For example, a function is passed a locale-base name, a hat size, and a time value. The hat size is formatted in a UTF-8 (ASCII) @@ -676,10 +713,10 @@ columns. *** Characters Outside of Field Definitions -Characters in the format string are not part of a field definition are -copied to the output for the TEXT style, and are ignored for the JSON -and XML styles. For HTML, these characters are placed in a
with -class "text". +Characters in the format string that are not part of a field +definition are copied to the output for the TEXT style, and are +ignored for the JSON and XML styles. For HTML, these characters are +placed in a
with class "text". EXAMPLE: xo_emit("The hat is {:size/%s}.\n", size_val); @@ -854,7 +891,7 @@ container, a warning will be generated. *** Lists and Instances A list is set of one or more instances that appear under the same -parent. The instances contains details about a specific object. One +parent. The instances contain details about a specific object. One can think of instances as objects or records. A call is needed to open and close the list, while a distinct call is needed to open and close each instance of the list: @@ -874,8 +911,8 @@ generation of XML and JSON data. *** DTRT Mode -Some user may find tracking the names of open containers, lists, and -instances inconvenient. libxo offers "Do The Right Thing" mode, where +Some users may find tracking the names of open containers, lists, and +instances inconvenient. libxo offers a "Do The Right Thing" mode, where libxo will track the names of open containers, lists, and instances so the close function can be called without a name. To enable DTRT mode, turn on the XOF_DTRT flag prior to making any other libxo output. @@ -889,10 +926,42 @@ will close the open container, list, or instance: ... xo_close_container_d(); +This also works for lists and instances: + + xo_open_list("item"); + for (...) { + xo_open_instance("item"); + xo_emit(...); + xo_close_instance_d(); + } + xo_close_list_d(); + Note that the XOF_WARN flag will also cause libxo to track open -containers, lists, and instances. A warning is generated with the +containers, lists, and instances. A warning is generated when the name given to the close function and the name recorded do not match. +*** Markers + +Markers are used to protect and restore the state of open constructs. +While a marker is open, no other open constructs can be closed. When +a marker is closed, all constructs open since the marker was opened +will be closed. + +Markers use names which are not user-visible, allowing the caller to +choose appropriate internal names. + +In this example, the code whiffles through a list of fish, calling a +function to emit details about each fish. The marker "fish-guts" is +used to ensure that any constructs opened by the function are closed +properly. + + for (i = 0; fish[i]; i++) { + xo_open_instance("fish"); + xo_open_marker("fish-guts"); + dump_fish_details(i); + xo_close_marker("fish-guts"); + } + ** Handles libxo uses "handles" to control its rendering functionality. The @@ -952,7 +1021,7 @@ be passed NULL to access the default handle. For the typical command that is generating output on standard output, there is no need to create an explicit handle, but they are available -when needed, e.g. for daemons that generate multiple streams of +when needed, e.g., for daemons that generate multiple streams of output. *** xo_create @@ -972,7 +1041,7 @@ See also ^styles^ and ^flags^. By default, libxo writes output to standard output. A convenience function is provided for situations when output should be written to -different file: +a different file: xo_handle_t *xo_create_to_file (FILE *fp, unsigned style, unsigned flags); @@ -987,10 +1056,13 @@ which can tailor how libxo writes data. An opaque argument is recorded and passed back to the write function, allowing the function to acquire context information. The 'close' function can release this opaque data and any other resources as needed. +The flush function can flush buffered data associated with the opaque +object. void xo_set_writer (xo_handle_t *xop, void *opaque, xo_write_func_t write_func, xo_close_func_t close_func); + xo_flush_func_t flush_func); *** xo_set_style @@ -1068,7 +1140,7 @@ XML, JSON, and HTML output. Text output is not affected. The XOF_WARN flag requests that warnings will trigger diagnostic output (on standard error) when the library notices errors during -operations, or with arguments to functions. Without warning enabled, +operations, or with arguments to functions. Without warnings enabled, such conditions are ignored. Warnings allow developers to debug their interaction with libxo. @@ -1178,6 +1250,13 @@ parameter passed to xo_attr_hv(). XML: 00:14 +xo_attr is placed on the next container, instance, leaf, or leaf list +that is emitted. + +Since attributes are only emitted in XML, their use should be limited +to meta-data and additional or redundant representations of data +already emitted in other form. + *** Flushing Output (xo_flush) libxo buffers data, both for performance and consistency, but also to @@ -1188,6 +1267,10 @@ xo_flush() call is used for this: void xo_flush (void); void xo_flush_h (xo_handle_t *xop); +Calling xo_flush also triggers the flush function associated with the +handle. For the default handle, this is equivalent to +"fflush(stdio);". + *** Finishing Output (xo_finish) When the program is ready to exit or close a handle, a call to @@ -1250,7 +1333,7 @@ styles. Calls must be made to open and close a list, and for each instance of data in that list, calls must be make to open and close that instance. -The name given to all calls must be identical, and it is strong +The name given to all calls must be identical, and it is strongly suggested that the name be singular, not plural, as a matter of style and usage expectations. @@ -1314,6 +1397,16 @@ Following the call to xo_parse_args, the application can process the remaining arguments in a normal manner. See ^command-line-arguments^ for a description of valid arguments. +*** xo_set_program + +The xo_set_program function sets name of the program as reported by +functions like xo_failure, xo_warn, xo_err, etc. The program name is +initialized by xo_parse_args, but subsequent calls to xo_set_program +can override this value. + +Note that the value is not copied, so the memory passed to +xo_set_program (and xo_parse_args) must be maintained by the caller. + *** Field Information (xo_info_t) @info@ HTML data can include additional information in attributes that @@ -1353,7 +1446,7 @@ known to the application: ... xo_set_info(NULL, info, info_count); -Third, the emitting of info must be triggered with the XOF_INFO flag +Third, the emission of info must be triggered with the XOF_INFO flag using either the xo_set_flags() function or the "--libxo=info" command line argument. @@ -1405,6 +1498,10 @@ Complete HTML output can be generated with: % env LIBXO_OPTIONS=HXI my-app +Since environment variables are inherited, child processes will have +the same options, which may be undesirable, making the use of the +"--libxo" option is preferable in most situations. + *** Errors, Warnings, and Messages Many programs make use of the standard library functions err() and @@ -1435,6 +1532,20 @@ message associated with either "errno" or the "code" parameter. if (open(filename, O_RDONLY) < 0) xo_err(1, "cannot open file '%s'", filename); +*** xo_error + +The xo_error function can be used for generic errors that should be +reported over the handle, rather than to stderr. The xo_error +function behaves like xo_err for TEXT and HTML output styles, but puts +the error into XML or JSON elements: + + EXAMPLE:: + xo_error("Does not %s", "compute"); + XML:: + Does not compute + JSON:: + "error": { "message": "Does not compute" } + *** xo_no_setlocale libxo automatically initializes the locale based on setting of the @@ -1580,7 +1691,7 @@ and errors, warning, or informational messages as needed. | -X | Extract samples from xolint, suitable for testing | |------------+---------------------------------------------------| -Output message contain the source filename and line number, the +The output message will contain the source filename and line number, the class of the message, the message, and, if -p is given, the line that contains the error: @@ -1627,6 +1738,88 @@ libxo is an effort to mix the best aspects of the JUNOS strategy into FreeBSD in a seemless way, allowing commands to make printf-like output calls without needing to care how the output is rendered. +*** Did the complex semantics of format strings evolve over time? + +The history is both long and short: libxo's functionality is based +on what JUNOS does in a data modeling language called ODL (output +definition language). In JUNOS, all subcomponents generate XML, +which is feed to the CLI, where data from the ODL files tell is +how to render that XML into text. ODL might had a set of tags +like: + + tag docsis-state { + help "State of the DOCSIS interface"; + type string; + } + + tag docsis-mode { + help "DOCSIS mode (2.0/3.0) of the DOCSIS interface"; + type string; + } + + tag docsis-upstream-speed { + help "Operational upstream speed of the interface"; + type string; + } + + tag downstream-scanning { + help "Result of scanning in downstream direction"; + type string; + } + + tag ranging { + help "Result of ranging action"; + type string; + } + + tag signal-to-noise-ratio { + help "Signal to noise ratio for all channels"; + type string; + } + + tag power { + help "Operational power of the signal on all channels"; + type string; + } + + format docsis-status-format { + picture " + State : @, Mode: @, Upstream speed: @ + Downstream scanning: @, Ranging: @ + Signal to noise ratio: @ + Power: @ +"; + line { + field docsis-state; + field docsis-mode; + field docsis-upstream-speed; + field downstream-scanning; + field ranging; + field signal-to-noise-ratio; + field power; + } + } + +These tag definitions are compiled into field definitions +that are triggered when matching XML elements are seen. ODL +also supports other means of defining output. + +The roles and modifiers describe these details. + +In moving these ideas to bsd, two things had to happen: the +formatting had to happen at the source since BSD won't have +a JUNOS-like CLI to do the rendering, and we can't depend on +external data models like ODL, which was seen as too hard a +sell to the BSD community. + +The results were that the xo_emit strings are used to encode the +roles, modifiers, names, and formats. They are dense and a bit +cryptic, but not so unlike printf format strings that developers will +be lost. + +libxo is a new implementation of these ideas and is distinct from +the previous implementation in JUNOS. + *** What makes a good field name? To make useful, consistent field names, follow these guidelines: @@ -1660,7 +1853,7 @@ Nothing's worse than writing expressions like: } Find someone else who is expressing similar data and follow their -field's and hierarchy. Remember the quote is not "Consistency is the +fields and hierarchy. Remember the quote is not "Consistency is the hobgoblin of little minds", but "A foolish consistency is the hobgoblin of little minds". = Think about your users @@ -1670,7 +1863,7 @@ content with xo_attr() calls (^xo_attr^) or "{e:}" fields (^e-modifier^) to make the data useful. = Don't use an arbitrary number postfix What does "errors2" mean? No one will know. "errors-after-restart" -would be a better choice. Think of you users, and think of the +would be a better choice. Think of your users, and think of the future. If you make "errors2", the next guy will happily make "errors3" and before you know it, someone will be asking what's the difference between errors37 and errors63. @@ -1689,7 +1882,7 @@ After using "xolint" to find errors in your field descriptors, use "xolint -V" to spell check your field names and to detect different names for the same data. "dropped-short" and "dropped-too-short" are both reasonable names, but using them both will lead users to ask the -difference between the two fields. If there isn't a difference, +difference between the two fields. If there is no difference, use only one of the field names. If there is a difference, change the names to make that difference more obvious. diff --git a/contrib/libxo/libxo/libxo.3 b/contrib/libxo/libxo/libxo.3 index fca0774eb134..f9b0e6f8b2a9 100644 --- a/contrib/libxo/libxo/libxo.3 +++ b/contrib/libxo/libxo/libxo.3 @@ -7,7 +7,7 @@ .\" # LICENSE. .\" # Phil Shafer, July 2014 .\" -.Dd July, 2014 +.Dd December 8, 2014 .Dt LIBXO 3 .Os .Sh NAME @@ -19,58 +19,82 @@ .In libxo/xo.h .Sh DESCRIPTION The functions defined in -.Lb libxo +.Nm are used to generate a choice of .Em TEXT , .Em XML , .Em JSON , or .Em HTML -output. A common set of functions are used, with +output. +A common set of functions are used, with command line switches passed to the library to control the details of the output. .Pp -Most commands emit text output aimed at humans. It is designed -to be parsed and understood by a user. Humans are gifted at extracted -details and pattern matching. Often programmers need to extract -information from this human-oriented output. Programmers use tools -like grep, awk, and regular expressions to ferret out the pieces of -information they need. Such solutions are fragile and require +Most commands emit text output aimed at humans. +It is designed +to be parsed and understood by a user. +Humans are gifted at extracting +details and pattern matching. +Often programmers need to extract +information from this human-oriented output. +Programmers use tools +like +.Xr grep 1 , +.Xr awk 1 , +and regular expressions to ferret out the pieces of +information they need. +Such solutions are fragile and require updates when output contents change or evolve, requiring testing and validation. .Pp -Modern tool developers favors encoding schemes like XML and JSON, -which allow trivial parsing and extraction of data. Such formats are +Modern tool developers favor encoding schemes like XML and JSON, +which allow trivial parsing and extraction of data. +Such formats are simple, well understood, hierarchical, easily parsed, and often integrate easier with common tools and environments. .Pp In addition, modern reality means that more output ends up in web browsers than in terminals, making HTML output valuable. .Pp -.Em libxo +.Nm allows a single set of function calls in source code to generate -traditional text output, as well as XML and JSON formatted data. HTML +traditional text output, as well as XML and JSON formatted data. +HTML can also be generated; "
" elements surround the traditional text output, with attributes that detail how to render the data. .Pp -There are four encoding styles supported by libxo: TEXT, HTML, JSON, -and XML. JSON and XML are suitable for encoding data, while TEXT and -HTML are suited for display to the user. TEXT output can be display +There are four encoding styles supported by +.Nm : +TEXT, HTML, JSON, +and XML. +JSON and XML are suitable for encoding data, while TEXT and +HTML are suited for display to the user. +TEXT output can be display on a terminal session, allowing compatibility with traditional usage. HTML can be matched with a small CSS file to permit rendering in any -HTML5 browser. XML output is suitable for tools like XPath and -protocols like NETCONF. JSON output can be used for RESTful APIs. +HTML5 browser. +XML output is suitable for tools like XPath and +protocols like NETCONF. +JSON output can be used for RESTful APIs. .Pp The -.Em libxo +.Nm library allows an application to generate text, XML, JSON, -and HTML output using a common set of function calls. The application -decides at run time which output style should be produced. The +and HTML output using a common set of function calls. +The application +decides at run time which output style should be produced. +The application calls a function -.Fn xo_emit +.Xr xo_emit 3 to product output that is -described in a format string. A "field descriptor" tells libxo what -the field is and what it means. Each field descriptor is placed in +described in a format string. +A +.Dq field descriptor +tells +.Nm +what the field is and what it means. +Each field descriptor is placed in braces with a printf-like format string: .Bd -literal -offset indent xo_emit(" {:lines/%7ju} {:words/%7ju} " @@ -79,55 +103,199 @@ braces with a printf-like format string: .Ed .Pp Each field can have a role, with the 'value' role being the default, -and the role tells libxo how and when to render that field, as well as +and the role tells +.Nm +how and when to render that field, as well as a -.Xr printf 3 -like +.Xr printf 3 Ns -like format string. .Pp Output can then be generated in various style, using the "--libxo" option. .Sh DEFAULT HANDLE -Handles give an abstraction for libxo that encapsulates the state of a -stream of output. Handles have the data type "xo_handle_t" and are +Handles give an abstraction for +.Nm +that encapsulates the state of a +stream of output. +Handles have the data type "xo_handle_t" and are opaque to the caller. - +.Pp The library has a default handle that is automatically initialized. By default, this handle will send text style output to standard output. -The xo_set_style and xo_set_flags functions can be used to change this +The +.Xr xo_set_style 3 +and +.Xr xo_set_flags 3 +functions can be used to change this behavior. - -Many libxo functions take a handle as their first parameter; most that -do not use the default handle. Any function taking a handle can -be passed NULL to access the default handle. - +.Pp +Many +.Nm +functions take a handle as their first parameter; most that +do not use the default handle. +Any function taking a handle can +be passed +.Dv NULL +to access the default handle. +.Pp For the typical command that is generating output on standard output, there is no need to create an explicit handle, but they are available -when needed, e.g. for daemons that generate multiple streams of +when needed, e.g., for daemons that generate multiple streams of output. +.Sh FUNCTION OVERVIEW +The +.Nm +library includes the following functions: +.Bl -tag -width "xo_close_container_hd" +.It Sy "Function Description" +.It Fn xo_attr +.It Fn xo_attr_h +.It Fn xo_attr_hv +Allows the caller to emit XML attributes with the next open element. +.It Fn xo_create +.It Fn xo_create_to_file +Allow the caller to create a new handle. +Note that +.Nm +has a default handle that allows the caller to avoid use of an +explicitly created handle. +Only callers writing to files other than +.Dv stdout +would need to call +.Fn xo_create . +.It Fn xo_destroy +Frees any resources associated with the handle, including the handle +itself. +.It Fn xo_emit +.It Fn xo_emit_h +.It Fn xo_emit_hv +Emit formatted output. +The +.Fa fmt +string controls the conversion of the remaining arguments into +formatted output. +See +.Xr xo_format 5 +for details. +.It Fn xo_warn +.It Fn xo_warnx +.It Fn xo_warn_c +.It Fn xo_warn_hc +.It Fn xo_err +.It Fn xo_errc +.It Fn xo_errx +.It Fn xo_message +.It Fn xo_message_c +.It Fn xo_message_hc +.It Fn xo_message_hcv +These functions are meant to be compatible with their standard libc namesakes. +.It Fn xo_finish +.It Fn xo_finish_h +Flush output, close open construct, and complete any pending +operations. +.It Fn xo_flush +.It Fn xo_flush_h +Allow the caller to flush any pending output for a handle. +.It Fn xo_no_setlocale +Direct +.Nm +to avoid initializing the locale. +This function should be called before any other +.Nm +function is called. +.It Fn xo_open_container +.It Fn xo_open_container_h +.It Fn xo_open_container_hd +.It Fn xo_open_container_d +.It Fn xo_close_container +.It Fn xo_close_container_h +.It Fn xo_close_container_hd +.It Fn xo_close_container_d +Containers a singleton levels of hierarchy, typically used to organize +related content. +.It Fn xo_open_list_h +.It Fn xo_open_list +.It Fn xo_open_list_hd +.It Fn xo_open_list_d +.It Fn xo_open_instance_h +.It Fn xo_open_instance +.It Fn xo_open_instance_hd +.It Fn xo_open_instance_d +.It Fn xo_close_instance_h +.It Fn xo_close_instance +.It Fn xo_close_instance_hd +.It Fn xo_close_instance_d +.It Fn xo_close_list_h +.It Fn xo_close_list +.It Fn xo_close_list_hd +.It Fn xo_close_list_d +Lists are levels of hierarchy that can appear multiple times within +the same parent. +Two calls are needed to encapsulate them, one for +the list and one for each instance of that list. +Typically +.Fn xo_open_list +and +.Fn xo_close_list +are called outside a +for-loop, where +.Fn xo_open_instance +it called at the top of the loop, and +.Fn xo_close_instance +is called at the bottom of the loop. +.It Fn xo_parse_args +Inspects command line arguments for directions to +.Nm . +This function should be called before +.Va argv +is inspected by the application. +.It Fn xo_set_allocator +Instructs +.Nm +to use an alternative memory allocator and deallocator. +.It Fn xo_set_flags +.It Fn xo_clear_flags +Change the flags set for a handle. +.It Fn xo_set_info +Provides additional information about elements for use with HTML +rendering. +.It Fn xo_set_options +Changes formatting options used by handle. +.It Fn xo_set_style +.It Fn xo_set_style_name +Changes the output style used by a handle. +.It Fn xo_set_writer +Instructs +.Nm +to use an alternative set of low-level output functions. +.El .Sh ADDITIONAL DOCUMENTATION -.Pp Complete documentation can be found on github: .Bd -literal -offset indent http://juniper.github.io/libxo/libxo-manual.html .Ed .Pp -libxo lives on github as: +.Nm +lives on github as: .Bd -literal -offset indent https://github.com/Juniper/libxo .Ed .Pp -The latest release of libxo is available at: +The latest release of +.Nm +is available at: .Bd -literal -offset indent https://github.com/Juniper/libxo/releases .Ed .Sh SEE ALSO +.Xr xo 1 , +.Xr xolint 1 , .Xr xo_attr 3 , .Xr xo_create 3 , .Xr xo_emit 3 , .Xr xo_err 3 , .Xr xo_finish 3 , .Xr xo_flush 3 , -.Xr xo_format 5 , .Xr xo_no_setlocale 3 , .Xr xo_open_container 3 , .Xr xo_open_list 3 , @@ -138,12 +306,11 @@ https://github.com/Juniper/libxo/releases .Xr xo_set_options 3 , .Xr xo_set_style 3 , .Xr xo_set_writer 3 , -.Xr xo 1 , -and -.Xr xolint 1 . +.Xr xo_format 5 .Sh HISTORY The -.Fa libxo -library was added in FreeBSD 11.0. +.Nm +library was added in +.Fx 11.0 . .Sh AUTHOR Phil Shafer diff --git a/contrib/libxo/libxo/libxo.c b/contrib/libxo/libxo/libxo.c index 2c9733773378..e9d05ce0ceb3 100644 --- a/contrib/libxo/libxo/libxo.c +++ b/contrib/libxo/libxo/libxo.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Juniper Networks, Inc. + * Copyright (c) 2014-2015, Juniper Networks, Inc. * All rights reserved. * This SOFTWARE is licensed under the LICENSE provided in the * ../Copyright file. By downloading, installing, copying, or otherwise @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,10 @@ #include "xo.h" #include "xoversion.h" +#ifdef HAVE_STDIO_EXT_H +#include +#endif /* HAVE_STDIO_EXT_H */ + const char xo_version[] = LIBXO_VERSION; const char xo_version_extra[] = LIBXO_VERSION_EXTRA; @@ -58,6 +63,52 @@ typedef unsigned xo_xsf_flags_t; /* XSF_* flags */ #define XSF_INSTANCE (1<<2) /* Frame is an instance */ #define XSF_DTRT (1<<3) /* Save the name for DTRT mode */ +#define XSF_CONTENT (1<<4) /* Some content has been emitted */ +#define XSF_EMIT (1<<5) /* Some field has been emitted */ +#define XSF_EMIT_KEY (1<<6) /* A key has been emitted */ +#define XSF_EMIT_LEAF_LIST (1<<7) /* A leaf-list field has been emitted */ + +/* These are the flags we propagate between markers and their parents */ +#define XSF_MARKER_FLAGS \ + (XSF_NOT_FIRST | XSF_CONTENT | XSF_EMIT | XSF_EMIT_KEY | XSF_EMIT_LEAF_LIST ) + +/* + * A word about states: We're moving to a finite state machine (FMS) + * approach to help remove fragility from the caller's code. Instead + * of requiring a specific order of calls, we'll allow the caller more + * flexibility and make the library responsible for recovering from + * missed steps. The goal is that the library should not be capable of + * emitting invalid xml or json, but the developer shouldn't need + * to know or understand all the details about these encodings. + * + * You can think of states as either states or event, since they + * function rather like both. None of the XO_CLOSE_* events will + * persist as states, since their stack frame will be popped. + * Same is true of XSS_EMIT, which is an event that asks us to + * prep for emitting output fields. + */ + +/* Stack frame states */ +typedef unsigned xo_state_t; +#define XSS_INIT 0 /* Initial stack state */ +#define XSS_OPEN_CONTAINER 1 +#define XSS_CLOSE_CONTAINER 2 +#define XSS_OPEN_LIST 3 +#define XSS_CLOSE_LIST 4 +#define XSS_OPEN_INSTANCE 5 +#define XSS_CLOSE_INSTANCE 6 +#define XSS_OPEN_LEAF_LIST 7 +#define XSS_CLOSE_LEAF_LIST 8 +#define XSS_DISCARDING 9 /* Discarding data until recovered */ +#define XSS_MARKER 10 /* xo_open_marker's marker */ +#define XSS_EMIT 11 /* xo_emit has a leaf field */ +#define XSS_EMIT_LEAF_LIST 12 /* xo_emit has a leaf-list ({l:}) */ +#define XSS_FINISH 13 /* xo_finish was called */ + +#define XSS_MAX 13 + +#define XSS_TRANSITION(_old, _new) ((_old) << 8 | (_new)) + /* * xo_stack_t: As we open and close containers and levels, we * create a stack of frames to track them. This is needed for @@ -65,6 +116,7 @@ typedef unsigned xo_xsf_flags_t; /* XSF_* flags */ */ typedef struct xo_stack_s { xo_xsf_flags_t xs_flags; /* Flags for this frame */ + xo_state_t xs_state; /* State for this stack frame */ char *xs_name; /* Name (for XPath value) */ char *xs_keys; /* XPath predicate for any key fields */ } xo_stack_t; @@ -74,12 +126,13 @@ typedef struct xo_stack_s { * It's used as a store for state, options, and content. */ struct xo_handle_s { - unsigned long xo_flags; /* Flags */ + xo_xof_flags_t xo_flags; /* Flags */ unsigned short xo_style; /* XO_STYLE_* value */ unsigned short xo_indent; /* Indent level (if pretty) */ unsigned short xo_indent_by; /* Indent amount (tab stop) */ xo_write_func_t xo_write; /* Write callback */ xo_close_func_t xo_close; /* Close callback */ + xo_flush_func_t xo_flush; /* Flush callback */ xo_formatter_t xo_formatter; /* Custom formating function */ xo_checkpointer_t xo_checkpointer; /* Custom formating support function */ void *xo_opaque; /* Opaque data for write function */ @@ -197,7 +250,7 @@ typedef struct xo_format_s { static xo_handle_t xo_default_handle; static int xo_default_inited; static int xo_locale_inited; -static char *xo_program; +static const char *xo_program; /* * To allow libxo to be used in diverse environment, we allow the @@ -210,6 +263,10 @@ static xo_free_func_t xo_free = free; static void xo_failure (xo_handle_t *xop, const char *fmt, ...); +static int +xo_transition (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name, + xo_state_t new_state); + static void xo_buf_append_div (xo_handle_t *xop, const char *class, xo_xff_flags_t flags, const char *name, int nlen, @@ -226,6 +283,7 @@ static int xo_write_to_file (void *opaque, const char *data) { FILE *fp = (FILE *) opaque; + return fprintf(fp, "%s", data); } @@ -236,9 +294,21 @@ static void xo_close_file (void *opaque) { FILE *fp = (FILE *) opaque; + fclose(fp); } +/* + * Callback to flush a FILE pointer + */ +static int +xo_flush_file (void *opaque) +{ + FILE *fp = (FILE *) opaque; + + return fflush(fp); +} + /* * Initialize the contents of an xo_buffer_t. */ @@ -290,6 +360,29 @@ xo_no_setlocale (void) xo_locale_inited = 1; /* Skip initialization */ } +/* + * We need to decide if stdout is line buffered (_IOLBF). Lacking a + * standard way to decide this (e.g. getlinebuf()), we have configure + * look to find __flbf, which glibc supported. If not, we'll rely + * on isatty, with the assumption that terminals are the only thing + * that's line buffered. We _could_ test for "steam._flags & _IOLBF", + * which is all __flbf does, but that's even tackier. Like a + * bedazzled Elvis outfit on an ugly lap dog sort of tacky. Not + * something we're willing to do. + */ +static int +xo_is_line_buffered (FILE *stream) +{ +#if HAVE___FLBF + if (__flbf(stream)) + return 1; +#else /* HAVE___FLBF */ + if (isatty(fileno(stream))) + return 1; +#endif /* HAVE___FLBF */ + return 0; +} + /* * Initialize an xo_handle_t, using both static defaults and * the global settings from the LIBXO_OPTIONS environment @@ -300,6 +393,10 @@ xo_init_handle (xo_handle_t *xop) { xop->xo_opaque = stdout; xop->xo_write = xo_write_to_file; + xop->xo_flush = xo_flush_file; + + if (xo_is_line_buffered(stdout)) + xop->xo_flags |= XOF_FLUSH_LINE; /* * We need to initialize the locale, which isn't really pretty. @@ -415,7 +512,7 @@ xo_indent (xo_handle_t *xop) rc += xop->xo_indent_by; } - return rc; + return (rc > 0) ? rc : 0; } static void @@ -500,9 +597,9 @@ xo_escape_json (xo_buffer_t *xbp, int len) char *cp, *ep, *ip; for (cp = xbp->xb_curp, ep = cp + len; cp < ep; cp++) { - if (*cp == '\\') + if (*cp == '\\' || *cp == '"') delta += 1; - else if (*cp == '"') + else if (*cp == '\n' || *cp == '\r') delta += 1; } @@ -519,13 +616,18 @@ xo_escape_json (xo_buffer_t *xbp, int len) cp -= 1; ip -= 1; - if (*cp != '\\' && *cp != '"') { + if (*cp == '\\' || *cp == '"') { + *ip-- = *cp; + *ip = '\\'; + } else if (*cp == '\n') { + *ip-- = 'n'; + *ip = '\\'; + } else if (*cp == '\r') { + *ip-- = 'r'; + *ip = '\\'; + } else { *ip = *cp; - continue; } - - *ip-- = *cp; - *ip = '\\'; } while (cp > ep && cp != ip); @@ -572,20 +674,23 @@ xo_buf_escape (xo_handle_t *xop, xo_buffer_t *xbp, * Write the current contents of the data buffer using the handle's * xo_write function. */ -static void +static int xo_write (xo_handle_t *xop) { + int rc = 0; xo_buffer_t *xbp = &xop->xo_data; if (xbp->xb_curp != xbp->xb_bufp) { xo_buf_append(xbp, "", 1); /* Append ending NUL */ xo_anchor_clear(xop); - xop->xo_write(xop->xo_opaque, xbp->xb_bufp); + rc = xop->xo_write(xop->xo_opaque, xbp->xb_bufp); xbp->xb_curp = xbp->xb_bufp; } /* Turn off the flags that don't survive across writes */ xop->xo_flags &= ~(XOF_UNITS_PENDING); + + return rc; } /* @@ -947,7 +1052,7 @@ xo_warn_hcv (xo_handle_t *xop, int code, int check_warn, int len = strlen(fmt); int plen = xo_program ? strlen(xo_program) : 0; - char *newfmt = alloca(len + 2 + plen + 2); /* newline, NUL, and ": " */ + char *newfmt = alloca(len + 1 + plen + 2); /* NUL, and ": " */ if (plen) { memcpy(newfmt, xo_program, plen); @@ -955,7 +1060,6 @@ xo_warn_hcv (xo_handle_t *xop, int code, int check_warn, newfmt[plen++] = ' '; } memcpy(newfmt + plen, fmt, len); - newfmt[len + plen] = '\0'; if (xop->xo_flags & XOF_WARN_XML) { @@ -994,7 +1098,7 @@ xo_warn_hcv (xo_handle_t *xop, int code, int check_warn, xo_buf_append(xbp, msg_close, sizeof(msg_close) - 1); xo_buf_append(xbp, err_close, sizeof(err_close) - 1); - if (code > 0) { + if (code >= 0) { const char *msg = strerror(code); if (msg) { xo_buf_append(xbp, ": ", 2); @@ -1003,11 +1107,16 @@ xo_warn_hcv (xo_handle_t *xop, int code, int check_warn, } xo_buf_append(xbp, "\n", 2); /* Append newline and NUL to string */ - xo_write(xop); + (void) xo_write(xop); } else { vfprintf(stderr, newfmt, vap); - fprintf(stderr, ": %s\n", strerror(code)); + if (code >= 0) { + const char *msg = strerror(code); + if (msg) + fprintf(stderr, ": %s", msg); + } + fprintf(stderr, "\n"); } } @@ -1027,7 +1136,7 @@ xo_warn_c (int code, const char *fmt, ...) va_list vap; va_start(vap, fmt); - xo_warn_hcv(NULL, 0, code, fmt, vap); + xo_warn_hcv(NULL, code, 0, fmt, vap); va_end(vap); } @@ -1149,7 +1258,7 @@ xo_message_hcv (xo_handle_t *xop, int code, const char *fmt, va_list vap) xo_buf_append(xbp, msg_close, sizeof(msg_close) - 1); if (need_nl) xo_buf_append(xbp, "\n", 2); /* Append newline and NUL to string */ - xo_write(xop); + (void) xo_write(xop); break; case XO_STYLE_HTML: @@ -1211,7 +1320,7 @@ xo_message_hcv (xo_handle_t *xop, int code, const char *fmt, va_list vap) break; } - xo_flush_h(xop); + (void) xo_flush_h(xop); } void @@ -1299,6 +1408,7 @@ xo_create_to_file (FILE *fp, xo_style_t style, xo_xof_flags_t flags) xop->xo_opaque = fp; xop->xo_write = xo_write_to_file; xop->xo_close = xo_close_file; + xop->xo_flush = xo_flush_file; } return xop; @@ -1323,7 +1433,7 @@ xo_destroy (xo_handle_t *xop_arg) xo_buf_cleanup(&xop->xo_attrs); if (xop_arg == NULL) { - bzero(&xo_default_handle, sizeof(&xo_default_handle)); + bzero(&xo_default_handle, sizeof(xo_default_handle)); xo_default_inited = 0; } else xo_free(xop); @@ -1451,6 +1561,10 @@ xo_set_options (xo_handle_t *xop, const char *input) xop->xo_flags |= XOF_FLUSH; break; + case 'F': + xop->xo_flags |= XOF_FLUSH_LINE; + break; + case 'H': xop->xo_style = XO_STYLE_HTML; break; @@ -1651,6 +1765,33 @@ xo_clear_flags (xo_handle_t *xop, xo_xof_flags_t flags) xop->xo_flags &= ~flags; } +static const char * +xo_state_name (xo_state_t state) +{ + static const char *names[] = { + "init", + "open_container", + "close_container", + "open_list", + "close_list", + "open_instance", + "close_instance", + "open_leaf_list", + "close_leaf_list", + "discarding", + "marker", + "emit", + "emit_leaf_list", + "finish", + NULL + }; + + if (state < (sizeof(names) / sizeof(names[0]))) + return names[state]; + + return "unknown"; +} + static void xo_line_ensure_open (xo_handle_t *xop, xo_xff_flags_t flags UNUSED) { @@ -1867,14 +2008,20 @@ xo_format_string_direct (xo_handle_t *xop, xo_buffer_t *xbp, goto done_with_encoding; /* Need multi-level 'break' */ case XO_STYLE_JSON: - if (wc != '\\' && wc != '"') + if (wc != '\\' && wc != '"' && wc != '\n' && wc != '\r') break; if (!xo_buf_has_room(xbp, 2)) return -1; *xbp->xb_curp++ = '\\'; - *xbp->xb_curp++ = wc & 0x7f; + if (wc == '\n') + wc = 'n'; + else if (wc == '\r') + wc = 'r'; + else wc = wc & 0x7f; + + *xbp->xb_curp++ = wc; goto done_with_encoding; } @@ -2550,6 +2697,15 @@ xo_buf_append_div (xo_handle_t *xop, const char *class, xo_xff_flags_t flags, if (xsp->xs_name == NULL) continue; + /* + * XSS_OPEN_LIST and XSS_OPEN_LEAF_LIST stack frames + * are directly under XSS_OPEN_INSTANCE frames so we + * don't need to put these in our XPath expressions. + */ + if (xsp->xs_state == XSS_OPEN_LIST + || xsp->xs_state == XSS_OPEN_LEAF_LIST) + continue; + xo_data_append(xop, "/", 1); xo_data_escape(xop, xsp->xs_name, strlen(xsp->xs_name)); if (xsp->xs_keys) { @@ -2615,6 +2771,11 @@ xo_format_title (xo_handle_t *xop, const char *str, int len, static char div_open[] = "
"; static char div_close[] = "
"; + if (flen == 0) { + fmt = "%s"; + flen = 2; + } + switch (xop->xo_style) { case XO_STYLE_XML: case XO_STYLE_JSON: @@ -2748,6 +2909,75 @@ xo_format_value (xo_handle_t *xop, const char *name, int nlen, int quote; xo_buffer_t *xbp; + /* + * Before we emit a value, we need to know that the frame is ready. + */ + xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth]; + + if (flags & XFF_LEAF_LIST) { + /* + * Check if we've already started to emit normal leafs + * or if we're not in a leaf list. + */ + if ((xsp->xs_flags & (XSF_EMIT | XSF_EMIT_KEY)) + || !(xsp->xs_flags & XSF_EMIT_LEAF_LIST)) { + char nbuf[nlen + 1]; + memcpy(nbuf, name, nlen); + nbuf[nlen] = '\0'; + + int rc = xo_transition(xop, 0, nbuf, XSS_EMIT_LEAF_LIST); + if (rc < 0) + flags |= XFF_DISPLAY_ONLY | XFF_ENCODE_ONLY; + else + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_EMIT_LEAF_LIST; + } + + xsp = &xop->xo_stack[xop->xo_depth]; + if (xsp->xs_name) { + name = xsp->xs_name; + nlen = strlen(name); + } + + } else if (flags & XFF_KEY) { + /* Emitting a 'k' (key) field */ + if ((xsp->xs_flags & XSF_EMIT) && !(flags & XFF_DISPLAY_ONLY)) { + xo_failure(xop, "key field emitted after normal value field: '%.*s'", + nlen, name); + + } else if (!(xsp->xs_flags & XSF_EMIT_KEY)) { + char nbuf[nlen + 1]; + memcpy(nbuf, name, nlen); + nbuf[nlen] = '\0'; + + int rc = xo_transition(xop, 0, nbuf, XSS_EMIT); + if (rc < 0) + flags |= XFF_DISPLAY_ONLY | XFF_ENCODE_ONLY; + else + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_EMIT_KEY; + + xsp = &xop->xo_stack[xop->xo_depth]; + xsp->xs_flags |= XSF_EMIT_KEY; + } + + } else { + /* Emitting a normal value field */ + if ((xsp->xs_flags & XSF_EMIT_LEAF_LIST) + || !(xsp->xs_flags & XSF_EMIT)) { + char nbuf[nlen + 1]; + memcpy(nbuf, name, nlen); + nbuf[nlen] = '\0'; + + int rc = xo_transition(xop, 0, nbuf, XSS_EMIT); + if (rc < 0) + flags |= XFF_DISPLAY_ONLY | XFF_ENCODE_ONLY; + else + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_EMIT; + + xsp = &xop->xo_stack[xop->xo_depth]; + xsp->xs_flags |= XSF_EMIT; + } + } + switch (xop->xo_style) { case XO_STYLE_TEXT: if (flags & XFF_ENCODE_ONLY) @@ -3157,13 +3387,15 @@ xo_do_emit (xo_handle_t *xop, const char *fmt) const char *cp, *sp, *ep, *basep; char *newp = NULL; int flush = (xop->xo_flags & XOF_FLUSH) ? 1 : 0; + int flush_line = (xop->xo_flags & XOF_FLUSH_LINE) ? 1 : 0; xop->xo_columns = 0; /* Always reset it */ for (cp = fmt; *cp; ) { if (*cp == '\n') { xo_line_close(xop); - xo_flush_h(xop); + if (flush_line && xo_flush_h(xop) < 0) + return -1; cp += 1; continue; @@ -3375,42 +3607,53 @@ xo_do_emit (xo_handle_t *xop, const char *fmt) return -1; } - if (format == NULL && ftype != '[' && ftype != ']' ) { - format = "%s"; - flen = 2; - } + if (ftype == 0 || ftype == 'V') { + if (format == NULL) { + /* Default format for value fields is '%s' */ + format = "%s"; + flen = 2; + } - if (ftype == 0 || ftype == 'V') xo_format_value(xop, content, clen, format, flen, encoding, elen, flags); - else if (ftype == 'D') - xo_format_content(xop, "decoration", NULL, 1, - content, clen, format, flen); - else if (ftype == 'E') - xo_format_content(xop, "error", "error", 0, - content, clen, format, flen); - else if (ftype == 'L') - xo_format_content(xop, "label", NULL, 1, - content, clen, format, flen); - else if (ftype == 'N') - xo_format_content(xop, "note", NULL, 1, - content, clen, format, flen); - else if (ftype == 'P') - xo_format_content(xop, "padding", NULL, 1, - content, clen, format, flen); - else if (ftype == 'T') - xo_format_title(xop, content, clen, format, flen); - else if (ftype == 'U') { - if (flags & XFF_WS) - xo_format_content(xop, "padding", NULL, 1, " ", 1, NULL, 0); - xo_format_units(xop, content, clen, format, flen); - } else if (ftype == 'W') - xo_format_content(xop, "warning", "warning", 0, - content, clen, format, flen); - else if (ftype == '[') - xo_anchor_start(xop, content, clen, format, flen); + + } else if (ftype == '[') + xo_anchor_start(xop, content, clen, format, flen); else if (ftype == ']') - xo_anchor_stop(xop, content, clen, format, flen); + xo_anchor_stop(xop, content, clen, format, flen); + + else if (clen || format) { /* Need either content or format */ + if (format == NULL) { + /* Default format for value fields is '%s' */ + format = "%s"; + flen = 2; + } + + if (ftype == 'D') + xo_format_content(xop, "decoration", NULL, 1, + content, clen, format, flen); + else if (ftype == 'E') + xo_format_content(xop, "error", "error", 0, + content, clen, format, flen); + else if (ftype == 'L') + xo_format_content(xop, "label", NULL, 1, + content, clen, format, flen); + else if (ftype == 'N') + xo_format_content(xop, "note", NULL, 1, + content, clen, format, flen); + else if (ftype == 'P') + xo_format_content(xop, "padding", NULL, 1, + content, clen, format, flen); + else if (ftype == 'T') + xo_format_title(xop, content, clen, format, flen); + else if (ftype == 'U') { + if (flags & XFF_WS) + xo_format_content(xop, "padding", NULL, 1, " ", 1, NULL, 0); + xo_format_units(xop, content, clen, format, flen); + } else if (ftype == 'W') + xo_format_content(xop, "warning", "warning", 0, + content, clen, format, flen); + } if (flags & XFF_COLON) xo_format_content(xop, "decoration", NULL, 1, ":", 1, NULL, 0); @@ -3425,8 +3668,12 @@ xo_do_emit (xo_handle_t *xop, const char *fmt) } /* If we don't have an anchor, write the text out */ - if (flush && !(xop->xo_flags & XOF_ANCHOR)) - xo_write(xop); + if (flush && !(xop->xo_flags & XOF_ANCHOR)) { + if (xo_write(xop) < 0) + rc = -1; /* Report failure */ + else if (xop->xo_flush && xop->xo_flush(xop->xo_opaque) < 0) + rc = -1; + } return (rc < 0) ? rc : (int) xop->xo_columns; } @@ -3549,8 +3796,11 @@ xo_stack_set_flags (xo_handle_t *xop) static void xo_depth_change (xo_handle_t *xop, const char *name, - int delta, int indent, xo_xsf_flags_t flags) + int delta, int indent, xo_state_t state, xo_xsf_flags_t flags) { + if (xop->xo_style == XO_STYLE_HTML || xop->xo_style == XO_STYLE_TEXT) + indent = 0; + if (xop->xo_flags & XOF_DTRT) flags |= XSF_DTRT; @@ -3560,18 +3810,17 @@ xo_depth_change (xo_handle_t *xop, const char *name, xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth + delta]; xsp->xs_flags = flags; + xsp->xs_state = state; xo_stack_set_flags(xop); - unsigned save = (xop->xo_flags & (XOF_XPATH | XOF_WARN | XOF_DTRT)); - save |= (flags & XSF_DTRT); + if (name == NULL) + name = XO_FAILURE_NAME; - if (name && save) { - int len = strlen(name) + 1; - char *cp = xo_realloc(NULL, len); - if (cp) { - memcpy(cp, name, len); - xsp->xs_name = cp; - } + int len = strlen(name) + 1; + char *cp = xo_realloc(NULL, len); + if (cp) { + memcpy(cp, name, len); + xsp->xs_name = cp; } } else { /* Pop operation */ @@ -3636,10 +3885,8 @@ xo_stack_flags (unsigned xflags) } static int -xo_open_container_hf (xo_handle_t *xop, xo_xof_flags_t flags, const char *name) +xo_do_open_container (xo_handle_t *xop, xo_xof_flags_t flags, const char *name) { - xop = xo_default(xop); - int rc = 0; const char *ppn = (xop->xo_flags & XOF_PRETTY) ? "\n" : ""; const char *pre_nl = ""; @@ -3653,9 +3900,16 @@ xo_open_container_hf (xo_handle_t *xop, xo_xof_flags_t flags, const char *name) switch (xop->xo_style) { case XO_STYLE_XML: - rc = xo_printf(xop, "%*s<%s>%s", xo_indent(xop), "", - name, ppn); - xo_depth_change(xop, name, 1, 1, xo_stack_flags(flags)); + rc = xo_printf(xop, "%*s<%s", xo_indent(xop), "", name); + + if (xop->xo_attrs.xb_curp != xop->xo_attrs.xb_bufp) { + rc += xop->xo_attrs.xb_curp - xop->xo_attrs.xb_bufp; + xo_data_append(xop, xop->xo_attrs.xb_bufp, + xop->xo_attrs.xb_curp - xop->xo_attrs.xb_bufp); + xop->xo_attrs.xb_curp = xop->xo_attrs.xb_bufp; + } + + rc += xo_printf(xop, ">%s", ppn); break; case XO_STYLE_JSON: @@ -3674,18 +3928,21 @@ xo_open_container_hf (xo_handle_t *xop, xo_xof_flags_t flags, const char *name) rc = xo_printf(xop, "%s%*s\"%s\": {%s", pre_nl, xo_indent(xop), "", name, ppn); - xo_depth_change(xop, name, 1, 1, xo_stack_flags(flags)); - break; - - case XO_STYLE_HTML: - case XO_STYLE_TEXT: - xo_depth_change(xop, name, 1, 0, xo_stack_flags(flags)); break; } + xo_depth_change(xop, name, 1, 1, XSS_OPEN_CONTAINER, + xo_stack_flags(flags)); + return rc; } +static int +xo_open_container_hf (xo_handle_t *xop, xo_xof_flags_t flags, const char *name) +{ + return xo_transition(xop, flags, name, XSS_OPEN_CONTAINER); +} + int xo_open_container_h (xo_handle_t *xop, const char *name) { @@ -3710,8 +3967,8 @@ xo_open_container_d (const char *name) return xo_open_container_hf(NULL, XOF_DTRT, name); } -int -xo_close_container_h (xo_handle_t *xop, const char *name) +static int +xo_do_close_container (xo_handle_t *xop, const char *name) { xop = xo_default(xop); @@ -3721,8 +3978,6 @@ xo_close_container_h (xo_handle_t *xop, const char *name) if (name == NULL) { xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth]; - if (!(xsp->xs_flags & XSF_DTRT)) - xo_failure(xop, "missing name without 'dtrt' mode"); name = xsp->xs_name; if (name) { @@ -3731,13 +3986,15 @@ xo_close_container_h (xo_handle_t *xop, const char *name) char *cp = alloca(len); memcpy(cp, name, len); name = cp; - } else + } else if (!(xsp->xs_flags & XSF_DTRT)) { + xo_failure(xop, "missing name without 'dtrt' mode"); name = XO_FAILURE_NAME; + } } switch (xop->xo_style) { case XO_STYLE_XML: - xo_depth_change(xop, name, -1, -1, 0); + xo_depth_change(xop, name, -1, -1, XSS_CLOSE_CONTAINER, 0); rc = xo_printf(xop, "%*s%s", xo_indent(xop), "", name, ppn); break; @@ -3745,20 +4002,26 @@ xo_close_container_h (xo_handle_t *xop, const char *name) pre_nl = (xop->xo_flags & XOF_PRETTY) ? "\n" : ""; ppn = (xop->xo_depth <= 1) ? "\n" : ""; - xo_depth_change(xop, name, -1, -1, 0); + xo_depth_change(xop, name, -1, -1, XSS_CLOSE_CONTAINER, 0); rc = xo_printf(xop, "%s%*s}%s", pre_nl, xo_indent(xop), "", ppn); xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; break; case XO_STYLE_HTML: case XO_STYLE_TEXT: - xo_depth_change(xop, name, -1, 0, 0); + xo_depth_change(xop, name, -1, 0, XSS_CLOSE_CONTAINER, 0); break; } return rc; } +int +xo_close_container_h (xo_handle_t *xop, const char *name) +{ + return xo_transition(xop, 0, name, XSS_CLOSE_CONTAINER); +} + int xo_close_container (const char *name) { @@ -3778,42 +4041,52 @@ xo_close_container_d (void) } static int -xo_open_list_hf (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name) +xo_do_open_list (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name) { + int rc = 0; + int indent = 0; + xop = xo_default(xop); - if (xop->xo_style != XO_STYLE_JSON) - return 0; + if (xop->xo_style == XO_STYLE_JSON) { + const char *ppn = (xop->xo_flags & XOF_PRETTY) ? "\n" : ""; + const char *pre_nl = ""; - int rc = 0; - const char *ppn = (xop->xo_flags & XOF_PRETTY) ? "\n" : ""; - const char *pre_nl = ""; - - if (!(xop->xo_flags & XOF_NO_TOP)) { - if (!(xop->xo_flags & XOF_TOP_EMITTED)) { - xo_printf(xop, "%*s{%s", xo_indent(xop), "", ppn); - xop->xo_flags |= XOF_TOP_EMITTED; + indent = 1; + if (!(xop->xo_flags & XOF_NO_TOP)) { + if (!(xop->xo_flags & XOF_TOP_EMITTED)) { + xo_printf(xop, "%*s{%s", xo_indent(xop), "", ppn); + xop->xo_flags |= XOF_TOP_EMITTED; + } } + + if (name == NULL) { + xo_failure(xop, "NULL passed for list name"); + name = XO_FAILURE_NAME; + } + + xo_stack_set_flags(xop); + + if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST) + pre_nl = (xop->xo_flags & XOF_PRETTY) ? ",\n" : ", "; + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; + + rc = xo_printf(xop, "%s%*s\"%s\": [%s", + pre_nl, xo_indent(xop), "", name, ppn); } - if (name == NULL) { - xo_failure(xop, "NULL passed for list name"); - name = XO_FAILURE_NAME; - } - - xo_stack_set_flags(xop); - - if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST) - pre_nl = (xop->xo_flags & XOF_PRETTY) ? ",\n" : ", "; - xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; - - rc = xo_printf(xop, "%s%*s\"%s\": [%s", - pre_nl, xo_indent(xop), "", name, ppn); - xo_depth_change(xop, name, 1, 1, XSF_LIST | xo_stack_flags(flags)); + xo_depth_change(xop, name, 1, indent, XSS_OPEN_LIST, + XSF_LIST | xo_stack_flags(flags)); return rc; } +static int +xo_open_list_hf (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name) +{ + return xo_transition(xop, flags, name, XSS_OPEN_LIST); +} + int xo_open_list_h (xo_handle_t *xop, const char *name UNUSED) { @@ -3838,21 +4111,14 @@ xo_open_list_d (const char *name) return xo_open_list_hf(NULL, XOF_DTRT, name); } -int -xo_close_list_h (xo_handle_t *xop, const char *name) +static int +xo_do_close_list (xo_handle_t *xop, const char *name) { int rc = 0; const char *pre_nl = ""; - xop = xo_default(xop); - - if (xop->xo_style != XO_STYLE_JSON) - return 0; - if (name == NULL) { xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth]; - if (!(xsp->xs_flags & XSF_DTRT)) - xo_failure(xop, "missing name without 'dtrt' mode"); name = xsp->xs_name; if (name) { @@ -3861,21 +4127,35 @@ xo_close_list_h (xo_handle_t *xop, const char *name) char *cp = alloca(len); memcpy(cp, name, len); name = cp; - } else + } else if (!(xsp->xs_flags & XSF_DTRT)) { + xo_failure(xop, "missing name without 'dtrt' mode"); name = XO_FAILURE_NAME; + } } - if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST) - pre_nl = (xop->xo_flags & XOF_PRETTY) ? "\n" : ""; - xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; + if (xop->xo_style == XO_STYLE_JSON) { + if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST) + pre_nl = (xop->xo_flags & XOF_PRETTY) ? "\n" : ""; + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; - xo_depth_change(xop, name, -1, -1, XSF_LIST); - rc = xo_printf(xop, "%s%*s]", pre_nl, xo_indent(xop), ""); - xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; + xo_depth_change(xop, name, -1, -1, XSS_CLOSE_LIST, XSF_LIST); + rc = xo_printf(xop, "%s%*s]", pre_nl, xo_indent(xop), ""); + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; + + } else { + xo_depth_change(xop, name, -1, 0, XSS_CLOSE_LIST, XSF_LIST); + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; + } return rc; } +int +xo_close_list_h (xo_handle_t *xop, const char *name) +{ + return xo_transition(xop, 0, name, XSS_CLOSE_LIST); +} + int xo_close_list (const char *name) { @@ -3895,7 +4175,88 @@ xo_close_list_d (void) } static int -xo_open_instance_hf (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name) +xo_do_open_leaf_list (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name) +{ + int rc = 0; + int indent = 0; + + xop = xo_default(xop); + + if (xop->xo_style == XO_STYLE_JSON) { + const char *ppn = (xop->xo_flags & XOF_PRETTY) ? "\n" : ""; + const char *pre_nl = ""; + + indent = 1; + + if (!(xop->xo_flags & XOF_NO_TOP)) { + if (!(xop->xo_flags & XOF_TOP_EMITTED)) { + xo_printf(xop, "%*s{%s", xo_indent(xop), "", ppn); + xop->xo_flags |= XOF_TOP_EMITTED; + } + } + + if (name == NULL) { + xo_failure(xop, "NULL passed for list name"); + name = XO_FAILURE_NAME; + } + + xo_stack_set_flags(xop); + + if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST) + pre_nl = (xop->xo_flags & XOF_PRETTY) ? ",\n" : ", "; + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; + + rc = xo_printf(xop, "%s%*s\"%s\": [%s", + pre_nl, xo_indent(xop), "", name, ppn); + } + + xo_depth_change(xop, name, 1, indent, XSS_OPEN_LEAF_LIST, + XSF_LIST | xo_stack_flags(flags)); + + return rc; +} + +static int +xo_do_close_leaf_list (xo_handle_t *xop, const char *name) +{ + int rc = 0; + const char *pre_nl = ""; + + if (name == NULL) { + xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth]; + + name = xsp->xs_name; + if (name) { + int len = strlen(name) + 1; + /* We need to make a local copy; xo_depth_change will free it */ + char *cp = alloca(len); + memcpy(cp, name, len); + name = cp; + } else if (!(xsp->xs_flags & XSF_DTRT)) { + xo_failure(xop, "missing name without 'dtrt' mode"); + name = XO_FAILURE_NAME; + } + } + + if (xop->xo_style == XO_STYLE_JSON) { + if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST) + pre_nl = (xop->xo_flags & XOF_PRETTY) ? "\n" : ""; + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; + + xo_depth_change(xop, name, -1, -1, XSS_CLOSE_LEAF_LIST, XSF_LIST); + rc = xo_printf(xop, "%s%*s]", pre_nl, xo_indent(xop), ""); + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; + + } else { + xo_depth_change(xop, name, -1, 0, XSS_CLOSE_LEAF_LIST, XSF_LIST); + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; + } + + return rc; +} + +static int +xo_do_open_instance (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name) { xop = xo_default(xop); @@ -3912,8 +4273,16 @@ xo_open_instance_hf (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name) switch (xop->xo_style) { case XO_STYLE_XML: - rc = xo_printf(xop, "%*s<%s>%s", xo_indent(xop), "", name, ppn); - xo_depth_change(xop, name, 1, 1, xo_stack_flags(flags)); + rc = xo_printf(xop, "%*s<%s", xo_indent(xop), "", name); + + if (xop->xo_attrs.xb_curp != xop->xo_attrs.xb_bufp) { + rc += xop->xo_attrs.xb_curp - xop->xo_attrs.xb_bufp; + xo_data_append(xop, xop->xo_attrs.xb_bufp, + xop->xo_attrs.xb_curp - xop->xo_attrs.xb_bufp); + xop->xo_attrs.xb_curp = xop->xo_attrs.xb_bufp; + } + + rc += xo_printf(xop, ">%s", ppn); break; case XO_STYLE_JSON: @@ -3925,18 +4294,20 @@ xo_open_instance_hf (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name) rc = xo_printf(xop, "%s%*s{%s", pre_nl, xo_indent(xop), "", ppn); - xo_depth_change(xop, name, 1, 1, xo_stack_flags(flags)); - break; - - case XO_STYLE_HTML: - case XO_STYLE_TEXT: - xo_depth_change(xop, name, 1, 0, xo_stack_flags(flags)); break; } + xo_depth_change(xop, name, 1, 1, XSS_OPEN_INSTANCE, xo_stack_flags(flags)); + return rc; } +static int +xo_open_instance_hf (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name) +{ + return xo_transition(xop, flags, name, XSS_OPEN_INSTANCE); +} + int xo_open_instance_h (xo_handle_t *xop, const char *name) { @@ -3961,8 +4332,8 @@ xo_open_instance_d (const char *name) return xo_open_instance_hf(NULL, XOF_DTRT, name); } -int -xo_close_instance_h (xo_handle_t *xop, const char *name) +static int +xo_do_close_instance (xo_handle_t *xop, const char *name) { xop = xo_default(xop); @@ -3972,8 +4343,6 @@ xo_close_instance_h (xo_handle_t *xop, const char *name) if (name == NULL) { xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth]; - if (!(xsp->xs_flags & XSF_DTRT)) - xo_failure(xop, "missing name without 'dtrt' mode"); name = xsp->xs_name; if (name) { @@ -3982,33 +4351,41 @@ xo_close_instance_h (xo_handle_t *xop, const char *name) char *cp = alloca(len); memcpy(cp, name, len); name = cp; - } else + } else if (!(xsp->xs_flags & XSF_DTRT)) { + xo_failure(xop, "missing name without 'dtrt' mode"); name = XO_FAILURE_NAME; + } } switch (xop->xo_style) { case XO_STYLE_XML: - xo_depth_change(xop, name, -1, -1, 0); + xo_depth_change(xop, name, -1, -1, XSS_CLOSE_INSTANCE, 0); rc = xo_printf(xop, "%*s%s", xo_indent(xop), "", name, ppn); break; case XO_STYLE_JSON: pre_nl = (xop->xo_flags & XOF_PRETTY) ? "\n" : ""; - xo_depth_change(xop, name, -1, -1, 0); + xo_depth_change(xop, name, -1, -1, XSS_CLOSE_INSTANCE, 0); rc = xo_printf(xop, "%s%*s}", pre_nl, xo_indent(xop), ""); xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; break; case XO_STYLE_HTML: case XO_STYLE_TEXT: - xo_depth_change(xop, name, -1, 0, 0); + xo_depth_change(xop, name, -1, 0, XSS_CLOSE_INSTANCE, 0); break; } return rc; } +int +xo_close_instance_h (xo_handle_t *xop, const char *name) +{ + return xo_transition(xop, 0, name, XSS_CLOSE_INSTANCE); +} + int xo_close_instance (const char *name) { @@ -4027,15 +4404,421 @@ xo_close_instance_d (void) return xo_close_instance_h(NULL, NULL); } +static int +xo_do_close_all (xo_handle_t *xop, xo_stack_t *limit) +{ + xo_stack_t *xsp; + int rc = 0; + xo_xsf_flags_t flags; + + for (xsp = &xop->xo_stack[xop->xo_depth]; xsp >= limit; xsp--) { + switch (xsp->xs_state) { + case XSS_INIT: + /* Nothing */ + rc = 0; + break; + + case XSS_OPEN_CONTAINER: + rc = xo_do_close_container(xop, NULL); + break; + + case XSS_OPEN_LIST: + rc = xo_do_close_list(xop, NULL); + break; + + case XSS_OPEN_INSTANCE: + rc = xo_do_close_instance(xop, NULL); + break; + + case XSS_OPEN_LEAF_LIST: + rc = xo_do_close_leaf_list(xop, NULL); + break; + + case XSS_MARKER: + flags = xsp->xs_flags & XSF_MARKER_FLAGS; + xo_depth_change(xop, xsp->xs_name, -1, 0, XSS_MARKER, 0); + xop->xo_stack[xop->xo_depth].xs_flags |= flags; + rc = 0; + break; + } + + if (rc < 0) + xo_failure(xop, "close %d failed: %d", xsp->xs_state, rc); + } + + return 0; +} + +/* + * This function is responsible for clearing out whatever is needed + * to get to the desired state, if possible. + */ +static int +xo_do_close (xo_handle_t *xop, const char *name, xo_state_t new_state) +{ + xo_stack_t *xsp, *limit = NULL; + int rc; + xo_state_t need_state = new_state; + + if (new_state == XSS_CLOSE_CONTAINER) + need_state = XSS_OPEN_CONTAINER; + else if (new_state == XSS_CLOSE_LIST) + need_state = XSS_OPEN_LIST; + else if (new_state == XSS_CLOSE_INSTANCE) + need_state = XSS_OPEN_INSTANCE; + else if (new_state == XSS_CLOSE_LEAF_LIST) + need_state = XSS_OPEN_LEAF_LIST; + else if (new_state == XSS_MARKER) + need_state = XSS_MARKER; + else + return 0; /* Unknown or useless new states are ignored */ + + for (xsp = &xop->xo_stack[xop->xo_depth]; xsp > xop->xo_stack; xsp--) { + /* + * Marker's normally stop us from going any further, unless + * we are popping a marker (new_state == XSS_MARKER). + */ + if (xsp->xs_state == XSS_MARKER && need_state != XSS_MARKER) { + if (name) { + xo_failure(xop, "close (xo_%s) fails at marker '%s'; " + "not found '%s'", + xo_state_name(new_state), + xsp->xs_name, name); + return 0; + + } else { + limit = xsp; + xo_failure(xop, "close stops at marker '%s'", xsp->xs_name); + } + break; + } + + if (xsp->xs_state != need_state) + continue; + + if (name && xsp->xs_name && strcmp(name, xsp->xs_name) != 0) + continue; + + limit = xsp; + break; + } + + if (limit == NULL) { + xo_failure(xop, "xo_%s can't find match for '%s'", + xo_state_name(new_state), name); + return 0; + } + + rc = xo_do_close_all(xop, limit); + + return rc; +} + +/* + * We are in a given state and need to transition to the new state. + */ +static int +xo_transition (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name, + xo_state_t new_state) +{ + xo_stack_t *xsp; + int rc; + int old_state, on_marker; + + xop = xo_default(xop); + + rc = 0; + xsp = &xop->xo_stack[xop->xo_depth]; + old_state = xsp->xs_state; + on_marker = (old_state == XSS_MARKER); + + /* If there's a marker on top of the stack, we need to find a real state */ + while (old_state == XSS_MARKER) { + if (xsp == xop->xo_stack) + break; + xsp -= 1; + old_state = xsp->xs_state; + } + + /* + * At this point, the list of possible states are: + * XSS_INIT, XSS_OPEN_CONTAINER, XSS_OPEN_LIST, + * XSS_OPEN_INSTANCE, XSS_OPEN_LEAF_LIST, XSS_DISCARDING + */ + switch (XSS_TRANSITION(old_state, new_state)) { + + open_container: + case XSS_TRANSITION(XSS_INIT, XSS_OPEN_CONTAINER): + case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_OPEN_CONTAINER): + case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_OPEN_CONTAINER): + rc = xo_do_open_container(xop, flags, name); + break; + + case XSS_TRANSITION(XSS_OPEN_LIST, XSS_OPEN_CONTAINER): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close_list(xop, NULL); + if (rc >= 0) + goto open_container; + break; + + case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_OPEN_CONTAINER): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close_leaf_list(xop, NULL); + if (rc >= 0) + goto open_container; + break; + + /*close_container:*/ + case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_CLOSE_CONTAINER): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close(xop, name, new_state); + break; + + case XSS_TRANSITION(XSS_INIT, XSS_CLOSE_CONTAINER): + /* This is an exception for "xo --close" */ + rc = xo_do_close_container(xop, name); + break; + + case XSS_TRANSITION(XSS_OPEN_LIST, XSS_CLOSE_CONTAINER): + case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_CLOSE_CONTAINER): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close(xop, name, new_state); + break; + + case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_CLOSE_CONTAINER): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close_leaf_list(xop, NULL); + if (rc >= 0) + rc = xo_do_close(xop, name, new_state); + break; + + open_list: + case XSS_TRANSITION(XSS_INIT, XSS_OPEN_LIST): + case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_OPEN_LIST): + case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_OPEN_LIST): + rc = xo_do_open_list(xop, flags, name); + break; + + case XSS_TRANSITION(XSS_OPEN_LIST, XSS_OPEN_LIST): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close_list(xop, NULL); + if (rc >= 0) + goto open_list; + break; + + case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_OPEN_LIST): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close_leaf_list(xop, NULL); + if (rc >= 0) + goto open_list; + break; + + /*close_list:*/ + case XSS_TRANSITION(XSS_OPEN_LIST, XSS_CLOSE_LIST): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close(xop, name, new_state); + break; + + case XSS_TRANSITION(XSS_INIT, XSS_CLOSE_LIST): + case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_CLOSE_LIST): + case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_CLOSE_LIST): + case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_CLOSE_LIST): + rc = xo_do_close(xop, name, new_state); + break; + + open_instance: + case XSS_TRANSITION(XSS_OPEN_LIST, XSS_OPEN_INSTANCE): + rc = xo_do_open_instance(xop, flags, name); + break; + + case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_OPEN_INSTANCE): + case XSS_TRANSITION(XSS_INIT, XSS_OPEN_INSTANCE): + rc = xo_do_open_list(xop, flags, name); + if (rc >= 0) + goto open_instance; + break; + + case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_OPEN_INSTANCE): + if (on_marker) { + rc = xo_do_open_list(xop, flags, name); + } else { + rc = xo_do_close_instance(xop, NULL); + } + if (rc >= 0) + goto open_instance; + break; + + case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_OPEN_INSTANCE): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close_leaf_list(xop, NULL); + if (rc >= 0) + goto open_instance; + break; + + /*close_instance:*/ + case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_CLOSE_INSTANCE): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close_instance(xop, name); + break; + + case XSS_TRANSITION(XSS_INIT, XSS_CLOSE_INSTANCE): + /* This one makes no sense; ignore it */ + break; + + case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_CLOSE_INSTANCE): + case XSS_TRANSITION(XSS_OPEN_LIST, XSS_CLOSE_INSTANCE): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close(xop, name, new_state); + break; + + case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_CLOSE_INSTANCE): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close_leaf_list(xop, NULL); + if (rc >= 0) + rc = xo_do_close(xop, name, new_state); + break; + + open_leaf_list: + case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_OPEN_LEAF_LIST): + case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_OPEN_LEAF_LIST): + case XSS_TRANSITION(XSS_INIT, XSS_OPEN_LEAF_LIST): + rc = xo_do_open_leaf_list(xop, flags, name); + break; + + case XSS_TRANSITION(XSS_OPEN_LIST, XSS_OPEN_LEAF_LIST): + case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_OPEN_LEAF_LIST): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close_list(xop, NULL); + if (rc >= 0) + goto open_leaf_list; + break; + + /*close_leaf_list:*/ + case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_CLOSE_LEAF_LIST): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close_leaf_list(xop, name); + break; + + case XSS_TRANSITION(XSS_INIT, XSS_CLOSE_LEAF_LIST): + /* Makes no sense; ignore */ + break; + + case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_CLOSE_LEAF_LIST): + case XSS_TRANSITION(XSS_OPEN_LIST, XSS_CLOSE_LEAF_LIST): + case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_CLOSE_LEAF_LIST): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close(xop, name, new_state); + break; + + /*emit:*/ + case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_EMIT): + case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_EMIT): + break; + + case XSS_TRANSITION(XSS_OPEN_LIST, XSS_EMIT): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close(xop, NULL, XSS_CLOSE_LIST); + break; + + case XSS_TRANSITION(XSS_INIT, XSS_EMIT): + break; + + case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_EMIT): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close_leaf_list(xop, NULL); + break; + + /*emit_leaf_list:*/ + case XSS_TRANSITION(XSS_INIT, XSS_EMIT_LEAF_LIST): + case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_EMIT_LEAF_LIST): + case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_EMIT_LEAF_LIST): + rc = xo_do_open_leaf_list(xop, flags, name); + break; + + case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_EMIT_LEAF_LIST): + break; + + case XSS_TRANSITION(XSS_OPEN_LIST, XSS_EMIT_LEAF_LIST): + /* + * We need to be backward compatible with the pre-xo_open_leaf_list + * API, where both lists and leaf-lists were opened as lists. So + * if we find an open list that hasn't had anything written to it, + * we'll accept it. + */ + break; + + default: + xo_failure(xop, "unknown transition: (%u -> %u)", + xsp->xs_state, new_state); + } + + return rc; + + marker_prevents_close: + xo_failure(xop, "marker '%s' prevents transition from %s to %s", + xop->xo_stack[xop->xo_depth].xs_name, + xo_state_name(old_state), xo_state_name(new_state)); + return -1; +} + +int +xo_open_marker_h (xo_handle_t *xop, const char *name) +{ + xop = xo_default(xop); + + xo_depth_change(xop, name, 1, 0, XSS_MARKER, + xop->xo_stack[xop->xo_depth].xs_flags & XSF_MARKER_FLAGS); + + return 0; +} + +int +xo_open_marker (const char *name) +{ + return xo_open_marker_h(NULL, name); +} + +int +xo_close_marker_h (xo_handle_t *xop, const char *name) +{ + xop = xo_default(xop); + + return xo_do_close(xop, name, XSS_MARKER); +} + +int +xo_close_marker (const char *name) +{ + return xo_close_marker_h(NULL, name); +} + void xo_set_writer (xo_handle_t *xop, void *opaque, xo_write_func_t write_func, - xo_close_func_t close_func) + xo_close_func_t close_func, xo_flush_func_t flush_func) { xop = xo_default(xop); xop->xo_opaque = opaque; xop->xo_write = write_func; xop->xo_close = close_func; + xop->xo_flush = flush_func; } void @@ -4045,10 +4828,11 @@ xo_set_allocator (xo_realloc_func_t realloc_func, xo_free_func_t free_func) xo_free = free_func; } -void +int xo_flush_h (xo_handle_t *xop) { static char div_close[] = "
"; + int rc; xop = xo_default(xop); @@ -4064,21 +4848,29 @@ xo_flush_h (xo_handle_t *xop) break; } - xo_write(xop); + rc = xo_write(xop); + if (rc >= 0 && xop->xo_flush) + if (xop->xo_flush(xop->xo_opaque) < 0) + return -1; + + return rc; } -void +int xo_flush (void) { - xo_flush_h(NULL); + return xo_flush_h(NULL); } -void +int xo_finish_h (xo_handle_t *xop) { const char *cp = ""; xop = xo_default(xop); + if (!(xop->xo_flags & XOF_NO_CLOSE)) + xo_do_close_all(xop, xop->xo_stack); + switch (xop->xo_style) { case XO_STYLE_JSON: if (!(xop->xo_flags & XOF_NO_TOP)) { @@ -4091,13 +4883,13 @@ xo_finish_h (xo_handle_t *xop) break; } - xo_flush_h(xop); + return xo_flush_h(xop); } -void +int xo_finish (void) { - xo_finish_h(NULL); + return xo_finish_h(NULL); } /* @@ -4141,6 +4933,7 @@ xo_error_hv (xo_handle_t *xop, const char *fmt, va_list vap) break; case XO_STYLE_XML: + case XO_STYLE_JSON: va_copy(xop->xo_vap, vap); xo_open_container_h(xop, "error"); @@ -4235,6 +5028,30 @@ xo_parse_args (int argc, char **argv) return save; } +void +xo_dump_stack (xo_handle_t *xop) +{ + int i; + xo_stack_t *xsp; + + xop = xo_default(xop); + + fprintf(stderr, "Stack dump:\n"); + + xsp = xop->xo_stack; + for (i = 1, xsp++; i <= xop->xo_depth; i++, xsp++) { + fprintf(stderr, " [%d] %s '%s' [%x]\n", + i, xo_state_name(xsp->xs_state), + xsp->xs_name ?: "--", xsp->xs_flags); + } +} + +void +xo_set_program (const char *name) +{ + xo_program = name; +} + #ifdef UNIT_TEST int main (int argc, char **argv) diff --git a/contrib/libxo/libxo/xo.h b/contrib/libxo/libxo/xo.h index 3a59e4c81efc..82b965a29202 100644 --- a/contrib/libxo/libxo/xo.h +++ b/contrib/libxo/libxo/xo.h @@ -25,35 +25,39 @@ typedef unsigned xo_style_t; #define XO_STYLE_HTML 3 /** Generate HTML output */ /** Flags for libxo */ -typedef unsigned long xo_xof_flags_t; -#define XOF_CLOSE_FP (1<<0) /** Close file pointer on xo_close() */ -#define XOF_PRETTY (1<<1) /** Make 'pretty printed' output */ -#define XOF_DIV_OPEN (1<<2) /** Internal use only: a
is open */ -#define XOF_LINE_OPEN (1<<3) /** Internal use only: a
*/ +typedef unsigned long long xo_xof_flags_t; +#define XOF_BIT(_n) ((xo_xof_flags_t) 1 << (_n)) +#define XOF_CLOSE_FP XOF_BIT(0) /** Close file pointer on xo_close() */ +#define XOF_PRETTY XOF_BIT(1) /** Make 'pretty printed' output */ +#define XOF_DIV_OPEN XOF_BIT(2) /** Internal use only: a
is open */ +#define XOF_LINE_OPEN XOF_BIT(3) /** Internal use only:
*/ -#define XOF_WARN (1<<4) /** Generate warnings for broken calls */ -#define XOF_XPATH (1<<5) /** Emit XPath attributes in HTML */ -#define XOF_INFO (1<<6) /** Emit additional info fields (HTML) */ -#define XOF_WARN_XML (1<<7) /** Emit warnings in XML (on stdout) */ +#define XOF_WARN XOF_BIT(4) /** Generate warnings for broken calls */ +#define XOF_XPATH XOF_BIT(5) /** Emit XPath attributes in HTML */ +#define XOF_INFO XOF_BIT(6) /** Emit additional info fields (HTML) */ +#define XOF_WARN_XML XOF_BIT(7) /** Emit warnings in XML (on stdout) */ -#define XOF_NO_ENV (1<<8) /** Don't look at the LIBXO_OPTIONS env var */ -#define XOF_NO_VA_ARG (1<<9) /** Don't advance va_list w/ va_arg() */ -#define XOF_DTRT (1<<10) /** Enable "do the right thing" mode */ -#define XOF_KEYS (1<<11) /** Flag 'key' fields for xml and json */ +#define XOF_NO_ENV XOF_BIT(8) /** Don't look at LIBXO_OPTIONS env var */ +#define XOF_NO_VA_ARG XOF_BIT(9) /** Don't advance va_list w/ va_arg() */ +#define XOF_DTRT XOF_BIT(10) /** Enable "do the right thing" mode */ +#define XOF_KEYS XOF_BIT(11) /** Flag 'key' fields for xml and json */ -#define XOF_IGNORE_CLOSE (1<<12) /** Ignore errors on close tags */ -#define XOF_NOT_FIRST (1<<13) /* Not the first item (JSON) */ -#define XOF_NO_LOCALE (1<<14) /** Don't bother with locale */ -#define XOF_TOP_EMITTED (1<<15) /* The top JSON braces have been emitted */ +#define XOF_IGNORE_CLOSE XOF_BIT(12) /** Ignore errors on close tags */ +#define XOF_NOT_FIRST XOF_BIT(13) /* Not the first item (JSON) */ +#define XOF_NO_LOCALE XOF_BIT(14) /** Don't bother with locale */ +#define XOF_TOP_EMITTED XOF_BIT(15) /* The top JSON braces have been emitted */ -#define XOF_NO_TOP (1<<16) /** Don't emit the top braces in JSON */ -#define XOF_ANCHOR (1<<17) /** An anchor is in place */ -#define XOF_UNITS (1<<18) /** Encode units in XML */ -#define XOF_UNITS_PENDING (1<<19) /** We have a units-insertion pending */ +#define XOF_NO_TOP XOF_BIT(16) /** Don't emit the top braces in JSON */ +#define XOF_ANCHOR XOF_BIT(17) /** An anchor is in place */ +#define XOF_UNITS XOF_BIT(18) /** Encode units in XML */ +#define XOF_UNITS_PENDING XOF_BIT(19) /** We have a units-insertion pending */ -#define XOF_UNDERSCORES (1<<20) /** Replace dashes with underscores (JSON) */ -#define XOF_COLUMNS (1<<21) /** xo_emit should return a column count */ -#define XOF_FLUSH (1<<22) /** Flush after each xo_emit call */ +#define XOF_UNDERSCORES XOF_BIT(20) /** Replace dashes with underscores (JSON)*/ +#define XOF_COLUMNS XOF_BIT(21) /** xo_emit should return a column count */ +#define XOF_FLUSH XOF_BIT(22) /** Flush after each xo_emit call */ +#define XOF_FLUSH_LINE XOF_BIT(23) /** Flush after each newline */ + +#define XOF_NO_CLOSE XOF_BIT(24) /** xo_finish won't close open elements */ /* * The xo_info_t structure provides a mapping between names and @@ -70,6 +74,7 @@ typedef struct xo_handle_s xo_handle_t; /* Handle for XO output */ typedef int (*xo_write_func_t)(void *, const char *); typedef void (*xo_close_func_t)(void *); +typedef int (*xo_flush_func_t)(void *); typedef void *(*xo_realloc_func_t)(void *, size_t); typedef void (*xo_free_func_t)(void *); @@ -93,7 +98,7 @@ xo_destroy (xo_handle_t *xop); void xo_set_writer (xo_handle_t *xop, void *opaque, xo_write_func_t write_func, - xo_close_func_t close_func); + xo_close_func_t close_func, xo_flush_func_t flush_func); void xo_set_allocator (xo_realloc_func_t realloc_func, xo_free_func_t free_func); @@ -209,6 +214,18 @@ xo_close_instance_hd (xo_handle_t *xop); int xo_close_instance_d (void); +int +xo_open_marker_h (xo_handle_t *xop, const char *name); + +int +xo_open_marker (const char *name); + +int +xo_close_marker_h (xo_handle_t *xop, const char *name); + +int +xo_close_marker (const char *name); + int xo_attr_h (xo_handle_t *xop, const char *name, const char *fmt, ...); @@ -227,16 +244,16 @@ xo_error_h (xo_handle_t *xop, const char *fmt, ...); void xo_error (const char *fmt, ...); -void +int xo_flush_h (xo_handle_t *xop); -void +int xo_flush (void); -void +int xo_finish_h (xo_handle_t *xop); -void +int xo_finish (void); void @@ -297,4 +314,10 @@ xo_parse_args (int argc, char **argv); extern const char xo_version[]; extern const char xo_version_extra[]; +void +xo_dump_stack (xo_handle_t *xop); + +void +xo_set_program (const char *name); + #endif /* INCLUDE_XO_H */ diff --git a/contrib/libxo/libxo/xo_attr.3 b/contrib/libxo/libxo/xo_attr.3 index afd805f54f01..1c183605975b 100644 --- a/contrib/libxo/libxo/xo_attr.3 +++ b/contrib/libxo/libxo/xo_attr.3 @@ -51,6 +51,10 @@ parameter as passed to XML: 00:14 .Ed +.Pp +Since attributes are only emitted in XML, their use should be limited +to meta-data and additional or redundant representations of data +already emitted in other form. .Sh ADDITIONAL DOCUMENTATION .Pp Complete documentation can be found on github: diff --git a/contrib/libxo/libxo/xo_create.3 b/contrib/libxo/libxo/xo_create.3 index ec241ee1e0e1..b0e896522707 100644 --- a/contrib/libxo/libxo/xo_create.3 +++ b/contrib/libxo/libxo/xo_create.3 @@ -7,7 +7,7 @@ .\" # LICENSE. .\" # Phil Shafer, July 2014 .\" -.Dd July, 2014 +.Dd December 4, 2014 .Dt LIBXO 3 .Os .Sh NAME @@ -25,7 +25,7 @@ .Fn xo_destroy "xo_handle_t *handle" .Sh DESCRIPTION A -.Em libxo +.Nm libxo handle can be allocated using the .Fn xo_create function. @@ -37,49 +37,55 @@ function. .Ed .Pp By default, -.Em libxo -writes output to standard output. A convenience -function is provided for situations when output should be written to +.Nm libxo +writes output to standard output. +A convenience +function is provided for situations when output should be written to a different file. .Pp Use the -.Em XOF_CLOSE_FP +.Dv XOF_CLOSE_FP flag to trigger a call to -.Em fclose 3 -for the FILE pointer when the handle is destroyed. +.Xr fclose 3 +for the +.Dv FILE +pointer when the handle is destroyed. .Pp The .Fn xo_destroy function releases a handle and any resources it is -using. Calling +using. +Calling .Fn xo_destroy with a -.Em NULL +.Dv NULL handle will release any resources associated with the default handle. .Sh ADDITIONAL DOCUMENTATION -.Pp Complete documentation can be found on github: .Bd -literal -offset indent http://juniper.github.io/libxo/libxo-manual.html .Ed .Pp -libxo lives on github as: +.Nm libxo +lives on github as: .Bd -literal -offset indent https://github.com/Juniper/libxo .Ed .Pp -The latest release of libxo is available at: +The latest release of +.Nm libxo +is available at: .Bd -literal -offset indent https://github.com/Juniper/libxo/releases .Ed .Sh SEE ALSO -.Xr xo_emit 3 -and -.Xr xo_set_options 3 . +.Xr xo_emit 3 , +.Xr xo_set_options 3 .Sh HISTORY The -.Fa libxo -library was added in FreeBSD 11.0. +.Nm libxo +library was added in +.Fx 11.0 . .Sh AUTHOR Phil Shafer diff --git a/contrib/libxo/libxo/xo_emit.3 b/contrib/libxo/libxo/xo_emit.3 index 9f76e13c6329..706082450986 100644 --- a/contrib/libxo/libxo/xo_emit.3 +++ b/contrib/libxo/libxo/xo_emit.3 @@ -7,7 +7,7 @@ .\" # LICENSE. .\" # Phil Shafer, July 2014 .\" -.Dd July, 2014 +.Dd December 4, 2014 .Dt LIBXO 3 .Os .Sh NAME @@ -44,13 +44,13 @@ accepts a .Fa va_list for additional flexibility. .Sh ADDITIONAL DOCUMENTATION -.Pp Complete documentation can be found on github: .Bd -literal -offset indent http://juniper.github.io/libxo/libxo-manual.html .Ed .Pp -libxo lives on github as: +.Nm libxo +lives on github as: .Bd -literal -offset indent https://github.com/Juniper/libxo .Ed @@ -61,11 +61,12 @@ https://github.com/Juniper/libxo/releases .Ed .Sh SEE ALSO .Xr xo_open_container 3 , -.Xr xo_open_list 3 , and -.Xr xo_format 5 . +.Xr xo_open_list 3 , +.Xr xo_format 5 .Sh HISTORY The -.Fa libxo -library was added in FreeBSD 11.0. +.Nm libxo +library was added in +.Fx 11.0 . .Sh AUTHOR Phil Shafer diff --git a/contrib/libxo/libxo/xo_err.3 b/contrib/libxo/libxo/xo_err.3 index 2445aa70f652..5584309f3bf0 100644 --- a/contrib/libxo/libxo/xo_err.3 +++ b/contrib/libxo/libxo/xo_err.3 @@ -7,7 +7,7 @@ .\" # LICENSE. .\" # Phil Shafer, July 2014 .\" -.Dd July, 2014 +.Dd December 4, 2014 .Dt LIBXO 3 .Os .Sh NAME @@ -45,32 +45,38 @@ Many programs make use of the standard library functions and .Xr warn 3 to generate errors and warnings for the user. -.Em libxo +.Nm libxo wants to pass that information via the current output style, and provides compatible functions to allow this. .Pp These functions display the program name, a colon, a formatted message based on the arguments, and then optionally a colon and an error -message associated with either "errno" or the "code" parameter. +message associated with either +.Fa errno +or the +.Fa code +parameter. .Bd -literal -offset indent EXAMPLE: if (open(filename, O_RDONLY) < 0) xo_err(1, "cannot open file '%s'", filename); .Ed .Sh ADDITIONAL DOCUMENTATION -.Pp Complete documentation can be found on github: .Bd -literal -offset indent http://juniper.github.io/libxo/libxo-manual.html .Ed .Pp -libxo lives on github as: +.Nm libxo +lives on github as: .Bd -literal -offset indent https://github.com/Juniper/libxo .Ed .Pp -The latest release of libxo is available at: +The latest release of +.Nm libxo +is available at: .Bd -literal -offset indent https://github.com/Juniper/libxo/releases .Ed @@ -78,7 +84,8 @@ https://github.com/Juniper/libxo/releases .Xr xo_emit 3 .Sh HISTORY The -.Fa libxo -library was added in FreeBSD 11.0. +.Nm libxo +library was added in +.Fx 11.0 . .Sh AUTHOR Phil Shafer diff --git a/contrib/libxo/libxo/xo_error.3 b/contrib/libxo/libxo/xo_error.3 new file mode 100644 index 000000000000..da91785928d5 --- /dev/null +++ b/contrib/libxo/libxo/xo_error.3 @@ -0,0 +1,64 @@ +.\" # +.\" # Copyright (c) 2014, Juniper Networks, Inc. +.\" # All rights reserved. +.\" # This SOFTWARE is licensed under the LICENSE provided in the +.\" # ../Copyright file. By downloading, installing, copying, or +.\" # using the SOFTWARE, you agree to be bound by the terms of that +.\" # LICENSE. +.\" # Phil Shafer, July 2014 +.\" +.Dd December 4, 2014 +.Dt LIBXO 3 +.Os +.Sh NAME +.Nm xo_error +.Nd generate error messages +.Sh LIBRARY +.Lb libxo +.Sh SYNOPSIS +.In libxo/xo.h +.Ft void +.Fn xo_error "const char *fmt" "..." +.Sh DESCRIPTION +Use the +.Fn xo_error +function to generate error messages to standard error. +The +.Fa fmt +argument is a string containing printf-style formatting +instructions that describe the remaining arguments. +.Pp +When converting an application to libxo, one can replace +.Em "fprintf(stderr,...)" +calls with +.Fn xo_error +calls. +.Pp +.Sh ADDITIONAL DOCUMENTATION +Complete documentation can be found on github: +.Bd -literal -offset indent +http://juniper.github.io/libxo/libxo-manual.html +.Ed +.Pp +.Nm libxo +lives on github as: +.Bd -literal -offset indent +https://github.com/Juniper/libxo +.Ed +.Pp +The latest release of +.Nm libxo +is available at: +.Bd -literal -offset indent +https://github.com/Juniper/libxo/releases +.Ed +.Sh SEE ALSO +.Xr printf 3 +.Xr xo_emit 3 +.Sh HISTORY +The +.Nm libxo +library was added in +.Fx 11.0 . +.Sh AUTHOR +Phil Shafer diff --git a/contrib/libxo/libxo/xo_finish.3 b/contrib/libxo/libxo/xo_finish.3 index 3b25dc34cbfc..421e94557bf9 100644 --- a/contrib/libxo/libxo/xo_finish.3 +++ b/contrib/libxo/libxo/xo_finish.3 @@ -7,7 +7,7 @@ .\" # LICENSE. .\" # Phil Shafer, July 2014 .\" -.Dd July, 2014 +.Dd December 4, 2014 .Dt LIBXO 3 .Os .Sh NAME @@ -24,9 +24,10 @@ .Sh DESCRIPTION When the program is ready to exit or close a handle, a call to .Fn xo_finish -is required. This flushes any buffered data, closes +is required. +This flushes any buffered data, closes open -.Em libxo +.Nm libxo constructs, and completes any pending operations. .Pp Calling this function is @@ -34,18 +35,20 @@ Calling this function is to the proper operation of libxo, especially for the non-TEXT output styles. .Sh ADDITIONAL DOCUMENTATION -.Pp Complete documentation can be found on github: .Bd -literal -offset indent http://juniper.github.io/libxo/libxo-manual.html .Ed .Pp -libxo lives on github as: +.Nm libxo +lives on github as: .Bd -literal -offset indent https://github.com/Juniper/libxo .Ed .Pp -The latest release of libxo is available at: +The latest release of +.Nm libxo +is available at: .Bd -literal -offset indent https://github.com/Juniper/libxo/releases .Ed @@ -53,7 +56,8 @@ https://github.com/Juniper/libxo/releases .Xr xo_emit 3 .Sh HISTORY The -.Fa libxo -library was added in FreeBSD 11.0. +.Nm libxo +library was added in +.Fx 11.0 . .Sh AUTHOR Phil Shafer diff --git a/contrib/libxo/libxo/xo_flush.3 b/contrib/libxo/libxo/xo_flush.3 index 160f634773de..b85e9f786d0c 100644 --- a/contrib/libxo/libxo/xo_flush.3 +++ b/contrib/libxo/libxo/xo_flush.3 @@ -7,7 +7,7 @@ .\" # LICENSE. .\" # Phil Shafer, July 2014 .\" -.Dd July, 2014 +.Dd December 4, 2014 .Dt LIBXO 3 .Os .Sh NAME @@ -22,25 +22,29 @@ .Ft void .Fn xo_flush_h "xo_handle_t *handle" .Sh DESCRIPTION -.Em libxo +.Nm libxo buffers data, both for performance and consistency, but also to -allow some advanced features to work properly. At various times, the -caller may wish to flush any data buffered within the library. The +allow some advanced features to work properly. +At various times, the +caller may wish to flush any data buffered within the library. +The .Fn xo_flush function is used for this. .Sh ADDITIONAL DOCUMENTATION -.Pp Complete documentation can be found on github: .Bd -literal -offset indent http://juniper.github.io/libxo/libxo-manual.html .Ed .Pp -libxo lives on github as: +.Nm libxo +lives on github as: .Bd -literal -offset indent https://github.com/Juniper/libxo .Ed .Pp -The latest release of libxo is available at: +The latest release of +.Nm libxo +is available at: .Bd -literal -offset indent https://github.com/Juniper/libxo/releases .Ed @@ -48,7 +52,8 @@ https://github.com/Juniper/libxo/releases .Xr xo_emit 3 .Sh HISTORY The -.Fa libxo -library was added in FreeBSD 11.0. +.Nm libxo +library was added in +.Fx 11.0 . .Sh AUTHOR Phil Shafer diff --git a/contrib/libxo/libxo/xo_format.5 b/contrib/libxo/libxo/xo_format.5 index 62cfeb6b92f8..b021b98fd559 100644 --- a/contrib/libxo/libxo/xo_format.5 +++ b/contrib/libxo/libxo/xo_format.5 @@ -7,7 +7,7 @@ .\" # LICENSE. .\" # Phil Shafer, July 2014 .\" -.Dd July, 2014 +.Dd December 4, 2014 .Dt LIBXO 3 .Os .Sh NAME @@ -15,7 +15,7 @@ .Nd content of format descriptors for xo_emit .Sh DESCRIPTION .Pp -.Em libxo +.Nm libxo uses format strings to control the rendering of data into various output styles, including .Em text , @@ -25,25 +25,28 @@ and .Em HTML . Each format string contains a set of zero or more .Dq field descriptions , -which describe independent data fields. Each -field description contains a set of +which describe independent data fields. +Each field description contains a set of .Dq modifiers , a .Dq content string , and zero, one, or two .Dq format descriptors . The modifiers tell -.Em libxo +.Nm libxo what the field is and how to treat it, while the format descriptors are formatting instructions using -.Xr printf 3 -style +.Xr printf 3 Ns -style format strings, telling -libxo how to format the field. The field description is placed inside +.Nm libxo +how to format the field. +The field description is placed inside a set of braces, with a colon .Ql ( \&: ) after the modifiers and a slash .Ql ( \&/ ) -before each format descriptors. Text may be intermixed with +before each format descriptors. +Text may be intermixed with field descriptions within the format string. .Pp The field description is given as follows: @@ -53,15 +56,19 @@ The field description is given as follows: .Ed .Pp The role describes the function of the field, while the modifiers -enable optional behaviors. The contents, field-format, and -encoding-format are used in varying ways, based on the role. These -are described in the following sections. +enable optional behaviors. +The contents, field-format, and +encoding-format are used in varying ways, based on the role. +These are described in the following sections. .Pp -In the following example, three field descriptors appear. The first +In the following example, three field descriptors appear. +The first is a padding field containing three spaces of padding, the second is a -label ("In stock"), and the third is a value field ("in-stock"). The -in-stock field has a "%u" format that will parse the next argument -passed to the xo_emit function as an unsigned integer. +label ("In stock"), and the third is a value field ("in-stock"). +The in-stock field has a "%u" format that will parse the next argument +passed to the +.Xr xo_emit 3 , +function as an unsigned integer. .Bd -literal -offset indent xo_emit("{P: }{Lwc:In stock}{:in-stock/%u}\\n", 65); .Ed @@ -71,7 +78,8 @@ This single line of code can generate text ("In stock: 65\\n"), XML lengthy to be listed here). .Ss Modifier Roles Modifiers are optional, and indicate the role and formatting of the -content. The roles are listed below; only one role is permitted: +content. +The roles are listed below; only one role is permitted: .Pp .Bl -column "M" "Name12341234" .It Sy "M Name Description" @@ -91,7 +99,8 @@ content. The roles are listed below; only one role is permitted: .Ss The Decoration Role ({D:}) Decorations are typically punctuation marks such as colons, semi-colons, and commas used to decorate the text and make it simpler -for human readers. By marking these distinctly, HTML usage scenarios +for human readers. +By marking these distinctly, HTML usage scenarios can use CSS to direct their display parameters. .Bd -literal -offset indent xo_emit("{D:((}{:name}{D:))}\\n", name); @@ -116,8 +125,9 @@ if preceded by a slash ("/"): xo_emit("{P:/30s}{Lwc:Cost}{:cost/%u}\\n", "", cost); .Ed .Ss The Title Role ({T:}) -Title are heading or column headers that are meant to be displayed to -the user. The title can be either static, when placed directly within +Titles are heading or column headers that are meant to be displayed to +the user. +The title can be either static, when placed directly within the field descriptor, or a printf-style format descriptor can be used, if preceded by a slash ("/"): .Bd -literal -offset indent @@ -126,7 +136,8 @@ if preceded by a slash ("/"): .Ed .Ss The Units Role ({U:}) Units are the dimension by which values are measured, such as degrees, -miles, bytes, and decibels. The units field carries this information +miles, bytes, and decibels. +The units field carries this information for the previous value field. .Bd -literal -offset indent xo_emit("{Lwc:Distance}{:distance/%u}{Uw:miles}\\n", miles); @@ -136,7 +147,7 @@ Note that the sense of the 'w' modifier is reversed for units; a blank is added before the contents, rather than after it. .Pp When the -.Em XOF_UNITS +.Dv XOF_UNITS flag is set, units are rendered in XML as the .Dq units attribute: @@ -151,14 +162,19 @@ Units can also be rendered in HTML as the "data-units" attribute: .Ed .Ss The Value Role ({V:} and {:}) The value role is used to represent the a data value that is -interesting for the non-display output styles (XML and JSON). Value +interesting for the non-display output styles (XML and JSON). +Value is the default role; if no other role designation is given, the field -is a value. The field name must appear within the field descriptor, -followed by one or two format descriptors. The first format +is a value. +The field name must appear within the field descriptor, +followed by one or two format descriptors. +The first format descriptor is used for display styles (TEXT and HTML), while the -second one is used for encoding styles (XML and JSON). If no second +second one is used for encoding styles (XML and JSON). +If no second format is given, the encoding format defaults to the first format, -with any minimum width removed. If no first format is given, both +with any minimum width removed. +If no first format is given, both format descriptors default to "%s". .Bd -literal -offset indent xo_emit("{:length/%02u}x{:width/%02u}x{:height/%02u}\\n", @@ -168,9 +184,13 @@ format descriptors default to "%s". .Ed .Ss The Anchor Modifiers ({[:} and {]:}) The anchor roles allow a set of strings by be padded as a group, -but still be visible to xo_emit as distinct fields. Either the start +but still be visible to +.Xr xo_emit 3 +as distinct fields. +Either the start or stop anchor can give a field width and it can be either directly in -the descriptor or passed as an argument. Any fields between the start +the descriptor or passed as an argument. +Any fields between the start and stop anchor are padded to meet the minimum width given. .Pp To give a width directly, encode it as the content of the anchor tag: @@ -179,21 +199,26 @@ To give a width directly, encode it as the content of the anchor tag: .Ed .Pp To pass a width as an argument, use "%d" as the format, which must -appear after the "/". Note that only "%d" is supported for widths. +appear after the "/". +Note that only "%d" is supported for widths. Using any other value could ruin your day. .Bd -literal -offset indent xo_emit("({[:/%d}{:min/%d}/{:max/%d}{]:})\\n", width, min, max); .Ed .Pp If the width is negative, padding will be added on the right, suitable -for left justification. Otherwise the padding will be added to the +for left justification. +Otherwise the padding will be added to the left of the fields between the start and stop anchors, suitable for -right justification. If the width is zero, nothing happens. If the +right justification. +If the width is zero, nothing happens. +If the number of columns of output between the start and stop anchors is less than the absolute value of the given width, nothing happens. .Pp -Widths over 8k are considered probable errors and not supported. If -.Em XOF_WARN +Widths over 8k are considered probable errors and not supported. +If +.Dv XOF_WARN is set, a warning will be generated. .Ss Modifier Flags The modifiers can also include the following flags, which modify the @@ -201,19 +226,20 @@ content emitted for some output styles: .Pp .Bl -column M "Name12341234" .It Sy M "Name Description" -.It c "colon " "A colon (":") is appended after the label" +.It c "colon " "A colon ("":"") is appended after the label" .It d "display " "Only emit field for display styles (text/HTML)" .It e "encoding " "Only emit for encoding styles (XML/JSON)" .It k "key " "Field is a key, suitable for XPath predicates" .It n "no-quotes " "Do not quote the field when using JSON style" .It q "quotes " "Quote the field when using JSON style" -.It w "white space " "A blank (" ") is appended after the label" +.It w "white space " "A blank ("" "") is appended after the label" .El .Pp For example, the modifier string "Lwc" means the field has a label role (text that describes the next field) and should be followed by a -colon ('c') and a space ('w'). The modifier string "Vkq" means the -field is has value role, that it is a key for the current instance, and +colon ('c') and a space ('w'). +The modifier string "Vkq" means the +field has a value role, that it is a key for the current instance, and that the value should be quoted when encoded for JSON. .Ss The Colon Modifier ({c:}) The colon modifier appends a single colon to the data value: @@ -225,7 +251,8 @@ The colon modifier appends a single colon to the data value: .Ed .Pp The colon modifier is only used for the TEXT and HTML output -styles. It is commonly combined with the space modifier ('{w:'). +styles. +It is commonly combined with the space modifier ('{w:}'). It is purely a convenience feature. .Ss The Display Modifier ({d:}) The display modifier indicated the field should only be generated for @@ -270,15 +297,34 @@ uniquely identify an instance of list data. xo_close_list("user"); .Ed .Pp -Currently the key modifier is only used when generating XPath value +Currently the key modifier is only used when generating XPath values for the HTML output style when -.Em XOF_XPATH +.Dv XOF_XPATH is set, but other uses are likely in the near future. +.Ss The Leaf-List Modifier ({l:}) +The leaf-list modifier is used to distinguish lists where each +instance consists of only a single value. In XML, these are +rendered as single elements, where JSON renders them as arrays. +.Bd -literal -offset indent + EXAMPLE: + xo_open_list("user"); + for (i = 0; i < num_users; i++) { + xo_emit("Member {l:name}\n", user[i].u_name); + } + xo_close_list("user"); + XML: + phil + pallavi + JSON: + "user": [ "phil", "pallavi" ] +.Ed .Ss The No-Quotes Modifier ({n:}) The no-quotes modifier (and its twin, the 'quotes' modifier) affect -the quoting of values in the JSON output style. JSON uses quotes for -string value, but no quotes for numeric, boolean, and null data. -xo_emit applies a simple heuristic to determine whether quotes are +the quoting of values in the JSON output style. +JSON uses quotes for +string values, but no quotes for numeric, boolean, and null data. +.Xr xo_emit 3 +applies a simple heuristic to determine whether quotes are needed, but often this needs to be controlled by the caller. .Bd -literal -offset indent EXAMPLE: @@ -289,9 +335,11 @@ needed, but often this needs to be controlled by the caller. .Ed .Ss The Quotes Modifier ({q:}) The quotes modifier (and its twin, the 'no-quotes' modifier) affect -the quoting of values in the JSON output style. JSON uses quotes for -string value, but no quotes for numeric, boolean, and null data. -xo_emit applies a simple heuristic to determine whether quotes are +the quoting of values in the JSON output style. +JSON uses quotes for +string values, but no quotes for numeric, boolean, and null data. +.Xr xo_emit 3 +applies a simple heuristic to determine whether quotes are needed, but often this needs to be controlled by the caller. .Bd -literal -offset indent EXAMPLE: @@ -309,7 +357,8 @@ The white space modifier appends a single space to the data value: .Ed .Pp The white space modifier is only used for the TEXT and HTML output -styles. It is commonly combined with the colon modifier ('{c:'). +styles. +It is commonly combined with the colon modifier ('{c:}'). It is purely a convenience feature. .Pp Note that the sense of the 'w' modifier is reversed for the units role @@ -317,16 +366,20 @@ Note that the sense of the 'w' modifier is reversed for the units role .Ss Field Formatting The field format is similar to the format string for .Xr printf 3 . -It's used varies based on the role of the field, but generally is used to +Its use varies based on the role of the field, but generally is used to format the field's contents. .Pp -If not provided, the format string defaults to "%s". +If the format string is not provided for a value field, it defaults +to "%s". .Pp Note a field definition can contain zero or more printf-style .Dq directives , -which are sequences that start with a '%' and end with a -one of following characters: "diouxXDOUeEfFgGaAcCsSp". Each directive -is matched by one of more arguments to the xo_emit function. +which are sequences that start with a '%' and end with +one of following characters: "diouxXDOUeEfFgGaAcCsSp". +Each directive +is matched by one of more arguments to the +.Xr xo_emit 3 +function. .Pp The format string has the form: .Bd -literal -offset indent @@ -346,19 +399,22 @@ a leading zero ('0') indicating the output value should be padded on the left with zeroes instead of spaces (' '). .It one or more digits ('0' - '9') indicating the minimum width of the -argument. If the width in columns of the output value is less that -the minumum width, the value will be padded to reach the minimum. +argument. +If the width in columns of the output value is less than +the minimum width, the value will be padded to reach the minimum. .It a period followed by one or more digits indicating the maximum number of bytes which will be examined for a string argument, or the maximum -width for a non-string argument. When handling ASCII strings this is +width for a non-string argument. +When handling ASCII strings this functions as the field width but for multi-byte characters, a single character may be composed of multiple bytes. -xo_emit will never dereference memory beyond the given number of bytes. +.Xr xo_emit 3 +will never dereference memory beyond the given number of bytes. .It a second period followed by one or more digits indicating the maximum -width for a string argument. This modifier cannot be given for non-string -arguments. +width for a string argument. +This modifier cannot be given for non-string arguments. .It one or more 'h' characters, indicating shorter input data. .It @@ -420,39 +476,50 @@ argument: .El .Pp .Ss UTF-8 and Locale Strings -All strings for libxo must be UTF-8. libxo will handle turning them +All strings for +.Nm libxo +must be UTF-8. +.Nm libxo +will handle turning them into locale-based strings for display to the user. .Pp For strings, the 'h' and 'l' modifiers affect the interpretation of -the bytes pointed to argument. The default '%s' string is a 'char *' -pointer to a string encoded as UTF-8. Since UTF-8 is compatible with +the bytes pointed to argument. +The default '%s' string is a 'char *' +pointer to a string encoded as UTF-8. +Since UTF-8 is compatible with .Em ASCII data, a normal 7-bit .Em ASCII - string can be used. '%ls' expects a -'wchar_t *' pointer to a wide-character string, encoded as a 32-bit -Unicode values. '%hs' expects a 'char *' pointer to a multi-byte +string can be used. +'%ls' expects a +'wchar_t *' pointer to a wide-character string, encoded as 32-bit +Unicode values. +'%hs' expects a 'char *' pointer to a multi-byte string encoded with the current locale, as given by the -.Em LC_CTYPE , -.Em LANG , +.Ev LC_CTYPE , +.Ev LANG , or -.Em LC_ALL -environment varibles. The first of this list of -variables is used and if none of the variables, the locale defaults to -.Em UTF-8. +.Ev LC_ALL +environment variables. +The first of this list of +variables is used and if none of the variables are set, the locale defaults to +.Em UTF-8 . .Pp -libxo will +.Nm libxo +will convert these arguments as needed to either UTF-8 (for XML, JSON, and HTML styles) or locale-based strings for display in text style. .Bd -literal -offset indent - xo_emit("Alll strings are utf-8 content {:tag/%ls}", + xo_emit("All strings are utf-8 content {:tag/%ls}", L"except for wide strings"); .Ed .Pp "%S" is equivalent to "%ls". .Pp For example, a function is passed a locale-base name, a hat size, -and a time value. The hat size is formatted in a UTF-8 (ASCII) +and a time value. +The hat size is formatted in a UTF-8 (ASCII) string, and the time value is formatted into a wchar_t string. .Bd -literal -offset indent void print_order (const char *name, int size, @@ -475,29 +542,35 @@ string, and the time value is formatted into a wchar_t string. } .Ed .Pp -It is important to note that xo_emit will perform the conversion -required to make appropriate output. Text style output uses the +It is important to note that +.Xr xo_emit 3 +will perform the conversion +required to make appropriate output. +Text style output uses the current locale (as described above), while XML, JSON, and HTML use UTF-8. .Pp UTF-8 and locale-encoded strings can use multiple bytes to encode one -column of data. The traditional "precision'" (aka "max-width") value +column of data. +The traditional "precision'" (aka "max-width") value for "%s" printf formatting becomes overloaded since it specifies both the number of bytes that can be safely referenced and the maximum -number of columns to emit. xo_emit uses the precision as the former, +number of columns to emit. +.Xr xo_emit 3 +uses the precision as the former, and adds a third value for specifying the maximum number of columns. .Pp In this example, the name field is printed with a minimum of 3 columns -and a maximum of 6. Up to ten bytes are in used in filling those -columns. +and a maximum of 6. +Up to ten bytes are in used in filling those columns. .Bd -literal -offset indent xo_emit("{:name/%3.10.6s}", name); .Ed .Ss Characters Outside of Field Definitions -Characters in the format string are not part of a field definition are +Characters in the format string that are not part of a field definition are copied to the output for the TEXT style, and are ignored for the JSON -and XML styles. For HTML, these characters are placed in a
with -class "text". +and XML styles. +For HTML, these characters are placed in a
with class "text". .Bd -literal -offset indent EXAMPLE: xo_emit("The hat is {:size/%s}.\\n", size_val); @@ -513,13 +586,16 @@ class "text".
.
.Ed .Ss "%n" is Not Supported -libxo does not support the '%n' directive. It's a bad idea and we -just don't do it. +.Nm libxo +does not support the '%n' directive. +It is a bad idea and we +just do not do it. .Ss The Encoding Format (eformat) The "eformat" string is the format string used when encoding the field -for JSON and XML. If not provided, it defaults to the primary format -with any minimum width removed. If the primary is not given, both -default to "%s". +for JSON and XML. +If not provided, it defaults to the primary format +with any minimum width removed. +If the primary is not given, both default to "%s". .Sh EXAMPLE In this example, the value for the number of items in stock is emitted: .Bd -literal -offset indent @@ -547,9 +623,9 @@ This call will generate the following output: .Pp Clearly HTML wins the verbosity award, and this output does not include -.Em XOF_XPATH +.Dv XOF_XPATH or -.Em XOF_INFO +.Dv XOF_INFO data, which would expand the penultimate line to: .Bd -literal -offset indent
- +.Ss Use - Using the form - or -- helps in making consistent, useful names, avoiding the situation where one app uses "sent-packet" and another "packets-sent" and another -"packets-we-have-sent". The can be dropped when it is +"packets-we-have-sent". +The can be dropped when it is obvious, as can obvious words in the classification. Use "receive-after-window-packets" instead of "received-packets-of-data-after-window". -.Se Reuse existing field names -Nothing's worse than writing expressions like: +.Ss Reuse existing field names +Nothing is worse than writing expressions like: .Bd -literal -offset indent if ($src1/process[pid == $pid]/name == $src2/proc-table/proc/p[process-id == $pid]/proc-name) { @@ -591,32 +672,38 @@ Nothing's worse than writing expressions like: .Ed .Pp Find someone else who is expressing similar data and follow their -field's and hierarchy. Remember the quote is not +fields and hierarchy. +Remember the quote is not .Dq Consistency is the hobgoblin of little minds but -.Dq A foolish consistency is the hobgoblin of little minds. +.Dq A foolish consistency is the hobgoblin of little minds . .Ss Think about your users Have empathy for your users, choosing clear and useful fields that -contain clear and useful data. You may need to augment the display -content with +contain clear and useful data. +You may need to augment the display content with .Xr xo_attr 3 calls or "{e:}" fields to make the data useful. -.Ss Don't use an arbitrary number postfix -What does "errors2" mean? No one will know. "errors-after-restart" -would be a better choice. Think of you users, and think of the -future. If you make "errors2", the next guy will happily make -"errors3" and before you know it, someone will be asking what's the +.Ss Do not use an arbitrary number postfix +What does "errors2" mean? +No one will know. +"errors-after-restart" would be a better choice. +Think of your users, and think of the future. +If you make "errors2", the next guy will happily make +"errors3" and before you know it, someone will be asking what is the difference between errors37 and errors63. .Ss Be consistent, uniform, unsurprising, and predictable -Think of your field vocabulary as an API. You want it useful, -expressive, meaningful, direct, and obvious. You want the client +Think of your field vocabulary as an API. +You want it useful, +expressive, meaningful, direct, and obvious. +You want the client application's programmer to move between without the need to -understand a variety of opinions on how fields are named. They should +understand a variety of opinions on how fields are named. +They should see the system as a single cohesive whole, not a sack of cats. .Pp Field names constitute the means by which client programmers interact -with our system. By choosing wise names now, you are making their -lives better. +with our system. +By choosing wise names now, you are making their lives better. .Pp After using .Xr xolint 1 @@ -628,30 +715,36 @@ names for the same data. and .Dq dropped-too-short are both reasonable names, but using them both will lead users to ask the -difference between the two fields. If there isn't a difference, -use only one of the field names. If there is a difference, change the +difference between the two fields. +If there is no difference, +use only one of the field names. +If there is a difference, change the names to make that difference more obvious. .Sh ADDITIONAL DOCUMENTATION -.Pp Complete documentation can be found on github: .Bd -literal -offset indent http://juniper.github.io/libxo/libxo-manual.html .Ed .Pp -libxo lives on github as: +.Nm libxo +lives on github as: .Bd -literal -offset indent https://github.com/Juniper/libxo .Ed .Pp -The latest release of libxo is available at: +The latest release of +.Nm libxo +is available at: .Bd -literal -offset indent https://github.com/Juniper/libxo/releases .Ed .Sh SEE ALSO +.Xr xolint 1 , .Xr xo_emit 3 .Sh HISTORY The -.Fa libxo -library was added in FreeBSD 11.0. +.Nm libxo +library was added in +.Fx 11.0 . .Sh AUTHOR Phil Shafer diff --git a/contrib/libxo/libxo/xo_no_setlocale.3 b/contrib/libxo/libxo/xo_no_setlocale.3 index 94a126440f83..c3f32a403d03 100644 --- a/contrib/libxo/libxo/xo_no_setlocale.3 +++ b/contrib/libxo/libxo/xo_no_setlocale.3 @@ -7,12 +7,13 @@ .\" # LICENSE. .\" # Phil Shafer, July 2014 .\" -.Dd July, 2014 +.Dd December 4, 2014 .Dt LIBXO 3 .Os .Sh NAME .Nm xo_no_setlocale -.Nd prevent implicit call to setlocale() +.Nd prevent implicit call to +.Fn setlocale .Sh LIBRARY .Lb libxo .Sh SYNOPSIS @@ -20,44 +21,48 @@ .Ft void .Fn xo_no_setlocale "void" .Sh DESCRIPTION -.Em libxo -automatically initializes the locale based on setting of the +.Nm libxo +automatically initializes the locale based on the setting of the environment variables -.Em LC_CTYPE , -.Em LANG , +.Ev LC_CTYPE , +.Ev LANG , and -.Em LC_ALL . +.Ev LC_ALL . The first of this -list of variables is used and if none of the variables, the locale +list of variables is used and if none of the variables are set, the locale defaults to -.Em UTF-8. The caller may wish to avoid this behavior, and +.Em UTF-8 . +The caller may wish to avoid this behavior, and can do so by calling the .Fn xo_no_setlocale function. .Sh ADDITIONAL DOCUMENTATION -.Pp Complete documentation can be found on github: .Bd -literal -offset indent http://juniper.github.io/libxo/libxo-manual.html .Ed .Pp -libxo lives on github as: +.Nm libxo +lives on github as: .Bd -literal -offset indent https://github.com/Juniper/libxo .Ed .Pp -The latest release of libxo is available at: +The latest release of +.Nm libxo +is available at: .Bd -literal -offset indent https://github.com/Juniper/libxo/releases .Ed .Sh SEE ALSO .Xr xo_emit 3 , .Xr xo_open_container 3 , -.Xr xo_open_list 3 , and -.Xr xo_format 5 . +.Xr xo_open_list 3 , +.Xr xo_format 5 .Sh HISTORY The -.Fa libxo -library was added in FreeBSD 11.0. +.Nm libxo +library was added in +.Fx 11.0 . .Sh AUTHOR Phil Shafer diff --git a/contrib/libxo/libxo/xo_open_container.3 b/contrib/libxo/libxo/xo_open_container.3 index 9ba32c98f6f4..86412ca91da7 100644 --- a/contrib/libxo/libxo/xo_open_container.3 +++ b/contrib/libxo/libxo/xo_open_container.3 @@ -7,7 +7,7 @@ .\" # LICENSE. .\" # Phil Shafer, July 2014 .\" -.Dd July, 2014 +.Dd December 4, 2014 .Dt LIBXO 3 .Os .Sh NAME @@ -47,13 +47,14 @@ .Ft int .Fn xo_close_container_d "void" .Sh DESCRIPTION -.Fa libxo +.Nm libxo represents to types of hierarchy: .Dq containers and .Dq lists . A container appears once under a given parent where a list contains -instances that can appear multiple times. A container is used to hold +instances that can appear multiple times. +A container is used to hold related fields and to give the data organization and scope. The container has no value, but serves to contain other nodes. @@ -71,8 +72,9 @@ or .Fn xo_close_container_h functions. .Pp -Each open call must have a matching close call. If the -.Fa XOF_WARN +Each open call must have a matching close call. +If the +.Dv XOF_WARN flag is set and the name given does not match the name of the currently open container, a warning will be generated. @@ -115,8 +117,8 @@ The .Fa handle parameter contains a handle such as returned by .Xr xo_create 3 -or a -.Em NULL +or +.Dv NULL to use the default handle. The .Fa name @@ -134,18 +136,18 @@ suffix are used in .Dq \&Do The Right Thing mode, where the name of the open containers, lists, and instances are maintained internally by -.Em libxo +.Nm libxo to allow the caller to avoid keeping track of the open container name. .Pp Use the -.Em XOF_WARN +.Dv XOF_WARN flag to generate a warning if the name given on the close does not match the current open container. .Pp For TEXT and HTML output, containers are not rendered into output text, though for HTML they are used when the -.Em XOF_XPATH +.Dv XOF_XPATH flag is set. .Pp .Bd -literal -offset indent -compact @@ -157,21 +159,22 @@ flag is set. foo .Ed .Sh DTRT MODE -Some user may find tracking the names of open containers, lists, and +Some users may find tracking the names of open containers, lists, and instances inconvenient. -.Em libxo -offers +.Nm libxo +offers a .Dq \&Do The Right Thing mode, where -.Em libxo +.Nm libxo will track the names of open containers, lists, and instances so -the close function can be called without a name. To enable +the close function can be called without a name. +To enable .Em DTRT mode, turn on the -.Em XOF_DTRT +.Dv XOF_DTRT flag prior to making any other -.Em libxo +.Nm libxo output. .Bd -literal -offset indent -compact xo_set_flags(NULL, XOF_DTRT); @@ -185,24 +188,28 @@ which will close the open container, list, or instance: xo_close_container_d(); .Ed Note that the -.Em XOF_WARN -flag will also cause libxo to track open +.Dv XOF_WARN +flag will also cause +.Nm libxo +to track open containers, lists, and instances. -A warning is generated with the name given to the close function +A warning is generated when the name given to the close function and the name recorded do not match. .Sh ADDITIONAL DOCUMENTATION -.Pp Complete documentation can be found on github: .Bd -literal -offset indent http://juniper.github.io/libxo/libxo-manual.html .Ed .Pp -libxo lives on github as: +.Nm libxo +lives on github as: .Bd -literal -offset indent https://github.com/Juniper/libxo .Ed .Pp -The latest release of libxo is available at: +The latest release of +.Nm libxo +is available at: .Bd -literal -offset indent https://github.com/Juniper/libxo/releases .Ed @@ -210,7 +217,8 @@ https://github.com/Juniper/libxo/releases .Xr xo_emit 3 .Sh HISTORY The -.Fa libxo -library was added in FreeBSD 11.0. +.Nm libxo +library was added in +.Fx 11.0 . .Sh AUTHOR Phil Shafer diff --git a/contrib/libxo/libxo/xo_open_list.3 b/contrib/libxo/libxo/xo_open_list.3 index 9a6a21504c7c..047af87596fa 100644 --- a/contrib/libxo/libxo/xo_open_list.3 +++ b/contrib/libxo/libxo/xo_open_list.3 @@ -7,7 +7,7 @@ .\" # LICENSE. .\" # Phil Shafer, July 2014 .\" -.Dd July, 2014 +.Dd December 4, 2014 .Dt LIBXO 3 .Os .Sh NAME @@ -71,19 +71,23 @@ .Ft int .Fn xo_close_list_d "void" .Sh DESCRIPTION -Lists are sequences of instances of homogeneous data objects. Two +Lists are sequences of instances of homogeneous data objects. +Two distinct levels of calls are needed to represent them in our output -styles. Calls must be made to open and close a list, and for each +styles. +Calls must be made to open and close a list, and for each instance of data in that list, calls must be make to open and close that instance. .Pp -The name given to all calls must be identical, and it is strong +The name given to all calls must be identical, and it is strongly suggested that the name be singular, not plural, as a matter of style and usage expectations. .Pp -A list is set of one or more instances that appear under the same -parent. The instances contains details about a specific object. One -can think of instances as objects or records. A call is needed to +A list is a set of one or more instances that appear under the same +parent. +The instances contain details about a specific object. +One can think of instances as objects or records. +A call is needed to open and close the list, while a distinct call is needed to open and close each instance of the list: .Bd -literal -offset indent -compact @@ -143,19 +147,45 @@ generation of XML and JSON data. } ] .Ed -.Sh ADDITIONAL DOCUMENTATION .Pp +.Sh LEAF LISTS +In contrast to a list of instances, a "leaf list" is list of simple +values. +To emit a leaf list, call the +.Fn xo_emit +function using the ""l"" modifier: +.Bd -literal -offset indent -compact + for (ip = list; ip->i_title; ip++) { + xo_emit("{Lwc:Item}{l:item}\n", ip->i_title); + } +.Ed +.Pp +The name of the field must match the name of the leaf list. +.Pp +In JSON, leaf lists are rendered as arrays of values. In XML, they +are rendered as multiple leaf elements. +.Bd -literal -offset indent -compact + JSON: + "item": "hammer", "nail" + XML: + hammer + nail +.Ed +.Sh ADDITIONAL DOCUMENTATION Complete documentation can be found on github: .Bd -literal -offset indent http://juniper.github.io/libxo/libxo-manual.html .Ed .Pp -libxo lives on github as: +.Nm libxo +lives on github as: .Bd -literal -offset indent https://github.com/Juniper/libxo .Ed .Pp -The latest release of libxo is available at: +The latest release of +.Nm libxo +is available at: .Bd -literal -offset indent https://github.com/Juniper/libxo/releases .Ed @@ -163,7 +193,8 @@ https://github.com/Juniper/libxo/releases .Xr xo_emit 3 .Sh HISTORY The -.Fa libxo -library was added in FreeBSD 11.0. +.Nm libxo +library was added in +.Fx 11.0 . .Sh AUTHOR Phil Shafer diff --git a/contrib/libxo/libxo/xo_parse_args.3 b/contrib/libxo/libxo/xo_parse_args.3 index a9b4cec29b30..f66546bd3c9e 100644 --- a/contrib/libxo/libxo/xo_parse_args.3 +++ b/contrib/libxo/libxo/xo_parse_args.3 @@ -7,27 +7,31 @@ .\" # LICENSE. .\" # Phil Shafer, July 2014 .\" -.Dd July, 2014 +.Dd December 4, 2014 .Dt LIBXO 3 .Os .Sh NAME .Nm xo_parse_args .Nd detect, parse, and remove arguments for libxo .Sh LIBRARY -.Nm libxo +.Lb libxo .Sh SYNOPSIS .In libxo/xo.h .Ft int .Fn xo_parse_args "int argc" "char **argv" +.Ft int +.Fn xo_set_program "const char *name" .Sh DESCRIPTION The .Fn xo_parse_args function is used to process command-line arguments. -.Em libxo -specific +.Nm libxo +specific options are processed and removed from the argument list so the calling application does not -need to process them. If successful, a new value for argc -is returned. On failure, a message it emitted and -1 is returned. +need to process them. +If successful, a new value for argc is returned. +On failure, a message it emitted and -1 is returned. .Bd -literal -offset indent argc = xo_parse_args(argc, argv); if (argc < 0) @@ -38,9 +42,9 @@ Following the call to .Fn xo_parse_args , the application can process the remaining arguments in a normal manner. .Pp -.Em libxo -uses command line options to trigger rendering behavior. The -following options are recognised: +.Nm libxo +uses command line options to trigger rendering behavior. +The following options are recognised: .Pp .Bl -tag -width "--libxo" .It @@ -56,44 +60,45 @@ styles, flags, or features: .Pp .Bl -tag -width "12345678" .It Sy "Token Action" -.It dtrt +.It Dv dtrt Enable "Do The Right Thing" mode -.It html +.It Dv html Emit HTML output -.It indent=xx +.It Dv indent=xx Set the indentation level -.It info +.It Dv info Add info attributes (HTML) -.It json +.It Dv json Emit JSON output -.It keys +.It Dv keys Emit the key attribute for keys (XML) -.It no-locale +.It Dv no-locale Do not initialize the locale setting -.It no-top +.It Dv no-top Do not emit a top set of braces (JSON) -.It not-first +.It Dv not-first Pretend the 1st output item was not 1st (JSON) -.It pretty +.It Dv pretty Emit pretty-printed output -.It text +.It Dv text Emit TEXT output -.It units +.It Dv units Add the 'units' (XML) or 'data-units (HTML) attribute -.It warn +.It Dv warn Emit warnings when libxo detects bad calls -.It warn-xml +.It Dv warn-xml Emit warnings in XML -.It xml +.It Dv xml Emit XML output -.It xpath +.It Dv xpath Add XPath expressions (HTML) .El .Pp The .Dq brief-options are single letter commands, designed for those with -too little patience to use real tokens. No comma separator is used. +too little patience to use real tokens. +No comma separator is used. .Bl -column "i" .It Sy "Token Action" .It "H " "Enable HTML output (XO_STYLE_HTML)" @@ -107,19 +112,41 @@ too little patience to use real tokens. No comma separator is used. .It "x " "Enable XPath data (XOF_XPATH)" .El .Pp -.Sh ADDITIONAL DOCUMENTATION +The +.Fn xo_set_program +function sets name of the program as reported by +functions like +.Fn xo_failure , +.Fn xo_warn , +.Fn xo_err , +etc. +The program name is initialized by +.Fn xo_parse_args , +but subsequent calls to +.Fn xo_set_program +can override this value. .Pp +Note that the value is not copied, so the memory passed to +.Fn xo_set_program +(and +.Fn xo_parse_args ) +must be maintained by the caller. +.Pp +.Sh ADDITIONAL DOCUMENTATION Complete documentation can be found on github: .Bd -literal -offset indent http://juniper.github.io/libxo/libxo-manual.html .Ed .Pp -libxo lives on github as: +.Nm libxo +lives on github as: .Bd -literal -offset indent https://github.com/Juniper/libxo .Ed .Pp -The latest release of libxo is available at: +The latest release of +.Nm libxo +is available at: .Bd -literal -offset indent https://github.com/Juniper/libxo/releases .Ed @@ -127,7 +154,8 @@ https://github.com/Juniper/libxo/releases .Xr xo_emit 3 .Sh HISTORY The -.Fa libxo -library was added in FreeBSD 11.0. +.Nm libxo +library was added in +.Fx 11.0 . .Sh AUTHOR Phil Shafer diff --git a/contrib/libxo/libxo/xo_set_allocator.3 b/contrib/libxo/libxo/xo_set_allocator.3 index 508cc8e9af53..70bfdd59a45d 100644 --- a/contrib/libxo/libxo/xo_set_allocator.3 +++ b/contrib/libxo/libxo/xo_set_allocator.3 @@ -7,7 +7,7 @@ .\" # LICENSE. .\" # Phil Shafer, July 2014 .\" -.Dd July, 2014 +.Dd December 4, 2014 .Dt LIBXO 3 .Os .Sh NAME @@ -25,7 +25,9 @@ .Sh DESCRIPTION The .Fn xo_set_allocator -function allows libxo to be used in environments +function allows +.Nm libxo +to be used in environments where the standard .Xr realloc 3 and @@ -40,7 +42,7 @@ a pointer to memory following the same convention. .Fa free_func will receive the same argument as .Xr free 3 -and should release it, asappropriate for the environment. +and should release it, as appropriate for the environment. .Pp By default, the standard .Xr realloc 3 @@ -48,18 +50,20 @@ and .Xr free 3 functions are used. .Sh ADDITIONAL DOCUMENTATION -.Pp Complete documentation can be found on github: .Bd -literal -offset indent http://juniper.github.io/libxo/libxo-manual.html .Ed .Pp -libxo lives on github as: +.Nm libxo +lives on github as: .Bd -literal -offset indent https://github.com/Juniper/libxo .Ed .Pp -The latest release of libxo is available at: +The latest release of +.Nm libxo +is available at: .Bd -literal -offset indent https://github.com/Juniper/libxo/releases .Ed @@ -67,7 +71,8 @@ https://github.com/Juniper/libxo/releases .Xr xo_emit 3 .Sh HISTORY The -.Fa libxo -library was added in FreeBSD 11.0. +.Nm libxo +library was added in +.Fx 11.0 . .Sh AUTHOR Phil Shafer diff --git a/contrib/libxo/libxo/xo_set_flags.3 b/contrib/libxo/libxo/xo_set_flags.3 index a23de7bfdd7b..ca6655360d21 100644 --- a/contrib/libxo/libxo/xo_set_flags.3 +++ b/contrib/libxo/libxo/xo_set_flags.3 @@ -7,7 +7,7 @@ .\" # LICENSE. .\" # Phil Shafer, July 2014 .\" -.Dd July, 2014 +.Dd December 4, 2014 .Dt LIBXO 3 .Os .Sh NAME @@ -25,96 +25,121 @@ Use the .Fn xo_set_flags function to set the flags for a -.Em libxo -handle. To use the default handle, pass a NULL handle. +.Nm libxo +handle. +To use the default handle, pass a +.Dv NULL +handle. .Pp The set of valid flags include: .Bl -tag -width "XOF_UNDERSCORES" .It Sy "Flag Description" -.It XOF_CLOSE_FP -Close file pointer on xo_destroy(). This -flag will trigger the call of the close_func +.It Dv XOF_CLOSE_FP +Close file pointer on +.Xr xo_destroy 3 . +This flag will trigger the call of the +.Fn close_func (provided via -.Fn xo_set_writer 3 ) +.Xr xo_set_writer 3 ) when the handle is destroyed. -.It XOF_DTRT +.It Dv XOF_DTRT Enable "do the right thing" mode -.It XOF_INFO +.It Dv XOF_INFO Display info data attributes (HTML) -.It XOF_KEYS +.It Dv XOF_KEYS Emit the key attribute (XML) -.It XOF_NO_ENV -Do not use the LIBXO_OPTIONS env var -.It XOF_PRETTY +.It Dv XOF_NO_ENV +Do not use the +.Ev LIBXO_OPTIONS +environment variable. +.It Dv XOF_PRETTY Make 'pretty printed' output, with the addition of indentation and newlines to enhance the readability of -XML, JSON, and HTML output. Text output is not affected. -.It XOF_UNDERSCORES +XML, JSON, and HTML output. +Text output is not affected. +.It Dv XOF_UNDERSCORES Replaces hyphens with underscores -.It XOF_UNITS +.It Dv XOF_UNITS Display units (XML and HMTL) -.It XOF_WARN +.It Dv XOF_WARN Generate warnings for broken calls, triggering diagnostic output (on standard error) when the library notices errors during -operations, or with arguments to functions. Without warning enabled, -such conditions are ignored. -Warnings allow developers to debug their interaction with libxo. -The function "xo_failure" can used as a breakpoint for a debugger, +operations, or with arguments to functions. +Without warnings enabled, such conditions are ignored. +Warnings allow developers to debug their interaction with +.Nm libxo . +The function +.Fn xo_failure +can be used as a breakpoint for a debugger, regardless of whether warnings are enabled. -.It XOF_WARN_XML +.It Dv XOF_WARN_XML Generate warnings in XML on stdout -.It XOF_XPATH +.It Dv XOF_XPATH Emit XPath expressions (HTML) -.It XOF_COLUMNS -Force xo_emit to return columns used -.It XOF_FLUSH -Flush output after each xo_emit call +.It Dv XOF_COLUMNS +Force +.Xr xo_emit 3 +to return columns used +.It Dv XOF_FLUSH +Flush output after each +.Xr xo_emit 3 +call .El .Pp -If the style is XO_STYLE_HTML, the following additional flags can be +If the style is +.Dv XO_STYLE_HTML , +the following additional flags can be used: .Bl -tag -width "XOF_UNDERSCORES" .It Sy "Flag Description" -.It XOF_XPATH +.It Dv XOF_XPATH Emit "data-xpath" attributes -.It XOF_INFO +.It Dv XOF_INFO Emit additional informational fields for HTML -output. See +output. +See .Xr xo_set_info 3 for details. .El .Pp The -.Em XOF_XPATH +.Dv XOF_XPATH flag enables the emission of XPath expressions detailing the hierarchy of XML elements used to encode the data field, if the XPATH style of output were requested. .Pp -If the style is XO_STYLE_XML, the following additional flags can be +If the style is +.Dv XO_STYLE_XML , +the following additional flags can be used: .Bl -tag -width "XOF_UNDERSCORES" .It Sy "Flag Description" .It XOF_KEYS Add 'key' attribute to the XML encoding for -field definitions that use the 'k' modifier. The key attribute has +field definitions that use the 'k' modifier. +The key attribute has the value "key". .El .Pp -The xo_clear_flags() function turns off the given flags in a specific +The +.Fn xo_clear_flags +function turns off the given flags in a specific handle. .Sh ADDITIONAL DOCUMENTATION -.Pp Complete documentation can be found on github: .Bd -literal -offset indent http://juniper.github.io/libxo/libxo-manual.html .Ed .Pp -libxo lives on github as: +.Nm libxo +lives on github as: .Bd -literal -offset indent https://github.com/Juniper/libxo .Ed .Pp -The latest release of libxo is available at: +The latest release of +.Nm libxo +is available at: .Bd -literal -offset indent https://github.com/Juniper/libxo/releases .Ed @@ -122,7 +147,8 @@ https://github.com/Juniper/libxo/releases .Xr xo_emit 3 .Sh HISTORY The -.Fa libxo -library was added in FreeBSD 11.0. +.Nm libxo +library was added in +.Fx 11.0 . .Sh AUTHOR Phil Shafer diff --git a/contrib/libxo/libxo/xo_set_info.3 b/contrib/libxo/libxo/xo_set_info.3 index dbb3c9c88c93..4f8c5877c72a 100644 --- a/contrib/libxo/libxo/xo_set_info.3 +++ b/contrib/libxo/libxo/xo_set_info.3 @@ -7,7 +7,7 @@ .\" # LICENSE. .\" # Phil Shafer, July 2014 .\" -.Dd July, 2014 +.Dd December 4, 2014 .Dt LIBXO 3 .Os .Sh NAME @@ -21,19 +21,23 @@ .Fn xo_set_info "xo_handle_t *handle" "xo_info_t *info" "int count" .Sh DESCRIPTION HTML data can include additional information in attributes that -begin with "data-". To enable this, three things must occur: +begin with "data-". +To enable this, three things must occur: .Pp -First the application must build an array of xo_info_t structures, -one per tag. The array must be sorted by name, since -.Em libxo +First the application must build an array of +.Dv xo_info_t +structures, +one per tag. +The array must be sorted by name, since +.Nm libxo uses a binary search to find the entry that matches names from format instructions. .Pp The -.Em xo_info_t +.Dv xo_info_t structure is defined in -.Em : +.In libxo/xo.h : .Bd -literal -offset indent typedef struct xo_info_s { const char *xi_name; /* Name of the element */ @@ -43,21 +47,27 @@ structure is defined in .Ed .Pp Second, the application must inform -.Em libxo +.Nm libxo about this information using the .Fn xo_set_info -call. Like other libxo calls, passing NULL for the handle tells -.Em libxo +call. +Like other +.Nm libxo +calls, passing +.Dv NULL +for the handle tells +.Nm libxo to use the default handle. .Pp If the .Fa count is -1, -.Em libxo +.Nm libxo will count the elements of .Fa info , but there -must be an empty element at the end. More typically, the number is +must be an empty element at the end. +More typically, the number is known to the application: .Bd -literal -offset indent xo_info_t info[] = { @@ -72,8 +82,8 @@ known to the application: xo_set_info(NULL, info, info_count); .Ed .Pp -Third, the emitting of info must be triggered with the -.Em XOF_INFO +Third, the emission of info must be triggered with the +.Dv XOF_INFO flag using either the .Fn xo_set_flags @@ -88,18 +98,20 @@ and "data-help" attributes: data-help="Stock Keeping Unit">GRO-000-533
.Ed .Sh ADDITIONAL DOCUMENTATION -.Pp Complete documentation can be found on github: .Bd -literal -offset indent http://juniper.github.io/libxo/libxo-manual.html .Ed .Pp -libxo lives on github as: +.Nm libxo +lives on github as: .Bd -literal -offset indent https://github.com/Juniper/libxo .Ed .Pp -The latest release of libxo is available at: +The latest release of +.Nm libxo +is available at: .Bd -literal -offset indent https://github.com/Juniper/libxo/releases .Ed @@ -107,7 +119,8 @@ https://github.com/Juniper/libxo/releases .Xr xo_emit 3 .Sh HISTORY The -.Fa libxo -library was added in FreeBSD 11.0. +.Nm libxo +library was added in +.Fx 11.0 . .Sh AUTHOR Phil Shafer diff --git a/contrib/libxo/libxo/xo_set_options.3 b/contrib/libxo/libxo/xo_set_options.3 index af7e95cdcce1..bedbf912da15 100644 --- a/contrib/libxo/libxo/xo_set_options.3 +++ b/contrib/libxo/libxo/xo_set_options.3 @@ -7,12 +7,12 @@ .\" # LICENSE. .\" # Phil Shafer, July 2014 .\" -.Dd July, 2014 +.Dd December 4, 2014 .Dt LIBXO 3 .Os .Sh NAME -.Nm xo_emit -.Nd emit formatted output based on format string and arguments +.Nm xo_set_options +.Nd change options used by a handle .Sh LIBRARY .Lb libxo .Sh SYNOPSIS @@ -27,18 +27,20 @@ and flags and enables them for a specific handle. The options are identical to those listed in .Xr xo_parse_args 3 . .Sh ADDITIONAL DOCUMENTATION -.Pp Complete documentation can be found on github: .Bd -literal -offset indent http://juniper.github.io/libxo/libxo-manual.html .Ed .Pp -libxo lives on github as: +.Nm libxo +lives on github as: .Bd -literal -offset indent https://github.com/Juniper/libxo .Ed .Pp -The latest release of libxo is available at: +The latest release of +.Nm libxo +is available at: .Bd -literal -offset indent https://github.com/Juniper/libxo/releases .Ed @@ -46,7 +48,8 @@ https://github.com/Juniper/libxo/releases .Xr xo_emit 3 .Sh HISTORY The -.Fa libxo -library was added in FreeBSD 11.0. +.Nm libxo +library was added in +.Fx 11.0 . .Sh AUTHOR Phil Shafer diff --git a/contrib/libxo/libxo/xo_set_style.3 b/contrib/libxo/libxo/xo_set_style.3 index 83371ac71b15..f11f190bf13f 100644 --- a/contrib/libxo/libxo/xo_set_style.3 +++ b/contrib/libxo/libxo/xo_set_style.3 @@ -7,7 +7,7 @@ .\" # LICENSE. .\" # Phil Shafer, July 2014 .\" -.Dd July, 2014 +.Dd December 4, 2014 .Dt LIBXO 3 .Os .Sh NAME @@ -25,9 +25,11 @@ Use the .Fn xo_set_style function to set the output style for a handle. -To use the default handle, pass a NULL handle. +To use the default handle, pass a +.Dv NULL +handle. The set of output styles used by -.Em libxo +.Nm libxo is: .Bl -column "XO_STYLE_TEXT12" .It Sy "Flag Description" @@ -47,18 +49,20 @@ The name can be any of the styles: "text", "xml", "json", or "html". xo_set_style_name(NULL, "html"); .Ed .Sh ADDITIONAL DOCUMENTATION -.Pp Complete documentation can be found on github: .Bd -literal -offset indent http://juniper.github.io/libxo/libxo-manual.html .Ed .Pp -libxo lives on github as: +.Nm libxo +lives on github as: .Bd -literal -offset indent https://github.com/Juniper/libxo .Ed .Pp -The latest release of libxo is available at: +The latest release of +.Nm libxo +is available at: .Bd -literal -offset indent https://github.com/Juniper/libxo/releases .Ed @@ -66,7 +70,8 @@ https://github.com/Juniper/libxo/releases .Xr xo_emit 3 .Sh HISTORY The -.Fa libxo -library was added in FreeBSD 11.0. +.Nm libxo +library was added in +.Fx 11.0 . .Sh AUTHOR Phil Shafer diff --git a/contrib/libxo/libxo/xo_set_writer.3 b/contrib/libxo/libxo/xo_set_writer.3 index 9185f10dd601..942bcc2866b6 100644 --- a/contrib/libxo/libxo/xo_set_writer.3 +++ b/contrib/libxo/libxo/xo_set_writer.3 @@ -7,7 +7,7 @@ .\" # LICENSE. .\" # Phil Shafer, July 2014 .\" -.Dd July, 2014 +.Dd December 4, 2014 .Dt LIBXO 3 .Os .Sh NAME @@ -21,9 +21,12 @@ .Sy typedef int (*xo_write_func_t)(void *, const char *); .Pp .Sy typedef void (*xo_close_func_t)(void *); +.Pp +.Sy typedef int (*xo_flush_func_t)(void *); .Fn xo_set_writer "xo_handle_t *handle" "void *opaque" "xo_write_func_t write_func" "xo_close_func_t close_func" + "xo_flush_func_t flush_func" .Sh DESCRIPTION The .Fn xo_set_writer @@ -31,30 +34,38 @@ function allows custom .Dq write functions which can tailor how -.Em libxo -writes data. An +.Nm libxo +writes data. +An .Fa opaque argument is recorded and passed back to the .Fa write_func function, allowing the function -to acquire context information. The +to acquire context information. +The .Fa close_func function can release this opaque data and any other resources as needed. +The +.Fa flush_func +function should +flush any pending data associated with the opaque pointer. .Sh ADDITIONAL DOCUMENTATION -.Pp Complete documentation can be found on github: .Bd -literal -offset indent http://juniper.github.io/libxo/libxo-manual.html .Ed .Pp -libxo lives on github as: +.Nm libxo +lives on github as: .Bd -literal -offset indent https://github.com/Juniper/libxo .Ed .Pp -The latest release of libxo is available at: +The latest release of +.Nm libxo +is available at: .Bd -literal -offset indent https://github.com/Juniper/libxo/releases .Ed @@ -62,7 +73,8 @@ https://github.com/Juniper/libxo/releases .Xr xo_emit 3 .Sh HISTORY The -.Fa libxo -library was added in FreeBSD 11.0. +.Nm libxo +library was added in +.Fx 11.0 . .Sh AUTHOR Phil Shafer diff --git a/contrib/libxo/libxo/xoconfig.h b/contrib/libxo/libxo/xoconfig.h index 0870e3587209..4c596b4adf6e 100644 --- a/contrib/libxo/libxo/xoconfig.h +++ b/contrib/libxo/libxo/xoconfig.h @@ -87,6 +87,9 @@ /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 +/* Define to 1 if you have the header file. */ +/* #undef HAVE_STDIO_EXT_H */ + /* Define to 1 if you have the header file. */ #define HAVE_STDIO_H 1 @@ -141,6 +144,9 @@ /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 +/* Define to 1 if you have the `__flbf' function. */ +/* #undef HAVE___FLBF */ + /* Enable debugging */ /* #undef LIBXO_DEBUG */ @@ -158,7 +164,7 @@ #define PACKAGE_NAME "libxo" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "libxo 0.1.6" +#define PACKAGE_STRING "libxo 0.2.0" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "libxo" @@ -167,7 +173,7 @@ #define PACKAGE_URL "" /* Define to the version of this package. */ -#define PACKAGE_VERSION "0.1.6" +#define PACKAGE_VERSION "0.2.0" /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be @@ -181,7 +187,7 @@ #define STDC_HEADERS 1 /* Version number of package */ -#define VERSION "0.1.6" +#define VERSION "0.2.0" /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ diff --git a/contrib/libxo/libxo/xoconfig.h.in b/contrib/libxo/libxo/xoconfig.h.in index 3fe736571d07..467f5644d6b7 100644 --- a/contrib/libxo/libxo/xoconfig.h.in +++ b/contrib/libxo/libxo/xoconfig.h.in @@ -86,6 +86,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H +/* Define to 1 if you have the header file. */ +#undef HAVE_STDIO_EXT_H + /* Define to 1 if you have the header file. */ #undef HAVE_STDIO_H @@ -140,6 +143,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H +/* Define to 1 if you have the `__flbf' function. */ +#undef HAVE___FLBF + /* Enable debugging */ #undef LIBXO_DEBUG diff --git a/contrib/libxo/libxo/xoversion.h b/contrib/libxo/libxo/xoversion.h index 60c6118be935..4c29e82963eb 100644 --- a/contrib/libxo/libxo/xoversion.h +++ b/contrib/libxo/libxo/xoversion.h @@ -18,17 +18,17 @@ /** * The version string */ -#define LIBXO_VERSION "0.1.6" +#define LIBXO_VERSION "0.2.0" /** * The version number */ -#define LIBXO_VERSION_NUMBER 1006 +#define LIBXO_VERSION_NUMBER 2000 /** * The version number as a string */ -#define LIBXO_VERSION_STRING "1006" +#define LIBXO_VERSION_STRING "2000" /** * The version number extra info as a string diff --git a/contrib/libxo/packaging/libxo.rb.base.in b/contrib/libxo/packaging/libxo.rb.base.in new file mode 100644 index 000000000000..70b712da2acb --- /dev/null +++ b/contrib/libxo/packaging/libxo.rb.base.in @@ -0,0 +1,20 @@ +# +# Homebrew formula file for libxo +# https://github.com/mxcl/homebrew +# + +require 'formula' + +class Libxo < Formula + homepage 'https://github.com/Juniper/@PACKAGE-NAME@' + url 'https://github.com/Juniper/@PACKAGE_NAME@/releases/@PACKAGE_VERSION@/@PACKAGE_NAME@-@PACKAGE_VERSION@.tar.gz' + sha1 '__SHA1__' + + depends_on 'libtool' => :build + + def install + system "./configure", "--disable-dependency-tracking", + "--prefix=#{prefix}" + system "make install" + end +end diff --git a/contrib/libxo/tests/core/Makefile.am b/contrib/libxo/tests/core/Makefile.am index a5470f375478..f145d183d81c 100644 --- a/contrib/libxo/tests/core/Makefile.am +++ b/contrib/libxo/tests/core/Makefile.am @@ -18,7 +18,9 @@ test_03.c \ test_04.c \ test_05.c \ test_06.c \ -test_07.c +test_07.c \ +test_08.c \ +test_09.c test_01_test_SOURCES = test_01.c test_02_test_SOURCES = test_02.c @@ -27,6 +29,8 @@ test_04_test_SOURCES = test_04.c test_05_test_SOURCES = test_05.c test_06_test_SOURCES = test_06.c test_07_test_SOURCES = test_07.c +test_08_test_SOURCES = test_08.c +test_09_test_SOURCES = test_09.c # TEST_CASES := $(shell cd ${srcdir} ; echo *.c ) diff --git a/contrib/libxo/tests/core/saved/test_01.H.out b/contrib/libxo/tests/core/saved/test_01.H.out index e61eecc0aa28..4d4f2f171b60 100644 --- a/contrib/libxo/tests/core/saved/test_01.H.out +++ b/contrib/libxo/tests/core/saved/test_01.H.out @@ -1 +1 @@ -
Item
Total Sold
In Stock
On Order
SKU
gum
1412
54
10
GRO-000-415
rope
85
4
2
HRD-000-212
ladder
0
2
1
HRD-000-517
bolt
4123
144
42
HRD-000-632
water
17
14
2
GRO-000-2331
Item
'
gum
':
Total sold
:
1412.0
In stock
:
54
On order
:
10
SKU
:
GRO-000-415
Item
'
rope
':
Total sold
:
85.0
In stock
:
4
On order
:
2
SKU
:
HRD-000-212
Item
'
ladder
':
Total sold
:
0
In stock
:
2
On order
:
1
SKU
:
HRD-000-517
Item
'
bolt
':
Total sold
:
4123.0
In stock
:
144
On order
:
42
SKU
:
HRD-000-632
Item
'
water
':
Total sold
:
17.0
In stock
:
14
On order
:
2
SKU
:
GRO-000-2331
Item
'
fish
':
Total sold
:
1321.0
In stock
:
45
On order
:
1
SKU
:
GRO-000-533
\ No newline at end of file +
Item
Total Sold
In Stock
On Order
SKU
gum
1412
54
10
GRO-000-415
rope
85
4
2
HRD-000-212
ladder
0
2
1
HRD-000-517
bolt
4123
144
42
HRD-000-632
water
17
14
2
GRO-000-2331
Item
'
gum
':
Total sold
:
1412.0
In stock
:
54
On order
:
10
SKU
:
GRO-000-415
Item
'
rope
':
Total sold
:
85.0
In stock
:
4
On order
:
2
SKU
:
HRD-000-212
Item
'
ladder
':
Total sold
:
0
In stock
:
2
On order
:
1
SKU
:
HRD-000-517
Item
'
bolt
':
Total sold
:
4123.0
In stock
:
144
On order
:
42
SKU
:
HRD-000-632
Item
'
water
':
Total sold
:
17.0
In stock
:
14
On order
:
2
SKU
:
GRO-000-2331
Item
'
fish
':
Total sold
:
1321.0
In stock
:
45
On order
:
1
SKU
:
GRO-000-533
Item
:
gum
Item
:
rope
Item
:
ladder
Item
:
bolt
Item
:
water
X
X
X
X
X
X
X
X
X
X
Cost
:
425
X
X
Cost
:
455
\ No newline at end of file diff --git a/contrib/libxo/tests/core/saved/test_01.HIPx.out b/contrib/libxo/tests/core/saved/test_01.HIPx.out index c38eb04d3d29..2bafff91c45c 100644 --- a/contrib/libxo/tests/core/saved/test_01.HIPx.out +++ b/contrib/libxo/tests/core/saved/test_01.HIPx.out @@ -236,3 +236,61 @@
:
GRO-000-533
+
+
Item
+
:
+
+
gum
+
+
+
Item
+
:
+
+
rope
+
+
+
Item
+
:
+
+
ladder
+
+
+
Item
+
:
+
+
bolt
+
+
+
Item
+
:
+
+
water
+
+
+
X
+
X
+
X
+
X
+
X
+
X
+
X
+
X
+
+
+
X
+
+
X
+
Cost
+
:
+
+
425
+
+
+
X
+
+
X
+
Cost
+
:
+
+
455
+
diff --git a/contrib/libxo/tests/core/saved/test_01.HP.out b/contrib/libxo/tests/core/saved/test_01.HP.out index a8874769d887..a007778c39ae 100644 --- a/contrib/libxo/tests/core/saved/test_01.HP.out +++ b/contrib/libxo/tests/core/saved/test_01.HP.out @@ -236,3 +236,61 @@
:
GRO-000-533
+
+
Item
+
:
+
+
gum
+
+
+
Item
+
:
+
+
rope
+
+
+
Item
+
:
+
+
ladder
+
+
+
Item
+
:
+
+
bolt
+
+
+
Item
+
:
+
+
water
+
+
+
X
+
X
+
X
+
X
+
X
+
X
+
X
+
X
+
+
+
X
+
+
X
+
Cost
+
:
+
+
425
+
+
+
X
+
+
X
+
Cost
+
:
+
+
455
+
diff --git a/contrib/libxo/tests/core/saved/test_01.J.out b/contrib/libxo/tests/core/saved/test_01.J.out index 289a95210532..6fcdbd416307 100644 --- a/contrib/libxo/tests/core/saved/test_01.J.out +++ b/contrib/libxo/tests/core/saved/test_01.J.out @@ -1,2 +1,2 @@ -{"top": {"data": {"item": [{"sku":"GRO-000-415","name":"gum","sold":1412,"in-stock":54,"on-order":10}, {"sku":"HRD-000-212","name":"rope","sold":85,"in-stock":4,"on-order":2}, {"sku":"HRD-000-517","name":"ladder","sold":0,"in-stock":2,"on-order":1}, {"sku":"HRD-000-632","name":"bolt","sold":4123,"in-stock":144,"on-order":42}, {"sku":"GRO-000-2331","name":"water","sold":17,"in-stock":14,"on-order":2}]}, "data": {"item": [{"sku":"GRO-000-415","name":"gum","sold":1412.0,"in-stock":54,"on-order":10}, {"sku":"HRD-000-212","name":"rope","sold":85.0,"in-stock":4,"on-order":2}, {"sku":"HRD-000-517","name":"ladder","sold":0,"in-stock":2,"on-order":1}, {"sku":"HRD-000-632","name":"bolt","sold":4123.0,"in-stock":144,"on-order":42}, {"sku":"GRO-000-2331","name":"water","sold":17.0,"in-stock":14,"on-order":2}]}, "data": {"item": [{"sku":"GRO-000-533","name":"fish","sold":1321.0,"in-stock":45,"on-order":1}]}} +{"top": {"data": {"item": [{"sku":"GRO-000-415","name":"gum","sold":1412,"in-stock":54,"on-order":10}, {"sku":"HRD-000-212","name":"rope","sold":85,"in-stock":4,"on-order":2}, {"sku":"HRD-000-517","name":"ladder","sold":0,"in-stock":2,"on-order":1}, {"sku":"HRD-000-632","name":"bolt","sold":4123,"in-stock":144,"on-order":42}, {"sku":"GRO-000-2331","name":"water","sold":17,"in-stock":14,"on-order":2}]}, "data": {"item": [{"sku":"GRO-000-415","name":"gum","sold":1412.0,"in-stock":54,"on-order":10}, {"sku":"HRD-000-212","name":"rope","sold":85.0,"in-stock":4,"on-order":2}, {"sku":"HRD-000-517","name":"ladder","sold":0,"in-stock":2,"on-order":1}, {"sku":"HRD-000-632","name":"bolt","sold":4123.0,"in-stock":144,"on-order":42}, {"sku":"GRO-000-2331","name":"water","sold":17.0,"in-stock":14,"on-order":2}]}, "data": {"item": [{"sku":"GRO-000-533","name":"fish","sold":1321.0,"in-stock":45,"on-order":1}]}, "data": {"item": ["gum","rope","ladder","bolt","water"]},"cost":425,"cost":455} } diff --git a/contrib/libxo/tests/core/saved/test_01.JP.out b/contrib/libxo/tests/core/saved/test_01.JP.out index 56758457f365..e1fd2318d670 100644 --- a/contrib/libxo/tests/core/saved/test_01.JP.out +++ b/contrib/libxo/tests/core/saved/test_01.JP.out @@ -88,6 +88,13 @@ "on-order": 1 } ] - } + }, + "data": { + "item": [ + "gum", "rope", "ladder", "bolt", "water" + ] + }, + "cost": 425, + "cost": 455 } } diff --git a/contrib/libxo/tests/core/saved/test_01.T.out b/contrib/libxo/tests/core/saved/test_01.T.out index c2ad7a005274..c45b13001a18 100644 --- a/contrib/libxo/tests/core/saved/test_01.T.out +++ b/contrib/libxo/tests/core/saved/test_01.T.out @@ -36,3 +36,11 @@ Item 'fish': In stock: 45 On order: 1 SKU: GRO-000-533 +Item: gum +Item: rope +Item: ladder +Item: bolt +Item: water +XXXXXXXX +X XCost: 425 +X XCost: 455 diff --git a/contrib/libxo/tests/core/saved/test_01.X.out b/contrib/libxo/tests/core/saved/test_01.X.out index c3e07c85ee69..ce2719268aad 100644 --- a/contrib/libxo/tests/core/saved/test_01.X.out +++ b/contrib/libxo/tests/core/saved/test_01.X.out @@ -1 +1 @@ -GRO-000-415gum14125410HRD-000-212rope8542HRD-000-517ladder021HRD-000-632bolt412314442GRO-000-2331water17142GRO-000-415gum1412.05410HRD-000-212rope85.042HRD-000-517ladder021HRD-000-632bolt4123.014442GRO-000-2331water17.0142GRO-000-533fish1321.0451 \ No newline at end of file +GRO-000-415gum14125410HRD-000-212rope8542HRD-000-517ladder021HRD-000-632bolt412314442GRO-000-2331water17142GRO-000-415gum1412.05410HRD-000-212rope85.042HRD-000-517ladder021HRD-000-632bolt4123.014442GRO-000-2331water17.0142GRO-000-533fish1321.0451gumropeladderboltwater425455 \ No newline at end of file diff --git a/contrib/libxo/tests/core/saved/test_01.XP.out b/contrib/libxo/tests/core/saved/test_01.XP.out index 49fc6dab91fb..e5ea3e088976 100644 --- a/contrib/libxo/tests/core/saved/test_01.XP.out +++ b/contrib/libxo/tests/core/saved/test_01.XP.out @@ -1,35 +1,35 @@ - - - GRO-000-415 + + + GRO-000-415 gum 1412 54 10 - HRD-000-212 + HRD-000-212 rope 85 4 2 - HRD-000-517 + HRD-000-517 ladder 0 2 1 - HRD-000-632 + HRD-000-632 bolt 4123 144 42 - GRO-000-2331 + GRO-000-2331 water 17 14 @@ -82,4 +82,13 @@ 1 + + gum + rope + ladder + bolt + water + + 425 + 455 diff --git a/contrib/libxo/tests/core/saved/test_02.J.out b/contrib/libxo/tests/core/saved/test_02.J.out index 621e06190900..5b4502a1d158 100644 --- a/contrib/libxo/tests/core/saved/test_02.J.out +++ b/contrib/libxo/tests/core/saved/test_02.J.out @@ -1,2 +1,2 @@ -{"top": {"data": {"mbuf-current":10,"mbuf-cache":20,"mbuf-total":30,"distance":50,"location":"Boston","memory":64,"total":640,"memory":64,"total":640,"ten":10,"eleven":11,"unknown":1010,"min":15,"cur":20,"max":30,"min":15,"cur":20,"max":125,"min":15,"cur":20,"max":125,"min":15,"cur":20,"max":125, "flag": ["one","two","three"],"empty-tag":true,"t1":"1000","t2":"test5000","t3":"ten-longx","t4":"xtest","count":10,"test":4}} +{"top": {"data": {"mbuf-current":10,"mbuf-cache":20,"mbuf-total":30,"distance":50,"location":"Boston","memory":64,"total":640,"memory":64,"total":640,"ten":10,"eleven":11,"unknown":1010,"min":15,"cur":20,"max":30,"min":15,"cur":20,"max":125,"min":15,"cur":20,"max":125,"min":15,"cur":20,"max":125, "flag": ["one","two","three"],"empty-tag":true,"t1":"1000","t2":"test5000","t3":"ten-longx","t4":"xtest","count":10,"test":4, "error": {"message":"Shut 'er down, Clancey! She's a-pumpin' mud! <>!,\"!<>\n"}}} } diff --git a/contrib/libxo/tests/core/saved/test_02.JP.out b/contrib/libxo/tests/core/saved/test_02.JP.out index 9479817b91af..21b168bdad77 100644 --- a/contrib/libxo/tests/core/saved/test_02.JP.out +++ b/contrib/libxo/tests/core/saved/test_02.JP.out @@ -34,7 +34,10 @@ "t3": "ten-longx", "t4": "xtest", "count": 10, - "test": 4 + "test": 4, + "error": { + "message": "Shut 'er down, Clancey! She's a-pumpin' mud! <>!,\"!<>\n" + } } } } diff --git a/contrib/libxo/tests/core/saved/test_07.J.out b/contrib/libxo/tests/core/saved/test_07.J.out index 9285ff5a6c5e..8e9efaec8000 100644 --- a/contrib/libxo/tests/core/saved/test_07.J.out +++ b/contrib/libxo/tests/core/saved/test_07.J.out @@ -1,2 +1,2 @@ -{"employees": {"test": [{"filename":"(null)"}],"v1":"γιγνώσκειν","v2":"ὦ ἄνδρες ᾿Αθηναῖοι","columns":28,"columns":2,"v1":"ახლავე გაიაროთ რეგისტრაცია","v2":"Unicode-ის მეათე საერთაშორისო","columns":55, "employee": ["columns":0, {"first-name":"Jim","nic-name":"\"რეგტ\"","last-name":"გთხოვთ ახ","department":431,"percent-time":90,"columns":23,"benefits":"full"}, {"first-name":"Terry","nic-name":"\"
Item
Count
gum
1412
rope
85
ladder
0
bolt
4123
water
17
Item
Count
gum
1412
rope
85
ladder
0
bolt
4123
water
17
Item
Count
gum
1412
rope
85
ladder
0
bolt
4123
water
17
one
Item
Count
gum
1412
Name
:
0
+ 1 =
1
Name
:
1
+ 1 =
2
Name
:
2
+ 1 =
3
Last
:
3
rope
85
Name
:
0
+ 1 =
1
Name
:
1
+ 1 =
2
Name
:
2
+ 1 =
3
Last
:
3
ladder
0
Name
:
0
+ 1 =
1
Name
:
1
+ 1 =
2
Name
:
2
+ 1 =
3
Last
:
3
bolt
4123
Name
:
0
+ 1 =
1
Name
:
1
+ 1 =
2
Name
:
2
+ 1 =
3
Last
:
3
water
17
Name
:
0
+ 1 =
1
Name
:
1
+ 1 =
2
Name
:
2
+ 1 =
3
Last
:
3
one
\ No newline at end of file diff --git a/contrib/libxo/tests/core/saved/test_08.HIPx.err b/contrib/libxo/tests/core/saved/test_08.HIPx.err new file mode 100644 index 000000000000..445bfb7172f2 --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_08.HIPx.err @@ -0,0 +1,18 @@ +test: close (xo_close_container) fails at marker 'm1'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm1'; not found 'data' +test: close (xo_close_container) fails at marker 'm1'; not found 'top' diff --git a/contrib/libxo/tests/core/saved/test_08.HIPx.out b/contrib/libxo/tests/core/saved/test_08.HIPx.out new file mode 100644 index 000000000000..87bfbed33d11 --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_08.HIPx.out @@ -0,0 +1,264 @@ +
+
Item
+
Count
+
+
+
gum
+
1412
+
+
+
rope
+
85
+
+
+
ladder
+
0
+
+
+
bolt
+
4123
+
+
+
water
+
17
+
+
+
+
+
+
+
Item
+
Count
+
+
+
gum
+
1412
+
+
+
rope
+
85
+
+
+
ladder
+
0
+
+
+
bolt
+
4123
+
+
+
water
+
17
+
+
+
+
+
+
+
Item
+
Count
+
+
+
gum
+
1412
+
+
+
rope
+
85
+
+
+
ladder
+
0
+
+
+
bolt
+
4123
+
+
+
water
+
17
+
+
+
one
+
+
+
+
+
Item
+
Count
+
+
+
gum
+
1412
+
+
+
Name
+
:
+
+
0
+
+ 1 =
+
1
+
+
+
Name
+
:
+
+
1
+
+ 1 =
+
2
+
+
+
Name
+
:
+
+
2
+
+ 1 =
+
3
+
+
+
Last
+
:
+
+
3
+
+
+
rope
+
85
+
+
+
Name
+
:
+
+
0
+
+ 1 =
+
1
+
+
+
Name
+
:
+
+
1
+
+ 1 =
+
2
+
+
+
Name
+
:
+
+
2
+
+ 1 =
+
3
+
+
+
Last
+
:
+
+
3
+
+
+
ladder
+
0
+
+
+
Name
+
:
+
+
0
+
+ 1 =
+
1
+
+
+
Name
+
:
+
+
1
+
+ 1 =
+
2
+
+
+
Name
+
:
+
+
2
+
+ 1 =
+
3
+
+
+
Last
+
:
+
+
3
+
+
+
bolt
+
4123
+
+
+
Name
+
:
+
+
0
+
+ 1 =
+
1
+
+
+
Name
+
:
+
+
1
+
+ 1 =
+
2
+
+
+
Name
+
:
+
+
2
+
+ 1 =
+
3
+
+
+
Last
+
:
+
+
3
+
+
+
water
+
17
+
+
+
Name
+
:
+
+
0
+
+ 1 =
+
1
+
+
+
Name
+
:
+
+
1
+
+ 1 =
+
2
+
+
+
Name
+
:
+
+
2
+
+ 1 =
+
3
+
+
+
Last
+
:
+
+
3
+
+
+
one
+
+
+
diff --git a/contrib/libxo/tests/core/saved/test_08.HP.err b/contrib/libxo/tests/core/saved/test_08.HP.err new file mode 100644 index 000000000000..445bfb7172f2 --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_08.HP.err @@ -0,0 +1,18 @@ +test: close (xo_close_container) fails at marker 'm1'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm1'; not found 'data' +test: close (xo_close_container) fails at marker 'm1'; not found 'top' diff --git a/contrib/libxo/tests/core/saved/test_08.HP.out b/contrib/libxo/tests/core/saved/test_08.HP.out new file mode 100644 index 000000000000..3524f5e9fac1 --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_08.HP.out @@ -0,0 +1,264 @@ +
+
Item
+
Count
+
+
+
gum
+
1412
+
+
+
rope
+
85
+
+
+
ladder
+
0
+
+
+
bolt
+
4123
+
+
+
water
+
17
+
+
+
+
+
+
+
Item
+
Count
+
+
+
gum
+
1412
+
+
+
rope
+
85
+
+
+
ladder
+
0
+
+
+
bolt
+
4123
+
+
+
water
+
17
+
+
+
+
+
+
+
Item
+
Count
+
+
+
gum
+
1412
+
+
+
rope
+
85
+
+
+
ladder
+
0
+
+
+
bolt
+
4123
+
+
+
water
+
17
+
+
+
one
+
+
+
+
+
Item
+
Count
+
+
+
gum
+
1412
+
+
+
Name
+
:
+
+
0
+
+ 1 =
+
1
+
+
+
Name
+
:
+
+
1
+
+ 1 =
+
2
+
+
+
Name
+
:
+
+
2
+
+ 1 =
+
3
+
+
+
Last
+
:
+
+
3
+
+
+
rope
+
85
+
+
+
Name
+
:
+
+
0
+
+ 1 =
+
1
+
+
+
Name
+
:
+
+
1
+
+ 1 =
+
2
+
+
+
Name
+
:
+
+
2
+
+ 1 =
+
3
+
+
+
Last
+
:
+
+
3
+
+
+
ladder
+
0
+
+
+
Name
+
:
+
+
0
+
+ 1 =
+
1
+
+
+
Name
+
:
+
+
1
+
+ 1 =
+
2
+
+
+
Name
+
:
+
+
2
+
+ 1 =
+
3
+
+
+
Last
+
:
+
+
3
+
+
+
bolt
+
4123
+
+
+
Name
+
:
+
+
0
+
+ 1 =
+
1
+
+
+
Name
+
:
+
+
1
+
+ 1 =
+
2
+
+
+
Name
+
:
+
+
2
+
+ 1 =
+
3
+
+
+
Last
+
:
+
+
3
+
+
+
water
+
17
+
+
+
Name
+
:
+
+
0
+
+ 1 =
+
1
+
+
+
Name
+
:
+
+
1
+
+ 1 =
+
2
+
+
+
Name
+
:
+
+
2
+
+ 1 =
+
3
+
+
+
Last
+
:
+
+
3
+
+
+
one
+
+
+
diff --git a/contrib/libxo/tests/core/saved/test_08.J.err b/contrib/libxo/tests/core/saved/test_08.J.err new file mode 100644 index 000000000000..445bfb7172f2 --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_08.J.err @@ -0,0 +1,18 @@ +test: close (xo_close_container) fails at marker 'm1'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm1'; not found 'data' +test: close (xo_close_container) fails at marker 'm1'; not found 'top' diff --git a/contrib/libxo/tests/core/saved/test_08.J.out b/contrib/libxo/tests/core/saved/test_08.J.out new file mode 100644 index 000000000000..cbce0910b6c2 --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_08.J.out @@ -0,0 +1,2 @@ +{"top": {"data": {"contents": {"item": [{"name":"gum","count":1412}, {"name":"rope","count":85}, {"name":"ladder","count":0}, {"name":"bolt","count":4123}, {"name":"water","count":17}]}}, "data": {"contents": {"item": [{"name":"gum","count":1412}, {"name":"rope","count":85}, {"name":"ladder","count":0}, {"name":"bolt","count":4123}, {"name":"water","count":17}]}}, "data": {"contents": {"item": [{"name":"gum","count":1412}, {"name":"rope","count":85}, {"name":"ladder","count":0}, {"name":"bolt","count":4123}, {"name":"water","count":17,"test":"one"}]}}, "data": {"contents": {"item": [{"name":"gum","count":1412, "sub": [{"name":0,"next":1}, {"name":1,"next":2}, {"name":2,"next":3}],"last":3}, {"name":"rope","count":85, "sub": [{"name":0,"next":1}, {"name":1,"next":2}, {"name":2,"next":3}],"last":3}, {"name":"ladder","count":0, "sub": [{"name":0,"next":1}, {"name":1,"next":2}, {"name":2,"next":3}],"last":3}, {"name":"bolt","count":4123, "sub": [{"name":0,"next":1}, {"name":1,"next":2}, {"name":2,"next":3}],"last":3}, {"name":"water","count":17, "sub": [{"name":0,"next":1}, {"name":1,"next":2}, {"name":2,"next":3}],"last":3,"test":"one"}]}}} +} diff --git a/contrib/libxo/tests/core/saved/test_08.JP.err b/contrib/libxo/tests/core/saved/test_08.JP.err new file mode 100644 index 000000000000..445bfb7172f2 --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_08.JP.err @@ -0,0 +1,18 @@ +test: close (xo_close_container) fails at marker 'm1'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm1'; not found 'data' +test: close (xo_close_container) fails at marker 'm1'; not found 'top' diff --git a/contrib/libxo/tests/core/saved/test_08.JP.out b/contrib/libxo/tests/core/saved/test_08.JP.out new file mode 100644 index 000000000000..932d6a12d94b --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_08.JP.out @@ -0,0 +1,185 @@ +{ + "top": { + "data": { + "contents": { + "item": [ + { + "name": "gum", + "count": 1412 + }, + { + "name": "rope", + "count": 85 + }, + { + "name": "ladder", + "count": 0 + }, + { + "name": "bolt", + "count": 4123 + }, + { + "name": "water", + "count": 17 + } + ] + } + }, + "data": { + "contents": { + "item": [ + { + "name": "gum", + "count": 1412 + }, + { + "name": "rope", + "count": 85 + }, + { + "name": "ladder", + "count": 0 + }, + { + "name": "bolt", + "count": 4123 + }, + { + "name": "water", + "count": 17 + } + ] + } + }, + "data": { + "contents": { + "item": [ + { + "name": "gum", + "count": 1412 + }, + { + "name": "rope", + "count": 85 + }, + { + "name": "ladder", + "count": 0 + }, + { + "name": "bolt", + "count": 4123 + }, + { + "name": "water", + "count": 17, + "test": "one" + } + ] + } + }, + "data": { + "contents": { + "item": [ + { + "name": "gum", + "count": 1412, + "sub": [ + { + "name": 0, + "next": 1 + }, + { + "name": 1, + "next": 2 + }, + { + "name": 2, + "next": 3 + } + ], + "last": 3 + }, + { + "name": "rope", + "count": 85, + "sub": [ + { + "name": 0, + "next": 1 + }, + { + "name": 1, + "next": 2 + }, + { + "name": 2, + "next": 3 + } + ], + "last": 3 + }, + { + "name": "ladder", + "count": 0, + "sub": [ + { + "name": 0, + "next": 1 + }, + { + "name": 1, + "next": 2 + }, + { + "name": 2, + "next": 3 + } + ], + "last": 3 + }, + { + "name": "bolt", + "count": 4123, + "sub": [ + { + "name": 0, + "next": 1 + }, + { + "name": 1, + "next": 2 + }, + { + "name": 2, + "next": 3 + } + ], + "last": 3 + }, + { + "name": "water", + "count": 17, + "sub": [ + { + "name": 0, + "next": 1 + }, + { + "name": 1, + "next": 2 + }, + { + "name": 2, + "next": 3 + } + ], + "last": 3, + "test": "one" + } + ] + } + } + } +} diff --git a/contrib/libxo/tests/core/saved/test_08.T.err b/contrib/libxo/tests/core/saved/test_08.T.err new file mode 100644 index 000000000000..445bfb7172f2 --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_08.T.err @@ -0,0 +1,18 @@ +test: close (xo_close_container) fails at marker 'm1'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm1'; not found 'data' +test: close (xo_close_container) fails at marker 'm1'; not found 'top' diff --git a/contrib/libxo/tests/core/saved/test_08.T.out b/contrib/libxo/tests/core/saved/test_08.T.out new file mode 100644 index 000000000000..8923b93642a8 --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_08.T.out @@ -0,0 +1,52 @@ +Item Count +gum 1412 +rope 85 +ladder 0 +bolt 4123 +water 17 + + +Item Count +gum 1412 +rope 85 +ladder 0 +bolt 4123 +water 17 + + +Item Count +gum 1412 +rope 85 +ladder 0 +bolt 4123 +water 17 +one + +Item Count +gum 1412 +Name: 0 + 1 = 1 +Name: 1 + 1 = 2 +Name: 2 + 1 = 3 +Last: 3 +rope 85 +Name: 0 + 1 = 1 +Name: 1 + 1 = 2 +Name: 2 + 1 = 3 +Last: 3 +ladder 0 +Name: 0 + 1 = 1 +Name: 1 + 1 = 2 +Name: 2 + 1 = 3 +Last: 3 +bolt 4123 +Name: 0 + 1 = 1 +Name: 1 + 1 = 2 +Name: 2 + 1 = 3 +Last: 3 +water 17 +Name: 0 + 1 = 1 +Name: 1 + 1 = 2 +Name: 2 + 1 = 3 +Last: 3 +one + diff --git a/contrib/libxo/tests/core/saved/test_08.X.err b/contrib/libxo/tests/core/saved/test_08.X.err new file mode 100644 index 000000000000..445bfb7172f2 --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_08.X.err @@ -0,0 +1,18 @@ +test: close (xo_close_container) fails at marker 'm1'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm1'; not found 'data' +test: close (xo_close_container) fails at marker 'm1'; not found 'top' diff --git a/contrib/libxo/tests/core/saved/test_08.X.out b/contrib/libxo/tests/core/saved/test_08.X.out new file mode 100644 index 000000000000..5eb72b209ad1 --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_08.X.out @@ -0,0 +1 @@ +gum1412rope85ladder0bolt4123water17gum1412rope85ladder0bolt4123water17gum1412rope85ladder0bolt4123water17onegum14120112233rope850112233ladder00112233bolt41230112233water170112233one \ No newline at end of file diff --git a/contrib/libxo/tests/core/saved/test_08.XP.err b/contrib/libxo/tests/core/saved/test_08.XP.err new file mode 100644 index 000000000000..445bfb7172f2 --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_08.XP.err @@ -0,0 +1,18 @@ +test: close (xo_close_container) fails at marker 'm1'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm2'; not found 'data' +test: close (xo_close_container) fails at marker 'm1'; not found 'data' +test: close (xo_close_container) fails at marker 'm1'; not found 'top' diff --git a/contrib/libxo/tests/core/saved/test_08.XP.out b/contrib/libxo/tests/core/saved/test_08.XP.out new file mode 100644 index 000000000000..99520c074a9c --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_08.XP.out @@ -0,0 +1,165 @@ + + + + + gum + 1412 + + + rope + 85 + + + ladder + 0 + + + bolt + 4123 + + + water + 17 + + + + + + + gum + 1412 + + + rope + 85 + + + ladder + 0 + + + bolt + 4123 + + + water + 17 + + + + + + + gum + 1412 + + + rope + 85 + + + ladder + 0 + + + bolt + 4123 + + + water + 17 + one + + + + + + + gum + 1412 + + 0 + 1 + + + 1 + 2 + + + 2 + 3 + + 3 + + + rope + 85 + + 0 + 1 + + + 1 + 2 + + + 2 + 3 + + 3 + + + ladder + 0 + + 0 + 1 + + + 1 + 2 + + + 2 + 3 + + 3 + + + bolt + 4123 + + 0 + 1 + + + 1 + 2 + + + 2 + 3 + + 3 + + + water + 17 + + 0 + 1 + + + 1 + 2 + + + 2 + 3 + + 3 + one + + + + diff --git a/contrib/libxo/tests/core/saved/test_09.H.err b/contrib/libxo/tests/core/saved/test_09.H.err new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/libxo/tests/core/saved/test_09.H.out b/contrib/libxo/tests/core/saved/test_09.H.out new file mode 100644 index 000000000000..899cd2f40458 --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_09.H.out @@ -0,0 +1 @@ +
Item
Count
Name:
gum
Name:
rope
Name:
ladder
Name:
bolt
Name:
water
Item
Count
Name:
gum
Name:
rope
Name:
ladder
Name:
bolt
Name:
water
Test
Three
Name:
gum
Name:
rope
Name:
ladder
Name:
bolt
Name:
water
Total:
:
six
one
two
three
\ No newline at end of file diff --git a/contrib/libxo/tests/core/saved/test_09.HIPx.err b/contrib/libxo/tests/core/saved/test_09.HIPx.err new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/libxo/tests/core/saved/test_09.HIPx.out b/contrib/libxo/tests/core/saved/test_09.HIPx.out new file mode 100644 index 000000000000..a63f29264df9 --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_09.HIPx.out @@ -0,0 +1,93 @@ +
+
Item
+
Count
+
+
+
Name:
+
gum
+
+
+
Name:
+
rope
+
+
+
Name:
+
ladder
+
+
+
Name:
+
bolt
+
+
+
Name:
+
water
+
+
+
+
+
+
+
Item
+
Count
+
+
+
Name:
+
gum
+
+
+
Name:
+
rope
+
+
+
Name:
+
ladder
+
+
+
Name:
+
bolt
+
+
+
Name:
+
water
+
+
+
+
+
+
+
Test
+
Three
+
+
+
Name:
+
gum
+
+
+
Name:
+
rope
+
+
+
Name:
+
ladder
+
+
+
Name:
+
bolt
+
+
+
Name:
+
water
+
+
+
Total:
+
:
+
+
six
+
+
+
one
+
two
+
three
+
+
+
diff --git a/contrib/libxo/tests/core/saved/test_09.HP.err b/contrib/libxo/tests/core/saved/test_09.HP.err new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/libxo/tests/core/saved/test_09.HP.out b/contrib/libxo/tests/core/saved/test_09.HP.out new file mode 100644 index 000000000000..8a8f700338e6 --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_09.HP.out @@ -0,0 +1,93 @@ +
+
Item
+
Count
+
+
+
Name:
+
gum
+
+
+
Name:
+
rope
+
+
+
Name:
+
ladder
+
+
+
Name:
+
bolt
+
+
+
Name:
+
water
+
+
+
+
+
+
+
Item
+
Count
+
+
+
Name:
+
gum
+
+
+
Name:
+
rope
+
+
+
Name:
+
ladder
+
+
+
Name:
+
bolt
+
+
+
Name:
+
water
+
+
+
+
+
+
+
Test
+
Three
+
+
+
Name:
+
gum
+
+
+
Name:
+
rope
+
+
+
Name:
+
ladder
+
+
+
Name:
+
bolt
+
+
+
Name:
+
water
+
+
+
Total:
+
:
+
+
six
+
+
+
one
+
two
+
three
+
+
+
diff --git a/contrib/libxo/tests/core/saved/test_09.J.err b/contrib/libxo/tests/core/saved/test_09.J.err new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/libxo/tests/core/saved/test_09.J.out b/contrib/libxo/tests/core/saved/test_09.J.out new file mode 100644 index 000000000000..e43ad3150c30 --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_09.J.out @@ -0,0 +1,2 @@ +{"top": {"data": {"contents": {"name": ["gum","rope","ladder","bolt","water"]}, "contents": {"item": ["gum","rope","ladder","bolt","water"]}, "contents": {"item": ["gum","rope","ladder","bolt","water"],"total":"six","one":"one", "two": ["two"],"three":"three"}}} +} diff --git a/contrib/libxo/tests/core/saved/test_09.JP.err b/contrib/libxo/tests/core/saved/test_09.JP.err new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/libxo/tests/core/saved/test_09.JP.out b/contrib/libxo/tests/core/saved/test_09.JP.out new file mode 100644 index 000000000000..8340b275606b --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_09.JP.out @@ -0,0 +1,27 @@ +{ + "top": { + "data": { + "contents": { + "name": [ + "gum", "rope", "ladder", "bolt", "water" + ] + }, + "contents": { + "item": [ + "gum", "rope", "ladder", "bolt", "water" + ] + }, + "contents": { + "item": [ + "gum", "rope", "ladder", "bolt", "water" + ], + "total": "six", + "one": "one", + "two": [ + "two" + ], + "three": "three" + } + } + } +} diff --git a/contrib/libxo/tests/core/saved/test_09.T.err b/contrib/libxo/tests/core/saved/test_09.T.err new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/libxo/tests/core/saved/test_09.T.out b/contrib/libxo/tests/core/saved/test_09.T.out new file mode 100644 index 000000000000..5bb163ed8668 --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_09.T.out @@ -0,0 +1,25 @@ +Item Count +Name: gum +Name: rope +Name: ladder +Name: bolt +Name: water + + +Item Count +Name: gum +Name: rope +Name: ladder +Name: bolt +Name: water + + +Test Three +Name: gum +Name: rope +Name: ladder +Name: bolt +Name: water +Total:: six +onetwothree + diff --git a/contrib/libxo/tests/core/saved/test_09.X.err b/contrib/libxo/tests/core/saved/test_09.X.err new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/libxo/tests/core/saved/test_09.X.out b/contrib/libxo/tests/core/saved/test_09.X.out new file mode 100644 index 000000000000..21ce1ce6956d --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_09.X.out @@ -0,0 +1 @@ +gumropeladderboltwatergumropeladderboltwatergumropeladderboltwatersixonetwothree \ No newline at end of file diff --git a/contrib/libxo/tests/core/saved/test_09.XP.err b/contrib/libxo/tests/core/saved/test_09.XP.err new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/libxo/tests/core/saved/test_09.XP.out b/contrib/libxo/tests/core/saved/test_09.XP.out new file mode 100644 index 000000000000..9476126e372c --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_09.XP.out @@ -0,0 +1,29 @@ + + + + gum + rope + ladder + bolt + water + + + gum + rope + ladder + bolt + water + + + gum + rope + ladder + bolt + water + six + one + two + three + + + diff --git a/contrib/libxo/tests/core/test_01.c b/contrib/libxo/tests/core/test_01.c index 164a38b9943e..9a9ed2c07fe9 100644 --- a/contrib/libxo/tests/core/test_01.c +++ b/contrib/libxo/tests/core/test_01.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include "xo.h" @@ -69,6 +71,10 @@ main (int argc, char **argv) xo_set_flags(NULL, XOF_XPATH); else if (strcmp(argv[argc], "info") == 0) xo_set_flags(NULL, XOF_INFO); + else if (strcmp(argv[argc], "error") == 0) { + close(-1); + xo_err(1, "error detected"); + } } xo_set_info(NULL, info, info_count); @@ -76,14 +82,17 @@ main (int argc, char **argv) xo_open_container_h(NULL, "top"); + xo_attr("test", "value"); xo_open_container("data"); xo_open_list("item"); + xo_attr("test2", "value2"); xo_emit("{T:Item/%-10s}{T:Total Sold/%12s}{T:In Stock/%12s}" "{T:On Order/%12s}{T:SKU/%5s}\n"); for (ip = list; ip->i_title; ip++) { xo_open_instance("item"); + xo_attr("test3", "value3"); xo_emit("{keq:sku/%s-%u/%s-000-%u}" "{k:name/%-10s/%s}{n:sold/%12u/%u}{:in-stock/%12u/%u}" @@ -142,6 +151,25 @@ main (int argc, char **argv) xo_close_list("item"); xo_close_container("data"); + xo_open_container("data"); + xo_open_list("item"); + + for (ip = list; ip->i_title; ip++) { + xo_attr("test4", "value4"); + xo_emit("{Lwc:Item}{l:item}\n", ip->i_title); + } + + xo_close_list("item"); + xo_close_container("data"); + + xo_emit("X{P:}X", "epic fail"); + xo_emit("X{T:}X", "epic fail"); + xo_emit("X{N:}X", "epic fail"); + xo_emit("X{L:}X\n", "epic fail"); + + xo_emit("X{P: }X{Lwc:Cost}{:cost/%u}\n", 425); + xo_emit("X{P:/%30s}X{Lwc:Cost}{:cost/%u}\n", "", 455); + xo_close_container_h(NULL, "top"); xo_finish(); diff --git a/contrib/libxo/tests/core/test_07.c b/contrib/libxo/tests/core/test_07.c index 18b7baa146b3..5b1ed57292a2 100644 --- a/contrib/libxo/tests/core/test_07.c +++ b/contrib/libxo/tests/core/test_07.c @@ -68,11 +68,12 @@ main (int argc, char **argv) "Unicode-ის მეათე საერთაშორისო"); xo_emit("{:columns/%d}\n", rc); - xo_open_list("employee"); rc = xo_emit("{T:First Name/%-25s}{T:Last Name/%-14s}" "{T:/%-12s}{T:Time (%)}\n", "Department"); xo_emit("{:columns/%d}\n", rc); + + xo_open_list("employee"); for ( ; ep->e_first; ep++) { xo_open_instance("employee"); rc = xo_emit("{[:-25}{:first-name/%s} ({:nic-name/\"%s\"}){]:}" diff --git a/contrib/libxo/tests/core/test_08.c b/contrib/libxo/tests/core/test_08.c new file mode 100644 index 000000000000..eb3776dcfbbb --- /dev/null +++ b/contrib/libxo/tests/core/test_08.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2015, Juniper Networks, Inc. + * All rights reserved. + * This SOFTWARE is licensed under the LICENSE provided in the + * ../Copyright file. By downloading, installing, copying, or otherwise + * using the SOFTWARE, you agree to be bound by the terms of that + * LICENSE. + * Phil Shafer, July 2015 + */ + +#include +#include +#include +#include +#include + +#include "xo.h" + +int +main (int argc, char **argv) +{ + struct item { + const char *i_title; + int i_count; + }; + struct item list[] = { + { "gum", 1412 }, + { "rope", 85 }, + { "ladder", 0 }, + { "bolt", 4123 }, + { "water", 17 }, + { NULL, 0 } + }; + struct item *ip; + int i; + + argc = xo_parse_args(argc, argv); + if (argc < 0) + return 1; + + for (argc = 1; argv[argc]; argc++) { + if (strcmp(argv[argc], "xml") == 0) + xo_set_style(NULL, XO_STYLE_XML); + else if (strcmp(argv[argc], "json") == 0) + xo_set_style(NULL, XO_STYLE_JSON); + else if (strcmp(argv[argc], "text") == 0) + xo_set_style(NULL, XO_STYLE_TEXT); + else if (strcmp(argv[argc], "html") == 0) + xo_set_style(NULL, XO_STYLE_HTML); + else if (strcmp(argv[argc], "pretty") == 0) + xo_set_flags(NULL, XOF_PRETTY); + else if (strcmp(argv[argc], "xpath") == 0) + xo_set_flags(NULL, XOF_XPATH); + else if (strcmp(argv[argc], "info") == 0) + xo_set_flags(NULL, XOF_INFO); + else if (strcmp(argv[argc], "error") == 0) { + close(-1); + xo_err(1, "error detected"); + } + } + + xo_set_flags(NULL, XOF_KEYS); + xo_set_program("test"); + + xo_open_container_h(NULL, "top"); + + xo_open_container("data"); + xo_open_container("contents"); + xo_open_list("item"); + + xo_emit("{T:Item/%-10s}{T:Count/%12s}\n"); + + for (ip = list; ip->i_title; ip++) { + xo_open_instance("item"); + + xo_emit("{k:name/%-10s/%s}{n:count/%12u/%u}\n", + ip->i_title, ip->i_count); + + xo_close_instance("item"); + } + + xo_close_list("item"); + xo_close_container("contents"); + xo_close_container("data"); + + xo_emit("\n\n"); + + xo_open_container("data"); + xo_open_container("contents"); + + xo_emit("{T:Item/%-10s}{T:Count/%12s}\n"); + + for (ip = list; ip->i_title; ip++) { + xo_open_instance("item"); + + xo_emit("{k:name/%-10s/%s}{n:count/%12u/%u}\n", + ip->i_title, ip->i_count); + } + + xo_close_container("data"); + + xo_emit("\n\n"); + + xo_open_container("data"); + xo_open_marker("m1"); + xo_open_container("contents"); + + xo_emit("{T:Item/%-10s}{T:Count/%12s}\n"); + + for (ip = list; ip->i_title; ip++) { + xo_open_instance("item"); + + xo_emit("{k:name/%-10s/%s}{n:count/%12u/%u}\n", + ip->i_title, ip->i_count); + } + + xo_close_container("data"); /* Should be a noop */ + xo_emit("{:test}", "one"); + + xo_close_marker("m1"); + xo_close_container("data"); /* Should be a noop */ + + xo_emit("\n\n"); + + xo_open_container("data"); + xo_open_marker("m1"); + xo_open_container("contents"); + + xo_emit("{T:Item/%-10s}{T:Count/%12s}\n"); + + for (ip = list; ip->i_title; ip++) { + xo_open_instance("item"); + + xo_emit("{k:name/%-10s/%s}{n:count/%12u/%u}\n", + ip->i_title, ip->i_count); + + xo_open_marker("m2"); + for (i = 0; i < 3; i++) { + xo_open_instance("sub"); + xo_emit("{Lwc:/Name}{:name/%d} + 1 = {:next/%d}\n", i, i + 1); + xo_close_container("data"); + } + xo_close_marker("m2"); + xo_emit("{Lwc:/Last}{:last/%d}\n", i); + } + + xo_close_container("data"); /* Should be a noop */ + xo_emit("{:test}", "one"); + + xo_emit("\n\n"); + + xo_close_container_h(NULL, "top"); + + xo_finish(); + + return 0; +} diff --git a/contrib/libxo/tests/core/test_09.c b/contrib/libxo/tests/core/test_09.c new file mode 100644 index 000000000000..a612a647d7f8 --- /dev/null +++ b/contrib/libxo/tests/core/test_09.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2015, Juniper Networks, Inc. + * All rights reserved. + * This SOFTWARE is licensed under the LICENSE provided in the + * ../Copyright file. By downloading, installing, copying, or otherwise + * using the SOFTWARE, you agree to be bound by the terms of that + * LICENSE. + * Phil Shafer, July 2015 + */ + +#include +#include +#include +#include +#include + +#include "xo.h" + +int +main (int argc, char **argv) +{ + struct item { + const char *i_title; + int i_count; + }; + struct item list[] = { + { "gum", 1412 }, + { "rope", 85 }, + { "ladder", 0 }, + { "bolt", 4123 }, + { "water", 17 }, + { NULL, 0 } + }; + struct item *ip; + int i; + + argc = xo_parse_args(argc, argv); + if (argc < 0) + return 1; + + for (argc = 1; argv[argc]; argc++) { + if (strcmp(argv[argc], "xml") == 0) + xo_set_style(NULL, XO_STYLE_XML); + else if (strcmp(argv[argc], "json") == 0) + xo_set_style(NULL, XO_STYLE_JSON); + else if (strcmp(argv[argc], "text") == 0) + xo_set_style(NULL, XO_STYLE_TEXT); + else if (strcmp(argv[argc], "html") == 0) + xo_set_style(NULL, XO_STYLE_HTML); + else if (strcmp(argv[argc], "pretty") == 0) + xo_set_flags(NULL, XOF_PRETTY); + else if (strcmp(argv[argc], "xpath") == 0) + xo_set_flags(NULL, XOF_XPATH); + else if (strcmp(argv[argc], "info") == 0) + xo_set_flags(NULL, XOF_INFO); + else if (strcmp(argv[argc], "error") == 0) { + close(-1); + xo_err(1, "error detected"); + } + } + + xo_set_flags(NULL, XOF_KEYS); + xo_set_program("test"); + + xo_open_container_h(NULL, "top"); + + xo_open_container("data"); + xo_open_container("contents"); + + xo_emit("{T:Item/%-10s}{T:Count/%12s}\n"); + + for (ip = list; ip->i_title; ip++) { + xo_emit("Name: {l:name/%-10s/%s}\n", ip->i_title); + } + + xo_close_container("contents"); + + xo_emit("\n\n"); + xo_open_container("contents"); + + xo_emit("{T:Item/%-10s}{T:Count/%12s}\n"); + + for (ip = list; ip->i_title; ip++) { + xo_emit("Name: {l:item/%-10s/%s}\n", ip->i_title); + } + + xo_close_container("contents"); + + xo_emit("\n\n"); + + xo_open_container("contents"); + xo_emit("{T:Test/%-10s}{T:Three/%12s}\n"); + + xo_open_list("item"); + for (ip = list; ip->i_title; ip++) { + xo_emit("Name: {l:item/%-10s/%s}\n", ip->i_title); + } + xo_emit("{Lwc:/Total:}{:total}\n", "six"); + + xo_emit("{:one}", "one"); + xo_emit("{l:two}", "two"); + xo_emit("{:three}", "three"); + + + xo_close_container("contents"); + + xo_emit("\n\n"); + + xo_close_container_h(NULL, "top"); + + xo_finish(); + + return 0; +} diff --git a/contrib/libxo/xo/xo.1 b/contrib/libxo/xo/xo.1 index 1833b0a4559c..12fc959481cc 100644 --- a/contrib/libxo/xo/xo.1 +++ b/contrib/libxo/xo/xo.1 @@ -7,27 +7,29 @@ .\" # LICENSE. .\" # Phil Shafer, July 2014 .\" -.Dd July, 2014 -.Dt LIBXO 3 +.Dd December 4, 2014 +.Dt XO 1 .Os .Sh NAME .Nm xo .Nd emit formatted output based on format string and arguments .Sh SYNOPSIS -.Nm xo +.Nm .Op Fl options .Op Ar argument... .Sh DESCRIPTION The -.Nm xo +.Nm utility allows command line access to the functionality of the -.Em libxo -library. Using -.Nm xo , +.Nm libxo +library. +Using +.Nm , shell scripts can emit .Em XML , -.Em JSON , or +.Em JSON , +or .Em HTML using the same commands that emit text output. .Pp @@ -63,11 +65,11 @@ Wrap output in a set of containers .It Fl "-xml OR -X" Generate XML output .It Fl "-xpath" -Add XPath data to HTML output); +Add XPath data to HTML output .El .Pp The -.Nm xo +.Nm utility accepts a format string suitable for .Xr xo_emit 3 and a set of zero or more arguments used to supply data for that string. @@ -95,7 +97,8 @@ and a set of zero or more arguments used to supply data for that string. The .Fl "-wrap " option can be used to wrap emitted content in a -specific hierarchy. The path is a set of hierarchical names separated +specific hierarchy. +The path is a set of hierarchical names separated by the '/' character. .Bd -literal -offset indent xo --wrap top/a/b/c '{:tag}' value @@ -128,11 +131,14 @@ and .Fl "\-close " can be used to emit hierarchical information without the matching close and open -tag. This allows a shell script to emit open tags, data, and -then close tags. The +tag. +This allows a shell script to emit open tags, data, and +then close tags. +The .Fl \-depth option may be used to set the -depth for indentation. The +depth for indentation. +The .Fl "\-leading-xpath" may be used to prepend data to the XPath values used for HTML output style. @@ -154,37 +160,39 @@ prepend data to the XPath values used for HTML output style. } } .Ed -.Pp .Sh EXAMPLE -.Bd -literal -offset indent +.Bd -literal % xo 'The {:product} is {:status}\n' stereo "in route" The stereo is in route % xo -p -X 'The {:product} is {:status}\n' stereo "in route" stereo in route .Ed -.Pp .Sh ADDITIONAL DOCUMENTATION -.Pp Complete documentation can be found on github: .Bd -literal -offset indent http://juniper.github.io/libxo/libxo-manual.html .Ed .Pp -libxo lives on github as: +.Nm libxo +lives on github as: .Bd -literal -offset indent https://github.com/Juniper/libxo .Ed .Pp -The latest release of libxo is available at: +The latest release of +.Nm libxo +is available at: .Bd -literal -offset indent https://github.com/Juniper/libxo/releases .Ed .Sh SEE ALSO +.Xr libxo 3 , .Xr xo_emit 3 .Sh HISTORY The -.Fa libxo -library was added in FreeBSD 11.0. +.Nm libxo +library was added in +.Fx 11.0 . .Sh AUTHOR Phil Shafer diff --git a/contrib/libxo/xo/xo.c b/contrib/libxo/xo/xo.c index 698d9d653090..c364539091af 100644 --- a/contrib/libxo/xo/xo.c +++ b/contrib/libxo/xo/xo.c @@ -362,8 +362,7 @@ main (int argc UNUSED, char **argv) } xo_set_formatter(NULL, formatter, checkpoint); - xo_set_flags(NULL, XOF_NO_VA_ARG); - xo_set_flags(NULL, XOF_NO_TOP); + xo_set_flags(NULL, XOF_NO_VA_ARG | XOF_NO_TOP | XOF_NO_CLOSE); fmt = *argv++; if (opt_opener == NULL && opt_closer == NULL && fmt == NULL) { diff --git a/contrib/libxo/xolint/Makefile.am b/contrib/libxo/xolint/Makefile.am index 0f8ef62613a4..a847e72c784c 100644 --- a/contrib/libxo/xolint/Makefile.am +++ b/contrib/libxo/xolint/Makefile.am @@ -11,4 +11,4 @@ man_MANS = xolint.1 EXTRA_DIST = xolint.1 xolint.pl install-exec-hook: - install ${srcdir}/xolint.pl ${bindir}/xolint + install ${srcdir}/xolint.pl ${DESTDIR}${bindir}/xolint diff --git a/contrib/libxo/xolint/xolint.1 b/contrib/libxo/xolint/xolint.1 index b7ed130a4fe9..fcf7bcdeec73 100644 --- a/contrib/libxo/xolint/xolint.1 +++ b/contrib/libxo/xolint/xolint.1 @@ -7,12 +7,13 @@ .\" # LICENSE. .\" # Phil Shafer, July 2014 .\" -.Dd July, 2014 -.Dt LIBXO 3 +.Dd December 4, 2014 +.Dt XOLINT 1 .Os .Sh NAME .Nm xolint -.Nd detect errors in programs using xo_emit +.Nd detect errors in programs using +.Xr xo_emit 3 .Sh SYNOPSIS .Nm xolint .Op Fl c @@ -25,34 +26,45 @@ .Op Fl "X" .Op Ar files... .Sh DESCRIPTION -xolint is a tool for reporting common mistakes in format strings -in source code that invokes xo_emit(). It allows these errors +.Nm +is a tool for reporting common mistakes in format strings +in source code that invokes +.Xr xo_emit 3 . +It allows these errors to be diagnosed at build time, rather than waiting until runtime. .Pp -xolint takes the one or more C files as arguments, and reports -and errors, warning, or informational messages as needed. +.Nm +takes one or more C files as arguments, and reports +error, warning, or informational messages as needed. .Bl -tag -width "C " .It Fl c Invoke 'cpp' against the input file .It Fl "C " -Flags that are passed to 'cpp +Flags that are passed to 'cpp' .It Fl "d" Enable debug output .It Fl "D" -Generate documentation for all xolint messages +Generate documentation for all +.Nm +messages .It Fl "I" -Generate a table of xo_info_t structures. +Generate a table of +.Dv xo_info_t +structures. .It Fl "p" Print the offending lines after the error message is displayed .It Fl "V" Do not report errors, but instead print a complete list of -all field names, sorted alphabetically. The output can help spot +all field names, sorted alphabetically. +The output can help spot inconsistencies and spelling errors. .It Fl "X" -Extract samples from xolint, suitable for internal testing. +Extract samples from +.Nm , +suitable for internal testing. .El .Pp -Output message contain the source filename and line number, the +The output message contains the source filename and line number, the class of the message, the message, and, if .Fl p is given, the @@ -62,28 +74,31 @@ line that contains the error: xolint.c: 16: error: anchor format should be "%d" 16 xo_emit("{[:/%s}"); .Ed -.Pp .Sh ADDITIONAL DOCUMENTATION -.Pp Complete documentation can be found on github: .Bd -literal -offset indent http://juniper.github.io/libxo/libxo-manual.html .Ed .Pp -libxo lives on github as: +.Nm libxo +lives on github as: .Bd -literal -offset indent https://github.com/Juniper/libxo .Ed .Pp -The latest release of libxo is available at: +The latest release of +.Nm libxo +is available at: .Bd -literal -offset indent https://github.com/Juniper/libxo/releases .Ed .Sh SEE ALSO +.Xr libxo 3 , .Xr xo_emit 3 .Sh HISTORY The -.Fa libxo -library was added in FreeBSD 10.1. +.Nm libxo +library was added in +.Fx 10.1 . .Sh AUTHOR Phil Shafer diff --git a/lib/libxo/Makefile b/lib/libxo/Makefile index 770db20c125f..cc0e72aa4a91 100644 --- a/lib/libxo/Makefile +++ b/lib/libxo/Makefile @@ -21,6 +21,7 @@ MAN+= xo_attr.3 \ xo_create.3 \ xo_emit.3 \ xo_err.3 \ + xo_error.3 \ xo_finish.3 \ xo_flush.3 \ xo_no_setlocale.3 \ From 8fa2e2513fe9dbec0abce5ce0e7d267f47ef5d18 Mon Sep 17 00:00:00 2001 From: pfg Date: Mon, 19 Jan 2015 03:30:45 +0000 Subject: [PATCH 064/258] ext2: Garbage-collect some unused variables Reported by: clang static analysis MFC after: 2 weeks --- sys/fs/ext2fs/ext2_bmap.c | 2 -- sys/fs/ext2fs/ext2_extents.c | 2 -- sys/fs/ext2fs/ext2_htree.c | 4 ++-- sys/fs/ext2fs/ext2_inode.c | 2 -- sys/fs/ext2fs/ext2_lookup.c | 1 - sys/fs/ext2fs/ext2_vfsops.c | 2 -- sys/fs/ext2fs/ext2_vnops.c | 3 --- 7 files changed, 2 insertions(+), 14 deletions(-) diff --git a/sys/fs/ext2fs/ext2_bmap.c b/sys/fs/ext2fs/ext2_bmap.c index 12f9560d93b0..d144e926f0ba 100644 --- a/sys/fs/ext2fs/ext2_bmap.c +++ b/sys/fs/ext2fs/ext2_bmap.c @@ -145,7 +145,6 @@ ext2_bmaparray(struct vnode *vp, daddr_t bn, daddr_t *bnp, int *runp, int *runb) struct buf *bp; struct ext2mount *ump; struct mount *mp; - struct vnode *devvp; struct indir a[NIADDR+1], *ap; daddr_t daddr; e2fs_lbn_t metalbn; @@ -156,7 +155,6 @@ ext2_bmaparray(struct vnode *vp, daddr_t bn, daddr_t *bnp, int *runp, int *runb) ip = VTOI(vp); mp = vp->v_mount; ump = VFSTOEXT2(mp); - devvp = ump->um_devvp; bsize = EXT2_BLOCK_SIZE(ump->um_e2fs); diff --git a/sys/fs/ext2fs/ext2_extents.c b/sys/fs/ext2fs/ext2_extents.c index 26e6a222cc94..68704bb88504 100644 --- a/sys/fs/ext2fs/ext2_extents.c +++ b/sys/fs/ext2fs/ext2_extents.c @@ -131,13 +131,11 @@ struct ext4_extent_path * ext4_ext_find_extent(struct m_ext2fs *fs, struct inode *ip, daddr_t lbn, struct ext4_extent_path *path) { - struct vnode *vp; struct ext4_extent_header *ehp; uint16_t i; int error, size; daddr_t nblk; - vp = ITOV(ip); ehp = (struct ext4_extent_header *)(char *)ip->i_db; if (ehp->eh_magic != EXT4_EXT_MAGIC) diff --git a/sys/fs/ext2fs/ext2_htree.c b/sys/fs/ext2fs/ext2_htree.c index 33e4c0f7d42d..70a2f4786e9c 100644 --- a/sys/fs/ext2fs/ext2_htree.c +++ b/sys/fs/ext2fs/ext2_htree.c @@ -395,7 +395,7 @@ ext2_htree_append_block(struct vnode *vp, char *data, int error; cursize = roundup(dp->i_size, blksize); - newsize = roundup(dp->i_size, blksize) + blksize; + newsize = cursize + blksize; auio.uio_offset = cursize; auio.uio_resid = blksize; @@ -771,7 +771,7 @@ ext2_htree_add_entry(struct vnode *dvp, struct ext2fs_direct_2 *entry, dst_node->h_fake_dirent.e2d_reclen = blksize; cursize = roundup(ip->i_size, blksize); - dirsize = roundup(ip->i_size, blksize) + blksize; + dirsize = cursize + blksize; blknum = dirsize / blksize - 1; error = ext2_htree_append_block(dvp, newidxblock, diff --git a/sys/fs/ext2fs/ext2_inode.c b/sys/fs/ext2fs/ext2_inode.c index 43b0fc9d144b..2fc2192d05bd 100644 --- a/sys/fs/ext2fs/ext2_inode.c +++ b/sys/fs/ext2fs/ext2_inode.c @@ -115,7 +115,6 @@ ext2_truncate(struct vnode *vp, off_t length, int flags, struct ucred *cred, struct inode *oip; int32_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR]; uint32_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR]; - struct bufobj *bo; struct m_ext2fs *fs; struct buf *bp; int offset, size, level; @@ -124,7 +123,6 @@ ext2_truncate(struct vnode *vp, off_t length, int flags, struct ucred *cred, off_t osize; oip = VTOI(ovp); - bo = &ovp->v_bufobj; ASSERT_VOP_LOCKED(vp, "ext2_truncate"); diff --git a/sys/fs/ext2fs/ext2_lookup.c b/sys/fs/ext2fs/ext2_lookup.c index e59b60614c4a..f9845bd3e65a 100644 --- a/sys/fs/ext2fs/ext2_lookup.c +++ b/sys/fs/ext2fs/ext2_lookup.c @@ -343,7 +343,6 @@ ext2_lookup_ino(struct vnode *vdp, struct vnode **vpp, struct componentname *cnp * we watch for a place to put the new file in * case it doesn't already exist. */ - ino = 0; i_diroff = dp->i_diroff; ss.slotstatus = FOUND; ss.slotfreespace = ss.slotsize = ss.slotneeded = 0; diff --git a/sys/fs/ext2fs/ext2_vfsops.c b/sys/fs/ext2fs/ext2_vfsops.c index b97356d072ac..6879e42ac95d 100644 --- a/sys/fs/ext2fs/ext2_vfsops.c +++ b/sys/fs/ext2fs/ext2_vfsops.c @@ -902,7 +902,6 @@ ext2_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) struct ext2mount *ump; struct buf *bp; struct vnode *vp; - struct cdev *dev; struct thread *td; int i, error; int used_blocks; @@ -913,7 +912,6 @@ ext2_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) return (error); ump = VFSTOEXT2(mp); - dev = ump->um_dev; ip = malloc(sizeof(struct inode), M_EXT2NODE, M_WAITOK | M_ZERO); /* Allocate a new vnode/inode. */ diff --git a/sys/fs/ext2fs/ext2_vnops.c b/sys/fs/ext2fs/ext2_vnops.c index 5baca5aacbad..dd30aea279c4 100644 --- a/sys/fs/ext2fs/ext2_vnops.c +++ b/sys/fs/ext2fs/ext2_vnops.c @@ -1223,7 +1223,6 @@ ext2_rmdir(struct vop_rmdir_args *ap) * the current directory and thus be * non-empty.) */ - error = 0; if (ip->i_nlink != 2 || !ext2_dirempty(ip, dp->i_number, cnp->cn_cred)) { error = ENOTEMPTY; goto out; @@ -1329,12 +1328,10 @@ ext2_strategy(struct vop_strategy_args *ap) { struct buf *bp = ap->a_bp; struct vnode *vp = ap->a_vp; - struct inode *ip; struct bufobj *bo; daddr_t blkno; int error; - ip = VTOI(vp); if (vp->v_type == VBLK || vp->v_type == VCHR) panic("ext2_strategy: spec"); if (bp->b_blkno == bp->b_lblkno) { From af9bc7a40f2d38430430e3ed9591762b9efa6c2d Mon Sep 17 00:00:00 2001 From: ian Date: Mon, 19 Jan 2015 04:56:17 +0000 Subject: [PATCH 065/258] For armv6 builds, add -mfloat-abi=softfp. This tells the compiler it can use floating point hardware instructions (because all armv6/7 systems we support have fp hardware), but it passes args using a soft-float compatible ABI. This should give noticible performance improvement (but not as much as using the armv6hf arch). --- share/mk/bsd.cpu.mk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/share/mk/bsd.cpu.mk b/share/mk/bsd.cpu.mk index a3b9c1fd016d..da5f5f2d38e0 100644 --- a/share/mk/bsd.cpu.mk +++ b/share/mk/bsd.cpu.mk @@ -251,6 +251,10 @@ MACHINE_CPU = v9 ultrasparc ultrasparc3 CFLAGS += -G0 .endif +.if ${MACHINE_ARCH} == "armv6" +_CPUCFLAGS += -mfloat-abi=softfp +.endif + # NB: COPTFLAGS is handled in /usr/src/sys/conf/kern.pre.mk .if !defined(NO_CPU_CFLAGS) From 989d372488c4b535b35c80ce32ea34b54f2efb11 Mon Sep 17 00:00:00 2001 From: nwhitehorn Date: Mon, 19 Jan 2015 05:14:07 +0000 Subject: [PATCH 066/258] Provide a tunable (machdep.moea64_bpvo_pool_size) to set the bootstrap PVO pool size. The default errs on the exceedingly large side, so absent any intelligent automatic tuning, at least let the user set it to save RAM on memory-constrained systems. MFC after: 2 weeks --- sys/powerpc/aim/mmu_oea64.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/sys/powerpc/aim/mmu_oea64.c b/sys/powerpc/aim/mmu_oea64.c index 1eb4b83cdf72..84ba8bbc1f9f 100644 --- a/sys/powerpc/aim/mmu_oea64.c +++ b/sys/powerpc/aim/mmu_oea64.c @@ -221,9 +221,10 @@ struct pvo_head *moea64_pvo_table; /* pvo entries by pteg index */ uma_zone_t moea64_upvo_zone; /* zone for pvo entries for unmanaged pages */ uma_zone_t moea64_mpvo_zone; /* zone for pvo entries for managed pages */ -#define BPVO_POOL_SIZE 327680 static struct pvo_entry *moea64_bpvo_pool; static int moea64_bpvo_pool_index = 0; +static int moea64_bpvo_pool_size = 327680; +TUNABLE_INT("machdep.moea64_bpvo_pool_size", &moea64_bpvo_pool_size); SYSCTL_INT(_machdep, OID_AUTO, moea64_allocated_bpvo_entries, CTLFLAG_RD, &moea64_bpvo_pool_index, 0, ""); @@ -647,7 +648,7 @@ moea64_setup_direct_map(mmu_t mmup, vm_offset_t kernelstart, off = (vm_offset_t)(moea64_pvo_table); for (pa = off; pa < off + size; pa += PAGE_SIZE) moea64_kenter(mmup, pa, pa); - size = BPVO_POOL_SIZE*sizeof(struct pvo_entry); + size = moea64_bpvo_pool_size*sizeof(struct pvo_entry); off = (vm_offset_t)(moea64_bpvo_pool); for (pa = off; pa < off + size; pa += PAGE_SIZE) moea64_kenter(mmup, pa, pa); @@ -815,7 +816,7 @@ moea64_mid_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend) * Initialise the unmanaged pvo pool. */ moea64_bpvo_pool = (struct pvo_entry *)moea64_bootstrap_alloc( - BPVO_POOL_SIZE*sizeof(struct pvo_entry), 0); + moea64_bpvo_pool_size*sizeof(struct pvo_entry), 0); moea64_bpvo_pool_index = 0; /* @@ -2282,10 +2283,10 @@ moea64_pvo_enter(mmu_t mmu, pmap_t pm, uma_zone_t zone, * If we aren't overwriting a mapping, try to allocate. */ if (bootstrap) { - if (moea64_bpvo_pool_index >= BPVO_POOL_SIZE) { + if (moea64_bpvo_pool_index >= moea64_bpvo_pool_size) { panic("moea64_enter: bpvo pool exhausted, %d, %d, %zd", - moea64_bpvo_pool_index, BPVO_POOL_SIZE, - BPVO_POOL_SIZE * sizeof(struct pvo_entry)); + moea64_bpvo_pool_index, moea64_bpvo_pool_size, + moea64_bpvo_pool_size * sizeof(struct pvo_entry)); } pvo = &moea64_bpvo_pool[moea64_bpvo_pool_index]; moea64_bpvo_pool_index++; From 4b4c58b79e26365d5da4f6d520bbfad5a8f9a974 Mon Sep 17 00:00:00 2001 From: ngie Date: Mon, 19 Jan 2015 06:10:01 +0000 Subject: [PATCH 067/258] Expect :overflow to fail with FreeBSD's expr as it doesn't have stringent overflow checks like NetBSD's expr does MFC after: 3 days PR: 196867 --- contrib/netbsd-tests/bin/expr/t_expr.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contrib/netbsd-tests/bin/expr/t_expr.sh b/contrib/netbsd-tests/bin/expr/t_expr.sh index 97a559b1d978..ef99b021cd31 100755 --- a/contrib/netbsd-tests/bin/expr/t_expr.sh +++ b/contrib/netbsd-tests/bin/expr/t_expr.sh @@ -54,6 +54,9 @@ overflow_head() { atf_set "descr" "Test overflow cases" } overflow_body() { + # Begin FreeBSD + atf_expect_fail "FreeBSD's expr does not check overflow to the same degree NetBSD's expr does; see bug 196867 for more details" + # End FreeBSD test_expr '4611686018427387904 + 4611686018427387903' \ '9223372036854775807' test_expr '4611686018427387904 + 4611686018427387904' \ From 63c8385f8bbc4fb18ce8d54745e5c79829d532b5 Mon Sep 17 00:00:00 2001 From: ngie Date: Mon, 19 Jan 2015 06:13:07 +0000 Subject: [PATCH 068/258] Integrate contrib/netbsd-tests/bin/expr into the build/kyua as bin/expr/tests MFC after: 1 week Sponsored by: EMC / Isilon Storage Division --- bin/expr/Makefile | 6 ++++++ bin/expr/tests/Makefile | 16 ++++++++++++++++ etc/mtree/BSD.tests.dist | 2 ++ 3 files changed, 24 insertions(+) create mode 100644 bin/expr/tests/Makefile diff --git a/bin/expr/Makefile b/bin/expr/Makefile index b86cf6686ab0..a1f6cbf21091 100644 --- a/bin/expr/Makefile +++ b/bin/expr/Makefile @@ -1,9 +1,15 @@ # $FreeBSD$ +.include + PROG= expr SRCS= expr.y YFLAGS= NO_WMISSING_VARIABLE_DECLARATIONS= +.if ${MK_TESTS} != "no" +SUBDIR+= tests +.endif + .include diff --git a/bin/expr/tests/Makefile b/bin/expr/tests/Makefile new file mode 100644 index 000000000000..80c130c3df20 --- /dev/null +++ b/bin/expr/tests/Makefile @@ -0,0 +1,16 @@ +# $FreeBSD$ + +OBJTOP= ${.OBJDIR}/../../.. +SRCTOP= ${.CURDIR}/../../.. +TESTSRC= ${SRCTOP}/contrib/netbsd-tests/bin/expr + +TESTSDIR= ${TESTSBASE}/bin/expr + +NETBSD_ATF_TESTS_SH= expr_test + +ATF_TESTS_SH_SED_expr_test+= -e 's/eval expr/eval expr --/g' +ATF_TESTS_SH_SED_expr_test+= -e 's/"expr: integer overflow or underflow occurred for operation.*"/"expr: overflow"/g' + +.include + +.include diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist index cbd65dc8a6a3..c43f1aea48dc 100644 --- a/etc/mtree/BSD.tests.dist +++ b/etc/mtree/BSD.tests.dist @@ -12,6 +12,8 @@ .. date .. + expr + .. mv .. pax From 9d0b530c897c5323dd868e5afccf90a6b0c23b6e Mon Sep 17 00:00:00 2001 From: neel Date: Mon, 19 Jan 2015 06:51:04 +0000 Subject: [PATCH 069/258] Fix a bug in libvmmapi 'vm_copy_setup()' where it would return success even if the 'gpa' was in the guest MMIO region. This would manifest as a segmentation fault in 'vm_map_copyin()' or 'vm_map_copyout()' because 'vm_map_gpa()' would return NULL for this 'gpa'. Fix this by calling 'vm_map_gpa()' in 'vm_copy_setup' and returning a failure if the 'gpa' cannot be mapped. This matches the behavior of 'vm_copy_setup()' in vmm.ko. MFC after: 1 week --- lib/libvmmapi/vmmapi.c | 22 +++++++++++++++------- lib/libvmmapi/vmmapi.h | 2 ++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/lib/libvmmapi/vmmapi.c b/lib/libvmmapi/vmmapi.c index 5660f3b7bc50..982887688664 100644 --- a/lib/libvmmapi/vmmapi.c +++ b/lib/libvmmapi/vmmapi.c @@ -987,6 +987,7 @@ int vm_copy_setup(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, uint64_t gla, size_t len, int prot, struct iovec *iov, int iovcnt) { + void *va; uint64_t gpa; int error, fault, i, n, off; @@ -1006,7 +1007,11 @@ vm_copy_setup(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, off = gpa & PAGE_MASK; n = min(len, PAGE_SIZE - off); - iov->iov_base = (void *)gpa; + va = vm_map_gpa(ctx, gpa, n); + if (va == NULL) + return (-1); + + iov->iov_base = va; iov->iov_len = n; iov++; iovcnt--; @@ -1017,20 +1022,25 @@ vm_copy_setup(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, return (0); } +void +vm_copy_teardown(struct vmctx *ctx, int vcpu, struct iovec *iov, int iovcnt) +{ + + return; +} + void vm_copyin(struct vmctx *ctx, int vcpu, struct iovec *iov, void *vp, size_t len) { const char *src; char *dst; - uint64_t gpa; size_t n; dst = vp; while (len) { assert(iov->iov_len); - gpa = (uint64_t)iov->iov_base; n = min(len, iov->iov_len); - src = vm_map_gpa(ctx, gpa, n); + src = iov->iov_base; bcopy(src, dst, n); iov++; @@ -1045,15 +1055,13 @@ vm_copyout(struct vmctx *ctx, int vcpu, const void *vp, struct iovec *iov, { const char *src; char *dst; - uint64_t gpa; size_t n; src = vp; while (len) { assert(iov->iov_len); - gpa = (uint64_t)iov->iov_base; n = min(len, iov->iov_len); - dst = vm_map_gpa(ctx, gpa, n); + dst = iov->iov_base; bcopy(src, dst, n); iov++; diff --git a/lib/libvmmapi/vmmapi.h b/lib/libvmmapi/vmmapi.h index 8634762d0065..06b29302640d 100644 --- a/lib/libvmmapi/vmmapi.h +++ b/lib/libvmmapi/vmmapi.h @@ -137,6 +137,8 @@ void vm_copyin(struct vmctx *ctx, int vcpu, struct iovec *guest_iov, void *host_dst, size_t len); void vm_copyout(struct vmctx *ctx, int vcpu, const void *host_src, struct iovec *guest_iov, size_t len); +void vm_copy_teardown(struct vmctx *ctx, int vcpu, struct iovec *iov, + int iovcnt); /* RTC */ int vm_rtc_write(struct vmctx *ctx, int offset, uint8_t value); From e901ab485a464056672377acf53a18e0cc16e462 Mon Sep 17 00:00:00 2001 From: neel Date: Mon, 19 Jan 2015 06:53:31 +0000 Subject: [PATCH 070/258] MOVS instruction emulation. These instructions are emitted by 'bus_space_read_region()' when accessing MMIO regions. Since MOVS can be used with a repeat prefix start decoding the REPZ and REPNZ prefixes. Also start decoding the segment override prefix since MOVS allows overriding the source operand segment register. Tested by: tychon MFC after: 1 week --- sys/amd64/include/vmm.h | 6 +- sys/amd64/vmm/vmm_instruction_emul.c | 271 ++++++++++++++++++++++++++- 2 files changed, 272 insertions(+), 5 deletions(-) diff --git a/sys/amd64/include/vmm.h b/sys/amd64/include/vmm.h index 253654d43758..cf7f5bcae0cd 100644 --- a/sys/amd64/include/vmm.h +++ b/sys/amd64/include/vmm.h @@ -446,8 +446,11 @@ struct vie { rex_x:1, rex_b:1, rex_present:1, + repz_present:1, /* REP/REPE/REPZ prefix */ + repnz_present:1, /* REPNE/REPNZ prefix */ opsize_override:1, /* Operand size override */ - addrsize_override:1; /* Address size override */ + addrsize_override:1, /* Address size override */ + segment_override:1; /* Segment override */ uint8_t mod:2, /* ModRM byte */ reg:4, @@ -463,6 +466,7 @@ struct vie { uint8_t scale; int base_register; /* VM_REG_GUEST_xyz */ int index_register; /* VM_REG_GUEST_xyz */ + int segment_register; /* VM_REG_GUEST_xyz */ int64_t displacement; /* optional addr displacement */ int64_t immediate; /* optional immediate operand */ diff --git a/sys/amd64/vmm/vmm_instruction_emul.c b/sys/amd64/vmm/vmm_instruction_emul.c index d1d7173447d5..3db890e9559a 100644 --- a/sys/amd64/vmm/vmm_instruction_emul.c +++ b/sys/amd64/vmm/vmm_instruction_emul.c @@ -70,6 +70,7 @@ enum { VIE_OP_TYPE_PUSH, VIE_OP_TYPE_CMP, VIE_OP_TYPE_POP, + VIE_OP_TYPE_MOVS, VIE_OP_TYPE_LAST }; @@ -78,6 +79,7 @@ enum { #define VIE_OP_F_IMM8 (1 << 1) /* 8-bit immediate operand */ #define VIE_OP_F_MOFFSET (1 << 2) /* 16/32/64-bit immediate moffset */ #define VIE_OP_F_NO_MODRM (1 << 3) +#define VIE_OP_F_NO_GLA_VERIFICATION (1 << 4) static const struct vie_op two_byte_opcodes[256] = { [0xB6] = { @@ -133,6 +135,16 @@ static const struct vie_op one_byte_opcodes[256] = { .op_type = VIE_OP_TYPE_MOV, .op_flags = VIE_OP_F_MOFFSET | VIE_OP_F_NO_MODRM, }, + [0xA4] = { + .op_byte = 0xA4, + .op_type = VIE_OP_TYPE_MOVS, + .op_flags = VIE_OP_F_NO_MODRM | VIE_OP_F_NO_GLA_VERIFICATION + }, + [0xA5] = { + .op_byte = 0xA5, + .op_type = VIE_OP_TYPE_MOVS, + .op_flags = VIE_OP_F_NO_MODRM | VIE_OP_F_NO_GLA_VERIFICATION + }, [0xC6] = { /* XXX Group 11 extended opcode - not just MOV */ .op_byte = 0xC6, @@ -559,6 +571,217 @@ emulate_movx(void *vm, int vcpuid, uint64_t gpa, struct vie *vie, return (error); } +/* + * Helper function to calculate and validate a linear address. + * + * Returns 0 on success and 1 if an exception was injected into the guest. + */ +static int +get_gla(void *vm, int vcpuid, struct vie *vie, struct vm_guest_paging *paging, + int opsize, int addrsize, int prot, enum vm_reg_name seg, + enum vm_reg_name gpr, uint64_t *gla) +{ + struct seg_desc desc; + uint64_t cr0, val, rflags; + int error; + + error = vie_read_register(vm, vcpuid, VM_REG_GUEST_CR0, &cr0); + KASSERT(error == 0, ("%s: error %d getting cr0", __func__, error)); + + error = vie_read_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, &rflags); + KASSERT(error == 0, ("%s: error %d getting rflags", __func__, error)); + + error = vm_get_seg_desc(vm, vcpuid, seg, &desc); + KASSERT(error == 0, ("%s: error %d getting segment descriptor %d", + __func__, error, seg)); + + error = vie_read_register(vm, vcpuid, gpr, &val); + KASSERT(error == 0, ("%s: error %d getting register %d", __func__, + error, gpr)); + + if (vie_calculate_gla(paging->cpu_mode, seg, &desc, val, opsize, + addrsize, prot, gla)) { + if (seg == VM_REG_GUEST_SS) + vm_inject_ss(vm, vcpuid, 0); + else + vm_inject_gp(vm, vcpuid); + return (1); + } + + if (vie_canonical_check(paging->cpu_mode, *gla)) { + if (seg == VM_REG_GUEST_SS) + vm_inject_ss(vm, vcpuid, 0); + else + vm_inject_gp(vm, vcpuid); + return (1); + } + + if (vie_alignment_check(paging->cpl, opsize, cr0, rflags, *gla)) { + vm_inject_ac(vm, vcpuid, 0); + return (1); + } + + return (0); +} + +static int +emulate_movs(void *vm, int vcpuid, uint64_t gpa, struct vie *vie, + struct vm_guest_paging *paging, mem_region_read_t memread, + mem_region_write_t memwrite, void *arg) +{ +#ifdef _KERNEL + struct vm_copyinfo copyinfo[2]; +#else + struct iovec copyinfo[2]; +#endif + uint64_t dstaddr, srcaddr, val; + uint64_t rcx, rdi, rsi, rflags; + int error, opsize, seg, repeat; + + opsize = (vie->op.op_byte == 0xA4) ? 1 : vie->opsize; + val = 0; + error = 0; + + /* + * XXX although the MOVS instruction is only supposed to be used with + * the "rep" prefix some guests like FreeBSD will use "repnz" instead. + * + * Empirically the "repnz" prefix has identical behavior to "rep" + * and the zero flag does not make a difference. + */ + repeat = vie->repz_present | vie->repnz_present; + + if (repeat) { + error = vie_read_register(vm, vcpuid, VM_REG_GUEST_RCX, &rcx); + KASSERT(!error, ("%s: error %d getting rcx", __func__, error)); + + /* + * The count register is %rcx, %ecx or %cx depending on the + * address size of the instruction. + */ + if ((rcx & vie_size2mask(vie->addrsize)) == 0) + return (0); + } + + /* + * Source Destination Comments + * -------------------------------------------- + * (1) memory memory n/a + * (2) memory mmio emulated + * (3) mmio memory emulated + * (4) mmio mmio not emulated + * + * At this point we don't have sufficient information to distinguish + * between (2), (3) and (4). We use 'vm_copy_setup()' to tease this + * out because it will succeed only when operating on regular memory. + * + * XXX the emulation doesn't properly handle the case where 'gpa' + * is straddling the boundary between the normal memory and MMIO. + */ + + seg = vie->segment_override ? vie->segment_register : VM_REG_GUEST_DS; + error = get_gla(vm, vcpuid, vie, paging, opsize, vie->addrsize, + PROT_READ, seg, VM_REG_GUEST_RSI, &srcaddr); + if (error) + goto done; + + error = vm_copy_setup(vm, vcpuid, paging, srcaddr, opsize, PROT_READ, + copyinfo, nitems(copyinfo)); + if (error == 0) { + /* + * case (2): read from system memory and write to mmio. + */ + vm_copyin(vm, vcpuid, copyinfo, &val, opsize); + vm_copy_teardown(vm, vcpuid, copyinfo, nitems(copyinfo)); + error = memwrite(vm, vcpuid, gpa, val, opsize, arg); + goto done; + } else if (error > 0) { + /* + * Resume guest execution to handle fault. + */ + goto done; + } else { + /* + * 'vm_copy_setup()' is expected to fail for cases (3) and (4) + * if 'srcaddr' is in the mmio space. + */ + } + + error = get_gla(vm, vcpuid, vie, paging, opsize, vie->addrsize, + PROT_WRITE, VM_REG_GUEST_ES, VM_REG_GUEST_RDI, &dstaddr); + if (error) + goto done; + + error = vm_copy_setup(vm, vcpuid, paging, dstaddr, opsize, + PROT_WRITE, copyinfo, nitems(copyinfo)); + if (error == 0) { + /* + * case (3): read from MMIO and write to system memory. + * + * A MMIO read can have side-effects so we commit to it + * only after vm_copy_setup() is successful. If a page-fault + * needs to be injected into the guest then it will happen + * before the MMIO read is attempted. + */ + error = memread(vm, vcpuid, gpa, &val, opsize, arg); + if (error) + goto done; + + vm_copyout(vm, vcpuid, &val, copyinfo, opsize); + vm_copy_teardown(vm, vcpuid, copyinfo, nitems(copyinfo)); + } else if (error > 0) { + /* + * Resume guest execution to handle fault. + */ + goto done; + } else { + goto done; + } + + error = vie_read_register(vm, vcpuid, VM_REG_GUEST_RSI, &rsi); + KASSERT(error == 0, ("%s: error %d getting rsi", __func__, error)); + + error = vie_read_register(vm, vcpuid, VM_REG_GUEST_RDI, &rdi); + KASSERT(error == 0, ("%s: error %d getting rdi", __func__, error)); + + error = vie_read_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, &rflags); + KASSERT(error == 0, ("%s: error %d getting rflags", __func__, error)); + + if (rflags & PSL_D) { + rsi -= opsize; + rdi -= opsize; + } else { + rsi += opsize; + rdi += opsize; + } + + error = vie_update_register(vm, vcpuid, VM_REG_GUEST_RSI, rsi, + vie->addrsize); + KASSERT(error == 0, ("%s: error %d updating rsi", __func__, error)); + + error = vie_update_register(vm, vcpuid, VM_REG_GUEST_RDI, rdi, + vie->addrsize); + KASSERT(error == 0, ("%s: error %d updating rdi", __func__, error)); + + if (repeat) { + rcx = rcx - 1; + error = vie_update_register(vm, vcpuid, VM_REG_GUEST_RCX, + rcx, vie->addrsize); + KASSERT(!error, ("%s: error %d updating rcx", __func__, error)); + + /* + * Repeat the instruction if the count register is not zero. + */ + if ((rcx & vie_size2mask(vie->addrsize)) != 0) + vm_restart_instruction(vm, vcpuid); + } +done: + if (error < 0) + return (EFAULT); + else + return (0); +} + static int emulate_and(void *vm, int vcpuid, uint64_t gpa, struct vie *vie, mem_region_read_t memread, mem_region_write_t memwrite, void *arg) @@ -926,9 +1149,7 @@ emulate_stack_op(void *vm, int vcpuid, uint64_t mmio_gpa, struct vie *vie, error = memwrite(vm, vcpuid, mmio_gpa, val, size, arg); rsp += size; } -#ifdef _KERNEL vm_copy_teardown(vm, vcpuid, copyinfo, nitems(copyinfo)); -#endif if (error == 0) { error = vie_update_register(vm, vcpuid, VM_REG_GUEST_RSP, rsp, @@ -1012,6 +1233,10 @@ vmm_emulate_instruction(void *vm, int vcpuid, uint64_t gpa, struct vie *vie, error = emulate_movx(vm, vcpuid, gpa, vie, memread, memwrite, memarg); break; + case VIE_OP_TYPE_MOVS: + error = emulate_movs(vm, vcpuid, gpa, vie, paging, memread, + memwrite, memarg); + break; case VIE_OP_TYPE_AND: error = emulate_and(vm, vcpuid, gpa, vie, memread, memwrite, memarg); @@ -1193,6 +1418,7 @@ vie_init(struct vie *vie, const char *inst_bytes, int inst_length) vie->base_register = VM_REG_LAST; vie->index_register = VM_REG_LAST; + vie->segment_register = VM_REG_LAST; if (inst_length) { bcopy(inst_bytes, vie->inst, inst_length); @@ -1458,6 +1684,35 @@ vie_advance(struct vie *vie) vie->num_processed++; } +static bool +segment_override(uint8_t x, int *seg) +{ + + switch (x) { + case 0x2E: + *seg = VM_REG_GUEST_CS; + break; + case 0x36: + *seg = VM_REG_GUEST_SS; + break; + case 0x3E: + *seg = VM_REG_GUEST_DS; + break; + case 0x26: + *seg = VM_REG_GUEST_ES; + break; + case 0x64: + *seg = VM_REG_GUEST_FS; + break; + case 0x65: + *seg = VM_REG_GUEST_GS; + break; + default: + return (false); + } + return (true); +} + static int decode_prefixes(struct vie *vie, enum vm_cpu_mode cpu_mode, int cs_d) { @@ -1471,6 +1726,12 @@ decode_prefixes(struct vie *vie, enum vm_cpu_mode cpu_mode, int cs_d) vie->opsize_override = 1; else if (x == 0x67) vie->addrsize_override = 1; + else if (x == 0xF3) + vie->repz_present = 1; + else if (x == 0xF2) + vie->repnz_present = 1; + else if (segment_override(x, &vie->segment_register)) + vie->segment_override = 1; else break; @@ -1923,8 +2184,10 @@ vmm_decode_instruction(struct vm *vm, int cpuid, uint64_t gla, if (verify_inst_length(vie)) return (-1); - if (verify_gla(vm, cpuid, gla, vie)) - return (-1); + if ((vie->op.op_flags & VIE_OP_F_NO_GLA_VERIFICATION) == 0) { + if (verify_gla(vm, cpuid, gla, vie)) + return (-1); + } vie->decoded = 1; /* success */ From f94357dba95e02b60c8a1a47ec87ed6f28b2aea8 Mon Sep 17 00:00:00 2001 From: ngie Date: Mon, 19 Jan 2015 07:10:08 +0000 Subject: [PATCH 071/258] Fix the build when INVARIANTS is defined by restoring `bo`'s definition in ext2_truncate(..) and by putting it under INVARIANTS ifdefs X-MFC with: r277354 MFC after: 2 weeks --- sys/fs/ext2fs/ext2_inode.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sys/fs/ext2fs/ext2_inode.c b/sys/fs/ext2fs/ext2_inode.c index 2fc2192d05bd..36768fb1c418 100644 --- a/sys/fs/ext2fs/ext2_inode.c +++ b/sys/fs/ext2fs/ext2_inode.c @@ -121,8 +121,14 @@ ext2_truncate(struct vnode *vp, off_t length, int flags, struct ucred *cred, e4fs_daddr_t count, nblocks, blocksreleased = 0; int error, i, allerror; off_t osize; +#ifdef INVARIANTS + struct bufobj *bo; +#endif oip = VTOI(ovp); +#ifdef INVARIANTS + bo = &ovp->v_bufobj; +#endif ASSERT_VOP_LOCKED(vp, "ext2_truncate"); From 373e66ec57f233306235c095dd55eda1eff76e84 Mon Sep 17 00:00:00 2001 From: hselasky Date: Mon, 19 Jan 2015 07:29:07 +0000 Subject: [PATCH 072/258] Minor refactoring of code block. MFC after: 1 day --- sys/cam/scsi/scsi_da.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index 6865a61b9a75..2d09d571826a 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -3101,11 +3101,10 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) * give them an 'illegal' value we'll avoid that * here. */ - if (block_size == 0 && maxsector == 0) { - block_size = 512; - maxsector = -1; - } else if (block_size == 0) { + if (block_size == 0) { block_size = 512; + if (maxsector == 0) + maxsector = -1; } if (block_size >= MAXPHYS) { xpt_print(periph->path, From 7a9bfe31c3ff7a58d19c465a5d60c5be55b1d1ef Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 19 Jan 2015 11:06:56 +0000 Subject: [PATCH 073/258] Make the clock-frequency property optional as it may not be present on FDT systems. Sponsored by: The FreeBSD Foundation --- sys/dev/ofw/ofw_cpu.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/sys/dev/ofw/ofw_cpu.c b/sys/dev/ofw/ofw_cpu.c index 1d01b63993e9..02dc2b500554 100644 --- a/sys/dev/ofw/ofw_cpu.c +++ b/sys/dev/ofw/ofw_cpu.c @@ -1,7 +1,11 @@ /*- * Copyright (C) 2009 Nathan Whitehorn + * Copyright (C) 2015 The FreeBSD Foundation * All rights reserved. * + * Portions of this software were developed by Andrew Turner + * 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: @@ -193,10 +197,11 @@ ofw_cpu_attach(device_t dev) } sc->sc_cpu_pcpu = pcpu_find(cell); if (OF_getencprop(node, "clock-frequency", &cell, sizeof(cell)) < 0) { - device_printf(dev, "missing 'clock-frequency' property\n"); - return (ENXIO); - } - sc->sc_nominal_mhz = cell / 1000000; /* convert to MHz */ + if (bootverbose) + device_printf(dev, + "missing 'clock-frequency' property\n"); + } else + sc->sc_nominal_mhz = cell / 1000000; /* convert to MHz */ bus_generic_probe(dev); return (bus_generic_attach(dev)); @@ -214,8 +219,11 @@ ofw_cpu_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) *result = (uintptr_t)sc->sc_cpu_pcpu; return (0); case CPU_IVAR_NOMINAL_MHZ: - *result = (uintptr_t)sc->sc_nominal_mhz; - return (0); + if (sc->sc_nominal_mhz > 0) { + *result = (uintptr_t)sc->sc_nominal_mhz; + return (0); + } + break; } return (ENOENT); From f9503d306057aeb93b43d5297b9b9f70741a72e6 Mon Sep 17 00:00:00 2001 From: tuexen Date: Mon, 19 Jan 2015 11:52:08 +0000 Subject: [PATCH 074/258] Code cleanup. Reported by: Coverity CID: 749578 MFC after: 1 week --- sys/netinet/sctp_timer.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/sys/netinet/sctp_timer.c b/sys/netinet/sctp_timer.c index 7d861acbefff..d7a3f0c405b0 100644 --- a/sys/netinet/sctp_timer.c +++ b/sys/netinet/sctp_timer.c @@ -337,7 +337,7 @@ sctp_find_alternate_net(struct sctp_tcb *stcb, return (NULL); } } - do { + for (;;) { alt = TAILQ_NEXT(mnet, sctp_next); if (alt == NULL) { once++; @@ -356,7 +356,6 @@ sctp_find_alternate_net(struct sctp_tcb *stcb, } alt->src_addr_selected = 0; } - /* sa_ignore NO_NULL_CHK */ if (((alt->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE) && (alt->ro.ro_rt != NULL) && (!(alt->dest_state & SCTP_ADDR_UNCONFIRMED))) { @@ -364,14 +363,14 @@ sctp_find_alternate_net(struct sctp_tcb *stcb, break; } mnet = alt; - } while (alt != NULL); + } if (alt == NULL) { /* Case where NO insv network exists (dormant state) */ /* we rotate destinations */ once = 0; mnet = net; - do { + for (;;) { if (mnet == NULL) { return (TAILQ_FIRST(&stcb->asoc.nets)); } @@ -382,15 +381,17 @@ sctp_find_alternate_net(struct sctp_tcb *stcb, break; } alt = TAILQ_FIRST(&stcb->asoc.nets); + if (alt == NULL) { + break; + } } - /* sa_ignore NO_NULL_CHK */ if ((!(alt->dest_state & SCTP_ADDR_UNCONFIRMED)) && (alt != net)) { /* Found an alternate address */ break; } mnet = alt; - } while (alt != NULL); + } } if (alt == NULL) { return (net); From d00410aae5a62e6f7bd318556be9ad1aa007768e Mon Sep 17 00:00:00 2001 From: mav Date: Mon, 19 Jan 2015 15:52:32 +0000 Subject: [PATCH 075/258] Remove extra mtx_unlock(). Submitted by: Dmitry Luhtionov MFC after: 1 week --- sys/cam/cam_xpt.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c index 36f22145146e..f37bc0a890cd 100644 --- a/sys/cam/cam_xpt.c +++ b/sys/cam/cam_xpt.c @@ -893,7 +893,6 @@ xpt_init(void *dummy) if ((status = xpt_create_path(&path, NULL, CAM_XPT_PATH_ID, CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD)) != CAM_REQ_CMP) { - mtx_unlock(&xsoftc.xpt_lock); printf("xpt_init: xpt_create_path failed with status %#x," " failing attach\n", status); return (EINVAL); From b3741c8701d1d593047434400ecd44500cdc804f Mon Sep 17 00:00:00 2001 From: kib Date: Mon, 19 Jan 2015 17:24:52 +0000 Subject: [PATCH 076/258] Ignore devfs directory entries for devices either being destroyed or delisted. The check is racy. Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 1 week --- sys/fs/devfs/devfs_devs.c | 10 ++++++++++ sys/fs/devfs/devfs_vnops.c | 3 +++ 2 files changed, 13 insertions(+) diff --git a/sys/fs/devfs/devfs_devs.c b/sys/fs/devfs/devfs_devs.c index 294bd62be7ba..986d06692bb4 100644 --- a/sys/fs/devfs/devfs_devs.c +++ b/sys/fs/devfs/devfs_devs.c @@ -192,6 +192,16 @@ devfs_find(struct devfs_dirent *dd, const char *name, int namelen, int type) continue; if (type != 0 && type != de->de_dirent->d_type) continue; + + /* + * The race with finding non-active name is not + * completely closed by the check, but it is similar + * to the devfs_allocv() in making it unlikely enough. + */ + if (de->de_dirent->d_type == DT_CHR && + (de->de_cdp->cdp_flags & CDP_ACTIVE) == 0) + continue; + if (bcmp(name, de->de_dirent->d_name, namelen) != 0) continue; break; diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c index 91535881952a..570f710e6496 100644 --- a/sys/fs/devfs/devfs_vnops.c +++ b/sys/fs/devfs/devfs_vnops.c @@ -1045,6 +1045,9 @@ devfs_mknod(struct vop_mknod_args *ap) TAILQ_FOREACH(de, &dd->de_dlist, de_list) { if (cnp->cn_namelen != de->de_dirent->d_namlen) continue; + if (de->de_dirent->d_type == DT_CHR && + (de->de_cdp->cdp_flags & CDP_ACTIVE) == 0) + continue; if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, de->de_dirent->d_namlen) != 0) continue; From f748dc7ade0eee53b5b866b6a9adc48ecf24b098 Mon Sep 17 00:00:00 2001 From: kib Date: Mon, 19 Jan 2015 17:36:52 +0000 Subject: [PATCH 077/258] Stop enforcing additional reference on all cdevs, which was introduced in r277199. Acquire the neccessary reference in delist_dev_locked() and inform destroy_devl() about it using CDP_UNREF_DTR flag. Fix some style nits, add asserts. Discussed with: hselasky Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 1 week --- sys/fs/devfs/devfs_devs.c | 6 ------ sys/fs/devfs/devfs_int.h | 1 + sys/kern/kern_conf.c | 33 ++++++++++++++++++++++++++++----- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/sys/fs/devfs/devfs_devs.c b/sys/fs/devfs/devfs_devs.c index 986d06692bb4..6620aefc4c45 100644 --- a/sys/fs/devfs/devfs_devs.c +++ b/sys/fs/devfs/devfs_devs.c @@ -137,12 +137,6 @@ devfs_alloc(int flags) vfs_timestamp(&ts); cdev->si_atime = cdev->si_mtime = cdev->si_ctime = ts; cdev->si_cred = NULL; - /* - * Avoid race with dev_rel() by setting the initial - * reference count to 1. This last reference is taken - * by the destroy_dev() function. - */ - cdev->si_refcount = 1; return (cdev); } diff --git a/sys/fs/devfs/devfs_int.h b/sys/fs/devfs/devfs_int.h index ce55416f6c08..6c571092877d 100644 --- a/sys/fs/devfs/devfs_int.h +++ b/sys/fs/devfs/devfs_int.h @@ -56,6 +56,7 @@ struct cdev_priv { u_int cdp_flags; #define CDP_ACTIVE (1 << 0) #define CDP_SCHED_DTR (1 << 1) +#define CDP_UNREF_DTR (1 << 2) u_int cdp_inuse; u_int cdp_maxdirent; diff --git a/sys/kern/kern_conf.c b/sys/kern/kern_conf.c index bcd6fb926fe9..79c8fea69e0d 100644 --- a/sys/kern/kern_conf.c +++ b/sys/kern/kern_conf.c @@ -116,6 +116,8 @@ dev_free_devlocked(struct cdev *cdev) mtx_assert(&devmtx, MA_OWNED); cdp = cdev2priv(cdev); + KASSERT((cdp->cdp_flags & CDP_UNREF_DTR) == 0, + ("destroy_dev() was not called after delist_dev(%p)", cdev)); TAILQ_INSERT_HEAD(&cdevp_free_list, cdp, cdp_list); } @@ -1035,6 +1037,7 @@ destroy_devl(struct cdev *dev) { struct cdevsw *csw; struct cdev_privdata *p; + struct cdev_priv *cdp; mtx_assert(&devmtx, MA_OWNED); KASSERT(dev->si_flags & SI_NAMED, @@ -1043,7 +1046,18 @@ destroy_devl(struct cdev *dev) ("WARNING: Driver mistake: destroy_dev on eternal %d\n", dev2unit(dev))); - devfs_destroy(dev); + cdp = cdev2priv(dev); + if ((cdp->cdp_flags & CDP_UNREF_DTR) == 0) { + /* + * Avoid race with dev_rel(), e.g. from the populate + * loop. If CDP_UNREF_DTR flag is set, the reference + * to be dropped at the end of destroy_devl() was + * already taken by delist_dev_locked(). + */ + dev_refl(dev); + + devfs_destroy(dev); + } /* Remove name marking */ dev->si_flags &= ~SI_NAMED; @@ -1103,19 +1117,27 @@ destroy_devl(struct cdev *dev) } } dev->si_flags &= ~SI_ALIAS; - dev->si_refcount--; /* Avoid race with dev_rel() */ + cdp->cdp_flags &= ~CDP_UNREF_DTR; + dev->si_refcount--; - if (dev->si_refcount > 0) { + if (dev->si_refcount > 0) LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list); - } else { + else dev_free_devlocked(dev); - } } static void delist_dev_locked(struct cdev *dev) { + struct cdev_priv *cdp; struct cdev *child; + + mtx_assert(&devmtx, MA_OWNED); + cdp = cdev2priv(dev); + if ((cdp->cdp_flags & CDP_UNREF_DTR) != 0) + return; + cdp->cdp_flags |= CDP_UNREF_DTR; + dev_refl(dev); devfs_destroy(dev); LIST_FOREACH(child, &dev->si_children, si_siblings) delist_dev_locked(child); @@ -1124,6 +1146,7 @@ delist_dev_locked(struct cdev *dev) void delist_dev(struct cdev *dev) { + dev_lock(); delist_dev_locked(dev); dev_unlock(); From fb73b4e2f2ff339821cf787fb9bd4ed7f0d638a1 Mon Sep 17 00:00:00 2001 From: nwhitehorn Date: Mon, 19 Jan 2015 17:58:01 +0000 Subject: [PATCH 078/258] Add some initial infrastructure for relocating the kernel in place. MFC after: 2 months Differential revision: D1554 --- sys/powerpc/aim/locore64.S | 26 ++++++++++++++++++++--- sys/powerpc/powerpc/elf64_machdep.c | 33 +++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/sys/powerpc/aim/locore64.S b/sys/powerpc/aim/locore64.S index 30ee3a95dc9f..abce9d83e5b6 100644 --- a/sys/powerpc/aim/locore64.S +++ b/sys/powerpc/aim/locore64.S @@ -121,13 +121,33 @@ ASENTRY_NOPROF(__start) .align 3 0: nop bl 1f - .llong __tocbase + 0x8000 + .llong __tocbase + 0x8000 - . 1: mflr %r2 - ld %r2,0(%r2) + ld %r1,0(%r2) + add %r2,%r1,%r2 /* Set up the stack pointer */ ld %r1,TOC_REF(tmpstk)(%r2) - addi %r1,%r1,TMPSTKSZ-48 + addi %r1,%r1,TMPSTKSZ-96 + + /* Relocate kernel */ + std %r3,48(%r1) + std %r4,56(%r1) + std %r5,64(%r1) + std %r6,72(%r1) + bl 1f + .llong _DYNAMIC-. +1: mflr %r3 + ld %r4,0(%r3) + add %r3,%r4,%r3 + ld %r4,-0x8000(%r2) /* First TOC entry is TOC base */ + subf %r4,%r4,%r2 /* Subtract from real TOC base to get base */ + bl elf_reloc_self + nop + ld %r3,48(%r1) + ld %r4,56(%r1) + ld %r5,64(%r1) + ld %r6,72(%r1) /* Switch to 64-bit mode */ mfmsr %r9 diff --git a/sys/powerpc/powerpc/elf64_machdep.c b/sys/powerpc/powerpc/elf64_machdep.c index a0fc7b75bb91..d23f7ffaa2ff 100644 --- a/sys/powerpc/powerpc/elf64_machdep.c +++ b/sys/powerpc/powerpc/elf64_machdep.c @@ -119,6 +119,8 @@ SYSINIT(oelf64, SI_SUB_EXEC, SI_ORDER_ANY, (sysinit_cfunc_t) elf64_insert_brand_entry, &freebsd_brand_oinfo); +void elf_reloc_self(Elf_Dyn *dynp, Elf_Addr relocbase); + void elf64_dump_thread(struct thread *td, void *dst, size_t *off) { @@ -198,6 +200,37 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, return(0); } +void +elf_reloc_self(Elf_Dyn *dynp, Elf_Addr relocbase) +{ + Elf_Rela *rela = 0, *relalim; + Elf_Addr relasz = 0; + Elf_Addr *where; + + /* + * Extract the rela/relasz values from the dynamic section + */ + for (; dynp->d_tag != DT_NULL; dynp++) { + switch (dynp->d_tag) { + case DT_RELA: + rela = (Elf_Rela *)(relocbase+dynp->d_un.d_ptr); + break; + case DT_RELASZ: + relasz = dynp->d_un.d_val; + break; + } + } + + /* + * Relocate these values + */ + relalim = (Elf_Rela *)((caddr_t)rela + relasz); + for (; rela < relalim; rela++) { + where = (Elf_Addr *)(relocbase + rela->r_offset); + *where = (Elf_Addr)(relocbase + rela->r_addend); + } +} + int elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type, elf_lookup_fn lookup) From b4271ae0c2b4c61c103639b9ec43de48e3b32d7c Mon Sep 17 00:00:00 2001 From: hselasky Date: Mon, 19 Jan 2015 20:39:48 +0000 Subject: [PATCH 079/258] Add more functions to the Linux kernel compatibility layer. Add some missing includes which are needed when the header files are not included in a particular order. MFC after: 1 month Sponsored by: Mellanox Technologies --- sys/ofed/include/linux/bitops.h | 6 ++++++ sys/ofed/include/linux/cache.h | 3 +-- sys/ofed/include/linux/dma-mapping.h | 8 ++++++++ sys/ofed/include/linux/etherdevice.h | 5 ++++- sys/ofed/include/linux/gfp.h | 2 ++ sys/ofed/include/linux/io.h | 15 +++++++++++++++ sys/ofed/include/linux/kernel.h | 5 +++++ sys/ofed/include/linux/ktime.h | 9 +++++++++ sys/ofed/include/linux/slab.h | 2 ++ 9 files changed, 52 insertions(+), 3 deletions(-) diff --git a/sys/ofed/include/linux/bitops.h b/sys/ofed/include/linux/bitops.h index 93a3aa93a157..f225fdc6d9db 100644 --- a/sys/ofed/include/linux/bitops.h +++ b/sys/ofed/include/linux/bitops.h @@ -288,9 +288,15 @@ bitmap_empty(unsigned long *addr, int size) #define NBLONG (NBBY * sizeof(long)) +#define __set_bit(i, a) \ + atomic_set_long(&((volatile long *)(a))[(i)/NBLONG], 1UL << ((i) % NBLONG)) + #define set_bit(i, a) \ atomic_set_long(&((volatile long *)(a))[(i)/NBLONG], 1UL << ((i) % NBLONG)) +#define __clear_bit(i, a) \ + atomic_clear_long(&((volatile long *)(a))[(i)/NBLONG], 1UL << ((i) % NBLONG)) + #define clear_bit(i, a) \ atomic_clear_long(&((volatile long *)(a))[(i)/NBLONG], 1UL << ((i) % NBLONG)) diff --git a/sys/ofed/include/linux/cache.h b/sys/ofed/include/linux/cache.h index e4a9d0924639..921a507ea662 100644 --- a/sys/ofed/include/linux/cache.h +++ b/sys/ofed/include/linux/cache.h @@ -30,8 +30,7 @@ #ifndef _LINUX_CACHE_H_ #define _LINUX_CACHE_H_ - #define cache_line_size() CACHE_LINE_SIZE - +#define L1_CACHE_BYTES CACHE_LINE_SIZE #endif /* _LINUX_CACHE_H_ */ diff --git a/sys/ofed/include/linux/dma-mapping.h b/sys/ofed/include/linux/dma-mapping.h index 2f0762b430be..f9fc3cb095b1 100644 --- a/sys/ofed/include/linux/dma-mapping.h +++ b/sys/ofed/include/linux/dma-mapping.h @@ -139,6 +139,14 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, *dma_handle = 0; return (mem); } + +static inline void * +dma_zalloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, + gfp_t flag) +{ + + return (dma_alloc_coherent(dev, size, dma_handle, flag | __GFP_ZERO)); +} static inline void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, diff --git a/sys/ofed/include/linux/etherdevice.h b/sys/ofed/include/linux/etherdevice.h index 7d1114501ce7..d863651894a7 100644 --- a/sys/ofed/include/linux/etherdevice.h +++ b/sys/ofed/include/linux/etherdevice.h @@ -89,6 +89,9 @@ static inline bool is_valid_ether_addr(const u8 *addr) return !is_multicast_ether_addr(addr) && !is_zero_ether_addr(addr); } - +static inline void ether_addr_copy(u8 *dst, const u8 *src) +{ + memcpy(dst, src, 6); +} #endif /* _LINUX_ETHERDEVICE */ diff --git a/sys/ofed/include/linux/gfp.h b/sys/ofed/include/linux/gfp.h index af30faacab64..3e773028dee9 100644 --- a/sys/ofed/include/linux/gfp.h +++ b/sys/ofed/include/linux/gfp.h @@ -30,6 +30,8 @@ #ifndef _LINUX_GFP_H_ #define _LINUX_GFP_H_ +#include +#include #include #include diff --git a/sys/ofed/include/linux/io.h b/sys/ofed/include/linux/io.h index 2fc25b567eb0..4c8c9f524b21 100644 --- a/sys/ofed/include/linux/io.h +++ b/sys/ofed/include/linux/io.h @@ -31,6 +31,7 @@ #define _LINUX_IO_H_ #include +#include static inline uint32_t __raw_readl(const volatile void *addr) @@ -89,6 +90,20 @@ writew(uint16_t b, void *addr) *(volatile uint16_t *)addr = b; } +#undef ioread32be +static inline uint32_t +ioread32be(const volatile void *addr) +{ + return be32toh(*(const volatile uint32_t *)addr); +} + +#undef iowrite32be +static inline void +iowrite32be(uint32_t v, volatile void *addr) +{ + *(volatile uint32_t *)addr = htobe32(v); +} + void *_ioremap_attr(vm_paddr_t phys_addr, unsigned long size, int attr); #define ioremap_nocache(addr, size) \ _ioremap_attr((addr), (size), VM_MEMATTR_UNCACHEABLE) diff --git a/sys/ofed/include/linux/kernel.h b/sys/ofed/include/linux/kernel.h index d9d1ab6613ba..5d4e50bdab31 100644 --- a/sys/ofed/include/linux/kernel.h +++ b/sys/ofed/include/linux/kernel.h @@ -29,6 +29,8 @@ #ifndef _LINUX_KERNEL_H_ #define _LINUX_KERNEL_H_ +#include +#include #include #include #include @@ -57,6 +59,8 @@ #define KERN_INFO "<6>" #define KERN_DEBUG "<7>" +#define BUILD_BUG_ON(x) CTASSERT(x) + #define BUG() panic("BUG") #define BUG_ON(condition) do { if (condition) BUG(); } while(0) #define WARN_ON BUG_ON @@ -84,6 +88,7 @@ #endif #define udelay(t) DELAY(t) +#define usleep_range(min,max) DELAY(min) #ifndef pr_fmt #define pr_fmt(fmt) fmt diff --git a/sys/ofed/include/linux/ktime.h b/sys/ofed/include/linux/ktime.h index c59c7b9dacd4..7524afcf1ab2 100644 --- a/sys/ofed/include/linux/ktime.h +++ b/sys/ofed/include/linux/ktime.h @@ -288,4 +288,13 @@ static inline s64 ktime_to_ns(const ktime_t kt) #endif /* !((BITS_PER_LONG == 64) || defined(CONFIG_KTIME_SCALAR)) */ +static inline s64 ktime_get_ns(void) +{ + struct timespec ts; + ktime_t kt; + ktime_get_ts(&ts); + kt = timespec_to_ktime(ts); + return (ktime_to_ns(kt)); +} + #endif /* _LINUX_KTIME_H */ diff --git a/sys/ofed/include/linux/slab.h b/sys/ofed/include/linux/slab.h index 1d373ce0322e..0d01a3659c2a 100644 --- a/sys/ofed/include/linux/slab.h +++ b/sys/ofed/include/linux/slab.h @@ -40,6 +40,7 @@ MALLOC_DECLARE(M_KMALLOC); #define kmalloc(size, flags) malloc((size), M_KMALLOC, (flags)) +#define kvmalloc(size) kmalloc((size), 0) #define kzalloc(size, flags) kmalloc((size), (flags) | M_ZERO) #define kzalloc_node(size, flags, node) kzalloc(size, flags) #define kfree(ptr) free(__DECONST(void *, (ptr)), M_KMALLOC) @@ -47,6 +48,7 @@ MALLOC_DECLARE(M_KMALLOC); #define kcalloc(n, size, flags) kmalloc((n) * (size), flags | M_ZERO) #define vzalloc(size) kzalloc(size, GFP_KERNEL | __GFP_NOWARN) #define vfree(arg) kfree(arg) +#define kvfree(arg) kfree(arg) #define vmalloc(size) kmalloc(size, GFP_KERNEL) #define vmalloc_node(size, node) kmalloc(size, GFP_KERNEL) From 551300d1123f7cc0163b0a449f3add8ca22e12c3 Mon Sep 17 00:00:00 2001 From: hselasky Date: Mon, 19 Jan 2015 21:53:00 +0000 Subject: [PATCH 080/258] Add missing linuxapi module dependencies and always use the FreeBSD "MODULE_VERSION" macro definition. Remove the redefinition of the "MODULE_VERSION" macro from the Linux kernel compatibility API. MFC after: 1 month Reported by: np@ Sponsored by: Mellanox Technologies --- sys/contrib/rdma/krping/krping.c | 2 ++ sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb.c | 5 ++--- sys/dev/cxgbe/iw_cxgbe/device.c | 3 +-- sys/ofed/drivers/infiniband/core/device.c | 2 -- sys/ofed/drivers/infiniband/hw/mlx4/main.c | 4 ++-- sys/ofed/drivers/infiniband/hw/mthca/mthca_main.c | 4 +++- sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c | 2 -- sys/ofed/drivers/net/mlx4/en_main.c | 4 ++-- sys/ofed/drivers/net/mlx4/main.c | 5 ----- sys/ofed/include/linux/module.h | 8 ++++---- 10 files changed, 16 insertions(+), 23 deletions(-) diff --git a/sys/contrib/rdma/krping/krping.c b/sys/contrib/rdma/krping/krping.c index a770423cfde8..c89339edf31b 100644 --- a/sys/contrib/rdma/krping/krping.c +++ b/sys/contrib/rdma/krping/krping.c @@ -60,6 +60,8 @@ extern int krping_debug; MODULE_AUTHOR("Steve Wise"); MODULE_DESCRIPTION("RDMA ping client/server"); MODULE_LICENSE("Dual BSD/GPL"); +MODULE_VERSION(krping, 1); +MODULE_DEPEND(krping, linuxapi, 1, 1, 1); static __inline uint64_t get_cycles(void) diff --git a/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb.c b/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb.c index 1825a430d040..18876fe4245b 100644 --- a/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb.c +++ b/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb.c @@ -251,9 +251,6 @@ iwch_mod_unload(void) } #endif /* TCP_OFFLOAD */ -#undef MODULE_VERSION -#include - static int iwch_modevent(module_t mod, int cmd, void *arg) { @@ -299,3 +296,5 @@ MODULE_DEPEND(t3_tom, cxgbc, 1, 1, 1); MODULE_DEPEND(iw_cxgb, toecore, 1, 1, 1); MODULE_DEPEND(iw_cxgb, t3_tom, 1, 1, 1); MODULE_DEPEND(iw_cxgb, ibcore, 1, 1, 1); +MODULE_DEPEND(iw_cxgb, linuxapi, 1, 1, 1); + diff --git a/sys/dev/cxgbe/iw_cxgbe/device.c b/sys/dev/cxgbe/iw_cxgbe/device.c index adb283d8f719..92a574215b2a 100644 --- a/sys/dev/cxgbe/iw_cxgbe/device.c +++ b/sys/dev/cxgbe/iw_cxgbe/device.c @@ -321,8 +321,6 @@ c4iw_mod_unload(void) } #endif -#undef MODULE_VERSION -#include /* * t4_tom won't load on kernels without TCP_OFFLOAD and this module's dependency @@ -366,4 +364,5 @@ MODULE_VERSION(iw_cxgbe, 1); MODULE_DEPEND(iw_cxgbe, t4nex, 1, 1, 1); MODULE_DEPEND(iw_cxgbe, t4_tom, 1, 1, 1); MODULE_DEPEND(iw_cxgbe, ibcore, 1, 1, 1); +MODULE_DEPEND(iw_cxgbe, linuxapi, 1, 1, 1); DECLARE_MODULE(iw_cxgbe, c4iw_mod_data, SI_SUB_EXEC, SI_ORDER_ANY); diff --git a/sys/ofed/drivers/infiniband/core/device.c b/sys/ofed/drivers/infiniband/core/device.c index e2e6bafdf699..98adf489b81a 100644 --- a/sys/ofed/drivers/infiniband/core/device.c +++ b/sys/ofed/drivers/infiniband/core/device.c @@ -754,8 +754,6 @@ static void __exit ib_core_cleanup(void) module_init(ib_core_init); module_exit(ib_core_cleanup); -#undef MODULE_VERSION -#include static int ibcore_evhand(module_t mod, int event, void *arg) { diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/main.c b/sys/ofed/drivers/infiniband/hw/mlx4/main.c index 441ee739bb26..fd0b7235873a 100644 --- a/sys/ofed/drivers/infiniband/hw/mlx4/main.c +++ b/sys/ofed/drivers/infiniband/hw/mlx4/main.c @@ -67,7 +67,9 @@ MODULE_AUTHOR("Roland Dreier"); MODULE_DESCRIPTION("Mellanox ConnectX HCA InfiniBand driver"); MODULE_LICENSE("Dual BSD/GPL"); +#ifdef __linux__ MODULE_VERSION(DRV_VERSION); +#endif int mlx4_ib_sm_guid_assign = 1; @@ -2404,8 +2406,6 @@ static void __exit mlx4_ib_cleanup(void) module_init_order(mlx4_ib_init, SI_ORDER_MIDDLE); module_exit(mlx4_ib_cleanup); -#undef MODULE_VERSION -#include static int mlx4ib_evhand(module_t mod, int event, void *arg) { diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_main.c b/sys/ofed/drivers/infiniband/hw/mthca/mthca_main.c index d1da694f62a7..8596bdd3d7eb 100644 --- a/sys/ofed/drivers/infiniband/hw/mthca/mthca_main.c +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_main.c @@ -47,7 +47,9 @@ MODULE_AUTHOR("Roland Dreier"); MODULE_DESCRIPTION("Mellanox InfiniBand HCA low-level driver"); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_VERSION(DRV_VERSION); +MODULE_VERSION(mthca, 1); +MODULE_DEPEND(mthca, linuxapi, 1, 1, 1); +MODULE_DEPEND(mthca, ibcore, 1, 1, 1); #ifdef CONFIG_INFINIBAND_MTHCA_DEBUG diff --git a/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c index fe517389b65b..695621f16a84 100644 --- a/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1527,8 +1527,6 @@ ipoib_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa, module_init(ipoib_init_module); module_exit(ipoib_cleanup_module); -#undef MODULE_VERSION -#include static int ipoib_evhand(module_t mod, int event, void *arg) { diff --git a/sys/ofed/drivers/net/mlx4/en_main.c b/sys/ofed/drivers/net/mlx4/en_main.c index 983f99e382c0..1249d62a4f92 100644 --- a/sys/ofed/drivers/net/mlx4/en_main.c +++ b/sys/ofed/drivers/net/mlx4/en_main.c @@ -45,7 +45,9 @@ MODULE_AUTHOR("Liran Liss, Yevgeny Petrilin"); MODULE_DESCRIPTION("Mellanox ConnectX HCA Ethernet driver"); MODULE_LICENSE("Dual BSD/GPL"); +#ifdef __linux__ MODULE_VERSION(DRV_VERSION " ("DRV_RELDATE")"); +#endif static const char mlx4_en_version[] = DRV_NAME ": Mellanox ConnectX HCA Ethernet driver v" @@ -336,8 +338,6 @@ static void __exit mlx4_en_cleanup(void) module_init(mlx4_en_init); module_exit(mlx4_en_cleanup); -#undef MODULE_VERSION -#include static int mlxen_evhand(module_t mod, int event, void *arg) { diff --git a/sys/ofed/drivers/net/mlx4/main.c b/sys/ofed/drivers/net/mlx4/main.c index 1b8f85fc2dc6..84c40eddf24b 100644 --- a/sys/ofed/drivers/net/mlx4/main.c +++ b/sys/ofed/drivers/net/mlx4/main.c @@ -34,10 +34,6 @@ */ #include -/* - * kmod.h must be included before module.h since it includes (indirectly) sys/module.h - * To use the FBSD macro sys/module.h should define MODULE_VERSION before linux/module does. -*/ #include #include #include @@ -3783,7 +3779,6 @@ static void __exit mlx4_cleanup(void) module_init_order(mlx4_init, SI_ORDER_MIDDLE); module_exit(mlx4_cleanup); -#include static int mlx4_evhand(module_t mod, int event, void *arg) { diff --git a/sys/ofed/include/linux/module.h b/sys/ofed/include/linux/module.h index fbbc45219f8a..cd9f4d556079 100644 --- a/sys/ofed/include/linux/module.h +++ b/sys/ofed/include/linux/module.h @@ -29,6 +29,10 @@ #ifndef _LINUX_MODULE_H_ #define _LINUX_MODULE_H_ +#include +#include +#include + #include #include #include @@ -39,10 +43,6 @@ #define MODULE_DESCRIPTION(name) #define MODULE_LICENSE(name) -#ifndef MODULE_VERSION -#define MODULE_VERSION(name) -#endif - #define THIS_MODULE ((struct module *)0) #define EXPORT_SYMBOL(name) From 68d3af83c8dfcf9006e67bdf9de87e932de4ac50 Mon Sep 17 00:00:00 2001 From: gonzo Date: Tue, 20 Jan 2015 02:24:08 +0000 Subject: [PATCH 081/258] Properly clear IRQ status in order to fix "Spurious IRQ" message from AINT. This register is not documented in TRM but that's what linux driver does --- sys/arm/ti/am335x/am335x_lcd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sys/arm/ti/am335x/am335x_lcd.c b/sys/arm/ti/am335x/am335x_lcd.c index 09f81f0d517e..a4c56b914922 100644 --- a/sys/arm/ti/am335x/am335x_lcd.c +++ b/sys/arm/ti/am335x/am335x_lcd.c @@ -150,6 +150,7 @@ __FBSDID("$FreeBSD$"); #define IRQ_SYNC_LOST (1 << 2) #define IRQ_RASTER_DONE (1 << 1) #define IRQ_FRAME_DONE (1 << 0) +#define LCD_END_OF_INT_IND 0x68 #define LCD_CLKC_ENABLE 0x6C #define CLKC_ENABLE_DMA (1 << 2) #define CLKC_ENABLE_LDID (1 << 1) @@ -397,6 +398,8 @@ am335x_lcd_intr(void *arg) if (reg & IRQ_ACB) { /* TODO: Handle ACB */ } + + LCD_WRITE4(sc, LCD_END_OF_INT_IND, 0); } static int From 1fe4c6403b0aba5e8d556a641e6eb749d3c1f1ba Mon Sep 17 00:00:00 2001 From: neel Date: Tue, 20 Jan 2015 03:54:30 +0000 Subject: [PATCH 082/258] Update the vdso timehands only via tc_windup(). Prior to this change CLOCK_MONOTONIC could go backwards when the timecounter hardware was changed via 'sysctl kern.timecounter.hardware'. This happened because the vdso timehands update was missing the special treatment in tc_windup() when changing timecounters. Reviewed by: kib --- sys/kern/kern_tc.c | 15 +++++++++++---- sys/kern/subr_dummy_vdso_tc.c | 5 +++-- sys/sys/vdso.h | 8 ++++++-- sys/x86/x86/tsc.c | 13 +++++++------ 4 files changed, 27 insertions(+), 14 deletions(-) diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c index 7a6b4e6d959b..1c29041b1f29 100644 --- a/sys/kern/kern_tc.c +++ b/sys/kern/kern_tc.c @@ -1424,7 +1424,15 @@ sysctl_kern_timecounter_hardware(SYSCTL_HANDLER_ARGS) (void)newtc->tc_get_timecount(newtc); timecounter = newtc; - timekeep_push_vdso(); + + /* + * The vdso timehands update is deferred until the next + * 'tc_windup()'. + * + * This is prudent given that 'timekeep_push_vdso()' does not + * use any locking and that it can be called in hard interrupt + * context via 'tc_windup()'. + */ return (0); } return (EINVAL); @@ -1982,7 +1990,6 @@ sysctl_fast_gettime(SYSCTL_HANDLER_ARGS) if (error != 0) return (error); vdso_th_enable = old_vdso_th_enable; - timekeep_push_vdso(); return (0); } SYSCTL_PROC(_kern_timecounter, OID_AUTO, fast_gettime, @@ -2002,7 +2009,7 @@ tc_fill_vdso_timehands(struct vdso_timehands *vdso_th) vdso_th->th_counter_mask = th->th_counter->tc_counter_mask; vdso_th->th_offset = th->th_offset; vdso_th->th_boottime = boottimebin; - enabled = cpu_fill_vdso_timehands(vdso_th); + enabled = cpu_fill_vdso_timehands(vdso_th, th->th_counter); if (!vdso_th_enable) enabled = 0; return (enabled); @@ -2024,7 +2031,7 @@ tc_fill_vdso_timehands32(struct vdso_timehands32 *vdso_th32) *(uint64_t *)&vdso_th32->th_offset.frac[0] = th->th_offset.frac; vdso_th32->th_boottime.sec = boottimebin.sec; *(uint64_t *)&vdso_th32->th_boottime.frac[0] = boottimebin.frac; - enabled = cpu_fill_vdso_timehands32(vdso_th32); + enabled = cpu_fill_vdso_timehands32(vdso_th32, th->th_counter); if (!vdso_th_enable) enabled = 0; return (enabled); diff --git a/sys/kern/subr_dummy_vdso_tc.c b/sys/kern/subr_dummy_vdso_tc.c index 9c845014f50f..d1c36b74ead0 100644 --- a/sys/kern/subr_dummy_vdso_tc.c +++ b/sys/kern/subr_dummy_vdso_tc.c @@ -33,7 +33,7 @@ __FBSDID("$FreeBSD$"); #include uint32_t -cpu_fill_vdso_timehands(struct vdso_timehands *vdso_th) +cpu_fill_vdso_timehands(struct vdso_timehands *vdso_th, struct timecounter *tc) { return (0); @@ -41,7 +41,8 @@ cpu_fill_vdso_timehands(struct vdso_timehands *vdso_th) #ifdef COMPAT_FREEBSD32 uint32_t -cpu_fill_vdso_timehands32(struct vdso_timehands32 *vdso_th32) +cpu_fill_vdso_timehands32(struct vdso_timehands32 *vdso_th32, + struct timecounter *tc) { return (0); diff --git a/sys/sys/vdso.h b/sys/sys/vdso.h index f584315b9561..d905304ac68a 100644 --- a/sys/sys/vdso.h +++ b/sys/sys/vdso.h @@ -69,6 +69,8 @@ int __vdso_gettimekeep(struct vdso_timekeep **tk); #ifdef _KERNEL +struct timecounter; + void timekeep_push_vdso(void); uint32_t tc_fill_vdso_timehands(struct vdso_timehands *vdso_th); @@ -81,7 +83,8 @@ uint32_t tc_fill_vdso_timehands(struct vdso_timehands *vdso_th); * global sysctl enable override is handled by machine-independed code * after cpu_fill_vdso_timehands() call is made. */ -uint32_t cpu_fill_vdso_timehands(struct vdso_timehands *vdso_th); +uint32_t cpu_fill_vdso_timehands(struct vdso_timehands *vdso_th, + struct timecounter *tc); #define VDSO_TH_NUM 4 @@ -110,7 +113,8 @@ struct vdso_timekeep32 { }; uint32_t tc_fill_vdso_timehands32(struct vdso_timehands32 *vdso_th32); -uint32_t cpu_fill_vdso_timehands32(struct vdso_timehands32 *vdso_th32); +uint32_t cpu_fill_vdso_timehands32(struct vdso_timehands32 *vdso_th32, + struct timecounter *tc); #endif #endif diff --git a/sys/x86/x86/tsc.c b/sys/x86/x86/tsc.c index c84f28a3e603..e2ae73517fa1 100644 --- a/sys/x86/x86/tsc.c +++ b/sys/x86/x86/tsc.c @@ -720,21 +720,22 @@ tsc_get_timecount_low_mfence(struct timecounter *tc) } uint32_t -cpu_fill_vdso_timehands(struct vdso_timehands *vdso_th) +cpu_fill_vdso_timehands(struct vdso_timehands *vdso_th, struct timecounter *tc) { - vdso_th->th_x86_shift = (int)(intptr_t)timecounter->tc_priv; + vdso_th->th_x86_shift = (int)(intptr_t)tc->tc_priv; bzero(vdso_th->th_res, sizeof(vdso_th->th_res)); - return (timecounter == &tsc_timecounter); + return (tc == &tsc_timecounter); } #ifdef COMPAT_FREEBSD32 uint32_t -cpu_fill_vdso_timehands32(struct vdso_timehands32 *vdso_th32) +cpu_fill_vdso_timehands32(struct vdso_timehands32 *vdso_th32, + struct timecounter *tc) { - vdso_th32->th_x86_shift = (int)(intptr_t)timecounter->tc_priv; + vdso_th32->th_x86_shift = (int)(intptr_t)tc->tc_priv; bzero(vdso_th32->th_res, sizeof(vdso_th32->th_res)); - return (timecounter == &tsc_timecounter); + return (tc == &tsc_timecounter); } #endif From 27a273f2842e8f5ed0719ef8b5d50e5ff42c3f7c Mon Sep 17 00:00:00 2001 From: nwhitehorn Date: Tue, 20 Jan 2015 05:28:03 +0000 Subject: [PATCH 083/258] Zero BSS explicitly if not started by loader(8). Add a check for the magic values that ePAPR-compliant loaders (like skiboot) put in the register loader uses for the metadata pointer to avoid confusing them. --- sys/powerpc/aim/machdep.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c index fdbe48b4b54f..d0aac4c7f466 100644 --- a/sys/powerpc/aim/machdep.c +++ b/sys/powerpc/aim/machdep.c @@ -224,6 +224,10 @@ cpu_startup(void *dummy) } extern vm_offset_t __startkernel, __endkernel; +extern unsigned char __bss_start[]; +extern unsigned char __sbss_start[]; +extern unsigned char __sbss_end[]; +extern unsigned char _end[]; #ifndef __powerpc64__ /* Bits for running on 64-bit systems in 32-bit mode. */ @@ -272,9 +276,6 @@ powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp) trap_offset = 0; cacheline_warn = 0; - /* Store boot environment state */ - OF_initial_setup((void *)fdt, NULL, (int (*)(void *))ofentry); - /* First guess at start/end kernel positions */ startkernel = __startkernel; endkernel = __endkernel; @@ -289,6 +290,10 @@ powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp) mdp = NULL; #endif + /* Check for ePAPR loader, which puts a magic value into r6 */ + if (mdp == (void *)0x65504150) + mdp = NULL; + /* * Parse metadata if present and fetch parameters. Must be done * before console is inited so cninit gets the right value of @@ -308,8 +313,14 @@ powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp) db_fetch_ksymtab(ksym_start, ksym_end); #endif } + } else { + bzero(__sbss_start, __sbss_end - __sbss_start); + bzero(__bss_start, _end - __bss_start); } + /* Store boot environment state */ + OF_initial_setup((void *)fdt, NULL, (int (*)(void *))ofentry); + /* * Init params/tunables that can be overridden by the loader */ From 32e84f90539f6b05972c3f5e827938b55bbec4d4 Mon Sep 17 00:00:00 2001 From: nwhitehorn Date: Tue, 20 Jan 2015 05:44:21 +0000 Subject: [PATCH 084/258] Remove space in the FDT reservation map from the available memory regions in ofw_mem_regions(). This function is actually MI and should move to dev/ofw at some point in the near future so that ARM and MIPS can use the same code. --- sys/powerpc/ofw/ofw_machdep.c | 91 +++++++++++++++++++++++++++++++++-- 1 file changed, 87 insertions(+), 4 deletions(-) diff --git a/sys/powerpc/ofw/ofw_machdep.c b/sys/powerpc/ofw/ofw_machdep.c index 1c02fa3e90d3..50f9d9e86532 100644 --- a/sys/powerpc/ofw/ofw_machdep.c +++ b/sys/powerpc/ofw/ofw_machdep.c @@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include @@ -211,12 +212,89 @@ parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output) return (sz); } +static int +excise_fdt_reserved(struct mem_region *avail, int asz) +{ + struct { + uint64_t address; + uint64_t size; + } fdtmap[16]; + ssize_t fdtmapsize; + phandle_t chosen; + int i, j, k; + + chosen = OF_finddevice("/chosen"); + fdtmapsize = OF_getprop(chosen, "fdtmemreserv", fdtmap, sizeof(fdtmap)); + + for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) { + fdtmap[j].address = be64toh(fdtmap[j].address); + fdtmap[j].size = be64toh(fdtmap[j].size); + } + + for (i = 0; i < asz; i++) { + for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) { + /* + * Case 1: Exclusion region encloses complete + * available entry. Drop it and move on. + */ + if (fdtmap[j].address <= avail[i].mr_start && + fdtmap[j].address + fdtmap[j].size >= + avail[i].mr_start + avail[i].mr_size) { + for (k = i+1; k < asz; k++) + avail[k-1] = avail[k]; + asz--; + i--; /* Repeat some entries */ + continue; + } + + /* + * Case 2: Exclusion region starts in available entry. + * Trim it to where the entry begins and append + * a new available entry with the region after + * the excluded region, if any. + */ + if (fdtmap[j].address >= avail[i].mr_start && + fdtmap[j].address < avail[i].mr_start + + avail[i].mr_size) { + if (fdtmap[j].address + fdtmap[j].size < + avail[i].mr_start + avail[i].mr_size) { + avail[asz].mr_start = + roundup2(fdtmap[j].address + + fdtmap[j].size, PAGE_SIZE); + avail[asz].mr_size = avail[i].mr_start + + avail[i].mr_size - + avail[asz].mr_start; + asz++; + } + + avail[i].mr_size = + rounddown2(fdtmap[j].address, PAGE_MASK) - + avail[i].mr_start; + } + + /* + * Case 3: Exclusion region ends in available entry. + * Move start point to where the exclusion zone ends. + * The case of a contained exclusion zone has already + * been caught in case 2. + */ + if (fdtmap[j].address + fdtmap[j].size >= + avail[i].mr_start && fdtmap[j].address + + fdtmap[j].size < avail[i].mr_start + + avail[i].mr_size) { + avail[i].mr_start = + roundup2(fdtmap[j].address + fdtmap[j].size, PAGE_MASK); + } + } + } + + return (asz); +} + /* * This is called during powerpc_init, before the system is really initialized. * It shall provide the total and the available regions of RAM. - * Both lists must have a zero-size entry as terminator. - * The available regions need not take the kernel into account, but needs - * to provide space for two additional entry beyond the terminating one. + * The available regions need not take the kernel into account. */ void ofw_mem_regions(struct mem_region *memp, int *memsz, @@ -236,7 +314,8 @@ ofw_mem_regions(struct mem_region *memp, int *memsz, phandle = OF_peer(phandle)) { if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0) continue; - if (strncmp(name, "memory", sizeof(name)) != 0) + if (strncmp(name, "memory", sizeof(name)) != 0 && + strncmp(name, "memory@", strlen("memory@")) != 0) continue; res = parse_ofw_memory(phandle, "reg", &memp[msz]); @@ -249,6 +328,10 @@ ofw_mem_regions(struct mem_region *memp, int *memsz, asz += res/sizeof(struct mem_region); } + phandle = OF_finddevice("/chosen"); + if (OF_hasprop(phandle, "fdtmemreserv")) + asz = excise_fdt_reserved(availp, asz); + *memsz = msz; *availsz = asz; } From 7ddeee68ed7a5543fb54e81f5f9d60e000f22fce Mon Sep 17 00:00:00 2001 From: ganbold Date: Tue, 20 Jan 2015 09:07:28 +0000 Subject: [PATCH 085/258] Enable Synopsys DesignWare Mobile Storage Host Controller driver on Rockchip boards. It currently supports PIO mode and dma mode needs external dma controller to be used. Submitted by: jmcneill Approved by: stas (mentor) --- sys/arm/conf/RK3188 | 5 +- sys/arm/rockchip/files.rk30xx | 2 + sys/boot/fdt/dts/arm/rk3188-radxa-lite.dts | 4 + sys/boot/fdt/dts/arm/rk3188-radxa.dts | 4 + sys/boot/fdt/dts/arm/rk3188.dtsi | 12 +- sys/dev/mmc/host/dwmmc.c | 169 +++++++++++++++++---- sys/dev/mmc/host/dwmmc.h | 2 + 7 files changed, 163 insertions(+), 35 deletions(-) diff --git a/sys/arm/conf/RK3188 b/sys/arm/conf/RK3188 index 13e2ed09a63f..2aba68e184d3 100644 --- a/sys/arm/conf/RK3188 +++ b/sys/arm/conf/RK3188 @@ -76,8 +76,9 @@ options DIAGNOSTIC options ROOTDEVNAME=\"ufs:/dev/da0s2\" # MMC/SD/SDIO Card slot support -#device mmc # mmc/sd bus -#device mmcsd # mmc/sd flash cards +device mmc # mmc/sd bus +device mmcsd # mmc/sd flash cards +device dwmmc # Console and misc device uart diff --git a/sys/arm/rockchip/files.rk30xx b/sys/arm/rockchip/files.rk30xx index bfbf7617657c..0bcc34c36578 100644 --- a/sys/arm/rockchip/files.rk30xx +++ b/sys/arm/rockchip/files.rk30xx @@ -19,3 +19,5 @@ arm/rockchip/rk30xx_grf.c standard arm/rockchip/rk30xx_wdog.c standard arm/rockchip/rk30xx_gpio.c optional gpio arm/rockchip/rk30xx_mp.c optional smp + +dev/mmc/host/dwmmc.c optional dwmmc diff --git a/sys/boot/fdt/dts/arm/rk3188-radxa-lite.dts b/sys/boot/fdt/dts/arm/rk3188-radxa-lite.dts index 8f8977683e67..643f5d0ea826 100644 --- a/sys/boot/fdt/dts/arm/rk3188-radxa-lite.dts +++ b/sys/boot/fdt/dts/arm/rk3188-radxa-lite.dts @@ -48,6 +48,10 @@ status = "okay"; }; + mmc@10214000 { + status = "okay"; + }; + }; chosen { diff --git a/sys/boot/fdt/dts/arm/rk3188-radxa.dts b/sys/boot/fdt/dts/arm/rk3188-radxa.dts index ff9ee87a8dbd..c3740a0a5a4d 100644 --- a/sys/boot/fdt/dts/arm/rk3188-radxa.dts +++ b/sys/boot/fdt/dts/arm/rk3188-radxa.dts @@ -48,6 +48,10 @@ status = "okay"; }; + mmc@10214000 { + status = "okay"; + }; + }; chosen { diff --git a/sys/boot/fdt/dts/arm/rk3188.dtsi b/sys/boot/fdt/dts/arm/rk3188.dtsi index c6ac38561a1f..f16c1b86818e 100644 --- a/sys/boot/fdt/dts/arm/rk3188.dtsi +++ b/sys/boot/fdt/dts/arm/rk3188.dtsi @@ -231,22 +231,26 @@ }; mmc@10214000 { - compatible = "rockchip,rk30xx-mmc"; + compatible = "rockchip,rk2928-dw-mshc"; reg = <0x10214000 0x1000>; interrupts = <55>; #address-cells = <1>; #size-cells = <0>; - clock-frequency = <24000000>; /* TODO: verify freq */ + bus-frequency = <48000000>; /* TODO: verify freq */ + fifo-depth = <0x40>; + num-slots = <1>; status = "disabled"; }; mmc@10218000 { - compatible = "rockchip,rk30xx-mmc"; + compatible = "rockchip,rk2928-dw-mshc"; reg = <0x10218000 0x1000>; interrupts = <56>; #address-cells = <1>; #size-cells = <0>; - clock-frequency = <24000000>; /* TODO: verify freq */ + bus-frequency = <48000000>; /* TODO: verify freq */ + fifo-depth = <0x40>; + num-slots = <1>; status = "disabled"; }; }; diff --git a/sys/dev/mmc/host/dwmmc.c b/sys/dev/mmc/host/dwmmc.c index 79fe69b40f60..81e3083a33cf 100644 --- a/sys/dev/mmc/host/dwmmc.c +++ b/sys/dev/mmc/host/dwmmc.c @@ -129,6 +129,8 @@ struct dwmmc_softc { uint32_t flags; uint32_t hwtype; uint32_t use_auto_stop; + uint32_t use_pio; + uint32_t pwren_inverted; bus_dma_tag_t desc_tag; bus_dmamap_t desc_map; @@ -152,6 +154,8 @@ static void dwmmc_next_operation(struct dwmmc_softc *); static int dwmmc_setup_bus(struct dwmmc_softc *, int); static int dma_done(struct dwmmc_softc *, struct mmc_command *); static int dma_stop(struct dwmmc_softc *); +static void pio_read(struct dwmmc_softc *, struct mmc_command *); +static void pio_write(struct dwmmc_softc *, struct mmc_command *); static struct resource_spec dwmmc_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, @@ -163,6 +167,7 @@ enum { HWTYPE_NONE, HWTYPE_ALTERA, HWTYPE_EXYNOS, + HWTYPE_ROCKCHIP, }; #define HWTYPE_MASK (0x0000ffff) @@ -171,6 +176,7 @@ enum { static struct ofw_compat_data compat_data[] = { {"altr,socfpga-dw-mshc", HWTYPE_ALTERA}, {"samsung,exynos5420-dw-mshc", HWTYPE_EXYNOS}, + {"rockchip,rk2928-dw-mshc", HWTYPE_ROCKCHIP}, {NULL, HWTYPE_NONE}, }; @@ -395,8 +401,10 @@ dwmmc_intr(void *arg) dprintf("data err 0x%08x cmd 0x%08x\n", reg, cmd->opcode); cmd->error = MMC_ERR_FAILED; - dma_done(sc, cmd); - dma_stop(sc); + if (!sc->use_pio) { + dma_done(sc, cmd); + dma_stop(sc); + } } if (reg & SDMMC_INTMASK_CMD_DONE) { @@ -421,15 +429,24 @@ dwmmc_intr(void *arg) } } - /* Now handle DMA interrupts */ - reg = READ4(sc, SDMMC_IDSTS); - if (reg) { - dprintf("dma intr 0x%08x\n", reg); - if (reg & (SDMMC_IDINTEN_TI | SDMMC_IDINTEN_RI)) { - WRITE4(sc, SDMMC_IDSTS, (SDMMC_IDINTEN_TI | - SDMMC_IDINTEN_RI)); - WRITE4(sc, SDMMC_IDSTS, SDMMC_IDINTEN_NI); - dma_done(sc, cmd); + if (sc->use_pio) { + if (reg & (SDMMC_INTMASK_RXDR|SDMMC_INTMASK_DTO)) { + pio_read(sc, cmd); + } + if (reg & (SDMMC_INTMASK_TXDR|SDMMC_INTMASK_DTO)) { + pio_write(sc, cmd); + } + } else { + /* Now handle DMA interrupts */ + reg = READ4(sc, SDMMC_IDSTS); + if (reg) { + dprintf("dma intr 0x%08x\n", reg); + if (reg & (SDMMC_IDINTEN_TI | SDMMC_IDINTEN_RI)) { + WRITE4(sc, SDMMC_IDSTS, (SDMMC_IDINTEN_TI | + SDMMC_IDINTEN_RI)); + WRITE4(sc, SDMMC_IDSTS, SDMMC_IDINTEN_NI); + dma_done(sc, cmd); + } } } @@ -560,17 +577,29 @@ dwmmc_attach(device_t dev) device_printf(dev, "Hardware version ID is %04x\n", READ4(sc, SDMMC_VERID) & 0xffff); - WRITE4(sc, EMMCP_MPSBEGIN0, 0); - WRITE4(sc, EMMCP_SEND0, 0); - WRITE4(sc, EMMCP_CTRL0, (MPSCTRL_SECURE_READ_BIT | - MPSCTRL_SECURE_WRITE_BIT | - MPSCTRL_NON_SECURE_READ_BIT | - MPSCTRL_NON_SECURE_WRITE_BIT | - MPSCTRL_VALID)); + sc->use_pio = 0; + sc->pwren_inverted = 0; + + if ((sc->hwtype & HWTYPE_MASK) == HWTYPE_ROCKCHIP) { + sc->use_pio = 1; + sc->pwren_inverted = 1; + } else { + WRITE4(sc, EMMCP_MPSBEGIN0, 0); + WRITE4(sc, EMMCP_SEND0, 0); + WRITE4(sc, EMMCP_CTRL0, (MPSCTRL_SECURE_READ_BIT | + MPSCTRL_SECURE_WRITE_BIT | + MPSCTRL_NON_SECURE_READ_BIT | + MPSCTRL_NON_SECURE_WRITE_BIT | + MPSCTRL_VALID)); + } /* XXX: we support operation for slot index 0 only */ slot = 0; - WRITE4(sc, SDMMC_PWREN, (1 << slot)); + if (sc->pwren_inverted) { + WRITE4(sc, SDMMC_PWREN, (0 << slot)); + } else { + WRITE4(sc, SDMMC_PWREN, (1 << slot)); + } /* Reset all */ if (dwmmc_ctrl_reset(sc, (SDMMC_CTRL_RESET | @@ -580,17 +609,19 @@ dwmmc_attach(device_t dev) dwmmc_setup_bus(sc, sc->host.f_min); - if (dma_setup(sc)) - return (ENXIO); + if (!sc->use_pio) { + if (dma_setup(sc)) + return (ENXIO); - /* Install desc base */ - WRITE4(sc, SDMMC_DBADDR, sc->desc_ring_paddr); + /* Install desc base */ + WRITE4(sc, SDMMC_DBADDR, sc->desc_ring_paddr); - /* Enable DMA interrupts */ - WRITE4(sc, SDMMC_IDSTS, SDMMC_IDINTEN_MASK); - WRITE4(sc, SDMMC_IDINTEN, (SDMMC_IDINTEN_NI | - SDMMC_IDINTEN_RI | - SDMMC_IDINTEN_TI)); + /* Enable DMA interrupts */ + WRITE4(sc, SDMMC_IDSTS, SDMMC_IDINTEN_MASK); + WRITE4(sc, SDMMC_IDINTEN, (SDMMC_IDINTEN_NI | + SDMMC_IDINTEN_RI | + SDMMC_IDINTEN_TI)); + } /* Clear and disable interrups for a while */ WRITE4(sc, SDMMC_RINTSTS, 0xffffffff); @@ -797,6 +828,79 @@ dma_prepare(struct dwmmc_softc *sc, struct mmc_command *cmd) return (0); } +static int +pio_prepare(struct dwmmc_softc *sc, struct mmc_command *cmd) +{ + struct mmc_data *data; + int reg; + + data = cmd->data; + data->xfer_len = 0; + + reg = (DEF_MSIZE << SDMMC_FIFOTH_MSIZE_S); + reg |= ((sc->fifo_depth / 2) - 1) << SDMMC_FIFOTH_RXWMARK_S; + reg |= (sc->fifo_depth / 2) << SDMMC_FIFOTH_TXWMARK_S; + + WRITE4(sc, SDMMC_FIFOTH, reg); + wmb(); + + return (0); +} + +static void +pio_read(struct dwmmc_softc *sc, struct mmc_command *cmd) +{ + struct mmc_data *data; + uint32_t *p, status; + + if (cmd == NULL || cmd->data == NULL) + return; + + data = cmd->data; + if ((data->flags & MMC_DATA_READ) == 0) + return; + + KASSERT((data->xfer_len & 3) == 0, ("xfer_len not aligned")); + p = (uint32_t *)data->data + (data->xfer_len >> 2); + + while (data->xfer_len < data->len) { + status = READ4(sc, SDMMC_STATUS); + if (status & SDMMC_STATUS_FIFO_EMPTY) + break; + *p++ = READ4(sc, SDMMC_DATA); + data->xfer_len += 4; + } + + WRITE4(sc, SDMMC_RINTSTS, SDMMC_INTMASK_RXDR); +} + +static void +pio_write(struct dwmmc_softc *sc, struct mmc_command *cmd) +{ + struct mmc_data *data; + uint32_t *p, status; + + if (cmd == NULL || cmd->data == NULL) + return; + + data = cmd->data; + if ((data->flags & MMC_DATA_WRITE) == 0) + return; + + KASSERT((data->xfer_len & 3) == 0, ("xfer_len not aligned")); + p = (uint32_t *)data->data + (data->xfer_len >> 2); + + while (data->xfer_len < data->len) { + status = READ4(sc, SDMMC_STATUS); + if (status & SDMMC_STATUS_FIFO_FULL) + break; + WRITE4(sc, SDMMC_DATA, *p++); + data->xfer_len += 4; + } + + WRITE4(sc, SDMMC_RINTSTS, SDMMC_INTMASK_TXDR); +} + static void dwmmc_start_cmd(struct dwmmc_softc *sc, struct mmc_command *cmd) { @@ -807,6 +911,9 @@ dwmmc_start_cmd(struct dwmmc_softc *sc, struct mmc_command *cmd) sc->curcmd = cmd; data = cmd->data; + if ((sc->hwtype & HWTYPE_MASK) == HWTYPE_ROCKCHIP) + dwmmc_setup_bus(sc, sc->host.ios.clock); + /* XXX Upper layers don't always set this */ cmd->mrq = sc->req; @@ -861,7 +968,11 @@ dwmmc_start_cmd(struct dwmmc_softc *sc, struct mmc_command *cmd) data->len : MMC_SECTOR_SIZE; WRITE4(sc, SDMMC_BLKSIZ, blksz); - dma_prepare(sc, cmd); + if (sc->use_pio) { + pio_prepare(sc, cmd); + } else { + dma_prepare(sc, cmd); + } wmb(); } diff --git a/sys/dev/mmc/host/dwmmc.h b/sys/dev/mmc/host/dwmmc.h index 8f763cd50417..a075adbbf3ca 100644 --- a/sys/dev/mmc/host/dwmmc.h +++ b/sys/dev/mmc/host/dwmmc.h @@ -91,6 +91,8 @@ #define SDMMC_RINTSTS 0x44 /* Raw Interrupt Status Register */ #define SDMMC_STATUS 0x48 /* Status Register */ #define SDMMC_STATUS_DATA_BUSY (1 << 9) /* card_data[0] */ +#define SDMMC_STATUS_FIFO_FULL (1 << 3) /* FIFO full */ +#define SDMMC_STATUS_FIFO_EMPTY (1 << 2) /* FIFO empty */ #define SDMMC_FIFOTH 0x4C /* FIFO Threshold Watermark Register */ #define SDMMC_FIFOTH_MSIZE_S 28 /* Burst size of multiple transaction */ #define SDMMC_FIFOTH_RXWMARK_S 16 /* FIFO threshold watermark level */ From 5a896dc0ff42038d80ec99e785b47e2d53ebe135 Mon Sep 17 00:00:00 2001 From: br Date: Tue, 20 Jan 2015 11:10:25 +0000 Subject: [PATCH 086/258] Add 128-byte cache flushing routines. Leave CNMIPS untouched as these functions depends on config2 register. --- sys/mips/include/cache_mipsNN.h | 2 - sys/mips/mips/cache.c | 4 - sys/mips/mips/cache_mipsNN.c | 219 ++++++++++++++++++++++++++++++++ 3 files changed, 219 insertions(+), 6 deletions(-) diff --git a/sys/mips/include/cache_mipsNN.h b/sys/mips/include/cache_mipsNN.h index 435993b9b72b..1969ab1a9115 100644 --- a/sys/mips/include/cache_mipsNN.h +++ b/sys/mips/include/cache_mipsNN.h @@ -57,7 +57,6 @@ void mipsNN_pdcache_inv_range_16(vm_offset_t, vm_size_t); void mipsNN_pdcache_inv_range_32(vm_offset_t, vm_size_t); void mipsNN_pdcache_wb_range_16(vm_offset_t, vm_size_t); void mipsNN_pdcache_wb_range_32(vm_offset_t, vm_size_t); -#ifdef CPU_CNMIPS void mipsNN_icache_sync_all_128(void); void mipsNN_icache_sync_range_128(vm_offset_t, vm_size_t); void mipsNN_icache_sync_range_index_128(vm_offset_t, vm_size_t); @@ -66,7 +65,6 @@ void mipsNN_pdcache_wbinv_range_128(vm_offset_t, vm_size_t); void mipsNN_pdcache_wbinv_range_index_128(vm_offset_t, vm_size_t); void mipsNN_pdcache_inv_range_128(vm_offset_t, vm_size_t); void mipsNN_pdcache_wb_range_128(vm_offset_t, vm_size_t); -#endif void mipsNN_sdcache_wbinv_all_32(void); void mipsNN_sdcache_wbinv_range_32(vm_offset_t, vm_size_t); void mipsNN_sdcache_wbinv_range_index_32(vm_offset_t, vm_size_t); diff --git a/sys/mips/mips/cache.c b/sys/mips/mips/cache.c index 70a1db380421..59172d705b0d 100644 --- a/sys/mips/mips/cache.c +++ b/sys/mips/mips/cache.c @@ -104,7 +104,6 @@ mips_config_cache(struct mips_cpuinfo * cpuinfo) mips_cache_ops.mco_icache_sync_range_index = mipsNN_icache_sync_range_index_32; break; -#ifdef CPU_CNMIPS case 128: mips_cache_ops.mco_icache_sync_all = mipsNN_icache_sync_all_128; mips_cache_ops.mco_icache_sync_range = @@ -112,7 +111,6 @@ mips_config_cache(struct mips_cpuinfo * cpuinfo) mips_cache_ops.mco_icache_sync_range_index = mipsNN_icache_sync_range_index_128; break; -#endif #ifdef MIPS_DISABLE_L1_CACHE case 0: @@ -172,7 +170,6 @@ mips_config_cache(struct mips_cpuinfo * cpuinfo) mipsNN_pdcache_wb_range_32; #endif break; -#ifdef CPU_CNMIPS case 128: mips_cache_ops.mco_pdcache_wbinv_all = mips_cache_ops.mco_intern_pdcache_wbinv_all = @@ -188,7 +185,6 @@ mips_config_cache(struct mips_cpuinfo * cpuinfo) mips_cache_ops.mco_intern_pdcache_wb_range = mipsNN_pdcache_wb_range_128; break; -#endif #ifdef MIPS_DISABLE_L1_CACHE case 0: mips_cache_ops.mco_pdcache_wbinv_all = diff --git a/sys/mips/mips/cache_mipsNN.c b/sys/mips/mips/cache_mipsNN.c index ac104c2cfd2a..2bb1fa159c72 100644 --- a/sys/mips/mips/cache_mipsNN.c +++ b/sys/mips/mips/cache_mipsNN.c @@ -647,6 +647,225 @@ mipsNN_pdcache_wb_range_128(vm_offset_t va, vm_size_t size) SYNC; } +#else + +void +mipsNN_icache_sync_all_128(void) +{ + vm_offset_t va, eva; + + va = MIPS_PHYS_TO_KSEG0(0); + eva = va + picache_size; + + /* + * Since we're hitting the whole thing, we don't have to + * worry about the N different "ways". + */ + + mips_intern_dcache_wbinv_all(); + + while (va < eva) { + cache_r4k_op_32lines_128(va, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); + va += (32 * 128); + } + + SYNC; +} + +void +mipsNN_icache_sync_range_128(vm_offset_t va, vm_size_t size) +{ + vm_offset_t eva; + + eva = round_line128(va + size); + va = trunc_line128(va); + + mips_intern_dcache_wb_range(va, (eva - va)); + + while ((eva - va) >= (32 * 128)) { + cache_r4k_op_32lines_128(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV); + va += (32 * 128); + } + + while (va < eva) { + cache_op_r4k_line(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV); + va += 128; + } + + SYNC; +} + +void +mipsNN_icache_sync_range_index_128(vm_offset_t va, vm_size_t size) +{ + vm_offset_t eva, tmpva; + int i, stride, loopcount; + + /* + * Since we're doing Index ops, we expect to not be able + * to access the address we've been given. So, get the + * bits that determine the cache index, and make a KSEG0 + * address out of them. + */ + va = MIPS_PHYS_TO_KSEG0(va & picache_way_mask); + + eva = round_line128(va + size); + va = trunc_line128(va); + + /* + * GCC generates better code in the loops if we reference local + * copies of these global variables. + */ + stride = picache_stride; + loopcount = picache_loopcount; + + mips_intern_dcache_wbinv_range_index(va, (eva - va)); + + while ((eva - va) >= (32 * 128)) { + tmpva = va; + for (i = 0; i < loopcount; i++, tmpva += stride) + cache_r4k_op_32lines_128(tmpva, + CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); + va += 32 * 128; + } + + while (va < eva) { + tmpva = va; + for (i = 0; i < loopcount; i++, tmpva += stride) + cache_op_r4k_line(tmpva, + CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); + va += 128; + } +} + +void +mipsNN_pdcache_wbinv_all_128(void) +{ + vm_offset_t va, eva; + + va = MIPS_PHYS_TO_KSEG0(0); + eva = va + pdcache_size; + + /* + * Since we're hitting the whole thing, we don't have to + * worry about the N different "ways". + */ + + while (va < eva) { + cache_r4k_op_32lines_128(va, + CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); + va += (32 * 128); + } + + SYNC; +} + + +void +mipsNN_pdcache_wbinv_range_128(vm_offset_t va, vm_size_t size) +{ + vm_offset_t eva; + + eva = round_line128(va + size); + va = trunc_line128(va); + + while ((eva - va) >= (32 * 128)) { + cache_r4k_op_32lines_128(va, + CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV); + va += (32 * 128); + } + + while (va < eva) { + cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV); + va += 128; + } + + SYNC; +} + +void +mipsNN_pdcache_wbinv_range_index_128(vm_offset_t va, vm_size_t size) +{ + vm_offset_t eva, tmpva; + int i, stride, loopcount; + + /* + * Since we're doing Index ops, we expect to not be able + * to access the address we've been given. So, get the + * bits that determine the cache index, and make a KSEG0 + * address out of them. + */ + va = MIPS_PHYS_TO_KSEG0(va & pdcache_way_mask); + + eva = round_line128(va + size); + va = trunc_line128(va); + + /* + * GCC generates better code in the loops if we reference local + * copies of these global variables. + */ + stride = pdcache_stride; + loopcount = pdcache_loopcount; + + while ((eva - va) >= (32 * 128)) { + tmpva = va; + for (i = 0; i < loopcount; i++, tmpva += stride) + cache_r4k_op_32lines_128(tmpva, + CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); + va += 32 * 128; + } + + while (va < eva) { + tmpva = va; + for (i = 0; i < loopcount; i++, tmpva += stride) + cache_op_r4k_line(tmpva, + CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); + va += 128; + } +} + +void +mipsNN_pdcache_inv_range_128(vm_offset_t va, vm_size_t size) +{ + vm_offset_t eva; + + eva = round_line128(va + size); + va = trunc_line128(va); + + while ((eva - va) >= (32 * 128)) { + cache_r4k_op_32lines_128(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV); + va += (32 * 128); + } + + while (va < eva) { + cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV); + va += 128; + } + + SYNC; +} + +void +mipsNN_pdcache_wb_range_128(vm_offset_t va, vm_size_t size) +{ + vm_offset_t eva; + + eva = round_line128(va + size); + va = trunc_line128(va); + + while ((eva - va) >= (32 * 128)) { + cache_r4k_op_32lines_128(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB); + va += (32 * 128); + } + + while (va < eva) { + cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB); + va += 128; + } + + SYNC; +} + #endif void From 1672a09eb021611b9bd0c452ac3d4ef8426e64f9 Mon Sep 17 00:00:00 2001 From: andrew Date: Tue, 20 Jan 2015 11:11:32 +0000 Subject: [PATCH 087/258] Add the User and PL1 read only and reqd write thread ID registers. Sponsored by: The FreeBSD Foundation --- sys/arm/include/cpu-v6.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sys/arm/include/cpu-v6.h b/sys/arm/include/cpu-v6.h index 8d1a413b9ce3..1eafb62da7c3 100644 --- a/sys/arm/include/cpu-v6.h +++ b/sys/arm/include/cpu-v6.h @@ -179,6 +179,13 @@ _WF1(cp15_pminten_set, CP15_PMINTENSET(%0)) _WF1(cp15_pminten_clr, CP15_PMINTENCLR(%0)) #endif +_RF0(cp15_tpidrurw_get, CP15_TPIDRURW(%0)) +_WF1(cp15_tpidrurw_set, CP15_TPIDRURW(%0)) +_RF0(cp15_tpidruro_get, CP15_TPIDRURO(%0)) +_WF1(cp15_tpidruro_set, CP15_TPIDRURO(%0)) +_RF0(cp15_tpidrpwr_get, CP15_TPIDRPRW(%0)) +_WF1(cp15_tpidrpwr_set, CP15_TPIDRPRW(%0)) + #undef _FX #undef _RF0 #undef _WF0 From 0cbd82bbb22b8e5786ea4067ef052f4c44ad2963 Mon Sep 17 00:00:00 2001 From: andrew Date: Tue, 20 Jan 2015 11:32:48 +0000 Subject: [PATCH 088/258] Remove the SMP code from locore-v4. These will never use the SMP code as there is no multi-core hardware prior to ARMv6. Sponsored by: The FreeBSD Foundation --- sys/arm/arm/locore-v4.S | 92 ----------------------------------------- 1 file changed, 92 deletions(-) diff --git a/sys/arm/arm/locore-v4.S b/sys/arm/arm/locore-v4.S index 6c20b683fd26..8ef53e93fa00 100644 --- a/sys/arm/arm/locore-v4.S +++ b/sys/arm/arm/locore-v4.S @@ -218,9 +218,6 @@ Lunmapped: bl build_pagetables #endif -#if defined(SMP) - orr r0, r0, #2 /* Set TTB shared memory flag */ -#endif mcr p15, 0, r0, c2, c0, 0 /* Set TTB */ mcr p15, 0, r0, c8, c7, 0 /* Flush TLB */ @@ -338,9 +335,6 @@ translate_va_to_pa: build_pagetables: /* Set the required page attributed */ ldr r4, =(L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW)) -#if defined(SMP) - orr r4, #(L1_SHARED) -#endif orr r1, r4 /* Move the virtual address to the correct bit location */ @@ -394,92 +388,6 @@ pagetable: .Lcpufuncs: .word _C_LABEL(cpufuncs) -#if defined(SMP) - -.Lmpvirt_done: - .word mpvirt_done -VA_TO_PA_POINTER(Lstartup_pagetable_secondary, temp_pagetable) - -ASENTRY_NP(mpentry) - - /* Make sure interrupts are disabled. */ - mrs r7, cpsr - orr r7, r7, #(PSR_I | PSR_F) - msr cpsr_c, r7 - - /* Disable MMU. It should be disabled already, but make sure. */ - mrc p15, 0, r2, c1, c0, 0 - bic r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\ - CPU_CONTROL_WBUF_ENABLE) - bic r2, r2, #(CPU_CONTROL_IC_ENABLE) - bic r2, r2, #(CPU_CONTROL_BPRD_ENABLE) - mcr p15, 0, r2, c1, c0, 0 - nop - nop - nop - CPWAIT(r0) - -#if ARM_MMU_V6 - bl armv6_idcache_inv_all /* Modifies r0 only */ -#elif ARM_MMU_V7 - bl armv7_idcache_inv_all /* Modifies r0-r3, ip */ -#endif - - /* Load the page table physical address */ - adr r0, Lstartup_pagetable_secondary - bl translate_va_to_pa - /* Load the address the secondary page table */ - ldr r0, [r0] - - orr r0, r0, #2 /* Set TTB shared memory flag */ - mcr p15, 0, r0, c2, c0, 0 /* Set TTB */ - mcr p15, 0, r0, c8, c7, 0 /* Flush TLB */ - - mov r0, #0 - mcr p15, 0, r0, c13, c0, 1 /* Set ASID to 0 */ - - /* Set the Domain Access register. Very important! */ - mov r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT) - mcr p15, 0, r0, c3, c0, 0 - /* Enable MMU */ - mrc p15, 0, r0, c1, c0, 0 - orr r0, r0, #CPU_CONTROL_V6_EXTPAGE - orr r0, r0, #CPU_CONTROL_AF_ENABLE - orr r0, r0, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\ - CPU_CONTROL_WBUF_ENABLE) - orr r0, r0, #(CPU_CONTROL_IC_ENABLE) - orr r0, r0, #(CPU_CONTROL_BPRD_ENABLE) - mcr p15, 0, r0, c1, c0, 0 - nop - nop - nop - CPWAIT(r0) - - adr r1, .Lstart - ldmia r1, {r1, r2, sp} /* Set initial stack and */ - mrc p15, 0, r0, c0, c0, 5 - and r0, r0, #15 - mov r1, #2048 - mul r2, r1, r0 - sub sp, sp, r2 - str r1, [sp] - ldr pc, .Lmpvirt_done - -mpvirt_done: - - mov fp, #0 /* trace back starts here */ - bl _C_LABEL(init_secondary) /* Off we go */ - - adr r0, .Lmpreturned - b _C_LABEL(panic) - /* NOTREACHED */ - -.Lmpreturned: - .asciz "init_secondary() returned" - .align 2 -END(mpentry) -#endif - ENTRY_NP(cpu_halt) mrs r2, cpsr bic r2, r2, #(PSR_MODE) From 827c65e7ef3341ba0cd7906e6e8417b2db035566 Mon Sep 17 00:00:00 2001 From: hselasky Date: Tue, 20 Jan 2015 11:43:16 +0000 Subject: [PATCH 089/258] Fix returned data for the USB_GET_DEV_PORT_PATH IOCTL in particular the value returned in the "udp_port_level" field. Reported by: Uffe Jakobsen MFC after: 1 week --- sys/dev/usb/usb_generic.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sys/dev/usb/usb_generic.c b/sys/dev/usb/usb_generic.c index 96dfe8bceb87..17956cbc7993 100644 --- a/sys/dev/usb/usb_generic.c +++ b/sys/dev/usb/usb_generic.c @@ -1849,14 +1849,13 @@ ugen_get_port_path(struct usb_fifo *f, struct usb_device_port_path *dpp) if (nlevel > USB_DEVICE_PORT_PATH_MAX) goto error; + /* store total level of ports */ + dpp->udp_port_level = nlevel; + /* store port index array */ next = udev; while (next->parent_hub != NULL) { - nlevel--; - - dpp->udp_port_no[nlevel] = next->port_no; - dpp->udp_port_level = nlevel; - + dpp->udp_port_no[--nlevel] = next->port_no; next = next->parent_hub; } return (0); /* success */ From 313e96ad334aae0ab1c78f7cdd21462fd5e91e22 Mon Sep 17 00:00:00 2001 From: royger Date: Tue, 20 Jan 2015 12:28:24 +0000 Subject: [PATCH 090/258] loader: fix the size of MODINFOMD_MODULEP The data in MODINFOMD_MODULEP is packed by the loader as a 4 byte type, but the amd64 kernel expects a vm_paddr_t, which is of size 8 bytes. Fix this by saving it as 8 bytes in the loader and retrieving it using the proper type in the kernel. Sponsored by: Citrix Systems R&D --- sys/boot/i386/libi386/bootinfo64.c | 5 +++-- sys/x86/xen/pv.c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/sys/boot/i386/libi386/bootinfo64.c b/sys/boot/i386/libi386/bootinfo64.c index a97ab84ed7e3..751e806e1b8f 100644 --- a/sys/boot/i386/libi386/bootinfo64.c +++ b/sys/boot/i386/libi386/bootinfo64.c @@ -185,6 +185,7 @@ bi_load64(char *args, vm_offset_t addr, vm_offset_t *modulep, struct file_metadata *md; u_int64_t kernend; u_int64_t envp; + u_int64_t module; vm_offset_t size; char *rootdevname; int howto; @@ -222,7 +223,7 @@ bi_load64(char *args, vm_offset_t addr, vm_offset_t *modulep, addr = roundup(addr, PAGE_SIZE); /* place the metadata before anything */ - *modulep = addr; + module = *modulep = addr; kfp = file_findfile(NULL, "elf kernel"); if (kfp == NULL) @@ -233,7 +234,7 @@ bi_load64(char *args, vm_offset_t addr, vm_offset_t *modulep, file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); - file_addmetadata(kfp, MODINFOMD_MODULEP, sizeof modulep, modulep); + file_addmetadata(kfp, MODINFOMD_MODULEP, sizeof module, &module); if (add_smap != 0) bios_addsmapdata(kfp); diff --git a/sys/x86/xen/pv.c b/sys/x86/xen/pv.c index e8cdca4f0bca..233bf3e013b9 100644 --- a/sys/x86/xen/pv.c +++ b/sys/x86/xen/pv.c @@ -402,7 +402,7 @@ xen_pv_parse_preload_data(u_int64_t modulep) * then calculating the offset with mod_start, * which contains the relocated modulep address. */ - metadata = MD_FETCH(kmdp, MODINFOMD_MODULEP, int); + metadata = MD_FETCH(kmdp, MODINFOMD_MODULEP, vm_paddr_t); off = HYPERVISOR_start_info->mod_start - metadata; preload_bootstrap_relocate(off); From 24b6750419f6979b7cbb18a485d70d553fcb9fcd Mon Sep 17 00:00:00 2001 From: mav Date: Tue, 20 Jan 2015 13:09:12 +0000 Subject: [PATCH 091/258] Allow skipping dmu_buf_will_dirty() call in dsl_dir_transfer_space(). dsl_dir_transfer_space() is mostly called after dsl_dir_diduse_space(), which already calls dmu_buf_will_dirty() for the same dbuf and tx, so its duplicate call in those cases will change nothing, only spend time. Skipping this call by four times reduces time spent in dbuf_write_done() and descendants, updating dataset statistics with several congested lock acquisitions. When rewriting 8K zvol blocks at 1GB/s rate, this reduces CPU time spent inside dbuf_write_done(), according to profiling, from 45% of 683K samples to 18% of 422K. MFC after: 2 weeks --- .../contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c | 6 +++--- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c index 34bef4ee5698..ce22f4efb52f 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c @@ -136,7 +136,7 @@ dsl_dataset_block_born(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx) dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, delta, compressed, uncompressed, tx); dsl_dir_transfer_space(ds->ds_dir, used - delta, - DD_USED_REFRSRV, DD_USED_HEAD, tx); + DD_USED_REFRSRV, DD_USED_HEAD, NULL); } int @@ -179,7 +179,7 @@ dsl_dataset_block_kill(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx, dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, delta, -compressed, -uncompressed, tx); dsl_dir_transfer_space(ds->ds_dir, -used - delta, - DD_USED_REFRSRV, DD_USED_HEAD, tx); + DD_USED_REFRSRV, DD_USED_HEAD, NULL); } else { dprintf_bp(bp, "putting on dead list: %s", ""); if (async) { @@ -2837,7 +2837,7 @@ dsl_dataset_clone_swap_sync_impl(dsl_dataset_t *clone, origin_head->ds_dir->dd_origin_txg, UINT64_MAX, &odl_used, &odl_comp, &odl_uncomp); dsl_dir_transfer_space(origin_head->ds_dir, cdl_used - odl_used, - DD_USED_HEAD, DD_USED_SNAP, tx); + DD_USED_HEAD, DD_USED_SNAP, NULL); } /* swap ds_*_bytes */ diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c index 5a891d1ba3d6..1862f8cb8d7c 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c @@ -1389,7 +1389,7 @@ dsl_dir_diduse_space(dsl_dir_t *dd, dd_used_t type, accounted_delta, compressed, uncompressed, tx); dsl_dir_transfer_space(dd->dd_parent, used - accounted_delta, - DD_USED_CHILD_RSRV, DD_USED_CHILD, tx); + DD_USED_CHILD_RSRV, DD_USED_CHILD, NULL); } } @@ -1397,7 +1397,7 @@ void dsl_dir_transfer_space(dsl_dir_t *dd, int64_t delta, dd_used_t oldtype, dd_used_t newtype, dmu_tx_t *tx) { - ASSERT(dmu_tx_is_syncing(tx)); + ASSERT(tx == NULL || dmu_tx_is_syncing(tx)); ASSERT(oldtype < DD_USED_NUM); ASSERT(newtype < DD_USED_NUM); @@ -1405,7 +1405,8 @@ dsl_dir_transfer_space(dsl_dir_t *dd, int64_t delta, !(dsl_dir_phys(dd)->dd_flags & DD_FLAG_USED_BREAKDOWN)) return; - dmu_buf_will_dirty(dd->dd_dbuf, tx); + if (tx != NULL) + dmu_buf_will_dirty(dd->dd_dbuf, tx); mutex_enter(&dd->dd_lock); ASSERT(delta > 0 ? dsl_dir_phys(dd)->dd_used_breakdown[oldtype] >= delta : From 9896a88f220b781873672a420aae843c3150710b Mon Sep 17 00:00:00 2001 From: br Date: Tue, 20 Jan 2015 15:45:09 +0000 Subject: [PATCH 092/258] o Do notify USB host each time we receive 'set packet filter' request. This makes Mac OS X happy when it returns back from suspending. o Switch notify state after data is transferred, but not before. o Consider there is also Super Speed mode. o Do not set stall bit on any pipes in device mode as Mac OS X seems don't support it. In collaboration with: hselasky@ --- sys/dev/usb/net/if_cdce.c | 93 +++++++++++++++++++++++++++++---------- 1 file changed, 69 insertions(+), 24 deletions(-) diff --git a/sys/dev/usb/net/if_cdce.c b/sys/dev/usb/net/if_cdce.c index 76134baa10a8..6824fbcdf163 100644 --- a/sys/dev/usb/net/if_cdce.c +++ b/sys/dev/usb/net/if_cdce.c @@ -857,9 +857,12 @@ cdce_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); if (error != USB_ERR_CANCELLED) { - /* try to clear stall first */ - usbd_xfer_set_stall(xfer); - goto tr_setup; + if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) { + /* try to clear stall first */ + usbd_xfer_set_stall(xfer); + } else { + goto tr_setup; + } } break; } @@ -1024,10 +1027,12 @@ cdce_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) if (error != USB_ERR_CANCELLED) { tr_stall: - /* try to clear stall first */ - usbd_xfer_set_stall(xfer); - usbd_xfer_set_frames(xfer, 0); - usbd_transfer_submit(xfer); + if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) { + /* try to clear stall first */ + usbd_xfer_set_stall(xfer); + usbd_xfer_set_frames(xfer, 0); + usbd_transfer_submit(xfer); + } break; } @@ -1040,6 +1045,7 @@ cdce_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) static void cdce_intr_read_callback(struct usb_xfer *xfer, usb_error_t error) { + struct cdce_softc *sc = usbd_xfer_softc(xfer); int actlen; usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); @@ -1061,8 +1067,10 @@ cdce_intr_read_callback(struct usb_xfer *xfer, usb_error_t error) default: /* Error */ if (error != USB_ERR_CANCELLED) { /* start clear stall */ - usbd_xfer_set_stall(xfer); - goto tr_setup; + if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) + usbd_xfer_set_stall(xfer); + else + goto tr_setup; } break; } @@ -1084,6 +1092,17 @@ cdce_intr_write_callback(struct usb_xfer *xfer, usb_error_t error) DPRINTF("Transferred %d bytes\n", actlen); + switch (sc->sc_notify_state) { + case (CDCE_NOTIFY_NETWORK_CONNECTION): + sc->sc_notify_state = CDCE_NOTIFY_SPEED_CHANGE; + break; + case (CDCE_NOTIFY_SPEED_CHANGE): + sc->sc_notify_state = CDCE_NOTIFY_DONE; + break; + default: + break; + } + /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: @@ -1105,7 +1124,6 @@ cdce_intr_write_callback(struct usb_xfer *xfer, usb_error_t error) usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); usbd_xfer_set_frames(xfer, 1); usbd_transfer_submit(xfer); - sc->sc_notify_state = CDCE_NOTIFY_SPEED_CHANGE; } else if (sc->sc_notify_state == CDCE_NOTIFY_SPEED_CHANGE) { req.bmRequestType = UCDC_NOTIFICATION; @@ -1116,7 +1134,7 @@ cdce_intr_write_callback(struct usb_xfer *xfer, usb_error_t error) USETW(req.wLength, 8); /* Peak theoretical bulk trasfer rate in bits/s */ - if (usbd_get_speed(sc->sc_ue.ue_udev) == USB_SPEED_HIGH) + if (usbd_get_speed(sc->sc_ue.ue_udev) != USB_SPEED_FULL) speed = (13 * 512 * 8 * 1000 * 8); else speed = (19 * 64 * 1 * 1000 * 8); @@ -1129,15 +1147,17 @@ cdce_intr_write_callback(struct usb_xfer *xfer, usb_error_t error) usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); usbd_xfer_set_frames(xfer, 1); usbd_transfer_submit(xfer); - sc->sc_notify_state = CDCE_NOTIFY_DONE; } break; default: /* Error */ if (error != USB_ERR_CANCELLED) { - /* start clear stall */ - usbd_xfer_set_stall(xfer); - goto tr_setup; + if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) { + /* start clear stall */ + usbd_xfer_set_stall(xfer); + } else { + goto tr_setup; + } } break; } @@ -1145,9 +1165,30 @@ cdce_intr_write_callback(struct usb_xfer *xfer, usb_error_t error) static int cdce_handle_request(device_t dev, - const void *req, void **pptr, uint16_t *plen, + const void *preq, void **pptr, uint16_t *plen, uint16_t offset, uint8_t *pstate) { + struct cdce_softc *sc = device_get_softc(dev); + const struct usb_device_request *req = preq; + uint8_t is_complete = *pstate; + + /* + * When Mac OS X resumes after suspending it expects + * to be notified again after this request. + */ + if (req->bmRequestType == UT_WRITE_CLASS_INTERFACE && \ + req->bRequest == UCDC_NCM_SET_ETHERNET_PACKET_FILTER) { + + if (is_complete == 1) { + mtx_lock(&sc->sc_mtx); + sc->sc_notify_state = CDCE_NOTIFY_SPEED_CHANGE; + usbd_transfer_start(sc->sc_xfer[CDCE_INTR_TX]); + mtx_unlock(&sc->sc_mtx); + } + + return (0); + } + return (ENXIO); /* use builtin handler */ } @@ -1363,10 +1404,12 @@ cdce_ncm_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); if (error != USB_ERR_CANCELLED) { - /* try to clear stall first */ - usbd_xfer_set_stall(xfer); - usbd_xfer_set_frames(xfer, 0); - usbd_transfer_submit(xfer); + if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) { + /* try to clear stall first */ + usbd_xfer_set_stall(xfer); + usbd_xfer_set_frames(xfer, 0); + usbd_transfer_submit(xfer); + } } break; } @@ -1524,10 +1567,12 @@ cdce_ncm_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) if (error != USB_ERR_CANCELLED) { tr_stall: - /* try to clear stall first */ - usbd_xfer_set_stall(xfer); - usbd_xfer_set_frames(xfer, 0); - usbd_transfer_submit(xfer); + if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) { + /* try to clear stall first */ + usbd_xfer_set_stall(xfer); + usbd_xfer_set_frames(xfer, 0); + usbd_transfer_submit(xfer); + } } break; } From db4917fe678406724d297957c0af59ac37434b1a Mon Sep 17 00:00:00 2001 From: nwhitehorn Date: Tue, 20 Jan 2015 16:21:59 +0000 Subject: [PATCH 093/258] There does not seem to be any reason to acquire GIANT here. Follow amd64 in removing it. MFC after: 1 month --- sys/powerpc/powerpc/mem.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sys/powerpc/powerpc/mem.c b/sys/powerpc/powerpc/mem.c index 358871cbd55f..a7fbfa3edf84 100644 --- a/sys/powerpc/powerpc/mem.c +++ b/sys/powerpc/powerpc/mem.c @@ -100,8 +100,6 @@ memrw(struct cdev *dev, struct uio *uio, int flags) cnt = 0; error = 0; - GIANT_REQUIRED; - while (uio->uio_resid > 0 && !error) { iov = uio->uio_iov; if (iov->iov_len == 0) { From c8c1bd7911b30045e7d4cd9b70000bb68cf7b3f8 Mon Sep 17 00:00:00 2001 From: br Date: Tue, 20 Jan 2015 16:30:02 +0000 Subject: [PATCH 094/258] o Restore 'goto tr_setup;' when operating in host mode mistakenly removed in r277414. o Remove extra parentheses around cases. --- sys/dev/usb/net/if_cdce.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/sys/dev/usb/net/if_cdce.c b/sys/dev/usb/net/if_cdce.c index 6824fbcdf163..13fca9359f2b 100644 --- a/sys/dev/usb/net/if_cdce.c +++ b/sys/dev/usb/net/if_cdce.c @@ -860,9 +860,8 @@ cdce_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) { /* try to clear stall first */ usbd_xfer_set_stall(xfer); - } else { - goto tr_setup; } + goto tr_setup; } break; } @@ -1069,8 +1068,7 @@ cdce_intr_read_callback(struct usb_xfer *xfer, usb_error_t error) /* start clear stall */ if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) usbd_xfer_set_stall(xfer); - else - goto tr_setup; + goto tr_setup; } break; } @@ -1093,10 +1091,10 @@ cdce_intr_write_callback(struct usb_xfer *xfer, usb_error_t error) DPRINTF("Transferred %d bytes\n", actlen); switch (sc->sc_notify_state) { - case (CDCE_NOTIFY_NETWORK_CONNECTION): + case CDCE_NOTIFY_NETWORK_CONNECTION: sc->sc_notify_state = CDCE_NOTIFY_SPEED_CHANGE; break; - case (CDCE_NOTIFY_SPEED_CHANGE): + case CDCE_NOTIFY_SPEED_CHANGE: sc->sc_notify_state = CDCE_NOTIFY_DONE; break; default: @@ -1155,9 +1153,8 @@ cdce_intr_write_callback(struct usb_xfer *xfer, usb_error_t error) if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) { /* start clear stall */ usbd_xfer_set_stall(xfer); - } else { - goto tr_setup; } + goto tr_setup; } break; } From 667029aa90f1a067a6a2ef0a0cc5bdffe58edb8e Mon Sep 17 00:00:00 2001 From: sbruno Date: Tue, 20 Jan 2015 17:00:28 +0000 Subject: [PATCH 095/258] Allow clang to be built for mips/mips64 backend types by adding our mips triple ids This only allows testing and does not change the defaults for mips/mips64. They still build/use gcc by default. Differential Revision: https://reviews.freebsd.org/D1190 Reviewed by: dim --- contrib/llvm/tools/clang/lib/Driver/Tools.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/contrib/llvm/tools/clang/lib/Driver/Tools.cpp b/contrib/llvm/tools/clang/lib/Driver/Tools.cpp index 89db52e6071a..f33fb32b06af 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Tools.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Tools.cpp @@ -6587,6 +6587,17 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("elf32ppc_fbsd"); } + if (Arg *A = Args.getLastArg(options::OPT_G)) { + if (ToolChain.getArch() == llvm::Triple::mips || + ToolChain.getArch() == llvm::Triple::mipsel || + ToolChain.getArch() == llvm::Triple::mips64 || + ToolChain.getArch() == llvm::Triple::mips64el) { + StringRef v = A->getValue(); + CmdArgs.push_back(Args.MakeArgString("-G" + v)); + A->claim(); + } + } + if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); From a83608a7d8bce7208cebe4a09a5479c3bb71ff9f Mon Sep 17 00:00:00 2001 From: tuexen Date: Tue, 20 Jan 2015 19:08:55 +0000 Subject: [PATCH 096/258] Remove comparisons which are not necessary. Reported by: Coverity CID: 1237826, 1237844, 1237847 MFC after: 1 week --- sys/netinet/sctp_sysctl.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sys/netinet/sctp_sysctl.c b/sys/netinet/sctp_sysctl.c index 1ca5983f6848..285d7fb3f9b4 100644 --- a/sys/netinet/sctp_sysctl.c +++ b/sys/netinet/sctp_sysctl.c @@ -569,8 +569,12 @@ sctp_sysctl_handle_udp_tunneling(SYSCTL_HANDLER_ARGS) error = sysctl_handle_int(oidp, &new, 0, req); if ((error == 0) && (req->newptr != NULL)) { +#if (SCTPCTL_UDP_TUNNELING_PORT_MIN == 0) + if (new > SCTPCTL_UDP_TUNNELING_PORT_MAX) { +#else if ((new < SCTPCTL_UDP_TUNNELING_PORT_MIN) || (new > SCTPCTL_UDP_TUNNELING_PORT_MAX)) { +#endif error = EINVAL; } else { SCTP_INP_INFO_WLOCK(); @@ -598,9 +602,14 @@ sctp_sysctl_handle_auth(SYSCTL_HANDLER_ARGS) error = sysctl_handle_int(oidp, &new, 0, req); if ((error == 0) && (req->newptr != NULL)) { +#if (SCTPCTL_AUTH_ENABLE_MIN == 0) + if ((new > SCTPCTL_AUTH_ENABLE_MAX) || + ((new == 0) && (SCTP_BASE_SYSCTL(sctp_asconf_enable) == 1))) { +#else if ((new < SCTPCTL_AUTH_ENABLE_MIN) || (new > SCTPCTL_AUTH_ENABLE_MAX) || ((new == 0) && (SCTP_BASE_SYSCTL(sctp_asconf_enable) == 1))) { +#endif error = EINVAL; } else { SCTP_BASE_SYSCTL(sctp_auth_enable) = new; @@ -619,9 +628,14 @@ sctp_sysctl_handle_asconf(SYSCTL_HANDLER_ARGS) error = sysctl_handle_int(oidp, &new, 0, req); if ((error == 0) && (req->newptr != NULL)) { +#if (SCTPCTL_ASCONF_ENABLE_MIN == 0) + if ((new > SCTPCTL_ASCONF_ENABLE_MAX) || + ((new == 1) && (SCTP_BASE_SYSCTL(sctp_auth_enable) == 0))) { +#else if ((new < SCTPCTL_ASCONF_ENABLE_MIN) || (new > SCTPCTL_ASCONF_ENABLE_MAX) || ((new == 1) && (SCTP_BASE_SYSCTL(sctp_auth_enable) == 0))) { +#endif error = EINVAL; } else { SCTP_BASE_SYSCTL(sctp_asconf_enable) = new; From d8a01f771b23abe22fe19259e64e6c9cf443d5d3 Mon Sep 17 00:00:00 2001 From: delphij Date: Tue, 20 Jan 2015 20:36:36 +0000 Subject: [PATCH 097/258] MFV r277432: Plug various memory leaks in libzfs import implementation. Illumos issue: 5518 Memory leaks in libzfs import implementation MFC after: 2 weeks --- .../lib/libzfs/common/libzfs_import.c | 55 +++++++++++-------- .../lib/libzfs/common/libzfs_pool.c | 25 +++++---- 2 files changed, 47 insertions(+), 33 deletions(-) diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c index 67eba1b88eb7..c4e9adae98ab 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c @@ -18,10 +18,11 @@ * * CDDL HEADER END */ + /* + * Copyright 2015 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013 by Delphix. All rights reserved. - * Copyright 2014 Nexenta Systems, Inc. All rights reserved. */ /* @@ -198,8 +199,10 @@ fix_paths(nvlist_t *nv, name_entry_t *names) if ((devid = get_devid(best->ne_name)) == NULL) { (void) nvlist_remove_all(nv, ZPOOL_CONFIG_DEVID); } else { - if (nvlist_add_string(nv, ZPOOL_CONFIG_DEVID, devid) != 0) + if (nvlist_add_string(nv, ZPOOL_CONFIG_DEVID, devid) != 0) { + devid_str_free(devid); return (-1); + } devid_str_free(devid); } @@ -665,8 +668,10 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok) nvlist_add_uint64(holey, ZPOOL_CONFIG_ID, c) != 0 || nvlist_add_uint64(holey, - ZPOOL_CONFIG_GUID, 0ULL) != 0) + ZPOOL_CONFIG_GUID, 0ULL) != 0) { + nvlist_free(holey); goto nomem; + } child[c] = holey; } } @@ -1118,8 +1123,10 @@ zpool_clear_label(int fd) for (l = 0; l < VDEV_LABELS; l++) { if (pwrite64(fd, label, sizeof (vdev_label_t), - label_offset(size, l)) != sizeof (vdev_label_t)) + label_offset(size, l)) != sizeof (vdev_label_t)) { + free(label); return (-1); + } } free(label); @@ -1137,7 +1144,6 @@ static nvlist_t * zpool_find_import_impl(libzfs_handle_t *hdl, importargs_t *iarg) { int i, dirs = iarg->paths; - DIR *dirp = NULL; struct dirent64 *dp; char path[MAXPATHLEN]; char *end, **dir = iarg->path; @@ -1167,6 +1173,8 @@ zpool_find_import_impl(libzfs_handle_t *hdl, importargs_t *iarg) tpool_t *t; char *rdsk; int dfd; + boolean_t config_failed = B_FALSE; + DIR *dirp; /* use realpath to normalize the path */ if (realpath(dir[i], path) == 0) { @@ -1191,6 +1199,8 @@ zpool_find_import_impl(libzfs_handle_t *hdl, importargs_t *iarg) if ((dfd = open64(rdsk, O_RDONLY)) < 0 || (dirp = fdopendir(dfd)) == NULL) { + if (dfd >= 0) + (void) close(dfd); zfs_error_aux(hdl, strerror(errno)); (void) zfs_error_fmt(hdl, EZFS_BADPATH, dgettext(TEXT_DOMAIN, "cannot open '%s'"), @@ -1272,7 +1282,7 @@ zpool_find_import_impl(libzfs_handle_t *hdl, importargs_t *iarg) cookie = NULL; while ((slice = avl_destroy_nodes(&slice_cache, &cookie)) != NULL) { - if (slice->rn_config != NULL) { + if (slice->rn_config != NULL && !config_failed) { nvlist_t *config = slice->rn_config; boolean_t matched = B_TRUE; @@ -1293,13 +1303,16 @@ zpool_find_import_impl(libzfs_handle_t *hdl, importargs_t *iarg) } if (!matched) { nvlist_free(config); - config = NULL; - continue; + } else { + /* + * use the non-raw path for the config + */ + (void) strlcpy(end, slice->rn_name, + pathleft); + if (add_config(hdl, &pools, path, + config) != 0) + config_failed = B_TRUE; } - /* use the non-raw path for the config */ - (void) strlcpy(end, slice->rn_name, pathleft); - if (add_config(hdl, &pools, path, config) != 0) - goto error; } free(slice->rn_name); free(slice); @@ -1307,7 +1320,9 @@ zpool_find_import_impl(libzfs_handle_t *hdl, importargs_t *iarg) avl_destroy(&slice_cache); (void) closedir(dirp); - dirp = NULL; + + if (config_failed) + goto error; } ret = get_configs(hdl, &pools, iarg->can_be_active); @@ -1330,14 +1345,10 @@ zpool_find_import_impl(libzfs_handle_t *hdl, importargs_t *iarg) for (ne = pools.names; ne != NULL; ne = nenext) { nenext = ne->ne_next; - if (ne->ne_name) - free(ne->ne_name); + free(ne->ne_name); free(ne); } - if (dirp) - (void) closedir(dirp); - return (ret); } @@ -1695,9 +1706,9 @@ zpool_in_use(libzfs_handle_t *hdl, int fd, pool_state_t *state, char **namestr, cb.cb_type = ZPOOL_CONFIG_SPARES; if (zpool_iter(hdl, find_aux, &cb) == 1) { name = (char *)zpool_get_name(cb.cb_zhp); - ret = TRUE; + ret = B_TRUE; } else { - ret = FALSE; + ret = B_FALSE; } break; @@ -1711,9 +1722,9 @@ zpool_in_use(libzfs_handle_t *hdl, int fd, pool_state_t *state, char **namestr, cb.cb_type = ZPOOL_CONFIG_L2CACHE; if (zpool_iter(hdl, find_aux, &cb) == 1) { name = (char *)zpool_get_name(cb.cb_zhp); - ret = TRUE; + ret = B_TRUE; } else { - ret = FALSE; + ret = B_FALSE; } break; diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c index 78a34f931d67..b9db421dcbcf 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c @@ -20,8 +20,8 @@ */ /* + * Copyright 2015 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2011, 2014 by Delphix. All rights reserved. * Copyright (c) 2013, Joyent, Inc. All rights reserved. */ @@ -1715,7 +1715,7 @@ zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, thename = origname; } - if (props) { + if (props != NULL) { uint64_t version; prop_flags_t flags = { .create = B_FALSE, .import = B_TRUE }; @@ -1723,12 +1723,13 @@ zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, &version) == 0); if ((props = zpool_valid_proplist(hdl, origname, - props, version, flags, errbuf)) == NULL) { + props, version, flags, errbuf)) == NULL) return (-1); - } else if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { + if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { nvlist_free(props); return (-1); } + nvlist_free(props); } (void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name)); @@ -1737,11 +1738,11 @@ zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, &zc.zc_guid) == 0); if (zcmd_write_conf_nvlist(hdl, &zc, config) != 0) { - nvlist_free(props); + zcmd_free_nvlists(&zc); return (-1); } if (zcmd_alloc_dst_nvlist(hdl, &zc, zc.zc_nvlist_conf_size * 2) != 0) { - nvlist_free(props); + zcmd_free_nvlists(&zc); return (-1); } @@ -1757,6 +1758,9 @@ zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, error = errno; (void) zcmd_read_dst_nvlist(hdl, &zc, &nv); + + zcmd_free_nvlists(&zc); + zpool_get_rewind_policy(config, &policy); if (error) { @@ -1862,9 +1866,6 @@ zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, return (0); } - zcmd_free_nvlists(&zc); - nvlist_free(props); - return (ret); } @@ -3332,8 +3333,10 @@ devid_to_path(char *devid_str) if (ret != 0) return (NULL); - if ((path = strdup(list[0].devname)) == NULL) - return (NULL); + /* + * In a case the strdup() fails, we will just return NULL below. + */ + path = strdup(list[0].devname); devid_free_nmlist(list); From 4aade7954cad2265f804e1861c3a1e6fc3c0b808 Mon Sep 17 00:00:00 2001 From: will Date: Tue, 20 Jan 2015 21:15:33 +0000 Subject: [PATCH 098/258] Restore the CAM XPT peripheral generation counter, and export it via sysctl. Define it as an atomic uint32_t. These increments happen infrequently enough for the atomic overhead to be a problem, and since they're now independent atomics, they won't contend with xpt_lock_buses(). This counter is useful as a means of cheaply identifying whether any changes have been made to the CAM peripheral list. Userland programs have no guarantee that the counter won't change on them while being returned or while processing the information, so they must be written accordingly. Discussed with: ken, mav (in general) MFC after: 1 week Sponsored by: Spectra Logic --- sys/cam/cam_xpt.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c index f37bc0a890cd..33bc2ac17ca7 100644 --- a/sys/cam/cam_xpt.c +++ b/sys/cam/cam_xpt.c @@ -93,6 +93,8 @@ struct xpt_task { }; struct xpt_softc { + uint32_t xpt_generation; + /* number of high powered commands that can go through right now */ struct mtx xpt_highpower_lock; STAILQ_HEAD(highpowerlist, cam_ed) highpowerq; @@ -151,6 +153,8 @@ static struct xpt_softc xsoftc; SYSCTL_INT(_kern_cam, OID_AUTO, boot_delay, CTLFLAG_RDTUN, &xsoftc.boot_delay, 0, "Bus registration wait time"); +SYSCTL_UINT(_kern_cam, OID_AUTO, xpt_generation, CTLFLAG_RD, + &xsoftc.xpt_generation, 0, "CAM peripheral generation count"); struct cam_doneq { struct mtx_padalign cam_doneq_mtx; @@ -976,6 +980,7 @@ xpt_add_periph(struct cam_periph *periph) device->generation++; SLIST_INSERT_HEAD(&device->periphs, periph, periph_links); mtx_unlock(&device->target->bus->eb_mtx); + atomic_add_32(&xsoftc.xpt_generation, 1); } return (status); @@ -992,6 +997,7 @@ xpt_remove_periph(struct cam_periph *periph) device->generation++; SLIST_REMOVE(&device->periphs, periph, cam_periph, periph_links); mtx_unlock(&device->target->bus->eb_mtx); + atomic_add_32(&xsoftc.xpt_generation, 1); } } From 1fb64f35de7dc5faa60161e28b19621b3a515296 Mon Sep 17 00:00:00 2001 From: jbeich Date: Tue, 20 Jan 2015 21:49:50 +0000 Subject: [PATCH 099/258] - Add jbeich as a ports committer - List bapt and flo as his mentors Differential Revision: https://reviews.freebsd.org/D1562 Approved by: flo (mentor) --- share/misc/committers-ports.dot | 3 +++ 1 file changed, 3 insertions(+) diff --git a/share/misc/committers-ports.dot b/share/misc/committers-ports.dot index e97acba95840..00e85f755bfe 100644 --- a/share/misc/committers-ports.dot +++ b/share/misc/committers-ports.dot @@ -116,6 +116,7 @@ itetcu [label="Ion-Mihai Tetcu\nitetcu@FreeBSD.org\n2006/06/07"] jacula [label="Giuseppe Pilichi\njacula@FreeBSD.org\n2010/04/05"] jadawin [label="Philippe Audeoud\njadawin@FreeBSD.org\n2008/03/02"] jase [label="Jase Thew\njase@FreeBSD.org\n2012/05/30"] +jbeich [label="Jan Beich\njbeich@FreeBSD.org\n2015/01/19"] jgh [label="Jason Helfman\njgh@FreeBSD.org\n2011/12/16"] jhale [label="Jason E. Hale\njhale@FreeBSD.org\n2012/09/10"] jkim [label="Jung-uk Kim\njkim@FreeBSD.org\n2007/09/12"] @@ -267,6 +268,7 @@ bapt -> bdrewery bapt -> bofh bapt -> eadler bapt -> grembo +bapt -> jbeich bapt -> jlaffaye bapt -> marius bapt -> marino @@ -350,6 +352,7 @@ fjoe -> osa flo -> bar flo -> jase +flo -> jbeich flo -> grembo flz -> garga From 4bd09b7583b8b79b6d771f1449dcf6131a1a6738 Mon Sep 17 00:00:00 2001 From: will Date: Tue, 20 Jan 2015 22:27:45 +0000 Subject: [PATCH 100/258] Remove unused strdup() #define. --- sys/cddl/compat/opensolaris/sys/sunddi.h | 1 - 1 file changed, 1 deletion(-) diff --git a/sys/cddl/compat/opensolaris/sys/sunddi.h b/sys/cddl/compat/opensolaris/sys/sunddi.h index 63b8a8983df1..3a493b7f00d8 100644 --- a/sys/cddl/compat/opensolaris/sys/sunddi.h +++ b/sys/cddl/compat/opensolaris/sys/sunddi.h @@ -35,7 +35,6 @@ #include #include -#define strdup(ptr) strdup((ptr), M_SOLARIS) #define ddi_driver_major(zfs_dip) (0) #define ddi_copyin(from, to, size, flag) \ (copyin((from), (to), (size)), 0) From 3c6834bfdd1fd49f027cc3d8b162401169ebac98 Mon Sep 17 00:00:00 2001 From: will Date: Tue, 20 Jan 2015 22:29:27 +0000 Subject: [PATCH 101/258] NSEC_TO_TICK(usec) -> NSEC_TO_TICK(nsec) --- sys/cddl/compat/opensolaris/sys/time.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/cddl/compat/opensolaris/sys/time.h b/sys/cddl/compat/opensolaris/sys/time.h index fe4857ad1f92..b54780c45f39 100644 --- a/sys/cddl/compat/opensolaris/sys/time.h +++ b/sys/cddl/compat/opensolaris/sys/time.h @@ -51,7 +51,7 @@ typedef longlong_t hrtime_t; #endif #define SEC_TO_TICK(sec) ((sec) * hz) -#define NSEC_TO_TICK(usec) ((usec) / (NANOSEC / hz)) +#define NSEC_TO_TICK(nsec) ((nsec) / (NANOSEC / hz)) #ifdef _KERNEL static __inline hrtime_t From 559379347466b89c0d532c48e80d065b287402d7 Mon Sep 17 00:00:00 2001 From: will Date: Tue, 20 Jan 2015 22:31:26 +0000 Subject: [PATCH 102/258] Use the "zfs_gfs" tag for GFS vnodes to make them easier to identify. MFC after: 1 week Sponsored by: Spectra Logic --- sys/cddl/contrib/opensolaris/uts/common/fs/gfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/gfs.c b/sys/cddl/contrib/opensolaris/uts/common/fs/gfs.c index 2ff8df6ae894..89882f403f70 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/gfs.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/gfs.c @@ -489,7 +489,7 @@ gfs_file_create(size_t size, vnode_t *pvp, vfs_t *vfsp, vnodeops_t *ops) * Allocate vnode and internal data structure */ fp = kmem_zalloc(size, KM_SLEEP); - error = getnewvnode("zfs", vfsp, ops, &vp); + error = getnewvnode("zfs_gfs", vfsp, ops, &vp); ASSERT(error == 0); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); vp->v_data = (caddr_t)fp; From f9be6e3f2540ed668f64c0ebeb08e87aa2a7f2a5 Mon Sep 17 00:00:00 2001 From: will Date: Tue, 20 Jan 2015 22:39:10 +0000 Subject: [PATCH 103/258] Fix arc__shrink DTrace probe's to_free argument. Remove the unnecessary #ifdef _KERNEL, which did not differ in the true or false cases. Actually set the value of to_free before using it. MFC after: 1 week Sponsored by: Spectra Logic --- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c index 29e9eca56706..e180850a9369 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c @@ -2540,13 +2540,9 @@ arc_shrink(void) if (arc_c > arc_c_min) { uint64_t to_free; + to_free = arc_c >> arc_shrink_shift; DTRACE_PROBE4(arc__shrink, uint64_t, arc_c, uint64_t, arc_c_min, uint64_t, arc_p, uint64_t, to_free); -#ifdef _KERNEL - to_free = arc_c >> arc_shrink_shift; -#else - to_free = arc_c >> arc_shrink_shift; -#endif if (arc_c > arc_c_min + to_free) atomic_add_64(&arc_c, -to_free); else From e8c89293c35c4212733027029af488e6d52ff0d2 Mon Sep 17 00:00:00 2001 From: ngie Date: Tue, 20 Jan 2015 22:51:29 +0000 Subject: [PATCH 104/258] Garbage collect a prove test wrapper MFC after: 3 days Sponsored by: EMC / Isilon Storage Division --- tools/regression/lib/libc/stdio/test-fmemopen.t | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 tools/regression/lib/libc/stdio/test-fmemopen.t diff --git a/tools/regression/lib/libc/stdio/test-fmemopen.t b/tools/regression/lib/libc/stdio/test-fmemopen.t deleted file mode 100644 index bd5157b5d8f8..000000000000 --- a/tools/regression/lib/libc/stdio/test-fmemopen.t +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -echo 1..1 -if ./$executable; then - echo ok 1 - $executable successful -else - echo not ok 1 - $executable failed -fi From fd7fb7b57b7b64f2c0b58fb82d01605540b7916a Mon Sep 17 00:00:00 2001 From: ian Date: Tue, 20 Jan 2015 22:56:59 +0000 Subject: [PATCH 105/258] Add inline implementations of arm bus_space_read/write_N(). Reviewed by: cognet --- sys/arm/arm/bus_space-v6.c | 32 ++++++++++----------- sys/arm/include/bus.h | 58 +++++++++++++++++++++++++------------- 2 files changed, 54 insertions(+), 36 deletions(-) diff --git a/sys/arm/arm/bus_space-v6.c b/sys/arm/arm/bus_space-v6.c index d91306e1a1df..738e4c6fc362 100644 --- a/sys/arm/arm/bus_space-v6.c +++ b/sys/arm/arm/bus_space-v6.c @@ -65,10 +65,10 @@ static struct bus_space _base_tag = { generic_bs_barrier, /* read (single) */ - generic_bs_r_1, - generic_armv4_bs_r_2, - generic_bs_r_4, - NULL, + NULL, /* bs_r_1, Use inline code in bus.h */ + NULL, /* bs_r_2, Use inline code in bus.h */ + NULL, /* bs_r_4, Use inline code in bus.h */ + NULL, /* bs_r_8, Use inline code in bus.h */ /* read multiple */ generic_bs_rm_1, @@ -83,10 +83,10 @@ static struct bus_space _base_tag = { NULL, /* write (single) */ - generic_bs_w_1, - generic_armv4_bs_w_2, - generic_bs_w_4, - NULL, + NULL, /* bs_w_1, Use inline code in bus.h */ + NULL, /* bs_w_2, Use inline code in bus.h */ + NULL, /* bs_w_4, Use inline code in bus.h */ + NULL, /* bs_w_8, Use inline code in bus.h */ /* write multiple */ generic_bs_wm_1, @@ -119,10 +119,10 @@ static struct bus_space _base_tag = { NULL, /* read stream (single) */ - NULL, - NULL, - NULL, - NULL, + NULL, /* bs_r_1_s, Use inline code in bus.h */ + NULL, /* bs_r_2_s, Use inline code in bus.h */ + NULL, /* bs_r_4_s, Use inline code in bus.h */ + NULL, /* bs_r_8_s, Use inline code in bus.h */ /* read multiple stream */ NULL, @@ -137,10 +137,10 @@ static struct bus_space _base_tag = { NULL, /* write stream (single) */ - NULL, - NULL, - NULL, - NULL, + NULL, /* bs_w_1_s, Use inline code in bus.h */ + NULL, /* bs_w_2_s, Use inline code in bus.h */ + NULL, /* bs_w_4_s, Use inline code in bus.h */ + NULL, /* bs_w_8_s, Use inline code in bus.h */ /* write multiple stream */ NULL, diff --git a/sys/arm/include/bus.h b/sys/arm/include/bus.h index 0749838df8e4..f044bec4a0bf 100644 --- a/sys/arm/include/bus.h +++ b/sys/arm/include/bus.h @@ -252,10 +252,6 @@ struct bus_space { #define __bs_c(a,b) __CONCAT(a,b) #define __bs_opname(op,size) __bs_c(__bs_c(__bs_c(bs_,op),_),size) -#define __bs_rs(sz, t, h, o) \ - (*(t)->__bs_opname(r,sz))((t)->bs_cookie, h, o) -#define __bs_ws(sz, t, h, o, v) \ - (*(t)->__bs_opname(w,sz))((t)->bs_cookie, h, o, v) #define __bs_nonsingle(type, sz, t, h, o, a, c) \ (*(t)->__bs_opname(type,sz))((t)->bs_cookie, h, o, a, c) #define __bs_set(type, sz, t, h, o, v, c) \ @@ -272,6 +268,28 @@ struct bus_space { (*(t)->__bs_opname_s(type,sz))((t)->bs_cookie, h, o, a, c) +#define __generate_inline_bs_rs(IFN, MBR, TYP) \ + static inline TYP \ + IFN(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o) \ + { \ + \ + if (__predict_true(t->MBR == NULL)) \ + return (*(volatile TYP *)(h + o)); \ + else \ + return (t->MBR(t->bs_cookie, h, o)); \ + } + +#define __generate_inline_bs_ws(IFN, MBR, TYP) \ + static inline void \ + IFN(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, TYP v)\ + { \ + \ + if (__predict_true(t->MBR == NULL)) \ + *(volatile TYP *)(h + o) = v; \ + else \ + t->MBR(t->bs_cookie, h, o, v); \ + } + /* * Mapping and unmapping operations. */ @@ -304,15 +322,15 @@ struct bus_space { /* * Bus read (single) operations. */ -#define bus_space_read_1(t, h, o) __bs_rs(1,(t),(h),(o)) -#define bus_space_read_2(t, h, o) __bs_rs(2,(t),(h),(o)) -#define bus_space_read_4(t, h, o) __bs_rs(4,(t),(h),(o)) -#define bus_space_read_8(t, h, o) __bs_rs(8,(t),(h),(o)) +__generate_inline_bs_rs(bus_space_read_1, bs_r_1, uint8_t); +__generate_inline_bs_rs(bus_space_read_2, bs_r_2, uint16_t); +__generate_inline_bs_rs(bus_space_read_4, bs_r_4, uint32_t); +__generate_inline_bs_rs(bus_space_read_8, bs_r_8, uint64_t); -#define bus_space_read_stream_1(t, h, o) __bs_rs_s(1,(t), (h), (o)) -#define bus_space_read_stream_2(t, h, o) __bs_rs_s(2,(t), (h), (o)) -#define bus_space_read_stream_4(t, h, o) __bs_rs_s(4,(t), (h), (o)) -#define bus_space_read_stream_8(t, h, o) __bs_rs_s(8,8,(t),(h),(o)) +__generate_inline_bs_rs(bus_space_read_stream_1, bs_r_1_s, uint8_t); +__generate_inline_bs_rs(bus_space_read_stream_2, bs_r_2_s, uint16_t); +__generate_inline_bs_rs(bus_space_read_stream_4, bs_r_4_s, uint32_t); +__generate_inline_bs_rs(bus_space_read_stream_8, bs_r_8_s, uint64_t); /* * Bus read multiple operations. @@ -361,15 +379,15 @@ struct bus_space { /* * Bus write (single) operations. */ -#define bus_space_write_1(t, h, o, v) __bs_ws(1,(t),(h),(o),(v)) -#define bus_space_write_2(t, h, o, v) __bs_ws(2,(t),(h),(o),(v)) -#define bus_space_write_4(t, h, o, v) __bs_ws(4,(t),(h),(o),(v)) -#define bus_space_write_8(t, h, o, v) __bs_ws(8,(t),(h),(o),(v)) +__generate_inline_bs_ws(bus_space_write_1, bs_w_1, uint8_t); +__generate_inline_bs_ws(bus_space_write_2, bs_w_2, uint16_t); +__generate_inline_bs_ws(bus_space_write_4, bs_w_4, uint32_t); +__generate_inline_bs_ws(bus_space_write_8, bs_w_8, uint64_t); -#define bus_space_write_stream_1(t, h, o, v) __bs_ws_s(1,(t),(h),(o),(v)) -#define bus_space_write_stream_2(t, h, o, v) __bs_ws_s(2,(t),(h),(o),(v)) -#define bus_space_write_stream_4(t, h, o, v) __bs_ws_s(4,(t),(h),(o),(v)) -#define bus_space_write_stream_8(t, h, o, v) __bs_ws_s(8,(t),(h),(o),(v)) +__generate_inline_bs_ws(bus_space_write_stream_1, bs_w_1_s, uint8_t); +__generate_inline_bs_ws(bus_space_write_stream_2, bs_w_2_s, uint16_t); +__generate_inline_bs_ws(bus_space_write_stream_4, bs_w_4_s, uint32_t); +__generate_inline_bs_ws(bus_space_write_stream_8, bs_w_8_s, uint64_t); /* From c25b839fb87a16beaf55843df79865bc1ec5cae0 Mon Sep 17 00:00:00 2001 From: ian Date: Wed, 21 Jan 2015 01:06:08 +0000 Subject: [PATCH 106/258] Revise the arm bus_space implementation to avoid dereferencing the tag on every operation to retrieve the bs_cookie value almost nothing actually uses. The bus_space struct contains a private data pointer (poorly named bs_cookie, now renamed to bs_privdata) which is used only by a few old armv4 xscale implementations. The bus_space functions were all defined to take this value as the first parameter instead of the bus_space_tag_t, requiring all the inline macro and function expansions to dereference the tag to pass it to another function, which never uses it. Now all the functions take the tag as the first parameter and retrieve the privdata if they need it. Also fix a couple bus_space_unmap() implementations that were calling kva_free() instead of pmap_unmapdev(). Discussed with: cognet --- sys/arm/arm/bus_space_generic.c | 12 +- sys/arm/at91/at91.c | 19 +- sys/arm/include/bus.h | 416 +++++++++++----------- sys/arm/versatile/bus_space.c | 2 +- sys/arm/xilinx/zy7_bus_space.c | 2 +- sys/arm/xscale/i80321/i80321_space.c | 40 +-- sys/arm/xscale/i8134x/i81342_space.c | 30 +- sys/arm/xscale/ixp425/avila_ata.c | 38 +- sys/arm/xscale/ixp425/cambria_exp_space.c | 34 +- sys/arm/xscale/ixp425/ixp425_a4x_space.c | 2 +- sys/arm/xscale/ixp425/ixp425_pci_space.c | 151 ++++---- sys/arm/xscale/ixp425/ixp425_space.c | 2 +- sys/arm/xscale/pxa/pxa_space.c | 20 +- sys/dev/usb/controller/ehci_ixp4xx.c | 34 +- 14 files changed, 388 insertions(+), 414 deletions(-) diff --git a/sys/arm/arm/bus_space_generic.c b/sys/arm/arm/bus_space_generic.c index 35052ecf9904..2df18dc1510b 100644 --- a/sys/arm/arm/bus_space_generic.c +++ b/sys/arm/arm/bus_space_generic.c @@ -57,7 +57,7 @@ __FBSDID("$FreeBSD$"); bs_protos(generic); int -generic_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flags, +generic_bs_map(bus_space_tag_t t, bus_addr_t bpa, bus_size_t size, int flags, bus_space_handle_t *bshp) { void *va; @@ -74,7 +74,7 @@ generic_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flags, } int -generic_bs_alloc(void *t, bus_addr_t rstart, bus_addr_t rend, bus_size_t size, +generic_bs_alloc(bus_space_tag_t t, bus_addr_t rstart, bus_addr_t rend, bus_size_t size, bus_size_t alignment, bus_size_t boundary, int flags, bus_addr_t *bpap, bus_space_handle_t *bshp) { @@ -84,21 +84,21 @@ generic_bs_alloc(void *t, bus_addr_t rstart, bus_addr_t rend, bus_size_t size, void -generic_bs_unmap(void *t, bus_space_handle_t h, bus_size_t size) +generic_bs_unmap(bus_space_tag_t t, bus_space_handle_t h, bus_size_t size) { pmap_unmapdev((vm_offset_t)h, size); } void -generic_bs_free(void *t, bus_space_handle_t bsh, bus_size_t size) +generic_bs_free(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size) { panic("generic_bs_free(): not implemented"); } int -generic_bs_subregion(void *t, bus_space_handle_t bsh, bus_size_t offset, +generic_bs_subregion(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp) { @@ -107,7 +107,7 @@ generic_bs_subregion(void *t, bus_space_handle_t bsh, bus_size_t offset, } void -generic_bs_barrier(void *t, bus_space_handle_t bsh, bus_size_t offset, +generic_bs_barrier(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset, bus_size_t len, int flags) { diff --git a/sys/arm/at91/at91.c b/sys/arm/at91/at91.c index 1942389738b2..a8a1f5e4af3e 100644 --- a/sys/arm/at91/at91.c +++ b/sys/arm/at91/at91.c @@ -55,7 +55,7 @@ __FBSDID("$FreeBSD$"); uint32_t at91_master_clock; static int -at91_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flags, +at91_bs_map(bus_space_tag_t tag, bus_addr_t bpa, bus_size_t size, int flags, bus_space_handle_t *bshp) { vm_paddr_t pa, endpa; @@ -77,23 +77,18 @@ at91_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flags, } static void -at91_bs_unmap(void *t, bus_space_handle_t h, bus_size_t size) +at91_bs_unmap(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t size) { - vm_offset_t va, endva; + vm_offset_t va; - if (t == 0) - return; - va = trunc_page((vm_offset_t)t); + va = (vm_offset_t)h; if (va >= AT91_BASE && va <= AT91_BASE + 0xff00000) return; - endva = round_page((vm_offset_t)t + size); - - /* Free the kernel virtual mapping. */ - kva_free(va, endva - va); + pmap_unmapdev(va, size); } static int -at91_bs_subregion(void *t, bus_space_handle_t bsh, bus_size_t offset, +at91_bs_subregion(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp) { @@ -102,7 +97,7 @@ at91_bs_subregion(void *t, bus_space_handle_t bsh, bus_size_t offset, } static void -at91_barrier(void *t, bus_space_handle_t bsh, bus_size_t size, bus_size_t b, +at91_barrier(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t size, bus_size_t b, int a) { } diff --git a/sys/arm/include/bus.h b/sys/arm/include/bus.h index f044bec4a0bf..f9a677e4f263 100644 --- a/sys/arm/include/bus.h +++ b/sys/arm/include/bus.h @@ -81,168 +81,168 @@ struct bus_space { /* cookie */ - void *bs_cookie; + void *bs_privdata; /* mapping/unmapping */ - int (*bs_map) (void *, bus_addr_t, bus_size_t, + int (*bs_map) (bus_space_tag_t, bus_addr_t, bus_size_t, int, bus_space_handle_t *); - void (*bs_unmap) (void *, bus_space_handle_t, bus_size_t); - int (*bs_subregion) (void *, bus_space_handle_t, + void (*bs_unmap) (bus_space_tag_t, bus_space_handle_t, bus_size_t); + int (*bs_subregion) (bus_space_tag_t, bus_space_handle_t, bus_size_t, bus_size_t, bus_space_handle_t *); /* allocation/deallocation */ - int (*bs_alloc) (void *, bus_addr_t, bus_addr_t, + int (*bs_alloc) (bus_space_tag_t, bus_addr_t, bus_addr_t, bus_size_t, bus_size_t, bus_size_t, int, bus_addr_t *, bus_space_handle_t *); - void (*bs_free) (void *, bus_space_handle_t, + void (*bs_free) (bus_space_tag_t, bus_space_handle_t, bus_size_t); /* get kernel virtual address */ /* barrier */ - void (*bs_barrier) (void *, bus_space_handle_t, + void (*bs_barrier) (bus_space_tag_t, bus_space_handle_t, bus_size_t, bus_size_t, int); /* read (single) */ - u_int8_t (*bs_r_1) (void *, bus_space_handle_t, bus_size_t); - u_int16_t (*bs_r_2) (void *, bus_space_handle_t, bus_size_t); - u_int32_t (*bs_r_4) (void *, bus_space_handle_t, bus_size_t); - u_int64_t (*bs_r_8) (void *, bus_space_handle_t, bus_size_t); + uint8_t (*bs_r_1) (bus_space_tag_t, bus_space_handle_t, bus_size_t); + uint16_t (*bs_r_2) (bus_space_tag_t, bus_space_handle_t, bus_size_t); + uint32_t (*bs_r_4) (bus_space_tag_t, bus_space_handle_t, bus_size_t); + uint64_t (*bs_r_8) (bus_space_tag_t, bus_space_handle_t, bus_size_t); /* read multiple */ - void (*bs_rm_1) (void *, bus_space_handle_t, bus_size_t, - u_int8_t *, bus_size_t); - void (*bs_rm_2) (void *, bus_space_handle_t, bus_size_t, - u_int16_t *, bus_size_t); - void (*bs_rm_4) (void *, bus_space_handle_t, - bus_size_t, u_int32_t *, bus_size_t); - void (*bs_rm_8) (void *, bus_space_handle_t, - bus_size_t, u_int64_t *, bus_size_t); + void (*bs_rm_1) (bus_space_tag_t, bus_space_handle_t, bus_size_t, + uint8_t *, bus_size_t); + void (*bs_rm_2) (bus_space_tag_t, bus_space_handle_t, bus_size_t, + uint16_t *, bus_size_t); + void (*bs_rm_4) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint32_t *, bus_size_t); + void (*bs_rm_8) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint64_t *, bus_size_t); /* read region */ - void (*bs_rr_1) (void *, bus_space_handle_t, - bus_size_t, u_int8_t *, bus_size_t); - void (*bs_rr_2) (void *, bus_space_handle_t, - bus_size_t, u_int16_t *, bus_size_t); - void (*bs_rr_4) (void *, bus_space_handle_t, - bus_size_t, u_int32_t *, bus_size_t); - void (*bs_rr_8) (void *, bus_space_handle_t, - bus_size_t, u_int64_t *, bus_size_t); + void (*bs_rr_1) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint8_t *, bus_size_t); + void (*bs_rr_2) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint16_t *, bus_size_t); + void (*bs_rr_4) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint32_t *, bus_size_t); + void (*bs_rr_8) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint64_t *, bus_size_t); /* write (single) */ - void (*bs_w_1) (void *, bus_space_handle_t, - bus_size_t, u_int8_t); - void (*bs_w_2) (void *, bus_space_handle_t, - bus_size_t, u_int16_t); - void (*bs_w_4) (void *, bus_space_handle_t, - bus_size_t, u_int32_t); - void (*bs_w_8) (void *, bus_space_handle_t, - bus_size_t, u_int64_t); + void (*bs_w_1) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint8_t); + void (*bs_w_2) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint16_t); + void (*bs_w_4) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint32_t); + void (*bs_w_8) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint64_t); /* write multiple */ - void (*bs_wm_1) (void *, bus_space_handle_t, - bus_size_t, const u_int8_t *, bus_size_t); - void (*bs_wm_2) (void *, bus_space_handle_t, - bus_size_t, const u_int16_t *, bus_size_t); - void (*bs_wm_4) (void *, bus_space_handle_t, - bus_size_t, const u_int32_t *, bus_size_t); - void (*bs_wm_8) (void *, bus_space_handle_t, - bus_size_t, const u_int64_t *, bus_size_t); + void (*bs_wm_1) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, const uint8_t *, bus_size_t); + void (*bs_wm_2) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, const uint16_t *, bus_size_t); + void (*bs_wm_4) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, const uint32_t *, bus_size_t); + void (*bs_wm_8) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, const uint64_t *, bus_size_t); /* write region */ - void (*bs_wr_1) (void *, bus_space_handle_t, - bus_size_t, const u_int8_t *, bus_size_t); - void (*bs_wr_2) (void *, bus_space_handle_t, - bus_size_t, const u_int16_t *, bus_size_t); - void (*bs_wr_4) (void *, bus_space_handle_t, - bus_size_t, const u_int32_t *, bus_size_t); - void (*bs_wr_8) (void *, bus_space_handle_t, - bus_size_t, const u_int64_t *, bus_size_t); + void (*bs_wr_1) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, const uint8_t *, bus_size_t); + void (*bs_wr_2) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, const uint16_t *, bus_size_t); + void (*bs_wr_4) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, const uint32_t *, bus_size_t); + void (*bs_wr_8) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, const uint64_t *, bus_size_t); /* set multiple */ - void (*bs_sm_1) (void *, bus_space_handle_t, - bus_size_t, u_int8_t, bus_size_t); - void (*bs_sm_2) (void *, bus_space_handle_t, - bus_size_t, u_int16_t, bus_size_t); - void (*bs_sm_4) (void *, bus_space_handle_t, - bus_size_t, u_int32_t, bus_size_t); - void (*bs_sm_8) (void *, bus_space_handle_t, - bus_size_t, u_int64_t, bus_size_t); + void (*bs_sm_1) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint8_t, bus_size_t); + void (*bs_sm_2) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint16_t, bus_size_t); + void (*bs_sm_4) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint32_t, bus_size_t); + void (*bs_sm_8) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint64_t, bus_size_t); /* set region */ - void (*bs_sr_1) (void *, bus_space_handle_t, - bus_size_t, u_int8_t, bus_size_t); - void (*bs_sr_2) (void *, bus_space_handle_t, - bus_size_t, u_int16_t, bus_size_t); - void (*bs_sr_4) (void *, bus_space_handle_t, - bus_size_t, u_int32_t, bus_size_t); - void (*bs_sr_8) (void *, bus_space_handle_t, - bus_size_t, u_int64_t, bus_size_t); + void (*bs_sr_1) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint8_t, bus_size_t); + void (*bs_sr_2) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint16_t, bus_size_t); + void (*bs_sr_4) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint32_t, bus_size_t); + void (*bs_sr_8) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint64_t, bus_size_t); /* copy */ - void (*bs_c_1) (void *, bus_space_handle_t, bus_size_t, + void (*bs_c_1) (bus_space_tag_t, bus_space_handle_t, bus_size_t, bus_space_handle_t, bus_size_t, bus_size_t); - void (*bs_c_2) (void *, bus_space_handle_t, bus_size_t, + void (*bs_c_2) (bus_space_tag_t, bus_space_handle_t, bus_size_t, bus_space_handle_t, bus_size_t, bus_size_t); - void (*bs_c_4) (void *, bus_space_handle_t, bus_size_t, + void (*bs_c_4) (bus_space_tag_t, bus_space_handle_t, bus_size_t, bus_space_handle_t, bus_size_t, bus_size_t); - void (*bs_c_8) (void *, bus_space_handle_t, bus_size_t, + void (*bs_c_8) (bus_space_tag_t, bus_space_handle_t, bus_size_t, bus_space_handle_t, bus_size_t, bus_size_t); /* read stream (single) */ - u_int8_t (*bs_r_1_s) (void *, bus_space_handle_t, bus_size_t); - u_int16_t (*bs_r_2_s) (void *, bus_space_handle_t, bus_size_t); - u_int32_t (*bs_r_4_s) (void *, bus_space_handle_t, bus_size_t); - u_int64_t (*bs_r_8_s) (void *, bus_space_handle_t, bus_size_t); + uint8_t (*bs_r_1_s) (bus_space_tag_t, bus_space_handle_t, bus_size_t); + uint16_t (*bs_r_2_s) (bus_space_tag_t, bus_space_handle_t, bus_size_t); + uint32_t (*bs_r_4_s) (bus_space_tag_t, bus_space_handle_t, bus_size_t); + uint64_t (*bs_r_8_s) (bus_space_tag_t, bus_space_handle_t, bus_size_t); /* read multiple stream */ - void (*bs_rm_1_s) (void *, bus_space_handle_t, bus_size_t, - u_int8_t *, bus_size_t); - void (*bs_rm_2_s) (void *, bus_space_handle_t, bus_size_t, - u_int16_t *, bus_size_t); - void (*bs_rm_4_s) (void *, bus_space_handle_t, - bus_size_t, u_int32_t *, bus_size_t); - void (*bs_rm_8_s) (void *, bus_space_handle_t, - bus_size_t, u_int64_t *, bus_size_t); + void (*bs_rm_1_s) (bus_space_tag_t, bus_space_handle_t, bus_size_t, + uint8_t *, bus_size_t); + void (*bs_rm_2_s) (bus_space_tag_t, bus_space_handle_t, bus_size_t, + uint16_t *, bus_size_t); + void (*bs_rm_4_s) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint32_t *, bus_size_t); + void (*bs_rm_8_s) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint64_t *, bus_size_t); /* read region stream */ - void (*bs_rr_1_s) (void *, bus_space_handle_t, - bus_size_t, u_int8_t *, bus_size_t); - void (*bs_rr_2_s) (void *, bus_space_handle_t, - bus_size_t, u_int16_t *, bus_size_t); - void (*bs_rr_4_s) (void *, bus_space_handle_t, - bus_size_t, u_int32_t *, bus_size_t); - void (*bs_rr_8_s) (void *, bus_space_handle_t, - bus_size_t, u_int64_t *, bus_size_t); + void (*bs_rr_1_s) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint8_t *, bus_size_t); + void (*bs_rr_2_s) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint16_t *, bus_size_t); + void (*bs_rr_4_s) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint32_t *, bus_size_t); + void (*bs_rr_8_s) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint64_t *, bus_size_t); /* write stream (single) */ - void (*bs_w_1_s) (void *, bus_space_handle_t, - bus_size_t, u_int8_t); - void (*bs_w_2_s) (void *, bus_space_handle_t, - bus_size_t, u_int16_t); - void (*bs_w_4_s) (void *, bus_space_handle_t, - bus_size_t, u_int32_t); - void (*bs_w_8_s) (void *, bus_space_handle_t, - bus_size_t, u_int64_t); + void (*bs_w_1_s) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint8_t); + void (*bs_w_2_s) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint16_t); + void (*bs_w_4_s) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint32_t); + void (*bs_w_8_s) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint64_t); /* write multiple stream */ - void (*bs_wm_1_s) (void *, bus_space_handle_t, - bus_size_t, const u_int8_t *, bus_size_t); - void (*bs_wm_2_s) (void *, bus_space_handle_t, - bus_size_t, const u_int16_t *, bus_size_t); - void (*bs_wm_4_s) (void *, bus_space_handle_t, - bus_size_t, const u_int32_t *, bus_size_t); - void (*bs_wm_8_s) (void *, bus_space_handle_t, - bus_size_t, const u_int64_t *, bus_size_t); + void (*bs_wm_1_s) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, const uint8_t *, bus_size_t); + void (*bs_wm_2_s) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, const uint16_t *, bus_size_t); + void (*bs_wm_4_s) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, const uint32_t *, bus_size_t); + void (*bs_wm_8_s) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, const uint64_t *, bus_size_t); /* write region stream */ - void (*bs_wr_1_s) (void *, bus_space_handle_t, - bus_size_t, const u_int8_t *, bus_size_t); - void (*bs_wr_2_s) (void *, bus_space_handle_t, - bus_size_t, const u_int16_t *, bus_size_t); - void (*bs_wr_4_s) (void *, bus_space_handle_t, - bus_size_t, const u_int32_t *, bus_size_t); - void (*bs_wr_8_s) (void *, bus_space_handle_t, - bus_size_t, const u_int64_t *, bus_size_t); + void (*bs_wr_1_s) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, const uint8_t *, bus_size_t); + void (*bs_wr_2_s) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, const uint16_t *, bus_size_t); + void (*bs_wr_4_s) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, const uint32_t *, bus_size_t); + void (*bs_wr_8_s) (bus_space_tag_t, bus_space_handle_t, + bus_size_t, const uint64_t *, bus_size_t); }; @@ -253,19 +253,19 @@ struct bus_space { #define __bs_opname(op,size) __bs_c(__bs_c(__bs_c(bs_,op),_),size) #define __bs_nonsingle(type, sz, t, h, o, a, c) \ - (*(t)->__bs_opname(type,sz))((t)->bs_cookie, h, o, a, c) + (*(t)->__bs_opname(type,sz))((t), h, o, a, c) #define __bs_set(type, sz, t, h, o, v, c) \ - (*(t)->__bs_opname(type,sz))((t)->bs_cookie, h, o, v, c) + (*(t)->__bs_opname(type,sz))((t), h, o, v, c) #define __bs_copy(sz, t, h1, o1, h2, o2, cnt) \ - (*(t)->__bs_opname(c,sz))((t)->bs_cookie, h1, o1, h2, o2, cnt) + (*(t)->__bs_opname(c,sz))((t), h1, o1, h2, o2, cnt) #define __bs_opname_s(op,size) __bs_c(__bs_c(__bs_c(__bs_c(bs_,op),_),size),_s) #define __bs_rs_s(sz, t, h, o) \ - (*(t)->__bs_opname_s(r,sz))((t)->bs_cookie, h, o) + (*(t)->__bs_opname_s(r,sz))((t), h, o) #define __bs_ws_s(sz, t, h, o, v) \ - (*(t)->__bs_opname_s(w,sz))((t)->bs_cookie, h, o, v) + (*(t)->__bs_opname_s(w,sz))((t), h, o, v) #define __bs_nonsingle_s(type, sz, t, h, o, a, c) \ - (*(t)->__bs_opname_s(type,sz))((t)->bs_cookie, h, o, a, c) + (*(t)->__bs_opname_s(type,sz))((t), h, o, a, c) #define __generate_inline_bs_rs(IFN, MBR, TYP) \ @@ -276,7 +276,7 @@ struct bus_space { if (__predict_true(t->MBR == NULL)) \ return (*(volatile TYP *)(h + o)); \ else \ - return (t->MBR(t->bs_cookie, h, o)); \ + return (t->MBR(t, h, o)); \ } #define __generate_inline_bs_ws(IFN, MBR, TYP) \ @@ -287,34 +287,34 @@ struct bus_space { if (__predict_true(t->MBR == NULL)) \ *(volatile TYP *)(h + o) = v; \ else \ - t->MBR(t->bs_cookie, h, o, v); \ + t->MBR(t, h, o, v); \ } /* * Mapping and unmapping operations. */ #define bus_space_map(t, a, s, c, hp) \ - (*(t)->bs_map)((t)->bs_cookie, (a), (s), (c), (hp)) + (*(t)->bs_map)((t), (a), (s), (c), (hp)) #define bus_space_unmap(t, h, s) \ - (*(t)->bs_unmap)((t)->bs_cookie, (h), (s)) + (*(t)->bs_unmap)((t), (h), (s)) #define bus_space_subregion(t, h, o, s, hp) \ - (*(t)->bs_subregion)((t)->bs_cookie, (h), (o), (s), (hp)) + (*(t)->bs_subregion)((t), (h), (o), (s), (hp)) /* * Allocation and deallocation operations. */ #define bus_space_alloc(t, rs, re, s, a, b, c, ap, hp) \ - (*(t)->bs_alloc)((t)->bs_cookie, (rs), (re), (s), (a), (b), \ + (*(t)->bs_alloc)((t), (rs), (re), (s), (a), (b), \ (c), (ap), (hp)) #define bus_space_free(t, h, s) \ - (*(t)->bs_free)((t)->bs_cookie, (h), (s)) + (*(t)->bs_free)((t), (h), (s)) /* * Bus barrier operations. */ #define bus_space_barrier(t, h, o, l, f) \ - (*(t)->bs_barrier)((t)->bs_cookie, (h), (o), (l), (f)) + (*(t)->bs_barrier)((t), (h), (o), (l), (f)) #define BUS_SPACE_BARRIER_READ 0x01 #define BUS_SPACE_BARRIER_WRITE 0x02 @@ -478,204 +478,204 @@ __generate_inline_bs_ws(bus_space_write_stream_8, bs_w_8_s, uint64_t); */ #define bs_map_proto(f) \ -int __bs_c(f,_bs_map) (void *t, bus_addr_t addr, \ +int __bs_c(f,_bs_map) (bus_space_tag_t t, bus_addr_t addr, \ bus_size_t size, int cacheable, bus_space_handle_t *bshp); #define bs_unmap_proto(f) \ -void __bs_c(f,_bs_unmap) (void *t, bus_space_handle_t bsh, \ +void __bs_c(f,_bs_unmap) (bus_space_tag_t t, bus_space_handle_t bsh, \ bus_size_t size); #define bs_subregion_proto(f) \ -int __bs_c(f,_bs_subregion) (void *t, bus_space_handle_t bsh, \ +int __bs_c(f,_bs_subregion) (bus_space_tag_t t, bus_space_handle_t bsh, \ bus_size_t offset, bus_size_t size, \ bus_space_handle_t *nbshp); #define bs_alloc_proto(f) \ -int __bs_c(f,_bs_alloc) (void *t, bus_addr_t rstart, \ +int __bs_c(f,_bs_alloc) (bus_space_tag_t t, bus_addr_t rstart, \ bus_addr_t rend, bus_size_t size, bus_size_t align, \ bus_size_t boundary, int cacheable, bus_addr_t *addrp, \ bus_space_handle_t *bshp); #define bs_free_proto(f) \ -void __bs_c(f,_bs_free) (void *t, bus_space_handle_t bsh, \ +void __bs_c(f,_bs_free) (bus_space_tag_t t, bus_space_handle_t bsh, \ bus_size_t size); #define bs_mmap_proto(f) \ int __bs_c(f,_bs_mmap) (struct cdev *, vm_offset_t, vm_paddr_t *, int); #define bs_barrier_proto(f) \ -void __bs_c(f,_bs_barrier) (void *t, bus_space_handle_t bsh, \ +void __bs_c(f,_bs_barrier) (bus_space_tag_t t, bus_space_handle_t bsh, \ bus_size_t offset, bus_size_t len, int flags); #define bs_r_1_proto(f) \ -u_int8_t __bs_c(f,_bs_r_1) (void *t, bus_space_handle_t bsh, \ +uint8_t __bs_c(f,_bs_r_1) (bus_space_tag_t t, bus_space_handle_t bsh, \ bus_size_t offset); #define bs_r_2_proto(f) \ -u_int16_t __bs_c(f,_bs_r_2) (void *t, bus_space_handle_t bsh, \ +uint16_t __bs_c(f,_bs_r_2) (bus_space_tag_t t, bus_space_handle_t bsh, \ bus_size_t offset); #define bs_r_4_proto(f) \ -u_int32_t __bs_c(f,_bs_r_4) (void *t, bus_space_handle_t bsh, \ +uint32_t __bs_c(f,_bs_r_4) (bus_space_tag_t t, bus_space_handle_t bsh, \ bus_size_t offset); #define bs_r_8_proto(f) \ -u_int64_t __bs_c(f,_bs_r_8) (void *t, bus_space_handle_t bsh, \ +uint64_t __bs_c(f,_bs_r_8) (bus_space_tag_t t, bus_space_handle_t bsh, \ bus_size_t offset); #define bs_r_1_s_proto(f) \ -u_int8_t __bs_c(f,_bs_r_1_s) (void *t, bus_space_handle_t bsh, \ +uint8_t __bs_c(f,_bs_r_1_s) (bus_space_tag_t t, bus_space_handle_t bsh, \ bus_size_t offset); #define bs_r_2_s_proto(f) \ -u_int16_t __bs_c(f,_bs_r_2_s) (void *t, bus_space_handle_t bsh, \ +uint16_t __bs_c(f,_bs_r_2_s) (bus_space_tag_t t, bus_space_handle_t bsh, \ bus_size_t offset); #define bs_r_4_s_proto(f) \ -u_int32_t __bs_c(f,_bs_r_4_s) (void *t, bus_space_handle_t bsh, \ +uint32_t __bs_c(f,_bs_r_4_s) (bus_space_tag_t t, bus_space_handle_t bsh, \ bus_size_t offset); #define bs_w_1_proto(f) \ -void __bs_c(f,_bs_w_1) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, u_int8_t value); +void __bs_c(f,_bs_w_1) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, uint8_t value); #define bs_w_2_proto(f) \ -void __bs_c(f,_bs_w_2) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, u_int16_t value); +void __bs_c(f,_bs_w_2) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, uint16_t value); #define bs_w_4_proto(f) \ -void __bs_c(f,_bs_w_4) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, u_int32_t value); +void __bs_c(f,_bs_w_4) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, uint32_t value); #define bs_w_8_proto(f) \ -void __bs_c(f,_bs_w_8) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, u_int64_t value); +void __bs_c(f,_bs_w_8) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, uint64_t value); #define bs_w_1_s_proto(f) \ -void __bs_c(f,_bs_w_1_s) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, u_int8_t value); +void __bs_c(f,_bs_w_1_s) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, uint8_t value); #define bs_w_2_s_proto(f) \ -void __bs_c(f,_bs_w_2_s) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, u_int16_t value); +void __bs_c(f,_bs_w_2_s) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, uint16_t value); #define bs_w_4_s_proto(f) \ -void __bs_c(f,_bs_w_4_s) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, u_int32_t value); +void __bs_c(f,_bs_w_4_s) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, uint32_t value); #define bs_rm_1_proto(f) \ -void __bs_c(f,_bs_rm_1) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, u_int8_t *addr, bus_size_t count); +void __bs_c(f,_bs_rm_1) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, uint8_t *addr, bus_size_t count); #define bs_rm_2_proto(f) \ -void __bs_c(f,_bs_rm_2) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, u_int16_t *addr, bus_size_t count); +void __bs_c(f,_bs_rm_2) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, uint16_t *addr, bus_size_t count); #define bs_rm_4_proto(f) \ -void __bs_c(f,_bs_rm_4) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, u_int32_t *addr, bus_size_t count); +void __bs_c(f,_bs_rm_4) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, uint32_t *addr, bus_size_t count); #define bs_rm_8_proto(f) \ -void __bs_c(f,_bs_rm_8) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, u_int64_t *addr, bus_size_t count); +void __bs_c(f,_bs_rm_8) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, uint64_t *addr, bus_size_t count); #define bs_wm_1_proto(f) \ -void __bs_c(f,_bs_wm_1) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, const u_int8_t *addr, bus_size_t count); +void __bs_c(f,_bs_wm_1) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, const uint8_t *addr, bus_size_t count); #define bs_wm_2_proto(f) \ -void __bs_c(f,_bs_wm_2) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, const u_int16_t *addr, bus_size_t count); +void __bs_c(f,_bs_wm_2) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, const uint16_t *addr, bus_size_t count); #define bs_wm_4_proto(f) \ -void __bs_c(f,_bs_wm_4) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, const u_int32_t *addr, bus_size_t count); +void __bs_c(f,_bs_wm_4) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, const uint32_t *addr, bus_size_t count); #define bs_wm_8_proto(f) \ -void __bs_c(f,_bs_wm_8) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, const u_int64_t *addr, bus_size_t count); +void __bs_c(f,_bs_wm_8) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, const uint64_t *addr, bus_size_t count); #define bs_rr_1_proto(f) \ -void __bs_c(f, _bs_rr_1) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, u_int8_t *addr, bus_size_t count); +void __bs_c(f, _bs_rr_1) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, uint8_t *addr, bus_size_t count); #define bs_rr_2_proto(f) \ -void __bs_c(f, _bs_rr_2) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, u_int16_t *addr, bus_size_t count); +void __bs_c(f, _bs_rr_2) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, uint16_t *addr, bus_size_t count); #define bs_rr_4_proto(f) \ -void __bs_c(f, _bs_rr_4) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, u_int32_t *addr, bus_size_t count); +void __bs_c(f, _bs_rr_4) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, uint32_t *addr, bus_size_t count); #define bs_rr_8_proto(f) \ -void __bs_c(f, _bs_rr_8) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, u_int64_t *addr, bus_size_t count); +void __bs_c(f, _bs_rr_8) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, uint64_t *addr, bus_size_t count); #define bs_wr_1_proto(f) \ -void __bs_c(f, _bs_wr_1) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, const u_int8_t *addr, bus_size_t count); +void __bs_c(f, _bs_wr_1) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, const uint8_t *addr, bus_size_t count); #define bs_wr_2_proto(f) \ -void __bs_c(f, _bs_wr_2) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, const u_int16_t *addr, bus_size_t count); +void __bs_c(f, _bs_wr_2) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, const uint16_t *addr, bus_size_t count); #define bs_wr_4_proto(f) \ -void __bs_c(f, _bs_wr_4) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, const u_int32_t *addr, bus_size_t count); +void __bs_c(f, _bs_wr_4) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, const uint32_t *addr, bus_size_t count); #define bs_wr_8_proto(f) \ -void __bs_c(f, _bs_wr_8) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, const u_int64_t *addr, bus_size_t count); +void __bs_c(f, _bs_wr_8) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, const uint64_t *addr, bus_size_t count); #define bs_sm_1_proto(f) \ -void __bs_c(f,_bs_sm_1) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, u_int8_t value, bus_size_t count); +void __bs_c(f,_bs_sm_1) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, uint8_t value, bus_size_t count); #define bs_sm_2_proto(f) \ -void __bs_c(f,_bs_sm_2) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, u_int16_t value, bus_size_t count); +void __bs_c(f,_bs_sm_2) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, uint16_t value, bus_size_t count); #define bs_sm_4_proto(f) \ -void __bs_c(f,_bs_sm_4) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, u_int32_t value, bus_size_t count); +void __bs_c(f,_bs_sm_4) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, uint32_t value, bus_size_t count); #define bs_sm_8_proto(f) \ -void __bs_c(f,_bs_sm_8) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, u_int64_t value, bus_size_t count); +void __bs_c(f,_bs_sm_8) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, uint64_t value, bus_size_t count); #define bs_sr_1_proto(f) \ -void __bs_c(f,_bs_sr_1) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, u_int8_t value, bus_size_t count); +void __bs_c(f,_bs_sr_1) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, uint8_t value, bus_size_t count); #define bs_sr_2_proto(f) \ -void __bs_c(f,_bs_sr_2) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, u_int16_t value, bus_size_t count); +void __bs_c(f,_bs_sr_2) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, uint16_t value, bus_size_t count); #define bs_sr_4_proto(f) \ -void __bs_c(f,_bs_sr_4) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, u_int32_t value, bus_size_t count); +void __bs_c(f,_bs_sr_4) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, uint32_t value, bus_size_t count); #define bs_sr_8_proto(f) \ -void __bs_c(f,_bs_sr_8) (void *t, bus_space_handle_t bsh, \ - bus_size_t offset, u_int64_t value, bus_size_t count); +void __bs_c(f,_bs_sr_8) (bus_space_tag_t t, bus_space_handle_t bsh, \ + bus_size_t offset, uint64_t value, bus_size_t count); #define bs_c_1_proto(f) \ -void __bs_c(f,_bs_c_1) (void *t, bus_space_handle_t bsh1, \ +void __bs_c(f,_bs_c_1) (bus_space_tag_t t, bus_space_handle_t bsh1, \ bus_size_t offset1, bus_space_handle_t bsh2, \ bus_size_t offset2, bus_size_t count); #define bs_c_2_proto(f) \ -void __bs_c(f,_bs_c_2) (void *t, bus_space_handle_t bsh1, \ +void __bs_c(f,_bs_c_2) (bus_space_tag_t t, bus_space_handle_t bsh1, \ bus_size_t offset1, bus_space_handle_t bsh2, \ bus_size_t offset2, bus_size_t count); #define bs_c_4_proto(f) \ -void __bs_c(f,_bs_c_4) (void *t, bus_space_handle_t bsh1, \ +void __bs_c(f,_bs_c_4) (bus_space_tag_t t, bus_space_handle_t bsh1, \ bus_size_t offset1, bus_space_handle_t bsh2, \ bus_size_t offset2, bus_size_t count); #define bs_c_8_proto(f) \ -void __bs_c(f,_bs_c_8) (void *t, bus_space_handle_t bsh1, \ +void __bs_c(f,_bs_c_8) (bus_space_tag_t t, bus_space_handle_t bsh1, \ bus_size_t offset1, bus_space_handle_t bsh2, \ bus_size_t offset2, bus_size_t count); diff --git a/sys/arm/versatile/bus_space.c b/sys/arm/versatile/bus_space.c index 375c5514c403..e7ffc09f0213 100644 --- a/sys/arm/versatile/bus_space.c +++ b/sys/arm/versatile/bus_space.c @@ -46,7 +46,7 @@ bs_protos(generic_armv4); struct bus_space _base_tag = { /* cookie */ - .bs_cookie = (void *) 0, + .bs_privdata = (void *) 0, /* mapping/unmapping */ .bs_map = generic_bs_map, diff --git a/sys/arm/xilinx/zy7_bus_space.c b/sys/arm/xilinx/zy7_bus_space.c index 375c5514c403..e7ffc09f0213 100644 --- a/sys/arm/xilinx/zy7_bus_space.c +++ b/sys/arm/xilinx/zy7_bus_space.c @@ -46,7 +46,7 @@ bs_protos(generic_armv4); struct bus_space _base_tag = { /* cookie */ - .bs_cookie = (void *) 0, + .bs_privdata = (void *) 0, /* mapping/unmapping */ .bs_map = generic_bs_map, diff --git a/sys/arm/xscale/i80321/i80321_space.c b/sys/arm/xscale/i80321/i80321_space.c index ce1db83bfd45..44a2ca800218 100644 --- a/sys/arm/xscale/i80321/i80321_space.c +++ b/sys/arm/xscale/i80321/i80321_space.c @@ -182,7 +182,7 @@ i80321_bs_init(bus_space_tag_t bs, void *cookie) { *bs = i80321_bs_tag_template; - bs->bs_cookie = cookie; + bs->bs_privdata = cookie; } void @@ -190,7 +190,7 @@ i80321_io_bs_init(bus_space_tag_t bs, void *cookie) { *bs = i80321_bs_tag_template; - bs->bs_cookie = cookie; + bs->bs_privdata = cookie; bs->bs_map = i80321_io_bs_map; bs->bs_unmap = i80321_io_bs_unmap; @@ -204,7 +204,7 @@ i80321_mem_bs_init(bus_space_tag_t bs, void *cookie) { *bs = i80321_bs_tag_template; - bs->bs_cookie = cookie; + bs->bs_privdata = cookie; bs->bs_map = i80321_mem_bs_map; bs->bs_unmap = i80321_mem_bs_unmap; @@ -216,7 +216,7 @@ i80321_mem_bs_init(bus_space_tag_t bs, void *cookie) /* *** Routines shared by i80321, PCI IO, and PCI MEM. *** */ int -i80321_bs_subregion(void *t, bus_space_handle_t bsh, bus_size_t offset, +i80321_bs_subregion(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp) { @@ -225,7 +225,7 @@ i80321_bs_subregion(void *t, bus_space_handle_t bsh, bus_size_t offset, } void -i80321_bs_barrier(void *t, bus_space_handle_t bsh, bus_size_t offset, +i80321_bs_barrier(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t offset, bus_size_t len, int flags) { @@ -236,7 +236,7 @@ i80321_bs_barrier(void *t, bus_space_handle_t bsh, bus_size_t offset, extern struct i80321_softc *i80321_softc; int -i80321_io_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flags, +i80321_io_bs_map(bus_space_tag_t tag, bus_addr_t bpa, bus_size_t size, int flags, bus_space_handle_t *bshp) { struct i80321_softc *sc = i80321_softc; @@ -264,14 +264,14 @@ i80321_io_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flags, } void -i80321_io_bs_unmap(void *t, bus_space_handle_t h, bus_size_t size) +i80321_io_bs_unmap(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t size) { /* Nothing to do. */ } int -i80321_io_bs_alloc(void *t, bus_addr_t rstart, bus_addr_t rend, +i80321_io_bs_alloc(bus_space_tag_t tag, bus_addr_t rstart, bus_addr_t rend, bus_size_t size, bus_size_t alignment, bus_size_t boundary, int flags, bus_addr_t *bpap, bus_space_handle_t *bshp) { @@ -280,7 +280,7 @@ i80321_io_bs_alloc(void *t, bus_addr_t rstart, bus_addr_t rend, } void -i80321_io_bs_free(void *t, bus_space_handle_t bsh, bus_size_t size) +i80321_io_bs_free(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t size) { panic("i80321_io_bs_free(): not implemented"); @@ -290,33 +290,23 @@ i80321_io_bs_free(void *t, bus_space_handle_t bsh, bus_size_t size) /* *** Routines for PCI MEM. *** */ extern int badaddr_read(void *, int, void *); int -i80321_mem_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flags, +i80321_mem_bs_map(bus_space_tag_t tag, bus_addr_t bpa, bus_size_t size, int flags, bus_space_handle_t *bshp) { - vm_paddr_t pa, endpa; - pa = trunc_page(bpa); - endpa = round_page(bpa + size); - - *bshp = (vm_offset_t)pmap_mapdev(pa, endpa - pa); - + *bshp = (vm_offset_t)pmap_mapdev(bpa, size); return (0); } void -i80321_mem_bs_unmap(void *t, bus_space_handle_t h, bus_size_t size) +i80321_mem_bs_unmap(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t size) { - vm_offset_t va, endva; - va = trunc_page((vm_offset_t)t); - endva = va + round_page(size); - - /* Free the kernel virtual mapping. */ - kva_free(va, endva - va); + pmap_unmapdev((vm_offset_t)h, size); } int -i80321_mem_bs_alloc(void *t, bus_addr_t rstart, bus_addr_t rend, +i80321_mem_bs_alloc(bus_space_tag_t tag, bus_addr_t rstart, bus_addr_t rend, bus_size_t size, bus_size_t alignment, bus_size_t boundary, int flags, bus_addr_t *bpap, bus_space_handle_t *bshp) { @@ -325,7 +315,7 @@ i80321_mem_bs_alloc(void *t, bus_addr_t rstart, bus_addr_t rend, } void -i80321_mem_bs_free(void *t, bus_space_handle_t bsh, bus_size_t size) +i80321_mem_bs_free(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t size) { panic("i80321_mem_bs_free(): not implemented"); diff --git a/sys/arm/xscale/i8134x/i81342_space.c b/sys/arm/xscale/i8134x/i81342_space.c index bd19a77c5418..e19447472d71 100644 --- a/sys/arm/xscale/i8134x/i81342_space.c +++ b/sys/arm/xscale/i8134x/i81342_space.c @@ -183,7 +183,7 @@ i81342_bs_init(bus_space_tag_t bs, void *cookie) { *bs = i81342_bs_tag_template; - bs->bs_cookie = cookie; + bs->bs_privdata = cookie; } void @@ -191,7 +191,7 @@ i81342_io_bs_init(bus_space_tag_t bs, void *cookie) { *bs = i81342_bs_tag_template; - bs->bs_cookie = cookie; + bs->bs_privdata = cookie; bs->bs_map = i81342_io_bs_map; bs->bs_unmap = i81342_io_bs_unmap; @@ -205,7 +205,7 @@ i81342_mem_bs_init(bus_space_tag_t bs, void *cookie) { *bs = i81342_bs_tag_template; - bs->bs_cookie = cookie; + bs->bs_privdata = cookie; bs->bs_map = i81342_mem_bs_map; bs->bs_unmap = i81342_mem_bs_unmap; @@ -217,7 +217,7 @@ i81342_mem_bs_init(bus_space_tag_t bs, void *cookie) /* *** Routines shared by i81342, PCI IO, and PCI MEM. *** */ int -i81342_bs_subregion(void *t, bus_space_handle_t bsh, bus_size_t offset, +i81342_bs_subregion(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp) { @@ -226,7 +226,7 @@ i81342_bs_subregion(void *t, bus_space_handle_t bsh, bus_size_t offset, } void -i81342_bs_barrier(void *t, bus_space_handle_t bsh, bus_size_t offset, +i81342_bs_barrier(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t offset, bus_size_t len, int flags) { @@ -236,7 +236,7 @@ i81342_bs_barrier(void *t, bus_space_handle_t bsh, bus_size_t offset, /* *** Routines for PCI IO. *** */ int -i81342_io_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flags, +i81342_io_bs_map(bus_space_tag_t tag, bus_addr_t bpa, bus_size_t size, int flags, bus_space_handle_t *bshp) { @@ -245,14 +245,14 @@ i81342_io_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flags, } void -i81342_io_bs_unmap(void *t, bus_space_handle_t h, bus_size_t size) +i81342_io_bs_unmap(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t size) { /* Nothing to do. */ } int -i81342_io_bs_alloc(void *t, bus_addr_t rstart, bus_addr_t rend, +i81342_io_bs_alloc(bus_space_tag_t tag, bus_addr_t rstart, bus_addr_t rend, bus_size_t size, bus_size_t alignment, bus_size_t boundary, int flags, bus_addr_t *bpap, bus_space_handle_t *bshp) { @@ -261,7 +261,7 @@ i81342_io_bs_alloc(void *t, bus_addr_t rstart, bus_addr_t rend, } void -i81342_io_bs_free(void *t, bus_space_handle_t bsh, bus_size_t size) +i81342_io_bs_free(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t size) { panic("i81342_io_bs_free(): not implemented"); @@ -272,10 +272,10 @@ i81342_io_bs_free(void *t, bus_space_handle_t bsh, bus_size_t size) extern int badaddr_read(void *, int, void *); static vm_offset_t allocable = 0xe1000000; int -i81342_mem_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flags, +i81342_mem_bs_map(bus_space_tag_t tag, bus_addr_t bpa, bus_size_t size, int flags, bus_space_handle_t *bshp) { - struct i81342_pci_softc *sc = (struct i81342_pci_softc *)t; + struct i81342_pci_softc *sc = (struct i81342_pci_softc *)tag->bs_privdata; struct i81342_pci_map *tmp; vm_offset_t addr, endaddr; vm_paddr_t paddr; @@ -315,12 +315,12 @@ i81342_mem_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flags, } void -i81342_mem_bs_unmap(void *t, bus_space_handle_t h, bus_size_t size) +i81342_mem_bs_unmap(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t size) { #if 0 vm_offset_t va, endva; - va = trunc_page((vm_offset_t)t); + va = trunc_page((vm_offset_t)h); endva = va + round_page(size); /* Free the kernel virtual mapping. */ @@ -329,7 +329,7 @@ i81342_mem_bs_unmap(void *t, bus_space_handle_t h, bus_size_t size) } int -i81342_mem_bs_alloc(void *t, bus_addr_t rstart, bus_addr_t rend, +i81342_mem_bs_alloc(bus_space_tag_t tag, bus_addr_t rstart, bus_addr_t rend, bus_size_t size, bus_size_t alignment, bus_size_t boundary, int flags, bus_addr_t *bpap, bus_space_handle_t *bshp) { @@ -338,7 +338,7 @@ i81342_mem_bs_alloc(void *t, bus_addr_t rstart, bus_addr_t rend, } void -i81342_mem_bs_free(void *t, bus_space_handle_t bsh, bus_size_t size) +i81342_mem_bs_free(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t size) { panic("i81342_mem_bs_free(): not implemented"); diff --git a/sys/arm/xscale/ixp425/avila_ata.c b/sys/arm/xscale/ixp425/avila_ata.c index e63071420512..217cfc8d405d 100644 --- a/sys/arm/xscale/ixp425/avila_ata.c +++ b/sys/arm/xscale/ixp425/avila_ata.c @@ -147,9 +147,9 @@ struct ata_avila_softc { static void ata_avila_intr(void *); bs_protos(ata); -static void ata_bs_rm_2_s(void *, bus_space_handle_t, bus_size_t, +static void ata_bs_rm_2_s(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, u_int16_t *, bus_size_t); -static void ata_bs_wm_2_s(void *, bus_space_handle_t, bus_size_t, +static void ata_bs_wm_2_s(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, const u_int16_t *, bus_size_t); static int @@ -200,7 +200,7 @@ ata_avila_attach(device_t dev) * XXX probably should just make this generic for * accessing the expansion bus. */ - sc->sc_expbus_tag.bs_cookie = sc; /* NB: backpointer */ + sc->sc_expbus_tag.bs_privdata = sc; /* NB: backpointer */ /* read single */ sc->sc_expbus_tag.bs_r_1 = ata_bs_r_1, sc->sc_expbus_tag.bs_r_2 = ata_bs_r_2, @@ -355,25 +355,25 @@ disable_16(struct ata_avila_softc *sc) } uint8_t -ata_bs_r_1(void *t, bus_space_handle_t h, bus_size_t o) +ata_bs_r_1(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o) { - struct ata_avila_softc *sc = t; + struct ata_avila_softc *sc = tag->bs_privdata; return bus_space_read_1(sc->sc_iot, h, o); } void -ata_bs_w_1(void *t, bus_space_handle_t h, bus_size_t o, u_int8_t v) +ata_bs_w_1(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, u_int8_t v) { - struct ata_avila_softc *sc = t; + struct ata_avila_softc *sc = tag->bs_privdata; bus_space_write_1(sc->sc_iot, h, o, v); } uint16_t -ata_bs_r_2(void *t, bus_space_handle_t h, bus_size_t o) +ata_bs_r_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o) { - struct ata_avila_softc *sc = t; + struct ata_avila_softc *sc = tag->bs_privdata; uint16_t v; enable_16(sc); @@ -383,9 +383,9 @@ ata_bs_r_2(void *t, bus_space_handle_t h, bus_size_t o) } void -ata_bs_w_2(void *t, bus_space_handle_t h, bus_size_t o, uint16_t v) +ata_bs_w_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, uint16_t v) { - struct ata_avila_softc *sc = t; + struct ata_avila_softc *sc = tag->bs_privdata; enable_16(sc); bus_space_write_2(sc->sc_iot, h, o, v); @@ -393,10 +393,10 @@ ata_bs_w_2(void *t, bus_space_handle_t h, bus_size_t o, uint16_t v) } void -ata_bs_rm_2(void *t, bus_space_handle_t h, bus_size_t o, +ata_bs_rm_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, u_int16_t *d, bus_size_t c) { - struct ata_avila_softc *sc = t; + struct ata_avila_softc *sc = tag->bs_privdata; enable_16(sc); bus_space_read_multi_2(sc->sc_iot, h, o, d, c); @@ -404,10 +404,10 @@ ata_bs_rm_2(void *t, bus_space_handle_t h, bus_size_t o, } void -ata_bs_wm_2(void *t, bus_space_handle_t h, bus_size_t o, +ata_bs_wm_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, const u_int16_t *d, bus_size_t c) { - struct ata_avila_softc *sc = t; + struct ata_avila_softc *sc = tag->bs_privdata; enable_16(sc); bus_space_write_multi_2(sc->sc_iot, h, o, d, c); @@ -417,10 +417,10 @@ ata_bs_wm_2(void *t, bus_space_handle_t h, bus_size_t o, /* XXX workaround ata driver by (incorrectly) byte swapping stream cases */ void -ata_bs_rm_2_s(void *t, bus_space_handle_t h, bus_size_t o, +ata_bs_rm_2_s(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, u_int16_t *d, bus_size_t c) { - struct ata_avila_softc *sc = t; + struct ata_avila_softc *sc = tag->bs_privdata; uint16_t v; bus_size_t i; @@ -437,10 +437,10 @@ ata_bs_rm_2_s(void *t, bus_space_handle_t h, bus_size_t o, } void -ata_bs_wm_2_s(void *t, bus_space_handle_t h, bus_size_t o, +ata_bs_wm_2_s(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, const u_int16_t *d, bus_size_t c) { - struct ata_avila_softc *sc = t; + struct ata_avila_softc *sc = tag->bs_privdata; bus_size_t i; enable_16(sc); diff --git a/sys/arm/xscale/ixp425/cambria_exp_space.c b/sys/arm/xscale/ixp425/cambria_exp_space.c index 30dfac5582ab..9dce5778b8e3 100644 --- a/sys/arm/xscale/ixp425/cambria_exp_space.c +++ b/sys/arm/xscale/ixp425/cambria_exp_space.c @@ -83,9 +83,9 @@ disable_16(struct ixp425_softc *sc, bus_size_t cs) } static uint8_t -cambria_bs_r_1(void *t, bus_space_handle_t h, bus_size_t o) +cambria_bs_r_1(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o) { - struct expbus_softc *exp = t; + struct expbus_softc *exp = tag->bs_privdata; struct ixp425_softc *sc = exp->sc; uint8_t v; @@ -96,9 +96,9 @@ cambria_bs_r_1(void *t, bus_space_handle_t h, bus_size_t o) } static void -cambria_bs_w_1(void *t, bus_space_handle_t h, bus_size_t o, u_int8_t v) +cambria_bs_w_1(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, u_int8_t v) { - struct expbus_softc *exp = t; + struct expbus_softc *exp = tag->bs_privdata; struct ixp425_softc *sc = exp->sc; EXP_LOCK(exp); @@ -107,9 +107,9 @@ cambria_bs_w_1(void *t, bus_space_handle_t h, bus_size_t o, u_int8_t v) } static uint16_t -cambria_bs_r_2(void *t, bus_space_handle_t h, bus_size_t o) +cambria_bs_r_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o) { - struct expbus_softc *exp = t; + struct expbus_softc *exp = tag->bs_privdata; struct ixp425_softc *sc = exp->sc; uint16_t v; @@ -122,9 +122,9 @@ cambria_bs_r_2(void *t, bus_space_handle_t h, bus_size_t o) } static void -cambria_bs_w_2(void *t, bus_space_handle_t h, bus_size_t o, uint16_t v) +cambria_bs_w_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, uint16_t v) { - struct expbus_softc *exp = t; + struct expbus_softc *exp = tag->bs_privdata; struct ixp425_softc *sc = exp->sc; EXP_LOCK(exp); @@ -135,10 +135,10 @@ cambria_bs_w_2(void *t, bus_space_handle_t h, bus_size_t o, uint16_t v) } static void -cambria_bs_rm_2(void *t, bus_space_handle_t h, bus_size_t o, +cambria_bs_rm_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, u_int16_t *d, bus_size_t c) { - struct expbus_softc *exp = t; + struct expbus_softc *exp = tag->bs_privdata; struct ixp425_softc *sc = exp->sc; EXP_LOCK(exp); @@ -149,10 +149,10 @@ cambria_bs_rm_2(void *t, bus_space_handle_t h, bus_size_t o, } static void -cambria_bs_wm_2(void *t, bus_space_handle_t h, bus_size_t o, +cambria_bs_wm_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, const u_int16_t *d, bus_size_t c) { - struct expbus_softc *exp = t; + struct expbus_softc *exp = tag->bs_privdata; struct ixp425_softc *sc = exp->sc; EXP_LOCK(exp); @@ -165,10 +165,10 @@ cambria_bs_wm_2(void *t, bus_space_handle_t h, bus_size_t o, /* XXX workaround ata driver by (incorrectly) byte swapping stream cases */ static void -cambria_bs_rm_2_s(void *t, bus_space_handle_t h, bus_size_t o, +cambria_bs_rm_2_s(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, u_int16_t *d, bus_size_t c) { - struct expbus_softc *exp = t; + struct expbus_softc *exp = tag->bs_privdata; struct ixp425_softc *sc = exp->sc; uint16_t v; bus_size_t i; @@ -188,10 +188,10 @@ cambria_bs_rm_2_s(void *t, bus_space_handle_t h, bus_size_t o, } static void -cambria_bs_wm_2_s(void *t, bus_space_handle_t h, bus_size_t o, +cambria_bs_wm_2_s(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, const u_int16_t *d, bus_size_t c) { - struct expbus_softc *exp = t; + struct expbus_softc *exp = tag->bs_privdata; struct ixp425_softc *sc = exp->sc; bus_size_t i; @@ -244,7 +244,7 @@ cambria_exp_bus_init(struct ixp425_softc *sc) c3.sc = sc; c3.csoff = EXP_TIMING_CS3_OFFSET; EXP_LOCK_INIT(&c3); - cambria_exp_bs_tag.bs_cookie = &c3; + cambria_exp_bs_tag.bs_privdata = &c3; cs3 = EXP_BUS_READ_4(sc, EXP_TIMING_CS3_OFFSET); /* XXX force slowest possible timings and byte mode */ diff --git a/sys/arm/xscale/ixp425/ixp425_a4x_space.c b/sys/arm/xscale/ixp425/ixp425_a4x_space.c index 74239db6f5f1..23e48e8bb106 100644 --- a/sys/arm/xscale/ixp425/ixp425_a4x_space.c +++ b/sys/arm/xscale/ixp425/ixp425_a4x_space.c @@ -66,7 +66,7 @@ bs_protos(generic_armv4); struct bus_space ixp425_a4x_bs_tag = { /* cookie */ - .bs_cookie = (void *) 0, + .bs_privdata = (void *) 0, /* mapping/unmapping */ .bs_map = generic_bs_map, diff --git a/sys/arm/xscale/ixp425/ixp425_pci_space.c b/sys/arm/xscale/ixp425/ixp425_pci_space.c index 8617e8e1be11..bec3d9c9a980 100644 --- a/sys/arm/xscale/ixp425/ixp425_pci_space.c +++ b/sys/arm/xscale/ixp425/ixp425_pci_space.c @@ -72,30 +72,30 @@ bs_protos(ixp425_pci_io); bs_protos(ixp425_pci_mem); /* special I/O functions */ -static u_int8_t _pci_io_bs_r_1(void *, bus_space_handle_t, bus_size_t); -static u_int16_t _pci_io_bs_r_2(void *, bus_space_handle_t, bus_size_t); -static u_int32_t _pci_io_bs_r_4(void *, bus_space_handle_t, bus_size_t); +static u_int8_t _pci_io_bs_r_1(bus_space_tag_t tag, bus_space_handle_t, bus_size_t); +static u_int16_t _pci_io_bs_r_2(bus_space_tag_t tag, bus_space_handle_t, bus_size_t); +static u_int32_t _pci_io_bs_r_4(bus_space_tag_t tag, bus_space_handle_t, bus_size_t); -static void _pci_io_bs_w_1(void *, bus_space_handle_t, bus_size_t, u_int8_t); -static void _pci_io_bs_w_2(void *, bus_space_handle_t, bus_size_t, u_int16_t); -static void _pci_io_bs_w_4(void *, bus_space_handle_t, bus_size_t, u_int32_t); +static void _pci_io_bs_w_1(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, u_int8_t); +static void _pci_io_bs_w_2(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, u_int16_t); +static void _pci_io_bs_w_4(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, u_int32_t); #ifdef __ARMEB__ -static u_int8_t _pci_io_bs_r_1_s(void *, bus_space_handle_t, bus_size_t); -static u_int16_t _pci_io_bs_r_2_s(void *, bus_space_handle_t, bus_size_t); -static u_int32_t _pci_io_bs_r_4_s(void *, bus_space_handle_t, bus_size_t); +static u_int8_t _pci_io_bs_r_1_s(bus_space_tag_t tag, bus_space_handle_t, bus_size_t); +static u_int16_t _pci_io_bs_r_2_s(bus_space_tag_t tag, bus_space_handle_t, bus_size_t); +static u_int32_t _pci_io_bs_r_4_s(bus_space_tag_t tag, bus_space_handle_t, bus_size_t); -static void _pci_io_bs_w_1_s(void *, bus_space_handle_t, bus_size_t, u_int8_t); -static void _pci_io_bs_w_2_s(void *, bus_space_handle_t, bus_size_t, u_int16_t); -static void _pci_io_bs_w_4_s(void *, bus_space_handle_t, bus_size_t, u_int32_t); +static void _pci_io_bs_w_1_s(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, u_int8_t); +static void _pci_io_bs_w_2_s(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, u_int16_t); +static void _pci_io_bs_w_4_s(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, u_int32_t); -static u_int8_t _pci_mem_bs_r_1(void *, bus_space_handle_t, bus_size_t); -static u_int16_t _pci_mem_bs_r_2(void *, bus_space_handle_t, bus_size_t); -static u_int32_t _pci_mem_bs_r_4(void *, bus_space_handle_t, bus_size_t); +static u_int8_t _pci_mem_bs_r_1(bus_space_tag_t tag, bus_space_handle_t, bus_size_t); +static u_int16_t _pci_mem_bs_r_2(bus_space_tag_t tag, bus_space_handle_t, bus_size_t); +static u_int32_t _pci_mem_bs_r_4(bus_space_tag_t tag, bus_space_handle_t, bus_size_t); -static void _pci_mem_bs_w_1(void *, bus_space_handle_t, bus_size_t, u_int8_t); -static void _pci_mem_bs_w_2(void *, bus_space_handle_t, bus_size_t, u_int16_t); -static void _pci_mem_bs_w_4(void *, bus_space_handle_t, bus_size_t, u_int32_t); +static void _pci_mem_bs_w_1(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, u_int8_t); +static void _pci_mem_bs_w_2(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, u_int16_t); +static void _pci_mem_bs_w_4(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, u_int32_t); #endif struct bus_space ixp425_pci_io_bs_tag_template = { @@ -146,7 +146,7 @@ void ixp425_io_bs_init(bus_space_tag_t bs, void *cookie) { *bs = ixp425_pci_io_bs_tag_template; - bs->bs_cookie = cookie; + bs->bs_privdata = cookie; } struct bus_space ixp425_pci_mem_bs_tag_template = { @@ -202,12 +202,12 @@ void ixp425_mem_bs_init(bus_space_tag_t bs, void *cookie) { *bs = ixp425_pci_mem_bs_tag_template; - bs->bs_cookie = cookie; + bs->bs_privdata = cookie; } /* common routine */ int -ixp425_pci_bs_subregion(void *t, bus_space_handle_t bsh, bus_size_t offset, +ixp425_pci_bs_subregion(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp) { *nbshp = bsh + offset; @@ -215,7 +215,7 @@ ixp425_pci_bs_subregion(void *t, bus_space_handle_t bsh, bus_size_t offset, } void -ixp425_pci_bs_barrier(void *t, bus_space_handle_t bsh, bus_size_t offset, +ixp425_pci_bs_barrier(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t offset, bus_size_t len, int flags) { /* NULL */ @@ -223,7 +223,7 @@ ixp425_pci_bs_barrier(void *t, bus_space_handle_t bsh, bus_size_t offset, /* io bs */ int -ixp425_pci_io_bs_map(void *t, bus_addr_t bpa, bus_size_t size, +ixp425_pci_io_bs_map(bus_space_tag_t tag, bus_addr_t bpa, bus_size_t size, int cacheable, bus_space_handle_t *bshp) { *bshp = bpa; @@ -231,13 +231,13 @@ ixp425_pci_io_bs_map(void *t, bus_addr_t bpa, bus_size_t size, } void -ixp425_pci_io_bs_unmap(void *t, bus_space_handle_t h, bus_size_t size) +ixp425_pci_io_bs_unmap(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t size) { /* Nothing to do. */ } int -ixp425_pci_io_bs_alloc(void *t, bus_addr_t rstart, bus_addr_t rend, +ixp425_pci_io_bs_alloc(bus_space_tag_t tag, bus_addr_t rstart, bus_addr_t rend, bus_size_t size, bus_size_t alignment, bus_size_t boundary, int cacheable, bus_addr_t *bpap, bus_space_handle_t *bshp) { @@ -245,14 +245,14 @@ ixp425_pci_io_bs_alloc(void *t, bus_addr_t rstart, bus_addr_t rend, } void -ixp425_pci_io_bs_free(void *t, bus_space_handle_t bsh, bus_size_t size) +ixp425_pci_io_bs_free(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t size) { panic("ixp425_pci_io_bs_free(): not implemented\n"); } /* special I/O functions */ static __inline u_int32_t -_bs_r(void *v, bus_space_handle_t ioh, bus_size_t off, u_int32_t be) +_bs_r(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off, u_int32_t be) { u_int32_t data; @@ -266,75 +266,75 @@ _bs_r(void *v, bus_space_handle_t ioh, bus_size_t off, u_int32_t be) } static u_int8_t -_pci_io_bs_r_1(void *v, bus_space_handle_t ioh, bus_size_t off) +_pci_io_bs_r_1(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off) { u_int32_t data, n, be; n = (ioh + off) % 4; be = (0xf & ~(1U << n)) << NP_CBE_SHIFT; - data = _bs_r(v, ioh, off, be); + data = _bs_r(tag, ioh, off, be); return data >> (8 * n); } static u_int16_t -_pci_io_bs_r_2(void *v, bus_space_handle_t ioh, bus_size_t off) +_pci_io_bs_r_2(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off) { u_int32_t data, n, be; n = (ioh + off) % 4; be = (0xf & ~((1U << n) | (1U << (n + 1)))) << NP_CBE_SHIFT; - data = _bs_r(v, ioh, off, be); + data = _bs_r(tag, ioh, off, be); return data >> (8 * n); } static u_int32_t -_pci_io_bs_r_4(void *v, bus_space_handle_t ioh, bus_size_t off) +_pci_io_bs_r_4(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off) { u_int32_t data; - data = _bs_r(v, ioh, off, 0); + data = _bs_r(tag, ioh, off, 0); return data; } #ifdef __ARMEB__ static u_int8_t -_pci_io_bs_r_1_s(void *v, bus_space_handle_t ioh, bus_size_t off) +_pci_io_bs_r_1_s(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off) { u_int32_t data, n, be; n = (ioh + off) % 4; be = (0xf & ~(1U << n)) << NP_CBE_SHIFT; - data = _bs_r(v, ioh, off, be); + data = _bs_r(tag, ioh, off, be); return data >> (8 * n); } static u_int16_t -_pci_io_bs_r_2_s(void *v, bus_space_handle_t ioh, bus_size_t off) +_pci_io_bs_r_2_s(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off) { u_int32_t data, n, be; n = (ioh + off) % 4; be = (0xf & ~((1U << n) | (1U << (n + 1)))) << NP_CBE_SHIFT; - data = _bs_r(v, ioh, off, be); + data = _bs_r(tag, ioh, off, be); return data >> (8 * n); } static u_int32_t -_pci_io_bs_r_4_s(void *v, bus_space_handle_t ioh, bus_size_t off) +_pci_io_bs_r_4_s(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off) { u_int32_t data; - data = _bs_r(v, ioh, off, 0); + data = _bs_r(tag, ioh, off, 0); return le32toh(data); } #endif /* __ARMEB__ */ static __inline void -_bs_w(void *v, bus_space_handle_t ioh, bus_size_t off, +_bs_w(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off, u_int32_t be, u_int32_t data) { CSR_WRITE_4(PCI_NP_AD, (ioh + off) & ~3); @@ -345,7 +345,7 @@ _bs_w(void *v, bus_space_handle_t ioh, bus_size_t off, } static void -_pci_io_bs_w_1(void *v, bus_space_handle_t ioh, bus_size_t off, +_pci_io_bs_w_1(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off, u_int8_t val) { u_int32_t data, n, be; @@ -353,11 +353,11 @@ _pci_io_bs_w_1(void *v, bus_space_handle_t ioh, bus_size_t off, n = (ioh + off) % 4; be = (0xf & ~(1U << n)) << NP_CBE_SHIFT; data = val << (8 * n); - _bs_w(v, ioh, off, be, data); + _bs_w(tag, ioh, off, be, data); } static void -_pci_io_bs_w_2(void *v, bus_space_handle_t ioh, bus_size_t off, +_pci_io_bs_w_2(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off, u_int16_t val) { u_int32_t data, n, be; @@ -365,19 +365,19 @@ _pci_io_bs_w_2(void *v, bus_space_handle_t ioh, bus_size_t off, n = (ioh + off) % 4; be = (0xf & ~((1U << n) | (1U << (n + 1)))) << NP_CBE_SHIFT; data = val << (8 * n); - _bs_w(v, ioh, off, be, data); + _bs_w(tag, ioh, off, be, data); } static void -_pci_io_bs_w_4(void *v, bus_space_handle_t ioh, bus_size_t off, +_pci_io_bs_w_4(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off, u_int32_t val) { - _bs_w(v, ioh, off, 0, val); + _bs_w(tag, ioh, off, 0, val); } #ifdef __ARMEB__ static void -_pci_io_bs_w_1_s(void *v, bus_space_handle_t ioh, bus_size_t off, +_pci_io_bs_w_1_s(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off, u_int8_t val) { u_int32_t data, n, be; @@ -385,11 +385,11 @@ _pci_io_bs_w_1_s(void *v, bus_space_handle_t ioh, bus_size_t off, n = (ioh + off) % 4; be = (0xf & ~(1U << n)) << NP_CBE_SHIFT; data = val << (8 * n); - _bs_w(v, ioh, off, be, data); + _bs_w(tag, ioh, off, be, data); } static void -_pci_io_bs_w_2_s(void *v, bus_space_handle_t ioh, bus_size_t off, +_pci_io_bs_w_2_s(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off, u_int16_t val) { u_int32_t data, n, be; @@ -397,46 +397,35 @@ _pci_io_bs_w_2_s(void *v, bus_space_handle_t ioh, bus_size_t off, n = (ioh + off) % 4; be = (0xf & ~((1U << n) | (1U << (n + 1)))) << NP_CBE_SHIFT; data = val << (8 * n); - _bs_w(v, ioh, off, be, data); + _bs_w(tag, ioh, off, be, data); } static void -_pci_io_bs_w_4_s(void *v, bus_space_handle_t ioh, bus_size_t off, +_pci_io_bs_w_4_s(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off, u_int32_t val) { - _bs_w(v, ioh, off, 0, htole32(val)); + _bs_w(tag, ioh, off, 0, htole32(val)); } #endif /* __ARMEB__ */ /* mem bs */ int -ixp425_pci_mem_bs_map(void *t, bus_addr_t bpa, bus_size_t size, +ixp425_pci_mem_bs_map(bus_space_tag_t tag, bus_addr_t bpa, bus_size_t size, int cacheable, bus_space_handle_t *bshp) { - vm_paddr_t pa, endpa; - - pa = trunc_page(bpa); - endpa = round_page(bpa + size); - - *bshp = (vm_offset_t)pmap_mapdev(pa, endpa - pa); - + *bshp = (vm_offset_t)pmap_mapdev(bpa, size); return (0); } void -ixp425_pci_mem_bs_unmap(void *t, bus_space_handle_t h, bus_size_t size) +ixp425_pci_mem_bs_unmap(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t size) { - vm_offset_t va, endva; - va = trunc_page((vm_offset_t)t); - endva = va + round_page(size); - - /* Free the kernel virtual mapping. */ - kva_free(va, endva - va); + pmap_unmapdev((vm_offset_t)h, size); } int -ixp425_pci_mem_bs_alloc(void *t, bus_addr_t rstart, bus_addr_t rend, +ixp425_pci_mem_bs_alloc(bus_space_tag_t tag, bus_addr_t rstart, bus_addr_t rend, bus_size_t size, bus_size_t alignment, bus_size_t boundary, int cacheable, bus_addr_t *bpap, bus_space_handle_t *bshp) { @@ -444,52 +433,52 @@ ixp425_pci_mem_bs_alloc(void *t, bus_addr_t rstart, bus_addr_t rend, } void -ixp425_pci_mem_bs_free(void *t, bus_space_handle_t bsh, bus_size_t size) +ixp425_pci_mem_bs_free(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t size) { panic("ixp425_mem_bs_free(): not implemented\n"); } #ifdef __ARMEB__ static u_int8_t -_pci_mem_bs_r_1(void *v, bus_space_handle_t ioh, bus_size_t off) +_pci_mem_bs_r_1(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off) { - return ixp425_pci_mem_bs_r_1(v, ioh, off); + return ixp425_pci_mem_bs_r_1(tag, ioh, off); } static u_int16_t -_pci_mem_bs_r_2(void *v, bus_space_handle_t ioh, bus_size_t off) +_pci_mem_bs_r_2(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off) { - return (ixp425_pci_mem_bs_r_2(v, ioh, off)); + return (ixp425_pci_mem_bs_r_2(tag, ioh, off)); } static u_int32_t -_pci_mem_bs_r_4(void *v, bus_space_handle_t ioh, bus_size_t off) +_pci_mem_bs_r_4(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off) { u_int32_t data; - data = ixp425_pci_mem_bs_r_4(v, ioh, off); + data = ixp425_pci_mem_bs_r_4(tag, ioh, off); return (le32toh(data)); } static void -_pci_mem_bs_w_1(void *v, bus_space_handle_t ioh, bus_size_t off, +_pci_mem_bs_w_1(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off, u_int8_t val) { - ixp425_pci_mem_bs_w_1(v, ioh, off, val); + ixp425_pci_mem_bs_w_1(tag, ioh, off, val); } static void -_pci_mem_bs_w_2(void *v, bus_space_handle_t ioh, bus_size_t off, +_pci_mem_bs_w_2(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off, u_int16_t val) { - ixp425_pci_mem_bs_w_2(v, ioh, off, val); + ixp425_pci_mem_bs_w_2(tag, ioh, off, val); } static void -_pci_mem_bs_w_4(void *v, bus_space_handle_t ioh, bus_size_t off, +_pci_mem_bs_w_4(bus_space_tag_t tag, bus_space_handle_t ioh, bus_size_t off, u_int32_t val) { - ixp425_pci_mem_bs_w_4(v, ioh, off, htole32(val)); + ixp425_pci_mem_bs_w_4(tag, ioh, off, htole32(val)); } #endif /* __ARMEB__ */ diff --git a/sys/arm/xscale/ixp425/ixp425_space.c b/sys/arm/xscale/ixp425/ixp425_space.c index 982ad4b1fed2..102bcd2acc0f 100644 --- a/sys/arm/xscale/ixp425/ixp425_space.c +++ b/sys/arm/xscale/ixp425/ixp425_space.c @@ -63,7 +63,7 @@ bs_protos(generic_armv4); struct bus_space ixp425_bs_tag = { /* cookie */ - .bs_cookie = (void *) 0, + .bs_privdata = (void *) 0, /* mapping/unmapping */ .bs_map = generic_bs_map, diff --git a/sys/arm/xscale/pxa/pxa_space.c b/sys/arm/xscale/pxa/pxa_space.c index f728e1d52009..cfaac37f7daf 100644 --- a/sys/arm/xscale/pxa/pxa_space.c +++ b/sys/arm/xscale/pxa/pxa_space.c @@ -145,7 +145,7 @@ pxa_obio_tag_init() { bcopy(&_base_tag, &_obio_tag, sizeof(struct bus_space)); - _obio_tag.bs_cookie = (void *)PXA2X0_PERIPH_OFFSET; + _obio_tag.bs_privdata = (void *)PXA2X0_PERIPH_OFFSET; obio_tag = &_obio_tag; } @@ -161,7 +161,7 @@ pxa_bus_tag_alloc(bus_addr_t offset) } bcopy(&_base_tag, tag, sizeof(struct bus_space)); - tag->bs_cookie = (void *)offset; + tag->bs_privdata = (void *)offset; return ((bus_space_tag_t)tag); } @@ -169,11 +169,11 @@ pxa_bus_tag_alloc(bus_addr_t offset) #define READ_SINGLE(type, proto, base) \ type \ - proto(void *cookie, bus_space_handle_t bsh, bus_size_t offset) \ + proto(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t offset) \ { \ bus_addr_t tag_offset; \ type value; \ - tag_offset = (bus_addr_t)cookie; \ + tag_offset = (bus_addr_t)tag->bs_privdata; \ value = base(NULL, bsh + tag_offset, offset); \ return (value); \ } @@ -186,11 +186,11 @@ READ_SINGLE(u_int32_t, pxa_bs_r_4, generic_bs_r_4) #define WRITE_SINGLE(type, proto, base) \ void \ - proto(void *cookie, bus_space_handle_t bsh, bus_size_t offset, \ + proto(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t offset, \ type value) \ { \ bus_addr_t tag_offset; \ - tag_offset = (bus_addr_t)cookie; \ + tag_offset = (bus_addr_t)tag->bs_privdata; \ base(NULL, bsh + tag_offset, offset, value); \ } @@ -202,11 +202,11 @@ WRITE_SINGLE(u_int32_t, pxa_bs_w_4, generic_bs_w_4) #define READ_MULTI(type, proto, base) \ void \ - proto(void *cookie, bus_space_handle_t bsh, bus_size_t offset, \ + proto(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t offset, \ type *dest, bus_size_t count) \ { \ bus_addr_t tag_offset; \ - tag_offset = (bus_addr_t)cookie; \ + tag_offset = (bus_addr_t)tag->bs_privdata; \ base(NULL, bsh + tag_offset, offset, dest, count); \ } @@ -219,11 +219,11 @@ READ_MULTI(u_int8_t, pxa_bs_rr_1, generic_bs_rr_1) #define WRITE_MULTI(type, proto, base) \ void \ - proto(void *cookie, bus_space_handle_t bsh, bus_size_t offset, \ + proto(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t offset, \ const type *src, bus_size_t count) \ { \ bus_addr_t tag_offset; \ - tag_offset = (bus_addr_t)cookie; \ + tag_offset = (bus_addr_t)tag->bs_privdata; \ base(NULL, bsh + tag_offset, offset, src, count); \ } diff --git a/sys/dev/usb/controller/ehci_ixp4xx.c b/sys/dev/usb/controller/ehci_ixp4xx.c index 956f73951a88..301032ed0260 100644 --- a/sys/dev/usb/controller/ehci_ixp4xx.c +++ b/sys/dev/usb/controller/ehci_ixp4xx.c @@ -79,12 +79,12 @@ struct ixp_ehci_softc { static device_attach_t ehci_ixp_attach; static device_detach_t ehci_ixp_detach; -static uint8_t ehci_bs_r_1(void *, bus_space_handle_t, bus_size_t); -static void ehci_bs_w_1(void *, bus_space_handle_t, bus_size_t, u_int8_t); -static uint16_t ehci_bs_r_2(void *, bus_space_handle_t, bus_size_t); -static void ehci_bs_w_2(void *, bus_space_handle_t, bus_size_t, uint16_t); -static uint32_t ehci_bs_r_4(void *, bus_space_handle_t, bus_size_t); -static void ehci_bs_w_4(void *, bus_space_handle_t, bus_size_t, uint32_t); +static uint8_t ehci_bs_r_1(bus_space_tag_t tag, bus_space_handle_t, bus_size_t); +static void ehci_bs_w_1(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, u_int8_t); +static uint16_t ehci_bs_r_2(bus_space_tag_t tag, bus_space_handle_t, bus_size_t); +static void ehci_bs_w_2(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, uint16_t); +static uint32_t ehci_bs_r_4(bus_space_tag_t tag, bus_space_handle_t, bus_size_t); +static void ehci_bs_w_4(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, uint32_t); static int ehci_ixp_probe(device_t self) @@ -132,7 +132,7 @@ ehci_ixp_attach(device_t self) * done with bus_space_subregion. */ isc->iot = rman_get_bustag(sc->sc_io_res); - isc->tag.bs_cookie = isc->iot; + isc->tag.bs_privdata = isc->iot; /* read single */ isc->tag.bs_r_1 = ehci_bs_r_1, isc->tag.bs_r_2 = ehci_bs_r_2, @@ -252,41 +252,41 @@ ehci_ixp_detach(device_t self) */ static uint8_t -ehci_bs_r_1(void *t, bus_space_handle_t h, bus_size_t o) +ehci_bs_r_1(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o) { - return bus_space_read_1((bus_space_tag_t) t, h, + return bus_space_read_1((bus_space_tag_t)tag->bs_privdata, h, 0x100 + (o &~ 3) + (3 - (o & 3))); } static void -ehci_bs_w_1(void *t, bus_space_handle_t h, bus_size_t o, u_int8_t v) +ehci_bs_w_1(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, u_int8_t v) { panic("%s", __func__); } static uint16_t -ehci_bs_r_2(void *t, bus_space_handle_t h, bus_size_t o) +ehci_bs_r_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o) { - return bus_space_read_2((bus_space_tag_t) t, h, + return bus_space_read_2((bus_space_tag_t)tag->bs_privdata, h, 0x100 + (o &~ 3) + (2 - (o & 3))); } static void -ehci_bs_w_2(void *t, bus_space_handle_t h, bus_size_t o, uint16_t v) +ehci_bs_w_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, uint16_t v) { panic("%s", __func__); } static uint32_t -ehci_bs_r_4(void *t, bus_space_handle_t h, bus_size_t o) +ehci_bs_r_4(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o) { - return bus_space_read_4((bus_space_tag_t) t, h, 0x100 + o); + return bus_space_read_4((bus_space_tag_t) tag->bs_privdata, h, 0x100 + o); } static void -ehci_bs_w_4(void *t, bus_space_handle_t h, bus_size_t o, uint32_t v) +ehci_bs_w_4(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, uint32_t v) { - bus_space_write_4((bus_space_tag_t) t, h, 0x100 + o, v); + bus_space_write_4((bus_space_tag_t) tag->bs_privdata, h, 0x100 + o, v); } static device_method_t ehci_methods[] = { From 03fe27a77383de96ee608557018620836fe5cb12 Mon Sep 17 00:00:00 2001 From: mjg Date: Wed, 21 Jan 2015 01:06:14 +0000 Subject: [PATCH 107/258] filedesc: plug a test for impossible condition in _fget --- sys/kern/kern_descrip.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 82ce56ddcaf3..4b4af296769a 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -2439,8 +2439,7 @@ _fget(struct thread *td, int fd, struct file **fpp, int flags, int error; *fpp = NULL; - if (td == NULL || (fdp = td->td_proc->p_fd) == NULL) - return (EBADF); + fdp = td->td_proc->p_fd; if (needrightsp != NULL) needrights = *needrightsp; else From b0c7bd39a20a4d8cfcb56c20be0428c1a6474ae8 Mon Sep 17 00:00:00 2001 From: emaste Date: Wed, 21 Jan 2015 01:07:58 +0000 Subject: [PATCH 108/258] redelf: Add missing R_X86_64_ relocation types PR: 196918 Reviewed by: dim Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D1570 --- contrib/elftoolchain/common/elfdefinitions.h | 8 +++++++- contrib/elftoolchain/readelf/readelf.c | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/contrib/elftoolchain/common/elfdefinitions.h b/contrib/elftoolchain/common/elfdefinitions.h index f63dc7f2178d..8b28aeb5eac7 100644 --- a/contrib/elftoolchain/common/elfdefinitions.h +++ b/contrib/elftoolchain/common/elfdefinitions.h @@ -1948,11 +1948,17 @@ _ELF_DEFINE_RELOC(R_X86_64_TPOFF32, 23) \ _ELF_DEFINE_RELOC(R_X86_64_PC64, 24) \ _ELF_DEFINE_RELOC(R_X86_64_GOTOFF64, 25) \ _ELF_DEFINE_RELOC(R_X86_64_GOTPC32, 26) \ +_ELF_DEFINE_RELOC(R_X86_64_GOT64, 27) \ +_ELF_DEFINE_RELOC(R_X86_64_GOTPCREL64, 28) \ +_ELF_DEFINE_RELOC(R_X86_64_GOTPC64, 29) \ +_ELF_DEFINE_RELOC(R_X86_64_GOTPLT64, 30) \ +_ELF_DEFINE_RELOC(R_X86_64_PLTOFF64, 31) \ _ELF_DEFINE_RELOC(R_X86_64_SIZE32, 32) \ _ELF_DEFINE_RELOC(R_X86_64_SIZE64, 33) \ _ELF_DEFINE_RELOC(R_X86_64_GOTPC32_TLSDESC, 34) \ _ELF_DEFINE_RELOC(R_X86_64_TLSDESC_CALL, 35) \ -_ELF_DEFINE_RELOC(R_X86_64_TLSDESC, 36) +_ELF_DEFINE_RELOC(R_X86_64_TLSDESC, 36) \ +_ELF_DEFINE_RELOC(R_X86_64_IRELATIVE, 37) #define _ELF_DEFINE_RELOCATIONS() \ _ELF_DEFINE_386_RELOCATIONS() \ diff --git a/contrib/elftoolchain/readelf/readelf.c b/contrib/elftoolchain/readelf/readelf.c index 6e1e52abfc5b..a8c15c465e54 100644 --- a/contrib/elftoolchain/readelf/readelf.c +++ b/contrib/elftoolchain/readelf/readelf.c @@ -1480,6 +1480,20 @@ r_type(unsigned int mach, unsigned int type) case 21: return "R_X86_64_DTPOFF32"; case 22: return "R_X86_64_GOTTPOFF"; case 23: return "R_X86_64_TPOFF32"; + case 24: return "R_X86_64_PC64"; + case 25: return "R_X86_64_GOTOFF64"; + case 26: return "R_X86_64_GOTPC32"; + case 27: return "R_X86_64_GOT64"; + case 28: return "R_X86_64_GOTPCREL64"; + case 29: return "R_X86_64_GOTPC64"; + case 30: return "R_X86_64_GOTPLT64"; + case 31: return "R_X86_64_PLTOFF64"; + case 32: return "R_X86_64_SIZE32"; + case 33: return "R_X86_64_SIZE64"; + case 34: return "R_X86_64_GOTPC32_TLSDESC"; + case 35: return "R_X86_64_TLSDESC_CALL"; + case 36: return "R_X86_64_TLSDESC"; + case 37: return "R_X86_64_IRELATIVE"; default: return ""; } default: return ""; From 637c00643a781090c43bf4f50d21be4ea591b939 Mon Sep 17 00:00:00 2001 From: delphij Date: Wed, 21 Jan 2015 01:11:37 +0000 Subject: [PATCH 109/258] Fix xz handling for files larger than 32K. Submitted by: Stefan Ehmann PR: bin/186861 MFC after: 2 weeks --- usr.bin/grep/file.c | 65 +++++++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/usr.bin/grep/file.c b/usr.bin/grep/file.c index 6bcaa52a7ecc..81f227d80739 100644 --- a/usr.bin/grep/file.c +++ b/usr.bin/grep/file.c @@ -65,6 +65,8 @@ __FBSDID("$FreeBSD$"); static gzFile gzbufdesc; #ifndef WITHOUT_LZMA static lzma_stream lstrm = LZMA_STREAM_INIT; +static lzma_action laction; +static uint8_t lin_buf[MAXBUFSIZ]; #endif #ifndef WITHOUT_BZIP2 static BZFILE* bzbufdesc; @@ -123,34 +125,34 @@ grep_refill(struct file *f) #endif #ifndef WITHOUT_LZMA } else if ((filebehave == FILE_XZ) || (filebehave == FILE_LZMA)) { - lzma_action action = LZMA_RUN; - uint8_t in_buf[MAXBUFSIZ]; lzma_ret ret; - - ret = (filebehave == FILE_XZ) ? - lzma_stream_decoder(&lstrm, UINT64_MAX, - LZMA_CONCATENATED) : - lzma_alone_decoder(&lstrm, UINT64_MAX); - - if (ret != LZMA_OK) - return (-1); - lstrm.next_out = buffer; - lstrm.avail_out = MAXBUFSIZ; - lstrm.next_in = in_buf; - nr = read(f->fd, in_buf, MAXBUFSIZ); - if (nr < 0) - return (-1); - else if (nr == 0) - action = LZMA_FINISH; + do { + if (lstrm.avail_in == 0) { + lstrm.next_in = lin_buf; + nr = read(f->fd, lin_buf, MAXBUFSIZ); - lstrm.avail_in = nr; - ret = lzma_code(&lstrm, action); + if (nr < 0) + return (-1); + else if (nr == 0) + laction = LZMA_FINISH; + + lstrm.avail_in = nr; + } + + ret = lzma_code(&lstrm, laction); + + if (ret != LZMA_OK && ret != LZMA_STREAM_END) + return (-1); + + if (lstrm.avail_out == 0 || ret == LZMA_STREAM_END) { + bufrem = MAXBUFSIZ - lstrm.avail_out; + lstrm.next_out = buffer; + lstrm.avail_out = MAXBUFSIZ; + } + } while (bufrem == 0 && ret != LZMA_STREAM_END); - if (ret != LZMA_OK && ret != LZMA_STREAM_END) - return (-1); - bufrem = MAXBUFSIZ - lstrm.avail_out; return (0); #endif /* WIHTOUT_LZMA */ } else @@ -291,6 +293,23 @@ grep_open(const char *path) (bzbufdesc = BZ2_bzdopen(f->fd, "r")) == NULL) goto error2; #endif +#ifndef WITHOUT_LZMA + else if ((filebehave == FILE_XZ) || (filebehave == FILE_LZMA)) { + lzma_ret ret; + + ret = (filebehave == FILE_XZ) ? + lzma_stream_decoder(&lstrm, UINT64_MAX, + LZMA_CONCATENATED) : + lzma_alone_decoder(&lstrm, UINT64_MAX); + + if (ret != LZMA_OK) + goto error2; + + lstrm.avail_in = 0; + lstrm.avail_out = MAXBUFSIZ; + laction = LZMA_RUN; + } +#endif /* Fill read buffer, also catches errors early */ if (bufrem == 0 && grep_refill(f) != 0) From d7249487a6c70125fcb94e9b61ff11404c4c6fe0 Mon Sep 17 00:00:00 2001 From: emaste Date: Wed, 21 Jan 2015 01:12:21 +0000 Subject: [PATCH 110/258] Add missing R_X86_64_ constants to elf_common.h PR: 196918 MFC after: 2 weeks Sponsored by: The FreeBSD Foundation --- sys/sys/elf_common.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sys/sys/elf_common.h b/sys/sys/elf_common.h index ebe2ee232883..c496a9014255 100644 --- a/sys/sys/elf_common.h +++ b/sys/sys/elf_common.h @@ -1223,6 +1223,19 @@ typedef struct { #define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ #define R_X86_64_GOTTPOFF 22 /* PC relative offset to IE GOT entry */ #define R_X86_64_TPOFF32 23 /* Offset in static TLS block */ +#define R_X86_64_PC64 24 /* PC-relative 64 bit signed sym value. */ +#define R_X86_64_GOTOFF64 25 +#define R_X86_64_GOTPC32 26 +#define R_X86_64_GOT64 27 +#define R_X86_64_GOTPCREL64 28 +#define R_X86_64_GOTPC64 29 +#define R_X86_64_GOTPLT64 30 +#define R_X86_64_PLTOFF64 31 +#define R_X86_64_SIZE32 32 +#define R_X86_64_SIZE64 33 +#define R_X86_64_GOTPC32_TLSDESC 34 +#define R_X86_64_TLSDESC_CALL 35 +#define R_X86_64_TLSDESC 36 #define R_X86_64_IRELATIVE 37 From 88d198cfcf5a4c68ac952834c4f76bb4bc501da1 Mon Sep 17 00:00:00 2001 From: ian Date: Wed, 21 Jan 2015 02:35:04 +0000 Subject: [PATCH 111/258] Use the explicit member initializer style to init the bus_space struct. Fill in some formerly NULL members where the implementation function exists. Add a dummy function that panics and use it as a placeholder for thigns that are still unimplemented. Remove a few unused includes. --- sys/arm/arm/bus_space-v6.c | 149 +++++++++++++++++++------------------ 1 file changed, 77 insertions(+), 72 deletions(-) diff --git a/sys/arm/arm/bus_space-v6.c b/sys/arm/arm/bus_space-v6.c index 738e4c6fc362..3414c5009cc9 100644 --- a/sys/arm/arm/bus_space-v6.c +++ b/sys/arm/arm/bus_space-v6.c @@ -34,125 +34,130 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include -#include - #include /* Prototypes for all the bus_space structure functions */ bs_protos(generic); bs_protos(generic_armv4); +static void +bs_unimplemented(void) +{ + + panic("unimplemented bus_space function called"); +} + +#define BS_UNIMPLEMENTED (void *)bs_unimplemented + /* * The bus space tag. This is constant for all instances, so * we never have to explicitly "create" it. */ static struct bus_space _base_tag = { - /* cookie */ - (void *) 0, + /* privdata is whatever the implementer wants; unused in base tag */ + .bs_privdata = NULL, /* mapping/unmapping */ - generic_bs_map, - generic_bs_unmap, - generic_bs_subregion, + .bs_map = generic_bs_map, + .bs_unmap = generic_bs_unmap, + .bs_subregion = generic_bs_subregion, /* allocation/deallocation */ - generic_bs_alloc, - generic_bs_free, + .bs_alloc = generic_bs_alloc, + .bs_free = generic_bs_free, /* barrier */ - generic_bs_barrier, + .bs_barrier = generic_bs_barrier, /* read (single) */ - NULL, /* bs_r_1, Use inline code in bus.h */ - NULL, /* bs_r_2, Use inline code in bus.h */ - NULL, /* bs_r_4, Use inline code in bus.h */ - NULL, /* bs_r_8, Use inline code in bus.h */ + .bs_r_1 = NULL, /* Use inline code in bus.h */ + .bs_r_2 = NULL, /* Use inline code in bus.h */ + .bs_r_4 = NULL, /* Use inline code in bus.h */ + .bs_r_8 = NULL, /* Use inline code in bus.h */ /* read multiple */ - generic_bs_rm_1, - generic_armv4_bs_rm_2, - generic_bs_rm_4, - NULL, + .bs_rm_1 = generic_bs_rm_1, + .bs_rm_2 = generic_armv4_bs_rm_2, + .bs_rm_4 = generic_bs_rm_4, + .bs_rm_8 = BS_UNIMPLEMENTED, /* read region */ - generic_bs_rr_1, - generic_armv4_bs_rr_2, - generic_bs_rr_4, - NULL, + .bs_rr_1 = generic_bs_rr_1, + .bs_rr_2 = generic_armv4_bs_rr_2, + .bs_rr_4 = generic_bs_rr_4, + .bs_rr_8 = BS_UNIMPLEMENTED, /* write (single) */ - NULL, /* bs_w_1, Use inline code in bus.h */ - NULL, /* bs_w_2, Use inline code in bus.h */ - NULL, /* bs_w_4, Use inline code in bus.h */ - NULL, /* bs_w_8, Use inline code in bus.h */ + .bs_w_1 = NULL, /* Use inline code in bus.h */ + .bs_w_2 = NULL, /* Use inline code in bus.h */ + .bs_w_4 = NULL, /* Use inline code in bus.h */ + .bs_w_8 = NULL, /* Use inline code in bus.h */ /* write multiple */ - generic_bs_wm_1, - generic_armv4_bs_wm_2, - generic_bs_wm_4, - NULL, + .bs_wm_1 = generic_bs_wm_1, + .bs_wm_2 = generic_armv4_bs_wm_2, + .bs_wm_4 = generic_bs_wm_4, + .bs_wm_8 = BS_UNIMPLEMENTED, /* write region */ - generic_bs_wr_1, - generic_armv4_bs_wr_2, - generic_bs_wr_4, - NULL, + .bs_wr_1 = generic_bs_wr_1, + .bs_wr_2 = generic_armv4_bs_wr_2, + .bs_wr_4 = generic_bs_wr_4, + .bs_wr_8 = BS_UNIMPLEMENTED, /* set multiple */ - NULL, - NULL, - NULL, - NULL, + .bs_sm_1 = BS_UNIMPLEMENTED, + .bs_sm_2 = BS_UNIMPLEMENTED, + .bs_sm_4 = BS_UNIMPLEMENTED, + .bs_sm_8 = BS_UNIMPLEMENTED, /* set region */ - generic_bs_sr_1, - generic_armv4_bs_sr_2, - generic_bs_sr_4, - NULL, + .bs_sr_1 = generic_bs_sr_1, + .bs_sr_2 = generic_armv4_bs_sr_2, + .bs_sr_4 = generic_bs_sr_4, + .bs_sr_8 = BS_UNIMPLEMENTED, /* copy */ - NULL, - generic_armv4_bs_c_2, - NULL, - NULL, + .bs_c_1 = BS_UNIMPLEMENTED, + .bs_c_2 = generic_armv4_bs_c_2, + .bs_c_4 = BS_UNIMPLEMENTED, + .bs_c_8 = BS_UNIMPLEMENTED, /* read stream (single) */ - NULL, /* bs_r_1_s, Use inline code in bus.h */ - NULL, /* bs_r_2_s, Use inline code in bus.h */ - NULL, /* bs_r_4_s, Use inline code in bus.h */ - NULL, /* bs_r_8_s, Use inline code in bus.h */ + .bs_r_1_s = NULL, /* Use inline code in bus.h */ + .bs_r_2_s = NULL, /* Use inline code in bus.h */ + .bs_r_4_s = NULL, /* Use inline code in bus.h */ + .bs_r_8_s = NULL, /* Use inline code in bus.h */ /* read multiple stream */ - NULL, - generic_armv4_bs_rm_2, /* bus_space_read_multi_stream_2 */ - NULL, - NULL, + .bs_rm_1_s = generic_bs_rm_1, + .bs_rm_2_s = generic_armv4_bs_rm_2, + .bs_rm_4_s = generic_bs_rm_4, + .bs_rm_8_s = BS_UNIMPLEMENTED, /* read region stream */ - NULL, - NULL, - NULL, - NULL, + .bs_rr_1_s = generic_bs_rr_1, + .bs_rr_2_s = generic_bs_rr_2, + .bs_rr_4_s = generic_bs_rr_4, + .bs_rr_8_s = BS_UNIMPLEMENTED, /* write stream (single) */ - NULL, /* bs_w_1_s, Use inline code in bus.h */ - NULL, /* bs_w_2_s, Use inline code in bus.h */ - NULL, /* bs_w_4_s, Use inline code in bus.h */ - NULL, /* bs_w_8_s, Use inline code in bus.h */ + .bs_w_1_s = NULL, /* Use inline code in bus.h */ + .bs_w_2_s = NULL, /* Use inline code in bus.h */ + .bs_w_4_s = NULL, /* Use inline code in bus.h */ + .bs_w_8_s = NULL, /* Use inline code in bus.h */ /* write multiple stream */ - NULL, - generic_armv4_bs_wm_2, /* bus_space_write_multi_stream_2 */ - NULL, - NULL, + .bs_wm_1_s = generic_bs_wm_1, + .bs_wm_2_s = generic_armv4_bs_wm_2, + .bs_wm_4_s = generic_bs_wm_4, + .bs_wm_8_s = BS_UNIMPLEMENTED, /* write region stream */ - NULL, - NULL, - NULL, - NULL + .bs_wr_1_s = generic_bs_wr_1, + .bs_wr_2_s = generic_bs_wr_4, + .bs_wr_4_s = generic_bs_wr_8, + .bs_wr_8_s = BS_UNIMPLEMENTED, }; bus_space_tag_t fdtbus_bs_tag = &_base_tag; From 8b44e14d1e5c4fd0caad8246869aab56c5aee152 Mon Sep 17 00:00:00 2001 From: ian Date: Wed, 21 Jan 2015 02:49:19 +0000 Subject: [PATCH 112/258] Use arm/bus_space-v6.c for all armv6 systems, the essentially identical files for lpc and xilinx aren't needed. Also, fix a couple paste-os. --- sys/arm/arm/bus_space-v6.c | 6 +- sys/arm/lpc/files.lpc | 2 +- sys/arm/lpc/lpc_space.c | 147 --------------------------------- sys/arm/xilinx/files.zynq7 | 2 +- sys/arm/xilinx/zy7_bus_space.c | 115 -------------------------- 5 files changed, 5 insertions(+), 267 deletions(-) delete mode 100644 sys/arm/lpc/lpc_space.c delete mode 100644 sys/arm/xilinx/zy7_bus_space.c diff --git a/sys/arm/arm/bus_space-v6.c b/sys/arm/arm/bus_space-v6.c index 3414c5009cc9..6b6d12004ab9 100644 --- a/sys/arm/arm/bus_space-v6.c +++ b/sys/arm/arm/bus_space-v6.c @@ -137,7 +137,7 @@ static struct bus_space _base_tag = { /* read region stream */ .bs_rr_1_s = generic_bs_rr_1, - .bs_rr_2_s = generic_bs_rr_2, + .bs_rr_2_s = generic_armv4_bs_rr_2, .bs_rr_4_s = generic_bs_rr_4, .bs_rr_8_s = BS_UNIMPLEMENTED, @@ -155,8 +155,8 @@ static struct bus_space _base_tag = { /* write region stream */ .bs_wr_1_s = generic_bs_wr_1, - .bs_wr_2_s = generic_bs_wr_4, - .bs_wr_4_s = generic_bs_wr_8, + .bs_wr_2_s = generic_armv4_bs_wr_2, + .bs_wr_4_s = generic_bs_wr_4, .bs_wr_8_s = BS_UNIMPLEMENTED, }; diff --git a/sys/arm/lpc/files.lpc b/sys/arm/lpc/files.lpc index 8b24d3b0a9b4..8e196ad5512a 100644 --- a/sys/arm/lpc/files.lpc +++ b/sys/arm/lpc/files.lpc @@ -1,9 +1,9 @@ # $FreeBSD$ +arm/arm/bus_space-v6.c standard arm/arm/bus_space_generic.c standard arm/arm/cpufunc_asm_arm9.S standard arm/arm/cpufunc_asm_armv5.S standard arm/lpc/lpc_machdep.c standard -arm/lpc/lpc_space.c standard arm/lpc/lpc_pwr.c standard arm/lpc/lpc_intc.c standard arm/lpc/lpc_timer.c standard diff --git a/sys/arm/lpc/lpc_space.c b/sys/arm/lpc/lpc_space.c deleted file mode 100644 index 194e469f2229..000000000000 --- a/sys/arm/lpc/lpc_space.c +++ /dev/null @@ -1,147 +0,0 @@ -/*- - * Copyright (c) 2011 Jakub Wojciech Klama - * 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 - -bs_protos(generic); -bs_protos(generic_armv4); - -static struct bus_space _base_tag = { - /* cookie */ - NULL, - - /* mapping/unmapping */ - generic_bs_map, - generic_bs_unmap, - generic_bs_subregion, - - /* allocation/deallocation */ - generic_bs_alloc, - generic_bs_free, - - /* barrier */ - generic_bs_barrier, - - /* read (single) */ - generic_bs_r_1, - generic_armv4_bs_r_2, - generic_bs_r_4, - NULL, - - /* read (multiple) */ - generic_bs_rm_1, - generic_armv4_bs_rm_2, - generic_bs_rm_4, - NULL, - - /* read region */ - generic_bs_rr_1, - generic_armv4_bs_rr_2, - generic_bs_rr_4, - NULL, - - /* write (single) */ - generic_bs_w_1, - generic_armv4_bs_w_2, - generic_bs_w_4, - NULL, - - /* write multiple */ - generic_bs_wm_1, - generic_armv4_bs_wm_2, - generic_bs_wm_4, - NULL, - - /* write region */ - NULL, - NULL, - NULL, - NULL, - - /* set multiple */ - NULL, - NULL, - NULL, - NULL, - - /* set region */ - NULL, - NULL, - NULL, - NULL, - - /* copy */ - NULL, - NULL, - NULL, - NULL, - - /* read stream (single) */ - NULL, - NULL, - NULL, - NULL, - - /* read multiple stream */ - NULL, - generic_armv4_bs_rm_2, - NULL, - NULL, - - /* read region stream */ - NULL, - NULL, - NULL, - NULL, - - /* write stream (single) */ - NULL, - NULL, - NULL, - NULL, - - /* write multiple stream */ - NULL, - generic_armv4_bs_wm_2, - NULL, - NULL, - - /* write region stream */ - NULL, - NULL, - NULL, - NULL, -}; - -bus_space_tag_t fdtbus_bs_tag = &_base_tag; diff --git a/sys/arm/xilinx/files.zynq7 b/sys/arm/xilinx/files.zynq7 index 4caf90afbecf..9682904d91ae 100644 --- a/sys/arm/xilinx/files.zynq7 +++ b/sys/arm/xilinx/files.zynq7 @@ -5,6 +5,7 @@ kern/kern_clocksource.c standard +arm/arm/bus_space-v6.c standard arm/arm/bus_space_generic.c standard arm/arm/bus_space_asm_generic.S standard arm/arm/cpufunc_asm_armv5.S standard @@ -18,7 +19,6 @@ arm/arm/pl310.c standard arm/xilinx/zy7_machdep.c standard arm/xilinx/zy7_l2cache.c standard -arm/xilinx/zy7_bus_space.c standard arm/xilinx/zy7_slcr.c standard arm/xilinx/zy7_devcfg.c standard arm/xilinx/zy7_mp.c optional smp diff --git a/sys/arm/xilinx/zy7_bus_space.c b/sys/arm/xilinx/zy7_bus_space.c deleted file mode 100644 index e7ffc09f0213..000000000000 --- a/sys/arm/xilinx/zy7_bus_space.c +++ /dev/null @@ -1,115 +0,0 @@ -/*- - * Copyright (C) 2008 MARVELL INTERNATIONAL LTD. - * All rights reserved. - * - * Developed by Semihalf. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of MARVELL nor the names of contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY 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 - -/* Prototypes for all the bus_space structure functions */ -bs_protos(generic); -bs_protos(generic_armv4); - -struct bus_space _base_tag = { - /* cookie */ - .bs_privdata = (void *) 0, - - /* mapping/unmapping */ - .bs_map = generic_bs_map, - .bs_unmap = generic_bs_unmap, - .bs_subregion = generic_bs_subregion, - - /* allocation/deallocation */ - .bs_alloc = generic_bs_alloc, - .bs_free = generic_bs_free, - - /* barrier */ - .bs_barrier = generic_bs_barrier, - - /* read (single) */ - .bs_r_1 = generic_bs_r_1, - .bs_r_2 = generic_armv4_bs_r_2, - .bs_r_4 = generic_bs_r_4, - .bs_r_8 = NULL, - - /* read multiple */ - .bs_rm_1 = generic_bs_rm_1, - .bs_rm_2 = generic_armv4_bs_rm_2, - .bs_rm_4 = generic_bs_rm_4, - .bs_rm_8 = NULL, - - /* read region */ - .bs_rr_1 = generic_bs_rr_1, - .bs_rr_2 = generic_armv4_bs_rr_2, - .bs_rr_4 = generic_bs_rr_4, - .bs_rr_8 = NULL, - - /* write (single) */ - .bs_w_1 = generic_bs_w_1, - .bs_w_2 = generic_armv4_bs_w_2, - .bs_w_4 = generic_bs_w_4, - .bs_w_8 = NULL, - - /* write multiple */ - .bs_wm_1 = generic_bs_wm_1, - .bs_wm_2 = generic_armv4_bs_wm_2, - .bs_wm_4 = generic_bs_wm_4, - .bs_wm_8 = NULL, - - /* write region */ - .bs_wr_1 = generic_bs_wr_1, - .bs_wr_2 = generic_armv4_bs_wr_2, - .bs_wr_4 = generic_bs_wr_4, - .bs_wr_8 = NULL, - - /* set multiple */ - /* XXX not implemented */ - - /* set region */ - .bs_sr_1 = NULL, - .bs_sr_2 = generic_armv4_bs_sr_2, - .bs_sr_4 = generic_bs_sr_4, - .bs_sr_8 = NULL, - - /* copy */ - .bs_c_1 = NULL, - .bs_c_2 = generic_armv4_bs_c_2, - .bs_c_4 = NULL, - .bs_c_8 = NULL, -}; - -bus_space_tag_t fdtbus_bs_tag = &_base_tag; From b4fa4f6baa40f0815a0bad3475903e47fee4b076 Mon Sep 17 00:00:00 2001 From: ian Date: Wed, 21 Jan 2015 02:56:13 +0000 Subject: [PATCH 113/258] For some reason, all the arm bus_space functions that work with uint16 values have armv4 in the name. There's nothing armv4-special about them, so just use the same sort of names as all the other functions. --- sys/arm/arm/bus_space-v6.c | 21 +++++++------- sys/arm/arm/bus_space_asm_generic.S | 32 ++++++++++----------- sys/arm/at91/at91.c | 29 +++++++++---------- sys/arm/cavium/cns11xx/econa.c | 15 +++++----- sys/arm/mv/bus_space.c | 15 +++++----- sys/arm/samsung/s3c2xx0/s3c2xx0_space.c | 17 ++++++----- sys/arm/versatile/bus_space.c | 17 ++++++----- sys/arm/versatile/versatile_pci_bus_space.c | 13 ++++----- sys/arm/xscale/i80321/i80321_space.c | 29 +++++++++---------- sys/arm/xscale/i80321/obio_space.c | 5 ++-- sys/arm/xscale/i8134x/i81342_space.c | 29 +++++++++---------- sys/arm/xscale/i8134x/obio_space.c | 5 ++-- sys/arm/xscale/ixp425/ixp425_a4x_space.c | 1 - sys/arm/xscale/ixp425/ixp425_space.c | 17 ++++++----- sys/arm/xscale/pxa/pxa_space.c | 9 +++--- 15 files changed, 120 insertions(+), 134 deletions(-) diff --git a/sys/arm/arm/bus_space-v6.c b/sys/arm/arm/bus_space-v6.c index 6b6d12004ab9..ce26c46171ef 100644 --- a/sys/arm/arm/bus_space-v6.c +++ b/sys/arm/arm/bus_space-v6.c @@ -38,7 +38,6 @@ __FBSDID("$FreeBSD$"); /* Prototypes for all the bus_space structure functions */ bs_protos(generic); -bs_protos(generic_armv4); static void bs_unimplemented(void) @@ -77,13 +76,13 @@ static struct bus_space _base_tag = { /* read multiple */ .bs_rm_1 = generic_bs_rm_1, - .bs_rm_2 = generic_armv4_bs_rm_2, + .bs_rm_2 = generic_bs_rm_2, .bs_rm_4 = generic_bs_rm_4, .bs_rm_8 = BS_UNIMPLEMENTED, /* read region */ .bs_rr_1 = generic_bs_rr_1, - .bs_rr_2 = generic_armv4_bs_rr_2, + .bs_rr_2 = generic_bs_rr_2, .bs_rr_4 = generic_bs_rr_4, .bs_rr_8 = BS_UNIMPLEMENTED, @@ -95,13 +94,13 @@ static struct bus_space _base_tag = { /* write multiple */ .bs_wm_1 = generic_bs_wm_1, - .bs_wm_2 = generic_armv4_bs_wm_2, + .bs_wm_2 = generic_bs_wm_2, .bs_wm_4 = generic_bs_wm_4, .bs_wm_8 = BS_UNIMPLEMENTED, /* write region */ .bs_wr_1 = generic_bs_wr_1, - .bs_wr_2 = generic_armv4_bs_wr_2, + .bs_wr_2 = generic_bs_wr_2, .bs_wr_4 = generic_bs_wr_4, .bs_wr_8 = BS_UNIMPLEMENTED, @@ -113,13 +112,13 @@ static struct bus_space _base_tag = { /* set region */ .bs_sr_1 = generic_bs_sr_1, - .bs_sr_2 = generic_armv4_bs_sr_2, + .bs_sr_2 = generic_bs_sr_2, .bs_sr_4 = generic_bs_sr_4, .bs_sr_8 = BS_UNIMPLEMENTED, /* copy */ .bs_c_1 = BS_UNIMPLEMENTED, - .bs_c_2 = generic_armv4_bs_c_2, + .bs_c_2 = generic_bs_c_2, .bs_c_4 = BS_UNIMPLEMENTED, .bs_c_8 = BS_UNIMPLEMENTED, @@ -131,13 +130,13 @@ static struct bus_space _base_tag = { /* read multiple stream */ .bs_rm_1_s = generic_bs_rm_1, - .bs_rm_2_s = generic_armv4_bs_rm_2, + .bs_rm_2_s = generic_bs_rm_2, .bs_rm_4_s = generic_bs_rm_4, .bs_rm_8_s = BS_UNIMPLEMENTED, /* read region stream */ .bs_rr_1_s = generic_bs_rr_1, - .bs_rr_2_s = generic_armv4_bs_rr_2, + .bs_rr_2_s = generic_bs_rr_2, .bs_rr_4_s = generic_bs_rr_4, .bs_rr_8_s = BS_UNIMPLEMENTED, @@ -149,13 +148,13 @@ static struct bus_space _base_tag = { /* write multiple stream */ .bs_wm_1_s = generic_bs_wm_1, - .bs_wm_2_s = generic_armv4_bs_wm_2, + .bs_wm_2_s = generic_bs_wm_2, .bs_wm_4_s = generic_bs_wm_4, .bs_wm_8_s = BS_UNIMPLEMENTED, /* write region stream */ .bs_wr_1_s = generic_bs_wr_1, - .bs_wr_2_s = generic_armv4_bs_wr_2, + .bs_wr_2_s = generic_bs_wr_2, .bs_wr_4_s = generic_bs_wr_4, .bs_wr_8_s = BS_UNIMPLEMENTED, }; diff --git a/sys/arm/arm/bus_space_asm_generic.S b/sys/arm/arm/bus_space_asm_generic.S index 4aa719760a5c..9d2b11df2fe5 100644 --- a/sys/arm/arm/bus_space_asm_generic.S +++ b/sys/arm/arm/bus_space_asm_generic.S @@ -52,10 +52,10 @@ ENTRY(generic_bs_r_1) RET END(generic_bs_r_1) -ENTRY(generic_armv4_bs_r_2) +ENTRY(generic_bs_r_2) ldrh r0, [r1, r2] RET -END(generic_armv4_bs_r_2) +END(generic_bs_r_2) ENTRY(generic_bs_r_4) ldr r0, [r1, r2] @@ -71,10 +71,10 @@ ENTRY(generic_bs_w_1) RET END(generic_bs_w_1) -ENTRY(generic_armv4_bs_w_2) +ENTRY(generic_bs_w_2) strh r3, [r1, r2] RET -END(generic_armv4_bs_w_2) +END(generic_bs_w_2) ENTRY(generic_bs_w_4) str r3, [r1, r2] @@ -100,7 +100,7 @@ ENTRY(generic_bs_rm_1) RET END(generic_bs_rm_1) -ENTRY(generic_armv4_bs_rm_2) +ENTRY(generic_bs_rm_2) add r0, r1, r2 mov r1, r3 ldr r2, [sp, #0] @@ -113,7 +113,7 @@ ENTRY(generic_armv4_bs_rm_2) bne 1b RET -END(generic_armv4_bs_rm_2) +END(generic_bs_rm_2) ENTRY(generic_bs_rm_4) add r0, r1, r2 @@ -149,7 +149,7 @@ ENTRY(generic_bs_wm_1) RET END(generic_bs_wm_1) -ENTRY(generic_armv4_bs_wm_2) +ENTRY(generic_bs_wm_2) add r0, r1, r2 mov r1, r3 ldr r2, [sp, #0] @@ -162,7 +162,7 @@ ENTRY(generic_armv4_bs_wm_2) bne 1b RET -END(generic_armv4_bs_wm_2) +END(generic_bs_wm_2) ENTRY(generic_bs_wm_4) add r0, r1, r2 @@ -198,7 +198,7 @@ ENTRY(generic_bs_rr_1) RET END(generic_bs_rr_1) -ENTRY(generic_armv4_bs_rr_2) +ENTRY(generic_bs_rr_2) add r0, r1, r2 mov r1, r3 ldr r2, [sp, #0] @@ -211,7 +211,7 @@ ENTRY(generic_armv4_bs_rr_2) bne 1b RET -END(generic_armv4_bs_rr_2) +END(generic_bs_rr_2) ENTRY(generic_bs_rr_4) add r0, r1, r2 @@ -247,7 +247,7 @@ ENTRY(generic_bs_wr_1) RET END(generic_bs_wr_1) -ENTRY(generic_armv4_bs_wr_2) +ENTRY(generic_bs_wr_2) add r0, r1, r2 mov r1, r3 ldr r2, [sp, #0] @@ -260,7 +260,7 @@ ENTRY(generic_armv4_bs_wr_2) bne 1b RET -END(generic_armv4_bs_wr_2) +END(generic_bs_wr_2) ENTRY(generic_bs_wr_4) add r0, r1, r2 @@ -295,7 +295,7 @@ ENTRY(generic_bs_sr_1) RET END(generic_bs_sr_1) -ENTRY(generic_armv4_bs_sr_2) +ENTRY(generic_bs_sr_2) add r0, r1, r2 mov r1, r3 ldr r2, [sp, #0] @@ -307,7 +307,7 @@ ENTRY(generic_armv4_bs_sr_2) bne 1b RET -END(generic_armv4_bs_sr_2) +END(generic_bs_sr_2) ENTRY(generic_bs_sr_4) add r0, r1, r2 @@ -327,7 +327,7 @@ END(generic_bs_sr_4) * copy region */ -ENTRY(generic_armv4_bs_c_2) +ENTRY(generic_bs_c_2) add r0, r1, r2 ldr r2, [sp, #0] add r1, r2, r3 @@ -356,5 +356,5 @@ ENTRY(generic_armv4_bs_c_2) bne 3b RET -END(generic_armv4_bs_c_2) +END(generic_bs_c_2) diff --git a/sys/arm/at91/at91.c b/sys/arm/at91/at91.c index a8a1f5e4af3e..8c5c86c39c29 100644 --- a/sys/arm/at91/at91.c +++ b/sys/arm/at91/at91.c @@ -116,7 +116,6 @@ bus_dma_get_range_nb(void) } bs_protos(generic); -bs_protos(generic_armv4); struct bus_space at91_bs_tag = { /* cookie */ @@ -136,37 +135,37 @@ struct bus_space at91_bs_tag = { /* read (single) */ generic_bs_r_1, - generic_armv4_bs_r_2, + generic_bs_r_2, generic_bs_r_4, NULL, /* read multiple */ generic_bs_rm_1, - generic_armv4_bs_rm_2, + generic_bs_rm_2, generic_bs_rm_4, NULL, /* read region */ generic_bs_rr_1, - generic_armv4_bs_rr_2, + generic_bs_rr_2, generic_bs_rr_4, NULL, /* write (single) */ generic_bs_w_1, - generic_armv4_bs_w_2, + generic_bs_w_2, generic_bs_w_4, NULL, /* write multiple */ generic_bs_wm_1, - generic_armv4_bs_wm_2, + generic_bs_wm_2, generic_bs_wm_4, NULL, /* write region */ NULL, - generic_armv4_bs_wr_2, + generic_bs_wr_2, generic_bs_wr_4, NULL, @@ -178,49 +177,49 @@ struct bus_space at91_bs_tag = { /* set region */ NULL, - generic_armv4_bs_sr_2, + generic_bs_sr_2, generic_bs_sr_4, NULL, /* copy */ NULL, - generic_armv4_bs_c_2, + generic_bs_c_2, NULL, NULL, /* read (single) stream */ generic_bs_r_1, - generic_armv4_bs_r_2, + generic_bs_r_2, generic_bs_r_4, NULL, /* read multiple stream */ generic_bs_rm_1, - generic_armv4_bs_rm_2, + generic_bs_rm_2, generic_bs_rm_4, NULL, /* read region stream */ generic_bs_rr_1, - generic_armv4_bs_rr_2, + generic_bs_rr_2, generic_bs_rr_4, NULL, /* write (single) stream */ generic_bs_w_1, - generic_armv4_bs_w_2, + generic_bs_w_2, generic_bs_w_4, NULL, /* write multiple stream */ generic_bs_wm_1, - generic_armv4_bs_wm_2, + generic_bs_wm_2, generic_bs_wm_4, NULL, /* write region stream */ NULL, - generic_armv4_bs_wr_2, + generic_bs_wr_2, generic_bs_wr_4, NULL, }; diff --git a/sys/arm/cavium/cns11xx/econa.c b/sys/arm/cavium/cns11xx/econa.c index c331e20d9260..e79e6e8d810a 100644 --- a/sys/arm/cavium/cns11xx/econa.c +++ b/sys/arm/cavium/cns11xx/econa.c @@ -57,7 +57,6 @@ unsigned int AHB_clock; unsigned int APB_clock; bs_protos(generic); -bs_protos(generic_armv4); struct bus_space econa_bs_tag = { /* cookie */ @@ -77,31 +76,31 @@ struct bus_space econa_bs_tag = { /* read (single) */ generic_bs_r_1, - generic_armv4_bs_r_2, + generic_bs_r_2, generic_bs_r_4, NULL, /* read multiple */ generic_bs_rm_1, - generic_armv4_bs_rm_2, + generic_bs_rm_2, generic_bs_rm_4, NULL, /* read region */ generic_bs_rr_1, - generic_armv4_bs_rr_2, + generic_bs_rr_2, generic_bs_rr_4, NULL, /* write (single) */ generic_bs_w_1, - generic_armv4_bs_w_2, + generic_bs_w_2, generic_bs_w_4, NULL, /* write multiple */ generic_bs_wm_1, - generic_armv4_bs_wm_2, + generic_bs_wm_2, generic_bs_wm_4, NULL, @@ -137,7 +136,7 @@ struct bus_space econa_bs_tag = { /* read multiple stream */ NULL, - generic_armv4_bs_rm_2, + generic_bs_rm_2, NULL, NULL, @@ -155,7 +154,7 @@ struct bus_space econa_bs_tag = { /* write multiple stream */ NULL, - generic_armv4_bs_wm_2, + generic_bs_wm_2, NULL, NULL, diff --git a/sys/arm/mv/bus_space.c b/sys/arm/mv/bus_space.c index 356f3e3db1db..6bd4f3486dfa 100644 --- a/sys/arm/mv/bus_space.c +++ b/sys/arm/mv/bus_space.c @@ -46,7 +46,6 @@ __FBSDID("$FreeBSD$"); /* Prototypes for all the bus_space structure functions */ bs_protos(generic); -bs_protos(generic_armv4); /* * The bus space tag. This is constant for all instances, so @@ -70,31 +69,31 @@ static struct bus_space _base_tag = { /* read (single) */ generic_bs_r_1, - generic_armv4_bs_r_2, + generic_bs_r_2, generic_bs_r_4, NULL, /* read multiple */ generic_bs_rm_1, - generic_armv4_bs_rm_2, + generic_bs_rm_2, generic_bs_rm_4, NULL, /* read region */ generic_bs_rr_1, - generic_armv4_bs_rr_2, + generic_bs_rr_2, generic_bs_rr_4, NULL, /* write (single) */ generic_bs_w_1, - generic_armv4_bs_w_2, + generic_bs_w_2, generic_bs_w_4, NULL, /* write multiple */ generic_bs_wm_1, - generic_armv4_bs_wm_2, + generic_bs_wm_2, generic_bs_wm_4, NULL, @@ -130,7 +129,7 @@ static struct bus_space _base_tag = { /* read multiple stream */ NULL, - generic_armv4_bs_rm_2, /* bus_space_read_multi_stream_2 */ + generic_bs_rm_2, /* bus_space_read_multi_stream_2 */ NULL, NULL, @@ -148,7 +147,7 @@ static struct bus_space _base_tag = { /* write multiple stream */ NULL, - generic_armv4_bs_wm_2, /* bus_space_write_multi_stream_2 */ + generic_bs_wm_2, /* bus_space_write_multi_stream_2 */ NULL, NULL, diff --git a/sys/arm/samsung/s3c2xx0/s3c2xx0_space.c b/sys/arm/samsung/s3c2xx0/s3c2xx0_space.c index fe01d2b389cb..61c00eb6841a 100644 --- a/sys/arm/samsung/s3c2xx0/s3c2xx0_space.c +++ b/sys/arm/samsung/s3c2xx0/s3c2xx0_space.c @@ -90,7 +90,6 @@ __FBSDID("$FreeBSD$"); /* Prototypes for all the bus_space structure functions */ bs_protos(generic); -bs_protos(generic_armv4); struct bus_space s3c2xx0_bs_tag = { /* cookie */ @@ -110,37 +109,37 @@ struct bus_space s3c2xx0_bs_tag = { /* read (single) */ generic_bs_r_1, - generic_armv4_bs_r_2, + generic_bs_r_2, generic_bs_r_4, NULL, /* read multiple */ generic_bs_rm_1, - generic_armv4_bs_rm_2, + generic_bs_rm_2, generic_bs_rm_4, NULL, /* read region */ generic_bs_rr_1, - generic_armv4_bs_rr_2, + generic_bs_rr_2, generic_bs_rr_4, NULL, /* write (single) */ generic_bs_w_1, - generic_armv4_bs_w_2, + generic_bs_w_2, generic_bs_w_4, NULL, /* write multiple */ generic_bs_wm_1, - generic_armv4_bs_wm_2, + generic_bs_wm_2, generic_bs_wm_4, NULL, /* write region */ generic_bs_wr_1, - generic_armv4_bs_wr_2, + generic_bs_wr_2, generic_bs_wr_4, NULL, @@ -152,13 +151,13 @@ struct bus_space s3c2xx0_bs_tag = { /* set region */ generic_bs_sr_1, - generic_armv4_bs_sr_2, + generic_bs_sr_2, NULL, NULL, /* copy */ NULL, - generic_armv4_bs_c_2, + generic_bs_c_2, NULL, NULL, }; diff --git a/sys/arm/versatile/bus_space.c b/sys/arm/versatile/bus_space.c index e7ffc09f0213..850feefb1aff 100644 --- a/sys/arm/versatile/bus_space.c +++ b/sys/arm/versatile/bus_space.c @@ -42,7 +42,6 @@ __FBSDID("$FreeBSD$"); /* Prototypes for all the bus_space structure functions */ bs_protos(generic); -bs_protos(generic_armv4); struct bus_space _base_tag = { /* cookie */ @@ -62,37 +61,37 @@ struct bus_space _base_tag = { /* read (single) */ .bs_r_1 = generic_bs_r_1, - .bs_r_2 = generic_armv4_bs_r_2, + .bs_r_2 = generic_bs_r_2, .bs_r_4 = generic_bs_r_4, .bs_r_8 = NULL, /* read multiple */ .bs_rm_1 = generic_bs_rm_1, - .bs_rm_2 = generic_armv4_bs_rm_2, + .bs_rm_2 = generic_bs_rm_2, .bs_rm_4 = generic_bs_rm_4, .bs_rm_8 = NULL, /* read region */ .bs_rr_1 = generic_bs_rr_1, - .bs_rr_2 = generic_armv4_bs_rr_2, + .bs_rr_2 = generic_bs_rr_2, .bs_rr_4 = generic_bs_rr_4, .bs_rr_8 = NULL, /* write (single) */ .bs_w_1 = generic_bs_w_1, - .bs_w_2 = generic_armv4_bs_w_2, + .bs_w_2 = generic_bs_w_2, .bs_w_4 = generic_bs_w_4, .bs_w_8 = NULL, /* write multiple */ .bs_wm_1 = generic_bs_wm_1, - .bs_wm_2 = generic_armv4_bs_wm_2, + .bs_wm_2 = generic_bs_wm_2, .bs_wm_4 = generic_bs_wm_4, .bs_wm_8 = NULL, /* write region */ .bs_wr_1 = generic_bs_wr_1, - .bs_wr_2 = generic_armv4_bs_wr_2, + .bs_wr_2 = generic_bs_wr_2, .bs_wr_4 = generic_bs_wr_4, .bs_wr_8 = NULL, @@ -101,13 +100,13 @@ struct bus_space _base_tag = { /* set region */ .bs_sr_1 = NULL, - .bs_sr_2 = generic_armv4_bs_sr_2, + .bs_sr_2 = generic_bs_sr_2, .bs_sr_4 = generic_bs_sr_4, .bs_sr_8 = NULL, /* copy */ .bs_c_1 = NULL, - .bs_c_2 = generic_armv4_bs_c_2, + .bs_c_2 = generic_bs_c_2, .bs_c_4 = NULL, .bs_c_8 = NULL, }; diff --git a/sys/arm/versatile/versatile_pci_bus_space.c b/sys/arm/versatile/versatile_pci_bus_space.c index 2c2e0b537c94..894544016972 100644 --- a/sys/arm/versatile/versatile_pci_bus_space.c +++ b/sys/arm/versatile/versatile_pci_bus_space.c @@ -37,7 +37,6 @@ __FBSDID("$FreeBSD$"); /* Prototypes for all the bus_space structure functions */ bs_protos(generic); -bs_protos(generic_armv4); /* * Bus space that handles offsets in word for 1/2 bytes read/write access. @@ -61,37 +60,37 @@ static struct bus_space bus_space_pcimem = { /* read (single) */ generic_bs_r_1, - generic_armv4_bs_r_2, + generic_bs_r_2, generic_bs_r_4, NULL, /* read multiple */ generic_bs_rm_1, - generic_armv4_bs_rm_2, + generic_bs_rm_2, generic_bs_rm_4, NULL, /* read region */ generic_bs_rr_1, - generic_armv4_bs_rr_2, + generic_bs_rr_2, generic_bs_rr_4, NULL, /* write (single) */ generic_bs_w_1, - generic_armv4_bs_w_2, + generic_bs_w_2, generic_bs_w_4, NULL, /* write multiple */ generic_bs_wm_1, - generic_armv4_bs_wm_2, + generic_bs_wm_2, generic_bs_wm_4, NULL, /* write region */ generic_bs_wr_1, - generic_armv4_bs_wr_2, + generic_bs_wr_2, generic_bs_wr_4, NULL, diff --git a/sys/arm/xscale/i80321/i80321_space.c b/sys/arm/xscale/i80321/i80321_space.c index 44a2ca800218..da4ad2185a86 100644 --- a/sys/arm/xscale/i80321/i80321_space.c +++ b/sys/arm/xscale/i80321/i80321_space.c @@ -64,7 +64,6 @@ bs_protos(i80321); bs_protos(i80321_io); bs_protos(i80321_mem); bs_protos(generic); -bs_protos(generic_armv4); /* * Template bus_space -- copied, and the bits that are NULL are @@ -88,37 +87,37 @@ const struct bus_space i80321_bs_tag_template = { /* read (single) */ generic_bs_r_1, - generic_armv4_bs_r_2, + generic_bs_r_2, generic_bs_r_4, NULL, /* read multiple */ generic_bs_rm_1, - generic_armv4_bs_rm_2, + generic_bs_rm_2, generic_bs_rm_4, NULL, /* read region */ generic_bs_rr_1, - generic_armv4_bs_rr_2, + generic_bs_rr_2, generic_bs_rr_4, NULL, /* write (single) */ generic_bs_w_1, - generic_armv4_bs_w_2, + generic_bs_w_2, generic_bs_w_4, NULL, /* write multiple */ generic_bs_wm_1, - generic_armv4_bs_wm_2, + generic_bs_wm_2, generic_bs_wm_4, NULL, /* write region */ NULL, - generic_armv4_bs_wr_2, + generic_bs_wr_2, generic_bs_wr_4, NULL, @@ -130,49 +129,49 @@ const struct bus_space i80321_bs_tag_template = { /* set region */ NULL, - generic_armv4_bs_sr_2, + generic_bs_sr_2, generic_bs_sr_4, NULL, /* copy */ NULL, - generic_armv4_bs_c_2, + generic_bs_c_2, NULL, NULL, /* read (single) stream */ generic_bs_r_1, - generic_armv4_bs_r_2, + generic_bs_r_2, generic_bs_r_4, NULL, /* read multiple stream */ generic_bs_rm_1, - generic_armv4_bs_rm_2, + generic_bs_rm_2, generic_bs_rm_4, NULL, /* read region stream */ generic_bs_rr_1, - generic_armv4_bs_rr_2, + generic_bs_rr_2, generic_bs_rr_4, NULL, /* write (single) stream */ generic_bs_w_1, - generic_armv4_bs_w_2, + generic_bs_w_2, generic_bs_w_4, NULL, /* write multiple stream */ generic_bs_wm_1, - generic_armv4_bs_wm_2, + generic_bs_wm_2, generic_bs_wm_4, NULL, /* write region stream */ NULL, - generic_armv4_bs_wr_2, + generic_bs_wr_2, generic_bs_wr_4, NULL, }; diff --git a/sys/arm/xscale/i80321/obio_space.c b/sys/arm/xscale/i80321/obio_space.c index 8b7b35e71e24..4eba7000dbc7 100644 --- a/sys/arm/xscale/i80321/obio_space.c +++ b/sys/arm/xscale/i80321/obio_space.c @@ -50,7 +50,6 @@ __FBSDID("$FreeBSD$"); /* Prototypes for all the bus_space structure functions */ bs_protos(generic); -bs_protos(generic_armv4); /* * The obio bus space tag. This is constant for all instances, so @@ -74,7 +73,7 @@ struct bus_space obio_bs_tag = { /* read (single) */ generic_bs_r_1, - generic_armv4_bs_r_2, + generic_bs_r_2, generic_bs_r_4, NULL, @@ -92,7 +91,7 @@ struct bus_space obio_bs_tag = { /* write (single) */ generic_bs_w_1, - generic_armv4_bs_w_2, + generic_bs_w_2, generic_bs_w_4, NULL, diff --git a/sys/arm/xscale/i8134x/i81342_space.c b/sys/arm/xscale/i8134x/i81342_space.c index e19447472d71..0f7912c83cac 100644 --- a/sys/arm/xscale/i8134x/i81342_space.c +++ b/sys/arm/xscale/i8134x/i81342_space.c @@ -65,7 +65,6 @@ bs_protos(i81342); bs_protos(i81342_io); bs_protos(i81342_mem); bs_protos(generic); -bs_protos(generic_armv4); /* * Template bus_space -- copied, and the bits that are NULL are @@ -89,37 +88,37 @@ const struct bus_space i81342_bs_tag_template = { /* read (single) */ generic_bs_r_1, - generic_armv4_bs_r_2, + generic_bs_r_2, generic_bs_r_4, NULL, /* read multiple */ generic_bs_rm_1, - generic_armv4_bs_rm_2, + generic_bs_rm_2, generic_bs_rm_4, NULL, /* read region */ generic_bs_rr_1, - generic_armv4_bs_rr_2, + generic_bs_rr_2, generic_bs_rr_4, NULL, /* write (single) */ generic_bs_w_1, - generic_armv4_bs_w_2, + generic_bs_w_2, generic_bs_w_4, NULL, /* write multiple */ generic_bs_wm_1, - generic_armv4_bs_wm_2, + generic_bs_wm_2, generic_bs_wm_4, NULL, /* write region */ NULL, - generic_armv4_bs_wr_2, + generic_bs_wr_2, generic_bs_wr_4, NULL, @@ -131,49 +130,49 @@ const struct bus_space i81342_bs_tag_template = { /* set region */ NULL, - generic_armv4_bs_sr_2, + generic_bs_sr_2, generic_bs_sr_4, NULL, /* copy */ NULL, - generic_armv4_bs_c_2, + generic_bs_c_2, NULL, NULL, /* read (single) stream */ generic_bs_r_1, - generic_armv4_bs_r_2, + generic_bs_r_2, generic_bs_r_4, NULL, /* read multiple stream */ generic_bs_rm_1, - generic_armv4_bs_rm_2, + generic_bs_rm_2, generic_bs_rm_4, NULL, /* read region stream */ generic_bs_rr_1, - generic_armv4_bs_rr_2, + generic_bs_rr_2, generic_bs_rr_4, NULL, /* write (single) stream */ generic_bs_w_1, - generic_armv4_bs_w_2, + generic_bs_w_2, generic_bs_w_4, NULL, /* write multiple stream */ generic_bs_wm_1, - generic_armv4_bs_wm_2, + generic_bs_wm_2, generic_bs_wm_4, NULL, /* write region stream */ NULL, - generic_armv4_bs_wr_2, + generic_bs_wr_2, generic_bs_wr_4, NULL, }; diff --git a/sys/arm/xscale/i8134x/obio_space.c b/sys/arm/xscale/i8134x/obio_space.c index 8b7b35e71e24..4eba7000dbc7 100644 --- a/sys/arm/xscale/i8134x/obio_space.c +++ b/sys/arm/xscale/i8134x/obio_space.c @@ -50,7 +50,6 @@ __FBSDID("$FreeBSD$"); /* Prototypes for all the bus_space structure functions */ bs_protos(generic); -bs_protos(generic_armv4); /* * The obio bus space tag. This is constant for all instances, so @@ -74,7 +73,7 @@ struct bus_space obio_bs_tag = { /* read (single) */ generic_bs_r_1, - generic_armv4_bs_r_2, + generic_bs_r_2, generic_bs_r_4, NULL, @@ -92,7 +91,7 @@ struct bus_space obio_bs_tag = { /* write (single) */ generic_bs_w_1, - generic_armv4_bs_w_2, + generic_bs_w_2, generic_bs_w_4, NULL, diff --git a/sys/arm/xscale/ixp425/ixp425_a4x_space.c b/sys/arm/xscale/ixp425/ixp425_a4x_space.c index 23e48e8bb106..1b128bbf0e25 100644 --- a/sys/arm/xscale/ixp425/ixp425_a4x_space.c +++ b/sys/arm/xscale/ixp425/ixp425_a4x_space.c @@ -62,7 +62,6 @@ __FBSDID("$FreeBSD$"); /* Prototypes for all the bus_space structure functions */ bs_protos(a4x); bs_protos(generic); -bs_protos(generic_armv4); struct bus_space ixp425_a4x_bs_tag = { /* cookie */ diff --git a/sys/arm/xscale/ixp425/ixp425_space.c b/sys/arm/xscale/ixp425/ixp425_space.c index 102bcd2acc0f..932c71bf5394 100644 --- a/sys/arm/xscale/ixp425/ixp425_space.c +++ b/sys/arm/xscale/ixp425/ixp425_space.c @@ -59,7 +59,6 @@ __FBSDID("$FreeBSD$"); /* Proto types for all the bus_space structure functions */ bs_protos(generic); -bs_protos(generic_armv4); struct bus_space ixp425_bs_tag = { /* cookie */ @@ -79,37 +78,37 @@ struct bus_space ixp425_bs_tag = { /* read (single) */ .bs_r_1 = generic_bs_r_1, - .bs_r_2 = generic_armv4_bs_r_2, + .bs_r_2 = generic_bs_r_2, .bs_r_4 = generic_bs_r_4, .bs_r_8 = NULL, /* read multiple */ .bs_rm_1 = generic_bs_rm_1, - .bs_rm_2 = generic_armv4_bs_rm_2, + .bs_rm_2 = generic_bs_rm_2, .bs_rm_4 = generic_bs_rm_4, .bs_rm_8 = NULL, /* read region */ .bs_rr_1 = generic_bs_rr_1, - .bs_rr_2 = generic_armv4_bs_rr_2, + .bs_rr_2 = generic_bs_rr_2, .bs_rr_4 = generic_bs_rr_4, .bs_rr_8 = NULL, /* write (single) */ .bs_w_1 = generic_bs_w_1, - .bs_w_2 = generic_armv4_bs_w_2, + .bs_w_2 = generic_bs_w_2, .bs_w_4 = generic_bs_w_4, .bs_w_8 = NULL, /* write multiple */ .bs_wm_1 = generic_bs_wm_1, - .bs_wm_2 = generic_armv4_bs_wm_2, + .bs_wm_2 = generic_bs_wm_2, .bs_wm_4 = generic_bs_wm_4, .bs_wm_8 = NULL, /* write region */ .bs_wr_1 = generic_bs_wr_1, - .bs_wr_2 = generic_armv4_bs_wr_2, + .bs_wr_2 = generic_bs_wr_2, .bs_wr_4 = generic_bs_wr_4, .bs_wr_8 = NULL, @@ -118,13 +117,13 @@ struct bus_space ixp425_bs_tag = { /* set region */ .bs_sr_1 = NULL, - .bs_sr_2 = generic_armv4_bs_sr_2, + .bs_sr_2 = generic_bs_sr_2, .bs_sr_4 = generic_bs_sr_4, .bs_sr_8 = NULL, /* copy */ .bs_c_1 = NULL, - .bs_c_2 = generic_armv4_bs_c_2, + .bs_c_2 = generic_bs_c_2, .bs_c_4 = NULL, .bs_c_8 = NULL, }; diff --git a/sys/arm/xscale/pxa/pxa_space.c b/sys/arm/xscale/pxa/pxa_space.c index cfaac37f7daf..7a9160a8974e 100644 --- a/sys/arm/xscale/pxa/pxa_space.c +++ b/sys/arm/xscale/pxa/pxa_space.c @@ -57,7 +57,6 @@ static MALLOC_DEFINE(M_PXATAG, "PXA bus_space tags", "Bus_space tags for PXA"); /* Prototypes for all the bus_space structure functions */ bs_protos(generic); -bs_protos(generic_armv4); bs_protos(pxa); /* @@ -179,7 +178,7 @@ pxa_bus_tag_alloc(bus_addr_t offset) } READ_SINGLE(u_int8_t, pxa_bs_r_1, generic_bs_r_1) -READ_SINGLE(u_int16_t, pxa_bs_r_2, generic_armv4_bs_r_2) +READ_SINGLE(u_int16_t, pxa_bs_r_2, generic_bs_r_2) READ_SINGLE(u_int32_t, pxa_bs_r_4, generic_bs_r_4) #undef READ_SINGLE @@ -195,7 +194,7 @@ READ_SINGLE(u_int32_t, pxa_bs_r_4, generic_bs_r_4) } WRITE_SINGLE(u_int8_t, pxa_bs_w_1, generic_bs_w_1) -WRITE_SINGLE(u_int16_t, pxa_bs_w_2, generic_armv4_bs_w_2) +WRITE_SINGLE(u_int16_t, pxa_bs_w_2, generic_bs_w_2) WRITE_SINGLE(u_int32_t, pxa_bs_w_4, generic_bs_w_4) #undef WRITE_SINGLE @@ -211,7 +210,7 @@ WRITE_SINGLE(u_int32_t, pxa_bs_w_4, generic_bs_w_4) } READ_MULTI(u_int8_t, pxa_bs_rm_1, generic_bs_rm_1) -READ_MULTI(u_int16_t, pxa_bs_rm_2, generic_armv4_bs_rm_2) +READ_MULTI(u_int16_t, pxa_bs_rm_2, generic_bs_rm_2) READ_MULTI(u_int8_t, pxa_bs_rr_1, generic_bs_rr_1) @@ -228,6 +227,6 @@ READ_MULTI(u_int8_t, pxa_bs_rr_1, generic_bs_rr_1) } WRITE_MULTI(u_int8_t, pxa_bs_wm_1, generic_bs_wm_1) -WRITE_MULTI(u_int16_t, pxa_bs_wm_2, generic_armv4_bs_wm_2) +WRITE_MULTI(u_int16_t, pxa_bs_wm_2, generic_bs_wm_2) #undef WRITE_MULTI From 301885260edcb68943c33844bd5d522ef7caaf2f Mon Sep 17 00:00:00 2001 From: nwhitehorn Date: Wed, 21 Jan 2015 02:57:54 +0000 Subject: [PATCH 114/258] On 64-bit PowerPC, use more native forms of the PPC 970 HID restore sequences, like are used to read the HIDs. This is both easier to read and avoids a miscompilation by GCC in certain circumstances. Also avoid double restoration of HID4 and HID5. MFC after: 2 weeks --- sys/powerpc/aim/mp_cpudep.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/sys/powerpc/aim/mp_cpudep.c b/sys/powerpc/aim/mp_cpudep.c index 3bc21a42f5d7..59a24e22e62d 100644 --- a/sys/powerpc/aim/mp_cpudep.c +++ b/sys/powerpc/aim/mp_cpudep.c @@ -58,7 +58,9 @@ SYSINIT(cpu_save_config, SI_SUB_CPU, SI_ORDER_ANY, cpudep_save_config, NULL); void cpudep_ap_early_bootstrap(void) { +#ifndef __powerpc64__ register_t reg; +#endif __asm __volatile("mtsprg 0, %0" :: "r"(ap_pcpu)); powerpc_sync(); @@ -69,12 +71,17 @@ cpudep_ap_early_bootstrap(void) case IBM970MP: /* Restore HID4 and HID5, which are necessary for the MMU */ +#ifdef __powerpc64__ + mtspr(SPR_HID4, bsp_state[2]); powerpc_sync(); isync(); + mtspr(SPR_HID5, bsp_state[3]); powerpc_sync(); isync(); +#else __asm __volatile("ld %0, 16(%2); sync; isync; \ mtspr %1, %0; sync; isync;" : "=r"(reg) : "K"(SPR_HID4), "r"(bsp_state)); __asm __volatile("ld %0, 24(%2); sync; isync; \ mtspr %1, %0; sync; isync;" : "=r"(reg) : "K"(SPR_HID5), "r"(bsp_state)); +#endif powerpc_sync(); break; } @@ -292,9 +299,24 @@ cpudep_ap_setup() /* * The 970 has strange rules about how to update HID registers. * See Table 2-3, 970MP manual + * + * Note: HID4 and HID5 restored already in + * cpudep_ap_early_bootstrap() */ __asm __volatile("mtasr %0; sync" :: "r"(0)); + #ifdef __powerpc64__ + __asm __volatile(" \ + sync; isync; \ + mtspr %1, %0; \ + mfspr %0, %1; mfspr %0, %1; mfspr %0, %1; \ + mfspr %0, %1; mfspr %0, %1; mfspr %0, %1; \ + sync; isync" + :: "r"(bsp_state[0]), "K"(SPR_HID0)); + __asm __volatile("sync; isync; \ + mtspr %1, %0; mtspr %1, %0; sync; isync" + :: "r"(bsp_state[1]), "K"(SPR_HID1)); + #else __asm __volatile(" \ ld %0,0(%2); \ sync; isync; \ @@ -306,12 +328,7 @@ cpudep_ap_setup() __asm __volatile("ld %0, 8(%2); sync; isync; \ mtspr %1, %0; mtspr %1, %0; sync; isync" : "=r"(reg) : "K"(SPR_HID1), "r"(bsp_state)); - __asm __volatile("ld %0, 16(%2); sync; isync; \ - mtspr %1, %0; sync; isync;" - : "=r"(reg) : "K"(SPR_HID4), "r"(bsp_state)); - __asm __volatile("ld %0, 24(%2); sync; isync; \ - mtspr %1, %0; sync; isync;" - : "=r"(reg) : "K"(SPR_HID5), "r"(bsp_state)); + #endif powerpc_sync(); break; From 4656715cba8cab12b5f759b5be871bff4ded3109 Mon Sep 17 00:00:00 2001 From: ian Date: Wed, 21 Jan 2015 03:22:37 +0000 Subject: [PATCH 115/258] The mv/bus_space.c file is essentially identical to arm/bus_space-v6.c, so just use it. --- sys/arm/mv/bus_space.c | 161 ----------------------------------------- sys/arm/mv/files.mv | 2 +- 2 files changed, 1 insertion(+), 162 deletions(-) delete mode 100644 sys/arm/mv/bus_space.c diff --git a/sys/arm/mv/bus_space.c b/sys/arm/mv/bus_space.c deleted file mode 100644 index 6bd4f3486dfa..000000000000 --- a/sys/arm/mv/bus_space.c +++ /dev/null @@ -1,161 +0,0 @@ -/*- - * Copyright (C) 2008 MARVELL INTERNATIONAL LTD. - * All rights reserved. - * - * Developed by Semihalf. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of MARVELL nor the names of contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY 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 - -/* - * Bus space functions for Marvell SoC family - */ - -/* Prototypes for all the bus_space structure functions */ -bs_protos(generic); - -/* - * The bus space tag. This is constant for all instances, so - * we never have to explicitly "create" it. - */ -static struct bus_space _base_tag = { - /* cookie */ - (void *) 0, - - /* mapping/unmapping */ - generic_bs_map, - generic_bs_unmap, - generic_bs_subregion, - - /* allocation/deallocation */ - generic_bs_alloc, - generic_bs_free, - - /* barrier */ - generic_bs_barrier, - - /* read (single) */ - generic_bs_r_1, - generic_bs_r_2, - generic_bs_r_4, - NULL, - - /* read multiple */ - generic_bs_rm_1, - generic_bs_rm_2, - generic_bs_rm_4, - NULL, - - /* read region */ - generic_bs_rr_1, - generic_bs_rr_2, - generic_bs_rr_4, - NULL, - - /* write (single) */ - generic_bs_w_1, - generic_bs_w_2, - generic_bs_w_4, - NULL, - - /* write multiple */ - generic_bs_wm_1, - generic_bs_wm_2, - generic_bs_wm_4, - NULL, - - /* write region */ - NULL, - NULL, - NULL, - NULL, - - /* set multiple */ - NULL, - NULL, - NULL, - NULL, - - /* set region */ - NULL, - NULL, - NULL, - NULL, - - /* copy */ - NULL, - NULL, - NULL, - NULL, - - /* read stream (single) */ - NULL, - NULL, - NULL, - NULL, - - /* read multiple stream */ - NULL, - generic_bs_rm_2, /* bus_space_read_multi_stream_2 */ - NULL, - NULL, - - /* read region stream */ - NULL, - NULL, - NULL, - NULL, - - /* write stream (single) */ - NULL, - NULL, - NULL, - NULL, - - /* write multiple stream */ - NULL, - generic_bs_wm_2, /* bus_space_write_multi_stream_2 */ - NULL, - NULL, - - /* write region stream */ - NULL, - NULL, - NULL, - NULL -}; - -bus_space_tag_t fdtbus_bs_tag = &_base_tag; diff --git a/sys/arm/mv/files.mv b/sys/arm/mv/files.mv index 0d14e4d92f6a..15622ae0d131 100644 --- a/sys/arm/mv/files.mv +++ b/sys/arm/mv/files.mv @@ -12,6 +12,7 @@ # - JTAG/ICE # - Vector Floating Point (VFP) unit # +arm/arm/bus_space-v6.c standard arm/arm/bus_space_generic.c standard arm/arm/cpufunc_asm_arm10.S standard arm/arm/cpufunc_asm_arm11.S standard @@ -21,7 +22,6 @@ arm/arm/cpufunc_asm_armv7.S standard arm/arm/cpufunc_asm_sheeva.S standard arm/arm/cpufunc_asm_pj4b.S standard -arm/mv/bus_space.c standard arm/mv/gpio.c standard arm/mv/mv_common.c standard arm/mv/mv_localbus.c standard From 7aeca12fb363467e173dad37677b1190d8810ce6 Mon Sep 17 00:00:00 2001 From: ian Date: Wed, 21 Jan 2015 03:24:18 +0000 Subject: [PATCH 116/258] Move bs_unimplemented() to bus_space_generic.c so it can be shared. --- sys/arm/arm/bus_space-v6.c | 9 --------- sys/arm/arm/bus_space_generic.c | 7 +++++++ sys/arm/include/bus.h | 3 +++ 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/sys/arm/arm/bus_space-v6.c b/sys/arm/arm/bus_space-v6.c index ce26c46171ef..4997c02bf88b 100644 --- a/sys/arm/arm/bus_space-v6.c +++ b/sys/arm/arm/bus_space-v6.c @@ -39,15 +39,6 @@ __FBSDID("$FreeBSD$"); /* Prototypes for all the bus_space structure functions */ bs_protos(generic); -static void -bs_unimplemented(void) -{ - - panic("unimplemented bus_space function called"); -} - -#define BS_UNIMPLEMENTED (void *)bs_unimplemented - /* * The bus space tag. This is constant for all instances, so * we never have to explicitly "create" it. diff --git a/sys/arm/arm/bus_space_generic.c b/sys/arm/arm/bus_space_generic.c index 2df18dc1510b..7beda42ab0ee 100644 --- a/sys/arm/arm/bus_space_generic.c +++ b/sys/arm/arm/bus_space_generic.c @@ -53,6 +53,13 @@ __FBSDID("$FreeBSD$"); #include #include +void +generic_bs_unimplemented(void) +{ + + panic("unimplemented bus_space function called"); +} + /* Prototypes for all the bus_space structure functions */ bs_protos(generic); diff --git a/sys/arm/include/bus.h b/sys/arm/include/bus.h index f9a677e4f263..88458d799ead 100644 --- a/sys/arm/include/bus.h +++ b/sys/arm/include/bus.h @@ -730,6 +730,9 @@ bs_c_2_proto(f); \ bs_c_4_proto(f); \ bs_c_8_proto(f); +void generic_bs_unimplemented(void); +#define BS_UNIMPLEMENTED (void *)generic_bs_unimplemented + #define BUS_SPACE_ALIGNED_POINTER(p, t) ALIGNED_POINTER(p, t) #define BUS_SPACE_MAXADDR_24BIT 0xFFFFFF From 7ca5bd2f19fa0b69c3f51467088cbef50b4cfe65 Mon Sep 17 00:00:00 2001 From: ian Date: Wed, 21 Jan 2015 03:28:07 +0000 Subject: [PATCH 117/258] Use explicit initializer style, fill in missing functions. --- sys/arm/at91/at91.c | 140 ++++++++++++++++++++-------------------- sys/arm/at91/files.at91 | 1 + 2 files changed, 71 insertions(+), 70 deletions(-) diff --git a/sys/arm/at91/at91.c b/sys/arm/at91/at91.c index 8c5c86c39c29..209a11997a15 100644 --- a/sys/arm/at91/at91.c +++ b/sys/arm/at91/at91.c @@ -118,110 +118,110 @@ bus_dma_get_range_nb(void) bs_protos(generic); struct bus_space at91_bs_tag = { - /* cookie */ - (void *) 0, + /* privdata is whatever the implementer wants; unused in base tag */ + .bs_privdata = NULL, /* mapping/unmapping */ - at91_bs_map, - at91_bs_unmap, - at91_bs_subregion, + .bs_map = at91_bs_map, + .bs_unmap = at91_bs_unmap, + .bs_subregion = at91_bs_subregion, /* allocation/deallocation */ - NULL, - NULL, + .bs_alloc = generic_bs_alloc, + .bs_free = generic_bs_free, /* barrier */ - at91_barrier, + .bs_barrier = at91_barrier, /* read (single) */ - generic_bs_r_1, - generic_bs_r_2, - generic_bs_r_4, - NULL, + .bs_r_1 = NULL, /* Use inline code in bus.h */ + .bs_r_2 = NULL, /* Use inline code in bus.h */ + .bs_r_4 = NULL, /* Use inline code in bus.h */ + .bs_r_8 = NULL, /* Use inline code in bus.h */ /* read multiple */ - generic_bs_rm_1, - generic_bs_rm_2, - generic_bs_rm_4, - NULL, + .bs_rm_1 = generic_bs_rm_1, + .bs_rm_2 = generic_bs_rm_2, + .bs_rm_4 = generic_bs_rm_4, + .bs_rm_8 = BS_UNIMPLEMENTED, /* read region */ - generic_bs_rr_1, - generic_bs_rr_2, - generic_bs_rr_4, - NULL, + .bs_rr_1 = generic_bs_rr_1, + .bs_rr_2 = generic_bs_rr_2, + .bs_rr_4 = generic_bs_rr_4, + .bs_rr_8 = BS_UNIMPLEMENTED, /* write (single) */ - generic_bs_w_1, - generic_bs_w_2, - generic_bs_w_4, - NULL, + .bs_w_1 = NULL, /* Use inline code in bus.h */ + .bs_w_2 = NULL, /* Use inline code in bus.h */ + .bs_w_4 = NULL, /* Use inline code in bus.h */ + .bs_w_8 = NULL, /* Use inline code in bus.h */ /* write multiple */ - generic_bs_wm_1, - generic_bs_wm_2, - generic_bs_wm_4, - NULL, + .bs_wm_1 = generic_bs_wm_1, + .bs_wm_2 = generic_bs_wm_2, + .bs_wm_4 = generic_bs_wm_4, + .bs_wm_8 = BS_UNIMPLEMENTED, /* write region */ - NULL, - generic_bs_wr_2, - generic_bs_wr_4, - NULL, + .bs_wr_1 = generic_bs_wr_1, + .bs_wr_2 = generic_bs_wr_2, + .bs_wr_4 = generic_bs_wr_4, + .bs_wr_8 = BS_UNIMPLEMENTED, /* set multiple */ - NULL, - NULL, - NULL, - NULL, + .bs_sm_1 = BS_UNIMPLEMENTED, + .bs_sm_2 = BS_UNIMPLEMENTED, + .bs_sm_4 = BS_UNIMPLEMENTED, + .bs_sm_8 = BS_UNIMPLEMENTED, /* set region */ - NULL, - generic_bs_sr_2, - generic_bs_sr_4, - NULL, + .bs_sr_1 = generic_bs_sr_1, + .bs_sr_2 = generic_bs_sr_2, + .bs_sr_4 = generic_bs_sr_4, + .bs_sr_8 = BS_UNIMPLEMENTED, /* copy */ - NULL, - generic_bs_c_2, - NULL, - NULL, + .bs_c_1 = BS_UNIMPLEMENTED, + .bs_c_2 = generic_bs_c_2, + .bs_c_4 = BS_UNIMPLEMENTED, + .bs_c_8 = BS_UNIMPLEMENTED, - /* read (single) stream */ - generic_bs_r_1, - generic_bs_r_2, - generic_bs_r_4, - NULL, + /* read stream (single) */ + .bs_r_1_s = NULL, /* Use inline code in bus.h */ + .bs_r_2_s = NULL, /* Use inline code in bus.h */ + .bs_r_4_s = NULL, /* Use inline code in bus.h */ + .bs_r_8_s = NULL, /* Use inline code in bus.h */ /* read multiple stream */ - generic_bs_rm_1, - generic_bs_rm_2, - generic_bs_rm_4, - NULL, + .bs_rm_1_s = generic_bs_rm_1, + .bs_rm_2_s = generic_bs_rm_2, + .bs_rm_4_s = generic_bs_rm_4, + .bs_rm_8_s = BS_UNIMPLEMENTED, /* read region stream */ - generic_bs_rr_1, - generic_bs_rr_2, - generic_bs_rr_4, - NULL, + .bs_rr_1_s = generic_bs_rr_1, + .bs_rr_2_s = generic_bs_rr_2, + .bs_rr_4_s = generic_bs_rr_4, + .bs_rr_8_s = BS_UNIMPLEMENTED, - /* write (single) stream */ - generic_bs_w_1, - generic_bs_w_2, - generic_bs_w_4, - NULL, + /* write stream (single) */ + .bs_w_1_s = NULL, /* Use inline code in bus.h */ + .bs_w_2_s = NULL, /* Use inline code in bus.h */ + .bs_w_4_s = NULL, /* Use inline code in bus.h */ + .bs_w_8_s = NULL, /* Use inline code in bus.h */ /* write multiple stream */ - generic_bs_wm_1, - generic_bs_wm_2, - generic_bs_wm_4, - NULL, + .bs_wm_1_s = generic_bs_wm_1, + .bs_wm_2_s = generic_bs_wm_2, + .bs_wm_4_s = generic_bs_wm_4, + .bs_wm_8_s = BS_UNIMPLEMENTED, /* write region stream */ - NULL, - generic_bs_wr_2, - generic_bs_wr_4, - NULL, + .bs_wr_1_s = generic_bs_wr_1, + .bs_wr_2_s = generic_bs_wr_2, + .bs_wr_4_s = generic_bs_wr_4, + .bs_wr_8_s = BS_UNIMPLEMENTED, }; #ifndef FDT diff --git a/sys/arm/at91/files.at91 b/sys/arm/at91/files.at91 index 29ada7d26c1d..e3061e11db0f 100644 --- a/sys/arm/at91/files.at91 +++ b/sys/arm/at91/files.at91 @@ -1,4 +1,5 @@ # $FreeBSD$ +arm/arm/bus_space_generic.c standard arm/arm/cpufunc_asm_arm9.S standard arm/at91/at91_machdep.c standard arm/at91/at91_aic.c standard From 2a957de5c05bfc237c68ba0e729739e9e6f5ad1f Mon Sep 17 00:00:00 2001 From: ian Date: Wed, 21 Jan 2015 03:44:29 +0000 Subject: [PATCH 118/258] Rename bus_space-v6.c to bus_space_base.c, because it's not v6-specific and now some v5 Marvell systems are using it. Only define fdt_bus_tag if option FDT is defined. --- sys/arm/allwinner/a20/files.a20 | 4 ++-- sys/arm/allwinner/files.a10 | 4 ++-- sys/arm/altera/socfpga/files.socfpga | 2 +- sys/arm/arm/{bus_space-v6.c => bus_space_base.c} | 8 ++++++-- sys/arm/broadcom/bcm2835/files.bcm2835 | 2 +- sys/arm/freescale/imx/files.imx51 | 2 +- sys/arm/freescale/imx/files.imx53 | 2 +- sys/arm/freescale/imx/files.imx6 | 2 +- sys/arm/freescale/vybrid/files.vybrid | 2 +- sys/arm/lpc/files.lpc | 2 +- sys/arm/mv/files.mv | 2 +- sys/arm/rockchip/files.rk30xx | 2 +- sys/arm/samsung/exynos/files.exynos5 | 2 +- sys/arm/ti/files.ti | 2 +- sys/arm/xilinx/files.zynq7 | 2 +- 15 files changed, 22 insertions(+), 18 deletions(-) rename sys/arm/arm/{bus_space-v6.c => bus_space_base.c} (97%) diff --git a/sys/arm/allwinner/a20/files.a20 b/sys/arm/allwinner/a20/files.a20 index 1c02e90a6ed4..04f23794309d 100644 --- a/sys/arm/allwinner/a20/files.a20 +++ b/sys/arm/allwinner/a20/files.a20 @@ -17,7 +17,7 @@ arm/allwinner/a10_ehci.c optional ehci arm/allwinner/if_emac.c optional emac arm/allwinner/a10_wdog.c standard arm/allwinner/timer.c standard -arm/arm/bus_space-v6.c standard -arm/allwinner/a10_common.c standard +arm/arm/bus_space_base.c standard +arm/allwinner/a10_common.c standard arm/allwinner/a10_machdep.c standard arm/allwinner/a20/a20_mp.c optional smp diff --git a/sys/arm/allwinner/files.a10 b/sys/arm/allwinner/files.a10 index c14ef2e4b644..eb5154eb7f64 100644 --- a/sys/arm/allwinner/files.a10 +++ b/sys/arm/allwinner/files.a10 @@ -19,5 +19,5 @@ arm/allwinner/a20/a20_cpu_cfg.c standard arm/allwinner/aintc.c standard arm/allwinner/if_emac.c optional emac arm/allwinner/timer.c standard -arm/arm/bus_space-v6.c standard -#arm/allwinner/console.c standard +arm/arm/bus_space_base.c standard +#arm/allwinner/console.c standard diff --git a/sys/arm/altera/socfpga/files.socfpga b/sys/arm/altera/socfpga/files.socfpga index 652ab9801ea8..22d7c28aebb8 100644 --- a/sys/arm/altera/socfpga/files.socfpga +++ b/sys/arm/altera/socfpga/files.socfpga @@ -9,7 +9,7 @@ arm/arm/cpufunc_asm_arm10.S standard arm/arm/cpufunc_asm_arm11.S standard arm/arm/cpufunc_asm_armv7.S standard -arm/arm/bus_space-v6.c standard +arm/arm/bus_space_base.c standard arm/arm/gic.c standard arm/arm/mpcore_timer.c standard diff --git a/sys/arm/arm/bus_space-v6.c b/sys/arm/arm/bus_space_base.c similarity index 97% rename from sys/arm/arm/bus_space-v6.c rename to sys/arm/arm/bus_space_base.c index 4997c02bf88b..8ddfcb0d3a0d 100644 --- a/sys/arm/arm/bus_space-v6.c +++ b/sys/arm/arm/bus_space_base.c @@ -36,6 +36,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include "opt_platform.h" + /* Prototypes for all the bus_space structure functions */ bs_protos(generic); @@ -43,7 +45,7 @@ bs_protos(generic); * The bus space tag. This is constant for all instances, so * we never have to explicitly "create" it. */ -static struct bus_space _base_tag = { +static struct bus_space arm_base_tag = { /* privdata is whatever the implementer wants; unused in base tag */ .bs_privdata = NULL, @@ -150,4 +152,6 @@ static struct bus_space _base_tag = { .bs_wr_8_s = BS_UNIMPLEMENTED, }; -bus_space_tag_t fdtbus_bs_tag = &_base_tag; +#ifdef FDT +bus_space_tag_t fdtbus_bs_tag = &arm_base_tag; +#endif diff --git a/sys/arm/broadcom/bcm2835/files.bcm2835 b/sys/arm/broadcom/bcm2835/files.bcm2835 index 11158cb822ae..53fd12f5c3d1 100644 --- a/sys/arm/broadcom/bcm2835/files.bcm2835 +++ b/sys/arm/broadcom/bcm2835/files.bcm2835 @@ -15,7 +15,7 @@ arm/broadcom/bcm2835/bcm2835_spi.c optional bcm2835_spi arm/broadcom/bcm2835/bcm2835_systimer.c standard arm/broadcom/bcm2835/bcm2835_wdog.c standard -arm/arm/bus_space-v6.c standard +arm/arm/bus_space_base.c standard arm/arm/bus_space_generic.c standard arm/arm/bus_space_asm_generic.S standard arm/arm/cpufunc_asm_arm11.S standard diff --git a/sys/arm/freescale/imx/files.imx51 b/sys/arm/freescale/imx/files.imx51 index 951cb4d148b1..986fc2c0af26 100644 --- a/sys/arm/freescale/imx/files.imx51 +++ b/sys/arm/freescale/imx/files.imx51 @@ -10,7 +10,7 @@ kern/kern_clocksource.c standard arm/freescale/imx/imx_common.c standard arm/freescale/imx/imx_machdep.c standard arm/freescale/imx/imx51_machdep.c standard -arm/arm/bus_space-v6.c standard +arm/arm/bus_space_base.c standard # Dummy serial console #arm/freescale/imx/console.c standard diff --git a/sys/arm/freescale/imx/files.imx53 b/sys/arm/freescale/imx/files.imx53 index 3918400edab1..c5dd30bf15b0 100644 --- a/sys/arm/freescale/imx/files.imx53 +++ b/sys/arm/freescale/imx/files.imx53 @@ -10,7 +10,7 @@ kern/kern_clocksource.c standard arm/freescale/imx/imx_common.c standard arm/freescale/imx/imx_machdep.c standard arm/freescale/imx/imx53_machdep.c standard -arm/arm/bus_space-v6.c standard +arm/arm/bus_space_base.c standard # Special serial console for debuging early boot code #arm/freescale/imx/console.c standard diff --git a/sys/arm/freescale/imx/files.imx6 b/sys/arm/freescale/imx/files.imx6 index 2fc6d3fb7dfc..df86ef9d596a 100644 --- a/sys/arm/freescale/imx/files.imx6 +++ b/sys/arm/freescale/imx/files.imx6 @@ -15,7 +15,7 @@ kern/kern_clocksource.c standard # arm/arm/gic.c standard arm/arm/pl310.c standard -arm/arm/bus_space-v6.c standard +arm/arm/bus_space_base.c standard arm/arm/mpcore_timer.c standard arm/freescale/fsl_ocotp.c standard arm/freescale/imx/imx6_anatop.c standard diff --git a/sys/arm/freescale/vybrid/files.vybrid b/sys/arm/freescale/vybrid/files.vybrid index 572a3ef1c4bb..1d301f23c49e 100644 --- a/sys/arm/freescale/vybrid/files.vybrid +++ b/sys/arm/freescale/vybrid/files.vybrid @@ -9,7 +9,7 @@ arm/arm/cpufunc_asm_arm10.S standard arm/arm/cpufunc_asm_arm11.S standard arm/arm/cpufunc_asm_armv7.S standard -arm/arm/bus_space-v6.c standard +arm/arm/bus_space_base.c standard arm/arm/gic.c standard arm/arm/mpcore_timer.c standard diff --git a/sys/arm/lpc/files.lpc b/sys/arm/lpc/files.lpc index 8e196ad5512a..1f8d768b7a68 100644 --- a/sys/arm/lpc/files.lpc +++ b/sys/arm/lpc/files.lpc @@ -1,5 +1,5 @@ # $FreeBSD$ -arm/arm/bus_space-v6.c standard +arm/arm/bus_space_base.c standard arm/arm/bus_space_generic.c standard arm/arm/cpufunc_asm_arm9.S standard arm/arm/cpufunc_asm_armv5.S standard diff --git a/sys/arm/mv/files.mv b/sys/arm/mv/files.mv index 15622ae0d131..d730c01d644c 100644 --- a/sys/arm/mv/files.mv +++ b/sys/arm/mv/files.mv @@ -12,7 +12,7 @@ # - JTAG/ICE # - Vector Floating Point (VFP) unit # -arm/arm/bus_space-v6.c standard +arm/arm/bus_space_base.c standard arm/arm/bus_space_generic.c standard arm/arm/cpufunc_asm_arm10.S standard arm/arm/cpufunc_asm_arm11.S standard diff --git a/sys/arm/rockchip/files.rk30xx b/sys/arm/rockchip/files.rk30xx index 0bcc34c36578..4160c1e684d0 100644 --- a/sys/arm/rockchip/files.rk30xx +++ b/sys/arm/rockchip/files.rk30xx @@ -11,7 +11,7 @@ arm/arm/cpufunc_asm_armv7.S standard arm/arm/gic.c standard arm/arm/mpcore_timer.c standard -arm/arm/bus_space-v6.c standard +arm/arm/bus_space_base.c standard arm/rockchip/rk30xx_common.c standard arm/rockchip/rk30xx_machdep.c standard arm/rockchip/rk30xx_pmu.c standard diff --git a/sys/arm/samsung/exynos/files.exynos5 b/sys/arm/samsung/exynos/files.exynos5 index 3883b2848a99..f1174dcb720c 100644 --- a/sys/arm/samsung/exynos/files.exynos5 +++ b/sys/arm/samsung/exynos/files.exynos5 @@ -9,7 +9,7 @@ arm/arm/cpufunc_asm_arm10.S standard arm/arm/cpufunc_asm_arm11.S standard arm/arm/cpufunc_asm_armv7.S standard -arm/arm/bus_space-v6.c standard +arm/arm/bus_space_base.c standard arm/arm/gic.c standard arm/arm/generic_timer.c standard diff --git a/sys/arm/ti/files.ti b/sys/arm/ti/files.ti index ef77cb99dfee..52ee22b05d5a 100644 --- a/sys/arm/ti/files.ti +++ b/sys/arm/ti/files.ti @@ -2,7 +2,7 @@ kern/kern_clocksource.c standard -arm/arm/bus_space-v6.c standard +arm/arm/bus_space_base.c standard arm/arm/bus_space_generic.c standard arm/arm/bus_space_asm_generic.S standard arm/arm/cpufunc_asm_armv5.S standard diff --git a/sys/arm/xilinx/files.zynq7 b/sys/arm/xilinx/files.zynq7 index 9682904d91ae..19759ac0e58f 100644 --- a/sys/arm/xilinx/files.zynq7 +++ b/sys/arm/xilinx/files.zynq7 @@ -5,7 +5,7 @@ kern/kern_clocksource.c standard -arm/arm/bus_space-v6.c standard +arm/arm/bus_space_base.c standard arm/arm/bus_space_generic.c standard arm/arm/bus_space_asm_generic.S standard arm/arm/cpufunc_asm_armv5.S standard From 1852f2db62c01de16f6d175ef3640b97fac602d1 Mon Sep 17 00:00:00 2001 From: ian Date: Wed, 21 Jan 2015 04:06:36 +0000 Subject: [PATCH 119/258] The versatile platform had two copies of a bus_space that are essentially duplicates of the standard arm base bus_space, so just use it. --- sys/arm/arm/bus_space_base.c | 6 +- sys/arm/include/bus.h | 1 + sys/arm/versatile/bus_space.c | 114 --------------- sys/arm/versatile/files.versatile | 3 +- sys/arm/versatile/versatile_pci.c | 2 +- sys/arm/versatile/versatile_pci_bus_space.c | 152 -------------------- sys/arm/versatile/versatile_pci_bus_space.h | 35 ----- 7 files changed, 7 insertions(+), 306 deletions(-) delete mode 100644 sys/arm/versatile/bus_space.c delete mode 100644 sys/arm/versatile/versatile_pci_bus_space.c delete mode 100644 sys/arm/versatile/versatile_pci_bus_space.h diff --git a/sys/arm/arm/bus_space_base.c b/sys/arm/arm/bus_space_base.c index 8ddfcb0d3a0d..a80b06466cc9 100644 --- a/sys/arm/arm/bus_space_base.c +++ b/sys/arm/arm/bus_space_base.c @@ -45,7 +45,7 @@ bs_protos(generic); * The bus space tag. This is constant for all instances, so * we never have to explicitly "create" it. */ -static struct bus_space arm_base_tag = { +static struct bus_space arm_base_bus_space = { /* privdata is whatever the implementer wants; unused in base tag */ .bs_privdata = NULL, @@ -153,5 +153,7 @@ static struct bus_space arm_base_tag = { }; #ifdef FDT -bus_space_tag_t fdtbus_bs_tag = &arm_base_tag; +bus_space_tag_t fdtbus_bs_tag = &arm_base_bus_space; #endif + +bus_space_tag_t arm_base_bs_tag = &arm_base_bus_space; diff --git a/sys/arm/include/bus.h b/sys/arm/include/bus.h index 88458d799ead..757919974a1f 100644 --- a/sys/arm/include/bus.h +++ b/sys/arm/include/bus.h @@ -245,6 +245,7 @@ struct bus_space { bus_size_t, const uint64_t *, bus_size_t); }; +extern bus_space_tag_t arm_base_bs_tag; /* * Utility macros; INTERNAL USE ONLY. diff --git a/sys/arm/versatile/bus_space.c b/sys/arm/versatile/bus_space.c deleted file mode 100644 index 850feefb1aff..000000000000 --- a/sys/arm/versatile/bus_space.c +++ /dev/null @@ -1,114 +0,0 @@ -/*- - * Copyright (C) 2008 MARVELL INTERNATIONAL LTD. - * All rights reserved. - * - * Developed by Semihalf. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of MARVELL nor the names of contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY 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 - -/* Prototypes for all the bus_space structure functions */ -bs_protos(generic); - -struct bus_space _base_tag = { - /* cookie */ - .bs_privdata = (void *) 0, - - /* mapping/unmapping */ - .bs_map = generic_bs_map, - .bs_unmap = generic_bs_unmap, - .bs_subregion = generic_bs_subregion, - - /* allocation/deallocation */ - .bs_alloc = generic_bs_alloc, - .bs_free = generic_bs_free, - - /* barrier */ - .bs_barrier = generic_bs_barrier, - - /* read (single) */ - .bs_r_1 = generic_bs_r_1, - .bs_r_2 = generic_bs_r_2, - .bs_r_4 = generic_bs_r_4, - .bs_r_8 = NULL, - - /* read multiple */ - .bs_rm_1 = generic_bs_rm_1, - .bs_rm_2 = generic_bs_rm_2, - .bs_rm_4 = generic_bs_rm_4, - .bs_rm_8 = NULL, - - /* read region */ - .bs_rr_1 = generic_bs_rr_1, - .bs_rr_2 = generic_bs_rr_2, - .bs_rr_4 = generic_bs_rr_4, - .bs_rr_8 = NULL, - - /* write (single) */ - .bs_w_1 = generic_bs_w_1, - .bs_w_2 = generic_bs_w_2, - .bs_w_4 = generic_bs_w_4, - .bs_w_8 = NULL, - - /* write multiple */ - .bs_wm_1 = generic_bs_wm_1, - .bs_wm_2 = generic_bs_wm_2, - .bs_wm_4 = generic_bs_wm_4, - .bs_wm_8 = NULL, - - /* write region */ - .bs_wr_1 = generic_bs_wr_1, - .bs_wr_2 = generic_bs_wr_2, - .bs_wr_4 = generic_bs_wr_4, - .bs_wr_8 = NULL, - - /* set multiple */ - /* XXX not implemented */ - - /* set region */ - .bs_sr_1 = NULL, - .bs_sr_2 = generic_bs_sr_2, - .bs_sr_4 = generic_bs_sr_4, - .bs_sr_8 = NULL, - - /* copy */ - .bs_c_1 = NULL, - .bs_c_2 = generic_bs_c_2, - .bs_c_4 = NULL, - .bs_c_8 = NULL, -}; - -bus_space_tag_t fdtbus_bs_tag = &_base_tag; diff --git a/sys/arm/versatile/files.versatile b/sys/arm/versatile/files.versatile index 199fecbb566a..217109f03ce3 100644 --- a/sys/arm/versatile/files.versatile +++ b/sys/arm/versatile/files.versatile @@ -1,5 +1,6 @@ # $FreeBSD$ +arm/arm/bus_space_base.c standard arm/arm/bus_space_asm_generic.S standard arm/arm/bus_space_generic.c standard arm/arm/cpufunc_asm_arm11.S standard @@ -7,14 +8,12 @@ arm/arm/cpufunc_asm_arm11x6.S standard arm/arm/cpufunc_asm_armv5.S standard arm/arm/cpufunc_asm_armv6.S standard -arm/versatile/bus_space.c standard arm/versatile/pl050.c optional sc arm/versatile/sp804.c standard arm/versatile/versatile_machdep.c standard arm/versatile/versatile_clcd.c optional sc arm/versatile/versatile_common.c standard arm/versatile/versatile_pci.c optional pci -arm/versatile/versatile_pci_bus_space.c optional pci arm/versatile/versatile_sic.c standard arm/versatile/versatile_timer.c standard diff --git a/sys/arm/versatile/versatile_pci.c b/sys/arm/versatile/versatile_pci.c index 0e4849682879..40a120a57798 100644 --- a/sys/arm/versatile/versatile_pci.c +++ b/sys/arm/versatile/versatile_pci.c @@ -355,7 +355,7 @@ versatile_pci_activate_resource(device_t bus, device_t child, int type, int rid, vaddr = (vm_offset_t)pmap_mapdev(rman_get_start(r), rman_get_size(r)); rman_set_bushandle(r, vaddr); - rman_set_bustag(r, versatile_bus_space_pcimem); + rman_set_bustag(r, arm_base_bs_tag); res = rman_activate_resource(r); break; case SYS_RES_IRQ: diff --git a/sys/arm/versatile/versatile_pci_bus_space.c b/sys/arm/versatile/versatile_pci_bus_space.c deleted file mode 100644 index 894544016972..000000000000 --- a/sys/arm/versatile/versatile_pci_bus_space.c +++ /dev/null @@ -1,152 +0,0 @@ -/*- - * Copyright (c) 2009, Oleksandr Tymoshenko - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice unmodified, this list of conditions, and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include - -#include -#include - -/* Prototypes for all the bus_space structure functions */ -bs_protos(generic); - -/* - * Bus space that handles offsets in word for 1/2 bytes read/write access. - * Byte order of values is handled by device drivers itself. - */ -static struct bus_space bus_space_pcimem = { - /* cookie */ - (void *) 0, - - /* mapping/unmapping */ - generic_bs_map, - generic_bs_unmap, - generic_bs_subregion, - - /* allocation/deallocation */ - NULL, - NULL, - - /* barrier */ - generic_bs_barrier, - - /* read (single) */ - generic_bs_r_1, - generic_bs_r_2, - generic_bs_r_4, - NULL, - - /* read multiple */ - generic_bs_rm_1, - generic_bs_rm_2, - generic_bs_rm_4, - NULL, - - /* read region */ - generic_bs_rr_1, - generic_bs_rr_2, - generic_bs_rr_4, - NULL, - - /* write (single) */ - generic_bs_w_1, - generic_bs_w_2, - generic_bs_w_4, - NULL, - - /* write multiple */ - generic_bs_wm_1, - generic_bs_wm_2, - generic_bs_wm_4, - NULL, - - /* write region */ - generic_bs_wr_1, - generic_bs_wr_2, - generic_bs_wr_4, - NULL, - - /* set multiple */ - NULL, - NULL, - NULL, - NULL, - - /* set region */ - NULL, - NULL, - generic_bs_sr_4, - NULL, - - /* copy */ - NULL, - NULL, - NULL, - NULL, - - /* read (single) stream */ - NULL, - NULL, - NULL, - NULL, - - /* read multiple stream */ - NULL, - NULL, - NULL, - NULL, - - /* read region stream */ - NULL, - NULL, - NULL, - NULL, - - /* write (single) stream */ - NULL, - NULL, - NULL, - NULL, - - /* write multiple stream */ - NULL, - NULL, - NULL, - NULL, - - /* write region stream */ - NULL, - NULL, - NULL, - NULL, -}; - -bus_space_tag_t versatile_bus_space_pcimem = &bus_space_pcimem; diff --git a/sys/arm/versatile/versatile_pci_bus_space.h b/sys/arm/versatile/versatile_pci_bus_space.h deleted file mode 100644 index d5b54efdcc4b..000000000000 --- a/sys/arm/versatile/versatile_pci_bus_space.h +++ /dev/null @@ -1,35 +0,0 @@ -/*- - * Copyright (c) 2009, Oleksandr Tymoshenko - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice unmodified, this list of conditions, and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef __VERSATILE_PCI_BUS_SPACEH__ -#define __VERSATILE_PCI_BUS_SPACEH__ - -extern bus_space_tag_t versatile_bus_space_pcimem; - -#endif /* __VERSATILE_PCI_BUS_SPACEH__ */ From 9729d18bdd383975c6f3ea983abef05703f916c3 Mon Sep 17 00:00:00 2001 From: ian Date: Wed, 21 Jan 2015 04:19:54 +0000 Subject: [PATCH 120/258] Remove a no-longer-used include. --- sys/arm/versatile/versatile_pci.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sys/arm/versatile/versatile_pci.c b/sys/arm/versatile/versatile_pci.c index 40a120a57798..7b198ca8f86e 100644 --- a/sys/arm/versatile/versatile_pci.c +++ b/sys/arm/versatile/versatile_pci.c @@ -53,8 +53,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include - #define MEM_SYS 0 #define MEM_CORE 1 #define MEM_BASE 2 From e35efd21995fef6eed2e2c4d67e28a47bdba8727 Mon Sep 17 00:00:00 2001 From: ian Date: Wed, 21 Jan 2015 04:22:20 +0000 Subject: [PATCH 121/258] Use the base arm bus_space instead of an identical local copy. --- sys/arm/cavium/cns11xx/econa.c | 117 ++--------------------------- sys/arm/cavium/cns11xx/files.econa | 1 + 2 files changed, 6 insertions(+), 112 deletions(-) diff --git a/sys/arm/cavium/cns11xx/econa.c b/sys/arm/cavium/cns11xx/econa.c index e79e6e8d810a..b9446f09606d 100644 --- a/sys/arm/cavium/cns11xx/econa.c +++ b/sys/arm/cavium/cns11xx/econa.c @@ -56,116 +56,7 @@ unsigned int CPU_clock = 200000000; unsigned int AHB_clock; unsigned int APB_clock; -bs_protos(generic); - -struct bus_space econa_bs_tag = { - /* cookie */ - (void *) 0, - - /* mapping/unmapping */ - generic_bs_map, - generic_bs_unmap, - generic_bs_subregion, - - /* allocation/deallocation */ - generic_bs_alloc, - generic_bs_free, - - /* barrier */ - generic_bs_barrier, - - /* read (single) */ - generic_bs_r_1, - generic_bs_r_2, - generic_bs_r_4, - NULL, - - /* read multiple */ - generic_bs_rm_1, - generic_bs_rm_2, - generic_bs_rm_4, - NULL, - - /* read region */ - generic_bs_rr_1, - generic_bs_rr_2, - generic_bs_rr_4, - NULL, - - /* write (single) */ - generic_bs_w_1, - generic_bs_w_2, - generic_bs_w_4, - NULL, - - /* write multiple */ - generic_bs_wm_1, - generic_bs_wm_2, - generic_bs_wm_4, - NULL, - - /* write region */ - NULL, - NULL, - NULL, - NULL, - - /* set multiple */ - NULL, - NULL, - NULL, - NULL, - - /* set region */ - NULL, - NULL, - NULL, - NULL, - - /* copy */ - NULL, - NULL, - NULL, - NULL, - - /* read (single) stream */ - NULL, - NULL, - NULL, - NULL, - - /* read multiple stream */ - NULL, - generic_bs_rm_2, - NULL, - NULL, - - /* read region stream */ - NULL, - NULL, - NULL, - NULL, - - /* write (single) stream */ - NULL, - NULL, - NULL, - NULL, - - /* write multiple stream */ - NULL, - generic_bs_wm_2, - NULL, - NULL, - - /* write region stream */ - NULL, - NULL, - NULL, - NULL -}; - -bus_space_tag_t obio_tag = &econa_bs_tag; +bus_space_tag_t obio_tag; static int econa_probe(device_t dev) @@ -464,8 +355,10 @@ econa_attach(device_t dev) struct econa_softc *sc = device_get_softc(dev); int i; + obio_tag = arm_base_bs_tag; + econa_softc = sc; - sc->ec_st = &econa_bs_tag; + sc->ec_st = arm_base_bs_tag; sc->ec_sh = ECONA_IO_BASE; sc->dev = dev; if (bus_space_subregion(sc->ec_st, sc->ec_sh, ECONA_PIC_BASE, @@ -547,7 +440,7 @@ econa_alloc_resource(device_t dev, device_t child, int type, int *rid, rle->res = rman_reserve_resource(&sc->ec_mem_rman, start, end, count, flags, child); if (rle->res != NULL) { - rman_set_bustag(rle->res, &econa_bs_tag); + rman_set_bustag(rle->res, arm_base_bs_tag); rman_set_bushandle(rle->res, start); } break; diff --git a/sys/arm/cavium/cns11xx/files.econa b/sys/arm/cavium/cns11xx/files.econa index c69895a8390d..14d9151cb293 100644 --- a/sys/arm/cavium/cns11xx/files.econa +++ b/sys/arm/cavium/cns11xx/files.econa @@ -6,6 +6,7 @@ arm/cavium/cns11xx/timer.c standard arm/cavium/cns11xx/uart_bus_ec.c optional uart arm/cavium/cns11xx/uart_cpu_ec.c optional uart dev/uart/uart_dev_ns8250.c optional uart +arm/arm/bus_space_base.c standard arm/arm/bus_space_generic.c standard arm/cavium/cns11xx/ehci_ebus.c optional ehci arm/cavium/cns11xx/ohci_ec.c optional ohci From 673eea0b9b771e4cca3edfed4dbbd827f64f462b Mon Sep 17 00:00:00 2001 From: ian Date: Wed, 21 Jan 2015 04:28:19 +0000 Subject: [PATCH 122/258] Use the base arm bus_space instead of an identical local copy. --- sys/arm/samsung/s3c2xx0/files.s3c2xx0 | 1 + sys/arm/samsung/s3c2xx0/s3c24x0.c | 57 ++++++++++++---------- sys/arm/samsung/s3c2xx0/s3c2xx0var.h | 2 +- sys/arm/samsung/s3c2xx0/uart_cpu_s3c2410.c | 4 +- 4 files changed, 34 insertions(+), 30 deletions(-) diff --git a/sys/arm/samsung/s3c2xx0/files.s3c2xx0 b/sys/arm/samsung/s3c2xx0/files.s3c2xx0 index eb02fc52de34..2ab57d5190d4 100644 --- a/sys/arm/samsung/s3c2xx0/files.s3c2xx0 +++ b/sys/arm/samsung/s3c2xx0/files.s3c2xx0 @@ -1,4 +1,5 @@ # $FreeBSD$ +arm/arm/bus_space_base.c standard arm/arm/bus_space_asm_generic.S standard arm/arm/bus_space_generic.c standard arm/arm/cpufunc_asm_arm9.S standard diff --git a/sys/arm/samsung/s3c2xx0/s3c24x0.c b/sys/arm/samsung/s3c2xx0/s3c24x0.c index 49acdc65dbdd..845651fd846b 100644 --- a/sys/arm/samsung/s3c2xx0/s3c24x0.c +++ b/sys/arm/samsung/s3c2xx0/s3c24x0.c @@ -56,6 +56,8 @@ __FBSDID("$FreeBSD$"); #define S3C2XX0_XTAL_CLK 12000000 +bus_space_tag_t s3c2xx0_bs_tag; + #define IPL_LEVELS 13 u_int irqmasks[IPL_LEVELS]; @@ -349,7 +351,7 @@ s3c24x0_alloc_resource(device_t bus, device_t child, int type, int *rid, panic("Unable to map address space %#lX-%#lX", start, end); - rman_set_bustag(res, &s3c2xx0_bs_tag); + rman_set_bustag(res, s3c2xx0_bs_tag); rman_set_bushandle(res, start); if (flags & RF_ACTIVE) { if (bus_activate_resource(child, type, *rid, res)) { @@ -442,8 +444,9 @@ s3c24x0_attach(device_t dev) unsigned int i, j; u_long irqmax; + s3c2xx0_bs_tag = arm_base_bs_tag; s3c2xx0_softc = &(sc->sc_sx); - sc->sc_sx.sc_iot = iot = &s3c2xx0_bs_tag; + sc->sc_sx.sc_iot = iot = s3c2xx0_bs_tag; s3c2xx0_softc->s3c2xx0_irq_rman.rm_type = RMAN_ARRAY; s3c2xx0_softc->s3c2xx0_irq_rman.rm_descr = "S3C24X0 IRQs"; s3c2xx0_softc->s3c2xx0_mem_rman.rm_type = RMAN_ARRAY; @@ -641,7 +644,7 @@ cpu_reset(void) { (void) disable_interrupts(PSR_I|PSR_F); - bus_space_write_4(&s3c2xx0_bs_tag, s3c2xx0_softc->sc_wdt_ioh, WDT_WTCON, + bus_space_write_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_wdt_ioh, WDT_WTCON, WTCON_ENABLE | WTCON_CLKSEL_16 | WTCON_ENRST); for(;;); } @@ -651,9 +654,9 @@ s3c24x0_sleep(int mode __unused) { int reg; - reg = bus_space_read_4(&s3c2xx0_bs_tag, s3c2xx0_softc->sc_clkman_ioh, + reg = bus_space_read_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_clkman_ioh, CLKMAN_CLKCON); - bus_space_write_4(&s3c2xx0_bs_tag, s3c2xx0_softc->sc_clkman_ioh, + bus_space_write_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_clkman_ioh, CLKMAN_CLKCON, reg | CLKCON_IDLE); } @@ -664,15 +667,15 @@ arm_get_next_irq(int last __unused) uint32_t intpnd; int irq, subirq; - if ((irq = bus_space_read_4(&s3c2xx0_bs_tag, + if ((irq = bus_space_read_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTOFFSET)) != 0) { /* Clear the pending bit */ - intpnd = bus_space_read_4(&s3c2xx0_bs_tag, + intpnd = bus_space_read_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTPND); - bus_space_write_4(&s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh, + bus_space_write_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh, INTCTL_SRCPND, intpnd); - bus_space_write_4(&s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh, + bus_space_write_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTPND, intpnd); switch (irq) { @@ -682,9 +685,9 @@ arm_get_next_irq(int last __unused) case S3C24X0_INT_UART2: /* Find the sub IRQ */ subirq = 0x7ff; - subirq &= bus_space_read_4(&s3c2xx0_bs_tag, + subirq &= bus_space_read_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh, INTCTL_SUBSRCPND); - subirq &= ~(bus_space_read_4(&s3c2xx0_bs_tag, + subirq &= ~(bus_space_read_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK)); if (subirq == 0) return (irq); @@ -692,7 +695,7 @@ arm_get_next_irq(int last __unused) subirq = ffs(subirq) - 1; /* Clear the sub irq pending bit */ - bus_space_write_4(&s3c2xx0_bs_tag, + bus_space_write_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh, INTCTL_SUBSRCPND, (1 << subirq)); @@ -716,9 +719,9 @@ arm_get_next_irq(int last __unused) case S3C24X0_INT_8_23: /* Find the external interrupt being called */ subirq = 0x7fffff; - subirq &= bus_space_read_4(&s3c2xx0_bs_tag, + subirq &= bus_space_read_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTPEND); - subirq &= ~bus_space_read_4(&s3c2xx0_bs_tag, + subirq &= ~bus_space_read_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTMASK); if (subirq == 0) return (irq); @@ -726,7 +729,7 @@ arm_get_next_irq(int last __unused) subirq = ffs(subirq) - 1; /* Clear the external irq pending bit */ - bus_space_write_4(&s3c2xx0_bs_tag, + bus_space_write_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTPEND, (1 << subirq)); @@ -748,22 +751,22 @@ arm_mask_irq(uintptr_t irq) irq -= S3C24X0_EXTIRQ_MIN; } if (irq < S3C24X0_SUBIRQ_MIN) { - mask = bus_space_read_4(&s3c2xx0_bs_tag, + mask = bus_space_read_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK); mask |= (1 << irq); - bus_space_write_4(&s3c2xx0_bs_tag, + bus_space_write_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK, mask); } else if (irq < S3C24X0_EXTIRQ_MIN) { - mask = bus_space_read_4(&s3c2xx0_bs_tag, + mask = bus_space_read_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK); mask |= (1 << (irq - S3C24X0_SUBIRQ_MIN)); - bus_space_write_4(&s3c2xx0_bs_tag, + bus_space_write_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK, mask); } else { - mask = bus_space_read_4(&s3c2xx0_bs_tag, + mask = bus_space_read_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTMASK); mask |= (1 << (irq - S3C24X0_EXTIRQ_MIN)); - bus_space_write_4(&s3c2xx0_bs_tag, + bus_space_write_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh, GPIO_EINTMASK, mask); } } @@ -778,22 +781,22 @@ arm_unmask_irq(uintptr_t irq) irq -= S3C24X0_EXTIRQ_MIN; } if (irq < S3C24X0_SUBIRQ_MIN) { - mask = bus_space_read_4(&s3c2xx0_bs_tag, + mask = bus_space_read_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK); mask &= ~(1 << irq); - bus_space_write_4(&s3c2xx0_bs_tag, + bus_space_write_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK, mask); } else if (irq < S3C24X0_EXTIRQ_MIN) { - mask = bus_space_read_4(&s3c2xx0_bs_tag, + mask = bus_space_read_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK); mask &= ~(1 << (irq - S3C24X0_SUBIRQ_MIN)); - bus_space_write_4(&s3c2xx0_bs_tag, + bus_space_write_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK, mask); } else { - mask = bus_space_read_4(&s3c2xx0_bs_tag, + mask = bus_space_read_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTMASK); mask &= ~(1 << (irq - S3C24X0_EXTIRQ_MIN)); - bus_space_write_4(&s3c2xx0_bs_tag, + bus_space_write_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh, GPIO_EINTMASK, mask); } } diff --git a/sys/arm/samsung/s3c2xx0/s3c2xx0var.h b/sys/arm/samsung/s3c2xx0/s3c2xx0var.h index fea0982e9b01..505c6b0f789e 100644 --- a/sys/arm/samsung/s3c2xx0/s3c2xx0var.h +++ b/sys/arm/samsung/s3c2xx0/s3c2xx0var.h @@ -74,7 +74,7 @@ struct s3c2xx0_ivar { typedef void *s3c2xx0_chipset_tag_t; -extern struct bus_space s3c2xx0_bs_tag; +extern bus_space_tag_t s3c2xx0_bs_tag; extern struct s3c2xx0_softc *s3c2xx0_softc; extern struct arm32_bus_dma_tag s3c2xx0_bus_dma; diff --git a/sys/arm/samsung/s3c2xx0/uart_cpu_s3c2410.c b/sys/arm/samsung/s3c2xx0/uart_cpu_s3c2410.c index 37b668e85da3..1beb12d77314 100644 --- a/sys/arm/samsung/s3c2xx0/uart_cpu_s3c2410.c +++ b/sys/arm/samsung/s3c2xx0/uart_cpu_s3c2410.c @@ -61,7 +61,7 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di) di->ops = uart_getops(&uart_s3c2410_class); di->bas.chan = 0; - di->bas.bst = &s3c2xx0_bs_tag; + di->bas.bst = s3c2xx0_bs_tag; di->bas.bsh = s3c2410_uart_vaddr; di->bas.regshft = 0; di->bas.rclk = s3c2410_pclk; @@ -69,7 +69,7 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di) di->databits = 8; di->stopbits = 1; di->parity = UART_PARITY_NONE; - uart_bus_space_io = &s3c2xx0_bs_tag; + uart_bus_space_io = s3c2xx0_bs_tag; uart_bus_space_mem = NULL; return (0); From 11083b32fd5a9aeaf4dcdf0421276dc5e7fa64a1 Mon Sep 17 00:00:00 2001 From: ian Date: Wed, 21 Jan 2015 05:05:07 +0000 Subject: [PATCH 123/258] Use the base arm bus_space instead of an identical local copy. --- sys/arm/xscale/i80321/ep80219_machdep.c | 2 +- sys/arm/xscale/i80321/files.ep80219 | 1 - sys/arm/xscale/i80321/files.i80219 | 1 + sys/arm/xscale/i80321/files.i80321 | 1 + sys/arm/xscale/i80321/files.iq31244 | 1 - sys/arm/xscale/i80321/iq31244_machdep.c | 2 +- sys/arm/xscale/i80321/obio.c | 5 +- sys/arm/xscale/i80321/obio_space.c | 127 ------------------------ sys/arm/xscale/i80321/obiovar.h | 2 +- sys/arm/xscale/i80321/uart_cpu_i80321.c | 4 +- sys/arm/xscale/i8134x/crb_machdep.c | 2 +- sys/arm/xscale/i8134x/files.i81342 | 2 +- sys/arm/xscale/i8134x/obio.c | 4 +- sys/arm/xscale/i8134x/obiovar.h | 2 +- sys/arm/xscale/i8134x/uart_cpu_i81342.c | 4 +- 15 files changed, 19 insertions(+), 141 deletions(-) delete mode 100644 sys/arm/xscale/i80321/obio_space.c diff --git a/sys/arm/xscale/i80321/ep80219_machdep.c b/sys/arm/xscale/i80321/ep80219_machdep.c index bf3e49ada307..f04f7fdef977 100644 --- a/sys/arm/xscale/i80321/ep80219_machdep.c +++ b/sys/arm/xscale/i80321/ep80219_machdep.c @@ -312,7 +312,7 @@ initarm(struct arm_boot_params *abp) * registers. */ i80321_calibrate_delay(); - i80321_sdram_bounds(&obio_bs_tag, IQ80321_80321_VBASE + VERDE_MCU_BASE, + i80321_sdram_bounds(obio_bs_tag, IQ80321_80321_VBASE + VERDE_MCU_BASE, &memstart, &memsize); physmem = memsize / PAGE_SIZE; cninit(); diff --git a/sys/arm/xscale/i80321/files.ep80219 b/sys/arm/xscale/i80321/files.ep80219 index cbf2e39ed5a8..0eaf9db2872c 100644 --- a/sys/arm/xscale/i80321/files.ep80219 +++ b/sys/arm/xscale/i80321/files.ep80219 @@ -6,7 +6,6 @@ arm/xscale/i80321/iq80321.c standard arm/xscale/i80321/ep80219_machdep.c standard arm/xscale/i80321/obio.c standard -arm/xscale/i80321/obio_space.c standard arm/xscale/i80321/uart_cpu_i80321.c optional uart arm/xscale/i80321/uart_bus_i80321.c optional uart dev/uart/uart_dev_ns8250.c optional uart diff --git a/sys/arm/xscale/i80321/files.i80219 b/sys/arm/xscale/i80321/files.i80219 index e9d9eab95643..10b7630b3da0 100644 --- a/sys/arm/xscale/i80321/files.i80219 +++ b/sys/arm/xscale/i80321/files.i80219 @@ -2,6 +2,7 @@ # # IOP Specific # +arm/arm/bus_space_base.c standard arm/arm/bus_space_generic.c standard arm/arm/cpufunc_asm_xscale.S standard arm/xscale/i80321/i80321.c standard diff --git a/sys/arm/xscale/i80321/files.i80321 b/sys/arm/xscale/i80321/files.i80321 index 48082242e3a3..48f9b08a07ff 100644 --- a/sys/arm/xscale/i80321/files.i80321 +++ b/sys/arm/xscale/i80321/files.i80321 @@ -1,4 +1,5 @@ #$FreeBSD$ +arm/arm/bus_space_base.c standard arm/arm/bus_space_generic.c standard arm/arm/cpufunc_asm_xscale.S standard arm/xscale/i80321/i80321.c standard diff --git a/sys/arm/xscale/i80321/files.iq31244 b/sys/arm/xscale/i80321/files.iq31244 index 66d89b3db630..d28d49b3a6b1 100644 --- a/sys/arm/xscale/i80321/files.iq31244 +++ b/sys/arm/xscale/i80321/files.iq31244 @@ -3,7 +3,6 @@ arm/xscale/i80321/iq80321.c standard arm/xscale/i80321/iq31244_machdep.c standard arm/xscale/i80321/iq31244_7seg.c optional iq31244_7seg arm/xscale/i80321/obio.c standard -arm/xscale/i80321/obio_space.c standard arm/xscale/i80321/uart_cpu_i80321.c optional uart arm/xscale/i80321/uart_bus_i80321.c optional uart dev/uart/uart_dev_ns8250.c optional uart diff --git a/sys/arm/xscale/i80321/iq31244_machdep.c b/sys/arm/xscale/i80321/iq31244_machdep.c index 9c119ed25bc0..1a1b9e72fc79 100644 --- a/sys/arm/xscale/i80321/iq31244_machdep.c +++ b/sys/arm/xscale/i80321/iq31244_machdep.c @@ -313,7 +313,7 @@ initarm(struct arm_boot_params *abp) * registers. */ i80321_calibrate_delay(); - i80321_sdram_bounds(&obio_bs_tag, IQ80321_80321_VBASE + VERDE_MCU_BASE, + i80321_sdram_bounds(obio_bs_tag, IQ80321_80321_VBASE + VERDE_MCU_BASE, &memstart, &memsize); physmem = memsize / PAGE_SIZE; cninit(); diff --git a/sys/arm/xscale/i80321/obio.c b/sys/arm/xscale/i80321/obio.c index 566d6cd11ce1..55218ccd20d1 100644 --- a/sys/arm/xscale/i80321/obio.c +++ b/sys/arm/xscale/i80321/obio.c @@ -58,6 +58,8 @@ __FBSDID("$FreeBSD$"); #include #include +bus_space_tag_t obio_bs_tag; + int obio_probe(device_t); int obio_attach(device_t); @@ -72,7 +74,8 @@ obio_attach(device_t dev) { struct obio_softc *sc = device_get_softc(dev); - sc->oba_st = &obio_bs_tag; + obio_bs_tag = arm_base_bs_tag; + sc->oba_st = obio_bs_tag; sc->oba_addr = IQ80321_OBIO_BASE; sc->oba_size = IQ80321_OBIO_SIZE; sc->oba_rman.rm_type = RMAN_ARRAY; diff --git a/sys/arm/xscale/i80321/obio_space.c b/sys/arm/xscale/i80321/obio_space.c deleted file mode 100644 index 4eba7000dbc7..000000000000 --- a/sys/arm/xscale/i80321/obio_space.c +++ /dev/null @@ -1,127 +0,0 @@ -/* $NetBSD: obio_space.c,v 1.6 2003/07/15 00:25:05 lukem Exp $ */ - -/*- - * Copyright (c) 2001, 2002, 2003 Wasabi Systems, Inc. - * All rights reserved. - * - * Written by Jason R. Thorpe for Wasabi Systems, Inc. - * - * 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 for the NetBSD Project by - * Wasabi Systems, Inc. - * 4. The name of Wasabi Systems, Inc. may not be used to endorse - * or promote products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC - * 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. - */ - -/* - * bus_space functions for IQ80321 on-board devices - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include - -#include - -/* Prototypes for all the bus_space structure functions */ -bs_protos(generic); - -/* - * The obio bus space tag. This is constant for all instances, so - * we never have to explicitly "create" it. - */ -struct bus_space obio_bs_tag = { - /* cookie */ - (void *) 0, - - /* mapping/unmapping */ - generic_bs_map, - generic_bs_unmap, - generic_bs_subregion, - - /* allocation/deallocation */ - generic_bs_alloc, - generic_bs_free, - - /* barrier */ - generic_bs_barrier, - - /* read (single) */ - generic_bs_r_1, - generic_bs_r_2, - generic_bs_r_4, - NULL, - - /* read multiple */ - generic_bs_rm_1, - NULL, - NULL, - NULL, - - /* read region */ - generic_bs_rr_1, - NULL, - NULL, - NULL, - - /* write (single) */ - generic_bs_w_1, - generic_bs_w_2, - generic_bs_w_4, - NULL, - - /* write multiple */ - generic_bs_wm_1, - NULL, - NULL, - NULL, - - /* write region */ - NULL, - NULL, - NULL, - NULL, - - /* set multiple */ - NULL, - NULL, - NULL, - NULL, - - /* set region */ - NULL, - NULL, - NULL, - NULL, - - /* copy */ - NULL, - NULL, - NULL, - NULL, -}; diff --git a/sys/arm/xscale/i80321/obiovar.h b/sys/arm/xscale/i80321/obiovar.h index 8e0c1459d708..182b52f57f5a 100644 --- a/sys/arm/xscale/i80321/obiovar.h +++ b/sys/arm/xscale/i80321/obiovar.h @@ -53,6 +53,6 @@ struct obio_softc { struct rman oba_irq_rman; }; -extern struct bus_space obio_bs_tag; +extern bus_space_tag_t obio_bs_tag; #endif /* _IQ80321_OBIOVAR_H_ */ diff --git a/sys/arm/xscale/i80321/uart_cpu_i80321.c b/sys/arm/xscale/i80321/uart_cpu_i80321.c index 32dd463cfb47..a3faec7289df 100644 --- a/sys/arm/xscale/i80321/uart_cpu_i80321.c +++ b/sys/arm/xscale/i80321/uart_cpu_i80321.c @@ -53,14 +53,14 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di) { di->ops = uart_getops(&uart_ns8250_class); di->bas.chan = 0; - di->bas.bst = &obio_bs_tag; + di->bas.bst = obio_bs_tag; di->bas.regshft = 0; di->bas.rclk = 0; di->baudrate = 115200; di->databits = 8; di->stopbits = 1; di->parity = UART_PARITY_NONE; - uart_bus_space_io = &obio_bs_tag; + uart_bus_space_io = obio_bs_tag; uart_bus_space_mem = NULL; di->bas.bsh = 0xfe800000; return (0); diff --git a/sys/arm/xscale/i8134x/crb_machdep.c b/sys/arm/xscale/i8134x/crb_machdep.c index 195304485bf7..3e6440d4b012 100644 --- a/sys/arm/xscale/i8134x/crb_machdep.c +++ b/sys/arm/xscale/i8134x/crb_machdep.c @@ -293,7 +293,7 @@ initarm(struct arm_boot_params *abp) cpu_setup(""); i80321_calibrate_delay(); - i81342_sdram_bounds(&obio_bs_tag, IOP34X_VADDR, &memstart, &memsize); + i81342_sdram_bounds(obio_bs_tag, IOP34X_VADDR, &memstart, &memsize); physmem = memsize / PAGE_SIZE; cninit(); /* Set stack for exception handlers */ diff --git a/sys/arm/xscale/i8134x/files.i81342 b/sys/arm/xscale/i8134x/files.i81342 index c9bd619ed641..089301689857 100644 --- a/sys/arm/xscale/i8134x/files.i81342 +++ b/sys/arm/xscale/i8134x/files.i81342 @@ -1,4 +1,5 @@ # $FreeBSD$ +arm/arm/bus_space_base.c standard arm/arm/bus_space_generic.c standard arm/arm/cpufunc_asm_xscale.S standard arm/arm/cpufunc_asm_xscale_c3.S standard @@ -9,7 +10,6 @@ arm/xscale/i8134x/i81342_mcu.c standard arm/xscale/i8134x/i81342_pci.c optional pci arm/xscale/i8134x/i81342_space.c standard arm/xscale/i8134x/obio.c standard -arm/xscale/i8134x/obio_space.c standard arm/xscale/i8134x/uart_bus_i81342.c optional uart arm/xscale/i8134x/uart_cpu_i81342.c optional uart dev/uart/uart_dev_ns8250.c optional uart diff --git a/sys/arm/xscale/i8134x/obio.c b/sys/arm/xscale/i8134x/obio.c index b8bccce43a1a..5aa3c477d2e2 100644 --- a/sys/arm/xscale/i8134x/obio.c +++ b/sys/arm/xscale/i8134x/obio.c @@ -56,6 +56,7 @@ __FBSDID("$FreeBSD$"); #include #include +bus_space_tag_t obio_bs_tag; static int obio_probe(device_t dev) @@ -68,7 +69,8 @@ obio_attach(device_t dev) { struct obio_softc *sc = device_get_softc(dev); - sc->oba_st = &obio_bs_tag; + obio_bs_tag = arm_base_bs_tag; + sc->oba_st = obio_bs_tag; sc->oba_rman.rm_type = RMAN_ARRAY; sc->oba_rman.rm_descr = "OBIO I/O"; if (rman_init(&sc->oba_rman) != 0 || diff --git a/sys/arm/xscale/i8134x/obiovar.h b/sys/arm/xscale/i8134x/obiovar.h index 7350d0ade1bb..237dd9e7d944 100644 --- a/sys/arm/xscale/i8134x/obiovar.h +++ b/sys/arm/xscale/i8134x/obiovar.h @@ -50,6 +50,6 @@ struct obio_softc { struct rman oba_irq_rman; }; -extern struct bus_space obio_bs_tag; +extern bus_space_tag_t obio_bs_tag; #endif /* _IQ80321_OBIOVAR_H_ */ diff --git a/sys/arm/xscale/i8134x/uart_cpu_i81342.c b/sys/arm/xscale/i8134x/uart_cpu_i81342.c index 2cb2902a9d1a..1d98d78bcfe2 100644 --- a/sys/arm/xscale/i8134x/uart_cpu_i81342.c +++ b/sys/arm/xscale/i8134x/uart_cpu_i81342.c @@ -54,14 +54,14 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di) di->ops = uart_getops(&uart_ns8250_class); di->bas.chan = 0; - di->bas.bst = &obio_bs_tag; + di->bas.bst = obio_bs_tag; di->bas.regshft = 2; di->bas.rclk = 33334000; di->baudrate = 115200; di->databits = 8; di->stopbits = 1; di->parity = UART_PARITY_NONE; - uart_bus_space_io = &obio_bs_tag; + uart_bus_space_io = obio_bs_tag; uart_bus_space_mem = NULL; di->bas.bsh = IOP34X_UART0_VADDR; return (0); From c9a8a6da01d6f4055fe440c2a94e815b8f53d519 Mon Sep 17 00:00:00 2001 From: ian Date: Wed, 21 Jan 2015 05:10:23 +0000 Subject: [PATCH 124/258] Use the base arm bus_space instead of an identical local copy. --- sys/arm/xscale/i80321/i80321_space.c | 118 +-------------------------- sys/arm/xscale/i8134x/i81342_space.c | 118 +-------------------------- 2 files changed, 6 insertions(+), 230 deletions(-) diff --git a/sys/arm/xscale/i80321/i80321_space.c b/sys/arm/xscale/i80321/i80321_space.c index da4ad2185a86..64c222522cd2 100644 --- a/sys/arm/xscale/i80321/i80321_space.c +++ b/sys/arm/xscale/i80321/i80321_space.c @@ -63,124 +63,12 @@ __FBSDID("$FreeBSD$"); bs_protos(i80321); bs_protos(i80321_io); bs_protos(i80321_mem); -bs_protos(generic); - -/* - * Template bus_space -- copied, and the bits that are NULL are - * filled in. - */ -const struct bus_space i80321_bs_tag_template = { - /* cookie */ - (void *) 0, - - /* mapping/unmapping */ - NULL, - NULL, - i80321_bs_subregion, - - /* allocation/deallocation */ - NULL, - NULL, - - /* barrier */ - i80321_bs_barrier, - - /* read (single) */ - generic_bs_r_1, - generic_bs_r_2, - generic_bs_r_4, - NULL, - - /* read multiple */ - generic_bs_rm_1, - generic_bs_rm_2, - generic_bs_rm_4, - NULL, - - /* read region */ - generic_bs_rr_1, - generic_bs_rr_2, - generic_bs_rr_4, - NULL, - - /* write (single) */ - generic_bs_w_1, - generic_bs_w_2, - generic_bs_w_4, - NULL, - - /* write multiple */ - generic_bs_wm_1, - generic_bs_wm_2, - generic_bs_wm_4, - NULL, - - /* write region */ - NULL, - generic_bs_wr_2, - generic_bs_wr_4, - NULL, - - /* set multiple */ - NULL, - NULL, - NULL, - NULL, - - /* set region */ - NULL, - generic_bs_sr_2, - generic_bs_sr_4, - NULL, - - /* copy */ - NULL, - generic_bs_c_2, - NULL, - NULL, - - /* read (single) stream */ - generic_bs_r_1, - generic_bs_r_2, - generic_bs_r_4, - NULL, - - /* read multiple stream */ - generic_bs_rm_1, - generic_bs_rm_2, - generic_bs_rm_4, - NULL, - - /* read region stream */ - generic_bs_rr_1, - generic_bs_rr_2, - generic_bs_rr_4, - NULL, - - /* write (single) stream */ - generic_bs_w_1, - generic_bs_w_2, - generic_bs_w_4, - NULL, - - /* write multiple stream */ - generic_bs_wm_1, - generic_bs_wm_2, - generic_bs_wm_4, - NULL, - - /* write region stream */ - NULL, - generic_bs_wr_2, - generic_bs_wr_4, - NULL, -}; void i80321_bs_init(bus_space_tag_t bs, void *cookie) { - *bs = i80321_bs_tag_template; + *bs = *arm_base_bs_tag; bs->bs_privdata = cookie; } @@ -188,7 +76,7 @@ void i80321_io_bs_init(bus_space_tag_t bs, void *cookie) { - *bs = i80321_bs_tag_template; + *bs = *arm_base_bs_tag; bs->bs_privdata = cookie; bs->bs_map = i80321_io_bs_map; @@ -202,7 +90,7 @@ void i80321_mem_bs_init(bus_space_tag_t bs, void *cookie) { - *bs = i80321_bs_tag_template; + *bs = *arm_base_bs_tag; bs->bs_privdata = cookie; bs->bs_map = i80321_mem_bs_map; diff --git a/sys/arm/xscale/i8134x/i81342_space.c b/sys/arm/xscale/i8134x/i81342_space.c index 0f7912c83cac..d5d9143c70c9 100644 --- a/sys/arm/xscale/i8134x/i81342_space.c +++ b/sys/arm/xscale/i8134x/i81342_space.c @@ -64,124 +64,12 @@ __FBSDID("$FreeBSD$"); bs_protos(i81342); bs_protos(i81342_io); bs_protos(i81342_mem); -bs_protos(generic); - -/* - * Template bus_space -- copied, and the bits that are NULL are - * filled in. - */ -const struct bus_space i81342_bs_tag_template = { - /* cookie */ - (void *) 0, - - /* mapping/unmapping */ - NULL, - NULL, - i81342_bs_subregion, - - /* allocation/deallocation */ - NULL, - NULL, - - /* barrier */ - i81342_bs_barrier, - - /* read (single) */ - generic_bs_r_1, - generic_bs_r_2, - generic_bs_r_4, - NULL, - - /* read multiple */ - generic_bs_rm_1, - generic_bs_rm_2, - generic_bs_rm_4, - NULL, - - /* read region */ - generic_bs_rr_1, - generic_bs_rr_2, - generic_bs_rr_4, - NULL, - - /* write (single) */ - generic_bs_w_1, - generic_bs_w_2, - generic_bs_w_4, - NULL, - - /* write multiple */ - generic_bs_wm_1, - generic_bs_wm_2, - generic_bs_wm_4, - NULL, - - /* write region */ - NULL, - generic_bs_wr_2, - generic_bs_wr_4, - NULL, - - /* set multiple */ - NULL, - NULL, - NULL, - NULL, - - /* set region */ - NULL, - generic_bs_sr_2, - generic_bs_sr_4, - NULL, - - /* copy */ - NULL, - generic_bs_c_2, - NULL, - NULL, - - /* read (single) stream */ - generic_bs_r_1, - generic_bs_r_2, - generic_bs_r_4, - NULL, - - /* read multiple stream */ - generic_bs_rm_1, - generic_bs_rm_2, - generic_bs_rm_4, - NULL, - - /* read region stream */ - generic_bs_rr_1, - generic_bs_rr_2, - generic_bs_rr_4, - NULL, - - /* write (single) stream */ - generic_bs_w_1, - generic_bs_w_2, - generic_bs_w_4, - NULL, - - /* write multiple stream */ - generic_bs_wm_1, - generic_bs_wm_2, - generic_bs_wm_4, - NULL, - - /* write region stream */ - NULL, - generic_bs_wr_2, - generic_bs_wr_4, - NULL, -}; void i81342_bs_init(bus_space_tag_t bs, void *cookie) { - *bs = i81342_bs_tag_template; + *bs = *arm_base_bs_tag; bs->bs_privdata = cookie; } @@ -189,7 +77,7 @@ void i81342_io_bs_init(bus_space_tag_t bs, void *cookie) { - *bs = i81342_bs_tag_template; + *bs = *arm_base_bs_tag; bs->bs_privdata = cookie; bs->bs_map = i81342_io_bs_map; @@ -203,7 +91,7 @@ void i81342_mem_bs_init(bus_space_tag_t bs, void *cookie) { - *bs = i81342_bs_tag_template; + *bs = *arm_base_bs_tag; bs->bs_privdata = cookie; bs->bs_map = i81342_mem_bs_map; From 0f984f8bbb285b0ed473715efafc80e9a0fb6d56 Mon Sep 17 00:00:00 2001 From: ian Date: Wed, 21 Jan 2015 05:23:09 +0000 Subject: [PATCH 125/258] Use explicit initializer style, fill in missing functions as unimplemented. --- sys/arm/xscale/pxa/pxa_space.c | 122 +++++++++++++++++++++------------ 1 file changed, 79 insertions(+), 43 deletions(-) diff --git a/sys/arm/xscale/pxa/pxa_space.c b/sys/arm/xscale/pxa/pxa_space.c index 7a9160a8974e..35b6cd9f4223 100644 --- a/sys/arm/xscale/pxa/pxa_space.c +++ b/sys/arm/xscale/pxa/pxa_space.c @@ -65,73 +65,109 @@ bs_protos(pxa); */ struct bus_space _base_tag = { /* cookie */ - (void *) 0, + .bs_privdata = NULL, /* mapping/unmapping */ - generic_bs_map, - generic_bs_unmap, - generic_bs_subregion, + .bs_map = generic_bs_map, + .bs_unmap = generic_bs_unmap, + .bs_subregion = generic_bs_subregion, /* allocation/deallocation */ - generic_bs_alloc, - generic_bs_free, + .bs_alloc = generic_bs_alloc, + .bs_free = generic_bs_free, /* barrier */ - generic_bs_barrier, + .bs_barrier = generic_bs_barrier, /* read (single) */ - pxa_bs_r_1, - pxa_bs_r_2, - pxa_bs_r_4, - NULL, + .bs_r_1 = pxa_bs_r_1, + .bs_r_2 = pxa_bs_r_2, + .bs_r_4 = pxa_bs_r_4, + .bs_r_8 = BS_UNIMPLEMENTED, /* read multiple */ - pxa_bs_rm_1, - pxa_bs_rm_2, - NULL, - NULL, + .bs_rm_1 = pxa_bs_rm_1, + .bs_rm_2 = pxa_bs_rm_2, + .bs_rm_4 = BS_UNIMPLEMENTED, + .bs_rm_8 = BS_UNIMPLEMENTED, /* read region */ - pxa_bs_rr_1, - NULL, - NULL, - NULL, + .bs_rr_1 = pxa_bs_rr_1, + .bs_rr_2 = BS_UNIMPLEMENTED, + .bs_rr_4 = BS_UNIMPLEMENTED, + .bs_rr_8 = BS_UNIMPLEMENTED, /* write (single) */ - pxa_bs_w_1, - pxa_bs_w_2, - pxa_bs_w_4, - NULL, + .bs_w_1 = pxa_bs_w_1, + .bs_w_2 = pxa_bs_w_2, + .bs_w_4 = pxa_bs_w_4, + .bs_w_8 = BS_UNIMPLEMENTED, /* write multiple */ - pxa_bs_wm_1, - pxa_bs_wm_2, - NULL, - NULL, + .bs_wm_1 = pxa_bs_wm_1, + .bs_wm_2 = pxa_bs_wm_2, + .bs_wm_4 = BS_UNIMPLEMENTED, + .bs_wm_8 = BS_UNIMPLEMENTED, /* write region */ - NULL, - NULL, - NULL, - NULL, + .bs_wr_1 = BS_UNIMPLEMENTED, + .bs_wr_2 = BS_UNIMPLEMENTED, + .bs_wr_4 = BS_UNIMPLEMENTED, + .bs_wr_8 = BS_UNIMPLEMENTED, /* set multiple */ - NULL, - NULL, - NULL, - NULL, + .bs_sm_1 = BS_UNIMPLEMENTED, + .bs_sm_2 = BS_UNIMPLEMENTED, + .bs_sm_4 = BS_UNIMPLEMENTED, + .bs_sm_8 = BS_UNIMPLEMENTED, /* set region */ - NULL, - NULL, - NULL, - NULL, + .bs_sr_1 = BS_UNIMPLEMENTED, + .bs_sr_2 = BS_UNIMPLEMENTED, + .bs_sr_4 = BS_UNIMPLEMENTED, + .bs_sr_8 = BS_UNIMPLEMENTED, /* copy */ - NULL, - NULL, - NULL, - NULL, + .bs_c_1 = BS_UNIMPLEMENTED, + .bs_c_2 = BS_UNIMPLEMENTED, + .bs_c_4 = BS_UNIMPLEMENTED, + .bs_c_8 = BS_UNIMPLEMENTED, + + /* read stream (single) */ + .bs_r_1_s = BS_UNIMPLEMENTED, + .bs_r_2_s = BS_UNIMPLEMENTED, + .bs_r_4_s = BS_UNIMPLEMENTED, + .bs_r_8_s = BS_UNIMPLEMENTED, + + /* read multiple stream */ + .bs_rm_1_s = BS_UNIMPLEMENTED, + .bs_rm_2_s = BS_UNIMPLEMENTED, + .bs_rm_4_s = BS_UNIMPLEMENTED, + .bs_rm_8_s = BS_UNIMPLEMENTED, + + /* read region stream */ + .bs_rr_1_s = BS_UNIMPLEMENTED, + .bs_rr_2_s = BS_UNIMPLEMENTED, + .bs_rr_4_s = BS_UNIMPLEMENTED, + .bs_rr_8_s = BS_UNIMPLEMENTED, + + /* write stream (single) */ + .bs_w_1_s = BS_UNIMPLEMENTED, + .bs_w_2_s = BS_UNIMPLEMENTED, + .bs_w_4_s = BS_UNIMPLEMENTED, + .bs_w_8_s = BS_UNIMPLEMENTED, + + /* write multiple stream */ + .bs_wm_1_s = BS_UNIMPLEMENTED, + .bs_wm_2_s = BS_UNIMPLEMENTED, + .bs_wm_4_s = BS_UNIMPLEMENTED, + .bs_wm_8_s = BS_UNIMPLEMENTED, + + /* write region stream */ + .bs_wr_1_s = BS_UNIMPLEMENTED, + .bs_wr_2_s = BS_UNIMPLEMENTED, + .bs_wr_4_s = BS_UNIMPLEMENTED, + .bs_wr_8_s = BS_UNIMPLEMENTED, }; static struct bus_space _obio_tag; From 3d363fe9808ea4d0101a181cd1106b2c76eac480 Mon Sep 17 00:00:00 2001 From: ian Date: Wed, 21 Jan 2015 05:31:54 +0000 Subject: [PATCH 126/258] Remove a couple files that are no longer used (functionality take over by arm/bus_space_base.c). --- sys/arm/samsung/s3c2xx0/files.s3c2xx0 | 1 - sys/arm/samsung/s3c2xx0/s3c2xx0_space.c | 164 ------------------------ sys/arm/xscale/i8134x/obio_space.c | 127 ------------------ 3 files changed, 292 deletions(-) delete mode 100644 sys/arm/samsung/s3c2xx0/s3c2xx0_space.c delete mode 100644 sys/arm/xscale/i8134x/obio_space.c diff --git a/sys/arm/samsung/s3c2xx0/files.s3c2xx0 b/sys/arm/samsung/s3c2xx0/files.s3c2xx0 index 2ab57d5190d4..7b6c7e4e9eca 100644 --- a/sys/arm/samsung/s3c2xx0/files.s3c2xx0 +++ b/sys/arm/samsung/s3c2xx0/files.s3c2xx0 @@ -7,7 +7,6 @@ arm/samsung/s3c2xx0/board_ln2410sbc.c optional board_ln2410sbc arm/samsung/s3c2xx0/s3c24x0_rtc.c standard arm/samsung/s3c2xx0/s3c24x0_machdep.c standard arm/samsung/s3c2xx0/s3c24x0.c standard -arm/samsung/s3c2xx0/s3c2xx0_space.c standard arm/samsung/s3c2xx0/s3c24x0_clk.c standard arm/samsung/s3c2xx0/uart_bus_s3c2410.c optional uart arm/samsung/s3c2xx0/uart_cpu_s3c2410.c optional uart diff --git a/sys/arm/samsung/s3c2xx0/s3c2xx0_space.c b/sys/arm/samsung/s3c2xx0/s3c2xx0_space.c deleted file mode 100644 index 61c00eb6841a..000000000000 --- a/sys/arm/samsung/s3c2xx0/s3c2xx0_space.c +++ /dev/null @@ -1,164 +0,0 @@ -/* $NetBSD: s3c2xx0_space.c,v 1.7 2005/11/24 13:08:32 yamt Exp $ */ - -/* - * Copyright (c) 2002 Fujitsu Component Limited - * Copyright (c) 2002 Genetec 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. - * 3. Neither the name of The Fujitsu Component Limited nor the name of - * Genetec corporation may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY FUJITSU COMPONENT LIMITED AND GENETEC - * CORPORATION ``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 FUJITSU COMPONENT LIMITED OR GENETEC - * CORPORATION 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. - */ -/* derived from sa11x0_io.c */ - -/* - * Copyright (c) 1997 Mark Brinicombe. - * Copyright (c) 1997 Causality Limited. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Ichiro FUKUHARA. - * - * 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 Mark Brinicombe. - * 4. The name of the company nor the name of the author may be used to - * endorse or promote products derived from this software without specific - * prior written permission. - * - * 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 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. - */ - -/* - * bus_space functions for Samsung S3C2800/2400/2410. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -/* Prototypes for all the bus_space structure functions */ -bs_protos(generic); - -struct bus_space s3c2xx0_bs_tag = { - /* cookie */ - (void *) 0, - - /* mapping/unmapping */ - generic_bs_map, - generic_bs_unmap, - generic_bs_subregion, - - /* allocation/deallocation */ - generic_bs_alloc, /* not implemented */ - generic_bs_free, /* not implemented */ - - /* barrier */ - generic_bs_barrier, - - /* read (single) */ - generic_bs_r_1, - generic_bs_r_2, - generic_bs_r_4, - NULL, - - /* read multiple */ - generic_bs_rm_1, - generic_bs_rm_2, - generic_bs_rm_4, - NULL, - - /* read region */ - generic_bs_rr_1, - generic_bs_rr_2, - generic_bs_rr_4, - NULL, - - /* write (single) */ - generic_bs_w_1, - generic_bs_w_2, - generic_bs_w_4, - NULL, - - /* write multiple */ - generic_bs_wm_1, - generic_bs_wm_2, - generic_bs_wm_4, - NULL, - - /* write region */ - generic_bs_wr_1, - generic_bs_wr_2, - generic_bs_wr_4, - NULL, - - /* set multiple */ - NULL, - NULL, - NULL, - NULL, - - /* set region */ - generic_bs_sr_1, - generic_bs_sr_2, - NULL, - NULL, - - /* copy */ - NULL, - generic_bs_c_2, - NULL, - NULL, -}; - diff --git a/sys/arm/xscale/i8134x/obio_space.c b/sys/arm/xscale/i8134x/obio_space.c deleted file mode 100644 index 4eba7000dbc7..000000000000 --- a/sys/arm/xscale/i8134x/obio_space.c +++ /dev/null @@ -1,127 +0,0 @@ -/* $NetBSD: obio_space.c,v 1.6 2003/07/15 00:25:05 lukem Exp $ */ - -/*- - * Copyright (c) 2001, 2002, 2003 Wasabi Systems, Inc. - * All rights reserved. - * - * Written by Jason R. Thorpe for Wasabi Systems, Inc. - * - * 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 for the NetBSD Project by - * Wasabi Systems, Inc. - * 4. The name of Wasabi Systems, Inc. may not be used to endorse - * or promote products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC - * 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. - */ - -/* - * bus_space functions for IQ80321 on-board devices - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include - -#include - -/* Prototypes for all the bus_space structure functions */ -bs_protos(generic); - -/* - * The obio bus space tag. This is constant for all instances, so - * we never have to explicitly "create" it. - */ -struct bus_space obio_bs_tag = { - /* cookie */ - (void *) 0, - - /* mapping/unmapping */ - generic_bs_map, - generic_bs_unmap, - generic_bs_subregion, - - /* allocation/deallocation */ - generic_bs_alloc, - generic_bs_free, - - /* barrier */ - generic_bs_barrier, - - /* read (single) */ - generic_bs_r_1, - generic_bs_r_2, - generic_bs_r_4, - NULL, - - /* read multiple */ - generic_bs_rm_1, - NULL, - NULL, - NULL, - - /* read region */ - generic_bs_rr_1, - NULL, - NULL, - NULL, - - /* write (single) */ - generic_bs_w_1, - generic_bs_w_2, - generic_bs_w_4, - NULL, - - /* write multiple */ - generic_bs_wm_1, - NULL, - NULL, - NULL, - - /* write region */ - NULL, - NULL, - NULL, - NULL, - - /* set multiple */ - NULL, - NULL, - NULL, - NULL, - - /* set region */ - NULL, - NULL, - NULL, - NULL, - - /* copy */ - NULL, - NULL, - NULL, - NULL, -}; From 7dd0db5f007e26595bddfe3a3872c5d75467ef85 Mon Sep 17 00:00:00 2001 From: kevlo Date: Wed, 21 Jan 2015 09:01:48 +0000 Subject: [PATCH 127/258] Typo: ivalid -> invalid. --- sys/dev/mii/mii.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/dev/mii/mii.c b/sys/dev/mii/mii.c index c4ff4ac092cf..e20c102e8e53 100644 --- a/sys/dev/mii/mii.c +++ b/sys/dev/mii/mii.c @@ -374,7 +374,7 @@ mii_attach(device_t dev, device_t *miibus, if_t ifp, } if (offloc != MII_OFFSET_ANY && (offloc < 0 || offloc >= MII_NPHY)) { - printf("%s: ivalid offloc %d\n", __func__, offloc); + printf("%s: invalid offloc %d\n", __func__, offloc); return (EINVAL); } @@ -383,7 +383,7 @@ mii_attach(device_t dev, device_t *miibus, if_t ifp, phymax = MII_NPHY - 1; } else { if (phyloc < 0 || phyloc >= MII_NPHY) { - printf("%s: ivalid phyloc %d\n", __func__, phyloc); + printf("%s: invalid phyloc %d\n", __func__, phyloc); return (EINVAL); } phymin = phymax = phyloc; From 62e65f40de0cda6f2f78e3775e559f18ad51ff4e Mon Sep 17 00:00:00 2001 From: ngie Date: Wed, 21 Jan 2015 10:47:28 +0000 Subject: [PATCH 128/258] Follow up to r277449 by fixing the remaining NSEC_TO_TICK macro to have the same named parameters Reported by: Ben Perrault , Willem Jan Withagen --- cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h b/cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h index 03027c35dc05..493be334891f 100644 --- a/cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h +++ b/cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h @@ -535,7 +535,7 @@ extern vnode_t *rootdir; extern void delay(clock_t ticks); #define SEC_TO_TICK(sec) ((sec) * hz) -#define NSEC_TO_TICK(usec) ((usec) / (NANOSEC / hz)) +#define NSEC_TO_TICK(nsec) ((nsec) / (NANOSEC / hz)) #define gethrestime_sec() time(NULL) #define gethrestime(t) \ From b4a285552ce98cadf6aebe324bb52b79e6f8a9f8 Mon Sep 17 00:00:00 2001 From: rrs Date: Wed, 21 Jan 2015 13:03:18 +0000 Subject: [PATCH 129/258] Fix minor errors found by coverity. Thanks Gleb for the pointers to the email! --- usr.sbin/pmcstudy/pmcstudy.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/usr.sbin/pmcstudy/pmcstudy.c b/usr.sbin/pmcstudy/pmcstudy.c index 6547489f430b..a99d59a8cb33 100644 --- a/usr.sbin/pmcstudy/pmcstudy.c +++ b/usr.sbin/pmcstudy/pmcstudy.c @@ -1808,6 +1808,9 @@ process_file(char *filename) if (cnts == NULL) { /* Nothing we can do */ printf("Nothing to do -- no counters built\n"); + if (io) { + fclose(io); + } return; } lace_cpus_together(); @@ -2044,7 +2047,7 @@ get_cpuid_set(void) printf("No memory3 allocation fails at startup?\n"); exit(-1); } - memset(more, sz, 0); + memset(more, 0, sz); memcpy(more, valid_pmcs, sz); pmc_allocated_cnt *= 2; free(valid_pmcs); From 8f91e56ef8071794d9c50e7d9fef5b6d8f605679 Mon Sep 17 00:00:00 2001 From: gavin Date: Wed, 21 Jan 2015 13:48:06 +0000 Subject: [PATCH 130/258] "softc" is short for "software context", use that phrase in the device_get_softc(9) man page. MFC after: 1 week --- share/man/man9/device_get_softc.9 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/share/man/man9/device_get_softc.9 b/share/man/man9/device_get_softc.9 index 76f94d448aff..5685773aeb96 100644 --- a/share/man/man9/device_get_softc.9 +++ b/share/man/man9/device_get_softc.9 @@ -28,7 +28,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 2, 2005 +.Dd January 21, 2015 .Dt DEVICE_GET_SOFTC 9 .Os .Sh NAME @@ -40,7 +40,7 @@ .Ft void * .Fn device_get_softc "device_t dev" .Sh DESCRIPTION -Return the driver-specific state of +Return the driver-specific software context of .Fa dev . The softc is automatically allocated and zeroed when the device is attached. From bd1a9e7b113063644600b40603bbac4df5933074 Mon Sep 17 00:00:00 2001 From: kib Date: Wed, 21 Jan 2015 16:10:37 +0000 Subject: [PATCH 131/258] An update for the i915 GPU driver, which brings the code up to Linux commit 4d93914ae3db4a897ead4b. Some related drm infrastructure changes are imported as needed. Biggest update is the rewrite of the i915 gem io to more closely follow Linux model, althought the mechanism used by FreeBSD port is different. Sponsored by: The FreeBSD Foundation MFC after: 2 month --- sys/dev/drm2/drm.h | 5 + sys/dev/drm2/drmP.h | 1 + sys/dev/drm2/drm_crtc.c | 586 ++- sys/dev/drm2/drm_crtc.h | 53 +- sys/dev/drm2/drm_crtc_helper.c | 2 +- sys/dev/drm2/drm_crtc_helper.h | 2 +- sys/dev/drm2/drm_drv.c | 62 +- sys/dev/drm2/drm_edid.c | 224 +- sys/dev/drm2/drm_edid.h | 26 +- sys/dev/drm2/drm_edid_modes.h | 412 +- sys/dev/drm2/drm_fb_helper.c | 5 +- sys/dev/drm2/drm_ioctl.c | 4 + sys/dev/drm2/drm_irq.c | 18 +- sys/dev/drm2/drm_memory.c | 8 + sys/dev/drm2/drm_mode.h | 16 + sys/dev/drm2/drm_pciids.h | 7 + sys/dev/drm2/drm_stub.c | 4 +- sys/dev/drm2/i915/i915_debug.c | 352 +- sys/dev/drm2/i915/i915_dma.c | 980 ++-- sys/dev/drm2/i915/i915_drm.h | 19 +- sys/dev/drm2/i915/i915_drv.c | 212 +- sys/dev/drm2/i915/i915_drv.h | 228 +- sys/dev/drm2/i915/i915_gem.c | 2319 +++++---- sys/dev/drm2/i915/i915_gem_context.c | 2 +- sys/dev/drm2/i915/i915_gem_evict.c | 40 +- sys/dev/drm2/i915/i915_gem_execbuffer.c | 203 +- sys/dev/drm2/i915/i915_gem_gtt.c | 60 +- sys/dev/drm2/i915/i915_gem_stolen.c | 205 + sys/dev/drm2/i915/i915_gem_tiling.c | 41 +- sys/dev/drm2/i915/i915_irq.c | 1813 ++++--- sys/dev/drm2/i915/i915_reg.h | 492 +- sys/dev/drm2/i915/i915_suspend.c | 18 +- sys/dev/drm2/i915/intel_bios.c | 45 +- sys/dev/drm2/i915/intel_crt.c | 78 +- sys/dev/drm2/i915/intel_ddi.c | 761 +++ sys/dev/drm2/i915/intel_display.c | 4409 +++++------------- sys/dev/drm2/i915/intel_dp.c | 53 +- sys/dev/drm2/i915/intel_drv.h | 100 +- sys/dev/drm2/i915/intel_fb.c | 2 +- sys/dev/drm2/i915/intel_hdmi.c | 320 +- sys/dev/drm2/i915/intel_iic.c | 402 +- sys/dev/drm2/i915/intel_lvds.c | 13 +- sys/dev/drm2/i915/intel_modes.c | 4 +- sys/dev/drm2/i915/intel_overlay.c | 107 +- sys/dev/drm2/i915/intel_panel.c | 20 +- sys/dev/drm2/i915/intel_pm.c | 3788 +++++++++++++++ sys/dev/drm2/i915/intel_ringbuffer.c | 754 ++- sys/dev/drm2/i915/intel_ringbuffer.h | 23 +- sys/dev/drm2/i915/intel_sdvo.c | 98 +- sys/dev/drm2/i915/intel_sprite.c | 102 +- sys/dev/drm2/i915/intel_tv.c | 17 +- sys/dev/drm2/radeon/atombios_encoders.c | 4 +- sys/dev/drm2/radeon/radeon_legacy_encoders.c | 2 +- sys/modules/drm2/i915kms/Makefile | 3 + 54 files changed, 12383 insertions(+), 7141 deletions(-) create mode 100644 sys/dev/drm2/i915/i915_gem_stolen.c create mode 100644 sys/dev/drm2/i915/intel_ddi.c create mode 100644 sys/dev/drm2/i915/intel_pm.c diff --git a/sys/dev/drm2/drm.h b/sys/dev/drm2/drm.h index dff0f94e8530..eca588531be2 100644 --- a/sys/dev/drm2/drm.h +++ b/sys/dev/drm2/drm.h @@ -1018,6 +1018,9 @@ struct drm_event_vblank { #define DRM_CAP_PRIME 0x5 #define DRM_CAP_TIMESTAMP_MONOTONIC 0x6 +#define DRM_PRIME_CAP_IMPORT 0x1 +#define DRM_PRIME_CAP_EXPORT 0x2 + #include "drm_mode.h" /** @@ -1126,6 +1129,8 @@ struct drm_event_vblank { #define DRM_IOCTL_MODE_GETPLANE DRM_IOWR(0xB6, struct drm_mode_get_plane) #define DRM_IOCTL_MODE_SETPLANE DRM_IOWR(0xB7, struct drm_mode_set_plane) #define DRM_IOCTL_MODE_ADDFB2 DRM_IOWR(0xB8, struct drm_mode_fb_cmd2) +#define DRM_IOCTL_MODE_OBJ_GETPROPERTIES DRM_IOWR(0xB9, struct drm_mode_obj_get_properties) +#define DRM_IOCTL_MODE_OBJ_SETPROPERTY DRM_IOWR(0xBA, struct drm_mode_obj_set_property) #define DRM_IOCTL_MM_INIT DRM_IOWR(0xc0, struct drm_mm_init_arg) #define DRM_IOCTL_MM_TAKEDOWN DRM_IOWR(0xc1, struct drm_mm_type_arg) diff --git a/sys/dev/drm2/drmP.h b/sys/dev/drm2/drmP.h index c724a2dc7d78..e33ab88003ba 100644 --- a/sys/dev/drm2/drmP.h +++ b/sys/dev/drm2/drmP.h @@ -1246,6 +1246,7 @@ int drm_ati_pcigart_cleanup(struct drm_device *dev, /* Cache management (drm_memory.c) */ void drm_clflush_pages(vm_page_t *pages, unsigned long num_pages); +void drm_clflush_virt_range(char *addr, unsigned long length); /* Locking IOCTL support (drm_drv.c) */ int drm_lock(struct drm_device *dev, void *data, diff --git a/sys/dev/drm2/drm_crtc.c b/sys/dev/drm2/drm_crtc.c index 7c6cb5d1b5b5..e044ec23241e 100644 --- a/sys/dev/drm2/drm_crtc.c +++ b/sys/dev/drm2/drm_crtc.c @@ -352,7 +352,7 @@ void drm_framebuffer_cleanup(struct drm_framebuffer *fb) * @funcs: callbacks for the new CRTC * * LOCKING: - * Caller must hold mode config lock. + * Takes mode_config lock. * * Inits a new object created as base part of an driver crtc object. * @@ -372,8 +372,11 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, if (ret) goto out; + crtc->base.properties = &crtc->properties; + list_add_tail(&crtc->head, &dev->mode_config.crtc_list); dev->mode_config.num_crtc++; + out: sx_xunlock(&dev->mode_config.mutex); @@ -474,6 +477,7 @@ int drm_connector_init(struct drm_device *dev, if (ret) goto out; + connector->base.properties = &connector->properties; connector->dev = dev; connector->funcs = funcs; connector->connector_type = connector_type; @@ -582,6 +586,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, if (ret) goto out; + plane->base.properties = &plane->properties; plane->dev = dev; plane->funcs = funcs; plane->format_types = malloc(sizeof(uint32_t) * format_count, @@ -1399,11 +1404,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, } connector = obj_to_connector(obj); - for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { - if (connector->property_ids[i] != 0) { - props_count++; - } - } + props_count = connector->properties.count; for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { if (connector->encoder_ids[i] != 0) { @@ -1456,21 +1457,19 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, copied = 0; prop_ptr = (uint32_t *)(uintptr_t)(out_resp->props_ptr); prop_values = (uint64_t *)(uintptr_t)(out_resp->prop_values_ptr); - for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { - if (connector->property_ids[i] != 0) { - if (copyout(&connector->property_ids[i], - prop_ptr + copied, sizeof(uint32_t))) { - ret = EFAULT; - goto out; - } - - if (copyout(&connector->property_values[i], - prop_values + copied, sizeof(uint64_t))) { - ret = EFAULT; - goto out; - } - copied++; + for (i = 0; i < connector->properties.count; i++) { + if (copyout(&connector->properties.ids[i], + prop_ptr + copied, sizeof(uint32_t))) { + ret = EFAULT; + goto out; } + + if (copyout(&connector->properties.values[i], + prop_values + copied, sizeof(uint64_t))) { + ret = EFAULT; + goto out; + } + copied++; } } out_resp->count_props = props_count; @@ -1808,7 +1807,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, struct drm_display_mode *mode = NULL; struct drm_mode_set set; uint32_t *set_connectors_ptr; - int ret = 0; + int ret; int i; if (!drm_core_check_feature(dev, DRIVER_MODESET)) @@ -2070,7 +2069,7 @@ int drm_mode_addfb(struct drm_device *dev, ret = -dev->mode_config.funcs->fb_create(dev, file_priv, &r, &fb); if (ret != 0) { - DRM_ERROR("could not create framebuffer, error %d\n", ret); + DRM_DEBUG_KMS("could not create framebuffer, error %d\n", ret); goto out; } @@ -2152,6 +2151,47 @@ static int format_check(struct drm_mode_fb_cmd2 *r) } } +static int framebuffer_check(struct drm_mode_fb_cmd2 *r) +{ + int ret, hsub, vsub, num_planes, i; + + ret = format_check(r); + if (ret) { + DRM_DEBUG_KMS("bad framebuffer format 0x%08x\n", r->pixel_format); + return ret; + } + + hsub = drm_format_horz_chroma_subsampling(r->pixel_format); + vsub = drm_format_vert_chroma_subsampling(r->pixel_format); + num_planes = drm_format_num_planes(r->pixel_format); + + if (r->width == 0 || r->width % hsub) { + DRM_DEBUG_KMS("bad framebuffer width %u\n", r->height); + return -EINVAL; + } + + if (r->height == 0 || r->height % vsub) { + DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height); + return -EINVAL; + } + + for (i = 0; i < num_planes; i++) { + unsigned int width = r->width / (i != 0 ? hsub : 1); + + if (!r->handles[i]) { + DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i); + return -EINVAL; + } + + if (r->pitches[i] < drm_format_plane_cpp(r->pixel_format, i) * width) { + DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i); + return -EINVAL; + } + } + + return 0; +} + /** * drm_mode_addfb2 - add an FB to the graphics configuration * @inode: inode from the ioctl @@ -2181,21 +2221,19 @@ int drm_mode_addfb2(struct drm_device *dev, return (EINVAL); if ((config->min_width > r->width) || (r->width > config->max_width)) { - DRM_ERROR("bad framebuffer width %d, should be >= %d && <= %d\n", + DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n", r->width, config->min_width, config->max_width); return (EINVAL); } if ((config->min_height > r->height) || (r->height > config->max_height)) { - DRM_ERROR("bad framebuffer height %d, should be >= %d && <= %d\n", + DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n", r->height, config->min_height, config->max_height); return (EINVAL); } - ret = format_check(r); - if (ret) { - DRM_ERROR("bad framebuffer format 0x%08x\n", r->pixel_format); - return ret; - } + ret = framebuffer_check(r); + if (ret) + return -ret; sx_xlock(&dev->mode_config.mutex); @@ -2204,7 +2242,7 @@ int drm_mode_addfb2(struct drm_device *dev, ret = -dev->mode_config.funcs->fb_create(dev, file_priv, r, &fb); if (ret != 0) { - DRM_ERROR("could not create framebuffer, error %d\n", ret); + DRM_DEBUG_KMS("could not create framebuffer, error %d\n", ret); goto out; } @@ -2335,7 +2373,7 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, struct drm_framebuffer *fb; unsigned flags; int num_clips; - int ret = 0; + int ret; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return (EINVAL); @@ -2530,7 +2568,7 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev, struct drm_display_mode *mode; struct drm_mode_object *obj; struct drm_mode_modeinfo *umode = &mode_cmd->mode; - int ret = 0; + int ret; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; @@ -2584,7 +2622,7 @@ int drm_mode_detachmode_ioctl(struct drm_device *dev, struct drm_connector *connector; struct drm_display_mode mode; struct drm_mode_modeinfo *umode = &mode_cmd->mode; - int ret = 0; + int ret; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; @@ -2672,6 +2710,33 @@ struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, return property; } +struct drm_property *drm_property_create_bitmask(struct drm_device *dev, + int flags, const char *name, + const struct drm_prop_enum_list *props, + int num_values) +{ + struct drm_property *property; + int i, ret; + + flags |= DRM_MODE_PROP_BITMASK; + + property = drm_property_create(dev, flags, name, num_values); + if (!property) + return NULL; + + for (i = 0; i < num_values; i++) { + ret = drm_property_add_enum(property, i, + props[i].type, + props[i].name); + if (ret) { + drm_property_destroy(dev, property); + return NULL; + } + } + + return property; +} + struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, const char *name, uint64_t min, uint64_t max) @@ -2695,7 +2760,14 @@ int drm_property_add_enum(struct drm_property *property, int index, { struct drm_property_enum *prop_enum; - if (!(property->flags & DRM_MODE_PROP_ENUM)) + if (!(property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK))) + return -EINVAL; + + /* + * Bitmask enum properties have the additional constraint of values + * from 0 to 63 + */ + if ((property->flags & DRM_MODE_PROP_BITMASK) && (value > 63)) return -EINVAL; if (!list_empty(&property->enum_blob_list)) { @@ -2736,56 +2808,71 @@ void drm_property_destroy(struct drm_device *dev, struct drm_property *property) free(property, DRM_MEM_KMS); } -int drm_connector_attach_property(struct drm_connector *connector, +void drm_connector_attach_property(struct drm_connector *connector, struct drm_property *property, uint64_t init_val) { - int i; - - for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { - if (connector->property_ids[i] == 0) { - connector->property_ids[i] = property->base.id; - connector->property_values[i] = init_val; - break; - } - } - - if (i == DRM_CONNECTOR_MAX_PROPERTY) - return -EINVAL; - return 0; + drm_object_attach_property(&connector->base, property, init_val); } int drm_connector_property_set_value(struct drm_connector *connector, struct drm_property *property, uint64_t value) { - int i; - - for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { - if (connector->property_ids[i] == property->base.id) { - connector->property_values[i] = value; - break; - } - } - - if (i == DRM_CONNECTOR_MAX_PROPERTY) - return -EINVAL; - return 0; + return drm_object_property_set_value(&connector->base, property, value); } int drm_connector_property_get_value(struct drm_connector *connector, struct drm_property *property, uint64_t *val) +{ + return drm_object_property_get_value(&connector->base, property, val); +} + +void drm_object_attach_property(struct drm_mode_object *obj, + struct drm_property *property, + uint64_t init_val) +{ + int count = obj->properties->count; + + if (count == DRM_OBJECT_MAX_PROPERTY) { + printf("Failed to attach object property (type: 0x%x). Please " + "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time " + "you see this message on the same object type.\n", + obj->type); + return; + } + + obj->properties->ids[count] = property->base.id; + obj->properties->values[count] = init_val; + obj->properties->count++; +} + +int drm_object_property_set_value(struct drm_mode_object *obj, + struct drm_property *property, uint64_t val) { int i; - for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { - if (connector->property_ids[i] == property->base.id) { - *val = connector->property_values[i]; - break; + for (i = 0; i < obj->properties->count; i++) { + if (obj->properties->ids[i] == property->base.id) { + obj->properties->values[i] = val; + return 0; } } - if (i == DRM_CONNECTOR_MAX_PROPERTY) - return -EINVAL; - return 0; + return -EINVAL; +} + +int drm_object_property_get_value(struct drm_mode_object *obj, + struct drm_property *property, uint64_t *val) +{ + int i; + + for (i = 0; i < obj->properties->count; i++) { + if (obj->properties->ids[i] == property->base.id) { + *val = obj->properties->values[i]; + return 0; + } + } + + return -EINVAL; } int drm_mode_getproperty_ioctl(struct drm_device *dev, @@ -2817,7 +2904,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, } property = obj_to_property(obj); - if (property->flags & DRM_MODE_PROP_ENUM) { + if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) { list_for_each_entry(prop_enum, &property->enum_blob_list, head) enum_count++; } else if (property->flags & DRM_MODE_PROP_BLOB) { @@ -2842,7 +2929,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, } out_resp->count_values = value_count; - if (property->flags & DRM_MODE_PROP_ENUM) { + if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) { if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { copied = 0; enum_ptr = (struct drm_mode_property_enum *)(uintptr_t)out_resp->enum_blob_ptr; @@ -2965,7 +3052,7 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector, struct edid *edid) { struct drm_device *dev = connector->dev; - int ret = 0, size; + int ret, size; if (connector->edid_blob_ptr) drm_property_destroy_blob(dev, connector->edid_blob_ptr); @@ -2988,13 +3075,159 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector, return ret; } +static bool drm_property_change_is_valid(struct drm_property *property, + u64 value) +{ + if (property->flags & DRM_MODE_PROP_IMMUTABLE) + return false; + if (property->flags & DRM_MODE_PROP_RANGE) { + if (value < property->values[0] || value > property->values[1]) + return false; + return true; + } else if (property->flags & DRM_MODE_PROP_BITMASK) { + int i; + u64 valid_mask = 0; + for (i = 0; i < property->num_values; i++) + valid_mask |= (1ULL << property->values[i]); + return !(value & ~valid_mask); + } else { + int i; + for (i = 0; i < property->num_values; i++) + if (property->values[i] == value) + return true; + return false; + } +} + int drm_mode_connector_property_set_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_mode_connector_set_property *out_resp = data; + struct drm_mode_connector_set_property *conn_set_prop = data; + struct drm_mode_obj_set_property obj_set_prop = { + .value = conn_set_prop->value, + .prop_id = conn_set_prop->prop_id, + .obj_id = conn_set_prop->connector_id, + .obj_type = DRM_MODE_OBJECT_CONNECTOR + }; + + /* It does all the locking and checking we need */ + return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv); +} + +static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, + struct drm_property *property, + uint64_t value) +{ + int ret = -EINVAL; + struct drm_connector *connector = obj_to_connector(obj); + + /* Do DPMS ourselves */ + if (property == connector->dev->mode_config.dpms_property) { + if (connector->funcs->dpms) + (*connector->funcs->dpms)(connector, (int)value); + ret = 0; + } else if (connector->funcs->set_property) + ret = connector->funcs->set_property(connector, property, value); + + /* store the property value if successful */ + if (!ret) + drm_connector_property_set_value(connector, property, value); + return ret; +} + +static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, + struct drm_property *property, + uint64_t value) +{ + int ret = -EINVAL; + struct drm_crtc *crtc = obj_to_crtc(obj); + + if (crtc->funcs->set_property) + ret = crtc->funcs->set_property(crtc, property, value); + if (!ret) + drm_object_property_set_value(obj, property, value); + + return ret; +} + +static int drm_mode_plane_set_obj_prop(struct drm_mode_object *obj, + struct drm_property *property, + uint64_t value) +{ + int ret = -EINVAL; + struct drm_plane *plane = obj_to_plane(obj); + + if (plane->funcs->set_property) + ret = plane->funcs->set_property(plane, property, value); + if (!ret) + drm_object_property_set_value(obj, property, value); + + return ret; +} + +int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_mode_obj_get_properties *arg = data; struct drm_mode_object *obj; + int ret = 0; + int i; + int copied = 0; + int props_count = 0; + uint32_t __user *props_ptr; + uint64_t __user *prop_values_ptr; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + sx_xlock(&dev->mode_config.mutex); + + obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); + if (!obj) { + ret = -EINVAL; + goto out; + } + if (!obj->properties) { + ret = -EINVAL; + goto out; + } + + props_count = obj->properties->count; + + /* This ioctl is called twice, once to determine how much space is + * needed, and the 2nd time to fill it. */ + if ((arg->count_props >= props_count) && props_count) { + copied = 0; + props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr); + prop_values_ptr = (uint64_t __user *)(unsigned long) + (arg->prop_values_ptr); + for (i = 0; i < props_count; i++) { + if (copyout(props_ptr + copied, + &obj->properties->ids[i], sizeof(uint32_t))) { + ret = -EFAULT; + goto out; + } + if (copyout(prop_values_ptr + copied, + &obj->properties->values[i], sizeof(uint64_t))) { + ret = -EFAULT; + goto out; + } + copied++; + } + } + arg->count_props = props_count; +out: + sx_xunlock(&dev->mode_config.mutex); + return ret; +} + +int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_mode_obj_set_property *arg = data; + struct drm_mode_object *arg_obj; + struct drm_mode_object *prop_obj; struct drm_property *property; - struct drm_connector *connector; int ret = -EINVAL; int i; @@ -3003,60 +3236,41 @@ int drm_mode_connector_property_set_ioctl(struct drm_device *dev, sx_xlock(&dev->mode_config.mutex); - obj = drm_mode_object_find(dev, out_resp->connector_id, DRM_MODE_OBJECT_CONNECTOR); - if (!obj) { + arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); + if (!arg_obj) + goto out; + if (!arg_obj->properties) goto out; - } - connector = obj_to_connector(obj); - for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { - if (connector->property_ids[i] == out_resp->prop_id) + for (i = 0; i < arg_obj->properties->count; i++) + if (arg_obj->properties->ids[i] == arg->prop_id) break; - } - if (i == DRM_CONNECTOR_MAX_PROPERTY) { - goto out; - } - - obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY); - if (!obj) { - goto out; - } - property = obj_to_property(obj); - - if (property->flags & DRM_MODE_PROP_IMMUTABLE) + if (i == arg_obj->properties->count) goto out; - if (property->flags & DRM_MODE_PROP_RANGE) { - if (out_resp->value < property->values[0]) - goto out; + prop_obj = drm_mode_object_find(dev, arg->prop_id, + DRM_MODE_OBJECT_PROPERTY); + if (!prop_obj) + goto out; + property = obj_to_property(prop_obj); - if (out_resp->value > property->values[1]) - goto out; - } else { - int found = 0; - for (i = 0; i < property->num_values; i++) { - if (property->values[i] == out_resp->value) { - found = 1; - break; - } - } - if (!found) { - goto out; - } + if (!drm_property_change_is_valid(property, arg->value)) + goto out; + + switch (arg_obj->type) { + case DRM_MODE_OBJECT_CONNECTOR: + ret = drm_mode_connector_set_obj_prop(arg_obj, property, + arg->value); + break; + case DRM_MODE_OBJECT_CRTC: + ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value); + break; + case DRM_MODE_OBJECT_PLANE: + ret = drm_mode_plane_set_obj_prop(arg_obj, property, arg->value); + break; } - /* Do DPMS ourselves */ - if (property == connector->dev->mode_config.dpms_property) { - if (connector->funcs->dpms) - (*connector->funcs->dpms)(connector, (int) out_resp->value); - ret = 0; - } else if (connector->funcs->set_property) - ret = connector->funcs->set_property(connector, property, out_resp->value); - - /* store the property value if successful */ - if (!ret) - drm_connector_property_set_value(connector, property, out_resp->value); out: sx_xunlock(&dev->mode_config.mutex); return ret; @@ -3176,6 +3390,11 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev, } crtc = obj_to_crtc(obj); + if (crtc->funcs->gamma_set == NULL) { + ret = -ENOSYS; + goto out; + } + /* memcpy into gamma store */ if (crtc_lut->gamma_size != crtc->gamma_size) { ret = -EINVAL; @@ -3417,3 +3636,136 @@ void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, break; } } + +/** + * drm_format_num_planes - get the number of planes for format + * @format: pixel format (DRM_FORMAT_*) + * + * RETURNS: + * The number of planes used by the specified pixel format. + */ +int drm_format_num_planes(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_YUV410: + case DRM_FORMAT_YVU410: + case DRM_FORMAT_YUV411: + case DRM_FORMAT_YVU411: + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + case DRM_FORMAT_YUV422: + case DRM_FORMAT_YVU422: + case DRM_FORMAT_YUV444: + case DRM_FORMAT_YVU444: + return 3; + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: + return 2; + default: + return 1; + } +} + +/** + * drm_format_plane_cpp - determine the bytes per pixel value + * @format: pixel format (DRM_FORMAT_*) + * @plane: plane index + * + * RETURNS: + * The bytes per pixel value for the specified plane. + */ +int drm_format_plane_cpp(uint32_t format, int plane) +{ + unsigned int depth; + int bpp; + + if (plane >= drm_format_num_planes(format)) + return 0; + + switch (format) { + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + return 2; + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: + return plane ? 2 : 1; + case DRM_FORMAT_YUV410: + case DRM_FORMAT_YVU410: + case DRM_FORMAT_YUV411: + case DRM_FORMAT_YVU411: + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + case DRM_FORMAT_YUV422: + case DRM_FORMAT_YVU422: + case DRM_FORMAT_YUV444: + case DRM_FORMAT_YVU444: + return 1; + default: + drm_fb_get_bpp_depth(format, &depth, &bpp); + return bpp >> 3; + } +} + +/** + * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor + * @format: pixel format (DRM_FORMAT_*) + * + * RETURNS: + * The horizontal chroma subsampling factor for the + * specified pixel format. + */ +int drm_format_horz_chroma_subsampling(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_YUV411: + case DRM_FORMAT_YVU411: + case DRM_FORMAT_YUV410: + case DRM_FORMAT_YVU410: + return 4; + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: + case DRM_FORMAT_YUV422: + case DRM_FORMAT_YVU422: + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + return 2; + default: + return 1; + } +} + +/** + * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor + * @format: pixel format (DRM_FORMAT_*) + * + * RETURNS: + * The vertical chroma subsampling factor for the + * specified pixel format. + */ +int drm_format_vert_chroma_subsampling(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_YUV410: + case DRM_FORMAT_YVU410: + return 4; + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + return 2; + default: + return 1; + } +} diff --git a/sys/dev/drm2/drm_crtc.h b/sys/dev/drm2/drm_crtc.h index 0ab2bf48ff88..36708c6de658 100644 --- a/sys/dev/drm2/drm_crtc.h +++ b/sys/dev/drm2/drm_crtc.h @@ -47,6 +47,14 @@ struct i2c_adapter; struct drm_mode_object { uint32_t id; uint32_t type; + struct drm_object_properties *properties; +}; + +#define DRM_OBJECT_MAX_PROPERTY 16 +struct drm_object_properties { + int count; + uint32_t ids[DRM_OBJECT_MAX_PROPERTY]; + uint64_t values[DRM_OBJECT_MAX_PROPERTY]; }; /* @@ -295,7 +303,8 @@ struct drm_plane; * @mode_fixup: fixup proposed mode * @mode_set: set the desired mode on the CRTC * @gamma_set: specify color ramp for CRTC - * @destroy: deinit and free object. + * @destroy: deinit and free object + * @set_property: called when a property is changed * * The drm_crtc_funcs structure is the central CRTC management structure * in the DRM. Each CRTC controls one or more connectors (note that the name @@ -339,6 +348,8 @@ struct drm_crtc_funcs { int (*page_flip)(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event); + int (*set_property)(struct drm_crtc *crtc, + struct drm_property *property, uint64_t val); }; /** @@ -347,6 +358,7 @@ struct drm_crtc_funcs { * @x: x position on screen * @y: y position on screen * @funcs: CRTC control functions + * @properties: property tracking for this CRTC * * Each CRTC may have one or more connectors associated with it. This structure * allows the CRTC to be controlled. @@ -382,6 +394,8 @@ struct drm_crtc { /* if you are using the helper */ void *helper_private; + + struct drm_object_properties properties; }; @@ -431,7 +445,6 @@ struct drm_encoder_funcs { }; #define DRM_CONNECTOR_MAX_UMODES 16 -#define DRM_CONNECTOR_MAX_PROPERTY 16 #define DRM_CONNECTOR_LEN 32 #define DRM_CONNECTOR_MAX_ENCODER 2 @@ -511,8 +524,7 @@ struct drm_connector { struct list_head user_modes; struct drm_property_blob *edid_blob_ptr; - u32 property_ids[DRM_CONNECTOR_MAX_PROPERTY]; - uint64_t property_values[DRM_CONNECTOR_MAX_PROPERTY]; + struct drm_object_properties properties; uint8_t polled; /* DRM_CONNECTOR_POLL_* */ @@ -543,6 +555,7 @@ struct drm_connector { * @update_plane: update the plane configuration * @disable_plane: shut down the plane * @destroy: clean up plane resources + * @set_property: called when a property is changed */ struct drm_plane_funcs { int (*update_plane)(struct drm_plane *plane, @@ -553,6 +566,8 @@ struct drm_plane_funcs { uint32_t src_w, uint32_t src_h); int (*disable_plane)(struct drm_plane *plane); void (*destroy)(struct drm_plane *plane); + int (*set_property)(struct drm_plane *plane, + struct drm_property *property, uint64_t val); }; /** @@ -570,6 +585,7 @@ struct drm_plane_funcs { * @enabled: enabled flag * @funcs: helper functions * @helper_private: storage for drver layer + @properties: property tracking for this plane */ struct drm_plane { struct drm_device *dev; @@ -592,6 +608,8 @@ struct drm_plane { const struct drm_plane_funcs *funcs; void *helper_private; + + struct drm_object_properties properties; }; /** @@ -806,6 +824,15 @@ extern int drm_connector_property_set_value(struct drm_connector *connector, extern int drm_connector_property_get_value(struct drm_connector *connector, struct drm_property *property, uint64_t *value); +void drm_object_attach_property(struct drm_mode_object *obj, + struct drm_property *property, + uint64_t init_val); +extern int drm_object_property_set_value(struct drm_mode_object *obj, + struct drm_property *property, + uint64_t val); +extern int drm_object_property_get_value(struct drm_mode_object *obj, + struct drm_property *property, + uint64_t *value); extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); extern void drm_framebuffer_set_object(struct drm_device *dev, unsigned long handle); @@ -818,7 +845,7 @@ extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); extern void drm_crtc_probe_connector_modes(struct drm_device *dev, int maxX, int maxY); extern bool drm_crtc_in_use(struct drm_crtc *crtc); -extern int drm_connector_attach_property(struct drm_connector *connector, +extern void drm_connector_attach_property(struct drm_connector *connector, struct drm_property *property, uint64_t init_val); extern struct drm_property *drm_property_create(struct drm_device *dev, int flags, const char *name, int num_values); @@ -826,6 +853,10 @@ extern struct drm_property *drm_property_create_enum(struct drm_device *dev, int const char *name, const struct drm_prop_enum_list *props, int num_values); +struct drm_property *drm_property_create_bitmask(struct drm_device *dev, + int flags, const char *name, + const struct drm_prop_enum_list *props, + int num_values); struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, const char *name, uint64_t min, uint64_t max); @@ -921,7 +952,8 @@ extern int drm_add_modes_noedid(struct drm_connector *connector, extern int drm_edid_header_is_valid(const u8 *raw_edid); extern bool drm_edid_is_valid(struct edid *edid); struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, - int hsize, int vsize, int fresh); + int hsize, int vsize, int fresh, + bool rb); extern int drm_mode_create_dumb_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); @@ -929,7 +961,16 @@ extern int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, int *bpp); +extern int drm_format_num_planes(uint32_t format); +extern int drm_format_plane_cpp(uint32_t format, int plane); +extern int drm_format_horz_chroma_subsampling(uint32_t format); +extern int drm_format_vert_chroma_subsampling(uint32_t format); + #endif /* __DRM_CRTC_H__ */ diff --git a/sys/dev/drm2/drm_crtc_helper.c b/sys/dev/drm2/drm_crtc_helper.c index 77e134640f96..9fb812006f0b 100644 --- a/sys/dev/drm2/drm_crtc_helper.c +++ b/sys/dev/drm2/drm_crtc_helper.c @@ -549,7 +549,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) int count = 0, ro, fail = 0; struct drm_crtc_helper_funcs *crtc_funcs; struct drm_mode_set save_set; - int ret = 0; + int ret; int i; DRM_DEBUG_KMS("\n"); diff --git a/sys/dev/drm2/drm_crtc_helper.h b/sys/dev/drm2/drm_crtc_helper.h index 0110949b1705..0f36b1fa3d40 100644 --- a/sys/dev/drm2/drm_crtc_helper.h +++ b/sys/dev/drm2/drm_crtc_helper.h @@ -78,7 +78,7 @@ struct drm_encoder_helper_funcs { void (*restore)(struct drm_encoder *encoder); bool (*mode_fixup)(struct drm_encoder *encoder, - const struct drm_display_mode *mode, + struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); void (*prepare)(struct drm_encoder *encoder); void (*commit)(struct drm_encoder *encoder); diff --git a/sys/dev/drm2/drm_drv.c b/sys/dev/drm2/drm_drv.c index d86cbbd27ccc..b5150e1821c9 100644 --- a/sys/dev/drm2/drm_drv.c +++ b/sys/dev/drm2/drm_drv.c @@ -188,6 +188,8 @@ static drm_ioctl_desc_t drm_ioctls[256] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), }; static struct cdevsw drm_cdevsw = { @@ -246,7 +248,8 @@ int drm_probe(device_t kdev, drm_pci_id_list_t *idlist) device = pci_get_device(kdev); if (pci_get_class(kdev) != PCIC_DISPLAY - || pci_get_subclass(kdev) != PCIS_DISPLAY_VGA) + || (pci_get_subclass(kdev) != PCIS_DISPLAY_VGA && + pci_get_subclass(kdev) != PCIS_DISPLAY_OTHER)) return ENXIO; id_entry = drm_find_description(vendor, device, idlist); @@ -1075,10 +1078,63 @@ SYSINIT(drm_register, SI_SUB_KLD, SI_ORDER_MIDDLE, SYSUNINIT(drm_unregister, SI_SUB_KLD, SI_ORDER_MIDDLE, drm_core_exit, NULL); +static bool +dmi_found(const struct dmi_system_id *dsi) +{ + char *hw_vendor, *hw_prod; + int i, slot; + bool res; + + hw_vendor = kern_getenv("smbios.planar.maker"); + hw_prod = kern_getenv("smbios.planar.product"); + res = true; + for (i = 0; i < nitems(dsi->matches); i++) { + slot = dsi->matches[i].slot; + switch (slot) { + case DMI_NONE: + break; + case DMI_SYS_VENDOR: + case DMI_BOARD_VENDOR: + if (hw_vendor != NULL && + !strcmp(hw_vendor, dsi->matches[i].substr)) { + break; + } else { + res = false; + goto out; + } + case DMI_PRODUCT_NAME: + case DMI_BOARD_NAME: + if (hw_prod != NULL && + !strcmp(hw_prod, dsi->matches[i].substr)) { + break; + } else { + res = false; + goto out; + } + default: + res = false; + goto out; + } + } +out: + freeenv(hw_vendor); + freeenv(hw_prod); + + return (res); +} + bool dmi_check_system(const struct dmi_system_id *sysid) { + const struct dmi_system_id *dsi; + bool res; - /* XXXKIB */ - return (false); + for (res = false, dsi = sysid; dsi->matches[0].slot != 0 ; dsi++) { + if (dmi_found(dsi)) { + res = true; + if (dsi->callback != NULL && dsi->callback(dsi)) + break; + } + } + return (res); } diff --git a/sys/dev/drm2/drm_edid.c b/sys/dev/drm2/drm_edid.c index 8a317a08d7bf..bf4cc9fd2541 100644 --- a/sys/dev/drm2/drm_edid.c +++ b/sys/dev/drm2/drm_edid.c @@ -84,7 +84,7 @@ struct detailed_mode_closure { #define LEVEL_CVT 3 static struct edid_quirk { - char *vendor; + char vendor[4]; int product_id; u32 quirks; } edid_quirk_list[] = { @@ -151,13 +151,13 @@ int drm_edid_header_is_valid(const u8 *raw_edid) * doesn't check out, or 1 if it's valid. */ static bool -drm_edid_block_valid(u8 *raw_edid) +drm_edid_block_valid(u8 *raw_edid, int block) { int i; u8 csum = 0; struct edid *edid = (struct edid *)raw_edid; - if (raw_edid[0] == 0x00) { + if (block == 0) { int score = drm_edid_header_is_valid(raw_edid); if (score == 8) ; else if (score >= 6) { @@ -230,7 +230,7 @@ bool drm_edid_is_valid(struct edid *edid) return false; for (i = 0; i <= edid->extensions; i++) - if (!drm_edid_block_valid(raw + i * EDID_LENGTH)) + if (!drm_edid_block_valid(raw + i * EDID_LENGTH, i)) return false; return true; @@ -320,7 +320,7 @@ drm_do_get_edid(struct drm_connector *connector, device_t adapter) for (i = 0; i < 4; i++) { if (drm_do_probe_ddc_edid(adapter, block, 0, EDID_LENGTH)) goto out; - if (drm_edid_block_valid(block)) + if (drm_edid_block_valid(block, 0)) break; if (i == 0 && drm_edid_is_zero(block, EDID_LENGTH)) { connector->null_edid_counter++; @@ -344,7 +344,7 @@ drm_do_get_edid(struct drm_connector *connector, device_t adapter) block + (valid_extensions + 1) * EDID_LENGTH, j, EDID_LENGTH)) goto out; - if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH)) { + if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH, j)) { valid_extensions++; break; } @@ -504,23 +504,47 @@ static void edid_fixup_preferred(struct drm_connector *connector, preferred_mode->type |= DRM_MODE_TYPE_PREFERRED; } -struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, - int hsize, int vsize, int fresh) +static bool +mode_is_rb(const struct drm_display_mode *mode) +{ + return (mode->htotal - mode->hdisplay == 160) && + (mode->hsync_end - mode->hdisplay == 80) && + (mode->hsync_end - mode->hsync_start == 32) && + (mode->vsync_start - mode->vdisplay == 3); +} + +/* + * drm_mode_find_dmt - Create a copy of a mode if present in DMT + * @dev: Device to duplicate against + * @hsize: Mode width + * @vsize: Mode height + * @fresh: Mode refresh rate + * @rb: Mode reduced-blanking-ness + * + * Walk the DMT mode list looking for a match for the given parameters. + * Return a newly allocated copy of the mode, or NULL if not found. + */ +struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, + int hsize, int vsize, int fresh, + bool rb) { - struct drm_display_mode *mode = NULL; int i; for (i = 0; i < drm_num_dmt_modes; i++) { struct drm_display_mode *ptr = &drm_dmt_modes[i]; - if (hsize == ptr->hdisplay && - vsize == ptr->vdisplay && - fresh == drm_mode_vrefresh(ptr)) { - /* get the expected default mode */ - mode = drm_mode_duplicate(dev, ptr); - break; - } + if (hsize != ptr->hdisplay) + continue; + if (vsize != ptr->vdisplay) + continue; + if (fresh != drm_mode_vrefresh(ptr)) + continue; + if (rb != mode_is_rb(ptr)) + continue; + + return drm_mode_duplicate(dev, ptr); } - return mode; + + return NULL; } typedef void detailed_cb(struct detailed_timing *timing, void *closure); @@ -763,10 +787,17 @@ drm_mode_std(struct drm_connector *connector, struct edid *edid, } /* check whether it can be found in default mode table */ - mode = drm_mode_find_dmt(dev, hsize, vsize, vrefresh_rate); + if (drm_monitor_supports_rb(edid)) { + mode = drm_mode_find_dmt(dev, hsize, vsize, vrefresh_rate, + true); + if (mode) + return mode; + } + mode = drm_mode_find_dmt(dev, hsize, vsize, vrefresh_rate, false); if (mode) return mode; + /* okay, generate it */ switch (timing_level) { case LEVEL_DMT: break; @@ -780,6 +811,8 @@ drm_mode_std(struct drm_connector *connector, struct edid *edid, * secondary GTF curve. Please don't do that. */ mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0); + if (!mode) + return NULL; if (drm_mode_hsync(mode) > drm_gtf2_hbreak(edid)) { free(mode, DRM_MEM_KMS); mode = drm_gtf_mode_complex(dev, hsize, vsize, @@ -940,15 +973,6 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, return mode; } -static bool -mode_is_rb(const struct drm_display_mode *mode) -{ - return (mode->htotal - mode->hdisplay == 160) && - (mode->hsync_end - mode->hdisplay == 80) && - (mode->hsync_end - mode->hsync_start == 32) && - (mode->vsync_start - mode->vdisplay == 3); -} - static bool mode_in_hsync_range(struct drm_display_mode *mode, struct edid *edid, u8 *t) @@ -1026,12 +1050,8 @@ mode_in_range(struct drm_display_mode *mode, struct edid *edid, return true; } -/* - * XXX If drm_dmt_modes ever regrows the CVT-R modes (and it will) this will - * need to account for them. - */ static int -drm_gtf_modes_for_range(struct drm_connector *connector, struct edid *edid, +drm_dmt_modes_for_range(struct drm_connector *connector, struct edid *edid, struct detailed_timing *timing) { int i, modes = 0; @@ -1051,17 +1071,110 @@ drm_gtf_modes_for_range(struct drm_connector *connector, struct edid *edid, return modes; } +/* fix up 1366x768 mode from 1368x768; + * GFT/CVT can't express 1366 width which isn't dividable by 8 + */ +static void fixup_mode_1366x768(struct drm_display_mode *mode) +{ + if (mode->hdisplay == 1368 && mode->vdisplay == 768) { + mode->hdisplay = 1366; + mode->hsync_start--; + mode->hsync_end--; + drm_mode_set_name(mode); + } +} + +static int +drm_gtf_modes_for_range(struct drm_connector *connector, struct edid *edid, + struct detailed_timing *timing) +{ + int i, modes = 0; + struct drm_display_mode *newmode; + struct drm_device *dev = connector->dev; + + for (i = 0; i < num_extra_modes; i++) { + const struct minimode *m = &extra_modes[i]; + newmode = drm_gtf_mode(dev, m->w, m->h, m->r, 0, 0); + if (!newmode) + return modes; + + fixup_mode_1366x768(newmode); + if (!mode_in_range(newmode, edid, timing)) { + drm_mode_destroy(dev, newmode); + continue; + } + + drm_mode_probed_add(connector, newmode); + modes++; + } + + return modes; +} + +static int +drm_cvt_modes_for_range(struct drm_connector *connector, struct edid *edid, + struct detailed_timing *timing) +{ + int i, modes = 0; + struct drm_display_mode *newmode; + struct drm_device *dev = connector->dev; + bool rb = drm_monitor_supports_rb(edid); + + for (i = 0; i < num_extra_modes; i++) { + const struct minimode *m = &extra_modes[i]; + newmode = drm_cvt_mode(dev, m->w, m->h, m->r, rb, 0, 0); + if (!newmode) + return modes; + + fixup_mode_1366x768(newmode); + if (!mode_in_range(newmode, edid, timing)) { + drm_mode_destroy(dev, newmode); + continue; + } + + drm_mode_probed_add(connector, newmode); + modes++; + } + + return modes; +} + static void do_inferred_modes(struct detailed_timing *timing, void *c) { struct detailed_mode_closure *closure = c; struct detailed_non_pixel *data = &timing->data.other_data; - int gtf = (closure->edid->features & DRM_EDID_FEATURE_DEFAULT_GTF); + struct detailed_data_monitor_range *range = &data->data.range; - if (gtf && data->type == EDID_DETAIL_MONITOR_RANGE) + if (data->type != EDID_DETAIL_MONITOR_RANGE) + return; + + closure->modes += drm_dmt_modes_for_range(closure->connector, + closure->edid, + timing); + + if (!version_greater(closure->edid, 1, 1)) + return; /* GTF not defined yet */ + + switch (range->flags) { + case 0x02: /* secondary gtf, XXX could do more */ + case 0x00: /* default gtf */ closure->modes += drm_gtf_modes_for_range(closure->connector, closure->edid, timing); + break; + case 0x04: /* cvt, only in 1.4+ */ + if (!version_greater(closure->edid, 1, 3)) + break; + + closure->modes += drm_cvt_modes_for_range(closure->connector, + closure->edid, + timing); + break; + case 0x01: /* just the ranges, no formula */ + default: + break; + } } static int @@ -1094,8 +1207,8 @@ drm_est3_modes(struct drm_connector *connector, struct detailed_timing *timing) mode = drm_mode_find_dmt(connector->dev, est3_modes[m].w, est3_modes[m].h, - est3_modes[m].r - /*, est3_modes[m].rb */); + est3_modes[m].r, + est3_modes[m].rb); if (mode) { drm_mode_probed_add(connector, mode); modes++; @@ -1343,6 +1456,8 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid, #define VENDOR_BLOCK 0x03 #define SPEAKER_BLOCK 0x04 #define EDID_BASIC_AUDIO (1 << 6) +#define EDID_CEA_YCRCB444 (1 << 5) +#define EDID_CEA_YCRCB422 (1 << 4) /** * Search EDID for CEA extension block. @@ -1647,13 +1762,29 @@ static void drm_add_display_info(struct edid *edid, info->bpc = 0; info->color_formats = 0; - /* Only defined for 1.4 with digital displays */ - if (edid->revision < 4) + if (edid->revision < 3) return; if (!(edid->input & DRM_EDID_INPUT_DIGITAL)) return; + /* Get data from CEA blocks if present */ + edid_ext = drm_find_cea_extension(edid); + if (edid_ext) { + info->cea_rev = edid_ext[1]; + + /* The existence of a CEA block should imply RGB support */ + info->color_formats = DRM_COLOR_FORMAT_RGB444; + if (edid_ext[3] & EDID_CEA_YCRCB444) + info->color_formats |= DRM_COLOR_FORMAT_YCRCB444; + if (edid_ext[3] & EDID_CEA_YCRCB422) + info->color_formats |= DRM_COLOR_FORMAT_YCRCB422; + } + + /* Only defined for 1.4 with digital displays */ + if (edid->revision < 4) + return; + switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) { case DRM_EDID_DIGITAL_DEPTH_6: info->bpc = 6; @@ -1679,18 +1810,11 @@ static void drm_add_display_info(struct edid *edid, break; } - info->color_formats = DRM_COLOR_FORMAT_RGB444; - if (info->color_formats & DRM_EDID_FEATURE_RGB_YCRCB444) - info->color_formats = DRM_COLOR_FORMAT_YCRCB444; - if (info->color_formats & DRM_EDID_FEATURE_RGB_YCRCB422) - info->color_formats = DRM_COLOR_FORMAT_YCRCB422; - - /* Get data from CEA blocks if present */ - edid_ext = drm_find_cea_extension(edid); - if (!edid_ext) - return; - - info->cea_rev = edid_ext[1]; + info->color_formats |= DRM_COLOR_FORMAT_RGB444; + if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB444) + info->color_formats |= DRM_COLOR_FORMAT_YCRCB444; + if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422) + info->color_formats |= DRM_COLOR_FORMAT_YCRCB422; } /** diff --git a/sys/dev/drm2/drm_edid.h b/sys/dev/drm2/drm_edid.h index e0c147054385..3dfe6e3c133c 100644 --- a/sys/dev/drm2/drm_edid.h +++ b/sys/dev/drm2/drm_edid.h @@ -93,12 +93,26 @@ struct detailed_data_monitor_range { u8 min_hfreq_khz; u8 max_hfreq_khz; u8 pixel_clock_mhz; /* need to multiply by 10 */ - u16 sec_gtf_toggle; /* A000=use above, 20=use below */ - u8 hfreq_start_khz; /* need to multiply by 2 */ - u8 c; /* need to divide by 2 */ - u16 m; - u8 k; - u8 j; /* need to divide by 2 */ + u8 flags; + union { + struct { + u8 reserved; + u8 hfreq_start_khz; /* need to multiply by 2 */ + u8 c; /* need to divide by 2 */ + u16 m; + u8 k; + u8 j; /* need to divide by 2 */ + } __attribute__((packed)) gtf2; + struct { + u8 version; + u8 data1; /* high 6 bits: extra clock resolution */ + u8 data2; /* plus low 2 of above: max hactive */ + u8 supported_aspects; + u8 flags; /* preferred aspect and blanking support */ + u8 supported_scalings; + u8 preferred_refresh; + } __attribute__((packed)) cvt; + } formula; } __attribute__((packed)); struct detailed_data_wpindex { diff --git a/sys/dev/drm2/drm_edid_modes.h b/sys/dev/drm2/drm_edid_modes.h index beded269bf4d..b6431d36c108 100644 --- a/sys/dev/drm2/drm_edid_modes.h +++ b/sys/dev/drm2/drm_edid_modes.h @@ -31,7 +31,6 @@ /* * Autogenerated from the DMT spec. * This table is copied from xfree86/modes/xf86EdidModes.c. - * But the mode with Reduced blank feature is deleted. */ static struct drm_display_mode drm_dmt_modes[] = { /* 640x350@85Hz */ @@ -82,6 +81,10 @@ static struct drm_display_mode drm_dmt_modes[] = { { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 56250, 800, 832, 896, 1048, 0, 600, 601, 604, 631, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 800x600@120Hz RB */ + { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 73250, 800, 848, + 880, 960, 0, 600, 603, 607, 636, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 848x480@60Hz */ { DRM_MODE("848x480", DRM_MODE_TYPE_DRIVER, 33750, 848, 864, 976, 1088, 0, 480, 486, 494, 517, 0, @@ -107,10 +110,18 @@ static struct drm_display_mode drm_dmt_modes[] = { { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 94500, 1024, 1072, 1168, 1376, 0, 768, 769, 772, 808, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1024x768@120Hz RB */ + { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 115500, 1024, 1072, + 1104, 1184, 0, 768, 771, 775, 813, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1152x864@75Hz */ { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216, 1344, 1600, 0, 864, 865, 868, 900, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1280x768@60Hz RB */ + { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 68250, 1280, 1328, + 1360, 1440, 0, 768, 771, 778, 790, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1280x768@60Hz */ { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 79500, 1280, 1344, 1472, 1664, 0, 768, 771, 778, 798, 0, @@ -123,6 +134,14 @@ static struct drm_display_mode drm_dmt_modes[] = { { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 117500, 1280, 1360, 1496, 1712, 0, 768, 771, 778, 809, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1280x768@120Hz RB */ + { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 140250, 1280, 1328, + 1360, 1440, 0, 768, 771, 778, 813, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1280x800@60Hz RB */ + { DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 71000, 1280, 1328, + 1360, 1440, 0, 800, 803, 809, 823, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1280x800@60Hz */ { DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 83500, 1280, 1352, 1480, 1680, 0, 800, 803, 809, 831, 0, @@ -135,6 +154,10 @@ static struct drm_display_mode drm_dmt_modes[] = { { DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 122500, 1280, 1360, 1496, 1712, 0, 800, 803, 809, 843, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1280x800@120Hz RB */ + { DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 146250, 1280, 1328, + 1360, 1440, 0, 800, 803, 809, 847, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1280x960@60Hz */ { DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1376, 1488, 1800, 0, 960, 961, 964, 1000, 0, @@ -143,6 +166,10 @@ static struct drm_display_mode drm_dmt_modes[] = { { DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1344, 1504, 1728, 0, 960, 961, 964, 1011, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1280x960@120Hz RB */ + { DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 175500, 1280, 1328, + 1360, 1440, 0, 960, 963, 967, 1017, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1280x1024@60Hz */ { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1328, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, @@ -155,22 +182,42 @@ static struct drm_display_mode drm_dmt_modes[] = { { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 157500, 1280, 1344, 1504, 1728, 0, 1024, 1025, 1028, 1072, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1280x1024@120Hz RB */ + { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 187250, 1280, 1328, + 1360, 1440, 0, 1024, 1027, 1034, 1084, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1360x768@60Hz */ { DRM_MODE("1360x768", DRM_MODE_TYPE_DRIVER, 85500, 1360, 1424, 1536, 1792, 0, 768, 771, 777, 795, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - /* 1440x1050@60Hz */ + /* 1360x768@120Hz RB */ + { DRM_MODE("1360x768", DRM_MODE_TYPE_DRIVER, 148250, 1360, 1408, + 1440, 1520, 0, 768, 771, 776, 813, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1400x1050@60Hz RB */ + { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 101000, 1400, 1448, + 1480, 1560, 0, 1050, 1053, 1057, 1080, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1400x1050@60Hz */ { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 121750, 1400, 1488, 1632, 1864, 0, 1050, 1053, 1057, 1089, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, - /* 1440x1050@75Hz */ + /* 1400x1050@75Hz */ { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 156000, 1400, 1504, 1648, 1896, 0, 1050, 1053, 1057, 1099, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, - /* 1440x1050@85Hz */ + /* 1400x1050@85Hz */ { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 179500, 1400, 1504, 1656, 1912, 0, 1050, 1053, 1057, 1105, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1400x1050@120Hz RB */ + { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 208000, 1400, 1448, + 1480, 1560, 0, 1050, 1053, 1057, 1112, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1440x900@60Hz RB */ + { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 88750, 1440, 1488, + 1520, 1600, 0, 900, 903, 909, 926, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1440x900@60Hz */ { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 106500, 1440, 1520, 1672, 1904, 0, 900, 903, 909, 934, 0, @@ -183,6 +230,10 @@ static struct drm_display_mode drm_dmt_modes[] = { { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 157000, 1440, 1544, 1696, 1952, 0, 900, 903, 909, 948, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1440x900@120Hz RB */ + { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 182750, 1440, 1488, + 1520, 1600, 0, 900, 903, 909, 953, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1600x1200@60Hz */ { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, @@ -203,6 +254,14 @@ static struct drm_display_mode drm_dmt_modes[] = { { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 229500, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1600x1200@120Hz RB */ + { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 268250, 1600, 1648, + 1680, 1760, 0, 1200, 1203, 1207, 1271, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1680x1050@60Hz RB */ + { DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 119000, 1680, 1728, + 1760, 1840, 0, 1050, 1053, 1059, 1080, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1680x1050@60Hz */ { DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 146250, 1680, 1784, 1960, 2240, 0, 1050, 1053, 1059, 1089, 0, @@ -215,15 +274,23 @@ static struct drm_display_mode drm_dmt_modes[] = { { DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 214750, 1680, 1808, 1984, 2288, 0, 1050, 1053, 1059, 1105, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1680x1050@120Hz RB */ + { DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 245500, 1680, 1728, + 1760, 1840, 0, 1050, 1053, 1059, 1112, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1792x1344@60Hz */ { DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 204750, 1792, 1920, 2120, 2448, 0, 1344, 1345, 1348, 1394, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, - /* 1729x1344@75Hz */ + /* 1792x1344@75Hz */ { DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 261000, 1792, 1888, 2104, 2456, 0, 1344, 1345, 1348, 1417, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, - /* 1853x1392@60Hz */ + /* 1792x1344@120Hz RB */ + { DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 333250, 1792, 1840, + 1872, 1952, 0, 1344, 1347, 1351, 1423, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1856x1392@60Hz */ { DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 218250, 1856, 1952, 2176, 2528, 0, 1392, 1393, 1396, 1439, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, @@ -231,6 +298,14 @@ static struct drm_display_mode drm_dmt_modes[] = { { DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 288000, 1856, 1984, 2208, 2560, 0, 1392, 1395, 1399, 1500, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1856x1392@120Hz RB */ + { DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 356500, 1856, 1904, + 1936, 2016, 0, 1392, 1395, 1399, 1474, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1920x1200@60Hz RB */ + { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 154000, 1920, 1968, + 2000, 2080, 0, 1200, 1203, 1209, 1235, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1920x1200@60Hz */ { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 193250, 1920, 2056, 2256, 2592, 0, 1200, 1203, 1209, 1245, 0, @@ -243,6 +318,10 @@ static struct drm_display_mode drm_dmt_modes[] = { { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 281250, 1920, 2064, 2272, 2624, 0, 1200, 1203, 1209, 1262, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1920x1200@120Hz RB */ + { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 317000, 1920, 1968, + 2000, 2080, 0, 1200, 1203, 1209, 1271, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1920x1440@60Hz */ { DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 234000, 1920, 2048, 2256, 2600, 0, 1440, 1441, 1444, 1500, 0, @@ -251,6 +330,14 @@ static struct drm_display_mode drm_dmt_modes[] = { { DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2064, 2288, 2640, 0, 1440, 1441, 1444, 1500, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1920x1440@120Hz RB */ + { DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 380500, 1920, 1968, + 2000, 2080, 0, 1440, 1443, 1447, 1525, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 2560x1600@60Hz RB */ + { DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 268500, 2560, 2608, + 2640, 2720, 0, 1600, 1603, 1609, 1646, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 2560x1600@60Hz */ { DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 348500, 2560, 2752, 3032, 3504, 0, 1600, 1603, 1609, 1658, 0, @@ -263,6 +350,11 @@ static struct drm_display_mode drm_dmt_modes[] = { { DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 505250, 2560, 2768, 3048, 3536, 0, 1600, 1603, 1609, 1682, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 2560x1600@120Hz RB */ + { DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 552750, 2560, 2608, + 2640, 2720, 0, 1600, 1603, 1609, 1694, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + }; static const int drm_num_dmt_modes = sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode); @@ -321,12 +413,14 @@ static struct drm_display_mode edid_est_modes[] = { DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1152x864@75Hz */ }; -static const struct { +struct minimode { short w; short h; short r; short rb; -} est3_modes[] = { +}; + +static const struct minimode est3_modes[] = { /* byte 6 */ { 640, 350, 85, 0 }, { 640, 400, 85, 0 }, @@ -378,4 +472,304 @@ static const struct { { 1920, 1440, 60, 0 }, { 1920, 1440, 75, 0 }, }; -static const int num_est3_modes = sizeof(est3_modes) / sizeof(est3_modes[0]); +static const int num_est3_modes = DRM_ARRAY_SIZE(est3_modes); + +static const struct minimode extra_modes[] = { + { 1024, 576, 60, 0 }, + { 1366, 768, 60, 0 }, + { 1600, 900, 60, 0 }, + { 1680, 945, 60, 0 }, + { 1920, 1080, 60, 0 }, + { 2048, 1152, 60, 0 }, + { 2048, 1536, 60, 0 }, +}; +static const int num_extra_modes = DRM_ARRAY_SIZE(extra_modes); + +/* + * Probably taken from CEA-861 spec. + * This table is converted from xorg's hw/xfree86/modes/xf86EdidModes.c. + */ +static const struct drm_display_mode edid_cea_modes[] = { + /* 1 - 640x480@60Hz */ + { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, + 752, 800, 0, 480, 490, 492, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 2 - 720x480@60Hz */ + { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736, + 798, 858, 0, 480, 489, 495, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 3 - 720x480@60Hz */ + { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736, + 798, 858, 0, 480, 489, 495, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 4 - 1280x720@60Hz */ + { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390, + 1430, 1650, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 5 - 1920x1080i@60Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008, + 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | + DRM_MODE_FLAG_INTERLACE) }, + /* 6 - 1440x480i@60Hz */ + { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, + 1602, 1716, 0, 480, 488, 494, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + /* 7 - 1440x480i@60Hz */ + { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, + 1602, 1716, 0, 480, 488, 494, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + /* 8 - 1440x240@60Hz */ + { DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, + 1602, 1716, 0, 240, 244, 247, 262, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_DBLCLK) }, + /* 9 - 1440x240@60Hz */ + { DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, + 1602, 1716, 0, 240, 244, 247, 262, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_DBLCLK) }, + /* 10 - 2880x480i@60Hz */ + { DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, + 3204, 3432, 0, 480, 488, 494, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE) }, + /* 11 - 2880x480i@60Hz */ + { DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, + 3204, 3432, 0, 480, 488, 494, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE) }, + /* 12 - 2880x240@60Hz */ + { DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, + 3204, 3432, 0, 240, 244, 247, 262, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 13 - 2880x240@60Hz */ + { DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, + 3204, 3432, 0, 240, 244, 247, 262, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 14 - 1440x480@60Hz */ + { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472, + 1596, 1716, 0, 480, 489, 495, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 15 - 1440x480@60Hz */ + { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472, + 1596, 1716, 0, 480, 489, 495, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 16 - 1920x1080@60Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008, + 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 17 - 720x576@50Hz */ + { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732, + 796, 864, 0, 576, 581, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 18 - 720x576@50Hz */ + { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732, + 796, 864, 0, 576, 581, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 19 - 1280x720@50Hz */ + { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720, + 1760, 1980, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 20 - 1920x1080i@50Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448, + 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | + DRM_MODE_FLAG_INTERLACE) }, + /* 21 - 1440x576i@50Hz */ + { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, + 1590, 1728, 0, 576, 580, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + /* 22 - 1440x576i@50Hz */ + { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, + 1590, 1728, 0, 576, 580, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + /* 23 - 1440x288@50Hz */ + { DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, + 1590, 1728, 0, 288, 290, 293, 312, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_DBLCLK) }, + /* 24 - 1440x288@50Hz */ + { DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, + 1590, 1728, 0, 288, 290, 293, 312, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_DBLCLK) }, + /* 25 - 2880x576i@50Hz */ + { DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, + 3180, 3456, 0, 576, 580, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE) }, + /* 26 - 2880x576i@50Hz */ + { DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, + 3180, 3456, 0, 576, 580, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE) }, + /* 27 - 2880x288@50Hz */ + { DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, + 3180, 3456, 0, 288, 290, 293, 312, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 28 - 2880x288@50Hz */ + { DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, + 3180, 3456, 0, 288, 290, 293, 312, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 29 - 1440x576@50Hz */ + { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, + 1592, 1728, 0, 576, 581, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 30 - 1440x576@50Hz */ + { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, + 1592, 1728, 0, 576, 581, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 31 - 1920x1080@50Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448, + 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 32 - 1920x1080@24Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2558, + 2602, 2750, 0, 1080, 1084, 1089, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 33 - 1920x1080@25Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448, + 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 34 - 1920x1080@30Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008, + 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 35 - 2880x480@60Hz */ + { DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944, + 3192, 3432, 0, 480, 489, 495, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 36 - 2880x480@60Hz */ + { DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944, + 3192, 3432, 0, 480, 489, 495, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 37 - 2880x576@50Hz */ + { DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928, + 3184, 3456, 0, 576, 581, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 38 - 2880x576@50Hz */ + { DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928, + 3184, 3456, 0, 576, 581, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 39 - 1920x1080i@50Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 72000, 1920, 1952, + 2120, 2304, 0, 1080, 1126, 1136, 1250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE) }, + /* 40 - 1920x1080i@100Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448, + 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | + DRM_MODE_FLAG_INTERLACE) }, + /* 41 - 1280x720@100Hz */ + { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1720, + 1760, 1980, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 42 - 720x576@100Hz */ + { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732, + 796, 864, 0, 576, 581, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 43 - 720x576@100Hz */ + { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732, + 796, 864, 0, 576, 581, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 44 - 1440x576i@100Hz */ + { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, + 1590, 1728, 0, 576, 580, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_DBLCLK) }, + /* 45 - 1440x576i@100Hz */ + { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, + 1590, 1728, 0, 576, 580, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_DBLCLK) }, + /* 46 - 1920x1080i@120Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008, + 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | + DRM_MODE_FLAG_INTERLACE) }, + /* 47 - 1280x720@120Hz */ + { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1390, + 1430, 1650, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 48 - 720x480@120Hz */ + { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736, + 798, 858, 0, 480, 489, 495, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 49 - 720x480@120Hz */ + { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736, + 798, 858, 0, 480, 489, 495, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 50 - 1440x480i@120Hz */ + { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478, + 1602, 1716, 0, 480, 488, 494, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + /* 51 - 1440x480i@120Hz */ + { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478, + 1602, 1716, 0, 480, 488, 494, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + /* 52 - 720x576@200Hz */ + { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732, + 796, 864, 0, 576, 581, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 53 - 720x576@200Hz */ + { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732, + 796, 864, 0, 576, 581, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 54 - 1440x576i@200Hz */ + { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464, + 1590, 1728, 0, 576, 580, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + /* 55 - 1440x576i@200Hz */ + { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464, + 1590, 1728, 0, 576, 580, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + /* 56 - 720x480@240Hz */ + { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736, + 798, 858, 0, 480, 489, 495, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 57 - 720x480@240Hz */ + { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736, + 798, 858, 0, 480, 489, 495, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 58 - 1440x480i@240 */ + { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478, + 1602, 1716, 0, 480, 488, 494, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + /* 59 - 1440x480i@240 */ + { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478, + 1602, 1716, 0, 480, 488, 494, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + /* 60 - 1280x720@24Hz */ + { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 59400, 1280, 3040, + 3080, 3300, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 61 - 1280x720@25Hz */ + { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3700, + 3740, 3960, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 62 - 1280x720@30Hz */ + { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3040, + 3080, 3300, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 63 - 1920x1080@120Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2008, + 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 64 - 1920x1080@100Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2448, + 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, +}; +static const int drm_num_cea_modes = DRM_ARRAY_SIZE(edid_cea_modes); diff --git a/sys/dev/drm2/drm_fb_helper.c b/sys/dev/drm2/drm_fb_helper.c index 2eb41a51dc7f..562bf82f5558 100644 --- a/sys/dev/drm2/drm_fb_helper.c +++ b/sys/dev/drm2/drm_fb_helper.c @@ -202,6 +202,9 @@ static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc) { uint16_t *r_base, *g_base, *b_base; + if (crtc->funcs->gamma_set == NULL) + return; + r_base = crtc->gamma_store; g_base = r_base + crtc->gamma_size; b_base = g_base + crtc->gamma_size; @@ -1225,7 +1228,7 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper, /* try and find a 1024x768 mode on each connector */ can_clone = true; - dmt_mode = drm_mode_find_dmt(fb_helper->dev, 1024, 768, 60); + dmt_mode = drm_mode_find_dmt(fb_helper->dev, 1024, 768, 60, false); for (i = 0; i < fb_helper->connector_count; i++) { diff --git a/sys/dev/drm2/drm_ioctl.c b/sys/dev/drm2/drm_ioctl.c index c0af3761d290..e13eec787af4 100644 --- a/sys/dev/drm2/drm_ioctl.c +++ b/sys/dev/drm2/drm_ioctl.c @@ -250,6 +250,10 @@ int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv) case DRM_CAP_DUMB_PREFER_SHADOW: req->value = dev->mode_config.prefer_shadow; break; + case DRM_CAP_PRIME: + req->value |= false /* XXXKIB dev->driver->prime_fd_to_handle */ ? DRM_PRIME_CAP_IMPORT : 0; + req->value |= false /* XXXKIB dev->driver->prime_handle_to_fd */ ? DRM_PRIME_CAP_EXPORT : 0; + break; case DRM_CAP_TIMESTAMP_MONOTONIC: req->value = drm_timestamp_monotonic; break; diff --git a/sys/dev/drm2/drm_irq.c b/sys/dev/drm2/drm_irq.c index 3a60fa971c00..4ab3de00fd0a 100644 --- a/sys/dev/drm2/drm_irq.c +++ b/sys/dev/drm2/drm_irq.c @@ -639,7 +639,7 @@ drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, struct timeval *tvblank, unsigned flags) { - int ret = 0; + int ret; /* Define requested maximum error on timestamps (nanoseconds). */ int max_error = (int) drm_timestamp_precision * 1000; @@ -930,18 +930,15 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_modeset_ctl *modeset = data; - int ret = 0; unsigned int crtc; /* If drm_vblank_init() hasn't been called yet, just no-op */ if (!dev->num_crtcs) - goto out; + return 0; crtc = modeset->crtc; - if (crtc >= dev->num_crtcs) { - ret = -EINVAL; - goto out; - } + if (crtc >= dev->num_crtcs) + return -EINVAL; switch (modeset->cmd) { case _DRM_PRE_MODESET: @@ -951,12 +948,11 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, drm_vblank_post_modeset(dev, crtc); break; default: - ret = -EINVAL; + return -EINVAL; break; } -out: - return ret; + return 0; } static void @@ -1054,7 +1050,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv) { union drm_wait_vblank *vblwait = data; - int ret = 0; + int ret; unsigned int flags, seq, crtc, high_crtc; if (/*(!drm_dev_to_irq(dev)) || */(!dev->irq_enabled)) diff --git a/sys/dev/drm2/drm_memory.c b/sys/dev/drm2/drm_memory.c index fa48197388cc..af43a89bbfd4 100644 --- a/sys/dev/drm2/drm_memory.c +++ b/sys/dev/drm2/drm_memory.c @@ -125,3 +125,11 @@ drm_clflush_pages(vm_page_t *pages, unsigned long num_pages) pmap_invalidate_cache_pages(pages, num_pages); } + +void +drm_clflush_virt_range(char *addr, unsigned long length) +{ + + pmap_invalidate_cache_range((vm_offset_t)addr, + (vm_offset_t)addr + length, TRUE); +} diff --git a/sys/dev/drm2/drm_mode.h b/sys/dev/drm2/drm_mode.h index bc2824011d19..79cf933d4c89 100644 --- a/sys/dev/drm2/drm_mode.h +++ b/sys/dev/drm2/drm_mode.h @@ -228,6 +228,7 @@ struct drm_mode_get_connector { #define DRM_MODE_PROP_IMMUTABLE (1<<2) #define DRM_MODE_PROP_ENUM (1<<3) /* enumerated type with text strings */ #define DRM_MODE_PROP_BLOB (1<<4) +#define DRM_MODE_PROP_BITMASK (1<<5) /* bitmask of enumerated types */ struct drm_mode_property_enum { uint64_t value; @@ -252,6 +253,21 @@ struct drm_mode_connector_set_property { uint32_t connector_id; }; +struct drm_mode_obj_get_properties { + uint64_t props_ptr; + uint64_t prop_values_ptr; + uint32_t count_props; + uint32_t obj_id; + uint32_t obj_type; +}; + +struct drm_mode_obj_set_property { + uint64_t value; + uint32_t prop_id; + uint32_t obj_id; + uint32_t obj_type; +}; + struct drm_mode_get_blob { uint32_t blob_id; uint32_t length; diff --git a/sys/dev/drm2/drm_pciids.h b/sys/dev/drm2/drm_pciids.h index 50fb932adc5f..cad56a161ce3 100644 --- a/sys/dev/drm2/drm_pciids.h +++ b/sys/dev/drm2/drm_pciids.h @@ -48,6 +48,13 @@ {0x8086, 0x0162, CHIP_I9XX|CHIP_I915, "Intel IvyBridge"}, \ {0x8086, 0x0166, CHIP_I9XX|CHIP_I915, "Intel IvyBridge (M)"}, \ {0x8086, 0x016A, CHIP_I9XX|CHIP_I915, "Intel IvyBridge (S)"}, \ + {0x8086, 0x0402, CHIP_I9XX|CHIP_I915, "Intel Haswell"}, \ + {0x8086, 0x0412, CHIP_I9XX|CHIP_I915, "Intel Haswell"}, \ + {0x8086, 0x040a, CHIP_I9XX|CHIP_I915, "Intel Haswell (S)"}, \ + {0x8086, 0x041a, CHIP_I9XX|CHIP_I915, "Intel Haswell (S)"}, \ + {0x8086, 0x0406, CHIP_I9XX|CHIP_I915, "Intel Haswell (M)"}, \ + {0x8086, 0x0416, CHIP_I9XX|CHIP_I915, "Intel Haswell (M)"}, \ + {0x8086, 0x0c16, CHIP_I9XX|CHIP_I915, "Intel Haswell (SDV)"}, \ {0x8086, 0x2562, CHIP_I8XX, "Intel i845G GMCH"}, \ {0x8086, 0x2572, CHIP_I8XX, "Intel i865G GMCH"}, \ {0x8086, 0x2582, CHIP_I9XX|CHIP_I915, "Intel i915G"}, \ diff --git a/sys/dev/drm2/drm_stub.c b/sys/dev/drm2/drm_stub.c index 2c87dec79153..6f6af51983d5 100644 --- a/sys/dev/drm2/drm_stub.c +++ b/sys/dev/drm2/drm_stub.c @@ -45,7 +45,7 @@ drm_setmaster_ioctl(struct drm_device *dev, void *data, if (file_priv->master != 0) return (0); - return (-EPERM); + return (EPERM); } int @@ -55,6 +55,6 @@ drm_dropmaster_ioctl(struct drm_device *dev, void *data, DRM_DEBUG("dropmaster\n"); if (file_priv->master != 0) - return (-EINVAL); + return (EINVAL); return (0); } diff --git a/sys/dev/drm2/i915/i915_debug.c b/sys/dev/drm2/i915/i915_debug.c index 384ed4ae8436..5f44a994481e 100644 --- a/sys/dev/drm2/i915/i915_debug.c +++ b/sys/dev/drm2/i915/i915_debug.c @@ -43,7 +43,6 @@ enum { FLUSHING_LIST, INACTIVE_LIST, PINNED_LIST, - DEFERRED_FREE_LIST, }; static const char * @@ -135,6 +134,8 @@ describe_obj(struct sbuf *m, struct drm_i915_gem_object *obj) obj->madv == I915_MADV_DONTNEED ? " purgeable" : ""); if (obj->base.name) sbuf_printf(m, " (name: %d)", obj->base.name); + if (obj->pin_display) + sbuf_printf(m, " (display)"); if (obj->fence_reg != I915_FENCE_REG_NONE) sbuf_printf(m, " (fence: %d)", obj->fence_reg); if (obj->gtt_space != NULL) @@ -175,18 +176,10 @@ i915_gem_object_list_info(struct drm_device *dev, struct sbuf *m, void *data) sbuf_printf(m, "Inactive:\n"); head = &dev_priv->mm.inactive_list; break; - case PINNED_LIST: - sbuf_printf(m, "Pinned:\n"); - head = &dev_priv->mm.pinned_list; - break; case FLUSHING_LIST: sbuf_printf(m, "Flushing:\n"); head = &dev_priv->mm.flushing_list; break; - case DEFERRED_FREE_LIST: - sbuf_printf(m, "Deferred free:\n"); - head = &dev_priv->mm.deferred_free_list; - break; default: DRM_UNLOCK(dev); return (EINVAL); @@ -244,21 +237,11 @@ i915_gem_object_info(struct drm_device *dev, struct sbuf *m, void *data) sbuf_printf(m, " %u [%u] active objects, %zu [%zu] bytes\n", count, mappable_count, size, mappable_size); - size = count = mappable_size = mappable_count = 0; - count_objects(&dev_priv->mm.pinned_list, mm_list); - sbuf_printf(m, " %u [%u] pinned objects, %zu [%zu] bytes\n", - count, mappable_count, size, mappable_size); - size = count = mappable_size = mappable_count = 0; count_objects(&dev_priv->mm.inactive_list, mm_list); sbuf_printf(m, " %u [%u] inactive objects, %zu [%zu] bytes\n", count, mappable_count, size, mappable_size); - size = count = mappable_size = mappable_count = 0; - count_objects(&dev_priv->mm.deferred_free_list, mm_list); - sbuf_printf(m, " %u [%u] freed objects, %zu [%zu] bytes\n", - count, mappable_count, size, mappable_size); - size = count = mappable_size = mappable_count = 0; list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) { if (obj->fault_mappable) { @@ -283,9 +266,10 @@ i915_gem_object_info(struct drm_device *dev, struct sbuf *m, void *data) } static int -i915_gem_gtt_info(struct drm_device *dev, struct sbuf *m, void* data) +i915_gem_gtt_info(struct drm_device *dev, struct sbuf *m, void *data) { struct drm_i915_private *dev_priv = dev->dev_private; + uintptr_t list = (uintptr_t)data; struct drm_i915_gem_object *obj; size_t total_obj_size, total_gtt_size; int count; @@ -295,6 +279,9 @@ i915_gem_gtt_info(struct drm_device *dev, struct sbuf *m, void* data) total_obj_size = total_gtt_size = count = 0; list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) { + if (list == PINNED_LIST && obj->pin_count == 0) + continue; + sbuf_printf(m, " "); describe_obj(m, obj); sbuf_printf(m, "\n"); @@ -420,10 +407,6 @@ i915_ring_seqno_info(struct sbuf *m, struct intel_ring_buffer *ring) if (ring->get_seqno) { sbuf_printf(m, "Current sequence (%s): %d\n", ring->name, ring->get_seqno(ring)); - sbuf_printf(m, "Waiter sequence (%s): %d\n", - ring->name, ring->waiting_seqno); - sbuf_printf(m, "IRQ sequence (%s): %d\n", - ring->name, ring->irq_seqno); } } @@ -451,7 +434,45 @@ i915_interrupt_info(struct drm_device *dev, struct sbuf *m, void *data) if (sx_xlock_sig(&dev->dev_struct_lock)) return (EINTR); - if (!HAS_PCH_SPLIT(dev)) { + if (IS_VALLEYVIEW(dev)) { + sbuf_printf(m, "Display IER:\t%08x\n", + I915_READ(VLV_IER)); + sbuf_printf(m, "Display IIR:\t%08x\n", + I915_READ(VLV_IIR)); + sbuf_printf(m, "Display IIR_RW:\t%08x\n", + I915_READ(VLV_IIR_RW)); + sbuf_printf(m, "Display IMR:\t%08x\n", + I915_READ(VLV_IMR)); + for_each_pipe(pipe) + sbuf_printf(m, "Pipe %c stat:\t%08x\n", + pipe_name(pipe), + I915_READ(PIPESTAT(pipe))); + + sbuf_printf(m, "Master IER:\t%08x\n", + I915_READ(VLV_MASTER_IER)); + + sbuf_printf(m, "Render IER:\t%08x\n", + I915_READ(GTIER)); + sbuf_printf(m, "Render IIR:\t%08x\n", + I915_READ(GTIIR)); + sbuf_printf(m, "Render IMR:\t%08x\n", + I915_READ(GTIMR)); + + sbuf_printf(m, "PM IER:\t\t%08x\n", + I915_READ(GEN6_PMIER)); + sbuf_printf(m, "PM IIR:\t\t%08x\n", + I915_READ(GEN6_PMIIR)); + sbuf_printf(m, "PM IMR:\t\t%08x\n", + I915_READ(GEN6_PMIMR)); + + sbuf_printf(m, "Port hotplug:\t%08x\n", + I915_READ(PORT_HOTPLUG_EN)); + sbuf_printf(m, "DPFLIPSTAT:\t%08x\n", + I915_READ(VLV_DPFLIPSTAT)); + sbuf_printf(m, "DPINVGTT:\t%08x\n", + I915_READ(DPINVGTT)); + + } else if (!HAS_PCH_SPLIT(dev)) { sbuf_printf(m, "Interrupt enable: %08x\n", I915_READ(IER)); sbuf_printf(m, "Interrupt identity: %08x\n", @@ -544,61 +565,6 @@ i915_hws_info(struct drm_device *dev, struct sbuf *m, void *data) return (0); } -static int -i915_ringbuffer_data(struct drm_device *dev, struct sbuf *m, void *data) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - struct intel_ring_buffer *ring; - - if (sx_xlock_sig(&dev->dev_struct_lock)) - return (EINTR); - ring = &dev_priv->rings[(uintptr_t)data]; - if (!ring->obj) { - sbuf_printf(m, "No ringbuffer setup\n"); - } else { - u8 *virt = ring->virtual_start; - uint32_t off; - - for (off = 0; off < ring->size; off += 4) { - uint32_t *ptr = (uint32_t *)(virt + off); - sbuf_printf(m, "%08x : %08x\n", off, *ptr); - } - } - DRM_UNLOCK(dev); - return (0); -} - -static int -i915_ringbuffer_info(struct drm_device *dev, struct sbuf *m, void *data) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - struct intel_ring_buffer *ring; - - ring = &dev_priv->rings[(uintptr_t)data]; - if (ring->size == 0) - return (0); - - if (sx_xlock_sig(&dev->dev_struct_lock)) - return (EINTR); - - sbuf_printf(m, "Ring %s:\n", ring->name); - sbuf_printf(m, " Head : %08x\n", I915_READ_HEAD(ring) & HEAD_ADDR); - sbuf_printf(m, " Tail : %08x\n", I915_READ_TAIL(ring) & TAIL_ADDR); - sbuf_printf(m, " Size : %08x\n", ring->size); - sbuf_printf(m, " Active : %08x\n", intel_ring_get_active_head(ring)); - sbuf_printf(m, " NOPID : %08x\n", I915_READ_NOPID(ring)); - if (IS_GEN6(dev) || IS_GEN7(dev)) { - sbuf_printf(m, " Sync 0 : %08x\n", I915_READ_SYNC_0(ring)); - sbuf_printf(m, " Sync 1 : %08x\n", I915_READ_SYNC_1(ring)); - } - sbuf_printf(m, " Control : %08x\n", I915_READ_CTL(ring)); - sbuf_printf(m, " Start : %08x\n", I915_READ_START(ring)); - - DRM_UNLOCK(dev); - - return (0); -} - static const char * ring_str(int ring) { @@ -677,6 +643,7 @@ i915_ring_error_state(struct sbuf *m, struct drm_device *dev, struct drm_i915_error_state *error, unsigned ring) { + MPASS((ring < I915_NUM_RINGS)); /* shut up confused gcc */ sbuf_printf(m, "%s command stream:\n", ring_str(ring)); sbuf_printf(m, " HEAD: 0x%08x\n", error->head[ring]); sbuf_printf(m, " TAIL: 0x%08x\n", error->tail[ring]); @@ -691,8 +658,8 @@ i915_ring_error_state(struct sbuf *m, struct drm_device *dev, if (INTEL_INFO(dev)->gen >= 4) sbuf_printf(m, " INSTPS: 0x%08x\n", error->instps[ring]); sbuf_printf(m, " INSTPM: 0x%08x\n", error->instpm[ring]); + sbuf_printf(m, " FADDR: 0x%08x\n", error->faddr[ring]); if (INTEL_INFO(dev)->gen >= 6) { - sbuf_printf(m, " FADDR: 0x%08x\n", error->faddr[ring]); sbuf_printf(m, " FAULT_REG: 0x%08x\n", error->fault_reg[ring]); sbuf_printf(m, " SYNC_0: 0x%08x\n", error->semaphore_mboxes[ring][0]); @@ -700,21 +667,28 @@ i915_ring_error_state(struct sbuf *m, struct drm_device *dev, error->semaphore_mboxes[ring][1]); } sbuf_printf(m, " seqno: 0x%08x\n", error->seqno[ring]); + sbuf_printf(m, " waiting: %s\n", yesno(error->waiting[ring])); sbuf_printf(m, " ring->head: 0x%08x\n", error->cpu_ring_head[ring]); sbuf_printf(m, " ring->tail: 0x%08x\n", error->cpu_ring_tail[ring]); } -static int i915_error_state(struct drm_device *dev, struct sbuf *m, +static int +i915_error_state(struct drm_device *dev, struct sbuf *m, void *unused) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_error_state *error; + struct intel_ring_buffer *ring; int i, j, page, offset, elt; mtx_lock(&dev_priv->error_lock); - if (!dev_priv->first_error) { + error = dev_priv->first_error; + if (error != NULL) + refcount_acquire(&error->ref); + mtx_unlock(&dev_priv->error_lock); + if (error == NULL) { sbuf_printf(m, "no error state collected\n"); - goto out; + return (0); } error = dev_priv->first_error; @@ -723,6 +697,7 @@ static int i915_error_state(struct drm_device *dev, struct sbuf *m, (intmax_t)error->time.tv_usec); sbuf_printf(m, "PCI ID: 0x%04x\n", dev->pci_device); sbuf_printf(m, "EIR: 0x%08x\n", error->eir); + sbuf_printf(m, "IER: 0x%08x\n", error->ier); sbuf_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er); for (i = 0; i < dev_priv->num_fence_regs; i++) @@ -734,11 +709,8 @@ static int i915_error_state(struct drm_device *dev, struct sbuf *m, sbuf_printf(m, "DONE_REG: 0x%08x\n", error->done_reg); } - i915_ring_error_state(m, dev, error, RCS); - if (HAS_BLT(dev)) - i915_ring_error_state(m, dev, error, BCS); - if (HAS_BSD(dev)) - i915_ring_error_state(m, dev, error, VCS); + for_each_ring(ring, dev_priv, i) + i915_ring_error_state(m, dev, error, i); if (error->active_bo) print_error_buffers(m, "Active", @@ -801,12 +773,28 @@ static int i915_error_state(struct drm_device *dev, struct sbuf *m, if (error->display) intel_display_print_error_state(m, dev, error->display); -out: - mtx_unlock(&dev_priv->error_lock); + if (refcount_release(&error->ref)) + i915_error_state_free(error); return (0); } +static int +i915_error_state_w(struct drm_device *dev, const char *str, void *unused) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_error_state *error; + + DRM_DEBUG_DRIVER("Resetting error state\n"); + mtx_lock(&dev_priv->error_lock); + error = dev_priv->first_error; + dev_priv->first_error = NULL; + mtx_unlock(&dev_priv->error_lock); + if (error != NULL && refcount_release(&error->ref)) + i915_error_state_free(error); + return (0); +} + static int i915_rstdby_delays(struct drm_device *dev, struct sbuf *m, void *unused) { @@ -1081,6 +1069,17 @@ gen6_drpc_info(struct drm_device *dev, struct sbuf *m) sbuf_printf(m, "Core Power Down: %s\n", yesno(gt_core_status & GEN6_CORE_CPD_STATE_MASK)); + + /* Not exactly sure what this is */ + sbuf_printf(m, "RC6 \"Locked to RPn\" residency since boot: %u\n", + I915_READ(GEN6_GT_GFX_RC6_LOCKED)); + sbuf_printf(m, "RC6 residency since boot: %u\n", + I915_READ(GEN6_GT_GFX_RC6)); + sbuf_printf(m, "RC6+ residency since boot: %u\n", + I915_READ(GEN6_GT_GFX_RC6p)); + sbuf_printf(m, "RC6++ residency since boot: %u\n", + I915_READ(GEN6_GT_GFX_RC6pp)); + return 0; } @@ -1444,6 +1443,52 @@ i915_ppgtt_info(struct drm_device *dev, struct sbuf *m, void *data) return (0); } +static int i915_dpio_info(struct drm_device *dev, struct sbuf *m, void *data) +{ + struct drm_i915_private *dev_priv; + int ret; + + if (!IS_VALLEYVIEW(dev)) { + sbuf_printf(m, "unsupported\n"); + return 0; + } + + dev_priv = dev->dev_private; + + ret = sx_xlock_sig(&dev->mode_config.mutex); + if (ret != 0) + return (EINTR); + + sbuf_printf(m, "DPIO_CTL: 0x%08x\n", I915_READ(DPIO_CTL)); + + sbuf_printf(m, "DPIO_DIV_A: 0x%08x\n", + intel_dpio_read(dev_priv, _DPIO_DIV_A)); + sbuf_printf(m, "DPIO_DIV_B: 0x%08x\n", + intel_dpio_read(dev_priv, _DPIO_DIV_B)); + + sbuf_printf(m, "DPIO_REFSFR_A: 0x%08x\n", + intel_dpio_read(dev_priv, _DPIO_REFSFR_A)); + sbuf_printf(m, "DPIO_REFSFR_B: 0x%08x\n", + intel_dpio_read(dev_priv, _DPIO_REFSFR_B)); + + sbuf_printf(m, "DPIO_CORE_CLK_A: 0x%08x\n", + intel_dpio_read(dev_priv, _DPIO_CORE_CLK_A)); + sbuf_printf(m, "DPIO_CORE_CLK_B: 0x%08x\n", + intel_dpio_read(dev_priv, _DPIO_CORE_CLK_B)); + + sbuf_printf(m, "DPIO_LFP_COEFF_A: 0x%08x\n", + intel_dpio_read(dev_priv, _DPIO_LFP_COEFF_A)); + sbuf_printf(m, "DPIO_LFP_COEFF_B: 0x%08x\n", + intel_dpio_read(dev_priv, _DPIO_LFP_COEFF_B)); + + sbuf_printf(m, "DPIO_FASTCLK_DISABLE: 0x%08x\n", + intel_dpio_read(dev_priv, DPIO_FASTCLK_DISABLE)); + + sx_xunlock(&dev->mode_config.mutex); + + return 0; +} + static int i915_debug_set_wedged(SYSCTL_HANDLER_ARGS) { @@ -1520,57 +1565,77 @@ i915_cache_sharing(SYSCTL_HANDLER_ARGS) return (0); } +static int +i915_stop_rings(SYSCTL_HANDLER_ARGS) +{ + struct drm_device *dev; + drm_i915_private_t *dev_priv; + int error, val; + + dev = arg1; + dev_priv = dev->dev_private; + if (dev_priv == NULL) + return (EBUSY); + DRM_LOCK(dev); + val = dev_priv->stop_rings; + DRM_UNLOCK(dev); + error = sysctl_handle_int(oidp, &val, 0, req); + if (error || !req->newptr) + return (error); + DRM_DEBUG("Stopping rings 0x%08x\n", val); + + DRM_LOCK(dev); + dev_priv->stop_rings = val; + DRM_UNLOCK(dev); + return (0); +} + static struct i915_info_sysctl_list { const char *name; int (*ptr)(struct drm_device *dev, struct sbuf *m, void *data); + int (*ptr_w)(struct drm_device *dev, const char *str, void *data); int flags; void *data; } i915_info_sysctl_list[] = { - {"i915_capabilities", i915_capabilities, 0}, - {"i915_gem_objects", i915_gem_object_info, 0}, - {"i915_gem_gtt", i915_gem_gtt_info, 0}, - {"i915_gem_active", i915_gem_object_list_info, 0, (void *)ACTIVE_LIST}, - {"i915_gem_flushing", i915_gem_object_list_info, 0, + {"i915_capabilities", i915_capabilities, NULL, 0}, + {"i915_gem_objects", i915_gem_object_info, NULL, 0}, + {"i915_gem_gtt", i915_gem_gtt_info, NULL, 0}, + {"i915_gem_pinned", i915_gem_gtt_info, NULL, 0, (void *)PINNED_LIST}, + {"i915_gem_active", i915_gem_object_list_info, NULL, 0, + (void *)ACTIVE_LIST}, + {"i915_gem_flushing", i915_gem_object_list_info, NULL, 0, (void *)FLUSHING_LIST}, - {"i915_gem_inactive", i915_gem_object_list_info, 0, + {"i915_gem_inactive", i915_gem_object_list_info, NULL, 0, (void *)INACTIVE_LIST}, - {"i915_gem_pinned", i915_gem_object_list_info, 0, - (void *)PINNED_LIST}, - {"i915_gem_deferred_free", i915_gem_object_list_info, 0, - (void *)DEFERRED_FREE_LIST}, - {"i915_gem_pageflip", i915_gem_pageflip_info, 0}, - {"i915_gem_request", i915_gem_request_info, 0}, - {"i915_gem_seqno", i915_gem_seqno_info, 0}, - {"i915_gem_fence_regs", i915_gem_fence_regs_info, 0}, - {"i915_gem_interrupt", i915_interrupt_info, 0}, - {"i915_gem_hws", i915_hws_info, 0, (void *)RCS}, - {"i915_gem_hws_blt", i915_hws_info, 0, (void *)BCS}, - {"i915_gem_hws_bsd", i915_hws_info, 0, (void *)VCS}, - {"i915_ringbuffer_data", i915_ringbuffer_data, 0, (void *)RCS}, - {"i915_ringbuffer_info", i915_ringbuffer_info, 0, (void *)RCS}, - {"i915_bsd_ringbuffer_data", i915_ringbuffer_data, 0, (void *)VCS}, - {"i915_bsd_ringbuffer_info", i915_ringbuffer_info, 0, (void *)VCS}, - {"i915_blt_ringbuffer_data", i915_ringbuffer_data, 0, (void *)BCS}, - {"i915_blt_ringbuffer_info", i915_ringbuffer_info, 0, (void *)BCS}, - {"i915_error_state", i915_error_state, 0}, - {"i915_rstdby_delays", i915_rstdby_delays, 0}, - {"i915_cur_delayinfo", i915_cur_delayinfo, 0}, - {"i915_delayfreq_table", i915_delayfreq_table, 0}, - {"i915_inttoext_table", i915_inttoext_table, 0}, - {"i915_drpc_info", i915_drpc_info, 0}, - {"i915_emon_status", i915_emon_status, 0}, - {"i915_ring_freq_table", i915_ring_freq_table, 0}, - {"i915_gfxec", i915_gfxec, 0}, - {"i915_fbc_status", i915_fbc_status, 0}, - {"i915_sr_status", i915_sr_status, 0}, + {"i915_gem_pageflip", i915_gem_pageflip_info, NULL, 0}, + {"i915_gem_request", i915_gem_request_info, NULL, 0}, + {"i915_gem_seqno", i915_gem_seqno_info, NULL, 0}, + {"i915_gem_fence_regs", i915_gem_fence_regs_info, NULL, 0}, + {"i915_gem_interrupt", i915_interrupt_info, NULL, 0}, + {"i915_gem_hws", i915_hws_info, NULL, 0, (void *)RCS}, + {"i915_gem_hws_blt", i915_hws_info, NULL, 0, (void *)BCS}, + {"i915_gem_hws_bsd", i915_hws_info, NULL, 0, (void *)VCS}, + {"i915_error_state", i915_error_state, i915_error_state_w, 0}, + {"i915_rstdby_delays", i915_rstdby_delays, NULL, 0}, + {"i915_cur_delayinfo", i915_cur_delayinfo, NULL, 0}, + {"i915_delayfreq_table", i915_delayfreq_table, NULL, 0}, + {"i915_inttoext_table", i915_inttoext_table, NULL, 0}, + {"i915_drpc_info", i915_drpc_info, NULL, 0}, + {"i915_emon_status", i915_emon_status, NULL, 0}, + {"i915_ring_freq_table", i915_ring_freq_table, NULL, 0}, + {"i915_gfxec", i915_gfxec, NULL, 0}, + {"i915_fbc_status", i915_fbc_status, NULL, 0}, + {"i915_sr_status", i915_sr_status, NULL, 0}, #if 0 - {"i915_opregion", i915_opregion, 0}, + {"i915_opregion", i915_opregion, NULL, 0}, #endif - {"i915_gem_framebuffer", i915_gem_framebuffer_info, 0}, - {"i915_context_status", i915_context_status, 0}, - {"i915_gen6_forcewake_count_info", i915_gen6_forcewake_count_info, 0}, - {"i915_swizzle_info", i915_swizzle_info, 0}, - {"i915_ppgtt_info", i915_ppgtt_info, 0}, + {"i915_gem_framebuffer", i915_gem_framebuffer_info, NULL, 0}, + {"i915_context_status", i915_context_status, NULL, 0}, + {"i915_gen6_forcewake_count_info", i915_gen6_forcewake_count_info, + NULL, 0}, + {"i915_swizzle_info", i915_swizzle_info, NULL, 0}, + {"i915_ppgtt_info", i915_ppgtt_info, NULL, 0}, + {"i915_dpio", i915_dpio_info, NULL, 0}, }; struct i915_info_sysctl_thunk { @@ -1586,6 +1651,7 @@ i915_info_sysctl_handler(SYSCTL_HANDLER_ARGS) struct i915_info_sysctl_thunk *thunk; struct drm_device *dev; drm_i915_private_t *dev_priv; + char *p; int error; thunk = arg1; @@ -1602,6 +1668,19 @@ i915_info_sysctl_handler(SYSCTL_HANDLER_ARGS) if (error == 0) error = sbuf_finish(&m); sbuf_delete(&m); + if (error != 0 || req->newptr == NULL) + return (error); + if (req->newlen > 2048) + return (E2BIG); + p = malloc(req->newlen + 1, M_TEMP, M_WAITOK); + error = SYSCTL_IN(req, p, req->newlen); + if (error != 0) + goto out; + p[req->newlen] = '\0'; + error = i915_info_sysctl_list[thunk->idx].ptr_w(dev, p, + thunk->arg); +out: + free(p, M_TEMP); return (error); } @@ -1632,7 +1711,9 @@ i915_sysctl_init(struct drm_device *dev, struct sysctl_ctx_list *ctx, return (ENOMEM); for (i = 0; i < DRM_ARRAY_SIZE(i915_info_sysctl_list); i++) { oid = SYSCTL_ADD_OID(ctx, SYSCTL_CHILDREN(info), OID_AUTO, - i915_info_sysctl_list[i].name, CTLTYPE_STRING | CTLFLAG_RD, + i915_info_sysctl_list[i].name, CTLTYPE_STRING | + (i915_info_sysctl_list[i].ptr_w != NULL ? CTLFLAG_RW : + CTLFLAG_RD), &thunks[i], 0, i915_info_sysctl_handler, "A", NULL); if (oid == NULL) return (ENOMEM); @@ -1655,6 +1736,11 @@ i915_sysctl_init(struct drm_device *dev, struct sysctl_ctx_list *ctx, 0, i915_cache_sharing, "I", NULL); if (oid == NULL) return (ENOMEM); + oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(top), OID_AUTO, + "stop_rings", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, + 0, i915_stop_rings, "I", NULL); + if (oid == NULL) + return (ENOMEM); oid = SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(top), OID_AUTO, "sync_exec", CTLFLAG_RW, &i915_gem_sync_exec_requests, 0, NULL); if (oid == NULL) diff --git a/sys/dev/drm2/i915/i915_dma.c b/sys/dev/drm2/i915/i915_dma.c index 3fceaadb433d..58dcae7b542d 100644 --- a/sys/dev/drm2/i915/i915_dma.c +++ b/sys/dev/drm2/i915/i915_dma.c @@ -36,22 +36,56 @@ __FBSDID("$FreeBSD$"); #include #include -static struct drm_i915_private *i915_mch_dev; -/* - * Lock protecting IPS related data structures - * - i915_mch_dev - * - dev_priv->max_delay - * - dev_priv->min_delay - * - dev_priv->fmax - * - dev_priv->gpu_busy - */ -static struct mtx mchdev_lock; -MTX_SYSINIT(mchdev, &mchdev_lock, "mchdev", MTX_DEF); +#define LP_RING(d) (&((struct drm_i915_private *)(d))->rings[RCS]) + +#define BEGIN_LP_RING(n) \ + intel_ring_begin(LP_RING(dev_priv), (n)) + +#define OUT_RING(x) \ + intel_ring_emit(LP_RING(dev_priv), x) + +#define ADVANCE_LP_RING() \ + intel_ring_advance(LP_RING(dev_priv)) + +#define RING_LOCK_TEST_WITH_RETURN(dev, file) do { \ + if (LP_RING(dev->dev_private)->obj == NULL) \ + LOCK_TEST_WITH_RETURN(dev, file); \ +} while (0) + +static inline u32 +intel_read_legacy_status_page(struct drm_i915_private *dev_priv, int reg) +{ + if (I915_NEED_GFX_HWS(dev_priv->dev)) + return ((volatile u32*)(dev_priv->dri1.gfx_hws_cpu_addr))[reg]; + else + return intel_read_status_page(LP_RING(dev_priv), reg); +} + +#define READ_HWSP(dev_priv, reg) intel_read_legacy_status_page(dev_priv, reg) +#define READ_BREADCRUMB(dev_priv) READ_HWSP(dev_priv, I915_BREADCRUMB_INDEX) +#define I915_BREADCRUMB_INDEX 0x21 -static void i915_pineview_get_mem_freq(struct drm_device *dev); -static void i915_ironlake_get_mem_freq(struct drm_device *dev); static int i915_driver_unload_int(struct drm_device *dev, bool locked); +void i915_update_dri1_breadcrumb(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; +#if 0 + struct drm_i915_master_private *master_priv; + + if (dev->primary->master) { + master_priv = dev->primary->master->driver_priv; + if (master_priv->sarea_priv) + master_priv->sarea_priv->last_dispatch = + READ_BREADCRUMB(dev_priv); + } +#else + if (dev_priv->sarea_priv) + dev_priv->sarea_priv->last_dispatch = + READ_BREADCRUMB(dev_priv); +#endif +} + static void i915_write_hws_pga(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -115,7 +149,8 @@ static void i915_free_hws(struct drm_device *dev) if (dev_priv->status_gfx_addr) { dev_priv->status_gfx_addr = 0; ring->status_page.gfx_addr = 0; - drm_core_ioremapfree(&dev_priv->hws_map, dev); + pmap_unmapdev((vm_offset_t)dev_priv->dri1.gfx_hws_cpu_addr, + PAGE_SIZE); } /* Need to rewrite hardware status page */ @@ -214,7 +249,7 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) /* Allow hardware batchbuffers unless told otherwise. */ - dev_priv->allow_batchbuffer = 1; + dev_priv->dri1.allow_batchbuffer = 1; return 0; } @@ -226,7 +261,7 @@ static int i915_dma_resume(struct drm_device * dev) DRM_DEBUG("\n"); - if (ring->map.handle == NULL) { + if (ring->virtual_start == NULL) { DRM_ERROR("can not ioremap virtual address for" " ring buffer\n"); return -ENOMEM; @@ -254,6 +289,9 @@ static int i915_dma_init(struct drm_device *dev, void *data, drm_i915_init_t *init = data; int retcode = 0; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -ENODEV; + switch (init->func) { case I915_INIT_DMA: retcode = i915_initialize(dev, init); @@ -502,6 +540,9 @@ i915_dispatch_batchbuffer(struct drm_device * dev, int nbox = batch->num_cliprects; int i, count, ret; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -ENODEV; + if ((batch->start | batch->used) & 0x7) { DRM_ERROR("alignment\n"); return -EINVAL; @@ -618,6 +659,9 @@ i915_flush_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { int ret; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -ENODEV; + RING_LOCK_TEST_WITH_RETURN(dev, file_priv); DRM_LOCK(dev); @@ -637,7 +681,7 @@ int i915_batchbuffer(struct drm_device *dev, void *data, size_t cliplen; int ret; - if (!dev_priv->allow_batchbuffer) { + if (!dev_priv->dri1.allow_batchbuffer) { DRM_ERROR("Batchbuffer ioctl disabled\n"); return -EINVAL; } @@ -686,6 +730,9 @@ int i915_cmdbuffer(struct drm_device *dev, void *data, void *batch_data; int ret; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -ENODEV; + DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n", cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects); @@ -733,11 +780,199 @@ int i915_cmdbuffer(struct drm_device *dev, void *data, return ret; } +static int i915_emit_irq(struct drm_device * dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; +#if 0 + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; +#endif + + i915_kernel_lost_context(dev); + + DRM_DEBUG("i915: emit_irq\n"); + + dev_priv->counter++; + if (dev_priv->counter > 0x7FFFFFFFUL) + dev_priv->counter = 1; +#if 0 + if (master_priv->sarea_priv) + master_priv->sarea_priv->last_enqueue = dev_priv->counter; +#else + if (dev_priv->sarea_priv) + dev_priv->sarea_priv->last_enqueue = dev_priv->counter; +#endif + + if (BEGIN_LP_RING(4) == 0) { + OUT_RING(MI_STORE_DWORD_INDEX); + OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT); + OUT_RING(dev_priv->counter); + OUT_RING(MI_USER_INTERRUPT); + ADVANCE_LP_RING(); + } + + return dev_priv->counter; +} + +static int i915_wait_irq(struct drm_device * dev, int irq_nr) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; +#if 0 + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; +#endif + int ret; + struct intel_ring_buffer *ring = LP_RING(dev_priv); + + DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr, + READ_BREADCRUMB(dev_priv)); + +#if 0 + if (READ_BREADCRUMB(dev_priv) >= irq_nr) { + if (master_priv->sarea_priv) + master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); + return 0; + } + + if (master_priv->sarea_priv) + master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; +#else + if (READ_BREADCRUMB(dev_priv) >= irq_nr) { + if (dev_priv->sarea_priv) { + dev_priv->sarea_priv->last_dispatch = + READ_BREADCRUMB(dev_priv); + } + return 0; + } + + if (dev_priv->sarea_priv) + dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; +#endif + + ret = 0; + mtx_lock(&dev_priv->irq_lock); + if (ring->irq_get(ring)) { + DRM_UNLOCK(dev); + while (ret == 0 && READ_BREADCRUMB(dev_priv) < irq_nr) { + ret = -msleep(ring, &dev_priv->irq_lock, PCATCH, + "915wtq", 3 * hz); + } + ring->irq_put(ring); + mtx_unlock(&dev_priv->irq_lock); + DRM_LOCK(dev); + } else { + mtx_unlock(&dev_priv->irq_lock); + if (_intel_wait_for(dev, READ_BREADCRUMB(dev_priv) >= irq_nr, + 3000, 1, "915wir")) + ret = -EBUSY; + } + + if (ret == -EBUSY) { + DRM_ERROR("EBUSY -- rec: %d emitted: %d\n", + READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); + } + + return ret; +} + +/* Needs the lock as it touches the ring. + */ +int i915_irq_emit(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_irq_emit_t *emit = data; + int result; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -ENODEV; + + if (!dev_priv || !LP_RING(dev_priv)->virtual_start) { + DRM_ERROR("called with no initialization\n"); + return -EINVAL; + } + + RING_LOCK_TEST_WITH_RETURN(dev, file_priv); + + DRM_LOCK(dev); + result = i915_emit_irq(dev); + DRM_UNLOCK(dev); + + if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) { + DRM_ERROR("copy_to_user\n"); + return -EFAULT; + } + + return 0; +} + +/* Doesn't need the hardware lock. + */ +static int i915_irq_wait(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_irq_wait_t *irqwait = data; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -ENODEV; + + if (!dev_priv) { + DRM_ERROR("called with no initialization\n"); + return -EINVAL; + } + + return i915_wait_irq(dev, irqwait->irq_seq); +} + +static int i915_vblank_pipe_get(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_vblank_pipe_t *pipe = data; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -ENODEV; + + if (!dev_priv) { + DRM_ERROR("called with no initialization\n"); + return -EINVAL; + } + + pipe->pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; + + return 0; +} + +/** + * Schedule buffer swap at given vertical blank. + */ +static int i915_vblank_swap(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + /* The delayed swap mechanism was fundamentally racy, and has been + * removed. The model was that the client requested a delayed flip/swap + * from the kernel, then waited for vblank before continuing to perform + * rendering. The problem was that the kernel might wake the client + * up before it dispatched the vblank swap (since the lock has to be + * held while touching the ringbuffer), in which case the client would + * clear and start the next frame before the swap occurred, and + * flicker would occur in addition to likely missing the vblank. + * + * In the absence of this ioctl, userland falls back to a correct path + * of waiting for a vblank, then dispatching the swap on its own. + * Context switching to userland and back is plenty fast enough for + * meeting the requirements of vblank swapping. + */ + return -EINVAL; +} + static int i915_flip_bufs(struct drm_device *dev, void *data, struct drm_file *file_priv) { int ret; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -ENODEV; + DRM_DEBUG("%s\n", __func__); RING_LOCK_TEST_WITH_RETURN(dev, file_priv); @@ -764,7 +999,7 @@ int i915_getparam(struct drm_device *dev, void *data, value = dev->irq_enabled ? 1 : 0; break; case I915_PARAM_ALLOW_BATCHBUFFER: - value = dev_priv->allow_batchbuffer ? 1 : 0; + value = dev_priv->dri1.allow_batchbuffer ? 1 : 0; break; case I915_PARAM_LAST_DISPATCH: value = READ_BREADCRUMB(dev_priv); @@ -788,10 +1023,10 @@ int i915_getparam(struct drm_device *dev, void *data, value = 1; break; case I915_PARAM_HAS_BSD: - value = HAS_BSD(dev); + value = intel_ring_initialized(&dev_priv->rings[VCS]); break; case I915_PARAM_HAS_BLT: - value = HAS_BLT(dev); + value = intel_ring_initialized(&dev_priv->rings[BCS]); break; case I915_PARAM_HAS_RELAXED_FENCING: value = 1; @@ -811,6 +1046,9 @@ int i915_getparam(struct drm_device *dev, void *data, case I915_PARAM_HAS_LLC: value = HAS_LLC(dev); break; + case I915_PARAM_HAS_ALIASING_PPGTT: + value = dev_priv->mm.aliasing_ppgtt ? 1 : 0; + break; default: DRM_DEBUG_DRIVER("Unknown parameter %d\n", param->param); @@ -840,10 +1078,9 @@ static int i915_setparam(struct drm_device *dev, void *data, case I915_SETPARAM_USE_MI_BATCHBUFFER_START: break; case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY: - dev_priv->tex_lru_log_granularity = param->value; break; case I915_SETPARAM_ALLOW_BATCHBUFFER: - dev_priv->allow_batchbuffer = param->value; + dev_priv->dri1.allow_batchbuffer = param->value ? 1 : 0; break; case I915_SETPARAM_NUM_USED_FENCES: if (param->value > dev_priv->num_fence_regs || @@ -867,6 +1104,9 @@ static int i915_set_status_page(struct drm_device *dev, void *data, drm_i915_hws_addr_t *hws = data; struct intel_ring_buffer *ring = LP_RING(dev_priv); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -ENODEV; + if (!I915_NEED_GFX_HWS(dev)) return -EINVAL; @@ -884,24 +1124,18 @@ static int i915_set_status_page(struct drm_device *dev, void *data, ring->status_page.gfx_addr = dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12); - dev_priv->hws_map.offset = dev->agp->base + hws->addr; - dev_priv->hws_map.size = 4*1024; - dev_priv->hws_map.type = 0; - dev_priv->hws_map.flags = 0; - dev_priv->hws_map.mtrr = 0; - - drm_core_ioremap_wc(&dev_priv->hws_map, dev); - if (dev_priv->hws_map.virtual == NULL) { + dev_priv->dri1.gfx_hws_cpu_addr = pmap_mapdev_attr( + dev->agp->base + hws->addr, PAGE_SIZE, + VM_MEMATTR_WRITE_COMBINING); + if (dev_priv->dri1.gfx_hws_cpu_addr == NULL) { i915_dma_cleanup(dev); ring->status_page.gfx_addr = dev_priv->status_gfx_addr = 0; DRM_ERROR("can not ioremap virtual address for" " G33 hw status page\n"); return -ENOMEM; } - ring->status_page.page_addr = dev_priv->hw_status_page = - dev_priv->hws_map.virtual; - memset(dev_priv->hw_status_page, 0, PAGE_SIZE); + memset(dev_priv->dri1.gfx_hws_cpu_addr, 0, PAGE_SIZE); I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); DRM_DEBUG("load hws HWS_PGA with gfx mem 0x%x\n", dev_priv->status_gfx_addr); @@ -909,90 +1143,6 @@ static int i915_set_status_page(struct drm_device *dev, void *data, return 0; } -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; -} - -static int -i915_load_gem_init(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long prealloc_size, gtt_size, mappable_size; - int ret; - - prealloc_size = dev_priv->mm.gtt.stolen_size; - gtt_size = dev_priv->mm.gtt.gtt_total_entries << PAGE_SHIFT; - mappable_size = dev_priv->mm.gtt.gtt_mappable_entries << PAGE_SHIFT; - - /* Basic memrange allocator for stolen space */ - drm_mm_init(&dev_priv->mm.stolen, 0, prealloc_size); - - 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; - /* For paranoia keep the guard page in between. */ - gtt_size -= PAGE_SIZE; - - i915_gem_do_init(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_do_init(dev, 0, mappable_size, gtt_size - PAGE_SIZE); - } - - ret = i915_gem_init_hw(dev); - DRM_UNLOCK(dev); - if (ret != 0) { - i915_gem_cleanup_aliasing_ppgtt(dev); - return (ret); - } - -#if 0 - /* Try to set up FBC with a reasonable compressed buffer size */ - if (I915_HAS_FBC(dev) && i915_powersave) { - int cfb_size; - - /* Leave 1M for line length buffer & misc. */ - - /* Try to get a 32M buffer... */ - if (prealloc_size > (36*1024*1024)) - cfb_size = 32*1024*1024; - else /* fall back to 7/8 of the stolen space */ - cfb_size = prealloc_size * 7 / 8; - i915_setup_compression(dev, cfb_size); - } -#endif - - /* Allow hardware batchbuffers unless told otherwise. */ - dev_priv->allow_batchbuffer = 1; - return 0; -} - static int i915_load_modeset_init(struct drm_device *dev) { @@ -1007,15 +1157,18 @@ i915_load_modeset_init(struct drm_device *dev) intel_register_dsm_handler(); #endif - /* IIR "flip pending" bit means done if this bit is set */ - if (IS_GEN3(dev) && (I915_READ(ECOSKPD) & ECO_FLIP_DONE)) - dev_priv->flip_pending_is_done = true; + /* Initialise stolen first so that we may reserve preallocated + * objects for the BIOS to KMS transition. + */ + ret = i915_gem_init_stolen(dev); + if (ret) + goto cleanup_vga_switcheroo; intel_modeset_init(dev); - ret = i915_load_gem_init(dev); + ret = i915_gem_init(dev); if (ret != 0) - goto cleanup_gem; + goto cleanup_gem_stolen; intel_modeset_gem_init(dev); @@ -1041,6 +1194,9 @@ i915_load_modeset_init(struct drm_device *dev) i915_gem_cleanup_ringbuffer(dev); DRM_UNLOCK(dev); i915_gem_cleanup_aliasing_ppgtt(dev); +cleanup_gem_stolen: + i915_gem_cleanup_stolen(dev); +cleanup_vga_switcheroo: return (ret); } @@ -1197,9 +1353,17 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) { struct drm_i915_private *dev_priv = dev->dev_private; + const struct intel_device_info *info; unsigned long base, size; int mmio_bar, ret; + info = i915_get_device_id(dev->pci_device); + + /* Refuse to load on gen6+ without kms enabled. */ + if (info->gen >= 6 && !drm_core_check_feature(dev, DRIVER_MODESET)) + return -ENODEV; + + ret = 0; /* i915 has 4 more counters */ @@ -1211,12 +1375,10 @@ i915_driver_load(struct drm_device *dev, unsigned long flags) dev_priv = malloc(sizeof(drm_i915_private_t), DRM_MEM_DRIVER, M_ZERO | M_WAITOK); - if (dev_priv == NULL) - return -ENOMEM; dev->dev_private = (void *)dev_priv; dev_priv->dev = dev; - dev_priv->info = i915_get_device_id(dev->pci_device); + dev_priv->info = info; if (i915_get_bridge_dev(dev)) { free(dev_priv, DRM_MEM_DRIVER); @@ -1239,8 +1401,8 @@ i915_driver_load(struct drm_device *dev, unsigned long flags) mtx_init(&dev_priv->error_lock, "915err", NULL, MTX_DEF); mtx_init(&dev_priv->error_completion_lock, "915cmp", NULL, MTX_DEF); mtx_init(&dev_priv->rps_lock, "915rps", NULL, MTX_DEF); + mtx_init(&dev_priv->dpio_lock, "915dpi", NULL, MTX_DEF); - dev_priv->has_gem = 1; intel_irq_init(dev); intel_setup_mchbar(dev); @@ -1262,14 +1424,9 @@ i915_driver_load(struct drm_device *dev, unsigned long flags) } } - if (IS_PINEVIEW(dev)) - i915_pineview_get_mem_freq(dev); - else if (IS_GEN5(dev)) - i915_ironlake_get_mem_freq(dev); - mtx_init(&dev_priv->irq_lock, "userirq", NULL, MTX_DEF); - if (IS_IVYBRIDGE(dev)) + if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) dev_priv->num_pipe = 3; else if (IS_MOBILE(dev) || !IS_GEN2(dev)) dev_priv->num_pipe = 2; @@ -1301,12 +1458,8 @@ i915_driver_load(struct drm_device *dev, unsigned long flags) callout_reset(&dev_priv->hangcheck_timer, DRM_I915_HANGCHECK_PERIOD, i915_hangcheck_elapsed, dev); - if (IS_GEN5(dev)) { - mtx_lock(&mchdev_lock); - i915_mch_dev = dev_priv; - dev_priv->mchdev_lock = &mchdev_lock; - mtx_unlock(&mchdev_lock); - } + if (IS_GEN5(dev)) + intel_gpu_ips_init(dev_priv); return (0); @@ -1324,9 +1477,10 @@ i915_driver_unload_int(struct drm_device *dev, bool locked) if (!locked) DRM_LOCK(dev); - ret = i915_gpu_idle(dev, true); + ret = i915_gpu_idle(dev); if (ret) DRM_ERROR("failed to idle hardware: %d\n", ret); + i915_gem_retire_requests(dev); if (!locked) DRM_UNLOCK(dev); @@ -1386,6 +1540,7 @@ i915_driver_unload_int(struct drm_device *dev, bool locked) drm_rmmap(dev, dev_priv->mmio_map); intel_teardown_gmbus(dev); + mtx_destroy(&dev_priv->dpio_lock); mtx_destroy(&dev_priv->error_lock); mtx_destroy(&dev_priv->error_completion_lock); mtx_destroy(&dev_priv->rps_lock); @@ -1466,7 +1621,7 @@ struct drm_ioctl_desc i915_ioctls[] = { DRM_IOCTL_DEF(DRM_I915_INIT_HEAP, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_I915_CMDBUFFER, i915_cmdbuffer, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_DESTROY_HEAP, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ), - DRM_IOCTL_DEF(DRM_I915_SET_VBLANK_PIPE, i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ), + DRM_IOCTL_DEF(DRM_I915_SET_VBLANK_PIPE, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ), DRM_IOCTL_DEF(DRM_I915_GET_VBLANK_PIPE, i915_vblank_pipe_get, DRM_AUTH ), DRM_IOCTL_DEF(DRM_I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), @@ -1541,550 +1696,13 @@ struct drm_driver_info i915_driver_info = { .patchlevel = DRIVER_PATCHLEVEL, }; -/** - * Determine if the device really is AGP or not. - * - * All Intel graphics chipsets are treated as AGP, even if they are really - * built-in. - * - * \param dev The device to be tested. - * - * \returns - * A value of 1 is always retured to indictate every i9x5 is AGP. +/* + * This is really ugly: Because old userspace abused the linux agp interface to + * manage the gtt, we need to claim that all intel devices are agp. For + * otherwise the drm core refuses to initialize the agp support code. */ int i915_driver_device_is_agp(struct drm_device * dev) { return 1; } -static void i915_pineview_get_mem_freq(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - u32 tmp; - - tmp = I915_READ(CLKCFG); - - switch (tmp & CLKCFG_FSB_MASK) { - case CLKCFG_FSB_533: - dev_priv->fsb_freq = 533; /* 133*4 */ - break; - case CLKCFG_FSB_800: - dev_priv->fsb_freq = 800; /* 200*4 */ - break; - case CLKCFG_FSB_667: - dev_priv->fsb_freq = 667; /* 167*4 */ - break; - case CLKCFG_FSB_400: - dev_priv->fsb_freq = 400; /* 100*4 */ - break; - } - - switch (tmp & CLKCFG_MEM_MASK) { - case CLKCFG_MEM_533: - dev_priv->mem_freq = 533; - break; - case CLKCFG_MEM_667: - dev_priv->mem_freq = 667; - break; - case CLKCFG_MEM_800: - dev_priv->mem_freq = 800; - break; - } - - /* detect pineview DDR3 setting */ - tmp = I915_READ(CSHRDDR3CTL); - dev_priv->is_ddr3 = (tmp & CSHRDDR3CTL_DDR3) ? 1 : 0; -} - -static void i915_ironlake_get_mem_freq(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - u16 ddrpll, csipll; - - ddrpll = I915_READ16(DDRMPLL1); - csipll = I915_READ16(CSIPLL0); - - switch (ddrpll & 0xff) { - case 0xc: - dev_priv->mem_freq = 800; - break; - case 0x10: - dev_priv->mem_freq = 1066; - break; - case 0x14: - dev_priv->mem_freq = 1333; - break; - case 0x18: - dev_priv->mem_freq = 1600; - break; - default: - DRM_DEBUG("unknown memory frequency 0x%02x\n", - ddrpll & 0xff); - dev_priv->mem_freq = 0; - break; - } - - dev_priv->r_t = dev_priv->mem_freq; - - switch (csipll & 0x3ff) { - case 0x00c: - dev_priv->fsb_freq = 3200; - break; - case 0x00e: - dev_priv->fsb_freq = 3733; - break; - case 0x010: - dev_priv->fsb_freq = 4266; - break; - case 0x012: - dev_priv->fsb_freq = 4800; - break; - case 0x014: - dev_priv->fsb_freq = 5333; - break; - case 0x016: - dev_priv->fsb_freq = 5866; - break; - case 0x018: - dev_priv->fsb_freq = 6400; - break; - default: - DRM_DEBUG("unknown fsb frequency 0x%04x\n", - csipll & 0x3ff); - dev_priv->fsb_freq = 0; - break; - } - - if (dev_priv->fsb_freq == 3200) { - dev_priv->c_m = 0; - } else if (dev_priv->fsb_freq > 3200 && dev_priv->fsb_freq <= 4800) { - dev_priv->c_m = 1; - } else { - dev_priv->c_m = 2; - } -} - -static const struct cparams { - u16 i; - u16 t; - u16 m; - u16 c; -} cparams[] = { - { 1, 1333, 301, 28664 }, - { 1, 1066, 294, 24460 }, - { 1, 800, 294, 25192 }, - { 0, 1333, 276, 27605 }, - { 0, 1066, 276, 27605 }, - { 0, 800, 231, 23784 }, -}; - -unsigned long i915_chipset_val(struct drm_i915_private *dev_priv) -{ - u64 total_count, diff, ret; - u32 count1, count2, count3, m = 0, c = 0; - unsigned long now = jiffies_to_msecs(jiffies), diff1; - int i; - - diff1 = now - dev_priv->last_time1; - /* - * sysctl(8) reads the value of sysctl twice in rapid - * succession. There is high chance that it happens in the - * same timer tick. Use the cached value to not divide by - * zero and give the hw a chance to gather more samples. - */ - if (diff1 <= 10) - return (dev_priv->chipset_power); - - count1 = I915_READ(DMIEC); - count2 = I915_READ(DDREC); - count3 = I915_READ(CSIEC); - - total_count = count1 + count2 + count3; - - /* FIXME: handle per-counter overflow */ - if (total_count < dev_priv->last_count1) { - diff = ~0UL - dev_priv->last_count1; - diff += total_count; - } else { - diff = total_count - dev_priv->last_count1; - } - - for (i = 0; i < DRM_ARRAY_SIZE(cparams); i++) { - if (cparams[i].i == dev_priv->c_m && - cparams[i].t == dev_priv->r_t) { - m = cparams[i].m; - c = cparams[i].c; - break; - } - } - - diff = diff / diff1; - ret = ((m * diff) + c); - ret = ret / 10; - - dev_priv->last_count1 = total_count; - dev_priv->last_time1 = now; - - dev_priv->chipset_power = ret; - return (ret); -} - -unsigned long i915_mch_val(struct drm_i915_private *dev_priv) -{ - unsigned long m, x, b; - u32 tsfs; - - tsfs = I915_READ(TSFS); - - m = ((tsfs & TSFS_SLOPE_MASK) >> TSFS_SLOPE_SHIFT); - x = I915_READ8(I915_TR1); - - b = tsfs & TSFS_INTR_MASK; - - return ((m * x) / 127) - b; -} - -static u16 pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid) -{ - static const struct v_table { - u16 vd; /* in .1 mil */ - u16 vm; /* in .1 mil */ - } v_table[] = { - { 0, 0, }, - { 375, 0, }, - { 500, 0, }, - { 625, 0, }, - { 750, 0, }, - { 875, 0, }, - { 1000, 0, }, - { 1125, 0, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4250, 3125, }, - { 4375, 3250, }, - { 4500, 3375, }, - { 4625, 3500, }, - { 4750, 3625, }, - { 4875, 3750, }, - { 5000, 3875, }, - { 5125, 4000, }, - { 5250, 4125, }, - { 5375, 4250, }, - { 5500, 4375, }, - { 5625, 4500, }, - { 5750, 4625, }, - { 5875, 4750, }, - { 6000, 4875, }, - { 6125, 5000, }, - { 6250, 5125, }, - { 6375, 5250, }, - { 6500, 5375, }, - { 6625, 5500, }, - { 6750, 5625, }, - { 6875, 5750, }, - { 7000, 5875, }, - { 7125, 6000, }, - { 7250, 6125, }, - { 7375, 6250, }, - { 7500, 6375, }, - { 7625, 6500, }, - { 7750, 6625, }, - { 7875, 6750, }, - { 8000, 6875, }, - { 8125, 7000, }, - { 8250, 7125, }, - { 8375, 7250, }, - { 8500, 7375, }, - { 8625, 7500, }, - { 8750, 7625, }, - { 8875, 7750, }, - { 9000, 7875, }, - { 9125, 8000, }, - { 9250, 8125, }, - { 9375, 8250, }, - { 9500, 8375, }, - { 9625, 8500, }, - { 9750, 8625, }, - { 9875, 8750, }, - { 10000, 8875, }, - { 10125, 9000, }, - { 10250, 9125, }, - { 10375, 9250, }, - { 10500, 9375, }, - { 10625, 9500, }, - { 10750, 9625, }, - { 10875, 9750, }, - { 11000, 9875, }, - { 11125, 10000, }, - { 11250, 10125, }, - { 11375, 10250, }, - { 11500, 10375, }, - { 11625, 10500, }, - { 11750, 10625, }, - { 11875, 10750, }, - { 12000, 10875, }, - { 12125, 11000, }, - { 12250, 11125, }, - { 12375, 11250, }, - { 12500, 11375, }, - { 12625, 11500, }, - { 12750, 11625, }, - { 12875, 11750, }, - { 13000, 11875, }, - { 13125, 12000, }, - { 13250, 12125, }, - { 13375, 12250, }, - { 13500, 12375, }, - { 13625, 12500, }, - { 13750, 12625, }, - { 13875, 12750, }, - { 14000, 12875, }, - { 14125, 13000, }, - { 14250, 13125, }, - { 14375, 13250, }, - { 14500, 13375, }, - { 14625, 13500, }, - { 14750, 13625, }, - { 14875, 13750, }, - { 15000, 13875, }, - { 15125, 14000, }, - { 15250, 14125, }, - { 15375, 14250, }, - { 15500, 14375, }, - { 15625, 14500, }, - { 15750, 14625, }, - { 15875, 14750, }, - { 16000, 14875, }, - { 16125, 15000, }, - }; - if (dev_priv->info->is_mobile) - return v_table[pxvid].vm; - else - return v_table[pxvid].vd; -} - -void i915_update_gfx_val(struct drm_i915_private *dev_priv) -{ - struct timespec now, diff1; - u64 diff; - unsigned long diffms; - u32 count; - - if (dev_priv->info->gen != 5) - return; - - nanotime(&now); - diff1 = now; - timespecsub(&diff1, &dev_priv->last_time2); - - /* Don't divide by 0 */ - diffms = diff1.tv_sec * 1000 + diff1.tv_nsec / 1000000; - if (!diffms) - return; - - count = I915_READ(GFXEC); - - if (count < dev_priv->last_count2) { - diff = ~0UL - dev_priv->last_count2; - diff += count; - } else { - diff = count - dev_priv->last_count2; - } - - dev_priv->last_count2 = count; - dev_priv->last_time2 = now; - - /* More magic constants... */ - diff = diff * 1181; - diff = diff / (diffms * 10); - dev_priv->gfx_power = diff; -} - -unsigned long i915_gfx_val(struct drm_i915_private *dev_priv) -{ - unsigned long t, corr, state1, corr2, state2; - u32 pxvid, ext_v; - - pxvid = I915_READ(PXVFREQ_BASE + (dev_priv->cur_delay * 4)); - pxvid = (pxvid >> 24) & 0x7f; - ext_v = pvid_to_extvid(dev_priv, pxvid); - - state1 = ext_v; - - t = i915_mch_val(dev_priv); - - /* Revel in the empirically derived constants */ - - /* Correction factor in 1/100000 units */ - if (t > 80) - corr = ((t * 2349) + 135940); - else if (t >= 50) - corr = ((t * 964) + 29317); - else /* < 50 */ - corr = ((t * 301) + 1004); - - corr = corr * ((150142 * state1) / 10000 - 78642); - corr /= 100000; - corr2 = (corr * dev_priv->corr); - - state2 = (corr2 * state1) / 10000; - state2 /= 100; /* convert to mW */ - - i915_update_gfx_val(dev_priv); - - return dev_priv->gfx_power + state2; -} - -/** - * i915_read_mch_val - return value for IPS use - * - * Calculate and return a value for the IPS driver to use when deciding whether - * we have thermal and power headroom to increase CPU or GPU power budget. - */ -unsigned long i915_read_mch_val(void) -{ - struct drm_i915_private *dev_priv; - unsigned long chipset_val, graphics_val, ret = 0; - - mtx_lock(&mchdev_lock); - if (!i915_mch_dev) - goto out_unlock; - dev_priv = i915_mch_dev; - - chipset_val = i915_chipset_val(dev_priv); - graphics_val = i915_gfx_val(dev_priv); - - ret = chipset_val + graphics_val; - -out_unlock: - mtx_unlock(&mchdev_lock); - - return ret; -} - -/** - * i915_gpu_raise - raise GPU frequency limit - * - * Raise the limit; IPS indicates we have thermal headroom. - */ -bool i915_gpu_raise(void) -{ - struct drm_i915_private *dev_priv; - bool ret = true; - - mtx_lock(&mchdev_lock); - if (!i915_mch_dev) { - ret = false; - goto out_unlock; - } - dev_priv = i915_mch_dev; - - if (dev_priv->max_delay > dev_priv->fmax) - dev_priv->max_delay--; - -out_unlock: - mtx_unlock(&mchdev_lock); - - return ret; -} - -/** - * i915_gpu_lower - lower GPU frequency limit - * - * IPS indicates we're close to a thermal limit, so throttle back the GPU - * frequency maximum. - */ -bool i915_gpu_lower(void) -{ - struct drm_i915_private *dev_priv; - bool ret = true; - - mtx_lock(&mchdev_lock); - if (!i915_mch_dev) { - ret = false; - goto out_unlock; - } - dev_priv = i915_mch_dev; - - if (dev_priv->max_delay < dev_priv->min_delay) - dev_priv->max_delay++; - -out_unlock: - mtx_unlock(&mchdev_lock); - - return ret; -} - -/** - * i915_gpu_busy - indicate GPU business to IPS - * - * Tell the IPS driver whether or not the GPU is busy. - */ -bool i915_gpu_busy(void) -{ - struct drm_i915_private *dev_priv; - bool ret = false; - - mtx_lock(&mchdev_lock); - if (!i915_mch_dev) - goto out_unlock; - dev_priv = i915_mch_dev; - - ret = dev_priv->busy; - -out_unlock: - mtx_unlock(&mchdev_lock); - - return ret; -} - -/** - * i915_gpu_turbo_disable - disable graphics turbo - * - * Disable graphics turbo by resetting the max frequency and setting the - * current frequency to the default. - */ -bool i915_gpu_turbo_disable(void) -{ - struct drm_i915_private *dev_priv; - bool ret = true; - - mtx_lock(&mchdev_lock); - if (!i915_mch_dev) { - ret = false; - goto out_unlock; - } - dev_priv = i915_mch_dev; - - dev_priv->max_delay = dev_priv->fstart; - - if (!ironlake_set_drps(dev_priv->dev, dev_priv->fstart)) - ret = false; - -out_unlock: - mtx_unlock(&mchdev_lock); - - return ret; -} diff --git a/sys/dev/drm2/i915/i915_drm.h b/sys/dev/drm2/i915/i915_drm.h index cf5227f20be2..c6e5c7e6b8f9 100644 --- a/sys/dev/drm2/i915/i915_drm.h +++ b/sys/dev/drm2/i915/i915_drm.h @@ -301,15 +301,15 @@ typedef struct drm_i915_irq_wait { /* Ioctl to query kernel params: */ -#define I915_PARAM_IRQ_ACTIVE 1 -#define I915_PARAM_ALLOW_BATCHBUFFER 2 -#define I915_PARAM_LAST_DISPATCH 3 -#define I915_PARAM_CHIPSET_ID 4 -#define I915_PARAM_HAS_GEM 5 -#define I915_PARAM_NUM_FENCES_AVAIL 6 -#define I915_PARAM_HAS_OVERLAY 7 +#define I915_PARAM_IRQ_ACTIVE 1 +#define I915_PARAM_ALLOW_BATCHBUFFER 2 +#define I915_PARAM_LAST_DISPATCH 3 +#define I915_PARAM_CHIPSET_ID 4 +#define I915_PARAM_HAS_GEM 5 +#define I915_PARAM_NUM_FENCES_AVAIL 6 +#define I915_PARAM_HAS_OVERLAY 7 #define I915_PARAM_HAS_PAGEFLIPPING 8 -#define I915_PARAM_HAS_EXECBUF2 9 +#define I915_PARAM_HAS_EXECBUF2 9 #define I915_PARAM_HAS_BSD 10 #define I915_PARAM_HAS_BLT 11 #define I915_PARAM_HAS_RELAXED_FENCING 12 @@ -317,7 +317,8 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_HAS_EXEC_CONSTANTS 14 #define I915_PARAM_HAS_RELAXED_DELTA 15 #define I915_PARAM_HAS_GEN7_SOL_RESET 16 -#define I915_PARAM_HAS_LLC 17 +#define I915_PARAM_HAS_LLC 17 +#define I915_PARAM_HAS_ALIASING_PPGTT 18 typedef struct drm_i915_getparam { int param; diff --git a/sys/dev/drm2/i915/i915_drv.c b/sys/dev/drm2/i915/i915_drv.c index 2380d237f0fa..b5a43a54df3f 100644 --- a/sys/dev/drm2/i915/i915_drv.c +++ b/sys/dev/drm2/i915/i915_drv.c @@ -132,6 +132,7 @@ static const struct intel_device_info intel_ironlake_d_info = { .gen = 5, .need_gfx_hws = 1, .has_hotplug = 1, .has_bsd_ring = 1, + .has_pch_split = 1, }; static const struct intel_device_info intel_ironlake_m_info = { @@ -139,6 +140,7 @@ static const struct intel_device_info intel_ironlake_m_info = { .need_gfx_hws = 1, .has_hotplug = 1, .has_fbc = 0, /* disabled due to buggy hardware */ .has_bsd_ring = 1, + .has_pch_split = 1, }; static const struct intel_device_info intel_sandybridge_d_info = { @@ -147,6 +149,7 @@ static const struct intel_device_info intel_sandybridge_d_info = { .has_bsd_ring = 1, .has_blt_ring = 1, .has_llc = 1, + .has_pch_split = 1, }; static const struct intel_device_info intel_sandybridge_m_info = { @@ -156,6 +159,7 @@ static const struct intel_device_info intel_sandybridge_m_info = { .has_bsd_ring = 1, .has_blt_ring = 1, .has_llc = 1, + .has_pch_split = 1, }; static const struct intel_device_info intel_ivybridge_d_info = { @@ -164,6 +168,7 @@ static const struct intel_device_info intel_ivybridge_d_info = { .has_bsd_ring = 1, .has_blt_ring = 1, .has_llc = 1, + .has_pch_split = 1, }; static const struct intel_device_info intel_ivybridge_m_info = { @@ -173,6 +178,45 @@ static const struct intel_device_info intel_ivybridge_m_info = { .has_bsd_ring = 1, .has_blt_ring = 1, .has_llc = 1, + .has_pch_split = 1, +}; + +#if 0 +static const struct intel_device_info intel_valleyview_m_info = { + .gen = 7, .is_mobile = 1, + .need_gfx_hws = 1, .has_hotplug = 1, + .has_fbc = 0, + .has_bsd_ring = 1, + .has_blt_ring = 1, + .is_valleyview = 1, +}; + +static const struct intel_device_info intel_valleyview_d_info = { + .gen = 7, + .need_gfx_hws = 1, .has_hotplug = 1, + .has_fbc = 0, + .has_bsd_ring = 1, + .has_blt_ring = 1, + .is_valleyview = 1, +}; +#endif + +static const struct intel_device_info intel_haswell_d_info = { + .is_haswell = 1, .gen = 7, + .need_gfx_hws = 1, .has_hotplug = 1, + .has_bsd_ring = 1, + .has_blt_ring = 1, + .has_llc = 1, + .has_pch_split = 1, +}; + +static const struct intel_device_info intel_haswell_m_info = { + .is_haswell = 1, .gen = 7, .is_mobile = 1, + .need_gfx_hws = 1, .has_hotplug = 1, + .has_bsd_ring = 1, + .has_blt_ring = 1, + .has_llc = 1, + .has_pch_split = 1, }; #define INTEL_VGA_DEVICE(id, info_) { \ @@ -228,6 +272,13 @@ static const struct intel_gfx_device_id { INTEL_VGA_DEVICE(0x0162, &intel_ivybridge_d_info), /* GT2 desktop */ INTEL_VGA_DEVICE(0x015a, &intel_ivybridge_d_info), /* GT1 server */ INTEL_VGA_DEVICE(0x016a, &intel_ivybridge_d_info), /* GT2 server */ + INTEL_VGA_DEVICE(0x0402, &intel_haswell_d_info), /* GT1 desktop */ + INTEL_VGA_DEVICE(0x0412, &intel_haswell_d_info), /* GT2 desktop */ + INTEL_VGA_DEVICE(0x040a, &intel_haswell_d_info), /* GT1 server */ + INTEL_VGA_DEVICE(0x041a, &intel_haswell_d_info), /* GT2 server */ + INTEL_VGA_DEVICE(0x0406, &intel_haswell_m_info), /* GT1 mobile */ + INTEL_VGA_DEVICE(0x0416, &intel_haswell_m_info), /* GT2 mobile */ + INTEL_VGA_DEVICE(0x0c16, &intel_haswell_d_info), /* SDV */ {0, 0} }; @@ -304,14 +355,15 @@ static int i915_drm_thaw(struct drm_device *dev) /* KMS EnterVT equivalent */ if (drm_core_check_feature(dev, DRIVER_MODESET)) { - dev_priv->mm.suspended = 0; - - error = i915_gem_init_hw(dev); - if (HAS_PCH_SPLIT(dev)) ironlake_init_pch_refclk(dev); + dev_priv->mm.suspended = 0; + + error = i915_gem_init_hw(dev); DRM_UNLOCK(dev); + + intel_modeset_init_hw(dev); sx_xlock(&dev->mode_config.mutex); drm_mode_config_reset(dev); sx_xunlock(&dev->mode_config.mutex); @@ -321,9 +373,6 @@ static int i915_drm_thaw(struct drm_device *dev) /* Resume the modeset for every activated CRTC */ drm_helper_resume_force_mode(dev); sx_xunlock(&dev->mode_config.mutex); - - if (IS_IRONLAKE_M(dev)) - ironlake_enable_rc6(dev); DRM_LOCK(dev); } @@ -445,7 +494,11 @@ MODULE_DEPEND(i915kms, iicbb, 1, 1, 1); int intel_iommu_enabled = 0; TUNABLE_INT("drm.i915.intel_iommu_enabled", &intel_iommu_enabled); +int intel_iommu_gfx_mapped = 0; +TUNABLE_INT("drm.i915.intel_iommu_gfx_mapped", &intel_iommu_gfx_mapped); +int i915_prefault_disable; +TUNABLE_INT("drm.i915.prefault_disable", &i915_prefault_disable); int i915_semaphores = -1; TUNABLE_INT("drm.i915.semaphores", &i915_semaphores); static int i915_try_reset = 1; @@ -460,10 +513,14 @@ int i915_enable_fbc = 0; TUNABLE_INT("drm.i915.enable_fbc", &i915_enable_fbc); int i915_enable_rc6 = 0; TUNABLE_INT("drm.i915.enable_rc6", &i915_enable_rc6); +int i915_lvds_channel_mode; +TUNABLE_INT("drm.i915.lvds_channel_mode", &i915_lvds_channel_mode); int i915_panel_use_ssc = -1; TUNABLE_INT("drm.i915.panel_use_ssc", &i915_panel_use_ssc); int i915_panel_ignore_lid = 0; TUNABLE_INT("drm.i915.panel_ignore_lid", &i915_panel_ignore_lid); +int i915_panel_invert_brightness; +TUNABLE_INT("drm.i915.panel_invert_brightness", &i915_panel_invert_brightness); int i915_modeset = 1; TUNABLE_INT("drm.i915.modeset", &i915_modeset); int i915_enable_ppgtt = -1; @@ -476,9 +533,9 @@ TUNABLE_INT("drm.i915.enable_hangcheck", &i915_enable_hangcheck); #define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 #define INTEL_PCH_CPT_DEVICE_ID_TYPE 0x1c00 #define INTEL_PCH_PPT_DEVICE_ID_TYPE 0x1e00 +#define INTEL_PCH_LPT_DEVICE_ID_TYPE 0x8c00 -void -intel_detect_pch(struct drm_device *dev) +void intel_detect_pch(struct drm_device *dev) { struct drm_i915_private *dev_priv; device_t pch; @@ -490,20 +547,44 @@ intel_detect_pch(struct drm_device *dev) id = pci_get_device(pch) & INTEL_PCH_DEVICE_ID_MASK; if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) { dev_priv->pch_type = PCH_IBX; + dev_priv->num_pch_pll = 2; DRM_DEBUG_KMS("Found Ibex Peak PCH\n"); } else if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) { dev_priv->pch_type = PCH_CPT; + dev_priv->num_pch_pll = 2; DRM_DEBUG_KMS("Found CougarPoint PCH\n"); } else if (id == INTEL_PCH_PPT_DEVICE_ID_TYPE) { /* PantherPoint is CPT compatible */ dev_priv->pch_type = PCH_CPT; + dev_priv->num_pch_pll = 2; DRM_DEBUG_KMS("Found PatherPoint PCH\n"); + } else if (id == INTEL_PCH_LPT_DEVICE_ID_TYPE) { + dev_priv->pch_type = PCH_LPT; + dev_priv->num_pch_pll = 0; + DRM_DEBUG_KMS("Found LynxPoint PCH\n"); } else DRM_DEBUG_KMS("No PCH detected\n"); + KASSERT(dev_priv->num_pch_pll <= I915_NUM_PLLS, + ("num_pch_pll %d\n", dev_priv->num_pch_pll)); } else DRM_DEBUG_KMS("No Intel PCI-ISA bridge found\n"); } +bool i915_semaphore_is_enabled(struct drm_device *dev) +{ + if (INTEL_INFO(dev)->gen < 6) + return 0; + + if (i915_semaphores >= 0) + return i915_semaphores; + + /* Enable semaphores on SNB when IO remapping is off */ + if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped) + return false; + + return 1; +} + void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) { @@ -530,7 +611,7 @@ __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv) while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_MT_ACK) & 1)) DELAY(10); - I915_WRITE_NOTRACE(FORCEWAKE_MT, (1<<16) | 1); + I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_ENABLE(1)); POSTING_READ(FORCEWAKE_MT); count = 0; @@ -573,7 +654,7 @@ void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv) { - I915_WRITE_NOTRACE(FORCEWAKE_MT, (1<<16) | 0); + I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_DISABLE(1)); /* The below doubles as a POSTING_READ */ gen6_gt_check_fifodbg(dev_priv); } @@ -611,6 +692,31 @@ __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv) return (ret); } +void vlv_force_wake_get(struct drm_i915_private *dev_priv) +{ + int count; + + count = 0; + + /* Already awake? */ + if ((I915_READ(0x130094) & 0xa1) == 0xa1) + return; + + I915_WRITE_NOTRACE(FORCEWAKE_VLV, 0xffffffff); + POSTING_READ(FORCEWAKE_VLV); + + count = 0; + while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & 1) == 0) + DELAY(10); +} + +void vlv_force_wake_put(struct drm_i915_private *dev_priv) +{ + I915_WRITE_NOTRACE(FORCEWAKE_VLV, 0xffff0000); + /* FIXME: confirm VLV behavior with Punit folks */ + POSTING_READ(FORCEWAKE_VLV); +} + static int i8xx_do_reset(struct drm_device *dev) { @@ -653,12 +759,13 @@ i965_reset_complete(struct drm_device *dev) u8 gdrst; gdrst = pci_read_config(dev->device, I965_GDRST, 1); - return (gdrst & 0x1); + return (gdrst & GRDOM_RESET_ENABLE) == 0; } static int i965_do_reset(struct drm_device *dev) { + int ret; u8 gdrst; /* @@ -670,8 +777,16 @@ i965_do_reset(struct drm_device *dev) pci_write_config(dev->device, I965_GDRST, gdrst | GRDOM_RENDER | GRDOM_RESET_ENABLE, 1); - return (_intel_wait_for(dev, i965_reset_complete(dev), 500, 1, - "915rst")); + ret = wait_for(i965_reset_complete(dev), 500); + if (ret) + return ret; + + /* We can't reset render&media without also resetting display ... */ + gdrst = pci_read_config(dev->device, I965_GDRST, 1); + pci_write_config(dev->device, I965_GDRST, + gdrst | GRDOM_MEDIA | GRDOM_RESET_ENABLE, 1); + + return wait_for(i965_reset_complete(dev), 500); } static int @@ -679,14 +794,21 @@ ironlake_do_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv; u32 gdrst; + int ret; dev_priv = dev->dev_private; gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR); I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, - gdrst | GRDOM_RENDER | GRDOM_RESET_ENABLE); - return (_intel_wait_for(dev, - (I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1) != 0, - 500, 1, "915rst")); + gdrst | GRDOM_RENDER | GRDOM_RESET_ENABLE); + ret = wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500); + if (ret) + return ret; + + /* We can't reset render&media without also resetting display ... */ + gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR); + I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, + gdrst | GRDOM_MEDIA | GRDOM_RESET_ENABLE); + return wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500); } static int @@ -713,7 +835,7 @@ gen6_do_reset(struct drm_device *dev) /* Spin waiting for the device to ack the reset request */ ret = _intel_wait_for(dev, (I915_READ_NOTRACE(GEN6_GDRST) & GEN6_GRDOM_FULL) == 0, - 500, 1, "915rst"); + 500, 0, "915rst"); /* If reset with a user forcewake, try to restore, otherwise turn it off */ if (dev_priv->forcewake_count) @@ -728,7 +850,8 @@ gen6_do_reset(struct drm_device *dev) return (ret); } -int intel_gpu_reset(struct drm_device *dev) +int +intel_gpu_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int ret = -ENODEV; @@ -763,15 +886,9 @@ int intel_gpu_reset(struct drm_device *dev) return ret; } -int -i915_reset(struct drm_device *dev) +int i915_reset(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - /* - * We really should only reset the display subsystem if we actually - * need to - */ - bool need_display = true; int ret; if (!i915_try_reset) @@ -780,12 +897,14 @@ i915_reset(struct drm_device *dev) if (!sx_try_xlock(&dev->dev_struct_lock)) return (-EBUSY); + dev_priv->stop_rings = 0; + i915_gem_reset(dev); ret = -ENODEV; - if (time_second - dev_priv->last_gpu_reset < 5) { + if (time_second - dev_priv->last_gpu_reset < 5) DRM_ERROR("GPU hanging too fast, declaring wedged!\n"); - } else + else ret = intel_gpu_reset(dev); dev_priv->last_gpu_reset = time_second; @@ -797,36 +916,41 @@ i915_reset(struct drm_device *dev) if (drm_core_check_feature(dev, DRIVER_MODESET) || !dev_priv->mm.suspended) { + struct intel_ring_buffer *ring; + int i; + dev_priv->mm.suspended = 0; i915_gem_init_swizzling(dev); - dev_priv->rings[RCS].init(&dev_priv->rings[RCS]); - if (HAS_BSD(dev)) - dev_priv->rings[VCS].init(&dev_priv->rings[VCS]); - if (HAS_BLT(dev)) - dev_priv->rings[BCS].init(&dev_priv->rings[BCS]); + for_each_ring(ring, dev_priv, i) + ring->init(ring); i915_gem_context_init(dev); i915_gem_init_ppgtt(dev); + DRM_UNLOCK(dev); + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + intel_modeset_init_hw(dev); + + DRM_LOCK(dev); drm_irq_uninstall(dev); - drm_mode_config_reset(dev); DRM_UNLOCK(dev); drm_irq_install(dev); - DRM_LOCK(dev); - } - DRM_UNLOCK(dev); - - if (need_display) { - sx_xlock(&dev->mode_config.mutex); - drm_helper_resume_force_mode(dev); - sx_xunlock(&dev->mode_config.mutex); - } + } else + DRM_UNLOCK(dev); return (0); } +/* We give fast paths for the really cool registers */ +#define NEEDS_FORCE_WAKE(dev_priv, reg) \ + (((dev_priv)->info->gen >= 6) && \ + ((reg) < 0x40000) && \ + ((reg) != FORCEWAKE)) && \ + (!IS_VALLEYVIEW((dev_priv)->dev)) + #define __i915_read(x, y) \ u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ u##x val = 0; \ diff --git a/sys/dev/drm2/i915/i915_drv.h b/sys/dev/drm2/i915/i915_drv.h index b84f4f39a74d..c5f85d642ee4 100644 --- a/sys/dev/drm2/i915/i915_drv.h +++ b/sys/dev/drm2/i915/i915_drv.h @@ -66,10 +66,31 @@ enum plane { }; #define plane_name(p) ((p) + 'A') -#define I915_GEM_GPU_DOMAINS (~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT)) +enum port { + PORT_A = 0, + PORT_B, + PORT_C, + PORT_D, + PORT_E, + I915_MAX_PORTS +}; +#define port_name(p) ((p) + 'A') + +#define I915_GEM_GPU_DOMAINS (~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT)) + #define for_each_pipe(p) for ((p) = 0; (p) < dev_priv->num_pipe; (p)++) +struct intel_pch_pll { + int refcount; /* count of number of CRTCs sharing this PLL */ + int active; /* count of number of active CRTCs (i.e. DPMS on) */ + bool on; /* is the PLL actually active? Disabled during modeset */ + int pll_reg; + int fp0_reg; + int fp1_reg; +}; +#define I915_NUM_PLLS 2 + /* Interface history: * * 1.1: Original. @@ -115,11 +136,15 @@ struct drm_i915_display_funcs { void (*update_wm)(struct drm_device *dev); void (*update_sprite_wm)(struct drm_device *dev, int pipe, uint32_t sprite_width, int pixel_size); + void (*sanitize_pm)(struct drm_device *dev); + void (*update_linetime_wm)(struct drm_device *dev, int pipe, + struct drm_display_mode *mode); int (*crtc_mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, int x, int y, struct drm_framebuffer *old_fb); + void (*off)(struct drm_crtc *crtc); void (*write_eld)(struct drm_connector *connector, struct drm_crtc *crtc); void (*fdi_link_train)(struct drm_crtc *crtc); @@ -152,6 +177,9 @@ struct intel_device_info { u8 is_broadwater:1; u8 is_crestline:1; u8 is_ivybridge:1; + u8 is_valleyview:1; + u8 has_pch_split:1; + u8 is_haswell:1; u8 has_fbc:1; u8 has_pipe_cxsr:1; u8 has_hotplug:1; @@ -227,7 +255,6 @@ struct intel_opregion { struct drm_i915_fence_reg { struct list_head lru_list; struct drm_i915_gem_object *obj; - uint32_t setup_seqno; int pin_count; }; @@ -243,10 +270,12 @@ struct sdvo_device_mapping { enum intel_pch { PCH_IBX, /* Ibexpeak PCH */ PCH_CPT, /* Cougarpoint PCH */ + PCH_LPT, /* Lynxpoint PCH */ }; #define QUIRK_PIPEA_FORCE (1<<0) #define QUIRK_LVDS_SSC_DISABLE (1<<1) +#define QUIRK_INVERT_BRIGHTNESS (1<<2) struct intel_fbdev; struct intel_fbc_work; @@ -254,15 +283,15 @@ struct intel_fbc_work; typedef struct drm_i915_private { struct drm_device *dev; - device_t *gmbus_bridge; - device_t *bbbus_bridge; - device_t *gmbus; - device_t *bbbus; + device_t gmbus_bridge[GMBUS_NUM_PORTS + 1]; + device_t bbbus_bridge[GMBUS_NUM_PORTS + 1]; + device_t gmbus[GMBUS_NUM_PORTS + 1]; + device_t bbbus[GMBUS_NUM_PORTS + 1]; /** gmbus_sx protects against concurrent usage of the single hw gmbus * controller on different i2c buses. */ struct sx gmbus_sx; + uint32_t gpio_mmio_base; - int has_gem; int relative_constants_mode; drm_local_map_t *sarea; @@ -286,7 +315,6 @@ typedef struct drm_i915_private { dma_addr_t dma_status_page; uint32_t counter; unsigned int status_gfx_addr; - drm_local_map_t hws_map; struct drm_gem_object *hws_obj; struct drm_i915_gem_object *pwrctx; @@ -308,23 +336,23 @@ typedef struct drm_i915_private { u32 pch_irq_mask; struct mtx irq_lock; + struct mtx dpio_lock; + u32 hotplug_supported_mask; - int tex_lru_log_granularity; - int allow_batchbuffer; unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; - int vblank_pipe; int num_pipe; + int num_pch_pll; /* For hangcheck timer */ #define DRM_I915_HANGCHECK_PERIOD ((1500 /* in ms */ * hz) / 1000) int hangcheck_count; - uint32_t last_acthd; - uint32_t last_acthd_bsd; - uint32_t last_acthd_blt; + uint32_t last_acthd[I915_NUM_RINGS]; uint32_t last_instdone; uint32_t last_instdone1; + unsigned int stop_rings; + struct intel_opregion opregion; @@ -346,6 +374,8 @@ typedef struct drm_i915_private { unsigned int lvds_use_ssc:1; unsigned int display_clock_mode:1; int lvds_ssc_freq; + unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */ + unsigned int lvds_val; /* used for checking LVDS channel mode */ struct { int rate; int lanes; @@ -575,23 +605,9 @@ typedef struct drm_i915_private { */ struct list_head inactive_list; - /** - * LRU list of objects which are not in the ringbuffer but - * are still pinned in the GTT. - */ - struct list_head pinned_list; - /** LRU list of objects with fence regs on them. */ struct list_head fence_list; - /** - * List of objects currently pending being freed. - * - * These objects are no longer in use, but due to a signal - * we were prevented from freeing them at the appointed time. - */ - struct list_head deferred_free_list; - /** * We leave the user IRQ off as much as possible, * but this means that requests will finish and never @@ -658,6 +674,15 @@ typedef struct drm_i915_private { const struct intel_device_info *info; + /* Old dri1 support infrastructure, beware the dragons ya fools entering + * here! */ + struct { + unsigned allow_batchbuffer : 1; + u32 *gfx_hws_cpu_addr; + } dri1; + + /* Kernel Modesetting */ + struct sdvo_device_mapping sdvo_mappings[2]; /* indicate whether the LVDS_BORDER should be enabled or not */ unsigned int lvds_border_bits; @@ -667,7 +692,8 @@ typedef struct drm_i915_private { struct drm_crtc *plane_to_crtc_mapping[3]; struct drm_crtc *pipe_to_crtc_mapping[3]; /* wait_queue_head_t pending_flip_queue; XXXKIB */ - bool flip_pending_is_done; + + struct intel_pch_pll pch_plls[I915_NUM_PLLS]; /* Reclocking support */ bool render_reclock_avail; @@ -711,7 +737,8 @@ typedef struct drm_i915_private { enum no_fbc_reason no_fbc_reason; - unsigned int stop_rings; + struct drm_mm_node *compressed_fb; + struct drm_mm_node *compressed_llb; unsigned long cfb_size; unsigned int cfb_fb; @@ -726,6 +753,7 @@ typedef struct drm_i915_private { struct task hotplug_task; int error_completion; struct mtx error_completion_lock; + /* Protected by dev->error_lock. */ struct drm_i915_error_state *first_error; struct mtx error_lock; struct callout hangcheck_timer; @@ -816,7 +844,14 @@ struct drm_i915_gem_object { * Current tiling mode for the object. */ unsigned int tiling_mode:2; - unsigned int tiling_changed:1; + /** + * Whether the tiling parameters for the currently associated fence + * register have changed. Note that for the purposes of tracking + * tiling changes we also treat the unfenced register, the register + * slot that the object occupies whilst it executes a fenced + * command (such as BLT on gen2/3), as a "fence". + */ + unsigned int fence_dirty:1; /** How many users have pinned this object in GTT space. The following * users can each hold at most one reference: pwrite/pread, pin_ioctl @@ -843,6 +878,7 @@ struct drm_i915_gem_object { */ unsigned int fault_mappable:1; unsigned int pin_mappable:1; + unsigned int pin_display:1; /* * Is the GPU currently using a fence to access this buffer, @@ -856,6 +892,7 @@ struct drm_i915_gem_object { unsigned int has_global_gtt_mapping:1; vm_page_t *pages; + int pages_pin_count; /** * DMAR support @@ -876,13 +913,12 @@ struct drm_i915_gem_object { */ uint32_t gtt_offset; - /** Breadcrumb of last rendering to the buffer. */ - uint32_t last_rendering_seqno; struct intel_ring_buffer *ring; + /** Breadcrumb of last rendering to the buffer. */ + uint32_t last_rendering_seqno; /** Breadcrumb of last fenced GPU access to the buffer. */ uint32_t last_fenced_seqno; - struct intel_ring_buffer *last_fenced_ring; /** Current tiling stride for the object, if it's tiled. */ uint32_t stride; @@ -890,12 +926,6 @@ struct drm_i915_gem_object { /** Record of address bit 17 of each page at last unbind. */ unsigned long *bit_17; - /** - * If present, while GEM_DOMAIN_CPU is in the read domain this array - * flags which individual pages are valid. - */ - uint8_t *page_cpu_valid; - /** User space pin count and filp owning the pin */ uint32_t user_pin_count; struct drm_file *pin_filp; @@ -953,8 +983,11 @@ struct drm_i915_file_private { }; struct drm_i915_error_state { + u_int ref; u32 eir; u32 pgtbl_er; + u32 ier; + bool waiting[I915_NUM_RINGS]; u32 pipestat[I915_MAX_PIPES]; u32 tail[I915_NUM_RINGS]; u32 head[I915_NUM_RINGS]; @@ -1037,9 +1070,12 @@ extern struct drm_driver_info i915_driver_info; extern struct cdev_pager_ops i915_gem_pager_ops; extern unsigned int i915_fbpercrtc; extern int i915_panel_ignore_lid; +extern int i915_panel_invert_brightness; extern unsigned int i915_powersave; +extern int i915_prefault_disable; extern int i915_semaphores; extern unsigned int i915_lvds_downclock; +extern int i915_lvds_channel_mode; extern int i915_panel_use_ssc; extern int i915_vbt_sdvo_panel_type; extern int i915_enable_rc6; @@ -1049,8 +1085,8 @@ extern int i915_enable_hangcheck; const struct intel_device_info *i915_get_device_id(int device); -extern int intel_gpu_reset(struct drm_device *dev); int i915_reset(struct drm_device *dev); +extern int intel_gpu_reset(struct drm_device *dev); /* i915_debug.c */ int i915_sysctl_init(struct drm_device *dev, struct sysctl_ctx_list *ctx, @@ -1064,6 +1100,7 @@ int i915_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv); int i915_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv); +void i915_update_dri1_breadcrumb(struct drm_device *dev); extern void i915_kernel_lost_context(struct drm_device * dev); extern int i915_driver_load(struct drm_device *, unsigned long flags); extern int i915_driver_unload(struct drm_device *); @@ -1095,20 +1132,12 @@ bool i915_gpu_turbo_disable(void); /* i915_irq.c */ extern int i915_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int i915_irq_wait(struct drm_device *dev, void *data, - struct drm_file *file_priv); - extern void intel_irq_init(struct drm_device *dev); -extern int i915_vblank_pipe_set(struct drm_device *dev, void *data, - struct drm_file *file_priv); -extern int i915_vblank_pipe_get(struct drm_device *dev, void *data, - struct drm_file *file_priv); -extern int i915_vblank_swap(struct drm_device *dev, void *data, - struct drm_file *file_priv); void intel_enable_asle(struct drm_device *dev); void i915_hangcheck_elapsed(void *context); void i915_handle_error(struct drm_device *dev, bool wedged); +void i915_error_state_free(struct drm_i915_error_state *error); void i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask); void i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask); @@ -1169,13 +1198,15 @@ int i915_gem_object_unbind(struct drm_i915_gem_object *obj); void i915_gem_lastclose(struct drm_device *dev); uint32_t i915_get_gem_seqno(struct drm_device *dev); -static inline void +static inline bool i915_gem_object_pin_fence(struct drm_i915_gem_object *obj) { if (obj->fence_reg != I915_FENCE_REG_NONE) { struct drm_i915_private *dev_priv = obj->base.dev->dev_private; dev_priv->fence_regs[obj->fence_reg].pin_count++; - } + return true; + } else + return false; } static inline void @@ -1192,36 +1223,38 @@ void i915_gem_retire_requests_ring(struct intel_ring_buffer *ring); void i915_gem_clflush_object(struct drm_i915_gem_object *obj); struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev, size_t size); -int i915_gem_do_init(struct drm_device *dev, unsigned long start, - unsigned long mappable_end, unsigned long end); uint32_t i915_gem_get_unfenced_gtt_alignment(struct drm_device *dev, uint32_t size, int tiling_mode); int i915_mutex_lock_interruptible(struct drm_device *dev); int i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write); +int i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, + bool write); int i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, u32 alignment, struct intel_ring_buffer *pipelined); +void i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj); int i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj); int i915_gem_flush_ring(struct intel_ring_buffer *ring, uint32_t invalidate_domains, uint32_t flush_domains); void i915_gem_release_mmap(struct drm_i915_gem_object *obj); int i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj); +int i915_gem_object_sync(struct drm_i915_gem_object *obj, + struct intel_ring_buffer *to); int i915_gem_object_put_fence(struct drm_i915_gem_object *obj); int i915_gem_idle(struct drm_device *dev); +int i915_gem_init(struct drm_device *dev); int i915_gem_init_hw(struct drm_device *dev); void i915_gem_init_swizzling(struct drm_device *dev); void i915_gem_init_ppgtt(struct drm_device *dev); void i915_gem_cleanup_ringbuffer(struct drm_device *dev); -int i915_gpu_idle(struct drm_device *dev, bool do_retire); +int i915_gpu_idle(struct drm_device *dev); void i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, struct intel_ring_buffer *ring, uint32_t seqno); int i915_add_request(struct intel_ring_buffer *ring, struct drm_file *file, struct drm_i915_gem_request *request); -int i915_gem_object_get_fence(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *pipelined); +int i915_gem_object_get_fence(struct drm_i915_gem_object *obj); void i915_gem_reset(struct drm_device *dev); -int i915_wait_request(struct intel_ring_buffer *ring, uint32_t seqno, - bool do_retire); +int i915_wait_request(struct intel_ring_buffer *ring, uint32_t seqno); int i915_gem_mmap(struct drm_device *dev, uint64_t offset, int prot); int i915_gem_fault(struct drm_device *dev, uint64_t offset, int prot, uint64_t *phys); @@ -1257,12 +1290,17 @@ int i915_gem_dumb_destroy(struct drm_file *file_priv, struct drm_device *dev, void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj); void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj); +void i915_gem_object_do_bit_17_swizzle_page(struct drm_i915_gem_object *obj, + struct vm_page *m); /* i915_gem_evict.c */ int i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignment, bool mappable); int i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only); -int i915_gem_evict_inactive(struct drm_device *dev, bool purgeable_only); + +/* i915_gem_stolen.c */ +int i915_gem_init_stolen(struct drm_device *dev); +void i915_gem_cleanup_stolen(struct drm_device *dev); /* i915_suspend.c */ extern int i915_save_state(struct drm_device *dev); @@ -1274,6 +1312,12 @@ extern void intel_teardown_gmbus(struct drm_device *dev); extern void intel_gmbus_set_speed(device_t idev, int speed); extern void intel_gmbus_force_bit(device_t idev, bool force_bit); extern void intel_iic_reset(struct drm_device *dev); +static inline bool intel_gmbus_is_port_valid(unsigned port) +{ + return (port >= GMBUS_PORT_SSC && port <= GMBUS_PORT_DPD); +} +extern device_t intel_gmbus_get_adapter(struct drm_i915_private *dev_priv, + unsigned port); /* intel_opregion.c */ int intel_opregion_setup(struct drm_device *dev); @@ -1292,12 +1336,16 @@ void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt, struct drm_i915_gem_object *obj); void i915_gem_restore_gtt_mappings(struct drm_device *dev); -int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj); +int i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj); +void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj, + enum i915_cache_level cache_level); void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj); -void i915_gem_gtt_rebind_object(struct drm_i915_gem_object *obj, - enum i915_cache_level cache_level); +void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj); +int i915_gem_init_global_gtt(struct drm_device *dev, unsigned long start, + unsigned long mappable_end, unsigned long end); /* modesetting */ +extern void intel_modeset_init_hw(struct drm_device *dev); extern void intel_modeset_init(struct drm_device *dev); extern void intel_modeset_gem_init(struct drm_device *dev); extern void intel_modeset_cleanup(struct drm_device *dev); @@ -1310,12 +1358,19 @@ extern void ironlake_enable_rc6(struct drm_device *dev); extern void gen6_set_rps(struct drm_device *dev, u8 val); extern void intel_detect_pch(struct drm_device *dev); extern int intel_trans_dp_port_sel(struct drm_crtc *crtc); +/* IPS */ +extern void intel_gpu_ips_init(struct drm_i915_private *dev_priv); +extern void intel_gpu_ips_teardown(void); +extern bool i915_semaphore_is_enabled(struct drm_device *dev); extern void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv); extern void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv); extern void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv); extern void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv); +extern void vlv_force_wake_get(struct drm_i915_private *dev_priv); +extern void vlv_force_wake_put(struct drm_i915_private *dev_priv); + extern struct intel_overlay_error_state *intel_overlay_capture_error_state( struct drm_device *dev); extern void intel_overlay_print_error_state(struct sbuf *m, @@ -1340,12 +1395,6 @@ void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv); void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv); int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv); -/* We give fast paths for the really cool registers */ -#define NEEDS_FORCE_WAKE(dev_priv, reg) \ - (((dev_priv)->info->gen >= 6) && \ - ((reg) < 0x40000) && \ - ((reg) != FORCEWAKE)) - #define __i915_read(x, y) \ u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg); @@ -1385,22 +1434,6 @@ __i915_write(64, 64) #define I915_VERBOSE 0 -#define LP_RING(d) (&((struct drm_i915_private *)(d))->rings[RCS]) - -#define BEGIN_LP_RING(n) \ - intel_ring_begin(LP_RING(dev_priv), (n)) - -#define OUT_RING(x) \ - intel_ring_emit(LP_RING(dev_priv), x) - -#define ADVANCE_LP_RING() \ - intel_ring_advance(LP_RING(dev_priv)) - -#define RING_LOCK_TEST_WITH_RETURN(dev, file) do { \ - if (LP_RING(dev->dev_private)->obj == NULL) \ - LOCK_TEST_WITH_RETURN(dev, file); \ -} while (0) - /** * Reads a dword out of the status page, which is written to from the command * queue by automatic updates, MI_REPORT_HEAD, MI_STORE_DATA_INDEX, or @@ -1416,10 +1449,7 @@ __i915_write(64, 64) * * The area from dword 0x20 to 0x3ff is available for driver usage. */ -#define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hw_status_page))[reg]) -#define READ_BREADCRUMB(dev_priv) READ_HWSP(dev_priv, I915_BREADCRUMB_INDEX) #define I915_GEM_HWS_INDEX 0x20 -#define I915_BREADCRUMB_INDEX 0x21 #define INTEL_INFO(dev) (((struct drm_i915_private *) (dev)->dev_private)->info) @@ -1442,6 +1472,8 @@ __i915_write(64, 64) #define IS_IRONLAKE_D(dev) ((dev)->pci_device == 0x0042) #define IS_IRONLAKE_M(dev) ((dev)->pci_device == 0x0046) #define IS_IVYBRIDGE(dev) (INTEL_INFO(dev)->is_ivybridge) +#define IS_VALLEYVIEW(dev) (INTEL_INFO(dev)->is_valleyview) +#define IS_HASWELL(dev) (INTEL_INFO(dev)->is_haswell) #define IS_MOBILE(dev) (INTEL_INFO(dev)->is_mobile) /* XXXKIB LEGACY */ @@ -1503,10 +1535,11 @@ __i915_write(64, 64) #define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr) #define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc) -#define HAS_PCH_SPLIT(dev) (IS_GEN5(dev) || IS_GEN6(dev) || IS_IVYBRIDGE(dev)) +#define HAS_PCH_SPLIT(dev) (INTEL_INFO(dev)->has_pch_split) #define HAS_PIPE_CONTROL(dev) (INTEL_INFO(dev)->gen >= 5) #define INTEL_PCH_TYPE(dev) (((struct drm_i915_private *)(dev)->dev_private)->pch_type) +#define HAS_PCH_LPT(dev) (INTEL_PCH_TYPE(dev) == PCH_LPT) #define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT) #define HAS_PCH_IBX(dev) (INTEL_PCH_TYPE(dev) == PCH_IBX) @@ -1519,6 +1552,23 @@ i915_seqno_passed(uint32_t seq1, uint32_t seq2) return ((int32_t)(seq1 - seq2) >= 0); } +static inline void i915_gem_chipset_flush(struct drm_device *dev) +{ + if (INTEL_INFO(dev)->gen < 6) + intel_gtt_chipset_flush(); +} + +static inline void i915_gem_object_pin_pages(struct drm_i915_gem_object *obj) +{ + /* KASSERT(obj->pages != NULL, ("pin and NULL pages")); */ + obj->pages_pin_count++; +} +static inline void i915_gem_object_unpin_pages(struct drm_i915_gem_object *obj) +{ + KASSERT(obj->pages_pin_count != 0, ("zero pages_pin_count")); + obj->pages_pin_count--; +} + u32 i915_gem_next_request_seqno(struct intel_ring_buffer *ring); #endif diff --git a/sys/dev/drm2/i915/i915_gem.c b/sys/dev/drm2/i915/i915_gem.c index 45e770d30f3e..cf346fc9a146 100644 --- a/sys/dev/drm2/i915/i915_gem.c +++ b/sys/dev/drm2/i915/i915_gem.c @@ -67,6 +67,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include + static void i915_gem_object_flush_cpu_write_domain( struct drm_i915_gem_object *obj); static uint32_t i915_gem_get_gtt_size(struct drm_device *dev, uint32_t size, @@ -78,32 +80,57 @@ static int i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, static int i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj, int flags); static void i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj); -static int i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, - bool write); -static void i915_gem_object_set_to_full_cpu_read_domain( - struct drm_i915_gem_object *obj); -static int i915_gem_object_set_cpu_read_domain_range( - struct drm_i915_gem_object *obj, uint64_t offset, uint64_t size); +static void i915_gem_object_put_pages_range(struct drm_i915_gem_object *obj, + off_t start, off_t end); +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_finish_gtt(struct drm_i915_gem_object *obj); static void i915_gem_object_truncate(struct drm_i915_gem_object *obj); static int i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj); static bool i915_gem_object_is_inactive(struct drm_i915_gem_object *obj); static int i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj); -static vm_page_t i915_gem_wire_page(vm_object_t object, vm_pindex_t pindex); +static vm_page_t i915_gem_wire_page(vm_object_t object, vm_pindex_t pindex, + bool *fresh); static void i915_gem_process_flushing_list(struct intel_ring_buffer *ring, uint32_t flush_domains); -static void i915_gem_clear_fence_reg(struct drm_device *dev, - struct drm_i915_fence_reg *reg); static void i915_gem_reset_fences(struct drm_device *dev); static void i915_gem_retire_task_handler(void *arg, int pending); -static int i915_gem_phys_pwrite(struct drm_device *dev, - struct drm_i915_gem_object *obj, uint64_t data_ptr, uint64_t offset, - uint64_t size, struct drm_file *file_priv); static void i915_gem_lowmem(void *arg); +static void i915_gem_write_fence(struct drm_device *dev, int reg, + struct drm_i915_gem_object *obj); +static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, + bool interruptible); +static int i915_gem_check_olr(struct intel_ring_buffer *ring, u32 seqno); 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; +} + static void i915_gem_info_add_obj(struct drm_i915_private *dev_priv, size_t size) { @@ -172,50 +199,42 @@ i915_mutex_lock_interruptible(struct drm_device *dev) } -static void -i915_gem_free_object_tail(struct drm_i915_gem_object *obj) +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; drm_i915_private_t *dev_priv; - int ret; dev = obj->base.dev; dev_priv = dev->dev_private; - ret = i915_gem_object_unbind(obj); - if (ret == -ERESTART) { - list_move(&obj->mm_list, &dev_priv->mm.deferred_free_list); - return; + 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; } - CTR1(KTR_DRM, "object_destroy_tail %p", obj); 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->page_cpu_valid, DRM_I915_GEM); free(obj->bit_17, DRM_I915_GEM); free(obj, DRM_I915_GEM); } -void -i915_gem_free_object(struct drm_gem_object *gem_obj) -{ - struct drm_i915_gem_object *obj; - struct drm_device *dev; - - obj = to_intel_bo(gem_obj); - dev = obj->base.dev; - - while (obj->pin_count > 0) - i915_gem_object_unpin(obj); - - if (obj->phys_obj != NULL) - i915_gem_detach_phys_object(dev, obj); - - i915_gem_free_object_tail(obj); -} - static void init_ring_lists(struct intel_ring_buffer *ring) { @@ -236,9 +255,7 @@ i915_gem_load(struct drm_device *dev) 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.pinned_list); INIT_LIST_HEAD(&dev_priv->mm.fence_list); - INIT_LIST_HEAD(&dev_priv->mm.deferred_free_list); INIT_LIST_HEAD(&dev_priv->mm.gtt_list); for (i = 0; i < I915_NUM_RINGS; i++) init_ring_lists(&dev_priv->rings[i]); @@ -250,16 +267,8 @@ i915_gem_load(struct drm_device *dev) /* On GEN3 we really need to make sure the ARB C3 LP bit is set */ if (IS_GEN3(dev)) { - u32 tmp = I915_READ(MI_ARB_STATE); - if (!(tmp & MI_ARB_C3_LP_WRITE_ENABLE)) { - /* - * arb state is a masked write, so set bit + - * bit in mask. - */ - tmp = MI_ARB_C3_LP_WRITE_ENABLE | - (MI_ARB_C3_LP_WRITE_ENABLE << MI_ARB_MASK_SHIFT); - I915_WRITE(MI_ARB_STATE, tmp); - } + I915_WRITE(MI_ARB_STATE, + _MASKED_BIT_ENABLE(MI_ARB_C3_LP_WRITE_ENABLE)); } dev_priv->relative_constants_mode = I915_EXEC_CONSTANTS_REL_GENERAL; @@ -275,9 +284,8 @@ i915_gem_load(struct drm_device *dev) dev_priv->num_fence_regs = 8; /* Initialize fence registers to zero */ - for (i = 0; i < dev_priv->num_fence_regs; i++) { - i915_gem_clear_fence_reg(dev, &dev_priv->fence_regs[i]); - } + i915_gem_reset_fences(dev); + i915_gem_detect_bit_6_swizzle(dev); dev_priv->mm.interruptible = true; @@ -285,35 +293,6 @@ i915_gem_load(struct drm_device *dev) i915_gem_lowmem, dev, EVENTHANDLER_PRI_ANY); } -int -i915_gem_do_init(struct drm_device *dev, unsigned long start, - unsigned long mappable_end, unsigned long end) -{ - drm_i915_private_t *dev_priv; - unsigned long mappable; - int error; - - dev_priv = dev->dev_private; - mappable = min(end, mappable_end) - start; - - drm_mm_init(&dev_priv->mm.gtt_space, start, end - start); - - dev_priv->mm.gtt_start = start; - dev_priv->mm.gtt_mappable_end = mappable_end; - dev_priv->mm.gtt_end = end; - dev_priv->mm.gtt_total = end - start; - dev_priv->mm.mappable_gtt_total = mappable; - - /* Take over this portion of the GTT */ - intel_gtt_clear_range(start / PAGE_SIZE, (end-start) / PAGE_SIZE); - device_printf(dev->device, - "taking over the fictitious range 0x%lx-0x%lx\n", - dev->agp->base + start, dev->agp->base + start + mappable); - error = -vm_phys_fictitious_reg_range(dev->agp->base + start, - dev->agp->base + start + mappable, VM_MEMATTR_WRITE_COMBINING); - return (error); -} - int i915_gem_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file) @@ -321,6 +300,9 @@ i915_gem_init_ioctl(struct drm_device *dev, void *data, struct drm_i915_gem_init *args; drm_i915_private_t *dev_priv; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -ENODEV; + dev_priv = dev->dev_private; args = data; @@ -330,11 +312,16 @@ i915_gem_init_ioctl(struct drm_device *dev, void *data, 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. */ - return (i915_gem_do_init(dev, args->gtt_start, args->gtt_end, + return (i915_gem_init_global_gtt(dev, args->gtt_start, args->gtt_end, args->gtt_end)); } @@ -348,13 +335,14 @@ i915_gem_idle(struct drm_device *dev) if (dev_priv->mm.suspended) return (0); - ret = i915_gpu_idle(dev, true); + ret = i915_gpu_idle(dev); if (ret != 0) 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_inactive(dev, false); + ret = i915_gem_evict_everything(dev, false); if (ret != 0) return ret; } @@ -393,15 +381,15 @@ i915_gem_init_swizzling(struct drm_device *dev) if (IS_GEN5(dev)) return; + I915_WRITE(TILECTL, I915_READ(TILECTL) | TILECTL_SWZCTL); if (IS_GEN6(dev)) - I915_WRITE(ARB_MODE, ARB_MODE_ENABLE(ARB_MODE_SWIZZLE_SNB)); + I915_WRITE(ARB_MODE, _MASKED_BIT_ENABLE(ARB_MODE_SWIZZLE_SNB)); else - I915_WRITE(ARB_MODE, ARB_MODE_ENABLE(ARB_MODE_SWIZZLE_IVB)); + I915_WRITE(ARB_MODE, _MASKED_BIT_ENABLE(ARB_MODE_SWIZZLE_IVB)); } -void -i915_gem_init_ppgtt(struct drm_device *dev) +void i915_gem_init_ppgtt(struct drm_device *dev) { drm_i915_private_t *dev_priv; struct i915_hw_ppgtt *ppgtt; @@ -429,21 +417,27 @@ i915_gem_init_ppgtt(struct drm_device *dev) pd_offset <<= 16; if (INTEL_INFO(dev)->gen == 6) { - uint32_t ecochk = I915_READ(GAM_ECOCHK); + uint32_t ecochk, gab_ctl, ecobits; + + ecobits = I915_READ(GAC_ECO_BITS); + I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_PPGTT_CACHE64B); + + gab_ctl = I915_READ(GAB_CTL); + I915_WRITE(GAB_CTL, gab_ctl | GAB_CTL_CONT_AFTER_PAGEFAULT); + + ecochk = I915_READ(GAM_ECOCHK); I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT | ECOCHK_PPGTT_CACHE64B); - I915_WRITE(GFX_MODE, GFX_MODE_ENABLE(GFX_PPGTT_ENABLE)); + I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); } else if (INTEL_INFO(dev)->gen >= 7) { I915_WRITE(GAM_ECOCHK, ECOCHK_PPGTT_CACHE64B); /* GFX_MODE is per-ring on gen7+ */ } - for (i = 0; i < I915_NUM_RINGS; i++) { - ring = &dev_priv->rings[i]; - + for_each_ring(ring, dev_priv, i) { if (INTEL_INFO(dev)->gen >= 7) I915_WRITE(RING_MODE_GEN7(ring), - GFX_MODE_ENABLE(GFX_PPGTT_ENABLE)); + _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G); I915_WRITE(RING_PP_DIR_BASE(ring), pd_offset); @@ -488,6 +482,69 @@ i915_gem_init_hw(struct drm_device *dev) 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 != 0) { + 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; +} + int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, struct drm_file *file) @@ -500,13 +557,11 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, dev_priv = dev->dev_private; args = data; - if (!(dev->driver->driver_features & DRIVER_GEM)) - return (-ENODEV); - pinned = 0; DRM_LOCK(dev); - list_for_each_entry(obj, &dev_priv->mm.pinned_list, mm_list) - pinned += obj->gtt_space->size; + 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; @@ -519,15 +574,10 @@ int i915_gem_object_pin(struct drm_i915_gem_object *obj, uint32_t alignment, bool map_and_fenceable) { - struct drm_device *dev; - struct drm_i915_private *dev_priv; int ret; - dev = obj->base.dev; - dev_priv = dev->dev_private; - - KASSERT(obj->pin_count != DRM_I915_GEM_OBJECT_MAX_PIN_COUNT, - ("Max pin count")); + 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)) || @@ -551,47 +601,24 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj, uint32_t alignment, return (ret); } - if (obj->pin_count++ == 0 && !obj->active) - list_move_tail(&obj->mm_list, &dev_priv->mm.pinned_list); + 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; -#if 1 - KIB_NOTYET(); -#else - WARN_ON(i915_verify_lists(dev)); -#endif - return (0); + return 0; } void i915_gem_object_unpin(struct drm_i915_gem_object *obj) { - struct drm_device *dev; - drm_i915_private_t *dev_priv; - - dev = obj->base.dev; - dev_priv = dev->dev_private; - -#if 1 - KIB_NOTYET(); -#else - WARN_ON(i915_verify_lists(dev)); -#endif KASSERT(obj->pin_count != 0, ("zero pin count")); KASSERT(obj->gtt_space != NULL, ("No gtt mapping")); - if (--obj->pin_count == 0) { - if (!obj->active) - list_move_tail(&obj->mm_list, - &dev_priv->mm.inactive_list); + if (--obj->pin_count == 0) obj->pin_mappable = false; - } -#if 1 - KIB_NOTYET(); -#else - WARN_ON(i915_verify_lists(dev)); -#endif } int @@ -693,7 +720,6 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, { struct drm_i915_gem_busy *args; struct drm_i915_gem_object *obj; - struct drm_i915_gem_request *request; int ret; args = data; @@ -713,13 +739,9 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) { ret = i915_gem_flush_ring(obj->ring, 0, obj->base.write_domain); - } else if (obj->ring->outstanding_lazy_request == - obj->last_rendering_seqno) { - request = malloc(sizeof(*request), DRM_I915_GEM, - M_WAITOK | M_ZERO); - ret = i915_add_request(obj->ring, NULL, request); - if (ret != 0) - free(request, DRM_I915_GEM); + } else { + ret = i915_gem_check_olr(obj->ring, + obj->last_rendering_seqno); } i915_gem_retire_requests_ring(obj->ring); @@ -763,26 +785,7 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) if (seqno == 0) return (0); - ret = 0; - mtx_lock(&ring->irq_lock); - if (!i915_seqno_passed(ring->get_seqno(ring), seqno)) { - if (ring->irq_get(ring)) { - while (ret == 0 && - !(i915_seqno_passed(ring->get_seqno(ring), seqno) || - atomic_load_acq_int(&dev_priv->mm.wedged))) - ret = -msleep(ring, &ring->irq_lock, PCATCH, - "915thr", 0); - ring->irq_put(ring); - if (ret == 0 && atomic_load_acq_int(&dev_priv->mm.wedged)) - ret = -EIO; - } else if (_intel_wait_for(dev, - i915_seqno_passed(ring->get_seqno(ring), seqno) || - atomic_load_acq_int(&dev_priv->mm.wedged), 3000, 0, "915rtr")) { - ret = -EBUSY; - } - } - mtx_unlock(&ring->irq_lock); - + ret = __wait_seqno(ring, seqno, true); if (ret == 0) taskqueue_enqueue_timeout(dev_priv->tq, &dev_priv->mm.retire_task, 0); @@ -847,11 +850,12 @@ void i915_gem_cleanup_ringbuffer(struct drm_device *dev) { drm_i915_private_t *dev_priv; + struct intel_ring_buffer *ring; int i; dev_priv = dev->dev_private; - for (i = 0; i < I915_NUM_RINGS; i++) - intel_cleanup_ring_buffer(&dev_priv->rings[i]); + for_each_ring(ring, dev_priv, i) + intel_cleanup_ring_buffer(ring); } int @@ -859,7 +863,7 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_i915_private_t *dev_priv; - int ret, i; + int ret; if (drm_core_check_feature(dev, DRIVER_MODESET)) return (0); @@ -879,13 +883,6 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, 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")); - for (i = 0; i < I915_NUM_RINGS; i++) { - KASSERT(list_empty(&dev_priv->rings[i].active_list), - ("ring %d active list", i)); - KASSERT(list_empty(&dev_priv->rings[i].request_list), - ("ring %d request list", i)); - } - DRM_UNLOCK(dev); ret = drm_irq_install(dev); DRM_LOCK(dev); @@ -973,215 +970,810 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data, return (i915_gem_create(file, dev, args->size, &args->handle)); } -static int -i915_gem_swap_io(struct drm_device *dev, struct drm_i915_gem_object *obj, - uint64_t data_ptr, uint64_t size, uint64_t offset, enum uio_rw rw, - struct drm_file *file) +#define __user +#define __force +#define __iomem +#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 inline long +__copy_to_user(void __user *to, const void *from, unsigned long n) +{ + return (copyout(from, to, n) != 0 ? n : 0); +} +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(void *to, const void __user *from, unsigned long n) +{ + return ((copyin(__DECONST(void *, from), to, n) != 0 ? n : 0)); +} +#define copy_from_user(to, from, n) __copy_from_user((to), (from), (n)) +static inline unsigned long +__copy_from_user_inatomic_nocache(void *to, const void __user *from, + unsigned long n) { - vm_object_t vm_obj; - vm_page_t m; - struct sf_buf *sf; - vm_offset_t mkva; - vm_pindex_t obj_pi; - int cnt, do_bit17_swizzling, length, obj_po, ret, swizzled_po; - if (obj->gtt_offset != 0 && rw == UIO_READ) - do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); - else - do_bit17_swizzling = 0; + /* + * 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; - obj->dirty = 1; - vm_obj = obj->base.vm_obj; - ret = 0; - - VM_OBJECT_WLOCK(vm_obj); - vm_object_pip_add(vm_obj, 1); - while (size > 0) { - obj_pi = OFF_TO_IDX(offset); - obj_po = offset & PAGE_MASK; - - m = i915_gem_wire_page(vm_obj, obj_pi); - VM_OBJECT_WUNLOCK(vm_obj); - - sched_pin(); - sf = sf_buf_alloc(m, SFB_CPUPRIVATE); - mkva = sf_buf_kva(sf); - length = min(size, PAGE_SIZE - obj_po); - while (length > 0) { - if (do_bit17_swizzling && - (VM_PAGE_TO_PHYS(m) & (1 << 17)) != 0) { - cnt = roundup2(obj_po + 1, 64); - cnt = min(cnt - obj_po, length); - swizzled_po = obj_po ^ 64; - } else { - cnt = length; - swizzled_po = obj_po; - } - if (rw == UIO_READ) - ret = -copyout_nofault( - (char *)mkva + swizzled_po, - (void *)(uintptr_t)data_ptr, cnt); - else - ret = -copyin_nofault( - (void *)(uintptr_t)data_ptr, - (char *)mkva + swizzled_po, cnt); - if (ret != 0) - break; - data_ptr += cnt; - size -= cnt; - length -= cnt; - offset += cnt; - obj_po += cnt; - } - sf_buf_free(sf); - sched_unpin(); - VM_OBJECT_WLOCK(vm_obj); - if (rw == UIO_WRITE) - vm_page_dirty(m); - vm_page_reference(m); - vm_page_lock(m); - vm_page_unwire(m, PQ_ACTIVE); - vm_page_unlock(m); - atomic_add_long(&i915_gem_wired_pages_cnt, -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; +} + +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; +} + +/* 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); } - vm_object_pip_wakeup(vm_obj); - VM_OBJECT_WUNLOCK(vm_obj); - return (ret); +out: + i915_gem_object_unpin_pages(obj); + i915_gem_object_put_pages_range(obj, soffset, soffset + sremain); + + return ret; } -static int -i915_gem_gtt_write(struct drm_device *dev, struct drm_i915_gem_object *obj, - uint64_t data_ptr, uint64_t size, uint64_t offset, struct drm_file *file) -{ - vm_offset_t mkva; - vm_pindex_t obj_pi; - int obj_po, ret; - - obj_pi = OFF_TO_IDX(offset); - obj_po = offset & PAGE_MASK; - - mkva = (vm_offset_t)pmap_mapdev_attr(dev->agp->base + obj->gtt_offset + - IDX_TO_OFF(obj_pi), size, PAT_WRITE_COMBINING); - ret = -copyin_nofault((void *)(uintptr_t)data_ptr, (char *)mkva + - obj_po, size); - pmap_unmapdev(mkva, size); - return (ret); -} - -static int -i915_gem_obj_io(struct drm_device *dev, uint32_t handle, uint64_t data_ptr, - uint64_t size, uint64_t offset, enum uio_rw rw, struct drm_file *file) +/** + * 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; - vm_page_t *ma; - vm_offset_t start, end; - int npages, ret; + int ret = 0; - if (size == 0) - return (0); - start = trunc_page(data_ptr); - end = round_page(data_ptr + size); - npages = howmany(end - start, PAGE_SIZE); - ma = malloc(npages * sizeof(vm_page_t), DRM_I915_GEM, M_WAITOK | - M_ZERO); - npages = vm_fault_quick_hold_pages(&curproc->p_vmspace->vm_map, - (vm_offset_t)data_ptr, size, - (rw == UIO_READ ? VM_PROT_WRITE : 0 ) | VM_PROT_READ, ma, npages); - if (npages == -1) { - ret = -EFAULT; - goto free_ma; - } + 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 != 0) - goto unlocked; + if (ret) + return ret; - obj = to_intel_bo(drm_gem_object_lookup(dev, file, handle)); + obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); if (&obj->base == NULL) { ret = -ENOENT; goto unlock; } - if (offset > obj->base.size || size > obj->base.size - offset) { + + /* Bounds check source. */ + if (args->offset > obj->base.size || + args->size > obj->base.size - args->offset) { ret = -EINVAL; goto out; } - if (rw == UIO_READ) { - CTR3(KTR_DRM, "object_pread %p %jx %jx", obj, offset, size); - ret = i915_gem_object_set_cpu_read_domain_range(obj, - offset, size); - if (ret != 0) - goto out; - ret = i915_gem_swap_io(dev, obj, data_ptr, size, offset, - UIO_READ, file); - } else { - if (obj->phys_obj) { - CTR3(KTR_DRM, "object_phys_write %p %jx %jx", obj, - offset, size); - ret = i915_gem_phys_pwrite(dev, obj, data_ptr, offset, - size, file); - } else if (obj->gtt_space && - obj->base.write_domain != I915_GEM_DOMAIN_CPU) { - CTR3(KTR_DRM, "object_gtt_write %p %jx %jx", obj, - offset, size); - ret = i915_gem_object_pin(obj, 0, true); - if (ret != 0) - goto out; - ret = i915_gem_object_set_to_gtt_domain(obj, true); - if (ret != 0) - goto out_unpin; - ret = i915_gem_object_put_fence(obj); - if (ret != 0) - goto out_unpin; - ret = i915_gem_gtt_write(dev, obj, data_ptr, size, - offset, file); -out_unpin: - i915_gem_object_unpin(obj); - } else { - CTR3(KTR_DRM, "object_pwrite %p %jx %jx", obj, - offset, size); - ret = i915_gem_object_set_to_cpu_domain(obj, true); - if (ret != 0) - goto out; - ret = i915_gem_swap_io(dev, obj, data_ptr, size, offset, - UIO_WRITE, file); - } +#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); -unlocked: - vm_page_unhold_pages(ma, npages); -free_ma: - free(ma, DRM_I915_GEM); - return (ret); + return ret; } -int -i915_gem_pread_ioctl(struct drm_device *dev, void *data, struct drm_file *file) +/* 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) { - struct drm_i915_gem_pread *args; + void __iomem *vaddr_atomic; + void *vaddr; + unsigned long unwritten; - args = data; - return (i915_gem_obj_io(dev, args->handle, args->data_ptr, args->size, - args->offset, UIO_READ, file)); + 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 *)vaddr_atomic + page_offset; + unwritten = __copy_from_user_inatomic_nocache(vaddr, + user_data, length); + pmap_unmapdev((vm_offset_t)vaddr_atomic, length); + return unwritten; } -int -i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, struct drm_file *file) +/** + * 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) { - struct drm_i915_gem_pwrite *args; + ssize_t remain; + off_t offset, page_base; + char __user *user_data; + int page_offset, page_length, ret; - args = data; - return (i915_gem_obj_io(dev, args->handle, args->data_ptr, args->size, - args->offset, UIO_WRITE, file)); + ret = i915_gem_object_pin(obj, 0, true); + /* XXXKIB ret = i915_gem_obj_ggtt_pin(obj, 0, true, true); */ + if (ret != 0) + 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; +} +#undef __user +#undef __force +#undef __iomem +#undef to_user_ptr +#undef offset_in_page +#undef page_to_phys + int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, struct drm_file *file) @@ -1192,9 +1784,6 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, uint32_t write_domain; int ret; - if ((dev->driver->driver_features & DRIVER_GEM) == 0) - return (-ENODEV); - args = data; read_domains = args->read_domains; write_domain = args->write_domain; @@ -1236,9 +1825,7 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, int ret; args = data; - ret = 0; - if ((dev->driver->driver_features & DRIVER_GEM) == 0) - return (ENODEV); + ret = i915_mutex_lock_interruptible(dev); if (ret != 0) return (ret); @@ -1269,9 +1856,6 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data, args = data; - if ((dev->driver->driver_features & DRIVER_GEM) == 0) - return (-ENODEV); - obj = drm_gem_object_lookup(dev, file, args->handle); if (obj == NULL) return (-ENOENT); @@ -1415,10 +1999,10 @@ i915_gem_pager_fault(vm_object_t vm_obj, vm_ooffset_t offset, int prot, } } - if (obj->tiling_mode == I915_TILING_NONE) - ret = i915_gem_object_put_fence(obj); - else - ret = i915_gem_object_get_fence(obj, NULL); + 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; @@ -1517,9 +2101,6 @@ i915_gem_mmap_gtt(struct drm_file *file, struct drm_device *dev, struct drm_i915_gem_object *obj; int ret; - if (!(dev->driver->driver_features & DRIVER_GEM)) - return (-ENODEV); - dev_priv = dev->dev_private; ret = i915_mutex_lock_interruptible(dev); @@ -1679,6 +2260,7 @@ i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj) 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; @@ -1712,6 +2294,10 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) obj->dirty = 1; } + /* 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); + CTR3(KTR_DRM, "object_change_domain set_to_gtt %p %x %x", obj, old_read_domains, old_write_domain); return (0); @@ -1752,7 +2338,8 @@ i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, return (ret); } - i915_gem_gtt_rebind_object(obj, cache_level); + 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); @@ -1786,6 +2373,22 @@ i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, 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) @@ -1798,18 +2401,19 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, return (ret); if (pipelined != obj->ring) { - ret = i915_gem_object_wait_rendering(obj); - if (ret == -ERESTART || ret == -EINTR) + ret = i915_gem_object_sync(obj, pipelined); + if (ret) return (ret); } + obj->pin_display = true; ret = i915_gem_object_set_cache_level(obj, I915_CACHE_NONE); if (ret != 0) - return (ret); + goto err_unpin_display; ret = i915_gem_object_pin(obj, alignment, true); if (ret != 0) - return (ret); + goto err_unpin_display; i915_gem_object_flush_cpu_write_domain(obj); @@ -1823,6 +2427,17 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, 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 @@ -1848,7 +2463,7 @@ i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj) return (0); } -static int +int i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write) { uint32_t old_write_domain, old_read_domains; @@ -1861,12 +2476,13 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write) if (ret != 0) return (ret); - ret = i915_gem_object_wait_rendering(obj); - if (ret != 0) - return (ret); + if (write || obj->pending_gpu_write) { + ret = i915_gem_object_wait_rendering(obj); + if (ret != 0) + return (ret); + } i915_gem_object_flush_gtt_write_domain(obj); - i915_gem_object_set_to_full_cpu_read_domain(obj); old_write_domain = obj->base.write_domain; old_read_domains = obj->base.read_domains; @@ -1889,74 +2505,6 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write) return (0); } -static void -i915_gem_object_set_to_full_cpu_read_domain(struct drm_i915_gem_object *obj) -{ - int i; - - if (obj->page_cpu_valid == NULL) - return; - - if ((obj->base.read_domains & I915_GEM_DOMAIN_CPU) != 0) { - for (i = 0; i <= (obj->base.size - 1) / PAGE_SIZE; i++) { - if (obj->page_cpu_valid[i] != 0) - continue; - drm_clflush_pages(obj->pages + i, 1); - } - } - - free(obj->page_cpu_valid, DRM_I915_GEM); - obj->page_cpu_valid = NULL; -} - -static int -i915_gem_object_set_cpu_read_domain_range(struct drm_i915_gem_object *obj, - uint64_t offset, uint64_t size) -{ - uint32_t old_read_domains; - int i, ret; - - if (offset == 0 && size == obj->base.size) - return (i915_gem_object_set_to_cpu_domain(obj, 0)); - - ret = i915_gem_object_flush_gpu_write_domain(obj); - if (ret != 0) - return (ret); - ret = i915_gem_object_wait_rendering(obj); - if (ret != 0) - return (ret); - - i915_gem_object_flush_gtt_write_domain(obj); - - if (obj->page_cpu_valid == NULL && - (obj->base.read_domains & I915_GEM_DOMAIN_CPU) != 0) - return (0); - - if (obj->page_cpu_valid == NULL) { - obj->page_cpu_valid = malloc(obj->base.size / PAGE_SIZE, - DRM_I915_GEM, M_WAITOK | M_ZERO); - } else if ((obj->base.read_domains & I915_GEM_DOMAIN_CPU) == 0) - memset(obj->page_cpu_valid, 0, obj->base.size / PAGE_SIZE); - - for (i = offset / PAGE_SIZE; i <= (offset + size - 1) / PAGE_SIZE; - i++) { - if (obj->page_cpu_valid[i]) - continue; - drm_clflush_pages(obj->pages + i, 1); - obj->page_cpu_valid[i] = 1; - } - - KASSERT((obj->base.write_domain & ~I915_GEM_DOMAIN_CPU) == 0, - ("In gpu write domain")); - - old_read_domains = obj->base.read_domains; - obj->base.read_domains |= I915_GEM_DOMAIN_CPU; - - CTR3(KTR_DRM, "object_change_domain set_cpu_read %p %x %x", obj, - old_read_domains, obj->base.write_domain); - return (0); -} - static uint32_t i915_gem_get_gtt_size(struct drm_device *dev, uint32_t size, int tiling_mode) { @@ -2107,7 +2655,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, return (ret); } - ret = i915_gem_gtt_bind_object(obj); + ret = i915_gem_gtt_prepare_object(obj); if (ret != 0) { i915_gem_object_put_pages_gtt(obj); drm_mm_put_block(obj->gtt_space); @@ -2117,6 +2665,9 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, 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); @@ -2140,8 +2691,48 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, return (0); } -static void -i915_gem_object_finish_gtt(struct drm_i915_gem_object *obj) +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; @@ -2196,14 +2787,17 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj) } ret = i915_gem_object_put_fence(obj); - if (ret == -ERESTART) + if (ret) return (ret); - i915_gem_gtt_unbind_object(obj); + 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); @@ -2221,6 +2815,70 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj) return (ret); } +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 m; + vm_pindex_t i; + + vm_obj = obj->base.vm_obj; + VM_OBJECT_ASSERT_LOCKED(vm_obj); + for (i = si, m = vm_page_lookup(vm_obj, i); i < ei; + m = vm_page_next(m), i++) { + KASSERT(m->pindex == i, ("pindex %jx %jx", + (uintmax_t)m->pindex, (uintmax_t)i)); + vm_page_lock(m); + vm_page_unwire(m, PQ_INACTIVE); + if (m->wire_count == 0) + atomic_add_long(&i915_gem_wired_pages_cnt, -1); + vm_page_unlock(m); + } +} + +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 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 m; + 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++) { + m = i915_gem_wire_page(vm_obj, i, &fresh); + if (m == NULL) + goto failed; + if (need_swizzle && fresh) + i915_gem_object_do_bit_17_swizzle_page(obj, m); + } + 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) @@ -2228,36 +2886,30 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj, struct drm_device *dev; vm_object_t vm_obj; vm_page_t m; - int page_count, i, j; + vm_pindex_t i, page_count; + int res; dev = obj->base.dev; KASSERT(obj->pages == NULL, ("Obj already has pages")); - page_count = obj->base.size / PAGE_SIZE; + 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; i < page_count; i++) { - if ((obj->pages[i] = i915_gem_wire_page(vm_obj, i)) == NULL) - goto failed; + for (i = 0, m = vm_page_lookup(vm_obj, 0); i < page_count; + i++, m = vm_page_next(m)) { + KASSERT(m->pindex == i, ("pindex %jx %jx", + (uintmax_t)m->pindex, (uintmax_t)i)); + obj->pages[i] = m; } VM_OBJECT_WUNLOCK(vm_obj); - if (i915_gem_object_needs_bit17_swizzle(obj)) - i915_gem_object_do_bit_17_swizzle(obj); return (0); - -failed: - for (j = 0; j < i; j++) { - m = obj->pages[j]; - vm_page_lock(m); - vm_page_unwire(m, PQ_INACTIVE); - vm_page_unlock(m); - atomic_add_long(&i915_gem_wired_pages_cnt, -1); - } - VM_OBJECT_WUNLOCK(vm_obj); - free(obj->pages, DRM_I915_GEM); - obj->pages = NULL; - return (-EIO); } #define GEM_PARANOID_CHECK_GTT 0 @@ -2366,10 +3018,10 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *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, - true); + ret = i915_wait_request(obj->ring, obj->last_rendering_seqno); if (ret != 0) return (ret); + i915_gem_retire_requests_ring(obj->ring); } return (0); } @@ -2398,7 +3050,6 @@ i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, obj->last_rendering_seqno = seqno; if (obj->fenced_gpu_access) { obj->last_fenced_seqno = seqno; - obj->last_fenced_ring = ring; /* Bump MRU to take account of the delayed flush */ if (obj->fence_reg != I915_FENCE_REG_NONE) { @@ -2435,15 +3086,11 @@ 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; - if (obj->pin_count != 0) - list_move_tail(&obj->mm_list, &dev_priv->mm.pinned_list); - else - list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list); + 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; - obj->last_fenced_ring = NULL; i915_gem_object_move_off_active(obj); obj->fenced_gpu_access = false; @@ -2468,6 +3115,7 @@ i915_gem_object_truncate(struct drm_i915_gem_object *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; } @@ -2511,7 +3159,7 @@ i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj) } static vm_page_t -i915_gem_wire_page(vm_object_t object, vm_pindex_t pindex) +i915_gem_wire_page(vm_object_t object, vm_pindex_t pindex, bool *fresh) { vm_page_t m; int rv; @@ -2530,11 +3178,17 @@ i915_gem_wire_page(vm_object_t object, vm_pindex_t pindex) vm_page_unlock(m); return (NULL); } + if (fresh != NULL) + *fresh = true; } else { pmap_zero_page(m); m->valid = VM_PAGE_BITS_ALL; m->dirty = 0; + if (fresh != NULL) + *fresh = false; } + } else if (fresh != NULL) { + *fresh = false; } vm_page_lock(m); vm_page_wire(m); @@ -2565,7 +3219,7 @@ i915_gem_flush_ring(struct intel_ring_buffer *ring, uint32_t invalidate_domains, } static int -i915_ring_idle(struct intel_ring_buffer *ring, bool do_retire) +i915_ring_idle(struct intel_ring_buffer *ring) { int ret; @@ -2579,12 +3233,11 @@ i915_ring_idle(struct intel_ring_buffer *ring, bool do_retire) return ret; } - return (i915_wait_request(ring, i915_gem_next_request_seqno(ring), - do_retire)); + return (i915_wait_request(ring, i915_gem_next_request_seqno(ring))); } int -i915_gpu_idle(struct drm_device *dev, bool do_retire) +i915_gpu_idle(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; struct intel_ring_buffer *ring; @@ -2596,29 +3249,25 @@ i915_gpu_idle(struct drm_device *dev, bool do_retire) if (ret) return ret; - ret = i915_ring_idle(ring, do_retire); + ret = i915_ring_idle(ring); if (ret) return ret; + + /* Is the device fubar? */ + if (!list_empty(&ring->gpu_write_list)) + return -EBUSY; } return 0; } -int -i915_wait_request(struct intel_ring_buffer *ring, uint32_t seqno, bool do_retire) +static int +i915_gem_check_wedge(struct drm_i915_private *dev_priv) { - drm_i915_private_t *dev_priv; - struct drm_i915_gem_request *request; - uint32_t ier; - int flags, ret; - bool recovery_complete; - - KASSERT(seqno != 0, ("Zero seqno")); - - dev_priv = ring->dev->dev_private; - ret = 0; + 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; @@ -2626,11 +3275,25 @@ i915_wait_request(struct intel_ring_buffer *ring, uint32_t seqno, bool do_retire 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 = 0; + + DRM_LOCK_ASSERT(ring->dev); + if (seqno == ring->outstanding_lazy_request) { + struct drm_i915_gem_request *request; + request = malloc(sizeof(*request), DRM_I915_GEM, M_WAITOK | M_ZERO); - if (request == NULL) - return (-ENOMEM); ret = i915_add_request(ring, NULL, request); if (ret != 0) { @@ -2638,59 +3301,64 @@ i915_wait_request(struct intel_ring_buffer *ring, uint32_t seqno, bool do_retire return (ret); } - seqno = request->seqno; + 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); } - if (!i915_seqno_passed(ring->get_seqno(ring), seqno)) { - if (HAS_PCH_SPLIT(ring->dev)) - ier = I915_READ(DEIER) | I915_READ(GTIER); - else - ier = I915_READ(IER); - if (!ier) { - DRM_ERROR("something (likely vbetool) disabled " - "interrupts, re-enabling\n"); - ring->dev->driver->irq_preinstall(ring->dev); - ring->dev->driver->irq_postinstall(ring->dev); - } + 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); + ring->irq_put(ring); + mtx_unlock(&dev_priv->irq_lock); - CTR2(KTR_DRM, "request_wait_begin %s %d", ring->name, seqno); + CTR3(KTR_DRM, "request_wait_end %s %d %d", ring->name, seqno, ret); - ring->waiting_seqno = seqno; - mtx_lock(&ring->irq_lock); - if (ring->irq_get(ring)) { - flags = dev_priv->mm.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, &ring->irq_lock, flags, - "915gwr", 0); - } - ring->irq_put(ring); - mtx_unlock(&ring->irq_lock); - } else { - mtx_unlock(&ring->irq_lock); - if (_intel_wait_for(ring->dev, - i915_seqno_passed(ring->get_seqno(ring), seqno) || - atomic_load_acq_int(&dev_priv->mm.wedged), 3000, - 0, "i915wrq") != 0) - ret = -EBUSY; - } - ring->waiting_seqno = 0; + return ret; +} - CTR3(KTR_DRM, "request_wait_end %s %d %d", ring->name, seqno, - ret); - } +int +i915_wait_request(struct intel_ring_buffer *ring, uint32_t seqno) +{ + drm_i915_private_t *dev_priv; + int ret; + + KASSERT(seqno != 0, ("Zero seqno")); + + dev_priv = ring->dev->dev_private; + ret = 0; + + 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; - /* Directly dispatch request retiring. While we have the work queue - * to handle this, the waiter on a request often wants an associated - * buffer to have made it to the inactive list, and we would need - * a separate wait queue to handle that. - */ - if (ret == 0 && do_retire) - i915_gem_retire_requests_ring(ring); - return (ret); } @@ -2851,20 +3519,18 @@ i915_gem_reset_fences(struct drm_device *dev) for (i = 0; i < dev_priv->num_fence_regs; i++) { struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i]; - struct drm_i915_gem_object *obj = reg->obj; - if (!obj) - continue; + i915_gem_write_fence(dev, i, NULL); - if (obj->tiling_mode) - i915_gem_release_mmap(obj); + if (reg->obj) + i915_gem_object_fence_lost(reg->obj); - reg->obj->fence_reg = I915_FENCE_REG_NONE; - reg->obj->fenced_gpu_access = false; - reg->obj->last_fenced_seqno = 0; - reg->obj->last_fenced_ring = NULL; - i915_gem_clear_fence_reg(dev, reg); + reg->pin_count = 0; + reg->obj = NULL; + INIT_LIST_HEAD(®->lru_list); } + + INIT_LIST_HEAD(&dev_priv->mm.fence_list); } void @@ -2872,10 +3538,11 @@ 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 (i = 0; i < I915_NUM_RINGS; i++) - i915_gem_reset_ring_lists(dev_priv, &dev_priv->rings[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 @@ -2961,9 +3628,10 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring) if (ring->trace_irq_seqno && i915_seqno_passed(seqno, ring->trace_irq_seqno)) { - mtx_lock(&ring->irq_lock); + struct drm_i915_private *dev_priv = ring->dev->dev_private; + mtx_lock(&dev_priv->irq_lock); ring->irq_put(ring); - mtx_unlock(&ring->irq_lock); + mtx_unlock(&dev_priv->irq_lock); ring->trace_irq_seqno = 0; } } @@ -2972,209 +3640,188 @@ void i915_gem_retire_requests(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj, *next; + struct intel_ring_buffer *ring; int i; - if (!list_empty(&dev_priv->mm.deferred_free_list)) { - list_for_each_entry_safe(obj, next, - &dev_priv->mm.deferred_free_list, mm_list) - i915_gem_free_object_tail(obj); - } - - for (i = 0; i < I915_NUM_RINGS; i++) - i915_gem_retire_requests_ring(&dev_priv->rings[i]); + for_each_ring(ring, dev_priv, i) + i915_gem_retire_requests_ring(ring); } -static int -sandybridge_write_fence_reg(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *pipelined) +static void sandybridge_write_fence_reg(struct drm_device *dev, int reg, + struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; - u32 size = obj->gtt_space->size; - int regnum = obj->fence_reg; uint64_t val; - 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) { + u32 size = obj->gtt_space->size; - if (obj->tiling_mode == I915_TILING_Y) - val |= 1 << I965_FENCE_TILING_Y_SHIFT; - val |= I965_FENCE_REG_VALID; + 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 (pipelined) { - int ret = intel_ring_begin(pipelined, 6); - if (ret) - return ret; - - intel_ring_emit(pipelined, MI_NOOP); - intel_ring_emit(pipelined, MI_LOAD_REGISTER_IMM(2)); - intel_ring_emit(pipelined, FENCE_REG_SANDYBRIDGE_0 + regnum*8); - intel_ring_emit(pipelined, (u32)val); - intel_ring_emit(pipelined, FENCE_REG_SANDYBRIDGE_0 + regnum*8 + 4); - intel_ring_emit(pipelined, (u32)(val >> 32)); - intel_ring_advance(pipelined); + if (obj->tiling_mode == I915_TILING_Y) + val |= 1 << I965_FENCE_TILING_Y_SHIFT; + val |= I965_FENCE_REG_VALID; } else - I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + regnum * 8, val); + val = 0; - return 0; + I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + reg * 8, val); + POSTING_READ(FENCE_REG_SANDYBRIDGE_0 + reg * 8); } -static int -i965_write_fence_reg(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *pipelined) +static void i965_write_fence_reg(struct drm_device *dev, int reg, + struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; - u32 size = obj->gtt_space->size; - int regnum = obj->fence_reg; uint64_t val; - 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; + if (obj) { + u32 size = obj->gtt_space->size; - if (pipelined) { - int ret = intel_ring_begin(pipelined, 6); - if (ret) - return ret; - - intel_ring_emit(pipelined, MI_NOOP); - intel_ring_emit(pipelined, MI_LOAD_REGISTER_IMM(2)); - intel_ring_emit(pipelined, FENCE_REG_965_0 + regnum*8); - intel_ring_emit(pipelined, (u32)val); - intel_ring_emit(pipelined, FENCE_REG_965_0 + regnum*8 + 4); - intel_ring_emit(pipelined, (u32)(val >> 32)); - intel_ring_advance(pipelined); + 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 - I915_WRITE64(FENCE_REG_965_0 + regnum * 8, val); + val = 0; - return 0; + I915_WRITE64(FENCE_REG_965_0 + reg * 8, val); + POSTING_READ(FENCE_REG_965_0 + reg * 8); } -static int -i915_write_fence_reg(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *pipelined) +static void i915_write_fence_reg(struct drm_device *dev, int reg, + struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; - u32 size = obj->gtt_space->size; - u32 fence_reg, val, pitch_val; - int tile_width; + u32 val; - 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); - return -EINVAL; - } + if (obj) { + u32 size = obj->gtt_space->size; + int pitch_val; + int tile_width; - if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)) - tile_width = 128; - else - tile_width = 512; + 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); - /* Note: pitch better be a power of two tile widths */ - pitch_val = obj->stride / tile_width; - pitch_val = ffs(pitch_val) - 1; + if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)) + tile_width = 128; + else + tile_width = 512; - 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; + /* Note: pitch better be a power of two tile widths */ + pitch_val = obj->stride / tile_width; + pitch_val = ffs(pitch_val) - 1; - fence_reg = obj->fence_reg; - if (fence_reg < 8) - fence_reg = FENCE_REG_830_0 + fence_reg * 4; - else - fence_reg = FENCE_REG_945_8 + (fence_reg - 8) * 4; - - if (pipelined) { - int ret = intel_ring_begin(pipelined, 4); - if (ret) - return ret; - - intel_ring_emit(pipelined, MI_NOOP); - intel_ring_emit(pipelined, MI_LOAD_REGISTER_IMM(1)); - intel_ring_emit(pipelined, fence_reg); - intel_ring_emit(pipelined, val); - intel_ring_advance(pipelined); + 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 - I915_WRITE(fence_reg, val); + val = 0; - return 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 int -i830_write_fence_reg(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *pipelined) +static void i830_write_fence_reg(struct drm_device *dev, int reg, + struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; - u32 size = obj->gtt_space->size; - int regnum = obj->fence_reg; uint32_t val; - 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); - return -EINVAL; - } + if (obj) { + u32 size = obj->gtt_space->size; + uint32_t pitch_val; - pitch_val = obj->stride / 128; - pitch_val = ffs(pitch_val) - 1; + 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); - 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; + pitch_val = obj->stride / 128; + pitch_val = ffs(pitch_val) - 1; - if (pipelined) { - int ret = intel_ring_begin(pipelined, 4); - if (ret) - return ret; - - intel_ring_emit(pipelined, MI_NOOP); - intel_ring_emit(pipelined, MI_LOAD_REGISTER_IMM(1)); - intel_ring_emit(pipelined, FENCE_REG_830_0 + regnum*4); - intel_ring_emit(pipelined, val); - intel_ring_advance(pipelined); + 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 - I915_WRITE(FENCE_REG_830_0 + regnum * 4, val); + val = 0; - return 0; + I915_WRITE(FENCE_REG_830_0 + reg * 4, val); + POSTING_READ(FENCE_REG_830_0 + reg * 4); } -static bool ring_passed_seqno(struct intel_ring_buffer *ring, u32 seqno) +static void i915_gem_write_fence(struct drm_device *dev, int reg, + struct drm_i915_gem_object *obj) { - return i915_seqno_passed(ring->get_seqno(ring), seqno); + 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_i915_private *dev_priv = obj->base.dev->dev_private; + int reg = fence_number(dev_priv, fence); + + i915_gem_write_fence(obj->base.dev, reg, enable ? obj : NULL); + + if (enable) { + obj->fence_reg = 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, - struct intel_ring_buffer *pipelined) +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->last_fenced_ring, 0, - obj->base.write_domain); + ret = i915_gem_flush_ring(obj->ring, + 0, obj->base.write_domain); if (ret) return ret; } @@ -3182,18 +3829,13 @@ i915_gem_object_flush_fence(struct drm_i915_gem_object *obj, obj->fenced_gpu_access = false; } - if (obj->last_fenced_seqno && pipelined != obj->last_fenced_ring) { - if (!ring_passed_seqno(obj->last_fenced_ring, - obj->last_fenced_seqno)) { - ret = i915_wait_request(obj->last_fenced_ring, - obj->last_fenced_seqno, - true); - if (ret) - return ret; - } + if (obj->last_fenced_seqno) { + ret = i915_wait_request(obj->ring, + obj->last_fenced_seqno); + if (ret) + return ret; obj->last_fenced_seqno = 0; - obj->last_fenced_ring = NULL; } /* Ensure that all CPU reads are completed before installing a fence @@ -3208,35 +3850,29 @@ i915_gem_object_flush_fence(struct drm_i915_gem_object *obj, 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; - if (obj->tiling_mode) - i915_gem_release_mmap(obj); - - ret = i915_gem_object_flush_fence(obj, NULL); + ret = i915_gem_object_flush_fence(obj); if (ret) return ret; - if (obj->fence_reg != I915_FENCE_REG_NONE) { - struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + if (obj->fence_reg == I915_FENCE_REG_NONE) + return 0; - if (dev_priv->fence_regs[obj->fence_reg].pin_count != 0) - printf("%s: pin_count %d\n", __func__, - dev_priv->fence_regs[obj->fence_reg].pin_count); - i915_gem_clear_fence_reg(obj->base.dev, - &dev_priv->fence_regs[obj->fence_reg]); - - obj->fence_reg = I915_FENCE_REG_NONE; - } + 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 intel_ring_buffer *pipelined) +i915_find_fence_reg(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_fence_reg *reg, *first, *avail; + struct drm_i915_fence_reg *reg, *avail; int i; /* First try to find a free reg */ @@ -3254,195 +3890,64 @@ i915_find_fence_reg(struct drm_device *dev, struct intel_ring_buffer *pipelined) return NULL; /* None available, try to steal one or wait for a user to finish */ - avail = first = NULL; list_for_each_entry(reg, &dev_priv->mm.fence_list, lru_list) { if (reg->pin_count) continue; - if (first == NULL) - first = reg; - - if (!pipelined || - !reg->obj->last_fenced_ring || - reg->obj->last_fenced_ring == pipelined) { - avail = reg; - break; - } + return reg; } - if (avail == NULL) - avail = first; - - return avail; + return NULL; } int -i915_gem_object_get_fence(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *pipelined) +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; - pipelined = NULL; + /* 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; + } + ret = 0; 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); + 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 (obj->tiling_changed) { - ret = i915_gem_object_flush_fence(obj, pipelined); + if (reg->obj) { + struct drm_i915_gem_object *old = reg->obj; + + ret = i915_gem_object_flush_fence(old); if (ret) return ret; - if (!obj->fenced_gpu_access && !obj->last_fenced_seqno) - pipelined = NULL; - - if (pipelined) { - reg->setup_seqno = - i915_gem_next_request_seqno(pipelined); - obj->last_fenced_seqno = reg->setup_seqno; - obj->last_fenced_ring = pipelined; - } - - goto update; + i915_gem_object_fence_lost(old); } - - if (!pipelined) { - if (reg->setup_seqno) { - if (!ring_passed_seqno(obj->last_fenced_ring, - reg->setup_seqno)) { - ret = i915_wait_request( - obj->last_fenced_ring, - reg->setup_seqno, - true); - if (ret) - return ret; - } - - reg->setup_seqno = 0; - } - } else if (obj->last_fenced_ring && - obj->last_fenced_ring != pipelined) { - ret = i915_gem_object_flush_fence(obj, pipelined); - if (ret) - return ret; - } - - if (!obj->fenced_gpu_access && !obj->last_fenced_seqno) - pipelined = NULL; - KASSERT(pipelined || reg->setup_seqno == 0, ("!pipelined")); - - if (obj->tiling_changed) { - if (pipelined) { - reg->setup_seqno = - i915_gem_next_request_seqno(pipelined); - obj->last_fenced_seqno = reg->setup_seqno; - obj->last_fenced_ring = pipelined; - } - goto update; - } - + } else return 0; - } - reg = i915_find_fence_reg(dev, pipelined); - if (reg == NULL) - return -EDEADLK; + i915_gem_object_update_fence(obj, reg, enable); + obj->fence_dirty = false; - ret = i915_gem_object_flush_fence(obj, pipelined); - if (ret) - return ret; - - if (reg->obj) { - struct drm_i915_gem_object *old = reg->obj; - - drm_gem_object_reference(&old->base); - - if (old->tiling_mode) - i915_gem_release_mmap(old); - - ret = i915_gem_object_flush_fence(old, pipelined); - if (ret) { - drm_gem_object_unreference(&old->base); - return ret; - } - - if (old->last_fenced_seqno == 0 && obj->last_fenced_seqno == 0) - pipelined = NULL; - - old->fence_reg = I915_FENCE_REG_NONE; - old->last_fenced_ring = pipelined; - old->last_fenced_seqno = - pipelined ? i915_gem_next_request_seqno(pipelined) : 0; - - drm_gem_object_unreference(&old->base); - } else if (obj->last_fenced_seqno == 0) - pipelined = NULL; - - reg->obj = obj; - list_move_tail(®->lru_list, &dev_priv->mm.fence_list); - obj->fence_reg = reg - dev_priv->fence_regs; - obj->last_fenced_ring = pipelined; - - reg->setup_seqno = - pipelined ? i915_gem_next_request_seqno(pipelined) : 0; - obj->last_fenced_seqno = reg->setup_seqno; - -update: - obj->tiling_changed = false; - switch (INTEL_INFO(dev)->gen) { - case 7: - case 6: - ret = sandybridge_write_fence_reg(obj, pipelined); - break; - case 5: - case 4: - ret = i965_write_fence_reg(obj, pipelined); - break; - case 3: - ret = i915_write_fence_reg(obj, pipelined); - break; - case 2: - ret = i830_write_fence_reg(obj, pipelined); - break; - } - - return ret; -} - -static void -i915_gem_clear_fence_reg(struct drm_device *dev, struct drm_i915_fence_reg *reg) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - uint32_t fence_reg = reg - dev_priv->fence_regs; - - switch (INTEL_INFO(dev)->gen) { - case 7: - case 6: - I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + fence_reg*8, 0); - break; - case 5: - case 4: - I915_WRITE64(FENCE_REG_965_0 + fence_reg*8, 0); - break; - case 3: - if (fence_reg >= 8) - fence_reg = FENCE_REG_945_8 + (fence_reg - 8) * 4; - else - case 2: - fence_reg = FENCE_REG_830_0 + fence_reg * 4; - - I915_WRITE(fence_reg, 0); - break; - } - - list_del_init(®->lru_list); - reg->obj = NULL; - reg->setup_seqno = 0; - reg->pin_count = 0; + return 0; } int @@ -3457,7 +3962,7 @@ static bool i915_gem_object_is_inactive(struct drm_i915_gem_object *obj) { - return (obj->gtt_space && !obj->active && obj->pin_count == 0); + return !obj->active; } static void @@ -3465,6 +3970,7 @@ 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; @@ -3486,7 +3992,7 @@ i915_gem_retire_task_handler(void *arg, int pending) * objects indefinitely. */ idle = true; - for (i = 0; i < I915_NUM_RINGS; i++) { + for_each_ring(ring, dev_priv, i) { struct intel_ring_buffer *ring = &dev_priv->rings[i]; if (!list_empty(&ring->gpu_write_list)) { @@ -3602,7 +4108,7 @@ i915_gem_detach_phys_object(struct drm_device *dev, page_count = obj->base.size / PAGE_SIZE; VM_OBJECT_WLOCK(obj->base.vm_obj); for (i = 0; i < page_count; i++) { - m = i915_gem_wire_page(obj->base.vm_obj, i); + m = i915_gem_wire_page(obj->base.vm_obj, i, NULL); if (m == NULL) continue; /* XXX */ @@ -3668,7 +4174,7 @@ i915_gem_attach_phys_object(struct drm_device *dev, VM_OBJECT_WLOCK(obj->base.vm_obj); ret = 0; for (i = 0; i < page_count; i++) { - m = i915_gem_wire_page(obj->base.vm_obj, i); + m = i915_gem_wire_page(obj->base.vm_obj, i, NULL); if (m == NULL) { ret = -EIO; break; @@ -3693,33 +4199,6 @@ i915_gem_attach_phys_object(struct drm_device *dev, return (0); } -static int -i915_gem_phys_pwrite(struct drm_device *dev, struct drm_i915_gem_object *obj, - uint64_t data_ptr, uint64_t offset, uint64_t size, - struct drm_file *file_priv) -{ - char *user_data, *vaddr; - int ret; - - vaddr = (char *)obj->phys_obj->handle->vaddr + offset; - user_data = (char *)(uintptr_t)data_ptr; - - if (copyin_nofault(user_data, vaddr, size) != 0) { - /* 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); - ret = -copyin(user_data, vaddr, size); - DRM_LOCK(dev); - if (ret != 0) - return (ret); - } - - intel_gtt_chipset_flush(); - return (0); -} - static int i915_gpu_is_active(struct drm_device *dev) { @@ -3777,7 +4256,7 @@ i915_gem_lowmem(void *arg) * This has a dramatic impact to reduce the number of * OOM-killer events whilst running the GPU aggressively. */ - if (i915_gpu_idle(dev, true) == 0) + if (i915_gpu_idle(dev) == 0) goto rescan; } DRM_UNLOCK(dev); diff --git a/sys/dev/drm2/i915/i915_gem_context.c b/sys/dev/drm2/i915/i915_gem_context.c index 07d7a66d09e2..dc4204320b67 100644 --- a/sys/dev/drm2/i915/i915_gem_context.c +++ b/sys/dev/drm2/i915/i915_gem_context.c @@ -405,7 +405,7 @@ static int do_switch(struct i915_hw_context *to) } if (!to->obj->has_global_gtt_mapping) - i915_gem_gtt_bind_object(to->obj); + i915_gem_gtt_bind_object(to->obj, to->obj->cache_level); if (!to->is_initialized || is_default_context(to)) hw_flags |= MI_RESTORE_INHIBIT; diff --git a/sys/dev/drm2/i915/i915_gem_evict.c b/sys/dev/drm2/i915/i915_gem_evict.c index 0d8ac80d4d7a..cadd9ff1a26d 100644 --- a/sys/dev/drm2/i915/i915_gem_evict.c +++ b/sys/dev/drm2/i915/i915_gem_evict.c @@ -37,6 +37,9 @@ __FBSDID("$FreeBSD$"); static bool mark_free(struct drm_i915_gem_object *obj, struct list_head *unwind) { + if (obj->pin_count) + return false; + list_add(&obj->exec_list, unwind); return drm_mm_scan_add_block(obj->gtt_space); } @@ -93,7 +96,7 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, /* Now merge in the soon-to-be-expired objects... */ list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) { /* Does the object require an outstanding flush? */ - if (obj->base.write_domain || obj->pin_count) + if (obj->base.write_domain) continue; if (mark_free(obj, &unwind_list)) @@ -102,14 +105,11 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, /* Finally add anything with a pending flush (in order of retirement) */ list_for_each_entry(obj, &dev_priv->mm.flushing_list, mm_list) { - if (obj->pin_count) - continue; - if (mark_free(obj, &unwind_list)) goto found; } list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) { - if (!obj->base.write_domain || obj->pin_count) + if (!obj->base.write_domain) continue; if (mark_free(obj, &unwind_list)) @@ -169,8 +169,9 @@ int i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only) { drm_i915_private_t *dev_priv = dev->dev_private; - int ret; + struct drm_i915_gem_object *obj, *next; bool lists_empty; + int ret; lists_empty = (list_empty(&dev_priv->mm.inactive_list) && list_empty(&dev_priv->mm.flushing_list) && @@ -180,32 +181,25 @@ i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only) CTR2(KTR_DRM, "evict_everything %p %d", dev, purgeable_only); - /* Flush everything (on to the inactive lists) and evict */ - ret = i915_gpu_idle(dev, true); + /* The gpu_idle will flush everything in the write domain to the + * active list. Then we must move everything off the active list + * with retire requests. + */ + ret = i915_gpu_idle(dev); if (ret) return ret; + i915_gem_retire_requests(dev); + KASSERT(list_empty(&dev_priv->mm.flushing_list), ("flush list not empty")); - return i915_gem_evict_inactive(dev, purgeable_only); -} - -/** Unbinds all inactive objects. */ -int -i915_gem_evict_inactive(struct drm_device *dev, bool purgeable_only) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj, *next; - - CTR2(KTR_DRM, "evict_inactive %p %d", dev, purgeable_only); - + /* Having flushed everything, unbind() should never raise an error */ list_for_each_entry_safe(obj, next, &dev_priv->mm.inactive_list, mm_list) { if (!purgeable_only || obj->madv != I915_MADV_WILLNEED) { - int ret = i915_gem_object_unbind(obj); - if (ret) - return ret; + if (obj->pin_count == 0) + i915_gem_object_unbind(obj); } } diff --git a/sys/dev/drm2/i915/i915_gem_execbuffer.c b/sys/dev/drm2/i915/i915_gem_execbuffer.c index e47141a29aa0..b84dab55fdc4 100644 --- a/sys/dev/drm2/i915/i915_gem_execbuffer.c +++ b/sys/dev/drm2/i915/i915_gem_execbuffer.c @@ -263,6 +263,12 @@ eb_destroy(struct eb_objects *eb) free(eb, DRM_I915_GEM); } +static inline int use_cpu_reloc(struct drm_i915_gem_object *obj) +{ + return (obj->base.write_domain == I915_GEM_DOMAIN_CPU || + obj->cache_level != I915_CACHE_NONE); +} + static int i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, struct eb_objects *eb, @@ -270,6 +276,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, { struct drm_device *dev = obj->base.dev; struct drm_gem_object *target_obj; + struct drm_i915_gem_object *target_i915_obj; uint32_t target_offset; int ret = -EINVAL; @@ -278,7 +285,8 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, if (unlikely(target_obj == NULL)) return -ENOENT; - target_offset = to_intel_bo(target_obj)->gtt_offset; + target_i915_obj = to_intel_bo(target_obj); + target_offset = target_i915_obj->gtt_offset; #if WATCH_RELOC DRM_INFO("%s: obj %p offset %08x target %d " @@ -364,12 +372,20 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, return ret; } + /* We can't wait for rendering with pagefaults disabled */ + if (obj->active && (curthread->td_pflags & TDP_NOFAULTING) != 0) + return (-EFAULT); + reloc->delta += target_offset; - if (obj->base.write_domain == I915_GEM_DOMAIN_CPU) { + if (use_cpu_reloc(obj)) { uint32_t page_offset = reloc->offset & PAGE_MASK; char *vaddr; struct sf_buf *sf; + ret = i915_gem_object_set_to_cpu_domain(obj, 1); + if (ret) + return ret; + sf = sf_buf_alloc(obj->pages[OFF_TO_IDX(reloc->offset)], SFB_NOWAIT); if (sf == NULL) @@ -381,10 +397,11 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, uint32_t *reloc_entry; char *reloc_page; - /* We can't wait for rendering with pagefaults disabled */ - if (obj->active && (curthread->td_pflags & TDP_NOFAULTING) != 0) - return (-EFAULT); - ret = i915_gem_object_set_to_gtt_domain(obj, 1); + ret = i915_gem_object_set_to_gtt_domain(obj, true); + if (ret) + return ret; + + ret = i915_gem_object_put_fence(obj); if (ret) return ret; @@ -401,6 +418,16 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, pmap_unmapdev((vm_offset_t)reloc_page, PAGE_SIZE); } + /* Sandybridge PPGTT errata: We need a global gtt mapping for MI and + * pipe_control writes because the gpu doesn't properly redirect them + * through the ppgtt for non_secure batchbuffers. */ + if (unlikely(IS_GEN6(dev) && + reloc->write_domain == I915_GEM_DOMAIN_INSTRUCTION && + !target_i915_obj->has_global_gtt_mapping)) { + i915_gem_gtt_bind_object(target_i915_obj, + target_i915_obj->cache_level); + } + /* and update the user's relocation entry */ reloc->presumed_offset = target_offset; @@ -411,28 +438,44 @@ static int i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj, struct eb_objects *eb) { +#define N_RELOC(x) ((x) / sizeof(struct drm_i915_gem_relocation_entry)) + struct drm_i915_gem_relocation_entry stack_reloc[N_RELOC(512)]; struct drm_i915_gem_relocation_entry *user_relocs; struct drm_i915_gem_exec_object2 *entry = obj->exec_entry; - struct drm_i915_gem_relocation_entry reloc; - int i, ret; + int remain, ret; user_relocs = (void *)(uintptr_t)entry->relocs_ptr; - for (i = 0; i < entry->relocation_count; i++) { - ret = -copyin_nofault(user_relocs + i, &reloc, sizeof(reloc)); + remain = entry->relocation_count; + while (remain) { + struct drm_i915_gem_relocation_entry *r = stack_reloc; + int count = remain; + if (count > DRM_ARRAY_SIZE(stack_reloc)) + count = DRM_ARRAY_SIZE(stack_reloc); + remain -= count; + + ret = -copyin_nofault(user_relocs, r, count*sizeof(r[0])); if (ret != 0) return (ret); - ret = i915_gem_execbuffer_relocate_entry(obj, eb, &reloc); - if (ret != 0) - return (ret); + do { + u64 offset = r->presumed_offset; + + ret = i915_gem_execbuffer_relocate_entry(obj, eb, r); + if (ret) + return ret; - ret = -copyout_nofault(&reloc.presumed_offset, - &user_relocs[i].presumed_offset, - sizeof(reloc.presumed_offset)); - if (ret != 0) - return (ret); + if (r->presumed_offset != offset && + copyout_nofault(&r->presumed_offset, + &user_relocs->presumed_offset, + sizeof(r->presumed_offset))) { + return -EFAULT; + } + + user_relocs++; + r++; + } while (--count); } - +#undef N_RELOC return (0); } @@ -486,6 +529,13 @@ i915_gem_execbuffer_relocate(struct drm_device *dev, #define __EXEC_OBJECT_HAS_FENCE (1<<31) +static int +need_reloc_mappable(struct drm_i915_gem_object *obj) +{ + struct drm_i915_gem_exec_object2 *entry = obj->exec_entry; + return entry->relocation_count && !use_cpu_reloc(obj); +} + static int pin_and_fence_object(struct drm_i915_gem_object *obj, struct intel_ring_buffer *ring) @@ -499,8 +549,7 @@ pin_and_fence_object(struct drm_i915_gem_object *obj, has_fenced_gpu_access && entry->flags & EXEC_OBJECT_NEEDS_FENCE && obj->tiling_mode != I915_TILING_NONE; - need_mappable = - entry->relocation_count ? true : need_fence; + need_mappable = need_fence || need_reloc_mappable(obj); ret = i915_gem_object_pin(obj, entry->alignment, need_mappable); if (ret) @@ -508,18 +557,13 @@ pin_and_fence_object(struct drm_i915_gem_object *obj, if (has_fenced_gpu_access) { if (entry->flags & EXEC_OBJECT_NEEDS_FENCE) { - if (obj->tiling_mode) { - ret = i915_gem_object_get_fence(obj, ring); - if (ret) - goto err_unpin; + ret = i915_gem_object_get_fence(obj); + if (ret) + goto err_unpin; + if (i915_gem_object_pin_fence(obj)) entry->flags |= __EXEC_OBJECT_HAS_FENCE; - i915_gem_object_pin_fence(obj); - } else { - ret = i915_gem_object_put_fence(obj); - if (ret) - goto err_unpin; - } + obj->pending_fenced_gpu_access = true; } } @@ -558,8 +602,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, has_fenced_gpu_access && entry->flags & EXEC_OBJECT_NEEDS_FENCE && obj->tiling_mode != I915_TILING_NONE; - need_mappable = - entry->relocation_count ? true : need_fence; + need_mappable = need_fence || need_reloc_mappable(obj); if (need_mappable) list_move(&obj->exec_list, &ordered_objects); @@ -600,8 +643,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, has_fenced_gpu_access && entry->flags & EXEC_OBJECT_NEEDS_FENCE && obj->tiling_mode != I915_TILING_NONE; - need_mappable = - entry->relocation_count ? true : need_fence; + need_mappable = need_fence || need_reloc_mappable(obj); if ((entry->alignment && obj->gtt_offset & (entry->alignment - 1)) || (need_mappable && !obj->map_and_fenceable)) @@ -815,62 +857,6 @@ i915_gem_execbuffer_flush(struct drm_device *dev, return 0; } -static bool -intel_enable_semaphores(struct drm_device *dev) -{ - if (INTEL_INFO(dev)->gen < 6) - return 0; - - if (i915_semaphores >= 0) - return i915_semaphores; - - /* Enable semaphores on SNB when IO remapping is off */ - if (INTEL_INFO(dev)->gen == 6) - return !intel_iommu_enabled; - - return 1; -} - -static int -i915_gem_execbuffer_sync_rings(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; - - /* XXX gpu semaphores are implicated in various hard hangs on SNB */ - if (!intel_enable_semaphores(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; - } - - from->sync_seqno[idx] = seqno; - - return to->sync_to(to, from, seqno - 1); -} - static int i915_gem_execbuffer_wait_for_flips(struct intel_ring_buffer *ring, u32 flips) { @@ -937,7 +923,7 @@ i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring, } list_for_each_entry(obj, objects, exec_list) { - ret = i915_gem_execbuffer_sync_rings(obj, ring); + ret = i915_gem_object_sync(obj, ring); if (ret) return ret; } @@ -1015,11 +1001,14 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects, obj->pending_gpu_write = true; list_move_tail(&obj->gpu_write_list, &ring->gpu_write_list); - intel_mark_busy(ring->dev, obj); + if (obj->pin_count) /* check for potential scanout */ + intel_mark_busy(ring->dev, obj); } CTR3(KTR_DRM, "object_change_domain move_to_active %p %x %x", obj, old_read, old_write); } + + intel_mark_busy(ring->dev, NULL); } int i915_gem_sync_exec_requests; @@ -1051,8 +1040,10 @@ i915_gem_execbuffer_retire_commands(struct drm_device *dev, if (request == NULL || i915_add_request(ring, file, request)) { i915_gem_next_request_seqno(ring); free(request, DRM_I915_GEM); - } else if (i915_gem_sync_exec_requests) - i915_wait_request(ring, request->seqno, true); + } else if (i915_gem_sync_exec_requests) { + i915_wait_request(ring, request->seqno); + i915_gem_retire_requests(dev); + } } static void @@ -1154,10 +1145,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, ring = &dev_priv->rings[RCS]; break; case I915_EXEC_BSD: - if (!HAS_BSD(dev)) { - DRM_DEBUG("execbuf with invalid ring (BSD)\n"); - return -EINVAL; - } ring = &dev_priv->rings[VCS]; if (ctx_id != 0) { DRM_DEBUG("Ring %s doesn't support contexts\n", @@ -1166,10 +1153,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } break; case I915_EXEC_BLT: - if (!HAS_BLT(dev)) { - DRM_DEBUG("execbuf with invalid ring (BLT)\n"); - return -EINVAL; - } ring = &dev_priv->rings[BCS]; if (ctx_id != 0) { DRM_DEBUG("Ring %s doesn't support contexts\n", @@ -1183,6 +1166,11 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, ret = -EINVAL; goto pre_struct_lock_err; } + if (!intel_ring_initialized(ring)) { + DRM_DEBUG("execbuf with invalid ring: %d\n", + (int)(args->flags & I915_EXEC_RING_MASK)); + return -EINVAL; + } mode = args->flags & I915_EXEC_CONSTANTS_MASK; mask = I915_EXEC_CONSTANTS_MASK; @@ -1227,6 +1215,12 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto pre_struct_lock_err; } + if (INTEL_INFO(dev)->gen >= 5) { + DRM_DEBUG("clip rectangles are only valid on pre-gen5\n"); + ret = -EINVAL; + goto pre_struct_lock_err; + } + if (args->num_cliprects > UINT_MAX / sizeof(*cliprects)) { DRM_DEBUG("execbuf with %u cliprects\n", args->num_cliprects); @@ -1328,9 +1322,10 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, * so every billion or so execbuffers, we need to stall * the GPU in order to reset the counters. */ - ret = i915_gpu_idle(dev, true); + ret = i915_gpu_idle(dev); if (ret) goto err; + i915_gem_retire_requests(dev); KASSERT(ring->sync_seqno[i] == 0, ("Non-zero sync_seqno")); } diff --git a/sys/dev/drm2/i915/i915_gem_gtt.c b/sys/dev/drm2/i915/i915_gem_gtt.c index 6204c06349cb..ce6c53b494a3 100644 --- a/sys/dev/drm2/i915/i915_gem_gtt.c +++ b/sys/dev/drm2/i915/i915_gem_gtt.c @@ -245,7 +245,7 @@ do_idling(struct drm_i915_private *dev_priv) if (dev_priv->mm.gtt.do_idle_maps) { dev_priv->mm.interruptible = false; - if (i915_gpu_idle(dev_priv->dev, false)) { + if (i915_gpu_idle(dev_priv->dev)) { DRM_ERROR("Couldn't idle GPU\n"); /* Wait a bit, in hopes it avoids the hang */ DELAY(10); @@ -277,28 +277,21 @@ i915_gem_restore_gtt_mappings(struct drm_device *dev) list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) { i915_gem_clflush_object(obj); - i915_gem_gtt_rebind_object(obj, obj->cache_level); + i915_gem_gtt_bind_object(obj, obj->cache_level); } intel_gtt_chipset_flush(); } int -i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj) +i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj) { - unsigned int agp_type; - - agp_type = cache_level_to_agp_type(obj->base.dev, obj->cache_level); - intel_gtt_insert_pages(obj->gtt_space->start >> PAGE_SHIFT, - obj->base.size >> PAGE_SHIFT, obj->pages, agp_type); - - obj->has_global_gtt_mapping = 1; return (0); } void -i915_gem_gtt_rebind_object(struct drm_i915_gem_object *obj, +i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj, enum i915_cache_level cache_level) { struct drm_device *dev; @@ -312,11 +305,21 @@ i915_gem_gtt_rebind_object(struct drm_i915_gem_object *obj, intel_gtt_insert_pages(obj->gtt_space->start >> PAGE_SHIFT, obj->base.size >> PAGE_SHIFT, obj->pages, agp_type); - obj->has_global_gtt_mapping = 0; + obj->has_global_gtt_mapping = 1; } void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj) +{ + + intel_gtt_clear_range(obj->gtt_space->start >> PAGE_SHIFT, + obj->base.size >> PAGE_SHIFT); + + obj->has_global_gtt_mapping = 0; +} + +void +i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj) { struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -327,8 +330,35 @@ i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj) interruptible = do_idling(dev_priv); - intel_gtt_clear_range(obj->gtt_space->start >> PAGE_SHIFT, - obj->base.size >> PAGE_SHIFT); - undo_idling(dev_priv, interruptible); } + +int +i915_gem_init_global_gtt(struct drm_device *dev, unsigned long start, + unsigned long mappable_end, unsigned long end) +{ + drm_i915_private_t *dev_priv; + unsigned long mappable; + int error; + + dev_priv = dev->dev_private; + mappable = min(end, mappable_end) - start; + + /* Substract the guard page ... */ + drm_mm_init(&dev_priv->mm.gtt_space, start, end - start - PAGE_SIZE); + + dev_priv->mm.gtt_start = start; + dev_priv->mm.gtt_mappable_end = mappable_end; + dev_priv->mm.gtt_end = end; + dev_priv->mm.gtt_total = end - start; + dev_priv->mm.mappable_gtt_total = mappable; + + /* ... but ensure that we clear the entire range. */ + intel_gtt_clear_range(start / PAGE_SIZE, (end-start) / PAGE_SIZE); + device_printf(dev->device, + "taking over the fictitious range 0x%lx-0x%lx\n", + dev->agp->base + start, dev->agp->base + start + mappable); + error = -vm_phys_fictitious_reg_range(dev->agp->base + start, + dev->agp->base + start + mappable, VM_MEMATTR_WRITE_COMBINING); + return (error); +} diff --git a/sys/dev/drm2/i915/i915_gem_stolen.c b/sys/dev/drm2/i915/i915_gem_stolen.c new file mode 100644 index 000000000000..1955a112f4a4 --- /dev/null +++ b/sys/dev/drm2/i915/i915_gem_stolen.c @@ -0,0 +1,205 @@ +/* + * Copyright © 2008-2012 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 + * Chris Wilson + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +/* + * The BIOS typically reserves some of the system's memory for the exclusive + * use of the integrated graphics. This memory is no longer available for + * use by the OS and so the user finds that his system has less memory + * available than he put in. We refer to this memory as stolen. + * + * The BIOS will allocate its framebuffer from the stolen memory. Our + * goal is try to reuse that object for our own fbcon which must always + * be available for panics. Anything else we can reuse the stolen memory + * for is a boon. + */ + +#define PTE_ADDRESS_MASK 0xfffff000 +#define PTE_ADDRESS_MASK_HIGH 0x000000f0 /* i915+ */ +#define PTE_MAPPING_TYPE_UNCACHED (0 << 1) +#define PTE_MAPPING_TYPE_DCACHE (1 << 1) /* i830 only */ +#define PTE_MAPPING_TYPE_CACHED (3 << 1) +#define PTE_MAPPING_TYPE_MASK (3 << 1) +#define PTE_VALID (1 << 0) + +/** + * i915_stolen_to_phys - take an offset into stolen memory and turn it into + * a physical one + * @dev: drm device + * @offset: address to translate + * + * Some chip functions require allocations from stolen space and need the + * physical address of the memory in question. + */ +static unsigned long i915_stolen_to_phys(struct drm_device *dev, u32 offset) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + device_t pdev = dev_priv->bridge_dev; + u32 base; + +#if 0 + /* On the machines I have tested the Graphics Base of Stolen Memory + * is unreliable, so compute the base by subtracting the stolen memory + * from the Top of Low Usable DRAM which is where the BIOS places + * the graphics stolen memory. + */ + if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) { + /* top 32bits are reserved = 0 */ + pci_read_config_dword(pdev, 0xA4, &base); + } else { + /* XXX presume 8xx is the same as i915 */ + pci_bus_read_config_dword(pdev->bus, 2, 0x5C, &base); + } +#else + if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) { + u16 val; + val = pci_read_config(pdev, 0xb0, 2); + base = val >> 4 << 20; + } else { + u8 val; + val = pci_read_config(pdev, 0x9c, 1); + base = val >> 3 << 27; + } + base -= dev_priv->mm.gtt.stolen_size; +#endif + + return base + offset; +} + +static void i915_warn_stolen(struct drm_device *dev) +{ + DRM_INFO("not enough stolen space for compressed buffer, disabling\n"); + DRM_INFO("hint: you may be able to increase stolen memory size in the BIOS to avoid this\n"); +} + +static void i915_setup_compression(struct drm_device *dev, int size) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_mm_node *compressed_fb, *compressed_llb; + unsigned long cfb_base; + unsigned long ll_base = 0; + + /* Just in case the BIOS is doing something questionable. */ + intel_disable_fbc(dev); + + compressed_fb = drm_mm_search_free(&dev_priv->mm.stolen, size, 4096, 0); + if (compressed_fb) + compressed_fb = drm_mm_get_block(compressed_fb, size, 4096); + if (!compressed_fb) + goto err; + + cfb_base = i915_stolen_to_phys(dev, compressed_fb->start); + if (!cfb_base) + goto err_fb; + + if (!(IS_GM45(dev) || HAS_PCH_SPLIT(dev))) { + compressed_llb = drm_mm_search_free(&dev_priv->mm.stolen, + 4096, 4096, 0); + if (compressed_llb) + compressed_llb = drm_mm_get_block(compressed_llb, + 4096, 4096); + if (!compressed_llb) + goto err_fb; + + ll_base = i915_stolen_to_phys(dev, compressed_llb->start); + if (!ll_base) + goto err_llb; + } + + dev_priv->cfb_size = size; + + dev_priv->compressed_fb = compressed_fb; + if (HAS_PCH_SPLIT(dev)) + I915_WRITE(ILK_DPFC_CB_BASE, compressed_fb->start); + else if (IS_GM45(dev)) { + I915_WRITE(DPFC_CB_BASE, compressed_fb->start); + } else { + I915_WRITE(FBC_CFB_BASE, cfb_base); + I915_WRITE(FBC_LL_BASE, ll_base); + dev_priv->compressed_llb = compressed_llb; + } + + DRM_DEBUG_KMS("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n", + cfb_base, ll_base, size >> 20); + return; + +err_llb: + drm_mm_put_block(compressed_llb); +err_fb: + drm_mm_put_block(compressed_fb); +err: + dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL; + i915_warn_stolen(dev); +} + +static void i915_cleanup_compression(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + drm_mm_put_block(dev_priv->compressed_fb); + if (dev_priv->compressed_llb) + drm_mm_put_block(dev_priv->compressed_llb); +} + +void i915_gem_cleanup_stolen(struct drm_device *dev) +{ + if (I915_HAS_FBC(dev) && i915_powersave) + i915_cleanup_compression(dev); +} + +int i915_gem_init_stolen(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long prealloc_size = dev_priv->mm.gtt.stolen_size; + + /* Basic memrange allocator for stolen space */ + drm_mm_init(&dev_priv->mm.stolen, 0, prealloc_size); + + /* Try to set up FBC with a reasonable compressed buffer size */ + if (I915_HAS_FBC(dev) && i915_powersave) { + int cfb_size; + + /* Leave 1M for line length buffer & misc. */ + + /* Try to get a 32M buffer... */ + if (prealloc_size > (36*1024*1024)) + cfb_size = 32*1024*1024; + else /* fall back to 7/8 of the stolen space */ + cfb_size = prealloc_size * 7 / 8; + i915_setup_compression(dev, cfb_size); + } + + return 0; +} diff --git a/sys/dev/drm2/i915/i915_gem_tiling.c b/sys/dev/drm2/i915/i915_gem_tiling.c index b3d98c8768d8..6ca39627f054 100644 --- a/sys/dev/drm2/i915/i915_gem_tiling.c +++ b/sys/dev/drm2/i915/i915_gem_tiling.c @@ -357,11 +357,18 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, /* We need to rebind the object if its current allocation * no longer meets the alignment restrictions for its new * tiling mode. Otherwise we can just leave it alone, but - * need to ensure that any fence register is cleared. + * need to ensure that any fence register is updated before + * the next fenced (either through the GTT or by the BLT unit + * on older GPUs) access. + * + * After updating the tiling parameters, we then flag whether + * we need to update an associated fence register. Note this + * has to also include the unfenced register the GPU uses + * whilst executing a fenced command for an untiled object. */ - i915_gem_release_mmap(obj); - obj->map_and_fenceable = obj->gtt_space == NULL || + obj->map_and_fenceable = + obj->gtt_space == NULL || (obj->gtt_offset + obj->base.size <= dev_priv->mm.gtt_mappable_end && i915_gem_object_fence_ok(obj, args->tiling_mode)); @@ -374,12 +381,20 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, if (obj->gtt_offset & (unfenced_alignment - 1)) ret = i915_gem_object_unbind(obj); } + if (ret == 0) { - obj->tiling_changed = true; + obj->fence_dirty = + obj->fenced_gpu_access || + obj->fence_reg != I915_FENCE_REG_NONE; + + obj->tiling_mode = args->tiling_mode; obj->stride = args->stride; + + /* Force the fence to be reacquired for GTT access */ + i915_gem_release_mmap(obj); } - } + } /* we have to maintain this existing ABI... */ args->stride = obj->stride; args->tiling_mode = obj->tiling_mode; @@ -455,6 +470,22 @@ i915_gem_swizzle_page(vm_page_t m) sf_buf_free(sf); } +void +i915_gem_object_do_bit_17_swizzle_page(struct drm_i915_gem_object *obj, + vm_page_t m) +{ + char new_bit_17; + + if (obj->bit_17 == NULL) + return; + + new_bit_17 = VM_PAGE_TO_PHYS(m) >> 17; + if ((new_bit_17 & 0x1) != (test_bit(m->pindex, obj->bit_17) != 0)) { + i915_gem_swizzle_page(m); + vm_page_dirty(m); + } +} + void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj) { diff --git a/sys/dev/drm2/i915/i915_irq.c b/sys/dev/drm2/i915/i915_irq.c index 15d0a613d101..346d9c07467c 100644 --- a/sys/dev/drm2/i915/i915_irq.c +++ b/sys/dev/drm2/i915/i915_irq.c @@ -36,37 +36,11 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include static void i915_capture_error_state(struct drm_device *dev); static u32 ring_last_seqno(struct intel_ring_buffer *ring); -/** - * Interrupts that are always left unmasked. - * - * Since pipe events are edge-triggered from the PIPESTAT register to IIR, - * we leave them always unmasked in IMR and then control enabling them through - * PIPESTAT alone. - */ -#define I915_INTERRUPT_ENABLE_FIX \ - (I915_ASLE_INTERRUPT | \ - I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \ - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | \ - I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | \ - I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT | \ - I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) - -/** Interrupts that we mask and unmask at runtime. */ -#define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT | I915_BSD_USER_INTERRUPT) - -#define I915_PIPE_VBLANK_STATUS (PIPE_START_VBLANK_INTERRUPT_STATUS |\ - PIPE_VBLANK_INTERRUPT_STATUS) - -#define I915_PIPE_VBLANK_ENABLE (PIPE_START_VBLANK_INTERRUPT_ENABLE |\ - PIPE_VBLANK_INTERRUPT_ENABLE) - -#define DRM_I915_VBLANK_PIPE_ALL (DRM_I915_VBLANK_PIPE_A | \ - DRM_I915_VBLANK_PIPE_B) - /* For display hotplug interrupt */ static void ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask) @@ -120,6 +94,10 @@ void intel_enable_asle(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; + /* FIXME: opregion/asle for VLV */ + if (IS_VALLEYVIEW(dev)) + return; + mtx_lock(&dev_priv->irq_lock); if (HAS_PCH_SPLIT(dev)) @@ -368,18 +346,16 @@ static void notify_ring(struct drm_device *dev, struct intel_ring_buffer *ring) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 seqno; if (ring->obj == NULL) return; - seqno = ring->get_seqno(ring); - CTR2(KTR_DRM, "request_complete %s %d", ring->name, seqno); + CTR2(KTR_DRM, "request_complete %s %d", ring->name, + ring->get_seqno(ring)); - mtx_lock(&ring->irq_lock); - ring->irq_seqno = seqno; + mtx_lock(&dev_priv->irq_lock); wakeup(ring); - mtx_unlock(&ring->irq_lock); + mtx_unlock(&dev_priv->irq_lock); if (i915_enable_hangcheck) { dev_priv->hangcheck_count = 0; @@ -445,14 +421,141 @@ gen6_pm_rps_work_func(void *arg, int pending) DRM_UNLOCK(dev); } -static void pch_irq_handler(struct drm_device *dev) +static void snb_gt_irq_handler(struct drm_device *dev, + struct drm_i915_private *dev_priv, + u32 gt_iir) +{ + + if (gt_iir & (GEN6_RENDER_USER_INTERRUPT | + GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT)) + notify_ring(dev, &dev_priv->rings[RCS]); + if (gt_iir & GEN6_BSD_USER_INTERRUPT) + notify_ring(dev, &dev_priv->rings[VCS]); + if (gt_iir & GEN6_BLITTER_USER_INTERRUPT) + notify_ring(dev, &dev_priv->rings[BCS]); + + if (gt_iir & (GT_GEN6_BLT_CS_ERROR_INTERRUPT | + GT_GEN6_BSD_CS_ERROR_INTERRUPT | + GT_RENDER_CS_ERROR_INTERRUPT)) { + DRM_ERROR("GT error interrupt 0x%08x\n", gt_iir); + i915_handle_error(dev, false); + } +} + +static void gen6_queue_rps_work(struct drm_i915_private *dev_priv, + u32 pm_iir) +{ + + /* + * IIR bits should never already be set because IMR should + * prevent an interrupt from being shown in IIR. The warning + * displays a case where we've unsafely cleared + * dev_priv->pm_iir. Although missing an interrupt of the same + * type is not a problem, it displays a problem in the logic. + * + * The mask bit in IMR is cleared by rps_work. + */ + + mtx_lock(&dev_priv->rps_lock); + if (dev_priv->pm_iir & pm_iir) + printf("Missed a PM interrupt\n"); + dev_priv->pm_iir |= pm_iir; + I915_WRITE(GEN6_PMIMR, dev_priv->pm_iir); + POSTING_READ(GEN6_PMIMR); + mtx_unlock(&dev_priv->rps_lock); + + taskqueue_enqueue(dev_priv->tq, &dev_priv->rps_task); +} + +static void valleyview_irq_handler(void *arg) +{ + struct drm_device *dev = (struct drm_device *) arg; + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 iir, gt_iir, pm_iir; + int pipe; + u32 pipe_stats[I915_MAX_PIPES]; + u32 vblank_status; + int vblank = 0; + bool blc_event; + + atomic_inc(&dev_priv->irq_received); + + vblank_status = PIPE_START_VBLANK_INTERRUPT_STATUS | + PIPE_VBLANK_INTERRUPT_STATUS; + + while (true) { + iir = I915_READ(VLV_IIR); + gt_iir = I915_READ(GTIIR); + pm_iir = I915_READ(GEN6_PMIIR); + + if (gt_iir == 0 && pm_iir == 0 && iir == 0) + goto out; + + snb_gt_irq_handler(dev, dev_priv, gt_iir); + + mtx_lock(&dev_priv->irq_lock); + for_each_pipe(pipe) { + int reg = PIPESTAT(pipe); + pipe_stats[pipe] = I915_READ(reg); + + /* + * Clear the PIPE*STAT regs before the IIR + */ + if (pipe_stats[pipe] & 0x8000ffff) { + if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS) + DRM_DEBUG_DRIVER("pipe %c underrun\n", + pipe_name(pipe)); + I915_WRITE(reg, pipe_stats[pipe]); + } + } + mtx_unlock(&dev_priv->irq_lock); + + /* Consume port. Then clear IIR or we'll miss events */ + if (iir & I915_DISPLAY_PORT_INTERRUPT) { + u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); + + DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", + hotplug_status); + if (hotplug_status & dev_priv->hotplug_supported_mask) + taskqueue_enqueue(dev_priv->tq, + &dev_priv->hotplug_task); + + I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); + I915_READ(PORT_HOTPLUG_STAT); + } + + + if (iir & I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT) { + drm_handle_vblank(dev, 0); + vblank++; + intel_finish_page_flip(dev, 0); + } + + if (iir & I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT) { + drm_handle_vblank(dev, 1); + vblank++; + intel_finish_page_flip(dev, 0); + } + + if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) + blc_event = true; + + if (pm_iir & GEN6_PM_DEFERRED_EVENTS) + gen6_queue_rps_work(dev_priv, pm_iir); + + I915_WRITE(GTIIR, gt_iir); + I915_WRITE(GEN6_PMIIR, pm_iir); + I915_WRITE(VLV_IIR, iir); + } + +out:; +} + +static void pch_irq_handler(struct drm_device *dev, u32 pch_iir) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 pch_iir; int pipe; - pch_iir = I915_READ(SDEIIR); - if (pch_iir & SDE_AUDIO_POWER_MASK) DRM_DEBUG("i915: PCH audio power change on port %d\n", (pch_iir & SDE_AUDIO_POWER_MASK) >> @@ -493,10 +596,8 @@ ivybridge_irq_handler(void *arg) { struct drm_device *dev = (struct drm_device *) arg; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir; -#if 0 - struct drm_i915_master_private *master_priv; -#endif + u32 de_iir, gt_iir, de_ier, pm_iir; + int i; atomic_inc(&dev_priv->irq_received); @@ -505,84 +606,64 @@ ivybridge_irq_handler(void *arg) I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL); POSTING_READ(DEIER); + gt_iir = I915_READ(GTIIR); + if (gt_iir) { + snb_gt_irq_handler(dev, dev_priv, gt_iir); + I915_WRITE(GTIIR, gt_iir); + } + de_iir = I915_READ(DEIIR); - gt_iir = I915_READ(GTIIR); - pch_iir = I915_READ(SDEIIR); + if (de_iir) { + if (de_iir & DE_GSE_IVB) + intel_opregion_gse_intr(dev); + + for (i = 0; i < 3; i++) { + if (de_iir & (DE_PLANEA_FLIP_DONE_IVB << (5 * i))) { + intel_prepare_page_flip(dev, i); + intel_finish_page_flip_plane(dev, i); + } + if (de_iir & (DE_PIPEA_VBLANK_IVB << (5 * i))) + drm_handle_vblank(dev, i); + } + + /* check event from PCH */ + if (de_iir & DE_PCH_EVENT_IVB) { + u32 pch_iir = I915_READ(SDEIIR); + + if (pch_iir & SDE_HOTPLUG_MASK_CPT) + taskqueue_enqueue(dev_priv->tq, + &dev_priv->hotplug_task); + pch_irq_handler(dev, pch_iir); + + /* clear PCH hotplug event before clear CPU irq */ + I915_WRITE(SDEIIR, pch_iir); + } + + I915_WRITE(DEIIR, de_iir); + } + pm_iir = I915_READ(GEN6_PMIIR); - - CTR4(KTR_DRM, "ivybridge_irq de %x gt %x pch %x pm %x", de_iir, - gt_iir, pch_iir, pm_iir); - - if (de_iir == 0 && gt_iir == 0 && pch_iir == 0 && pm_iir == 0) - goto done; - -#if 0 - if (dev->primary->master) { - master_priv = dev->primary->master->driver_priv; - if (master_priv->sarea_priv) - master_priv->sarea_priv->last_dispatch = - READ_BREADCRUMB(dev_priv); - } -#else - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->last_dispatch = - READ_BREADCRUMB(dev_priv); -#endif - - if (gt_iir & (GT_USER_INTERRUPT | GT_PIPE_NOTIFY)) - notify_ring(dev, &dev_priv->rings[RCS]); - if (gt_iir & GT_GEN6_BSD_USER_INTERRUPT) - notify_ring(dev, &dev_priv->rings[VCS]); - if (gt_iir & GT_BLT_USER_INTERRUPT) - notify_ring(dev, &dev_priv->rings[BCS]); - - if (de_iir & DE_GSE_IVB) { - intel_opregion_gse_intr(dev); + if (pm_iir) { + if (pm_iir & GEN6_PM_DEFERRED_EVENTS) + gen6_queue_rps_work(dev_priv, pm_iir); + I915_WRITE(GEN6_PMIIR, pm_iir); } - if (de_iir & DE_PLANEA_FLIP_DONE_IVB) { - intel_prepare_page_flip(dev, 0); - intel_finish_page_flip_plane(dev, 0); - } - - if (de_iir & DE_PLANEB_FLIP_DONE_IVB) { - intel_prepare_page_flip(dev, 1); - intel_finish_page_flip_plane(dev, 1); - } - - if (de_iir & DE_PIPEA_VBLANK_IVB) - drm_handle_vblank(dev, 0); - - if (de_iir & DE_PIPEB_VBLANK_IVB) - drm_handle_vblank(dev, 1); - - /* check event from PCH */ - if (de_iir & DE_PCH_EVENT_IVB) { - if (pch_iir & SDE_HOTPLUG_MASK_CPT) - taskqueue_enqueue(dev_priv->tq, &dev_priv->hotplug_task); - pch_irq_handler(dev); - } - - if (pm_iir & GEN6_PM_DEFERRED_EVENTS) { - mtx_lock(&dev_priv->rps_lock); - if ((dev_priv->pm_iir & pm_iir) != 0) - printf("Missed a PM interrupt\n"); - dev_priv->pm_iir |= pm_iir; - I915_WRITE(GEN6_PMIMR, dev_priv->pm_iir); - POSTING_READ(GEN6_PMIMR); - mtx_unlock(&dev_priv->rps_lock); - taskqueue_enqueue(dev_priv->tq, &dev_priv->rps_task); - } - - /* should clear PCH hotplug event before clear CPU irq */ - I915_WRITE(SDEIIR, pch_iir); - I915_WRITE(GTIIR, gt_iir); - I915_WRITE(DEIIR, de_iir); - I915_WRITE(GEN6_PMIIR, pm_iir); - -done: I915_WRITE(DEIER, de_ier); POSTING_READ(DEIER); + + CTR3(KTR_DRM, "ivybridge_irq de %x gt %x pm %x", de_iir, + gt_iir, pm_iir); +} + +static void ilk_gt_irq_handler(struct drm_device *dev, + struct drm_i915_private *dev_priv, + u32 gt_iir) +{ + if (gt_iir & (GT_USER_INTERRUPT | GT_PIPE_NOTIFY)) + notify_ring(dev, &dev_priv->rings[RCS]); + if (gt_iir & GT_BSD_USER_INTERRUPT) + notify_ring(dev, &dev_priv->rings[VCS]); } static void @@ -592,16 +673,9 @@ ironlake_irq_handler(void *arg) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir; u32 hotplug_mask; -#if 0 - struct drm_i915_master_private *master_priv; -#endif - u32 bsd_usr_interrupt = GT_BSD_USER_INTERRUPT; atomic_inc(&dev_priv->irq_received); - if (IS_GEN6(dev)) - bsd_usr_interrupt = GT_GEN6_BSD_USER_INTERRUPT; - /* disable master interrupt before clearing iir */ de_ier = I915_READ(DEIER); I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL); @@ -624,25 +698,10 @@ ironlake_irq_handler(void *arg) else hotplug_mask = SDE_HOTPLUG_MASK; -#if 0 - if (dev->primary->master) { - master_priv = dev->primary->master->driver_priv; - if (master_priv->sarea_priv) - master_priv->sarea_priv->last_dispatch = - READ_BREADCRUMB(dev_priv); - } -#else - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->last_dispatch = - READ_BREADCRUMB(dev_priv); -#endif - - if (gt_iir & (GT_USER_INTERRUPT | GT_PIPE_NOTIFY)) - notify_ring(dev, &dev_priv->rings[RCS]); - if (gt_iir & bsd_usr_interrupt) - notify_ring(dev, &dev_priv->rings[VCS]); - if (gt_iir & GT_BLT_USER_INTERRUPT) - notify_ring(dev, &dev_priv->rings[BCS]); + if (IS_GEN5(dev)) + ilk_gt_irq_handler(dev, dev_priv, gt_iir); + else + snb_gt_irq_handler(dev, dev_priv, gt_iir); if (de_iir & DE_GSE) { intel_opregion_gse_intr(dev); @@ -669,7 +728,7 @@ ironlake_irq_handler(void *arg) if (pch_iir & hotplug_mask) taskqueue_enqueue(dev_priv->tq, &dev_priv->hotplug_task); - pch_irq_handler(dev); + pch_irq_handler(dev, pch_iir); } if (de_iir & DE_PCU_EVENT) { @@ -677,16 +736,8 @@ ironlake_irq_handler(void *arg) i915_handle_rps_change(dev); } - if (pm_iir & GEN6_PM_DEFERRED_EVENTS) { - mtx_lock(&dev_priv->rps_lock); - if ((dev_priv->pm_iir & pm_iir) != 0) - printf("Missed a PM interrupt\n"); - dev_priv->pm_iir |= pm_iir; - I915_WRITE(GEN6_PMIMR, dev_priv->pm_iir); - POSTING_READ(GEN6_PMIMR); - mtx_unlock(&dev_priv->rps_lock); - taskqueue_enqueue(dev_priv->tq, &dev_priv->rps_task); - } + if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS) + gen6_queue_rps_work(dev_priv, pm_iir); /* should clear PCH hotplug event before clear CPU irq */ I915_WRITE(SDEIIR, pch_iir); @@ -728,6 +779,8 @@ i915_error_work_func(void *context, int pending) } } +#define pr_err(...) printf(__VA_ARGS__) + static void i915_report_and_clear_eir(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -743,26 +796,20 @@ static void i915_report_and_clear_eir(struct drm_device *dev) if (eir & (GM45_ERROR_MEM_PRIV | GM45_ERROR_CP_PRIV)) { u32 ipeir = I915_READ(IPEIR_I965); - printf(" IPEIR: 0x%08x\n", - I915_READ(IPEIR_I965)); - printf(" IPEHR: 0x%08x\n", - I915_READ(IPEHR_I965)); - printf(" INSTDONE: 0x%08x\n", + pr_err(" IPEIR: 0x%08x\n", I915_READ(IPEIR_I965)); + pr_err(" IPEHR: 0x%08x\n", I915_READ(IPEHR_I965)); + pr_err(" INSTDONE: 0x%08x\n", I915_READ(INSTDONE_I965)); - printf(" INSTPS: 0x%08x\n", - I915_READ(INSTPS)); - printf(" INSTDONE1: 0x%08x\n", - I915_READ(INSTDONE1)); - printf(" ACTHD: 0x%08x\n", - I915_READ(ACTHD_I965)); + pr_err(" INSTPS: 0x%08x\n", I915_READ(INSTPS)); + pr_err(" INSTDONE1: 0x%08x\n", I915_READ(INSTDONE1)); + pr_err(" ACTHD: 0x%08x\n", I915_READ(ACTHD_I965)); I915_WRITE(IPEIR_I965, ipeir); POSTING_READ(IPEIR_I965); } if (eir & GM45_ERROR_PAGE_TABLE) { u32 pgtbl_err = I915_READ(PGTBL_ER); - printf("page table error\n"); - printf(" PGTBL_ER: 0x%08x\n", - pgtbl_err); + pr_err("page table error\n"); + pr_err(" PGTBL_ER: 0x%08x\n", pgtbl_err); I915_WRITE(PGTBL_ER, pgtbl_err); POSTING_READ(PGTBL_ER); } @@ -771,53 +818,42 @@ static void i915_report_and_clear_eir(struct drm_device *dev) if (!IS_GEN2(dev)) { if (eir & I915_ERROR_PAGE_TABLE) { u32 pgtbl_err = I915_READ(PGTBL_ER); - printf("page table error\n"); - printf(" PGTBL_ER: 0x%08x\n", - pgtbl_err); + pr_err("page table error\n"); + pr_err(" PGTBL_ER: 0x%08x\n", pgtbl_err); I915_WRITE(PGTBL_ER, pgtbl_err); POSTING_READ(PGTBL_ER); } } if (eir & I915_ERROR_MEMORY_REFRESH) { - printf("memory refresh error:\n"); + pr_err("memory refresh error:\n"); for_each_pipe(pipe) - printf("pipe %c stat: 0x%08x\n", + pr_err("pipe %c stat: 0x%08x\n", pipe_name(pipe), I915_READ(PIPESTAT(pipe))); /* pipestat has already been acked */ } if (eir & I915_ERROR_INSTRUCTION) { - printf("instruction error\n"); - printf(" INSTPM: 0x%08x\n", - I915_READ(INSTPM)); + pr_err("instruction error\n"); + pr_err(" INSTPM: 0x%08x\n", I915_READ(INSTPM)); if (INTEL_INFO(dev)->gen < 4) { u32 ipeir = I915_READ(IPEIR); - printf(" IPEIR: 0x%08x\n", - I915_READ(IPEIR)); - printf(" IPEHR: 0x%08x\n", - I915_READ(IPEHR)); - printf(" INSTDONE: 0x%08x\n", - I915_READ(INSTDONE)); - printf(" ACTHD: 0x%08x\n", - I915_READ(ACTHD)); + pr_err(" IPEIR: 0x%08x\n", I915_READ(IPEIR)); + pr_err(" IPEHR: 0x%08x\n", I915_READ(IPEHR)); + pr_err(" INSTDONE: 0x%08x\n", I915_READ(INSTDONE)); + pr_err(" ACTHD: 0x%08x\n", I915_READ(ACTHD)); I915_WRITE(IPEIR, ipeir); POSTING_READ(IPEIR); } else { u32 ipeir = I915_READ(IPEIR_I965); - printf(" IPEIR: 0x%08x\n", - I915_READ(IPEIR_I965)); - printf(" IPEHR: 0x%08x\n", - I915_READ(IPEHR_I965)); - printf(" INSTDONE: 0x%08x\n", + pr_err(" IPEIR: 0x%08x\n", I915_READ(IPEIR_I965)); + pr_err(" IPEHR: 0x%08x\n", I915_READ(IPEHR_I965)); + pr_err(" INSTDONE: 0x%08x\n", I915_READ(INSTDONE_I965)); - printf(" INSTPS: 0x%08x\n", - I915_READ(INSTPS)); - printf(" INSTDONE1: 0x%08x\n", - I915_READ(INSTDONE1)); - printf(" ACTHD: 0x%08x\n", - I915_READ(ACTHD_I965)); + pr_err(" INSTPS: 0x%08x\n", I915_READ(INSTPS)); + pr_err(" INSTDONE1: 0x%08x\n", I915_READ(INSTDONE1)); + pr_err(" ACTHD: 0x%08x\n", I915_READ(ACTHD_I965)); I915_WRITE(IPEIR_I965, ipeir); POSTING_READ(IPEIR_I965); } @@ -850,6 +886,8 @@ static void i915_report_and_clear_eir(struct drm_device *dev) void i915_handle_error(struct drm_device *dev, bool wedged) { struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring; + int i; i915_capture_error_state(dev); i915_report_and_clear_eir(dev); @@ -864,18 +902,10 @@ void i915_handle_error(struct drm_device *dev, bool wedged) /* * Wakeup waiting processes so they don't hang */ - mtx_lock(&dev_priv->rings[RCS].irq_lock); - wakeup(&dev_priv->rings[RCS]); - mtx_unlock(&dev_priv->rings[RCS].irq_lock); - if (HAS_BSD(dev)) { - mtx_lock(&dev_priv->rings[VCS].irq_lock); - wakeup(&dev_priv->rings[VCS]); - mtx_unlock(&dev_priv->rings[VCS].irq_lock); - } - if (HAS_BLT(dev)) { - mtx_lock(&dev_priv->rings[BCS].irq_lock); - wakeup(&dev_priv->rings[BCS]); - mtx_unlock(&dev_priv->rings[BCS].irq_lock); + for_each_ring(ring, dev_priv, i) { + mtx_lock(&dev_priv->irq_lock); + wakeup(ring); + mtx_unlock(&dev_priv->irq_lock); } } @@ -908,7 +938,8 @@ static void i915_pageflip_stall_check(struct drm_device *dev, int pipe) obj = work->pending_flip_obj; if (INTEL_INFO(dev)->gen >= 4) { int dspsurf = DSPSURF(intel_crtc->plane); - stall_detected = I915_READ(dspsurf) == obj->gtt_offset; + stall_detected = I915_HI_DISPBASE(I915_READ(dspsurf)) == + obj->gtt_offset; } else { int dspaddr = DSPADDR(intel_crtc->plane); stall_detected = I915_READ(dspaddr) == (obj->gtt_offset + @@ -924,288 +955,6 @@ static void i915_pageflip_stall_check(struct drm_device *dev, int pipe) } } -static void -i915_driver_irq_handler(void *arg) -{ - struct drm_device *dev = (struct drm_device *)arg; - drm_i915_private_t *dev_priv = (drm_i915_private_t *)dev->dev_private; -#if 0 - struct drm_i915_master_private *master_priv; -#endif - u32 iir, new_iir; - u32 pipe_stats[I915_MAX_PIPES]; - u32 vblank_status; - int vblank = 0; - int irq_received; - int pipe; - bool blc_event = false; - - atomic_inc(&dev_priv->irq_received); - - iir = I915_READ(IIR); - - CTR1(KTR_DRM, "driver_irq_handler %x", iir); - - if (INTEL_INFO(dev)->gen >= 4) - vblank_status = PIPE_START_VBLANK_INTERRUPT_STATUS; - else - vblank_status = PIPE_VBLANK_INTERRUPT_STATUS; - - for (;;) { - irq_received = iir != 0; - - /* Can't rely on pipestat interrupt bit in iir as it might - * have been cleared after the pipestat interrupt was received. - * It doesn't set the bit in iir again, but it still produces - * interrupts (for non-MSI). - */ - mtx_lock(&dev_priv->irq_lock); - if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) - i915_handle_error(dev, false); - - for_each_pipe(pipe) { - int reg = PIPESTAT(pipe); - pipe_stats[pipe] = I915_READ(reg); - - /* - * Clear the PIPE*STAT regs before the IIR - */ - if (pipe_stats[pipe] & 0x8000ffff) { - if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS) - DRM_DEBUG("pipe %c underrun\n", - pipe_name(pipe)); - I915_WRITE(reg, pipe_stats[pipe]); - irq_received = 1; - } - } - mtx_unlock(&dev_priv->irq_lock); - - if (!irq_received) - break; - - /* Consume port. Then clear IIR or we'll miss events */ - if ((I915_HAS_HOTPLUG(dev)) && - (iir & I915_DISPLAY_PORT_INTERRUPT)) { - u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); - - DRM_DEBUG("i915: hotplug event received, stat 0x%08x\n", - hotplug_status); - if (hotplug_status & dev_priv->hotplug_supported_mask) - taskqueue_enqueue(dev_priv->tq, - &dev_priv->hotplug_task); - - I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); - I915_READ(PORT_HOTPLUG_STAT); - } - - I915_WRITE(IIR, iir); - new_iir = I915_READ(IIR); /* Flush posted writes */ - -#if 0 - if (dev->primary->master) { - master_priv = dev->primary->master->driver_priv; - if (master_priv->sarea_priv) - master_priv->sarea_priv->last_dispatch = - READ_BREADCRUMB(dev_priv); - } -#else - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->last_dispatch = - READ_BREADCRUMB(dev_priv); -#endif - - if (iir & I915_USER_INTERRUPT) - notify_ring(dev, &dev_priv->rings[RCS]); - if (iir & I915_BSD_USER_INTERRUPT) - notify_ring(dev, &dev_priv->rings[VCS]); - - if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) { - intel_prepare_page_flip(dev, 0); - if (dev_priv->flip_pending_is_done) - intel_finish_page_flip_plane(dev, 0); - } - - if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) { - intel_prepare_page_flip(dev, 1); - if (dev_priv->flip_pending_is_done) - intel_finish_page_flip_plane(dev, 1); - } - - for_each_pipe(pipe) { - if (pipe_stats[pipe] & vblank_status && - drm_handle_vblank(dev, pipe)) { - vblank++; - if (!dev_priv->flip_pending_is_done) { - i915_pageflip_stall_check(dev, pipe); - intel_finish_page_flip(dev, pipe); - } - } - - if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) - blc_event = true; - } - - - if (blc_event || (iir & I915_ASLE_INTERRUPT)) { - intel_opregion_asle_intr(dev); - } - - /* With MSI, interrupts are only generated when iir - * transitions from zero to nonzero. If another bit got - * set while we were handling the existing iir bits, then - * we would never get another interrupt. - * - * This is fine on non-MSI as well, as if we hit this path - * we avoid exiting the interrupt handler only to generate - * another one. - * - * Note that for MSI this could cause a stray interrupt report - * if an interrupt landed in the time between writing IIR and - * the posting read. This should be rare enough to never - * trigger the 99% of 100,000 interrupts test for disabling - * stray interrupts. - */ - iir = new_iir; - } -} - -static int i915_emit_irq(struct drm_device * dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; -#if 0 - struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; -#endif - - i915_kernel_lost_context(dev); - - DRM_DEBUG("i915: emit_irq\n"); - - dev_priv->counter++; - if (dev_priv->counter > 0x7FFFFFFFUL) - dev_priv->counter = 1; -#if 0 - if (master_priv->sarea_priv) - master_priv->sarea_priv->last_enqueue = dev_priv->counter; -#else - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->last_enqueue = dev_priv->counter; -#endif - - if (BEGIN_LP_RING(4) == 0) { - OUT_RING(MI_STORE_DWORD_INDEX); - OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - OUT_RING(dev_priv->counter); - OUT_RING(MI_USER_INTERRUPT); - ADVANCE_LP_RING(); - } - - return dev_priv->counter; -} - -static int i915_wait_irq(struct drm_device * dev, int irq_nr) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; -#if 0 - struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; -#endif - int ret; - struct intel_ring_buffer *ring = LP_RING(dev_priv); - - DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr, - READ_BREADCRUMB(dev_priv)); - -#if 0 - if (READ_BREADCRUMB(dev_priv) >= irq_nr) { - if (master_priv->sarea_priv) - master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); - return 0; - } - - if (master_priv->sarea_priv) - master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; -#else - if (READ_BREADCRUMB(dev_priv) >= irq_nr) { - if (dev_priv->sarea_priv) { - dev_priv->sarea_priv->last_dispatch = - READ_BREADCRUMB(dev_priv); - } - return 0; - } - - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; -#endif - - ret = 0; - mtx_lock(&ring->irq_lock); - if (ring->irq_get(ring)) { - DRM_UNLOCK(dev); - while (ret == 0 && READ_BREADCRUMB(dev_priv) < irq_nr) { - ret = -msleep(ring, &ring->irq_lock, PCATCH, - "915wtq", 3 * hz); - } - ring->irq_put(ring); - mtx_unlock(&ring->irq_lock); - DRM_LOCK(dev); - } else { - mtx_unlock(&ring->irq_lock); - if (_intel_wait_for(dev, READ_BREADCRUMB(dev_priv) >= irq_nr, - 3000, 1, "915wir")) - ret = -EBUSY; - } - - if (ret == -EBUSY) { - DRM_ERROR("EBUSY -- rec: %d emitted: %d\n", - READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); - } - - return ret; -} - -/* Needs the lock as it touches the ring. - */ -int i915_irq_emit(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_irq_emit_t *emit = data; - int result; - - if (!dev_priv || !LP_RING(dev_priv)->virtual_start) { - DRM_ERROR("called with no initialization\n"); - return -EINVAL; - } - - RING_LOCK_TEST_WITH_RETURN(dev, file_priv); - - DRM_LOCK(dev); - result = i915_emit_irq(dev); - DRM_UNLOCK(dev); - - if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) { - DRM_ERROR("copy_to_user\n"); - return -EFAULT; - } - - return 0; -} - -/* Doesn't need the hardware lock. - */ -int i915_irq_wait(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_irq_wait_t *irqwait = data; - - if (!dev_priv) { - DRM_ERROR("called with no initialization\n"); - return -EINVAL; - } - - return i915_wait_irq(dev, irqwait->irq_seq); -} - /* Called from drm generic code, passed 'crtc' which * we use as a pipe index */ @@ -1227,7 +976,7 @@ i915_enable_vblank(struct drm_device *dev, int pipe) /* maintain vblank delivery even in deep C-states */ if (dev_priv->info->gen == 3) - I915_WRITE(INSTPM, INSTPM_AGPBUSY_DIS << 16); + I915_WRITE(INSTPM, _MASKED_BIT_DISABLE(INSTPM_AGPBUSY_DIS)); mtx_unlock(&dev_priv->irq_lock); CTR1(KTR_DRM, "i915_enable_vblank %d", pipe); @@ -1260,14 +1009,38 @@ ivybridge_enable_vblank(struct drm_device *dev, int pipe) return -EINVAL; mtx_lock(&dev_priv->irq_lock); - ironlake_enable_display_irq(dev_priv, (pipe == 0) ? - DE_PIPEA_VBLANK_IVB : DE_PIPEB_VBLANK_IVB); + ironlake_enable_display_irq(dev_priv, + DE_PIPEA_VBLANK_IVB << (5 * pipe)); mtx_unlock(&dev_priv->irq_lock); CTR1(KTR_DRM, "ivybridge_enable_vblank %d", pipe); return 0; } +static int valleyview_enable_vblank(struct drm_device *dev, int pipe) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 dpfl, imr; + + if (!i915_pipe_enabled(dev, pipe)) + return -EINVAL; + + mtx_lock(&dev_priv->irq_lock); + dpfl = I915_READ(VLV_DPFLIPSTAT); + imr = I915_READ(VLV_IMR); + if (pipe == 0) { + dpfl |= PIPEA_VBLANK_INT_EN; + imr &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT; + } else { + dpfl |= PIPEA_VBLANK_INT_EN; + imr &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; + } + I915_WRITE(VLV_DPFLIPSTAT, dpfl); + I915_WRITE(VLV_IMR, imr); + mtx_unlock(&dev_priv->irq_lock); + + return 0; +} /* Called from drm generic code, passed 'crtc' which * we use as a pipe index @@ -1279,8 +1052,7 @@ i915_disable_vblank(struct drm_device *dev, int pipe) mtx_lock(&dev_priv->irq_lock); if (dev_priv->info->gen == 3) - I915_WRITE(INSTPM, - INSTPM_AGPBUSY_DIS << 16 | INSTPM_AGPBUSY_DIS); + I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_AGPBUSY_DIS)); i915_disable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_ENABLE | @@ -1307,64 +1079,30 @@ ivybridge_disable_vblank(struct drm_device *dev, int pipe) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; mtx_lock(&dev_priv->irq_lock); - ironlake_disable_display_irq(dev_priv, (pipe == 0) ? - DE_PIPEA_VBLANK_IVB : DE_PIPEB_VBLANK_IVB); + ironlake_disable_display_irq(dev_priv, + DE_PIPEA_VBLANK_IVB << (pipe * 5)); mtx_unlock(&dev_priv->irq_lock); CTR1(KTR_DRM, "ivybridge_disable_vblank %d", pipe); } -/* Set the vblank monitor pipe - */ -int i915_vblank_pipe_set(struct drm_device *dev, void *data, - struct drm_file *file_priv) +static void valleyview_disable_vblank(struct drm_device *dev, int pipe) { - drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 dpfl, imr; - if (!dev_priv) { - DRM_ERROR("called with no initialization\n"); - return -EINVAL; + mtx_lock(&dev_priv->irq_lock); + dpfl = I915_READ(VLV_DPFLIPSTAT); + imr = I915_READ(VLV_IMR); + if (pipe == 0) { + dpfl &= ~PIPEA_VBLANK_INT_EN; + imr |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT; + } else { + dpfl &= ~PIPEB_VBLANK_INT_EN; + imr |= I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; } - - return 0; -} - -int i915_vblank_pipe_get(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_vblank_pipe_t *pipe = data; - - if (!dev_priv) { - DRM_ERROR("called with no initialization\n"); - return -EINVAL; - } - - pipe->pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; - - return 0; -} - -/** - * Schedule buffer swap at given vertical blank. - */ -int i915_vblank_swap(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - /* The delayed swap mechanism was fundamentally racy, and has been - * removed. The model was that the client requested a delayed flip/swap - * from the kernel, then waited for vblank before continuing to perform - * rendering. The problem was that the kernel might wake the client - * up before it dispatched the vblank swap (since the lock has to be - * held while touching the ringbuffer), in which case the client would - * clear and start the next frame before the swap occurred, and - * flicker would occur in addition to likely missing the vblank. - * - * In the absence of this ioctl, userland falls back to a correct path - * of waiting for a vblank, then dispatching the swap on its own. - * Context switching to userland and back is plenty fast enough for - * meeting the requirements of vblank swapping. - */ - return -EINVAL; + I915_WRITE(VLV_IMR, imr); + I915_WRITE(VLV_DPFLIPSTAT, dpfl); + mtx_unlock(&dev_priv->irq_lock); } static u32 @@ -1383,15 +1121,15 @@ static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, bool *err) if (list_empty(&ring->request_list) || i915_seqno_passed(ring->get_seqno(ring), ring_last_seqno(ring))) { /* Issue a wake-up to catch stuck h/w. */ - if (ring->waiting_seqno) { - DRM_ERROR( -"Hangcheck timer elapsed... %s idle [waiting on %d, at %d], missed IRQ?\n", - ring->name, - ring->waiting_seqno, - ring->get_seqno(ring)); + sleepq_lock(ring); + if (sleepq_sleepcnt(ring, 0) != 0) { + sleepq_release(ring); + DRM_ERROR("Hangcheck timer elapsed... %s idle\n", + ring->name); wakeup(ring); *err = true; - } + } else + sleepq_release(ring); return true; } return false; @@ -1411,6 +1149,35 @@ static bool kick_ring(struct intel_ring_buffer *ring) return false; } +static bool i915_hangcheck_hung(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + if (dev_priv->hangcheck_count++ > 1) { + bool hung = true; + + DRM_ERROR("Hangcheck timer elapsed... GPU hung\n"); + i915_handle_error(dev, true); + + if (!IS_GEN2(dev)) { + struct intel_ring_buffer *ring; + int i; + + /* Is the chip hanging on a WAIT_FOR_EVENT? + * If so we can simply poke the RB_WAIT bit + * and break the hang. This should work on + * all but the second generation chipsets. + */ + for_each_ring(ring, dev_priv, i) + hung &= !kick_ring(ring); + } + + return hung; + } + + return false; +} + /** * This is called when the chip hasn't reported back with completed * batchbuffers in a long time. The first time this is called we simply record @@ -1422,19 +1189,31 @@ i915_hangcheck_elapsed(void *context) { struct drm_device *dev = (struct drm_device *)context; drm_i915_private_t *dev_priv = dev->dev_private; - uint32_t acthd, instdone, instdone1, acthd_bsd, acthd_blt; - bool err = false; + uint32_t acthd[I915_NUM_RINGS], instdone, instdone1; + struct intel_ring_buffer *ring; + bool err = false, idle; + int i; if (!i915_enable_hangcheck) return; + memset(acthd, 0, sizeof(acthd)); + idle = true; + for_each_ring(ring, dev_priv, i) { + idle &= i915_hangcheck_ring_idle(ring, &err); + acthd[i] = intel_ring_get_active_head(ring); + } + /* If all work is done then ACTHD clearly hasn't advanced. */ - if (i915_hangcheck_ring_idle(&dev_priv->rings[RCS], &err) && - i915_hangcheck_ring_idle(&dev_priv->rings[VCS], &err) && - i915_hangcheck_ring_idle(&dev_priv->rings[BCS], &err)) { - dev_priv->hangcheck_count = 0; - if (err) + if (idle) { + if (err) { + if (i915_hangcheck_hung(dev)) + return; + goto repeat; + } + + dev_priv->hangcheck_count = 0; return; } @@ -1445,47 +1224,15 @@ i915_hangcheck_elapsed(void *context) instdone = I915_READ(INSTDONE_I965); instdone1 = I915_READ(INSTDONE1); } - acthd = intel_ring_get_active_head(&dev_priv->rings[RCS]); - acthd_bsd = HAS_BSD(dev) ? - intel_ring_get_active_head(&dev_priv->rings[VCS]) : 0; - acthd_blt = HAS_BLT(dev) ? - intel_ring_get_active_head(&dev_priv->rings[BCS]) : 0; - - if (dev_priv->last_acthd == acthd && - dev_priv->last_acthd_bsd == acthd_bsd && - dev_priv->last_acthd_blt == acthd_blt && + if (memcmp(dev_priv->last_acthd, acthd, sizeof(acthd)) == 0 && dev_priv->last_instdone == instdone && dev_priv->last_instdone1 == instdone1) { - if (dev_priv->hangcheck_count++ > 1) { - DRM_ERROR("Hangcheck timer elapsed... GPU hung\n"); - i915_handle_error(dev, true); - - if (!IS_GEN2(dev)) { - /* Is the chip hanging on a WAIT_FOR_EVENT? - * If so we can simply poke the RB_WAIT bit - * and break the hang. This should work on - * all but the second generation chipsets. - */ - if (kick_ring(&dev_priv->rings[RCS])) - goto repeat; - - if (HAS_BSD(dev) && - kick_ring(&dev_priv->rings[VCS])) - goto repeat; - - if (HAS_BLT(dev) && - kick_ring(&dev_priv->rings[BCS])) - goto repeat; - } - + if (i915_hangcheck_hung(dev)) return; - } } else { dev_priv->hangcheck_count = 0; - dev_priv->last_acthd = acthd; - dev_priv->last_acthd_bsd = acthd_bsd; - dev_priv->last_acthd_blt = acthd_blt; + memcpy(dev_priv->last_acthd, acthd, sizeof(acthd)); dev_priv->last_instdone = instdone; dev_priv->last_instdone1 = instdone1; } @@ -1504,13 +1251,6 @@ ironlake_irq_preinstall(struct drm_device *dev) atomic_set(&dev_priv->irq_received, 0); - TASK_INIT(&dev_priv->hotplug_task, 0, i915_hotplug_work_func, - dev->dev_private); - TASK_INIT(&dev_priv->error_task, 0, i915_error_work_func, - dev->dev_private); - TASK_INIT(&dev_priv->rps_task, 0, gen6_pm_rps_work_func, - dev->dev_private); - I915_WRITE(HWSTAM, 0xeffe); /* XXX hotplug from PCH */ @@ -1530,6 +1270,38 @@ ironlake_irq_preinstall(struct drm_device *dev) POSTING_READ(SDEIER); } +static void valleyview_irq_preinstall(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + int pipe; + + atomic_set(&dev_priv->irq_received, 0); + + /* VLV magic */ + I915_WRITE(VLV_IMR, 0); + I915_WRITE(RING_IMR(RENDER_RING_BASE), 0); + I915_WRITE(RING_IMR(GEN6_BSD_RING_BASE), 0); + I915_WRITE(RING_IMR(BLT_RING_BASE), 0); + + /* and GT */ + I915_WRITE(GTIIR, I915_READ(GTIIR)); + I915_WRITE(GTIIR, I915_READ(GTIIR)); + I915_WRITE(GTIMR, 0xffffffff); + I915_WRITE(GTIER, 0x0); + POSTING_READ(GTIER); + + I915_WRITE(DPINVGTT, 0xff); + + I915_WRITE(PORT_HOTPLUG_EN, 0); + I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); + for_each_pipe(pipe) + I915_WRITE(PIPESTAT(pipe), 0xffff); + I915_WRITE(VLV_IIR, 0xffffffff); + I915_WRITE(VLV_IMR, 0xffffffff); + I915_WRITE(VLV_IER, 0x0); + POSTING_READ(VLV_IER); +} + /* * Enable digital hotplug on the PCH, and configure the DP short pulse * duration to 2ms (which is the minimum in the Display Port spec) @@ -1559,7 +1331,6 @@ static int ironlake_irq_postinstall(struct drm_device *dev) u32 render_irqs; u32 hotplug_mask; - dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; dev_priv->irq_mask = ~display_mask; /* should always can generate irq */ @@ -1576,8 +1347,8 @@ static int ironlake_irq_postinstall(struct drm_device *dev) if (IS_GEN6(dev)) render_irqs = GT_USER_INTERRUPT | - GT_GEN6_BSD_USER_INTERRUPT | - GT_BLT_USER_INTERRUPT; + GEN6_BSD_USER_INTERRUPT | + GEN6_BLITTER_USER_INTERRUPT; else render_irqs = GT_USER_INTERRUPT | @@ -1623,20 +1394,24 @@ ivybridge_irq_postinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; /* enable kind of interrupts always enabled */ - u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE_IVB | - DE_PCH_EVENT_IVB | DE_PLANEA_FLIP_DONE_IVB | - DE_PLANEB_FLIP_DONE_IVB; + u32 display_mask = + DE_MASTER_IRQ_CONTROL | DE_GSE_IVB | DE_PCH_EVENT_IVB | + DE_PLANEC_FLIP_DONE_IVB | + DE_PLANEB_FLIP_DONE_IVB | + DE_PLANEA_FLIP_DONE_IVB; u32 render_irqs; u32 hotplug_mask; - dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; dev_priv->irq_mask = ~display_mask; /* should always can generate irq */ I915_WRITE(DEIIR, I915_READ(DEIIR)); I915_WRITE(DEIMR, dev_priv->irq_mask); - I915_WRITE(DEIER, display_mask | DE_PIPEA_VBLANK_IVB | - DE_PIPEB_VBLANK_IVB); + I915_WRITE(DEIER, + display_mask | + DE_PIPEC_VBLANK_IVB | + DE_PIPEB_VBLANK_IVB | + DE_PIPEA_VBLANK_IVB); POSTING_READ(DEIER); dev_priv->gt_irq_mask = ~0; @@ -1644,8 +1419,8 @@ ivybridge_irq_postinstall(struct drm_device *dev) I915_WRITE(GTIIR, I915_READ(GTIIR)); I915_WRITE(GTIMR, dev_priv->gt_irq_mask); - render_irqs = GT_USER_INTERRUPT | GT_GEN6_BSD_USER_INTERRUPT | - GT_BLT_USER_INTERRUPT; + render_irqs = GT_USER_INTERRUPT | GEN6_BSD_USER_INTERRUPT | + GEN6_BLITTER_USER_INTERRUPT; I915_WRITE(GTIER, render_irqs); POSTING_READ(GTIER); @@ -1665,20 +1440,494 @@ ivybridge_irq_postinstall(struct drm_device *dev) return 0; } +static int valleyview_irq_postinstall(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 render_irqs; + u32 enable_mask; + u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN); + u16 msid; + + enable_mask = I915_DISPLAY_PORT_INTERRUPT; + enable_mask |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT | + I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; + + dev_priv->irq_mask = ~enable_mask; + + dev_priv->pipestat[0] = 0; + dev_priv->pipestat[1] = 0; + + /* Hack for broken MSIs on VLV */ + pci_write_config(dev->device, 0x94, 0xfee00000, 4); + msid = pci_read_config(dev->device, 0x98, 2); + msid &= 0xff; /* mask out delivery bits */ + msid |= (1<<14); + pci_write_config(dev->device, 0x98, msid, 2); + + I915_WRITE(VLV_IMR, dev_priv->irq_mask); + I915_WRITE(VLV_IER, enable_mask); + I915_WRITE(VLV_IIR, 0xffffffff); + I915_WRITE(PIPESTAT(0), 0xffff); + I915_WRITE(PIPESTAT(1), 0xffff); + POSTING_READ(VLV_IER); + + I915_WRITE(VLV_IIR, 0xffffffff); + I915_WRITE(VLV_IIR, 0xffffffff); + + render_irqs = GT_GEN6_BLT_FLUSHDW_NOTIFY_INTERRUPT | + GT_GEN6_BLT_CS_ERROR_INTERRUPT | + GT_GEN6_BLT_USER_INTERRUPT | + GT_GEN6_BSD_USER_INTERRUPT | + GT_GEN6_BSD_CS_ERROR_INTERRUPT | + GT_GEN7_L3_PARITY_ERROR_INTERRUPT | + GT_PIPE_NOTIFY | + GT_RENDER_CS_ERROR_INTERRUPT | + GT_SYNC_STATUS | + GT_USER_INTERRUPT; + + dev_priv->gt_irq_mask = ~render_irqs; + + I915_WRITE(GTIIR, I915_READ(GTIIR)); + I915_WRITE(GTIIR, I915_READ(GTIIR)); + I915_WRITE(GTIMR, 0); + I915_WRITE(GTIER, render_irqs); + POSTING_READ(GTIER); + + /* ack & enable invalid PTE error interrupts */ +#if 0 /* FIXME: add support to irq handler for checking these bits */ + I915_WRITE(DPINVGTT, DPINVGTT_STATUS_MASK); + I915_WRITE(DPINVGTT, DPINVGTT_EN_MASK); +#endif + + I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE); +#if 0 /* FIXME: check register definitions; some have moved */ + /* Note HDMI and DP share bits */ + if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS) + hotplug_en |= HDMIB_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS) + hotplug_en |= HDMIC_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS) + hotplug_en |= HDMID_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS) + hotplug_en |= SDVOC_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS) + hotplug_en |= SDVOB_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) { + hotplug_en |= CRT_HOTPLUG_INT_EN; + hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; + } +#endif + + I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); + + return 0; +} + +static void valleyview_irq_uninstall(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + int pipe; + + if (!dev_priv) + return; + + for_each_pipe(pipe) + I915_WRITE(PIPESTAT(pipe), 0xffff); + + I915_WRITE(HWSTAM, 0xffffffff); + I915_WRITE(PORT_HOTPLUG_EN, 0); + I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); + for_each_pipe(pipe) + I915_WRITE(PIPESTAT(pipe), 0xffff); + I915_WRITE(VLV_IIR, 0xffffffff); + I915_WRITE(VLV_IMR, 0xffffffff); + I915_WRITE(VLV_IER, 0x0); + POSTING_READ(VLV_IER); +} + static void -i915_driver_irq_preinstall(struct drm_device * dev) +ironlake_irq_uninstall(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + + if (dev_priv == NULL) + return; + + I915_WRITE(HWSTAM, 0xffffffff); + + I915_WRITE(DEIMR, 0xffffffff); + I915_WRITE(DEIER, 0x0); + I915_WRITE(DEIIR, I915_READ(DEIIR)); + + I915_WRITE(GTIMR, 0xffffffff); + I915_WRITE(GTIER, 0x0); + I915_WRITE(GTIIR, I915_READ(GTIIR)); + + I915_WRITE(SDEIMR, 0xffffffff); + I915_WRITE(SDEIER, 0x0); + I915_WRITE(SDEIIR, I915_READ(SDEIIR)); +} + +static void i8xx_irq_preinstall(struct drm_device * dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + int pipe; + + atomic_set(&dev_priv->irq_received, 0); + + for_each_pipe(pipe) + I915_WRITE(PIPESTAT(pipe), 0); + I915_WRITE16(IMR, 0xffff); + I915_WRITE16(IER, 0x0); + POSTING_READ16(IER); +} + +static int i8xx_irq_postinstall(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + + dev_priv->pipestat[0] = 0; + dev_priv->pipestat[1] = 0; + + I915_WRITE16(EMR, + ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH)); + + /* Unmask the interrupts that we always want on. */ + dev_priv->irq_mask = + ~(I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | + I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | + I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | + I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT | + I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); + I915_WRITE16(IMR, dev_priv->irq_mask); + + I915_WRITE16(IER, + I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | + I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | + I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT | + I915_USER_INTERRUPT); + POSTING_READ16(IER); + + return 0; +} + +static void i8xx_irq_handler(void *arg) +{ + struct drm_device *dev = (struct drm_device *) arg; + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u16 iir, new_iir; + u32 pipe_stats[2]; + int irq_received; + int pipe; + u16 flip_mask = + I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | + I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; + + atomic_inc(&dev_priv->irq_received); + + iir = I915_READ16(IIR); + if (iir == 0) + return; + + while (iir & ~flip_mask) { + /* Can't rely on pipestat interrupt bit in iir as it might + * have been cleared after the pipestat interrupt was received. + * It doesn't set the bit in iir again, but it still produces + * interrupts (for non-MSI). + */ + mtx_lock(&dev_priv->irq_lock); + if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) + i915_handle_error(dev, false); + + for_each_pipe(pipe) { + int reg = PIPESTAT(pipe); + pipe_stats[pipe] = I915_READ(reg); + + /* + * Clear the PIPE*STAT regs before the IIR + */ + if (pipe_stats[pipe] & 0x8000ffff) { + if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS) + DRM_DEBUG_DRIVER("pipe %c underrun\n", + pipe_name(pipe)); + I915_WRITE(reg, pipe_stats[pipe]); + irq_received = 1; + } + } + mtx_unlock(&dev_priv->irq_lock); + + I915_WRITE16(IIR, iir & ~flip_mask); + new_iir = I915_READ16(IIR); /* Flush posted writes */ + + i915_update_dri1_breadcrumb(dev); + + if (iir & I915_USER_INTERRUPT) + notify_ring(dev, &dev_priv->rings[RCS]); + + if (pipe_stats[0] & PIPE_VBLANK_INTERRUPT_STATUS && + drm_handle_vblank(dev, 0)) { + if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) { + intel_prepare_page_flip(dev, 0); + intel_finish_page_flip(dev, 0); + flip_mask &= ~I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT; + } + } + + if (pipe_stats[1] & PIPE_VBLANK_INTERRUPT_STATUS && + drm_handle_vblank(dev, 1)) { + if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) { + intel_prepare_page_flip(dev, 1); + intel_finish_page_flip(dev, 1); + flip_mask &= ~I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; + } + } + + iir = new_iir; + } +} + +static void i8xx_irq_uninstall(struct drm_device * dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + int pipe; + + for_each_pipe(pipe) { + /* Clear enable bits; then clear status bits */ + I915_WRITE(PIPESTAT(pipe), 0); + I915_WRITE(PIPESTAT(pipe), I915_READ(PIPESTAT(pipe))); + } + I915_WRITE16(IMR, 0xffff); + I915_WRITE16(IER, 0x0); + I915_WRITE16(IIR, I915_READ16(IIR)); +} + +static void i915_irq_preinstall(struct drm_device * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int pipe; atomic_set(&dev_priv->irq_received, 0); - TASK_INIT(&dev_priv->hotplug_task, 0, i915_hotplug_work_func, - dev->dev_private); - TASK_INIT(&dev_priv->error_task, 0, i915_error_work_func, - dev->dev_private); - TASK_INIT(&dev_priv->rps_task, 0, gen6_pm_rps_work_func, - dev->dev_private); + if (I915_HAS_HOTPLUG(dev)) { + I915_WRITE(PORT_HOTPLUG_EN, 0); + I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); + } + + I915_WRITE16(HWSTAM, 0xeffe); + for_each_pipe(pipe) + I915_WRITE(PIPESTAT(pipe), 0); + I915_WRITE(IMR, 0xffffffff); + I915_WRITE(IER, 0x0); + POSTING_READ(IER); +} + +static int i915_irq_postinstall(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 enable_mask; + + dev_priv->pipestat[0] = 0; + dev_priv->pipestat[1] = 0; + + I915_WRITE(EMR, ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH)); + + /* Unmask the interrupts that we always want on. */ + dev_priv->irq_mask = + ~(I915_ASLE_INTERRUPT | + I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | + I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | + I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | + I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT | + I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); + + enable_mask = + I915_ASLE_INTERRUPT | + I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | + I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | + I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT | + I915_USER_INTERRUPT; + + if (I915_HAS_HOTPLUG(dev)) { + /* Enable in IER... */ + enable_mask |= I915_DISPLAY_PORT_INTERRUPT; + /* and unmask in IMR */ + dev_priv->irq_mask &= ~I915_DISPLAY_PORT_INTERRUPT; + } + + I915_WRITE(IMR, dev_priv->irq_mask); + I915_WRITE(IER, enable_mask); + POSTING_READ(IER); + + if (I915_HAS_HOTPLUG(dev)) { + u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN); + + if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS) + hotplug_en |= HDMIB_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS) + hotplug_en |= HDMIC_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS) + hotplug_en |= HDMID_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS) + hotplug_en |= SDVOC_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS) + hotplug_en |= SDVOB_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) { + hotplug_en |= CRT_HOTPLUG_INT_EN; + hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; + } + + /* Ignore TV since it's buggy */ + + I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); + } + + intel_opregion_enable_asle(dev); + + return 0; +} + +static void i915_irq_handler(void *arg) +{ + struct drm_device *dev = (struct drm_device *) arg; + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 iir, new_iir, pipe_stats[I915_MAX_PIPES]; + u32 flip_mask = + I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | + I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; + u32 flip[2] = { + I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT, + I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT + }; + int pipe; + + atomic_inc(&dev_priv->irq_received); + + iir = I915_READ(IIR); + do { + bool irq_received = (iir & ~flip_mask) != 0; + bool blc_event = false; + + /* Can't rely on pipestat interrupt bit in iir as it might + * have been cleared after the pipestat interrupt was received. + * It doesn't set the bit in iir again, but it still produces + * interrupts (for non-MSI). + */ + mtx_lock(&dev_priv->irq_lock); + if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) + i915_handle_error(dev, false); + + for_each_pipe(pipe) { + int reg = PIPESTAT(pipe); + pipe_stats[pipe] = I915_READ(reg); + + /* Clear the PIPE*STAT regs before the IIR */ + if (pipe_stats[pipe] & 0x8000ffff) { + if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS) + DRM_DEBUG_DRIVER("pipe %c underrun\n", + pipe_name(pipe)); + I915_WRITE(reg, pipe_stats[pipe]); + irq_received = true; + } + } + mtx_unlock(&dev_priv->irq_lock); + + if (!irq_received) + break; + + /* Consume port. Then clear IIR or we'll miss events */ + if ((I915_HAS_HOTPLUG(dev)) && + (iir & I915_DISPLAY_PORT_INTERRUPT)) { + u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); + + DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", + hotplug_status); + if (hotplug_status & dev_priv->hotplug_supported_mask) + taskqueue_enqueue(dev_priv->tq, + &dev_priv->hotplug_task); + + I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); + POSTING_READ(PORT_HOTPLUG_STAT); + } + + I915_WRITE(IIR, iir & ~flip_mask); + new_iir = I915_READ(IIR); /* Flush posted writes */ + + if (iir & I915_USER_INTERRUPT) + notify_ring(dev, &dev_priv->rings[RCS]); + + for_each_pipe(pipe) { + int plane = pipe; + if (IS_MOBILE(dev)) + plane = !plane; + if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS && + drm_handle_vblank(dev, pipe)) { + if (iir & flip[plane]) { + intel_prepare_page_flip(dev, plane); + intel_finish_page_flip(dev, pipe); + flip_mask &= ~flip[plane]; + } + } + + if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) + blc_event = true; + } + + if (blc_event || (iir & I915_ASLE_INTERRUPT)) + intel_opregion_asle_intr(dev); + + + /* With MSI, interrupts are only generated when iir + * transitions from zero to nonzero. If another bit got + * set while we were handling the existing iir bits, then + * we would never get another interrupt. + * + * This is fine on non-MSI as well, as if we hit this path + * we avoid exiting the interrupt handler only to generate + * another one. + * + * Note that for MSI this could cause a stray interrupt report + * if an interrupt landed in the time between writing IIR and + * the posting read. This should be rare enough to never + * trigger the 99% of 100,000 interrupts test for disabling + * stray interrupts. + */ + iir = new_iir; + } while (iir & ~flip_mask); + + i915_update_dri1_breadcrumb(dev); +} + +static void i915_irq_uninstall(struct drm_device * dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + int pipe; + + if (!dev_priv) + return; + + if (I915_HAS_HOTPLUG(dev)) { + I915_WRITE(PORT_HOTPLUG_EN, 0); + I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); + } + + I915_WRITE16(HWSTAM, 0xffff); + for_each_pipe(pipe) { + /* Clear enable bits; then clear status bits */ + I915_WRITE(PIPESTAT(pipe), 0); + I915_WRITE(PIPESTAT(pipe), I915_READ(PIPESTAT(pipe))); + } + I915_WRITE(IMR, 0xffffffff); + I915_WRITE(IER, 0x0); + + I915_WRITE(IIR, I915_READ(IIR)); +} + +static void i965_irq_preinstall(struct drm_device * dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + int pipe; + + atomic_set(&dev_priv->irq_received, 0); if (I915_HAS_HOTPLUG(dev)) { I915_WRITE(PORT_HOTPLUG_EN, 0); @@ -1693,21 +1942,25 @@ i915_driver_irq_preinstall(struct drm_device * dev) POSTING_READ(IER); } -/* - * Must be called after intel_modeset_init or hotplug interrupts won't be - * enabled correctly. - */ -static int -i915_driver_irq_postinstall(struct drm_device *dev) +static int i965_irq_postinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR; + u32 enable_mask; u32 error_mask; - dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; - /* Unmask the interrupts that we always want on. */ - dev_priv->irq_mask = ~I915_INTERRUPT_ENABLE_FIX; + dev_priv->irq_mask = ~(I915_ASLE_INTERRUPT | + I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | + I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | + I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | + I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT | + I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); + + enable_mask = ~dev_priv->irq_mask; + enable_mask |= I915_USER_INTERRUPT; + + if (IS_G4X(dev)) + enable_mask |= I915_BSD_USER_INTERRUPT; dev_priv->pipestat[0] = 0; dev_priv->pipestat[1] = 0; @@ -1774,45 +2027,123 @@ i915_driver_irq_postinstall(struct drm_device *dev) return 0; } -static void -ironlake_irq_uninstall(struct drm_device *dev) +static void i965_irq_handler(void *arg) { + struct drm_device *dev = (struct drm_device *) arg; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 iir, new_iir; + u32 pipe_stats[I915_MAX_PIPES]; + int irq_received; + int pipe; - if (dev_priv == NULL) - return; + atomic_inc(&dev_priv->irq_received); - dev_priv->vblank_pipe = 0; + iir = I915_READ(IIR); - I915_WRITE(HWSTAM, 0xffffffff); + for (;;) { + bool blc_event = false; - I915_WRITE(DEIMR, 0xffffffff); - I915_WRITE(DEIER, 0x0); - I915_WRITE(DEIIR, I915_READ(DEIIR)); + irq_received = iir != 0; - I915_WRITE(GTIMR, 0xffffffff); - I915_WRITE(GTIER, 0x0); - I915_WRITE(GTIIR, I915_READ(GTIIR)); + /* Can't rely on pipestat interrupt bit in iir as it might + * have been cleared after the pipestat interrupt was received. + * It doesn't set the bit in iir again, but it still produces + * interrupts (for non-MSI). + */ + mtx_lock(&dev_priv->irq_lock); + if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) + i915_handle_error(dev, false); - I915_WRITE(SDEIMR, 0xffffffff); - I915_WRITE(SDEIER, 0x0); - I915_WRITE(SDEIIR, I915_READ(SDEIIR)); + for_each_pipe(pipe) { + int reg = PIPESTAT(pipe); + pipe_stats[pipe] = I915_READ(reg); - taskqueue_drain(dev_priv->tq, &dev_priv->hotplug_task); - taskqueue_drain(dev_priv->tq, &dev_priv->error_task); - taskqueue_drain(dev_priv->tq, &dev_priv->rps_task); + /* + * Clear the PIPE*STAT regs before the IIR + */ + if (pipe_stats[pipe] & 0x8000ffff) { + if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS) + DRM_DEBUG_DRIVER("pipe %c underrun\n", + pipe_name(pipe)); + I915_WRITE(reg, pipe_stats[pipe]); + irq_received = 1; + } + } + mtx_unlock(&dev_priv->irq_lock); + + if (!irq_received) + break; + + /* Consume port. Then clear IIR or we'll miss events */ + if ((I915_HAS_HOTPLUG(dev)) && + (iir & I915_DISPLAY_PORT_INTERRUPT)) { + u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); + + DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", + hotplug_status); + if (hotplug_status & dev_priv->hotplug_supported_mask) + taskqueue_enqueue(dev_priv->tq, + &dev_priv->hotplug_task); + + I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); + I915_READ(PORT_HOTPLUG_STAT); + } + + I915_WRITE(IIR, iir); + new_iir = I915_READ(IIR); /* Flush posted writes */ + + if (iir & I915_USER_INTERRUPT) + notify_ring(dev, &dev_priv->rings[RCS]); + if (iir & I915_BSD_USER_INTERRUPT) + notify_ring(dev, &dev_priv->rings[VCS]); + + if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) + intel_prepare_page_flip(dev, 0); + + if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) + intel_prepare_page_flip(dev, 1); + + for_each_pipe(pipe) { + if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS && + drm_handle_vblank(dev, pipe)) { + i915_pageflip_stall_check(dev, pipe); + intel_finish_page_flip(dev, pipe); + } + + if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) + blc_event = true; + } + + + if (blc_event || (iir & I915_ASLE_INTERRUPT)) + intel_opregion_asle_intr(dev); + + /* With MSI, interrupts are only generated when iir + * transitions from zero to nonzero. If another bit got + * set while we were handling the existing iir bits, then + * we would never get another interrupt. + * + * This is fine on non-MSI as well, as if we hit this path + * we avoid exiting the interrupt handler only to generate + * another one. + * + * Note that for MSI this could cause a stray interrupt report + * if an interrupt landed in the time between writing IIR and + * the posting read. This should be rare enough to never + * trigger the 99% of 100,000 interrupts test for disabling + * stray interrupts. + */ + iir = new_iir; + } + + i915_update_dri1_breadcrumb(dev); } -static void i915_driver_irq_uninstall(struct drm_device * dev) +static void i965_irq_uninstall(struct drm_device * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int pipe; - if (!dev_priv) - return; - - dev_priv->vblank_pipe = 0; - if (I915_HAS_HOTPLUG(dev)) { I915_WRITE(PORT_HOTPLUG_EN, 0); I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); @@ -1828,30 +2159,39 @@ static void i915_driver_irq_uninstall(struct drm_device * dev) I915_WRITE(PIPESTAT(pipe), I915_READ(PIPESTAT(pipe)) & 0x8000ffff); I915_WRITE(IIR, I915_READ(IIR)); - - taskqueue_drain(dev_priv->tq, &dev_priv->hotplug_task); - taskqueue_drain(dev_priv->tq, &dev_priv->error_task); - taskqueue_drain(dev_priv->tq, &dev_priv->rps_task); } -void -intel_irq_init(struct drm_device *dev) +void intel_irq_init(struct drm_device *dev) { + struct drm_i915_private *dev_priv = dev->dev_private; + + TASK_INIT(&dev_priv->hotplug_task, 0, i915_hotplug_work_func, + dev->dev_private); + TASK_INIT(&dev_priv->error_task, 0, i915_error_work_func, + dev->dev_private); + TASK_INIT(&dev_priv->rps_task, 0, gen6_pm_rps_work_func, + dev->dev_private); dev->driver->get_vblank_counter = i915_get_vblank_counter; dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ - if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev) || IS_IVYBRIDGE(dev)) { + if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */ dev->driver->get_vblank_counter = gm45_get_vblank_counter; } - if (drm_core_check_feature(dev, DRIVER_MODESET)) dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp; else dev->driver->get_vblank_timestamp = NULL; dev->driver->get_scanout_position = i915_get_crtc_scanoutpos; - if (IS_IVYBRIDGE(dev)) { + if (IS_VALLEYVIEW(dev)) { + dev->driver->irq_handler = valleyview_irq_handler; + dev->driver->irq_preinstall = valleyview_irq_preinstall; + dev->driver->irq_postinstall = valleyview_irq_postinstall; + dev->driver->irq_uninstall = valleyview_irq_uninstall; + dev->driver->enable_vblank = valleyview_enable_vblank; + dev->driver->disable_vblank = valleyview_disable_vblank; + } else if (IS_IVYBRIDGE(dev)) { /* Share pre & uninstall handlers with ILK/SNB */ dev->driver->irq_handler = ivybridge_irq_handler; dev->driver->irq_preinstall = ironlake_irq_preinstall; @@ -1859,6 +2199,14 @@ intel_irq_init(struct drm_device *dev) dev->driver->irq_uninstall = ironlake_irq_uninstall; dev->driver->enable_vblank = ivybridge_enable_vblank; dev->driver->disable_vblank = ivybridge_disable_vblank; + } else if (IS_HASWELL(dev)) { + /* Share interrupts handling with IVB */ + dev->driver->irq_handler = ivybridge_irq_handler; + dev->driver->irq_preinstall = ironlake_irq_preinstall; + dev->driver->irq_postinstall = ivybridge_irq_postinstall; + dev->driver->irq_uninstall = ironlake_irq_uninstall; + dev->driver->enable_vblank = ivybridge_enable_vblank; + dev->driver->disable_vblank = ivybridge_disable_vblank; } else if (HAS_PCH_SPLIT(dev)) { dev->driver->irq_handler = ironlake_irq_handler; dev->driver->irq_preinstall = ironlake_irq_preinstall; @@ -1867,10 +2215,25 @@ intel_irq_init(struct drm_device *dev) dev->driver->enable_vblank = ironlake_enable_vblank; dev->driver->disable_vblank = ironlake_disable_vblank; } else { - dev->driver->irq_preinstall = i915_driver_irq_preinstall; - dev->driver->irq_postinstall = i915_driver_irq_postinstall; - dev->driver->irq_uninstall = i915_driver_irq_uninstall; - dev->driver->irq_handler = i915_driver_irq_handler; + if (INTEL_INFO(dev)->gen == 2) { + dev->driver->irq_preinstall = i8xx_irq_preinstall; + dev->driver->irq_postinstall = i8xx_irq_postinstall; + dev->driver->irq_handler = i8xx_irq_handler; + dev->driver->irq_uninstall = i8xx_irq_uninstall; + } else if (INTEL_INFO(dev)->gen == 3) { + /* IIR "flip pending" means done if this bit is set */ + I915_WRITE(ECOSKPD, _MASKED_BIT_DISABLE(ECO_FLIP_DONE)); + + dev->driver->irq_preinstall = i915_irq_preinstall; + dev->driver->irq_postinstall = i915_irq_postinstall; + dev->driver->irq_uninstall = i915_irq_uninstall; + dev->driver->irq_handler = i915_irq_handler; + } else { + dev->driver->irq_preinstall = i965_irq_preinstall; + dev->driver->irq_postinstall = i965_irq_postinstall; + dev->driver->irq_uninstall = i965_irq_uninstall; + dev->driver->irq_handler = i965_irq_handler; + } dev->driver->enable_vblank = i915_enable_vblank; dev->driver->disable_vblank = i915_disable_vblank; } @@ -1902,7 +2265,8 @@ i915_error_object_create(struct drm_i915_private *dev_priv, if (d == NULL) goto unwind; - if (reloc_offset < dev_priv->mm.gtt_mappable_end) { + if (reloc_offset < dev_priv->mm.gtt_mappable_end && + src->has_global_gtt_mapping) { /* Simply ignore tiling or any overlapping fence. * It's part of the error state, and this hopefully * captures what the GPU read. @@ -1960,9 +2324,8 @@ i915_error_object_free(struct drm_i915_error_object *obj) free(obj, DRM_I915_GEM); } -static void -i915_error_state_free(struct drm_device *dev, - struct drm_i915_error_state *error) +void +i915_error_state_free(struct drm_i915_error_state *error) { int i; @@ -1977,39 +2340,59 @@ i915_error_state_free(struct drm_device *dev, free(error, DRM_I915_GEM); } -static u32 -capture_bo_list(struct drm_i915_error_buffer *err, int count, - struct list_head *head) +static void capture_bo(struct drm_i915_error_buffer *err, + struct drm_i915_gem_object *obj) +{ + err->size = obj->base.size; + err->name = obj->base.name; + err->seqno = obj->last_rendering_seqno; + err->gtt_offset = obj->gtt_offset; + err->read_domains = obj->base.read_domains; + err->write_domain = obj->base.write_domain; + err->fence_reg = obj->fence_reg; + err->pinned = 0; + if (obj->pin_count > 0) + err->pinned = 1; + if (obj->user_pin_count > 0) + err->pinned = -1; + err->tiling = obj->tiling_mode; + err->dirty = obj->dirty; + err->purgeable = obj->madv != I915_MADV_WILLNEED; + err->ring = obj->ring ? obj->ring->id : -1; + err->cache_level = obj->cache_level; +} + +static u32 capture_active_bo(struct drm_i915_error_buffer *err, + int count, struct list_head *head) { struct drm_i915_gem_object *obj; int i = 0; list_for_each_entry(obj, head, mm_list) { - err->size = obj->base.size; - err->name = obj->base.name; - err->seqno = obj->last_rendering_seqno; - err->gtt_offset = obj->gtt_offset; - err->read_domains = obj->base.read_domains; - err->write_domain = obj->base.write_domain; - err->fence_reg = obj->fence_reg; - err->pinned = 0; - if (obj->pin_count > 0) - err->pinned = 1; - if (obj->user_pin_count > 0) - err->pinned = -1; - err->tiling = obj->tiling_mode; - err->dirty = obj->dirty; - err->purgeable = obj->madv != I915_MADV_WILLNEED; - err->ring = obj->ring ? obj->ring->id : -1; - err->cache_level = obj->cache_level; - + capture_bo(err++, obj); if (++i == count) break; - - err++; } - return (i); + return i; +} + +static u32 capture_pinned_bo(struct drm_i915_error_buffer *err, + int count, struct list_head *head) +{ + struct drm_i915_gem_object *obj; + int i = 0; + + list_for_each_entry(obj, head, gtt_list) { + if (obj->pin_count == 0) + continue; + + capture_bo(err++, obj); + if (++i == count) + break; + } + + return i; } static void @@ -2083,7 +2466,6 @@ i915_record_ring_state(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; if (INTEL_INFO(dev)->gen >= 6) { - error->faddr[ring->id] = I915_READ(RING_DMA_FADD(ring->mmio_base)); error->fault_reg[ring->id] = I915_READ(RING_FAULT_REG(ring)); error->semaphore_mboxes[ring->id][0] = I915_READ(RING_SYNC_0(ring->mmio_base)); @@ -2092,6 +2474,7 @@ i915_record_ring_state(struct drm_device *dev, } if (INTEL_INFO(dev)->gen >= 4) { + error->faddr[ring->id] = I915_READ(RING_DMA_FADD(ring->mmio_base)); error->ipeir[ring->id] = I915_READ(RING_IPEIR(ring->mmio_base)); error->ipehr[ring->id] = I915_READ(RING_IPEHR(ring->mmio_base)); error->instdone[ring->id] = I915_READ(RING_INSTDONE(ring->mmio_base)); @@ -2101,11 +2484,15 @@ i915_record_ring_state(struct drm_device *dev, error->bbaddr = I915_READ64(BB_ADDR); } } else { + error->faddr[ring->id] = I915_READ(DMA_FADD_I8XX); error->ipeir[ring->id] = I915_READ(IPEIR); error->ipehr[ring->id] = I915_READ(IPEHR); error->instdone[ring->id] = I915_READ(INSTDONE); } + sleepq_lock(ring); + error->waiting[ring->id] = sleepq_sleepcnt(ring, 0) != 0; + sleepq_release(ring); error->instpm[ring->id] = I915_READ(RING_INSTPM(ring->mmio_base)); error->seqno[ring->id] = ring->get_seqno(ring); error->acthd[ring->id] = intel_ring_get_active_head(ring); @@ -2121,15 +2508,11 @@ i915_gem_record_rings(struct drm_device *dev, struct drm_i915_error_state *error) { struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring; struct drm_i915_gem_request *request; int i, count; - for (i = 0; i < I915_NUM_RINGS; i++) { - struct intel_ring_buffer *ring = &dev_priv->rings[i]; - - if (ring->obj == NULL) - continue; - + for_each_ring(ring, dev_priv, i) { i915_record_ring_state(dev, error, ring); error->ring[i].batchbuffer = @@ -2187,8 +2570,19 @@ i915_capture_error_state(struct drm_device *dev) DRM_INFO("capturing error event; look for more information in " "sysctl hw.dri.%d.info.i915_error_state\n", dev->sysctl_node_idx); + refcount_init(&error->ref, 1); error->eir = I915_READ(EIR); error->pgtbl_er = I915_READ(PGTBL_ER); + + if (HAS_PCH_SPLIT(dev)) + error->ier = I915_READ(DEIER) | I915_READ(GTIER); + else if (IS_VALLEYVIEW(dev)) + error->ier = I915_READ(GTIER) | I915_READ(VLV_IER); + else if (IS_GEN2(dev)) + error->ier = I915_READ16(IER); + else + error->ier = I915_READ(IER); + for_each_pipe(pipe) error->pipestat[pipe] = I915_READ(PIPESTAT(pipe)); @@ -2208,8 +2602,9 @@ i915_capture_error_state(struct drm_device *dev) list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) i++; error->active_bo_count = i; - list_for_each_entry(obj, &dev_priv->mm.pinned_list, mm_list) - i++; + list_for_each_entry(obj, &dev_priv->mm.gtt_list, mm_list) + if (obj->pin_count) + i++; error->pinned_bo_count = i - error->active_bo_count; error->active_bo = NULL; @@ -2223,12 +2618,16 @@ i915_capture_error_state(struct drm_device *dev) } if (error->active_bo) - error->active_bo_count = capture_bo_list(error->active_bo, - error->active_bo_count, &dev_priv->mm.active_list); + error->active_bo_count = + capture_active_bo(error->active_bo, + error->active_bo_count, + &dev_priv->mm.active_list); if (error->pinned_bo) - error->pinned_bo_count = capture_bo_list(error->pinned_bo, - error->pinned_bo_count, &dev_priv->mm.pinned_list); + error->pinned_bo_count = + capture_pinned_bo(error->pinned_bo, + error->pinned_bo_count, + &dev_priv->mm.gtt_list); microtime(&error->time); @@ -2243,7 +2642,7 @@ i915_capture_error_state(struct drm_device *dev) mtx_unlock(&dev_priv->error_lock); if (error != NULL) - i915_error_state_free(dev, error); + i915_error_state_free(error); } void @@ -2257,6 +2656,6 @@ i915_destroy_error_state(struct drm_device *dev) dev_priv->first_error = NULL; mtx_unlock(&dev_priv->error_lock); - if (error != NULL) - i915_error_state_free(dev, error); + if (error != NULL && refcount_release(&error->ref)) + i915_error_state_free(error); } diff --git a/sys/dev/drm2/i915/i915_reg.h b/sys/dev/drm2/i915/i915_reg.h index 492fac480429..0eed2767477d 100644 --- a/sys/dev/drm2/i915/i915_reg.h +++ b/sys/dev/drm2/i915/i915_reg.h @@ -30,6 +30,11 @@ __FBSDID("$FreeBSD$"); #define _PIPE(pipe, a, b) ((a) + (pipe)*((b)-(a))) +#define _PORT(port, a, b) ((a) + (port)*((b)-(a))) + +#define _MASKED_BIT_ENABLE(a) (((a) << 16) | (a)) +#define _MASKED_BIT_DISABLE(a) ((a) << 16) + /* * The Bridge device's PCI config space has information about the * fb aperture size and the amount of pre-reserved memory. @@ -129,6 +134,13 @@ __FBSDID("$FreeBSD$"); #define ECOCHK_PPGTT_CACHE64B (0x3<<3) #define ECOCHK_PPGTT_CACHE4B (0x0<<3) +#define GAC_ECO_BITS 0x14090 +#define ECOBITS_PPGTT_CACHE64B (3<<8) +#define ECOBITS_PPGTT_CACHE4B (0<<8) + +#define GAB_CTL 0x24000 +#define GAB_CTL_CONT_AFTER_PAGEFAULT (1<<8) + /* VGA stuff */ #define VGA_ST01_MDA 0x3ba @@ -230,6 +242,7 @@ __FBSDID("$FreeBSD$"); #define MI_BATCH_NON_SECURE (1) #define MI_BATCH_NON_SECURE_I965 (1<<8) #define MI_BATCH_BUFFER_START MI_INSTR(0x31, 0) +#define MI_BATCH_GTT (2<<6) /* aliased with (1<<7) on gen4 */ #define MI_SEMAPHORE_MBOX MI_INSTR(0x16, 1) /* gen6+ */ #define MI_SEMAPHORE_GLOBAL_GTT (1<<22) #define MI_SEMAPHORE_UPDATE (1<<21) @@ -309,6 +322,61 @@ __FBSDID("$FreeBSD$"); #define DEBUG_RESET_RENDER (1<<8) #define DEBUG_RESET_DISPLAY (1<<9) +/* + * DPIO - a special bus for various display related registers to hide behind: + * 0x800c: m1, m2, n, p1, p2, k dividers + * 0x8014: REF and SFR select + * 0x8014: N divider, VCO select + * 0x801c/3c: core clock bits + * 0x8048/68: low pass filter coefficients + * 0x8100: fast clock controls + */ +#define DPIO_PKT 0x2100 +#define DPIO_RID (0<<24) +#define DPIO_OP_WRITE (1<<16) +#define DPIO_OP_READ (0<<16) +#define DPIO_PORTID (0x12<<8) +#define DPIO_BYTE (0xf<<4) +#define DPIO_BUSY (1<<0) /* status only */ +#define DPIO_DATA 0x2104 +#define DPIO_REG 0x2108 +#define DPIO_CTL 0x2110 +#define DPIO_MODSEL1 (1<<3) /* if ref clk b == 27 */ +#define DPIO_MODSEL0 (1<<2) /* if ref clk a == 27 */ +#define DPIO_SFR_BYPASS (1<<1) +#define DPIO_RESET (1<<0) + +#define _DPIO_DIV_A 0x800c +#define DPIO_POST_DIV_SHIFT (28) /* 3 bits */ +#define DPIO_K_SHIFT (24) /* 4 bits */ +#define DPIO_P1_SHIFT (21) /* 3 bits */ +#define DPIO_P2_SHIFT (16) /* 5 bits */ +#define DPIO_N_SHIFT (12) /* 4 bits */ +#define DPIO_ENABLE_CALIBRATION (1<<11) +#define DPIO_M1DIV_SHIFT (8) /* 3 bits */ +#define DPIO_M2DIV_MASK 0xff +#define _DPIO_DIV_B 0x802c +#define DPIO_DIV(pipe) _PIPE(pipe, _DPIO_DIV_A, _DPIO_DIV_B) + +#define _DPIO_REFSFR_A 0x8014 +#define DPIO_REFSEL_OVERRIDE 27 +#define DPIO_PLL_MODESEL_SHIFT 24 /* 3 bits */ +#define DPIO_BIAS_CURRENT_CTL_SHIFT 21 /* 3 bits, always 0x7 */ +#define DPIO_PLL_REFCLK_SEL_SHIFT 16 /* 2 bits */ +#define DPIO_DRIVER_CTL_SHIFT 12 /* always set to 0x8 */ +#define DPIO_CLK_BIAS_CTL_SHIFT 8 /* always set to 0x5 */ +#define _DPIO_REFSFR_B 0x8034 +#define DPIO_REFSFR(pipe) _PIPE(pipe, _DPIO_REFSFR_A, _DPIO_REFSFR_B) + +#define _DPIO_CORE_CLK_A 0x801c +#define _DPIO_CORE_CLK_B 0x803c +#define DPIO_CORE_CLK(pipe) _PIPE(pipe, _DPIO_CORE_CLK_A, _DPIO_CORE_CLK_B) + +#define _DPIO_LFP_COEFF_A 0x8048 +#define _DPIO_LFP_COEFF_B 0x8068 +#define DPIO_LFP_COEFF(pipe) _PIPE(pipe, _DPIO_LFP_COEFF_A, _DPIO_LFP_COEFF_B) + +#define DPIO_FASTCLK_DISABLE 0x8100 /* * Fence registers @@ -368,8 +436,6 @@ __FBSDID("$FreeBSD$"); #define ARB_MODE 0x04030 #define ARB_MODE_SWIZZLE_SNB (1<<4) #define ARB_MODE_SWIZZLE_IVB (1<<5) -#define ARB_MODE_ENABLE(x) GFX_MODE_ENABLE(x) -#define ARB_MODE_DISABLE(x) GFX_MODE_DISABLE(x) #define RENDER_HWS_PGA_GEN7 (0x04080) #define RING_FAULT_REG(ring) (0x4094 + 0x100*(ring)->id) #define DONE_REG 0x40b0 @@ -425,6 +491,7 @@ __FBSDID("$FreeBSD$"); #define INSTDONE 0x02090 #define NOPID 0x02094 #define HWSTAM 0x02098 +#define DMA_FADD_I8XX 0x020d0 #define ERROR_GEN6 0x040a0 @@ -440,6 +507,7 @@ __FBSDID("$FreeBSD$"); */ # define _3D_CHICKEN2_WM_READ_PIPELINED (1 << 14) #define _3D_CHICKEN3 0x02090 +#define _3D_CHICKEN_SF_DISABLE_FASTCLIP_CULL (1 << 5) #define MI_MODE 0x0209c # define VS_TIMER_DISPATCH (1 << 6) @@ -455,14 +523,16 @@ __FBSDID("$FreeBSD$"); #define GFX_PSMI_GRANULARITY (1<<10) #define GFX_PPGTT_ENABLE (1<<9) -#define GFX_MODE_ENABLE(bit) (((bit) << 16) | (bit)) -#define GFX_MODE_DISABLE(bit) (((bit) << 16) | (0)) - #define SCPD0 0x0209c /* 915+ only */ #define IER 0x020a0 #define IIR 0x020a4 #define IMR 0x020a8 #define ISR 0x020ac +#define VLV_IIR_RW 0x182084 +#define VLV_IER 0x1820a0 +#define VLV_IIR 0x1820a4 +#define VLV_IMR 0x1820a8 +#define VLV_ISR 0x1820ac #define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18) #define I915_DISPLAY_PORT_INTERRUPT (1<<17) #define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15) @@ -508,7 +578,6 @@ __FBSDID("$FreeBSD$"); #define LM_BURST_LENGTH 0x00000700 #define LM_FIFO_WATERMARK 0x0000001F #define MI_ARB_STATE 0x020e4 /* 915+ only */ -#define MI_ARB_MASK_SHIFT 16 /* shift for enable bits */ /* Make render/texture TLB fetches lower priorty than associated data * fetches. This is not turned on by default @@ -573,7 +642,6 @@ __FBSDID("$FreeBSD$"); #define MI_ARB_DISPLAY_PRIORITY_B_A (1 << 0) /* display B > display A */ #define CACHE_MODE_0 0x02120 /* 915+ only */ -#define CM0_MASK_SHIFT 16 #define CM0_IZ_OPT_DISABLE (1<<6) #define CM0_ZR_OPT_DISABLE (1<<5) #define CM0_STC_EVICT_DISABLE_LRA_SNB (1<<5) @@ -587,7 +655,12 @@ __FBSDID("$FreeBSD$"); #define ECO_GATING_CX_ONLY (1<<3) #define ECO_FLIP_DONE (1<<0) -/* GEN6 interrupt control */ +#define CACHE_MODE_1 0x7004 /* IVB+ */ +#define PIXEL_SUBSPAN_COLLECT_OPT_DISABLE (1<<6) + +/* GEN6 interrupt control + * Note that the per-ring interrupt bits do alias with the global interrupt bits + * in GTIMR. */ #define GEN6_RENDER_HWSTAM 0x2098 #define GEN6_RENDER_IMR 0x20a8 #define GEN6_RENDER_CONTEXT_SWITCH_INTERRUPT (1 << 8) @@ -623,6 +696,21 @@ __FBSDID("$FreeBSD$"); #define GEN6_BSD_RNCID 0x12198 +#define GEN7_FF_THREAD_MODE 0x20a0 +#define GEN7_FF_SCHED_MASK 0x0077070 +#define GEN7_FF_TS_SCHED_HS1 (0x5<<16) +#define GEN7_FF_TS_SCHED_HS0 (0x3<<16) +#define GEN7_FF_TS_SCHED_LOAD_BALANCE (0x1<<16) +#define GEN7_FF_TS_SCHED_HW (0x0<<16) /* Default */ +#define GEN7_FF_VS_SCHED_HS1 (0x5<<12) +#define GEN7_FF_VS_SCHED_HS0 (0x3<<12) +#define GEN7_FF_VS_SCHED_LOAD_BALANCE (0x1<<12) /* Default */ +#define GEN7_FF_VS_SCHED_HW (0x0<<12) +#define GEN7_FF_DS_SCHED_HS1 (0x5<<4) +#define GEN7_FF_DS_SCHED_HS0 (0x3<<4) +#define GEN7_FF_DS_SCHED_LOAD_BALANCE (0x1<<4) /* Default */ +#define GEN7_FF_DS_SCHED_HW (0x0<<4) + /* * Framebuffer compression (915+ only) */ @@ -751,9 +839,9 @@ __FBSDID("$FreeBSD$"); #define GMBUS_PORT_PANEL 3 #define GMBUS_PORT_DPC 4 /* HDMIC */ #define GMBUS_PORT_DPB 5 /* SDVO, HDMIB */ - /* 6 reserved */ -#define GMBUS_PORT_DPD 7 /* HDMID */ -#define GMBUS_NUM_PORTS 8 +#define GMBUS_PORT_DPD 6 /* HDMID */ +#define GMBUS_PORT_RESERVED 7 /* 7 reserved */ +#define GMBUS_NUM_PORTS (GMBUS_PORT_DPD - GMBUS_PORT_SSC + 1) #define GMBUS1 0x5104 /* command/status */ #define GMBUS_SW_CLR_INT (1<<31) #define GMBUS_SW_RDY (1<<30) @@ -805,7 +893,9 @@ __FBSDID("$FreeBSD$"); #define DPLL(pipe) _PIPE(pipe, _DPLL_A, _DPLL_B) #define DPLL_VCO_ENABLE (1 << 31) #define DPLL_DVO_HIGH_SPEED (1 << 30) +#define DPLL_EXT_BUFFER_ENABLE_VLV (1 << 30) #define DPLL_SYNCLOCK_ENABLE (1 << 29) +#define DPLL_REFA_CLK_ENABLE_VLV (1 << 29) #define DPLL_VGA_MODE_DIS (1 << 28) #define DPLLB_MODE_DAC_SERIAL (1 << 26) /* i915 */ #define DPLLB_MODE_LVDS (2 << 26) /* i915 */ @@ -817,6 +907,7 @@ __FBSDID("$FreeBSD$"); #define DPLL_P2_CLOCK_DIV_MASK 0x03000000 /* i915 */ #define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */ #define DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW 0x00ff8000 /* Pineview */ +#define DPLL_INTEGRATED_CLOCK_VLV (1<<13) #define SRX_INDEX 0x3c4 #define SRX_DATA 0x3c5 @@ -912,6 +1003,7 @@ __FBSDID("$FreeBSD$"); #define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0 #define _DPLL_B_MD 0x06020 /* 965+ only */ #define DPLL_MD(pipe) _PIPE(pipe, _DPLL_A_MD, _DPLL_B_MD) + #define _FPA0 0x06040 #define _FPA1 0x06044 #define _FPB0 0x06048 @@ -1052,6 +1144,9 @@ __FBSDID("$FreeBSD$"); #define RAMCLK_GATE_D 0x6210 /* CRL only */ #define DEUC 0x6214 /* CRL only */ +#define FW_BLC_SELF_VLV 0x6500 +#define FW_CSPWRDWNEN (1<<15) + /* * Palette regs */ @@ -1634,9 +1729,12 @@ __FBSDID("$FreeBSD$"); /* Video Data Island Packet control */ #define VIDEO_DIP_DATA 0x61178 #define VIDEO_DIP_CTL 0x61170 +/* Pre HSW: */ #define VIDEO_DIP_ENABLE (1 << 31) #define VIDEO_DIP_PORT_B (1 << 29) #define VIDEO_DIP_PORT_C (2 << 29) +#define VIDEO_DIP_PORT_D (3 << 29) +#define VIDEO_DIP_PORT_MASK (3 << 29) #define VIDEO_DIP_ENABLE_AVI (1 << 21) #define VIDEO_DIP_ENABLE_VENDOR (2 << 21) #define VIDEO_DIP_ENABLE_SPD (8 << 21) @@ -1647,6 +1745,10 @@ __FBSDID("$FreeBSD$"); #define VIDEO_DIP_FREQ_ONCE (0 << 16) #define VIDEO_DIP_FREQ_VSYNC (1 << 16) #define VIDEO_DIP_FREQ_2VSYNC (2 << 16) +#define VIDEO_DIP_FREQ_MASK (3 << 16) +/* HSW and later: */ +#define VIDEO_DIP_ENABLE_AVI_HSW (1 << 12) +#define VIDEO_DIP_ENABLE_SPD_HSW (1 << 0) /* Panel power sequencing */ #define PP_STATUS 0x61200 @@ -2413,7 +2515,8 @@ __FBSDID("$FreeBSD$"); /* Pipe A */ #define _PIPEADSL 0x70000 -#define DSL_LINEMASK 0x00000fff +#define DSL_LINEMASK_GEN2 0x00000fff +#define DSL_LINEMASK_GEN3 0x00001fff #define _PIPEACONF 0x70008 #define PIPECONF_ENABLE (1<<31) #define PIPECONF_DISABLE 0 @@ -2455,23 +2558,30 @@ __FBSDID("$FreeBSD$"); #define PIPECONF_DITHER_TYPE_TEMP (3<<2) #define _PIPEASTAT 0x70024 #define PIPE_FIFO_UNDERRUN_STATUS (1UL<<31) +#define SPRITE1_FLIPDONE_INT_EN_VLV (1UL<<30) #define PIPE_CRC_ERROR_ENABLE (1UL<<29) #define PIPE_CRC_DONE_ENABLE (1UL<<28) #define PIPE_GMBUS_EVENT_ENABLE (1UL<<27) +#define PLANE_FLIP_DONE_INT_EN_VLV (1UL<<26) #define PIPE_HOTPLUG_INTERRUPT_ENABLE (1UL<<26) #define PIPE_VSYNC_INTERRUPT_ENABLE (1UL<<25) #define PIPE_DISPLAY_LINE_COMPARE_ENABLE (1UL<<24) #define PIPE_DPST_EVENT_ENABLE (1UL<<23) +#define SPRITE0_FLIP_DONE_INT_EN_VLV (1UL<<26) #define PIPE_LEGACY_BLC_EVENT_ENABLE (1UL<<22) #define PIPE_ODD_FIELD_INTERRUPT_ENABLE (1UL<<21) #define PIPE_EVEN_FIELD_INTERRUPT_ENABLE (1UL<<20) #define PIPE_HOTPLUG_TV_INTERRUPT_ENABLE (1UL<<18) /* pre-965 */ #define PIPE_START_VBLANK_INTERRUPT_ENABLE (1UL<<18) /* 965 or later */ #define PIPE_VBLANK_INTERRUPT_ENABLE (1UL<<17) +#define PIPEA_HBLANK_INT_EN_VLV (1UL<<16) #define PIPE_OVERLAY_UPDATED_ENABLE (1UL<<16) +#define SPRITE1_FLIPDONE_INT_STATUS_VLV (1UL<<15) +#define SPRITE0_FLIPDONE_INT_STATUS_VLV (1UL<<15) #define PIPE_CRC_ERROR_INTERRUPT_STATUS (1UL<<13) #define PIPE_CRC_DONE_INTERRUPT_STATUS (1UL<<12) #define PIPE_GMBUS_INTERRUPT_STATUS (1UL<<11) +#define PLANE_FLIPDONE_INT_STATUS_VLV (1UL<<10) #define PIPE_HOTPLUG_INTERRUPT_STATUS (1UL<<10) #define PIPE_VSYNC_INTERRUPT_STATUS (1UL<<9) #define PIPE_DISPLAY_LINE_COMPARE_STATUS (1UL<<8) @@ -2496,6 +2606,40 @@ __FBSDID("$FreeBSD$"); #define PIPEFRAMEPIXEL(pipe) _PIPE(pipe, _PIPEAFRAMEPIXEL, _PIPEBFRAMEPIXEL) #define PIPESTAT(pipe) _PIPE(pipe, _PIPEASTAT, _PIPEBSTAT) +#define VLV_DPFLIPSTAT 0x70028 +#define PIPEB_LINE_COMPARE_STATUS (1<<29) +#define PIPEB_HLINE_INT_EN (1<<28) +#define PIPEB_VBLANK_INT_EN (1<<27) +#define SPRITED_FLIPDONE_INT_EN (1<<26) +#define SPRITEC_FLIPDONE_INT_EN (1<<25) +#define PLANEB_FLIPDONE_INT_EN (1<<24) +#define PIPEA_LINE_COMPARE_STATUS (1<<21) +#define PIPEA_HLINE_INT_EN (1<<20) +#define PIPEA_VBLANK_INT_EN (1<<19) +#define SPRITEB_FLIPDONE_INT_EN (1<<18) +#define SPRITEA_FLIPDONE_INT_EN (1<<17) +#define PLANEA_FLIPDONE_INT_EN (1<<16) + +#define DPINVGTT 0x7002c /* VLV only */ +#define CURSORB_INVALID_GTT_INT_EN (1<<23) +#define CURSORA_INVALID_GTT_INT_EN (1<<22) +#define SPRITED_INVALID_GTT_INT_EN (1<<21) +#define SPRITEC_INVALID_GTT_INT_EN (1<<20) +#define PLANEB_INVALID_GTT_INT_EN (1<<19) +#define SPRITEB_INVALID_GTT_INT_EN (1<<18) +#define SPRITEA_INVALID_GTT_INT_EN (1<<17) +#define PLANEA_INVALID_GTT_INT_EN (1<<16) +#define DPINVGTT_EN_MASK 0xff0000 +#define CURSORB_INVALID_GTT_STATUS (1<<7) +#define CURSORA_INVALID_GTT_STATUS (1<<6) +#define SPRITED_INVALID_GTT_STATUS (1<<5) +#define SPRITEC_INVALID_GTT_STATUS (1<<4) +#define PLANEB_INVALID_GTT_STATUS (1<<3) +#define SPRITEB_INVALID_GTT_STATUS (1<<2) +#define SPRITEA_INVALID_GTT_STATUS (1<<1) +#define PLANEA_INVALID_GTT_STATUS (1<<0) +#define DPINVGTT_STATUS_MASK 0xff + #define DSPARB 0x70030 #define DSPARB_CSTART_MASK (0x7f << 7) #define DSPARB_CSTART_SHIFT 7 @@ -2525,11 +2669,28 @@ __FBSDID("$FreeBSD$"); #define DSPFW_HPLL_CURSOR_MASK (0x3f<<16) #define DSPFW_HPLL_SR_MASK (0x1ff) +/* drain latency register values*/ +#define DRAIN_LATENCY_PRECISION_32 32 +#define DRAIN_LATENCY_PRECISION_16 16 +#define VLV_DDL1 0x70050 +#define DDL_CURSORA_PRECISION_32 (1<<31) +#define DDL_CURSORA_PRECISION_16 (0<<31) +#define DDL_CURSORA_SHIFT 24 +#define DDL_PLANEA_PRECISION_32 (1<<7) +#define DDL_PLANEA_PRECISION_16 (0<<7) +#define VLV_DDL2 0x70054 +#define DDL_CURSORB_PRECISION_32 (1<<31) +#define DDL_CURSORB_PRECISION_16 (0<<31) +#define DDL_CURSORB_SHIFT 24 +#define DDL_PLANEB_PRECISION_32 (1<<7) +#define DDL_PLANEB_PRECISION_16 (0<<7) + /* FIFO watermark sizes etc */ #define G4X_FIFO_LINE_SIZE 64 #define I915_FIFO_LINE_SIZE 64 #define I830_FIFO_LINE_SIZE 32 +#define VALLEYVIEW_FIFO_SIZE 255 #define G4X_FIFO_SIZE 127 #define I965_FIFO_SIZE 512 #define I945_FIFO_SIZE 127 @@ -2537,6 +2698,7 @@ __FBSDID("$FreeBSD$"); #define I855GM_FIFO_SIZE 127 /* In cachelines */ #define I830_FIFO_SIZE 95 +#define VALLEYVIEW_MAX_WM 0xff #define G4X_MAX_WM 0x3f #define I915_MAX_WM 0x3f @@ -2551,6 +2713,7 @@ __FBSDID("$FreeBSD$"); #define PINEVIEW_CURSOR_DFT_WM 0 #define PINEVIEW_CURSOR_GUARD_WM 5 +#define VALLEYVIEW_CURSOR_MAX_WM 64 #define I965_CURSOR_FIFO 64 #define I965_CURSOR_MAX_WM 32 #define I965_CURSOR_DFT_WM 8 @@ -2759,6 +2922,13 @@ __FBSDID("$FreeBSD$"); #define DSPSURF(plane) _PIPE(plane, _DSPASURF, _DSPBSURF) #define DSPTILEOFF(plane) _PIPE(plane, _DSPATILEOFF, _DSPBTILEOFF) +/* Display/Sprite base address macros */ +#define DISP_BASEADDR_MASK (0xfffff000) +#define I915_LO_DISPBASE(val) (val & ~DISP_BASEADDR_MASK) +#define I915_HI_DISPBASE(val) (val & DISP_BASEADDR_MASK) +#define I915_MODIFY_DISPBASE(reg, gfx_addr) \ + (I915_WRITE(reg, gfx_addr | I915_LO_DISPBASE(I915_READ(reg)))) + /* VBIOS flags */ #define SWF00 0x71410 #define SWF01 0x71414 @@ -3091,26 +3261,38 @@ __FBSDID("$FreeBSD$"); #define DE_PCH_EVENT_IVB (1<<28) #define DE_DP_A_HOTPLUG_IVB (1<<27) #define DE_AUX_CHANNEL_A_IVB (1<<26) +#define DE_SPRITEC_FLIP_DONE_IVB (1<<14) +#define DE_PLANEC_FLIP_DONE_IVB (1<<13) +#define DE_PIPEC_VBLANK_IVB (1<<10) #define DE_SPRITEB_FLIP_DONE_IVB (1<<9) -#define DE_SPRITEA_FLIP_DONE_IVB (1<<4) #define DE_PLANEB_FLIP_DONE_IVB (1<<8) -#define DE_PLANEA_FLIP_DONE_IVB (1<<3) #define DE_PIPEB_VBLANK_IVB (1<<5) +#define DE_SPRITEA_FLIP_DONE_IVB (1<<4) +#define DE_PLANEA_FLIP_DONE_IVB (1<<3) #define DE_PIPEA_VBLANK_IVB (1<<0) +#define VLV_MASTER_IER 0x4400c /* Gunit master IER */ +#define MASTER_INTERRUPT_ENABLE (1<<31) + #define DEISR 0x44000 #define DEIMR 0x44004 #define DEIIR 0x44008 #define DEIER 0x4400c -/* GT interrupt */ -#define GT_PIPE_NOTIFY (1 << 4) -#define GT_RENDER_CS_ERROR (1 << 3) -#define GT_SYNC_STATUS (1 << 2) -#define GT_USER_INTERRUPT (1 << 0) -#define GT_BSD_USER_INTERRUPT (1 << 5) -#define GT_GEN6_BSD_USER_INTERRUPT (1 << 12) -#define GT_BLT_USER_INTERRUPT (1 << 22) +/* GT interrupt. + * Note that for gen6+ the ring-specific interrupt bits do alias with the + * corresponding bits in the per-ring interrupt control registers. */ +#define GT_GEN6_BLT_FLUSHDW_NOTIFY_INTERRUPT (1 << 26) +#define GT_GEN6_BLT_CS_ERROR_INTERRUPT (1 << 25) +#define GT_GEN6_BLT_USER_INTERRUPT (1 << 22) +#define GT_GEN6_BSD_CS_ERROR_INTERRUPT (1 << 15) +#define GT_GEN6_BSD_USER_INTERRUPT (1 << 12) +#define GT_BSD_USER_INTERRUPT (1 << 5) /* ilk only */ +#define GT_GEN7_L3_PARITY_ERROR_INTERRUPT (1 << 5) +#define GT_PIPE_NOTIFY (1 << 4) +#define GT_RENDER_CS_ERROR_INTERRUPT (1 << 3) +#define GT_SYNC_STATUS (1 << 2) +#define GT_USER_INTERRUPT (1 << 0) #define GTISR 0x44010 #define GTIMR 0x44014 @@ -3260,15 +3442,15 @@ __FBSDID("$FreeBSD$"); #define _PCH_DPLL_A 0xc6014 #define _PCH_DPLL_B 0xc6018 -#define PCH_DPLL(pipe) (pipe == 0 ? _PCH_DPLL_A : _PCH_DPLL_B) +#define _PCH_DPLL(pll) (pll == 0 ? _PCH_DPLL_A : _PCH_DPLL_B) #define _PCH_FPA0 0xc6040 #define FP_CB_TUNE (0x3<<22) #define _PCH_FPA1 0xc6044 #define _PCH_FPB0 0xc6048 #define _PCH_FPB1 0xc604c -#define PCH_FP0(pipe) (pipe == 0 ? _PCH_FPA0 : _PCH_FPB0) -#define PCH_FP1(pipe) (pipe == 0 ? _PCH_FPA1 : _PCH_FPB1) +#define _PCH_FP0(pll) (pll == 0 ? _PCH_FPA0 : _PCH_FPB0) +#define _PCH_FP1(pll) (pll == 0 ? _PCH_FPA1 : _PCH_FPB1) #define PCH_DPLL_TEST 0xc606c @@ -3363,6 +3545,57 @@ __FBSDID("$FreeBSD$"); #define TVIDEO_DIP_DATA(pipe) _PIPE(pipe, _VIDEO_DIP_DATA_A, _VIDEO_DIP_DATA_B) #define TVIDEO_DIP_GCP(pipe) _PIPE(pipe, _VIDEO_DIP_GCP_A, _VIDEO_DIP_GCP_B) +#define VLV_VIDEO_DIP_CTL_A 0x60220 +#define VLV_VIDEO_DIP_DATA_A 0x60208 +#define VLV_VIDEO_DIP_GDCP_PAYLOAD_A 0x60210 + +#define VLV_VIDEO_DIP_CTL_B 0x61170 +#define VLV_VIDEO_DIP_DATA_B 0x61174 +#define VLV_VIDEO_DIP_GDCP_PAYLOAD_B 0x61178 + +#define VLV_TVIDEO_DIP_CTL(pipe) \ + _PIPE(pipe, VLV_VIDEO_DIP_CTL_A, VLV_VIDEO_DIP_CTL_B) +#define VLV_TVIDEO_DIP_DATA(pipe) \ + _PIPE(pipe, VLV_VIDEO_DIP_DATA_A, VLV_VIDEO_DIP_DATA_B) +#define VLV_TVIDEO_DIP_GCP(pipe) \ + _PIPE(pipe, VLV_VIDEO_DIP_GDCP_PAYLOAD_A, VLV_VIDEO_DIP_GDCP_PAYLOAD_B) + +/* Haswell DIP controls */ +#define HSW_VIDEO_DIP_CTL_A 0x60200 +#define HSW_VIDEO_DIP_AVI_DATA_A 0x60220 +#define HSW_VIDEO_DIP_VS_DATA_A 0x60260 +#define HSW_VIDEO_DIP_SPD_DATA_A 0x602A0 +#define HSW_VIDEO_DIP_GMP_DATA_A 0x602E0 +#define HSW_VIDEO_DIP_VSC_DATA_A 0x60320 +#define HSW_VIDEO_DIP_AVI_ECC_A 0x60240 +#define HSW_VIDEO_DIP_VS_ECC_A 0x60280 +#define HSW_VIDEO_DIP_SPD_ECC_A 0x602C0 +#define HSW_VIDEO_DIP_GMP_ECC_A 0x60300 +#define HSW_VIDEO_DIP_VSC_ECC_A 0x60344 +#define HSW_VIDEO_DIP_GCP_A 0x60210 + +#define HSW_VIDEO_DIP_CTL_B 0x61200 +#define HSW_VIDEO_DIP_AVI_DATA_B 0x61220 +#define HSW_VIDEO_DIP_VS_DATA_B 0x61260 +#define HSW_VIDEO_DIP_SPD_DATA_B 0x612A0 +#define HSW_VIDEO_DIP_GMP_DATA_B 0x612E0 +#define HSW_VIDEO_DIP_VSC_DATA_B 0x61320 +#define HSW_VIDEO_DIP_BVI_ECC_B 0x61240 +#define HSW_VIDEO_DIP_VS_ECC_B 0x61280 +#define HSW_VIDEO_DIP_SPD_ECC_B 0x612C0 +#define HSW_VIDEO_DIP_GMP_ECC_B 0x61300 +#define HSW_VIDEO_DIP_VSC_ECC_B 0x61344 +#define HSW_VIDEO_DIP_GCP_B 0x61210 + +#define HSW_TVIDEO_DIP_CTL(pipe) \ + _PIPE(pipe, HSW_VIDEO_DIP_CTL_A, HSW_VIDEO_DIP_CTL_B) +#define HSW_TVIDEO_DIP_AVI_DATA(pipe) \ + _PIPE(pipe, HSW_VIDEO_DIP_AVI_DATA_A, HSW_VIDEO_DIP_AVI_DATA_B) +#define HSW_TVIDEO_DIP_SPD_DATA(pipe) \ + _PIPE(pipe, HSW_VIDEO_DIP_SPD_DATA_A, HSW_VIDEO_DIP_SPD_DATA_B) +#define HSW_TVIDEO_DIP_GCP(pipe) \ + _PIPE(pipe, HSW_VIDEO_DIP_GCP_A, HSW_VIDEO_DIP_GCP_B) + #define _TRANS_HTOTAL_B 0xe1000 #define _TRANS_HBLANK_B 0xe1004 #define _TRANS_HSYNC_B 0xe1008 @@ -3522,6 +3755,9 @@ __FBSDID("$FreeBSD$"); #define FDI_LINK_TRAIN_PATTERN_IDLE_CPT (2<<8) #define FDI_LINK_TRAIN_NORMAL_CPT (3<<8) #define FDI_LINK_TRAIN_PATTERN_MASK_CPT (3<<8) +/* LPT */ +#define FDI_PORT_WIDTH_2X_LPT (1<<19) +#define FDI_PORT_WIDTH_1X_LPT (0<<19) #define _FDI_RXA_MISC 0xf0010 #define _FDI_RXB_MISC 0xf1010 @@ -3582,6 +3818,7 @@ __FBSDID("$FreeBSD$"); #define ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1<<16) /* or SDVOB */ +#define VLV_HDMIB 0x61140 #define HDMIB 0xe1140 #define PORT_ENABLE (1 << 31) #define TRANSCODER(pipe) ((pipe) << 30) @@ -3747,6 +3984,8 @@ __FBSDID("$FreeBSD$"); #define EDP_LINK_TRAIN_VOL_EMP_MASK_IVB (0x3f<<22) #define FORCEWAKE 0xA18C +#define FORCEWAKE_VLV 0x1300b0 +#define FORCEWAKE_ACK_VLV 0x1300b4 #define FORCEWAKE_ACK 0x130090 #define FORCEWAKE_MT 0xa188 /* multi-threaded */ #define FORCEWAKE_MT_ACK 0x130040 @@ -3764,6 +4003,7 @@ __FBSDID("$FreeBSD$"); #define GEN6_UCGCTL1 0x9400 # define GEN6_BLBUNIT_CLOCK_GATE_DISABLE (1 << 5) +# define GEN6_CSUNIT_CLOCK_GATE_DISABLE (1 << 7) #define GEN6_UCGCTL2 0x9404 # define GEN6_RCZUNIT_CLOCK_GATE_DISABLE (1 << 13) @@ -3841,8 +4081,13 @@ __FBSDID("$FreeBSD$"); #define GEN6_PM_RP_UP_EI_EXPIRED (1<<2) #define GEN6_PM_RP_DOWN_EI_EXPIRED (1<<1) #define GEN6_PM_DEFERRED_EVENTS (GEN6_PM_RP_UP_THRESHOLD | \ - GEN6_PM_RP_DOWN_THRESHOLD | \ - GEN6_PM_RP_DOWN_TIMEOUT) + GEN6_PM_RP_DOWN_THRESHOLD | \ + GEN6_PM_RP_DOWN_TIMEOUT) + +#define GEN6_GT_GFX_RC6_LOCKED 0x138104 +#define GEN6_GT_GFX_RC6 0x138108 +#define GEN6_GT_GFX_RC6p 0x13810C +#define GEN6_GT_GFX_RC6pp 0x138110 #define GEN6_PCODE_MAILBOX 0x138124 #define GEN6_PCODE_READY (1<<31) @@ -3903,4 +4148,197 @@ __FBSDID("$FreeBSD$"); #define AUD_CONFIG_PIXEL_CLOCK_HDMI (0xf << 16) #define AUD_CONFIG_DISABLE_NCTS (1 << 3) +/* HSW Power Wells */ +#define HSW_PWR_WELL_CTL1 0x45400 /* BIOS */ +#define HSW_PWR_WELL_CTL2 0x45404 /* Driver */ +#define HSW_PWR_WELL_CTL3 0x45408 /* KVMR */ +#define HSW_PWR_WELL_CTL4 0x4540C /* Debug */ +#define HSW_PWR_WELL_ENABLE (1<<31) +#define HSW_PWR_WELL_STATE (1<<30) +#define HSW_PWR_WELL_CTL5 0x45410 +#define HSW_PWR_WELL_ENABLE_SINGLE_STEP (1<<31) +#define HSW_PWR_WELL_PWR_GATE_OVERRIDE (1<<20) +#define HSW_PWR_WELL_FORCE_ON (1<<19) +#define HSW_PWR_WELL_CTL6 0x45414 + +/* Per-pipe DDI Function Control */ +#define PIPE_DDI_FUNC_CTL_A 0x60400 +#define PIPE_DDI_FUNC_CTL_B 0x61400 +#define PIPE_DDI_FUNC_CTL_C 0x62400 +#define PIPE_DDI_FUNC_CTL_EDP 0x6F400 +#define DDI_FUNC_CTL(pipe) _PIPE(pipe, \ + PIPE_DDI_FUNC_CTL_A, \ + PIPE_DDI_FUNC_CTL_B) +#define PIPE_DDI_FUNC_ENABLE (1<<31) +/* Those bits are ignored by pipe EDP since it can only connect to DDI A */ +#define PIPE_DDI_PORT_MASK (0xf<<28) +#define PIPE_DDI_SELECT_PORT(x) ((x)<<28) +#define PIPE_DDI_MODE_SELECT_HDMI (0<<24) +#define PIPE_DDI_MODE_SELECT_DVI (1<<24) +#define PIPE_DDI_MODE_SELECT_DP_SST (2<<24) +#define PIPE_DDI_MODE_SELECT_DP_MST (3<<24) +#define PIPE_DDI_MODE_SELECT_FDI (4<<24) +#define PIPE_DDI_BPC_8 (0<<20) +#define PIPE_DDI_BPC_10 (1<<20) +#define PIPE_DDI_BPC_6 (2<<20) +#define PIPE_DDI_BPC_12 (3<<20) +#define PIPE_DDI_BFI_ENABLE (1<<4) +#define PIPE_DDI_PORT_WIDTH_X1 (0<<1) +#define PIPE_DDI_PORT_WIDTH_X2 (1<<1) +#define PIPE_DDI_PORT_WIDTH_X4 (3<<1) + +/* DisplayPort Transport Control */ +#define DP_TP_CTL_A 0x64040 +#define DP_TP_CTL_B 0x64140 +#define DP_TP_CTL(port) _PORT(port, \ + DP_TP_CTL_A, \ + DP_TP_CTL_B) +#define DP_TP_CTL_ENABLE (1<<31) +#define DP_TP_CTL_MODE_SST (0<<27) +#define DP_TP_CTL_MODE_MST (1<<27) +#define DP_TP_CTL_ENHANCED_FRAME_ENABLE (1<<18) +#define DP_TP_CTL_FDI_AUTOTRAIN (1<<15) +#define DP_TP_CTL_LINK_TRAIN_MASK (7<<8) +#define DP_TP_CTL_LINK_TRAIN_PAT1 (0<<8) +#define DP_TP_CTL_LINK_TRAIN_PAT2 (1<<8) +#define DP_TP_CTL_LINK_TRAIN_NORMAL (3<<8) + +/* DisplayPort Transport Status */ +#define DP_TP_STATUS_A 0x64044 +#define DP_TP_STATUS_B 0x64144 +#define DP_TP_STATUS(port) _PORT(port, \ + DP_TP_STATUS_A, \ + DP_TP_STATUS_B) +#define DP_TP_STATUS_AUTOTRAIN_DONE (1<<12) + +/* DDI Buffer Control */ +#define DDI_BUF_CTL_A 0x64000 +#define DDI_BUF_CTL_B 0x64100 +#define DDI_BUF_CTL(port) _PORT(port, \ + DDI_BUF_CTL_A, \ + DDI_BUF_CTL_B) +#define DDI_BUF_CTL_ENABLE (1<<31) +#define DDI_BUF_EMP_400MV_0DB_HSW (0<<24) /* Sel0 */ +#define DDI_BUF_EMP_400MV_3_5DB_HSW (1<<24) /* Sel1 */ +#define DDI_BUF_EMP_400MV_6DB_HSW (2<<24) /* Sel2 */ +#define DDI_BUF_EMP_400MV_9_5DB_HSW (3<<24) /* Sel3 */ +#define DDI_BUF_EMP_600MV_0DB_HSW (4<<24) /* Sel4 */ +#define DDI_BUF_EMP_600MV_3_5DB_HSW (5<<24) /* Sel5 */ +#define DDI_BUF_EMP_600MV_6DB_HSW (6<<24) /* Sel6 */ +#define DDI_BUF_EMP_800MV_0DB_HSW (7<<24) /* Sel7 */ +#define DDI_BUF_EMP_800MV_3_5DB_HSW (8<<24) /* Sel8 */ +#define DDI_BUF_EMP_MASK (0xf<<24) +#define DDI_BUF_IS_IDLE (1<<7) +#define DDI_PORT_WIDTH_X1 (0<<1) +#define DDI_PORT_WIDTH_X2 (1<<1) +#define DDI_PORT_WIDTH_X4 (3<<1) +#define DDI_INIT_DISPLAY_DETECTED (1<<0) + +/* DDI Buffer Translations */ +#define DDI_BUF_TRANS_A 0x64E00 +#define DDI_BUF_TRANS_B 0x64E60 +#define DDI_BUF_TRANS(port) _PORT(port, \ + DDI_BUF_TRANS_A, \ + DDI_BUF_TRANS_B) + +/* Sideband Interface (SBI) is programmed indirectly, via + * SBI_ADDR, which contains the register offset; and SBI_DATA, + * which contains the payload */ +#define SBI_ADDR 0xC6000 +#define SBI_DATA 0xC6004 +#define SBI_CTL_STAT 0xC6008 +#define SBI_CTL_OP_CRRD (0x6<<8) +#define SBI_CTL_OP_CRWR (0x7<<8) +#define SBI_RESPONSE_FAIL (0x1<<1) +#define SBI_RESPONSE_SUCCESS (0x0<<1) +#define SBI_BUSY (0x1<<0) +#define SBI_READY (0x0<<0) + +/* SBI offsets */ +#define SBI_SSCDIVINTPHASE6 0x0600 +#define SBI_SSCDIVINTPHASE_DIVSEL_MASK ((0x7f)<<1) +#define SBI_SSCDIVINTPHASE_DIVSEL(x) ((x)<<1) +#define SBI_SSCDIVINTPHASE_INCVAL_MASK ((0x7f)<<8) +#define SBI_SSCDIVINTPHASE_INCVAL(x) ((x)<<8) +#define SBI_SSCDIVINTPHASE_DIR(x) ((x)<<15) +#define SBI_SSCDIVINTPHASE_PROPAGATE (1<<0) +#define SBI_SSCCTL 0x020c +#define SBI_SSCCTL6 0x060C +#define SBI_SSCCTL_DISABLE (1<<0) +#define SBI_SSCAUXDIV6 0x0610 +#define SBI_SSCAUXDIV_FINALDIV2SEL(x) ((x)<<4) +#define SBI_DBUFF0 0x2a00 + +/* LPT PIXCLK_GATE */ +#define PIXCLK_GATE 0xC6020 +#define PIXCLK_GATE_UNGATE 1<<0 +#define PIXCLK_GATE_GATE 0<<0 + +/* SPLL */ +#define SPLL_CTL 0x46020 +#define SPLL_PLL_ENABLE (1<<31) +#define SPLL_PLL_SCC (1<<28) +#define SPLL_PLL_NON_SCC (2<<28) +#define SPLL_PLL_FREQ_810MHz (0<<26) +#define SPLL_PLL_FREQ_1350MHz (1<<26) + +/* WRPLL */ +#define WRPLL_CTL1 0x46040 +#define WRPLL_CTL2 0x46060 +#define WRPLL_PLL_ENABLE (1<<31) +#define WRPLL_PLL_SELECT_SSC (0x01<<28) +#define WRPLL_PLL_SELECT_NON_SCC (0x02<<28) +#define WRPLL_PLL_SELECT_LCPLL_2700 (0x03<<28) +/* WRPLL divider programming */ +#define WRPLL_DIVIDER_REFERENCE(x) ((x)<<0) +#define WRPLL_DIVIDER_POST(x) ((x)<<8) +#define WRPLL_DIVIDER_FEEDBACK(x) ((x)<<16) + +/* Port clock selection */ +#define PORT_CLK_SEL_A 0x46100 +#define PORT_CLK_SEL_B 0x46104 +#define PORT_CLK_SEL(port) _PORT(port, \ + PORT_CLK_SEL_A, \ + PORT_CLK_SEL_B) +#define PORT_CLK_SEL_LCPLL_2700 (0<<29) +#define PORT_CLK_SEL_LCPLL_1350 (1<<29) +#define PORT_CLK_SEL_LCPLL_810 (2<<29) +#define PORT_CLK_SEL_SPLL (3<<29) +#define PORT_CLK_SEL_WRPLL1 (4<<29) +#define PORT_CLK_SEL_WRPLL2 (5<<29) + +/* Pipe clock selection */ +#define PIPE_CLK_SEL_A 0x46140 +#define PIPE_CLK_SEL_B 0x46144 +#define PIPE_CLK_SEL(pipe) _PIPE(pipe, \ + PIPE_CLK_SEL_A, \ + PIPE_CLK_SEL_B) +/* For each pipe, we need to select the corresponding port clock */ +#define PIPE_CLK_SEL_DISABLED (0x0<<29) +#define PIPE_CLK_SEL_PORT(x) ((x+1)<<29) + +/* LCPLL Control */ +#define LCPLL_CTL 0x130040 +#define LCPLL_PLL_DISABLE (1<<31) +#define LCPLL_PLL_LOCK (1<<30) +#define LCPLL_CD_CLOCK_DISABLE (1<<25) +#define LCPLL_CD2X_CLOCK_DISABLE (1<<23) + +/* Pipe WM_LINETIME - watermark line time */ +#define PIPE_WM_LINETIME_A 0x45270 +#define PIPE_WM_LINETIME_B 0x45274 +#define PIPE_WM_LINETIME(pipe) _PIPE(pipe, \ + PIPE_WM_LINETIME_A, \ + PIPE_WM_LINETIME_A) +#define PIPE_WM_LINETIME_MASK (0x1ff) +#define PIPE_WM_LINETIME_TIME(x) ((x)) +#define PIPE_WM_LINETIME_IPS_LINETIME_MASK (0x1ff<<16) +#define PIPE_WM_LINETIME_IPS_LINETIME(x) ((x)<<16) + +/* SFUSE_STRAP */ +#define SFUSE_STRAP 0xc2014 +#define SFUSE_STRAP_DDIB_DETECTED (1<<2) +#define SFUSE_STRAP_DDIC_DETECTED (1<<1) +#define SFUSE_STRAP_DDID_DETECTED (1<<0) + #endif /* _I915_REG_H_ */ diff --git a/sys/dev/drm2/i915/i915_suspend.c b/sys/dev/drm2/i915/i915_suspend.c index 1e219a1612ac..fd31120233e9 100644 --- a/sys/dev/drm2/i915/i915_suspend.c +++ b/sys/dev/drm2/i915/i915_suspend.c @@ -42,7 +42,7 @@ static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe) return false; if (HAS_PCH_SPLIT(dev)) - dpll_reg = PCH_DPLL(pipe); + dpll_reg = _PCH_DPLL(pipe); else dpll_reg = (pipe == PIPE_A) ? _DPLL_A : _DPLL_B; @@ -873,22 +873,6 @@ int i915_restore_state(struct drm_device *dev) I915_WRITE(IER, dev_priv->saveIER); I915_WRITE(IMR, dev_priv->saveIMR); } - DRM_UNLOCK(dev); - - if (drm_core_check_feature(dev, DRIVER_MODESET)) - intel_init_clock_gating(dev); - - if (IS_IRONLAKE_M(dev)) { - ironlake_enable_drps(dev); - intel_init_emon(dev); - } - - if (INTEL_INFO(dev)->gen >= 6) { - gen6_enable_rps(dev_priv); - gen6_update_ring_freq(dev_priv); - } - - DRM_LOCK(dev); /* Cache mode state */ I915_WRITE(CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000); diff --git a/sys/dev/drm2/i915/intel_bios.c b/sys/dev/drm2/i915/intel_bios.c index 8bf38a5722c1..049979442908 100644 --- a/sys/dev/drm2/i915/intel_bios.c +++ b/sys/dev/drm2/i915/intel_bios.c @@ -175,6 +175,28 @@ get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *lvds_lfp_data, return (const struct lvds_dvo_timing *)(entry + dvo_timing_offset); } +/* get lvds_fp_timing entry + * this function may return NULL if the corresponding entry is invalid + */ +static const struct lvds_fp_timing * +get_lvds_fp_timing(const struct bdb_header *bdb, + const struct bdb_lvds_lfp_data *data, + const struct bdb_lvds_lfp_data_ptrs *ptrs, + int index) +{ + size_t data_ofs = (const u8 *)data - (const u8 *)bdb; + u16 data_size = ((const u16 *)data)[-1]; /* stored in header */ + size_t ofs; + + if (index >= DRM_ARRAY_SIZE(ptrs->ptr)) + return NULL; + ofs = ptrs->ptr[index].fp_timing_offset; + if (ofs < data_ofs || + ofs + sizeof(struct lvds_fp_timing) > data_ofs + data_size) + return NULL; + return (const struct lvds_fp_timing *)((const u8 *)bdb + ofs); +} + /* Try to find integrated panel data */ static void parse_lfp_panel_data(struct drm_i915_private *dev_priv, @@ -184,6 +206,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, const struct bdb_lvds_lfp_data *lvds_lfp_data; const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs; const struct lvds_dvo_timing *panel_dvo_timing; + const struct lvds_fp_timing *fp_timing; struct drm_display_mode *panel_fixed_mode; int i, downclock; @@ -244,6 +267,19 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, "Normal Clock %dKHz, downclock %dKHz\n", panel_fixed_mode->clock, 10 * downclock); } + + fp_timing = get_lvds_fp_timing(bdb, lvds_lfp_data, + lvds_lfp_data_ptrs, + lvds_options->panel_type); + if (fp_timing) { + /* check the resolution, just to be sure */ + if (fp_timing->x_res == panel_fixed_mode->hdisplay && + fp_timing->y_res == panel_fixed_mode->vdisplay) { + dev_priv->bios_lvds_val = fp_timing->lvds_reg_val; + DRM_DEBUG_KMS("VBT initial LVDS value %x\n", + dev_priv->bios_lvds_val); + } + } } /* Try to find sdvo panel data */ @@ -256,6 +292,11 @@ parse_sdvo_panel_data(struct drm_i915_private *dev_priv, int index; index = i915_vbt_sdvo_panel_type; + if (index == -2) { + DRM_DEBUG_KMS("Ignore SDVO panel mode from BIOS VBT tables.\n"); + return; + } + if (index == -1) { struct bdb_sdvo_lvds_options *sdvo_lvds_options; @@ -331,11 +372,11 @@ parse_general_definitions(struct drm_i915_private *dev_priv, if (block_size >= sizeof(*general)) { int bus_pin = general->crt_ddc_gmbus_pin; DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin); - if (bus_pin >= 1 && bus_pin <= 6) + if (intel_gmbus_is_port_valid(bus_pin)) dev_priv->crt_ddc_pin = bus_pin; } else { DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n", - block_size); + block_size); } } } diff --git a/sys/dev/drm2/i915/intel_crt.c b/sys/dev/drm2/i915/intel_crt.c index 5d96d2f22cb2..c1b39eb096b5 100644 --- a/sys/dev/drm2/i915/intel_crt.c +++ b/sys/dev/drm2/i915/intel_crt.c @@ -55,18 +55,36 @@ static struct intel_crt *intel_attached_crt(struct drm_connector *connector) struct intel_crt, base); } -static void intel_crt_dpms(struct drm_encoder *encoder, int mode) +static void pch_crt_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - u32 temp, reg; + u32 temp; - if (HAS_PCH_SPLIT(dev)) - reg = PCH_ADPA; - else - reg = ADPA; + temp = I915_READ(PCH_ADPA); + temp &= ~ADPA_DAC_ENABLE; - temp = I915_READ(reg); + switch (mode) { + case DRM_MODE_DPMS_ON: + temp |= ADPA_DAC_ENABLE; + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + /* Just leave port enable cleared */ + break; + } + + I915_WRITE(PCH_ADPA, temp); +} + +static void gmch_crt_dpms(struct drm_encoder *encoder, int mode) +{ + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 temp; + + temp = I915_READ(ADPA); temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); temp &= ~ADPA_DAC_ENABLE; @@ -85,7 +103,7 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode) break; } - I915_WRITE(reg, temp); + I915_WRITE(ADPA, temp); } static int intel_crt_mode_valid(struct drm_connector *connector, @@ -111,7 +129,7 @@ static int intel_crt_mode_valid(struct drm_connector *connector, } static bool intel_crt_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, + struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { return true; @@ -279,9 +297,10 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector) if (intel_ddc_probe(&crt->base, dev_priv->crt_ddc_pin)) { struct edid *edid; bool is_digital = false; + device_t iic; - edid = drm_get_edid(connector, - dev_priv->gmbus[dev_priv->crt_ddc_pin]); + iic = intel_gmbus_get_adapter(dev_priv, dev_priv->crt_ddc_pin); + edid = drm_get_edid(connector, iic); /* * This may be a DVI-I connector with a shared DDC * link between analog and digital outputs, so we @@ -480,15 +499,16 @@ static int intel_crt_get_modes(struct drm_connector *connector) struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; int ret; + device_t iic; - ret = intel_ddc_get_modes(connector, - dev_priv->gmbus[dev_priv->crt_ddc_pin]); + iic = intel_gmbus_get_adapter(dev_priv, dev_priv->crt_ddc_pin); + ret = intel_ddc_get_modes(connector, iic); if (ret || !IS_G4X(dev)) return ret; /* Try to probe digital port for output in DVI-I -> VGA mode. */ - return (intel_ddc_get_modes(connector, - dev_priv->gmbus[GMBUS_PORT_DPB])); + iic = intel_gmbus_get_adapter(dev_priv, GMBUS_PORT_DPB); + return intel_ddc_get_modes(connector, iic); } static int intel_crt_set_property(struct drm_connector *connector, @@ -511,12 +531,20 @@ static void intel_crt_reset(struct drm_connector *connector) * Routines for controlling stuff on the analog port */ -static const struct drm_encoder_helper_funcs intel_crt_helper_funcs = { - .dpms = intel_crt_dpms, +static const struct drm_encoder_helper_funcs pch_encoder_funcs = { .mode_fixup = intel_crt_mode_fixup, .prepare = intel_encoder_prepare, .commit = intel_encoder_commit, .mode_set = intel_crt_mode_set, + .dpms = pch_crt_dpms, +}; + +static const struct drm_encoder_helper_funcs gmch_encoder_funcs = { + .mode_fixup = intel_crt_mode_fixup, + .prepare = intel_encoder_prepare, + .commit = intel_encoder_commit, + .mode_set = intel_crt_mode_set, + .dpms = gmch_crt_dpms, }; static const struct drm_connector_funcs intel_crt_connector_funcs = { @@ -540,7 +568,7 @@ static const struct drm_encoder_funcs intel_crt_enc_funcs = { static int intel_no_crt_dmi_callback(const struct dmi_system_id *id) { - DRM_DEBUG_KMS("Skipping CRT initialization for %s\n", id->ident); + DRM_INFO("Skipping CRT initialization for %s\n", id->ident); return 1; } @@ -562,6 +590,7 @@ void intel_crt_init(struct drm_device *dev) struct intel_crt *crt; struct intel_connector *intel_connector; struct drm_i915_private *dev_priv = dev->dev_private; + const struct drm_encoder_helper_funcs *encoder_helper_funcs; /* Skip machines without VGA that falsely report hotplug events */ if (dmi_check_system(intel_no_crt)) @@ -584,14 +613,23 @@ void intel_crt_init(struct drm_device *dev) crt->base.clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT | 1 << INTEL_ANALOG_CLONE_BIT | 1 << INTEL_SDVO_LVDS_CLONE_BIT); - crt->base.crtc_mask = (1 << 0) | (1 << 1); + if (IS_HASWELL(dev)) + crt->base.crtc_mask = (1 << 0); + else + crt->base.crtc_mask = (1 << 0) | (1 << 1); + if (IS_GEN2(dev)) connector->interlace_allowed = 0; else connector->interlace_allowed = 1; connector->doublescan_allowed = 0; - drm_encoder_helper_add(&crt->base.base, &intel_crt_helper_funcs); + if (HAS_PCH_SPLIT(dev)) + encoder_helper_funcs = &pch_encoder_funcs; + else + encoder_helper_funcs = &gmch_encoder_funcs; + + drm_encoder_helper_add(&crt->base.base, encoder_helper_funcs); drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); #if 0 diff --git a/sys/dev/drm2/i915/intel_ddi.c b/sys/dev/drm2/i915/intel_ddi.c new file mode 100644 index 000000000000..dc320f68fa73 --- /dev/null +++ b/sys/dev/drm2/i915/intel_ddi.c @@ -0,0 +1,761 @@ +/* + * Copyright © 2012 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: + * Eugeni Dodonov + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +/* HDMI/DVI modes ignore everything but the last 2 items. So we share + * them for both DP and FDI transports, allowing those ports to + * automatically adapt to HDMI connections as well + */ +static const u32 hsw_ddi_translations_dp[] = { + 0x00FFFFFF, 0x0006000E, /* DP parameters */ + 0x00D75FFF, 0x0005000A, + 0x00C30FFF, 0x00040006, + 0x80AAAFFF, 0x000B0000, + 0x00FFFFFF, 0x0005000A, + 0x00D75FFF, 0x000C0004, + 0x80C30FFF, 0x000B0000, + 0x00FFFFFF, 0x00040006, + 0x80D75FFF, 0x000B0000, + 0x00FFFFFF, 0x00040006 /* HDMI parameters */ +}; + +static const u32 hsw_ddi_translations_fdi[] = { + 0x00FFFFFF, 0x0007000E, /* FDI parameters */ + 0x00D75FFF, 0x000F000A, + 0x00C30FFF, 0x00060006, + 0x00AAAFFF, 0x001E0000, + 0x00FFFFFF, 0x000F000A, + 0x00D75FFF, 0x00160004, + 0x00C30FFF, 0x001E0000, + 0x00FFFFFF, 0x00060006, + 0x00D75FFF, 0x001E0000, + 0x00FFFFFF, 0x00040006 /* HDMI parameters */ +}; + +/* On Haswell, DDI port buffers must be programmed with correct values + * in advance. The buffer values are different for FDI and DP modes, + * but the HDMI/DVI fields are shared among those. So we program the DDI + * in either FDI or DP modes only, as HDMI connections will work with both + * of those + */ +static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port, bool use_fdi_mode) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 reg; + int i; + const u32 *ddi_translations = ((use_fdi_mode) ? + hsw_ddi_translations_fdi : + hsw_ddi_translations_dp); + + DRM_DEBUG_DRIVER("Initializing DDI buffers for port %c in %s mode\n", + port_name(port), + use_fdi_mode ? "FDI" : "DP"); + + if (use_fdi_mode && (port != PORT_E)) + DRM_DEBUG_KMS("Programming port %c in FDI mode, this probably will not work.\n", + port_name(port)); + + for (i=0, reg=DDI_BUF_TRANS(port); i < DRM_ARRAY_SIZE(hsw_ddi_translations_fdi); i++) { + I915_WRITE(reg, ddi_translations[i]); + reg += 4; + } +} + +/* Program DDI buffers translations for DP. By default, program ports A-D in DP + * mode and port E for FDI. + */ +void intel_prepare_ddi(struct drm_device *dev) +{ + int port; + + if (IS_HASWELL(dev)) { + for (port = PORT_A; port < PORT_E; port++) + intel_prepare_ddi_buffers(dev, port, false); + + /* DDI E is the suggested one to work in FDI mode, so program is as such by + * default. It will have to be re-programmed in case a digital DP output + * will be detected on it + */ + intel_prepare_ddi_buffers(dev, PORT_E, true); + } +} + +static const long hsw_ddi_buf_ctl_values[] = { + DDI_BUF_EMP_400MV_0DB_HSW, + DDI_BUF_EMP_400MV_3_5DB_HSW, + DDI_BUF_EMP_400MV_6DB_HSW, + DDI_BUF_EMP_400MV_9_5DB_HSW, + DDI_BUF_EMP_600MV_0DB_HSW, + DDI_BUF_EMP_600MV_3_5DB_HSW, + DDI_BUF_EMP_600MV_6DB_HSW, + DDI_BUF_EMP_800MV_0DB_HSW, + DDI_BUF_EMP_800MV_3_5DB_HSW +}; + + +/* Starting with Haswell, different DDI ports can work in FDI mode for + * connection to the PCH-located connectors. For this, it is necessary to train + * both the DDI port and PCH receiver for the desired DDI buffer settings. + * + * The recommended port to work in FDI mode is DDI E, which we use here. Also, + * please note that when FDI mode is active on DDI E, it shares 2 lines with + * DDI A (which is used for eDP) + */ + +void hsw_fdi_link_train(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + u32 reg, temp, i; + + /* Configure CPU PLL, wait for warmup */ + I915_WRITE(SPLL_CTL, + SPLL_PLL_ENABLE | + SPLL_PLL_FREQ_1350MHz | + SPLL_PLL_SCC); + + /* Use SPLL to drive the output when in FDI mode */ + I915_WRITE(PORT_CLK_SEL(PORT_E), + PORT_CLK_SEL_SPLL); + I915_WRITE(PIPE_CLK_SEL(pipe), + PIPE_CLK_SEL_PORT(PORT_E)); + + DELAY(20); + + /* Start the training iterating through available voltages and emphasis */ + for (i=0; i < DRM_ARRAY_SIZE(hsw_ddi_buf_ctl_values); i++) { + /* Configure DP_TP_CTL with auto-training */ + I915_WRITE(DP_TP_CTL(PORT_E), + DP_TP_CTL_FDI_AUTOTRAIN | + DP_TP_CTL_ENHANCED_FRAME_ENABLE | + DP_TP_CTL_LINK_TRAIN_PAT1 | + DP_TP_CTL_ENABLE); + + /* Configure and enable DDI_BUF_CTL for DDI E with next voltage */ + temp = I915_READ(DDI_BUF_CTL(PORT_E)); + temp = (temp & ~DDI_BUF_EMP_MASK); + I915_WRITE(DDI_BUF_CTL(PORT_E), + temp | + DDI_BUF_CTL_ENABLE | + DDI_PORT_WIDTH_X2 | + hsw_ddi_buf_ctl_values[i]); + + DELAY(600); + + /* Enable CPU FDI Receiver with auto-training */ + reg = FDI_RX_CTL(pipe); + I915_WRITE(reg, + I915_READ(reg) | + FDI_LINK_TRAIN_AUTO | + FDI_RX_ENABLE | + FDI_LINK_TRAIN_PATTERN_1_CPT | + FDI_RX_ENHANCE_FRAME_ENABLE | + FDI_PORT_WIDTH_2X_LPT | + FDI_RX_PLL_ENABLE); + POSTING_READ(reg); + DELAY(100); + + temp = I915_READ(DP_TP_STATUS(PORT_E)); + if (temp & DP_TP_STATUS_AUTOTRAIN_DONE) { + DRM_DEBUG_DRIVER("BUF_CTL training done on %d step\n", i); + + /* Enable normal pixel sending for FDI */ + I915_WRITE(DP_TP_CTL(PORT_E), + DP_TP_CTL_FDI_AUTOTRAIN | + DP_TP_CTL_LINK_TRAIN_NORMAL | + DP_TP_CTL_ENHANCED_FRAME_ENABLE | + DP_TP_CTL_ENABLE); + + /* Enable PIPE_DDI_FUNC_CTL for the pipe to work in FDI mode */ + temp = I915_READ(DDI_FUNC_CTL(pipe)); + temp &= ~PIPE_DDI_PORT_MASK; + temp |= PIPE_DDI_SELECT_PORT(PORT_E) | + PIPE_DDI_MODE_SELECT_FDI | + PIPE_DDI_FUNC_ENABLE | + PIPE_DDI_PORT_WIDTH_X2; + I915_WRITE(DDI_FUNC_CTL(pipe), + temp); + break; + } else { + DRM_ERROR("Error training BUF_CTL %d\n", i); + + /* Disable DP_TP_CTL and FDI_RX_CTL) and retry */ + I915_WRITE(DP_TP_CTL(PORT_E), + I915_READ(DP_TP_CTL(PORT_E)) & + ~DP_TP_CTL_ENABLE); + I915_WRITE(FDI_RX_CTL(pipe), + I915_READ(FDI_RX_CTL(pipe)) & + ~FDI_RX_PLL_ENABLE); + continue; + } + } + + DRM_DEBUG_KMS("FDI train done.\n"); +} + +/* For DDI connections, it is possible to support different outputs over the + * same DDI port, such as HDMI or DP or even VGA via FDI. So we don't know by + * the time the output is detected what exactly is on the other end of it. This + * function aims at providing support for this detection and proper output + * configuration. + */ +void intel_ddi_init(struct drm_device *dev, enum port port) +{ + /* For now, we don't do any proper output detection and assume that we + * handle HDMI only */ + + switch(port){ + case PORT_A: + /* We don't handle eDP and DP yet */ + DRM_DEBUG_DRIVER("Found digital output on DDI port A\n"); + break; + /* Assume that the ports B, C and D are working in HDMI mode for now */ + case PORT_B: + case PORT_C: + case PORT_D: + intel_hdmi_init(dev, DDI_BUF_CTL(port)); + break; + default: + DRM_DEBUG_DRIVER("No handlers defined for port %d, skipping DDI initialization\n", + port); + break; + } +} + +/* WRPLL clock dividers */ +struct wrpll_tmds_clock { + u32 clock; + u16 p; /* Post divider */ + u16 n2; /* Feedback divider */ + u16 r2; /* Reference divider */ +}; + +/* Table of matching values for WRPLL clocks programming for each frequency */ +static const struct wrpll_tmds_clock wrpll_tmds_clock_table[] = { + {19750, 38, 25, 18}, + {20000, 48, 32, 18}, + {21000, 36, 21, 15}, + {21912, 42, 29, 17}, + {22000, 36, 22, 15}, + {23000, 36, 23, 15}, + {23500, 40, 40, 23}, + {23750, 26, 16, 14}, + {23750, 26, 16, 14}, + {24000, 36, 24, 15}, + {25000, 36, 25, 15}, + {25175, 26, 40, 33}, + {25200, 30, 21, 15}, + {26000, 36, 26, 15}, + {27000, 30, 21, 14}, + {27027, 18, 100, 111}, + {27500, 30, 29, 19}, + {28000, 34, 30, 17}, + {28320, 26, 30, 22}, + {28322, 32, 42, 25}, + {28750, 24, 23, 18}, + {29000, 30, 29, 18}, + {29750, 32, 30, 17}, + {30000, 30, 25, 15}, + {30750, 30, 41, 24}, + {31000, 30, 31, 18}, + {31500, 30, 28, 16}, + {32000, 30, 32, 18}, + {32500, 28, 32, 19}, + {33000, 24, 22, 15}, + {34000, 28, 30, 17}, + {35000, 26, 32, 19}, + {35500, 24, 30, 19}, + {36000, 26, 26, 15}, + {36750, 26, 46, 26}, + {37000, 24, 23, 14}, + {37762, 22, 40, 26}, + {37800, 20, 21, 15}, + {38000, 24, 27, 16}, + {38250, 24, 34, 20}, + {39000, 24, 26, 15}, + {40000, 24, 32, 18}, + {40500, 20, 21, 14}, + {40541, 22, 147, 89}, + {40750, 18, 19, 14}, + {41000, 16, 17, 14}, + {41500, 22, 44, 26}, + {41540, 22, 44, 26}, + {42000, 18, 21, 15}, + {42500, 22, 45, 26}, + {43000, 20, 43, 27}, + {43163, 20, 24, 15}, + {44000, 18, 22, 15}, + {44900, 20, 108, 65}, + {45000, 20, 25, 15}, + {45250, 20, 52, 31}, + {46000, 18, 23, 15}, + {46750, 20, 45, 26}, + {47000, 20, 40, 23}, + {48000, 18, 24, 15}, + {49000, 18, 49, 30}, + {49500, 16, 22, 15}, + {50000, 18, 25, 15}, + {50500, 18, 32, 19}, + {51000, 18, 34, 20}, + {52000, 18, 26, 15}, + {52406, 14, 34, 25}, + {53000, 16, 22, 14}, + {54000, 16, 24, 15}, + {54054, 16, 173, 108}, + {54500, 14, 24, 17}, + {55000, 12, 22, 18}, + {56000, 14, 45, 31}, + {56250, 16, 25, 15}, + {56750, 14, 25, 17}, + {57000, 16, 27, 16}, + {58000, 16, 43, 25}, + {58250, 16, 38, 22}, + {58750, 16, 40, 23}, + {59000, 14, 26, 17}, + {59341, 14, 40, 26}, + {59400, 16, 44, 25}, + {60000, 16, 32, 18}, + {60500, 12, 39, 29}, + {61000, 14, 49, 31}, + {62000, 14, 37, 23}, + {62250, 14, 42, 26}, + {63000, 12, 21, 15}, + {63500, 14, 28, 17}, + {64000, 12, 27, 19}, + {65000, 14, 32, 19}, + {65250, 12, 29, 20}, + {65500, 12, 32, 22}, + {66000, 12, 22, 15}, + {66667, 14, 38, 22}, + {66750, 10, 21, 17}, + {67000, 14, 33, 19}, + {67750, 14, 58, 33}, + {68000, 14, 30, 17}, + {68179, 14, 46, 26}, + {68250, 14, 46, 26}, + {69000, 12, 23, 15}, + {70000, 12, 28, 18}, + {71000, 12, 30, 19}, + {72000, 12, 24, 15}, + {73000, 10, 23, 17}, + {74000, 12, 23, 14}, + {74176, 8, 100, 91}, + {74250, 10, 22, 16}, + {74481, 12, 43, 26}, + {74500, 10, 29, 21}, + {75000, 12, 25, 15}, + {75250, 10, 39, 28}, + {76000, 12, 27, 16}, + {77000, 12, 53, 31}, + {78000, 12, 26, 15}, + {78750, 12, 28, 16}, + {79000, 10, 38, 26}, + {79500, 10, 28, 19}, + {80000, 12, 32, 18}, + {81000, 10, 21, 14}, + {81081, 6, 100, 111}, + {81624, 8, 29, 24}, + {82000, 8, 17, 14}, + {83000, 10, 40, 26}, + {83950, 10, 28, 18}, + {84000, 10, 28, 18}, + {84750, 6, 16, 17}, + {85000, 6, 17, 18}, + {85250, 10, 30, 19}, + {85750, 10, 27, 17}, + {86000, 10, 43, 27}, + {87000, 10, 29, 18}, + {88000, 10, 44, 27}, + {88500, 10, 41, 25}, + {89000, 10, 28, 17}, + {89012, 6, 90, 91}, + {89100, 10, 33, 20}, + {90000, 10, 25, 15}, + {91000, 10, 32, 19}, + {92000, 10, 46, 27}, + {93000, 10, 31, 18}, + {94000, 10, 40, 23}, + {94500, 10, 28, 16}, + {95000, 10, 44, 25}, + {95654, 10, 39, 22}, + {95750, 10, 39, 22}, + {96000, 10, 32, 18}, + {97000, 8, 23, 16}, + {97750, 8, 42, 29}, + {98000, 8, 45, 31}, + {99000, 8, 22, 15}, + {99750, 8, 34, 23}, + {100000, 6, 20, 18}, + {100500, 6, 19, 17}, + {101000, 6, 37, 33}, + {101250, 8, 21, 14}, + {102000, 6, 17, 15}, + {102250, 6, 25, 22}, + {103000, 8, 29, 19}, + {104000, 8, 37, 24}, + {105000, 8, 28, 18}, + {106000, 8, 22, 14}, + {107000, 8, 46, 29}, + {107214, 8, 27, 17}, + {108000, 8, 24, 15}, + {108108, 8, 173, 108}, + {109000, 6, 23, 19}, + {109000, 6, 23, 19}, + {110000, 6, 22, 18}, + {110013, 6, 22, 18}, + {110250, 8, 49, 30}, + {110500, 8, 36, 22}, + {111000, 8, 23, 14}, + {111264, 8, 150, 91}, + {111375, 8, 33, 20}, + {112000, 8, 63, 38}, + {112500, 8, 25, 15}, + {113100, 8, 57, 34}, + {113309, 8, 42, 25}, + {114000, 8, 27, 16}, + {115000, 6, 23, 18}, + {116000, 8, 43, 25}, + {117000, 8, 26, 15}, + {117500, 8, 40, 23}, + {118000, 6, 38, 29}, + {119000, 8, 30, 17}, + {119500, 8, 46, 26}, + {119651, 8, 39, 22}, + {120000, 8, 32, 18}, + {121000, 6, 39, 29}, + {121250, 6, 31, 23}, + {121750, 6, 23, 17}, + {122000, 6, 42, 31}, + {122614, 6, 30, 22}, + {123000, 6, 41, 30}, + {123379, 6, 37, 27}, + {124000, 6, 51, 37}, + {125000, 6, 25, 18}, + {125250, 4, 13, 14}, + {125750, 4, 27, 29}, + {126000, 6, 21, 15}, + {127000, 6, 24, 17}, + {127250, 6, 41, 29}, + {128000, 6, 27, 19}, + {129000, 6, 43, 30}, + {129859, 4, 25, 26}, + {130000, 6, 26, 18}, + {130250, 6, 42, 29}, + {131000, 6, 32, 22}, + {131500, 6, 38, 26}, + {131850, 6, 41, 28}, + {132000, 6, 22, 15}, + {132750, 6, 28, 19}, + {133000, 6, 34, 23}, + {133330, 6, 37, 25}, + {134000, 6, 61, 41}, + {135000, 6, 21, 14}, + {135250, 6, 167, 111}, + {136000, 6, 62, 41}, + {137000, 6, 35, 23}, + {138000, 6, 23, 15}, + {138500, 6, 40, 26}, + {138750, 6, 37, 24}, + {139000, 6, 34, 22}, + {139050, 6, 34, 22}, + {139054, 6, 34, 22}, + {140000, 6, 28, 18}, + {141000, 6, 36, 23}, + {141500, 6, 22, 14}, + {142000, 6, 30, 19}, + {143000, 6, 27, 17}, + {143472, 4, 17, 16}, + {144000, 6, 24, 15}, + {145000, 6, 29, 18}, + {146000, 6, 47, 29}, + {146250, 6, 26, 16}, + {147000, 6, 49, 30}, + {147891, 6, 23, 14}, + {148000, 6, 23, 14}, + {148250, 6, 28, 17}, + {148352, 4, 100, 91}, + {148500, 6, 33, 20}, + {149000, 6, 48, 29}, + {150000, 6, 25, 15}, + {151000, 4, 19, 17}, + {152000, 6, 27, 16}, + {152280, 6, 44, 26}, + {153000, 6, 34, 20}, + {154000, 6, 53, 31}, + {155000, 6, 31, 18}, + {155250, 6, 50, 29}, + {155750, 6, 45, 26}, + {156000, 6, 26, 15}, + {157000, 6, 61, 35}, + {157500, 6, 28, 16}, + {158000, 6, 65, 37}, + {158250, 6, 44, 25}, + {159000, 6, 53, 30}, + {159500, 6, 39, 22}, + {160000, 6, 32, 18}, + {161000, 4, 31, 26}, + {162000, 4, 18, 15}, + {162162, 4, 131, 109}, + {162500, 4, 53, 44}, + {163000, 4, 29, 24}, + {164000, 4, 17, 14}, + {165000, 4, 22, 18}, + {166000, 4, 32, 26}, + {167000, 4, 26, 21}, + {168000, 4, 46, 37}, + {169000, 4, 104, 83}, + {169128, 4, 64, 51}, + {169500, 4, 39, 31}, + {170000, 4, 34, 27}, + {171000, 4, 19, 15}, + {172000, 4, 51, 40}, + {172750, 4, 32, 25}, + {172800, 4, 32, 25}, + {173000, 4, 41, 32}, + {174000, 4, 49, 38}, + {174787, 4, 22, 17}, + {175000, 4, 35, 27}, + {176000, 4, 30, 23}, + {177000, 4, 38, 29}, + {178000, 4, 29, 22}, + {178500, 4, 37, 28}, + {179000, 4, 53, 40}, + {179500, 4, 73, 55}, + {180000, 4, 20, 15}, + {181000, 4, 55, 41}, + {182000, 4, 31, 23}, + {183000, 4, 42, 31}, + {184000, 4, 30, 22}, + {184750, 4, 26, 19}, + {185000, 4, 37, 27}, + {186000, 4, 51, 37}, + {187000, 4, 36, 26}, + {188000, 4, 32, 23}, + {189000, 4, 21, 15}, + {190000, 4, 38, 27}, + {190960, 4, 41, 29}, + {191000, 4, 41, 29}, + {192000, 4, 27, 19}, + {192250, 4, 37, 26}, + {193000, 4, 20, 14}, + {193250, 4, 53, 37}, + {194000, 4, 23, 16}, + {194208, 4, 23, 16}, + {195000, 4, 26, 18}, + {196000, 4, 45, 31}, + {197000, 4, 35, 24}, + {197750, 4, 41, 28}, + {198000, 4, 22, 15}, + {198500, 4, 25, 17}, + {199000, 4, 28, 19}, + {200000, 4, 37, 25}, + {201000, 4, 61, 41}, + {202000, 4, 112, 75}, + {202500, 4, 21, 14}, + {203000, 4, 146, 97}, + {204000, 4, 62, 41}, + {204750, 4, 44, 29}, + {205000, 4, 38, 25}, + {206000, 4, 29, 19}, + {207000, 4, 23, 15}, + {207500, 4, 40, 26}, + {208000, 4, 37, 24}, + {208900, 4, 48, 31}, + {209000, 4, 48, 31}, + {209250, 4, 31, 20}, + {210000, 4, 28, 18}, + {211000, 4, 25, 16}, + {212000, 4, 22, 14}, + {213000, 4, 30, 19}, + {213750, 4, 38, 24}, + {214000, 4, 46, 29}, + {214750, 4, 35, 22}, + {215000, 4, 43, 27}, + {216000, 4, 24, 15}, + {217000, 4, 37, 23}, + {218000, 4, 42, 26}, + {218250, 4, 42, 26}, + {218750, 4, 34, 21}, + {219000, 4, 47, 29}, + {219000, 4, 47, 29}, + {220000, 4, 44, 27}, + {220640, 4, 49, 30}, + {220750, 4, 36, 22}, + {221000, 4, 36, 22}, + {222000, 4, 23, 14}, + {222525, 4, 28, 17}, + {222750, 4, 33, 20}, + {227000, 4, 37, 22}, + {230250, 4, 29, 17}, + {233500, 4, 38, 22}, + {235000, 4, 40, 23}, + {238000, 4, 30, 17}, + {241500, 2, 17, 19}, + {245250, 2, 20, 22}, + {247750, 2, 22, 24}, + {253250, 2, 15, 16}, + {256250, 2, 18, 19}, + {262500, 2, 31, 32}, + {267250, 2, 66, 67}, + {268500, 2, 94, 95}, + {270000, 2, 14, 14}, + {272500, 2, 77, 76}, + {273750, 2, 57, 56}, + {280750, 2, 24, 23}, + {281250, 2, 23, 22}, + {286000, 2, 17, 16}, + {291750, 2, 26, 24}, + {296703, 2, 56, 51}, + {297000, 2, 22, 20}, + {298000, 2, 21, 19}, +}; + +void intel_ddi_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc = encoder->crtc; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + int port = intel_hdmi->ddi_port; + int pipe = intel_crtc->pipe; + int p, n2, r2, valid=0; + u32 temp, i; + + /* On Haswell, we need to enable the clocks and prepare DDI function to + * work in HDMI mode for this pipe. + */ + DRM_DEBUG_KMS("Preparing HDMI DDI mode for Haswell on port %c, pipe %c\n", port_name(port), pipe_name(pipe)); + + for (i=0; i < DRM_ARRAY_SIZE(wrpll_tmds_clock_table); i++) { + if (crtc->mode.clock == wrpll_tmds_clock_table[i].clock) { + p = wrpll_tmds_clock_table[i].p; + n2 = wrpll_tmds_clock_table[i].n2; + r2 = wrpll_tmds_clock_table[i].r2; + + DRM_DEBUG_KMS("WR PLL clock: found settings for %dKHz refresh rate: p=%d, n2=%d, r2=%d\n", + crtc->mode.clock, + p, n2, r2); + + valid = 1; + break; + } + } + + if (!valid) { + DRM_ERROR("Unable to find WR PLL clock settings for %dKHz refresh rate\n", + crtc->mode.clock); + return; + } + + /* Enable LCPLL if disabled */ + temp = I915_READ(LCPLL_CTL); + if (temp & LCPLL_PLL_DISABLE) + I915_WRITE(LCPLL_CTL, + temp & ~LCPLL_PLL_DISABLE); + + /* Configure WR PLL 1, program the correct divider values for + * the desired frequency and wait for warmup */ + I915_WRITE(WRPLL_CTL1, + WRPLL_PLL_ENABLE | + WRPLL_PLL_SELECT_LCPLL_2700 | + WRPLL_DIVIDER_REFERENCE(r2) | + WRPLL_DIVIDER_FEEDBACK(n2) | + WRPLL_DIVIDER_POST(p)); + + DELAY(20); + + /* Use WRPLL1 clock to drive the output to the port, and tell the pipe to use + * this port for connection. + */ + I915_WRITE(PORT_CLK_SEL(port), + PORT_CLK_SEL_WRPLL1); + I915_WRITE(PIPE_CLK_SEL(pipe), + PIPE_CLK_SEL_PORT(port)); + + DELAY(20); + + if (intel_hdmi->has_audio) { + /* Proper support for digital audio needs a new logic and a new set + * of registers, so we leave it for future patch bombing. + */ + DRM_DEBUG_DRIVER("HDMI audio on pipe %c not yet supported on DDI\n", + pipe_name(intel_crtc->pipe)); + } + + /* Enable PIPE_DDI_FUNC_CTL for the pipe to work in HDMI mode */ + temp = I915_READ(DDI_FUNC_CTL(pipe)); + temp &= ~PIPE_DDI_PORT_MASK; + temp &= ~PIPE_DDI_BPC_12; + temp |= PIPE_DDI_SELECT_PORT(port) | + PIPE_DDI_MODE_SELECT_HDMI | + ((intel_crtc->bpp > 24) ? + PIPE_DDI_BPC_12 : + PIPE_DDI_BPC_8) | + PIPE_DDI_FUNC_ENABLE; + + I915_WRITE(DDI_FUNC_CTL(pipe), temp); + + intel_hdmi_set_avi_infoframe(encoder, adjusted_mode); + intel_hdmi_set_spd_infoframe(encoder); +} + +void intel_ddi_dpms(struct drm_encoder *encoder, int mode) +{ + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + int port = intel_hdmi->ddi_port; + u32 temp; + + temp = I915_READ(DDI_BUF_CTL(port)); + + if (mode != DRM_MODE_DPMS_ON) { + temp &= ~DDI_BUF_CTL_ENABLE; + } else { + temp |= DDI_BUF_CTL_ENABLE; + } + + /* Enable DDI_BUF_CTL. In HDMI/DVI mode, the port width, + * and swing/emphasis values are ignored so nothing special needs + * to be done besides enabling the port. + */ + I915_WRITE(DDI_BUF_CTL(port), + temp); +} diff --git a/sys/dev/drm2/i915/intel_display.c b/sys/dev/drm2/i915/intel_display.c index ccff1e42f2bd..86c3a4de54cf 100644 --- a/sys/dev/drm2/i915/intel_display.c +++ b/sys/dev/drm2/i915/intel_display.c @@ -35,13 +35,11 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #define HAS_eDP (intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) bool intel_pipe_has_type(struct drm_crtc *crtc, int type); -static void intel_update_watermarks(struct drm_device *dev); static void intel_increase_pllclock(struct drm_crtc *crtc); static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on); @@ -357,6 +355,110 @@ static const intel_limit_t intel_limits_ironlake_display_port = { .find_pll = intel_find_pll_ironlake_dp, }; +u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg) +{ + u32 val = 0; + + mtx_lock(&dev_priv->dpio_lock); + if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) { + DRM_ERROR("DPIO idle wait timed out\n"); + goto out_unlock; + } + + I915_WRITE(DPIO_REG, reg); + I915_WRITE(DPIO_PKT, DPIO_RID | DPIO_OP_READ | DPIO_PORTID | + DPIO_BYTE); + if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) { + DRM_ERROR("DPIO read wait timed out\n"); + goto out_unlock; + } + val = I915_READ(DPIO_DATA); + +out_unlock: + mtx_unlock(&dev_priv->dpio_lock); + return val; +} + +#if 0 +static void intel_dpio_write(struct drm_i915_private *dev_priv, int reg, + u32 val) +{ + + mtx_lock(&dev_priv->dpio_lock); + if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) { + DRM_ERROR("DPIO idle wait timed out\n"); + goto out_unlock; + } + + I915_WRITE(DPIO_DATA, val); + I915_WRITE(DPIO_REG, reg); + I915_WRITE(DPIO_PKT, DPIO_RID | DPIO_OP_WRITE | DPIO_PORTID | + DPIO_BYTE); + if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) + DRM_ERROR("DPIO write wait timed out\n"); + +out_unlock: + mtx_unlock(&dev_priv->dpio_lock); +} +#endif + +static void vlv_init_dpio(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* Reset the DPIO config */ + I915_WRITE(DPIO_CTL, 0); + POSTING_READ(DPIO_CTL); + I915_WRITE(DPIO_CTL, 1); + POSTING_READ(DPIO_CTL); +} + +static int intel_dual_link_lvds_callback(const struct dmi_system_id *id) +{ + DRM_INFO("Forcing lvds to dual link mode on %s\n", id->ident); + return 1; +} + +static const struct dmi_system_id intel_dual_link_lvds[] = { + { + .callback = intel_dual_link_lvds_callback, + .ident = "Apple MacBook Pro (Core i5/i7 Series)", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro8,2"), + }, + }, + { } /* terminating entry */ +}; + +static bool is_dual_link_lvds(struct drm_i915_private *dev_priv, + unsigned int reg) +{ + unsigned int val; + + /* use the module option value if specified */ + if (i915_lvds_channel_mode > 0) + return i915_lvds_channel_mode == 2; + + if (dmi_check_system(intel_dual_link_lvds)) + return true; + + if (dev_priv->lvds_val) + val = dev_priv->lvds_val; + else { + /* BIOS should set the proper LVDS register value at boot, but + * in reality, it doesn't set the value when the lid is closed; + * we need to check "the value to be set" in VBT when LVDS + * register is uninitialized. + */ + val = I915_READ(reg); + if (!(val & ~LVDS_DETECTED)) + val = dev_priv->bios_lvds_val; + dev_priv->lvds_val = val; + } + return (val & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP; +} + static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc, int refclk) { @@ -365,8 +467,7 @@ static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc, const intel_limit_t *limit; if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { - if ((I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == - LVDS_CLKB_POWER_UP) { + if (is_dual_link_lvds(dev_priv, PCH_LVDS)) { /* LVDS dual channel */ if (refclk == 100000) limit = &intel_limits_ironlake_dual_lvds_100m; @@ -394,8 +495,7 @@ static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc) const intel_limit_t *limit; if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { - if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) == - LVDS_CLKB_POWER_UP) + if (is_dual_link_lvds(dev_priv, LVDS)) /* LVDS with dual channel */ limit = &intel_limits_g4x_dual_channel_lvds; else @@ -533,8 +633,7 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, * reliably set up different single/dual channel state, if we * even can. */ - if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) == - LVDS_CLKB_POWER_UP) + if (is_dual_link_lvds(dev_priv, LVDS)) clock.p2 = limit->p2.p2_fast; else clock.p2 = limit->p2.p2_slow; @@ -703,6 +802,17 @@ intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc, return true; } +static void ironlake_wait_for_vblank(struct drm_device *dev, int pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 frame, frame_reg = PIPEFRAME(pipe); + + frame = I915_READ(frame_reg); + + if (wait_for(I915_READ_NOTRACE(frame_reg) != frame, 50)) + DRM_DEBUG_KMS("vblank wait timed out\n"); +} + /** * intel_wait_for_vblank - wait for vblank on a given pipe * @dev: drm device @@ -716,6 +826,11 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe) struct drm_i915_private *dev_priv = dev->dev_private; int pipestat_reg = PIPESTAT(pipe); + if (INTEL_INFO(dev)->gen >= 5) { + ironlake_wait_for_vblank(dev, pipe); + return; + } + /* Clear existing vblank status. Note this will clear any other * sticky status fields as well. * @@ -769,15 +884,20 @@ void intel_wait_for_pipe_off(struct drm_device *dev, int pipe) 1, "915pip")) DRM_DEBUG_KMS("pipe_off wait timed out\n"); } else { - u32 last_line; + u32 last_line, line_mask; int reg = PIPEDSL(pipe); unsigned long timeout = jiffies + msecs_to_jiffies(100); + if (IS_GEN2(dev)) + line_mask = DSL_LINEMASK_GEN2; + else + line_mask = DSL_LINEMASK_GEN3; + /* Wait for the display line to settle */ do { - last_line = I915_READ(reg) & DSL_LINEMASK; + last_line = I915_READ(reg) & line_mask; DELAY(5000); - } while (((I915_READ(reg) & DSL_LINEMASK) != last_line) && + } while (((I915_READ(reg) & line_mask) != last_line) && time_after(timeout, jiffies)); if (time_after(jiffies, timeout)) DRM_DEBUG_KMS("pipe_off wait timed out\n"); @@ -809,26 +929,33 @@ static void assert_pll(struct drm_i915_private *dev_priv, /* For ILK+ */ static void assert_pch_pll(struct drm_i915_private *dev_priv, - enum pipe pipe, bool state) + struct intel_crtc *intel_crtc, bool state) { int reg; u32 val; bool cur_state; + if (HAS_PCH_LPT(dev_priv->dev)) { + DRM_DEBUG_DRIVER("LPT detected: skipping PCH PLL test\n"); + return; + } + + if (!intel_crtc->pch_pll) { + printf("asserting PCH PLL enabled with no PLL\n"); + return; + } + if (HAS_PCH_CPT(dev_priv->dev)) { u32 pch_dpll; pch_dpll = I915_READ(PCH_DPLL_SEL); /* Make sure the selected PLL is enabled to the transcoder */ - KASSERT(((pch_dpll >> (4 * pipe)) & 8) != 0, - ("transcoder %d PLL not enabled\n", pipe)); - - /* Convert the transcoder pipe number to a pll pipe number */ - pipe = (pch_dpll >> (4 * pipe)) & 1; + KASSERT(((pch_dpll >> (4 * intel_crtc->pipe)) & 8) != 0, + ("transcoder %d PLL not enabled\n", intel_crtc->pipe)); } - reg = PCH_DPLL(pipe); + reg = intel_crtc->pch_pll->pll_reg; val = I915_READ(reg); cur_state = !!(val & DPLL_VCO_ENABLE); if (cur_state != state) @@ -845,9 +972,16 @@ static void assert_fdi_tx(struct drm_i915_private *dev_priv, u32 val; bool cur_state; - reg = FDI_TX_CTL(pipe); - val = I915_READ(reg); - cur_state = !!(val & FDI_TX_ENABLE); + if (IS_HASWELL(dev_priv->dev)) { + /* On Haswell, DDI is used instead of FDI_TX_CTL */ + reg = DDI_FUNC_CTL(pipe); + val = I915_READ(reg); + cur_state = !!(val & PIPE_DDI_FUNC_ENABLE); + } else { + reg = FDI_TX_CTL(pipe); + val = I915_READ(reg); + cur_state = !!(val & FDI_TX_ENABLE); + } if (cur_state != state) printf("FDI TX state assertion failure (expected %s, current %s)\n", state_string(state), state_string(cur_state)); @@ -862,9 +996,14 @@ static void assert_fdi_rx(struct drm_i915_private *dev_priv, u32 val; bool cur_state; - reg = FDI_RX_CTL(pipe); - val = I915_READ(reg); - cur_state = !!(val & FDI_RX_ENABLE); + if (IS_HASWELL(dev_priv->dev) && pipe > 0) { + DRM_ERROR("Attempting to enable FDI_RX on Haswell pipe > 0\n"); + return; + } else { + reg = FDI_RX_CTL(pipe); + val = I915_READ(reg); + cur_state = !!(val & FDI_RX_ENABLE); + } if (cur_state != state) printf("FDI RX state assertion failure (expected %s, current %s)\n", state_string(state), state_string(cur_state)); @@ -882,6 +1021,10 @@ static void assert_fdi_tx_pll_enabled(struct drm_i915_private *dev_priv, if (dev_priv->info->gen == 5) return; + /* On Haswell, DDI ports are responsible for the FDI PLL setup */ + if (IS_HASWELL(dev_priv->dev)) + return; + reg = FDI_TX_CTL(pipe); val = I915_READ(reg); if (!(val & FDI_TX_PLL_ENABLE)) @@ -894,6 +1037,10 @@ static void assert_fdi_rx_pll_enabled(struct drm_i915_private *dev_priv, int reg; u32 val; + if (IS_HASWELL(dev_priv->dev) && pipe > 0) { + DRM_ERROR("Attempting to enable FDI on Haswell with pipe > 0\n"); + return; + } reg = FDI_RX_CTL(pipe); val = I915_READ(reg); if (!(val & FDI_RX_PLL_ENABLE)) @@ -1000,6 +1147,11 @@ static void assert_pch_refclk_enabled(struct drm_i915_private *dev_priv) u32 val; bool enabled; + if (HAS_PCH_LPT(dev_priv->dev)) { + DRM_DEBUG_DRIVER("LPT does not has PCH refclk, skipping check\n"); + return; + } + val = I915_READ(PCH_DREF_CONTROL); enabled = !!(val & (DREF_SSC_SOURCE_MASK | DREF_NONSPREAD_SOURCE_MASK | DREF_SUPERSPREAD_SOURCE_MASK)); @@ -1199,6 +1351,68 @@ static void intel_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) POSTING_READ(reg); } +/* SBI access */ +static void +intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value) +{ + + mtx_lock(&dev_priv->dpio_lock); + if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_READY) == 0, + 100)) { + DRM_ERROR("timeout waiting for SBI to become ready\n"); + goto out_unlock; + } + + I915_WRITE(SBI_ADDR, + (reg << 16)); + I915_WRITE(SBI_DATA, + value); + I915_WRITE(SBI_CTL_STAT, + SBI_BUSY | + SBI_CTL_OP_CRWR); + + if (wait_for((I915_READ(SBI_CTL_STAT) & (SBI_READY | SBI_RESPONSE_SUCCESS)) == 0, + 100)) { + DRM_ERROR("timeout waiting for SBI to complete write transaction\n"); + goto out_unlock; + } + +out_unlock: + mtx_unlock(&dev_priv->dpio_lock); +} + +static u32 +intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg) +{ + u32 value; + + value = 0; + mtx_lock(&dev_priv->dpio_lock); + if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_READY) == 0, + 100)) { + DRM_ERROR("timeout waiting for SBI to become ready\n"); + goto out_unlock; + } + + I915_WRITE(SBI_ADDR, + (reg << 16)); + I915_WRITE(SBI_CTL_STAT, + SBI_BUSY | + SBI_CTL_OP_CRRD); + + if (wait_for((I915_READ(SBI_CTL_STAT) & (SBI_READY | SBI_RESPONSE_SUCCESS)) == 0, + 100)) { + DRM_ERROR("timeout waiting for SBI to complete read transaction\n"); + goto out_unlock; + } + + value = I915_READ(SBI_DATA); + +out_unlock: + mtx_unlock(&dev_priv->dpio_lock); + return value; +} + /** * intel_enable_pch_pll - enable PCH PLL * @dev_priv: i915 private structure @@ -1207,60 +1421,93 @@ static void intel_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) * The PCH PLL needs to be enabled before the PCH transcoder, since it * drives the transcoder clock. */ -static void intel_enable_pch_pll(struct drm_i915_private *dev_priv, - enum pipe pipe) +static void intel_enable_pch_pll(struct intel_crtc *intel_crtc) { + struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private; + struct intel_pch_pll *pll; int reg; u32 val; - if (pipe > 1) + /* PCH PLLs only available on ILK, SNB and IVB */ + KASSERT(dev_priv->info->gen >= 5, ("Wrong device gen")); + pll = intel_crtc->pch_pll; + if (pll == NULL) return; - /* PCH only available on ILK+ */ - KASSERT(dev_priv->info->gen >= 5, ("Wrong device gen")); + if (pll->refcount == 0) { + DRM_DEBUG_KMS("pll->refcount == 0\n"); + return; + } + + DRM_DEBUG_KMS("enable PCH PLL %x (active %d, on? %d)for crtc %d\n", + pll->pll_reg, pll->active, pll->on, + intel_crtc->base.base.id); /* PCH refclock must be enabled first */ assert_pch_refclk_enabled(dev_priv); - reg = PCH_DPLL(pipe); + if (pll->active++ && pll->on) { + assert_pch_pll_enabled(dev_priv, intel_crtc); + return; + } + + DRM_DEBUG_KMS("enabling PCH PLL %x\n", pll->pll_reg); + + reg = pll->pll_reg; val = I915_READ(reg); val |= DPLL_VCO_ENABLE; I915_WRITE(reg, val); POSTING_READ(reg); DELAY(200); + + pll->on = true; } -static void intel_disable_pch_pll(struct drm_i915_private *dev_priv, - enum pipe pipe) +static void intel_disable_pch_pll(struct intel_crtc *intel_crtc) { + struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private; + struct intel_pch_pll *pll = intel_crtc->pch_pll; int reg; - u32 val, pll_mask = TRANSC_DPLL_ENABLE | TRANSC_DPLLB_SEL, - pll_sel = TRANSC_DPLL_ENABLE; - - if (pipe > 1) - return; + u32 val; /* PCH only available on ILK+ */ KASSERT(dev_priv->info->gen >= 5, ("Wrong device gen")); - - /* Make sure transcoder isn't still depending on us */ - assert_transcoder_disabled(dev_priv, pipe); - - if (pipe == 0) - pll_sel |= TRANSC_DPLLA_SEL; - else if (pipe == 1) - pll_sel |= TRANSC_DPLLB_SEL; - - - if ((I915_READ(PCH_DPLL_SEL) & pll_mask) == pll_sel) + if (pll == NULL) return; - reg = PCH_DPLL(pipe); + if (pll->refcount == 0) { + DRM_DEBUG_KMS("pll->refcount == 0\n"); + return; + } + + DRM_DEBUG_KMS("disable PCH PLL %x (active %d, on? %d) for crtc %d\n", + pll->pll_reg, pll->active, pll->on, + intel_crtc->base.base.id); + + if (pll->active == 0) { + DRM_DEBUG_KMS("pll->active == 0\n"); + assert_pch_pll_disabled(dev_priv, intel_crtc); + return; + } + + if (--pll->active) { + assert_pch_pll_enabled(dev_priv, intel_crtc); + return; + } + + DRM_DEBUG_KMS("disabling PCH PLL %x\n", pll->pll_reg); + + /* Make sure transcoder isn't still depending on us */ + assert_transcoder_disabled(dev_priv, intel_crtc->pipe); + + reg = pll->pll_reg; val = I915_READ(reg); val &= ~DPLL_VCO_ENABLE; I915_WRITE(reg, val); POSTING_READ(reg); DELAY(200); + + pll->on = false; } static void intel_enable_transcoder(struct drm_i915_private *dev_priv, @@ -1274,17 +1521,19 @@ static void intel_enable_transcoder(struct drm_i915_private *dev_priv, KASSERT(dev_priv->info->gen >= 5, ("Wrong device gen")); /* Make sure PCH DPLL is enabled */ - assert_pch_pll_enabled(dev_priv, pipe); + assert_pch_pll_enabled(dev_priv, to_intel_crtc(crtc)); /* FDI must be feeding us bits for PCH ports */ assert_fdi_tx_enabled(dev_priv, pipe); assert_fdi_rx_enabled(dev_priv, pipe); - + if (IS_HASWELL(dev_priv->dev) && pipe > 0) { + DRM_ERROR("Attempting to enable transcoder on Haswell with pipe > 0\n"); + return; + } reg = TRANSCONF(pipe); val = I915_READ(reg); pipeconf_val = I915_READ(PIPECONF(pipe)); - if (HAS_PCH_IBX(dev_priv->dev)) { /* * make the BPC in transcoder be consistent with @@ -1420,7 +1669,7 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv, * Plane regs are double buffered, going from enabled->disabled needs a * trigger in order to latch. The display address reg provides this. */ -static void intel_flush_display_plane(struct drm_i915_private *dev_priv, +void intel_flush_display_plane(struct drm_i915_private *dev_priv, enum plane plane) { I915_WRITE(DSPADDR(plane), I915_READ(DSPADDR(plane))); @@ -1531,486 +1780,6 @@ static void intel_disable_pch_ports(struct drm_i915_private *dev_priv, disable_pch_hdmi(dev_priv, pipe, HDMID); } -static void i8xx_disable_fbc(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 fbc_ctl; - - /* Disable compression */ - fbc_ctl = I915_READ(FBC_CONTROL); - if ((fbc_ctl & FBC_CTL_EN) == 0) - return; - - fbc_ctl &= ~FBC_CTL_EN; - I915_WRITE(FBC_CONTROL, fbc_ctl); - - /* Wait for compressing bit to clear */ - if (_intel_wait_for(dev, - (I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10, - 1, "915fbd")) { - DRM_DEBUG_KMS("FBC idle timed out\n"); - return; - } - - DRM_DEBUG_KMS("disabled FBC\n"); -} - -static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_framebuffer *fb = crtc->fb; - struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); - struct drm_i915_gem_object *obj = intel_fb->obj; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int cfb_pitch; - int plane, i; - u32 fbc_ctl, fbc_ctl2; - - cfb_pitch = dev_priv->cfb_size / FBC_LL_SIZE; - if (fb->pitches[0] < cfb_pitch) - cfb_pitch = fb->pitches[0]; - - /* FBC_CTL wants 64B units */ - cfb_pitch = (cfb_pitch / 64) - 1; - plane = intel_crtc->plane == 0 ? FBC_CTL_PLANEA : FBC_CTL_PLANEB; - - /* Clear old tags */ - for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++) - I915_WRITE(FBC_TAG + (i * 4), 0); - - /* Set it up... */ - fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE; - fbc_ctl2 |= plane; - I915_WRITE(FBC_CONTROL2, fbc_ctl2); - I915_WRITE(FBC_FENCE_OFF, crtc->y); - - /* enable it... */ - fbc_ctl = FBC_CTL_EN | FBC_CTL_PERIODIC; - if (IS_I945GM(dev)) - fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */ - fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT; - fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT; - fbc_ctl |= obj->fence_reg; - I915_WRITE(FBC_CONTROL, fbc_ctl); - - DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %d, ", - cfb_pitch, crtc->y, intel_crtc->plane); -} - -static bool i8xx_fbc_enabled(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - return I915_READ(FBC_CONTROL) & FBC_CTL_EN; -} - -static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_framebuffer *fb = crtc->fb; - struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); - struct drm_i915_gem_object *obj = intel_fb->obj; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB; - unsigned long stall_watermark = 200; - u32 dpfc_ctl; - - dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X; - dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg; - I915_WRITE(DPFC_CHICKEN, DPFC_HT_MODIFY); - - I915_WRITE(DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN | - (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) | - (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT)); - I915_WRITE(DPFC_FENCE_YOFF, crtc->y); - - /* enable it... */ - I915_WRITE(DPFC_CONTROL, I915_READ(DPFC_CONTROL) | DPFC_CTL_EN); - - DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane); -} - -static void g4x_disable_fbc(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 dpfc_ctl; - - /* Disable compression */ - dpfc_ctl = I915_READ(DPFC_CONTROL); - if (dpfc_ctl & DPFC_CTL_EN) { - dpfc_ctl &= ~DPFC_CTL_EN; - I915_WRITE(DPFC_CONTROL, dpfc_ctl); - - DRM_DEBUG_KMS("disabled FBC\n"); - } -} - -static bool g4x_fbc_enabled(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN; -} - -static void sandybridge_blit_fbc_update(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 blt_ecoskpd; - - /* Make sure blitter notifies FBC of writes */ - gen6_gt_force_wake_get(dev_priv); - blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD); - blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY << - GEN6_BLITTER_LOCK_SHIFT; - I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd); - blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY; - I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd); - blt_ecoskpd &= ~(GEN6_BLITTER_FBC_NOTIFY << - GEN6_BLITTER_LOCK_SHIFT); - I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd); - POSTING_READ(GEN6_BLITTER_ECOSKPD); - gen6_gt_force_wake_put(dev_priv); -} - -static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_framebuffer *fb = crtc->fb; - struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); - struct drm_i915_gem_object *obj = intel_fb->obj; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB; - unsigned long stall_watermark = 200; - u32 dpfc_ctl; - - dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); - dpfc_ctl &= DPFC_RESERVED; - dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X); - /* Set persistent mode for front-buffer rendering, ala X. */ - dpfc_ctl |= DPFC_CTL_PERSISTENT_MODE; - dpfc_ctl |= (DPFC_CTL_FENCE_EN | obj->fence_reg); - I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY); - - I915_WRITE(ILK_DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN | - (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) | - (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT)); - I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y); - I915_WRITE(ILK_FBC_RT_BASE, obj->gtt_offset | ILK_FBC_RT_VALID); - /* enable it... */ - I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); - - if (IS_GEN6(dev)) { - I915_WRITE(SNB_DPFC_CTL_SA, - SNB_CPU_FENCE_ENABLE | obj->fence_reg); - I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y); - sandybridge_blit_fbc_update(dev); - } - - DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane); -} - -static void ironlake_disable_fbc(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 dpfc_ctl; - - /* Disable compression */ - dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); - if (dpfc_ctl & DPFC_CTL_EN) { - dpfc_ctl &= ~DPFC_CTL_EN; - I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl); - - DRM_DEBUG_KMS("disabled FBC\n"); - } -} - -static bool ironlake_fbc_enabled(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN; -} - -bool intel_fbc_enabled(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (!dev_priv->display.fbc_enabled) - return false; - - return dev_priv->display.fbc_enabled(dev); -} - -static void intel_fbc_work_fn(void *arg, int pending) -{ - struct intel_fbc_work *work = arg; - struct drm_device *dev = work->crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - - DRM_LOCK(dev); - if (work == dev_priv->fbc_work) { - /* Double check that we haven't switched fb without cancelling - * the prior work. - */ - if (work->crtc->fb == work->fb) { - dev_priv->display.enable_fbc(work->crtc, - work->interval); - - dev_priv->cfb_plane = to_intel_crtc(work->crtc)->plane; - dev_priv->cfb_fb = work->crtc->fb->base.id; - dev_priv->cfb_y = work->crtc->y; - } - - dev_priv->fbc_work = NULL; - } - DRM_UNLOCK(dev); - - free(work, DRM_MEM_KMS); -} - -static void intel_cancel_fbc_work(struct drm_i915_private *dev_priv) -{ - u_int pending; - - if (dev_priv->fbc_work == NULL) - return; - - DRM_DEBUG_KMS("cancelling pending FBC enable\n"); - - /* Synchronisation is provided by struct_mutex and checking of - * dev_priv->fbc_work, so we can perform the cancellation - * entirely asynchronously. - */ - if (taskqueue_cancel_timeout(dev_priv->tq, &dev_priv->fbc_work->task, - &pending) == 0) - /* tasklet was killed before being run, clean up */ - free(dev_priv->fbc_work, DRM_MEM_KMS); - - /* Mark the work as no longer wanted so that if it does - * wake-up (because the work was already running and waiting - * for our mutex), it will discover that is no longer - * necessary to run. - */ - dev_priv->fbc_work = NULL; -} - -static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval) -{ - struct intel_fbc_work *work; - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - - if (!dev_priv->display.enable_fbc) - return; - - intel_cancel_fbc_work(dev_priv); - - work = malloc(sizeof(*work), DRM_MEM_KMS, M_WAITOK | M_ZERO); - work->crtc = crtc; - work->fb = crtc->fb; - work->interval = interval; - TIMEOUT_TASK_INIT(dev_priv->tq, &work->task, 0, intel_fbc_work_fn, - work); - - dev_priv->fbc_work = work; - - DRM_DEBUG_KMS("scheduling delayed FBC enable\n"); - - /* Delay the actual enabling to let pageflipping cease and the - * display to settle before starting the compression. Note that - * this delay also serves a second purpose: it allows for a - * vblank to pass after disabling the FBC before we attempt - * to modify the control registers. - * - * A more complicated solution would involve tracking vblanks - * following the termination of the page-flipping sequence - * and indeed performing the enable as a co-routine and not - * waiting synchronously upon the vblank. - */ - taskqueue_enqueue_timeout(dev_priv->tq, &work->task, - msecs_to_jiffies(50)); -} - -void intel_disable_fbc(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - intel_cancel_fbc_work(dev_priv); - - if (!dev_priv->display.disable_fbc) - return; - - dev_priv->display.disable_fbc(dev); - dev_priv->cfb_plane = -1; -} - -/** - * intel_update_fbc - enable/disable FBC as needed - * @dev: the drm_device - * - * Set up the framebuffer compression hardware at mode set time. We - * enable it if possible: - * - plane A only (on pre-965) - * - no pixel mulitply/line duplication - * - no alpha buffer discard - * - no dual wide - * - framebuffer <= 2048 in width, 1536 in height - * - * We can't assume that any compression will take place (worst case), - * so the compressed buffer has to be the same size as the uncompressed - * one. It also must reside (along with the line length buffer) in - * stolen memory. - * - * We need to enable/disable FBC on a global basis. - */ -static void intel_update_fbc(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc = NULL, *tmp_crtc; - struct intel_crtc *intel_crtc; - struct drm_framebuffer *fb; - struct intel_framebuffer *intel_fb; - struct drm_i915_gem_object *obj; - int enable_fbc; - - DRM_DEBUG_KMS("\n"); - - if (!i915_powersave) - return; - - if (!I915_HAS_FBC(dev)) - return; - - /* - * If FBC is already on, we just have to verify that we can - * keep it that way... - * Need to disable if: - * - more than one pipe is active - * - changing FBC params (stride, fence, mode) - * - new fb is too large to fit in compressed buffer - * - going to an unsupported config (interlace, pixel multiply, etc.) - */ - list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) { - if (tmp_crtc->enabled && tmp_crtc->fb) { - if (crtc) { - DRM_DEBUG_KMS("more than one pipe active, disabling compression\n"); - dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES; - goto out_disable; - } - crtc = tmp_crtc; - } - } - - if (!crtc || crtc->fb == NULL) { - DRM_DEBUG_KMS("no output, disabling\n"); - dev_priv->no_fbc_reason = FBC_NO_OUTPUT; - goto out_disable; - } - - intel_crtc = to_intel_crtc(crtc); - fb = crtc->fb; - intel_fb = to_intel_framebuffer(fb); - obj = intel_fb->obj; - - enable_fbc = i915_enable_fbc; - if (enable_fbc < 0) { - DRM_DEBUG_KMS("fbc set to per-chip default\n"); - enable_fbc = 1; - if (INTEL_INFO(dev)->gen <= 6) - enable_fbc = 0; - } - if (!enable_fbc) { - DRM_DEBUG_KMS("fbc disabled per module param\n"); - dev_priv->no_fbc_reason = FBC_MODULE_PARAM; - goto out_disable; - } - if (intel_fb->obj->base.size > dev_priv->cfb_size) { - DRM_DEBUG_KMS("framebuffer too large, disabling " - "compression\n"); - dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL; - goto out_disable; - } - if ((crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) || - (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)) { - DRM_DEBUG_KMS("mode incompatible with compression, " - "disabling\n"); - dev_priv->no_fbc_reason = FBC_UNSUPPORTED_MODE; - goto out_disable; - } - if ((crtc->mode.hdisplay > 2048) || - (crtc->mode.vdisplay > 1536)) { - DRM_DEBUG_KMS("mode too large for compression, disabling\n"); - dev_priv->no_fbc_reason = FBC_MODE_TOO_LARGE; - goto out_disable; - } - if ((IS_I915GM(dev) || IS_I945GM(dev)) && intel_crtc->plane != 0) { - DRM_DEBUG_KMS("plane not 0, disabling compression\n"); - dev_priv->no_fbc_reason = FBC_BAD_PLANE; - goto out_disable; - } - if (obj->tiling_mode != I915_TILING_X || - obj->fence_reg == I915_FENCE_REG_NONE) { - DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n"); - dev_priv->no_fbc_reason = FBC_NOT_TILED; - goto out_disable; - } - - /* If the kernel debugger is active, always disable compression */ - if (kdb_active) - goto out_disable; - - /* If the scanout has not changed, don't modify the FBC settings. - * Note that we make the fundamental assumption that the fb->obj - * cannot be unpinned (and have its GTT offset and fence revoked) - * without first being decoupled from the scanout and FBC disabled. - */ - if (dev_priv->cfb_plane == intel_crtc->plane && - dev_priv->cfb_fb == fb->base.id && - dev_priv->cfb_y == crtc->y) - return; - - if (intel_fbc_enabled(dev)) { - /* We update FBC along two paths, after changing fb/crtc - * configuration (modeswitching) and after page-flipping - * finishes. For the latter, we know that not only did - * we disable the FBC at the start of the page-flip - * sequence, but also more than one vblank has passed. - * - * For the former case of modeswitching, it is possible - * to switch between two FBC valid configurations - * instantaneously so we do need to disable the FBC - * before we can modify its control registers. We also - * have to wait for the next vblank for that to take - * effect. However, since we delay enabling FBC we can - * assume that a vblank has passed since disabling and - * that we can safely alter the registers in the deferred - * callback. - * - * In the scenario that we go from a valid to invalid - * and then back to valid FBC configuration we have - * no strict enforcement that a vblank occurred since - * disabling the FBC. However, along all current pipe - * disabling paths we do need to wait for a vblank at - * some point. And we wait before enabling FBC anyway. - */ - DRM_DEBUG_KMS("disabling active FBC for update\n"); - intel_disable_fbc(dev); - } - - intel_enable_fbc(crtc, 500); - return; - -out_disable: - /* Multiple disables should be harmless */ - if (intel_fbc_enabled(dev)) { - DRM_DEBUG_KMS("unsupported config, disabling FBC\n"); - intel_disable_fbc(dev); - } -} - int intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_i915_gem_object *obj, @@ -2052,19 +1821,17 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, * framebuffer compression. For simplicity, we always install * a fence as the cost is not that onerous. */ - if (obj->tiling_mode != I915_TILING_NONE) { - ret = i915_gem_object_get_fence(obj, pipelined); - if (ret) - goto err_unpin; + ret = i915_gem_object_get_fence(obj); + if (ret) + goto err_unpin; - i915_gem_object_pin_fence(obj); - } + i915_gem_object_pin_fence(obj); dev_priv->mm.interruptible = true; return 0; err_unpin: - i915_gem_object_unpin(obj); + i915_gem_object_unpin_from_display_plane(obj); err_interruptible: dev_priv->mm.interruptible = true; return ret; @@ -2073,7 +1840,7 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, void intel_unpin_fb_obj(struct drm_i915_gem_object *obj) { i915_gem_object_unpin_fence(obj); - i915_gem_object_unpin(obj); + i915_gem_object_unpin_from_display_plane(obj); } static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, @@ -2139,7 +1906,7 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, Start, Offset, x, y, fb->pitches[0]); I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]); if (INTEL_INFO(dev)->gen >= 4) { - I915_WRITE(DSPSURF(plane), Start); + I915_MODIFY_DISPBASE(DSPSURF(plane), Start); I915_WRITE(DSPTILEOFF(plane), (y << 16) | x); I915_WRITE(DSPADDR(plane), Offset); } else @@ -2224,7 +1991,7 @@ static int ironlake_update_plane(struct drm_crtc *crtc, DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n", Start, Offset, x, y, fb->pitches[0]); I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]); - I915_WRITE(DSPSURF(plane), Start); + I915_MODIFY_DISPBASE(DSPSURF(plane), Start); I915_WRITE(DSPTILEOFF(plane), (y << 16) | x); I915_WRITE(DSPADDR(plane), Offset); POSTING_READ(reg); @@ -2239,16 +2006,12 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - int ret; - ret = dev_priv->display.update_plane(crtc, fb, x, y); - if (ret) - return ret; - - intel_update_fbc(dev); + if (dev_priv->display.disable_fbc) + dev_priv->display.disable_fbc(dev); intel_increase_pllclock(crtc); - return 0; + return dev_priv->display.update_plane(crtc, fb, x, y); } static int @@ -2287,10 +2050,9 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb) { struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; #if 0 struct drm_i915_master_private *master_priv; -#else - drm_i915_private_t *dev_priv = dev->dev_private; #endif struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int ret; @@ -2301,16 +2063,10 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return 0; } - switch (intel_crtc->plane) { - case 0: - case 1: - break; - case 2: - if (IS_IVYBRIDGE(dev)) - break; - /* fall through otherwise */ - default: - DRM_ERROR("no plane for crtc\n"); + if(intel_crtc->plane > dev_priv->num_pipe) { + DRM_ERROR("no plane for crtc: plane %d, num_pipes %d\n", + intel_crtc->plane, + dev_priv->num_pipe); return -EINVAL; } @@ -2327,8 +2083,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, if (old_fb) intel_finish_fb(old_fb); - ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y, - LEAVE_ATOMIC_MODE_SET); + ret = dev_priv->display.update_plane(crtc, crtc->fb, x, y); if (ret) { intel_unpin_fb_obj(to_intel_framebuffer(crtc->fb)->obj); DRM_UNLOCK(dev); @@ -2341,6 +2096,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, intel_unpin_fb_obj(to_intel_framebuffer(old_fb)->obj); } + intel_update_fbc(dev); DRM_UNLOCK(dev); #if 0 @@ -2576,7 +2332,7 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; - u32 reg, temp, i; + u32 reg, temp, i, retry; /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit for train result */ @@ -2628,15 +2384,20 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) POSTING_READ(reg); DELAY(500); - reg = FDI_RX_IIR(pipe); - temp = I915_READ(reg); - DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp); + for (retry = 0; retry < 5; retry++) { + reg = FDI_RX_IIR(pipe); + temp = I915_READ(reg); + DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp); - if (temp & FDI_RX_BIT_LOCK) { - I915_WRITE(reg, temp | FDI_RX_BIT_LOCK); - DRM_DEBUG_KMS("FDI train 1 done.\n"); - break; + if (temp & FDI_RX_BIT_LOCK) { + I915_WRITE(reg, temp | FDI_RX_BIT_LOCK); + DRM_DEBUG_KMS("FDI train 1 done.\n"); + break; + } + DELAY(50); } + if (retry < 5) + break; } if (i == 4) DRM_ERROR("FDI train 1 fail!\n"); @@ -2677,15 +2438,20 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) POSTING_READ(reg); DELAY(500); - reg = FDI_RX_IIR(pipe); - temp = I915_READ(reg); - DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp); + for (retry = 0; retry < 5; retry++) { + reg = FDI_RX_IIR(pipe); + temp = I915_READ(reg); + DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp); - if (temp & FDI_RX_SYMBOL_LOCK) { - I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK); - DRM_DEBUG_KMS("FDI train 2 done.\n"); - break; + if (temp & FDI_RX_SYMBOL_LOCK) { + I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK); + DRM_DEBUG_KMS("FDI train 2 done.\n"); + break; + } + DELAY(50); } + if (retry < 5) + break; } if (i == 4) DRM_ERROR("FDI train 2 fail!\n"); @@ -2834,15 +2600,19 @@ static void ironlake_fdi_pll_enable(struct drm_crtc *crtc) POSTING_READ(reg); DELAY(200); - /* Enable CPU FDI TX PLL, always on for Ironlake */ - reg = FDI_TX_CTL(pipe); - temp = I915_READ(reg); - if ((temp & FDI_TX_PLL_ENABLE) == 0) { - I915_WRITE(reg, temp | FDI_TX_PLL_ENABLE); + /* On Haswell, the PLL configuration for ports and pipes is handled + * separately, as part of DDI setup */ + if (!IS_HASWELL(dev)) { + /* Enable CPU FDI TX PLL, always on for Ironlake */ + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); + if ((temp & FDI_TX_PLL_ENABLE) == 0) { + I915_WRITE(reg, temp | FDI_TX_PLL_ENABLE); - POSTING_READ(reg); - DELAY(100); - } + POSTING_READ(reg); + DELAY(100); + } + } } static void cpt_phase_pointer_disable(struct drm_device *dev, int pipe) @@ -2915,42 +2685,16 @@ static void ironlake_fdi_disable(struct drm_crtc *crtc) DELAY(100); } -/* - * When we disable a pipe, we need to clear any pending scanline wait events - * to avoid hanging the ring, which we assume we are waiting on. - */ -static void intel_clear_scanline_wait(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_ring_buffer *ring; - u32 tmp; - - if (IS_GEN2(dev)) - /* Can't break the hang on i8xx */ - return; - - ring = LP_RING(dev_priv); - tmp = I915_READ_CTL(ring); - if (tmp & RING_WAIT) - I915_WRITE_CTL(ring, tmp); -} - static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) { - struct drm_i915_gem_object *obj; - struct drm_i915_private *dev_priv; - struct drm_device *dev; + struct drm_device *dev = crtc->dev; if (crtc->fb == NULL) return; - obj = to_intel_framebuffer(crtc->fb)->obj; - dev = crtc->dev; - dev_priv = dev->dev_private; - mtx_lock(&dev->event_lock); - while (atomic_load_acq_int(&obj->pending_flip) != 0) - msleep(&obj->pending_flip, &dev->event_lock, 0, "915wfl", 0); - mtx_unlock(&dev->event_lock); + DRM_LOCK(dev); + intel_finish_fb(crtc->fb); + DRM_UNLOCK(dev); } static bool intel_crtc_driving_pch(struct drm_crtc *crtc) @@ -2967,6 +2711,23 @@ static bool intel_crtc_driving_pch(struct drm_crtc *crtc) if (encoder->base.crtc != crtc) continue; + /* On Haswell, LPT PCH handles the VGA connection via FDI, and Haswell + * CPU handles all others */ + if (IS_HASWELL(dev)) { + /* It is still unclear how this will work on PPT, so throw up a warning */ + if (!HAS_PCH_LPT(dev)) + DRM_DEBUG_KMS("Haswell: PPT\n"); + + if (encoder->type == DRM_MODE_ENCODER_DAC) { + DRM_DEBUG_KMS("Haswell detected DAC encoder, assuming is PCH\n"); + return true; + } else { + DRM_DEBUG_KMS("Haswell detected encoder %d, assuming is CPU\n", + encoder->type); + return false; + } + } + switch (encoder->type) { case INTEL_OUTPUT_EDP: if (!intel_encoder_is_pch_edp(&encoder->base)) @@ -2978,6 +2739,99 @@ static bool intel_crtc_driving_pch(struct drm_crtc *crtc) return true; } +/* Program iCLKIP clock to the desired frequency */ +static void lpt_program_iclkip(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 divsel, phaseinc, auxdiv, phasedir = 0; + u32 temp; + + /* It is necessary to ungate the pixclk gate prior to programming + * the divisors, and gate it back when it is done. + */ + I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_GATE); + + /* Disable SSCCTL */ + intel_sbi_write(dev_priv, SBI_SSCCTL6, + intel_sbi_read(dev_priv, SBI_SSCCTL6) | + SBI_SSCCTL_DISABLE); + + /* 20MHz is a corner case which is out of range for the 7-bit divisor */ + if (crtc->mode.clock == 20000) { + auxdiv = 1; + divsel = 0x41; + phaseinc = 0x20; + } else { + /* The iCLK virtual clock root frequency is in MHz, + * but the crtc->mode.clock in in KHz. To get the divisors, + * it is necessary to divide one by another, so we + * convert the virtual clock precision to KHz here for higher + * precision. + */ + u32 iclk_virtual_root_freq = 172800 * 1000; + u32 iclk_pi_range = 64; + u32 desired_divisor, msb_divisor_value, pi_value; + + desired_divisor = (iclk_virtual_root_freq / crtc->mode.clock); + msb_divisor_value = desired_divisor / iclk_pi_range; + pi_value = desired_divisor % iclk_pi_range; + + auxdiv = 0; + divsel = msb_divisor_value - 2; + phaseinc = pi_value; + } + + /* This should not happen with any sane values */ + if ((SBI_SSCDIVINTPHASE_DIVSEL(divsel) & + ~SBI_SSCDIVINTPHASE_DIVSEL_MASK)) + DRM_DEBUG_KMS("DIVSEL_MASK"); + if ((SBI_SSCDIVINTPHASE_DIR(phasedir) & + ~SBI_SSCDIVINTPHASE_INCVAL_MASK)) + DRM_DEBUG_KMS("INCVAL_MASK"); + + DRM_DEBUG_KMS("iCLKIP clock: found settings for %dKHz refresh rate: auxdiv=%x, divsel=%x, phasedir=%x, phaseinc=%x\n", + crtc->mode.clock, + auxdiv, + divsel, + phasedir, + phaseinc); + + /* Program SSCDIVINTPHASE6 */ + temp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE6); + temp &= ~SBI_SSCDIVINTPHASE_DIVSEL_MASK; + temp |= SBI_SSCDIVINTPHASE_DIVSEL(divsel); + temp &= ~SBI_SSCDIVINTPHASE_INCVAL_MASK; + temp |= SBI_SSCDIVINTPHASE_INCVAL(phaseinc); + temp |= SBI_SSCDIVINTPHASE_DIR(phasedir); + temp |= SBI_SSCDIVINTPHASE_PROPAGATE; + + intel_sbi_write(dev_priv, + SBI_SSCDIVINTPHASE6, + temp); + + /* Program SSCAUXDIV */ + temp = intel_sbi_read(dev_priv, SBI_SSCAUXDIV6); + temp &= ~SBI_SSCAUXDIV_FINALDIV2SEL(1); + temp |= SBI_SSCAUXDIV_FINALDIV2SEL(auxdiv); + intel_sbi_write(dev_priv, + SBI_SSCAUXDIV6, + temp); + + + /* Enable modulator and associated divider */ + temp = intel_sbi_read(dev_priv, SBI_SSCCTL6); + temp &= ~SBI_SSCCTL_DISABLE; + intel_sbi_write(dev_priv, + SBI_SSCCTL6, + temp); + + /* Wait for initialization time */ + DELAY(24); + + I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_UNGATE); +} + /* * Enable PCH resources required for PCH ports: * - PCH PLLs @@ -2992,29 +2846,41 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; - u32 reg, temp, transc_sel; + u32 reg, temp; + + assert_transcoder_disabled(dev_priv, pipe); /* For PCH output, training FDI link */ dev_priv->display.fdi_link_train(crtc); - intel_enable_pch_pll(dev_priv, pipe); + intel_enable_pch_pll(intel_crtc); - if (HAS_PCH_CPT(dev)) { - transc_sel = intel_crtc->use_pll_a ? TRANSC_DPLLA_SEL : - TRANSC_DPLLB_SEL; + if (HAS_PCH_LPT(dev)) { + DRM_DEBUG_KMS("LPT detected: programming iCLKIP\n"); + lpt_program_iclkip(crtc); + } else if (HAS_PCH_CPT(dev)) { + u32 sel; - /* Be sure PCH DPLL SEL is set */ temp = I915_READ(PCH_DPLL_SEL); - if (pipe == 0) { - temp &= ~(TRANSA_DPLLB_SEL); - temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL); - } else if (pipe == 1) { - temp &= ~(TRANSB_DPLLB_SEL); - temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL); - } else if (pipe == 2) { - temp &= ~(TRANSC_DPLLB_SEL); - temp |= (TRANSC_DPLL_ENABLE | transc_sel); + switch (pipe) { + default: + case 0: + temp |= TRANSA_DPLL_ENABLE; + sel = TRANSA_DPLLB_SEL; + break; + case 1: + temp |= TRANSB_DPLL_ENABLE; + sel = TRANSB_DPLLB_SEL; + break; + case 2: + temp |= TRANSC_DPLL_ENABLE; + sel = TRANSC_DPLLB_SEL; + break; } + if (intel_crtc->pch_pll->pll_reg == _PCH_DPLL_B) + temp |= sel; + else + temp &= ~sel; I915_WRITE(PCH_DPLL_SEL, temp); } @@ -3029,7 +2895,8 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) I915_WRITE(TRANS_VSYNC(pipe), I915_READ(VSYNC(pipe))); I915_WRITE(TRANS_VSYNCSHIFT(pipe), I915_READ(VSYNCSHIFT(pipe))); - intel_fdi_normal_train(crtc); + if (!IS_HASWELL(dev)) + intel_fdi_normal_train(crtc); /* For PCH DP, enable TRANS_DP_CTL */ if (HAS_PCH_CPT(dev) && @@ -3072,6 +2939,93 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) intel_enable_transcoder(dev_priv, pipe); } +static void intel_put_pch_pll(struct intel_crtc *intel_crtc) +{ + struct intel_pch_pll *pll = intel_crtc->pch_pll; + + if (pll == NULL) + return; + + if (pll->refcount == 0) { + printf("bad PCH PLL refcount\n"); + return; + } + + --pll->refcount; + intel_crtc->pch_pll = NULL; +} + +static struct intel_pch_pll *intel_get_pch_pll(struct intel_crtc *intel_crtc, u32 dpll, u32 fp) +{ + struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private; + struct intel_pch_pll *pll; + int i; + + pll = intel_crtc->pch_pll; + if (pll) { + DRM_DEBUG_KMS("CRTC:%d reusing existing PCH PLL %x\n", + intel_crtc->base.base.id, pll->pll_reg); + goto prepare; + } + + if (HAS_PCH_IBX(dev_priv->dev)) { + /* Ironlake PCH has a fixed PLL->PCH pipe mapping. */ + i = intel_crtc->pipe; + pll = &dev_priv->pch_plls[i]; + + DRM_DEBUG_KMS("CRTC:%d using pre-allocated PCH PLL %x\n", + intel_crtc->base.base.id, pll->pll_reg); + + goto found; + } + + for (i = 0; i < dev_priv->num_pch_pll; i++) { + pll = &dev_priv->pch_plls[i]; + + /* Only want to check enabled timings first */ + if (pll->refcount == 0) + continue; + + if (dpll == (I915_READ(pll->pll_reg) & 0x7fffffff) && + fp == I915_READ(pll->fp0_reg)) { + DRM_DEBUG_KMS("CRTC:%d sharing existing PCH PLL %x (refcount %d, ative %d)\n", + intel_crtc->base.base.id, + pll->pll_reg, pll->refcount, pll->active); + + goto found; + } + } + + /* Ok no matching timings, maybe there's a free one? */ + for (i = 0; i < dev_priv->num_pch_pll; i++) { /* XXXKIB: HACK */ + pll = &dev_priv->pch_plls[i]; + if (pll->refcount == 0) { + DRM_DEBUG_KMS("CRTC:%d allocated PCH PLL %x\n", + intel_crtc->base.base.id, pll->pll_reg); + goto found; + } + } + + return NULL; + +found: + intel_crtc->pch_pll = pll; + pll->refcount++; + DRM_DEBUG_DRIVER("using pll %d for pipe %d\n", i, intel_crtc->pipe); +prepare: /* separate function? */ + DRM_DEBUG_DRIVER("switching PLL %x off\n", pll->pll_reg); + + /* Wait for the clocks to stabilize before rewriting the regs */ + I915_WRITE(pll->pll_reg, dpll & ~DPLL_VCO_ENABLE); + POSTING_READ(pll->pll_reg); + DELAY(150); + + I915_WRITE(pll->fp0_reg, fp); + I915_WRITE(pll->pll_reg, dpll & ~DPLL_VCO_ENABLE); + pll->on = false; + return pll; +} + void intel_cpt_verify_modeset(struct drm_device *dev, int pipe) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -3213,8 +3167,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) } /* disable PCH DPLL */ - if (!intel_crtc->no_pll) - intel_disable_pch_pll(dev_priv, pipe); + intel_disable_pch_pll(intel_crtc); /* Switch from PCDclk to Rawclk */ reg = FDI_RX_CTL(pipe); @@ -3242,7 +3195,6 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) DRM_LOCK(dev); intel_update_fbc(dev); - intel_clear_scanline_wait(dev); DRM_UNLOCK(dev); } @@ -3270,6 +3222,12 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) } } +static void ironlake_crtc_off(struct drm_crtc *crtc) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + intel_put_pch_pll(intel_crtc); +} + static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable) { if (!enable && intel_crtc->overlay) { @@ -3341,7 +3299,6 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) intel_crtc->active = false; intel_update_fbc(dev); intel_update_watermarks(dev); - intel_clear_scanline_wait(dev); } static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) @@ -3361,6 +3318,10 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) } } +static void i9xx_crtc_off(struct drm_crtc *crtc) +{ +} + /** * Sets the power management mode of the pipe and plane. */ @@ -3425,26 +3386,12 @@ static void intel_crtc_disable(struct drm_crtc *crtc) { struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; struct drm_device *dev = crtc->dev; - - /* Flush any pending WAITs before we disable the pipe. Note that - * we need to drop the struct_mutex in order to acquire it again - * during the lowlevel dpms routines around a couple of the - * operations. It does not look trivial nor desirable to move - * that locking higher. So instead we leave a window for the - * submission of further commands on the fb before we can actually - * disable it. This race with userspace exists anyway, and we can - * only rely on the pipe being disabled by userspace after it - * receives the hotplug notification and has flushed any pending - * batches. - */ - if (crtc->fb) { - DRM_LOCK(dev); - intel_finish_fb(crtc->fb); - DRM_UNLOCK(dev); - } + struct drm_i915_private *dev_priv = dev->dev_private; crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); - assert_plane_disabled(dev->dev_private, to_intel_crtc(crtc)->plane); + dev_priv->display.off(crtc); + + assert_plane_disabled(dev->dev_private, to_intel_crtc(crtc)->plane); assert_pipe_disabled(dev->dev_private, to_intel_crtc(crtc)->pipe); if (crtc->fb) { @@ -3493,8 +3440,7 @@ void intel_encoder_commit(struct drm_encoder *encoder) { struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; struct drm_device *dev = encoder->dev; - struct intel_encoder *intel_encoder = to_intel_encoder(encoder); - struct intel_crtc *intel_crtc = to_intel_crtc(intel_encoder->base.crtc); + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); /* lvds has its own version of commit see intel_lvds_commit */ encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); @@ -3532,6 +3478,11 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, return true; } +static int valleyview_get_display_clock_speed(struct drm_device *dev) +{ + return 400000; /* FIXME */ +} + static int i945_get_display_clock_speed(struct drm_device *dev) { return 400000; @@ -3629,1341 +3580,6 @@ ironlake_compute_m_n(int bits_per_pixel, int nlanes, int pixel_clock, fdi_reduce_ratio(&m_n->link_m, &m_n->link_n); } - -struct intel_watermark_params { - unsigned long fifo_size; - unsigned long max_wm; - unsigned long default_wm; - unsigned long guard_size; - unsigned long cacheline_size; -}; - -/* Pineview has different values for various configs */ -static const struct intel_watermark_params pineview_display_wm = { - PINEVIEW_DISPLAY_FIFO, - PINEVIEW_MAX_WM, - PINEVIEW_DFT_WM, - PINEVIEW_GUARD_WM, - PINEVIEW_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params pineview_display_hplloff_wm = { - PINEVIEW_DISPLAY_FIFO, - PINEVIEW_MAX_WM, - PINEVIEW_DFT_HPLLOFF_WM, - PINEVIEW_GUARD_WM, - PINEVIEW_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params pineview_cursor_wm = { - PINEVIEW_CURSOR_FIFO, - PINEVIEW_CURSOR_MAX_WM, - PINEVIEW_CURSOR_DFT_WM, - PINEVIEW_CURSOR_GUARD_WM, - PINEVIEW_FIFO_LINE_SIZE, -}; -static const struct intel_watermark_params pineview_cursor_hplloff_wm = { - PINEVIEW_CURSOR_FIFO, - PINEVIEW_CURSOR_MAX_WM, - PINEVIEW_CURSOR_DFT_WM, - PINEVIEW_CURSOR_GUARD_WM, - PINEVIEW_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params g4x_wm_info = { - G4X_FIFO_SIZE, - G4X_MAX_WM, - G4X_MAX_WM, - 2, - G4X_FIFO_LINE_SIZE, -}; -static const struct intel_watermark_params g4x_cursor_wm_info = { - I965_CURSOR_FIFO, - I965_CURSOR_MAX_WM, - I965_CURSOR_DFT_WM, - 2, - G4X_FIFO_LINE_SIZE, -}; -static const struct intel_watermark_params i965_cursor_wm_info = { - I965_CURSOR_FIFO, - I965_CURSOR_MAX_WM, - I965_CURSOR_DFT_WM, - 2, - I915_FIFO_LINE_SIZE, -}; -static const struct intel_watermark_params i945_wm_info = { - I945_FIFO_SIZE, - I915_MAX_WM, - 1, - 2, - I915_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params i915_wm_info = { - I915_FIFO_SIZE, - I915_MAX_WM, - 1, - 2, - I915_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params i855_wm_info = { - I855GM_FIFO_SIZE, - I915_MAX_WM, - 1, - 2, - I830_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params i830_wm_info = { - I830_FIFO_SIZE, - I915_MAX_WM, - 1, - 2, - I830_FIFO_LINE_SIZE -}; - -static const struct intel_watermark_params ironlake_display_wm_info = { - ILK_DISPLAY_FIFO, - ILK_DISPLAY_MAXWM, - ILK_DISPLAY_DFTWM, - 2, - ILK_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params ironlake_cursor_wm_info = { - ILK_CURSOR_FIFO, - ILK_CURSOR_MAXWM, - ILK_CURSOR_DFTWM, - 2, - ILK_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params ironlake_display_srwm_info = { - ILK_DISPLAY_SR_FIFO, - ILK_DISPLAY_MAX_SRWM, - ILK_DISPLAY_DFT_SRWM, - 2, - ILK_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params ironlake_cursor_srwm_info = { - ILK_CURSOR_SR_FIFO, - ILK_CURSOR_MAX_SRWM, - ILK_CURSOR_DFT_SRWM, - 2, - ILK_FIFO_LINE_SIZE -}; - -static const struct intel_watermark_params sandybridge_display_wm_info = { - SNB_DISPLAY_FIFO, - SNB_DISPLAY_MAXWM, - SNB_DISPLAY_DFTWM, - 2, - SNB_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params sandybridge_cursor_wm_info = { - SNB_CURSOR_FIFO, - SNB_CURSOR_MAXWM, - SNB_CURSOR_DFTWM, - 2, - SNB_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params sandybridge_display_srwm_info = { - SNB_DISPLAY_SR_FIFO, - SNB_DISPLAY_MAX_SRWM, - SNB_DISPLAY_DFT_SRWM, - 2, - SNB_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params sandybridge_cursor_srwm_info = { - SNB_CURSOR_SR_FIFO, - SNB_CURSOR_MAX_SRWM, - SNB_CURSOR_DFT_SRWM, - 2, - SNB_FIFO_LINE_SIZE -}; - - -/** - * intel_calculate_wm - calculate watermark level - * @clock_in_khz: pixel clock - * @wm: chip FIFO params - * @pixel_size: display pixel size - * @latency_ns: memory latency for the platform - * - * Calculate the watermark level (the level at which the display plane will - * start fetching from memory again). Each chip has a different display - * FIFO size and allocation, so the caller needs to figure that out and pass - * in the correct intel_watermark_params structure. - * - * As the pixel clock runs, the FIFO will be drained at a rate that depends - * on the pixel size. When it reaches the watermark level, it'll start - * fetching FIFO line sized based chunks from memory until the FIFO fills - * past the watermark point. If the FIFO drains completely, a FIFO underrun - * will occur, and a display engine hang could result. - */ -static unsigned long intel_calculate_wm(unsigned long clock_in_khz, - const struct intel_watermark_params *wm, - int fifo_size, - int pixel_size, - unsigned long latency_ns) -{ - long entries_required, wm_size; - - /* - * Note: we need to make sure we don't overflow for various clock & - * latency values. - * clocks go from a few thousand to several hundred thousand. - * latency is usually a few thousand - */ - entries_required = ((clock_in_khz / 1000) * pixel_size * latency_ns) / - 1000; - entries_required = howmany(entries_required, wm->cacheline_size); - - DRM_DEBUG_KMS("FIFO entries required for mode: %ld\n", entries_required); - - wm_size = fifo_size - (entries_required + wm->guard_size); - - DRM_DEBUG_KMS("FIFO watermark level: %ld\n", wm_size); - - /* Don't promote wm_size to unsigned... */ - if (wm_size > (long)wm->max_wm) - wm_size = wm->max_wm; - if (wm_size <= 0) - wm_size = wm->default_wm; - return wm_size; -} - -struct cxsr_latency { - int is_desktop; - int is_ddr3; - unsigned long fsb_freq; - unsigned long mem_freq; - unsigned long display_sr; - unsigned long display_hpll_disable; - unsigned long cursor_sr; - unsigned long cursor_hpll_disable; -}; - -static const struct cxsr_latency cxsr_latency_table[] = { - {1, 0, 800, 400, 3382, 33382, 3983, 33983}, /* DDR2-400 SC */ - {1, 0, 800, 667, 3354, 33354, 3807, 33807}, /* DDR2-667 SC */ - {1, 0, 800, 800, 3347, 33347, 3763, 33763}, /* DDR2-800 SC */ - {1, 1, 800, 667, 6420, 36420, 6873, 36873}, /* DDR3-667 SC */ - {1, 1, 800, 800, 5902, 35902, 6318, 36318}, /* DDR3-800 SC */ - - {1, 0, 667, 400, 3400, 33400, 4021, 34021}, /* DDR2-400 SC */ - {1, 0, 667, 667, 3372, 33372, 3845, 33845}, /* DDR2-667 SC */ - {1, 0, 667, 800, 3386, 33386, 3822, 33822}, /* DDR2-800 SC */ - {1, 1, 667, 667, 6438, 36438, 6911, 36911}, /* DDR3-667 SC */ - {1, 1, 667, 800, 5941, 35941, 6377, 36377}, /* DDR3-800 SC */ - - {1, 0, 400, 400, 3472, 33472, 4173, 34173}, /* DDR2-400 SC */ - {1, 0, 400, 667, 3443, 33443, 3996, 33996}, /* DDR2-667 SC */ - {1, 0, 400, 800, 3430, 33430, 3946, 33946}, /* DDR2-800 SC */ - {1, 1, 400, 667, 6509, 36509, 7062, 37062}, /* DDR3-667 SC */ - {1, 1, 400, 800, 5985, 35985, 6501, 36501}, /* DDR3-800 SC */ - - {0, 0, 800, 400, 3438, 33438, 4065, 34065}, /* DDR2-400 SC */ - {0, 0, 800, 667, 3410, 33410, 3889, 33889}, /* DDR2-667 SC */ - {0, 0, 800, 800, 3403, 33403, 3845, 33845}, /* DDR2-800 SC */ - {0, 1, 800, 667, 6476, 36476, 6955, 36955}, /* DDR3-667 SC */ - {0, 1, 800, 800, 5958, 35958, 6400, 36400}, /* DDR3-800 SC */ - - {0, 0, 667, 400, 3456, 33456, 4103, 34106}, /* DDR2-400 SC */ - {0, 0, 667, 667, 3428, 33428, 3927, 33927}, /* DDR2-667 SC */ - {0, 0, 667, 800, 3443, 33443, 3905, 33905}, /* DDR2-800 SC */ - {0, 1, 667, 667, 6494, 36494, 6993, 36993}, /* DDR3-667 SC */ - {0, 1, 667, 800, 5998, 35998, 6460, 36460}, /* DDR3-800 SC */ - - {0, 0, 400, 400, 3528, 33528, 4255, 34255}, /* DDR2-400 SC */ - {0, 0, 400, 667, 3500, 33500, 4079, 34079}, /* DDR2-667 SC */ - {0, 0, 400, 800, 3487, 33487, 4029, 34029}, /* DDR2-800 SC */ - {0, 1, 400, 667, 6566, 36566, 7145, 37145}, /* DDR3-667 SC */ - {0, 1, 400, 800, 6042, 36042, 6584, 36584}, /* DDR3-800 SC */ -}; - -static const struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, - int is_ddr3, - int fsb, - int mem) -{ - const struct cxsr_latency *latency; - int i; - - if (fsb == 0 || mem == 0) - return NULL; - - for (i = 0; i < DRM_ARRAY_SIZE(cxsr_latency_table); i++) { - latency = &cxsr_latency_table[i]; - if (is_desktop == latency->is_desktop && - is_ddr3 == latency->is_ddr3 && - fsb == latency->fsb_freq && mem == latency->mem_freq) - return latency; - } - - DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n"); - - return NULL; -} - -static void pineview_disable_cxsr(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - /* deactivate cxsr */ - I915_WRITE(DSPFW3, I915_READ(DSPFW3) & ~PINEVIEW_SELF_REFRESH_EN); -} - -/* - * Latency for FIFO fetches is dependent on several factors: - * - memory configuration (speed, channels) - * - chipset - * - current MCH state - * It can be fairly high in some situations, so here we assume a fairly - * pessimal value. It's a tradeoff between extra memory fetches (if we - * set this value too high, the FIFO will fetch frequently to stay full) - * and power consumption (set it too low to save power and we might see - * FIFO underruns and display "flicker"). - * - * A value of 5us seems to be a good balance; safe for very low end - * platforms but not overly aggressive on lower latency configs. - */ -static const int latency_ns = 5000; - -static int i9xx_get_fifo_size(struct drm_device *dev, int plane) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t dsparb = I915_READ(DSPARB); - int size; - - size = dsparb & 0x7f; - if (plane) - size = ((dsparb >> DSPARB_CSTART_SHIFT) & 0x7f) - size; - - DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb, - plane ? "B" : "A", size); - - return size; -} - -static int i85x_get_fifo_size(struct drm_device *dev, int plane) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t dsparb = I915_READ(DSPARB); - int size; - - size = dsparb & 0x1ff; - if (plane) - size = ((dsparb >> DSPARB_BEND_SHIFT) & 0x1ff) - size; - size >>= 1; /* Convert to cachelines */ - - DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb, - plane ? "B" : "A", size); - - return size; -} - -static int i845_get_fifo_size(struct drm_device *dev, int plane) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t dsparb = I915_READ(DSPARB); - int size; - - size = dsparb & 0x7f; - size >>= 2; /* Convert to cachelines */ - - DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb, - plane ? "B" : "A", - size); - - return size; -} - -static int i830_get_fifo_size(struct drm_device *dev, int plane) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t dsparb = I915_READ(DSPARB); - int size; - - size = dsparb & 0x7f; - size >>= 1; /* Convert to cachelines */ - - DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb, - plane ? "B" : "A", size); - - return size; -} - -static struct drm_crtc *single_enabled_crtc(struct drm_device *dev) -{ - struct drm_crtc *crtc, *enabled = NULL; - - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (crtc->enabled && crtc->fb) { - if (enabled) - return NULL; - enabled = crtc; - } - } - - return enabled; -} - -static void pineview_update_wm(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc; - const struct cxsr_latency *latency; - u32 reg; - unsigned long wm; - - latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->is_ddr3, - dev_priv->fsb_freq, dev_priv->mem_freq); - if (!latency) { - DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n"); - pineview_disable_cxsr(dev); - return; - } - - crtc = single_enabled_crtc(dev); - if (crtc) { - int clock = crtc->mode.clock; - int pixel_size = crtc->fb->bits_per_pixel / 8; - - /* Display SR */ - wm = intel_calculate_wm(clock, &pineview_display_wm, - pineview_display_wm.fifo_size, - pixel_size, latency->display_sr); - reg = I915_READ(DSPFW1); - reg &= ~DSPFW_SR_MASK; - reg |= wm << DSPFW_SR_SHIFT; - I915_WRITE(DSPFW1, reg); - DRM_DEBUG_KMS("DSPFW1 register is %x\n", reg); - - /* cursor SR */ - wm = intel_calculate_wm(clock, &pineview_cursor_wm, - pineview_display_wm.fifo_size, - pixel_size, latency->cursor_sr); - reg = I915_READ(DSPFW3); - reg &= ~DSPFW_CURSOR_SR_MASK; - reg |= (wm & 0x3f) << DSPFW_CURSOR_SR_SHIFT; - I915_WRITE(DSPFW3, reg); - - /* Display HPLL off SR */ - wm = intel_calculate_wm(clock, &pineview_display_hplloff_wm, - pineview_display_hplloff_wm.fifo_size, - pixel_size, latency->display_hpll_disable); - reg = I915_READ(DSPFW3); - reg &= ~DSPFW_HPLL_SR_MASK; - reg |= wm & DSPFW_HPLL_SR_MASK; - I915_WRITE(DSPFW3, reg); - - /* cursor HPLL off SR */ - wm = intel_calculate_wm(clock, &pineview_cursor_hplloff_wm, - pineview_display_hplloff_wm.fifo_size, - pixel_size, latency->cursor_hpll_disable); - reg = I915_READ(DSPFW3); - reg &= ~DSPFW_HPLL_CURSOR_MASK; - reg |= (wm & 0x3f) << DSPFW_HPLL_CURSOR_SHIFT; - I915_WRITE(DSPFW3, reg); - DRM_DEBUG_KMS("DSPFW3 register is %x\n", reg); - - /* activate cxsr */ - I915_WRITE(DSPFW3, - I915_READ(DSPFW3) | PINEVIEW_SELF_REFRESH_EN); - DRM_DEBUG_KMS("Self-refresh is enabled\n"); - } else { - pineview_disable_cxsr(dev); - DRM_DEBUG_KMS("Self-refresh is disabled\n"); - } -} - -static bool g4x_compute_wm0(struct drm_device *dev, - int plane, - const struct intel_watermark_params *display, - int display_latency_ns, - const struct intel_watermark_params *cursor, - int cursor_latency_ns, - int *plane_wm, - int *cursor_wm) -{ - struct drm_crtc *crtc; - int htotal, hdisplay, clock, pixel_size; - int line_time_us, line_count; - int entries, tlb_miss; - - crtc = intel_get_crtc_for_plane(dev, plane); - if (crtc->fb == NULL || !crtc->enabled) { - *cursor_wm = cursor->guard_size; - *plane_wm = display->guard_size; - return false; - } - - htotal = crtc->mode.htotal; - hdisplay = crtc->mode.hdisplay; - clock = crtc->mode.clock; - pixel_size = crtc->fb->bits_per_pixel / 8; - - /* Use the small buffer method to calculate plane watermark */ - entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000; - tlb_miss = display->fifo_size*display->cacheline_size - hdisplay * 8; - if (tlb_miss > 0) - entries += tlb_miss; - entries = howmany(entries, display->cacheline_size); - *plane_wm = entries + display->guard_size; - if (*plane_wm > (int)display->max_wm) - *plane_wm = display->max_wm; - - /* Use the large buffer method to calculate cursor watermark */ - line_time_us = ((htotal * 1000) / clock); - line_count = (cursor_latency_ns / line_time_us + 1000) / 1000; - entries = line_count * 64 * pixel_size; - tlb_miss = cursor->fifo_size*cursor->cacheline_size - hdisplay * 8; - if (tlb_miss > 0) - entries += tlb_miss; - entries = howmany(entries, cursor->cacheline_size); - *cursor_wm = entries + cursor->guard_size; - if (*cursor_wm > (int)cursor->max_wm) - *cursor_wm = (int)cursor->max_wm; - - return true; -} - -/* - * Check the wm result. - * - * If any calculated watermark values is larger than the maximum value that - * can be programmed into the associated watermark register, that watermark - * must be disabled. - */ -static bool g4x_check_srwm(struct drm_device *dev, - int display_wm, int cursor_wm, - const struct intel_watermark_params *display, - const struct intel_watermark_params *cursor) -{ - DRM_DEBUG_KMS("SR watermark: display plane %d, cursor %d\n", - display_wm, cursor_wm); - - if (display_wm > display->max_wm) { - DRM_DEBUG_KMS("display watermark is too large(%d/%ld), disabling\n", - display_wm, display->max_wm); - return false; - } - - if (cursor_wm > cursor->max_wm) { - DRM_DEBUG_KMS("cursor watermark is too large(%d/%ld), disabling\n", - cursor_wm, cursor->max_wm); - return false; - } - - if (!(display_wm || cursor_wm)) { - DRM_DEBUG_KMS("SR latency is 0, disabling\n"); - return false; - } - - return true; -} - -static bool g4x_compute_srwm(struct drm_device *dev, - int plane, - int latency_ns, - const struct intel_watermark_params *display, - const struct intel_watermark_params *cursor, - int *display_wm, int *cursor_wm) -{ - struct drm_crtc *crtc; - int hdisplay, htotal, pixel_size, clock; - unsigned long line_time_us; - int line_count, line_size; - int small, large; - int entries; - - if (!latency_ns) { - *display_wm = *cursor_wm = 0; - return false; - } - - crtc = intel_get_crtc_for_plane(dev, plane); - hdisplay = crtc->mode.hdisplay; - htotal = crtc->mode.htotal; - clock = crtc->mode.clock; - pixel_size = crtc->fb->bits_per_pixel / 8; - - line_time_us = (htotal * 1000) / clock; - line_count = (latency_ns / line_time_us + 1000) / 1000; - line_size = hdisplay * pixel_size; - - /* Use the minimum of the small and large buffer method for primary */ - small = ((clock * pixel_size / 1000) * latency_ns) / 1000; - large = line_count * line_size; - - entries = howmany(min(small, large), display->cacheline_size); - *display_wm = entries + display->guard_size; - - /* calculate the self-refresh watermark for display cursor */ - entries = line_count * pixel_size * 64; - entries = howmany(entries, cursor->cacheline_size); - *cursor_wm = entries + cursor->guard_size; - - return g4x_check_srwm(dev, - *display_wm, *cursor_wm, - display, cursor); -} - -#define single_plane_enabled(mask) ((mask) != 0 && powerof2(mask)) - -static void g4x_update_wm(struct drm_device *dev) -{ - static const int sr_latency_ns = 12000; - struct drm_i915_private *dev_priv = dev->dev_private; - int planea_wm, planeb_wm, cursora_wm, cursorb_wm; - int plane_sr, cursor_sr; - unsigned int enabled = 0; - - if (g4x_compute_wm0(dev, 0, - &g4x_wm_info, latency_ns, - &g4x_cursor_wm_info, latency_ns, - &planea_wm, &cursora_wm)) - enabled |= 1; - - if (g4x_compute_wm0(dev, 1, - &g4x_wm_info, latency_ns, - &g4x_cursor_wm_info, latency_ns, - &planeb_wm, &cursorb_wm)) - enabled |= 2; - - plane_sr = cursor_sr = 0; - if (single_plane_enabled(enabled) && - g4x_compute_srwm(dev, ffs(enabled) - 1, - sr_latency_ns, - &g4x_wm_info, - &g4x_cursor_wm_info, - &plane_sr, &cursor_sr)) - I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN); - else - I915_WRITE(FW_BLC_SELF, - I915_READ(FW_BLC_SELF) & ~FW_BLC_SELF_EN); - - DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n", - planea_wm, cursora_wm, - planeb_wm, cursorb_wm, - plane_sr, cursor_sr); - - I915_WRITE(DSPFW1, - (plane_sr << DSPFW_SR_SHIFT) | - (cursorb_wm << DSPFW_CURSORB_SHIFT) | - (planeb_wm << DSPFW_PLANEB_SHIFT) | - planea_wm); - I915_WRITE(DSPFW2, - (I915_READ(DSPFW2) & DSPFW_CURSORA_MASK) | - (cursora_wm << DSPFW_CURSORA_SHIFT)); - /* HPLL off in SR has some issues on G4x... disable it */ - I915_WRITE(DSPFW3, - (I915_READ(DSPFW3) & ~DSPFW_HPLL_SR_EN) | - (cursor_sr << DSPFW_CURSOR_SR_SHIFT)); -} - -static void i965_update_wm(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc; - int srwm = 1; - int cursor_sr = 16; - - /* Calc sr entries for one plane configs */ - crtc = single_enabled_crtc(dev); - if (crtc) { - /* self-refresh has much higher latency */ - static const int sr_latency_ns = 12000; - int clock = crtc->mode.clock; - int htotal = crtc->mode.htotal; - int hdisplay = crtc->mode.hdisplay; - int pixel_size = crtc->fb->bits_per_pixel / 8; - unsigned long line_time_us; - int entries; - - line_time_us = ((htotal * 1000) / clock); - - /* Use ns/us then divide to preserve precision */ - entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * - pixel_size * hdisplay; - entries = howmany(entries, I915_FIFO_LINE_SIZE); - srwm = I965_FIFO_SIZE - entries; - if (srwm < 0) - srwm = 1; - srwm &= 0x1ff; - DRM_DEBUG_KMS("self-refresh entries: %d, wm: %d\n", - entries, srwm); - - entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * - pixel_size * 64; - entries = howmany(entries, i965_cursor_wm_info.cacheline_size); - cursor_sr = i965_cursor_wm_info.fifo_size - - (entries + i965_cursor_wm_info.guard_size); - - if (cursor_sr > i965_cursor_wm_info.max_wm) - cursor_sr = i965_cursor_wm_info.max_wm; - - DRM_DEBUG_KMS("self-refresh watermark: display plane %d " - "cursor %d\n", srwm, cursor_sr); - - if (IS_CRESTLINE(dev)) - I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN); - } else { - /* Turn off self refresh if both pipes are enabled */ - if (IS_CRESTLINE(dev)) - I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF) - & ~FW_BLC_SELF_EN); - } - - DRM_DEBUG_KMS("Setting FIFO watermarks - A: 8, B: 8, C: 8, SR %d\n", - srwm); - - /* 965 has limitations... */ - I915_WRITE(DSPFW1, (srwm << DSPFW_SR_SHIFT) | - (8 << 16) | (8 << 8) | (8 << 0)); - I915_WRITE(DSPFW2, (8 << 8) | (8 << 0)); - /* update cursor SR watermark */ - I915_WRITE(DSPFW3, (cursor_sr << DSPFW_CURSOR_SR_SHIFT)); -} - -static void i9xx_update_wm(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - const struct intel_watermark_params *wm_info; - uint32_t fwater_lo; - uint32_t fwater_hi; - int cwm, srwm = 1; - int fifo_size; - int planea_wm, planeb_wm; - struct drm_crtc *crtc, *enabled = NULL; - - if (IS_I945GM(dev)) - wm_info = &i945_wm_info; - else if (!IS_GEN2(dev)) - wm_info = &i915_wm_info; - else - wm_info = &i855_wm_info; - - fifo_size = dev_priv->display.get_fifo_size(dev, 0); - crtc = intel_get_crtc_for_plane(dev, 0); - if (crtc->enabled && crtc->fb) { - planea_wm = intel_calculate_wm(crtc->mode.clock, - wm_info, fifo_size, - crtc->fb->bits_per_pixel / 8, - latency_ns); - enabled = crtc; - } else - planea_wm = fifo_size - wm_info->guard_size; - - fifo_size = dev_priv->display.get_fifo_size(dev, 1); - crtc = intel_get_crtc_for_plane(dev, 1); - if (crtc->enabled && crtc->fb) { - planeb_wm = intel_calculate_wm(crtc->mode.clock, - wm_info, fifo_size, - crtc->fb->bits_per_pixel / 8, - latency_ns); - if (enabled == NULL) - enabled = crtc; - else - enabled = NULL; - } else - planeb_wm = fifo_size - wm_info->guard_size; - - DRM_DEBUG_KMS("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm); - - /* - * Overlay gets an aggressive default since video jitter is bad. - */ - cwm = 2; - - /* Play safe and disable self-refresh before adjusting watermarks. */ - if (IS_I945G(dev) || IS_I945GM(dev)) - I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | 0); - else if (IS_I915GM(dev)) - I915_WRITE(INSTPM, I915_READ(INSTPM) & ~INSTPM_SELF_EN); - - /* Calc sr entries for one plane configs */ - if (HAS_FW_BLC(dev) && enabled) { - /* self-refresh has much higher latency */ - static const int sr_latency_ns = 6000; - int clock = enabled->mode.clock; - int htotal = enabled->mode.htotal; - int hdisplay = enabled->mode.hdisplay; - int pixel_size = enabled->fb->bits_per_pixel / 8; - unsigned long line_time_us; - int entries; - - line_time_us = (htotal * 1000) / clock; - - /* Use ns/us then divide to preserve precision */ - entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * - pixel_size * hdisplay; - entries = howmany(entries, wm_info->cacheline_size); - DRM_DEBUG_KMS("self-refresh entries: %d\n", entries); - srwm = wm_info->fifo_size - entries; - if (srwm < 0) - srwm = 1; - - if (IS_I945G(dev) || IS_I945GM(dev)) - I915_WRITE(FW_BLC_SELF, - FW_BLC_SELF_FIFO_MASK | (srwm & 0xff)); - else if (IS_I915GM(dev)) - I915_WRITE(FW_BLC_SELF, srwm & 0x3f); - } - - DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n", - planea_wm, planeb_wm, cwm, srwm); - - fwater_lo = ((planeb_wm & 0x3f) << 16) | (planea_wm & 0x3f); - fwater_hi = (cwm & 0x1f); - - /* Set request length to 8 cachelines per fetch */ - fwater_lo = fwater_lo | (1 << 24) | (1 << 8); - fwater_hi = fwater_hi | (1 << 8); - - I915_WRITE(FW_BLC, fwater_lo); - I915_WRITE(FW_BLC2, fwater_hi); - - if (HAS_FW_BLC(dev)) { - if (enabled) { - if (IS_I945G(dev) || IS_I945GM(dev)) - I915_WRITE(FW_BLC_SELF, - FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN); - else if (IS_I915GM(dev)) - I915_WRITE(INSTPM, I915_READ(INSTPM) | INSTPM_SELF_EN); - DRM_DEBUG_KMS("memory self refresh enabled\n"); - } else - DRM_DEBUG_KMS("memory self refresh disabled\n"); - } -} - -static void i830_update_wm(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc; - uint32_t fwater_lo; - int planea_wm; - - crtc = single_enabled_crtc(dev); - if (crtc == NULL) - return; - - planea_wm = intel_calculate_wm(crtc->mode.clock, &i830_wm_info, - dev_priv->display.get_fifo_size(dev, 0), - crtc->fb->bits_per_pixel / 8, - latency_ns); - fwater_lo = I915_READ(FW_BLC) & ~0xfff; - fwater_lo |= (3<<8) | planea_wm; - - DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d\n", planea_wm); - - I915_WRITE(FW_BLC, fwater_lo); -} - -#define ILK_LP0_PLANE_LATENCY 700 -#define ILK_LP0_CURSOR_LATENCY 1300 - -/* - * Check the wm result. - * - * If any calculated watermark values is larger than the maximum value that - * can be programmed into the associated watermark register, that watermark - * must be disabled. - */ -static bool ironlake_check_srwm(struct drm_device *dev, int level, - int fbc_wm, int display_wm, int cursor_wm, - const struct intel_watermark_params *display, - const struct intel_watermark_params *cursor) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - DRM_DEBUG_KMS("watermark %d: display plane %d, fbc lines %d," - " cursor %d\n", level, display_wm, fbc_wm, cursor_wm); - - if (fbc_wm > SNB_FBC_MAX_SRWM) { - DRM_DEBUG_KMS("fbc watermark(%d) is too large(%d), disabling wm%d+\n", - fbc_wm, SNB_FBC_MAX_SRWM, level); - - /* fbc has it's own way to disable FBC WM */ - I915_WRITE(DISP_ARB_CTL, - I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS); - return false; - } - - if (display_wm > display->max_wm) { - DRM_DEBUG_KMS("display watermark(%d) is too large(%d), disabling wm%d+\n", - display_wm, SNB_DISPLAY_MAX_SRWM, level); - return false; - } - - if (cursor_wm > cursor->max_wm) { - DRM_DEBUG_KMS("cursor watermark(%d) is too large(%d), disabling wm%d+\n", - cursor_wm, SNB_CURSOR_MAX_SRWM, level); - return false; - } - - if (!(fbc_wm || display_wm || cursor_wm)) { - DRM_DEBUG_KMS("latency %d is 0, disabling wm%d+\n", level, level); - return false; - } - - return true; -} - -/* - * Compute watermark values of WM[1-3], - */ -static bool ironlake_compute_srwm(struct drm_device *dev, int level, int plane, - int latency_ns, - const struct intel_watermark_params *display, - const struct intel_watermark_params *cursor, - int *fbc_wm, int *display_wm, int *cursor_wm) -{ - struct drm_crtc *crtc; - unsigned long line_time_us; - int hdisplay, htotal, pixel_size, clock; - int line_count, line_size; - int small, large; - int entries; - - if (!latency_ns) { - *fbc_wm = *display_wm = *cursor_wm = 0; - return false; - } - - crtc = intel_get_crtc_for_plane(dev, plane); - hdisplay = crtc->mode.hdisplay; - htotal = crtc->mode.htotal; - clock = crtc->mode.clock; - pixel_size = crtc->fb->bits_per_pixel / 8; - - line_time_us = (htotal * 1000) / clock; - line_count = (latency_ns / line_time_us + 1000) / 1000; - line_size = hdisplay * pixel_size; - - /* Use the minimum of the small and large buffer method for primary */ - small = ((clock * pixel_size / 1000) * latency_ns) / 1000; - large = line_count * line_size; - - entries = howmany(min(small, large), display->cacheline_size); - *display_wm = entries + display->guard_size; - - /* - * Spec says: - * FBC WM = ((Final Primary WM * 64) / number of bytes per line) + 2 - */ - *fbc_wm = howmany(*display_wm * 64, line_size) + 2; - - /* calculate the self-refresh watermark for display cursor */ - entries = line_count * pixel_size * 64; - entries = howmany(entries, cursor->cacheline_size); - *cursor_wm = entries + cursor->guard_size; - - return ironlake_check_srwm(dev, level, - *fbc_wm, *display_wm, *cursor_wm, - display, cursor); -} - -static void ironlake_update_wm(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int fbc_wm, plane_wm, cursor_wm; - unsigned int enabled; - - enabled = 0; - if (g4x_compute_wm0(dev, 0, - &ironlake_display_wm_info, - ILK_LP0_PLANE_LATENCY, - &ironlake_cursor_wm_info, - ILK_LP0_CURSOR_LATENCY, - &plane_wm, &cursor_wm)) { - I915_WRITE(WM0_PIPEA_ILK, - (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm); - DRM_DEBUG_KMS("FIFO watermarks For pipe A -" - " plane %d, " "cursor: %d\n", - plane_wm, cursor_wm); - enabled |= 1; - } - - if (g4x_compute_wm0(dev, 1, - &ironlake_display_wm_info, - ILK_LP0_PLANE_LATENCY, - &ironlake_cursor_wm_info, - ILK_LP0_CURSOR_LATENCY, - &plane_wm, &cursor_wm)) { - I915_WRITE(WM0_PIPEB_ILK, - (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm); - DRM_DEBUG_KMS("FIFO watermarks For pipe B -" - " plane %d, cursor: %d\n", - plane_wm, cursor_wm); - enabled |= 2; - } - - /* - * Calculate and update the self-refresh watermark only when one - * display plane is used. - */ - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); - - if (!single_plane_enabled(enabled)) - return; - enabled = ffs(enabled) - 1; - - /* WM1 */ - if (!ironlake_compute_srwm(dev, 1, enabled, - ILK_READ_WM1_LATENCY() * 500, - &ironlake_display_srwm_info, - &ironlake_cursor_srwm_info, - &fbc_wm, &plane_wm, &cursor_wm)) - return; - - I915_WRITE(WM1_LP_ILK, - WM1_LP_SR_EN | - (ILK_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) | - (fbc_wm << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); - - /* WM2 */ - if (!ironlake_compute_srwm(dev, 2, enabled, - ILK_READ_WM2_LATENCY() * 500, - &ironlake_display_srwm_info, - &ironlake_cursor_srwm_info, - &fbc_wm, &plane_wm, &cursor_wm)) - return; - - I915_WRITE(WM2_LP_ILK, - WM2_LP_EN | - (ILK_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) | - (fbc_wm << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); - - /* - * WM3 is unsupported on ILK, probably because we don't have latency - * data for that power state - */ -} - -void sandybridge_update_wm(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */ - u32 val; - int fbc_wm, plane_wm, cursor_wm; - unsigned int enabled; - - enabled = 0; - if (g4x_compute_wm0(dev, 0, - &sandybridge_display_wm_info, latency, - &sandybridge_cursor_wm_info, latency, - &plane_wm, &cursor_wm)) { - val = I915_READ(WM0_PIPEA_ILK); - val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); - I915_WRITE(WM0_PIPEA_ILK, val | - ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm)); - DRM_DEBUG_KMS("FIFO watermarks For pipe A -" - " plane %d, " "cursor: %d\n", - plane_wm, cursor_wm); - enabled |= 1; - } - - if (g4x_compute_wm0(dev, 1, - &sandybridge_display_wm_info, latency, - &sandybridge_cursor_wm_info, latency, - &plane_wm, &cursor_wm)) { - val = I915_READ(WM0_PIPEB_ILK); - val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); - I915_WRITE(WM0_PIPEB_ILK, val | - ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm)); - DRM_DEBUG_KMS("FIFO watermarks For pipe B -" - " plane %d, cursor: %d\n", - plane_wm, cursor_wm); - enabled |= 2; - } - - /* IVB has 3 pipes */ - if (IS_IVYBRIDGE(dev) && - g4x_compute_wm0(dev, 2, - &sandybridge_display_wm_info, latency, - &sandybridge_cursor_wm_info, latency, - &plane_wm, &cursor_wm)) { - val = I915_READ(WM0_PIPEC_IVB); - val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); - I915_WRITE(WM0_PIPEC_IVB, val | - ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm)); - DRM_DEBUG_KMS("FIFO watermarks For pipe C -" - " plane %d, cursor: %d\n", - plane_wm, cursor_wm); - enabled |= 3; - } - - /* - * Calculate and update the self-refresh watermark only when one - * display plane is used. - * - * SNB support 3 levels of watermark. - * - * WM1/WM2/WM2 watermarks have to be enabled in the ascending order, - * and disabled in the descending order - * - */ - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); - - if (!single_plane_enabled(enabled) || - dev_priv->sprite_scaling_enabled) - return; - enabled = ffs(enabled) - 1; - - /* WM1 */ - if (!ironlake_compute_srwm(dev, 1, enabled, - SNB_READ_WM1_LATENCY() * 500, - &sandybridge_display_srwm_info, - &sandybridge_cursor_srwm_info, - &fbc_wm, &plane_wm, &cursor_wm)) - return; - - I915_WRITE(WM1_LP_ILK, - WM1_LP_SR_EN | - (SNB_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) | - (fbc_wm << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); - - /* WM2 */ - if (!ironlake_compute_srwm(dev, 2, enabled, - SNB_READ_WM2_LATENCY() * 500, - &sandybridge_display_srwm_info, - &sandybridge_cursor_srwm_info, - &fbc_wm, &plane_wm, &cursor_wm)) - return; - - I915_WRITE(WM2_LP_ILK, - WM2_LP_EN | - (SNB_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) | - (fbc_wm << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); - - /* WM3 */ - if (!ironlake_compute_srwm(dev, 3, enabled, - SNB_READ_WM3_LATENCY() * 500, - &sandybridge_display_srwm_info, - &sandybridge_cursor_srwm_info, - &fbc_wm, &plane_wm, &cursor_wm)) - return; - - I915_WRITE(WM3_LP_ILK, - WM3_LP_EN | - (SNB_READ_WM3_LATENCY() << WM1_LP_LATENCY_SHIFT) | - (fbc_wm << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); -} - -static bool -sandybridge_compute_sprite_wm(struct drm_device *dev, int plane, - uint32_t sprite_width, int pixel_size, - const struct intel_watermark_params *display, - int display_latency_ns, int *sprite_wm) -{ - struct drm_crtc *crtc; - int clock; - int entries, tlb_miss; - - crtc = intel_get_crtc_for_plane(dev, plane); - if (crtc->fb == NULL || !crtc->enabled) { - *sprite_wm = display->guard_size; - return false; - } - - clock = crtc->mode.clock; - - /* Use the small buffer method to calculate the sprite watermark */ - entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000; - tlb_miss = display->fifo_size*display->cacheline_size - - sprite_width * 8; - if (tlb_miss > 0) - entries += tlb_miss; - entries = howmany(entries, display->cacheline_size); - *sprite_wm = entries + display->guard_size; - if (*sprite_wm > (int)display->max_wm) - *sprite_wm = display->max_wm; - - return true; -} - -static bool -sandybridge_compute_sprite_srwm(struct drm_device *dev, int plane, - uint32_t sprite_width, int pixel_size, - const struct intel_watermark_params *display, - int latency_ns, int *sprite_wm) -{ - struct drm_crtc *crtc; - unsigned long line_time_us; - int clock; - int line_count, line_size; - int small, large; - int entries; - - if (!latency_ns) { - *sprite_wm = 0; - return false; - } - - crtc = intel_get_crtc_for_plane(dev, plane); - clock = crtc->mode.clock; - if (!clock) { - *sprite_wm = 0; - return false; - } - - line_time_us = (sprite_width * 1000) / clock; - if (!line_time_us) { - *sprite_wm = 0; - return false; - } - - line_count = (latency_ns / line_time_us + 1000) / 1000; - line_size = sprite_width * pixel_size; - - /* Use the minimum of the small and large buffer method for primary */ - small = ((clock * pixel_size / 1000) * latency_ns) / 1000; - large = line_count * line_size; - - entries = howmany(min(small, large), display->cacheline_size); - *sprite_wm = entries + display->guard_size; - - return *sprite_wm > 0x3ff ? false : true; -} - -static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe, - uint32_t sprite_width, int pixel_size) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */ - u32 val; - int sprite_wm, reg; - int ret; - - switch (pipe) { - case 0: - reg = WM0_PIPEA_ILK; - break; - case 1: - reg = WM0_PIPEB_ILK; - break; - case 2: - reg = WM0_PIPEC_IVB; - break; - default: - return; /* bad pipe */ - } - - ret = sandybridge_compute_sprite_wm(dev, pipe, sprite_width, pixel_size, - &sandybridge_display_wm_info, - latency, &sprite_wm); - if (!ret) { - DRM_DEBUG_KMS("failed to compute sprite wm for pipe %d\n", - pipe); - return; - } - - val = I915_READ(reg); - val &= ~WM0_PIPE_SPRITE_MASK; - I915_WRITE(reg, val | (sprite_wm << WM0_PIPE_SPRITE_SHIFT)); - DRM_DEBUG_KMS("sprite watermarks For pipe %d - %d\n", pipe, sprite_wm); - - - ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width, - pixel_size, - &sandybridge_display_srwm_info, - SNB_READ_WM1_LATENCY() * 500, - &sprite_wm); - if (!ret) { - DRM_DEBUG_KMS("failed to compute sprite lp1 wm on pipe %d\n", - pipe); - return; - } - I915_WRITE(WM1S_LP_ILK, sprite_wm); - - /* Only IVB has two more LP watermarks for sprite */ - if (!IS_IVYBRIDGE(dev)) - return; - - ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width, - pixel_size, - &sandybridge_display_srwm_info, - SNB_READ_WM2_LATENCY() * 500, - &sprite_wm); - if (!ret) { - DRM_DEBUG_KMS("failed to compute sprite lp2 wm on pipe %d\n", - pipe); - return; - } - I915_WRITE(WM2S_LP_IVB, sprite_wm); - - ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width, - pixel_size, - &sandybridge_display_srwm_info, - SNB_READ_WM3_LATENCY() * 500, - &sprite_wm); - if (!ret) { - DRM_DEBUG_KMS("failed to compute sprite lp3 wm on pipe %d\n", - pipe); - return; - } - I915_WRITE(WM3S_LP_IVB, sprite_wm); -} - -/** - * intel_update_watermarks - update FIFO watermark values based on current modes - * - * Calculate watermark values for the various WM regs based on current mode - * and plane configuration. - * - * There are several cases to deal with here: - * - normal (i.e. non-self-refresh) - * - self-refresh (SR) mode - * - lines are large relative to FIFO size (buffer can hold up to 2) - * - lines are small relative to FIFO size (buffer can hold more than 2 - * lines), so need to account for TLB latency - * - * The normal calculation is: - * watermark = dotclock * bytes per pixel * latency - * where latency is platform & configuration dependent (we assume pessimal - * values here). - * - * The SR calculation is: - * watermark = (trunc(latency/line time)+1) * surface width * - * bytes per pixel - * where - * line time = htotal / dotclock - * surface width = hdisplay for normal plane and 64 for cursor - * and latency is assumed to be high, as above. - * - * The final value programmed to the register should always be rounded up, - * and include an extra 2 entries to account for clock crossings. - * - * We don't use the sprite, so we can ignore that. And on Crestline we have - * to set the non-SR watermarks to 8. - */ -static void intel_update_watermarks(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (dev_priv->display.update_wm) - dev_priv->display.update_wm(dev); -} - -void intel_update_sprite_watermarks(struct drm_device *dev, int pipe, - uint32_t sprite_width, int pixel_size) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (dev_priv->display.update_sprite_wm) - dev_priv->display.update_sprite_wm(dev, pipe, sprite_width, - pixel_size); -} - static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) { if (i915_panel_use_ssc >= 0) @@ -5187,6 +3803,222 @@ static void i9xx_update_pll_dividers(struct drm_crtc *crtc, } } +static void intel_update_lvds(struct drm_crtc *crtc, intel_clock_t *clock, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + u32 temp; + + temp = I915_READ(LVDS); + temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; + if (pipe == 1) { + temp |= LVDS_PIPEB_SELECT; + } else { + temp &= ~LVDS_PIPEB_SELECT; + } + /* set the corresponsding LVDS_BORDER bit */ + temp |= dev_priv->lvds_border_bits; + /* Set the B0-B3 data pairs corresponding to whether we're going to + * set the DPLLs for dual-channel mode or not. + */ + if (clock->p2 == 7) + temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; + else + temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); + + /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) + * appropriately here, but we need to look more thoroughly into how + * panels behave in the two modes. + */ + /* set the dithering flag on LVDS as needed */ + if (INTEL_INFO(dev)->gen >= 4) { + if (dev_priv->lvds_dither) + temp |= LVDS_ENABLE_DITHER; + else + temp &= ~LVDS_ENABLE_DITHER; + } + temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY); + if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) + temp |= LVDS_HSYNC_POLARITY; + if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) + temp |= LVDS_VSYNC_POLARITY; + I915_WRITE(LVDS, temp); +} + +static void i9xx_update_pll(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + intel_clock_t *clock, intel_clock_t *reduced_clock, + int num_connectors) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + u32 dpll; + bool is_sdvo; + + is_sdvo = intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO) || + intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI); + + dpll = DPLL_VGA_MODE_DIS; + + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) + dpll |= DPLLB_MODE_LVDS; + else + dpll |= DPLLB_MODE_DAC_SERIAL; + if (is_sdvo) { + int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); + if (pixel_multiplier > 1) { + if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) + dpll |= (pixel_multiplier - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; + } + dpll |= DPLL_DVO_HIGH_SPEED; + } + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) + dpll |= DPLL_DVO_HIGH_SPEED; + + /* compute bitmask from p1 value */ + if (IS_PINEVIEW(dev)) + dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW; + else { + dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; + if (IS_G4X(dev) && reduced_clock) + dpll |= (1 << (reduced_clock->p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT; + } + switch (clock->p2) { + case 5: + dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5; + break; + case 7: + dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7; + break; + case 10: + dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10; + break; + case 14: + dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14; + break; + } + if (INTEL_INFO(dev)->gen >= 4) + dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT); + + if (is_sdvo && intel_pipe_has_type(crtc, INTEL_OUTPUT_TVOUT)) + dpll |= PLL_REF_INPUT_TVCLKINBC; + else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_TVOUT)) + /* XXX: just matching BIOS for now */ + /* dpll |= PLL_REF_INPUT_TVCLKINBC; */ + dpll |= 3; + else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && + intel_panel_use_ssc(dev_priv) && num_connectors < 2) + dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN; + else + dpll |= PLL_REF_INPUT_DREFCLK; + + dpll |= DPLL_VCO_ENABLE; + I915_WRITE(DPLL(pipe), dpll & ~DPLL_VCO_ENABLE); + POSTING_READ(DPLL(pipe)); + DELAY(150); + + /* The LVDS pin pair needs to be on before the DPLLs are enabled. + * This is an exception to the general rule that mode_set doesn't turn + * things on. + */ + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) + intel_update_lvds(crtc, clock, adjusted_mode); + + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) + intel_dp_set_m_n(crtc, mode, adjusted_mode); + + I915_WRITE(DPLL(pipe), dpll); + + /* Wait for the clocks to stabilize. */ + POSTING_READ(DPLL(pipe)); + DELAY(150); + + if (INTEL_INFO(dev)->gen >= 4) { + u32 temp = 0; + if (is_sdvo) { + temp = intel_mode_get_pixel_multiplier(adjusted_mode); + if (temp > 1) + temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT; + else + temp = 0; + } + I915_WRITE(DPLL_MD(pipe), temp); + } else { + /* The pixel multiplier can only be updated once the + * DPLL is enabled and the clocks are stable. + * + * So write it again. + */ + I915_WRITE(DPLL(pipe), dpll); + } +} + +static void i8xx_update_pll(struct drm_crtc *crtc, + struct drm_display_mode *adjusted_mode, + intel_clock_t *clock, + int num_connectors) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + u32 dpll; + + dpll = DPLL_VGA_MODE_DIS; + + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { + dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; + } else { + if (clock->p1 == 2) + dpll |= PLL_P1_DIVIDE_BY_TWO; + else + dpll |= (clock->p1 - 2) << DPLL_FPA01_P1_POST_DIV_SHIFT; + if (clock->p2 == 4) + dpll |= PLL_P2_DIVIDE_BY_4; + } + + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_TVOUT)) + /* XXX: just matching BIOS for now */ + /* dpll |= PLL_REF_INPUT_TVCLKINBC; */ + dpll |= 3; + else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && + intel_panel_use_ssc(dev_priv) && num_connectors < 2) + dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN; + else + dpll |= PLL_REF_INPUT_DREFCLK; + + dpll |= DPLL_VCO_ENABLE; + I915_WRITE(DPLL(pipe), dpll & ~DPLL_VCO_ENABLE); + POSTING_READ(DPLL(pipe)); + DELAY(150); + + I915_WRITE(DPLL(pipe), dpll); + + /* Wait for the clocks to stabilize. */ + POSTING_READ(DPLL(pipe)); + DELAY(150); + + /* The LVDS pin pair needs to be on before the DPLLs are enabled. + * This is an exception to the general rule that mode_set doesn't turn + * things on. + */ + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) + intel_update_lvds(crtc, clock, adjusted_mode); + + /* The pixel multiplier can only be updated once the + * DPLL is enabled and the clocks are stable. + * + * So write it again. + */ + I915_WRITE(DPLL(pipe), dpll); +} + static int i9xx_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -5200,15 +4032,13 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, int plane = intel_crtc->plane; int refclk, num_connectors = 0; intel_clock_t clock, reduced_clock; - u32 dpll, dspcntr, pipeconf, vsyncshift; - bool ok, has_reduced_clock = false, is_sdvo = false, is_dvo = false; - bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false; + u32 dspcntr, pipeconf, vsyncshift; + bool ok, has_reduced_clock = false, is_sdvo = false; + bool is_lvds = false, is_tv = false, is_dp = false; struct drm_mode_config *mode_config = &dev->mode_config; struct intel_encoder *encoder; const intel_limit_t *limit; int ret; - u32 temp; - u32 lvds_sync = 0; list_for_each_entry(encoder, &mode_config->encoder_list, base.head) { if (encoder->base.crtc != crtc) @@ -5224,15 +4054,9 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, if (encoder->needs_tv_clock) is_tv = true; break; - case INTEL_OUTPUT_DVO: - is_dvo = true; - break; case INTEL_OUTPUT_TVOUT: is_tv = true; break; - case INTEL_OUTPUT_ANALOG: - is_crt = true; - break; case INTEL_OUTPUT_DISPLAYPORT: is_dp = true; break; @@ -5279,71 +4103,12 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, i9xx_update_pll_dividers(crtc, &clock, has_reduced_clock ? &reduced_clock : NULL); - dpll = DPLL_VGA_MODE_DIS; - - if (!IS_GEN2(dev)) { - if (is_lvds) - dpll |= DPLLB_MODE_LVDS; - else - dpll |= DPLLB_MODE_DAC_SERIAL; - if (is_sdvo) { - int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); - if (pixel_multiplier > 1) { - if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) - dpll |= (pixel_multiplier - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; - } - dpll |= DPLL_DVO_HIGH_SPEED; - } - if (is_dp) - dpll |= DPLL_DVO_HIGH_SPEED; - - /* compute bitmask from p1 value */ - if (IS_PINEVIEW(dev)) - dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW; - else { - dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; - if (IS_G4X(dev) && has_reduced_clock) - dpll |= (1 << (reduced_clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT; - } - switch (clock.p2) { - case 5: - dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5; - break; - case 7: - dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7; - break; - case 10: - dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10; - break; - case 14: - dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14; - break; - } - if (INTEL_INFO(dev)->gen >= 4) - dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT); - } else { - if (is_lvds) { - dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; - } else { - if (clock.p1 == 2) - dpll |= PLL_P1_DIVIDE_BY_TWO; - else - dpll |= (clock.p1 - 2) << DPLL_FPA01_P1_POST_DIV_SHIFT; - if (clock.p2 == 4) - dpll |= PLL_P2_DIVIDE_BY_4; - } - } - - if (is_sdvo && is_tv) - dpll |= PLL_REF_INPUT_TVCLKINBC; - else if (is_tv) - /* XXX: just matching BIOS for now */ - /* dpll |= PLL_REF_INPUT_TVCLKINBC; */ - dpll |= 3; - else if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) - dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN; + if (IS_GEN2(dev)) + i8xx_update_pll(crtc, adjusted_mode, &clock, num_connectors); else - dpll |= PLL_REF_INPUT_DREFCLK; + i9xx_update_pll(crtc, mode, adjusted_mode, &clock, + has_reduced_clock ? &reduced_clock : NULL, + num_connectors); /* setup pipeconf */ pipeconf = I915_READ(PIPECONF(pipe)); @@ -5380,97 +4145,9 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, } } - dpll |= DPLL_VCO_ENABLE; - DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); drm_mode_debug_printmodeline(mode); - I915_WRITE(DPLL(pipe), dpll & ~DPLL_VCO_ENABLE); - - POSTING_READ(DPLL(pipe)); - DELAY(150); - - /* The LVDS pin pair needs to be on before the DPLLs are enabled. - * This is an exception to the general rule that mode_set doesn't turn - * things on. - */ - if (is_lvds) { - temp = I915_READ(LVDS); - temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; - if (pipe == 1) { - temp |= LVDS_PIPEB_SELECT; - } else { - temp &= ~LVDS_PIPEB_SELECT; - } - /* set the corresponsding LVDS_BORDER bit */ - temp |= dev_priv->lvds_border_bits; - /* Set the B0-B3 data pairs corresponding to whether we're going to - * set the DPLLs for dual-channel mode or not. - */ - if (clock.p2 == 7) - temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; - else - temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); - - /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) - * appropriately here, but we need to look more thoroughly into how - * panels behave in the two modes. - */ - /* set the dithering flag on LVDS as needed */ - if (INTEL_INFO(dev)->gen >= 4) { - if (dev_priv->lvds_dither) - temp |= LVDS_ENABLE_DITHER; - else - temp &= ~LVDS_ENABLE_DITHER; - } - if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) - lvds_sync |= LVDS_HSYNC_POLARITY; - if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) - lvds_sync |= LVDS_VSYNC_POLARITY; - if ((temp & (LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY)) - != lvds_sync) { - char flags[2] = "-+"; - DRM_INFO("Changing LVDS panel from " - "(%chsync, %cvsync) to (%chsync, %cvsync)\n", - flags[!(temp & LVDS_HSYNC_POLARITY)], - flags[!(temp & LVDS_VSYNC_POLARITY)], - flags[!(lvds_sync & LVDS_HSYNC_POLARITY)], - flags[!(lvds_sync & LVDS_VSYNC_POLARITY)]); - temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY); - temp |= lvds_sync; - } - I915_WRITE(LVDS, temp); - } - - if (is_dp) { - intel_dp_set_m_n(crtc, mode, adjusted_mode); - } - - I915_WRITE(DPLL(pipe), dpll); - - /* Wait for the clocks to stabilize. */ - POSTING_READ(DPLL(pipe)); - DELAY(150); - - if (INTEL_INFO(dev)->gen >= 4) { - temp = 0; - if (is_sdvo) { - temp = intel_mode_get_pixel_multiplier(adjusted_mode); - if (temp > 1) - temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT; - else - temp = 0; - } - I915_WRITE(DPLL_MD(pipe), temp); - } else { - /* The pixel multiplier can only be updated once the - * DPLL is enabled and the clocks are stable. - * - * So write it again. - */ - I915_WRITE(DPLL(pipe), dpll); - } - if (HAS_PIPE_CXSR(dev)) { if (intel_crtc->lowfreq_avail) { DRM_DEBUG_KMS("enabling CxSR downclocking\n"); @@ -5536,7 +4213,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(DSPCNTR(plane), dspcntr); POSTING_READ(DSPCNTR(plane)); - intel_enable_plane(dev_priv, plane, pipe); ret = intel_pipe_set_base(crtc, x, y, old_fb); @@ -5712,17 +4388,16 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf; bool ok, has_reduced_clock = false, is_sdvo = false; bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false; - struct intel_encoder *has_edp_encoder = NULL; struct drm_mode_config *mode_config = &dev->mode_config; - struct intel_encoder *encoder; + struct intel_encoder *encoder, *edp_encoder = NULL; const intel_limit_t *limit; int ret; struct fdi_m_n m_n = {0}; u32 temp; - u32 lvds_sync = 0; int target_clock, pixel_multiplier, lane, link_bw, factor; unsigned int pipe_bpp; bool dither; + bool is_cpu_edp = false, is_pch_edp = false; list_for_each_entry(encoder, &mode_config->encoder_list, base.head) { if (encoder->base.crtc != crtc) @@ -5748,7 +4423,12 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, is_dp = true; break; case INTEL_OUTPUT_EDP: - has_edp_encoder = encoder; + is_dp = true; + if (intel_encoder_is_pch_edp(&encoder->base)) + is_pch_edp = true; + else + is_cpu_edp = true; + edp_encoder = encoder; break; } @@ -5811,15 +4491,13 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, lane = 0; /* CPU eDP doesn't require FDI link, so just set DP M/N according to current link config */ - if (has_edp_encoder && - !intel_encoder_is_pch_edp(&has_edp_encoder->base)) { + if (is_cpu_edp) { target_clock = mode->clock; - intel_edp_link_config(has_edp_encoder, - &lane, &link_bw); + intel_edp_link_config(edp_encoder, &lane, &link_bw); } else { /* [e]DP over FDI requires target mode clock instead of link clock */ - if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base)) + if (is_dp) target_clock = mode->clock; else target_clock = adjusted_mode->clock; @@ -5910,7 +4588,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, } dpll |= DPLL_DVO_HIGH_SPEED; } - if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base)) + if (is_dp && !is_cpu_edp) dpll |= DPLL_DVO_HIGH_SPEED; /* compute bitmask from p1 value */ @@ -5949,34 +4627,25 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, /* Set up the display plane register */ dspcntr = DISPPLANE_GAMMA_ENABLE; - DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe); drm_mode_debug_printmodeline(mode); - /* PCH eDP needs FDI, but CPU eDP does not */ - if (!intel_crtc->no_pll) { - if (!has_edp_encoder || - intel_encoder_is_pch_edp(&has_edp_encoder->base)) { - I915_WRITE(PCH_FP0(pipe), fp); - I915_WRITE(PCH_DPLL(pipe), dpll & ~DPLL_VCO_ENABLE); + /* CPU eDP is the only output that doesn't need a PCH PLL of its own on + * pre-Haswell/LPT generation */ + if (HAS_PCH_LPT(dev)) { + DRM_DEBUG_KMS("LPT detected: no PLL for pipe %d necessary\n", + pipe); + } else if (!is_cpu_edp) { + struct intel_pch_pll *pll; - POSTING_READ(PCH_DPLL(pipe)); - DELAY(150); - } - } else { - if (dpll == (I915_READ(PCH_DPLL(0)) & 0x7fffffff) && - fp == I915_READ(PCH_FP0(0))) { - intel_crtc->use_pll_a = true; - DRM_DEBUG_KMS("using pipe a dpll\n"); - } else if (dpll == (I915_READ(PCH_DPLL(1)) & 0x7fffffff) && - fp == I915_READ(PCH_FP0(1))) { - intel_crtc->use_pll_a = false; - DRM_DEBUG_KMS("using pipe b dpll\n"); - } else { - DRM_DEBUG_KMS("no matching PLL configuration for pipe 2\n"); - return -EINVAL; - } - } + pll = intel_get_pch_pll(intel_crtc, dpll, fp); + if (pll == NULL) { + DRM_DEBUG_DRIVER("failed to find PLL for pipe %d\n", + pipe); + return -EINVAL; + } + } else + intel_put_pch_pll(intel_crtc); /* The LVDS pin pair needs to be on before the DPLLs are enabled. * This is an exception to the general rule that mode_set doesn't turn @@ -6009,22 +4678,11 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, * appropriately here, but we need to look more thoroughly into how * panels behave in the two modes. */ + temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY); if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) - lvds_sync |= LVDS_HSYNC_POLARITY; + temp |= LVDS_HSYNC_POLARITY; if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) - lvds_sync |= LVDS_VSYNC_POLARITY; - if ((temp & (LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY)) - != lvds_sync) { - char flags[2] = "-+"; - DRM_INFO("Changing LVDS panel from " - "(%chsync, %cvsync) to (%chsync, %cvsync)\n", - flags[!(temp & LVDS_HSYNC_POLARITY)], - flags[!(temp & LVDS_VSYNC_POLARITY)], - flags[!(lvds_sync & LVDS_HSYNC_POLARITY)], - flags[!(lvds_sync & LVDS_VSYNC_POLARITY)]); - temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY); - temp |= lvds_sync; - } + temp |= LVDS_VSYNC_POLARITY; I915_WRITE(PCH_LVDS, temp); } @@ -6034,7 +4692,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, pipeconf |= PIPECONF_DITHER_EN; pipeconf |= PIPECONF_DITHER_TYPE_SP; } - if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base)) { + if (is_dp && !is_cpu_edp) { intel_dp_set_m_n(crtc, mode, adjusted_mode); } else { /* For non-DP output, clear any trans DP clock recovery setting.*/ @@ -6044,13 +4702,11 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(TRANSDPLINK_N1(pipe), 0); } - if (!intel_crtc->no_pll && - (!has_edp_encoder || - intel_encoder_is_pch_edp(&has_edp_encoder->base))) { - I915_WRITE(PCH_DPLL(pipe), dpll); + if (intel_crtc->pch_pll) { + I915_WRITE(intel_crtc->pch_pll->pll_reg, dpll); /* Wait for the clocks to stabilize. */ - POSTING_READ(PCH_DPLL(pipe)); + POSTING_READ(intel_crtc->pch_pll->pll_reg); DELAY(150); /* The pixel multiplier can only be updated once the @@ -6058,20 +4714,20 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, * * So write it again. */ - I915_WRITE(PCH_DPLL(pipe), dpll); + I915_WRITE(intel_crtc->pch_pll->pll_reg, dpll); } intel_crtc->lowfreq_avail = false; - if (!intel_crtc->no_pll) { + if (intel_crtc->pch_pll) { if (is_lvds && has_reduced_clock && i915_powersave) { - I915_WRITE(PCH_FP1(pipe), fp2); + I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp2); intel_crtc->lowfreq_avail = true; if (HAS_PIPE_CXSR(dev)) { DRM_DEBUG_KMS("enabling CxSR downclocking\n"); pipeconf |= PIPECONF_CXSR_DOWNCLOCK; } } else { - I915_WRITE(PCH_FP1(pipe), fp); + I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp); if (HAS_PIPE_CXSR(dev)) { DRM_DEBUG_KMS("disabling CxSR downclocking\n"); pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK; @@ -6124,10 +4780,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m); I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n); - if (has_edp_encoder && - !intel_encoder_is_pch_edp(&has_edp_encoder->base)) { + if (is_cpu_edp) ironlake_set_pll_edp(crtc, adjusted_mode->clock); - } I915_WRITE(PIPECONF(pipe), pipeconf); POSTING_READ(PIPECONF(pipe)); @@ -6141,6 +4795,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, intel_update_watermarks(dev); + intel_update_linetime_watermarks(dev, pipe, adjusted_mode); + return ret; } @@ -6499,7 +5155,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc, if (!visible && !intel_crtc->cursor_visible) return; - if (IS_IVYBRIDGE(dev)) { + if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) { I915_WRITE(CURPOS_IVB(pipe), pos); ivb_update_cursor(crtc, base); } else { @@ -6509,9 +5165,6 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc, else i9xx_update_cursor(crtc, base); } - - if (visible) - intel_mark_busy(dev, to_intel_framebuffer(crtc->fb)->obj); } static int intel_crtc_cursor_set(struct drm_crtc *crtc, @@ -6596,7 +5249,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, if (intel_crtc->cursor_bo != obj) i915_gem_detach_phys_object(dev, intel_crtc->cursor_bo); } else - i915_gem_object_unpin(intel_crtc->cursor_bo); + i915_gem_object_unpin_from_display_plane(intel_crtc->cursor_bo); drm_gem_object_unreference(&intel_crtc->cursor_bo->base); } @@ -6611,7 +5264,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, return 0; fail_unpin: - i915_gem_object_unpin(obj); + i915_gem_object_unpin_from_display_plane(obj); fail_locked: DRM_UNLOCK(dev); fail: @@ -7039,7 +5692,6 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, mode->vsync_end = ((vsync & 0xffff0000) >> 16) + 1; drm_mode_set_name(mode); - drm_mode_set_crtcinfo(mode, 0); return mode; } @@ -7206,12 +5858,16 @@ void intel_mark_busy(struct drm_device *dev, struct drm_i915_gem_object *obj) if (!drm_core_check_feature(dev, DRIVER_MODESET)) return; - if (!dev_priv->busy) + if (!dev_priv->busy) { + intel_sanitize_pm(dev); dev_priv->busy = true; - else + } else callout_reset(&dev_priv->idle_callout, GPU_IDLE_TIMEOUT, intel_gpu_idle_timer, dev); + if (obj == NULL) + return; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (!crtc->fb) continue; @@ -7384,18 +6040,19 @@ static int intel_gen2_queue_flip(struct drm_device *dev, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); unsigned long offset; u32 flip_mask; + struct intel_ring_buffer *ring = &dev_priv->rings[RCS]; int ret; - ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv)); + ret = intel_pin_and_fence_fb_obj(dev, obj, ring); if (ret) - goto out; + goto err; /* Offset into the new buffer for cases of shared fbs between CRTCs */ offset = crtc->y * fb->pitches[0] + crtc->x * fb->bits_per_pixel/8; - ret = BEGIN_LP_RING(6); + ret = intel_ring_begin(ring, 6); if (ret) - goto out; + goto err_unpin; /* Can't queue multiple flips, so wait for the previous * one to finish before executing the next. @@ -7404,15 +6061,19 @@ static int intel_gen2_queue_flip(struct drm_device *dev, flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; else flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; - OUT_RING(MI_WAIT_FOR_EVENT | flip_mask); - OUT_RING(MI_NOOP); - OUT_RING(MI_DISPLAY_FLIP | - MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); - OUT_RING(fb->pitches[0]); - OUT_RING(obj->gtt_offset + offset); - OUT_RING(0); /* aux display base address, unused */ - ADVANCE_LP_RING(); -out: + intel_ring_emit(ring, MI_WAIT_FOR_EVENT | flip_mask); + intel_ring_emit(ring, MI_NOOP); + intel_ring_emit(ring, MI_DISPLAY_FLIP | + MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); + intel_ring_emit(ring, fb->pitches[0]); + intel_ring_emit(ring, obj->gtt_offset + offset); + intel_ring_emit(ring, 0); /* aux display base address, unused */ + intel_ring_advance(ring); + return 0; + +err_unpin: + intel_unpin_fb_obj(obj); +err: return ret; } @@ -7425,33 +6086,38 @@ static int intel_gen3_queue_flip(struct drm_device *dev, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); unsigned long offset; u32 flip_mask; + struct intel_ring_buffer *ring = &dev_priv->rings[RCS]; int ret; - ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv)); + ret = intel_pin_and_fence_fb_obj(dev, obj, ring); if (ret) - goto out; + goto err; /* Offset into the new buffer for cases of shared fbs between CRTCs */ offset = crtc->y * fb->pitches[0] + crtc->x * fb->bits_per_pixel/8; - ret = BEGIN_LP_RING(6); + ret = intel_ring_begin(ring, 6); if (ret) - goto out; + goto err_unpin; if (intel_crtc->plane) flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; else flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; - OUT_RING(MI_WAIT_FOR_EVENT | flip_mask); - OUT_RING(MI_NOOP); - OUT_RING(MI_DISPLAY_FLIP_I915 | - MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); - OUT_RING(fb->pitches[0]); - OUT_RING(obj->gtt_offset + offset); - OUT_RING(MI_NOOP); + intel_ring_emit(ring, MI_WAIT_FOR_EVENT | flip_mask); + intel_ring_emit(ring, MI_NOOP); + intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | + MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); + intel_ring_emit(ring, fb->pitches[0]); + intel_ring_emit(ring, obj->gtt_offset + offset); + intel_ring_emit(ring, MI_NOOP); - ADVANCE_LP_RING(); -out: + intel_ring_advance(ring); + return 0; + +err_unpin: + intel_unpin_fb_obj(obj); +err: return ret; } @@ -7463,24 +6129,25 @@ static int intel_gen4_queue_flip(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); uint32_t pf, pipesrc; + struct intel_ring_buffer *ring = &dev_priv->rings[RCS]; int ret; - ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv)); + ret = intel_pin_and_fence_fb_obj(dev, obj, ring); if (ret) - goto out; + goto err; - ret = BEGIN_LP_RING(4); + ret = intel_ring_begin(ring, 4); if (ret) - goto out; + goto err_unpin; /* i965+ uses the linear or tiled offsets from the * Display Registers (which do not change across a page-flip) * so we need only reprogram the base address. */ - OUT_RING(MI_DISPLAY_FLIP | - MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); - OUT_RING(fb->pitches[0]); - OUT_RING(obj->gtt_offset | obj->tiling_mode); + intel_ring_emit(ring, MI_DISPLAY_FLIP | + MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); + intel_ring_emit(ring, fb->pitches[0]); + intel_ring_emit(ring, obj->gtt_offset | obj->tiling_mode); /* XXX Enabling the panel-fitter across page-flip is so far * untested on non-native modes, so ignore it for now. @@ -7488,9 +6155,13 @@ static int intel_gen4_queue_flip(struct drm_device *dev, */ pf = 0; pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff; - OUT_RING(pf | pipesrc); - ADVANCE_LP_RING(); -out: + intel_ring_emit(ring, pf | pipesrc); + intel_ring_advance(ring); + return 0; + +err_unpin: + intel_unpin_fb_obj(obj); +err: return ret; } @@ -7501,21 +6172,22 @@ static int intel_gen6_queue_flip(struct drm_device *dev, { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_ring_buffer *ring = &dev_priv->rings[RCS]; uint32_t pf, pipesrc; int ret; - ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv)); + ret = intel_pin_and_fence_fb_obj(dev, obj, ring); if (ret) - goto out; + goto err; - ret = BEGIN_LP_RING(4); + ret = intel_ring_begin(ring, 4); if (ret) - goto out; + goto err_unpin; - OUT_RING(MI_DISPLAY_FLIP | - MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); - OUT_RING(fb->pitches[0] | obj->tiling_mode); - OUT_RING(obj->gtt_offset); + intel_ring_emit(ring, MI_DISPLAY_FLIP | + MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); + intel_ring_emit(ring, fb->pitches[0] | obj->tiling_mode); + intel_ring_emit(ring, obj->gtt_offset); /* Contrary to the suggestions in the documentation, * "Enable Panel Fitter" does not seem to be required when page @@ -7525,9 +6197,13 @@ static int intel_gen6_queue_flip(struct drm_device *dev, */ pf = 0; pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff; - OUT_RING(pf | pipesrc); - ADVANCE_LP_RING(); -out: + intel_ring_emit(ring, pf | pipesrc); + intel_ring_advance(ring); + return 0; + +err_unpin: + intel_unpin_fb_obj(obj); +err: return ret; } @@ -7549,18 +6225,22 @@ static int intel_gen7_queue_flip(struct drm_device *dev, ret = intel_pin_and_fence_fb_obj(dev, obj, ring); if (ret) - goto out; + goto err; ret = intel_ring_begin(ring, 4); if (ret) - goto out; + goto err_unpin; intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | (intel_crtc->plane << 19)); intel_ring_emit(ring, (fb->pitches[0] | obj->tiling_mode)); intel_ring_emit(ring, (obj->gtt_offset)); intel_ring_emit(ring, (MI_NOOP)); intel_ring_advance(ring); -out: + return 0; + +err_unpin: + intel_unpin_fb_obj(obj); +err: return ret; } @@ -7633,6 +6313,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, if (ret) goto cleanup_pending; intel_disable_fbc(dev); + intel_mark_busy(dev, obj); DRM_UNLOCK(dev); CTR2(KTR_DRM, "i915_flip_request %d %p", intel_crtc->plane, obj); @@ -7661,10 +6342,11 @@ static void intel_sanitize_modesetting(struct drm_device *dev, { struct drm_i915_private *dev_priv = dev->dev_private; u32 reg, val; + int i; /* Clear any frame start delays used for debugging left by the BIOS */ - for_each_pipe(pipe) { - reg = PIPECONF(pipe); + for_each_pipe(i) { + reg = PIPECONF(i); I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK); } @@ -7734,6 +6416,23 @@ static const struct drm_crtc_funcs intel_crtc_funcs = { .page_flip = intel_crtc_page_flip, }; +static void intel_pch_pll_init(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int i; + + if (dev_priv->num_pch_pll == 0) { + DRM_DEBUG_KMS("No PCH PLLs on this hardware, skipping initialisation\n"); + return; + } + + for (i = 0; i < dev_priv->num_pch_pll; i++) { + dev_priv->pch_plls[i].pll_reg = _PCH_DPLL(i); + dev_priv->pch_plls[i].fp0_reg = _PCH_FP0(i); + dev_priv->pch_plls[i].fp1_reg = _PCH_FP1(i); + } +} + static void intel_crtc_init(struct drm_device *dev, int pipe) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -7772,8 +6471,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) intel_crtc->bpp = 24; /* default for pre-Ironlake */ if (HAS_PCH_SPLIT(dev)) { - if (pipe == 2 && IS_IVYBRIDGE(dev)) - intel_crtc->no_pll = true; intel_helper_funcs.prepare = ironlake_crtc_prepare; intel_helper_funcs.commit = ironlake_crtc_commit; } else { @@ -7791,15 +6488,12 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, struct drm_file *file) { - drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_get_pipe_from_crtc_id *pipe_from_crtc_id = data; struct drm_mode_object *drmmode_obj; struct intel_crtc *crtc; - if (!dev_priv) { - DRM_ERROR("called with no initialization\n"); - return -EINVAL; - } + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -ENODEV; drmmode_obj = drm_mode_object_find(dev, pipe_from_crtc_id->crtc_id, DRM_MODE_OBJECT_CRTC); @@ -7872,7 +6566,26 @@ static void intel_setup_outputs(struct drm_device *dev) intel_crt_init(dev); - if (HAS_PCH_SPLIT(dev)) { + if (IS_HASWELL(dev)) { + int found; + + /* Haswell uses DDI functions to detect digital outputs */ + found = I915_READ(DDI_BUF_CTL_A) & DDI_INIT_DISPLAY_DETECTED; + /* DDI A only supports eDP */ + if (found) + intel_ddi_init(dev, PORT_A); + + /* DDI B, C and D detection is indicated by the SFUSE_STRAP + * register */ + found = I915_READ(SFUSE_STRAP); + + if (found & SFUSE_STRAP_DDIB_DETECTED) + intel_ddi_init(dev, PORT_B); + if (found & SFUSE_STRAP_DDIC_DETECTED) + intel_ddi_init(dev, PORT_C); + if (found & SFUSE_STRAP_DDID_DETECTED) + intel_ddi_init(dev, PORT_D); + } else if (HAS_PCH_SPLIT(dev)) { int found; DRM_DEBUG_KMS( @@ -7887,7 +6600,7 @@ static void intel_setup_outputs(struct drm_device *dev) if (I915_READ(HDMIB) & PORT_DETECTED) { /* PCH SDVOB multiplex with HDMIB */ - found = intel_sdvo_init(dev, PCH_SDVOB); + found = intel_sdvo_init(dev, PCH_SDVOB, true); if (!found) intel_hdmi_init(dev, HDMIB); if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED)) @@ -7911,7 +6624,7 @@ static void intel_setup_outputs(struct drm_device *dev) if (I915_READ(SDVOB) & SDVO_DETECTED) { DRM_DEBUG_KMS("probing SDVOB\n"); - found = intel_sdvo_init(dev, SDVOB); + found = intel_sdvo_init(dev, SDVOB, true); if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) { DRM_DEBUG_KMS("probing HDMI on SDVOB\n"); intel_hdmi_init(dev, SDVOB); @@ -7927,7 +6640,7 @@ static void intel_setup_outputs(struct drm_device *dev) if (I915_READ(SDVOB) & SDVO_DETECTED) { DRM_DEBUG_KMS("probing SDVOC\n"); - found = intel_sdvo_init(dev, SDVOC); + found = intel_sdvo_init(dev, SDVOC, false); } if (!found && (I915_READ(SDVOC) & SDVO_DETECTED)) { @@ -8061,905 +6774,6 @@ static const struct drm_mode_config_funcs intel_mode_funcs = { .output_poll_changed = intel_fb_output_poll_changed, }; -static struct drm_i915_gem_object * -intel_alloc_context_page(struct drm_device *dev) -{ - struct drm_i915_gem_object *ctx; - int ret; - - DRM_LOCK_ASSERT(dev); - - ctx = i915_gem_alloc_object(dev, 4096); - if (!ctx) { - DRM_DEBUG("failed to alloc power context, RC6 disabled\n"); - return NULL; - } - - ret = i915_gem_object_pin(ctx, 4096, true); - if (ret) { - DRM_ERROR("failed to pin power context: %d\n", ret); - goto err_unref; - } - - ret = i915_gem_object_set_to_gtt_domain(ctx, 1); - if (ret) { - DRM_ERROR("failed to set-domain on power context: %d\n", ret); - goto err_unpin; - } - - return ctx; - -err_unpin: - i915_gem_object_unpin(ctx); -err_unref: - drm_gem_object_unreference(&ctx->base); - DRM_UNLOCK(dev); - return NULL; -} - -bool ironlake_set_drps(struct drm_device *dev, u8 val) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u16 rgvswctl; - - rgvswctl = I915_READ16(MEMSWCTL); - if (rgvswctl & MEMCTL_CMD_STS) { - DRM_DEBUG("gpu busy, RCS change rejected\n"); - return false; /* still busy with another command */ - } - - rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) | - (val << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM; - I915_WRITE16(MEMSWCTL, rgvswctl); - POSTING_READ16(MEMSWCTL); - - rgvswctl |= MEMCTL_CMD_STS; - I915_WRITE16(MEMSWCTL, rgvswctl); - - return true; -} - -void ironlake_enable_drps(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 rgvmodectl = I915_READ(MEMMODECTL); - u8 fmax, fmin, fstart, vstart; - - /* Enable temp reporting */ - I915_WRITE16(PMMISC, I915_READ(PMMISC) | MCPPCE_EN); - I915_WRITE16(TSC1, I915_READ(TSC1) | TSE); - - /* 100ms RC evaluation intervals */ - I915_WRITE(RCUPEI, 100000); - I915_WRITE(RCDNEI, 100000); - - /* Set max/min thresholds to 90ms and 80ms respectively */ - I915_WRITE(RCBMAXAVG, 90000); - I915_WRITE(RCBMINAVG, 80000); - - I915_WRITE(MEMIHYST, 1); - - /* Set up min, max, and cur for interrupt handling */ - fmax = (rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT; - fmin = (rgvmodectl & MEMMODE_FMIN_MASK); - fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >> - MEMMODE_FSTART_SHIFT; - - vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >> - PXVFREQ_PX_SHIFT; - - dev_priv->fmax = fmax; /* IPS callback will increase this */ - dev_priv->fstart = fstart; - - dev_priv->max_delay = fstart; - dev_priv->min_delay = fmin; - dev_priv->cur_delay = fstart; - - DRM_DEBUG("fmax: %d, fmin: %d, fstart: %d\n", - fmax, fmin, fstart); - - I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN); - - /* - * Interrupts will be enabled in ironlake_irq_postinstall - */ - - I915_WRITE(VIDSTART, vstart); - POSTING_READ(VIDSTART); - - rgvmodectl |= MEMMODE_SWMODE_EN; - I915_WRITE(MEMMODECTL, rgvmodectl); - - if (_intel_wait_for(dev, - (I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10, - 1, "915per")) - DRM_ERROR("stuck trying to change perf mode\n"); - pause("915dsp", 1); - - ironlake_set_drps(dev, fstart); - - dev_priv->last_count1 = I915_READ(0x112e4) + I915_READ(0x112e8) + - I915_READ(0x112e0); - dev_priv->last_time1 = jiffies_to_msecs(jiffies); - dev_priv->last_count2 = I915_READ(0x112f4); - nanotime(&dev_priv->last_time2); -} - -void ironlake_disable_drps(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u16 rgvswctl = I915_READ16(MEMSWCTL); - - /* Ack interrupts, disable EFC interrupt */ - I915_WRITE(MEMINTREN, I915_READ(MEMINTREN) & ~MEMINT_EVAL_CHG_EN); - I915_WRITE(MEMINTRSTS, MEMINT_EVAL_CHG); - I915_WRITE(DEIER, I915_READ(DEIER) & ~DE_PCU_EVENT); - I915_WRITE(DEIIR, DE_PCU_EVENT); - I915_WRITE(DEIMR, I915_READ(DEIMR) | DE_PCU_EVENT); - - /* Go back to the starting frequency */ - ironlake_set_drps(dev, dev_priv->fstart); - pause("915dsp", 1); - rgvswctl |= MEMCTL_CMD_STS; - I915_WRITE(MEMSWCTL, rgvswctl); - pause("915dsp", 1); - -} - -void gen6_set_rps(struct drm_device *dev, u8 val) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 swreq; - - swreq = (val & 0x3ff) << 25; - I915_WRITE(GEN6_RPNSWREQ, swreq); -} - -void gen6_disable_rps(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - I915_WRITE(GEN6_RPNSWREQ, 1 << 31); - I915_WRITE(GEN6_PMINTRMSK, 0xffffffff); - I915_WRITE(GEN6_PMIER, 0); - /* Complete PM interrupt masking here doesn't race with the rps work - * item again unmasking PM interrupts because that is using a different - * register (PMIMR) to mask PM interrupts. The only risk is in leaving - * stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */ - - mtx_lock(&dev_priv->rps_lock); - dev_priv->pm_iir = 0; - mtx_unlock(&dev_priv->rps_lock); - - I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR)); -} - -static unsigned long intel_pxfreq(u32 vidfreq) -{ - unsigned long freq; - int div = (vidfreq & 0x3f0000) >> 16; - int post = (vidfreq & 0x3000) >> 12; - int pre = (vidfreq & 0x7); - - if (!pre) - return 0; - - freq = ((div * 133333) / ((1<dev_private; - u32 lcfuse; - u8 pxw[16]; - int i; - - /* Disable to program */ - I915_WRITE(ECR, 0); - POSTING_READ(ECR); - - /* Program energy weights for various events */ - I915_WRITE(SDEW, 0x15040d00); - I915_WRITE(CSIEW0, 0x007f0000); - I915_WRITE(CSIEW1, 0x1e220004); - I915_WRITE(CSIEW2, 0x04000004); - - for (i = 0; i < 5; i++) - I915_WRITE(PEW + (i * 4), 0); - for (i = 0; i < 3; i++) - I915_WRITE(DEW + (i * 4), 0); - - /* Program P-state weights to account for frequency power adjustment */ - for (i = 0; i < 16; i++) { - u32 pxvidfreq = I915_READ(PXVFREQ_BASE + (i * 4)); - unsigned long freq = intel_pxfreq(pxvidfreq); - unsigned long vid = (pxvidfreq & PXVFREQ_PX_MASK) >> - PXVFREQ_PX_SHIFT; - unsigned long val; - - val = vid * vid; - val *= (freq / 1000); - val *= 255; - val /= (127*127*900); - if (val > 0xff) - DRM_ERROR("bad pxval: %ld\n", val); - pxw[i] = val; - } - /* Render standby states get 0 weight */ - pxw[14] = 0; - pxw[15] = 0; - - for (i = 0; i < 4; i++) { - u32 val = (pxw[i*4] << 24) | (pxw[(i*4)+1] << 16) | - (pxw[(i*4)+2] << 8) | (pxw[(i*4)+3]); - I915_WRITE(PXW + (i * 4), val); - } - - /* Adjust magic regs to magic values (more experimental results) */ - I915_WRITE(OGW0, 0); - I915_WRITE(OGW1, 0); - I915_WRITE(EG0, 0x00007f00); - I915_WRITE(EG1, 0x0000000e); - I915_WRITE(EG2, 0x000e0000); - I915_WRITE(EG3, 0x68000300); - I915_WRITE(EG4, 0x42000000); - I915_WRITE(EG5, 0x00140031); - I915_WRITE(EG6, 0); - I915_WRITE(EG7, 0); - - for (i = 0; i < 8; i++) - I915_WRITE(PXWL + (i * 4), 0); - - /* Enable PMON + select events */ - I915_WRITE(ECR, 0x80000019); - - lcfuse = I915_READ(LCFUSE02); - - dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK); -} - -static int intel_enable_rc6(struct drm_device *dev) -{ - /* - * Respect the kernel parameter if it is set - */ - if (i915_enable_rc6 >= 0) - return i915_enable_rc6; - - /* - * Disable RC6 on Ironlake - */ - if (INTEL_INFO(dev)->gen == 5) - return 0; - - /* - * Enable rc6 on Sandybridge if DMA remapping is disabled - */ - if (INTEL_INFO(dev)->gen == 6) { - DRM_DEBUG_DRIVER( - "Sandybridge: intel_iommu_enabled %s -- RC6 %sabled\n", - intel_iommu_enabled ? "true" : "false", - !intel_iommu_enabled ? "en" : "dis"); - return (intel_iommu_enabled ? 0 : INTEL_RC6_ENABLE); - } - DRM_DEBUG_DRIVER("RC6 and deep RC6 enabled\n"); - return (INTEL_RC6_ENABLE | INTEL_RC6p_ENABLE); -} - -void gen6_enable_rps(struct drm_i915_private *dev_priv) -{ - struct drm_device *dev = dev_priv->dev; - u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); - u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); - u32 pcu_mbox, rc6_mask = 0; - u32 gtfifodbg; - int cur_freq, min_freq, max_freq; - int rc6_mode; - int i; - - /* Here begins a magic sequence of register writes to enable - * auto-downclocking. - * - * Perhaps there might be some value in exposing these to - * userspace... - */ - I915_WRITE(GEN6_RC_STATE, 0); - DRM_LOCK(dev); - - /* Clear the DBG now so we don't confuse earlier errors */ - if ((gtfifodbg = I915_READ(GTFIFODBG))) { - DRM_ERROR("GT fifo had a previous error %x\n", gtfifodbg); - I915_WRITE(GTFIFODBG, gtfifodbg); - } - - gen6_gt_force_wake_get(dev_priv); - - /* disable the counters and set deterministic thresholds */ - I915_WRITE(GEN6_RC_CONTROL, 0); - - I915_WRITE(GEN6_RC1_WAKE_RATE_LIMIT, 1000 << 16); - I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 40 << 16 | 30); - I915_WRITE(GEN6_RC6pp_WAKE_RATE_LIMIT, 30); - I915_WRITE(GEN6_RC_EVALUATION_INTERVAL, 125000); - I915_WRITE(GEN6_RC_IDLE_HYSTERSIS, 25); - - for (i = 0; i < I915_NUM_RINGS; i++) - I915_WRITE(RING_MAX_IDLE(dev_priv->rings[i].mmio_base), 10); - - I915_WRITE(GEN6_RC_SLEEP, 0); - I915_WRITE(GEN6_RC1e_THRESHOLD, 1000); - I915_WRITE(GEN6_RC6_THRESHOLD, 50000); - I915_WRITE(GEN6_RC6p_THRESHOLD, 100000); - I915_WRITE(GEN6_RC6pp_THRESHOLD, 64000); /* unused */ - - rc6_mode = intel_enable_rc6(dev_priv->dev); - if (rc6_mode & INTEL_RC6_ENABLE) - rc6_mask |= GEN6_RC_CTL_RC6_ENABLE; - - if (rc6_mode & INTEL_RC6p_ENABLE) - rc6_mask |= GEN6_RC_CTL_RC6p_ENABLE; - - if (rc6_mode & INTEL_RC6pp_ENABLE) - rc6_mask |= GEN6_RC_CTL_RC6pp_ENABLE; - - DRM_INFO("Enabling RC6 states: RC6 %s, RC6p %s, RC6pp %s\n", - (rc6_mode & INTEL_RC6_ENABLE) ? "on" : "off", - (rc6_mode & INTEL_RC6p_ENABLE) ? "on" : "off", - (rc6_mode & INTEL_RC6pp_ENABLE) ? "on" : "off"); - - I915_WRITE(GEN6_RC_CONTROL, - rc6_mask | - GEN6_RC_CTL_EI_MODE(1) | - GEN6_RC_CTL_HW_ENABLE); - - I915_WRITE(GEN6_RPNSWREQ, - GEN6_FREQUENCY(10) | - GEN6_OFFSET(0) | - GEN6_AGGRESSIVE_TURBO); - I915_WRITE(GEN6_RC_VIDEO_FREQ, - GEN6_FREQUENCY(12)); - - I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000); - I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, - 18 << 24 | - 6 << 16); - I915_WRITE(GEN6_RP_UP_THRESHOLD, 10000); - I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 1000000); - I915_WRITE(GEN6_RP_UP_EI, 100000); - I915_WRITE(GEN6_RP_DOWN_EI, 5000000); - I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10); - I915_WRITE(GEN6_RP_CONTROL, - GEN6_RP_MEDIA_TURBO | - GEN6_RP_MEDIA_HW_MODE | - GEN6_RP_MEDIA_IS_GFX | - GEN6_RP_ENABLE | - GEN6_RP_UP_BUSY_AVG | - GEN6_RP_DOWN_IDLE_CONT); - - if (_intel_wait_for(dev, - (I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, 500, - 1, "915pr1")) - DRM_ERROR("timeout waiting for pcode mailbox to become idle\n"); - - I915_WRITE(GEN6_PCODE_DATA, 0); - I915_WRITE(GEN6_PCODE_MAILBOX, - GEN6_PCODE_READY | - GEN6_PCODE_WRITE_MIN_FREQ_TABLE); - if (_intel_wait_for(dev, - (I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, 500, - 1, "915pr2")) - DRM_ERROR("timeout waiting for pcode mailbox to finish\n"); - - min_freq = (rp_state_cap & 0xff0000) >> 16; - max_freq = rp_state_cap & 0xff; - cur_freq = (gt_perf_status & 0xff00) >> 8; - - /* Check for overclock support */ - if (_intel_wait_for(dev, - (I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, 500, - 1, "915pr3")) - DRM_ERROR("timeout waiting for pcode mailbox to become idle\n"); - I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_READ_OC_PARAMS); - pcu_mbox = I915_READ(GEN6_PCODE_DATA); - if (_intel_wait_for(dev, - (I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, 500, - 1, "915pr4")) - DRM_ERROR("timeout waiting for pcode mailbox to finish\n"); - if (pcu_mbox & (1<<31)) { /* OC supported */ - max_freq = pcu_mbox & 0xff; - DRM_DEBUG("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 50); - } - - /* In units of 100MHz */ - dev_priv->max_delay = max_freq; - dev_priv->min_delay = min_freq; - dev_priv->cur_delay = cur_freq; - - /* requires MSI enabled */ - I915_WRITE(GEN6_PMIER, - GEN6_PM_MBOX_EVENT | - GEN6_PM_THERMAL_EVENT | - GEN6_PM_RP_DOWN_TIMEOUT | - GEN6_PM_RP_UP_THRESHOLD | - GEN6_PM_RP_DOWN_THRESHOLD | - GEN6_PM_RP_UP_EI_EXPIRED | - GEN6_PM_RP_DOWN_EI_EXPIRED); - mtx_lock(&dev_priv->rps_lock); - if (dev_priv->pm_iir != 0) - printf("pm_iir %x\n", dev_priv->pm_iir); - I915_WRITE(GEN6_PMIMR, 0); - mtx_unlock(&dev_priv->rps_lock); - /* enable all PM interrupts */ - I915_WRITE(GEN6_PMINTRMSK, 0); - - gen6_gt_force_wake_put(dev_priv); - DRM_UNLOCK(dev); -} - -void gen6_update_ring_freq(struct drm_i915_private *dev_priv) -{ - struct drm_device *dev; - int min_freq = 15; - int gpu_freq, ia_freq, max_ia_freq; - int scaling_factor = 180; - uint64_t tsc_freq; - - dev = dev_priv->dev; -#if 0 - max_ia_freq = cpufreq_quick_get_max(0); - /* - * Default to measured freq if none found, PCU will ensure we don't go - * over - */ - if (!max_ia_freq) - max_ia_freq = tsc_freq; - - /* Convert from Hz to MHz */ - max_ia_freq /= 1000; -#else - tsc_freq = atomic_load_acq_64(&tsc_freq); - max_ia_freq = tsc_freq / 1000 / 1000; -#endif - - DRM_LOCK(dev); - - /* - * For each potential GPU frequency, load a ring frequency we'd like - * to use for memory access. We do this by specifying the IA frequency - * the PCU should use as a reference to determine the ring frequency. - */ - for (gpu_freq = dev_priv->max_delay; gpu_freq >= dev_priv->min_delay; - gpu_freq--) { - int diff = dev_priv->max_delay - gpu_freq; - int d; - - /* - * For GPU frequencies less than 750MHz, just use the lowest - * ring freq. - */ - if (gpu_freq < min_freq) - ia_freq = 800; - else - ia_freq = max_ia_freq - ((diff * scaling_factor) / 2); - d = 100; - ia_freq = (ia_freq + d / 2) / d; - - I915_WRITE(GEN6_PCODE_DATA, - (ia_freq << GEN6_PCODE_FREQ_IA_RATIO_SHIFT) | - gpu_freq); - I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY | - GEN6_PCODE_WRITE_MIN_FREQ_TABLE); - if (_intel_wait_for(dev, - (I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, - 10, 1, "915frq")) { - DRM_ERROR("pcode write of freq table timed out\n"); - continue; - } - } - - DRM_UNLOCK(dev); -} - -static void ironlake_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; - - /* Required for FBC */ - dspclk_gate |= DPFCUNIT_CLOCK_GATE_DISABLE | - DPFCRUNIT_CLOCK_GATE_DISABLE | - DPFDUNIT_CLOCK_GATE_DISABLE; - /* Required for CxSR */ - dspclk_gate |= DPARBUNIT_CLOCK_GATE_DISABLE; - - I915_WRITE(PCH_3DCGDIS0, - MARIUNIT_CLOCK_GATE_DISABLE | - SVSMUNIT_CLOCK_GATE_DISABLE); - I915_WRITE(PCH_3DCGDIS1, - VFMUNIT_CLOCK_GATE_DISABLE); - - I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); - - /* - * According to the spec the following bits should be set in - * order to enable memory self-refresh - * The bit 22/21 of 0x42004 - * The bit 5 of 0x42020 - * The bit 15 of 0x45000 - */ - I915_WRITE(ILK_DISPLAY_CHICKEN2, - (I915_READ(ILK_DISPLAY_CHICKEN2) | - ILK_DPARB_GATE | ILK_VSDPFD_FULL)); - I915_WRITE(ILK_DSPCLK_GATE, - (I915_READ(ILK_DSPCLK_GATE) | - ILK_DPARB_CLK_GATE)); - I915_WRITE(DISP_ARB_CTL, - (I915_READ(DISP_ARB_CTL) | - DISP_FBC_WM_DIS)); - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); - - /* - * Based on the document from hardware guys the following bits - * should be set unconditionally in order to enable FBC. - * The bit 22 of 0x42000 - * The bit 22 of 0x42004 - * The bit 7,8,9 of 0x42020. - */ - if (IS_IRONLAKE_M(dev)) { - I915_WRITE(ILK_DISPLAY_CHICKEN1, - I915_READ(ILK_DISPLAY_CHICKEN1) | - ILK_FBCQ_DIS); - I915_WRITE(ILK_DISPLAY_CHICKEN2, - I915_READ(ILK_DISPLAY_CHICKEN2) | - ILK_DPARB_GATE); - I915_WRITE(ILK_DSPCLK_GATE, - I915_READ(ILK_DSPCLK_GATE) | - ILK_DPFC_DIS1 | - ILK_DPFC_DIS2 | - ILK_CLK_FBC); - } - - I915_WRITE(ILK_DISPLAY_CHICKEN2, - I915_READ(ILK_DISPLAY_CHICKEN2) | - ILK_ELPIN_409_SELECT); - I915_WRITE(_3D_CHICKEN2, - _3D_CHICKEN2_WM_READ_PIPELINED << 16 | - _3D_CHICKEN2_WM_READ_PIPELINED); -} - -static void gen6_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int pipe; - uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; - - I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); - - I915_WRITE(ILK_DISPLAY_CHICKEN2, - I915_READ(ILK_DISPLAY_CHICKEN2) | - ILK_ELPIN_409_SELECT); - - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); - - I915_WRITE(GEN6_UCGCTL1, - I915_READ(GEN6_UCGCTL1) | - GEN6_BLBUNIT_CLOCK_GATE_DISABLE); - - /* According to the BSpec vol1g, bit 12 (RCPBUNIT) clock - * gating disable must be set. Failure to set it results in - * flickering pixels due to Z write ordering failures after - * some amount of runtime in the Mesa "fire" demo, and Unigine - * Sanctuary and Tropics, and apparently anything else with - * alpha test or pixel discard. - * - * According to the spec, bit 11 (RCCUNIT) must also be set, - * but we didn't debug actual testcases to find it out. - */ - I915_WRITE(GEN6_UCGCTL2, - GEN6_RCPBUNIT_CLOCK_GATE_DISABLE | - GEN6_RCCUNIT_CLOCK_GATE_DISABLE); - - /* - * According to the spec the following bits should be - * set in order to enable memory self-refresh and fbc: - * The bit21 and bit22 of 0x42000 - * The bit21 and bit22 of 0x42004 - * The bit5 and bit7 of 0x42020 - * The bit14 of 0x70180 - * The bit14 of 0x71180 - */ - I915_WRITE(ILK_DISPLAY_CHICKEN1, - I915_READ(ILK_DISPLAY_CHICKEN1) | - ILK_FBCQ_DIS | ILK_PABSTRETCH_DIS); - I915_WRITE(ILK_DISPLAY_CHICKEN2, - I915_READ(ILK_DISPLAY_CHICKEN2) | - ILK_DPARB_GATE | ILK_VSDPFD_FULL); - I915_WRITE(ILK_DSPCLK_GATE, - I915_READ(ILK_DSPCLK_GATE) | - ILK_DPARB_CLK_GATE | - ILK_DPFD_CLK_GATE); - - for_each_pipe(pipe) { - I915_WRITE(DSPCNTR(pipe), - I915_READ(DSPCNTR(pipe)) | - DISPPLANE_TRICKLE_FEED_DISABLE); - intel_flush_display_plane(dev_priv, pipe); - } -} - -static void ivybridge_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int pipe; - uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; - - I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); - - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); - - /* According to the spec, bit 13 (RCZUNIT) must be set on IVB. - * This implements the WaDisableRCZUnitClockGating workaround. - */ - I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE); - - I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE); - - I915_WRITE(IVB_CHICKEN3, - CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE | - CHICKEN3_DGMG_DONE_FIX_DISABLE); - - /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */ - I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1, - GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC); - - /* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */ - I915_WRITE(GEN7_L3CNTLREG1, - GEN7_WA_FOR_GEN7_L3_CONTROL); - I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER, - GEN7_WA_L3_CHICKEN_MODE); - - /* This is required by WaCatErrorRejectionIssue */ - I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG, - I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | - GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB); - - for_each_pipe(pipe) { - I915_WRITE(DSPCNTR(pipe), - I915_READ(DSPCNTR(pipe)) | - DISPPLANE_TRICKLE_FEED_DISABLE); - intel_flush_display_plane(dev_priv, pipe); - } -} - -static void g4x_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t dspclk_gate; - - I915_WRITE(RENCLK_GATE_D1, 0); - I915_WRITE(RENCLK_GATE_D2, VF_UNIT_CLOCK_GATE_DISABLE | - GS_UNIT_CLOCK_GATE_DISABLE | - CL_UNIT_CLOCK_GATE_DISABLE); - I915_WRITE(RAMCLK_GATE_D, 0); - dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE | - OVRUNIT_CLOCK_GATE_DISABLE | - OVCUNIT_CLOCK_GATE_DISABLE; - if (IS_GM45(dev)) - dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE; - I915_WRITE(DSPCLK_GATE_D, dspclk_gate); -} - -static void crestline_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE); - I915_WRITE(RENCLK_GATE_D2, 0); - I915_WRITE(DSPCLK_GATE_D, 0); - I915_WRITE(RAMCLK_GATE_D, 0); - I915_WRITE16(DEUC, 0); -} - -static void broadwater_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE | - I965_RCC_CLOCK_GATE_DISABLE | - I965_RCPB_CLOCK_GATE_DISABLE | - I965_ISC_CLOCK_GATE_DISABLE | - I965_FBC_CLOCK_GATE_DISABLE); - I915_WRITE(RENCLK_GATE_D2, 0); -} - -static void gen3_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 dstate = I915_READ(D_STATE); - - dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING | - DSTATE_DOT_CLOCK_GATING; - I915_WRITE(D_STATE, dstate); -} - -static void i85x_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - I915_WRITE(RENCLK_GATE_D1, SV_CLOCK_GATE_DISABLE); -} - -static void i830_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE); -} - -static void ibx_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - /* - * On Ibex Peak and Cougar Point, we need to disable clock - * gating for the panel power sequencer or it will fail to - * start up when no ports are active. - */ - I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE); -} - -static void cpt_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int pipe; - - /* - * On Ibex Peak and Cougar Point, we need to disable clock - * gating for the panel power sequencer or it will fail to - * start up when no ports are active. - */ - I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE); - I915_WRITE(SOUTH_CHICKEN2, I915_READ(SOUTH_CHICKEN2) | - DPLS_EDP_PPS_FIX_DIS); - /* Without this, mode sets may fail silently on FDI */ - for_each_pipe(pipe) - I915_WRITE(TRANS_CHICKEN2(pipe), TRANS_AUTOTRAIN_GEN_STALL_DIS); -} - -static void ironlake_teardown_rc6(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (dev_priv->renderctx) { - i915_gem_object_unpin(dev_priv->renderctx); - drm_gem_object_unreference(&dev_priv->renderctx->base); - dev_priv->renderctx = NULL; - } - - if (dev_priv->pwrctx) { - i915_gem_object_unpin(dev_priv->pwrctx); - drm_gem_object_unreference(&dev_priv->pwrctx->base); - dev_priv->pwrctx = NULL; - } -} - -static void ironlake_disable_rc6(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (I915_READ(PWRCTXA)) { - /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */ - I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT); - (void)_intel_wait_for(dev, - ((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON), - 50, 1, "915pro"); - - I915_WRITE(PWRCTXA, 0); - POSTING_READ(PWRCTXA); - - I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT); - POSTING_READ(RSTDBYCTL); - } - - ironlake_teardown_rc6(dev); -} - -static int ironlake_setup_rc6(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (dev_priv->renderctx == NULL) - dev_priv->renderctx = intel_alloc_context_page(dev); - if (!dev_priv->renderctx) - return -ENOMEM; - - if (dev_priv->pwrctx == NULL) - dev_priv->pwrctx = intel_alloc_context_page(dev); - if (!dev_priv->pwrctx) { - ironlake_teardown_rc6(dev); - return -ENOMEM; - } - - return 0; -} - -void ironlake_enable_rc6(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int ret; - - /* rc6 disabled by default due to repeated reports of hanging during - * boot and resume. - */ - if (!intel_enable_rc6(dev)) - return; - - DRM_LOCK(dev); - ret = ironlake_setup_rc6(dev); - if (ret) { - DRM_UNLOCK(dev); - return; - } - - /* - * GPU can automatically power down the render unit if given a page - * to save state. - */ - ret = BEGIN_LP_RING(6); - if (ret) { - ironlake_teardown_rc6(dev); - DRM_UNLOCK(dev); - return; - } - - OUT_RING(MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN); - OUT_RING(MI_SET_CONTEXT); - OUT_RING(dev_priv->renderctx->gtt_offset | - MI_MM_SPACE_GTT | - MI_SAVE_EXT_STATE_EN | - MI_RESTORE_EXT_STATE_EN | - MI_RESTORE_INHIBIT); - OUT_RING(MI_SUSPEND_FLUSH); - OUT_RING(MI_NOOP); - OUT_RING(MI_FLUSH); - ADVANCE_LP_RING(); - - /* - * Wait for the command parser to advance past MI_SET_CONTEXT. The HW - * does an implicit flush, combined with MI_FLUSH above, it should be - * safe to assume that renderctx is valid - */ - ret = intel_wait_ring_idle(LP_RING(dev_priv)); - if (ret) { - DRM_ERROR("failed to enable ironlake power power savings\n"); - ironlake_teardown_rc6(dev); - DRM_UNLOCK(dev); - return; - } - - I915_WRITE(PWRCTXA, dev_priv->pwrctx->gtt_offset | PWRCTX_EN); - I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT); - DRM_UNLOCK(dev); -} - -void intel_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - dev_priv->display.init_clock_gating(dev); - - if (dev_priv->display.init_pch_clock_gating) - dev_priv->display.init_pch_clock_gating(dev); -} - /* Set up chip specific display functions */ static void intel_init_display(struct drm_device *dev) { @@ -8969,32 +6783,20 @@ static void intel_init_display(struct drm_device *dev) if (HAS_PCH_SPLIT(dev)) { dev_priv->display.dpms = ironlake_crtc_dpms; dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set; + dev_priv->display.off = ironlake_crtc_off; dev_priv->display.update_plane = ironlake_update_plane; } else { dev_priv->display.dpms = i9xx_crtc_dpms; dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set; + dev_priv->display.off = i9xx_crtc_off; dev_priv->display.update_plane = i9xx_update_plane; } - if (I915_HAS_FBC(dev)) { - if (HAS_PCH_SPLIT(dev)) { - dev_priv->display.fbc_enabled = ironlake_fbc_enabled; - dev_priv->display.enable_fbc = ironlake_enable_fbc; - dev_priv->display.disable_fbc = ironlake_disable_fbc; - } else if (IS_GM45(dev)) { - dev_priv->display.fbc_enabled = g4x_fbc_enabled; - dev_priv->display.enable_fbc = g4x_enable_fbc; - dev_priv->display.disable_fbc = g4x_disable_fbc; - } else if (IS_CRESTLINE(dev)) { - dev_priv->display.fbc_enabled = i8xx_fbc_enabled; - dev_priv->display.enable_fbc = i8xx_enable_fbc; - dev_priv->display.disable_fbc = i8xx_disable_fbc; - } - /* 855GM needs testing */ - } - /* Returns the core display clock speed */ - if (IS_I945G(dev) || (IS_G33(dev) && !IS_PINEVIEW_M(dev))) + if (IS_VALLEYVIEW(dev)) + dev_priv->display.get_display_clock_speed = + valleyview_get_display_clock_speed; + else if (IS_I945G(dev) || (IS_G33(dev) && !IS_PINEVIEW_M(dev))) dev_priv->display.get_display_clock_speed = i945_get_display_clock_speed; else if (IS_I915G(dev)) @@ -9016,124 +6818,27 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.get_display_clock_speed = i830_get_display_clock_speed; - /* For FIFO watermark updates */ if (HAS_PCH_SPLIT(dev)) { - dev_priv->display.force_wake_get = __gen6_gt_force_wake_get; - dev_priv->display.force_wake_put = __gen6_gt_force_wake_put; - - /* IVB configs may use multi-threaded forcewake */ - if (IS_IVYBRIDGE(dev)) { - u32 ecobus; - - /* A small trick here - if the bios hasn't configured MT forcewake, - * and if the device is in RC6, then force_wake_mt_get will not wake - * the device and the ECOBUS read will return zero. Which will be - * (correctly) interpreted by the test below as MT forcewake being - * disabled. - */ - DRM_LOCK(dev); - __gen6_gt_force_wake_mt_get(dev_priv); - ecobus = I915_READ_NOTRACE(ECOBUS); - __gen6_gt_force_wake_mt_put(dev_priv); - DRM_UNLOCK(dev); - - if (ecobus & FORCEWAKE_MT_ENABLE) { - DRM_DEBUG_KMS("Using MT version of forcewake\n"); - dev_priv->display.force_wake_get = - __gen6_gt_force_wake_mt_get; - dev_priv->display.force_wake_put = - __gen6_gt_force_wake_mt_put; - } - } - - if (HAS_PCH_IBX(dev)) - dev_priv->display.init_pch_clock_gating = ibx_init_clock_gating; - else if (HAS_PCH_CPT(dev)) - dev_priv->display.init_pch_clock_gating = cpt_init_clock_gating; - if (IS_GEN5(dev)) { - if (I915_READ(MLTR_ILK) & ILK_SRLT_MASK) - dev_priv->display.update_wm = ironlake_update_wm; - else { - DRM_DEBUG_KMS("Failed to get proper latency. " - "Disable CxSR\n"); - dev_priv->display.update_wm = NULL; - } dev_priv->display.fdi_link_train = ironlake_fdi_link_train; - dev_priv->display.init_clock_gating = ironlake_init_clock_gating; dev_priv->display.write_eld = ironlake_write_eld; } else if (IS_GEN6(dev)) { - if (SNB_READ_WM0_LATENCY()) { - dev_priv->display.update_wm = sandybridge_update_wm; - dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm; - } else { - DRM_DEBUG_KMS("Failed to read display plane latency. " - "Disable CxSR\n"); - dev_priv->display.update_wm = NULL; - } dev_priv->display.fdi_link_train = gen6_fdi_link_train; - dev_priv->display.init_clock_gating = gen6_init_clock_gating; dev_priv->display.write_eld = ironlake_write_eld; } else if (IS_IVYBRIDGE(dev)) { /* FIXME: detect B0+ stepping and use auto training */ dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train; - if (SNB_READ_WM0_LATENCY()) { - dev_priv->display.update_wm = sandybridge_update_wm; - dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm; - } else { - DRM_DEBUG_KMS("Failed to read display plane latency. " - "Disable CxSR\n"); - dev_priv->display.update_wm = NULL; - } - dev_priv->display.init_clock_gating = ivybridge_init_clock_gating; + dev_priv->display.write_eld = ironlake_write_eld; + } else if (IS_HASWELL(dev)) { + dev_priv->display.fdi_link_train = hsw_fdi_link_train; dev_priv->display.write_eld = ironlake_write_eld; } else dev_priv->display.update_wm = NULL; - } else if (IS_PINEVIEW(dev)) { - if (!intel_get_cxsr_latency(IS_PINEVIEW_G(dev), - dev_priv->is_ddr3, - dev_priv->fsb_freq, - dev_priv->mem_freq)) { - DRM_INFO("failed to find known CxSR latency " - "(found ddr%s fsb freq %d, mem freq %d), " - "disabling CxSR\n", - (dev_priv->is_ddr3 == 1) ? "3" : "2", - dev_priv->fsb_freq, dev_priv->mem_freq); - /* Disable CxSR and never update its watermark again */ - pineview_disable_cxsr(dev); - dev_priv->display.update_wm = NULL; - } else - dev_priv->display.update_wm = pineview_update_wm; - dev_priv->display.init_clock_gating = gen3_init_clock_gating; + } else if (IS_VALLEYVIEW(dev)) { + dev_priv->display.force_wake_get = vlv_force_wake_get; + dev_priv->display.force_wake_put = vlv_force_wake_put; } else if (IS_G4X(dev)) { dev_priv->display.write_eld = g4x_write_eld; - dev_priv->display.update_wm = g4x_update_wm; - dev_priv->display.init_clock_gating = g4x_init_clock_gating; - } else if (IS_GEN4(dev)) { - dev_priv->display.update_wm = i965_update_wm; - if (IS_CRESTLINE(dev)) - dev_priv->display.init_clock_gating = crestline_init_clock_gating; - else if (IS_BROADWATER(dev)) - dev_priv->display.init_clock_gating = broadwater_init_clock_gating; - } else if (IS_GEN3(dev)) { - dev_priv->display.update_wm = i9xx_update_wm; - dev_priv->display.get_fifo_size = i9xx_get_fifo_size; - dev_priv->display.init_clock_gating = gen3_init_clock_gating; - } else if (IS_I865G(dev)) { - dev_priv->display.update_wm = i830_update_wm; - dev_priv->display.init_clock_gating = i85x_init_clock_gating; - dev_priv->display.get_fifo_size = i830_get_fifo_size; - } else if (IS_I85X(dev)) { - dev_priv->display.update_wm = i9xx_update_wm; - dev_priv->display.get_fifo_size = i85x_get_fifo_size; - dev_priv->display.init_clock_gating = i85x_init_clock_gating; - } else { - dev_priv->display.update_wm = i830_update_wm; - dev_priv->display.init_clock_gating = i830_init_clock_gating; - if (IS_845G(dev)) - dev_priv->display.get_fifo_size = i845_get_fifo_size; - else - dev_priv->display.get_fifo_size = i830_get_fifo_size; } /* Default just returns -ENODEV to indicate unsupported */ @@ -9172,7 +6877,7 @@ static void quirk_pipea_force(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; dev_priv->quirks |= QUIRK_PIPEA_FORCE; - DRM_DEBUG("applying pipe a force quirk\n"); + DRM_INFO("applying pipe a force quirk\n"); } /* @@ -9182,6 +6887,18 @@ static void quirk_ssc_force_disable(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; dev_priv->quirks |= QUIRK_LVDS_SSC_DISABLE; + DRM_INFO("applying lvds SSC disable quirk\n"); +} + +/* + * A machine (e.g. Acer Aspire 5734Z) may need to invert the panel backlight + * brightness value + */ +static void quirk_invert_brightness(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + dev_priv->quirks |= QUIRK_INVERT_BRIGHTNESS; + DRM_INFO("applying inverted panel brightness quirk\n"); } struct intel_quirk { @@ -9193,7 +6910,7 @@ struct intel_quirk { #define PCI_ANY_ID (~0u) -struct intel_quirk intel_quirks[] = { +static struct intel_quirk intel_quirks[] = { /* HP Mini needs pipe A force quirk (LP: #322104) */ { 0x27ae, 0x103c, 0x361a, quirk_pipea_force }, @@ -9218,6 +6935,9 @@ struct intel_quirk intel_quirks[] = { /* Sony Vaio Y cannot use SSC on LVDS */ { 0x0046, 0x104d, 0x9076, quirk_ssc_force_disable }, + + /* Acer Aspire 5734Z must invert backlight brightness */ + { 0x2a42, 0x1025, 0x0459, quirk_invert_brightness }, }; static void intel_init_quirks(struct drm_device *dev) @@ -9253,7 +6973,7 @@ static void i915_disable_vga(struct drm_device *dev) #if 0 vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO); #endif - outb(VGA_SR_INDEX, 1); + outb(VGA_SR_INDEX, SR01); sr1 = inb(VGA_SR_DATA); outb(VGA_SR_DATA, sr1 | 1 << 5); #if 0 @@ -9265,6 +6985,40 @@ static void i915_disable_vga(struct drm_device *dev) POSTING_READ(vga_reg); } +static void ivb_pch_pwm_override(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* + * IVB has CPU eDP backlight regs too, set things up to let the + * PCH regs control the backlight + */ + I915_WRITE(BLC_PWM_CPU_CTL2, PWM_ENABLE); + I915_WRITE(BLC_PWM_CPU_CTL, 0); + I915_WRITE(BLC_PWM_PCH_CTL1, PWM_ENABLE | (1<<30)); +} + +void intel_modeset_init_hw(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + intel_init_clock_gating(dev); + + if (IS_IRONLAKE_M(dev)) { + ironlake_enable_drps(dev); + ironlake_enable_rc6(dev); + intel_init_emon(dev); + } + + if ((IS_GEN6(dev) || IS_GEN7(dev)) && !IS_VALLEYVIEW(dev)) { + gen6_enable_rps(dev_priv); + gen6_update_ring_freq(dev_priv); + } + + if (IS_IVYBRIDGE(dev)) + ivb_pch_pwm_override(dev); +} + void intel_modeset_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -9278,11 +7032,14 @@ void intel_modeset_init(struct drm_device *dev) dev->mode_config.preferred_depth = 24; dev->mode_config.prefer_shadow = 1; - dev->mode_config.funcs = __DECONST(struct drm_mode_config_funcs *, - &intel_mode_funcs); + dev->mode_config.funcs = &intel_mode_funcs; intel_init_quirks(dev); + intel_init_pm(dev); + + intel_prepare_ddi(dev); + intel_init_display(dev); if (IS_GEN2(dev)) { @@ -9307,30 +7064,19 @@ void intel_modeset_init(struct drm_device *dev) DRM_DEBUG_KMS("plane %d init failed: %d\n", i, ret); } + intel_pch_pll_init(dev); + /* Just disable it once at startup */ i915_disable_vga(dev); intel_setup_outputs(dev); - intel_init_clock_gating(dev); - - if (IS_IRONLAKE_M(dev)) { - ironlake_enable_drps(dev); - intel_init_emon(dev); - } - - if (IS_GEN6(dev)) { - gen6_enable_rps(dev_priv); - gen6_update_ring_freq(dev_priv); - } - TASK_INIT(&dev_priv->idle_task, 0, intel_idle_update, dev_priv); callout_init(&dev_priv->idle_callout, CALLOUT_MPSAFE); } void intel_modeset_gem_init(struct drm_device *dev) { - if (IS_IRONLAKE_M(dev)) - ironlake_enable_rc6(dev); + intel_modeset_init_hw(dev); intel_setup_overlay(dev); } @@ -9361,12 +7107,15 @@ void intel_modeset_cleanup(struct drm_device *dev) if (IS_IRONLAKE_M(dev)) ironlake_disable_drps(dev); - if (IS_GEN6(dev)) + if ((IS_GEN6(dev) || IS_GEN7(dev)) && !IS_VALLEYVIEW(dev)) gen6_disable_rps(dev); if (IS_IRONLAKE_M(dev)) ironlake_disable_rc6(dev); + if (IS_VALLEYVIEW(dev)) + vlv_init_dpio(dev); + /* Disable the irq before mode object teardown, for the irq might * enqueue unpin/hotplug work. */ drm_irq_uninstall(dev); diff --git a/sys/dev/drm2/i915/intel_dp.c b/sys/dev/drm2/i915/intel_dp.c index e0df0bc27492..6382387e535b 100644 --- a/sys/dev/drm2/i915/intel_dp.c +++ b/sys/dev/drm2/i915/intel_dp.c @@ -673,7 +673,7 @@ intel_dp_i2c_init(struct intel_dp *intel_dp, } static bool -intel_dp_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, +intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; @@ -681,33 +681,44 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode * int lane_count, clock; int max_lane_count = intel_dp_max_lane_count(intel_dp); int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0; - int bpp; + int bpp, mode_rate; static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 }; if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) { intel_fixed_panel_mode(intel_dp->panel_fixed_mode, adjusted_mode); intel_pch_panel_fitting(dev, DRM_MODE_SCALE_FULLSCREEN, mode, adjusted_mode); + /* + * the mode->clock is used to calculate the Data&Link M/N + * of the pipe. For the eDP the fixed clock should be used. + */ + mode->clock = intel_dp->panel_fixed_mode->clock; } + DRM_DEBUG_KMS("DP link computation with max lane count %i " + "max bw %02x pixel clock %iKHz\n", + max_lane_count, bws[max_clock], mode->clock); + if (!intel_dp_adjust_dithering(intel_dp, adjusted_mode, adjusted_mode)) return false; bpp = adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC ? 18 : 24; + mode_rate = intel_dp_link_required(mode->clock, bpp); for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) { for (clock = 0; clock <= max_clock; clock++) { int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count); - if (intel_dp_link_required(adjusted_mode->clock, bpp) - <= link_avail) { + if (mode_rate <= link_avail) { intel_dp->link_bw = bws[clock]; intel_dp->lane_count = lane_count; adjusted_mode->clock = intel_dp_link_clock(intel_dp->link_bw); - DRM_DEBUG_KMS("Display port link bw %02x lane " - "count %d clock %d\n", + DRM_DEBUG_KMS("DP link bw %02x lane " + "count %d clock %d bpp %d\n", intel_dp->link_bw, intel_dp->lane_count, - adjusted_mode->clock); + adjusted_mode->clock, bpp); + DRM_DEBUG_KMS("DP link bw required %i available %i\n", + mode_rate, link_avail); return true; } } @@ -1140,6 +1151,7 @@ static void ironlake_edp_panel_off(struct intel_dp *intel_dp) if (intel_dp->want_panel_vdd) printf("Cannot turn power off while VDD is on\n"); + ironlake_panel_vdd_off_sync(intel_dp); /* finish any pending work */ pp = ironlake_get_pp_control(dev_priv); pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE); @@ -1937,6 +1949,23 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp) return false; } +static void +intel_dp_probe_oui(struct intel_dp *intel_dp) +{ + u8 buf[3]; + + if (!(intel_dp->dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT)) + return; + + if (intel_dp_aux_native_read_retry(intel_dp, DP_SINK_OUI, buf, 3)) + DRM_DEBUG_KMS("Sink OUI: %02x%02x%02x\n", + buf[0], buf[1], buf[2]); + + if (intel_dp_aux_native_read_retry(intel_dp, DP_BRANCH_OUI, buf, 3)) + DRM_DEBUG_KMS("Branch OUI: %02x%02x%02x\n", + buf[0], buf[1], buf[2]); +} + static bool intel_dp_get_sink_irq(struct intel_dp *intel_dp, u8 *sink_irq_vector) { @@ -2114,6 +2143,8 @@ intel_dp_detect(struct drm_connector *connector, bool force) if (status != connector_status_connected) return status; + intel_dp_probe_oui(intel_dp); + if (intel_dp->force_audio != HDMI_AUDIO_AUTO) { intel_dp->has_audio = (intel_dp->force_audio == HDMI_AUDIO_ON); } else { @@ -2428,6 +2459,7 @@ intel_dp_init(struct drm_device *dev, int output_reg) } intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); + connector->interlace_allowed = true; connector->doublescan_allowed = 0; @@ -2475,6 +2507,13 @@ intel_dp_init(struct drm_device *dev, int output_reg) pp_off = I915_READ(PCH_PP_OFF_DELAYS); pp_div = I915_READ(PCH_PP_DIVISOR); + if (!pp_on || !pp_off || !pp_div) { + DRM_INFO("bad panel power sequencing delays, disabling panel\n"); + intel_dp_encoder_destroy(&intel_dp->base.base); + intel_dp_destroy(&intel_connector->base); + return; + } + /* Pull timing values out of registers */ cur.t1_t3 = (pp_on & PANEL_POWER_UP_DELAY_MASK) >> PANEL_POWER_UP_DELAY_SHIFT; diff --git a/sys/dev/drm2/i915/intel_drv.h b/sys/dev/drm2/i915/intel_drv.h index bc2c55c6b917..f2b55225a2ee 100644 --- a/sys/dev/drm2/i915/intel_drv.h +++ b/sys/dev/drm2/i915/intel_drv.h @@ -55,6 +55,21 @@ ret; \ }) +#define wait_for_atomic_us(COND, US) ({ \ + int i, ret__ = -ETIMEDOUT; \ + for (i = 0; i < (US); i++) { \ + if ((COND)) { \ + ret__ = 0; \ + break; \ + } \ + DELAY(1); \ + } \ + ret__; \ +}) + +#define wait_for(COND, MS) _intel_wait_for(NULL, COND, MS, 1, "915wfi") +#define wait_for_atomic(COND, MS) _intel_wait_for(NULL, COND, MS, 0, "915wfa") + #define KHz(x) (1000*x) #define MHz(x) KHz(1000*x) @@ -174,8 +189,8 @@ struct intel_crtc { bool cursor_visible; unsigned int bpp; - bool no_pll; /* tertiary pipe for IVB */ - bool use_pll_a; + /* We can share PLLs across outputs if the timings match */ + struct intel_pch_pll *pch_pll; }; struct intel_plane { @@ -199,6 +214,25 @@ struct intel_plane { struct drm_intel_sprite_colorkey *key); }; +struct intel_watermark_params { + unsigned long fifo_size; + unsigned long max_wm; + unsigned long default_wm; + unsigned long guard_size; + unsigned long cacheline_size; +}; + +struct cxsr_latency { + int is_desktop; + int is_ddr3; + unsigned long fsb_freq; + unsigned long mem_freq; + unsigned long display_sr; + unsigned long display_hpll_disable; + unsigned long cursor_sr; + unsigned long cursor_hpll_disable; +}; + #define to_intel_crtc(x) container_of(x, struct intel_crtc, base) #define to_intel_connector(x) container_of(x, struct intel_connector, base) #define to_intel_encoder(x) container_of(x, struct intel_encoder, base) @@ -210,6 +244,8 @@ struct intel_plane { #define DIP_TYPE_AVI 0x82 #define DIP_VERSION_AVI 0x2 #define DIP_LEN_AVI 13 +#define DIP_AVI_PR_1 0 +#define DIP_AVI_PR_2 1 #define DIP_TYPE_SPD 0x83 #define DIP_VERSION_SPD 0x1 @@ -243,23 +279,36 @@ struct dip_infoframe { uint8_t ITC_EC_Q_SC; /* PB4 - VIC 6:0 */ uint8_t VIC; - /* PB5 - PR 3:0 */ - uint8_t PR; + /* PB5 - YQ 7:6, CN 5:4, PR 3:0 */ + uint8_t YQ_CN_PR; /* PB6 to PB13 */ uint16_t top_bar_end; uint16_t bottom_bar_start; uint16_t left_bar_end; uint16_t right_bar_start; - } avi; + } __attribute__ ((packed)) avi; struct { uint8_t vn[8]; uint8_t pd[16]; uint8_t sdi; - } spd; + } __attribute__ ((packed)) spd; uint8_t payload[27]; } __attribute__ ((packed)) body; } __attribute__((packed)); +struct intel_hdmi { + struct intel_encoder base; + u32 sdvox_reg; + int ddc_bus; + int ddi_port; + uint32_t color_range; + bool has_hdmi_sink; + bool has_audio; + enum hdmi_force_audio force_audio; + void (*write_infoframe)(struct drm_encoder *encoder, + struct dip_infoframe *frame); +}; + static inline struct drm_crtc * intel_get_crtc_for_pipe(struct drm_device *dev, int pipe) { @@ -299,8 +348,13 @@ extern void intel_attach_broadcast_rgb_property(struct drm_connector *connector) extern void intel_crt_init(struct drm_device *dev); extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg); -void intel_dip_infoframe_csum(struct dip_infoframe *avi_if); -extern bool intel_sdvo_init(struct drm_device *dev, int output_device); +extern struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder); +extern void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, + struct drm_display_mode *adjusted_mode); +extern void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder); +extern void intel_dip_infoframe_csum(struct dip_infoframe *avi_if); +extern bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, + bool is_sdvob); extern void intel_dvo_init(struct drm_device *dev); extern void intel_tv_init(struct drm_device *dev); extern void intel_mark_busy(struct drm_device *dev, @@ -314,6 +368,10 @@ extern bool intel_dpd_is_edp(struct drm_device *dev); extern void intel_edp_link_config(struct intel_encoder *, int *, int *); extern bool intel_encoder_is_pch_edp(struct drm_encoder *encoder); extern int intel_plane_init(struct drm_device *dev, enum pipe pipe); +extern void intel_flush_display_plane(struct drm_i915_private *dev_priv, + enum plane plane); + +void intel_sanitize_pm(struct drm_device *dev); /* intel_panel.c */ extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, @@ -371,12 +429,19 @@ extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, u16 *blue, int regno); extern void intel_enable_clock_gating(struct drm_device *dev); +extern void ironlake_disable_rc6(struct drm_device *dev); extern void ironlake_enable_drps(struct drm_device *dev); extern void ironlake_disable_drps(struct drm_device *dev); extern void gen6_enable_rps(struct drm_i915_private *dev_priv); extern void gen6_update_ring_freq(struct drm_i915_private *dev_priv); extern void gen6_disable_rps(struct drm_device *dev); extern void intel_init_emon(struct drm_device *dev); +extern int intel_enable_rc6(const struct drm_device *dev); + +extern void intel_ddi_dpms(struct drm_encoder *encoder, int mode); +extern void intel_ddi_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); extern int intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_i915_gem_object *obj, @@ -414,15 +479,30 @@ extern void intel_init_clock_gating(struct drm_device *dev); extern void intel_write_eld(struct drm_encoder *encoder, struct drm_display_mode *mode); extern void intel_cpt_verify_modeset(struct drm_device *dev, int pipe); +extern void intel_prepare_ddi(struct drm_device *dev); +extern void hsw_fdi_link_train(struct drm_crtc *crtc); +extern void intel_ddi_init(struct drm_device *dev, enum port port); /* For use by IVB LP watermark workaround in intel_sprite.c */ -extern void sandybridge_update_wm(struct drm_device *dev); +extern void intel_update_watermarks(struct drm_device *dev); extern void intel_update_sprite_watermarks(struct drm_device *dev, int pipe, uint32_t sprite_width, int pixel_size); +extern void intel_update_linetime_watermarks(struct drm_device *dev, int pipe, + struct drm_display_mode *mode); + extern int intel_sprite_set_colorkey(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int intel_sprite_get_colorkey(struct drm_device *dev, void *data, struct drm_file *file_priv); -#endif +extern u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg); + +/* Power-related functions, located in intel_pm.c */ +extern void intel_init_pm(struct drm_device *dev); +/* FBC */ +extern bool intel_fbc_enabled(struct drm_device *dev); +extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval); +extern void intel_update_fbc(struct drm_device *dev); + +#endif /* __INTEL_DRV_H__ */ diff --git a/sys/dev/drm2/i915/intel_fb.c b/sys/dev/drm2/i915/intel_fb.c index f8a68ec92b39..124b7693e1b6 100644 --- a/sys/dev/drm2/i915/intel_fb.c +++ b/sys/dev/drm2/i915/intel_fb.c @@ -73,7 +73,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev, DRM_LOCK(dev); /* Flush everything out, we'll be doing GTT only from now on */ - ret = intel_pin_and_fence_fb_obj(dev, obj, false); + ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); if (ret) { DRM_ERROR("failed to pin fb: %d\n", ret); goto out_unref; diff --git a/sys/dev/drm2/i915/intel_hdmi.c b/sys/dev/drm2/i915/intel_hdmi.c index f076608d30df..3f0572f260c7 100644 --- a/sys/dev/drm2/i915/intel_hdmi.c +++ b/sys/dev/drm2/i915/intel_hdmi.c @@ -37,19 +37,7 @@ __FBSDID("$FreeBSD$"); #include #include -struct intel_hdmi { - struct intel_encoder base; - u32 sdvox_reg; - int ddc_bus; - uint32_t color_range; - bool has_hdmi_sink; - bool has_audio; - enum hdmi_force_audio force_audio; - void (*write_infoframe)(struct drm_encoder *encoder, - struct dip_infoframe *frame); -}; - -static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder) +struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder) { return container_of(encoder, struct intel_hdmi, base.base); } @@ -75,107 +63,244 @@ void intel_dip_infoframe_csum(struct dip_infoframe *frame) frame->checksum = 0x100 - sum; } -static u32 intel_infoframe_index(struct dip_infoframe *frame) +static u32 g4x_infoframe_index(struct dip_infoframe *frame) { - u32 flags = 0; - switch (frame->type) { case DIP_TYPE_AVI: - flags |= VIDEO_DIP_SELECT_AVI; - break; + return VIDEO_DIP_SELECT_AVI; case DIP_TYPE_SPD: - flags |= VIDEO_DIP_SELECT_SPD; - break; + return VIDEO_DIP_SELECT_SPD; default: - DRM_DEBUG("unknown info frame type %d\n", frame->type); - break; + DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); + return 0; } - - return flags; } -static u32 intel_infoframe_flags(struct dip_infoframe *frame) +static u32 g4x_infoframe_enable(struct dip_infoframe *frame) { - u32 flags = 0; - switch (frame->type) { case DIP_TYPE_AVI: - flags |= VIDEO_DIP_ENABLE_AVI | VIDEO_DIP_FREQ_VSYNC; - break; + return VIDEO_DIP_ENABLE_AVI; case DIP_TYPE_SPD: - flags |= VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_FREQ_VSYNC; - break; + return VIDEO_DIP_ENABLE_SPD; default: - DRM_DEBUG("unknown info frame type %d\n", frame->type); - break; + DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); + return 0; } - - return flags; } -static void i9xx_write_infoframe(struct drm_encoder *encoder, - struct dip_infoframe *frame) +static u32 hsw_infoframe_enable(struct dip_infoframe *frame) +{ + switch (frame->type) { + case DIP_TYPE_AVI: + return VIDEO_DIP_ENABLE_AVI_HSW; + case DIP_TYPE_SPD: + return VIDEO_DIP_ENABLE_SPD_HSW; + default: + DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); + return 0; + } +} + +static u32 hsw_infoframe_data_reg(struct dip_infoframe *frame, enum pipe pipe) +{ + switch (frame->type) { + case DIP_TYPE_AVI: + return HSW_TVIDEO_DIP_AVI_DATA(pipe); + case DIP_TYPE_SPD: + return HSW_TVIDEO_DIP_SPD_DATA(pipe); + default: + DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); + return 0; + } +} + +static void g4x_write_infoframe(struct drm_encoder *encoder, + struct dip_infoframe *frame) { uint32_t *data = (uint32_t *)frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); - u32 port, flags, val = I915_READ(VIDEO_DIP_CTL); + u32 val = I915_READ(VIDEO_DIP_CTL); unsigned i, len = DIP_HEADER_SIZE + frame->len; - - /* XXX first guess at handling video port, is this corrent? */ + val &= ~VIDEO_DIP_PORT_MASK; if (intel_hdmi->sdvox_reg == SDVOB) - port = VIDEO_DIP_PORT_B; + val |= VIDEO_DIP_PORT_B; else if (intel_hdmi->sdvox_reg == SDVOC) - port = VIDEO_DIP_PORT_C; + val |= VIDEO_DIP_PORT_C; else return; - flags = intel_infoframe_index(frame); + val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ + val |= g4x_infoframe_index(frame); - val &= ~VIDEO_DIP_SELECT_MASK; + val &= ~g4x_infoframe_enable(frame); + val |= VIDEO_DIP_ENABLE; - I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | val | port | flags); + I915_WRITE(VIDEO_DIP_CTL, val); for (i = 0; i < len; i += 4) { I915_WRITE(VIDEO_DIP_DATA, *data); data++; } - flags |= intel_infoframe_flags(frame); + val |= g4x_infoframe_enable(frame); + val &= ~VIDEO_DIP_FREQ_MASK; + val |= VIDEO_DIP_FREQ_VSYNC; - I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | val | port | flags); + I915_WRITE(VIDEO_DIP_CTL, val); } -static void ironlake_write_infoframe(struct drm_encoder *encoder, - struct dip_infoframe *frame) +static void ibx_write_infoframe(struct drm_encoder *encoder, + struct dip_infoframe *frame) { uint32_t *data = (uint32_t *)frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc = encoder->crtc; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); int reg = TVIDEO_DIP_CTL(intel_crtc->pipe); unsigned i, len = DIP_HEADER_SIZE + frame->len; - u32 flags, val = I915_READ(reg); + u32 val = I915_READ(reg); + + val &= ~VIDEO_DIP_PORT_MASK; + switch (intel_hdmi->sdvox_reg) { + case HDMIB: + val |= VIDEO_DIP_PORT_B; + break; + case HDMIC: + val |= VIDEO_DIP_PORT_C; + break; + case HDMID: + val |= VIDEO_DIP_PORT_D; + break; + default: + return; + } intel_wait_for_vblank(dev, intel_crtc->pipe); - flags = intel_infoframe_index(frame); - val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ + val |= g4x_infoframe_index(frame); - I915_WRITE(reg, VIDEO_DIP_ENABLE | val | flags); + val &= ~g4x_infoframe_enable(frame); + val |= VIDEO_DIP_ENABLE; + + I915_WRITE(reg, val); for (i = 0; i < len; i += 4) { I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data); data++; } - flags |= intel_infoframe_flags(frame); + val |= g4x_infoframe_enable(frame); + val &= ~VIDEO_DIP_FREQ_MASK; + val |= VIDEO_DIP_FREQ_VSYNC; - I915_WRITE(reg, VIDEO_DIP_ENABLE | val | flags); + I915_WRITE(reg, val); +} + +static void cpt_write_infoframe(struct drm_encoder *encoder, + struct dip_infoframe *frame) +{ + uint32_t *data = (uint32_t *)frame; + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); + int reg = TVIDEO_DIP_CTL(intel_crtc->pipe); + unsigned i, len = DIP_HEADER_SIZE + frame->len; + u32 val = I915_READ(reg); + + intel_wait_for_vblank(dev, intel_crtc->pipe); + + val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ + val |= g4x_infoframe_index(frame); + + /* The DIP control register spec says that we need to update the AVI + * infoframe without clearing its enable bit */ + if (frame->type == DIP_TYPE_AVI) + val |= VIDEO_DIP_ENABLE_AVI; + else + val &= ~g4x_infoframe_enable(frame); + + val |= VIDEO_DIP_ENABLE; + + I915_WRITE(reg, val); + + for (i = 0; i < len; i += 4) { + I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data); + data++; + } + + val |= g4x_infoframe_enable(frame); + val &= ~VIDEO_DIP_FREQ_MASK; + val |= VIDEO_DIP_FREQ_VSYNC; + + I915_WRITE(reg, val); +} + +static void vlv_write_infoframe(struct drm_encoder *encoder, + struct dip_infoframe *frame) +{ + uint32_t *data = (uint32_t *)frame; + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); + int reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe); + unsigned i, len = DIP_HEADER_SIZE + frame->len; + u32 val = I915_READ(reg); + + intel_wait_for_vblank(dev, intel_crtc->pipe); + + val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ + val |= g4x_infoframe_index(frame); + + val &= ~g4x_infoframe_enable(frame); + val |= VIDEO_DIP_ENABLE; + + I915_WRITE(reg, val); + + for (i = 0; i < len; i += 4) { + I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), *data); + data++; + } + + val |= g4x_infoframe_enable(frame); + val &= ~VIDEO_DIP_FREQ_MASK; + val |= VIDEO_DIP_FREQ_VSYNC; + + I915_WRITE(reg, val); +} + +static void hsw_write_infoframe(struct drm_encoder *encoder, + struct dip_infoframe *frame) +{ + uint32_t *data = (uint32_t *)frame; + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); + u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->pipe); + u32 data_reg = hsw_infoframe_data_reg(frame, intel_crtc->pipe); + unsigned int i, len = DIP_HEADER_SIZE + frame->len; + u32 val = I915_READ(ctl_reg); + + if (data_reg == 0) + return; + + intel_wait_for_vblank(dev, intel_crtc->pipe); + + val &= ~hsw_infoframe_enable(frame); + I915_WRITE(ctl_reg, val); + + for (i = 0; i < len; i += 4) { + I915_WRITE(data_reg + i, *data); + data++; + } + + val |= hsw_infoframe_enable(frame); + I915_WRITE(ctl_reg, val); } static void intel_set_infoframe(struct drm_encoder *encoder, @@ -190,7 +315,8 @@ static void intel_set_infoframe(struct drm_encoder *encoder, intel_hdmi->write_infoframe(encoder, frame); } -static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder) +void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, + struct drm_display_mode *adjusted_mode) { struct dip_infoframe avi_if = { .type = DIP_TYPE_AVI, @@ -198,10 +324,13 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder) .len = DIP_LEN_AVI, }; + if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) + avi_if.body.avi.YQ_CN_PR |= DIP_AVI_PR_2; + intel_set_infoframe(encoder, &avi_if); } -static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder) +void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder) { struct dip_infoframe spd_if; @@ -222,8 +351,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, { struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc = encoder->crtc; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); u32 sdvox; @@ -260,7 +388,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, I915_WRITE(intel_hdmi->sdvox_reg, sdvox); POSTING_READ(intel_hdmi->sdvox_reg); - intel_hdmi_set_avi_infoframe(encoder); + intel_hdmi_set_avi_infoframe(encoder, adjusted_mode); intel_hdmi_set_spd_infoframe(encoder); } @@ -318,7 +446,7 @@ static int intel_hdmi_mode_valid(struct drm_connector *connector, } static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, + struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { return true; @@ -334,7 +462,8 @@ intel_hdmi_detect(struct drm_connector *connector, bool force) intel_hdmi->has_hdmi_sink = false; intel_hdmi->has_audio = false; - edid = drm_get_edid(connector, dev_priv->gmbus[intel_hdmi->ddc_bus]); + edid = drm_get_edid(connector, intel_gmbus_get_adapter(dev_priv, + intel_hdmi->ddc_bus)); if (edid) { if (edid->input & DRM_EDID_INPUT_DIGITAL) { @@ -371,7 +500,8 @@ static int intel_hdmi_get_modes(struct drm_connector *connector) */ return intel_ddc_get_modes(connector, - dev_priv->gmbus[intel_hdmi->ddc_bus]); + intel_gmbus_get_adapter(dev_priv, + intel_hdmi->ddc_bus)); } static bool @@ -382,7 +512,9 @@ intel_hdmi_detect_audio(struct drm_connector *connector) struct edid *edid; bool has_audio = false; - edid = drm_get_edid(connector, dev_priv->gmbus[intel_hdmi->ddc_bus]); + edid = drm_get_edid(connector, + intel_gmbus_get_adapter(dev_priv, + intel_hdmi->ddc_bus)); if (edid) { if (edid->input & DRM_EDID_INPUT_DIGITAL) has_audio = drm_detect_monitor_audio(edid); @@ -458,6 +590,14 @@ static void intel_hdmi_destroy(struct drm_connector *connector) free(connector, DRM_MEM_KMS); } +static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs_hsw = { + .dpms = intel_ddi_dpms, + .mode_fixup = intel_hdmi_mode_fixup, + .prepare = intel_encoder_prepare, + .mode_set = intel_ddi_mode_set, + .commit = intel_encoder_commit, +}; + static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = { .dpms = intel_hdmi_dpms, .mode_fixup = intel_hdmi_mode_fixup, @@ -542,21 +682,59 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) intel_encoder->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT); intel_hdmi->ddc_bus = GMBUS_PORT_DPD; dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS; + } else if (sdvox_reg == DDI_BUF_CTL(PORT_B)) { + DRM_DEBUG_DRIVER("LPT: detected output on DDI B\n"); + intel_encoder->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT); + intel_hdmi->ddc_bus = GMBUS_PORT_DPB; + intel_hdmi->ddi_port = PORT_B; + dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; + } else if (sdvox_reg == DDI_BUF_CTL(PORT_C)) { + DRM_DEBUG_DRIVER("LPT: detected output on DDI C\n"); + intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT); + intel_hdmi->ddc_bus = GMBUS_PORT_DPC; + intel_hdmi->ddi_port = PORT_C; + dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; + } else if (sdvox_reg == DDI_BUF_CTL(PORT_D)) { + DRM_DEBUG_DRIVER("LPT: detected output on DDI D\n"); + intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT); + intel_hdmi->ddc_bus = GMBUS_PORT_DPD; + intel_hdmi->ddi_port = PORT_D; + dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS; + } else { + /* If we got an unknown sdvox_reg, things are pretty much broken + * in a way that we should let the kernel know about it */ + DRM_DEBUG_KMS("unknown sdvox_reg %d\n", sdvox_reg); } - intel_hdmi->sdvox_reg = sdvox_reg; - if (!HAS_PCH_SPLIT(dev)) { - intel_hdmi->write_infoframe = i9xx_write_infoframe; + intel_hdmi->write_infoframe = g4x_write_infoframe; I915_WRITE(VIDEO_DIP_CTL, 0); + } else if (IS_VALLEYVIEW(dev)) { + intel_hdmi->write_infoframe = vlv_write_infoframe; + for_each_pipe(i) + I915_WRITE(VLV_TVIDEO_DIP_CTL(i), 0); + } else if (IS_HASWELL(dev)) { + /* FIXME: Haswell has a new set of DIP frame registers, but we are + * just doing the minimal required for HDMI to work at this stage. + */ + intel_hdmi->write_infoframe = hsw_write_infoframe; + for_each_pipe(i) + I915_WRITE(HSW_TVIDEO_DIP_CTL(i), 0); + } else if (HAS_PCH_IBX(dev)) { + intel_hdmi->write_infoframe = ibx_write_infoframe; + for_each_pipe(i) + I915_WRITE(TVIDEO_DIP_CTL(i), 0); } else { - intel_hdmi->write_infoframe = ironlake_write_infoframe; + intel_hdmi->write_infoframe = cpt_write_infoframe; for_each_pipe(i) I915_WRITE(TVIDEO_DIP_CTL(i), 0); } - drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs); + if (IS_HASWELL(dev)) + drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs_hsw); + else + drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs); intel_hdmi_add_properties(intel_hdmi, connector); diff --git a/sys/dev/drm2/i915/intel_iic.c b/sys/dev/drm2/i915/intel_iic.c index 412349c8d9d0..fdd59e5d1eda 100644 --- a/sys/dev/drm2/i915/intel_iic.c +++ b/sys/dev/drm2/i915/intel_iic.c @@ -67,9 +67,22 @@ __FBSDID("$FreeBSD$"); #include "iicbus_if.h" #include "iicbb_if.h" -static int intel_iic_quirk_xfer(device_t idev, struct iic_msg *msgs, int nmsgs); static void intel_teardown_gmbus_m(struct drm_device *dev, int m); +struct gmbus_port { + const char *name; + int reg; +}; + +static const struct gmbus_port gmbus_ports[] = { + { "ssc", GPIOB }, + { "vga", GPIOA }, + { "panel", GPIOC }, + { "dpc", GPIOD }, + { "dpb", GPIOE }, + { "dpd", GPIOF }, +}; + /* Intel GPIO access functions */ #define I2C_RISEFALL_TIME 10 @@ -128,10 +141,7 @@ intel_iic_reset(struct drm_device *dev) struct drm_i915_private *dev_priv; dev_priv = dev->dev_private; - if (HAS_PCH_SPLIT(dev)) - I915_WRITE(PCH_GMBUS0, 0); - else - I915_WRITE(GMBUS0, 0); + I915_WRITE(dev_priv->gpio_mmio_base + GMBUS0, 0); } static int @@ -224,129 +234,232 @@ intel_iicbb_getscl(device_t idev) return ((I915_READ_NOTRACE(sc->reg) & GPIO_CLOCK_VAL_IN) != 0); } +static int +gmbus_xfer_read(struct drm_i915_private *dev_priv, struct iic_msg *msg, + u32 gmbus1_index) +{ + int reg_offset = dev_priv->gpio_mmio_base; + u16 len = msg->len; + u8 *buf = msg->buf; + + I915_WRITE(GMBUS1 + reg_offset, + gmbus1_index | + GMBUS_CYCLE_WAIT | + (len << GMBUS_BYTE_COUNT_SHIFT) | + (msg->slave << (GMBUS_SLAVE_ADDR_SHIFT - 1)) | + GMBUS_SLAVE_READ | GMBUS_SW_RDY); + while (len) { + int ret; + u32 val, loop = 0; + u32 gmbus2; + + ret = _intel_wait_for(sc->drm_dev, + ((gmbus2 = I915_READ(GMBUS2 + reg_offset)) & + (GMBUS_SATOER | GMBUS_HW_RDY)), + 50, 1, "915gbr"); + if (ret) + return (ETIMEDOUT); + if (gmbus2 & GMBUS_SATOER) + return (ENXIO); + + val = I915_READ(GMBUS3 + reg_offset); + do { + *buf++ = val & 0xff; + val >>= 8; + } while (--len != 0 && ++loop < 4); + } + + return 0; +} + +static int +gmbus_xfer_write(struct drm_i915_private *dev_priv, struct iic_msg *msg) +{ + int reg_offset = dev_priv->gpio_mmio_base; + u16 len = msg->len; + u8 *buf = msg->buf; + u32 val, loop; + + val = loop = 0; + while (len && loop < 4) { + val |= *buf++ << (8 * loop++); + len -= 1; + } + + I915_WRITE(GMBUS3 + reg_offset, val); + I915_WRITE(GMBUS1 + reg_offset, + GMBUS_CYCLE_WAIT | + (msg->len << GMBUS_BYTE_COUNT_SHIFT) | + (msg->slave << (GMBUS_SLAVE_ADDR_SHIFT - 1)) | + GMBUS_SLAVE_WRITE | GMBUS_SW_RDY); + while (len) { + int ret; + u32 gmbus2; + + val = loop = 0; + do { + val |= *buf++ << (8 * loop); + } while (--len != 0 && ++loop < 4); + + I915_WRITE(GMBUS3 + reg_offset, val); + + ret = _intel_wait_for(sc->drm_dev, + ((gmbus2 = I915_READ(GMBUS2 + reg_offset)) & + (GMBUS_SATOER | GMBUS_HW_RDY)), + 50, 1, "915gbw"); + if (ret) + return (ETIMEDOUT); + if (gmbus2 & GMBUS_SATOER) + return (ENXIO); + } + return 0; +} + +/* + * The gmbus controller can combine a 1 or 2 byte write with a read that + * immediately follows it by using an "INDEX" cycle. + */ +static bool +gmbus_is_index_read(struct iic_msg *msgs, int i, int num) +{ + return (i + 1 < num && + !(msgs[i].flags & IIC_M_RD) && msgs[i].len <= 2 && + (msgs[i + 1].flags & IIC_M_RD)); +} + +static int +gmbus_xfer_index_read(struct drm_i915_private *dev_priv, struct iic_msg *msgs) +{ + int reg_offset = dev_priv->gpio_mmio_base; + u32 gmbus1_index = 0; + u32 gmbus5 = 0; + int ret; + + if (msgs[0].len == 2) + gmbus5 = GMBUS_2BYTE_INDEX_EN | + msgs[0].buf[1] | (msgs[0].buf[0] << 8); + if (msgs[0].len == 1) + gmbus1_index = GMBUS_CYCLE_INDEX | + (msgs[0].buf[0] << GMBUS_SLAVE_INDEX_SHIFT); + + /* GMBUS5 holds 16-bit index */ + if (gmbus5) + I915_WRITE(GMBUS5 + reg_offset, gmbus5); + + ret = gmbus_xfer_read(dev_priv, &msgs[1], gmbus1_index); + + /* Clear GMBUS5 after each index transfer */ + if (gmbus5) + I915_WRITE(GMBUS5 + reg_offset, 0); + + return ret; +} + static int intel_gmbus_transfer(device_t idev, struct iic_msg *msgs, uint32_t nmsgs) { struct intel_iic_softc *sc; struct drm_i915_private *dev_priv; - u8 *buf; - int error, i, reg_offset, unit; - u32 val, loop; - u16 len; + int error, i, ret, reg_offset, unit; + error = 0; sc = device_get_softc(idev); dev_priv = sc->drm_dev->dev_private; unit = device_get_unit(idev); sx_xlock(&dev_priv->gmbus_sx); if (sc->force_bit_dev) { - error = intel_iic_quirk_xfer(dev_priv->bbbus[unit], msgs, nmsgs); + error = IICBUS_TRANSFER(dev_priv->bbbus[unit], msgs, nmsgs); goto out; } - reg_offset = HAS_PCH_SPLIT(dev_priv->dev) ? PCH_GMBUS0 - GMBUS0 : 0; + reg_offset = dev_priv->gpio_mmio_base; I915_WRITE(GMBUS0 + reg_offset, sc->reg0); for (i = 0; i < nmsgs; i++) { - len = msgs[i].len; - buf = msgs[i].buf; + u32 gmbus2; - if ((msgs[i].flags & IIC_M_RD) != 0) { - I915_WRITE(GMBUS1 + reg_offset, GMBUS_CYCLE_WAIT | - (i + 1 == nmsgs ? GMBUS_CYCLE_STOP : 0) | - (len << GMBUS_BYTE_COUNT_SHIFT) | - (msgs[i].slave << (GMBUS_SLAVE_ADDR_SHIFT - 1)) | - GMBUS_SLAVE_READ | GMBUS_SW_RDY); - POSTING_READ(GMBUS2 + reg_offset); - do { - loop = 0; - - if (_intel_wait_for(sc->drm_dev, - (I915_READ(GMBUS2 + reg_offset) & - (GMBUS_SATOER | GMBUS_HW_RDY)) != 0, - 50, 1, "915gbr")) - goto timeout; - if ((I915_READ(GMBUS2 + reg_offset) & - GMBUS_SATOER) != 0) - goto clear_err; - - val = I915_READ(GMBUS3 + reg_offset); - do { - *buf++ = val & 0xff; - val >>= 8; - } while (--len != 0 && ++loop < 4); - } while (len != 0); + if (gmbus_is_index_read(msgs, i, nmsgs)) { + error = gmbus_xfer_index_read(dev_priv, &msgs[i]); + i += 1; /* set i to the index of the read xfer */ + } else if (msgs[i].flags & IIC_M_RD) { + error = gmbus_xfer_read(dev_priv, &msgs[i], 0); } else { - val = loop = 0; - do { - val |= *buf++ << (8 * loop); - } while (--len != 0 && ++loop < 4); - - I915_WRITE(GMBUS3 + reg_offset, val); - I915_WRITE(GMBUS1 + reg_offset, GMBUS_CYCLE_WAIT | - (i + 1 == nmsgs ? GMBUS_CYCLE_STOP : 0) | - (msgs[i].len << GMBUS_BYTE_COUNT_SHIFT) | - (msgs[i].slave << (GMBUS_SLAVE_ADDR_SHIFT - 1)) | - GMBUS_SLAVE_WRITE | GMBUS_SW_RDY); - POSTING_READ(GMBUS2+reg_offset); - - while (len != 0) { - if (_intel_wait_for(sc->drm_dev, - (I915_READ(GMBUS2 + reg_offset) & - (GMBUS_SATOER | GMBUS_HW_RDY)) != 0, - 50, 1, "915gbw")) - goto timeout; - if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) - goto clear_err; - - val = loop = 0; - do { - val |= *buf++ << (8 * loop); - } while (--len != 0 && ++loop < 4); - - I915_WRITE(GMBUS3 + reg_offset, val); - POSTING_READ(GMBUS2 + reg_offset); - } + error = gmbus_xfer_write(dev_priv, &msgs[i]); } - if (i + 1 < nmsgs && _intel_wait_for(sc->drm_dev, - (I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | - GMBUS_HW_WAIT_PHASE)) != 0, - 50, 1, "915gbh")) + if (error == ETIMEDOUT) goto timeout; - if ((I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) != 0) + if (error == ENXIO) + goto clear_err; + + ret = _intel_wait_for(sc->drm_dev, + ((gmbus2 = I915_READ(GMBUS2 + reg_offset)) & + (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE)), + 50, 1, "915gbh"); + if (ret) + goto timeout; + if (gmbus2 & GMBUS_SATOER) goto clear_err; } - error = 0; -done: + /* Generate a STOP condition on the bus. Note that gmbus can't generata + * a STOP on the very first cycle. To simplify the code we + * unconditionally generate the STOP condition with an additional gmbus + * cycle. */ + I915_WRITE(GMBUS1 + reg_offset, GMBUS_CYCLE_STOP | GMBUS_SW_RDY); + /* Mark the GMBUS interface as disabled after waiting for idle. * We will re-enable it at the start of the next xfer, * till then let it sleep. */ if (_intel_wait_for(dev, (I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0, - 10, 1, "915gbu")) - DRM_INFO("GMBUS timed out waiting for idle\n"); + 10, 1, "915gbu")) { + DRM_DEBUG_KMS("GMBUS [%s] timed out waiting for idle\n", + sc->name); + error = ETIMEDOUT; + } I915_WRITE(GMBUS0 + reg_offset, 0); -out: - sx_xunlock(&dev_priv->gmbus_sx); - return (error); + goto out; clear_err: + /* + * Wait for bus to IDLE before clearing NAK. + * If we clear the NAK while bus is still active, then it will stay + * active and the next transaction may fail. + */ + if (_intel_wait_for(dev, + (I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0, + 10, 1, "915gbu")) + DRM_DEBUG_KMS("GMBUS [%s] timed out after NAK\n", sc->name); + /* Toggle the Software Clear Interrupt bit. This has the effect * of resetting the GMBUS controller and so clearing the * BUS_ERROR raised by the slave's NAK. */ I915_WRITE(GMBUS1 + reg_offset, GMBUS_SW_CLR_INT); I915_WRITE(GMBUS1 + reg_offset, 0); - error = EIO; - goto done; + I915_WRITE(GMBUS0 + reg_offset, 0); + + DRM_DEBUG_KMS("GMBUS [%s] NAK for addr: %04x %c(%d)\n", + sc->name, msgs[i].slave, + (msgs[i].flags & IIC_M_RD) ? 'r' : 'w', msgs[i].len); + + /* + * If no ACK is received during the address phase of a transaction, + * the adapter must report -ENXIO. + * It is not clear what to return if no ACK is received at other times. + * So, we always return -ENXIO in all NAK cases, to ensure we send + * it at least during the one case that is specified. + */ + error = ENXIO; + goto out; timeout: - DRM_INFO("GMBUS timed out, falling back to bit banging on pin %d [%s]\n", - sc->reg0 & 0xff, sc->name); + DRM_INFO("GMBUS [%s] timed out, falling back to bit banging on pin %d\n", + sc->name, sc->reg0 & 0xff); I915_WRITE(GMBUS0 + reg_offset, 0); /* @@ -354,9 +467,23 @@ intel_gmbus_transfer(device_t idev, struct iic_msg *msgs, uint32_t nmsgs) * Try GPIO bitbanging instead. */ sc->force_bit_dev = true; - - error = intel_iic_quirk_xfer(dev_priv->bbbus[unit], msgs, nmsgs); + error = IICBUS_TRANSFER(idev, msgs, nmsgs); goto out; + +out: + sx_xunlock(&dev_priv->gmbus_sx); + return (error); +} + +device_t +intel_gmbus_get_adapter(struct drm_i915_private *dev_priv, + unsigned port) +{ + + if (!intel_gmbus_is_port_valid(port)) + DRM_ERROR("GMBUS get adapter %d: invalid port\n", port); + return (intel_gmbus_is_port_valid(port) ? dev_priv->gmbus[port - 1] : + NULL); } void @@ -379,46 +506,35 @@ intel_gmbus_force_bit(device_t idev, bool force_bit) } static int -intel_iic_quirk_xfer(device_t idev, struct iic_msg *msgs, int nmsgs) +intel_iicbb_pre_xfer(device_t idev) { - device_t bridge_dev; struct intel_iic_softc *sc; struct drm_i915_private *dev_priv; - int ret; - int i; - bridge_dev = device_get_parent(device_get_parent(idev)); - sc = device_get_softc(bridge_dev); + sc = device_get_softc(idev); dev_priv = sc->drm_dev->dev_private; intel_iic_reset(sc->drm_dev); intel_iic_quirk_set(dev_priv, true); - IICBB_SETSDA(bridge_dev, 1); - IICBB_SETSCL(bridge_dev, 1); + IICBB_SETSDA(idev, 1); + IICBB_SETSCL(idev, 1); DELAY(I2C_RISEFALL_TIME); - - for (i = 0; i < nmsgs - 1; i++) { - /* force use of repeated start instead of default stop+start */ - msgs[i].flags |= IIC_M_NOSTOP; - } - ret = iicbus_transfer(idev, msgs, nmsgs); - IICBB_SETSDA(bridge_dev, 1); - IICBB_SETSCL(bridge_dev, 1); - intel_iic_quirk_set(dev_priv, false); - - return (ret); + return (0); } -static const char *gpio_names[GMBUS_NUM_PORTS] = { - "disabled", - "ssc", - "vga", - "panel", - "dpc", - "dpb", - "reserved", - "dpd", -}; +static void +intel_iicbb_post_xfer(device_t idev) +{ + struct intel_iic_softc *sc; + struct drm_i915_private *dev_priv; + + sc = device_get_softc(idev); + dev_priv = sc->drm_dev->dev_private; + + IICBB_SETSDA(idev, 1); + IICBB_SETSCL(idev, 1); + intel_iic_quirk_set(dev_priv, false); +} static int intel_gmbus_probe(device_t dev) @@ -432,23 +548,28 @@ intel_gmbus_attach(device_t idev) { struct drm_i915_private *dev_priv; struct intel_iic_softc *sc; - int pin; + int pin, port; sc = device_get_softc(idev); sc->drm_dev = device_get_softc(device_get_parent(idev)); dev_priv = sc->drm_dev->dev_private; pin = device_get_unit(idev); + port = pin + 1; - snprintf(sc->name, sizeof(sc->name), "gmbus bus %s", gpio_names[pin]); + snprintf(sc->name, sizeof(sc->name), "gmbus %s", gmbus_ports[pin].name); device_set_desc(idev, sc->name); /* By default use a conservative clock rate */ - sc->reg0 = pin | GMBUS_RATE_100KHZ; + sc->reg0 = port | GMBUS_RATE_100KHZ; - /* XXX force bit banging until GMBUS is fully debugged */ + /* gmbus seems to be broken on i830 */ + if (IS_I830(sc->drm_dev)) + sc->force_bit_dev = true; +#if 0 if (IS_GEN2(sc->drm_dev)) { sc->force_bit_dev = true; } +#endif /* add bus interface device */ sc->iic_dev = device_add_child(idev, "iicbus", -1); @@ -490,17 +611,6 @@ intel_iicbb_probe(device_t dev) static int intel_iicbb_attach(device_t idev) { - static const int map_pin_to_reg[] = { - 0, - GPIOB, - GPIOA, - GPIOC, - GPIOD, - GPIOE, - 0, - GPIOF - }; - struct intel_iic_softc *sc; struct drm_i915_private *dev_priv; int pin; @@ -510,13 +620,12 @@ intel_iicbb_attach(device_t idev) dev_priv = sc->drm_dev->dev_private; pin = device_get_unit(idev); - snprintf(sc->name, sizeof(sc->name), "i915 iicbb %s", gpio_names[pin]); + snprintf(sc->name, sizeof(sc->name), "i915 iicbb %s", + gmbus_ports[pin].name); device_set_desc(idev, sc->name); sc->reg0 = pin | GMBUS_RATE_100KHZ; - sc->reg = map_pin_to_reg[pin]; - if (HAS_PCH_SPLIT(dev_priv->dev)) - sc->reg += PCH_GPIOA - GPIOA; + sc->reg = dev_priv->gpio_mmio_base + gmbus_ports[pin].reg; /* add generic bit-banging code */ sc->iic_dev = device_add_child(idev, "iicbb", -1); @@ -524,6 +633,7 @@ intel_iicbb_attach(device_t idev) return (ENXIO); device_quiet(sc->iic_dev); bus_generic_attach(idev); + iicbus_set_nostop(idev, true); return (0); } @@ -574,6 +684,8 @@ static device_method_t intel_iicbb_methods[] = { DEVMETHOD(iicbb_setscl, intel_iicbb_setscl), DEVMETHOD(iicbb_getsda, intel_iicbb_getsda), DEVMETHOD(iicbb_getscl, intel_iicbb_getscl), + DEVMETHOD(iicbb_pre_xfer, intel_iicbb_pre_xfer), + DEVMETHOD(iicbb_post_xfer, intel_iicbb_post_xfer), DEVMETHOD_END }; static driver_t intel_iicbb_driver = { @@ -595,14 +707,10 @@ intel_setup_gmbus(struct drm_device *dev) dev_priv = dev->dev_private; sx_init(&dev_priv->gmbus_sx, "gmbus"); - dev_priv->gmbus_bridge = malloc(sizeof(device_t) * GMBUS_NUM_PORTS, - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); - dev_priv->bbbus_bridge = malloc(sizeof(device_t) * GMBUS_NUM_PORTS, - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); - dev_priv->gmbus = malloc(sizeof(device_t) * GMBUS_NUM_PORTS, - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); - dev_priv->bbbus = malloc(sizeof(device_t) * GMBUS_NUM_PORTS, - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + if (HAS_PCH_SPLIT(dev)) + dev_priv->gpio_mmio_base = PCH_GPIOA - GPIOA; + else + dev_priv->gpio_mmio_base = 0; /* * The Giant there is recursed, most likely. Normally, the @@ -610,7 +718,7 @@ intel_setup_gmbus(struct drm_device *dev) * driver. */ mtx_lock(&Giant); - for (i = 0; i < GMBUS_NUM_PORTS; i++) { + for (i = 0; i <= GMBUS_NUM_PORTS; i++) { /* * Initialized bbbus_bridge before gmbus_bridge, since * gmbus may decide to force quirk transfer in the @@ -689,14 +797,6 @@ intel_teardown_gmbus_m(struct drm_device *dev, int m) dev_priv = dev->dev_private; - free(dev_priv->gmbus, DRM_MEM_DRIVER); - dev_priv->gmbus = NULL; - free(dev_priv->bbbus, DRM_MEM_DRIVER); - dev_priv->bbbus = NULL; - free(dev_priv->gmbus_bridge, DRM_MEM_DRIVER); - dev_priv->gmbus_bridge = NULL; - free(dev_priv->bbbus_bridge, DRM_MEM_DRIVER); - dev_priv->bbbus_bridge = NULL; sx_destroy(&dev_priv->gmbus_sx); } diff --git a/sys/dev/drm2/i915/intel_lvds.c b/sys/dev/drm2/i915/intel_lvds.c index cbf3ea4f7c29..5f749cedcd97 100644 --- a/sys/dev/drm2/i915/intel_lvds.c +++ b/sys/dev/drm2/i915/intel_lvds.c @@ -230,7 +230,7 @@ static inline u32 panel_fitter_scaling(u32 source, u32 target) } static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, + struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; @@ -482,7 +482,7 @@ static int intel_lvds_get_modes(struct drm_connector *connector) static int intel_no_modeset_on_lid_dmi_callback(const struct dmi_system_id *id) { - DRM_DEBUG_KMS("Skipping forced modeset for %s\n", id->ident); + DRM_INFO("Skipping forced modeset for %s\n", id->ident); return 1; } @@ -638,7 +638,7 @@ static const struct drm_encoder_funcs intel_lvds_enc_funcs = { static int intel_no_lvds_dmi_callback(const struct dmi_system_id *id) { - DRM_DEBUG_KMS("Skipping LVDS initialization for %s\n", id->ident); + DRM_INFO("Skipping LVDS initialization for %s\n", id->ident); return 1; } @@ -861,8 +861,8 @@ static bool lvds_is_present_in_vbt(struct drm_device *dev, child->device_type != DEVICE_TYPE_LFP) continue; - if (child->i2c_pin) - *i2c_pin = child->i2c_pin; + if (intel_gmbus_is_port_valid(child->i2c_pin)) + *i2c_pin = child->i2c_pin; /* However, we cannot trust the BIOS writers to populate * the VBT correctly. Since LVDS requires additional @@ -996,7 +996,8 @@ bool intel_lvds_init(struct drm_device *dev) * Attempt to get the fixed panel mode from DDC. Assume that the * preferred mode is the right one. */ - intel_lvds->edid = drm_get_edid(connector, dev_priv->gmbus[pin]); + intel_lvds->edid = drm_get_edid(connector, + intel_gmbus_get_adapter(dev_priv, pin)); if (intel_lvds->edid) { if (drm_add_edid_modes(connector, intel_lvds->edid)) { diff --git a/sys/dev/drm2/i915/intel_modes.c b/sys/dev/drm2/i915/intel_modes.c index 22969d38100a..6b83bae76ea2 100644 --- a/sys/dev/drm2/i915/intel_modes.c +++ b/sys/dev/drm2/i915/intel_modes.c @@ -58,8 +58,8 @@ bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus) } }; - return (iicbus_transfer(dev_priv->gmbus[ddc_bus], msgs, 2) - == 0/* XXXKIB 2*/); + return (iicbus_transfer(intel_gmbus_get_adapter(dev_priv, ddc_bus), + msgs, 2) == 0/* XXXKIB 2*/); } /** diff --git a/sys/dev/drm2/i915/intel_overlay.c b/sys/dev/drm2/i915/intel_overlay.c index 34f2c39224fd..715da2fe0f1c 100644 --- a/sys/dev/drm2/i915/intel_overlay.c +++ b/sys/dev/drm2/i915/intel_overlay.c @@ -219,20 +219,21 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay, { struct drm_device *dev = overlay->dev; drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring = &dev_priv->rings[RCS]; int ret; KASSERT(!overlay->last_flip_req, ("Overlay already has flip req")); - ret = i915_add_request(LP_RING(dev_priv), NULL, request); + ret = i915_add_request(ring, NULL, request); if (ret) { free(request, DRM_I915_GEM); return ret; } overlay->last_flip_req = request->seqno; overlay->flip_tail = tail; - ret = i915_wait_request(LP_RING(dev_priv), overlay->last_flip_req, - true); + ret = i915_wait_request(ring, overlay->last_flip_req); if (ret) return ret; + i915_gem_retire_requests(dev); overlay->last_flip_req = 0; return 0; @@ -266,7 +267,7 @@ i830_activate_pipe_a(struct drm_device *dev) DRM_DEBUG_DRIVER("Enabling pipe A in order to enable overlay\n"); mode = drm_mode_duplicate(dev, &vesa_640x480); - drm_mode_set_crtcinfo(mode, 0); + if (!drm_crtc_helper_set_mode(&crtc->base, mode, crtc->base.x, crtc->base.y, crtc->base.fb)) @@ -291,6 +292,7 @@ static int intel_overlay_on(struct intel_overlay *overlay) { struct drm_device *dev = overlay->dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring = &dev_priv->rings[RCS]; struct drm_i915_gem_request *request; int pipe_a_quirk = 0; int ret; @@ -306,17 +308,17 @@ static int intel_overlay_on(struct intel_overlay *overlay) request = malloc(sizeof(*request), DRM_I915_GEM, M_WAITOK | M_ZERO); - ret = BEGIN_LP_RING(4); + ret = intel_ring_begin(ring, 4); if (ret) { free(request, DRM_I915_GEM); goto out; } - OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON); - OUT_RING(overlay->flip_addr | OFC_UPDATE); - OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); - OUT_RING(MI_NOOP); - ADVANCE_LP_RING(); + intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_ON); + intel_ring_emit(ring, overlay->flip_addr | OFC_UPDATE); + intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); + intel_ring_emit(ring, MI_NOOP); + intel_ring_advance(ring); ret = intel_overlay_do_wait_request(overlay, request, NULL); out: @@ -332,6 +334,7 @@ static int intel_overlay_continue(struct intel_overlay *overlay, { struct drm_device *dev = overlay->dev; drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring = &dev_priv->rings[RCS]; struct drm_i915_gem_request *request; u32 flip_addr = overlay->flip_addr; u32 tmp; @@ -349,16 +352,16 @@ static int intel_overlay_continue(struct intel_overlay *overlay, if (tmp & (1 << 17)) DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp); - ret = BEGIN_LP_RING(2); + ret = intel_ring_begin(ring, 2); if (ret) { free(request, DRM_I915_GEM); return ret; } - OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); - OUT_RING(flip_addr); - ADVANCE_LP_RING(); + intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); + intel_ring_emit(ring, flip_addr); + intel_ring_advance(ring); - ret = i915_add_request(LP_RING(dev_priv), NULL, request); + ret = i915_add_request(ring, NULL, request); if (ret) { free(request, DRM_I915_GEM); return ret; @@ -399,6 +402,7 @@ static int intel_overlay_off(struct intel_overlay *overlay) { struct drm_device *dev = overlay->dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring = &dev_priv->rings[RCS]; u32 flip_addr = overlay->flip_addr; struct drm_i915_gem_request *request; int ret; @@ -413,20 +417,20 @@ static int intel_overlay_off(struct intel_overlay *overlay) * of the hw. Do it in both cases */ flip_addr |= OFC_UPDATE; - ret = BEGIN_LP_RING(6); + ret = intel_ring_begin(ring, 6); if (ret) { free(request, DRM_I915_GEM); return ret; } /* wait for overlay to go idle */ - OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); - OUT_RING(flip_addr); - OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); + intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); + intel_ring_emit(ring, flip_addr); + intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); /* turn overlay off */ - OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF); - OUT_RING(flip_addr); - OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); - ADVANCE_LP_RING(); + intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_OFF); + intel_ring_emit(ring, flip_addr); + intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); + intel_ring_advance(ring); return intel_overlay_do_wait_request(overlay, request, intel_overlay_off_tail); @@ -438,15 +442,16 @@ static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay) { struct drm_device *dev = overlay->dev; drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring = &dev_priv->rings[RCS]; int ret; if (overlay->last_flip_req == 0) return 0; - ret = i915_wait_request(LP_RING(dev_priv), overlay->last_flip_req, - true); + ret = i915_wait_request(ring, overlay->last_flip_req); if (ret) return ret; + i915_gem_retire_requests(dev); if (overlay->flip_tail) overlay->flip_tail(overlay); @@ -463,6 +468,7 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay) { struct drm_device *dev = overlay->dev; drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring = &dev_priv->rings[RCS]; int ret; /* Only wait if there is actually an old frame to release to @@ -477,15 +483,15 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay) /* synchronous slowpath */ request = malloc(sizeof(*request), DRM_I915_GEM, M_WAITOK | M_ZERO); - ret = BEGIN_LP_RING(2); + ret = intel_ring_begin(ring, 2); if (ret) { free(request, DRM_I915_GEM); return ret; } - OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); - OUT_RING(MI_NOOP); - ADVANCE_LP_RING(); + intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); + intel_ring_emit(ring, MI_NOOP); + intel_ring_advance(ring); ret = intel_overlay_do_wait_request(overlay, request, intel_overlay_release_old_vid_tail); @@ -764,6 +770,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, int ret, tmp_width; struct overlay_registers *regs; bool scale_changed = false; + u32 swidth, swidthsw, sheight, ostride; KASSERT(overlay != NULL, ("No overlay ?")); DRM_LOCK_ASSERT(overlay->dev); @@ -782,16 +789,18 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, goto out_unpin; if (!overlay->active) { + u32 oconfig; regs = intel_overlay_map_regs(overlay); if (!regs) { ret = -ENOMEM; goto out_unpin; } - regs->OCONFIG = OCONF_CC_OUT_8BIT; + oconfig = OCONF_CC_OUT_8BIT; if (IS_GEN4(overlay->dev)) - regs->OCONFIG |= OCONF_CSC_MODE_BT709; - regs->OCONFIG |= overlay->crtc->pipe == 0 ? + oconfig |= OCONF_CSC_MODE_BT709; + oconfig |= overlay->crtc->pipe == 0 ? OCONF_PIPE_A : OCONF_PIPE_B; + regs->OCONFIG = oconfig; intel_overlay_unmap_regs(overlay, regs); ret = intel_overlay_on(overlay); @@ -813,29 +822,33 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, else tmp_width = params->src_w; - regs->SWIDTH = params->src_w; - regs->SWIDTHSW = calc_swidthsw(overlay->dev, - params->offset_Y, tmp_width); - regs->SHEIGHT = params->src_h; + swidth = params->src_w; + swidthsw = calc_swidthsw(overlay->dev, params->offset_Y, tmp_width); + sheight = params->src_h; regs->OBUF_0Y = new_bo->gtt_offset + params->offset_Y; - regs->OSTRIDE = params->stride_Y; + ostride = params->stride_Y; if (params->format & I915_OVERLAY_YUV_PLANAR) { int uv_hscale = uv_hsubsampling(params->format); int uv_vscale = uv_vsubsampling(params->format); u32 tmp_U, tmp_V; - regs->SWIDTH |= (params->src_w/uv_hscale) << 16; + swidth |= (params->src_w/uv_hscale) << 16; tmp_U = calc_swidthsw(overlay->dev, params->offset_U, params->src_w/uv_hscale); tmp_V = calc_swidthsw(overlay->dev, params->offset_V, params->src_w/uv_hscale); - regs->SWIDTHSW |= max_u32(tmp_U, tmp_V) << 16; - regs->SHEIGHT |= (params->src_h/uv_vscale) << 16; + swidthsw |= max_u32(tmp_U, tmp_V) << 16; + sheight |= (params->src_h/uv_vscale) << 16; regs->OBUF_0U = new_bo->gtt_offset + params->offset_U; regs->OBUF_0V = new_bo->gtt_offset + params->offset_V; - regs->OSTRIDE |= params->stride_UV << 16; + ostride |= params->stride_UV << 16; } + regs->SWIDTH = swidth; + regs->SWIDTHSW = swidthsw; + regs->SHEIGHT = sheight; + regs->OSTRIDE = ostride; + scale_changed = update_scaling_factors(overlay, regs, params); update_colorkey(overlay, regs); @@ -1108,11 +1121,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, struct put_image_params *params; int ret; - if (!dev_priv) { - DRM_ERROR("called with no initialization\n"); - return -EINVAL; - } - + /* No need to check for DRIVER_MODESET - we don't set it up then. */ overlay = dev_priv->overlay; if (!overlay) { DRM_DEBUG("userspace bug: no overlay\n"); @@ -1307,11 +1316,7 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, struct overlay_registers *regs; int ret; - if (!dev_priv) { - DRM_ERROR("called with no initialization\n"); - return -EINVAL; - } - + /* No need to check for DRIVER_MODESET - we don't set it up then. */ overlay = dev_priv->overlay; if (!overlay) { DRM_DEBUG("userspace bug: no overlay\n"); diff --git a/sys/dev/drm2/i915/intel_panel.c b/sys/dev/drm2/i915/intel_panel.c index 504e2ac4de47..ef60f4945fe6 100644 --- a/sys/dev/drm2/i915/intel_panel.c +++ b/sys/dev/drm2/i915/intel_panel.c @@ -197,6 +197,20 @@ u32 intel_panel_get_max_backlight(struct drm_device *dev) return max; } +static u32 intel_panel_compute_brightness(struct drm_device *dev, u32 val) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (i915_panel_invert_brightness < 0) + return val; + + if (i915_panel_invert_brightness > 0 || + dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) + return intel_panel_get_max_backlight(dev) - val; + + return val; +} + u32 intel_panel_get_backlight(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -217,7 +231,8 @@ u32 intel_panel_get_backlight(struct drm_device *dev) } } - DRM_DEBUG("get backlight PWM = %d\n", val); + val = intel_panel_compute_brightness(dev, val); + DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val); return val; } @@ -233,7 +248,8 @@ static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level struct drm_i915_private *dev_priv = dev->dev_private; u32 tmp; - DRM_DEBUG("set backlight PWM = %d\n", level); + DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level); + level = intel_panel_compute_brightness(dev, level); if (HAS_PCH_SPLIT(dev)) return intel_pch_panel_set_backlight(dev, level); diff --git a/sys/dev/drm2/i915/intel_pm.c b/sys/dev/drm2/i915/intel_pm.c new file mode 100644 index 000000000000..7a8adbdbd8c5 --- /dev/null +++ b/sys/dev/drm2/i915/intel_pm.c @@ -0,0 +1,3788 @@ +/* + * Copyright © 2012 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: + * Eugeni Dodonov + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +static struct drm_i915_private *i915_mch_dev; +/* + * Lock protecting IPS related data structures + * - i915_mch_dev + * - dev_priv->max_delay + * - dev_priv->min_delay + * - dev_priv->fmax + * - dev_priv->gpu_busy + */ +static struct mtx mchdev_lock; +MTX_SYSINIT(mchdev, &mchdev_lock, "mchdev", MTX_DEF); + +/* FBC, or Frame Buffer Compression, is a technique employed to compress the + * framebuffer contents in-memory, aiming at reducing the required bandwidth + * during in-memory transfers and, therefore, reduce the power packet. + * + * The benefits of FBC are mostly visible with solid backgrounds and + * variation-less patterns. + * + * FBC-related functionality can be enabled by the means of the + * i915.i915_enable_fbc parameter + */ + +static void i8xx_disable_fbc(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 fbc_ctl; + + /* Disable compression */ + fbc_ctl = I915_READ(FBC_CONTROL); + if ((fbc_ctl & FBC_CTL_EN) == 0) + return; + + fbc_ctl &= ~FBC_CTL_EN; + I915_WRITE(FBC_CONTROL, fbc_ctl); + + /* Wait for compressing bit to clear */ + if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10)) { + DRM_DEBUG_KMS("FBC idle timed out\n"); + return; + } + + DRM_DEBUG_KMS("disabled FBC\n"); +} + +static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_framebuffer *fb = crtc->fb; + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); + struct drm_i915_gem_object *obj = intel_fb->obj; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int cfb_pitch; + int plane, i; + u32 fbc_ctl, fbc_ctl2; + + cfb_pitch = dev_priv->cfb_size / FBC_LL_SIZE; + if (fb->pitches[0] < cfb_pitch) + cfb_pitch = fb->pitches[0]; + + /* FBC_CTL wants 64B units */ + cfb_pitch = (cfb_pitch / 64) - 1; + plane = intel_crtc->plane == 0 ? FBC_CTL_PLANEA : FBC_CTL_PLANEB; + + /* Clear old tags */ + for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++) + I915_WRITE(FBC_TAG + (i * 4), 0); + + /* Set it up... */ + fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE; + fbc_ctl2 |= plane; + I915_WRITE(FBC_CONTROL2, fbc_ctl2); + I915_WRITE(FBC_FENCE_OFF, crtc->y); + + /* enable it... */ + fbc_ctl = FBC_CTL_EN | FBC_CTL_PERIODIC; + if (IS_I945GM(dev)) + fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */ + fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT; + fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT; + fbc_ctl |= obj->fence_reg; + I915_WRITE(FBC_CONTROL, fbc_ctl); + + DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %d, ", + cfb_pitch, crtc->y, intel_crtc->plane); +} + +static bool i8xx_fbc_enabled(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + return I915_READ(FBC_CONTROL) & FBC_CTL_EN; +} + +static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_framebuffer *fb = crtc->fb; + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); + struct drm_i915_gem_object *obj = intel_fb->obj; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB; + unsigned long stall_watermark = 200; + u32 dpfc_ctl; + + dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X; + dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg; + I915_WRITE(DPFC_CHICKEN, DPFC_HT_MODIFY); + + I915_WRITE(DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN | + (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) | + (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT)); + I915_WRITE(DPFC_FENCE_YOFF, crtc->y); + + /* enable it... */ + I915_WRITE(DPFC_CONTROL, I915_READ(DPFC_CONTROL) | DPFC_CTL_EN); + + DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane); +} + +static void g4x_disable_fbc(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 dpfc_ctl; + + /* Disable compression */ + dpfc_ctl = I915_READ(DPFC_CONTROL); + if (dpfc_ctl & DPFC_CTL_EN) { + dpfc_ctl &= ~DPFC_CTL_EN; + I915_WRITE(DPFC_CONTROL, dpfc_ctl); + + DRM_DEBUG_KMS("disabled FBC\n"); + } +} + +static bool g4x_fbc_enabled(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN; +} + +static void sandybridge_blit_fbc_update(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 blt_ecoskpd; + + /* Make sure blitter notifies FBC of writes */ + gen6_gt_force_wake_get(dev_priv); + blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD); + blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY << + GEN6_BLITTER_LOCK_SHIFT; + I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd); + blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY; + I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd); + blt_ecoskpd &= ~(GEN6_BLITTER_FBC_NOTIFY << + GEN6_BLITTER_LOCK_SHIFT); + I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd); + POSTING_READ(GEN6_BLITTER_ECOSKPD); + gen6_gt_force_wake_put(dev_priv); +} + +static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_framebuffer *fb = crtc->fb; + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); + struct drm_i915_gem_object *obj = intel_fb->obj; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB; + unsigned long stall_watermark = 200; + u32 dpfc_ctl; + + dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); + dpfc_ctl &= DPFC_RESERVED; + dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X); + /* Set persistent mode for front-buffer rendering, ala X. */ + dpfc_ctl |= DPFC_CTL_PERSISTENT_MODE; + dpfc_ctl |= (DPFC_CTL_FENCE_EN | obj->fence_reg); + I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY); + + I915_WRITE(ILK_DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN | + (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) | + (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT)); + I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y); + I915_WRITE(ILK_FBC_RT_BASE, obj->gtt_offset | ILK_FBC_RT_VALID); + /* enable it... */ + I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); + + if (IS_GEN6(dev)) { + I915_WRITE(SNB_DPFC_CTL_SA, + SNB_CPU_FENCE_ENABLE | obj->fence_reg); + I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y); + sandybridge_blit_fbc_update(dev); + } + + DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane); +} + +static void ironlake_disable_fbc(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 dpfc_ctl; + + /* Disable compression */ + dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); + if (dpfc_ctl & DPFC_CTL_EN) { + dpfc_ctl &= ~DPFC_CTL_EN; + I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl); + + DRM_DEBUG_KMS("disabled FBC\n"); + } +} + +static bool ironlake_fbc_enabled(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN; +} + +bool intel_fbc_enabled(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!dev_priv->display.fbc_enabled) + return false; + + return dev_priv->display.fbc_enabled(dev); +} + +static void intel_fbc_work_fn(void *arg, int pending) +{ + struct intel_fbc_work *work = arg; + struct drm_device *dev = work->crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + DRM_LOCK(dev); + if (work == dev_priv->fbc_work) { + /* Double check that we haven't switched fb without cancelling + * the prior work. + */ + if (work->crtc->fb == work->fb) { + dev_priv->display.enable_fbc(work->crtc, + work->interval); + + dev_priv->cfb_plane = to_intel_crtc(work->crtc)->plane; + dev_priv->cfb_fb = work->crtc->fb->base.id; + dev_priv->cfb_y = work->crtc->y; + } + + dev_priv->fbc_work = NULL; + } + DRM_UNLOCK(dev); + + free(work, DRM_MEM_KMS); +} + +static void intel_cancel_fbc_work(struct drm_i915_private *dev_priv) +{ + u_int pending; + + if (dev_priv->fbc_work == NULL) + return; + + DRM_DEBUG_KMS("cancelling pending FBC enable\n"); + + /* Synchronisation is provided by struct_mutex and checking of + * dev_priv->fbc_work, so we can perform the cancellation + * entirely asynchronously. + */ + if (taskqueue_cancel_timeout(dev_priv->tq, &dev_priv->fbc_work->task, + &pending) == 0) + /* tasklet was killed before being run, clean up */ + free(dev_priv->fbc_work, DRM_MEM_KMS); + + /* Mark the work as no longer wanted so that if it does + * wake-up (because the work was already running and waiting + * for our mutex), it will discover that is no longer + * necessary to run. + */ + dev_priv->fbc_work = NULL; +} + +void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +{ + struct intel_fbc_work *work; + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!dev_priv->display.enable_fbc) + return; + + intel_cancel_fbc_work(dev_priv); + + work = malloc(sizeof(*work), DRM_MEM_KMS, M_WAITOK | M_ZERO); + + work->crtc = crtc; + work->fb = crtc->fb; + work->interval = interval; + TIMEOUT_TASK_INIT(dev_priv->tq, &work->task, 0, intel_fbc_work_fn, + work); + + dev_priv->fbc_work = work; + + DRM_DEBUG_KMS("scheduling delayed FBC enable\n"); + + /* Delay the actual enabling to let pageflipping cease and the + * display to settle before starting the compression. Note that + * this delay also serves a second purpose: it allows for a + * vblank to pass after disabling the FBC before we attempt + * to modify the control registers. + * + * A more complicated solution would involve tracking vblanks + * following the termination of the page-flipping sequence + * and indeed performing the enable as a co-routine and not + * waiting synchronously upon the vblank. + */ + taskqueue_enqueue_timeout(dev_priv->tq, &work->task, + msecs_to_jiffies(50)); +} + +void intel_disable_fbc(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + intel_cancel_fbc_work(dev_priv); + + if (!dev_priv->display.disable_fbc) + return; + + dev_priv->display.disable_fbc(dev); + dev_priv->cfb_plane = -1; +} + +/** + * intel_update_fbc - enable/disable FBC as needed + * @dev: the drm_device + * + * Set up the framebuffer compression hardware at mode set time. We + * enable it if possible: + * - plane A only (on pre-965) + * - no pixel mulitply/line duplication + * - no alpha buffer discard + * - no dual wide + * - framebuffer <= 2048 in width, 1536 in height + * + * We can't assume that any compression will take place (worst case), + * so the compressed buffer has to be the same size as the uncompressed + * one. It also must reside (along with the line length buffer) in + * stolen memory. + * + * We need to enable/disable FBC on a global basis. + */ +void intel_update_fbc(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc = NULL, *tmp_crtc; + struct intel_crtc *intel_crtc; + struct drm_framebuffer *fb; + struct intel_framebuffer *intel_fb; + struct drm_i915_gem_object *obj; + int enable_fbc; + + DRM_DEBUG_KMS("\n"); + + if (!i915_powersave) + return; + + if (!I915_HAS_FBC(dev)) + return; + + /* + * If FBC is already on, we just have to verify that we can + * keep it that way... + * Need to disable if: + * - more than one pipe is active + * - changing FBC params (stride, fence, mode) + * - new fb is too large to fit in compressed buffer + * - going to an unsupported config (interlace, pixel multiply, etc.) + */ + list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) { + if (tmp_crtc->enabled && tmp_crtc->fb) { + if (crtc) { + DRM_DEBUG_KMS("more than one pipe active, disabling compression\n"); + dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES; + goto out_disable; + } + crtc = tmp_crtc; + } + } + + if (!crtc || crtc->fb == NULL) { + DRM_DEBUG_KMS("no output, disabling\n"); + dev_priv->no_fbc_reason = FBC_NO_OUTPUT; + goto out_disable; + } + + intel_crtc = to_intel_crtc(crtc); + fb = crtc->fb; + intel_fb = to_intel_framebuffer(fb); + obj = intel_fb->obj; + + enable_fbc = i915_enable_fbc; + if (enable_fbc < 0) { + DRM_DEBUG_KMS("fbc set to per-chip default\n"); + enable_fbc = 1; + if (INTEL_INFO(dev)->gen <= 6) + enable_fbc = 0; + } + if (!enable_fbc) { + DRM_DEBUG_KMS("fbc disabled per module param\n"); + dev_priv->no_fbc_reason = FBC_MODULE_PARAM; + goto out_disable; + } + if (intel_fb->obj->base.size > dev_priv->cfb_size) { + DRM_DEBUG_KMS("framebuffer too large, disabling " + "compression\n"); + dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL; + goto out_disable; + } + if ((crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) || + (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)) { + DRM_DEBUG_KMS("mode incompatible with compression, " + "disabling\n"); + dev_priv->no_fbc_reason = FBC_UNSUPPORTED_MODE; + goto out_disable; + } + if ((crtc->mode.hdisplay > 2048) || + (crtc->mode.vdisplay > 1536)) { + DRM_DEBUG_KMS("mode too large for compression, disabling\n"); + dev_priv->no_fbc_reason = FBC_MODE_TOO_LARGE; + goto out_disable; + } + if ((IS_I915GM(dev) || IS_I945GM(dev)) && intel_crtc->plane != 0) { + DRM_DEBUG_KMS("plane not 0, disabling compression\n"); + dev_priv->no_fbc_reason = FBC_BAD_PLANE; + goto out_disable; + } + + /* The use of a CPU fence is mandatory in order to detect writes + * by the CPU to the scanout and trigger updates to the FBC. + */ + if (obj->tiling_mode != I915_TILING_X || + obj->fence_reg == I915_FENCE_REG_NONE) { + DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n"); + dev_priv->no_fbc_reason = FBC_NOT_TILED; + goto out_disable; + } + + /* If the kernel debugger is active, always disable compression */ + if (kdb_active) + goto out_disable; + + /* If the scanout has not changed, don't modify the FBC settings. + * Note that we make the fundamental assumption that the fb->obj + * cannot be unpinned (and have its GTT offset and fence revoked) + * without first being decoupled from the scanout and FBC disabled. + */ + if (dev_priv->cfb_plane == intel_crtc->plane && + dev_priv->cfb_fb == fb->base.id && + dev_priv->cfb_y == crtc->y) + return; + + if (intel_fbc_enabled(dev)) { + /* We update FBC along two paths, after changing fb/crtc + * configuration (modeswitching) and after page-flipping + * finishes. For the latter, we know that not only did + * we disable the FBC at the start of the page-flip + * sequence, but also more than one vblank has passed. + * + * For the former case of modeswitching, it is possible + * to switch between two FBC valid configurations + * instantaneously so we do need to disable the FBC + * before we can modify its control registers. We also + * have to wait for the next vblank for that to take + * effect. However, since we delay enabling FBC we can + * assume that a vblank has passed since disabling and + * that we can safely alter the registers in the deferred + * callback. + * + * In the scenario that we go from a valid to invalid + * and then back to valid FBC configuration we have + * no strict enforcement that a vblank occurred since + * disabling the FBC. However, along all current pipe + * disabling paths we do need to wait for a vblank at + * some point. And we wait before enabling FBC anyway. + */ + DRM_DEBUG_KMS("disabling active FBC for update\n"); + intel_disable_fbc(dev); + } + + intel_enable_fbc(crtc, 500); + return; + +out_disable: + /* Multiple disables should be harmless */ + if (intel_fbc_enabled(dev)) { + DRM_DEBUG_KMS("unsupported config, disabling FBC\n"); + intel_disable_fbc(dev); + } +} + +static void i915_pineview_get_mem_freq(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + u32 tmp; + + tmp = I915_READ(CLKCFG); + + switch (tmp & CLKCFG_FSB_MASK) { + case CLKCFG_FSB_533: + dev_priv->fsb_freq = 533; /* 133*4 */ + break; + case CLKCFG_FSB_800: + dev_priv->fsb_freq = 800; /* 200*4 */ + break; + case CLKCFG_FSB_667: + dev_priv->fsb_freq = 667; /* 167*4 */ + break; + case CLKCFG_FSB_400: + dev_priv->fsb_freq = 400; /* 100*4 */ + break; + } + + switch (tmp & CLKCFG_MEM_MASK) { + case CLKCFG_MEM_533: + dev_priv->mem_freq = 533; + break; + case CLKCFG_MEM_667: + dev_priv->mem_freq = 667; + break; + case CLKCFG_MEM_800: + dev_priv->mem_freq = 800; + break; + } + + /* detect pineview DDR3 setting */ + tmp = I915_READ(CSHRDDR3CTL); + dev_priv->is_ddr3 = (tmp & CSHRDDR3CTL_DDR3) ? 1 : 0; +} + +static void i915_ironlake_get_mem_freq(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + u16 ddrpll, csipll; + + ddrpll = I915_READ16(DDRMPLL1); + csipll = I915_READ16(CSIPLL0); + + switch (ddrpll & 0xff) { + case 0xc: + dev_priv->mem_freq = 800; + break; + case 0x10: + dev_priv->mem_freq = 1066; + break; + case 0x14: + dev_priv->mem_freq = 1333; + break; + case 0x18: + dev_priv->mem_freq = 1600; + break; + default: + DRM_DEBUG("unknown memory frequency 0x%02x\n", + ddrpll & 0xff); + dev_priv->mem_freq = 0; + break; + } + + dev_priv->r_t = dev_priv->mem_freq; + + switch (csipll & 0x3ff) { + case 0x00c: + dev_priv->fsb_freq = 3200; + break; + case 0x00e: + dev_priv->fsb_freq = 3733; + break; + case 0x010: + dev_priv->fsb_freq = 4266; + break; + case 0x012: + dev_priv->fsb_freq = 4800; + break; + case 0x014: + dev_priv->fsb_freq = 5333; + break; + case 0x016: + dev_priv->fsb_freq = 5866; + break; + case 0x018: + dev_priv->fsb_freq = 6400; + break; + default: + DRM_DEBUG("unknown fsb frequency 0x%04x\n", + csipll & 0x3ff); + dev_priv->fsb_freq = 0; + break; + } + + if (dev_priv->fsb_freq == 3200) { + dev_priv->c_m = 0; + } else if (dev_priv->fsb_freq > 3200 && dev_priv->fsb_freq <= 4800) { + dev_priv->c_m = 1; + } else { + dev_priv->c_m = 2; + } +} + +static const struct cxsr_latency cxsr_latency_table[] = { + {1, 0, 800, 400, 3382, 33382, 3983, 33983}, /* DDR2-400 SC */ + {1, 0, 800, 667, 3354, 33354, 3807, 33807}, /* DDR2-667 SC */ + {1, 0, 800, 800, 3347, 33347, 3763, 33763}, /* DDR2-800 SC */ + {1, 1, 800, 667, 6420, 36420, 6873, 36873}, /* DDR3-667 SC */ + {1, 1, 800, 800, 5902, 35902, 6318, 36318}, /* DDR3-800 SC */ + + {1, 0, 667, 400, 3400, 33400, 4021, 34021}, /* DDR2-400 SC */ + {1, 0, 667, 667, 3372, 33372, 3845, 33845}, /* DDR2-667 SC */ + {1, 0, 667, 800, 3386, 33386, 3822, 33822}, /* DDR2-800 SC */ + {1, 1, 667, 667, 6438, 36438, 6911, 36911}, /* DDR3-667 SC */ + {1, 1, 667, 800, 5941, 35941, 6377, 36377}, /* DDR3-800 SC */ + + {1, 0, 400, 400, 3472, 33472, 4173, 34173}, /* DDR2-400 SC */ + {1, 0, 400, 667, 3443, 33443, 3996, 33996}, /* DDR2-667 SC */ + {1, 0, 400, 800, 3430, 33430, 3946, 33946}, /* DDR2-800 SC */ + {1, 1, 400, 667, 6509, 36509, 7062, 37062}, /* DDR3-667 SC */ + {1, 1, 400, 800, 5985, 35985, 6501, 36501}, /* DDR3-800 SC */ + + {0, 0, 800, 400, 3438, 33438, 4065, 34065}, /* DDR2-400 SC */ + {0, 0, 800, 667, 3410, 33410, 3889, 33889}, /* DDR2-667 SC */ + {0, 0, 800, 800, 3403, 33403, 3845, 33845}, /* DDR2-800 SC */ + {0, 1, 800, 667, 6476, 36476, 6955, 36955}, /* DDR3-667 SC */ + {0, 1, 800, 800, 5958, 35958, 6400, 36400}, /* DDR3-800 SC */ + + {0, 0, 667, 400, 3456, 33456, 4103, 34106}, /* DDR2-400 SC */ + {0, 0, 667, 667, 3428, 33428, 3927, 33927}, /* DDR2-667 SC */ + {0, 0, 667, 800, 3443, 33443, 3905, 33905}, /* DDR2-800 SC */ + {0, 1, 667, 667, 6494, 36494, 6993, 36993}, /* DDR3-667 SC */ + {0, 1, 667, 800, 5998, 35998, 6460, 36460}, /* DDR3-800 SC */ + + {0, 0, 400, 400, 3528, 33528, 4255, 34255}, /* DDR2-400 SC */ + {0, 0, 400, 667, 3500, 33500, 4079, 34079}, /* DDR2-667 SC */ + {0, 0, 400, 800, 3487, 33487, 4029, 34029}, /* DDR2-800 SC */ + {0, 1, 400, 667, 6566, 36566, 7145, 37145}, /* DDR3-667 SC */ + {0, 1, 400, 800, 6042, 36042, 6584, 36584}, /* DDR3-800 SC */ +}; + +static const struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, + int is_ddr3, + int fsb, + int mem) +{ + const struct cxsr_latency *latency; + int i; + + if (fsb == 0 || mem == 0) + return NULL; + + for (i = 0; i < DRM_ARRAY_SIZE(cxsr_latency_table); i++) { + latency = &cxsr_latency_table[i]; + if (is_desktop == latency->is_desktop && + is_ddr3 == latency->is_ddr3 && + fsb == latency->fsb_freq && mem == latency->mem_freq) + return latency; + } + + DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n"); + + return NULL; +} + +static void pineview_disable_cxsr(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* deactivate cxsr */ + I915_WRITE(DSPFW3, I915_READ(DSPFW3) & ~PINEVIEW_SELF_REFRESH_EN); +} + +/* + * Latency for FIFO fetches is dependent on several factors: + * - memory configuration (speed, channels) + * - chipset + * - current MCH state + * It can be fairly high in some situations, so here we assume a fairly + * pessimal value. It's a tradeoff between extra memory fetches (if we + * set this value too high, the FIFO will fetch frequently to stay full) + * and power consumption (set it too low to save power and we might see + * FIFO underruns and display "flicker"). + * + * A value of 5us seems to be a good balance; safe for very low end + * platforms but not overly aggressive on lower latency configs. + */ +static const int latency_ns = 5000; + +static int i9xx_get_fifo_size(struct drm_device *dev, int plane) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t dsparb = I915_READ(DSPARB); + int size; + + size = dsparb & 0x7f; + if (plane) + size = ((dsparb >> DSPARB_CSTART_SHIFT) & 0x7f) - size; + + DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb, + plane ? "B" : "A", size); + + return size; +} + +static int i85x_get_fifo_size(struct drm_device *dev, int plane) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t dsparb = I915_READ(DSPARB); + int size; + + size = dsparb & 0x1ff; + if (plane) + size = ((dsparb >> DSPARB_BEND_SHIFT) & 0x1ff) - size; + size >>= 1; /* Convert to cachelines */ + + DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb, + plane ? "B" : "A", size); + + return size; +} + +static int i845_get_fifo_size(struct drm_device *dev, int plane) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t dsparb = I915_READ(DSPARB); + int size; + + size = dsparb & 0x7f; + size >>= 2; /* Convert to cachelines */ + + DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb, + plane ? "B" : "A", + size); + + return size; +} + +static int i830_get_fifo_size(struct drm_device *dev, int plane) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t dsparb = I915_READ(DSPARB); + int size; + + size = dsparb & 0x7f; + size >>= 1; /* Convert to cachelines */ + + DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb, + plane ? "B" : "A", size); + + return size; +} + +/* Pineview has different values for various configs */ +static const struct intel_watermark_params pineview_display_wm = { + PINEVIEW_DISPLAY_FIFO, + PINEVIEW_MAX_WM, + PINEVIEW_DFT_WM, + PINEVIEW_GUARD_WM, + PINEVIEW_FIFO_LINE_SIZE +}; +static const struct intel_watermark_params pineview_display_hplloff_wm = { + PINEVIEW_DISPLAY_FIFO, + PINEVIEW_MAX_WM, + PINEVIEW_DFT_HPLLOFF_WM, + PINEVIEW_GUARD_WM, + PINEVIEW_FIFO_LINE_SIZE +}; +static const struct intel_watermark_params pineview_cursor_wm = { + PINEVIEW_CURSOR_FIFO, + PINEVIEW_CURSOR_MAX_WM, + PINEVIEW_CURSOR_DFT_WM, + PINEVIEW_CURSOR_GUARD_WM, + PINEVIEW_FIFO_LINE_SIZE, +}; +static const struct intel_watermark_params pineview_cursor_hplloff_wm = { + PINEVIEW_CURSOR_FIFO, + PINEVIEW_CURSOR_MAX_WM, + PINEVIEW_CURSOR_DFT_WM, + PINEVIEW_CURSOR_GUARD_WM, + PINEVIEW_FIFO_LINE_SIZE +}; +static const struct intel_watermark_params g4x_wm_info = { + G4X_FIFO_SIZE, + G4X_MAX_WM, + G4X_MAX_WM, + 2, + G4X_FIFO_LINE_SIZE, +}; +static const struct intel_watermark_params g4x_cursor_wm_info = { + I965_CURSOR_FIFO, + I965_CURSOR_MAX_WM, + I965_CURSOR_DFT_WM, + 2, + G4X_FIFO_LINE_SIZE, +}; +static const struct intel_watermark_params valleyview_wm_info = { + VALLEYVIEW_FIFO_SIZE, + VALLEYVIEW_MAX_WM, + VALLEYVIEW_MAX_WM, + 2, + G4X_FIFO_LINE_SIZE, +}; +static const struct intel_watermark_params valleyview_cursor_wm_info = { + I965_CURSOR_FIFO, + VALLEYVIEW_CURSOR_MAX_WM, + I965_CURSOR_DFT_WM, + 2, + G4X_FIFO_LINE_SIZE, +}; +static const struct intel_watermark_params i965_cursor_wm_info = { + I965_CURSOR_FIFO, + I965_CURSOR_MAX_WM, + I965_CURSOR_DFT_WM, + 2, + I915_FIFO_LINE_SIZE, +}; +static const struct intel_watermark_params i945_wm_info = { + I945_FIFO_SIZE, + I915_MAX_WM, + 1, + 2, + I915_FIFO_LINE_SIZE +}; +static const struct intel_watermark_params i915_wm_info = { + I915_FIFO_SIZE, + I915_MAX_WM, + 1, + 2, + I915_FIFO_LINE_SIZE +}; +static const struct intel_watermark_params i855_wm_info = { + I855GM_FIFO_SIZE, + I915_MAX_WM, + 1, + 2, + I830_FIFO_LINE_SIZE +}; +static const struct intel_watermark_params i830_wm_info = { + I830_FIFO_SIZE, + I915_MAX_WM, + 1, + 2, + I830_FIFO_LINE_SIZE +}; + +static const struct intel_watermark_params ironlake_display_wm_info = { + ILK_DISPLAY_FIFO, + ILK_DISPLAY_MAXWM, + ILK_DISPLAY_DFTWM, + 2, + ILK_FIFO_LINE_SIZE +}; +static const struct intel_watermark_params ironlake_cursor_wm_info = { + ILK_CURSOR_FIFO, + ILK_CURSOR_MAXWM, + ILK_CURSOR_DFTWM, + 2, + ILK_FIFO_LINE_SIZE +}; +static const struct intel_watermark_params ironlake_display_srwm_info = { + ILK_DISPLAY_SR_FIFO, + ILK_DISPLAY_MAX_SRWM, + ILK_DISPLAY_DFT_SRWM, + 2, + ILK_FIFO_LINE_SIZE +}; +static const struct intel_watermark_params ironlake_cursor_srwm_info = { + ILK_CURSOR_SR_FIFO, + ILK_CURSOR_MAX_SRWM, + ILK_CURSOR_DFT_SRWM, + 2, + ILK_FIFO_LINE_SIZE +}; + +static const struct intel_watermark_params sandybridge_display_wm_info = { + SNB_DISPLAY_FIFO, + SNB_DISPLAY_MAXWM, + SNB_DISPLAY_DFTWM, + 2, + SNB_FIFO_LINE_SIZE +}; +static const struct intel_watermark_params sandybridge_cursor_wm_info = { + SNB_CURSOR_FIFO, + SNB_CURSOR_MAXWM, + SNB_CURSOR_DFTWM, + 2, + SNB_FIFO_LINE_SIZE +}; +static const struct intel_watermark_params sandybridge_display_srwm_info = { + SNB_DISPLAY_SR_FIFO, + SNB_DISPLAY_MAX_SRWM, + SNB_DISPLAY_DFT_SRWM, + 2, + SNB_FIFO_LINE_SIZE +}; +static const struct intel_watermark_params sandybridge_cursor_srwm_info = { + SNB_CURSOR_SR_FIFO, + SNB_CURSOR_MAX_SRWM, + SNB_CURSOR_DFT_SRWM, + 2, + SNB_FIFO_LINE_SIZE +}; + + +/** + * intel_calculate_wm - calculate watermark level + * @clock_in_khz: pixel clock + * @wm: chip FIFO params + * @pixel_size: display pixel size + * @latency_ns: memory latency for the platform + * + * Calculate the watermark level (the level at which the display plane will + * start fetching from memory again). Each chip has a different display + * FIFO size and allocation, so the caller needs to figure that out and pass + * in the correct intel_watermark_params structure. + * + * As the pixel clock runs, the FIFO will be drained at a rate that depends + * on the pixel size. When it reaches the watermark level, it'll start + * fetching FIFO line sized based chunks from memory until the FIFO fills + * past the watermark point. If the FIFO drains completely, a FIFO underrun + * will occur, and a display engine hang could result. + */ +static unsigned long intel_calculate_wm(unsigned long clock_in_khz, + const struct intel_watermark_params *wm, + int fifo_size, + int pixel_size, + unsigned long latency_ns) +{ + long entries_required, wm_size; + + /* + * Note: we need to make sure we don't overflow for various clock & + * latency values. + * clocks go from a few thousand to several hundred thousand. + * latency is usually a few thousand + */ + entries_required = ((clock_in_khz / 1000) * pixel_size * latency_ns) / + 1000; + entries_required = DIV_ROUND_UP(entries_required, wm->cacheline_size); + + DRM_DEBUG_KMS("FIFO entries required for mode: %ld\n", entries_required); + + wm_size = fifo_size - (entries_required + wm->guard_size); + + DRM_DEBUG_KMS("FIFO watermark level: %ld\n", wm_size); + + /* Don't promote wm_size to unsigned... */ + if (wm_size > (long)wm->max_wm) + wm_size = wm->max_wm; + if (wm_size <= 0) + wm_size = wm->default_wm; + return wm_size; +} + +static struct drm_crtc *single_enabled_crtc(struct drm_device *dev) +{ + struct drm_crtc *crtc, *enabled = NULL; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (crtc->enabled && crtc->fb) { + if (enabled) + return NULL; + enabled = crtc; + } + } + + return enabled; +} + +static void pineview_update_wm(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc; + const struct cxsr_latency *latency; + u32 reg; + unsigned long wm; + + latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->is_ddr3, + dev_priv->fsb_freq, dev_priv->mem_freq); + if (!latency) { + DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n"); + pineview_disable_cxsr(dev); + return; + } + + crtc = single_enabled_crtc(dev); + if (crtc) { + int clock = crtc->mode.clock; + int pixel_size = crtc->fb->bits_per_pixel / 8; + + /* Display SR */ + wm = intel_calculate_wm(clock, &pineview_display_wm, + pineview_display_wm.fifo_size, + pixel_size, latency->display_sr); + reg = I915_READ(DSPFW1); + reg &= ~DSPFW_SR_MASK; + reg |= wm << DSPFW_SR_SHIFT; + I915_WRITE(DSPFW1, reg); + DRM_DEBUG_KMS("DSPFW1 register is %x\n", reg); + + /* cursor SR */ + wm = intel_calculate_wm(clock, &pineview_cursor_wm, + pineview_display_wm.fifo_size, + pixel_size, latency->cursor_sr); + reg = I915_READ(DSPFW3); + reg &= ~DSPFW_CURSOR_SR_MASK; + reg |= (wm & 0x3f) << DSPFW_CURSOR_SR_SHIFT; + I915_WRITE(DSPFW3, reg); + + /* Display HPLL off SR */ + wm = intel_calculate_wm(clock, &pineview_display_hplloff_wm, + pineview_display_hplloff_wm.fifo_size, + pixel_size, latency->display_hpll_disable); + reg = I915_READ(DSPFW3); + reg &= ~DSPFW_HPLL_SR_MASK; + reg |= wm & DSPFW_HPLL_SR_MASK; + I915_WRITE(DSPFW3, reg); + + /* cursor HPLL off SR */ + wm = intel_calculate_wm(clock, &pineview_cursor_hplloff_wm, + pineview_display_hplloff_wm.fifo_size, + pixel_size, latency->cursor_hpll_disable); + reg = I915_READ(DSPFW3); + reg &= ~DSPFW_HPLL_CURSOR_MASK; + reg |= (wm & 0x3f) << DSPFW_HPLL_CURSOR_SHIFT; + I915_WRITE(DSPFW3, reg); + DRM_DEBUG_KMS("DSPFW3 register is %x\n", reg); + + /* activate cxsr */ + I915_WRITE(DSPFW3, + I915_READ(DSPFW3) | PINEVIEW_SELF_REFRESH_EN); + DRM_DEBUG_KMS("Self-refresh is enabled\n"); + } else { + pineview_disable_cxsr(dev); + DRM_DEBUG_KMS("Self-refresh is disabled\n"); + } +} + +static bool g4x_compute_wm0(struct drm_device *dev, + int plane, + const struct intel_watermark_params *display, + int display_latency_ns, + const struct intel_watermark_params *cursor, + int cursor_latency_ns, + int *plane_wm, + int *cursor_wm) +{ + struct drm_crtc *crtc; + int htotal, hdisplay, clock, pixel_size; + int line_time_us, line_count; + int entries, tlb_miss; + + crtc = intel_get_crtc_for_plane(dev, plane); + if (crtc->fb == NULL || !crtc->enabled) { + *cursor_wm = cursor->guard_size; + *plane_wm = display->guard_size; + return false; + } + + htotal = crtc->mode.htotal; + hdisplay = crtc->mode.hdisplay; + clock = crtc->mode.clock; + pixel_size = crtc->fb->bits_per_pixel / 8; + + /* Use the small buffer method to calculate plane watermark */ + entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000; + tlb_miss = display->fifo_size*display->cacheline_size - hdisplay * 8; + if (tlb_miss > 0) + entries += tlb_miss; + entries = DIV_ROUND_UP(entries, display->cacheline_size); + *plane_wm = entries + display->guard_size; + if (*plane_wm > (int)display->max_wm) + *plane_wm = display->max_wm; + + /* Use the large buffer method to calculate cursor watermark */ + line_time_us = ((htotal * 1000) / clock); + line_count = (cursor_latency_ns / line_time_us + 1000) / 1000; + entries = line_count * 64 * pixel_size; + tlb_miss = cursor->fifo_size*cursor->cacheline_size - hdisplay * 8; + if (tlb_miss > 0) + entries += tlb_miss; + entries = DIV_ROUND_UP(entries, cursor->cacheline_size); + *cursor_wm = entries + cursor->guard_size; + if (*cursor_wm > (int)cursor->max_wm) + *cursor_wm = (int)cursor->max_wm; + + return true; +} + +/* + * Check the wm result. + * + * If any calculated watermark values is larger than the maximum value that + * can be programmed into the associated watermark register, that watermark + * must be disabled. + */ +static bool g4x_check_srwm(struct drm_device *dev, + int display_wm, int cursor_wm, + const struct intel_watermark_params *display, + const struct intel_watermark_params *cursor) +{ + DRM_DEBUG_KMS("SR watermark: display plane %d, cursor %d\n", + display_wm, cursor_wm); + + if (display_wm > display->max_wm) { + DRM_DEBUG_KMS("display watermark is too large(%d/%ld), disabling\n", + display_wm, display->max_wm); + return false; + } + + if (cursor_wm > cursor->max_wm) { + DRM_DEBUG_KMS("cursor watermark is too large(%d/%ld), disabling\n", + cursor_wm, cursor->max_wm); + return false; + } + + if (!(display_wm || cursor_wm)) { + DRM_DEBUG_KMS("SR latency is 0, disabling\n"); + return false; + } + + return true; +} + +static bool g4x_compute_srwm(struct drm_device *dev, + int plane, + int latency_ns, + const struct intel_watermark_params *display, + const struct intel_watermark_params *cursor, + int *display_wm, int *cursor_wm) +{ + struct drm_crtc *crtc; + int hdisplay, htotal, pixel_size, clock; + unsigned long line_time_us; + int line_count, line_size; + int small, large; + int entries; + + if (!latency_ns) { + *display_wm = *cursor_wm = 0; + return false; + } + + crtc = intel_get_crtc_for_plane(dev, plane); + hdisplay = crtc->mode.hdisplay; + htotal = crtc->mode.htotal; + clock = crtc->mode.clock; + pixel_size = crtc->fb->bits_per_pixel / 8; + + line_time_us = (htotal * 1000) / clock; + line_count = (latency_ns / line_time_us + 1000) / 1000; + line_size = hdisplay * pixel_size; + + /* Use the minimum of the small and large buffer method for primary */ + small = ((clock * pixel_size / 1000) * latency_ns) / 1000; + large = line_count * line_size; + + entries = DIV_ROUND_UP(min(small, large), display->cacheline_size); + *display_wm = entries + display->guard_size; + + /* calculate the self-refresh watermark for display cursor */ + entries = line_count * pixel_size * 64; + entries = DIV_ROUND_UP(entries, cursor->cacheline_size); + *cursor_wm = entries + cursor->guard_size; + + return g4x_check_srwm(dev, + *display_wm, *cursor_wm, + display, cursor); +} + +static bool vlv_compute_drain_latency(struct drm_device *dev, + int plane, + int *plane_prec_mult, + int *plane_dl, + int *cursor_prec_mult, + int *cursor_dl) +{ + struct drm_crtc *crtc; + int clock, pixel_size; + int entries; + + crtc = intel_get_crtc_for_plane(dev, plane); + if (crtc->fb == NULL || !crtc->enabled) + return false; + + clock = crtc->mode.clock; /* VESA DOT Clock */ + pixel_size = crtc->fb->bits_per_pixel / 8; /* BPP */ + + entries = (clock / 1000) * pixel_size; + *plane_prec_mult = (entries > 256) ? + DRAIN_LATENCY_PRECISION_32 : DRAIN_LATENCY_PRECISION_16; + *plane_dl = (64 * (*plane_prec_mult) * 4) / ((clock / 1000) * + pixel_size); + + entries = (clock / 1000) * 4; /* BPP is always 4 for cursor */ + *cursor_prec_mult = (entries > 256) ? + DRAIN_LATENCY_PRECISION_32 : DRAIN_LATENCY_PRECISION_16; + *cursor_dl = (64 * (*cursor_prec_mult) * 4) / ((clock / 1000) * 4); + + return true; +} + +/* + * Update drain latency registers of memory arbiter + * + * Valleyview SoC has a new memory arbiter and needs drain latency registers + * to be programmed. Each plane has a drain latency multiplier and a drain + * latency value. + */ + +static void vlv_update_drain_latency(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int planea_prec, planea_dl, planeb_prec, planeb_dl; + int cursora_prec, cursora_dl, cursorb_prec, cursorb_dl; + int plane_prec_mult, cursor_prec_mult; /* Precision multiplier is + either 16 or 32 */ + + /* For plane A, Cursor A */ + if (vlv_compute_drain_latency(dev, 0, &plane_prec_mult, &planea_dl, + &cursor_prec_mult, &cursora_dl)) { + cursora_prec = (cursor_prec_mult == DRAIN_LATENCY_PRECISION_32) ? + DDL_CURSORA_PRECISION_32 : DDL_CURSORA_PRECISION_16; + planea_prec = (plane_prec_mult == DRAIN_LATENCY_PRECISION_32) ? + DDL_PLANEA_PRECISION_32 : DDL_PLANEA_PRECISION_16; + + I915_WRITE(VLV_DDL1, cursora_prec | + (cursora_dl << DDL_CURSORA_SHIFT) | + planea_prec | planea_dl); + } + + /* For plane B, Cursor B */ + if (vlv_compute_drain_latency(dev, 1, &plane_prec_mult, &planeb_dl, + &cursor_prec_mult, &cursorb_dl)) { + cursorb_prec = (cursor_prec_mult == DRAIN_LATENCY_PRECISION_32) ? + DDL_CURSORB_PRECISION_32 : DDL_CURSORB_PRECISION_16; + planeb_prec = (plane_prec_mult == DRAIN_LATENCY_PRECISION_32) ? + DDL_PLANEB_PRECISION_32 : DDL_PLANEB_PRECISION_16; + + I915_WRITE(VLV_DDL2, cursorb_prec | + (cursorb_dl << DDL_CURSORB_SHIFT) | + planeb_prec | planeb_dl); + } +} + +#define single_plane_enabled(mask) ((mask) != 0 && powerof2(mask)) + +static void valleyview_update_wm(struct drm_device *dev) +{ + static const int sr_latency_ns = 12000; + struct drm_i915_private *dev_priv = dev->dev_private; + int planea_wm, planeb_wm, cursora_wm, cursorb_wm; + int plane_sr, cursor_sr; + unsigned int enabled = 0; + + vlv_update_drain_latency(dev); + + if (g4x_compute_wm0(dev, 0, + &valleyview_wm_info, latency_ns, + &valleyview_cursor_wm_info, latency_ns, + &planea_wm, &cursora_wm)) + enabled |= 1; + + if (g4x_compute_wm0(dev, 1, + &valleyview_wm_info, latency_ns, + &valleyview_cursor_wm_info, latency_ns, + &planeb_wm, &cursorb_wm)) + enabled |= 2; + + plane_sr = cursor_sr = 0; + if (single_plane_enabled(enabled) && + g4x_compute_srwm(dev, ffs(enabled) - 1, + sr_latency_ns, + &valleyview_wm_info, + &valleyview_cursor_wm_info, + &plane_sr, &cursor_sr)) + I915_WRITE(FW_BLC_SELF_VLV, FW_CSPWRDWNEN); + else + I915_WRITE(FW_BLC_SELF_VLV, + I915_READ(FW_BLC_SELF_VLV) & ~FW_CSPWRDWNEN); + + DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n", + planea_wm, cursora_wm, + planeb_wm, cursorb_wm, + plane_sr, cursor_sr); + + I915_WRITE(DSPFW1, + (plane_sr << DSPFW_SR_SHIFT) | + (cursorb_wm << DSPFW_CURSORB_SHIFT) | + (planeb_wm << DSPFW_PLANEB_SHIFT) | + planea_wm); + I915_WRITE(DSPFW2, + (I915_READ(DSPFW2) & DSPFW_CURSORA_MASK) | + (cursora_wm << DSPFW_CURSORA_SHIFT)); + I915_WRITE(DSPFW3, + (I915_READ(DSPFW3) | (cursor_sr << DSPFW_CURSOR_SR_SHIFT))); +} + +static void g4x_update_wm(struct drm_device *dev) +{ + static const int sr_latency_ns = 12000; + struct drm_i915_private *dev_priv = dev->dev_private; + int planea_wm, planeb_wm, cursora_wm, cursorb_wm; + int plane_sr, cursor_sr; + unsigned int enabled = 0; + + if (g4x_compute_wm0(dev, 0, + &g4x_wm_info, latency_ns, + &g4x_cursor_wm_info, latency_ns, + &planea_wm, &cursora_wm)) + enabled |= 1; + + if (g4x_compute_wm0(dev, 1, + &g4x_wm_info, latency_ns, + &g4x_cursor_wm_info, latency_ns, + &planeb_wm, &cursorb_wm)) + enabled |= 2; + + plane_sr = cursor_sr = 0; + if (single_plane_enabled(enabled) && + g4x_compute_srwm(dev, ffs(enabled) - 1, + sr_latency_ns, + &g4x_wm_info, + &g4x_cursor_wm_info, + &plane_sr, &cursor_sr)) + I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN); + else + I915_WRITE(FW_BLC_SELF, + I915_READ(FW_BLC_SELF) & ~FW_BLC_SELF_EN); + + DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n", + planea_wm, cursora_wm, + planeb_wm, cursorb_wm, + plane_sr, cursor_sr); + + I915_WRITE(DSPFW1, + (plane_sr << DSPFW_SR_SHIFT) | + (cursorb_wm << DSPFW_CURSORB_SHIFT) | + (planeb_wm << DSPFW_PLANEB_SHIFT) | + planea_wm); + I915_WRITE(DSPFW2, + (I915_READ(DSPFW2) & DSPFW_CURSORA_MASK) | + (cursora_wm << DSPFW_CURSORA_SHIFT)); + /* HPLL off in SR has some issues on G4x... disable it */ + I915_WRITE(DSPFW3, + (I915_READ(DSPFW3) & ~DSPFW_HPLL_SR_EN) | + (cursor_sr << DSPFW_CURSOR_SR_SHIFT)); +} + +static void i965_update_wm(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc; + int srwm = 1; + int cursor_sr = 16; + + /* Calc sr entries for one plane configs */ + crtc = single_enabled_crtc(dev); + if (crtc) { + /* self-refresh has much higher latency */ + static const int sr_latency_ns = 12000; + int clock = crtc->mode.clock; + int htotal = crtc->mode.htotal; + int hdisplay = crtc->mode.hdisplay; + int pixel_size = crtc->fb->bits_per_pixel / 8; + unsigned long line_time_us; + int entries; + + line_time_us = ((htotal * 1000) / clock); + + /* Use ns/us then divide to preserve precision */ + entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * + pixel_size * hdisplay; + entries = DIV_ROUND_UP(entries, I915_FIFO_LINE_SIZE); + srwm = I965_FIFO_SIZE - entries; + if (srwm < 0) + srwm = 1; + srwm &= 0x1ff; + DRM_DEBUG_KMS("self-refresh entries: %d, wm: %d\n", + entries, srwm); + + entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * + pixel_size * 64; + entries = DIV_ROUND_UP(entries, + i965_cursor_wm_info.cacheline_size); + cursor_sr = i965_cursor_wm_info.fifo_size - + (entries + i965_cursor_wm_info.guard_size); + + if (cursor_sr > i965_cursor_wm_info.max_wm) + cursor_sr = i965_cursor_wm_info.max_wm; + + DRM_DEBUG_KMS("self-refresh watermark: display plane %d " + "cursor %d\n", srwm, cursor_sr); + + if (IS_CRESTLINE(dev)) + I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN); + } else { + /* Turn off self refresh if both pipes are enabled */ + if (IS_CRESTLINE(dev)) + I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF) + & ~FW_BLC_SELF_EN); + } + + DRM_DEBUG_KMS("Setting FIFO watermarks - A: 8, B: 8, C: 8, SR %d\n", + srwm); + + /* 965 has limitations... */ + I915_WRITE(DSPFW1, (srwm << DSPFW_SR_SHIFT) | + (8 << 16) | (8 << 8) | (8 << 0)); + I915_WRITE(DSPFW2, (8 << 8) | (8 << 0)); + /* update cursor SR watermark */ + I915_WRITE(DSPFW3, (cursor_sr << DSPFW_CURSOR_SR_SHIFT)); +} + +static void i9xx_update_wm(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + const struct intel_watermark_params *wm_info; + uint32_t fwater_lo; + uint32_t fwater_hi; + int cwm, srwm = 1; + int fifo_size; + int planea_wm, planeb_wm; + struct drm_crtc *crtc, *enabled = NULL; + + if (IS_I945GM(dev)) + wm_info = &i945_wm_info; + else if (!IS_GEN2(dev)) + wm_info = &i915_wm_info; + else + wm_info = &i855_wm_info; + + fifo_size = dev_priv->display.get_fifo_size(dev, 0); + crtc = intel_get_crtc_for_plane(dev, 0); + if (crtc->enabled && crtc->fb) { + planea_wm = intel_calculate_wm(crtc->mode.clock, + wm_info, fifo_size, + crtc->fb->bits_per_pixel / 8, + latency_ns); + enabled = crtc; + } else + planea_wm = fifo_size - wm_info->guard_size; + + fifo_size = dev_priv->display.get_fifo_size(dev, 1); + crtc = intel_get_crtc_for_plane(dev, 1); + if (crtc->enabled && crtc->fb) { + planeb_wm = intel_calculate_wm(crtc->mode.clock, + wm_info, fifo_size, + crtc->fb->bits_per_pixel / 8, + latency_ns); + if (enabled == NULL) + enabled = crtc; + else + enabled = NULL; + } else + planeb_wm = fifo_size - wm_info->guard_size; + + DRM_DEBUG_KMS("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm); + + /* + * Overlay gets an aggressive default since video jitter is bad. + */ + cwm = 2; + + /* Play safe and disable self-refresh before adjusting watermarks. */ + if (IS_I945G(dev) || IS_I945GM(dev)) + I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | 0); + else if (IS_I915GM(dev)) + I915_WRITE(INSTPM, I915_READ(INSTPM) & ~INSTPM_SELF_EN); + + /* Calc sr entries for one plane configs */ + if (HAS_FW_BLC(dev) && enabled) { + /* self-refresh has much higher latency */ + static const int sr_latency_ns = 6000; + int clock = enabled->mode.clock; + int htotal = enabled->mode.htotal; + int hdisplay = enabled->mode.hdisplay; + int pixel_size = enabled->fb->bits_per_pixel / 8; + unsigned long line_time_us; + int entries; + + line_time_us = (htotal * 1000) / clock; + + /* Use ns/us then divide to preserve precision */ + entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * + pixel_size * hdisplay; + entries = DIV_ROUND_UP(entries, wm_info->cacheline_size); + DRM_DEBUG_KMS("self-refresh entries: %d\n", entries); + srwm = wm_info->fifo_size - entries; + if (srwm < 0) + srwm = 1; + + if (IS_I945G(dev) || IS_I945GM(dev)) + I915_WRITE(FW_BLC_SELF, + FW_BLC_SELF_FIFO_MASK | (srwm & 0xff)); + else if (IS_I915GM(dev)) + I915_WRITE(FW_BLC_SELF, srwm & 0x3f); + } + + DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n", + planea_wm, planeb_wm, cwm, srwm); + + fwater_lo = ((planeb_wm & 0x3f) << 16) | (planea_wm & 0x3f); + fwater_hi = (cwm & 0x1f); + + /* Set request length to 8 cachelines per fetch */ + fwater_lo = fwater_lo | (1 << 24) | (1 << 8); + fwater_hi = fwater_hi | (1 << 8); + + I915_WRITE(FW_BLC, fwater_lo); + I915_WRITE(FW_BLC2, fwater_hi); + + if (HAS_FW_BLC(dev)) { + if (enabled) { + if (IS_I945G(dev) || IS_I945GM(dev)) + I915_WRITE(FW_BLC_SELF, + FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN); + else if (IS_I915GM(dev)) + I915_WRITE(INSTPM, I915_READ(INSTPM) | INSTPM_SELF_EN); + DRM_DEBUG_KMS("memory self refresh enabled\n"); + } else + DRM_DEBUG_KMS("memory self refresh disabled\n"); + } +} + +static void i830_update_wm(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc; + uint32_t fwater_lo; + int planea_wm; + + crtc = single_enabled_crtc(dev); + if (crtc == NULL) + return; + + planea_wm = intel_calculate_wm(crtc->mode.clock, &i830_wm_info, + dev_priv->display.get_fifo_size(dev, 0), + crtc->fb->bits_per_pixel / 8, + latency_ns); + fwater_lo = I915_READ(FW_BLC) & ~0xfff; + fwater_lo |= (3<<8) | planea_wm; + + DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d\n", planea_wm); + + I915_WRITE(FW_BLC, fwater_lo); +} + +#define ILK_LP0_PLANE_LATENCY 700 +#define ILK_LP0_CURSOR_LATENCY 1300 + +/* + * Check the wm result. + * + * If any calculated watermark values is larger than the maximum value that + * can be programmed into the associated watermark register, that watermark + * must be disabled. + */ +static bool ironlake_check_srwm(struct drm_device *dev, int level, + int fbc_wm, int display_wm, int cursor_wm, + const struct intel_watermark_params *display, + const struct intel_watermark_params *cursor) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + DRM_DEBUG_KMS("watermark %d: display plane %d, fbc lines %d," + " cursor %d\n", level, display_wm, fbc_wm, cursor_wm); + + if (fbc_wm > SNB_FBC_MAX_SRWM) { + DRM_DEBUG_KMS("fbc watermark(%d) is too large(%d), disabling wm%d+\n", + fbc_wm, SNB_FBC_MAX_SRWM, level); + + /* fbc has it's own way to disable FBC WM */ + I915_WRITE(DISP_ARB_CTL, + I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS); + return false; + } + + if (display_wm > display->max_wm) { + DRM_DEBUG_KMS("display watermark(%d) is too large(%d), disabling wm%d+\n", + display_wm, SNB_DISPLAY_MAX_SRWM, level); + return false; + } + + if (cursor_wm > cursor->max_wm) { + DRM_DEBUG_KMS("cursor watermark(%d) is too large(%d), disabling wm%d+\n", + cursor_wm, SNB_CURSOR_MAX_SRWM, level); + return false; + } + + if (!(fbc_wm || display_wm || cursor_wm)) { + DRM_DEBUG_KMS("latency %d is 0, disabling wm%d+\n", level, level); + return false; + } + + return true; +} + +/* + * Compute watermark values of WM[1-3], + */ +static bool ironlake_compute_srwm(struct drm_device *dev, int level, int plane, + int latency_ns, + const struct intel_watermark_params *display, + const struct intel_watermark_params *cursor, + int *fbc_wm, int *display_wm, int *cursor_wm) +{ + struct drm_crtc *crtc; + unsigned long line_time_us; + int hdisplay, htotal, pixel_size, clock; + int line_count, line_size; + int small, large; + int entries; + + if (!latency_ns) { + *fbc_wm = *display_wm = *cursor_wm = 0; + return false; + } + + crtc = intel_get_crtc_for_plane(dev, plane); + hdisplay = crtc->mode.hdisplay; + htotal = crtc->mode.htotal; + clock = crtc->mode.clock; + pixel_size = crtc->fb->bits_per_pixel / 8; + + line_time_us = (htotal * 1000) / clock; + line_count = (latency_ns / line_time_us + 1000) / 1000; + line_size = hdisplay * pixel_size; + + /* Use the minimum of the small and large buffer method for primary */ + small = ((clock * pixel_size / 1000) * latency_ns) / 1000; + large = line_count * line_size; + + entries = DIV_ROUND_UP(min(small, large), display->cacheline_size); + *display_wm = entries + display->guard_size; + + /* + * Spec says: + * FBC WM = ((Final Primary WM * 64) / number of bytes per line) + 2 + */ + *fbc_wm = DIV_ROUND_UP(*display_wm * 64, line_size) + 2; + + /* calculate the self-refresh watermark for display cursor */ + entries = line_count * pixel_size * 64; + entries = DIV_ROUND_UP(entries, cursor->cacheline_size); + *cursor_wm = entries + cursor->guard_size; + + return ironlake_check_srwm(dev, level, + *fbc_wm, *display_wm, *cursor_wm, + display, cursor); +} + +static void ironlake_update_wm(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int fbc_wm, plane_wm, cursor_wm; + unsigned int enabled; + + enabled = 0; + if (g4x_compute_wm0(dev, 0, + &ironlake_display_wm_info, + ILK_LP0_PLANE_LATENCY, + &ironlake_cursor_wm_info, + ILK_LP0_CURSOR_LATENCY, + &plane_wm, &cursor_wm)) { + I915_WRITE(WM0_PIPEA_ILK, + (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm); + DRM_DEBUG_KMS("FIFO watermarks For pipe A -" + " plane %d, " "cursor: %d\n", + plane_wm, cursor_wm); + enabled |= 1; + } + + if (g4x_compute_wm0(dev, 1, + &ironlake_display_wm_info, + ILK_LP0_PLANE_LATENCY, + &ironlake_cursor_wm_info, + ILK_LP0_CURSOR_LATENCY, + &plane_wm, &cursor_wm)) { + I915_WRITE(WM0_PIPEB_ILK, + (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm); + DRM_DEBUG_KMS("FIFO watermarks For pipe B -" + " plane %d, cursor: %d\n", + plane_wm, cursor_wm); + enabled |= 2; + } + + /* + * Calculate and update the self-refresh watermark only when one + * display plane is used. + */ + I915_WRITE(WM3_LP_ILK, 0); + I915_WRITE(WM2_LP_ILK, 0); + I915_WRITE(WM1_LP_ILK, 0); + + if (!single_plane_enabled(enabled)) + return; + enabled = ffs(enabled) - 1; + + /* WM1 */ + if (!ironlake_compute_srwm(dev, 1, enabled, + ILK_READ_WM1_LATENCY() * 500, + &ironlake_display_srwm_info, + &ironlake_cursor_srwm_info, + &fbc_wm, &plane_wm, &cursor_wm)) + return; + + I915_WRITE(WM1_LP_ILK, + WM1_LP_SR_EN | + (ILK_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) | + (fbc_wm << WM1_LP_FBC_SHIFT) | + (plane_wm << WM1_LP_SR_SHIFT) | + cursor_wm); + + /* WM2 */ + if (!ironlake_compute_srwm(dev, 2, enabled, + ILK_READ_WM2_LATENCY() * 500, + &ironlake_display_srwm_info, + &ironlake_cursor_srwm_info, + &fbc_wm, &plane_wm, &cursor_wm)) + return; + + I915_WRITE(WM2_LP_ILK, + WM2_LP_EN | + (ILK_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) | + (fbc_wm << WM1_LP_FBC_SHIFT) | + (plane_wm << WM1_LP_SR_SHIFT) | + cursor_wm); + + /* + * WM3 is unsupported on ILK, probably because we don't have latency + * data for that power state + */ +} + +static void sandybridge_update_wm(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */ + u32 val; + int fbc_wm, plane_wm, cursor_wm; + unsigned int enabled; + + enabled = 0; + if (g4x_compute_wm0(dev, 0, + &sandybridge_display_wm_info, latency, + &sandybridge_cursor_wm_info, latency, + &plane_wm, &cursor_wm)) { + val = I915_READ(WM0_PIPEA_ILK); + val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); + I915_WRITE(WM0_PIPEA_ILK, val | + ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm)); + DRM_DEBUG_KMS("FIFO watermarks For pipe A -" + " plane %d, " "cursor: %d\n", + plane_wm, cursor_wm); + enabled |= 1; + } + + if (g4x_compute_wm0(dev, 1, + &sandybridge_display_wm_info, latency, + &sandybridge_cursor_wm_info, latency, + &plane_wm, &cursor_wm)) { + val = I915_READ(WM0_PIPEB_ILK); + val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); + I915_WRITE(WM0_PIPEB_ILK, val | + ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm)); + DRM_DEBUG_KMS("FIFO watermarks For pipe B -" + " plane %d, cursor: %d\n", + plane_wm, cursor_wm); + enabled |= 2; + } + + if ((dev_priv->num_pipe == 3) && + g4x_compute_wm0(dev, 2, + &sandybridge_display_wm_info, latency, + &sandybridge_cursor_wm_info, latency, + &plane_wm, &cursor_wm)) { + val = I915_READ(WM0_PIPEC_IVB); + val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); + I915_WRITE(WM0_PIPEC_IVB, val | + ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm)); + DRM_DEBUG_KMS("FIFO watermarks For pipe C -" + " plane %d, cursor: %d\n", + plane_wm, cursor_wm); + enabled |= 3; + } + + /* + * Calculate and update the self-refresh watermark only when one + * display plane is used. + * + * SNB support 3 levels of watermark. + * + * WM1/WM2/WM2 watermarks have to be enabled in the ascending order, + * and disabled in the descending order + * + */ + I915_WRITE(WM3_LP_ILK, 0); + I915_WRITE(WM2_LP_ILK, 0); + I915_WRITE(WM1_LP_ILK, 0); + + if (!single_plane_enabled(enabled) || + dev_priv->sprite_scaling_enabled) + return; + enabled = ffs(enabled) - 1; + + /* WM1 */ + if (!ironlake_compute_srwm(dev, 1, enabled, + SNB_READ_WM1_LATENCY() * 500, + &sandybridge_display_srwm_info, + &sandybridge_cursor_srwm_info, + &fbc_wm, &plane_wm, &cursor_wm)) + return; + + I915_WRITE(WM1_LP_ILK, + WM1_LP_SR_EN | + (SNB_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) | + (fbc_wm << WM1_LP_FBC_SHIFT) | + (plane_wm << WM1_LP_SR_SHIFT) | + cursor_wm); + + /* WM2 */ + if (!ironlake_compute_srwm(dev, 2, enabled, + SNB_READ_WM2_LATENCY() * 500, + &sandybridge_display_srwm_info, + &sandybridge_cursor_srwm_info, + &fbc_wm, &plane_wm, &cursor_wm)) + return; + + I915_WRITE(WM2_LP_ILK, + WM2_LP_EN | + (SNB_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) | + (fbc_wm << WM1_LP_FBC_SHIFT) | + (plane_wm << WM1_LP_SR_SHIFT) | + cursor_wm); + + /* WM3 */ + if (!ironlake_compute_srwm(dev, 3, enabled, + SNB_READ_WM3_LATENCY() * 500, + &sandybridge_display_srwm_info, + &sandybridge_cursor_srwm_info, + &fbc_wm, &plane_wm, &cursor_wm)) + return; + + I915_WRITE(WM3_LP_ILK, + WM3_LP_EN | + (SNB_READ_WM3_LATENCY() << WM1_LP_LATENCY_SHIFT) | + (fbc_wm << WM1_LP_FBC_SHIFT) | + (plane_wm << WM1_LP_SR_SHIFT) | + cursor_wm); +} + +static void +haswell_update_linetime_wm(struct drm_device *dev, int pipe, + struct drm_display_mode *mode) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 temp; + + temp = I915_READ(PIPE_WM_LINETIME(pipe)); + temp &= ~PIPE_WM_LINETIME_MASK; + + /* The WM are computed with base on how long it takes to fill a single + * row at the given clock rate, multiplied by 8. + * */ + temp |= PIPE_WM_LINETIME_TIME( + ((mode->crtc_hdisplay * 1000) / mode->clock) * 8); + + /* IPS watermarks are only used by pipe A, and are ignored by + * pipes B and C. They are calculated similarly to the common + * linetime values, except that we are using CD clock frequency + * in MHz instead of pixel rate for the division. + * + * This is a placeholder for the IPS watermark calculation code. + */ + + I915_WRITE(PIPE_WM_LINETIME(pipe), temp); +} + +static bool +sandybridge_compute_sprite_wm(struct drm_device *dev, int plane, + uint32_t sprite_width, int pixel_size, + const struct intel_watermark_params *display, + int display_latency_ns, int *sprite_wm) +{ + struct drm_crtc *crtc; + int clock; + int entries, tlb_miss; + + crtc = intel_get_crtc_for_plane(dev, plane); + if (crtc->fb == NULL || !crtc->enabled) { + *sprite_wm = display->guard_size; + return false; + } + + clock = crtc->mode.clock; + + /* Use the small buffer method to calculate the sprite watermark */ + entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000; + tlb_miss = display->fifo_size*display->cacheline_size - + sprite_width * 8; + if (tlb_miss > 0) + entries += tlb_miss; + entries = DIV_ROUND_UP(entries, display->cacheline_size); + *sprite_wm = entries + display->guard_size; + if (*sprite_wm > (int)display->max_wm) + *sprite_wm = display->max_wm; + + return true; +} + +static bool +sandybridge_compute_sprite_srwm(struct drm_device *dev, int plane, + uint32_t sprite_width, int pixel_size, + const struct intel_watermark_params *display, + int latency_ns, int *sprite_wm) +{ + struct drm_crtc *crtc; + unsigned long line_time_us; + int clock; + int line_count, line_size; + int small, large; + int entries; + + if (!latency_ns) { + *sprite_wm = 0; + return false; + } + + crtc = intel_get_crtc_for_plane(dev, plane); + clock = crtc->mode.clock; + if (!clock) { + *sprite_wm = 0; + return false; + } + + line_time_us = (sprite_width * 1000) / clock; + if (!line_time_us) { + *sprite_wm = 0; + return false; + } + + line_count = (latency_ns / line_time_us + 1000) / 1000; + line_size = sprite_width * pixel_size; + + /* Use the minimum of the small and large buffer method for primary */ + small = ((clock * pixel_size / 1000) * latency_ns) / 1000; + large = line_count * line_size; + + entries = DIV_ROUND_UP(min(small, large), display->cacheline_size); + *sprite_wm = entries + display->guard_size; + + return *sprite_wm > 0x3ff ? false : true; +} + +static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe, + uint32_t sprite_width, int pixel_size) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */ + u32 val; + int sprite_wm, reg; + int ret; + + switch (pipe) { + case 0: + reg = WM0_PIPEA_ILK; + break; + case 1: + reg = WM0_PIPEB_ILK; + break; + case 2: + reg = WM0_PIPEC_IVB; + break; + default: + return; /* bad pipe */ + } + + ret = sandybridge_compute_sprite_wm(dev, pipe, sprite_width, pixel_size, + &sandybridge_display_wm_info, + latency, &sprite_wm); + if (!ret) { + DRM_DEBUG_KMS("failed to compute sprite wm for pipe %d\n", + pipe); + return; + } + + val = I915_READ(reg); + val &= ~WM0_PIPE_SPRITE_MASK; + I915_WRITE(reg, val | (sprite_wm << WM0_PIPE_SPRITE_SHIFT)); + DRM_DEBUG_KMS("sprite watermarks For pipe %d - %d\n", pipe, sprite_wm); + + + ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width, + pixel_size, + &sandybridge_display_srwm_info, + SNB_READ_WM1_LATENCY() * 500, + &sprite_wm); + if (!ret) { + DRM_DEBUG_KMS("failed to compute sprite lp1 wm on pipe %d\n", + pipe); + return; + } + I915_WRITE(WM1S_LP_ILK, sprite_wm); + + /* Only IVB has two more LP watermarks for sprite */ + if (!IS_IVYBRIDGE(dev)) + return; + + ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width, + pixel_size, + &sandybridge_display_srwm_info, + SNB_READ_WM2_LATENCY() * 500, + &sprite_wm); + if (!ret) { + DRM_DEBUG_KMS("failed to compute sprite lp2 wm on pipe %d\n", + pipe); + return; + } + I915_WRITE(WM2S_LP_IVB, sprite_wm); + + ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width, + pixel_size, + &sandybridge_display_srwm_info, + SNB_READ_WM3_LATENCY() * 500, + &sprite_wm); + if (!ret) { + DRM_DEBUG_KMS("failed to compute sprite lp3 wm on pipe %d\n", + pipe); + return; + } + I915_WRITE(WM3S_LP_IVB, sprite_wm); +} + +/** + * intel_update_watermarks - update FIFO watermark values based on current modes + * + * Calculate watermark values for the various WM regs based on current mode + * and plane configuration. + * + * There are several cases to deal with here: + * - normal (i.e. non-self-refresh) + * - self-refresh (SR) mode + * - lines are large relative to FIFO size (buffer can hold up to 2) + * - lines are small relative to FIFO size (buffer can hold more than 2 + * lines), so need to account for TLB latency + * + * The normal calculation is: + * watermark = dotclock * bytes per pixel * latency + * where latency is platform & configuration dependent (we assume pessimal + * values here). + * + * The SR calculation is: + * watermark = (trunc(latency/line time)+1) * surface width * + * bytes per pixel + * where + * line time = htotal / dotclock + * surface width = hdisplay for normal plane and 64 for cursor + * and latency is assumed to be high, as above. + * + * The final value programmed to the register should always be rounded up, + * and include an extra 2 entries to account for clock crossings. + * + * We don't use the sprite, so we can ignore that. And on Crestline we have + * to set the non-SR watermarks to 8. + */ +void intel_update_watermarks(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->display.update_wm) + dev_priv->display.update_wm(dev); +} + +void intel_update_linetime_watermarks(struct drm_device *dev, + int pipe, struct drm_display_mode *mode) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->display.update_linetime_wm) + dev_priv->display.update_linetime_wm(dev, pipe, mode); +} + +void intel_update_sprite_watermarks(struct drm_device *dev, int pipe, + uint32_t sprite_width, int pixel_size) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->display.update_sprite_wm) + dev_priv->display.update_sprite_wm(dev, pipe, sprite_width, + pixel_size); +} + +static struct drm_i915_gem_object * +intel_alloc_context_page(struct drm_device *dev) +{ + struct drm_i915_gem_object *ctx; + int ret; + + DRM_LOCK_ASSERT(dev); + + ctx = i915_gem_alloc_object(dev, 4096); + if (!ctx) { + DRM_DEBUG("failed to alloc power context, RC6 disabled\n"); + return NULL; + } + + ret = i915_gem_object_pin(ctx, 4096, true); + if (ret) { + DRM_ERROR("failed to pin power context: %d\n", ret); + goto err_unref; + } + + ret = i915_gem_object_set_to_gtt_domain(ctx, 1); + if (ret) { + DRM_ERROR("failed to set-domain on power context: %d\n", ret); + goto err_unpin; + } + + return ctx; + +err_unpin: + i915_gem_object_unpin(ctx); +err_unref: + drm_gem_object_unreference(&ctx->base); + DRM_UNLOCK(dev); + return NULL; +} + +bool ironlake_set_drps(struct drm_device *dev, u8 val) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u16 rgvswctl; + + rgvswctl = I915_READ16(MEMSWCTL); + if (rgvswctl & MEMCTL_CMD_STS) { + DRM_DEBUG("gpu busy, RCS change rejected\n"); + return false; /* still busy with another command */ + } + + rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) | + (val << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM; + I915_WRITE16(MEMSWCTL, rgvswctl); + POSTING_READ16(MEMSWCTL); + + rgvswctl |= MEMCTL_CMD_STS; + I915_WRITE16(MEMSWCTL, rgvswctl); + + return true; +} + +void ironlake_enable_drps(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 rgvmodectl = I915_READ(MEMMODECTL); + u8 fmax, fmin, fstart, vstart; + + /* Enable temp reporting */ + I915_WRITE16(PMMISC, I915_READ(PMMISC) | MCPPCE_EN); + I915_WRITE16(TSC1, I915_READ(TSC1) | TSE); + + /* 100ms RC evaluation intervals */ + I915_WRITE(RCUPEI, 100000); + I915_WRITE(RCDNEI, 100000); + + /* Set max/min thresholds to 90ms and 80ms respectively */ + I915_WRITE(RCBMAXAVG, 90000); + I915_WRITE(RCBMINAVG, 80000); + + I915_WRITE(MEMIHYST, 1); + + /* Set up min, max, and cur for interrupt handling */ + fmax = (rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT; + fmin = (rgvmodectl & MEMMODE_FMIN_MASK); + fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >> + MEMMODE_FSTART_SHIFT; + + vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >> + PXVFREQ_PX_SHIFT; + + dev_priv->fmax = fmax; /* IPS callback will increase this */ + dev_priv->fstart = fstart; + + dev_priv->max_delay = fstart; + dev_priv->min_delay = fmin; + dev_priv->cur_delay = fstart; + + DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n", + fmax, fmin, fstart); + + I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN); + + /* + * Interrupts will be enabled in ironlake_irq_postinstall + */ + + I915_WRITE(VIDSTART, vstart); + POSTING_READ(VIDSTART); + + rgvmodectl |= MEMMODE_SWMODE_EN; + I915_WRITE(MEMMODECTL, rgvmodectl); + + if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10)) + DRM_ERROR("stuck trying to change perf mode\n"); + pause("915dsp", 1); + + ironlake_set_drps(dev, fstart); + + dev_priv->last_count1 = I915_READ(0x112e4) + I915_READ(0x112e8) + + I915_READ(0x112e0); + dev_priv->last_time1 = jiffies_to_msecs(jiffies); + dev_priv->last_count2 = I915_READ(0x112f4); + nanotime(&dev_priv->last_time2); +} + +void ironlake_disable_drps(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u16 rgvswctl = I915_READ16(MEMSWCTL); + + /* Ack interrupts, disable EFC interrupt */ + I915_WRITE(MEMINTREN, I915_READ(MEMINTREN) & ~MEMINT_EVAL_CHG_EN); + I915_WRITE(MEMINTRSTS, MEMINT_EVAL_CHG); + I915_WRITE(DEIER, I915_READ(DEIER) & ~DE_PCU_EVENT); + I915_WRITE(DEIIR, DE_PCU_EVENT); + I915_WRITE(DEIMR, I915_READ(DEIMR) | DE_PCU_EVENT); + + /* Go back to the starting frequency */ + ironlake_set_drps(dev, dev_priv->fstart); + pause("915dsp", 1); + rgvswctl |= MEMCTL_CMD_STS; + I915_WRITE(MEMSWCTL, rgvswctl); + pause("915dsp", 1); + +} + +void gen6_set_rps(struct drm_device *dev, u8 val) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 swreq; + + swreq = (val & 0x3ff) << 25; + I915_WRITE(GEN6_RPNSWREQ, swreq); +} + +void gen6_disable_rps(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(GEN6_RPNSWREQ, 1 << 31); + I915_WRITE(GEN6_PMINTRMSK, 0xffffffff); + I915_WRITE(GEN6_PMIER, 0); + /* Complete PM interrupt masking here doesn't race with the rps work + * item again unmasking PM interrupts because that is using a different + * register (PMIMR) to mask PM interrupts. The only risk is in leaving + * stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */ + + mtx_lock(&dev_priv->rps_lock); + dev_priv->pm_iir = 0; + mtx_unlock(&dev_priv->rps_lock); + + I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR)); +} + +int intel_enable_rc6(const struct drm_device *dev) +{ + /* + * Respect the kernel parameter if it is set + */ + if (i915_enable_rc6 >= 0) + return i915_enable_rc6; + + /* + * Disable RC6 on Ironlake + */ + if (INTEL_INFO(dev)->gen == 5) + return 0; + + /* Sorry Haswell, no RC6 for you for now. */ + if (IS_HASWELL(dev)) + return 0; + + /* + * Disable rc6 on Sandybridge + */ + if (INTEL_INFO(dev)->gen == 6) { + DRM_DEBUG_DRIVER("Sandybridge: deep RC6 disabled\n"); + return INTEL_RC6_ENABLE; + } + DRM_DEBUG_DRIVER("RC6 and deep RC6 enabled\n"); + return (INTEL_RC6_ENABLE | INTEL_RC6p_ENABLE); +} + +void gen6_enable_rps(struct drm_i915_private *dev_priv) +{ + struct intel_ring_buffer *ring; + u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); + u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); + u32 pcu_mbox, rc6_mask = 0; + u32 gtfifodbg; + int cur_freq, min_freq, max_freq; + int rc6_mode; + int i; + + /* Here begins a magic sequence of register writes to enable + * auto-downclocking. + * + * Perhaps there might be some value in exposing these to + * userspace... + */ + I915_WRITE(GEN6_RC_STATE, 0); + DRM_LOCK(dev_priv->dev); + + /* Clear the DBG now so we don't confuse earlier errors */ + if ((gtfifodbg = I915_READ(GTFIFODBG))) { + DRM_ERROR("GT fifo had a previous error %x\n", gtfifodbg); + I915_WRITE(GTFIFODBG, gtfifodbg); + } + + gen6_gt_force_wake_get(dev_priv); + + /* disable the counters and set deterministic thresholds */ + I915_WRITE(GEN6_RC_CONTROL, 0); + + I915_WRITE(GEN6_RC1_WAKE_RATE_LIMIT, 1000 << 16); + I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 40 << 16 | 30); + I915_WRITE(GEN6_RC6pp_WAKE_RATE_LIMIT, 30); + I915_WRITE(GEN6_RC_EVALUATION_INTERVAL, 125000); + I915_WRITE(GEN6_RC_IDLE_HYSTERSIS, 25); + + for_each_ring(ring, dev_priv, i) + I915_WRITE(RING_MAX_IDLE(ring->mmio_base), 10); + + I915_WRITE(GEN6_RC_SLEEP, 0); + I915_WRITE(GEN6_RC1e_THRESHOLD, 1000); + I915_WRITE(GEN6_RC6_THRESHOLD, 50000); + I915_WRITE(GEN6_RC6p_THRESHOLD, 100000); + I915_WRITE(GEN6_RC6pp_THRESHOLD, 64000); /* unused */ + + rc6_mode = intel_enable_rc6(dev_priv->dev); + if (rc6_mode & INTEL_RC6_ENABLE) + rc6_mask |= GEN6_RC_CTL_RC6_ENABLE; + + if (rc6_mode & INTEL_RC6p_ENABLE) + rc6_mask |= GEN6_RC_CTL_RC6p_ENABLE; + + if (rc6_mode & INTEL_RC6pp_ENABLE) + rc6_mask |= GEN6_RC_CTL_RC6pp_ENABLE; + + DRM_INFO("Enabling RC6 states: RC6 %s, RC6p %s, RC6pp %s\n", + (rc6_mode & INTEL_RC6_ENABLE) ? "on" : "off", + (rc6_mode & INTEL_RC6p_ENABLE) ? "on" : "off", + (rc6_mode & INTEL_RC6pp_ENABLE) ? "on" : "off"); + + I915_WRITE(GEN6_RC_CONTROL, + rc6_mask | + GEN6_RC_CTL_EI_MODE(1) | + GEN6_RC_CTL_HW_ENABLE); + + I915_WRITE(GEN6_RPNSWREQ, + GEN6_FREQUENCY(10) | + GEN6_OFFSET(0) | + GEN6_AGGRESSIVE_TURBO); + I915_WRITE(GEN6_RC_VIDEO_FREQ, + GEN6_FREQUENCY(12)); + + I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000); + I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, + 18 << 24 | + 6 << 16); + I915_WRITE(GEN6_RP_UP_THRESHOLD, 10000); + I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 1000000); + I915_WRITE(GEN6_RP_UP_EI, 100000); + I915_WRITE(GEN6_RP_DOWN_EI, 5000000); + I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10); + I915_WRITE(GEN6_RP_CONTROL, + GEN6_RP_MEDIA_TURBO | + GEN6_RP_MEDIA_HW_MODE | + GEN6_RP_MEDIA_IS_GFX | + GEN6_RP_ENABLE | + GEN6_RP_UP_BUSY_AVG | + GEN6_RP_DOWN_IDLE_CONT); + + if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, + 500)) + DRM_ERROR("timeout waiting for pcode mailbox to become idle\n"); + + I915_WRITE(GEN6_PCODE_DATA, 0); + I915_WRITE(GEN6_PCODE_MAILBOX, + GEN6_PCODE_READY | + GEN6_PCODE_WRITE_MIN_FREQ_TABLE); + if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, + 500)) + DRM_ERROR("timeout waiting for pcode mailbox to finish\n"); + + min_freq = (rp_state_cap & 0xff0000) >> 16; + max_freq = rp_state_cap & 0xff; + cur_freq = (gt_perf_status & 0xff00) >> 8; + + /* Check for overclock support */ + if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, + 500)) + DRM_ERROR("timeout waiting for pcode mailbox to become idle\n"); + I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_READ_OC_PARAMS); + pcu_mbox = I915_READ(GEN6_PCODE_DATA); + if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, + 500)) + DRM_ERROR("timeout waiting for pcode mailbox to finish\n"); + if (pcu_mbox & (1<<31)) { /* OC supported */ + max_freq = pcu_mbox & 0xff; + DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 50); + } + + /* In units of 100MHz */ + dev_priv->max_delay = max_freq; + dev_priv->min_delay = min_freq; + dev_priv->cur_delay = cur_freq; + + /* requires MSI enabled */ + I915_WRITE(GEN6_PMIER, + GEN6_PM_MBOX_EVENT | + GEN6_PM_THERMAL_EVENT | + GEN6_PM_RP_DOWN_TIMEOUT | + GEN6_PM_RP_UP_THRESHOLD | + GEN6_PM_RP_DOWN_THRESHOLD | + GEN6_PM_RP_UP_EI_EXPIRED | + GEN6_PM_RP_DOWN_EI_EXPIRED); + mtx_lock(&dev_priv->rps_lock); + if (dev_priv->pm_iir != 0) + printf("KMS: pm_iir %x\n", dev_priv->pm_iir); + I915_WRITE(GEN6_PMIMR, 0); + mtx_unlock(&dev_priv->rps_lock); + /* enable all PM interrupts */ + I915_WRITE(GEN6_PMINTRMSK, 0); + + gen6_gt_force_wake_put(dev_priv); + DRM_UNLOCK(dev_priv->dev); +} + +void gen6_update_ring_freq(struct drm_i915_private *dev_priv) +{ + int min_freq = 15; + int gpu_freq, ia_freq, max_ia_freq; + int scaling_factor = 180; + uint64_t tsc_freq; + +#if 0 + max_ia_freq = cpufreq_quick_get_max(0); + /* + * Default to measured freq if none found, PCU will ensure we don't go + * over + */ + if (!max_ia_freq) + max_ia_freq = tsc_khz; + + /* Convert from kHz to MHz */ + max_ia_freq /= 1000; +#else + tsc_freq = atomic_load_acq_64(&tsc_freq); + max_ia_freq = tsc_freq / 1000 / 1000; +#endif + + DRM_LOCK(dev_priv->dev); + + /* + * For each potential GPU frequency, load a ring frequency we'd like + * to use for memory access. We do this by specifying the IA frequency + * the PCU should use as a reference to determine the ring frequency. + */ + for (gpu_freq = dev_priv->max_delay; gpu_freq >= dev_priv->min_delay; + gpu_freq--) { + int diff = dev_priv->max_delay - gpu_freq; + int d; + + /* + * For GPU frequencies less than 750MHz, just use the lowest + * ring freq. + */ + if (gpu_freq < min_freq) + ia_freq = 800; + else + ia_freq = max_ia_freq - ((diff * scaling_factor) / 2); + d = 100; + ia_freq = (ia_freq + d / 2) / d; + + I915_WRITE(GEN6_PCODE_DATA, + (ia_freq << GEN6_PCODE_FREQ_IA_RATIO_SHIFT) | + gpu_freq); + I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY | + GEN6_PCODE_WRITE_MIN_FREQ_TABLE); + if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & + GEN6_PCODE_READY) == 0, 10)) { + DRM_ERROR("pcode write of freq table timed out\n"); + continue; + } + } + + DRM_UNLOCK(dev_priv->dev); +} + +static void ironlake_teardown_rc6(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->renderctx) { + i915_gem_object_unpin(dev_priv->renderctx); + drm_gem_object_unreference(&dev_priv->renderctx->base); + dev_priv->renderctx = NULL; + } + + if (dev_priv->pwrctx) { + i915_gem_object_unpin(dev_priv->pwrctx); + drm_gem_object_unreference(&dev_priv->pwrctx->base); + dev_priv->pwrctx = NULL; + } +} + +void ironlake_disable_rc6(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (I915_READ(PWRCTXA)) { + /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */ + I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT); + wait_for(((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON), + 50); + + I915_WRITE(PWRCTXA, 0); + POSTING_READ(PWRCTXA); + + I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT); + POSTING_READ(RSTDBYCTL); + } + + ironlake_teardown_rc6(dev); +} + +static int ironlake_setup_rc6(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->renderctx == NULL) + dev_priv->renderctx = intel_alloc_context_page(dev); + if (!dev_priv->renderctx) + return -ENOMEM; + + if (dev_priv->pwrctx == NULL) + dev_priv->pwrctx = intel_alloc_context_page(dev); + if (!dev_priv->pwrctx) { + ironlake_teardown_rc6(dev); + return -ENOMEM; + } + + return 0; +} + +void ironlake_enable_rc6(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring = &dev_priv->rings[RCS]; + int ret; + + /* rc6 disabled by default due to repeated reports of hanging during + * boot and resume. + */ + if (!intel_enable_rc6(dev)) + return; + + DRM_LOCK(dev); + ret = ironlake_setup_rc6(dev); + if (ret) { + DRM_UNLOCK(dev); + return; + } + + /* + * GPU can automatically power down the render unit if given a page + * to save state. + */ + ret = intel_ring_begin(ring, 6); + if (ret) { + ironlake_teardown_rc6(dev); + DRM_UNLOCK(dev); + return; + } + + intel_ring_emit(ring, MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN); + intel_ring_emit(ring, MI_SET_CONTEXT); + intel_ring_emit(ring, dev_priv->renderctx->gtt_offset | + MI_MM_SPACE_GTT | + MI_SAVE_EXT_STATE_EN | + MI_RESTORE_EXT_STATE_EN | + MI_RESTORE_INHIBIT); + intel_ring_emit(ring, MI_SUSPEND_FLUSH); + intel_ring_emit(ring, MI_NOOP); + intel_ring_emit(ring, MI_FLUSH); + intel_ring_advance(ring); + + /* + * Wait for the command parser to advance past MI_SET_CONTEXT. The HW + * does an implicit flush, combined with MI_FLUSH above, it should be + * safe to assume that renderctx is valid + */ + ret = intel_wait_ring_idle(ring); + if (ret) { + DRM_ERROR("failed to enable ironlake power power savings\n"); + ironlake_teardown_rc6(dev); + DRM_UNLOCK(dev); + return; + } + + I915_WRITE(PWRCTXA, dev_priv->pwrctx->gtt_offset | PWRCTX_EN); + I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT); + DRM_UNLOCK(dev); +} + +static unsigned long intel_pxfreq(u32 vidfreq) +{ + unsigned long freq; + int div = (vidfreq & 0x3f0000) >> 16; + int post = (vidfreq & 0x3000) >> 12; + int pre = (vidfreq & 0x7); + + if (!pre) + return 0; + + freq = ((div * 133333) / ((1<last_time1; + /* + * sysctl(8) reads the value of sysctl twice in rapid + * succession. There is high chance that it happens in the + * same timer tick. Use the cached value to not divide by + * zero and give the hw a chance to gather more samples. + */ + if (diff1 <= 10) + return (dev_priv->chipset_power); + + count1 = I915_READ(DMIEC); + count2 = I915_READ(DDREC); + count3 = I915_READ(CSIEC); + + total_count = count1 + count2 + count3; + + /* FIXME: handle per-counter overflow */ + if (total_count < dev_priv->last_count1) { + diff = ~0UL - dev_priv->last_count1; + diff += total_count; + } else { + diff = total_count - dev_priv->last_count1; + } + + for (i = 0; i < DRM_ARRAY_SIZE(cparams); i++) { + if (cparams[i].i == dev_priv->c_m && + cparams[i].t == dev_priv->r_t) { + m = cparams[i].m; + c = cparams[i].c; + break; + } + } + + diff = diff / diff1; + ret = ((m * diff) + c); + ret = ret / 10; + + dev_priv->last_count1 = total_count; + dev_priv->last_time1 = now; + + dev_priv->chipset_power = ret; + return (ret); +} + +unsigned long i915_mch_val(struct drm_i915_private *dev_priv) +{ + unsigned long m, x, b; + u32 tsfs; + + tsfs = I915_READ(TSFS); + + m = ((tsfs & TSFS_SLOPE_MASK) >> TSFS_SLOPE_SHIFT); + x = I915_READ8(I915_TR1); + + b = tsfs & TSFS_INTR_MASK; + + return ((m * x) / 127) - b; +} + +static u16 pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid) +{ + static const struct v_table { + u16 vd; /* in .1 mil */ + u16 vm; /* in .1 mil */ + } v_table[] = { + { 0, 0, }, + { 375, 0, }, + { 500, 0, }, + { 625, 0, }, + { 750, 0, }, + { 875, 0, }, + { 1000, 0, }, + { 1125, 0, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4250, 3125, }, + { 4375, 3250, }, + { 4500, 3375, }, + { 4625, 3500, }, + { 4750, 3625, }, + { 4875, 3750, }, + { 5000, 3875, }, + { 5125, 4000, }, + { 5250, 4125, }, + { 5375, 4250, }, + { 5500, 4375, }, + { 5625, 4500, }, + { 5750, 4625, }, + { 5875, 4750, }, + { 6000, 4875, }, + { 6125, 5000, }, + { 6250, 5125, }, + { 6375, 5250, }, + { 6500, 5375, }, + { 6625, 5500, }, + { 6750, 5625, }, + { 6875, 5750, }, + { 7000, 5875, }, + { 7125, 6000, }, + { 7250, 6125, }, + { 7375, 6250, }, + { 7500, 6375, }, + { 7625, 6500, }, + { 7750, 6625, }, + { 7875, 6750, }, + { 8000, 6875, }, + { 8125, 7000, }, + { 8250, 7125, }, + { 8375, 7250, }, + { 8500, 7375, }, + { 8625, 7500, }, + { 8750, 7625, }, + { 8875, 7750, }, + { 9000, 7875, }, + { 9125, 8000, }, + { 9250, 8125, }, + { 9375, 8250, }, + { 9500, 8375, }, + { 9625, 8500, }, + { 9750, 8625, }, + { 9875, 8750, }, + { 10000, 8875, }, + { 10125, 9000, }, + { 10250, 9125, }, + { 10375, 9250, }, + { 10500, 9375, }, + { 10625, 9500, }, + { 10750, 9625, }, + { 10875, 9750, }, + { 11000, 9875, }, + { 11125, 10000, }, + { 11250, 10125, }, + { 11375, 10250, }, + { 11500, 10375, }, + { 11625, 10500, }, + { 11750, 10625, }, + { 11875, 10750, }, + { 12000, 10875, }, + { 12125, 11000, }, + { 12250, 11125, }, + { 12375, 11250, }, + { 12500, 11375, }, + { 12625, 11500, }, + { 12750, 11625, }, + { 12875, 11750, }, + { 13000, 11875, }, + { 13125, 12000, }, + { 13250, 12125, }, + { 13375, 12250, }, + { 13500, 12375, }, + { 13625, 12500, }, + { 13750, 12625, }, + { 13875, 12750, }, + { 14000, 12875, }, + { 14125, 13000, }, + { 14250, 13125, }, + { 14375, 13250, }, + { 14500, 13375, }, + { 14625, 13500, }, + { 14750, 13625, }, + { 14875, 13750, }, + { 15000, 13875, }, + { 15125, 14000, }, + { 15250, 14125, }, + { 15375, 14250, }, + { 15500, 14375, }, + { 15625, 14500, }, + { 15750, 14625, }, + { 15875, 14750, }, + { 16000, 14875, }, + { 16125, 15000, }, + }; + if (dev_priv->info->is_mobile) + return v_table[pxvid].vm; + else + return v_table[pxvid].vd; +} + +void i915_update_gfx_val(struct drm_i915_private *dev_priv) +{ + struct timespec now, diff1; + u64 diff; + unsigned long diffms; + u32 count; + + if (dev_priv->info->gen != 5) + return; + + nanotime(&now); + diff1 = now; + timespecsub(&diff1, &dev_priv->last_time2); + + /* Don't divide by 0 */ + diffms = diff1.tv_sec * 1000 + diff1.tv_nsec / 1000000; + if (!diffms) + return; + + count = I915_READ(GFXEC); + + if (count < dev_priv->last_count2) { + diff = ~0UL - dev_priv->last_count2; + diff += count; + } else { + diff = count - dev_priv->last_count2; + } + + dev_priv->last_count2 = count; + dev_priv->last_time2 = now; + + /* More magic constants... */ + diff = diff * 1181; + diff = diff / (diffms * 10); + dev_priv->gfx_power = diff; +} + +unsigned long i915_gfx_val(struct drm_i915_private *dev_priv) +{ + unsigned long t, corr, state1, corr2, state2; + u32 pxvid, ext_v; + + pxvid = I915_READ(PXVFREQ_BASE + (dev_priv->cur_delay * 4)); + pxvid = (pxvid >> 24) & 0x7f; + ext_v = pvid_to_extvid(dev_priv, pxvid); + + state1 = ext_v; + + t = i915_mch_val(dev_priv); + + /* Revel in the empirically derived constants */ + + /* Correction factor in 1/100000 units */ + if (t > 80) + corr = ((t * 2349) + 135940); + else if (t >= 50) + corr = ((t * 964) + 29317); + else /* < 50 */ + corr = ((t * 301) + 1004); + + corr = corr * ((150142 * state1) / 10000 - 78642); + corr /= 100000; + corr2 = (corr * dev_priv->corr); + + state2 = (corr2 * state1) / 10000; + state2 /= 100; /* convert to mW */ + + i915_update_gfx_val(dev_priv); + + return dev_priv->gfx_power + state2; +} + +/** + * i915_read_mch_val - return value for IPS use + * + * Calculate and return a value for the IPS driver to use when deciding whether + * we have thermal and power headroom to increase CPU or GPU power budget. + */ +unsigned long i915_read_mch_val(void) +{ + struct drm_i915_private *dev_priv; + unsigned long chipset_val, graphics_val, ret = 0; + + mtx_lock(&mchdev_lock); + if (!i915_mch_dev) + goto out_unlock; + dev_priv = i915_mch_dev; + + chipset_val = i915_chipset_val(dev_priv); + graphics_val = i915_gfx_val(dev_priv); + + ret = chipset_val + graphics_val; + +out_unlock: + mtx_unlock(&mchdev_lock); + + return ret; +} + +/** + * i915_gpu_raise - raise GPU frequency limit + * + * Raise the limit; IPS indicates we have thermal headroom. + */ +bool i915_gpu_raise(void) +{ + struct drm_i915_private *dev_priv; + bool ret = true; + + mtx_lock(&mchdev_lock); + if (!i915_mch_dev) { + ret = false; + goto out_unlock; + } + dev_priv = i915_mch_dev; + + if (dev_priv->max_delay > dev_priv->fmax) + dev_priv->max_delay--; + +out_unlock: + mtx_unlock(&mchdev_lock); + + return ret; +} + +/** + * i915_gpu_lower - lower GPU frequency limit + * + * IPS indicates we're close to a thermal limit, so throttle back the GPU + * frequency maximum. + */ +bool i915_gpu_lower(void) +{ + struct drm_i915_private *dev_priv; + bool ret = true; + + mtx_lock(&mchdev_lock); + if (!i915_mch_dev) { + ret = false; + goto out_unlock; + } + dev_priv = i915_mch_dev; + + if (dev_priv->max_delay < dev_priv->min_delay) + dev_priv->max_delay++; + +out_unlock: + mtx_unlock(&mchdev_lock); + + return ret; +} + +/** + * i915_gpu_busy - indicate GPU business to IPS + * + * Tell the IPS driver whether or not the GPU is busy. + */ +bool i915_gpu_busy(void) +{ + struct drm_i915_private *dev_priv; + bool ret = false; + + mtx_lock(&mchdev_lock); + if (!i915_mch_dev) + goto out_unlock; + dev_priv = i915_mch_dev; + + ret = dev_priv->busy; + +out_unlock: + mtx_unlock(&mchdev_lock); + + return ret; +} + +/** + * i915_gpu_turbo_disable - disable graphics turbo + * + * Disable graphics turbo by resetting the max frequency and setting the + * current frequency to the default. + */ +bool i915_gpu_turbo_disable(void) +{ + struct drm_i915_private *dev_priv; + bool ret = true; + + mtx_lock(&mchdev_lock); + if (!i915_mch_dev) { + ret = false; + goto out_unlock; + } + dev_priv = i915_mch_dev; + + dev_priv->max_delay = dev_priv->fstart; + + if (!ironlake_set_drps(dev_priv->dev, dev_priv->fstart)) + ret = false; + +out_unlock: + mtx_unlock(&mchdev_lock); + + return ret; +} + +void intel_gpu_ips_init(struct drm_i915_private *dev_priv) +{ + mtx_lock(&mchdev_lock); + i915_mch_dev = dev_priv; + dev_priv->mchdev_lock = &mchdev_lock; + mtx_unlock(&mchdev_lock); + +#if 0 + ips_ping_for_i915_load(); +#endif +} + +void intel_gpu_ips_teardown(void) +{ + mtx_lock(&mchdev_lock); + i915_mch_dev = NULL; + mtx_unlock(&mchdev_lock); +} + +void intel_init_emon(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 lcfuse; + u8 pxw[16]; + int i; + + /* Disable to program */ + I915_WRITE(ECR, 0); + POSTING_READ(ECR); + + /* Program energy weights for various events */ + I915_WRITE(SDEW, 0x15040d00); + I915_WRITE(CSIEW0, 0x007f0000); + I915_WRITE(CSIEW1, 0x1e220004); + I915_WRITE(CSIEW2, 0x04000004); + + for (i = 0; i < 5; i++) + I915_WRITE(PEW + (i * 4), 0); + for (i = 0; i < 3; i++) + I915_WRITE(DEW + (i * 4), 0); + + /* Program P-state weights to account for frequency power adjustment */ + for (i = 0; i < 16; i++) { + u32 pxvidfreq = I915_READ(PXVFREQ_BASE + (i * 4)); + unsigned long freq = intel_pxfreq(pxvidfreq); + unsigned long vid = (pxvidfreq & PXVFREQ_PX_MASK) >> + PXVFREQ_PX_SHIFT; + unsigned long val; + + val = vid * vid; + val *= (freq / 1000); + val *= 255; + val /= (127*127*900); + if (val > 0xff) + DRM_ERROR("bad pxval: %ld\n", val); + pxw[i] = val; + } + /* Render standby states get 0 weight */ + pxw[14] = 0; + pxw[15] = 0; + + for (i = 0; i < 4; i++) { + u32 val = (pxw[i*4] << 24) | (pxw[(i*4)+1] << 16) | + (pxw[(i*4)+2] << 8) | (pxw[(i*4)+3]); + I915_WRITE(PXW + (i * 4), val); + } + + /* Adjust magic regs to magic values (more experimental results) */ + I915_WRITE(OGW0, 0); + I915_WRITE(OGW1, 0); + I915_WRITE(EG0, 0x00007f00); + I915_WRITE(EG1, 0x0000000e); + I915_WRITE(EG2, 0x000e0000); + I915_WRITE(EG3, 0x68000300); + I915_WRITE(EG4, 0x42000000); + I915_WRITE(EG5, 0x00140031); + I915_WRITE(EG6, 0); + I915_WRITE(EG7, 0); + + for (i = 0; i < 8; i++) + I915_WRITE(PXWL + (i * 4), 0); + + /* Enable PMON + select events */ + I915_WRITE(ECR, 0x80000019); + + lcfuse = I915_READ(LCFUSE02); + + dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK); +} + +static void ironlake_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; + + /* Required for FBC */ + dspclk_gate |= DPFCUNIT_CLOCK_GATE_DISABLE | + DPFCRUNIT_CLOCK_GATE_DISABLE | + DPFDUNIT_CLOCK_GATE_DISABLE; + /* Required for CxSR */ + dspclk_gate |= DPARBUNIT_CLOCK_GATE_DISABLE; + + I915_WRITE(PCH_3DCGDIS0, + MARIUNIT_CLOCK_GATE_DISABLE | + SVSMUNIT_CLOCK_GATE_DISABLE); + I915_WRITE(PCH_3DCGDIS1, + VFMUNIT_CLOCK_GATE_DISABLE); + + I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); + + /* + * According to the spec the following bits should be set in + * order to enable memory self-refresh + * The bit 22/21 of 0x42004 + * The bit 5 of 0x42020 + * The bit 15 of 0x45000 + */ + I915_WRITE(ILK_DISPLAY_CHICKEN2, + (I915_READ(ILK_DISPLAY_CHICKEN2) | + ILK_DPARB_GATE | ILK_VSDPFD_FULL)); + I915_WRITE(ILK_DSPCLK_GATE, + (I915_READ(ILK_DSPCLK_GATE) | + ILK_DPARB_CLK_GATE)); + I915_WRITE(DISP_ARB_CTL, + (I915_READ(DISP_ARB_CTL) | + DISP_FBC_WM_DIS)); + I915_WRITE(WM3_LP_ILK, 0); + I915_WRITE(WM2_LP_ILK, 0); + I915_WRITE(WM1_LP_ILK, 0); + + /* + * Based on the document from hardware guys the following bits + * should be set unconditionally in order to enable FBC. + * The bit 22 of 0x42000 + * The bit 22 of 0x42004 + * The bit 7,8,9 of 0x42020. + */ + if (IS_IRONLAKE_M(dev)) { + I915_WRITE(ILK_DISPLAY_CHICKEN1, + I915_READ(ILK_DISPLAY_CHICKEN1) | + ILK_FBCQ_DIS); + I915_WRITE(ILK_DISPLAY_CHICKEN2, + I915_READ(ILK_DISPLAY_CHICKEN2) | + ILK_DPARB_GATE); + I915_WRITE(ILK_DSPCLK_GATE, + I915_READ(ILK_DSPCLK_GATE) | + ILK_DPFC_DIS1 | + ILK_DPFC_DIS2 | + ILK_CLK_FBC); + } + + I915_WRITE(ILK_DISPLAY_CHICKEN2, + I915_READ(ILK_DISPLAY_CHICKEN2) | + ILK_ELPIN_409_SELECT); + I915_WRITE(_3D_CHICKEN2, + _3D_CHICKEN2_WM_READ_PIPELINED << 16 | + _3D_CHICKEN2_WM_READ_PIPELINED); +} + +static void gen6_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe; + uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; + + I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); + + I915_WRITE(ILK_DISPLAY_CHICKEN2, + I915_READ(ILK_DISPLAY_CHICKEN2) | + ILK_ELPIN_409_SELECT); + + I915_WRITE(WM3_LP_ILK, 0); + I915_WRITE(WM2_LP_ILK, 0); + I915_WRITE(WM1_LP_ILK, 0); + + I915_WRITE(CACHE_MODE_0, + _MASKED_BIT_DISABLE(CM0_STC_EVICT_DISABLE_LRA_SNB)); + + I915_WRITE(GEN6_UCGCTL1, + I915_READ(GEN6_UCGCTL1) | + GEN6_BLBUNIT_CLOCK_GATE_DISABLE | + GEN6_CSUNIT_CLOCK_GATE_DISABLE); + + /* According to the BSpec vol1g, bit 12 (RCPBUNIT) clock + * gating disable must be set. Failure to set it results in + * flickering pixels due to Z write ordering failures after + * some amount of runtime in the Mesa "fire" demo, and Unigine + * Sanctuary and Tropics, and apparently anything else with + * alpha test or pixel discard. + * + * According to the spec, bit 11 (RCCUNIT) must also be set, + * but we didn't debug actual testcases to find it out. + */ + I915_WRITE(GEN6_UCGCTL2, + GEN6_RCPBUNIT_CLOCK_GATE_DISABLE | + GEN6_RCCUNIT_CLOCK_GATE_DISABLE); + + /* Bspec says we need to always set all mask bits. */ + I915_WRITE(_3D_CHICKEN, (0xFFFF << 16) | + _3D_CHICKEN_SF_DISABLE_FASTCLIP_CULL); + + /* + * According to the spec the following bits should be + * set in order to enable memory self-refresh and fbc: + * The bit21 and bit22 of 0x42000 + * The bit21 and bit22 of 0x42004 + * The bit5 and bit7 of 0x42020 + * The bit14 of 0x70180 + * The bit14 of 0x71180 + */ + I915_WRITE(ILK_DISPLAY_CHICKEN1, + I915_READ(ILK_DISPLAY_CHICKEN1) | + ILK_FBCQ_DIS | ILK_PABSTRETCH_DIS); + I915_WRITE(ILK_DISPLAY_CHICKEN2, + I915_READ(ILK_DISPLAY_CHICKEN2) | + ILK_DPARB_GATE | ILK_VSDPFD_FULL); + I915_WRITE(ILK_DSPCLK_GATE, + I915_READ(ILK_DSPCLK_GATE) | + ILK_DPARB_CLK_GATE | + ILK_DPFD_CLK_GATE); + + for_each_pipe(pipe) { + I915_WRITE(DSPCNTR(pipe), + I915_READ(DSPCNTR(pipe)) | + DISPPLANE_TRICKLE_FEED_DISABLE); + intel_flush_display_plane(dev_priv, pipe); + } +} + +static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv) +{ + uint32_t reg = I915_READ(GEN7_FF_THREAD_MODE); + + reg &= ~GEN7_FF_SCHED_MASK; + reg |= GEN7_FF_TS_SCHED_HW; + reg |= GEN7_FF_VS_SCHED_HW; + reg |= GEN7_FF_DS_SCHED_HW; + + I915_WRITE(GEN7_FF_THREAD_MODE, reg); +} + +static void ivybridge_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe; + uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; + + I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); + + I915_WRITE(WM3_LP_ILK, 0); + I915_WRITE(WM2_LP_ILK, 0); + I915_WRITE(WM1_LP_ILK, 0); + + /* According to the spec, bit 13 (RCZUNIT) must be set on IVB. + * This implements the WaDisableRCZUnitClockGating workaround. + */ + I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE); + + I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE); + + I915_WRITE(IVB_CHICKEN3, + CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE | + CHICKEN3_DGMG_DONE_FIX_DISABLE); + + /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */ + I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1, + GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC); + + /* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */ + I915_WRITE(GEN7_L3CNTLREG1, + GEN7_WA_FOR_GEN7_L3_CONTROL); + I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER, + GEN7_WA_L3_CHICKEN_MODE); + + /* This is required by WaCatErrorRejectionIssue */ + I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG, + I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | + GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB); + + for_each_pipe(pipe) { + I915_WRITE(DSPCNTR(pipe), + I915_READ(DSPCNTR(pipe)) | + DISPPLANE_TRICKLE_FEED_DISABLE); + intel_flush_display_plane(dev_priv, pipe); + } + + gen7_setup_fixed_func_scheduler(dev_priv); + + /* WaDisable4x2SubspanOptimization */ + I915_WRITE(CACHE_MODE_1, + _MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE)); +} + +static void valleyview_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe; + uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; + + I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); + + I915_WRITE(WM3_LP_ILK, 0); + I915_WRITE(WM2_LP_ILK, 0); + I915_WRITE(WM1_LP_ILK, 0); + + /* According to the spec, bit 13 (RCZUNIT) must be set on IVB. + * This implements the WaDisableRCZUnitClockGating workaround. + */ + I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE); + + I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE); + + I915_WRITE(IVB_CHICKEN3, + CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE | + CHICKEN3_DGMG_DONE_FIX_DISABLE); + + /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */ + I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1, + GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC); + + /* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */ + I915_WRITE(GEN7_L3CNTLREG1, GEN7_WA_FOR_GEN7_L3_CONTROL); + I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER, GEN7_WA_L3_CHICKEN_MODE); + + /* This is required by WaCatErrorRejectionIssue */ + I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG, + I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | + GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB); + + for_each_pipe(pipe) { + I915_WRITE(DSPCNTR(pipe), + I915_READ(DSPCNTR(pipe)) | + DISPPLANE_TRICKLE_FEED_DISABLE); + intel_flush_display_plane(dev_priv, pipe); + } + + I915_WRITE(CACHE_MODE_1, + _MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE)); +} + +static void g4x_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t dspclk_gate; + + I915_WRITE(RENCLK_GATE_D1, 0); + I915_WRITE(RENCLK_GATE_D2, VF_UNIT_CLOCK_GATE_DISABLE | + GS_UNIT_CLOCK_GATE_DISABLE | + CL_UNIT_CLOCK_GATE_DISABLE); + I915_WRITE(RAMCLK_GATE_D, 0); + dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE | + OVRUNIT_CLOCK_GATE_DISABLE | + OVCUNIT_CLOCK_GATE_DISABLE; + if (IS_GM45(dev)) + dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE; + I915_WRITE(DSPCLK_GATE_D, dspclk_gate); +} + +static void crestline_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE); + I915_WRITE(RENCLK_GATE_D2, 0); + I915_WRITE(DSPCLK_GATE_D, 0); + I915_WRITE(RAMCLK_GATE_D, 0); + I915_WRITE16(DEUC, 0); +} + +static void broadwater_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE | + I965_RCC_CLOCK_GATE_DISABLE | + I965_RCPB_CLOCK_GATE_DISABLE | + I965_ISC_CLOCK_GATE_DISABLE | + I965_FBC_CLOCK_GATE_DISABLE); + I915_WRITE(RENCLK_GATE_D2, 0); +} + +static void gen3_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 dstate = I915_READ(D_STATE); + + dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING | + DSTATE_DOT_CLOCK_GATING; + I915_WRITE(D_STATE, dstate); + + if (IS_PINEVIEW(dev)) + I915_WRITE(ECOSKPD, _MASKED_BIT_ENABLE(ECO_GATING_CX_ONLY)); +} + +static void i85x_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(RENCLK_GATE_D1, SV_CLOCK_GATE_DISABLE); +} + +static void i830_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE); +} + +static void ibx_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* + * On Ibex Peak and Cougar Point, we need to disable clock + * gating for the panel power sequencer or it will fail to + * start up when no ports are active. + */ + I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE); +} + +static void cpt_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe; + + /* + * On Ibex Peak and Cougar Point, we need to disable clock + * gating for the panel power sequencer or it will fail to + * start up when no ports are active. + */ + I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE); + I915_WRITE(SOUTH_CHICKEN2, I915_READ(SOUTH_CHICKEN2) | + DPLS_EDP_PPS_FIX_DIS); + /* Without this, mode sets may fail silently on FDI */ + for_each_pipe(pipe) + I915_WRITE(TRANS_CHICKEN2(pipe), TRANS_AUTOTRAIN_GEN_STALL_DIS); +} + +void intel_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + dev_priv->display.init_clock_gating(dev); + + if (dev_priv->display.init_pch_clock_gating) + dev_priv->display.init_pch_clock_gating(dev); +} + +static void gen6_sanitize_pm(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 limits, delay, old; + + gen6_gt_force_wake_get(dev_priv); + + old = limits = I915_READ(GEN6_RP_INTERRUPT_LIMITS); + /* Make sure we continue to get interrupts + * until we hit the minimum or maximum frequencies. + */ + limits &= ~(0x3f << 16 | 0x3f << 24); + delay = dev_priv->cur_delay; + if (delay < dev_priv->max_delay) + limits |= (dev_priv->max_delay & 0x3f) << 24; + if (delay > dev_priv->min_delay) + limits |= (dev_priv->min_delay & 0x3f) << 16; + + if (old != limits) { + DRM_ERROR("Power management discrepancy: GEN6_RP_INTERRUPT_LIMITS expected %08x, was %08x\n", + limits, old); + I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, limits); + } + + gen6_gt_force_wake_put(dev_priv); +} + +void intel_sanitize_pm(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->display.sanitize_pm) + dev_priv->display.sanitize_pm(dev); +} + +/* Starting with Haswell, we have different power wells for + * different parts of the GPU. This attempts to enable them all. + */ +static void intel_init_power_wells(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long power_wells[] = { + HSW_PWR_WELL_CTL1, + HSW_PWR_WELL_CTL2, + HSW_PWR_WELL_CTL4 + }; + int i; + + if (!IS_HASWELL(dev)) + return; + + DRM_LOCK(dev); + + for (i = 0; i < DRM_ARRAY_SIZE(power_wells); i++) { + int well = I915_READ(power_wells[i]); + + if ((well & HSW_PWR_WELL_STATE) == 0) { + I915_WRITE(power_wells[i], well & HSW_PWR_WELL_ENABLE); + if (wait_for(I915_READ(power_wells[i] & HSW_PWR_WELL_STATE), 20)) + DRM_ERROR("Error enabling power well %lx\n", power_wells[i]); + } + } + +printf("XXXKIB HACK: HSW RC OFF\n"); + I915_WRITE(GEN6_RC_STATE, 0); + I915_WRITE(GEN6_RC_CONTROL, 0); + DRM_UNLOCK(dev); +} + +/* Set up chip specific power management-related functions */ +void intel_init_pm(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (I915_HAS_FBC(dev)) { + if (HAS_PCH_SPLIT(dev)) { + dev_priv->display.fbc_enabled = ironlake_fbc_enabled; + dev_priv->display.enable_fbc = ironlake_enable_fbc; + dev_priv->display.disable_fbc = ironlake_disable_fbc; + } else if (IS_GM45(dev)) { + dev_priv->display.fbc_enabled = g4x_fbc_enabled; + dev_priv->display.enable_fbc = g4x_enable_fbc; + dev_priv->display.disable_fbc = g4x_disable_fbc; + } else if (IS_CRESTLINE(dev)) { + dev_priv->display.fbc_enabled = i8xx_fbc_enabled; + dev_priv->display.enable_fbc = i8xx_enable_fbc; + dev_priv->display.disable_fbc = i8xx_disable_fbc; + } + /* 855GM needs testing */ + } + + /* For cxsr */ + if (IS_PINEVIEW(dev)) + i915_pineview_get_mem_freq(dev); + else if (IS_GEN5(dev)) + i915_ironlake_get_mem_freq(dev); + + /* For FIFO watermark updates */ + if (HAS_PCH_SPLIT(dev)) { + dev_priv->display.force_wake_get = __gen6_gt_force_wake_get; + dev_priv->display.force_wake_put = __gen6_gt_force_wake_put; + + /* IVB configs may use multi-threaded forcewake */ + if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) { + u32 ecobus; + + /* A small trick here - if the bios hasn't configured MT forcewake, + * and if the device is in RC6, then force_wake_mt_get will not wake + * the device and the ECOBUS read will return zero. Which will be + * (correctly) interpreted by the test below as MT forcewake being + * disabled. + */ + DRM_LOCK(dev); + __gen6_gt_force_wake_mt_get(dev_priv); + ecobus = I915_READ_NOTRACE(ECOBUS); + __gen6_gt_force_wake_mt_put(dev_priv); + DRM_UNLOCK(dev); + + if (ecobus & FORCEWAKE_MT_ENABLE) { + DRM_DEBUG_KMS("Using MT version of forcewake\n"); + dev_priv->display.force_wake_get = + __gen6_gt_force_wake_mt_get; + dev_priv->display.force_wake_put = + __gen6_gt_force_wake_mt_put; + } + } + + if (HAS_PCH_IBX(dev)) + dev_priv->display.init_pch_clock_gating = ibx_init_clock_gating; + else if (HAS_PCH_CPT(dev)) + dev_priv->display.init_pch_clock_gating = cpt_init_clock_gating; + + if (IS_GEN5(dev)) { + if (I915_READ(MLTR_ILK) & ILK_SRLT_MASK) + dev_priv->display.update_wm = ironlake_update_wm; + else { + DRM_DEBUG_KMS("Failed to get proper latency. " + "Disable CxSR\n"); + dev_priv->display.update_wm = NULL; + } + dev_priv->display.init_clock_gating = ironlake_init_clock_gating; + } else if (IS_GEN6(dev)) { + if (SNB_READ_WM0_LATENCY()) { + dev_priv->display.update_wm = sandybridge_update_wm; + dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm; + } else { + DRM_DEBUG_KMS("Failed to read display plane latency. " + "Disable CxSR\n"); + dev_priv->display.update_wm = NULL; + } + dev_priv->display.init_clock_gating = gen6_init_clock_gating; + dev_priv->display.sanitize_pm = gen6_sanitize_pm; + } else if (IS_IVYBRIDGE(dev)) { + /* FIXME: detect B0+ stepping and use auto training */ + if (SNB_READ_WM0_LATENCY()) { + dev_priv->display.update_wm = sandybridge_update_wm; + dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm; + } else { + DRM_DEBUG_KMS("Failed to read display plane latency. " + "Disable CxSR\n"); + dev_priv->display.update_wm = NULL; + } + dev_priv->display.init_clock_gating = ivybridge_init_clock_gating; + dev_priv->display.sanitize_pm = gen6_sanitize_pm; + } else if (IS_HASWELL(dev)) { + if (SNB_READ_WM0_LATENCY()) { + dev_priv->display.update_wm = sandybridge_update_wm; + dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm; + dev_priv->display.update_linetime_wm = haswell_update_linetime_wm; + } else { + DRM_DEBUG_KMS("Failed to read display plane latency. " + "Disable CxSR\n"); + dev_priv->display.update_wm = NULL; + } + dev_priv->display.init_clock_gating = ivybridge_init_clock_gating; + dev_priv->display.sanitize_pm = gen6_sanitize_pm; + } else + dev_priv->display.update_wm = NULL; + } else if (IS_VALLEYVIEW(dev)) { + dev_priv->display.update_wm = valleyview_update_wm; + dev_priv->display.init_clock_gating = + valleyview_init_clock_gating; + dev_priv->display.force_wake_get = vlv_force_wake_get; + dev_priv->display.force_wake_put = vlv_force_wake_put; + } else if (IS_PINEVIEW(dev)) { + if (!intel_get_cxsr_latency(IS_PINEVIEW_G(dev), + dev_priv->is_ddr3, + dev_priv->fsb_freq, + dev_priv->mem_freq)) { + DRM_INFO("failed to find known CxSR latency " + "(found ddr%s fsb freq %d, mem freq %d), " + "disabling CxSR\n", + (dev_priv->is_ddr3 == 1) ? "3" : "2", + dev_priv->fsb_freq, dev_priv->mem_freq); + /* Disable CxSR and never update its watermark again */ + pineview_disable_cxsr(dev); + dev_priv->display.update_wm = NULL; + } else + dev_priv->display.update_wm = pineview_update_wm; + dev_priv->display.init_clock_gating = gen3_init_clock_gating; + } else if (IS_G4X(dev)) { + dev_priv->display.update_wm = g4x_update_wm; + dev_priv->display.init_clock_gating = g4x_init_clock_gating; + } else if (IS_GEN4(dev)) { + dev_priv->display.update_wm = i965_update_wm; + if (IS_CRESTLINE(dev)) + dev_priv->display.init_clock_gating = crestline_init_clock_gating; + else if (IS_BROADWATER(dev)) + dev_priv->display.init_clock_gating = broadwater_init_clock_gating; + } else if (IS_GEN3(dev)) { + dev_priv->display.update_wm = i9xx_update_wm; + dev_priv->display.get_fifo_size = i9xx_get_fifo_size; + dev_priv->display.init_clock_gating = gen3_init_clock_gating; + } else if (IS_I865G(dev)) { + dev_priv->display.update_wm = i830_update_wm; + dev_priv->display.init_clock_gating = i85x_init_clock_gating; + dev_priv->display.get_fifo_size = i830_get_fifo_size; + } else if (IS_I85X(dev)) { + dev_priv->display.update_wm = i9xx_update_wm; + dev_priv->display.get_fifo_size = i85x_get_fifo_size; + dev_priv->display.init_clock_gating = i85x_init_clock_gating; + } else { + dev_priv->display.update_wm = i830_update_wm; + dev_priv->display.init_clock_gating = i830_init_clock_gating; + if (IS_845G(dev)) + dev_priv->display.get_fifo_size = i845_get_fifo_size; + else + dev_priv->display.get_fifo_size = i830_get_fifo_size; + } + + /* We attempt to init the necessary power wells early in the initialization + * time, so the subsystems that expect power to be enabled can work. + */ + intel_init_power_wells(dev); +} + diff --git a/sys/dev/drm2/i915/intel_ringbuffer.c b/sys/dev/drm2/i915/intel_ringbuffer.c index 89a5c94c1039..d37386555872 100644 --- a/sys/dev/drm2/i915/intel_ringbuffer.c +++ b/sys/dev/drm2/i915/intel_ringbuffer.c @@ -52,12 +52,14 @@ struct pipe_control { void i915_trace_irq_get(struct intel_ring_buffer *ring, uint32_t seqno) { + struct drm_i915_private *dev_priv; if (ring->trace_irq_seqno == 0) { - mtx_lock(&ring->irq_lock); + dev_priv = ring->dev->dev_private; + mtx_lock(&dev_priv->irq_lock); if (ring->irq_get(ring)) ring->trace_irq_seqno = seqno; - mtx_unlock(&ring->irq_lock); + mtx_unlock(&dev_priv->irq_lock); } } @@ -70,9 +72,35 @@ static inline int ring_space(struct intel_ring_buffer *ring) } static int -render_ring_flush(struct intel_ring_buffer *ring, - uint32_t invalidate_domains, - uint32_t flush_domains) +gen2_render_ring_flush(struct intel_ring_buffer *ring, + u32 invalidate_domains, + u32 flush_domains) +{ + u32 cmd; + int ret; + + cmd = MI_FLUSH; + if (((invalidate_domains|flush_domains) & I915_GEM_DOMAIN_RENDER) == 0) + cmd |= MI_NO_WRITE_FLUSH; + + if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER) + cmd |= MI_READ_FLUSH; + + ret = intel_ring_begin(ring, 2); + if (ret) + return ret; + + intel_ring_emit(ring, cmd); + intel_ring_emit(ring, MI_NOOP); + intel_ring_advance(ring); + + return 0; +} + +static int +gen4_render_ring_flush(struct intel_ring_buffer *ring, + u32 invalidate_domains, + u32 flush_domains) { struct drm_device *dev = ring->dev; uint32_t cmd; @@ -107,17 +135,8 @@ render_ring_flush(struct intel_ring_buffer *ring, */ cmd = MI_FLUSH | MI_NO_WRITE_FLUSH; - if ((invalidate_domains|flush_domains) & - I915_GEM_DOMAIN_RENDER) + if ((invalidate_domains|flush_domains) & I915_GEM_DOMAIN_RENDER) cmd &= ~MI_NO_WRITE_FLUSH; - if (INTEL_INFO(dev)->gen < 4) { - /* - * On the 965, the sampler cache always gets flushed - * and this bit is reserved. - */ - if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER) - cmd |= MI_READ_FLUSH; - } if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION) cmd |= MI_EXE_FLUSH; @@ -407,12 +426,11 @@ static int init_render_ring(struct intel_ring_buffer *ring) int ret = init_ring_common(ring); if (INTEL_INFO(dev)->gen > 3) { - int mode = VS_TIMER_DISPATCH << 16 | VS_TIMER_DISPATCH; - I915_WRITE(MI_MODE, mode); + I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(VS_TIMER_DISPATCH)); if (IS_GEN7(dev)) I915_WRITE(GFX_MODE_GEN7, - GFX_MODE_DISABLE(GFX_TLB_INVALIDATE_ALWAYS) | - GFX_MODE_ENABLE(GFX_REPLAY_MODE)); + _MASKED_BIT_DISABLE(GFX_TLB_INVALIDATE_ALWAYS) | + _MASKED_BIT_ENABLE(GFX_REPLAY_MODE)); } if (INTEL_INFO(dev)->gen >= 5) { @@ -429,7 +447,7 @@ static int init_render_ring(struct intel_ring_buffer *ring) * policy is not supported." */ I915_WRITE(CACHE_MODE_0, - CM0_STC_EVICT_DISABLE_LRA_SNB << CM0_MASK_SHIFT); + _MASKED_BIT_DISABLE(CM0_STC_EVICT_DISABLE_LRA_SNB)); /* This is not explicitly set for GEN6, so read the register. * see intel_ring_mi_set_context() for why we care. @@ -439,10 +457,8 @@ static int init_render_ring(struct intel_ring_buffer *ring) !!(I915_READ(GFX_MODE) & GFX_TLB_INVALIDATE_ALWAYS); } - if (INTEL_INFO(dev)->gen >= 6) { - I915_WRITE(INSTPM, - INSTPM_FORCE_ORDERING << 16 | INSTPM_FORCE_ORDERING); - } + if (INTEL_INFO(dev)->gen >= 6) + I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING)); return ret; } @@ -513,21 +529,32 @@ gen6_add_request(struct intel_ring_buffer *ring, * @seqno - seqno which the waiter will block on */ static int -intel_ring_sync(struct intel_ring_buffer *waiter, - struct intel_ring_buffer *signaller, - int ring, - u32 seqno) +gen6_ring_sync(struct intel_ring_buffer *waiter, + struct intel_ring_buffer *signaller, + u32 seqno) { int ret; u32 dw1 = MI_SEMAPHORE_MBOX | MI_SEMAPHORE_COMPARE | MI_SEMAPHORE_REGISTER; + /* Throughout all of the GEM code, seqno passed implies our current + * seqno is >= the last seqno executed. However for hardware the + * comparison is strictly greater than. + */ + seqno -= 1; + + if (signaller->semaphore_register[waiter->id] == + MI_SEMAPHORE_SYNC_INVALID) + printf("gen6_ring_sync semaphore_register %d invalid\n", + waiter->id); + ret = intel_ring_begin(waiter, 4); if (ret) return ret; - intel_ring_emit(waiter, dw1 | signaller->semaphore_register[ring]); + intel_ring_emit(waiter, + dw1 | signaller->semaphore_register[waiter->id]); intel_ring_emit(waiter, seqno); intel_ring_emit(waiter, 0); intel_ring_emit(waiter, MI_NOOP); @@ -543,48 +570,6 @@ int gen6_bsd_ring_sync_to(struct intel_ring_buffer *waiter, int gen6_blt_ring_sync_to(struct intel_ring_buffer *waiter, struct intel_ring_buffer *signaller, u32 seqno); -/* VCS->RCS (RVSYNC) or BCS->RCS (RBSYNC) */ -int -render_ring_sync_to(struct intel_ring_buffer *waiter, - struct intel_ring_buffer *signaller, - u32 seqno) -{ - KASSERT(signaller->semaphore_register[RCS] != MI_SEMAPHORE_SYNC_INVALID, - ("valid RCS semaphore")); - return intel_ring_sync(waiter, - signaller, - RCS, - seqno); -} - -/* RCS->VCS (VRSYNC) or BCS->VCS (VBSYNC) */ -int -gen6_bsd_ring_sync_to(struct intel_ring_buffer *waiter, - struct intel_ring_buffer *signaller, - u32 seqno) -{ - KASSERT(signaller->semaphore_register[VCS] != MI_SEMAPHORE_SYNC_INVALID, - ("Valid VCS semaphore")); - return intel_ring_sync(waiter, - signaller, - VCS, - seqno); -} - -/* RCS->BCS (BRSYNC) or VCS->BCS (BVSYNC) */ -int -gen6_blt_ring_sync_to(struct intel_ring_buffer *waiter, - struct intel_ring_buffer *signaller, - u32 seqno) -{ - KASSERT(signaller->semaphore_register[BCS] != MI_SEMAPHORE_SYNC_INVALID, - ("Valid BCS semaphore")); - return intel_ring_sync(waiter, - signaller, - BCS, - seqno); -} - #define PIPE_CONTROL_FLUSH(ring__, addr__) \ do { \ intel_ring_emit(ring__, GFX_OP_PIPE_CONTROL(4) | PIPE_CONTROL_QW_WRITE | \ @@ -645,28 +630,7 @@ pc_render_add_request(struct intel_ring_buffer *ring, return 0; } -static int -render_ring_add_request(struct intel_ring_buffer *ring, - uint32_t *result) -{ - u32 seqno = i915_gem_next_request_seqno(ring); - int ret; - - ret = intel_ring_begin(ring, 4); - if (ret) - return ret; - - intel_ring_emit(ring, MI_STORE_DWORD_INDEX); - intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - intel_ring_emit(ring, seqno); - intel_ring_emit(ring, MI_USER_INTERRUPT); - intel_ring_advance(ring); - - *result = seqno; - return 0; -} - - static u32 +static u32 gen6_ring_get_seqno(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; @@ -697,40 +661,8 @@ pc_render_get_seqno(struct intel_ring_buffer *ring) return (-1); } -static void -ironlake_enable_irq(drm_i915_private_t *dev_priv, uint32_t mask) -{ - dev_priv->gt_irq_mask &= ~mask; - I915_WRITE(GTIMR, dev_priv->gt_irq_mask); - POSTING_READ(GTIMR); -} - -static void -ironlake_disable_irq(drm_i915_private_t *dev_priv, uint32_t mask) -{ - dev_priv->gt_irq_mask |= mask; - I915_WRITE(GTIMR, dev_priv->gt_irq_mask); - POSTING_READ(GTIMR); -} - -static void -i915_enable_irq(drm_i915_private_t *dev_priv, uint32_t mask) -{ - dev_priv->irq_mask &= ~mask; - I915_WRITE(IMR, dev_priv->irq_mask); - POSTING_READ(IMR); -} - -static void -i915_disable_irq(drm_i915_private_t *dev_priv, uint32_t mask) -{ - dev_priv->irq_mask |= mask; - I915_WRITE(IMR, dev_priv->irq_mask); - POSTING_READ(IMR); -} - static bool -render_ring_get_irq(struct intel_ring_buffer *ring) +gen5_ring_get_irq(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; drm_i915_private_t *dev_priv = dev->dev_private; @@ -738,32 +670,93 @@ render_ring_get_irq(struct intel_ring_buffer *ring) if (!dev->irq_enabled) return false; - mtx_assert(&ring->irq_lock, MA_OWNED); + mtx_assert(&dev_priv->irq_lock, MA_OWNED); if (ring->irq_refcount++ == 0) { - if (HAS_PCH_SPLIT(dev)) - ironlake_enable_irq(dev_priv, - GT_PIPE_NOTIFY | GT_USER_INTERRUPT); - else - i915_enable_irq(dev_priv, I915_USER_INTERRUPT); + dev_priv->gt_irq_mask &= ~ring->irq_enable_mask; + I915_WRITE(GTIMR, dev_priv->gt_irq_mask); + POSTING_READ(GTIMR); } return true; } static void -render_ring_put_irq(struct intel_ring_buffer *ring) +gen5_ring_put_irq(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; drm_i915_private_t *dev_priv = dev->dev_private; - mtx_assert(&ring->irq_lock, MA_OWNED); + mtx_assert(&dev_priv->irq_lock, MA_OWNED); if (--ring->irq_refcount == 0) { - if (HAS_PCH_SPLIT(dev)) - ironlake_disable_irq(dev_priv, - GT_USER_INTERRUPT | - GT_PIPE_NOTIFY); - else - i915_disable_irq(dev_priv, I915_USER_INTERRUPT); + dev_priv->gt_irq_mask |= ring->irq_enable_mask; + I915_WRITE(GTIMR, dev_priv->gt_irq_mask); + POSTING_READ(GTIMR); + } +} + +static bool +i9xx_ring_get_irq(struct intel_ring_buffer *ring) +{ + struct drm_device *dev = ring->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + + if (!dev->irq_enabled) + return false; + + mtx_assert(&dev_priv->irq_lock, MA_OWNED); + if (ring->irq_refcount++ == 0) { + dev_priv->irq_mask &= ~ring->irq_enable_mask; + I915_WRITE(IMR, dev_priv->irq_mask); + POSTING_READ(IMR); + } + + return true; +} + +static void +i9xx_ring_put_irq(struct intel_ring_buffer *ring) +{ + struct drm_device *dev = ring->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + + mtx_assert(&dev_priv->irq_lock, MA_OWNED); + if (--ring->irq_refcount == 0) { + dev_priv->irq_mask |= ring->irq_enable_mask; + I915_WRITE(IMR, dev_priv->irq_mask); + POSTING_READ(IMR); + } +} + +static bool +i8xx_ring_get_irq(struct intel_ring_buffer *ring) +{ + struct drm_device *dev = ring->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + + if (!dev->irq_enabled) + return false; + + mtx_assert(&dev_priv->irq_lock, MA_OWNED); + if (ring->irq_refcount++ == 0) { + dev_priv->irq_mask &= ~ring->irq_enable_mask; + I915_WRITE16(IMR, dev_priv->irq_mask); + POSTING_READ16(IMR); + } + + return true; +} + +static void +i8xx_ring_put_irq(struct intel_ring_buffer *ring) +{ + struct drm_device *dev = ring->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + + mtx_assert(&dev_priv->irq_lock, MA_OWNED); + if (--ring->irq_refcount == 0) { + dev_priv->irq_mask |= ring->irq_enable_mask; + I915_WRITE16(IMR, dev_priv->irq_mask); + POSTING_READ16(IMR); } } @@ -816,10 +809,10 @@ bsd_ring_flush(struct intel_ring_buffer *ring, } static int -ring_add_request(struct intel_ring_buffer *ring, - uint32_t *result) +i9xx_add_request(struct intel_ring_buffer *ring, + u32 *result) { - uint32_t seqno; + u32 seqno; int ret; ret = intel_ring_begin(ring, 4); @@ -839,7 +832,7 @@ ring_add_request(struct intel_ring_buffer *ring, } static bool -gen6_ring_get_irq(struct intel_ring_buffer *ring, uint32_t gflag, uint32_t rflag) +gen6_ring_get_irq(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; drm_i915_private_t *dev_priv = dev->dev_private; @@ -849,69 +842,36 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring, uint32_t gflag, uint32_t rflag gen6_gt_force_wake_get(dev_priv); - mtx_assert(&ring->irq_lock, MA_OWNED); + mtx_assert(&dev_priv->irq_lock, MA_OWNED); if (ring->irq_refcount++ == 0) { - ring->irq_mask &= ~rflag; - I915_WRITE_IMR(ring, ring->irq_mask); - ironlake_enable_irq(dev_priv, gflag); + I915_WRITE_IMR(ring, ~ring->irq_enable_mask); + dev_priv->gt_irq_mask &= ~ring->irq_enable_mask; + I915_WRITE(GTIMR, dev_priv->gt_irq_mask); + POSTING_READ(GTIMR); } return true; } static void -gen6_ring_put_irq(struct intel_ring_buffer *ring, uint32_t gflag, uint32_t rflag) +gen6_ring_put_irq(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; drm_i915_private_t *dev_priv = dev->dev_private; - mtx_assert(&ring->irq_lock, MA_OWNED); + mtx_assert(&dev_priv->irq_lock, MA_OWNED); if (--ring->irq_refcount == 0) { - ring->irq_mask |= rflag; - I915_WRITE_IMR(ring, ring->irq_mask); - ironlake_disable_irq(dev_priv, gflag); + I915_WRITE_IMR(ring, ~0); + dev_priv->gt_irq_mask |= ring->irq_enable_mask; + I915_WRITE(GTIMR, dev_priv->gt_irq_mask); + POSTING_READ(GTIMR); } gen6_gt_force_wake_put(dev_priv); } -static bool -bsd_ring_get_irq(struct intel_ring_buffer *ring) -{ - struct drm_device *dev = ring->dev; - drm_i915_private_t *dev_priv = dev->dev_private; - - if (!dev->irq_enabled) - return false; - - mtx_assert(&ring->irq_lock, MA_OWNED); - if (ring->irq_refcount++ == 0) { - if (IS_G4X(dev)) - i915_enable_irq(dev_priv, I915_BSD_USER_INTERRUPT); - else - ironlake_enable_irq(dev_priv, GT_BSD_USER_INTERRUPT); - } - - return true; -} -static void -bsd_ring_put_irq(struct intel_ring_buffer *ring) -{ - struct drm_device *dev = ring->dev; - drm_i915_private_t *dev_priv = dev->dev_private; - - mtx_assert(&ring->irq_lock, MA_OWNED); - if (--ring->irq_refcount == 0) { - if (IS_G4X(dev)) - i915_disable_irq(dev_priv, I915_BSD_USER_INTERRUPT); - else - ironlake_disable_irq(dev_priv, GT_BSD_USER_INTERRUPT); - } -} - static int -ring_dispatch_execbuffer(struct intel_ring_buffer *ring, uint32_t offset, - uint32_t length) +i965_dispatch_execbuffer(struct intel_ring_buffer *ring, u32 offset, u32 length) { int ret; @@ -920,7 +880,8 @@ ring_dispatch_execbuffer(struct intel_ring_buffer *ring, uint32_t offset, return ret; intel_ring_emit(ring, - MI_BATCH_BUFFER_START | (2 << 6) | + MI_BATCH_BUFFER_START | + MI_BATCH_GTT | MI_BATCH_NON_SECURE_I965); intel_ring_emit(ring, offset); intel_ring_advance(ring); @@ -929,37 +890,36 @@ ring_dispatch_execbuffer(struct intel_ring_buffer *ring, uint32_t offset, } static int -render_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, - uint32_t offset, uint32_t len) +i830_dispatch_execbuffer(struct intel_ring_buffer *ring, + u32 offset, u32 len) { - struct drm_device *dev = ring->dev; int ret; - if (IS_I830(dev) || IS_845G(dev)) { - ret = intel_ring_begin(ring, 4); - if (ret) - return ret; + ret = intel_ring_begin(ring, 4); + if (ret) + return ret; - intel_ring_emit(ring, MI_BATCH_BUFFER); - intel_ring_emit(ring, offset | MI_BATCH_NON_SECURE); - intel_ring_emit(ring, offset + len - 8); - intel_ring_emit(ring, 0); - } else { - ret = intel_ring_begin(ring, 2); - if (ret) - return ret; + intel_ring_emit(ring, MI_BATCH_BUFFER); + intel_ring_emit(ring, offset | MI_BATCH_NON_SECURE); + intel_ring_emit(ring, offset + len - 8); + intel_ring_emit(ring, 0); + intel_ring_advance(ring); - if (INTEL_INFO(dev)->gen >= 4) { - intel_ring_emit(ring, - MI_BATCH_BUFFER_START | (2 << 6) | - MI_BATCH_NON_SECURE_I965); - intel_ring_emit(ring, offset); - } else { - intel_ring_emit(ring, - MI_BATCH_BUFFER_START | (2 << 6)); - intel_ring_emit(ring, offset | MI_BATCH_NON_SECURE); - } - } + return 0; +} + +static int +i915_dispatch_execbuffer(struct intel_ring_buffer *ring, + u32 offset, u32 len) +{ + int ret; + + ret = intel_ring_begin(ring, 2); + if (ret) + return ret; + + intel_ring_emit(ring, MI_BATCH_BUFFER_START | MI_BATCH_GTT); + intel_ring_emit(ring, offset | MI_BATCH_NON_SECURE); intel_ring_advance(ring); return 0; @@ -967,7 +927,6 @@ render_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, static void cleanup_status_page(struct intel_ring_buffer *ring) { - drm_i915_private_t *dev_priv = ring->dev->dev_private; struct drm_i915_gem_object *obj; obj = ring->status_page.obj; @@ -980,14 +939,11 @@ static void cleanup_status_page(struct intel_ring_buffer *ring) i915_gem_object_unpin(obj); drm_gem_object_unreference(&obj->base); ring->status_page.obj = NULL; - - memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); } static int init_status_page(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; - drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj; int ret; @@ -1008,7 +964,6 @@ static int init_status_page(struct intel_ring_buffer *ring) ring->status_page.gfx_addr = obj->gtt_offset; ring->status_page.page_addr = (void *)kva_alloc(PAGE_SIZE); if (ring->status_page.page_addr == NULL) { - memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); goto err_unpin; } pmap_qenter((vm_offset_t)ring->status_page.page_addr, &obj->pages[0], @@ -1032,8 +987,7 @@ static int init_status_page(struct intel_ring_buffer *ring) return ret; } -static -int intel_init_ring_buffer(struct drm_device *dev, +static int intel_init_ring_buffer(struct drm_device *dev, struct intel_ring_buffer *ring) { struct drm_i915_gem_object *obj; @@ -1043,9 +997,7 @@ int intel_init_ring_buffer(struct drm_device *dev, INIT_LIST_HEAD(&ring->active_list); INIT_LIST_HEAD(&ring->request_list); INIT_LIST_HEAD(&ring->gpu_write_list); - - mtx_init(&ring->irq_lock, "ringb", NULL, MTX_DEF); - ring->irq_mask = ~0; + ring->size = 32 * PAGE_SIZE; if (I915_NEED_GFX_HWS(dev)) { ret = init_status_page(ring); @@ -1066,20 +1018,15 @@ int intel_init_ring_buffer(struct drm_device *dev, if (ret) goto err_unref; - ring->map.size = ring->size; - ring->map.offset = dev->agp->base + obj->gtt_offset; - ring->map.type = 0; - ring->map.flags = 0; - ring->map.mtrr = 0; - - drm_core_ioremap_wc(&ring->map, dev); - if (ring->map.virtual == NULL) { + ring->virtual_start = pmap_mapdev_attr( + dev->agp->base + obj->gtt_offset, ring->size, + VM_MEMATTR_WRITE_COMBINING); + if (ring->virtual_start == NULL) { DRM_ERROR("Failed to map ringbuffer.\n"); ret = -EINVAL; goto err_unpin; } - ring->virtual_start = ring->map.virtual; ret = ring->init(ring); if (ret) goto err_unmap; @@ -1095,7 +1042,7 @@ int intel_init_ring_buffer(struct drm_device *dev, return 0; err_unmap: - drm_core_ioremapfree(&ring->map, dev); + pmap_unmapdev((vm_offset_t)ring->virtual_start, ring->size); err_unpin: i915_gem_object_unpin(obj); err_unref: @@ -1119,7 +1066,7 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring) ret = intel_wait_ring_idle(ring); I915_WRITE_CTL(ring, 0); - drm_core_ioremapfree(&ring->map, ring->dev); + pmap_unmapdev((vm_offset_t)ring->virtual_start, ring->size); i915_gem_object_unpin(ring->obj); drm_gem_object_unreference(&ring->obj->base); @@ -1133,7 +1080,7 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring) static int intel_wrap_ring_buffer(struct intel_ring_buffer *ring) { - unsigned int *virt; + uint32_t *virt; int rem = ring->size - ring->tail; if (ring->space < rem) { @@ -1142,12 +1089,10 @@ static int intel_wrap_ring_buffer(struct intel_ring_buffer *ring) return ret; } - virt = (unsigned int *)((char *)ring->virtual_start + ring->tail); - rem /= 8; - while (rem--) { + virt = (uint32_t *)((char *)ring->virtual_start + ring->tail); + rem /= 4; + while (rem--) *virt++ = MI_NOOP; - *virt++ = MI_NOOP; - } ring->tail = 0; ring->space = ring_space(ring); @@ -1168,9 +1113,11 @@ static int intel_ring_wait_seqno(struct intel_ring_buffer *ring, u32 seqno) was_interruptible = dev_priv->mm.interruptible; dev_priv->mm.interruptible = false; - ret = i915_wait_request(ring, seqno, true); + ret = i915_wait_request(ring, seqno); dev_priv->mm.interruptible = was_interruptible; + if (!ret) + i915_gem_retire_requests_ring(ring); return ret; } @@ -1244,15 +1191,13 @@ int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n) return ret; CTR1(KTR_DRM, "ring_wait_begin %s", ring->name); - if (drm_core_check_feature(dev, DRIVER_GEM)) - /* With GEM the hangcheck timer should kick us out of the loop, - * leaving it early runs the risk of corrupting GEM state (due - * to running on almost untested codepaths). But on resume - * timers don't work yet, so prevent a complete hang in that - * case by choosing an insanely large timeout. */ - end = ticks + hz * 60; - else - end = ticks + hz * 3; + /* With GEM the hangcheck timer should kick us out of the loop, + * leaving it early runs the risk of corrupting GEM state (due + * to running on almost untested codepaths). But on resume + * timers don't work yet, so prevent a complete hang in that + * case by choosing an insanely large timeout. */ + end = ticks + hz * 60; + do { ring->head = I915_READ_HEAD(ring); ring->space = ring_space(ring); @@ -1310,51 +1255,17 @@ int intel_ring_begin(struct intel_ring_buffer *ring, void intel_ring_advance(struct intel_ring_buffer *ring) { + struct drm_i915_private *dev_priv = ring->dev->dev_private; + ring->tail &= ring->size - 1; + if (dev_priv->stop_rings & intel_ring_flag(ring)) + return; ring->write_tail(ring, ring->tail); } -static const struct intel_ring_buffer render_ring = { - .name = "render ring", - .id = RCS, - .mmio_base = RENDER_RING_BASE, - .size = 32 * PAGE_SIZE, - .init = init_render_ring, - .write_tail = ring_write_tail, - .flush = render_ring_flush, - .add_request = render_ring_add_request, - .get_seqno = ring_get_seqno, - .irq_get = render_ring_get_irq, - .irq_put = render_ring_put_irq, - .dispatch_execbuffer = render_ring_dispatch_execbuffer, - .cleanup = render_ring_cleanup, - .sync_to = render_ring_sync_to, - .semaphore_register = {MI_SEMAPHORE_SYNC_INVALID, - MI_SEMAPHORE_SYNC_RV, - MI_SEMAPHORE_SYNC_RB}, - .signal_mbox = {GEN6_VRSYNC, GEN6_BRSYNC}, -}; - -/* ring buffer for bit-stream decoder */ - -static const struct intel_ring_buffer bsd_ring = { - .name = "bsd ring", - .id = VCS, - .mmio_base = BSD_RING_BASE, - .size = 32 * PAGE_SIZE, - .init = init_ring_common, - .write_tail = ring_write_tail, - .flush = bsd_ring_flush, - .add_request = ring_add_request, - .get_seqno = ring_get_seqno, - .irq_get = bsd_ring_get_irq, - .irq_put = bsd_ring_put_irq, - .dispatch_execbuffer = ring_dispatch_execbuffer, -}; - static void gen6_bsd_ring_write_tail(struct intel_ring_buffer *ring, - uint32_t value) + u32 value) { drm_i915_private_t *dev_priv = ring->dev->dev_private; @@ -1415,81 +1326,12 @@ gen6_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, return 0; } -static bool -gen6_render_ring_get_irq(struct intel_ring_buffer *ring) -{ - return gen6_ring_get_irq(ring, - GT_USER_INTERRUPT, - GEN6_RENDER_USER_INTERRUPT); -} - -static void -gen6_render_ring_put_irq(struct intel_ring_buffer *ring) -{ - return gen6_ring_put_irq(ring, - GT_USER_INTERRUPT, - GEN6_RENDER_USER_INTERRUPT); -} - -static bool -gen6_bsd_ring_get_irq(struct intel_ring_buffer *ring) -{ - return gen6_ring_get_irq(ring, - GT_GEN6_BSD_USER_INTERRUPT, - GEN6_BSD_USER_INTERRUPT); -} - -static void -gen6_bsd_ring_put_irq(struct intel_ring_buffer *ring) -{ - return gen6_ring_put_irq(ring, - GT_GEN6_BSD_USER_INTERRUPT, - GEN6_BSD_USER_INTERRUPT); -} - -/* ring buffer for Video Codec for Gen6+ */ -static const struct intel_ring_buffer gen6_bsd_ring = { - .name = "gen6 bsd ring", - .id = VCS, - .mmio_base = GEN6_BSD_RING_BASE, - .size = 32 * PAGE_SIZE, - .init = init_ring_common, - .write_tail = gen6_bsd_ring_write_tail, - .flush = gen6_ring_flush, - .add_request = gen6_add_request, - .get_seqno = gen6_ring_get_seqno, - .irq_get = gen6_bsd_ring_get_irq, - .irq_put = gen6_bsd_ring_put_irq, - .dispatch_execbuffer = gen6_ring_dispatch_execbuffer, - .sync_to = gen6_bsd_ring_sync_to, - .semaphore_register = {MI_SEMAPHORE_SYNC_VR, - MI_SEMAPHORE_SYNC_INVALID, - MI_SEMAPHORE_SYNC_VB}, - .signal_mbox = {GEN6_RVSYNC, GEN6_BVSYNC}, -}; - /* Blitter support (SandyBridge+) */ -static bool -blt_ring_get_irq(struct intel_ring_buffer *ring) -{ - return gen6_ring_get_irq(ring, - GT_BLT_USER_INTERRUPT, - GEN6_BLITTER_USER_INTERRUPT); -} - -static void -blt_ring_put_irq(struct intel_ring_buffer *ring) -{ - gen6_ring_put_irq(ring, - GT_BLT_USER_INTERRUPT, - GEN6_BLITTER_USER_INTERRUPT); -} - static int blt_ring_flush(struct intel_ring_buffer *ring, - uint32_t invalidate, uint32_t flush) + u32 invalidate, u32 flush) { - uint32_t cmd; + u32 cmd; int ret; ret = intel_ring_begin(ring, 4); @@ -1507,42 +1349,63 @@ static int blt_ring_flush(struct intel_ring_buffer *ring, return 0; } -static const struct intel_ring_buffer gen6_blt_ring = { - .name = "blt ring", - .id = BCS, - .mmio_base = BLT_RING_BASE, - .size = 32 * PAGE_SIZE, - .init = init_ring_common, - .write_tail = ring_write_tail, - .flush = blt_ring_flush, - .add_request = gen6_add_request, - .get_seqno = gen6_ring_get_seqno, - .irq_get = blt_ring_get_irq, - .irq_put = blt_ring_put_irq, - .dispatch_execbuffer = gen6_ring_dispatch_execbuffer, - .sync_to = gen6_blt_ring_sync_to, - .semaphore_register = {MI_SEMAPHORE_SYNC_BR, - MI_SEMAPHORE_SYNC_BV, - MI_SEMAPHORE_SYNC_INVALID}, - .signal_mbox = {GEN6_RBSYNC, GEN6_VBSYNC}, -}; - int intel_init_render_ring_buffer(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; struct intel_ring_buffer *ring = &dev_priv->rings[RCS]; - *ring = render_ring; + ring->name = "render ring"; + ring->id = RCS; + ring->mmio_base = RENDER_RING_BASE; + if (INTEL_INFO(dev)->gen >= 6) { ring->add_request = gen6_add_request; ring->flush = gen6_render_ring_flush; - ring->irq_get = gen6_render_ring_get_irq; - ring->irq_put = gen6_render_ring_put_irq; + ring->irq_get = gen6_ring_get_irq; + ring->irq_put = gen6_ring_put_irq; + ring->irq_enable_mask = GT_USER_INTERRUPT; ring->get_seqno = gen6_ring_get_seqno; + ring->sync_to = gen6_ring_sync; + ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_INVALID; + ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_RV; + ring->semaphore_register[2] = MI_SEMAPHORE_SYNC_RB; + ring->signal_mbox[0] = GEN6_VRSYNC; + ring->signal_mbox[1] = GEN6_BRSYNC; } else if (IS_GEN5(dev)) { ring->add_request = pc_render_add_request; + ring->flush = gen4_render_ring_flush; ring->get_seqno = pc_render_get_seqno; + ring->irq_get = gen5_ring_get_irq; + ring->irq_put = gen5_ring_put_irq; + ring->irq_enable_mask = GT_USER_INTERRUPT | GT_PIPE_NOTIFY; + } else { + ring->add_request = i9xx_add_request; + if (INTEL_INFO(dev)->gen < 4) + ring->flush = gen2_render_ring_flush; + else + ring->flush = gen4_render_ring_flush; + ring->get_seqno = ring_get_seqno; + if (IS_GEN2(dev)) { + ring->irq_get = i8xx_ring_get_irq; + ring->irq_put = i8xx_ring_put_irq; + } else { + ring->irq_get = i9xx_ring_get_irq; + ring->irq_put = i9xx_ring_put_irq; + } + ring->irq_enable_mask = I915_USER_INTERRUPT; } + ring->write_tail = ring_write_tail; + if (INTEL_INFO(dev)->gen >= 6) + ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer; + else if (INTEL_INFO(dev)->gen >= 4) + ring->dispatch_execbuffer = i965_dispatch_execbuffer; + else if (IS_I830(dev) || IS_845G(dev)) + ring->dispatch_execbuffer = i830_dispatch_execbuffer; + else + ring->dispatch_execbuffer = i915_dispatch_execbuffer; + ring->init = init_render_ring; + ring->cleanup = render_ring_cleanup; + if (!I915_NEED_GFX_HWS(dev)) { ring->status_page.page_addr = dev_priv->status_page_dmah->vaddr; @@ -1552,22 +1415,47 @@ int intel_init_render_ring_buffer(struct drm_device *dev) return intel_init_ring_buffer(dev, ring); } -int intel_render_ring_init_dri(struct drm_device *dev, uint64_t start, - uint32_t size) +int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size) { drm_i915_private_t *dev_priv = dev->dev_private; struct intel_ring_buffer *ring = &dev_priv->rings[RCS]; - *ring = render_ring; + ring->name = "render ring"; + ring->id = RCS; + ring->mmio_base = RENDER_RING_BASE; + if (INTEL_INFO(dev)->gen >= 6) { - ring->add_request = gen6_add_request; - ring->irq_get = gen6_render_ring_get_irq; - ring->irq_put = gen6_render_ring_put_irq; - } else if (IS_GEN5(dev)) { - ring->add_request = pc_render_add_request; - ring->get_seqno = pc_render_get_seqno; + /* non-kms not supported on gen6+ */ + return -ENODEV; } + /* Note: gem is not supported on gen5/ilk without kms (the corresponding + * gem_init ioctl returns with -ENODEV). Hence we do not need to set up + * the special gen5 functions. */ + ring->add_request = i9xx_add_request; + if (INTEL_INFO(dev)->gen < 4) + ring->flush = gen2_render_ring_flush; + else + ring->flush = gen4_render_ring_flush; + ring->get_seqno = ring_get_seqno; + if (IS_GEN2(dev)) { + ring->irq_get = i8xx_ring_get_irq; + ring->irq_put = i8xx_ring_put_irq; + } else { + ring->irq_get = i9xx_ring_get_irq; + ring->irq_put = i9xx_ring_put_irq; + } + ring->irq_enable_mask = I915_USER_INTERRUPT; + ring->write_tail = ring_write_tail; + if (INTEL_INFO(dev)->gen >= 4) + ring->dispatch_execbuffer = i965_dispatch_execbuffer; + else if (IS_I830(dev) || IS_845G(dev)) + ring->dispatch_execbuffer = i830_dispatch_execbuffer; + else + ring->dispatch_execbuffer = i915_dispatch_execbuffer; + ring->init = init_render_ring; + ring->cleanup = render_ring_cleanup; + ring->dev = dev; INIT_LIST_HEAD(&ring->active_list); INIT_LIST_HEAD(&ring->request_list); @@ -1578,20 +1466,14 @@ int intel_render_ring_init_dri(struct drm_device *dev, uint64_t start, if (IS_I830(ring->dev)) ring->effective_size -= 128; - ring->map.offset = start; - ring->map.size = size; - ring->map.type = 0; - ring->map.flags = 0; - ring->map.mtrr = 0; - - drm_core_ioremap_wc(&ring->map, dev); - if (ring->map.virtual == NULL) { + ring->virtual_start = pmap_mapdev_attr(start, size, + VM_MEMATTR_WRITE_COMBINING); + if (ring->virtual_start == NULL) { DRM_ERROR("can not ioremap virtual address for" " ring buffer\n"); return -ENOMEM; } - ring->virtual_start = (void *)ring->map.virtual; return 0; } @@ -1600,10 +1482,46 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; struct intel_ring_buffer *ring = &dev_priv->rings[VCS]; - if (IS_GEN6(dev) || IS_GEN7(dev)) - *ring = gen6_bsd_ring; - else - *ring = bsd_ring; + ring->name = "bsd ring"; + ring->id = VCS; + + ring->write_tail = ring_write_tail; + if (IS_GEN6(dev) || IS_GEN7(dev)) { + ring->mmio_base = GEN6_BSD_RING_BASE; + /* gen6 bsd needs a special wa for tail updates */ + if (IS_GEN6(dev)) + ring->write_tail = gen6_bsd_ring_write_tail; + ring->flush = gen6_ring_flush; + ring->add_request = gen6_add_request; + ring->get_seqno = gen6_ring_get_seqno; + ring->irq_enable_mask = GEN6_BSD_USER_INTERRUPT; + ring->irq_get = gen6_ring_get_irq; + ring->irq_put = gen6_ring_put_irq; + ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer; + ring->sync_to = gen6_ring_sync; + ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_VR; + ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_INVALID; + ring->semaphore_register[2] = MI_SEMAPHORE_SYNC_VB; + ring->signal_mbox[0] = GEN6_RVSYNC; + ring->signal_mbox[1] = GEN6_BVSYNC; + } else { + ring->mmio_base = BSD_RING_BASE; + ring->flush = bsd_ring_flush; + ring->add_request = i9xx_add_request; + ring->get_seqno = ring_get_seqno; + if (IS_GEN5(dev)) { + ring->irq_enable_mask = GT_BSD_USER_INTERRUPT; + ring->irq_get = gen5_ring_get_irq; + ring->irq_put = gen5_ring_put_irq; + } else { + ring->irq_enable_mask = I915_BSD_USER_INTERRUPT; + ring->irq_get = i9xx_ring_get_irq; + ring->irq_put = i9xx_ring_put_irq; + } + ring->dispatch_execbuffer = i965_dispatch_execbuffer; + } + ring->init = init_ring_common; + return intel_init_ring_buffer(dev, ring); } @@ -1613,7 +1531,25 @@ int intel_init_blt_ring_buffer(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; struct intel_ring_buffer *ring = &dev_priv->rings[BCS]; - *ring = gen6_blt_ring; + ring->name = "blitter ring"; + ring->id = BCS; + + ring->mmio_base = BLT_RING_BASE; + ring->write_tail = ring_write_tail; + ring->flush = blt_ring_flush; + ring->add_request = gen6_add_request; + ring->get_seqno = gen6_ring_get_seqno; + ring->irq_enable_mask = GEN6_BLITTER_USER_INTERRUPT; + ring->irq_get = gen6_ring_get_irq; + ring->irq_put = gen6_ring_put_irq; + ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer; + ring->sync_to = gen6_ring_sync; + ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_BR; + ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_BV; + ring->semaphore_register[2] = MI_SEMAPHORE_SYNC_INVALID; + ring->signal_mbox[0] = GEN6_RBSYNC; + ring->signal_mbox[1] = GEN6_VBSYNC; + ring->init = init_ring_common; return intel_init_ring_buffer(dev, ring); } diff --git a/sys/dev/drm2/i915/intel_ringbuffer.h b/sys/dev/drm2/i915/intel_ringbuffer.h index c391b12c9f9f..efbc39bf9674 100644 --- a/sys/dev/drm2/i915/intel_ringbuffer.h +++ b/sys/dev/drm2/i915/intel_ringbuffer.h @@ -6,7 +6,7 @@ #define _INTEL_RINGBUFFER_H_ struct intel_hw_status_page { - uint32_t *page_addr; + u32 *page_addr; unsigned int gfx_addr; struct drm_i915_gem_object *obj; }; @@ -38,13 +38,13 @@ struct intel_ring_buffer { BCS, } id; #define I915_NUM_RINGS 3 - uint32_t mmio_base; + u32 mmio_base; void *virtual_start; struct drm_device *dev; struct drm_i915_gem_object *obj; - uint32_t head; - uint32_t tail; + u32 head; + u32 tail; int space; int size; int effective_size; @@ -60,13 +60,10 @@ struct intel_ring_buffer { */ u32 last_retired_head; - struct mtx irq_lock; - uint32_t irq_refcount; - uint32_t irq_mask; - uint32_t irq_seqno; /* last seq seem at irq time */ - uint32_t trace_irq_seqno; - uint32_t waiting_seqno; - uint32_t sync_seqno[I915_NUM_RINGS-1]; + u32 irq_refcount; + u32 irq_enable_mask; /* bitmask to enable ring interrupt */ + u32 trace_irq_seqno; + u32 sync_seqno[I915_NUM_RINGS-1]; bool (*irq_get)(struct intel_ring_buffer *ring); void (*irq_put)(struct intel_ring_buffer *ring); @@ -120,7 +117,7 @@ struct intel_ring_buffer { /** * Do we have some not yet emitted requests outstanding? */ - uint32_t outstanding_lazy_request; + u32 outstanding_lazy_request; /** * Do an explicit TLB flush before MI_SET_CONTEXT @@ -169,6 +166,8 @@ static inline uint32_t intel_read_status_page(struct intel_ring_buffer *ring, int reg) { + /* Ensure that the compiler doesn't optimize away the load. */ + __compiler_membar(); return (atomic_load_acq_32(ring->status_page.page_addr + reg)); } diff --git a/sys/dev/drm2/i915/intel_sdvo.c b/sys/dev/drm2/i915/intel_sdvo.c index 8cae7662d5dc..74e479a60f9d 100644 --- a/sys/dev/drm2/i915/intel_sdvo.c +++ b/sys/dev/drm2/i915/intel_sdvo.c @@ -44,7 +44,7 @@ __FBSDID("$FreeBSD$"); #define SDVO_TMDS_MASK (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1) #define SDVO_RGB_MASK (SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1) #define SDVO_LVDS_MASK (SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1) -#define SDVO_TV_MASK (SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_SVID0) +#define SDVO_TV_MASK (SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_YPRPB0) #define SDVO_OUTPUT_MASK (SDVO_TMDS_MASK | SDVO_RGB_MASK | SDVO_LVDS_MASK |\ SDVO_TV_MASK) @@ -77,7 +77,7 @@ struct intel_sdvo { device_t ddc_iic_bus, ddc; /* Register for the SDVO device: SDVOB or SDVOC */ - int sdvo_reg; + uint32_t sdvo_reg; /* Active outputs controlled by this SDVO output */ uint16_t controlled_output; @@ -117,6 +117,9 @@ struct intel_sdvo { */ bool is_tv; + /* On different gens SDVOB is at different places. */ + bool is_sdvob; + /* This is for current tv format name */ int tv_format_index; @@ -406,12 +409,10 @@ static const struct _sdvo_cmd_name { SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_DATA), }; -#define IS_SDVOB(reg) (reg == SDVOB || reg == PCH_SDVOB) -#define SDVO_NAME(svdo) (IS_SDVOB((svdo)->sdvo_reg) ? "SDVOB" : "SDVOC") +#define SDVO_NAME(svdo) ((svdo)->is_sdvob ? "SDVOB" : "SDVOC") -static void -intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd, - const void *args, int args_len) +static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd, + const void *args, int args_len) { int i; @@ -744,18 +745,18 @@ static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd, uint16_t h_sync_offset, v_sync_offset; int mode_clock; - width = mode->crtc_hdisplay; - height = mode->crtc_vdisplay; + width = mode->hdisplay; + height = mode->vdisplay; - /* do some mode translations */ - h_blank_len = mode->crtc_hblank_end - mode->crtc_hblank_start; - h_sync_len = mode->crtc_hsync_end - mode->crtc_hsync_start; + /* do some mode translations */ + h_blank_len = mode->htotal - mode->hdisplay; + h_sync_len = mode->hsync_end - mode->hsync_start; - v_blank_len = mode->crtc_vblank_end - mode->crtc_vblank_start; - v_sync_len = mode->crtc_vsync_end - mode->crtc_vsync_start; + v_blank_len = mode->vtotal - mode->vdisplay; + v_sync_len = mode->vsync_end - mode->vsync_start; - h_sync_offset = mode->crtc_hsync_start - mode->crtc_hblank_start; - v_sync_offset = mode->crtc_vsync_start - mode->crtc_vblank_start; + h_sync_offset = mode->hsync_start - mode->hdisplay; + v_sync_offset = mode->vsync_start - mode->vdisplay; mode_clock = mode->clock; mode_clock /= intel_mode_get_pixel_multiplier(mode) ?: 1; @@ -884,17 +885,24 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo) }; uint8_t tx_rate = SDVO_HBUF_TX_VSYNC; uint8_t set_buf_index[2] = { 1, 0 }; - uint64_t *data = (uint64_t *)&avi_if; + uint8_t sdvo_data[4 + sizeof(avi_if.body.avi)]; + uint64_t *data = (uint64_t *)sdvo_data; unsigned i; intel_dip_infoframe_csum(&avi_if); + /* sdvo spec says that the ecc is handled by the hw, and it looks like + * we must not send the ecc field, either. */ + memcpy(sdvo_data, &avi_if, 3); + sdvo_data[3] = avi_if.checksum; + memcpy(&sdvo_data[4], &avi_if.body, sizeof(avi_if.body.avi)); + if (!intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_HBUF_INDEX, set_buf_index, 2)) return false; - for (i = 0; i < sizeof(avi_if); i += 8) { + for (i = 0; i < sizeof(sdvo_data); i += 8) { if (!intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_HBUF_DATA, data, 8)) @@ -964,7 +972,7 @@ intel_sdvo_set_input_timings_for_mode(struct intel_sdvo *intel_sdvo, } static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, + struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder); @@ -1272,7 +1280,8 @@ intel_sdvo_get_analog_edid(struct drm_connector *connector) struct drm_i915_private *dev_priv = connector->dev->dev_private; return drm_get_edid(connector, - dev_priv->gmbus[dev_priv->crt_ddc_pin]); + intel_gmbus_get_adapter(dev_priv, + dev_priv->crt_ddc_pin)); } static enum drm_connector_status @@ -1361,8 +1370,7 @@ intel_sdvo_detect(struct drm_connector *connector, bool force) return connector_status_unknown; /* add 30ms delay when the output type might be TV */ - if (intel_sdvo->caps.output_flags & - (SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_CVBS0)) + if (intel_sdvo->caps.output_flags & SDVO_TV_MASK) drm_msleep(30, "915svo"); if (!intel_sdvo_read_response(intel_sdvo, &response, 2)) @@ -1582,9 +1590,6 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) intel_sdvo->sdvo_lvds_fixed_mode = drm_mode_duplicate(connector->dev, newmode); - drm_mode_set_crtcinfo(intel_sdvo->sdvo_lvds_fixed_mode, - 0); - intel_sdvo->is_lvds = true; break; } @@ -1916,7 +1921,7 @@ intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv, { struct sdvo_device_mapping *mapping; - if (IS_SDVOB(reg)) + if (sdvo->is_sdvob) mapping = &(dev_priv->sdvo_mappings[0]); else mapping = &(dev_priv->sdvo_mappings[1]); @@ -1934,7 +1939,7 @@ intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv, struct sdvo_device_mapping *mapping; u8 pin; - if (IS_SDVOB(reg)) + if (sdvo->is_sdvob) mapping = &dev_priv->sdvo_mappings[0]; else mapping = &dev_priv->sdvo_mappings[1]; @@ -1943,12 +1948,12 @@ intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv, if (mapping->initialized) pin = mapping->i2c_pin; - if (pin < GMBUS_NUM_PORTS) { - sdvo->i2c = dev_priv->gmbus[pin]; + if (intel_gmbus_is_port_valid(pin)) { + sdvo->i2c = intel_gmbus_get_adapter(dev_priv, pin); intel_gmbus_set_speed(sdvo->i2c, GMBUS_RATE_1MHZ); intel_gmbus_force_bit(sdvo->i2c, true); } else { - sdvo->i2c = dev_priv->gmbus[GMBUS_PORT_DPB]; + sdvo->i2c = intel_gmbus_get_adapter(dev_priv, GMBUS_PORT_DPB); } } @@ -1959,12 +1964,12 @@ intel_sdvo_is_hdmi_connector(struct intel_sdvo *intel_sdvo, int device) } static u8 -intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg) +intel_sdvo_get_slave_addr(struct drm_device *dev, struct intel_sdvo *sdvo) { struct drm_i915_private *dev_priv = dev->dev_private; struct sdvo_device_mapping *my_mapping, *other_mapping; - if (IS_SDVOB(sdvo_reg)) { + if (sdvo->is_sdvob) { my_mapping = &dev_priv->sdvo_mappings[0]; other_mapping = &dev_priv->sdvo_mappings[1]; } else { @@ -1989,7 +1994,7 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg) /* No SDVO device info is found for another DVO port, * so use mapping assumption we had before BIOS parsing. */ - if (IS_SDVOB(sdvo_reg)) + if (sdvo->is_sdvob) return 0x70; else return 0x72; @@ -2214,6 +2219,10 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags) if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_CVBS0)) return false; + if (flags & SDVO_OUTPUT_YPRPB0) + if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_YPRPB0)) + return false; + if (flags & SDVO_OUTPUT_RGB0) if (!intel_sdvo_analog_init(intel_sdvo, 0)) return false; @@ -2583,7 +2592,7 @@ DRIVER_MODULE_ORDERED(intel_sdvo_ddc_proxy, drmn, intel_sdvo_ddc_proxy_driver, intel_sdvo_devclass, 0, 0, SI_ORDER_FIRST); -bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) +bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_encoder *intel_encoder; @@ -2594,7 +2603,8 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) M_WAITOK | M_ZERO); intel_sdvo->sdvo_reg = sdvo_reg; - intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg) >> 1; + intel_sdvo->is_sdvob = is_sdvob; + intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, intel_sdvo) >> 1; intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo, sdvo_reg); if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev, sdvo_reg)) { free(intel_sdvo, DRM_MEM_KMS); @@ -2611,13 +2621,13 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) u8 byte; if (!intel_sdvo_read_byte(intel_sdvo, i, &byte)) { - DRM_DEBUG_KMS("No SDVO device found on SDVO%c\n", - IS_SDVOB(sdvo_reg) ? 'B' : 'C'); + DRM_DEBUG_KMS("No SDVO device found on %s\n", + SDVO_NAME(intel_sdvo)); goto err; } } - if (IS_SDVOB(sdvo_reg)) + if (intel_sdvo->is_sdvob) dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS; else dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS; @@ -2636,12 +2646,12 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) &intel_sdvo->hotplug_active, 2); intel_sdvo->hotplug_active[0] &= ~0x3; - if (!intel_sdvo_output_setup(intel_sdvo, - intel_sdvo->caps.output_flags)) { - DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n", - IS_SDVOB(sdvo_reg) ? 'B' : 'C'); - goto err; - } + if (intel_sdvo_output_setup(intel_sdvo, + intel_sdvo->caps.output_flags) != true) { + DRM_DEBUG_KMS("SDVO output failed to setup on %s\n", + SDVO_NAME(intel_sdvo)); + goto err; + } intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg); diff --git a/sys/dev/drm2/i915/intel_sprite.c b/sys/dev/drm2/i915/intel_sprite.c index 0737a5c6cf18..35f2baab57f9 100644 --- a/sys/dev/drm2/i915/intel_sprite.c +++ b/sys/dev/drm2/i915/intel_sprite.c @@ -114,14 +114,18 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, * when scaling is disabled. */ if (crtc_w != src_w || crtc_h != src_h) { - dev_priv->sprite_scaling_enabled = true; - sandybridge_update_wm(dev); - intel_wait_for_vblank(dev, pipe); + if (!dev_priv->sprite_scaling_enabled) { + dev_priv->sprite_scaling_enabled = true; + intel_update_watermarks(dev); + intel_wait_for_vblank(dev, pipe); + } sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h; } else { - dev_priv->sprite_scaling_enabled = false; - /* potentially re-enable LP watermarks */ - sandybridge_update_wm(dev); + if (dev_priv->sprite_scaling_enabled) { + dev_priv->sprite_scaling_enabled = false; + /* potentially re-enable LP watermarks */ + intel_update_watermarks(dev); + } } I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); @@ -137,7 +141,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, I915_WRITE(SPRSIZE(pipe), (crtc_h << 16) | crtc_w); I915_WRITE(SPRSCALE(pipe), sprscale); I915_WRITE(SPRCTL(pipe), sprctl); - I915_WRITE(SPRSURF(pipe), obj->gtt_offset); + I915_MODIFY_DISPBASE(SPRSURF(pipe), obj->gtt_offset); POSTING_READ(SPRSURF(pipe)); } @@ -153,8 +157,11 @@ ivb_disable_plane(struct drm_plane *plane) /* Can't leave the scaler enabled... */ I915_WRITE(SPRSCALE(pipe), 0); /* Activate double buffered register update */ - I915_WRITE(SPRSURF(pipe), 0); + I915_MODIFY_DISPBASE(SPRSURF(pipe), 0); POSTING_READ(SPRSURF(pipe)); + + dev_priv->sprite_scaling_enabled = false; + intel_update_watermarks(dev); } static int @@ -212,7 +219,7 @@ ivb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) } static void -snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, +ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t x, uint32_t y, @@ -222,7 +229,7 @@ snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(plane); int pipe = intel_plane->pipe, pixel_size; - u32 dvscntr, dvsscale = 0; + u32 dvscntr, dvsscale; dvscntr = I915_READ(DVSCNTR(pipe)); @@ -266,8 +273,8 @@ snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, if (obj->tiling_mode != I915_TILING_NONE) dvscntr |= DVS_TILED; - /* must disable */ - dvscntr |= DVS_TRICKLE_FEED_DISABLE; + if (IS_GEN6(dev)) + dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */ dvscntr |= DVS_ENABLE; /* Sizes are 0 based */ @@ -278,7 +285,8 @@ snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size); - if (crtc_w != src_w || crtc_h != src_h) + dvsscale = 0; + if (IS_GEN5(dev) || crtc_w != src_w || crtc_h != src_h) dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h; I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); @@ -294,12 +302,12 @@ snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w); I915_WRITE(DVSSCALE(pipe), dvsscale); I915_WRITE(DVSCNTR(pipe), dvscntr); - I915_WRITE(DVSSURF(pipe), obj->gtt_offset); + I915_MODIFY_DISPBASE(DVSSURF(pipe), obj->gtt_offset); POSTING_READ(DVSSURF(pipe)); } static void -snb_disable_plane(struct drm_plane *plane) +ilk_disable_plane(struct drm_plane *plane) { struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -310,7 +318,7 @@ snb_disable_plane(struct drm_plane *plane) /* Disable the scaler */ I915_WRITE(DVSSCALE(pipe), 0); /* Flush double buffered register updates */ - I915_WRITE(DVSSURF(pipe), 0); + I915_MODIFY_DISPBASE(DVSSURF(pipe), 0); POSTING_READ(DVSSURF(pipe)); } @@ -337,7 +345,7 @@ intel_disable_primary(struct drm_crtc *crtc) } static int -snb_update_colorkey(struct drm_plane *plane, +ilk_update_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) { struct drm_device *dev = plane->dev; @@ -366,7 +374,7 @@ snb_update_colorkey(struct drm_plane *plane, } static void -snb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) +ilk_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) { struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -554,14 +562,13 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_intel_sprite_colorkey *set = data; - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_mode_object *obj; struct drm_plane *plane; struct intel_plane *intel_plane; int ret = 0; - if (!dev_priv) - return -EINVAL; + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -ENODEV; /* Make sure we don't try to enable both src & dest simultaneously */ if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) @@ -588,14 +595,13 @@ int intel_sprite_get_colorkey(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_intel_sprite_colorkey *get = data; - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_mode_object *obj; struct drm_plane *plane; struct intel_plane *intel_plane; int ret = 0; - if (!dev_priv) - return -EINVAL; + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -ENODEV; sx_xlock(&dev->mode_config.mutex); @@ -620,6 +626,14 @@ static const struct drm_plane_funcs intel_plane_funcs = { .destroy = intel_destroy_plane, }; +static uint32_t ilk_plane_formats[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, +}; + static uint32_t snb_plane_formats[] = { DRM_FORMAT_XBGR8888, DRM_FORMAT_XRGB8888, @@ -634,33 +648,55 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe) { struct intel_plane *intel_plane; unsigned long possible_crtcs; + const uint32_t *plane_formats; + int num_plane_formats; int ret; - if (!(IS_GEN6(dev) || IS_GEN7(dev))) + if (INTEL_INFO(dev)->gen < 5) return -ENODEV; intel_plane = malloc(sizeof(struct intel_plane), DRM_MEM_KMS, M_WAITOK | M_ZERO); - if (IS_GEN6(dev)) { + switch (INTEL_INFO(dev)->gen) { + case 5: + case 6: intel_plane->max_downscale = 16; - intel_plane->update_plane = snb_update_plane; - intel_plane->disable_plane = snb_disable_plane; - intel_plane->update_colorkey = snb_update_colorkey; - intel_plane->get_colorkey = snb_get_colorkey; - } else if (IS_GEN7(dev)) { + intel_plane->update_plane = ilk_update_plane; + intel_plane->disable_plane = ilk_disable_plane; + intel_plane->update_colorkey = ilk_update_colorkey; + intel_plane->get_colorkey = ilk_get_colorkey; + + if (IS_GEN6(dev)) { + plane_formats = snb_plane_formats; + num_plane_formats = DRM_ARRAY_SIZE(snb_plane_formats); + } else { + plane_formats = ilk_plane_formats; + num_plane_formats = DRM_ARRAY_SIZE(ilk_plane_formats); + } + break; + + case 7: intel_plane->max_downscale = 2; intel_plane->update_plane = ivb_update_plane; intel_plane->disable_plane = ivb_disable_plane; intel_plane->update_colorkey = ivb_update_colorkey; intel_plane->get_colorkey = ivb_get_colorkey; + + plane_formats = snb_plane_formats; + num_plane_formats = DRM_ARRAY_SIZE(snb_plane_formats); + break; + + default: + return -ENODEV; } intel_plane->pipe = pipe; possible_crtcs = (1 << pipe); ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs, - &intel_plane_funcs, snb_plane_formats, - DRM_ARRAY_SIZE(snb_plane_formats), false); + &intel_plane_funcs, + plane_formats, num_plane_formats, + false); if (ret) free(intel_plane, DRM_MEM_KMS); diff --git a/sys/dev/drm2/i915/intel_tv.c b/sys/dev/drm2/i915/intel_tv.c index 57a2181f1aa6..ddc6c97ee12d 100644 --- a/sys/dev/drm2/i915/intel_tv.c +++ b/sys/dev/drm2/i915/intel_tv.c @@ -814,7 +814,7 @@ intel_tv_mode_lookup(const char *tv_format) { int i; - for (i = 0; i < sizeof(tv_modes) / sizeof(tv_modes[0]); i++) { + for (i = 0; i < DRM_ARRAY_SIZE(tv_modes); i++) { const struct tv_mode *tv_mode = &tv_modes[i]; if (!strcmp(tv_format, tv_mode->name)) @@ -846,7 +846,7 @@ intel_tv_mode_valid(struct drm_connector *connector, static bool -intel_tv_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, +intel_tv_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; @@ -1155,6 +1155,15 @@ intel_tv_detect_type(struct intel_tv *intel_tv, DAC_B_0_7_V | DAC_C_0_7_V); + + /* + * The TV sense state should be cleared to zero on cantiga platform. Otherwise + * the TV is misdetected. This is hardware requirement. + */ + if (IS_GM45(dev)) + tv_dac &= ~(TVDAC_STATE_CHG_EN | TVDAC_A_SENSE_CTL | + TVDAC_B_SENSE_CTL | TVDAC_C_SENSE_CTL); + I915_WRITE(TV_CTL, tv_ctl); I915_WRITE(TV_DAC, tv_dac); POSTING_READ(TV_DAC); @@ -1244,9 +1253,7 @@ intel_tv_detect(struct drm_connector *connector, bool force) mode = reported_modes[0]; drm_mode_set_crtcinfo(&mode, 0); - if (intel_tv->base.base.crtc && intel_tv->base.base.crtc->enabled) { - type = intel_tv_detect_type(intel_tv, connector); - } else if (force) { + if (force) { struct intel_load_detect_pipe tmp; if (intel_get_load_detect_pipe(&intel_tv->base, connector, diff --git a/sys/dev/drm2/radeon/atombios_encoders.c b/sys/dev/drm2/radeon/atombios_encoders.c index db23f137104e..9128aacf77f4 100644 --- a/sys/dev/drm2/radeon/atombios_encoders.c +++ b/sys/dev/drm2/radeon/atombios_encoders.c @@ -302,7 +302,7 @@ static inline bool radeon_encoder_is_digital(struct drm_encoder *encoder) } static bool radeon_atom_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, + struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); @@ -2451,7 +2451,7 @@ radeon_atom_ext_dpms(struct drm_encoder *encoder, int mode) } static bool radeon_atom_ext_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, + struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { return true; diff --git a/sys/dev/drm2/radeon/radeon_legacy_encoders.c b/sys/dev/drm2/radeon/radeon_legacy_encoders.c index 4a1ae163c9da..a4e6e284c3bd 100644 --- a/sys/dev/drm2/radeon/radeon_legacy_encoders.c +++ b/sys/dev/drm2/radeon/radeon_legacy_encoders.c @@ -245,7 +245,7 @@ static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder, } static bool radeon_legacy_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, + struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); diff --git a/sys/modules/drm2/i915kms/Makefile b/sys/modules/drm2/i915kms/Makefile index 4b4a595d02b8..8886be885453 100644 --- a/sys/modules/drm2/i915kms/Makefile +++ b/sys/modules/drm2/i915kms/Makefile @@ -11,11 +11,13 @@ SRCS = \ i915_gem_execbuffer.c \ i915_gem_evict.c \ i915_gem_gtt.c \ + i915_gem_stolen.c \ i915_gem_tiling.c \ i915_irq.c \ i915_suspend.c \ intel_bios.c \ intel_crt.c \ + intel_ddi.c \ intel_display.c \ intel_dp.c \ intel_fb.c \ @@ -26,6 +28,7 @@ SRCS = \ intel_opregion.c \ intel_overlay.c \ intel_panel.c \ + intel_pm.c \ intel_ringbuffer.c \ intel_sdvo.c \ intel_sprite.c \ From 6ef4d0dc99284b2c599b93d5678bc6f073296d53 Mon Sep 17 00:00:00 2001 From: kib Date: Wed, 21 Jan 2015 16:13:37 +0000 Subject: [PATCH 132/258] Fix bug in r276630. Do not allow pthread_sigmask() to block SIGCANCEL. Reported and tested by: royger Sponsored by: The FreeBSD Foundation MFC after: 3 days --- lib/libthr/thread/thr_sig.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/libthr/thread/thr_sig.c b/lib/libthr/thread/thr_sig.c index 7cd0f75412d8..11a131c1c5a4 100644 --- a/lib/libthr/thread/thr_sig.c +++ b/lib/libthr/thread/thr_sig.c @@ -604,7 +604,8 @@ __weak_reference(_pthread_sigmask, pthread_sigmask); int _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) { - if (_sigprocmask(how, set, oset)) + + if (__thr_sigprocmask(how, set, oset)) return (errno); return (0); } From ef36961ce12e25e2c86a5013a6ed33b650af51fb Mon Sep 17 00:00:00 2001 From: kib Date: Wed, 21 Jan 2015 16:32:54 +0000 Subject: [PATCH 133/258] Do not assert that the new pipepair mutex is not initialized. The backing memory contains garbage and might trigger the assertion. Reported and tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 2 weeks --- sys/kern/sys_pipe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c index f21b19c886cc..9d7d44bc3087 100644 --- a/sys/kern/sys_pipe.c +++ b/sys/kern/sys_pipe.c @@ -318,7 +318,7 @@ pipe_zone_init(void *mem, int size, int flags) pp = (struct pipepair *)mem; - mtx_init(&pp->pp_mtx, "pipe mutex", NULL, MTX_DEF); + mtx_init(&pp->pp_mtx, "pipe mutex", NULL, MTX_DEF | MTX_NEW); return (0); } From 4721e5b10a6394debc054efdb295af2478d19b08 Mon Sep 17 00:00:00 2001 From: andrew Date: Wed, 21 Jan 2015 16:41:05 +0000 Subject: [PATCH 134/258] Merge all the copies of _tcb_ctor and _tcb_dtor. The amd64, i386, and sparc64 versions were identical, with the one difference where the former two used inline asm instead of _tcb_get. I have compared the function before and after replacing the asm with _tcb_get and found the object files to be identical. The arm, mips, and powerpc versions were almost identical. The only difference was the powerpc version used an alignment of 1 where arm and mips used 16. As this is an increase in alignment is will be safe. Along with this arm, mips, and powerpc all passed, when initial was true, the value returned from _tcb_get as the first argument to _rtld_allocate_tls. This would then return this pointer back to the caller. We can remove these extra calls by checking if initial is set and setting the thread control block directly. As this is what the sparc64 code does we can use it directly. As after these observations all the architectures can now have identical code we can merge them into a common file. Differential Revision: https://reviews.freebsd.org/D1556 Reviewed by: kib Sponsored by: The FreeBSD Foundation --- lib/libthr/Makefile | 2 + lib/libthr/arch/amd64/Makefile.inc | 2 +- lib/libthr/arch/amd64/amd64/pthread_md.c | 55 ----------------- lib/libthr/arch/amd64/include/pthread_md.h | 3 - lib/libthr/arch/arm/Makefile.inc | 3 - lib/libthr/arch/arm/arm/pthread_md.c | 53 ----------------- lib/libthr/arch/arm/include/pthread_md.h | 6 -- lib/libthr/arch/i386/Makefile.inc | 2 +- lib/libthr/arch/i386/i386/pthread_md.c | 57 ------------------ lib/libthr/arch/i386/include/pthread_md.h | 6 -- lib/libthr/arch/mips/Makefile.inc | 3 - lib/libthr/arch/mips/include/pthread_md.h | 6 -- lib/libthr/arch/mips/mips/pthread_md.c | 59 ------------------- lib/libthr/arch/powerpc/Makefile.inc | 3 - lib/libthr/arch/powerpc/include/pthread_md.h | 3 - lib/libthr/arch/powerpc/powerpc/pthread_md.c | 54 ----------------- lib/libthr/arch/sparc64/Makefile.inc | 2 +- lib/libthr/arch/sparc64/include/pthread_md.h | 6 -- lib/libthr/thread/Makefile.inc | 1 + .../pthread_md.c => thread/thr_ctrdtr.c} | 2 +- lib/libthr/thread/thr_private.h | 3 + 21 files changed, 10 insertions(+), 321 deletions(-) delete mode 100644 lib/libthr/arch/amd64/amd64/pthread_md.c delete mode 100644 lib/libthr/arch/arm/Makefile.inc delete mode 100644 lib/libthr/arch/arm/arm/pthread_md.c delete mode 100644 lib/libthr/arch/i386/i386/pthread_md.c delete mode 100644 lib/libthr/arch/mips/Makefile.inc delete mode 100644 lib/libthr/arch/mips/mips/pthread_md.c delete mode 100644 lib/libthr/arch/powerpc/Makefile.inc delete mode 100644 lib/libthr/arch/powerpc/powerpc/pthread_md.c rename lib/libthr/{arch/sparc64/sparc64/pthread_md.c => thread/thr_ctrdtr.c} (98%) diff --git a/lib/libthr/Makefile b/lib/libthr/Makefile index 08d505254891..1acb17f04d3a 100644 --- a/lib/libthr/Makefile +++ b/lib/libthr/Makefile @@ -45,7 +45,9 @@ PRECIOUSLIB= .PATH: ${.CURDIR}/arch/${MACHINE_CPUARCH}/${MACHINE_CPUARCH} +.if exists(${.CURDIR}/arch/${MACHINE_CPUARCH}/Makefile.inc) .include "${.CURDIR}/arch/${MACHINE_CPUARCH}/Makefile.inc" +.endif .include "${.CURDIR}/sys/Makefile.inc" .include "${.CURDIR}/thread/Makefile.inc" diff --git a/lib/libthr/arch/amd64/Makefile.inc b/lib/libthr/arch/amd64/Makefile.inc index e6d99ec0f576..797618d4183a 100644 --- a/lib/libthr/arch/amd64/Makefile.inc +++ b/lib/libthr/arch/amd64/Makefile.inc @@ -1,3 +1,3 @@ #$FreeBSD$ -SRCS+= pthread_md.c _umtx_op_err.S +SRCS+= _umtx_op_err.S diff --git a/lib/libthr/arch/amd64/amd64/pthread_md.c b/lib/libthr/arch/amd64/amd64/pthread_md.c deleted file mode 100644 index b661657b44c2..000000000000 --- a/lib/libthr/arch/amd64/amd64/pthread_md.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2003 Daniel Eischen - * 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. Neither the name of the author 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include -#include - -#include "pthread_md.h" - -/* - * The constructors. - */ -struct tcb * -_tcb_ctor(struct pthread *thread, int initial) -{ - struct tcb *tcb; - - if (initial) - __asm __volatile("movq %%fs:0, %0" : "=r" (tcb)); - else - tcb = _rtld_allocate_tls(NULL, sizeof(struct tcb), 16); - if (tcb) - tcb->tcb_thread = thread; - return (tcb); -} - -void -_tcb_dtor(struct tcb *tcb) -{ - _rtld_free_tls(tcb, sizeof(struct tcb), 16); -} diff --git a/lib/libthr/arch/amd64/include/pthread_md.h b/lib/libthr/arch/amd64/include/pthread_md.h index 0ebea2e3bd24..e4a0dd2fe44c 100644 --- a/lib/libthr/arch/amd64/include/pthread_md.h +++ b/lib/libthr/arch/amd64/include/pthread_md.h @@ -77,9 +77,6 @@ struct tcb { __result; \ }) -struct tcb *_tcb_ctor(struct pthread *, int); -void _tcb_dtor(struct tcb *tcb); - static __inline void _tcb_set(struct tcb *tcb) { diff --git a/lib/libthr/arch/arm/Makefile.inc b/lib/libthr/arch/arm/Makefile.inc deleted file mode 100644 index 2ee224772e2b..000000000000 --- a/lib/libthr/arch/arm/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ -# $FreeBSD$ - -SRCS+= pthread_md.c diff --git a/lib/libthr/arch/arm/arm/pthread_md.c b/lib/libthr/arch/arm/arm/pthread_md.c deleted file mode 100644 index 028f06c17933..000000000000 --- a/lib/libthr/arch/arm/arm/pthread_md.c +++ /dev/null @@ -1,53 +0,0 @@ -/*- - * Copyright (C) 2005 David Xu - * 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. Neither the name of the author 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 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 "pthread_md.h" - -struct tcb * -_tcb_ctor(struct pthread *thread, int initial) -{ - struct tcb *tcb; - - tcb = _rtld_allocate_tls((initial) ? _tcb_get() : NULL, - sizeof(struct tcb), 16); - if (tcb) - tcb->tcb_thread = thread; - - return (tcb); -} - -void -_tcb_dtor(struct tcb *tcb) -{ - - _rtld_free_tls(tcb, sizeof(struct tcb), 16); -} diff --git a/lib/libthr/arch/arm/include/pthread_md.h b/lib/libthr/arch/arm/include/pthread_md.h index 3c3dd6dbea99..9a6b5233e515 100644 --- a/lib/libthr/arch/arm/include/pthread_md.h +++ b/lib/libthr/arch/arm/include/pthread_md.h @@ -47,12 +47,6 @@ struct tcb { struct pthread *tcb_thread; /* our hook */ }; -/* - * The tcb constructors. - */ -struct tcb *_tcb_ctor(struct pthread *, int); -void _tcb_dtor(struct tcb *); - /* Called from the thread to set its private data. */ static __inline void _tcb_set(struct tcb *tcb) diff --git a/lib/libthr/arch/i386/Makefile.inc b/lib/libthr/arch/i386/Makefile.inc index 01290d5ddac3..bdab0bc90fe6 100644 --- a/lib/libthr/arch/i386/Makefile.inc +++ b/lib/libthr/arch/i386/Makefile.inc @@ -1,3 +1,3 @@ # $FreeBSD$ -SRCS+= pthread_md.c _umtx_op_err.S +SRCS+= _umtx_op_err.S diff --git a/lib/libthr/arch/i386/i386/pthread_md.c b/lib/libthr/arch/i386/i386/pthread_md.c deleted file mode 100644 index a8b31d503ea7..000000000000 --- a/lib/libthr/arch/i386/i386/pthread_md.c +++ /dev/null @@ -1,57 +0,0 @@ -/*- - * Copyright (C) 2003 David Xu - * Copyright (c) 2001,2003 Daniel Eischen - * 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. Neither the name of the author 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 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 "pthread_md.h" - -struct tcb * -_tcb_ctor(struct pthread *thread, int initial) -{ - struct tcb *tcb; - - if (initial) - __asm __volatile("movl %%gs:0, %0" : "=r" (tcb)); - else - tcb = _rtld_allocate_tls(NULL, sizeof(struct tcb), 16); - if (tcb) - tcb->tcb_thread = thread; - return (tcb); -} - -void -_tcb_dtor(struct tcb *tcb) -{ - - _rtld_free_tls(tcb, sizeof(struct tcb), 16); -} diff --git a/lib/libthr/arch/i386/include/pthread_md.h b/lib/libthr/arch/i386/include/pthread_md.h index c160aa4fb4ad..ba7b75ceb2dc 100644 --- a/lib/libthr/arch/i386/include/pthread_md.h +++ b/lib/libthr/arch/i386/include/pthread_md.h @@ -76,12 +76,6 @@ struct tcb { __result; \ }) -/* - * The constructors. - */ -struct tcb *_tcb_ctor(struct pthread *, int); -void _tcb_dtor(struct tcb *tcb); - /* Called from the thread to set its private data. */ static __inline void _tcb_set(struct tcb *tcb) diff --git a/lib/libthr/arch/mips/Makefile.inc b/lib/libthr/arch/mips/Makefile.inc deleted file mode 100644 index 2ee224772e2b..000000000000 --- a/lib/libthr/arch/mips/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ -# $FreeBSD$ - -SRCS+= pthread_md.c diff --git a/lib/libthr/arch/mips/include/pthread_md.h b/lib/libthr/arch/mips/include/pthread_md.h index 19c9f38193dc..32af964c50a5 100644 --- a/lib/libthr/arch/mips/include/pthread_md.h +++ b/lib/libthr/arch/mips/include/pthread_md.h @@ -50,12 +50,6 @@ struct tcb { struct pthread *tcb_thread; }; -/* - * The tcb constructors. - */ -struct tcb *_tcb_ctor(struct pthread *, int); -void _tcb_dtor(struct tcb *); - /* Called from the thread to set its private data. */ static __inline void _tcb_set(struct tcb *tcb) diff --git a/lib/libthr/arch/mips/mips/pthread_md.c b/lib/libthr/arch/mips/mips/pthread_md.c deleted file mode 100644 index e596edc0e2ec..000000000000 --- a/lib/libthr/arch/mips/mips/pthread_md.c +++ /dev/null @@ -1,59 +0,0 @@ -/*- - * Copyright (C) 2005 David Xu - * 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. Neither the name of the author 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 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. - * - * from: src/lib/libthr/arch/arm/arm/pthread_md.c,v 1.2 2005/10/29 13:40:31 davidxu - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include - -#include - -#include "pthread_md.h" - -struct tcb * -_tcb_ctor(struct pthread *thread, int initial) -{ - struct tcb *tcb; - - tcb = _rtld_allocate_tls((initial) ? _tcb_get() : NULL, - sizeof(struct tcb), 16); - if (tcb) - tcb->tcb_thread = thread; - - return (tcb); -} - -void -_tcb_dtor(struct tcb *tcb) -{ - - _rtld_free_tls(tcb, sizeof(struct tcb), 16); -} diff --git a/lib/libthr/arch/powerpc/Makefile.inc b/lib/libthr/arch/powerpc/Makefile.inc deleted file mode 100644 index 2ee224772e2b..000000000000 --- a/lib/libthr/arch/powerpc/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ -# $FreeBSD$ - -SRCS+= pthread_md.c diff --git a/lib/libthr/arch/powerpc/include/pthread_md.h b/lib/libthr/arch/powerpc/include/pthread_md.h index 35632976a1b8..544ee1c5d5fc 100644 --- a/lib/libthr/arch/powerpc/include/pthread_md.h +++ b/lib/libthr/arch/powerpc/include/pthread_md.h @@ -55,9 +55,6 @@ struct tcb { struct pthread *tcb_thread; }; -struct tcb *_tcb_ctor(struct pthread *, int); -void _tcb_dtor(struct tcb *); - static __inline void _tcb_set(struct tcb *tcb) { diff --git a/lib/libthr/arch/powerpc/powerpc/pthread_md.c b/lib/libthr/arch/powerpc/powerpc/pthread_md.c deleted file mode 100644 index 66f043e294a7..000000000000 --- a/lib/libthr/arch/powerpc/powerpc/pthread_md.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2003 Daniel Eischen - * 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. Neither the name of the author 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include -#include - -#include "pthread_md.h" - -/* - * The constructors. - */ -struct tcb * -_tcb_ctor(struct pthread *thread, int initial) -{ - struct tcb *tcb; - - tcb = _rtld_allocate_tls((initial) ? _tcb_get() : NULL, - sizeof(struct tcb), 1); - if (tcb) - tcb->tcb_thread = thread; - return (tcb); - -} - -void -_tcb_dtor(struct tcb *tcb) -{ - _rtld_free_tls(tcb, sizeof(struct tcb), 1); -} diff --git a/lib/libthr/arch/sparc64/Makefile.inc b/lib/libthr/arch/sparc64/Makefile.inc index 88586b4840d2..bdab0bc90fe6 100644 --- a/lib/libthr/arch/sparc64/Makefile.inc +++ b/lib/libthr/arch/sparc64/Makefile.inc @@ -1,3 +1,3 @@ # $FreeBSD$ -SRCS+= _umtx_op_err.S pthread_md.c +SRCS+= _umtx_op_err.S diff --git a/lib/libthr/arch/sparc64/include/pthread_md.h b/lib/libthr/arch/sparc64/include/pthread_md.h index 7ee9654fd74a..35d8405b9d50 100644 --- a/lib/libthr/arch/sparc64/include/pthread_md.h +++ b/lib/libthr/arch/sparc64/include/pthread_md.h @@ -50,12 +50,6 @@ struct tcb { void *tcb_spare[1]; }; -/* - * The tcb constructors. - */ -struct tcb *_tcb_ctor(struct pthread *, int); -void _tcb_dtor(struct tcb *); - /* Called from the thread to set its private data. */ static __inline void _tcb_set(struct tcb *tcb) diff --git a/lib/libthr/thread/Makefile.inc b/lib/libthr/thread/Makefile.inc index ddde6e9180c2..1a7c63d14af9 100644 --- a/lib/libthr/thread/Makefile.inc +++ b/lib/libthr/thread/Makefile.inc @@ -14,6 +14,7 @@ SRCS+= \ thr_cond.c \ thr_condattr.c \ thr_create.c \ + thr_ctrdtr.c \ thr_detach.c \ thr_equal.c \ thr_event.c \ diff --git a/lib/libthr/arch/sparc64/sparc64/pthread_md.c b/lib/libthr/thread/thr_ctrdtr.c similarity index 98% rename from lib/libthr/arch/sparc64/sparc64/pthread_md.c rename to lib/libthr/thread/thr_ctrdtr.c index e1d439a8bad5..9d4301ef719f 100644 --- a/lib/libthr/arch/sparc64/sparc64/pthread_md.c +++ b/lib/libthr/thread/thr_ctrdtr.c @@ -32,7 +32,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include "pthread_md.h" +#include "thr_private.h" struct tcb * _tcb_ctor(struct pthread *thread, int initial) diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h index d62de98516d7..50be0596d13b 100644 --- a/lib/libthr/thread/thr_private.h +++ b/lib/libthr/thread/thr_private.h @@ -928,6 +928,9 @@ int __thr_sigwait(const sigset_t *set, int *sig); int __thr_sigwaitinfo(const sigset_t *set, siginfo_t *info); int __thr_swapcontext(ucontext_t *oucp, const ucontext_t *ucp); +struct tcb *_tcb_ctor(struct pthread *, int); +void _tcb_dtor(struct tcb *); + __END_DECLS #endif /* !_THR_PRIVATE_H */ From 68577bf3539672355648bd07058d38b648e0ee09 Mon Sep 17 00:00:00 2001 From: andrew Date: Wed, 21 Jan 2015 16:52:24 +0000 Subject: [PATCH 135/258] Update the parsing of the cpu node. We are unable to use the reg property as the cpu id on arm64 as it may use two cells. In it's place we can use the device id. It is expected we will use the reg data on arm64 to enable cores so we still need to read and store it even if it is not yet used. Differential Revision: https://reviews.freebsd.org/D1555 Reviewed by: nwhitehorn Sponsored by: The FreeBSD Foundation --- sys/dev/ofw/ofw_cpu.c | 48 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/sys/dev/ofw/ofw_cpu.c b/sys/dev/ofw/ofw_cpu.c index 02dc2b500554..0432560281a8 100644 --- a/sys/dev/ofw/ofw_cpu.c +++ b/sys/dev/ofw/ofw_cpu.c @@ -51,6 +51,10 @@ static const struct ofw_bus_devinfo *ofw_cpulist_get_devinfo(device_t dev, static MALLOC_DEFINE(M_OFWCPU, "ofwcpu", "OFW CPU device information"); +struct ofw_cpulist_softc { + pcell_t sc_addr_cells; +}; + static device_method_t ofw_cpulist_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ofw_cpulist_probe), @@ -74,7 +78,7 @@ static device_method_t ofw_cpulist_methods[] = { static driver_t ofw_cpulist_driver = { "cpulist", ofw_cpulist_methods, - 0 + sizeof(struct ofw_cpulist_softc) }; static devclass_t ofw_cpulist_devclass; @@ -100,12 +104,18 @@ ofw_cpulist_probe(device_t dev) static int ofw_cpulist_attach(device_t dev) { + struct ofw_cpulist_softc *sc; phandle_t root, child; device_t cdev; struct ofw_bus_devinfo *dinfo; + sc = device_get_softc(dev); root = ofw_bus_get_node(dev); + sc->sc_addr_cells = 1; + OF_getencprop(root, "#address-cells", &sc->sc_addr_cells, + sizeof(sc->sc_addr_cells)); + for (child = OF_child(root); child != 0; child = OF_peer(child)) { dinfo = malloc(sizeof(*dinfo), M_OFWCPU, M_WAITOK | M_ZERO); @@ -141,6 +151,8 @@ static int ofw_cpu_read_ivar(device_t dev, device_t child, int index, struct ofw_cpu_softc { struct pcpu *sc_cpu_pcpu; uint32_t sc_nominal_mhz; + boolean_t sc_reg_valid; + pcell_t sc_reg[2]; }; static device_method_t ofw_cpu_methods[] = { @@ -185,17 +197,39 @@ ofw_cpu_probe(device_t dev) static int ofw_cpu_attach(device_t dev) { + struct ofw_cpulist_softc *psc; struct ofw_cpu_softc *sc; phandle_t node; - uint32_t cell; + pcell_t cell; + int rv; sc = device_get_softc(dev); - node = ofw_bus_get_node(dev); - if (OF_getencprop(node, "reg", &cell, sizeof(cell)) < 0) { - cell = device_get_unit(dev); - device_printf(dev, "missing 'reg' property, using %u\n", cell); + psc = device_get_softc(device_get_parent(dev)); + + if (nitems(sc->sc_reg) < psc->sc_addr_cells) { + if (bootverbose) + device_printf(dev, "Too many address cells\n"); + return (EINVAL); } - sc->sc_cpu_pcpu = pcpu_find(cell); + + node = ofw_bus_get_node(dev); + + /* Read and validate the reg property for use later */ + sc->sc_reg_valid = false; + rv = OF_getencprop(node, "reg", sc->sc_reg, sizeof(sc->sc_reg)); + if (rv < 0) + device_printf(dev, "missing 'reg' property\n"); + else if ((rv % 4) != 0) { + if (bootverbose) + device_printf(dev, "Malformed reg property\n"); + } else if ((rv / 4) != psc->sc_addr_cells) { + if (bootverbose) + device_printf(dev, "Invalid reg size %u\n", rv); + } else + sc->sc_reg_valid = true; + + sc->sc_cpu_pcpu = pcpu_find(device_get_unit(dev)); + if (OF_getencprop(node, "clock-frequency", &cell, sizeof(cell)) < 0) { if (bootverbose) device_printf(dev, From 7cb7f93bfeba0e612f7c324a72f90c82b4781621 Mon Sep 17 00:00:00 2001 From: will Date: Wed, 21 Jan 2015 17:03:11 +0000 Subject: [PATCH 136/258] Add vfs.zfs.reference_tracking_enable sysctl/tunable. This is primarily for developer/debugging use; it enables built-in tagged tracking of refcounts inside ZFS. It can only be enabled from the loader, since it modifies how in-core state is managed. Default remains disabled. MFC after: 1 week Sponsored by: Spectra Logic --- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/refcount.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/refcount.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/refcount.c index 7e96e558ce57..ade681c1de8e 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/refcount.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/refcount.c @@ -30,6 +30,10 @@ #ifdef _KERNEL int reference_tracking_enable = FALSE; /* runs out of memory too easily */ +SYSCTL_DECL(_vfs_zfs); +SYSCTL_INT(_vfs_zfs, OID_AUTO, reference_tracking_enable, CTLFLAG_RDTUN, + &reference_tracking_enable, 0, + "Track reference holders to refcount_t objects, used mostly by ZFS"); #else int reference_tracking_enable = TRUE; #endif From 4b90cc79eee81c2c8350ef5dfecc1ea5892360e8 Mon Sep 17 00:00:00 2001 From: mjg Date: Wed, 21 Jan 2015 18:02:28 +0000 Subject: [PATCH 137/258] filedesc: fix whitespace nits in fget and fget_read No functional changes. --- sys/kern/kern_descrip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 4b4af296769a..2b2a53908ea6 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -2499,7 +2499,7 @@ int fget(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp) { - return(_fget(td, fd, fpp, 0, rightsp, NULL)); + return (_fget(td, fd, fpp, 0, rightsp, NULL)); } int @@ -2514,7 +2514,7 @@ int fget_read(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp) { - return(_fget(td, fd, fpp, FREAD, rightsp, NULL)); + return (_fget(td, fd, fpp, FREAD, rightsp, NULL)); } int From e15a87cc6afbdc8c09e8b31228795a62e99888c0 Mon Sep 17 00:00:00 2001 From: mjg Date: Wed, 21 Jan 2015 18:05:42 +0000 Subject: [PATCH 138/258] filedesc: return 0 from badfo_close The only potential in-tree consumer (_fdrop) special-cased it and returns 0 0 on its own instead of calling badfo_close. Remove the special case since it is not needed and very unlikely to encounter anyway. No objections from: kib --- sys/kern/kern_descrip.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 2b2a53908ea6..c88e55c2c388 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -2680,11 +2680,9 @@ _fdrop(struct file *fp, struct thread *td) { int error; - error = 0; if (fp->f_count != 0) panic("fdrop: count %d", fp->f_count); - if (fp->f_ops != &badfileops) - error = fo_close(fp, td); + error = fo_close(fp, td); atomic_subtract_int(&openfiles, 1); crfree(fp->f_cred); free(fp->f_advice, M_FADVISE); @@ -3664,7 +3662,7 @@ static int badfo_close(struct file *fp, struct thread *td) { - return (EBADF); + return (0); } static int From 9bc86796d313e438f3a218fdb300d416f6300f23 Mon Sep 17 00:00:00 2001 From: mjg Date: Wed, 21 Jan 2015 18:32:53 +0000 Subject: [PATCH 139/258] filedesc: avoid spurious copying of capabilities in fget_unlocked We obtain a stable copy and store it in local 'fde' variable. Storing another copy (based on aforementioned variable) does not serve any purpose. No functional changes. --- sys/kern/kern_descrip.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index c88e55c2c388..31352e9737e6 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -2337,7 +2337,7 @@ fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t *needrightsp, u_int count; #ifdef CAPABILITIES seq_t seq; - cap_rights_t haverights; + cap_rights_t *haverights; int error; #endif @@ -2367,9 +2367,9 @@ fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t *needrightsp, if (fp == NULL) return (EBADF); #ifdef CAPABILITIES - haverights = *cap_rights_fde(&fde); + haverights = cap_rights_fde(&fde); if (needrightsp != NULL) { - error = cap_check(&haverights, needrightsp); + error = cap_check(haverights, needrightsp); if (error != 0) return (error); if (cap_rights_is_set(needrightsp, CAP_FCNTL)) { @@ -2408,7 +2408,7 @@ fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t *needrightsp, *fpp = fp; if (haverightsp != NULL) { #ifdef CAPABILITIES - *haverightsp = haverights; + *haverightsp = *haverights; #else CAP_ALL(haverightsp); #endif From b56314b5da7669b2c2e1b0b0baf5e294a5e35eb4 Mon Sep 17 00:00:00 2001 From: emaste Date: Wed, 21 Jan 2015 19:04:55 +0000 Subject: [PATCH 140/258] Remove addr2line from cross elftoolchain tools list It is not required, and there is no reason to install it just because it came with the binutils cross tools. Sponsored by: The FreeBSD Foundation --- Makefile.inc1 | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile.inc1 b/Makefile.inc1 index 3d898c42be8e..984d240c6edb 100644 --- a/Makefile.inc1 +++ b/Makefile.inc1 @@ -1428,7 +1428,6 @@ _binutils= gnu/usr.bin/binutils .endif .if ${MK_ELFTOOLCHAIN_TOOLS} != "no" _elftctools= lib/libelftc \ - usr.bin/addr2line \ usr.bin/elfcopy \ usr.bin/nm \ usr.bin/size \ From cfd22197a35711b1807a4d462e503b6c92899204 Mon Sep 17 00:00:00 2001 From: nwhitehorn Date: Wed, 21 Jan 2015 19:07:45 +0000 Subject: [PATCH 141/258] Make 64-bit AIM trap handlers relocatable by changing all absolute branch instructions to call through pointers instead. In general, these are set implicitly through relocation processing. One has to be set explicitly in machdep.c, however, to fit one handler in the tiny (8 instruction) space available. Reviewed by: andreast Differential revision: D1554 Tested on: UP and SMP G5, Cell, POWER5+ --- sys/powerpc/aim/machdep.c | 3 +- sys/powerpc/aim/trap_subr64.S | 84 ++++++++++++++++++++++++++++------- sys/powerpc/include/trap.h | 3 +- 3 files changed, 72 insertions(+), 18 deletions(-) diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c index d0aac4c7f466..b463c48bee2d 100644 --- a/sys/powerpc/aim/machdep.c +++ b/sys/powerpc/aim/machdep.c @@ -238,7 +238,7 @@ extern void *trapcode64; #endif extern void *rstcode, *rstsize; -extern void *trapcode, *trapsize; +extern void *trapcode, *trapsize, *trapcode2; extern void *slbtrap, *slbtrapsize; extern void *alitrap, *alisize; extern void *dsitrap, *dsisize; @@ -506,6 +506,7 @@ powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp) generictrap = &trapcode; /* Set TOC base so that the interrupt code can get at it */ + *((void **)TRAP_GENTRAP) = &trapcode2; *((register_t *)TRAP_TOCBASE) = toc; #endif diff --git a/sys/powerpc/aim/trap_subr64.S b/sys/powerpc/aim/trap_subr64.S index 63ca50a4bfe3..a2d5bc5b1b40 100644 --- a/sys/powerpc/aim/trap_subr64.S +++ b/sys/powerpc/aim/trap_subr64.S @@ -302,8 +302,13 @@ CNAME(rstcode): insrdi %r9,%r8,1,0 mtmsrd %r9 isync + bl 1f + .llong cpu_reset +1: mflr %r9 + ld %r9,0(%r9) + mtlr %r9 - ba cpu_reset + blr CNAME(rstsize) = . - CNAME(rstcode) cpu_reset: @@ -342,16 +347,20 @@ cpu_reset: /* * This code gets copied to all the trap vectors - * (except ISI/DSI, ALI, and the interrupts) + * (except ISI/DSI, ALI, and the interrupts). Has to fit in 8 instructions! */ .globl CNAME(trapcode),CNAME(trapsize) + .p2align 3 CNAME(trapcode): mtsprg1 %r1 /* save SP */ mflr %r1 /* Save the old LR in r1 */ mtsprg2 %r1 /* And then in SPRG2 */ + li %r1,TRAP_GENTRAP + ld %r1,0(%r1) + mtlr %r1 li %r1, 0xA0 /* How to get the vector from LR */ - bla generictrap /* LR & SPRG3 is exception # */ + blrl /* Branch to generictrap */ CNAME(trapsize) = .-CNAME(trapcode) /* @@ -361,6 +370,7 @@ CNAME(trapsize) = .-CNAME(trapcode) * the only time this can be called. */ .globl CNAME(slbtrap),CNAME(slbtrapsize) + .p2align 3 CNAME(slbtrap): mtsprg1 %r1 /* save SP */ GET_CPUINFO(%r1) @@ -369,17 +379,31 @@ CNAME(slbtrap): std %r2,(PC_SLBSAVE+104)(%r1) mfsrr1 %r2 /* test kernel mode */ mtcr %r2 - bf 17,1f /* branch if PSL_PR is false */ + bf 17,2f /* branch if PSL_PR is false */ /* User mode */ ld %r2,(PC_SLBSAVE+104)(%r1) /* Restore CR */ mtcr %r2 ld %r2,(PC_SLBSAVE+16)(%r1) /* Restore R2 */ mflr %r1 /* Save the old LR in r1 */ mtsprg2 %r1 /* And then in SPRG2 */ + /* 52 bytes so far */ + bl 1f + .llong generictrap +1: mflr %r1 + ld %r1,0(%r1) + mtlr %r1 li %r1, 0x80 /* How to get the vector from LR */ - bla generictrap /* LR & SPRG3 is exception # */ -1: mflr %r2 /* Save the old LR in r2 */ - bla kern_slbtrap + blrl /* Branch to generictrap */ + /* 84 bytes */ +2: mflr %r2 /* Save the old LR in r2 */ + nop + bl 3f /* Begin dance to jump to kern_slbtrap*/ + .llong kern_slbtrap +3: mflr %r1 + ld %r1,0(%r1) + mtlr %r1 + GET_CPUINFO(%r1) + blrl /* 124 bytes -- 4 to spare */ CNAME(slbtrapsize) = .-CNAME(slbtrap) kern_slbtrap: @@ -518,6 +542,16 @@ CNAME(alitrap): mflr %r28 /* save LR */ mfcr %r29 /* save CR */ + /* Begin dance to branch to s_trap in a bit */ + b 1f + .p2align 3 +1: nop + bl 1f + .llong s_trap +1: mflr %r31 + ld %r31,0(%r31) + mtlr %r31 + /* Put our exception vector in SPRG3 */ li %r31, EXC_ALI mtsprg3 %r31 @@ -525,13 +559,12 @@ CNAME(alitrap): /* Test whether we already had PR set */ mfsrr1 %r31 mtcr %r31 - bla s_trap + blrl CNAME(alisize) = .-CNAME(alitrap) /* * Similar to the above for DSI - * Has to handle BAT spills - * and standard pagetable spills + * Has to handle standard pagetable spills */ .globl CNAME(dsitrap),CNAME(dsisize) CNAME(dsitrap): @@ -542,14 +575,18 @@ CNAME(dsitrap): std %r29,(PC_DISISAVE+CPUSAVE_R29)(%r1) std %r30,(PC_DISISAVE+CPUSAVE_R30)(%r1) std %r31,(PC_DISISAVE+CPUSAVE_R31)(%r1) - mfsprg1 %r1 /* restore SP */ mfcr %r29 /* save CR */ mfxer %r30 /* save XER */ mtsprg2 %r30 /* in SPRG2 */ mfsrr1 %r31 /* test kernel mode */ mtcr %r31 mflr %r28 /* save LR (SP already saved) */ - bla disitrap + bl 1f /* Begin branching to disitrap */ + .llong disitrap +1: mflr %r1 + ld %r1,0(%r1) + mtlr %r1 + blrl /* Branch to generictrap */ CNAME(dsisize) = .-CNAME(dsitrap) /* @@ -624,7 +661,7 @@ realtrap: bl restore_kernsrs /* enable kernel mapping */ mfsprg2 %r29 mr %r28,%r27 - ba s_trap + b s_trap /* * generictrap does some standard setup for trap handling to minimize @@ -636,6 +673,8 @@ realtrap: * SPRG2 - Original LR */ + .globl CNAME(trapcode2) +trapcode2: generictrap: /* Save R1 for computing the exception vector */ mtsprg3 %r1 @@ -657,6 +696,7 @@ generictrap: mfsprg3 %r31 ori %r31,%r31,0xff00 mflr %r30 + addi %r30,%r30,-4 /* The branch instruction, not the next */ and %r30,%r30,%r31 mtsprg3 %r30 @@ -804,9 +844,16 @@ CNAME(dblow): mfsprg2 %r29 /* ... and r29 */ mflr %r1 /* save LR */ mtsprg2 %r1 /* And then in SPRG2 */ - li %r1, 0 /* How to get the vector from LR */ - bla generictrap /* and we look like a generic trap */ + nop /* Begin branching to generictrap */ + bl 9f + .llong generictrap +9: mflr %r1 + ld %r1,0(%r1) + mtlr %r1 + li %r1, 0 /* How to get the vector from LR */ + blrl /* Branch to generictrap */ + 1: GET_CPUINFO(%r1) std %r27,(PC_DBSAVE+CPUSAVE_R27)(%r1) /* free r27 */ @@ -816,6 +863,11 @@ CNAME(dblow): std %r30,(PC_DBSAVE+CPUSAVE_R30)(%r1) /* free r30 */ std %r31,(PC_DBSAVE+CPUSAVE_R31)(%r1) /* free r31 */ mflr %r28 /* save LR */ - bla dbtrap + bl 9f /* Begin branch */ + .llong dbtrap +9: mflr %r1 + ld %r1,0(%r1) + mtlr %r1 + blrl /* Branch to generictrap */ CNAME(dbsize) = .-CNAME(dblow) #endif /* KDB */ diff --git a/sys/powerpc/include/trap.h b/sys/powerpc/include/trap.h index 3b1ade582e10..cd5ac188fd59 100644 --- a/sys/powerpc/include/trap.h +++ b/sys/powerpc/include/trap.h @@ -123,7 +123,8 @@ /* DTrace trap opcode. */ #define EXC_DTRACE 0x7c810808 -/* Magic pointer to store TOC base for trap handlers on ppc64 */ +/* Magic pointer to store TOC base and other info for trap handlers on ppc64 */ +#define TRAP_GENTRAP 0x1f0 #define TRAP_TOCBASE 0x1f8 #ifndef LOCORE From 6978841146a402d9acc3df8ce89744084f38a3e4 Mon Sep 17 00:00:00 2001 From: nwhitehorn Date: Wed, 21 Jan 2015 19:09:15 +0000 Subject: [PATCH 142/258] Make sure to relocate tmpstk with everything else and avoid processing non-relative relocations that the UART code makes for absent modules. --- sys/powerpc/aim/locore64.S | 8 ++++++-- sys/powerpc/powerpc/elf64_machdep.c | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/sys/powerpc/aim/locore64.S b/sys/powerpc/aim/locore64.S index abce9d83e5b6..e1fcd3ab050a 100644 --- a/sys/powerpc/aim/locore64.S +++ b/sys/powerpc/aim/locore64.S @@ -126,9 +126,14 @@ ASENTRY_NOPROF(__start) ld %r1,0(%r2) add %r2,%r1,%r2 + /* Get load offset */ + ld %r31,-0x8000(%r2) /* First TOC entry is TOC base */ + subf %r31,%r31,%r2 /* Subtract from real TOC base to get base */ + /* Set up the stack pointer */ ld %r1,TOC_REF(tmpstk)(%r2) addi %r1,%r1,TMPSTKSZ-96 + add %r1,%r1,%r31 /* Relocate kernel */ std %r3,48(%r1) @@ -140,8 +145,7 @@ ASENTRY_NOPROF(__start) 1: mflr %r3 ld %r4,0(%r3) add %r3,%r4,%r3 - ld %r4,-0x8000(%r2) /* First TOC entry is TOC base */ - subf %r4,%r4,%r2 /* Subtract from real TOC base to get base */ + mr %r4,%r31 bl elf_reloc_self nop ld %r3,48(%r1) diff --git a/sys/powerpc/powerpc/elf64_machdep.c b/sys/powerpc/powerpc/elf64_machdep.c index d23f7ffaa2ff..0b15ca3dea86 100644 --- a/sys/powerpc/powerpc/elf64_machdep.c +++ b/sys/powerpc/powerpc/elf64_machdep.c @@ -226,6 +226,8 @@ elf_reloc_self(Elf_Dyn *dynp, Elf_Addr relocbase) */ relalim = (Elf_Rela *)((caddr_t)rela + relasz); for (; rela < relalim; rela++) { + if (ELF_R_TYPE(rela->r_info) != R_PPC_RELATIVE) + continue; where = (Elf_Addr *)(relocbase + rela->r_offset); *where = (Elf_Addr)(relocbase + rela->r_addend); } From 67dd11691fe562a60913cd7107db2de9b75b97bb Mon Sep 17 00:00:00 2001 From: nwhitehorn Date: Wed, 21 Jan 2015 19:11:15 +0000 Subject: [PATCH 143/258] Add POWER7+ and POWER8 to the list of CPUs with 32 SLB slots. This is mostly a no-op since all currently-supported instances of these CPUs give the number of SLB slots in the device tree, but keep it here as well just in case. --- sys/powerpc/aim/machdep.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c index b463c48bee2d..82a72328d63e 100644 --- a/sys/powerpc/aim/machdep.c +++ b/sys/powerpc/aim/machdep.c @@ -394,6 +394,9 @@ powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp) break; #ifdef __powerpc64__ case IBMPOWER7: + case IBMPOWER7PLUS: + case IBMPOWER8: + case IBMPOWER8E: /* XXX: get from ibm,slb-size in device tree */ n_slbs = 32; break; From d9678db8e5fa468298a392aba202d02cc385c7b2 Mon Sep 17 00:00:00 2001 From: will Date: Wed, 21 Jan 2015 19:20:36 +0000 Subject: [PATCH 144/258] Eliminate an #ifdef illumos for zfs_ioc_rename(). Since allow_mounted is a FreeBSD-specific change, default to B_TRUE, then locally check for the magic bit. Unconditionally check allow_mounted below. Convert the setting of allow_mounted to an explicit boolean. MFC after: 1 week Sponsored by: Spectra Logic MFSpectraBSD: 672578 (in part) on 2013/07/19 --- .../opensolaris/uts/common/fs/zfs/zfs_ioctl.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c index 8801aa5abee3..a829b0698342 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c @@ -3751,10 +3751,12 @@ static int zfs_ioc_rename(zfs_cmd_t *zc) { boolean_t recursive = zc->zc_cookie & 1; -#ifdef __FreeBSD__ - boolean_t allow_mounted = zc->zc_cookie & 2; -#endif char *at; + boolean_t allow_mounted = B_TRUE; + +#ifdef __FreeBSD__ + allow_mounted = (zc->zc_cookie & 2) != 0; +#endif zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || @@ -3769,11 +3771,7 @@ zfs_ioc_rename(zfs_cmd_t *zc) if (strncmp(zc->zc_name, zc->zc_value, at - zc->zc_name + 1)) return (SET_ERROR(EXDEV)); *at = '\0'; -#ifdef illumos - if (zc->zc_objset_type == DMU_OST_ZFS) { -#else if (zc->zc_objset_type == DMU_OST_ZFS && allow_mounted) { -#endif error = dmu_objset_find(zc->zc_name, recursive_unmount, at + 1, recursive ? DS_FIND_CHILDREN : 0); From 23c5274c6bef2e473d8a03aaa52e797c3bb00a13 Mon Sep 17 00:00:00 2001 From: gonzo Date: Wed, 21 Jan 2015 19:23:46 +0000 Subject: [PATCH 145/258] Remove "#define DEBUG" that conflicts with "option DEBUG" in kernel config --- sys/arm/ti/ti_mbox.c | 1 - sys/arm/ti/ti_pruss.c | 1 - 2 files changed, 2 deletions(-) diff --git a/sys/arm/ti/ti_mbox.c b/sys/arm/ti/ti_mbox.c index 994b0a087834..3fb5c33e2246 100644 --- a/sys/arm/ti/ti_mbox.c +++ b/sys/arm/ti/ti_mbox.c @@ -54,7 +54,6 @@ __FBSDID("$FreeBSD$"); #include "mbox_if.h" -#define DEBUG #ifdef DEBUG #define DPRINTF(fmt, ...) do { \ printf("%s: ", __func__); \ diff --git a/sys/arm/ti/ti_pruss.c b/sys/arm/ti/ti_pruss.c index 55838d2d908c..03a76761b2be 100644 --- a/sys/arm/ti/ti_pruss.c +++ b/sys/arm/ti/ti_pruss.c @@ -52,7 +52,6 @@ __FBSDID("$FreeBSD$"); #include #include -#define DEBUG #ifdef DEBUG #define DPRINTF(fmt, ...) do { \ printf("%s: ", __func__); \ From dd05d56b153ed83b1532d3da556c658493fd080d Mon Sep 17 00:00:00 2001 From: will Date: Wed, 21 Jan 2015 19:25:57 +0000 Subject: [PATCH 146/258] Ignore sync requests from the system syncher, i.e. VFS_SYNC(waitfor=MNT_LAZY). ZFS already commits outstanding data every zfs_txg_timeout seconds, so these syncs are unnecessarily intrusive. Submitted by: gibbs Sponsored by: Spectra Logic MFSpectraBSD: 1105759 on 2014/12/11 --- .../contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c index 7b74145393b0..415db9edbe52 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c @@ -132,6 +132,13 @@ zfs_sync(vfs_t *vfsp, int waitfor) if (panicstr) return (0); + /* + * Ignore the system syncher. ZFS already commits async data + * at zfs_txg_timeout intervals. + */ + if (waitfor == MNT_LAZY) + return (0); + if (vfsp != NULL) { /* * Sync a specific filesystem. From ea98094037fba2498021d62e6df949587a444b26 Mon Sep 17 00:00:00 2001 From: will Date: Wed, 21 Jan 2015 19:30:01 +0000 Subject: [PATCH 147/258] Remove commented log messages. --- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zil.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zil.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zil.c index 2dcfe06dbff8..c558708b6dcc 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zil.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zil.c @@ -2090,7 +2090,6 @@ zil_replay(objset_t *os, void *arg, zil_replay_func_t *replay_func[TX_MAX_TYPE]) zil_destroy(zilog, B_TRUE); return; } - //printf("ZFS: Replaying ZIL on %s...\n", os->os->os_spa->spa_name); zr.zr_replay = replay_func; zr.zr_arg = arg; @@ -2112,7 +2111,6 @@ zil_replay(objset_t *os, void *arg, zil_replay_func_t *replay_func[TX_MAX_TYPE]) zil_destroy(zilog, B_FALSE); txg_wait_synced(zilog->zl_dmu_pool, zilog->zl_destroy_txg); zilog->zl_replay = B_FALSE; - //printf("ZFS: Replay of ZIL on %s finished.\n", os->os->os_spa->spa_name); } boolean_t From 2f2052508eb49e72875ddccb1c47d9ba35c00d32 Mon Sep 17 00:00:00 2001 From: will Date: Wed, 21 Jan 2015 19:53:52 +0000 Subject: [PATCH 148/258] Garbage collect dragonfly and legacy FreeBSD system support from dcons(4). Submitted by: gibbs MFC after: 1 week Sponsored by: Spectra Logic MFSpectraBSD: 1110990 on 2015/01/06 --- sys/dev/dcons/dcons.c | 4 +--- sys/dev/dcons/dcons_crom.c | 39 +++++--------------------------------- sys/dev/dcons/dcons_os.h | 1 - 3 files changed, 6 insertions(+), 38 deletions(-) diff --git a/sys/dev/dcons/dcons.c b/sys/dev/dcons/dcons.c index ace8f7e62c6f..da5183e15cd3 100644 --- a/sys/dev/dcons/dcons.c +++ b/sys/dev/dcons/dcons.c @@ -37,11 +37,9 @@ #include -#if defined(__DragonFly__) || defined(_BOOT) -#include "dcons.h" #if defined(_BOOT) +#include "dcons.h" #include "stand.h" -#endif #else #include #endif diff --git a/sys/dev/dcons/dcons_crom.c b/sys/dev/dcons/dcons_crom.c index ee263e95ac78..cb206752be9f 100644 --- a/sys/dev/dcons/dcons_crom.c +++ b/sys/dev/dcons/dcons_crom.c @@ -46,40 +46,25 @@ #include #include -#ifdef __DragonFly__ -#include -#include -#include -#include "dcons.h" -#include "dcons_os.h" -#else #include #include #include #include #include -#endif #include -#define EXPOSE_IDT_ADDR 1 - -#if (defined(__i386__) || defined(__amd64__)) && defined(EXPOSE_IDT_ADDR) +#if (defined(__i386__) || defined(__amd64__)) #include #include #include #include /* for idt */ #endif + static bus_addr_t dcons_paddr; -#if __FreeBSD_version >= 500000 static int force_console = 0; TUNABLE_INT("hw.firewire.dcons_crom.force_console", &force_console); -#endif - -#ifndef CSRVAL_VENDOR_PRIVATE -#define NEED_NEW_DRIVER -#endif #define ADDR_HI(x) (((x) >> 24) & 0xffffff) #define ADDR_LO(x) ((x) & 0xffffff) @@ -115,8 +100,7 @@ dcons_crom_probe(device_t dev) return (0); } -#ifndef NEED_NEW_DRIVER -#if (defined(__i386__) || defined(__amd64__)) && defined(EXPOSE_IDT_ADDR) +#if (defined(__i386__) || defined(__amd64__)) static void dcons_crom_expose_idt(struct dcons_crom_softc *sc) { @@ -129,6 +113,7 @@ dcons_crom_expose_idt(struct dcons_crom_softc *sc) crom_add_entry(&sc->unit, DCONS_CSR_KEY_RESET_LO, ADDR_LO(idt_paddr)); } #endif + static void dcons_crom_post_busreset(void *arg) { @@ -149,11 +134,10 @@ dcons_crom_post_busreset(void *arg) crom_add_simple_text(src, &sc->unit, &sc->ver, "dcons"); crom_add_entry(&sc->unit, DCONS_CSR_KEY_HI, ADDR_HI(dcons_paddr)); crom_add_entry(&sc->unit, DCONS_CSR_KEY_LO, ADDR_LO(dcons_paddr)); -#if (defined(__i386__) || defined(__amd64__)) && defined(EXPOSE_IDT_ADDR) +#if (defined(__i386__) || defined(__amd64__)) dcons_crom_expose_idt(sc); #endif } -#endif static void dmamap_cb(void *arg, bus_dma_segment_t *segments, int seg, int error) @@ -168,11 +152,7 @@ dmamap_cb(void *arg, bus_dma_segment_t *segments, int seg, int error) bus_dmamap_sync(sc->dma_tag, sc->dma_map, BUS_DMASYNC_PREWRITE); device_printf(sc->fd.dev, -#if __FreeBSD_version < 500000 - "bus_addr 0x%x\n", sc->bus_addr); -#else "bus_addr 0x%jx\n", (uintmax_t)sc->bus_addr); -#endif if (dcons_paddr != 0) { /* XXX */ device_printf(sc->fd.dev, "dcons_paddr is already set\n"); @@ -182,11 +162,9 @@ dmamap_cb(void *arg, bus_dma_segment_t *segments, int seg, int error) dcons_conf->dma_map = sc->dma_map; dcons_paddr = sc->bus_addr; -#if __FreeBSD_version >= 500000 /* Force to be the high-level console */ if (force_console) cnselect(dcons_conf->cdev); -#endif } static void @@ -200,10 +178,6 @@ dcons_crom_poll(void *p, int arg) static int dcons_crom_attach(device_t dev) { -#ifdef NEED_NEW_DRIVER - printf("dcons_crom: you need newer firewire driver\n"); - return (-1); -#else struct dcons_crom_softc *sc; int error; @@ -227,10 +201,8 @@ dcons_crom_attach(device_t dev) /*nsegments*/ 1, /*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT, /*flags*/ BUS_DMA_ALLOCNOW, -#if __FreeBSD_version >= 501102 /*lockfunc*/busdma_lock_mutex, /*lockarg*/&Giant, -#endif &sc->dma_tag); if (error != 0) return (error); @@ -245,7 +217,6 @@ dcons_crom_attach(device_t dev) sc->ehand = EVENTHANDLER_REGISTER(dcons_poll, dcons_crom_poll, (void *)sc, 0); return (0); -#endif } static int diff --git a/sys/dev/dcons/dcons_os.h b/sys/dev/dcons/dcons_os.h index 56a32c3e3eaa..bd6dfeff8009 100644 --- a/sys/dev/dcons/dcons_os.h +++ b/sys/dev/dcons/dcons_os.h @@ -34,7 +34,6 @@ * $FreeBSD$ */ - typedef void (*dcons_poll_fn)(void *, int); EVENTHANDLER_DECLARE(dcons_poll, dcons_poll_fn); From 142c5758be7e85f42da70b1a7ba5abf69b2ad24a Mon Sep 17 00:00:00 2001 From: will Date: Wed, 21 Jan 2015 19:59:09 +0000 Subject: [PATCH 149/258] Fix one cause of firewire panics. sys/dev/firewire/firewire.c: In fw_xfer_unload(), clear the FWXF_INQ flag on the xfer under protection of the FW_GMTX, after the xfer is removeed from the tx/rx queue. Otherwise it is possible for the xfer to be removed again (corrupting the list or immediately panicing) from another thread that has found this xfer in the transaction label table. Submitted by: gibbs MFC after: 1 week Sponsored by: Spectra Logic MFSpectraBSD: 1110200 on 2015/01/02 --- sys/dev/firewire/firewire.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/dev/firewire/firewire.c b/sys/dev/firewire/firewire.c index c5f5dbac1a7a..f06ac30cb183 100644 --- a/sys/dev/firewire/firewire.c +++ b/sys/dev/firewire/firewire.c @@ -1166,6 +1166,7 @@ fw_xfer_unload(struct fw_xfer *xfer) s = splfw(); FW_GLOCK(xfer->fc); STAILQ_REMOVE(&xfer->q->q, xfer, fw_xfer, link); + xfer->flag &= ~FWXF_INQ; #if 0 xfer->q->queued--; #endif From 0e8db589ba23f3b55a435fa0d58aeb82062f3ddc Mon Sep 17 00:00:00 2001 From: will Date: Wed, 21 Jan 2015 20:02:16 +0000 Subject: [PATCH 150/258] Fix a FWXF_INQ race in the firewire driver. sys/dev/firewire/firewire.c: In fw_xfer_unload() expand lock coverage so that the test for FWXF_INQ doesn't race with it being cleared in another thread. Submitted by: gibbs MFC after: 1 week Sponsored by: Spectra Logic MFSpectraBSD: 1110207 on 2015/01/02 --- sys/dev/firewire/firewire.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/sys/dev/firewire/firewire.c b/sys/dev/firewire/firewire.c index f06ac30cb183..6fff13299a14 100644 --- a/sys/dev/firewire/firewire.c +++ b/sys/dev/firewire/firewire.c @@ -1022,9 +1022,7 @@ static void fw_tl_free(struct firewire_comm *fc, struct fw_xfer *xfer) { struct fw_xfer *txfer; - int s; - s = splfw(); mtx_lock(&fc->tlabel_lock); if (xfer->tl < 0) { mtx_unlock(&fc->tlabel_lock); @@ -1042,14 +1040,12 @@ fw_tl_free(struct firewire_comm *fc, struct fw_xfer *xfer) fw_dump_hdr(&xfer->recv.hdr, "recv"); kdb_backtrace(); mtx_unlock(&fc->tlabel_lock); - splx(s); return; } STAILQ_REMOVE(&fc->tlabels[xfer->tl], xfer, fw_xfer, tlabel); xfer->tl = -1; mtx_unlock(&fc->tlabel_lock); - splx(s); return; } @@ -1157,22 +1153,18 @@ fw_xfer_done(struct fw_xfer *xfer) void fw_xfer_unload(struct fw_xfer *xfer) { - int s; if (xfer == NULL) return; + FW_GLOCK(xfer->fc); if (xfer->flag & FWXF_INQ) { - printf("fw_xfer_free FWXF_INQ\n"); - s = splfw(); - FW_GLOCK(xfer->fc); STAILQ_REMOVE(&xfer->q->q, xfer, fw_xfer, link); xfer->flag &= ~FWXF_INQ; #if 0 xfer->q->queued--; #endif - FW_GUNLOCK(xfer->fc); - splx(s); } + FW_GUNLOCK(xfer->fc); if (xfer->fc != NULL) { /* * Ensure that any tlabel owner can't access this From 9993d8d7e300e6efe491cf91a34811e7911a325a Mon Sep 17 00:00:00 2001 From: will Date: Wed, 21 Jan 2015 20:03:46 +0000 Subject: [PATCH 151/258] Fix panic in firewire and creation of invalid config ROM. sys/boot/i386/libfirewire/firewire.c: sys/dev/firewire/firewire.c: Fix configuration ROM generation count wrapping logic so that the generation count is never outside of allowed limits (0x2 -> 0xF). sys/dev/firewire/firewire.c: In fw_xfer_unload(), xfer->fc may be NULL. Protect against this before taking the fc lock. Submitted by: gibbs MFC after: 1 week Sponsored by: Spectra Logic MFSpectraBSD: 1110685 on 2015/01/05 --- sys/dev/firewire/firewire.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/sys/dev/firewire/firewire.c b/sys/dev/firewire/firewire.c index 6fff13299a14..026bd056d40f 100644 --- a/sys/dev/firewire/firewire.c +++ b/sys/dev/firewire/firewire.c @@ -761,8 +761,15 @@ fw_busreset(struct firewire_comm *fc, uint32_t new_status) src = &fc->crom_src_buf->src; crom_load(src, newrom, CROMSIZE); if (bcmp(newrom, fc->config_rom, CROMSIZE) != 0) { - if (src->businfo.generation++ > FW_MAX_GENERATION) + /* Bump generation and reload. */ + src->businfo.generation++; + + /* Handle generation count wraps. */ + if (src->businfo.generation < FW_GENERATION_CHANGEABLE) src->businfo.generation = FW_GENERATION_CHANGEABLE; + + /* Recalculate CRC to account for generation change. */ + crom_load(src, newrom, CROMSIZE); bcopy(newrom, fc->config_rom, CROMSIZE); } free(newrom, M_FW); @@ -1156,16 +1163,18 @@ fw_xfer_unload(struct fw_xfer *xfer) if (xfer == NULL) return; - FW_GLOCK(xfer->fc); - if (xfer->flag & FWXF_INQ) { - STAILQ_REMOVE(&xfer->q->q, xfer, fw_xfer, link); - xfer->flag &= ~FWXF_INQ; -#if 0 - xfer->q->queued--; -#endif - } - FW_GUNLOCK(xfer->fc); + if (xfer->fc != NULL) { + FW_GLOCK(xfer->fc); + if (xfer->flag & FWXF_INQ) { + STAILQ_REMOVE(&xfer->q->q, xfer, fw_xfer, link); + xfer->flag &= ~FWXF_INQ; + #if 0 + xfer->q->queued--; + #endif + } + FW_GUNLOCK(xfer->fc); + /* * Ensure that any tlabel owner can't access this * xfer after it's freed. From c3bc74cd91d12d1e58248127e67e9431b4a12d59 Mon Sep 17 00:00:00 2001 From: will Date: Wed, 21 Jan 2015 20:05:10 +0000 Subject: [PATCH 152/258] Properly lock accesss to the firewire_comm->devices list. sys/dev/firewire/firewire.c: Add missing FW_GLOCK/UNLOCK() usage to fw_noderesolve_nodeid(). sys/dev/firewire/firewire.c: sys/dev/firewire/fwmem.c: Remove no-op splfw() calls from functions that have been audited for proper lock usage. Submitted by: gibbs MFC after: 1 week Sponsored by: Spectra Logic MFSpectraBSD: 1110992 on 2015/01/06 --- sys/dev/firewire/firewire.c | 18 +++++------------- sys/dev/firewire/fwmem.c | 4 +--- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/sys/dev/firewire/firewire.c b/sys/dev/firewire/firewire.c index 026bd056d40f..976be69e721d 100644 --- a/sys/dev/firewire/firewire.c +++ b/sys/dev/firewire/firewire.c @@ -146,13 +146,12 @@ struct fw_device * fw_noderesolve_nodeid(struct firewire_comm *fc, int dst) { struct fw_device *fwdev; - int s; - s = splfw(); + FW_GLOCK(fc); STAILQ_FOREACH(fwdev, &fc->devices, link) if (fwdev->dst == dst && fwdev->status != FWDEVINVAL) break; - splx(s); + FW_GUNLOCK(fc); return fwdev; } @@ -164,15 +163,12 @@ struct fw_device * fw_noderesolve_eui64(struct firewire_comm *fc, struct fw_eui64 *eui) { struct fw_device *fwdev; - int s; - s = splfw(); FW_GLOCK(fc); STAILQ_FOREACH(fwdev, &fc->devices, link) if (FW_EUI64_EQUAL(fwdev->eui, *eui)) break; FW_GUNLOCK(fc); - splx(s); if (fwdev == NULL) return NULL; @@ -301,9 +297,7 @@ static void fw_asystart(struct fw_xfer *xfer) { struct firewire_comm *fc = xfer->fc; - int s; - s = splfw(); /* Protect from interrupt/timeout */ FW_GLOCK(fc); xfer->flag = FWXF_INQ; @@ -312,7 +306,6 @@ fw_asystart(struct fw_xfer *xfer) xfer->q->queued++; #endif FW_GUNLOCK(fc); - splx(s); /* XXX just queue for mbuf */ if (xfer->mbuf == NULL) xfer->q->start(fc); @@ -332,6 +325,7 @@ firewire_probe(device_t dev) return (0); } +/* Just use a per-packet callout? */ static void firewire_xfer_timeout(void *arg, int pending) { @@ -340,7 +334,7 @@ firewire_xfer_timeout(void *arg, int pending) struct timeval tv; struct timeval split_timeout; STAILQ_HEAD(, fw_xfer) xfer_timeout; - int i, s; + int i; split_timeout.tv_sec = 0; split_timeout.tv_usec = 200 * 1000; /* 200 msec */ @@ -349,9 +343,8 @@ firewire_xfer_timeout(void *arg, int pending) timevalsub(&tv, &split_timeout); STAILQ_INIT(&xfer_timeout); - s = splfw(); mtx_lock(&fc->tlabel_lock); - for (i = 0; i < 0x40; i++) { + for (i = 0; i < nitems(fc->tlabels); i++) { while ((xfer = STAILQ_FIRST(&fc->tlabels[i])) != NULL) { if ((xfer->flag & FWXF_SENT) == 0) /* not sent yet */ @@ -370,7 +363,6 @@ firewire_xfer_timeout(void *arg, int pending) } } mtx_unlock(&fc->tlabel_lock); - splx(s); fc->timeout(fc); STAILQ_FOREACH_SAFE(xfer, &xfer_timeout, tlabel, txfer) diff --git a/sys/dev/firewire/fwmem.c b/sys/dev/firewire/fwmem.c index 182fc8aba51a..6498daa480ab 100644 --- a/sys/dev/firewire/fwmem.c +++ b/sys/dev/firewire/fwmem.c @@ -348,12 +348,11 @@ fwmem_strategy(struct bio *bp) struct fw_device *fwdev; struct fw_xfer *xfer; struct cdev *dev; - int err = 0, s, iolen; + int err = 0, iolen; dev = bp->bio_dev; /* XXX check request length */ - s = splfw(); fms = dev->si_drv1; fwdev = fw_noderesolve_eui64(fms->sc->fc, &fms->eui); if (fwdev == NULL) { @@ -395,7 +394,6 @@ fwmem_strategy(struct bio *bp) /* XXX */ bp->bio_resid = bp->bio_bcount - iolen; error: - splx(s); if (err != 0) { if (fwmem_debug) printf("%s: err=%d\n", __func__, err); From 639d7a6139b5b93a3ebe6d511f9b552c2d7c74c6 Mon Sep 17 00:00:00 2001 From: will Date: Wed, 21 Jan 2015 20:06:25 +0000 Subject: [PATCH 153/258] Fix firewire panic when issuing a reply to an unhandled asynchronous remote dma request (DMA request that the hardware cannot automatically handle). sys/dev/firewire/firewire.c In fw_rcv(), add missing early return in the error path for DMA requests to unregistered regions. Submitted by: gibbs MFC after: 1 week Sponsored by: Spectra Logic MFSpectraBSD: 1110993 on 2015/01/06 --- sys/dev/firewire/firewire.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/dev/firewire/firewire.c b/sys/dev/firewire/firewire.c index 976be69e721d..72341887f46a 100644 --- a/sys/dev/firewire/firewire.c +++ b/sys/dev/firewire/firewire.c @@ -2030,6 +2030,7 @@ fw_rcv(struct fw_rcv_buf *rb) rb->xfer->hand = fw_xfer_free; if (fw_asyreq(rb->fc, -1, rb->xfer)) fw_xfer_free(rb->xfer); + return; } len = 0; for (i = 0; i < rb->nvec; i++) From 1aa07d7ef4d11520677c3c977e2aa320b3ef74b2 Mon Sep 17 00:00:00 2001 From: will Date: Wed, 21 Jan 2015 20:08:24 +0000 Subject: [PATCH 154/258] Fix remote DMA based firewire debugging when targeting systems with more than 4GB of physical memory. To remotely debug the system 'stealthy' which has a kernel with this change installed and firewire properly configured: % fwcontrol -m stealthy (or stealthy's firewire EUI64) % kgdb kernel /dev/fwmem0.0 sys/dev/firewire/fwohci.c: Rather than hard code the upper limit for hw based automatic responses to remote DMA requests at 4GB, program the hardware using Maxmem, the page number one higher than the highest physical page detected in the system. While here, garbage collect more useless splfw() calls. Submitted by: gibbs MFC after: 1 week Sponsored by: Spectra Logic MFSpectraBSD: 1110994 on 2015/01/06 --- sys/dev/firewire/fwohci.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/sys/dev/firewire/fwohci.c b/sys/dev/firewire/fwohci.c index 00a54e28da6d..70134af686e6 100644 --- a/sys/dev/firewire/fwohci.c +++ b/sys/dev/firewire/fwohci.c @@ -48,6 +48,7 @@ #include #include +#include #include #include @@ -188,6 +189,7 @@ static void fwohci_task_dma(void *, int); #define OHCI_PREQLO 0x118 #define OHCI_PREQLOCLR 0x11c #define OHCI_PREQUPPER 0x120 +#define OHCI_PREQUPPER_MAX 0xffff0000 #define OHCI_SID_BUF 0x64 #define OHCI_SID_CNT 0x68 @@ -854,7 +856,7 @@ fwohci_execute_db2(void *arg, bus_dma_segment_t *segs, int nseg, static void fwohci_start(struct fwohci_softc *sc, struct fwohci_dbch *dbch) { - int i, s; + int i; int tcode, hdr_len, pl_off; int fsegment = -1; uint32_t off; @@ -880,7 +882,6 @@ fwohci_start(struct fwohci_softc *sc, struct fwohci_dbch *dbch) if (dbch->flags & FWOHCI_DBCH_FULL) return; - s = splfw(); db_tr = dbch->top; txloop: xfer = STAILQ_FIRST(&dbch->xferq.q); @@ -1030,7 +1031,6 @@ fwohci_start(struct fwohci_softc *sc, struct fwohci_dbch *dbch) } dbch->top = db_tr; - splx(s); return; } @@ -1821,6 +1821,7 @@ static void fwohci_intr_core(struct fwohci_softc *sc, uint32_t stat, int count) { struct firewire_comm *fc = (struct firewire_comm *)sc; + uintmax_t prequpper; uint32_t node_id, plen; FW_GLOCK_ASSERT(fc); @@ -1852,8 +1853,17 @@ fwohci_intr_core(struct fwohci_softc *sc, uint32_t stat, int count) /* allow from all nodes */ OWRITE(sc, OHCI_PREQHI, 0x7fffffff); OWRITE(sc, OHCI_PREQLO, 0xffffffff); - /* 0 to 4GB region */ - OWRITE(sc, OHCI_PREQUPPER, 0x10000); + prequpper = ((uintmax_t)Maxmem << PAGE_SHIFT) >> 16; + if (prequpper > OHCI_PREQUPPER_MAX) { + device_printf(fc->dev, + "Physical memory size of 0x%jx exceeds " + "fire wire address space. Limiting dma " + "to memory below 0x%jx\n", + (uintmax_t)Maxmem << PAGE_SHIFT, + (uintmax_t)OHCI_PREQUPPER_MAX << 16); + prequpper = OHCI_PREQUPPER_MAX; + } + OWRITE(sc, OHCI_PREQUPPER, prequpper & 0xffffffff); } /* Set ATRetries register */ OWRITE(sc, OHCI_ATRETRY, 1<<(13 + 16) | 0xfff); @@ -2171,7 +2181,7 @@ fwohci_rbuf_update(struct fwohci_softc *sc, int dmach) struct fw_bulkxfer *chunk; struct fw_xferq *ir; uint32_t stat; - int s, w = 0, ldesc; + int w = 0, ldesc; ir = fc->ir[dmach]; ldesc = sc->ir[dmach].ndesc - 1; @@ -2179,7 +2189,6 @@ fwohci_rbuf_update(struct fwohci_softc *sc, int dmach) #if 0 dump_db(sc, dmach); #endif - s = splfw(); if ((ir->flag & FWXFERQ_HANDLER) == 0) FW_GLOCK(fc); fwdma_sync_multiseg_all(sc->ir[dmach].am, BUS_DMASYNC_POSTREAD); @@ -2218,7 +2227,6 @@ fwohci_rbuf_update(struct fwohci_softc *sc, int dmach) } if ((ir->flag & FWXFERQ_HANDLER) == 0) FW_GUNLOCK(fc); - splx(s); if (w == 0) return; From 33d628394687484eff2dda36b8e3c59075e589c8 Mon Sep 17 00:00:00 2001 From: ian Date: Wed, 21 Jan 2015 20:12:35 +0000 Subject: [PATCH 155/258] Micro-optimize the new arm inline bus_space implementation by grouping all the data the inline functions access together at the start of the bus_space struct. The start-of part isn't so important, it's the grouping-together that's the point: now all the most-accessed data should be in one cache line. Suggested by: cognet --- sys/arm/arm/bus_space_base.c | 2 +- sys/arm/include/bus.h | 37 +++++++++++++++++++++--------------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/sys/arm/arm/bus_space_base.c b/sys/arm/arm/bus_space_base.c index a80b06466cc9..ba138d59e00b 100644 --- a/sys/arm/arm/bus_space_base.c +++ b/sys/arm/arm/bus_space_base.c @@ -150,7 +150,7 @@ static struct bus_space arm_base_bus_space = { .bs_wr_2_s = generic_bs_wr_2, .bs_wr_4_s = generic_bs_wr_4, .bs_wr_8_s = BS_UNIMPLEMENTED, -}; +} __aligned(CACHE_LINE_SIZE); #ifdef FDT bus_space_tag_t fdtbus_bs_tag = &arm_base_bus_space; diff --git a/sys/arm/include/bus.h b/sys/arm/include/bus.h index 757919974a1f..ed9d317cd0a8 100644 --- a/sys/arm/include/bus.h +++ b/sys/arm/include/bus.h @@ -79,9 +79,27 @@ #define BUS_SPACE_MAP_LINEAR 0x02 #define BUS_SPACE_MAP_PREFETCHABLE 0x04 +/* + * Bus space for ARM. + * + * The functions used most often are grouped together at the beginning to ensure + * that all the data fits into a single cache line. The inline implementations + * of single read/write access these values a lot. + */ struct bus_space { - /* cookie */ - void *bs_privdata; + /* Read/write single and barrier: the most commonly used functions. */ + uint8_t (*bs_r_1)(bus_space_tag_t, bus_space_handle_t, bus_size_t); + uint32_t (*bs_r_4)(bus_space_tag_t, bus_space_handle_t, bus_size_t); + void (*bs_w_1)(bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint8_t); + void (*bs_w_4)(bus_space_tag_t, bus_space_handle_t, + bus_size_t, uint32_t); + void (*bs_barrier)(bus_space_tag_t, bus_space_handle_t, + bus_size_t, bus_size_t, int); + + /* Backlink to parent (if copied), and implementation private data. */ + struct bus_space *bs_parent; + void *bs_privdata; /* mapping/unmapping */ int (*bs_map) (bus_space_tag_t, bus_addr_t, bus_size_t, @@ -97,15 +115,8 @@ struct bus_space { void (*bs_free) (bus_space_tag_t, bus_space_handle_t, bus_size_t); - /* get kernel virtual address */ - /* barrier */ - void (*bs_barrier) (bus_space_tag_t, bus_space_handle_t, - bus_size_t, bus_size_t, int); - - /* read (single) */ - uint8_t (*bs_r_1) (bus_space_tag_t, bus_space_handle_t, bus_size_t); + /* Read single, the less commonly used functions. */ uint16_t (*bs_r_2) (bus_space_tag_t, bus_space_handle_t, bus_size_t); - uint32_t (*bs_r_4) (bus_space_tag_t, bus_space_handle_t, bus_size_t); uint64_t (*bs_r_8) (bus_space_tag_t, bus_space_handle_t, bus_size_t); /* read multiple */ @@ -128,13 +139,9 @@ struct bus_space { void (*bs_rr_8) (bus_space_tag_t, bus_space_handle_t, bus_size_t, uint64_t *, bus_size_t); - /* write (single) */ - void (*bs_w_1) (bus_space_tag_t, bus_space_handle_t, - bus_size_t, uint8_t); + /* Write single, the less commonly used functions. */ void (*bs_w_2) (bus_space_tag_t, bus_space_handle_t, bus_size_t, uint16_t); - void (*bs_w_4) (bus_space_tag_t, bus_space_handle_t, - bus_size_t, uint32_t); void (*bs_w_8) (bus_space_tag_t, bus_space_handle_t, bus_size_t, uint64_t); From fefa30c5dbcbd7c700a50eb7ca682664b42aec80 Mon Sep 17 00:00:00 2001 From: will Date: Wed, 21 Jan 2015 20:22:53 +0000 Subject: [PATCH 156/258] Change 1112791 by kenm@ken.spectrabsd8 on 2015/01/15 16:45:13 Fix SCSI status byte reporting on 4Gb and 8Gb Qlogic boards. The newer boards don't have the response field that indicates whether the SCSI status byte is present. You have to just look to see whether it is non-zero. The code was looking to see whether the sense length was valid before propagating the SCSI status byte (and sense information) up the stack. With a status like Reservation Conflict, there is no sense information, only the SCSI status byte. So it wasn't getting correctly returned. isp.c: In isp_intr(), if we are on a 2400 or 2500 type board and get a response, look at the actual contents of the SCSI status value and set the RQSF_GOT_STATUS flag accordingly so that return any SCSI status value we get. The RQSF_GOT_SENSE flag will get set later on if there is actual sense information returned. Submitted by: ken MFC after: 1 week Sponsored by: Spectra Logic MFSpectraBSD: 1112791 on 2015/01/15 --- sys/dev/isp/isp_freebsd.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sys/dev/isp/isp_freebsd.c b/sys/dev/isp/isp_freebsd.c index f9f3ed9cb69d..11658157ea9f 100644 --- a/sys/dev/isp/isp_freebsd.c +++ b/sys/dev/isp/isp_freebsd.c @@ -5123,19 +5123,34 @@ isp_action(struct cam_sim *sim, union ccb *ccb) break; #endif case XPT_RESET_DEV: /* BDR the specified SCSI device */ + { + struct isp_fc *fc; bus = cam_sim_bus(xpt_path_sim(ccb->ccb_h.path)); tgt = ccb->ccb_h.target_id; tgt |= (bus << 16); + if (IS_FC(isp)) + fc = ISP_FC_PC(isp, bus); + else + fc = NULL; error = isp_control(isp, ISPCTL_RESET_DEV, bus, tgt); if (error) { ccb->ccb_h.status = CAM_REQ_CMP_ERR; } else { + /* + * If we have a FC device, reset the Command + * Reference Number, because the target will expect + * that we re-start the CRN at 1 after a reset. + */ + if (fc != NULL) + isp_fcp_reset_crn(fc, tgt, /*tgt_set*/ 1); + ccb->ccb_h.status = CAM_REQ_CMP; } xpt_done(ccb); break; + } case XPT_ABORT: /* Abort the specified CCB */ { union ccb *accb = ccb->cab.abort_ccb; From b77b87e076a01677955871c5485bc47b733b4a72 Mon Sep 17 00:00:00 2001 From: will Date: Wed, 21 Jan 2015 20:27:11 +0000 Subject: [PATCH 157/258] Force commit to record the correct log for r277513. If the user sends an XPT_RESET_DEV CCB, make sure to reset the Fibre Channel Command Reference Number if we're running on a FC controller. We send a SCSI Target Reset when we get this CCB, and as a result need to reset the CRN to 1 on the next command. isp_freebsd.c: In the XPT_RESET_DEV implementation in isp_action(), reset the CRN if we're on a FC controller. Submitted by: ken MFC after: 1 week Sponsored by: Spectra Logic MFSpectraBSD: 1112787 on 2015/01/15 --- sys/dev/isp/isp_freebsd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/dev/isp/isp_freebsd.c b/sys/dev/isp/isp_freebsd.c index 11658157ea9f..881f58aa0d94 100644 --- a/sys/dev/isp/isp_freebsd.c +++ b/sys/dev/isp/isp_freebsd.c @@ -29,6 +29,7 @@ */ #include __FBSDID("$FreeBSD$"); + #include #include #include From 9703165a13dd302a045e0d2770fc8b812b5282e4 Mon Sep 17 00:00:00 2001 From: will Date: Wed, 21 Jan 2015 20:32:36 +0000 Subject: [PATCH 158/258] Fix SCSI status byte reporting on 4Gb and 8Gb Qlogic boards. The newer boards don't have the response field that indicates whether the SCSI status byte is present. You have to just look to see whether it is non-zero. The code was looking to see whether the sense length was valid before propagating the SCSI status byte (and sense information) up the stack. With a status like Reservation Conflict, there is no sense information, only the SCSI status byte. So it wasn't getting correctly returned. isp.c: In isp_intr(), if we are on a 2400 or 2500 type board and get a response, look at the actual contents of the SCSI status value and set the RQSF_GOT_STATUS flag accordingly so that return any SCSI status value we get. The RQSF_GOT_SENSE flag will get set later on if there is actual sense information returned. Submitted by: ken MFC after: 1 week Sponsored by: Spectra Logic MFSpectraBSD: 1112791 on 2015/01/15 --- sys/dev/isp/isp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c index 46361b95e482..dce666b23b35 100644 --- a/sys/dev/isp/isp.c +++ b/sys/dev/isp/isp.c @@ -5224,7 +5224,10 @@ isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) } scsi_status = sp2->req_scsi_status; completion_status = sp2->req_completion_status; - req_state_flags = 0; + if ((scsi_status & 0xff) != 0) + req_state_flags = RQSF_GOT_STATUS; + else + req_state_flags = 0; resid = sp2->req_resid; } else if (etype == RQSTYPE_RESPONSE) { isp_get_response(isp, (ispstatusreq_t *) hp, sp); From 9031260de2e471f261db6de4e913579f0e593791 Mon Sep 17 00:00:00 2001 From: ian Date: Wed, 21 Jan 2015 21:31:26 +0000 Subject: [PATCH 159/258] Move the __aligned() declaration to where it will actually do something. --- sys/arm/arm/bus_space_base.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/arm/arm/bus_space_base.c b/sys/arm/arm/bus_space_base.c index ba138d59e00b..4e4f33ce35ab 100644 --- a/sys/arm/arm/bus_space_base.c +++ b/sys/arm/arm/bus_space_base.c @@ -45,7 +45,7 @@ bs_protos(generic); * The bus space tag. This is constant for all instances, so * we never have to explicitly "create" it. */ -static struct bus_space arm_base_bus_space = { +static struct bus_space arm_base_bus_space __aligned(CACHE_LINE_SIZE) = { /* privdata is whatever the implementer wants; unused in base tag */ .bs_privdata = NULL, @@ -150,7 +150,7 @@ static struct bus_space arm_base_bus_space = { .bs_wr_2_s = generic_bs_wr_2, .bs_wr_4_s = generic_bs_wr_4, .bs_wr_8_s = BS_UNIMPLEMENTED, -} __aligned(CACHE_LINE_SIZE); +}; #ifdef FDT bus_space_tag_t fdtbus_bs_tag = &arm_base_bus_space; From 80662b88d827b4048bf8b999a9c4efb9d0127d14 Mon Sep 17 00:00:00 2001 From: emaste Date: Wed, 21 Jan 2015 21:49:03 +0000 Subject: [PATCH 160/258] Fix bootstrap on systems with old libdwarf and WITHOUT_CDDL ELF Tool Chain tools need libelf and libdwarf. Submitted by: jmallett (earlier version) Reviewed by: jmallett Sponsored by: The FreeBSD Foundation --- Makefile.inc1 | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Makefile.inc1 b/Makefile.inc1 index 984d240c6edb..afa49408e688 100644 --- a/Makefile.inc1 +++ b/Makefile.inc1 @@ -1292,12 +1292,16 @@ _clang_tblgen= \ usr.bin/clang/clang-tblgen .endif +# ELF Tool Chain libraries are needed for ELF tools and dtrace tools. # dtrace tools are required for older bootstrap env and cross-build # pre libdwarf -.if ${MK_CDDL} != "no" && (${BOOTSTRAPPING} < 1100006 \ - || (${MACHINE} != ${TARGET} || ${MACHINE_ARCH} != ${TARGET_ARCH})) -_dtrace_tools= cddl/usr.bin/sgsmsg cddl/lib/libctf lib/libelf \ - lib/libdwarf cddl/usr.bin/ctfconvert cddl/usr.bin/ctfmerge +.if ${BOOTSTRAPPING} < 1100006 || (${MACHINE} != ${TARGET} || \ + ${MACHINE_ARCH} != ${TARGET_ARCH}) +_elftoolchain_libs= lib/libelf lib/libdwarf +.if ${MK_CDDL} != "no" +_dtrace_tools= cddl/usr.bin/sgsmsg cddl/lib/libctf cddl/usr.bin/ctfconvert \ + cddl/usr.bin/ctfmerge +.endif .endif # Default to building the GPL DTC, but build the BSDL one if users explicitly @@ -1324,6 +1328,7 @@ bootstrap-tools: .MAKE .for _tool in \ ${_clang_tblgen} \ ${_kerberos5_bootstrap_tools} \ + ${_elftoolchain_libs} \ ${_dtrace_tools} \ ${_strfile} \ ${_gperf} \ From 2ed64417f268a191aaa926a0ad9e55fcec29c2a7 Mon Sep 17 00:00:00 2001 From: will Date: Thu, 22 Jan 2015 00:52:34 +0000 Subject: [PATCH 161/258] Enable nanobsd.sh to be executed when pwd != NANO_SRC. While here, fix a bug in which NANO_PMAKE would not be appended at the appropriate time. Simply move both checks to after the call to set_defaults_and_export(). Tested by: lstewart Sponsored by: Spectra Logic --- tools/tools/nanobsd/nanobsd.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) mode change 100644 => 100755 tools/tools/nanobsd/nanobsd.sh diff --git a/tools/tools/nanobsd/nanobsd.sh b/tools/tools/nanobsd/nanobsd.sh old mode 100644 new mode 100755 index a4464e0caf52..776b246599f1 --- a/tools/tools/nanobsd/nanobsd.sh +++ b/tools/tools/nanobsd/nanobsd.sh @@ -121,6 +121,13 @@ if [ $# -gt 0 ] ; then usage fi +####################################################################### +# And then it is as simple as that... + +# File descriptor 3 is used for logging output, see pprint +exec 3>&1 +set_defaults_and_export + if [ ! -d "${NANO_TOOLS}" ]; then echo "NANO_TOOLS directory does not exist" 1>&2 exit 1 @@ -130,13 +137,6 @@ if ! $do_clean; then NANO_PMAKE="${NANO_PMAKE} -DNO_CLEAN" fi -####################################################################### -# And then it is as simple as that... - -# File descriptor 3 is used for logging output, see pprint -exec 3>&1 -set_defaults_and_export - pprint 1 "NanoBSD image ${NANO_NAME} build starting" if $do_world ; then From 12e7b30255a9de99bf8f4627681e5cfd418afab8 Mon Sep 17 00:00:00 2001 From: glebius Date: Thu, 22 Jan 2015 01:23:16 +0000 Subject: [PATCH 162/258] Back out r276841, r276756, r276747, r276746. The change in r276747 is very very questionable, since it makes vimages more dependent on each other. But the reason for the backout is that it screwed up shutting down the pf purge threads, and now kernel immedially panics on pf module unload. Although module unloading isn't an advertised feature of pf, it is very important for development process. I'd like to not backout r276746, since in general it is good. But since it has introduced numerous build breakages, that later were addressed in r276841, r276756, r276747, I need to back it out as well. Better replay it in clean fashion from scratch. --- sys/net/pfvar.h | 7 +-- sys/netpfil/pf/pf.c | 97 +++++++++++++++++++++++++++------------ sys/netpfil/pf/pf_if.c | 36 +++++++-------- sys/netpfil/pf/pf_ioctl.c | 48 ++++++++++++------- sys/netpfil/pf/pf_norm.c | 9 ++-- sys/netpfil/pf/pf_table.c | 46 +++++++++---------- 6 files changed, 148 insertions(+), 95 deletions(-) diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 47febfdf721e..78a4e8a53d24 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -829,6 +829,7 @@ typedef int pflog_packet_t(struct pfi_kif *, struct mbuf *, sa_family_t, struct pf_ruleset *, struct pf_pdesc *, int); extern pflog_packet_t *pflog_packet_ptr; +#define V_pf_end_threads VNET(pf_end_threads) #endif /* _KERNEL */ #define PFSYNC_FLAG_SRCNODE 0x04 @@ -1494,7 +1495,7 @@ VNET_DECLARE(struct pf_altqqueue *, pf_altqs_inactive); VNET_DECLARE(struct pf_rulequeue, pf_unlinked_rules); #define V_pf_unlinked_rules VNET(pf_unlinked_rules) -void pf_vnet_initialize(void); +void pf_initialize(void); void pf_mtag_initialize(void); void pf_mtag_cleanup(void); void pf_cleanup(void); @@ -1586,7 +1587,7 @@ int pf_match_addr_range(struct pf_addr *, struct pf_addr *, struct pf_addr *, sa_family_t); int pf_match_port(u_int8_t, u_int16_t, u_int16_t, u_int16_t); -void pf_vnet_normalize_init(void); +void pf_normalize_init(void); void pf_normalize_cleanup(void); int pf_normalize_ip(struct mbuf **, int, struct pfi_kif *, u_short *, struct pf_pdesc *); @@ -1648,7 +1649,7 @@ MALLOC_DECLARE(PFI_MTYPE); VNET_DECLARE(struct pfi_kif *, pfi_all); #define V_pfi_all VNET(pfi_all) -void pfi_vnet_initialize(void); +void pfi_initialize(void); void pfi_cleanup(void); void pfi_kif_ref(struct pfi_kif *); void pfi_kif_unref(struct pfi_kif *); diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index bf47c185aecb..15667a6031e6 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -151,7 +151,6 @@ static VNET_DEFINE(struct pf_send_head, pf_sendqueue); #define V_pf_sendqueue VNET(pf_sendqueue) static struct mtx pf_sendqueue_mtx; -MTX_SYSINIT(pf_sendqueue_mtx, &pf_sendqueue_mtx, "pf send queue", MTX_DEF); #define PF_SENDQ_LOCK() mtx_lock(&pf_sendqueue_mtx) #define PF_SENDQ_UNLOCK() mtx_unlock(&pf_sendqueue_mtx) @@ -173,15 +172,11 @@ static VNET_DEFINE(struct task, pf_overloadtask); #define V_pf_overloadtask VNET(pf_overloadtask) static struct mtx pf_overloadqueue_mtx; -MTX_SYSINIT(pf_overloadqueue_mtx, &pf_overloadqueue_mtx, - "pf overload/flush queue", MTX_DEF); #define PF_OVERLOADQ_LOCK() mtx_lock(&pf_overloadqueue_mtx) #define PF_OVERLOADQ_UNLOCK() mtx_unlock(&pf_overloadqueue_mtx) VNET_DEFINE(struct pf_rulequeue, pf_unlinked_rules); struct mtx pf_unlnkdrules_mtx; -MTX_SYSINIT(pf_unlnkdrules_mtx, &pf_unlnkdrules_mtx, "pf unlinked rules", - MTX_DEF); static VNET_DEFINE(uma_zone_t, pf_sources_z); #define V_pf_sources_z VNET(pf_sources_z) @@ -295,6 +290,8 @@ static void pf_route6(struct mbuf **, struct pf_rule *, int, int in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len); +VNET_DECLARE(int, pf_end_threads); + VNET_DEFINE(struct pf_limit, pf_limits[PF_LIMIT_MAX]); #define PACKET_LOOPED(pd) ((pd)->pf_mtag && \ @@ -731,7 +728,7 @@ pf_mtag_initialize() /* Per-vnet data storage structures initialization. */ void -pf_vnet_initialize() +pf_initialize() { struct pf_keyhash *kh; struct pf_idhash *ih; @@ -791,9 +788,13 @@ pf_vnet_initialize() STAILQ_INIT(&V_pf_sendqueue); SLIST_INIT(&V_pf_overloadqueue); TASK_INIT(&V_pf_overloadtask, 0, pf_overload_task, curvnet); + mtx_init(&pf_sendqueue_mtx, "pf send queue", NULL, MTX_DEF); + mtx_init(&pf_overloadqueue_mtx, "pf overload/flush queue", NULL, + MTX_DEF); /* Unlinked, but may be referenced rules. */ TAILQ_INIT(&V_pf_unlinked_rules); + mtx_init(&pf_unlnkdrules_mtx, "pf unlinked rules", NULL, MTX_DEF); } void @@ -836,6 +837,10 @@ pf_cleanup() free(pfse, M_PFTEMP); } + mtx_destroy(&pf_sendqueue_mtx); + mtx_destroy(&pf_overloadqueue_mtx); + mtx_destroy(&pf_unlnkdrules_mtx); + uma_zdestroy(V_pf_sources_z); uma_zdestroy(V_pf_state_z); uma_zdestroy(V_pf_state_key_z); @@ -1381,37 +1386,71 @@ pf_intr(void *v) } void -pf_purge_thread(void *v __unused) +pf_purge_thread(void *v) { u_int idx = 0; - VNET_ITERATOR_DECL(vnet_iter); + + CURVNET_SET((struct vnet *)v); for (;;) { - tsleep(pf_purge_thread, PWAIT, "pftm", hz / 10); - VNET_LIST_RLOCK(); - VNET_FOREACH(vnet_iter) { - CURVNET_SET(vnet_iter); - /* Process 1/interval fraction of the state table every run. */ - idx = pf_purge_expired_states(idx, pf_hashmask / - (V_pf_default_rule.timeout[PFTM_INTERVAL] * 10)); + PF_RULES_RLOCK(); + rw_sleep(pf_purge_thread, &pf_rules_lock, 0, "pftm", hz / 10); - /* Purge other expired types every PFTM_INTERVAL seconds. */ - if (idx == 0) { - /* - * Order is important: - * - states and src nodes reference rules - * - states and rules reference kifs - */ - pf_purge_expired_fragments(); - pf_purge_expired_src_nodes(); - pf_purge_unlinked_rules(); - pfi_kif_purge(); - } - CURVNET_RESTORE(); + if (V_pf_end_threads) { + /* + * To cleanse up all kifs and rules we need + * two runs: first one clears reference flags, + * then pf_purge_expired_states() doesn't + * raise them, and then second run frees. + */ + PF_RULES_RUNLOCK(); + pf_purge_unlinked_rules(); + pfi_kif_purge(); + + /* + * Now purge everything. + */ + pf_purge_expired_states(0, pf_hashmask); + pf_purge_expired_fragments(); + pf_purge_expired_src_nodes(); + + /* + * Now all kifs & rules should be unreferenced, + * thus should be successfully freed. + */ + pf_purge_unlinked_rules(); + pfi_kif_purge(); + + /* + * Announce success and exit. + */ + PF_RULES_RLOCK(); + V_pf_end_threads++; + PF_RULES_RUNLOCK(); + wakeup(pf_purge_thread); + kproc_exit(0); + } + PF_RULES_RUNLOCK(); + + /* Process 1/interval fraction of the state table every run. */ + idx = pf_purge_expired_states(idx, pf_hashmask / + (V_pf_default_rule.timeout[PFTM_INTERVAL] * 10)); + + /* Purge other expired types every PFTM_INTERVAL seconds. */ + if (idx == 0) { + /* + * Order is important: + * - states and src nodes reference rules + * - states and rules reference kifs + */ + pf_purge_expired_fragments(); + pf_purge_expired_src_nodes(); + pf_purge_unlinked_rules(); + pfi_kif_purge(); } - VNET_LIST_RUNLOCK(); } /* not reached */ + CURVNET_RESTORE(); } u_int32_t diff --git a/sys/netpfil/pf/pf_if.c b/sys/netpfil/pf/pf_if.c index da79ed6f2762..41acc7dd477f 100644 --- a/sys/netpfil/pf/pf_if.c +++ b/sys/netpfil/pf/pf_if.c @@ -102,13 +102,10 @@ MALLOC_DEFINE(PFI_MTYPE, "pf_ifnet", "pf(4) interface database"); LIST_HEAD(pfi_list, pfi_kif); static VNET_DEFINE(struct pfi_list, pfi_unlinked_kifs); #define V_pfi_unlinked_kifs VNET(pfi_unlinked_kifs) - static struct mtx pfi_unlnkdkifs_mtx; -MTX_SYSINIT(pfi_unlnkdkifs_mtx, &pfi_unlnkdkifs_mtx, "pf unlinked interfaces", - MTX_DEF); void -pfi_vnet_initialize(void) +pfi_initialize(void) { struct ifg_group *ifg; struct ifnet *ifp; @@ -117,6 +114,9 @@ pfi_vnet_initialize(void) V_pfi_buffer_max = 64; V_pfi_buffer = malloc(V_pfi_buffer_max * sizeof(*V_pfi_buffer), PFI_MTYPE, M_WAITOK); + + mtx_init(&pfi_unlnkdkifs_mtx, "pf unlinked interfaces", NULL, MTX_DEF); + kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK); PF_RULES_WLOCK(); V_pfi_all = pfi_kif_attach(kif, IFG_ALL); @@ -129,20 +129,18 @@ pfi_vnet_initialize(void) pfi_attach_ifnet(ifp); IFNET_RUNLOCK(); - if (IS_DEFAULT_VNET(curvnet)) { - pfi_attach_cookie = EVENTHANDLER_REGISTER(ifnet_arrival_event, - pfi_attach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY); - pfi_detach_cookie = EVENTHANDLER_REGISTER(ifnet_departure_event, - pfi_detach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY); - pfi_attach_group_cookie = EVENTHANDLER_REGISTER(group_attach_event, - pfi_attach_group_event, curvnet, EVENTHANDLER_PRI_ANY); - pfi_change_group_cookie = EVENTHANDLER_REGISTER(group_change_event, - pfi_change_group_event, curvnet, EVENTHANDLER_PRI_ANY); - pfi_detach_group_cookie = EVENTHANDLER_REGISTER(group_detach_event, - pfi_detach_group_event, curvnet, EVENTHANDLER_PRI_ANY); - pfi_ifaddr_event_cookie = EVENTHANDLER_REGISTER(ifaddr_event, - pfi_ifaddr_event, NULL, EVENTHANDLER_PRI_ANY); - } + pfi_attach_cookie = EVENTHANDLER_REGISTER(ifnet_arrival_event, + pfi_attach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY); + pfi_detach_cookie = EVENTHANDLER_REGISTER(ifnet_departure_event, + pfi_detach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY); + pfi_attach_group_cookie = EVENTHANDLER_REGISTER(group_attach_event, + pfi_attach_group_event, curvnet, EVENTHANDLER_PRI_ANY); + pfi_change_group_cookie = EVENTHANDLER_REGISTER(group_change_event, + pfi_change_group_event, curvnet, EVENTHANDLER_PRI_ANY); + pfi_detach_group_cookie = EVENTHANDLER_REGISTER(group_detach_event, + pfi_detach_group_event, curvnet, EVENTHANDLER_PRI_ANY); + pfi_ifaddr_event_cookie = EVENTHANDLER_REGISTER(ifaddr_event, + pfi_ifaddr_event, NULL, EVENTHANDLER_PRI_ANY); } void @@ -168,6 +166,8 @@ pfi_cleanup(void) free(p, PFI_MTYPE); } + mtx_destroy(&pfi_unlnkdkifs_mtx); + free(V_pfi_buffer, PFI_MTYPE); } diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c index ef479bc4976b..213e49cb52f5 100644 --- a/sys/netpfil/pf/pf_ioctl.c +++ b/sys/netpfil/pf/pf_ioctl.c @@ -87,7 +87,7 @@ __FBSDID("$FreeBSD$"); #include #endif -static int pf_vnet_init(void); +static int pfattach(void); static struct pf_pool *pf_get_pool(char *, u_int32_t, u_int8_t, u_int32_t, u_int8_t, u_int8_t, u_int8_t); @@ -189,6 +189,7 @@ static struct cdevsw pf_cdevsw = { static volatile VNET_DEFINE(int, pf_pfil_hooked); #define V_pf_pfil_hooked VNET(pf_pfil_hooked) +VNET_DEFINE(int, pf_end_threads); struct rwlock pf_rules_lock; struct sx pf_ioctl_lock; @@ -204,20 +205,17 @@ pfsync_defer_t *pfsync_defer_ptr = NULL; pflog_packet_t *pflog_packet_ptr = NULL; static int -pf_vnet_init(void) +pfattach(void) { u_int32_t *my_timeout = V_pf_default_rule.timeout; int error; if (IS_DEFAULT_VNET(curvnet)) pf_mtag_initialize(); - TAILQ_INIT(&V_pf_tags); - TAILQ_INIT(&V_pf_qids); - - pf_vnet_initialize(); + pf_initialize(); pfr_initialize(); - pfi_vnet_initialize(); - pf_vnet_normalize_init(); + pfi_initialize(); + pf_normalize_init(); V_pf_limits[PF_LIMIT_STATES].limit = PFSTATE_HIWAT; V_pf_limits[PF_LIMIT_SRC_NODES].limit = PFSNODE_HIWAT; @@ -278,13 +276,10 @@ pf_vnet_init(void) for (int i = 0; i < SCNT_MAX; i++) V_pf_status.scounters[i] = counter_u64_alloc(M_WAITOK); - if (IS_DEFAULT_VNET(curvnet)) { - if ((error = kproc_create(pf_purge_thread, curvnet, NULL, 0, 0, - "pf purge")) != 0) { - /* XXXGL: leaked all above. */ - return (error); - } - } + if ((error = kproc_create(pf_purge_thread, curvnet, NULL, 0, 0, + "pf purge")) != 0) + /* XXXGL: leaked all above. */ + return (error); if ((error = swi_add(NULL, "pf send", pf_intr, curvnet, SWI_NET, INTR_MPSAFE, &V_pf_swi_cookie)) != 0) /* XXXGL: leaked all above. */ @@ -3720,11 +3715,27 @@ dehook_pf(void) static int pf_load(void) { + int error; + + VNET_ITERATOR_DECL(vnet_iter); + + VNET_LIST_RLOCK(); + VNET_FOREACH(vnet_iter) { + CURVNET_SET(vnet_iter); + V_pf_pfil_hooked = 0; + V_pf_end_threads = 0; + TAILQ_INIT(&V_pf_tags); + TAILQ_INIT(&V_pf_qids); + CURVNET_RESTORE(); + } + VNET_LIST_RUNLOCK(); rw_init(&pf_rules_lock, "pf rulesets"); sx_init(&pf_ioctl_lock, "pf ioctl"); pf_dev = make_dev(&pf_cdevsw, 0, 0, 0, 0600, PF_NAME); + if ((error = pfattach()) != 0) + return (error); return (0); } @@ -3748,6 +3759,11 @@ pf_unload(void) } PF_RULES_WLOCK(); shutdown_pf(); + V_pf_end_threads = 1; + while (V_pf_end_threads < 2) { + wakeup_one(pf_purge_thread); + rw_sleep(pf_purge_thread, &pf_rules_lock, 0, "pftmo", 0); + } pf_normalize_cleanup(); pfi_cleanup(); pfr_cleanup(); @@ -3797,5 +3813,3 @@ static moduledata_t pf_mod = { DECLARE_MODULE(pf, pf_mod, SI_SUB_PSEUDO, SI_ORDER_FIRST); MODULE_VERSION(pf, PF_MODVER); -VNET_SYSINIT(pf_vnet_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY - 255, - pf_vnet_init, NULL); diff --git a/sys/netpfil/pf/pf_norm.c b/sys/netpfil/pf/pf_norm.c index fa9acd66b281..fb30331a80cf 100644 --- a/sys/netpfil/pf/pf_norm.c +++ b/sys/netpfil/pf/pf_norm.c @@ -33,7 +33,6 @@ __FBSDID("$FreeBSD$"); #include "opt_pf.h" #include -#include #include #include #include @@ -93,7 +92,6 @@ struct pf_fragment { }; static struct mtx pf_frag_mtx; -MTX_SYSINIT(pf_frag_mtx, &pf_frag_mtx, "pf fragments", MTX_DEF); #define PF_FRAG_LOCK() mtx_lock(&pf_frag_mtx) #define PF_FRAG_UNLOCK() mtx_unlock(&pf_frag_mtx) #define PF_FRAG_ASSERT() mtx_assert(&pf_frag_mtx, MA_OWNED) @@ -148,7 +146,7 @@ static void pf_scrub_ip6(struct mbuf **, u_int8_t); } while(0) void -pf_vnet_normalize_init(void) +pf_normalize_init(void) { V_pf_frag_z = uma_zcreate("pf frags", sizeof(struct pf_fragment), @@ -163,6 +161,9 @@ pf_vnet_normalize_init(void) V_pf_limits[PF_LIMIT_FRAGS].limit = PFFRAG_FRENT_HIWAT; uma_zone_set_max(V_pf_frent_z, PFFRAG_FRENT_HIWAT); uma_zone_set_warning(V_pf_frent_z, "PF frag entries limit reached"); + + mtx_init(&pf_frag_mtx, "pf fragments", NULL, MTX_DEF); + TAILQ_INIT(&V_pf_fragqueue); TAILQ_INIT(&V_pf_cachequeue); } @@ -174,6 +175,8 @@ pf_normalize_cleanup(void) uma_zdestroy(V_pf_state_scrub_z); uma_zdestroy(V_pf_frent_z); uma_zdestroy(V_pf_frag_z); + + mtx_destroy(&pf_frag_mtx); } static int diff --git a/sys/netpfil/pf/pf_table.c b/sys/netpfil/pf/pf_table.c index 7cdca4039f84..b9f13b93de03 100644 --- a/sys/netpfil/pf/pf_table.c +++ b/sys/netpfil/pf/pf_table.c @@ -184,13 +184,9 @@ static struct pfr_kentry static RB_PROTOTYPE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare); static RB_GENERATE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare); -VNET_DEFINE(struct pfr_ktablehead, pfr_ktables); -#define V_pfr_ktables VNET(pfr_ktables) - +struct pfr_ktablehead pfr_ktables; struct pfr_table pfr_nulltable; - -VNET_DEFINE(int, pfr_ktable_cnt); -#define V_pfr_ktable_cnt VNET(pfr_ktable_cnt) +int pfr_ktable_cnt; void pfr_initialize(void) @@ -1087,7 +1083,7 @@ pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags) return (ENOENT); SLIST_INIT(&workq); - RB_FOREACH(p, pfr_ktablehead, &V_pfr_ktables) { + RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { if (pfr_skip_table(filter, p, flags)) continue; if (!strcmp(p->pfrkt_anchor, PF_RESERVED_ANCHOR)) @@ -1122,7 +1118,7 @@ pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags) flags & PFR_FLAG_USERIOCTL)) senderr(EINVAL); key.pfrkt_flags |= PFR_TFLAG_ACTIVE; - p = RB_FIND(pfr_ktablehead, &V_pfr_ktables, &key); + p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); if (p == NULL) { p = pfr_create_ktable(&key.pfrkt_t, tzero, 1); if (p == NULL) @@ -1138,7 +1134,7 @@ pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags) /* find or create root table */ bzero(key.pfrkt_anchor, sizeof(key.pfrkt_anchor)); - r = RB_FIND(pfr_ktablehead, &V_pfr_ktables, &key); + r = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); if (r != NULL) { p->pfrkt_root = r; goto _skip; @@ -1194,7 +1190,7 @@ pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags) if (pfr_validate_table(&key.pfrkt_t, 0, flags & PFR_FLAG_USERIOCTL)) return (EINVAL); - p = RB_FIND(pfr_ktablehead, &V_pfr_ktables, &key); + p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); if (p != NULL && (p->pfrkt_flags & PFR_TFLAG_ACTIVE)) { SLIST_FOREACH(q, &workq, pfrkt_workq) if (!pfr_ktable_compare(p, q)) @@ -1233,7 +1229,7 @@ pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size, *size = n; return (0); } - RB_FOREACH(p, pfr_ktablehead, &V_pfr_ktables) { + RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { if (pfr_skip_table(filter, p, flags)) continue; if (n-- <= 0) @@ -1268,7 +1264,7 @@ pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size, return (0); } SLIST_INIT(&workq); - RB_FOREACH(p, pfr_ktablehead, &V_pfr_ktables) { + RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { if (pfr_skip_table(filter, p, flags)) continue; if (n-- <= 0) @@ -1300,7 +1296,7 @@ pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags) bcopy(tbl + i, &key.pfrkt_t, sizeof(key.pfrkt_t)); if (pfr_validate_table(&key.pfrkt_t, 0, 0)) return (EINVAL); - p = RB_FIND(pfr_ktablehead, &V_pfr_ktables, &key); + p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); if (p != NULL) { SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); xzero++; @@ -1332,7 +1328,7 @@ pfr_set_tflags(struct pfr_table *tbl, int size, int setflag, int clrflag, if (pfr_validate_table(&key.pfrkt_t, 0, flags & PFR_FLAG_USERIOCTL)) return (EINVAL); - p = RB_FIND(pfr_ktablehead, &V_pfr_ktables, &key); + p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); if (p != NULL && (p->pfrkt_flags & PFR_TFLAG_ACTIVE)) { p->pfrkt_nflags = (p->pfrkt_flags | setflag) & ~clrflag; @@ -1374,7 +1370,7 @@ pfr_ina_begin(struct pfr_table *trs, u_int32_t *ticket, int *ndel, int flags) if (rs == NULL) return (ENOMEM); SLIST_INIT(&workq); - RB_FOREACH(p, pfr_ktablehead, &V_pfr_ktables) { + RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) || pfr_skip_table(trs, p, 0)) continue; @@ -1419,7 +1415,7 @@ pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size, return (EBUSY); tbl->pfrt_flags |= PFR_TFLAG_INACTIVE; SLIST_INIT(&tableq); - kt = RB_FIND(pfr_ktablehead, &V_pfr_ktables, (struct pfr_ktable *)tbl); + kt = RB_FIND(pfr_ktablehead, &pfr_ktables, (struct pfr_ktable *)tbl); if (kt == NULL) { kt = pfr_create_ktable(tbl, 0, 1); if (kt == NULL) @@ -1432,7 +1428,7 @@ pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size, /* find or create root table */ bzero(&key, sizeof(key)); strlcpy(key.pfrkt_name, tbl->pfrt_name, sizeof(key.pfrkt_name)); - rt = RB_FIND(pfr_ktablehead, &V_pfr_ktables, &key); + rt = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); if (rt != NULL) { kt->pfrkt_root = rt; goto _skip; @@ -1509,7 +1505,7 @@ pfr_ina_rollback(struct pfr_table *trs, u_int32_t ticket, int *ndel, int flags) if (rs == NULL || !rs->topen || ticket != rs->tticket) return (0); SLIST_INIT(&workq); - RB_FOREACH(p, pfr_ktablehead, &V_pfr_ktables) { + RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) || pfr_skip_table(trs, p, 0)) continue; @@ -1545,7 +1541,7 @@ pfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd, return (EBUSY); SLIST_INIT(&workq); - RB_FOREACH(p, pfr_ktablehead, &V_pfr_ktables) { + RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) || pfr_skip_table(trs, p, 0)) continue; @@ -1691,7 +1687,7 @@ pfr_table_count(struct pfr_table *filter, int flags) PF_RULES_ASSERT(); if (flags & PFR_FLAG_ALLRSETS) - return (V_pfr_ktable_cnt); + return (pfr_ktable_cnt); if (filter->pfrt_anchor[0]) { rs = pf_find_ruleset(filter->pfrt_anchor); return ((rs != NULL) ? rs->tables : -1); @@ -1724,8 +1720,8 @@ pfr_insert_ktable(struct pfr_ktable *kt) PF_RULES_WASSERT(); - RB_INSERT(pfr_ktablehead, &V_pfr_ktables, kt); - V_pfr_ktable_cnt++; + RB_INSERT(pfr_ktablehead, &pfr_ktables, kt); + pfr_ktable_cnt++; if (kt->pfrkt_root != NULL) if (!kt->pfrkt_root->pfrkt_refcnt[PFR_REFCNT_ANCHOR]++) pfr_setflags_ktable(kt->pfrkt_root, @@ -1756,14 +1752,14 @@ pfr_setflags_ktable(struct pfr_ktable *kt, int newf) if (!(newf & PFR_TFLAG_ACTIVE)) newf &= ~PFR_TFLAG_USRMASK; if (!(newf & PFR_TFLAG_SETMASK)) { - RB_REMOVE(pfr_ktablehead, &V_pfr_ktables, kt); + RB_REMOVE(pfr_ktablehead, &pfr_ktables, kt); if (kt->pfrkt_root != NULL) if (!--kt->pfrkt_root->pfrkt_refcnt[PFR_REFCNT_ANCHOR]) pfr_setflags_ktable(kt->pfrkt_root, kt->pfrkt_root->pfrkt_flags & ~PFR_TFLAG_REFDANCHOR); pfr_destroy_ktable(kt, 1); - V_pfr_ktable_cnt--; + pfr_ktable_cnt--; return; } if (!(newf & PFR_TFLAG_ACTIVE) && kt->pfrkt_cnt) { @@ -1884,7 +1880,7 @@ static struct pfr_ktable * pfr_lookup_table(struct pfr_table *tbl) { /* struct pfr_ktable start like a struct pfr_table */ - return (RB_FIND(pfr_ktablehead, &V_pfr_ktables, + return (RB_FIND(pfr_ktablehead, &pfr_ktables, (struct pfr_ktable *)tbl)); } From 6492a19e1de246c040e8285eeda8d2dff7ae5f88 Mon Sep 17 00:00:00 2001 From: gonzo Date: Thu, 22 Jan 2015 03:32:04 +0000 Subject: [PATCH 163/258] Write ACK for all kinds of LCDC interrupts --- sys/arm/ti/am335x/am335x_lcd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sys/arm/ti/am335x/am335x_lcd.c b/sys/arm/ti/am335x/am335x_lcd.c index a4c56b914922..ada08011b64c 100644 --- a/sys/arm/ti/am335x/am335x_lcd.c +++ b/sys/arm/ti/am335x/am335x_lcd.c @@ -365,7 +365,7 @@ am335x_lcd_intr(void *arg) reg = LCD_READ4(sc, LCD_RASTER_CTRL); reg |= RASTER_CTRL_LCDEN; LCD_WRITE4(sc, LCD_RASTER_CTRL, reg); - return; + goto done; } if (reg & IRQ_PL) { @@ -376,7 +376,7 @@ am335x_lcd_intr(void *arg) reg = LCD_READ4(sc, LCD_RASTER_CTRL); reg |= RASTER_CTRL_LCDEN; LCD_WRITE4(sc, LCD_RASTER_CTRL, reg); - return; + goto done; } if (reg & IRQ_EOF0) { @@ -399,6 +399,7 @@ am335x_lcd_intr(void *arg) /* TODO: Handle ACB */ } +done: LCD_WRITE4(sc, LCD_END_OF_INT_IND, 0); } From d6dbac5a021622b12a0c9d722bd447b1fddacefc Mon Sep 17 00:00:00 2001 From: gonzo Date: Thu, 22 Jan 2015 03:33:51 +0000 Subject: [PATCH 164/258] Add last_fault_code used in pmap-v6.c if kernel is compiled with "option DEBUG" --- sys/arm/arm/trap-v6.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sys/arm/arm/trap-v6.c b/sys/arm/arm/trap-v6.c index 463b1fa6dd3a..b9cad50bb465 100644 --- a/sys/arm/arm/trap-v6.c +++ b/sys/arm/arm/trap-v6.c @@ -67,6 +67,10 @@ __FBSDID("$FreeBSD$"); extern char fusubailout[]; +#ifdef DEBUG +int last_fault_code; /* For the benefit of pmap_fault_fixup() */ +#endif + struct ksig { int sig; u_long code; @@ -457,6 +461,10 @@ abort_handler(struct trapframe *tf, int prefetch) if (prefetch) ftype |= VM_PROT_EXECUTE; +#ifdef DEBUG + last_fault_code = fsr; +#endif + #ifndef ARM_NEW_PMAP if (pmap_fault_fixup(vmspace_pmap(td->td_proc->p_vmspace), va, ftype, usermode)) { From 238b6b9bd42217bdf52f8379f0563555437c47a9 Mon Sep 17 00:00:00 2001 From: rstone Date: Thu, 22 Jan 2015 03:56:23 +0000 Subject: [PATCH 165/258] style(9) cleanup --- sys/dev/hwpmc/hwpmc_core.c | 37 ++++++++++++++++++++++++------------- sys/dev/hwpmc/pmc_events.h | 4 ++-- sys/sys/pmc.h | 2 +- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/sys/dev/hwpmc/hwpmc_core.c b/sys/dev/hwpmc/hwpmc_core.c index 7d27817de77a..6c241422d9cd 100644 --- a/sys/dev/hwpmc/hwpmc_core.c +++ b/sys/dev/hwpmc/hwpmc_core.c @@ -680,7 +680,8 @@ static struct iap_event_descr iap_events[] = { IAPDESCR(08H_0EH, 0x08, 0x0E, IAP_F_FM | IAP_F_HW | IAP_F_HWX), IAPDESCR(08H_10H, 0x08, 0x10, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SB | IAP_F_SBX | IAP_F_HW | IAP_F_HWX), - IAPDESCR(08H_20H, 0x08, 0x20, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_HW | IAP_F_HWX), + IAPDESCR(08H_20H, 0x08, 0x20, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_HW | + IAP_F_HWX), IAPDESCR(08H_40H, 0x08, 0x40, IAP_F_FM | IAP_F_I7O | IAP_F_HW | IAP_F_HWX), IAPDESCR(08H_60H, 0x08, 0x60, IAP_F_FM | IAP_F_HW | IAP_F_HWX), IAPDESCR(08H_80H, 0x08, 0x80, IAP_F_FM | IAP_F_I7 | IAP_F_HW | IAP_F_HWX), @@ -710,9 +711,12 @@ static struct iap_event_descr iap_events[] = { IAPDESCR(0EH_01H, 0x0E, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX), IAPDESCR(0EH_02H, 0x0E, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(0EH_10H, 0x0E, 0x10, IAP_F_FM | IAP_F_IB | IAP_F_IBX | IAP_F_HW | IAP_F_HWX), - IAPDESCR(0EH_20H, 0x0E, 0x20, IAP_F_FM | IAP_F_IB | IAP_F_IBX | IAP_F_HW | IAP_F_HWX), - IAPDESCR(0EH_40H, 0x0E, 0x40, IAP_F_FM | IAP_F_IB | IAP_F_IBX | IAP_F_HW | IAP_F_HWX), + IAPDESCR(0EH_10H, 0x0E, 0x10, IAP_F_FM | IAP_F_IB | IAP_F_IBX | IAP_F_HW | + IAP_F_HWX), + IAPDESCR(0EH_20H, 0x0E, 0x20, IAP_F_FM | IAP_F_IB | IAP_F_IBX | IAP_F_HW | + IAP_F_HWX), + IAPDESCR(0EH_40H, 0x0E, 0x40, IAP_F_FM | IAP_F_IB | IAP_F_IBX | IAP_F_HW | + IAP_F_HWX), IAPDESCR(0FH_01H, 0x0F, 0x01, IAP_F_FM | IAP_F_I7), IAPDESCR(0FH_02H, 0x0F, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM), @@ -826,7 +830,8 @@ static struct iap_event_descr iap_events[] = { IAPDESCR(24H_AAH, 0x24, 0xAA, IAP_F_FM | IAP_F_I7 | IAP_F_WM), IAPDESCR(24H_F8H, 0x24, 0xF8, IAP_F_FM | IAP_F_HW | IAP_F_HWX), IAPDESCR(24H_3FH, 0x24, 0x3F, IAP_F_FM | IAP_F_HW | IAP_F_HWX), - IAPDESCR(24H_FFH, 0x24, 0xFF, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_HW | IAP_F_HWX), + IAPDESCR(24H_FFH, 0x24, 0xFF, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_HW | + IAP_F_HWX), IAPDESCR(25H, 0x25, IAP_M_CORE, IAP_F_ALLCPUSCORE2), @@ -967,7 +972,8 @@ static struct iap_event_descr iap_events[] = { IAPDESCR(49H_20H, 0x49, 0x20, IAP_F_FM | IAP_F_I7 | IAP_F_HW | IAP_F_HWX), IAPDESCR(49H_40H, 0x49, 0x40, IAP_F_FM | IAP_F_I7O | IAP_F_HW | IAP_F_HWX), IAPDESCR(49H_60H, 0x49, 0x60, IAP_F_FM | IAP_F_HW | IAP_F_HWX), - IAPDESCR(49H_80H, 0x49, 0x80, IAP_F_FM | IAP_F_WM | IAP_F_I7 | IAP_F_HW | IAP_F_HWX), + IAPDESCR(49H_80H, 0x49, 0x80, IAP_F_FM | IAP_F_WM | IAP_F_I7 | IAP_F_HW | + IAP_F_HWX), IAPDESCR(4BH_00H, 0x4B, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), IAPDESCR(4BH_01H, 0x4B, 0x01, IAP_F_FM | IAP_F_ALLCPUSCORE2 | IAP_F_I7O), @@ -1008,10 +1014,14 @@ static struct iap_event_descr iap_events[] = { IAPDESCR(53H_01H, 0x53, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(58H_01H, 0x58, 0x01, IAP_F_FM | IAP_F_IB | IAP_F_IBX | IAP_F_HW | IAP_F_HWX), - IAPDESCR(58H_02H, 0x58, 0x02, IAP_F_FM | IAP_F_IB | IAP_F_IBX | IAP_F_HW | IAP_F_HWX), - IAPDESCR(58H_04H, 0x58, 0x04, IAP_F_FM | IAP_F_IB | IAP_F_IBX | IAP_F_HW | IAP_F_HWX), - IAPDESCR(58H_08H, 0x58, 0x08, IAP_F_FM | IAP_F_IB | IAP_F_IBX | IAP_F_HW | IAP_F_HWX), + IAPDESCR(58H_01H, 0x58, 0x01, IAP_F_FM | IAP_F_IB | IAP_F_IBX | IAP_F_HW | + IAP_F_HWX), + IAPDESCR(58H_02H, 0x58, 0x02, IAP_F_FM | IAP_F_IB | IAP_F_IBX | IAP_F_HW | + IAP_F_HWX), + IAPDESCR(58H_04H, 0x58, 0x04, IAP_F_FM | IAP_F_IB | IAP_F_IBX | IAP_F_HW | + IAP_F_HWX), + IAPDESCR(58H_08H, 0x58, 0x08, IAP_F_FM | IAP_F_IB | IAP_F_IBX | IAP_F_HW | + IAP_F_HWX), IAPDESCR(59H_20H, 0x59, 0x20, IAP_F_FM | IAP_F_SB | IAP_F_SBX), IAPDESCR(59H_40H, 0x59, 0x40, IAP_F_FM | IAP_F_SB | IAP_F_SBX), @@ -1114,8 +1124,8 @@ static struct iap_event_descr iap_events[] = { IAPDESCR(79H_30H, 0x79, 0x30, IAP_F_FM | IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX), - - IAPDESCR(79H_3CH, 0x79, 0x3C, IAP_F_FM | IAP_F_IB | IAP_F_IBX | IAP_F_HW | IAP_F_HWX), + IAPDESCR(79H_18H, 0x79, 0x18, IAP_F_FM | IAP_F_IB | IAP_F_IBX | IAP_F_HW | + IAP_F_HWX), IAPDESCR(7AH, 0x7A, IAP_M_AGENT, IAP_F_CA | IAP_F_CC2), @@ -1367,7 +1377,8 @@ static struct iap_event_descr iap_events[] = { IAPDESCR(B6H_04H, 0xB6, 0x04, IAP_F_CAS), IAPDESCR(B7H_01H, 0xB7, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_CAS), + IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_CAS | + IAP_F_HWX), IAPDESCR(B7H_02H, 0xB7, 0x02, IAP_F_CAS), IAPDESCR(B8H_01H, 0xB8, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM), diff --git a/sys/dev/hwpmc/pmc_events.h b/sys/dev/hwpmc/pmc_events.h index 567d6f44823f..4953f19dbc1b 100644 --- a/sys/dev/hwpmc/pmc_events.h +++ b/sys/dev/hwpmc/pmc_events.h @@ -2734,7 +2734,7 @@ __PMC_EV_ALIAS("PAGE_WALKER_LOADS.ITLB_MEMORY", IAP_EVENT_BCH_28H) \ __PMC_EV_ALIAS("TLB_FLUSH.DTLB_THREAD", IAP_EVENT_BDH_01H) \ __PMC_EV_ALIAS("TLB_FLUSH.STLB_ANY", IAP_EVENT_BDH_20H) \ __PMC_EV_ALIAS("INST_RETIRED.ANY_P", IAP_EVENT_C0H_00H) \ -__PMC_EV_ALIAS("INST_RETIRED.PREC_DIST", IAP_EVENT_C0H_01H) \ +__PMC_EV_ALIAS("INST_RETIRED.PREC_DIST", IAP_EVENT_C0H_01H) \ __PMC_EV_ALIAS("OTHER_ASSISTS.AVX_TO_SSE", IAP_EVENT_C1H_08H) \ __PMC_EV_ALIAS("OTHER_ASSISTS.SSE_TO_AVX", IAP_EVENT_C1H_10H) \ __PMC_EV_ALIAS("OTHER_ASSISTS.ANY_WB_ASSIST", IAP_EVENT_C1H_40H) \ @@ -2963,7 +2963,7 @@ __PMC_EV_ALIAS("PAGE_WALKER_LOADS.ITLB_MEMORY", IAP_EVENT_BCH_28H) \ __PMC_EV_ALIAS("TLB_FLUSH.DTLB_THREAD", IAP_EVENT_BDH_01H) \ __PMC_EV_ALIAS("TLB_FLUSH.STLB_ANY", IAP_EVENT_BDH_20H) \ __PMC_EV_ALIAS("INST_RETIRED.ANY_P", IAP_EVENT_C0H_00H) \ -__PMC_EV_ALIAS("INST_RETIRED.PREC_DIST", IAP_EVENT_C0H_01H) \ +__PMC_EV_ALIAS("INST_RETIRED.PREC_DIST", IAP_EVENT_C0H_01H) \ __PMC_EV_ALIAS("OTHER_ASSISTS.AVX_TO_SSE", IAP_EVENT_C1H_08H) \ __PMC_EV_ALIAS("OTHER_ASSISTS.SSE_TO_AVX", IAP_EVENT_C1H_10H) \ __PMC_EV_ALIAS("OTHER_ASSISTS.ANY_WB_ASSIST", IAP_EVENT_C1H_40H) \ diff --git a/sys/sys/pmc.h b/sys/sys/pmc.h index 1812840308a7..76f000a53799 100644 --- a/sys/sys/pmc.h +++ b/sys/sys/pmc.h @@ -94,7 +94,7 @@ __PMC_CPU(INTEL_ATOM_SILVERMONT, 0x92, "Intel Atom Silvermont") \ __PMC_CPU(INTEL_NEHALEM_EX, 0x93, "Intel Nehalem Xeon 7500") \ __PMC_CPU(INTEL_WESTMERE_EX, 0x94, "Intel Westmere Xeon E7") \ - __PMC_CPU(INTEL_HASWELL_XEON, 0x95, "Intel Haswell Xeon E5 v3") \ + __PMC_CPU(INTEL_HASWELL_XEON, 0x95, "Intel Haswell Xeon E5 v3") \ __PMC_CPU(INTEL_XSCALE, 0x100, "Intel XScale") \ __PMC_CPU(MIPS_24K, 0x200, "MIPS 24K") \ __PMC_CPU(MIPS_OCTEON, 0x201, "Cavium Octeon") \ From 8925dffab199f6ca4955328774e9fa6d39e9f0c8 Mon Sep 17 00:00:00 2001 From: ngie Date: Thu, 22 Jan 2015 09:25:31 +0000 Subject: [PATCH 166/258] Make this compile with WARNS=6 and clang/gcc MFC after: 3 days Sponsored by: EMC / Isilon Storage Division --- tools/regression/file/flock/flock.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tools/regression/file/flock/flock.c b/tools/regression/file/flock/flock.c index fd426b0e625b..49e47b830896 100644 --- a/tools/regression/file/flock/flock.c +++ b/tools/regression/file/flock/flock.c @@ -27,6 +27,7 @@ * $FreeBSD$ */ +#include #include #include #ifdef __FreeBSD__ @@ -52,6 +53,10 @@ #endif #include #else +#ifndef nitems +#define nitems(x) (sizeof((x)) / sizeof((x)[0])) +#endif + #ifndef __unused #ifdef __GNUC__ #define __unused __attribute__((__unused__)) @@ -61,7 +66,7 @@ #endif #endif -int verbose = 0; +static int verbose = 0; static int make_file(const char *pathname, off_t sz) @@ -1519,7 +1524,7 @@ struct test { int intr; /* non-zero if the test interrupts a lock */ }; -struct test tests[] = { +static struct test tests[] = { { test1, 1, 0 }, { test2, 2, 0 }, { test3, 3, 1 }, @@ -1537,7 +1542,6 @@ struct test tests[] = { { test15, 15, 1 }, { test16, 16, 1 }, }; -int test_count = sizeof(tests) / sizeof(tests[0]); int main(int argc, const char *argv[]) @@ -1545,7 +1549,7 @@ main(int argc, const char *argv[]) int testnum; int fd; int nointr; - int i; + unsigned i; struct sigaction sa; int test_argc; const char **test_argv; @@ -1583,7 +1587,7 @@ main(int argc, const char *argv[]) } #endif - for (i = 0; i < test_count; i++) { + for (i = 0; i < nitems(tests); i++) { if (tests[i].intr && nointr) continue; if (!testnum || tests[i].num == testnum) From c0aba3b50d494dc9fefa1cd1304481521fa05a36 Mon Sep 17 00:00:00 2001 From: hselasky Date: Thu, 22 Jan 2015 11:12:42 +0000 Subject: [PATCH 167/258] Revert for r277213: FreeBSD developers need more time to review patches in the surrounding areas like the TCP stack which are using MPSAFE callouts to restore distribution of callouts on multiple CPUs. Bump the __FreeBSD_version instead of reverting it. Suggested by: kmacy, adrian, glebius and kib Differential Revision: https://reviews.freebsd.org/D1438 --- share/man/man9/Makefile | 1 - share/man/man9/timeout.9 | 874 +++++++++++----------- sys/kern/init_main.c | 3 +- sys/kern/kern_condvar.c | 12 +- sys/kern/kern_lock.c | 6 +- sys/kern/kern_switch.c | 2 + sys/kern/kern_synch.c | 13 +- sys/kern/kern_thread.c | 8 +- sys/kern/kern_timeout.c | 1049 ++++++++++++++------------- sys/kern/subr_sleepqueue.c | 149 ++-- sys/ofed/include/linux/completion.h | 2 - sys/sys/_callout.h | 19 +- sys/sys/callout.h | 14 +- sys/sys/param.h | 2 +- sys/sys/proc.h | 5 +- 15 files changed, 1111 insertions(+), 1048 deletions(-) diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile index e59c14fa9d17..cf64df7c811b 100644 --- a/share/man/man9/Makefile +++ b/share/man/man9/Makefile @@ -1570,7 +1570,6 @@ MLINKS+=timeout.9 callout.9 \ timeout.9 callout_active.9 \ timeout.9 callout_deactivate.9 \ timeout.9 callout_drain.9 \ - timeout.9 callout_drain_async.9 \ timeout.9 callout_handle_init.9 \ timeout.9 callout_init.9 \ timeout.9 callout_init_mtx.9 \ diff --git a/share/man/man9/timeout.9 b/share/man/man9/timeout.9 index 4f52a19cb61f..7202815a7824 100644 --- a/share/man/man9/timeout.9 +++ b/share/man/man9/timeout.9 @@ -29,14 +29,13 @@ .\" .\" $FreeBSD$ .\" -.Dd January 14, 2015 +.Dd October 8, 2014 .Dt TIMEOUT 9 .Os .Sh NAME .Nm callout_active , .Nm callout_deactivate , .Nm callout_drain , -.Nm callout_drain_async , .Nm callout_handle_init , .Nm callout_init , .Nm callout_init_mtx , @@ -64,232 +63,279 @@ .In sys/systm.h .Bd -literal typedef void timeout_t (void *); -typedef void callout_func_t (void *); .Ed +.Ft int +.Fn callout_active "struct callout *c" +.Ft void +.Fn callout_deactivate "struct callout *c" +.Ft int +.Fn callout_drain "struct callout *c" +.Ft void +.Fn callout_handle_init "struct callout_handle *handle" +.Bd -literal +struct callout_handle handle = CALLOUT_HANDLE_INITIALIZER(&handle); +.Ed +.Ft void +.Fn callout_init "struct callout *c" "int mpsafe" +.Ft void +.Fn callout_init_mtx "struct callout *c" "struct mtx *mtx" "int flags" +.Ft void +.Fn callout_init_rm "struct callout *c" "struct rmlock *rm" "int flags" +.Ft void +.Fn callout_init_rw "struct callout *c" "struct rwlock *rw" "int flags" +.Ft int +.Fn callout_pending "struct callout *c" +.Ft int +.Fn callout_reset "struct callout *c" "int ticks" "timeout_t *func" "void *arg" +.Ft int +.Fn callout_reset_curcpu "struct callout *c" "int ticks" "timeout_t *func" \ +"void *arg" +.Ft int +.Fn callout_reset_on "struct callout *c" "int ticks" "timeout_t *func" \ +"void *arg" "int cpu" +.Ft int +.Fn callout_reset_sbt "struct callout *c" "sbintime_t sbt" \ +"sbintime_t pr" "timeout_t *func" "void *arg" "int flags" +.Ft int +.Fn callout_reset_sbt_curcpu "struct callout *c" "sbintime_t sbt" \ +"sbintime_t pr" "timeout_t *func" "void *arg" "int flags" +.Ft int +.Fn callout_reset_sbt_on "struct callout *c" "sbintime_t sbt" \ +"sbintime_t pr" "timeout_t *func" "void *arg" "int cpu" "int flags" +.Ft int +.Fn callout_schedule "struct callout *c" "int ticks" +.Ft int +.Fn callout_schedule_curcpu "struct callout *c" "int ticks" +.Ft int +.Fn callout_schedule_on "struct callout *c" "int ticks" "int cpu" +.Ft int +.Fn callout_schedule_sbt "struct callout *c" "sbintime_t sbt" \ +"sbintime_t pr" "int flags" +.Ft int +.Fn callout_schedule_sbt_curcpu "struct callout *c" "sbintime_t sbt" \ +"sbintime_t pr" "int flags" +.Ft int +.Fn callout_schedule_sbt_on "struct callout *c" "sbintime_t sbt" \ +"sbintime_t pr" "int cpu" "int flags" +.Ft int +.Fn callout_stop "struct callout *c" +.Ft struct callout_handle +.Fn timeout "timeout_t *func" "void *arg" "int ticks" +.Ft void +.Fn untimeout "timeout_t *func" "void *arg" "struct callout_handle handle" .Sh DESCRIPTION The .Nm callout API is used to schedule a call to an arbitrary function at a specific -time in the future in a single-shot fashion. -Consumers of this API are required to allocate a +time in the future. +Consumers of this API are required to allocate a callout structure .Pq struct callout -structure for each pending function invocation. -The -.Pq struct callout -structure stores the full state about any pending function call and -should be drained by a call to -.Fn callout_drain +for each pending function invocation. +This structure stores state about the pending function invocation including +the function to be called and the time at which the function should be invoked. +Pending function calls can be cancelled or rescheduled to a different time. +In addition, +a callout structure may be reused to schedule a new function call after a +scheduled call is completed. +.Pp +Callouts only provide a single-shot mode. +If a consumer requires a periodic timer, +it must explicitly reschedule each function call. +This is normally done by rescheduling the subsequent call within the called +function. +.Pp +Callout functions must not sleep. +They may not acquire sleepable locks, +wait on condition variables, +perform blocking allocation requests, +or invoke any other action that might sleep. +.Pp +Each callout structure must be initialized by +.Fn callout_init , +.Fn callout_init_mtx , +.Fn callout_init_rm , or -.Fn callout_drain_async -before freeing. -.Sh INITIALISATION -.Ft void -.Fn callout_handle_init "struct callout_handle *handle" -This function is deprecated and is used to prepare a -.Pq struct callout_handle -structure before it can be used the first time. -If this function is called on a pending timeout, the pending timeout -cannot be cancelled and the -.Fn untimeout -function will return as if there was no timeout pending. -.Pp -.Fn CALLOUT_HANDLE_INITIALIZER "&handle" -This macro is deprecated and can be used instead of -.Fn callout_handle_init -to assign the default state to the -.Pq struct callout_handle -structure when declaring static timeouts. -.Pp -.Ft void -.Fn callout_init "struct callout *c" "int mpsafe" -This function prepares a -.Pq struct callout -structure before it can be used. -This function should not be used when the callout is pending a timeout. +.Fn callout_init_rw +before it is passed to any of the other callout functions. +The +.Fn callout_init +function initializes a callout structure in +.Fa c +that is not associated with a specific lock. If the .Fa mpsafe -argument is non-zero, the callback function will be running unlocked. -Else the Giant mutex will be locked before calling the callback function. +argument is zero, +the callout structure is not considered to be +.Dq multi-processor safe ; +and the Giant lock will be acquired before calling the callout function +and released when the callout function returns. .Pp -.Ft void -.Fn callout_init_mtx "struct callout *c" "struct mtx *mtx" "int flags" -This function prepares a -.Pq struct callout -structure before it can be used. -This function should not be used when the callout is pending a timeout. The -.Fa mtx -argument should be non-zero and should specify a pointer to a valid -spinlock type of mutex or a valid regular non-sleepable mutex which -the callback subsystem should lock before calling the callback -function. -Valid +.Fn callout_init_mtx , +.Fn callout_init_rm , +and +.Fn callout_init_rw +functions initialize a callout structure in +.Fa c +that is associated with a specific lock. +The lock is specified by the +.Fa mtx , +.Fa rm , +or +.Fa rw +parameter. +The associated lock must be held while stopping or rescheduling the +callout. +The callout subsystem acquires the associated lock before calling the +callout function and releases it after the function returns. +If the callout was cancelled while the callout subsystem waited for the +associated lock, +the callout function is not called, +and the associated lock is released. +This ensures that stopping or rescheduling the callout will abort any +previously scheduled invocation. +.Pp +Only regular mutexes may be used with +.Fn callout_init_mtx ; +spin mutexes are not supported. +A sleepable read-mostly lock +.Po +one initialized with the +.Dv RM_SLEEPABLE +flag +.Pc +may not be used with +.Fn callout_init_rm . +Similarly, other sleepable lock types such as +.Xr sx 9 +and +.Xr lockmgr 9 +cannot be used with callouts because sleeping is not permitted in +the callout subsystem. +.Pp +These .Fa flags -are: +may be specified for +.Fn callout_init_mtx , +.Fn callout_init_rm , +or +.Fn callout_init_rw : .Bl -tag -width ".Dv CALLOUT_RETURNUNLOCKED" .It Dv CALLOUT_RETURNUNLOCKED -It is assumed that the callout function has released the specified -mutex before returning. -Else the callout subsystem will release the specified mutex after the -callout function has returned. +The callout function will release the associated lock itself, +so the callout subsystem should not attempt to unlock it +after the callout function returns. +.It Dv CALLOUT_SHAREDLOCK +The lock is only acquired in read mode when running the callout handler. +This flag is ignored by +.Fn callout_init_mtx . .El .Pp -.Ft void -.Fn callout_init_rm "struct callout *c" "struct rmlock *rm" "int flags" -This function is the same like the -.Fn callout_init_mtx -function except it accepts a read-mostly type of lock. -The read-mostly lock must not be initialised with the -.Dv RM_SLEEPABLE -flag. +The function +.Fn callout_stop +cancels a callout +.Fa c +if it is currently pending. +If the callout is pending, then +.Fn callout_stop +returns a non-zero value. +If the callout is not set, +has already been serviced, +or is currently being serviced, +then zero will be returned. +If the callout has an associated lock, +then that lock must be held when this function is called. .Pp -.Ft void -.Fn callout_init_rw "struct callout *c" "struct rwlock *rw" "int flags" -This function is the same like the -.Fn callout_init_mtx -function except it accepts a reader-writer type of lock. -.Sh SCHEDULING CALLOUTS -.Ft struct callout_handle -.Fn timeout "timeout_t *func" "void *arg" "int ticks" -This function is deprecated and schedules a call to the function given by the argument -.Fa func -to take place after +The function +.Fn callout_drain +is identical to +.Fn callout_stop +except that it will wait for the callout +.Fa c +to complete if it is already in progress. +This function MUST NOT be called while holding any +locks on which the callout might block, or deadlock will result. +Note that if the callout subsystem has already begun processing this +callout, then the callout function may be invoked before +.Fn callout_drain +returns. +However, the callout subsystem does guarantee that the callout will be +fully stopped before +.Fn callout_drain +returns. +.Pp +The +.Fn callout_reset +and +.Fn callout_schedule +function families schedule a future function invocation for callout +.Fa c . +If +.Fa c +already has a pending callout, +it is cancelled before the new invocation is scheduled. +These functions return a non-zero value if a pending callout was cancelled +and zero if there was no pending callout. +If the callout has an associated lock, +then that lock must be held when any of these functions are called. +.Pp +The time at which the callout function will be invoked is determined by +either the +.Fa ticks +argument or the +.Fa sbt , +.Fa pr , +and +.Fa flags +arguments. +When +.Fa ticks +is used, +the callout is scheduled to execute after .Fa ticks Ns No /hz seconds. Non-positive values of .Fa ticks are silently converted to the value .Sq 1 . +.Pp The -.Fa func -argument should be a valid pointer to a function that takes a single -.Fa void * -argument. -Upon invocation, the -.Fa func -function will receive -.Fa arg -as its only argument. -The Giant lock is locked when the -.Fa arg -function is invoked and should not be unlocked by this function. -The returned value from -.Fn timeout -is a -.Ft struct callout_handle -structure which can be used in conjunction with the -.Fn untimeout -function to request that a scheduled timeout be cancelled. -As handles are recycled by the system, it is possible, although unlikely, -that a handle from one invocation of -.Fn timeout -may match the handle of another invocation of -.Fn timeout -if both calls used the same function pointer and argument, and the first -timeout is expired or canceled before the second call. -Please ensure that the function and argument pointers are unique when using this function. -.Pp -.Ft int -.Fn callout_reset "struct callout *c" "int ticks" "callout_func_t *func" "void *arg" -This function is used to schedule or re-schedule a callout. -This function at first stops the callout given by the -.Fa c -argument, if any. -Then it will start the callout given by the -.Fa c -argument. -The relative time until the timeout callback happens is given by the -.Fa ticks -argument. -The number of ticks in a second is defined by -.Dv hz -and can vary from system to system. -This function returns a non-zero value if the given callout was pending and -the callback function was prevented from being called. -Else a value of zero is returned. -If a lock is associated with the callout given by the -.Fa c -argument and it is exclusivly locked when this function is called this -function will always ensure that previous callback function, if any, -is never reached. -In other words the callout will be atomically restarted. -Else there is no such guarantee. -The callback function is given by the -.Fa func -argument and its function argument is given by the -.Fa arg -argument. -.Pp -.Ft int -.Fn callout_reset_curcpu "struct callout *c" "int ticks" "callout_func_t *func" \ -"void *arg" -This function works the same like the -.Fn callout_reset -function except the callback function given by the -.Fa func -argument will be executed on the same CPU which called this function. -A change in the CPU selection can happen if the callout has a lock -associated with it and is locked when this function is called. -A change in the CPU selection cannot happen if this function is -re-scheduled inside a callout function. -Else the callback function given by the -.Fa func -argument will be executed on the same CPU like previously done. -.Pp -.Ft int -.Fn callout_reset_on "struct callout *c" "int ticks" "callout_func_t *func" \ -"void *arg" "int cpu" -This function works the same like the -.Fn callout_reset -function except the callback function given by the -.Fa func -argument will be executed on the CPU given by the -.Fa cpu -argument. -A change in the CPU selection can happen if the callout has a lock -associated with it and is locked when this function is called. -A change in the CPU selection cannot happen if this function is -re-scheduled inside a callout function. -Else the callback function given by the -.Fa func -argument will be executed on the same CPU like previously done. -.Pp -.Ft int -.Fn callout_reset_sbt "struct callout *c" "sbintime_t sbt" \ -"sbintime_t pr" "callout_func_t *func" "void *arg" "int flags" -This function works the same like the -.Fn callout_reset -function except the relative or absolute time after which the timeout -callback should happen is given by the +.Fa sbt , +.Fa pr , +and +.Fa flags +arguments provide more control over the scheduled time including +support for higher resolution times, +specifying the precision of the scheduled time, +and setting an absolute deadline instead of a relative timeout. +The callout is scheduled to execute in a time window which begins at +the time specified in .Fa sbt -argument and extends for the amount of time specified in the -.Fa pr -argument. -This function is used when you need high precision timeouts. -If the +and extends for the amount of time specified in +.Fa pr . +If .Fa sbt -argument specifies a time in the past, +specifies a time in the past, the window is adjusted to start at the current time. A non-zero value for .Fa pr allows the callout subsystem to coalesce callouts scheduled close to each other into fewer timer interrupts, reducing processing overhead and power consumption. -The +These .Fa flags -argument may be non-zero to adjust the interpretation of the +may be specified to adjust the interpretation of .Fa sbt -and the -.Fa pr -arguments: +and +.Fa pr : .Bl -tag -width ".Dv C_DIRECT_EXEC" .It Dv C_ABSOLUTE Handle the .Fa sbt argument as an absolute time since boot. -By default, the +By default, .Fa sbt -argument is treated like a relative amount of time, +is treated as a relative amount of time, similar to .Fa ticks . .It Dv C_DIRECT_EXEC @@ -301,7 +347,7 @@ Callout functions run in this context may use only spin mutexes for locking and should be as small as possible because they run with absolute priority. .It Fn C_PREL Specifies relative event time precision as binary logarithm of time interval -divided by acceptable time deviation: 1 -- 1/2, 2 -- 1/4 and so on. +divided by acceptable time deviation: 1 -- 1/2, 2 -- 1/4, etc. Note that the larger of .Fa pr or this value is used as the length of the time window. @@ -314,215 +360,65 @@ Align the timeouts to calls if possible. .El .Pp -.Ft int -.Fn callout_reset_sbt_curcpu "struct callout *c" "sbintime_t sbt" \ -"sbintime_t pr" "callout_func_t *func" "void *arg" "int flags" -This function works the same like the -.Fn callout_reset_sbt -function except the callback function given by the -.Fa func -argument will be executed on the same CPU which called this function. -A change in the CPU selection can happen if the callout has a lock -associated with it and is locked when this function is called. -A change in the CPU selection cannot happen if this function is -re-scheduled inside a callout function. -Else the callback function given by the -.Fa func -argument will be executed on the same CPU like previously done. -.Pp -.Ft int -.Fn callout_reset_sbt_on "struct callout *c" "sbintime_t sbt" \ -"sbintime_t pr" "callout_func_t *func" "void *arg" "int cpu" "int flags" -This function works the same like the -.Fn callout_reset_sbt -function except the callback function given by the -.Fa func -argument will be executed on the CPU given by the -.Fa cpu -argument. -A change in the CPU selection can happen if the callout has a lock -associated with it and is locked when this function is called. -A change in the CPU selection cannot happen if this function is -re-scheduled inside a callout function. -Else the callback function given by the -.Fa func -argument will be executed on the same CPU like previously done. -.Pp -.Ft int -.Fn callout_schedule "struct callout *c" "int ticks" -This function works the same like the +The .Fn callout_reset -function except it re-uses the callback function and the callback argument -already stored in the -.Pq struct callout -structure. -.Pp -.Ft int -.Fn callout_schedule_curcpu "struct callout *c" "int ticks" -This function works the same like the -.Fn callout_reset_curcpu -function except it re-uses the callback function and the callback argument -already stored in the -.Pq struct callout -structure. -.Pp -.Ft int -.Fn callout_schedule_on "struct callout *c" "int ticks" "int cpu" -This function works the same like the -.Fn callout_reset_on -function except it re-uses the callback function and the callback argument -already stored in the -.Pq struct callout -structure. -.Pp -.Ft int -.Fn callout_schedule_sbt "struct callout *c" "sbintime_t sbt" \ -"sbintime_t pr" "int flags" -This function works the same like the -.Fn callout_reset_sbt -function except it re-uses the callback function and the callback argument -already stored in the -.Pq struct callout -structure. -.Pp -.Ft int -.Fn callout_schedule_sbt_curcpu "struct callout *c" "sbintime_t sbt" \ -"sbintime_t pr" "int flags" -This function works the same like the -.Fn callout_reset_sbt_curcpu -function except it re-uses the callback function and the callback argument -already stored in the -.Pq struct callout -structure. -.Pp -.Ft int -.Fn callout_schedule_sbt_on "struct callout *c" "sbintime_t sbt" \ -"sbintime_t pr" "int cpu" "int flags" -This function works the same like the -.Fn callout_reset_sbt_on -function except it re-uses the callback function and the callback argument -already stored in the -.Pq struct callout -structure. -.Sh CHECKING THE STATE OF CALLOUTS -.Ft int -.Fn callout_pending "struct callout *c" -This function returns non-zero if the callout pointed to by the -.Fa c -argument is pending for callback. -Else this function returns zero. -This function returns zero when inside the callout function if the -callout is not re-scheduled. -.Pp -.Ft int -.Fn callout_active "struct callout *c" -This function is deprecated and returns non-zero if the callout -pointed to by the -.Fa c -argument was scheduled in the past. -Else this function returns zero. -This function also returns zero after the -.Fn callout_deactivate -or the -.Fn callout_stop -or the -.Fn callout_drain -or the -.Fn callout_drain_async -function is called on the same callout as given by the -.Fa c -argument. -.Pp -.Ft void -.Fn callout_deactivate "struct callout *c" -This function is deprecated and ensures that subsequent calls to the -.Fn callout_activate -function returns zero until the callout is scheduled again. -.Sh STOPPING CALLOUTS -.Ft void -.Fn untimeout "timeout_t *func" "void *arg" "struct callout_handle handle" -This function is deprecated and cancels the timeout associated with the -.Fa handle -argument using the function pointed to by the +functions accept a .Fa func -argument and having the -.Fa arg -arguments to validate the handle. -If the handle does not correspond to a timeout with -the function -.Fa func -taking the argument -.Fa arg -no action is taken. The -.Fa handle -must be initialised by a previous call to -.Fn timeout , -.Fn callout_handle_init -or assigned the value of -.Fn CALLOUT_HANDLE_INITIALIZER "&handle" -before being passed to -.Fn untimeout . -The behavior of calling -.Fn untimeout -with an uninitialised handle -is undefined. -.Pp -.Ft int -.Fn callout_stop "struct callout *c" -This function is used to stop a timeout function invocation associated with the callout pointed to by the -.Fa c -argument, in a non-blocking fashion. -This function can be called multiple times in a row with no side effects, even if the callout is already stopped. This function however should not be called before the callout has been initialised. -This function returns a non-zero value if the given callout was pending and -the callback function was prevented from being called. -Else a value of zero is returned. -If a lock is associated with the callout given by the -.Fa c -argument and it is exclusivly locked when this function is called, the -.Fn callout_stop -function will always ensure that the callback function is never reached. -In other words the callout will be atomically stopped. -Else there is no such guarantee. -.Sh DRAINING CALLOUTS -.Ft int -.Fn callout_drain "struct callout *c" -This function works the same like the -.Fn callout_stop -function except it ensures that all callback functions have returned and there are no more references to the callout pointed to by the -.Fa c -argument inside the callout subsystem before it returns. -Also this function ensures that the lock, if any, associated with the -callout is no longer being used. -When this function returns, it is safe to free the callout structure pointed to by the -.Fa c +argument which identifies the function to be called when the time expires. +It must be a pointer to a function that takes a single +.Fa void * argument. -.Pp -.Ft int -.Fn callout_drain_async "struct callout *c" "callout_func_t *fn" "void *arg" -This function is non-blocking and works the same like the -.Fn callout_stop -function except if it returns non-zero it means the callback function pointed to by the -.Fa fn -argument will be called back with the +Upon invocation, +.Fa func +will receive .Fa arg -argument when all references to the callout pointed to by the -.Fa c -argument are gone. -If this function returns zero, it is safe to free the callout structure pointed to by the -.Fa c -argument right away. -.Sh CALLOUT FUNCTION RESTRICTIONS -Callout functions must not sleep. -They may not acquire sleepable locks, wait on condition variables, -perform blocking allocation requests, or invoke any other action that -might sleep. -.Sh CALLOUT SUBSYSTEM INTERNALS -The callout subsystem has its own set of spinlocks to protect its internal state. -The callout subsystem provides a softclock thread for each CPU in the -system. -Callouts are assigned to a single CPU and are executed by the -softclock thread for that CPU. -Initially, callouts are assigned to CPU 0. +as its only argument. +The +.Fn callout_schedule +functions reuse the +.Fa func +and +.Fa arg +arguments from the previous callout. +Note that one of the +.Fn callout_reset +functions must always be called to initialize +.Fa func +and +.Fa arg +before one of the +.Fn callout_schedule +functions can be used. +.Pp +The callout subsystem provides a softclock thread for each CPU in the system. +Callouts are assigned to a single CPU and are executed by the softclock thread +for that CPU. +Initially, +callouts are assigned to CPU 0. +The +.Fn callout_reset_on , +.Fn callout_reset_sbt_on , +.Fn callout_schedule_on +and +.Fn callout_schedule_sbt_on +functions assign the callout to CPU +.Fa cpu . +The +.Fn callout_reset_curcpu , +.Fn callout_reset_sbt_curpu , +.Fn callout_schedule_curcpu +and +.Fn callout_schedule_sbt_curcpu +functions assign the callout to the current CPU. +The +.Fn callout_reset , +.Fn callout_reset_sbt , +.Fn callout_schedule +and +.Fn callout_schedule_sbt +functions schedule the callout to execute in the softclock thread of the CPU +to which it is currently assigned. +.Pp Softclock threads are not pinned to their respective CPUs by default. The softclock thread for CPU 0 can be pinned to CPU 0 by setting the .Va kern.pin_default_swi @@ -531,7 +427,50 @@ Softclock threads for CPUs other than zero can be pinned to their respective CPUs by setting the .Va kern.pin_pcpu_swi loader tunable to a non-zero value. -.Sh "AVOIDING RACE CONDITIONS" +.Pp +The macros +.Fn callout_pending , +.Fn callout_active +and +.Fn callout_deactivate +provide access to the current state of the callout. +The +.Fn callout_pending +macro checks whether a callout is +.Em pending ; +a callout is considered +.Em pending +when a timeout has been set but the time has not yet arrived. +Note that once the timeout time arrives and the callout subsystem +starts to process this callout, +.Fn callout_pending +will return +.Dv FALSE +even though the callout function may not have finished +.Pq or even begun +executing. +The +.Fn callout_active +macro checks whether a callout is marked as +.Em active , +and the +.Fn callout_deactivate +macro clears the callout's +.Em active +flag. +The callout subsystem marks a callout as +.Em active +when a timeout is set and it clears the +.Em active +flag in +.Fn callout_stop +and +.Fn callout_drain , +but it +.Em does not +clear it when a callout expires normally via the execution of the +callout function. +.Ss "Avoiding Race Conditions" The callout subsystem invokes callout functions from its own thread context. Without some kind of synchronization, @@ -548,7 +487,7 @@ synchronization concerns. The first approach is preferred as it is the simplest: .Bl -enum -offset indent .It -Callouts can be associated with a specific lock when they are initialised +Callouts can be associated with a specific lock when they are initialized by .Fn callout_init_mtx , .Fn callout_init_rm , @@ -569,7 +508,7 @@ or .Fn callout_schedule functions to provide this safety. .Pp -A callout initialised via +A callout initialized via .Fn callout_init with .Fa mpsafe @@ -592,8 +531,9 @@ function families .Pc indicates whether or not the callout was removed. If it is known that the callout was set and the callout function has -not yet executed, then a return value of zero indicates that the -callout function is about to be called. +not yet executed, then a return value of +.Dv FALSE +indicates that the callout function is about to be called. For example: .Bd -literal -offset indent if (sc->sc_flags & SCFLG_CALLOUT_RUNNING) { @@ -649,14 +589,16 @@ The callout function should first check the .Em pending flag and return without action if .Fn callout_pending -returns non-zero. +returns +.Dv TRUE . This indicates that the callout was rescheduled using .Fn callout_reset just before the callout function was invoked. If .Fn callout_active -returns zero then the callout function should also return without -action. +returns +.Dv FALSE +then the callout function should also return without action. This indicates that the callout has been stopped. Finally, the callout function should call .Fn callout_deactivate @@ -726,13 +668,129 @@ a callout should always be drained prior to destroying its associated lock or releasing the storage for the callout structure. .Sh LEGACY API .Bf Sy -The -.Fn timeout -and -.Fn untimeout -functions are a legacy API that will be removed in a future release. +The functions below are a legacy API that will be removed in a future release. New code should not use these routines. .Ef +.Pp +The function +.Fn timeout +schedules a call to the function given by the argument +.Fa func +to take place after +.Fa ticks Ns No /hz +seconds. +Non-positive values of +.Fa ticks +are silently converted to the value +.Sq 1 . +.Fa func +should be a pointer to a function that takes a +.Fa void * +argument. +Upon invocation, +.Fa func +will receive +.Fa arg +as its only argument. +The return value from +.Fn timeout +is a +.Ft struct callout_handle +which can be used in conjunction with the +.Fn untimeout +function to request that a scheduled timeout be canceled. +.Pp +The function +.Fn callout_handle_init +can be used to initialize a handle to a state which will cause +any calls to +.Fn untimeout +with that handle to return with no side +effects. +.Pp +Assigning a callout handle the value of +.Fn CALLOUT_HANDLE_INITIALIZER +performs the same function as +.Fn callout_handle_init +and is provided for use on statically declared or global callout handles. +.Pp +The function +.Fn untimeout +cancels the timeout associated with +.Fa handle +using the +.Fa func +and +.Fa arg +arguments to validate the handle. +If the handle does not correspond to a timeout with +the function +.Fa func +taking the argument +.Fa arg +no action is taken. +.Fa handle +must be initialized by a previous call to +.Fn timeout , +.Fn callout_handle_init , +or assigned the value of +.Fn CALLOUT_HANDLE_INITIALIZER "&handle" +before being passed to +.Fn untimeout . +The behavior of calling +.Fn untimeout +with an uninitialized handle +is undefined. +.Pp +As handles are recycled by the system, it is possible (although unlikely) +that a handle from one invocation of +.Fn timeout +may match the handle of another invocation of +.Fn timeout +if both calls used the same function pointer and argument, and the first +timeout is expired or canceled before the second call. +The timeout facility offers O(1) running time for +.Fn timeout +and +.Fn untimeout . +Timeouts are executed from +.Fn softclock +with the +.Va Giant +lock held. +Thus they are protected from re-entrancy. +.Sh RETURN VALUES +The +.Fn callout_active +macro returns the state of a callout's +.Em active +flag. +.Pp +The +.Fn callout_pending +macro returns the state of a callout's +.Em pending +flag. +.Pp +The +.Fn callout_reset +and +.Fn callout_schedule +function families return non-zero if the callout was pending before the new +function invocation was scheduled. +.Pp +The +.Fn callout_stop +and +.Fn callout_drain +functions return non-zero if the callout was still pending when it was +called or zero otherwise. +The +.Fn timeout +function returns a +.Ft struct callout_handle +that can be passed to +.Fn untimeout . .Sh HISTORY The current timeout and untimeout routines are based on the work of .An Adam M. Costello @@ -757,4 +815,4 @@ The current implementation replaces the long standing .Bx linked list callout mechanism which offered O(n) insertion and removal running time -and did not generate or require handles for untimeout operations. +but did not generate or require handles for untimeout operations. diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 922959f8fa57..beb49bc56962 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -504,8 +504,7 @@ proc0_init(void *dummy __unused) callout_init_mtx(&p->p_itcallout, &p->p_mtx, 0); callout_init_mtx(&p->p_limco, &p->p_mtx, 0); - mtx_init(&td->td_slpmutex, "td_slpmutex", NULL, MTX_SPIN); - callout_init_mtx(&td->td_slpcallout, &td->td_slpmutex, 0); + callout_init(&td->td_slpcallout, CALLOUT_MPSAFE); /* Create credentials. */ p->p_ucred = crget(); diff --git a/sys/kern/kern_condvar.c b/sys/kern/kern_condvar.c index 8c2691babb3f..2700a25d477c 100644 --- a/sys/kern/kern_condvar.c +++ b/sys/kern/kern_condvar.c @@ -313,13 +313,15 @@ _cv_timedwait_sbt(struct cv *cvp, struct lock_object *lock, sbintime_t sbt, DROP_GIANT(); sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0); - sleepq_release(cvp); sleepq_set_timeout_sbt(cvp, sbt, pr, flags); if (lock != &Giant.lock_object) { + if (class->lc_flags & LC_SLEEPABLE) + sleepq_release(cvp); WITNESS_SAVE(lock, lock_witness); lock_state = class->lc_unlock(lock); + if (class->lc_flags & LC_SLEEPABLE) + sleepq_lock(cvp); } - sleepq_lock(cvp); rval = sleepq_timedwait(cvp, 0); #ifdef KTRACE @@ -381,13 +383,15 @@ _cv_timedwait_sig_sbt(struct cv *cvp, struct lock_object *lock, sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR | SLEEPQ_INTERRUPTIBLE, 0); - sleepq_release(cvp); sleepq_set_timeout_sbt(cvp, sbt, pr, flags); if (lock != &Giant.lock_object) { + if (class->lc_flags & LC_SLEEPABLE) + sleepq_release(cvp); WITNESS_SAVE(lock, lock_witness); lock_state = class->lc_unlock(lock); + if (class->lc_flags & LC_SLEEPABLE) + sleepq_lock(cvp); } - sleepq_lock(cvp); rval = sleepq_timedwait_sig(cvp, 0); #ifdef KTRACE diff --git a/sys/kern/kern_lock.c b/sys/kern/kern_lock.c index 38c870709c31..36a8470d2971 100644 --- a/sys/kern/kern_lock.c +++ b/sys/kern/kern_lock.c @@ -210,11 +210,9 @@ sleeplk(struct lock *lk, u_int flags, struct lock_object *ilk, GIANT_SAVE(); sleepq_add(&lk->lock_object, NULL, wmesg, SLEEPQ_LK | (catch ? SLEEPQ_INTERRUPTIBLE : 0), queue); - if ((flags & LK_TIMELOCK) && timo) { - sleepq_release(&lk->lock_object); + if ((flags & LK_TIMELOCK) && timo) sleepq_set_timeout(&lk->lock_object, timo); - sleepq_lock(&lk->lock_object); - } + /* * Decisional switch for real sleeping. */ diff --git a/sys/kern/kern_switch.c b/sys/kern/kern_switch.c index 61d914944640..d0009b1042f3 100644 --- a/sys/kern/kern_switch.c +++ b/sys/kern/kern_switch.c @@ -93,6 +93,8 @@ SCHED_STAT_DEFINE_VAR(turnstile, &DPCPU_NAME(sched_switch_stats[SWT_TURNSTILE]), ""); SCHED_STAT_DEFINE_VAR(sleepq, &DPCPU_NAME(sched_switch_stats[SWT_SLEEPQ]), ""); +SCHED_STAT_DEFINE_VAR(sleepqtimo, + &DPCPU_NAME(sched_switch_stats[SWT_SLEEPQTIMO]), ""); SCHED_STAT_DEFINE_VAR(relinquish, &DPCPU_NAME(sched_switch_stats[SWT_RELINQUISH]), ""); SCHED_STAT_DEFINE_VAR(needresched, diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c index 19bf4e8a094a..9501ba2ba07d 100644 --- a/sys/kern/kern_synch.c +++ b/sys/kern/kern_synch.c @@ -236,16 +236,12 @@ _sleep(void *ident, struct lock_object *lock, int priority, * return from cursig(). */ sleepq_add(ident, lock, wmesg, sleepq_flags, 0); + if (sbt != 0) + sleepq_set_timeout_sbt(ident, sbt, pr, flags); if (lock != NULL && class->lc_flags & LC_SLEEPABLE) { sleepq_release(ident); WITNESS_SAVE(lock, lock_witness); lock_state = class->lc_unlock(lock); - if (sbt != 0) - sleepq_set_timeout_sbt(ident, sbt, pr, flags); - sleepq_lock(ident); - } else if (sbt != 0) { - sleepq_release(ident); - sleepq_set_timeout_sbt(ident, sbt, pr, flags); sleepq_lock(ident); } if (sbt != 0 && catch) @@ -310,11 +306,8 @@ msleep_spin_sbt(void *ident, struct mtx *mtx, const char *wmesg, * We put ourselves on the sleep queue and start our timeout. */ sleepq_add(ident, &mtx->lock_object, wmesg, SLEEPQ_SLEEP, 0); - if (sbt != 0) { - sleepq_release(ident); + if (sbt != 0) sleepq_set_timeout_sbt(ident, sbt, pr, flags); - sleepq_lock(ident); - } /* * Can't call ktrace with any spin locks held so it can lock the diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c index b1e1a1263597..2d0b0d278a56 100644 --- a/sys/kern/kern_thread.c +++ b/sys/kern/kern_thread.c @@ -149,9 +149,6 @@ thread_ctor(void *mem, int size, void *arg, int flags) audit_thread_alloc(td); #endif umtx_thread_alloc(td); - - mtx_init(&td->td_slpmutex, "td_slpmutex", NULL, MTX_SPIN); - callout_init_mtx(&td->td_slpcallout, &td->td_slpmutex, 0); return (0); } @@ -165,10 +162,6 @@ thread_dtor(void *mem, int size, void *arg) td = (struct thread *)mem; - /* make sure to drain any use of the "td->td_slpcallout" */ - callout_drain(&td->td_slpcallout); - mtx_destroy(&td->td_slpmutex); - #ifdef INVARIANTS /* Verify that this thread is in a safe state to free. */ switch (td->td_state) { @@ -551,6 +544,7 @@ thread_link(struct thread *td, struct proc *p) LIST_INIT(&td->td_lprof[0]); LIST_INIT(&td->td_lprof[1]); sigqueue_init(&td->td_sigqueue, p); + callout_init(&td->td_slpcallout, CALLOUT_MPSAFE); TAILQ_INSERT_TAIL(&p->p_threads, td, td_plist); p->p_numthreads++; } diff --git a/sys/kern/kern_timeout.c b/sys/kern/kern_timeout.c index 4336faab3bf7..13822fd99ac6 100644 --- a/sys/kern/kern_timeout.c +++ b/sys/kern/kern_timeout.c @@ -54,8 +54,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include -#include #include #include #include @@ -126,216 +124,37 @@ SYSCTL_INT(_kern, OID_AUTO, pin_pcpu_swi, CTLFLAG_RDTUN | CTLFLAG_NOFETCH, &pin_ */ u_int callwheelsize, callwheelmask; -typedef void callout_mutex_op_t(struct lock_object *); -typedef int callout_owned_op_t(struct lock_object *); - -struct callout_mutex_ops { - callout_mutex_op_t *lock; - callout_mutex_op_t *unlock; - callout_owned_op_t *owned; -}; - -enum { - CALLOUT_LC_UNUSED_0, - CALLOUT_LC_UNUSED_1, - CALLOUT_LC_UNUSED_2, - CALLOUT_LC_UNUSED_3, - CALLOUT_LC_SPIN, - CALLOUT_LC_MUTEX, - CALLOUT_LC_RW, - CALLOUT_LC_RM, -}; - -static void -callout_mutex_op_none(struct lock_object *lock) -{ -} - -static int -callout_owned_op_none(struct lock_object *lock) -{ - return (0); -} - -static void -callout_mutex_lock(struct lock_object *lock) -{ - mtx_lock((struct mtx *)lock); -} - -static void -callout_mutex_unlock(struct lock_object *lock) -{ - mtx_unlock((struct mtx *)lock); -} - -static void -callout_mutex_lock_spin(struct lock_object *lock) -{ - mtx_lock_spin((struct mtx *)lock); -} - -static void -callout_mutex_unlock_spin(struct lock_object *lock) -{ - mtx_unlock_spin((struct mtx *)lock); -} - -static int -callout_mutex_owned(struct lock_object *lock) -{ - return (mtx_owned((struct mtx *)lock)); -} - -static void -callout_rm_wlock(struct lock_object *lock) -{ - rm_wlock((struct rmlock *)lock); -} - -static void -callout_rm_wunlock(struct lock_object *lock) -{ - rm_wunlock((struct rmlock *)lock); -} - -static int -callout_rm_owned(struct lock_object *lock) -{ - return (rm_wowned((struct rmlock *)lock)); -} - -static void -callout_rw_wlock(struct lock_object *lock) -{ - rw_wlock((struct rwlock *)lock); -} - -static void -callout_rw_wunlock(struct lock_object *lock) -{ - rw_wunlock((struct rwlock *)lock); -} - -static int -callout_rw_owned(struct lock_object *lock) -{ - return (rw_wowned((struct rwlock *)lock)); -} - -static const struct callout_mutex_ops callout_mutex_ops[8] = { - [CALLOUT_LC_UNUSED_0] = { - .lock = callout_mutex_op_none, - .unlock = callout_mutex_op_none, - .owned = callout_owned_op_none, - }, - [CALLOUT_LC_UNUSED_1] = { - .lock = callout_mutex_op_none, - .unlock = callout_mutex_op_none, - .owned = callout_owned_op_none, - }, - [CALLOUT_LC_UNUSED_2] = { - .lock = callout_mutex_op_none, - .unlock = callout_mutex_op_none, - .owned = callout_owned_op_none, - }, - [CALLOUT_LC_UNUSED_3] = { - .lock = callout_mutex_op_none, - .unlock = callout_mutex_op_none, - .owned = callout_owned_op_none, - }, - [CALLOUT_LC_SPIN] = { - .lock = callout_mutex_lock_spin, - .unlock = callout_mutex_unlock_spin, - .owned = callout_mutex_owned, - }, - [CALLOUT_LC_MUTEX] = { - .lock = callout_mutex_lock, - .unlock = callout_mutex_unlock, - .owned = callout_mutex_owned, - }, - [CALLOUT_LC_RW] = { - .lock = callout_rw_wlock, - .unlock = callout_rw_wunlock, - .owned = callout_rw_owned, - }, - [CALLOUT_LC_RM] = { - .lock = callout_rm_wlock, - .unlock = callout_rm_wunlock, - .owned = callout_rm_owned, - }, -}; - -static void -callout_lock_client(int c_flags, struct lock_object *c_lock) -{ - callout_mutex_ops[CALLOUT_GET_LC(c_flags)].lock(c_lock); -} - -static void -callout_unlock_client(int c_flags, struct lock_object *c_lock) -{ - callout_mutex_ops[CALLOUT_GET_LC(c_flags)].unlock(c_lock); -} - -#ifdef SMP -static int -callout_lock_owned_client(int c_flags, struct lock_object *c_lock) -{ - return (callout_mutex_ops[CALLOUT_GET_LC(c_flags)].owned(c_lock)); -} -#endif - /* - * The callout CPU exec structure represent information necessary for - * describing the state of callouts currently running on the CPU and - * for handling deferred callout restarts. - * - * In particular, the first entry of the array cc_exec_entity holds - * information for callouts running from the SWI thread context, while - * the second one holds information for callouts running directly from - * the hardware interrupt context. + * The callout cpu exec entities represent informations necessary for + * describing the state of callouts currently running on the CPU and the ones + * necessary for migrating callouts to the new callout cpu. In particular, + * the first entry of the array cc_exec_entity holds informations for callout + * running in SWI thread context, while the second one holds informations + * for callout running directly from hardware interrupt context. + * The cached informations are very important for deferring migration when + * the migrating callout is already running. */ struct cc_exec { - /* - * The "cc_curr" points to the currently executing callout and - * is protected by the "cc_lock" spinlock. If no callback is - * currently executing it is equal to "NULL". - */ + struct callout *cc_next; struct callout *cc_curr; - /* - * The "cc_restart_args" structure holds the argument for a - * deferred callback restart and is protected by the "cc_lock" - * spinlock. The structure is only valid if "cc_restart" is - * "true". If "cc_restart" is "false" the information in the - * "cc_restart_args" structure shall be ignored. - */ - struct callout_args cc_restart_args; - bool cc_restart; - /* - * The "cc_cancel" variable allows the currently pending - * callback to be atomically cancelled. This field is write - * protected by the "cc_lock" spinlock. - */ - bool cc_cancel; - /* - * The "cc_drain_fn" points to a function which shall be - * called with the argument stored in "cc_drain_arg" when an - * asynchronous drain is performed. This field is write - * protected by the "cc_lock" spinlock. - */ - callout_func_t *cc_drain_fn; - void *cc_drain_arg; +#ifdef SMP + void (*ce_migration_func)(void *); + void *ce_migration_arg; + int ce_migration_cpu; + sbintime_t ce_migration_time; + sbintime_t ce_migration_prec; +#endif + bool cc_cancel; + bool cc_waiting; }; /* - * There is one "struct callout_cpu" per CPU, holding all relevant + * There is one struct callout_cpu per cpu, holding all relevant * state for the callout processing thread on the individual CPU. */ struct callout_cpu { struct mtx_padalign cc_lock; struct cc_exec cc_exec_entity[2]; - struct callout *cc_exec_next_dir; struct callout *cc_callout; struct callout_list *cc_callwheel; struct callout_tailq cc_expireq; @@ -347,7 +166,27 @@ struct callout_cpu { char cc_ktr_event_name[20]; }; +#define cc_exec_curr cc_exec_entity[0].cc_curr +#define cc_exec_next cc_exec_entity[0].cc_next +#define cc_exec_cancel cc_exec_entity[0].cc_cancel +#define cc_exec_waiting cc_exec_entity[0].cc_waiting +#define cc_exec_curr_dir cc_exec_entity[1].cc_curr +#define cc_exec_next_dir cc_exec_entity[1].cc_next +#define cc_exec_cancel_dir cc_exec_entity[1].cc_cancel +#define cc_exec_waiting_dir cc_exec_entity[1].cc_waiting + #ifdef SMP +#define cc_migration_func cc_exec_entity[0].ce_migration_func +#define cc_migration_arg cc_exec_entity[0].ce_migration_arg +#define cc_migration_cpu cc_exec_entity[0].ce_migration_cpu +#define cc_migration_time cc_exec_entity[0].ce_migration_time +#define cc_migration_prec cc_exec_entity[0].ce_migration_prec +#define cc_migration_func_dir cc_exec_entity[1].ce_migration_func +#define cc_migration_arg_dir cc_exec_entity[1].ce_migration_arg +#define cc_migration_cpu_dir cc_exec_entity[1].ce_migration_cpu +#define cc_migration_time_dir cc_exec_entity[1].ce_migration_time +#define cc_migration_prec_dir cc_exec_entity[1].ce_migration_prec + struct callout_cpu cc_cpu[MAXCPU]; #define CPUBLOCK MAXCPU #define CC_CPU(cpu) (&cc_cpu[(cpu)]) @@ -372,9 +211,60 @@ static void softclock_call_cc(struct callout *c, struct callout_cpu *cc, static MALLOC_DEFINE(M_CALLOUT, "callout", "Callout datastructures"); +/** + * Locked by cc_lock: + * cc_curr - If a callout is in progress, it is cc_curr. + * If cc_curr is non-NULL, threads waiting in + * callout_drain() will be woken up as soon as the + * relevant callout completes. + * cc_cancel - Changing to 1 with both callout_lock and cc_lock held + * guarantees that the current callout will not run. + * The softclock() function sets this to 0 before it + * drops callout_lock to acquire c_lock, and it calls + * the handler only if curr_cancelled is still 0 after + * cc_lock is successfully acquired. + * cc_waiting - If a thread is waiting in callout_drain(), then + * callout_wait is nonzero. Set only when + * cc_curr is non-NULL. + */ + /* - * Kernel low level callwheel initialization called from cpu0 during - * kernel startup: + * Resets the execution entity tied to a specific callout cpu. + */ +static void +cc_cce_cleanup(struct callout_cpu *cc, int direct) +{ + + cc->cc_exec_entity[direct].cc_curr = NULL; + cc->cc_exec_entity[direct].cc_next = NULL; + cc->cc_exec_entity[direct].cc_cancel = false; + cc->cc_exec_entity[direct].cc_waiting = false; +#ifdef SMP + cc->cc_exec_entity[direct].ce_migration_cpu = CPUBLOCK; + cc->cc_exec_entity[direct].ce_migration_time = 0; + cc->cc_exec_entity[direct].ce_migration_prec = 0; + cc->cc_exec_entity[direct].ce_migration_func = NULL; + cc->cc_exec_entity[direct].ce_migration_arg = NULL; +#endif +} + +/* + * Checks if migration is requested by a specific callout cpu. + */ +static int +cc_cce_migrating(struct callout_cpu *cc, int direct) +{ + +#ifdef SMP + return (cc->cc_exec_entity[direct].ce_migration_cpu != CPUBLOCK); +#else + return (0); +#endif +} + +/* + * Kernel low level callwheel initialization + * called on cpu0 during kernel startup. */ static void callout_callwheel_init(void *dummy) @@ -434,6 +324,8 @@ callout_cpu_init(struct callout_cpu *cc, int cpu) LIST_INIT(&cc->cc_callwheel[i]); TAILQ_INIT(&cc->cc_expireq); cc->cc_firstevent = SBT_MAX; + for (i = 0; i < 2; i++) + cc_cce_cleanup(cc, i); snprintf(cc->cc_ktr_event_name, sizeof(cc->cc_ktr_event_name), "callwheel cpu %d", cpu); if (cc->cc_callout == NULL) /* Only cpu0 handles timeout(9) */ @@ -441,11 +333,41 @@ callout_cpu_init(struct callout_cpu *cc, int cpu) for (i = 0; i < ncallout; i++) { c = &cc->cc_callout[i]; callout_init(c, 0); - c->c_flags |= CALLOUT_LOCAL_ALLOC; + c->c_flags = CALLOUT_LOCAL_ALLOC; SLIST_INSERT_HEAD(&cc->cc_callfree, c, c_links.sle); } } +#ifdef SMP +/* + * Switches the cpu tied to a specific callout. + * The function expects a locked incoming callout cpu and returns with + * locked outcoming callout cpu. + */ +static struct callout_cpu * +callout_cpu_switch(struct callout *c, struct callout_cpu *cc, int new_cpu) +{ + struct callout_cpu *new_cc; + + MPASS(c != NULL && cc != NULL); + CC_LOCK_ASSERT(cc); + + /* + * Avoid interrupts and preemption firing after the callout cpu + * is blocked in order to avoid deadlocks as the new thread + * may be willing to acquire the callout cpu lock. + */ + c->c_cpu = CPUBLOCK; + spinlock_enter(); + CC_UNLOCK(cc); + new_cc = CC_CPU(new_cpu); + CC_LOCK(new_cc); + spinlock_exit(); + c->c_cpu = new_cpu; + return (new_cc); +} +#endif + /* * Start standard softclock thread. */ @@ -522,8 +444,9 @@ callout_process(sbintime_t now) #ifdef CALLOUT_PROFILING int depth_dir = 0, mpcalls_dir = 0, lockcalls_dir = 0; #endif + cc = CC_SELF(); - CC_LOCK(cc); + mtx_lock_spin_flags(&cc->cc_lock, MTX_QUIET); /* Compute the buckets of the last scan and present times. */ firstb = callout_hash(cc->cc_lastscan); @@ -626,7 +549,7 @@ callout_process(sbintime_t now) avg_mpcalls_dir += (mpcalls_dir * 1000 - avg_mpcalls_dir) >> 8; avg_lockcalls_dir += (lockcalls_dir * 1000 - avg_lockcalls_dir) >> 8; #endif - CC_UNLOCK(cc); + mtx_unlock_spin_flags(&cc->cc_lock, MTX_QUIET); /* * swi_sched acquires the thread lock, so we don't want to call it * with cc_lock held; incorrect locking order. @@ -639,55 +562,49 @@ static struct callout_cpu * callout_lock(struct callout *c) { struct callout_cpu *cc; - cc = CC_CPU(c->c_cpu); - CC_LOCK(cc); + int cpu; + + for (;;) { + cpu = c->c_cpu; +#ifdef SMP + if (cpu == CPUBLOCK) { + while (c->c_cpu == CPUBLOCK) + cpu_spinwait(); + continue; + } +#endif + cc = CC_CPU(cpu); + CC_LOCK(cc); + if (cpu == c->c_cpu) + break; + CC_UNLOCK(cc); + } return (cc); } -static struct callout_cpu * -callout_cc_add_locked(struct callout *c, struct callout_cpu *cc, - struct callout_args *coa, bool can_swap_cpu) +static void +callout_cc_add(struct callout *c, struct callout_cpu *cc, + sbintime_t sbt, sbintime_t precision, void (*func)(void *), + void *arg, int cpu, int flags) { -#ifndef NO_EVENTTIMERS - sbintime_t sbt; -#endif int bucket; CC_LOCK_ASSERT(cc); - - /* update flags before swapping locks, if any */ - c->c_flags &= ~(CALLOUT_PROCESSED | CALLOUT_DIRECT | CALLOUT_DEFRESTART); - if (coa->flags & C_DIRECT_EXEC) - c->c_flags |= (CALLOUT_ACTIVE | CALLOUT_PENDING | CALLOUT_DIRECT); - else - c->c_flags |= (CALLOUT_ACTIVE | CALLOUT_PENDING); - -#ifdef SMP - /* - * Check if we are changing the CPU on which the callback - * should be executed and if we have a lock protecting us: - */ - if (can_swap_cpu != false && coa->cpu != c->c_cpu && - callout_lock_owned_client(c->c_flags, c->c_lock) != 0) { - CC_UNLOCK(cc); - c->c_cpu = coa->cpu; - cc = callout_lock(c); - } -#endif - if (coa->time < cc->cc_lastscan) - coa->time = cc->cc_lastscan; - c->c_arg = coa->arg; - c->c_func = coa->func; - c->c_time = coa->time; - c->c_precision = coa->precision; - + if (sbt < cc->cc_lastscan) + sbt = cc->cc_lastscan; + c->c_arg = arg; + c->c_flags |= (CALLOUT_ACTIVE | CALLOUT_PENDING); + if (flags & C_DIRECT_EXEC) + c->c_flags |= CALLOUT_DIRECT; + c->c_flags &= ~CALLOUT_PROCESSED; + c->c_func = func; + c->c_time = sbt; + c->c_precision = precision; bucket = callout_get_bucket(c->c_time); CTR3(KTR_CALLOUT, "precision set for %p: %d.%08x", c, (int)(c->c_precision >> 32), (u_int)(c->c_precision & 0xffffffff)); LIST_INSERT_HEAD(&cc->cc_callwheel[bucket], c, c_links.le); - - /* Ensure we are first to be scanned, if called via a callback */ if (cc->cc_bucket == bucket) cc->cc_exec_next_dir = c; #ifndef NO_EVENTTIMERS @@ -700,16 +617,17 @@ callout_cc_add_locked(struct callout *c, struct callout_cpu *cc, sbt = c->c_time + c->c_precision; if (sbt < cc->cc_firstevent) { cc->cc_firstevent = sbt; - cpu_new_callout(coa->cpu, sbt, c->c_time); + cpu_new_callout(cpu, sbt, c->c_time); } #endif - return (cc); } static void callout_cc_del(struct callout *c, struct callout_cpu *cc) { + if ((c->c_flags & CALLOUT_LOCAL_ALLOC) == 0) + return; c->c_func = NULL; SLIST_INSERT_HEAD(&cc->cc_callfree, c, c_links.sle); } @@ -721,10 +639,20 @@ softclock_call_cc(struct callout *c, struct callout_cpu *cc, #endif int direct) { - callout_func_t *c_func; + struct rm_priotracker tracker; + void (*c_func)(void *); void *c_arg; + struct lock_class *class; struct lock_object *c_lock; + uintptr_t lock_status; int c_flags; +#ifdef SMP + struct callout_cpu *new_cc; + void (*new_func)(void *); + void *new_arg; + int flags, new_cpu; + sbintime_t new_prec, new_time; +#endif #if defined(DIAGNOSTIC) || defined(CALLOUT_PROFILING) sbintime_t sbt1, sbt2; struct timespec ts2; @@ -735,39 +663,37 @@ softclock_call_cc(struct callout *c, struct callout_cpu *cc, KASSERT((c->c_flags & (CALLOUT_PENDING | CALLOUT_ACTIVE)) == (CALLOUT_PENDING | CALLOUT_ACTIVE), ("softclock_call_cc: pend|act %p %x", c, c->c_flags)); + class = (c->c_lock != NULL) ? LOCK_CLASS(c->c_lock) : NULL; + lock_status = 0; + if (c->c_flags & CALLOUT_SHAREDLOCK) { + if (class == &lock_class_rm) + lock_status = (uintptr_t)&tracker; + else + lock_status = 1; + } c_lock = c->c_lock; c_func = c->c_func; c_arg = c->c_arg; c_flags = c->c_flags; - - /* remove pending bit */ - c->c_flags &= ~CALLOUT_PENDING; - - /* reset our local state */ + if (c->c_flags & CALLOUT_LOCAL_ALLOC) + c->c_flags = CALLOUT_LOCAL_ALLOC; + else + c->c_flags &= ~CALLOUT_PENDING; cc->cc_exec_entity[direct].cc_curr = c; - cc->cc_exec_entity[direct].cc_restart = false; - cc->cc_exec_entity[direct].cc_drain_fn = NULL; - cc->cc_exec_entity[direct].cc_drain_arg = NULL; - + cc->cc_exec_entity[direct].cc_cancel = false; + CC_UNLOCK(cc); if (c_lock != NULL) { - cc->cc_exec_entity[direct].cc_cancel = false; - CC_UNLOCK(cc); - - /* unlocked region for switching locks */ - - callout_lock_client(c_flags, c_lock); - + class->lc_lock(c_lock, lock_status); /* - * Check if the callout may have been cancelled while - * we were switching locks. Even though the callout is - * specifying a lock, it might not be certain this - * lock is locked when starting and stopping callouts. + * The callout may have been cancelled + * while we switched locks. */ - CC_LOCK(cc); if (cc->cc_exec_entity[direct].cc_cancel) { - callout_unlock_client(c_flags, c_lock); - goto skip_cc_locked; + class->lc_unlock(c_lock); + goto skip; } + /* The callout cannot be stopped now. */ + cc->cc_exec_entity[direct].cc_cancel = true; if (c_lock == &Giant.lock_object) { #ifdef CALLOUT_PROFILING (*gcalls)++; @@ -788,11 +714,6 @@ softclock_call_cc(struct callout *c, struct callout_cpu *cc, CTR3(KTR_CALLOUT, "callout %p func %p arg %p", c, c_func, c_arg); } - /* The callout cannot be stopped now! */ - cc->cc_exec_entity[direct].cc_cancel = true; - CC_UNLOCK(cc); - - /* unlocked region */ KTR_STATE3(KTR_SCHED, "callout", cc->cc_ktr_event_name, "running", "func:%p", c_func, "arg:%p", c_arg, "direct:%d", direct); #if defined(DIAGNOSTIC) || defined(CALLOUT_PROFILING) @@ -819,40 +740,85 @@ softclock_call_cc(struct callout *c, struct callout_cpu *cc, #endif KTR_STATE0(KTR_SCHED, "callout", cc->cc_ktr_event_name, "idle"); CTR1(KTR_CALLOUT, "callout %p finished", c); - - /* - * At this point the callback structure might have been freed, - * so we need to check the previously copied value of - * "c->c_flags": - */ if ((c_flags & CALLOUT_RETURNUNLOCKED) == 0) - callout_unlock_client(c_flags, c_lock); - + class->lc_unlock(c_lock); +skip: CC_LOCK(cc); - -skip_cc_locked: KASSERT(cc->cc_exec_entity[direct].cc_curr == c, ("mishandled cc_curr")); cc->cc_exec_entity[direct].cc_curr = NULL; - - /* Check if there is anything which needs draining */ - if (cc->cc_exec_entity[direct].cc_drain_fn != NULL) { + if (cc->cc_exec_entity[direct].cc_waiting) { /* - * Unlock the CPU callout last, so that any use of - * structures belonging to the callout are complete: + * There is someone waiting for the + * callout to complete. + * If the callout was scheduled for + * migration just cancel it. */ + if (cc_cce_migrating(cc, direct)) { + cc_cce_cleanup(cc, direct); + + /* + * It should be assert here that the callout is not + * destroyed but that is not easy. + */ + c->c_flags &= ~CALLOUT_DFRMIGRATION; + } + cc->cc_exec_entity[direct].cc_waiting = false; CC_UNLOCK(cc); - /* call drain function unlocked */ - cc->cc_exec_entity[direct].cc_drain_fn( - cc->cc_exec_entity[direct].cc_drain_arg); + wakeup(&cc->cc_exec_entity[direct].cc_waiting); CC_LOCK(cc); - } else if (c_flags & CALLOUT_LOCAL_ALLOC) { - /* return callout back to freelist */ - callout_cc_del(c, cc); - } else if (cc->cc_exec_entity[direct].cc_restart) { - /* [re-]schedule callout, if any */ - cc = callout_cc_add_locked(c, cc, - &cc->cc_exec_entity[direct].cc_restart_args, false); + } else if (cc_cce_migrating(cc, direct)) { + KASSERT((c_flags & CALLOUT_LOCAL_ALLOC) == 0, + ("Migrating legacy callout %p", c)); +#ifdef SMP + /* + * If the callout was scheduled for + * migration just perform it now. + */ + new_cpu = cc->cc_exec_entity[direct].ce_migration_cpu; + new_time = cc->cc_exec_entity[direct].ce_migration_time; + new_prec = cc->cc_exec_entity[direct].ce_migration_prec; + new_func = cc->cc_exec_entity[direct].ce_migration_func; + new_arg = cc->cc_exec_entity[direct].ce_migration_arg; + cc_cce_cleanup(cc, direct); + + /* + * It should be assert here that the callout is not destroyed + * but that is not easy. + * + * As first thing, handle deferred callout stops. + */ + if ((c->c_flags & CALLOUT_DFRMIGRATION) == 0) { + CTR3(KTR_CALLOUT, + "deferred cancelled %p func %p arg %p", + c, new_func, new_arg); + callout_cc_del(c, cc); + return; + } + c->c_flags &= ~CALLOUT_DFRMIGRATION; + + new_cc = callout_cpu_switch(c, cc, new_cpu); + flags = (direct) ? C_DIRECT_EXEC : 0; + callout_cc_add(c, new_cc, new_time, new_prec, new_func, + new_arg, new_cpu, flags); + CC_UNLOCK(new_cc); + CC_LOCK(cc); +#else + panic("migration should not happen"); +#endif } + /* + * If the current callout is locally allocated (from + * timeout(9)) then put it on the freelist. + * + * Note: we need to check the cached copy of c_flags because + * if it was not local, then it's not safe to deref the + * callout pointer. + */ + KASSERT((c_flags & CALLOUT_LOCAL_ALLOC) == 0 || + c->c_flags == CALLOUT_LOCAL_ALLOC, + ("corrupted callout")); + if (c_flags & CALLOUT_LOCAL_ALLOC) + callout_cc_del(c, cc); } /* @@ -933,11 +899,10 @@ timeout(timeout_t *ftn, void *arg, int to_ticks) /* XXX Attempt to malloc first */ panic("timeout table full"); SLIST_REMOVE_HEAD(&cc->cc_callfree, c_links.sle); + callout_reset(new, to_ticks, ftn, arg); handle.callout = new; CC_UNLOCK(cc); - callout_reset(new, to_ticks, ftn, arg); - return (handle); } @@ -945,7 +910,6 @@ void untimeout(timeout_t *ftn, void *arg, struct callout_handle handle) { struct callout_cpu *cc; - bool match; /* * Check for a handle that was initialized @@ -956,11 +920,9 @@ untimeout(timeout_t *ftn, void *arg, struct callout_handle handle) return; cc = callout_lock(handle.callout); - match = (handle.callout->c_func == ftn && handle.callout->c_arg == arg); - CC_UNLOCK(cc); - - if (match) + if (handle.callout->c_func == ftn && handle.callout->c_arg == arg) callout_stop(handle.callout); + CC_UNLOCK(cc); } void @@ -969,119 +931,6 @@ callout_handle_init(struct callout_handle *handle) handle->callout = NULL; } -static int -callout_restart_async(struct callout *c, struct callout_args *coa, - callout_func_t *drain_fn, void *drain_arg) -{ - struct callout_cpu *cc; - int cancelled; - int direct; - - cc = callout_lock(c); - - /* Figure out if the callout is direct or not */ - direct = ((c->c_flags & CALLOUT_DIRECT) != 0); - - /* - * Check if the callback is currently scheduled for - * completion: - */ - if (cc->cc_exec_entity[direct].cc_curr == c) { - /* - * Try to prevent the callback from running by setting - * the "cc_cancel" variable to "true". Also check if - * the callout was previously subject to a deferred - * callout restart: - */ - if (cc->cc_exec_entity[direct].cc_cancel == false || - (c->c_flags & CALLOUT_DEFRESTART) != 0) { - cc->cc_exec_entity[direct].cc_cancel = true; - cancelled = 1; - } else { - cancelled = 0; - } - - /* - * Prevent callback restart if "callout_drain_xxx()" - * is being called or we are stopping the callout or - * the callback was preallocated by us: - */ - if (cc->cc_exec_entity[direct].cc_drain_fn != NULL || - coa == NULL || (c->c_flags & CALLOUT_LOCAL_ALLOC) != 0) { - CTR4(KTR_CALLOUT, "%s %p func %p arg %p", - cancelled ? "cancelled and draining" : "draining", - c, c->c_func, c->c_arg); - - /* clear old flags, if any */ - c->c_flags &= ~(CALLOUT_ACTIVE | CALLOUT_PENDING | - CALLOUT_DEFRESTART | CALLOUT_PROCESSED); - - /* clear restart flag, if any */ - cc->cc_exec_entity[direct].cc_restart = false; - - /* set drain function, if any */ - if (drain_fn != NULL) { - cc->cc_exec_entity[direct].cc_drain_fn = drain_fn; - cc->cc_exec_entity[direct].cc_drain_arg = drain_arg; - cancelled |= 2; /* XXX define the value */ - } - } else { - CTR4(KTR_CALLOUT, "%s %p func %p arg %p", - cancelled ? "cancelled and restarting" : "restarting", - c, c->c_func, c->c_arg); - - /* get us back into the game */ - c->c_flags |= (CALLOUT_ACTIVE | CALLOUT_PENDING | - CALLOUT_DEFRESTART); - c->c_flags &= ~CALLOUT_PROCESSED; - - /* enable deferred restart */ - cc->cc_exec_entity[direct].cc_restart = true; - - /* store arguments for the deferred restart, if any */ - cc->cc_exec_entity[direct].cc_restart_args = *coa; - } - } else { - /* stop callout */ - if (c->c_flags & CALLOUT_PENDING) { - /* - * The callback has not yet been executed, and - * we simply just need to unlink it: - */ - if ((c->c_flags & CALLOUT_PROCESSED) == 0) { - if (cc->cc_exec_next_dir == c) - cc->cc_exec_next_dir = LIST_NEXT(c, c_links.le); - LIST_REMOVE(c, c_links.le); - } else { - TAILQ_REMOVE(&cc->cc_expireq, c, c_links.tqe); - } - cancelled = 1; - } else { - cancelled = 0; - } - - CTR4(KTR_CALLOUT, "%s %p func %p arg %p", - cancelled ? "rescheduled" : "scheduled", - c, c->c_func, c->c_arg); - - /* [re-]schedule callout, if any */ - if (coa != NULL) { - cc = callout_cc_add_locked(c, cc, coa, true); - } else { - /* clear old flags, if any */ - c->c_flags &= ~(CALLOUT_ACTIVE | CALLOUT_PENDING | - CALLOUT_DEFRESTART | CALLOUT_PROCESSED); - - /* return callback to pre-allocated list, if any */ - if ((c->c_flags & CALLOUT_LOCAL_ALLOC) && cancelled != 0) { - callout_cc_del(c, cc); - } - } - } - CC_UNLOCK(cc); - return (cancelled); -} - /* * New interface; clients allocate their own callout structures. * @@ -1100,32 +949,25 @@ callout_restart_async(struct callout *c, struct callout_args *coa, */ int callout_reset_sbt_on(struct callout *c, sbintime_t sbt, sbintime_t precision, - callout_func_t *ftn, void *arg, int cpu, int flags) + void (*ftn)(void *), void *arg, int cpu, int flags) { - struct callout_args coa; + sbintime_t to_sbt, pr; + struct callout_cpu *cc; + int cancelled, direct; - /* store arguments for callout add function */ - coa.func = ftn; - coa.arg = arg; - coa.precision = precision; - coa.flags = flags; - coa.cpu = cpu; - - /* compute the rest of the arguments needed */ - if (coa.flags & C_ABSOLUTE) { - coa.time = sbt; + cancelled = 0; + if (flags & C_ABSOLUTE) { + to_sbt = sbt; } else { - sbintime_t pr; - - if ((coa.flags & C_HARDCLOCK) && (sbt < tick_sbt)) + if ((flags & C_HARDCLOCK) && (sbt < tick_sbt)) sbt = tick_sbt; - if ((coa.flags & C_HARDCLOCK) || + if ((flags & C_HARDCLOCK) || #ifdef NO_EVENTTIMERS sbt >= sbt_timethreshold) { - coa.time = getsbinuptime(); + to_sbt = getsbinuptime(); /* Add safety belt for the case of hz > 1000. */ - coa.time += tc_tick_sbt - tick_sbt; + to_sbt += tc_tick_sbt - tick_sbt; #else sbt >= sbt_tickthreshold) { /* @@ -1135,29 +977,101 @@ callout_reset_sbt_on(struct callout *c, sbintime_t sbt, sbintime_t precision, * active ones. */ #ifdef __LP64__ - coa.time = DPCPU_GET(hardclocktime); + to_sbt = DPCPU_GET(hardclocktime); #else spinlock_enter(); - coa.time = DPCPU_GET(hardclocktime); + to_sbt = DPCPU_GET(hardclocktime); spinlock_exit(); #endif #endif - if ((coa.flags & C_HARDCLOCK) == 0) - coa.time += tick_sbt; + if ((flags & C_HARDCLOCK) == 0) + to_sbt += tick_sbt; } else - coa.time = sbinuptime(); - if (SBT_MAX - coa.time < sbt) - coa.time = SBT_MAX; + to_sbt = sbinuptime(); + if (SBT_MAX - to_sbt < sbt) + to_sbt = SBT_MAX; else - coa.time += sbt; - pr = ((C_PRELGET(coa.flags) < 0) ? sbt >> tc_precexp : - sbt >> C_PRELGET(coa.flags)); - if (pr > coa.precision) - coa.precision = pr; + to_sbt += sbt; + pr = ((C_PRELGET(flags) < 0) ? sbt >> tc_precexp : + sbt >> C_PRELGET(flags)); + if (pr > precision) + precision = pr; + } + /* + * Don't allow migration of pre-allocated callouts lest they + * become unbalanced. + */ + if (c->c_flags & CALLOUT_LOCAL_ALLOC) + cpu = c->c_cpu; + direct = (c->c_flags & CALLOUT_DIRECT) != 0; + KASSERT(!direct || c->c_lock == NULL, + ("%s: direct callout %p has lock", __func__, c)); + cc = callout_lock(c); + if (cc->cc_exec_entity[direct].cc_curr == c) { + /* + * We're being asked to reschedule a callout which is + * currently in progress. If there is a lock then we + * can cancel the callout if it has not really started. + */ + if (c->c_lock != NULL && !cc->cc_exec_entity[direct].cc_cancel) + cancelled = cc->cc_exec_entity[direct].cc_cancel = true; + if (cc->cc_exec_entity[direct].cc_waiting) { + /* + * Someone has called callout_drain to kill this + * callout. Don't reschedule. + */ + CTR4(KTR_CALLOUT, "%s %p func %p arg %p", + cancelled ? "cancelled" : "failed to cancel", + c, c->c_func, c->c_arg); + CC_UNLOCK(cc); + return (cancelled); + } + } + if (c->c_flags & CALLOUT_PENDING) { + if ((c->c_flags & CALLOUT_PROCESSED) == 0) { + if (cc->cc_exec_next_dir == c) + cc->cc_exec_next_dir = LIST_NEXT(c, c_links.le); + LIST_REMOVE(c, c_links.le); + } else + TAILQ_REMOVE(&cc->cc_expireq, c, c_links.tqe); + cancelled = 1; + c->c_flags &= ~(CALLOUT_ACTIVE | CALLOUT_PENDING); } - /* get callback started, if any */ - return (callout_restart_async(c, &coa, NULL, NULL)); +#ifdef SMP + /* + * If the callout must migrate try to perform it immediately. + * If the callout is currently running, just defer the migration + * to a more appropriate moment. + */ + if (c->c_cpu != cpu) { + if (cc->cc_exec_entity[direct].cc_curr == c) { + cc->cc_exec_entity[direct].ce_migration_cpu = cpu; + cc->cc_exec_entity[direct].ce_migration_time + = to_sbt; + cc->cc_exec_entity[direct].ce_migration_prec + = precision; + cc->cc_exec_entity[direct].ce_migration_func = ftn; + cc->cc_exec_entity[direct].ce_migration_arg = arg; + c->c_flags |= CALLOUT_DFRMIGRATION; + CTR6(KTR_CALLOUT, + "migration of %p func %p arg %p in %d.%08x to %u deferred", + c, c->c_func, c->c_arg, (int)(to_sbt >> 32), + (u_int)(to_sbt & 0xffffffff), cpu); + CC_UNLOCK(cc); + return (cancelled); + } + cc = callout_cpu_switch(c, cc, cpu); + } +#endif + + callout_cc_add(c, cc, to_sbt, precision, ftn, arg, cpu, flags); + CTR6(KTR_CALLOUT, "%sscheduled %p func %p arg %p in %d.%08x", + cancelled ? "re" : "", c, c->c_func, c->c_arg, (int)(to_sbt >> 32), + (u_int)(to_sbt & 0xffffffff)); + CC_UNLOCK(cc); + + return (cancelled); } /* @@ -1176,105 +1090,204 @@ callout_schedule(struct callout *c, int to_ticks) } int -callout_stop(struct callout *c) +_callout_stop_safe(struct callout *c, int safe) { - /* get callback stopped, if any */ - return (callout_restart_async(c, NULL, NULL, NULL)); -} + struct callout_cpu *cc, *old_cc; + struct lock_class *class; + int direct, sq_locked, use_lock; -static void -callout_drain_function(void *arg) -{ - wakeup(arg); -} + /* + * Some old subsystems don't hold Giant while running a callout_stop(), + * so just discard this check for the moment. + */ + if (!safe && c->c_lock != NULL) { + if (c->c_lock == &Giant.lock_object) + use_lock = mtx_owned(&Giant); + else { + use_lock = 1; + class = LOCK_CLASS(c->c_lock); + class->lc_assert(c->c_lock, LA_XLOCKED); + } + } else + use_lock = 0; + direct = (c->c_flags & CALLOUT_DIRECT) != 0; + sq_locked = 0; + old_cc = NULL; +again: + cc = callout_lock(c); -int -callout_drain_async(struct callout *c, callout_func_t *fn, void *arg) -{ - /* get callback stopped, if any */ - return (callout_restart_async(c, NULL, fn, arg) & 2); -} + /* + * If the callout was migrating while the callout cpu lock was + * dropped, just drop the sleepqueue lock and check the states + * again. + */ + if (sq_locked != 0 && cc != old_cc) { +#ifdef SMP + CC_UNLOCK(cc); + sleepq_release(&old_cc->cc_exec_entity[direct].cc_waiting); + sq_locked = 0; + old_cc = NULL; + goto again; +#else + panic("migration should not happen"); +#endif + } -int -callout_drain(struct callout *c) -{ - int cancelled; - - WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, - "Draining callout"); - - callout_lock_client(c->c_flags, c->c_lock); - - /* at this point the "c->c_cpu" field is not changing */ - - cancelled = callout_drain_async(c, &callout_drain_function, c); - - if (cancelled != 0) { - struct callout_cpu *cc; - int direct; - - CTR3(KTR_CALLOUT, "need to drain %p func %p arg %p", - c, c->c_func, c->c_arg); - - cc = callout_lock(c); - direct = ((c->c_flags & CALLOUT_DIRECT) != 0); + /* + * If the callout isn't pending, it's not on the queue, so + * don't attempt to remove it from the queue. We can try to + * stop it by other means however. + */ + if (!(c->c_flags & CALLOUT_PENDING)) { + c->c_flags &= ~CALLOUT_ACTIVE; /* - * We've gotten our callout CPU lock, it is safe to - * drop the initial lock: + * If it wasn't on the queue and it isn't the current + * callout, then we can't stop it, so just bail. */ - callout_unlock_client(c->c_flags, c->c_lock); + if (cc->cc_exec_entity[direct].cc_curr != c) { + CTR3(KTR_CALLOUT, "failed to stop %p func %p arg %p", + c, c->c_func, c->c_arg); + CC_UNLOCK(cc); + if (sq_locked) + sleepq_release( + &cc->cc_exec_entity[direct].cc_waiting); + return (0); + } - /* Wait for drain to complete */ + if (safe) { + /* + * The current callout is running (or just + * about to run) and blocking is allowed, so + * just wait for the current invocation to + * finish. + */ + while (cc->cc_exec_entity[direct].cc_curr == c) { + /* + * Use direct calls to sleepqueue interface + * instead of cv/msleep in order to avoid + * a LOR between cc_lock and sleepqueue + * chain spinlocks. This piece of code + * emulates a msleep_spin() call actually. + * + * If we already have the sleepqueue chain + * locked, then we can safely block. If we + * don't already have it locked, however, + * we have to drop the cc_lock to lock + * it. This opens several races, so we + * restart at the beginning once we have + * both locks. If nothing has changed, then + * we will end up back here with sq_locked + * set. + */ + if (!sq_locked) { + CC_UNLOCK(cc); + sleepq_lock( + &cc->cc_exec_entity[direct].cc_waiting); + sq_locked = 1; + old_cc = cc; + goto again; + } - while (cc->cc_exec_entity[direct].cc_curr == c) - msleep_spin(c, (struct mtx *)&cc->cc_lock, "codrain", 0); + /* + * Migration could be cancelled here, but + * as long as it is still not sure when it + * will be packed up, just let softclock() + * take care of it. + */ + cc->cc_exec_entity[direct].cc_waiting = true; + DROP_GIANT(); + CC_UNLOCK(cc); + sleepq_add( + &cc->cc_exec_entity[direct].cc_waiting, + &cc->cc_lock.lock_object, "codrain", + SLEEPQ_SLEEP, 0); + sleepq_wait( + &cc->cc_exec_entity[direct].cc_waiting, + 0); + sq_locked = 0; + old_cc = NULL; + /* Reacquire locks previously released. */ + PICKUP_GIANT(); + CC_LOCK(cc); + } + } else if (use_lock && + !cc->cc_exec_entity[direct].cc_cancel) { + /* + * The current callout is waiting for its + * lock which we hold. Cancel the callout + * and return. After our caller drops the + * lock, the callout will be skipped in + * softclock(). + */ + cc->cc_exec_entity[direct].cc_cancel = true; + CTR3(KTR_CALLOUT, "cancelled %p func %p arg %p", + c, c->c_func, c->c_arg); + KASSERT(!cc_cce_migrating(cc, direct), + ("callout wrongly scheduled for migration")); + CC_UNLOCK(cc); + KASSERT(!sq_locked, ("sleepqueue chain locked")); + return (1); + } else if ((c->c_flags & CALLOUT_DFRMIGRATION) != 0) { + c->c_flags &= ~CALLOUT_DFRMIGRATION; + CTR3(KTR_CALLOUT, "postponing stop %p func %p arg %p", + c, c->c_func, c->c_arg); + CC_UNLOCK(cc); + return (1); + } + CTR3(KTR_CALLOUT, "failed to stop %p func %p arg %p", + c, c->c_func, c->c_arg); CC_UNLOCK(cc); - } else { - callout_unlock_client(c->c_flags, c->c_lock); + KASSERT(!sq_locked, ("sleepqueue chain still locked")); + return (0); } + if (sq_locked) + sleepq_release(&cc->cc_exec_entity[direct].cc_waiting); + + c->c_flags &= ~(CALLOUT_ACTIVE | CALLOUT_PENDING); CTR3(KTR_CALLOUT, "cancelled %p func %p arg %p", c, c->c_func, c->c_arg); + if ((c->c_flags & CALLOUT_PROCESSED) == 0) { + if (cc->cc_exec_next_dir == c) + cc->cc_exec_next_dir = LIST_NEXT(c, c_links.le); + LIST_REMOVE(c, c_links.le); + } else + TAILQ_REMOVE(&cc->cc_expireq, c, c_links.tqe); + callout_cc_del(c, cc); - return (cancelled & 1); + CC_UNLOCK(cc); + return (1); } void callout_init(struct callout *c, int mpsafe) { + bzero(c, sizeof *c); if (mpsafe) { - _callout_init_lock(c, NULL, CALLOUT_RETURNUNLOCKED); + c->c_lock = NULL; + c->c_flags = CALLOUT_RETURNUNLOCKED; } else { - _callout_init_lock(c, &Giant.lock_object, 0); + c->c_lock = &Giant.lock_object; + c->c_flags = 0; } + c->c_cpu = timeout_cpu; } void _callout_init_lock(struct callout *c, struct lock_object *lock, int flags) { bzero(c, sizeof *c); - KASSERT((flags & ~CALLOUT_RETURNUNLOCKED) == 0, - ("callout_init_lock: bad flags 0x%08x", flags)); - flags &= CALLOUT_RETURNUNLOCKED; - if (lock != NULL) { - struct lock_class *class = LOCK_CLASS(lock); - if (class == &lock_class_mtx_sleep) - flags |= CALLOUT_SET_LC(CALLOUT_LC_MUTEX); - else if (class == &lock_class_mtx_spin) - flags |= CALLOUT_SET_LC(CALLOUT_LC_SPIN); - else if (class == &lock_class_rm) - flags |= CALLOUT_SET_LC(CALLOUT_LC_RM); - else if (class == &lock_class_rw) - flags |= CALLOUT_SET_LC(CALLOUT_LC_RW); - else - panic("callout_init_lock: Unsupported lock class '%s'\n", class->lc_name); - } else { - flags |= CALLOUT_SET_LC(CALLOUT_LC_UNUSED_0); - } c->c_lock = lock; - c->c_flags = flags; + KASSERT((flags & ~(CALLOUT_RETURNUNLOCKED | CALLOUT_SHAREDLOCK)) == 0, + ("callout_init_lock: bad flags %d", flags)); + KASSERT(lock != NULL || (flags & CALLOUT_RETURNUNLOCKED) == 0, + ("callout_init_lock: CALLOUT_RETURNUNLOCKED with no lock")); + KASSERT(lock == NULL || !(LOCK_CLASS(lock)->lc_flags & + (LC_SPINLOCK | LC_SLEEPABLE)), ("%s: invalid lock class", + __func__)); + c->c_flags = flags & (CALLOUT_RETURNUNLOCKED | CALLOUT_SHAREDLOCK); c->c_cpu = timeout_cpu; } diff --git a/sys/kern/subr_sleepqueue.c b/sys/kern/subr_sleepqueue.c index 18dc2a058f50..bbbec920ef0d 100644 --- a/sys/kern/subr_sleepqueue.c +++ b/sys/kern/subr_sleepqueue.c @@ -152,8 +152,7 @@ static uma_zone_t sleepq_zone; */ static int sleepq_catch_signals(void *wchan, int pri); static int sleepq_check_signals(void); -static int sleepq_check_timeout(struct thread *); -static void sleepq_stop_timeout(struct thread *); +static int sleepq_check_timeout(void); #ifdef INVARIANTS static void sleepq_dtor(void *mem, int size, void *arg); #endif @@ -374,14 +373,17 @@ void sleepq_set_timeout_sbt(void *wchan, sbintime_t sbt, sbintime_t pr, int flags) { + struct sleepqueue_chain *sc; struct thread *td; td = curthread; - - mtx_lock_spin(&td->td_slpmutex); + sc = SC_LOOKUP(wchan); + mtx_assert(&sc->sc_lock, MA_OWNED); + MPASS(TD_ON_SLEEPQ(td)); + MPASS(td->td_sleepqueue == NULL); + MPASS(wchan != NULL); callout_reset_sbt_on(&td->td_slpcallout, sbt, pr, sleepq_timeout, td, PCPU_GET(cpuid), flags | C_DIRECT_EXEC); - mtx_unlock_spin(&td->td_slpmutex); } /* @@ -557,8 +559,11 @@ sleepq_switch(void *wchan, int pri) * Check to see if we timed out. */ static int -sleepq_check_timeout(struct thread *td) +sleepq_check_timeout(void) { + struct thread *td; + + td = curthread; THREAD_LOCK_ASSERT(td, MA_OWNED); /* @@ -568,18 +573,25 @@ sleepq_check_timeout(struct thread *td) td->td_flags &= ~TDF_TIMEOUT; return (EWOULDBLOCK); } - return (0); -} -/* - * Atomically stop the timeout by using a mutex. - */ -static void -sleepq_stop_timeout(struct thread *td) -{ - mtx_lock_spin(&td->td_slpmutex); - callout_stop(&td->td_slpcallout); - mtx_unlock_spin(&td->td_slpmutex); + /* + * If TDF_TIMOFAIL is set, the timeout ran after we had + * already been woken up. + */ + if (td->td_flags & TDF_TIMOFAIL) + td->td_flags &= ~TDF_TIMOFAIL; + + /* + * If callout_stop() fails, then the timeout is running on + * another CPU, so synchronize with it to avoid having it + * accidentally wake up a subsequent sleep. + */ + else if (callout_stop(&td->td_slpcallout) == 0) { + td->td_flags |= TDF_TIMEOUT; + TD_SET_SLEEPING(td); + mi_switch(SW_INVOL | SWT_SLEEPQTIMO, NULL); + } + return (0); } /* @@ -652,11 +664,9 @@ sleepq_timedwait(void *wchan, int pri) MPASS(!(td->td_flags & TDF_SINTR)); thread_lock(td); sleepq_switch(wchan, pri); - rval = sleepq_check_timeout(td); + rval = sleepq_check_timeout(); thread_unlock(td); - sleepq_stop_timeout(td); - return (rval); } @@ -667,18 +677,12 @@ sleepq_timedwait(void *wchan, int pri) int sleepq_timedwait_sig(void *wchan, int pri) { - struct thread *td; int rcatch, rvalt, rvals; - td = curthread; - rcatch = sleepq_catch_signals(wchan, pri); - rvalt = sleepq_check_timeout(td); + rvalt = sleepq_check_timeout(); rvals = sleepq_check_signals(); - thread_unlock(td); - - sleepq_stop_timeout(td); - + thread_unlock(curthread); if (rcatch) return (rcatch); if (rvals) @@ -885,49 +889,64 @@ sleepq_broadcast(void *wchan, int flags, int pri, int queue) static void sleepq_timeout(void *arg) { - struct thread *td = arg; - int wakeup_swapper = 0; + struct sleepqueue_chain *sc; + struct sleepqueue *sq; + struct thread *td; + void *wchan; + int wakeup_swapper; + td = arg; + wakeup_swapper = 0; CTR3(KTR_PROC, "sleepq_timeout: thread %p (pid %ld, %s)", (void *)td, (long)td->td_proc->p_pid, (void *)td->td_name); - /* Handle the three cases which can happen */ - + /* + * First, see if the thread is asleep and get the wait channel if + * it is. + */ thread_lock(td); - if (TD_ON_SLEEPQ(td)) { - if (TD_IS_SLEEPING(td)) { - struct sleepqueue_chain *sc; - struct sleepqueue *sq; - void *wchan; - - /* - * Case I - thread is asleep and needs to be - * awoken: - */ - wchan = td->td_wchan; - sc = SC_LOOKUP(wchan); - THREAD_LOCKPTR_ASSERT(td, &sc->sc_lock); - sq = sleepq_lookup(wchan); - MPASS(sq != NULL); - td->td_flags |= TDF_TIMEOUT; - wakeup_swapper = sleepq_resume_thread(sq, td, 0); - } else { - /* - * Case II - cancel going to sleep by setting - * the timeout flag because the target thread - * is not asleep yet. It can be on another CPU - * in between sleepq_add() and one of the - * sleepq_*wait*() routines or it can be in - * sleepq_catch_signals(). - */ - td->td_flags |= TDF_TIMEOUT; - } - } else { - /* - * Case III - thread is already woken up by a wakeup - * call and should not timeout. Nothing to do! - */ + if (TD_IS_SLEEPING(td) && TD_ON_SLEEPQ(td)) { + wchan = td->td_wchan; + sc = SC_LOOKUP(wchan); + THREAD_LOCKPTR_ASSERT(td, &sc->sc_lock); + sq = sleepq_lookup(wchan); + MPASS(sq != NULL); + td->td_flags |= TDF_TIMEOUT; + wakeup_swapper = sleepq_resume_thread(sq, td, 0); + thread_unlock(td); + if (wakeup_swapper) + kick_proc0(); + return; } + + /* + * If the thread is on the SLEEPQ but isn't sleeping yet, it + * can either be on another CPU in between sleepq_add() and + * one of the sleepq_*wait*() routines or it can be in + * sleepq_catch_signals(). + */ + if (TD_ON_SLEEPQ(td)) { + td->td_flags |= TDF_TIMEOUT; + thread_unlock(td); + return; + } + + /* + * Now check for the edge cases. First, if TDF_TIMEOUT is set, + * then the other thread has already yielded to us, so clear + * the flag and resume it. If TDF_TIMEOUT is not set, then the + * we know that the other thread is not on a sleep queue, but it + * hasn't resumed execution yet. In that case, set TDF_TIMOFAIL + * to let it know that the timeout has already run and doesn't + * need to be canceled. + */ + if (td->td_flags & TDF_TIMEOUT) { + MPASS(TD_IS_SLEEPING(td)); + td->td_flags &= ~TDF_TIMEOUT; + TD_CLR_SLEEPING(td); + wakeup_swapper = setrunnable(td); + } else + td->td_flags |= TDF_TIMOFAIL; thread_unlock(td); if (wakeup_swapper) kick_proc0(); diff --git a/sys/ofed/include/linux/completion.h b/sys/ofed/include/linux/completion.h index 088828399c78..df4aec3595e4 100644 --- a/sys/ofed/include/linux/completion.h +++ b/sys/ofed/include/linux/completion.h @@ -105,9 +105,7 @@ _wait_for_timeout_common(struct completion *c, long timeout, int flags) if (c->done) break; sleepq_add(c, NULL, "completion", flags, 0); - sleepq_release(c); sleepq_set_timeout(c, end - ticks); - sleepq_lock(c); if (flags & SLEEPQ_INTERRUPTIBLE) { if (sleepq_timedwait_sig(c, 0) != 0) return (-ERESTARTSYS); diff --git a/sys/sys/_callout.h b/sys/sys/_callout.h index f58a3835c973..e186aecb8ddf 100644 --- a/sys/sys/_callout.h +++ b/sys/sys/_callout.h @@ -46,30 +46,19 @@ LIST_HEAD(callout_list, callout); SLIST_HEAD(callout_slist, callout); TAILQ_HEAD(callout_tailq, callout); -typedef void callout_func_t(void *); - -struct callout_args { - sbintime_t time; /* absolute time for the event */ - sbintime_t precision; /* delta allowed wrt opt */ - void *arg; /* function argument */ - callout_func_t *func; /* function to call */ - int flags; /* flags passed to callout_reset() */ - int cpu; /* CPU we're scheduled on */ -}; - struct callout { union { LIST_ENTRY(callout) le; SLIST_ENTRY(callout) sle; TAILQ_ENTRY(callout) tqe; } c_links; - sbintime_t c_time; /* absolute time for the event */ + sbintime_t c_time; /* ticks to the event */ sbintime_t c_precision; /* delta allowed wrt opt */ void *c_arg; /* function argument */ - callout_func_t *c_func; /* function to call */ - struct lock_object *c_lock; /* callback lock */ + void (*c_func)(void *); /* function to call */ + struct lock_object *c_lock; /* lock to handle */ int c_flags; /* state of this entry */ - int c_cpu; /* CPU we're scheduled on */ + volatile int c_cpu; /* CPU we're scheduled on */ }; #endif diff --git a/sys/sys/callout.h b/sys/sys/callout.h index 235da99f039a..1096cb26ff92 100644 --- a/sys/sys/callout.h +++ b/sys/sys/callout.h @@ -45,12 +45,10 @@ #define CALLOUT_PENDING 0x0004 /* callout is waiting for timeout */ #define CALLOUT_MPSAFE 0x0008 /* callout handler is mp safe */ #define CALLOUT_RETURNUNLOCKED 0x0010 /* handler returns with mtx unlocked */ -#define CALLOUT_UNUSED_5 0x0020 /* --available-- */ -#define CALLOUT_DEFRESTART 0x0040 /* callout restart is deferred */ +#define CALLOUT_SHAREDLOCK 0x0020 /* callout lock held in shared mode */ +#define CALLOUT_DFRMIGRATION 0x0040 /* callout in deferred migration mode */ #define CALLOUT_PROCESSED 0x0080 /* callout in wheel or processing list? */ #define CALLOUT_DIRECT 0x0100 /* allow exec from hw int context */ -#define CALLOUT_SET_LC(x) (((x) & 7) << 16) /* set lock class */ -#define CALLOUT_GET_LC(x) (((x) >> 16) & 7) /* get lock class */ #define C_DIRECT_EXEC 0x0001 /* direct execution of callout */ #define C_PRELBITS 7 @@ -67,8 +65,7 @@ struct callout_handle { #ifdef _KERNEL #define callout_active(c) ((c)->c_flags & CALLOUT_ACTIVE) #define callout_deactivate(c) ((c)->c_flags &= ~CALLOUT_ACTIVE) -int callout_drain(struct callout *); -int callout_drain_async(struct callout *, callout_func_t *, void *); +#define callout_drain(c) _callout_stop_safe(c, 1) void callout_init(struct callout *, int); void _callout_init_lock(struct callout *, struct lock_object *, int); #define callout_init_mtx(c, mtx, flags) \ @@ -82,7 +79,7 @@ void _callout_init_lock(struct callout *, struct lock_object *, int); NULL, (flags)) #define callout_pending(c) ((c)->c_flags & CALLOUT_PENDING) int callout_reset_sbt_on(struct callout *, sbintime_t, sbintime_t, - callout_func_t *, void *, int, int); + void (*)(void *), void *, int, int); #define callout_reset_sbt(c, sbt, pr, fn, arg, flags) \ callout_reset_sbt_on((c), (sbt), (pr), (fn), (arg), (c)->c_cpu, (flags)) #define callout_reset_sbt_curcpu(c, sbt, pr, fn, arg, flags) \ @@ -106,7 +103,8 @@ int callout_schedule(struct callout *, int); int callout_schedule_on(struct callout *, int, int); #define callout_schedule_curcpu(c, on_tick) \ callout_schedule_on((c), (on_tick), PCPU_GET(cpuid)) -int callout_stop(struct callout *); +#define callout_stop(c) _callout_stop_safe(c, 0) +int _callout_stop_safe(struct callout *, int); void callout_process(sbintime_t now); #endif diff --git a/sys/sys/param.h b/sys/sys/param.h index 0babf847870c..bf59b0bf7226 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -58,7 +58,7 @@ * in the range 5 to 9. */ #undef __FreeBSD_version -#define __FreeBSD_version 1100054 /* Master, propagated to newvers */ +#define __FreeBSD_version 1100055 /* Master, propagated to newvers */ /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD, diff --git a/sys/sys/proc.h b/sys/sys/proc.h index e694d918c45e..9b6c695d37fb 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -308,7 +308,6 @@ struct thread { } td_uretoff; /* (k) Syscall aux returns. */ #define td_retval td_uretoff.tdu_retval struct callout td_slpcallout; /* (h) Callout for sleep. */ - struct mtx td_slpmutex; /* (h) Mutex for sleep callout */ struct trapframe *td_frame; /* (k) */ struct vm_object *td_kstack_obj;/* (a) Kstack object. */ vm_offset_t td_kstack; /* (a) Kernel VA of kstack. */ @@ -365,7 +364,7 @@ do { \ #define TDF_ALLPROCSUSP 0x00000200 /* suspended by SINGLE_ALLPROC */ #define TDF_BOUNDARY 0x00000400 /* Thread suspended at user boundary */ #define TDF_ASTPENDING 0x00000800 /* Thread has some asynchronous events. */ -#define TDF_UNUSED12 0x00001000 /* --available-- */ +#define TDF_TIMOFAIL 0x00001000 /* Timeout from sleep after we were awake. */ #define TDF_SBDRY 0x00002000 /* Stop only on usermode boundary. */ #define TDF_UPIBLOCKED 0x00004000 /* Thread blocked on user PI mutex. */ #define TDF_NEEDSUSPCHK 0x00008000 /* Thread may need to suspend. */ @@ -707,7 +706,7 @@ struct proc { #define SWT_OWEPREEMPT 2 /* Switching due to opepreempt. */ #define SWT_TURNSTILE 3 /* Turnstile contention. */ #define SWT_SLEEPQ 4 /* Sleepq wait. */ -#define SWT_UNUSED5 5 /* --available-- */ +#define SWT_SLEEPQTIMO 5 /* Sleepq timeout wait. */ #define SWT_RELINQUISH 6 /* yield call. */ #define SWT_NEEDRESCHED 7 /* NEEDRESCHED was set. */ #define SWT_IDLE 8 /* Switching from the idle thread. */ From 8338b606180e552e36385959efa54801319e7358 Mon Sep 17 00:00:00 2001 From: mav Date: Thu, 22 Jan 2015 14:49:36 +0000 Subject: [PATCH 168/258] Don't count requests with status sent as overlapping. While those requests are still in target OOA queue, for initiator they are already completed, so tags can be reused. MFC after: 1 week --- sys/cam/ctl/ctl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c index e90a029b3593..35651779d410 100644 --- a/sys/cam/ctl/ctl.c +++ b/sys/cam/ctl/ctl.c @@ -10826,7 +10826,8 @@ ctl_check_for_blockage(struct ctl_lun *lun, union ctl_io *pending_io, ooa_io->io_hdr.nexus.targ_port) && (pending_io->io_hdr.nexus.initid.id == ooa_io->io_hdr.nexus.initid.id)) - && ((ooa_io->io_hdr.flags & CTL_FLAG_ABORT) == 0)) + && ((ooa_io->io_hdr.flags & (CTL_FLAG_ABORT | + CTL_FLAG_STATUS_SENT)) == 0)) return (CTL_ACTION_OVERLAP); /* @@ -10847,7 +10848,8 @@ ctl_check_for_blockage(struct ctl_lun *lun, union ctl_io *pending_io, ooa_io->io_hdr.nexus.targ_port) && (pending_io->io_hdr.nexus.initid.id == ooa_io->io_hdr.nexus.initid.id)) - && ((ooa_io->io_hdr.flags & CTL_FLAG_ABORT) == 0)) + && ((ooa_io->io_hdr.flags & (CTL_FLAG_ABORT | + CTL_FLAG_STATUS_SENT)) == 0)) return (CTL_ACTION_OVERLAP_TAG); /* From da2c397fb79fb2d06cf43afe833f63bca20ae949 Mon Sep 17 00:00:00 2001 From: will Date: Thu, 22 Jan 2015 17:09:54 +0000 Subject: [PATCH 169/258] Improve CARP logging so that all state transitions are logged. sys/netinet/ip_carp.c: Add a "reason" string parameter to carp_set_state() and carp_master_down_locked() allowing more specific logging information to be passed into these apis. Refactor existing state transition logging into a single log call in carp_set_state(). Update all calls to carp_set_state() and carp_master_down_locked() to pass an appropriate reason string. For state transitions that were previously logged, the output should be unchanged. Submitted by: gibbs (original), asomers (updated) MFC after: 1 week Sponsored by: Spectra Logic MFSpectraBSD: 1039697 on 2014/02/11 (original) 1049992 on 2014/03/21 (updated) --- sys/netinet/ip_carp.c | 57 +++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 34 deletions(-) diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index 4ecc58a0dfb2..5c449c0ddd56 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -304,11 +304,12 @@ static void carp_destroy(struct carp_softc *); static struct carp_if *carp_alloc_if(struct ifnet *); static void carp_free_if(struct carp_if *); -static void carp_set_state(struct carp_softc *, int); +static void carp_set_state(struct carp_softc *, int, const char* reason); static void carp_sc_state(struct carp_softc *); static void carp_setrun(struct carp_softc *, sa_family_t); static void carp_master_down(void *); -static void carp_master_down_locked(struct carp_softc *); +static void carp_master_down_locked(struct carp_softc *, + const char* reason); static void carp_send_ad(void *); static void carp_send_ad_locked(struct carp_softc *); static void carp_addroute(struct carp_softc *); @@ -654,11 +655,8 @@ carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af) if (timevalcmp(&sc_tv, &ch_tv, >) || timevalcmp(&sc_tv, &ch_tv, ==)) { callout_stop(&sc->sc_ad_tmo); - CARP_LOG("VHID %u@%s: MASTER -> BACKUP " - "(more frequent advertisement received)\n", - sc->sc_vhid, - sc->sc_carpdev->if_xname); - carp_set_state(sc, BACKUP); + carp_set_state(sc, BACKUP, + "more frequent advertisement received"); carp_setrun(sc, 0); carp_delroute(sc); } @@ -669,11 +667,8 @@ carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af) * and this one claims to be slower, treat him as down. */ if (V_carp_preempt && timevalcmp(&sc_tv, &ch_tv, <)) { - CARP_LOG("VHID %u@%s: BACKUP -> MASTER " - "(preempting a slower master)\n", - sc->sc_vhid, - sc->sc_carpdev->if_xname); - carp_master_down_locked(sc); + carp_master_down_locked(sc, + "preempting a slower master"); break; } @@ -684,11 +679,7 @@ carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af) */ sc_tv.tv_sec = sc->sc_advbase * 3; if (timevalcmp(&sc_tv, &ch_tv, <)) { - CARP_LOG("VHID %u@%s: BACKUP -> MASTER " - "(master timed out)\n", - sc->sc_vhid, - sc->sc_carpdev->if_xname); - carp_master_down_locked(sc); + carp_master_down_locked(sc, "master will time out"); break; } @@ -1153,10 +1144,7 @@ carp_master_down(void *v) CURVNET_SET(sc->sc_carpdev->if_vnet); if (sc->sc_state == BACKUP) { - CARP_LOG("VHID %u@%s: BACKUP -> MASTER (master down)\n", - sc->sc_vhid, - sc->sc_carpdev->if_xname); - carp_master_down_locked(sc); + carp_master_down_locked(sc, "master timed out"); } CURVNET_RESTORE(); @@ -1164,14 +1152,14 @@ carp_master_down(void *v) } static void -carp_master_down_locked(struct carp_softc *sc) +carp_master_down_locked(struct carp_softc *sc, const char *reason) { CARP_LOCK_ASSERT(sc); switch (sc->sc_state) { case BACKUP: - carp_set_state(sc, MASTER); + carp_set_state(sc, MASTER, reason); carp_send_ad_locked(sc); #ifdef INET carp_send_arp(sc); @@ -1212,10 +1200,7 @@ carp_setrun(struct carp_softc *sc, sa_family_t af) switch (sc->sc_state) { case INIT: - CARP_LOG("VHID %u@%s: INIT -> BACKUP\n", - sc->sc_vhid, - sc->sc_carpdev->if_xname); - carp_set_state(sc, BACKUP); + carp_set_state(sc, BACKUP, "initialization complete"); carp_setrun(sc, 0); break; case BACKUP: @@ -1717,12 +1702,12 @@ carp_ioctl(struct ifreq *ifr, u_long cmd, struct thread *td) switch (carpr.carpr_state) { case BACKUP: callout_stop(&sc->sc_ad_tmo); - carp_set_state(sc, BACKUP); + carp_set_state(sc, BACKUP, "SIOCSVH"); carp_setrun(sc, 0); carp_delroute(sc); break; case MASTER: - carp_master_down_locked(sc); + carp_master_down_locked(sc, "SIOCSVH"); break; default: break; @@ -1964,7 +1949,7 @@ carp_detach_locked(struct ifaddr *ifa) } static void -carp_set_state(struct carp_softc *sc, int state) +carp_set_state(struct carp_softc *sc, int state, const char *reason) { CARP_LOCK_ASSERT(sc); @@ -1973,10 +1958,14 @@ carp_set_state(struct carp_softc *sc, int state) const char *carp_states[] = { CARP_STATES }; char subsys[IFNAMSIZ+5]; - sc->sc_state = state; - snprintf(subsys, IFNAMSIZ+5, "%u@%s", sc->sc_vhid, sc->sc_carpdev->if_xname); + + CARP_LOG("%s: %s -> %s (%s)\n", subsys, + carp_states[sc->sc_state], carp_states[state], reason); + + sc->sc_state = state; + devctl_notify("CARP", subsys, carp_states[state], NULL); } } @@ -2010,13 +1999,13 @@ carp_sc_state(struct carp_softc *sc) #ifdef INET6 callout_stop(&sc->sc_md6_tmo); #endif - carp_set_state(sc, INIT); + carp_set_state(sc, INIT, "hw interface down"); carp_setrun(sc, 0); if (!sc->sc_suppress) carp_demote_adj(V_carp_ifdown_adj, "interface down"); sc->sc_suppress = 1; } else { - carp_set_state(sc, INIT); + carp_set_state(sc, INIT, "hw interface up"); carp_setrun(sc, 0); if (sc->sc_suppress) carp_demote_adj(-V_carp_ifdown_adj, "interface up"); From 291afb4e808cbeb84fa93cc5dfcd32ac4ca73ac7 Mon Sep 17 00:00:00 2001 From: ume Date: Thu, 22 Jan 2015 17:13:43 +0000 Subject: [PATCH 170/258] Don't include newvers.sh into freebsd-version. --- bin/freebsd-version/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/freebsd-version/Makefile b/bin/freebsd-version/Makefile index aac030686c3f..e515d0c225d5 100644 --- a/bin/freebsd-version/Makefile +++ b/bin/freebsd-version/Makefile @@ -11,7 +11,7 @@ freebsd-version.sh: ${.CURDIR}/freebsd-version.sh.in ${NEWVERS} s/@@TYPE@@/$${TYPE}/g; \ s/@@REVISION@@/$${REVISION}/g; \ s/@@BRANCH@@/$${BRANCH}/g; \ - " ${.ALLSRC} >${.TARGET} ; then \ + " ${.CURDIR}/freebsd-version.sh.in >${.TARGET} ; then \ rm -f ${.TARGET} ; \ exit 1 ; \ fi From dcf4d630dce106d149561c46c0b78fa9f6763d9e Mon Sep 17 00:00:00 2001 From: ian Date: Thu, 22 Jan 2015 17:42:30 +0000 Subject: [PATCH 171/258] Add the Maxmem global and set it to the highest physical page number plus 1. --- sys/arm/arm/physmem.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/sys/arm/arm/physmem.c b/sys/arm/arm/physmem.c index 8618e46e27ae..eae03f7ab5d7 100644 --- a/sys/arm/arm/physmem.c +++ b/sys/arm/arm/physmem.c @@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include /* @@ -86,8 +87,12 @@ static size_t excnt; vm_paddr_t phys_avail[MAX_AVAIL_ENTRIES + 2]; /* +2 to allow for a pair */ vm_paddr_t dump_avail[MAX_AVAIL_ENTRIES + 2]; /* of zeroes to terminate. */ -/* This is the total number of hardware pages, excluded or not. */ +/* + * realmem is the total number of hardware pages, excluded or not. + * Maxmem is one greater than the last physical page number. + */ long realmem; +long Maxmem; /* The address at which the kernel was loaded. Set early in initarm(). */ vm_paddr_t arm_physmem_kernaddr; @@ -152,8 +157,8 @@ arm_physmem_print_tables() * * Returns the number of pages of non-excluded memory added to the avail list. */ -static long -regions_to_avail(vm_paddr_t *avail, uint32_t exflags) +static size_t +regions_to_avail(vm_paddr_t *avail, uint32_t exflags, long *pavail) { size_t acnt, exi, hwi; vm_paddr_t end, start, xend, xstart; @@ -236,7 +241,9 @@ regions_to_avail(vm_paddr_t *avail, uint32_t exflags) panic("Not enough space in the dump/phys_avail arrays"); } - return (availmem); + if (pavail) + *pavail = availmem; + return (acnt); } /* @@ -311,13 +318,23 @@ void arm_physmem_exclude_region(vm_paddr_t pa, vm_size_t sz, uint32_t exflags) /* * Process all the regions added earlier into the global avail lists. + * + * Updates the kernel global 'physmem' with the number of physical pages + * available for use (all pages not in any exclusion region). + * + * Updates the kernel global 'Maxmem' with the page number one greater then the + * last page of physical memory in the system. */ void arm_physmem_init_kernel_globals(void) { + size_t nextidx; - regions_to_avail(dump_avail, EXFLAG_NODUMP); - physmem = regions_to_avail(phys_avail, EXFLAG_NOALLOC); + regions_to_avail(dump_avail, EXFLAG_NODUMP, NULL); + nextidx = regions_to_avail(phys_avail, EXFLAG_NOALLOC, &physmem); + if (nextidx == 0) + panic("No memory entries in phys_avail"); + Maxmem = atop(phys_avail[nextidx - 1]); } #ifdef DDB From f6d6d22c9ff0c37dd72a033cc247f03c56337cdb Mon Sep 17 00:00:00 2001 From: ian Date: Thu, 22 Jan 2015 17:46:05 +0000 Subject: [PATCH 172/258] Declare Maxmem on arm. This should have been part of r277532. --- sys/arm/include/md_var.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/arm/include/md_var.h b/sys/arm/include/md_var.h index d54a4259ef3b..030b48bf056f 100644 --- a/sys/arm/include/md_var.h +++ b/sys/arm/include/md_var.h @@ -33,6 +33,7 @@ #ifndef _MACHINE_MD_VAR_H_ #define _MACHINE_MD_VAR_H_ +extern long Maxmem; extern char sigcode[]; extern int szsigcode; extern uint32_t *vm_page_dump; From 8ef50ae63c03a35f988a15bd31fc2d584e5a3331 Mon Sep 17 00:00:00 2001 From: emaste Date: Thu, 22 Jan 2015 17:53:30 +0000 Subject: [PATCH 173/258] Update reported elftoolchain version The last elftoolchain update is upstream rev 3136. Update our reported version and add M (Modified) suffix as our elftoolchain contains additional fixes not yet committed upstream. Sponsored by: The FreeBSD Foundation --- lib/libelftc/elftc_version.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/libelftc/elftc_version.c b/lib/libelftc/elftc_version.c index 9f278e61e917..a6bf57155c1e 100644 --- a/lib/libelftc/elftc_version.c +++ b/lib/libelftc/elftc_version.c @@ -6,5 +6,5 @@ const char * elftc_version(void) { - return "libelftc r3130"; + return "elftoolchain r3136M"; } From a74cf6ece6a4ccf2bb4ff12aaa01aea80ebd1aac Mon Sep 17 00:00:00 2001 From: gjb Date: Thu, 22 Jan 2015 19:43:05 +0000 Subject: [PATCH 174/258] Rename the 'release' target to 'real-release', and add two targets, 'vm-release' and 'cloudware-release', that are invoked if WITH_VMIMAGES and WITH_CLOUDWARE are not empty. This fixes an issue where 'make release' would not build the cloud provider targets because CLOUDWARE was not yet set. [1] Move the WITH_VMIMAGES and WITH_CLOUDWARE targets to Makefile.vm. Note: There is no 'cloudware-install' target yet, since some of the disk image names may need to be specific to the provider, so this is probably best handled by the build scripts. Reported by: cperciva [1] MFC after: 1 month X-MFC-with: r277458 Sponsored by: The FreeBSD Foundation --- release/Makefile | 15 +++++++-------- release/Makefile.vm | 10 ++++++++++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/release/Makefile b/release/Makefile index e462bf3533ac..a601921b3303 100644 --- a/release/Makefile +++ b/release/Makefile @@ -8,7 +8,10 @@ # memstick: Builds memory stick image (memstick.img) # mini-memstick: Builds minimal memory stick image (mini-memstick.img) # ftp: Sets up FTP distribution area (ftp) -# release: Build all media and FTP distribution area +# release: Invokes real-release, vm-release, and cloudware-release targets +# real-release: Build all media and FTP distribution area +# vm-release: Build all virtual machine image targets +# cloudware-release: Build all cloud hosting provider targets # install: Invokes the release-install and vm-install targets # release-install: Copies all release installation media into ${DESTDIR} # vm-install: Copies all virtual machine images into ${DESTDIR} @@ -275,15 +278,11 @@ ftp: packagesystem mkdir -p ftp cp *.txz MANIFEST ftp -release: +release: real-release vm-release cloudware-release + +real-release: ${MAKE} -C ${.CURDIR} ${.MAKEFLAGS} obj ${MAKE} -C ${.CURDIR} ${.MAKEFLAGS} ${RELEASE_TARGETS} -.if defined(WITH_VMIMAGES) && !empty(WITH_VMIMAGES) - ${MAKE} -C ${.CURDIR} ${.MAKEFLAGS} ${VMTARGETS} -.endif -.if defined(WITH_CLOUDWARE) && !empty(WITH_CLOUDWARE) && !empty(CLOUDWARE) - ${MAKE} -C ${.CURDIR} ${.MAKEFLAGS} ${CLOUDTARGETS} -.endif install: release-install vm-install diff --git a/release/Makefile.vm b/release/Makefile.vm index 9b5f543dd659..17229bfb2792 100644 --- a/release/Makefile.vm +++ b/release/Makefile.vm @@ -109,3 +109,13 @@ vm-install: cd ${DESTDIR}/vmimages && md5 ${OSRELEASE}* > \ ${DESTDIR}/vmimages/CHECKSUM.MD5 .endif + +vm-release: +.if defined(WITH_VMIMAGES) && !empty(WITH_VMIMAGES) + ${MAKE} -C ${.CURDIR} ${.MAKEFLAGS} ${VMTARGETS} +.endif + +cloudware-release: +.if defined(WITH_CLOUDWARE) && !empty(WITH_CLOUDWARE) && !empty(CLOUDWARE) + ${MAKE} -C ${.CURDIR} ${.MAKEFLAGS} ${CLOUDTARGETS} +.endif From 02b832180aa3a176b14e8e39b81ee5ac693a8e95 Mon Sep 17 00:00:00 2001 From: nwhitehorn Date: Thu, 22 Jan 2015 22:04:43 +0000 Subject: [PATCH 175/258] Allow use of a pre-instantiated RTAS as well as a self-instantiated one. This lets the kernel boot on RTAS-based systems by being kexec'ed from Linux. --- sys/powerpc/ofw/rtas.c | 43 ++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/sys/powerpc/ofw/rtas.c b/sys/powerpc/ofw/rtas.c index 3e751b3ec08d..15cb58e8353e 100644 --- a/sys/powerpc/ofw/rtas.c +++ b/sys/powerpc/ofw/rtas.c @@ -86,12 +86,6 @@ rtas_setup(void *junk) return; } OF_package_to_path(rtas, path, sizeof(path)); - rtasi = OF_open(path); - if (rtasi == 0) { - rtas = 0; - printf("Error initializing RTAS: could not open node\n"); - return; - } mtx_init(&rtas_mtx, "RTAS", NULL, MTX_SPIN); @@ -110,7 +104,7 @@ rtas_setup(void *junk) * It must be 4KB-aligned and not cross a 256 MB boundary. */ - OF_getprop(rtas, "rtas-size", &rtas_size, sizeof(rtas_size)); + OF_getencprop(rtas, "rtas-size", &rtas_size, sizeof(rtas_size)); rtas_size = round_page(rtas_size); rtas_bounce_virt = contigmalloc(rtas_size + PAGE_SIZE, M_RTAS, 0, 0, ulmin(platform_real_maxaddr(), BUS_SPACE_MAXADDR_32BIT), @@ -125,15 +119,32 @@ rtas_setup(void *junk) * Instantiate RTAS. We always use the 32-bit version. */ - result = OF_call_method("instantiate-rtas", rtasi, 1, 1, - (cell_t)rtas_private_data, &rtas_ptr); - OF_close(rtasi); + if (OF_hasprop(rtas, "linux,rtas-entry") && + OF_hasprop(rtas, "linux,rtas-base")) { + OF_getencprop(rtas, "linux,rtas-base", &rtas_ptr, + sizeof(rtas_ptr)); + rtas_private_data = rtas_ptr; + OF_getencprop(rtas, "linux,rtas-entry", &rtas_ptr, + sizeof(rtas_ptr)); + } else { + rtasi = OF_open(path); + if (rtasi == 0) { + rtas = 0; + printf("Error initializing RTAS: could not open " + "node\n"); + return; + } - if (result != 0) { - rtas = 0; - rtas_ptr = 0; - printf("Error initializing RTAS (%d)\n", result); - return; + result = OF_call_method("instantiate-rtas", rtasi, 1, 1, + (cell_t)rtas_private_data, &rtas_ptr); + OF_close(rtasi); + + if (result != 0) { + rtas = 0; + rtas_ptr = 0; + printf("Error initializing RTAS (%d)\n", result); + return; + } } rtas_entry = (uintptr_t)(rtas_ptr); @@ -252,7 +263,7 @@ rtas_token_lookup(const char *method) if (!rtas_exists()) return (-1); - if (OF_getprop(rtas, method, &token, sizeof(token)) == -1) + if (OF_getencprop(rtas, method, &token, sizeof(token)) == -1) return (-1); return (token); From 3a0eab2e37aca76c631e1e71d35caa73f7f8a44a Mon Sep 17 00:00:00 2001 From: ngie Date: Thu, 22 Jan 2015 23:50:47 +0000 Subject: [PATCH 176/258] Add sample log rotation support for opensm Up to 7 archives of the log will be kept (just for consistency with the other log rotation rules) PR: 196788 MFC after: 1 week Reviewed by: hselasky Sponsored by: EMC / Isilon Storage Division --- etc/Makefile | 5 ++++- etc/newsyslog.conf.d/Makefile | 13 +++++++++++++ etc/newsyslog.conf.d/opensm.conf | 3 +++ 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 etc/newsyslog.conf.d/Makefile create mode 100644 etc/newsyslog.conf.d/opensm.conf diff --git a/etc/Makefile b/etc/Makefile index 76db02a0cb26..62b837fa49e6 100644 --- a/etc/Makefile +++ b/etc/Makefile @@ -3,8 +3,11 @@ .include +SUBDIR= \ + newsyslog.conf.d + .if ${MK_SENDMAIL} != "no" -SUBDIR= sendmail +SUBDIR+=sendmail .endif .if ${MK_TESTS} != "no" diff --git a/etc/newsyslog.conf.d/Makefile b/etc/newsyslog.conf.d/Makefile new file mode 100644 index 000000000000..c2574b74c432 --- /dev/null +++ b/etc/newsyslog.conf.d/Makefile @@ -0,0 +1,13 @@ +# $FreeBSD$ + +.include + +BINDIR= /etc/newsyslog.conf.d + +FILES= + +.if ${MK_OFED} != "no" +FILES+= opensm.conf +.endif + +.include diff --git a/etc/newsyslog.conf.d/opensm.conf b/etc/newsyslog.conf.d/opensm.conf new file mode 100644 index 000000000000..36248bde5fda --- /dev/null +++ b/etc/newsyslog.conf.d/opensm.conf @@ -0,0 +1,3 @@ +# $FreeBSD$ + +/var/log/opensm.log 600 7 * * Z /var/run/opensm.pid 30 From 2226bf3149cf20c677db8a9641b89ac91403c00f Mon Sep 17 00:00:00 2001 From: will Date: Fri, 23 Jan 2015 00:06:35 +0000 Subject: [PATCH 177/258] Improve the distribution of LAGG port traffic. I edited the original change to retain the use of arc4random() as a seed for the hashing as a very basic defense against intentional lagg port selection. The author's original commit message (edited slightly): sys/net/ieee8023ad_lacp.c sys/net/if_lagg.c In lagg_hashmbuf, use the FNV hash instead of the old hash32_buf. The hash32 family of functions operate one octet at a time, and when run on a string s of length n, their output is equivalent to : ----- i=n-1 \ n \ (n-i-1) 32 ( seed^ + / 33^ * s[i] ) % 2^ / ----- i=0 The problem is that the last five bytes of input don't get multiplied by sufficiently many powers of 33 to rollover 2^32. That means that changing the last few bytes (but obviously not the very last) of input will always change the value of the hash by a multiple of 33. In the case of lagg_hashmbuf() with ipv4 input, the last four bytes are the TCP or UDP port numbers. Since the output of lagg_hashmbuf is always taken modulo the port count, and 3 is a common port count for a lagg, that's bad. It means that the UDP or TCP source port will never affect which lagg member is selected on a 3-port lagg. At 10Gbps, I was not able to measure any difference in CPU consumption between the old and new hash. Submitted by: asomers (original commit) Reviewed by: emaste, glebius MFC after: 1 week Sponsored by: Spectra Logic MFSpectraBSD: 1001723 on 2013/08/28 (original) 1114258 on 2015/01/22 (edit) --- sys/net/ieee8023ad_lacp.c | 6 +++++- sys/net/if_lagg.c | 27 +++++++++++++++------------ 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/sys/net/ieee8023ad_lacp.c b/sys/net/ieee8023ad_lacp.c index 75f6366e7888..3052e4b526ee 100644 --- a/sys/net/ieee8023ad_lacp.c +++ b/sys/net/ieee8023ad_lacp.c @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include /* hz */ #include /* for net/if.h */ @@ -757,13 +758,16 @@ void lacp_attach(struct lagg_softc *sc) { struct lacp_softc *lsc; + uint32_t seed; lsc = malloc(sizeof(struct lacp_softc), M_DEVBUF, M_WAITOK | M_ZERO); sc->sc_psc = lsc; lsc->lsc_softc = sc; - lsc->lsc_hashkey = arc4random(); + seed = arc4random(); + lsc->lsc_hashkey = FNV1_32_INIT; + lsc->lsc_hashkey = fnv_32_buf(&seed, sizeof(seed), lsc->lsc_hashkey); lsc->lsc_active_aggregator = NULL; lsc->lsc_strict_mode = 1; LACP_LOCK_INIT(lsc); diff --git a/sys/net/if_lagg.c b/sys/net/if_lagg.c index a6e5b3c65a1f..ec828fa8a949 100644 --- a/sys/net/if_lagg.c +++ b/sys/net/if_lagg.c @@ -36,7 +36,7 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include +#include #include #include #include @@ -1853,13 +1853,13 @@ lagg_hashmbuf(struct lagg_softc *sc, struct mbuf *m, uint32_t key) eh = mtod(m, struct ether_header *); etype = ntohs(eh->ether_type); if (sc->sc_flags & LAGG_F_HASHL2) { - p = hash32_buf(&eh->ether_shost, ETHER_ADDR_LEN, p); - p = hash32_buf(&eh->ether_dhost, ETHER_ADDR_LEN, p); + p = fnv_32_buf(&eh->ether_shost, ETHER_ADDR_LEN, p); + p = fnv_32_buf(&eh->ether_dhost, ETHER_ADDR_LEN, p); } /* Special handling for encapsulating VLAN frames */ if ((m->m_flags & M_VLANTAG) && (sc->sc_flags & LAGG_F_HASHL2)) { - p = hash32_buf(&m->m_pkthdr.ether_vtag, + p = fnv_32_buf(&m->m_pkthdr.ether_vtag, sizeof(m->m_pkthdr.ether_vtag), p); } else if (etype == ETHERTYPE_VLAN) { vlan = lagg_gethdr(m, off, sizeof(*vlan), &buf); @@ -1867,7 +1867,7 @@ lagg_hashmbuf(struct lagg_softc *sc, struct mbuf *m, uint32_t key) goto out; if (sc->sc_flags & LAGG_F_HASHL2) - p = hash32_buf(&vlan->evl_tag, sizeof(vlan->evl_tag), p); + p = fnv_32_buf(&vlan->evl_tag, sizeof(vlan->evl_tag), p); etype = ntohs(vlan->evl_proto); off += sizeof(*vlan) - sizeof(*eh); } @@ -1880,8 +1880,8 @@ lagg_hashmbuf(struct lagg_softc *sc, struct mbuf *m, uint32_t key) goto out; if (sc->sc_flags & LAGG_F_HASHL3) { - p = hash32_buf(&ip->ip_src, sizeof(struct in_addr), p); - p = hash32_buf(&ip->ip_dst, sizeof(struct in_addr), p); + p = fnv_32_buf(&ip->ip_src, sizeof(struct in_addr), p); + p = fnv_32_buf(&ip->ip_dst, sizeof(struct in_addr), p); } if (!(sc->sc_flags & LAGG_F_HASHL4)) break; @@ -1896,7 +1896,7 @@ lagg_hashmbuf(struct lagg_softc *sc, struct mbuf *m, uint32_t key) ports = lagg_gethdr(m, off, sizeof(*ports), &buf); if (ports == NULL) break; - p = hash32_buf(ports, sizeof(*ports), p); + p = fnv_32_buf(ports, sizeof(*ports), p); break; } break; @@ -1909,10 +1909,10 @@ lagg_hashmbuf(struct lagg_softc *sc, struct mbuf *m, uint32_t key) if (ip6 == NULL) goto out; - p = hash32_buf(&ip6->ip6_src, sizeof(struct in6_addr), p); - p = hash32_buf(&ip6->ip6_dst, sizeof(struct in6_addr), p); + p = fnv_32_buf(&ip6->ip6_src, sizeof(struct in6_addr), p); + p = fnv_32_buf(&ip6->ip6_dst, sizeof(struct in6_addr), p); flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK; - p = hash32_buf(&flow, sizeof(flow), p); /* IPv6 flow label */ + p = fnv_32_buf(&flow, sizeof(flow), p); /* IPv6 flow label */ break; #endif } @@ -2087,12 +2087,15 @@ lagg_lb_attach(struct lagg_softc *sc) { struct lagg_port *lp; struct lagg_lb *lb; + uint32_t seed; lb = malloc(sizeof(struct lagg_lb), M_DEVBUF, M_WAITOK | M_ZERO); sc->sc_capabilities = IFCAP_LAGG_FULLDUPLEX; - lb->lb_key = arc4random(); + seed = arc4random(); + lb->lb_key = FNV1_32_INIT; + lb->lb_key = fnv_32_buf(&seed, sizeof(seed), lb->lb_key); sc->sc_psc = lb; SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) From 920fd43d82ba6bcbf7d076a3736808df4e8d6b39 Mon Sep 17 00:00:00 2001 From: ian Date: Fri, 23 Jan 2015 01:18:08 +0000 Subject: [PATCH 178/258] Enable all the mmc/sd controllers, because there's no telling which ones any given board will be using. Yes, changing source is an unusually primitive power control implementation. --- sys/arm/freescale/imx/imx6_ccm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/arm/freescale/imx/imx6_ccm.c b/sys/arm/freescale/imx/imx6_ccm.c index 769a84108be8..2c80bd9ee030 100644 --- a/sys/arm/freescale/imx/imx6_ccm.c +++ b/sys/arm/freescale/imx/imx6_ccm.c @@ -95,7 +95,7 @@ ccm_init_gates(struct ccm_softc *sc) WR4(sc, CCM_CCGR3, 0x3ff00000); /* DDR memory controller */ WR4(sc, CCM_CCGR4, 0x0000f300); /* pl301 bus crossbar */ WR4(sc, CCM_CCGR5, 0x0f000000); /* uarts */ - WR4(sc, CCM_CCGR6, 0x000000cc); /* usdhc 1 & 3 */ + WR4(sc, CCM_CCGR6, 0x000000ff); /* usdhc 1-4 */ } static int From d20a416d73ddf444f93a59ee260047f046a1884a Mon Sep 17 00:00:00 2001 From: danfe Date: Fri, 23 Jan 2015 07:30:57 +0000 Subject: [PATCH 179/258] Fix usage example in kvprintf(9) and its copy in libstand(3): trailing '\n' in bitfield argument is wrong, as it will be treated as bit 10, causing any code printing >=10 bits with bit 10 on as having a trailing comma. Newline (intended one) should be part of the format string (already present in the examples). Also fix grammar and kill EOL whitespace in comment while here. PR: 195005 Approved by: bdrewery --- lib/libstand/libstand.3 | 2 +- lib/libstand/printf.c | 4 ++-- share/man/man9/printf.9 | 2 +- sys/kern/subr_prf.c | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/libstand/libstand.3 b/lib/libstand/libstand.3 index b42c8b5bdd7f..42289c1bce41 100644 --- a/lib/libstand/libstand.3 +++ b/lib/libstand/libstand.3 @@ -288,7 +288,7 @@ Thus printf( .Qq reg=%b\en , 3, -.Qq \e10\e2BITTWO\e1BITONE\en +.Qq \e10\e2BITTWO\e1BITONE ); .Ed .Pp diff --git a/lib/libstand/printf.c b/lib/libstand/printf.c index 157b327ead88..fef534165616 100644 --- a/lib/libstand/printf.c +++ b/lib/libstand/printf.c @@ -187,7 +187,7 @@ ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) * the next characters (up to a control character, i.e. a character <= 32), * give the name of the register. Thus: * - * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); + * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE"); * * would produce output: * @@ -500,7 +500,7 @@ reswitch: switch (ch = (u_char)*fmt++) { while (percent < fmt) PCHAR(*percent++); /* - * Since we ignore an formatting argument it is no + * Since we ignore a formatting argument it is no * longer safe to obey the remaining formatting * arguments as the arguments will no longer match * the format specs. diff --git a/share/man/man9/printf.9 b/share/man/man9/printf.9 index 571e7e638c36..84ac822da023 100644 --- a/share/man/man9/printf.9 +++ b/share/man/man9/printf.9 @@ -151,7 +151,7 @@ void printf_test(void) { - printf("reg=%b\en", 3, "\e10\e2BITTWO\e1BITONE\en"); + printf("reg=%b\en", 3, "\e10\e2BITTWO\e1BITONE"); printf("out: %4D\en", "AAAA", ":"); } .Ed diff --git a/sys/kern/subr_prf.c b/sys/kern/subr_prf.c index 814e57f47947..cc30de1f645f 100644 --- a/sys/kern/subr_prf.c +++ b/sys/kern/subr_prf.c @@ -598,7 +598,7 @@ ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) * the next characters (up to a control character, i.e. a character <= 32), * give the name of the register. Thus: * - * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); + * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE"); * * would produce output: * @@ -911,7 +911,7 @@ reswitch: switch (ch = (u_char)*fmt++) { while (percent < fmt) PCHAR(*percent++); /* - * Since we ignore a formatting argument it is no + * Since we ignore a formatting argument it is no * longer safe to obey the remaining formatting * arguments as the arguments will no longer match * the format specs. From 73fdd2ded8fbebad43727981183ea1a56184968b Mon Sep 17 00:00:00 2001 From: nwhitehorn Date: Fri, 23 Jan 2015 07:36:51 +0000 Subject: [PATCH 180/258] Use relocation-safe methods to determine the sizes of the exception handlers. A "size" symbol with its address set to the length of handler would be shifted forward with all other addresses when relocations are processed. Instead, just note the end and do the subtraction at runtime. --- sys/powerpc/aim/machdep.c | 69 ++++++++++++++++++++--------------- sys/powerpc/aim/trap_subr32.S | 20 +++++----- sys/powerpc/aim/trap_subr64.S | 24 ++++++------ 3 files changed, 61 insertions(+), 52 deletions(-) diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c index 82a72328d63e..a6d254b3f145 100644 --- a/sys/powerpc/aim/machdep.c +++ b/sys/powerpc/aim/machdep.c @@ -237,14 +237,14 @@ extern void *rfid_patch, *rfi_patch1, *rfi_patch2; extern void *trapcode64; #endif -extern void *rstcode, *rstsize; -extern void *trapcode, *trapsize, *trapcode2; -extern void *slbtrap, *slbtrapsize; -extern void *alitrap, *alisize; -extern void *dsitrap, *dsisize; +extern void *rstcode, *rstcodeend; +extern void *trapcode, *trapcodeend, *trapcode2; +extern void *slbtrap, *slbtrapend; +extern void *alitrap, *aliend; +extern void *dsitrap, *dsiend; extern void *decrint, *decrsize; extern void *extint, *extsize; -extern void *dblow, *dbsize; +extern void *dblow, *dbend; extern void *imisstrap, *imisssize; extern void *dlmisstrap, *dlmisssize; extern void *dsmisstrap, *dsmisssize; @@ -255,7 +255,7 @@ powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp) struct pcpu *pc; vm_offset_t startkernel, endkernel; void *generictrap; - size_t trap_offset; + size_t trap_offset, trapsize; void *kmdp; char *env; register_t msr, scratch; @@ -513,35 +513,44 @@ powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp) *((register_t *)TRAP_TOCBASE) = toc; #endif - bcopy(&rstcode, (void *)(EXC_RST + trap_offset), (size_t)&rstsize); + trapsize = (size_t)&trapcodeend - (size_t)&trapcode; + + bcopy(&rstcode, (void *)(EXC_RST + trap_offset), (size_t)&rstcodeend - + (size_t)&rstcode); #ifdef KDB - bcopy(&dblow, (void *)(EXC_MCHK + trap_offset), (size_t)&dbsize); - bcopy(&dblow, (void *)(EXC_PGM + trap_offset), (size_t)&dbsize); - bcopy(&dblow, (void *)(EXC_TRC + trap_offset), (size_t)&dbsize); - bcopy(&dblow, (void *)(EXC_BPT + trap_offset), (size_t)&dbsize); + bcopy(&dblow, (void *)(EXC_MCHK + trap_offset), (size_t)&dbend - + (size_t)&dblow); + bcopy(&dblow, (void *)(EXC_PGM + trap_offset), (size_t)&dbend - + (size_t)&dblow); + bcopy(&dblow, (void *)(EXC_TRC + trap_offset), (size_t)&dbend - + (size_t)&dblow); + bcopy(&dblow, (void *)(EXC_BPT + trap_offset), (size_t)&dbend - + (size_t)&dblow); #else - bcopy(generictrap, (void *)EXC_MCHK, (size_t)&trapsize); - bcopy(generictrap, (void *)EXC_PGM, (size_t)&trapsize); - bcopy(generictrap, (void *)EXC_TRC, (size_t)&trapsize); - bcopy(generictrap, (void *)EXC_BPT, (size_t)&trapsize); + bcopy(generictrap, (void *)EXC_MCHK, trapsize); + bcopy(generictrap, (void *)EXC_PGM, trapsize); + bcopy(generictrap, (void *)EXC_TRC, trapsize); + bcopy(generictrap, (void *)EXC_BPT, trapsize); #endif - bcopy(&alitrap, (void *)(EXC_ALI + trap_offset), (size_t)&alisize); - bcopy(&dsitrap, (void *)(EXC_DSI + trap_offset), (size_t)&dsisize); - bcopy(generictrap, (void *)EXC_ISI, (size_t)&trapsize); + bcopy(&alitrap, (void *)(EXC_ALI + trap_offset), (size_t)&aliend - + (size_t)&alitrap); + bcopy(&dsitrap, (void *)(EXC_DSI + trap_offset), (size_t)&dsitrap - + (size_t)&dsitrap); + bcopy(generictrap, (void *)EXC_ISI, trapsize); #ifdef __powerpc64__ - bcopy(&slbtrap, (void *)EXC_DSE, (size_t)&slbtrapsize); - bcopy(&slbtrap, (void *)EXC_ISE, (size_t)&slbtrapsize); + bcopy(&slbtrap, (void *)EXC_DSE,(size_t)&slbtrapend - (size_t)&slbtrap); + bcopy(&slbtrap, (void *)EXC_ISE,(size_t)&slbtrapend - (size_t)&slbtrap); #endif - bcopy(generictrap, (void *)EXC_EXI, (size_t)&trapsize); - bcopy(generictrap, (void *)EXC_FPU, (size_t)&trapsize); - bcopy(generictrap, (void *)EXC_DECR, (size_t)&trapsize); - bcopy(generictrap, (void *)EXC_SC, (size_t)&trapsize); - bcopy(generictrap, (void *)EXC_FPA, (size_t)&trapsize); - bcopy(generictrap, (void *)EXC_VEC, (size_t)&trapsize); - bcopy(generictrap, (void *)EXC_PERF, (size_t)&trapsize); - bcopy(generictrap, (void *)EXC_VECAST_G4, (size_t)&trapsize); - bcopy(generictrap, (void *)EXC_VECAST_G5, (size_t)&trapsize); + bcopy(generictrap, (void *)EXC_EXI, trapsize); + bcopy(generictrap, (void *)EXC_FPU, trapsize); + bcopy(generictrap, (void *)EXC_DECR, trapsize); + bcopy(generictrap, (void *)EXC_SC, trapsize); + bcopy(generictrap, (void *)EXC_FPA, trapsize); + bcopy(generictrap, (void *)EXC_VEC, trapsize); + bcopy(generictrap, (void *)EXC_PERF, trapsize); + bcopy(generictrap, (void *)EXC_VECAST_G4, trapsize); + bcopy(generictrap, (void *)EXC_VECAST_G5, trapsize); #ifndef __powerpc64__ /* G2-specific TLB miss helper handlers */ bcopy(&imisstrap, (void *)EXC_IMISS, (size_t)&imisssize); diff --git a/sys/powerpc/aim/trap_subr32.S b/sys/powerpc/aim/trap_subr32.S index 2aae2a00abbc..7c753b541dda 100644 --- a/sys/powerpc/aim/trap_subr32.S +++ b/sys/powerpc/aim/trap_subr32.S @@ -299,10 +299,10 @@ CNAME(restorebridgesize) = .-CNAME(restorebridge) * not still hanging around in the trap handling region * once the MMU is turned on. */ - .globl CNAME(rstcode), CNAME(rstsize) + .globl CNAME(rstcode), CNAME(rstcodeend) CNAME(rstcode): ba cpu_reset -CNAME(rstsize) = . - CNAME(rstcode) +CNAME(rstcodeend): cpu_reset: bl 1f @@ -339,14 +339,14 @@ cpu_reset: * (except ISI/DSI, ALI, and the interrupts) */ - .globl CNAME(trapcode),CNAME(trapsize) + .globl CNAME(trapcode),CNAME(trapcodeend) CNAME(trapcode): mtsprg1 %r1 /* save SP */ mflr %r1 /* Save the old LR in r1 */ mtsprg2 %r1 /* And then in SPRG2 */ li %r1, 0x20 /* How to get the vector from LR */ bla generictrap /* LR & SPRG3 is exception # */ -CNAME(trapsize) = .-CNAME(trapcode) +CNAME(trapcodeend): /* * 64-bit version of trapcode. Identical, except it calls generictrap64. @@ -362,7 +362,7 @@ CNAME(trapcode64): /* * For ALI: has to save DSISR and DAR */ - .globl CNAME(alitrap),CNAME(alisize) + .globl CNAME(alitrap),CNAME(aliend) CNAME(alitrap): mtsprg1 %r1 /* save SP */ GET_CPUINFO(%r1) @@ -386,7 +386,7 @@ CNAME(alitrap): mfsrr1 %r31 mtcr %r31 bla s_trap -CNAME(alisize) = .-CNAME(alitrap) +CNAME(aliend): /* * G2 specific: instuction TLB miss. @@ -594,7 +594,7 @@ CNAME(dsmisssize) = .-CNAME(dsmisstrap) * Has to handle BAT spills * and standard pagetable spills */ - .globl CNAME(dsitrap),CNAME(dsisize) + .globl CNAME(dsitrap),CNAME(dsiend) CNAME(dsitrap): mtsprg1 %r1 /* save SP */ GET_CPUINFO(%r1) @@ -645,7 +645,7 @@ CNAME(dsitrap): 1: mflr %r28 /* save LR (SP already saved) */ bla disitrap -CNAME(dsisize) = .-CNAME(dsitrap) +CNAME(dsiend): /* * Preamble code for DSI/ISI traps @@ -883,7 +883,7 @@ CNAME(rfi_patch2): /* * In case of KDB we want a separate trap catcher for it */ - .globl CNAME(dblow),CNAME(dbsize) + .globl CNAME(dblow),CNAME(dbend) CNAME(dblow): mtsprg1 %r1 /* save SP */ mtsprg2 %r29 /* save r29 */ @@ -909,5 +909,5 @@ CNAME(dblow): stw %r31,(PC_DBSAVE+CPUSAVE_R31)(%r1) /* free r31 */ mflr %r28 /* save LR */ bla dbtrap -CNAME(dbsize) = .-CNAME(dblow) +CNAME(dbend): #endif /* KDB */ diff --git a/sys/powerpc/aim/trap_subr64.S b/sys/powerpc/aim/trap_subr64.S index a2d5bc5b1b40..de79845eded2 100644 --- a/sys/powerpc/aim/trap_subr64.S +++ b/sys/powerpc/aim/trap_subr64.S @@ -294,7 +294,7 @@ dtrace_invop_calltrap_addr: * not still hanging around in the trap handling region * once the MMU is turned on. */ - .globl CNAME(rstcode), CNAME(rstsize) + .globl CNAME(rstcode), CNAME(rstcodeend) CNAME(rstcode): /* Explicitly set MSR[SF] */ mfmsr %r9 @@ -309,7 +309,7 @@ CNAME(rstcode): mtlr %r9 blr -CNAME(rstsize) = . - CNAME(rstcode) +CNAME(rstcodeend): cpu_reset: GET_TOCBASE(%r2) @@ -350,7 +350,7 @@ cpu_reset: * (except ISI/DSI, ALI, and the interrupts). Has to fit in 8 instructions! */ - .globl CNAME(trapcode),CNAME(trapsize) + .globl CNAME(trapcode),CNAME(trapcodeend) .p2align 3 CNAME(trapcode): mtsprg1 %r1 /* save SP */ @@ -361,7 +361,7 @@ CNAME(trapcode): mtlr %r1 li %r1, 0xA0 /* How to get the vector from LR */ blrl /* Branch to generictrap */ -CNAME(trapsize) = .-CNAME(trapcode) +CNAME(trapcodeend): /* * For SLB misses: do special things for the kernel @@ -369,7 +369,7 @@ CNAME(trapsize) = .-CNAME(trapcode) * Note: SPRG1 is always safe to overwrite any time the MMU is on, which is * the only time this can be called. */ - .globl CNAME(slbtrap),CNAME(slbtrapsize) + .globl CNAME(slbtrap),CNAME(slbtrapend) .p2align 3 CNAME(slbtrap): mtsprg1 %r1 /* save SP */ @@ -404,7 +404,7 @@ CNAME(slbtrap): mtlr %r1 GET_CPUINFO(%r1) blrl /* 124 bytes -- 4 to spare */ -CNAME(slbtrapsize) = .-CNAME(slbtrap) +CNAME(slbtrapend): kern_slbtrap: std %r2,(PC_SLBSAVE+136)(%r1) /* old LR */ @@ -525,7 +525,7 @@ kern_slbtrap: /* * For ALI: has to save DSISR and DAR */ - .globl CNAME(alitrap),CNAME(alisize) + .globl CNAME(alitrap),CNAME(aliend) CNAME(alitrap): mtsprg1 %r1 /* save SP */ GET_CPUINFO(%r1) @@ -560,13 +560,13 @@ CNAME(alitrap): mfsrr1 %r31 mtcr %r31 blrl -CNAME(alisize) = .-CNAME(alitrap) +CNAME(aliend): /* * Similar to the above for DSI * Has to handle standard pagetable spills */ - .globl CNAME(dsitrap),CNAME(dsisize) + .globl CNAME(dsitrap),CNAME(dsiend) CNAME(dsitrap): mtsprg1 %r1 /* save SP */ GET_CPUINFO(%r1) @@ -587,7 +587,7 @@ CNAME(dsitrap): ld %r1,0(%r1) mtlr %r1 blrl /* Branch to generictrap */ -CNAME(dsisize) = .-CNAME(dsitrap) +CNAME(dsiend): /* * Preamble code for DSI/ISI traps @@ -830,7 +830,7 @@ dbleave: /* * In case of KDB we want a separate trap catcher for it */ - .globl CNAME(dblow),CNAME(dbsize) + .globl CNAME(dblow),CNAME(dbend) CNAME(dblow): mtsprg1 %r1 /* save SP */ mtsprg2 %r29 /* save r29 */ @@ -869,5 +869,5 @@ CNAME(dblow): ld %r1,0(%r1) mtlr %r1 blrl /* Branch to generictrap */ -CNAME(dbsize) = .-CNAME(dblow) +CNAME(dbend): #endif /* KDB */ From 2ea9ad214b62ac0f200aa5ea819765f00e1c41fd Mon Sep 17 00:00:00 2001 From: ae Date: Fri, 23 Jan 2015 13:26:35 +0000 Subject: [PATCH 181/258] After r270929 RAW IP code assumes that all IP fields are in network byte order. Fix ping(8) to pass an IP header with converted ip_off and ip_len fields, when IP_HDRINCL socket option used. --- sbin/ping/ping.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sbin/ping/ping.c b/sbin/ping/ping.c index aeb301430fb6..f24ecdeea0c9 100644 --- a/sbin/ping/ping.c +++ b/sbin/ping/ping.c @@ -713,7 +713,7 @@ main(int argc, char *const *argv) ip->ip_hl = sizeof(struct ip) >> 2; ip->ip_tos = tos; ip->ip_id = 0; - ip->ip_off = df ? IP_DF : 0; + ip->ip_off = htons(df ? IP_DF : 0); ip->ip_ttl = ttl; ip->ip_p = IPPROTO_ICMP; ip->ip_src.s_addr = source ? sock_in.sin_addr.s_addr : INADDR_ANY; @@ -1078,7 +1078,7 @@ pinger(void) if (options & F_HDRINCL) { cc += sizeof(struct ip); ip = (struct ip *)outpackhdr; - ip->ip_len = cc; + ip->ip_len = htons(cc); ip->ip_sum = in_cksum((u_short *)outpackhdr, cc); packet = outpackhdr; } From c2f9a8c8d99de94fd8673e277da83c6b717c0f66 Mon Sep 17 00:00:00 2001 From: will Date: Fri, 23 Jan 2015 14:28:12 +0000 Subject: [PATCH 182/258] When a CARP state change is caused by an ifconfig request, log it accordingly. Suggested by: glebius MFC after: 1 week MFC with: 277530 --- sys/netinet/ip_carp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index 5c449c0ddd56..b8881044f16d 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -1702,12 +1702,14 @@ carp_ioctl(struct ifreq *ifr, u_long cmd, struct thread *td) switch (carpr.carpr_state) { case BACKUP: callout_stop(&sc->sc_ad_tmo); - carp_set_state(sc, BACKUP, "SIOCSVH"); + carp_set_state(sc, BACKUP, + "user requested via ifconfig"); carp_setrun(sc, 0); carp_delroute(sc); break; case MASTER: - carp_master_down_locked(sc, "SIOCSVH"); + carp_master_down_locked(sc, + "user requested via ifconfig"); break; default: break; From af1640da48175acae16b54fd047a6b5a43ad4c2c Mon Sep 17 00:00:00 2001 From: will Date: Fri, 23 Jan 2015 14:30:24 +0000 Subject: [PATCH 183/258] Log hardware interface up/down as "hardware" rather than just "hw". Suggested by: glebius MFC after: 1 week MFC with: 277530 --- sys/netinet/ip_carp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index b8881044f16d..524ebd8443bb 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -2001,13 +2001,13 @@ carp_sc_state(struct carp_softc *sc) #ifdef INET6 callout_stop(&sc->sc_md6_tmo); #endif - carp_set_state(sc, INIT, "hw interface down"); + carp_set_state(sc, INIT, "hardware interface down"); carp_setrun(sc, 0); if (!sc->sc_suppress) carp_demote_adj(V_carp_ifdown_adj, "interface down"); sc->sc_suppress = 1; } else { - carp_set_state(sc, INIT, "hw interface up"); + carp_set_state(sc, INIT, "hardware interface up"); carp_setrun(sc, 0); if (sc->sc_suppress) carp_demote_adj(-V_carp_ifdown_adj, "interface up"); From b96dc49fd0aa2ada2c90ed515ec74daf52e51e09 Mon Sep 17 00:00:00 2001 From: kevlo Date: Fri, 23 Jan 2015 15:14:30 +0000 Subject: [PATCH 184/258] Remove break after return. --- sys/dev/agp/agp_nvidia.c | 10 +++++----- sys/dev/cx/cxddk.c | 6 +++--- sys/dev/dc/if_dc.c | 5 ----- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/sys/dev/agp/agp_nvidia.c b/sys/dev/agp/agp_nvidia.c index bb153f9cc49c..a0098f0252ec 100644 --- a/sys/dev/agp/agp_nvidia.c +++ b/sys/dev/agp/agp_nvidia.c @@ -274,11 +274,11 @@ static u_int32_t agp_nvidia_get_aperture(device_t dev) { switch (pci_read_config(dev, AGP_NVIDIA_0_APSIZE, 1) & 0x0f) { - case 0: return (512 * 1024 * 1024); break; - case 8: return (256 * 1024 * 1024); break; - case 12: return (128 * 1024 * 1024); break; - case 14: return (64 * 1024 * 1024); break; - case 15: return (32 * 1024 * 1024); break; + case 0: return (512 * 1024 * 1024); + case 8: return (256 * 1024 * 1024); + case 12: return (128 * 1024 * 1024); + case 14: return (64 * 1024 * 1024); + case 15: return (32 * 1024 * 1024); default: device_printf(dev, "Invalid aperture setting 0x%x\n", pci_read_config(dev, AGP_NVIDIA_0_APSIZE, 1)); diff --git a/sys/dev/cx/cxddk.c b/sys/dev/cx/cxddk.c index bbcc904051e8..94780fb3591f 100644 --- a/sys/dev/cx/cxddk.c +++ b/sys/dev/cx/cxddk.c @@ -875,9 +875,9 @@ int cx_get_port (cx_chan_t *c) if (iftype) switch (c->type) { - case T_UNIV_V35: return 1; break; - case T_UNIV_RS449: return 2; break; - default: return -1; break; + case T_UNIV_V35: return 1; + case T_UNIV_RS449: return 2; + default: return -1; } else return 0; diff --git a/sys/dev/dc/if_dc.c b/sys/dev/dc/if_dc.c index 9458a4444307..421e326d256c 100644 --- a/sys/dev/dc/if_dc.c +++ b/sys/dev/dc/if_dc.c @@ -671,20 +671,16 @@ dc_miibus_readreg(device_t dev, int phy, int reg) * code think there's a PHY here. */ return (BMSR_MEDIAMASK); - break; case MII_PHYIDR1: if (DC_IS_PNIC(sc)) return (DC_VENDORID_LO); return (DC_VENDORID_DEC); - break; case MII_PHYIDR2: if (DC_IS_PNIC(sc)) return (DC_DEVICEID_82C168); return (DC_DEVICEID_21143); - break; default: return (0); - break; } } else return (0); @@ -748,7 +744,6 @@ dc_miibus_readreg(device_t dev, int phy, int reg) device_printf(dev, "phy_read: bad phy register %x\n", reg); return (0); - break; } rval = CSR_READ_4(sc, phy_reg) & 0x0000FFFF; From fd94a9f5f8bf599226a25b08fba05b191f8ab292 Mon Sep 17 00:00:00 2001 From: will Date: Fri, 23 Jan 2015 15:55:03 +0000 Subject: [PATCH 185/258] Print transfer times for read, write, & overall independently. Round up calculated values for iops and average time per io to avoid a shifting display if there are 1000+ (or even 10000+) iops, or if an average time per io column is 1000+ ms. Reviewed by: ken MFC after: 1 week Sponsored by: Spectra Logic MFSpectraBSD: 1089947 on 2014/09/26 1093625 on 2014/09/29 1093650 on 2014/09/29 1095662 on 2014/10/09 --- usr.sbin/iostat/iostat.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/usr.sbin/iostat/iostat.c b/usr.sbin/iostat/iostat.c index f566f39036b3..195e59c540ae 100644 --- a/usr.sbin/iostat/iostat.c +++ b/usr.sbin/iostat/iostat.c @@ -726,15 +726,17 @@ static void devstats(int perf_select, long double etime, int havelast) { int dn; - long double transfers_per_second, transfers_per_second_read, transfers_per_second_write; - long double kb_per_transfer, mb_per_second, mb_per_second_read, mb_per_second_write; + long double transfers_per_second, transfers_per_second_read; + long double transfers_per_second_write; + long double kb_per_transfer, mb_per_second, mb_per_second_read; + long double mb_per_second_write; u_int64_t total_bytes, total_transfers, total_blocks; u_int64_t total_bytes_read, total_transfers_read; u_int64_t total_bytes_write, total_transfers_write; long double busy_pct, busy_time; u_int64_t queue_len; - long double total_mb; - long double blocks_per_second, ms_per_transaction, total_duration; + long double total_mb, blocks_per_second, total_duration; + long double ms_per_other, ms_per_read, ms_per_write, ms_per_transaction; int firstline = 1; char *devname; @@ -746,8 +748,8 @@ devstats(int perf_select, long double etime, int havelast) printf(" cpu "); printf("\n"); if (Iflag == 0) { - printf("device r/s w/s kr/s kw/s qlen " - "svc_t %%b "); + printf("device r/s w/s kr/s kw/s " + " ms/r ms/w ms/o ms/t qlen %%b "); } else { printf("device r/i w/i kr/i" " kw/i qlen tsvc_t/i sb/i "); @@ -786,6 +788,9 @@ devstats(int perf_select, long double etime, int havelast) DSM_MB_PER_SECOND_WRITE, &mb_per_second_write, DSM_BLOCKS_PER_SECOND, &blocks_per_second, DSM_MS_PER_TRANSACTION, &ms_per_transaction, + DSM_MS_PER_TRANSACTION_READ, &ms_per_read, + DSM_MS_PER_TRANSACTION_WRITE, &ms_per_write, + DSM_MS_PER_TRANSACTION_OTHER, &ms_per_other, DSM_BUSY_PCT, &busy_pct, DSM_QUEUE_LENGTH, &queue_len, DSM_TOTAL_DURATION, &total_duration, @@ -820,13 +825,18 @@ devstats(int perf_select, long double etime, int havelast) mb_per_second_write > ((long double).0005)/1024 || busy_pct > 0.5) { if (Iflag == 0) - printf("%-8.8s %5.1Lf %5.1Lf %7.1Lf %7.1Lf %4" PRIu64 " %5.1Lf %3.0Lf ", - devname, transfers_per_second_read, - transfers_per_second_write, + printf("%-8.8s %5d %5d %8.1Lf " + "%8.1Lf %5d %5d %5d %5d " + "%4" PRIu64 " %3.0Lf ", + devname, + (int)transfers_per_second_read, + (int)transfers_per_second_write, mb_per_second_read * 1024, mb_per_second_write * 1024, - queue_len, - ms_per_transaction, busy_pct); + (int)ms_per_read, (int)ms_per_write, + (int)ms_per_other, + (int)ms_per_transaction, + queue_len, busy_pct); else printf("%-8.8s %11.1Lf %11.1Lf " "%12.1Lf %12.1Lf %4" PRIu64 From 341f4a2128ad20f79cce8f6c69287feb07257642 Mon Sep 17 00:00:00 2001 From: will Date: Fri, 23 Jan 2015 16:03:02 +0000 Subject: [PATCH 186/258] Allow lists for "nooption" and "nooptions" keywords. usr.sbin/config/config.y According to config(5), the "device", "devices", "nodevice", "nodevices", "option", "options", "nooption", and "nooptions" keywords can all take a comma-separated list of values. However, the yacc code did not allow lists for "nooption" and "nooptions", only single values. This commit fixes the yacc code to allow comma separated values for all the above keywords. Submitted by: asomers MFC after: 1 week Sponsored by: Spectra Logic MFSpectraBSD: 1095296 on 2014/10/07 --- usr.sbin/config/config.y | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/usr.sbin/config/config.y b/usr.sbin/config/config.y index 81329d922afd..c7198a027bae 100644 --- a/usr.sbin/config/config.y +++ b/usr.sbin/config/config.y @@ -178,7 +178,7 @@ Config_spec: } | OPTIONS Opt_list | - NOOPTION Save_id { rmopt_schedule(&opt, $2); } | + NOOPTION NoOpt_list | MAKEOPTIONS Mkopt_list | NOMAKEOPTION Save_id { rmopt_schedule(&mkopt, $2); } | @@ -225,6 +225,11 @@ Opt_list: Option ; +NoOpt_list: + NoOpt_list COMMA NoOption + | + NoOption + ; Option: Save_id { newopt(&opt, $1, NULL, 0); @@ -236,6 +241,11 @@ Option: newopt(&opt, $1, $3, 0); } ; +NoOption: + Save_id { + rmopt_schedule(&opt, $1); + }; + Opt_value: ID { $$ = $1; } | NUMBER { From 46dec2e356b14245e929050c1768dc109e8abc64 Mon Sep 17 00:00:00 2001 From: ian Date: Fri, 23 Jan 2015 16:05:47 +0000 Subject: [PATCH 187/258] Add pinctrl driver support for the encoded input register config words that the linux guys made up on the fly (but didn't document) last August. This type of encoded config now appears in the imx6 fdt data. --- sys/arm/freescale/imx/imx_iomux.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/sys/arm/freescale/imx/imx_iomux.c b/sys/arm/freescale/imx/imx_iomux.c index 7786b76e0a4f..d1ac6cbc2657 100644 --- a/sys/arm/freescale/imx/imx_iomux.c +++ b/sys/arm/freescale/imx/imx_iomux.c @@ -117,10 +117,36 @@ WR4(struct iomux_softc *sc, bus_size_t off, uint32_t val) bus_write_4(sc->mem_res, off, val); } +static void +iomux_configure_input(struct iomux_softc *sc, uint32_t reg, uint32_t val) +{ + u_int select, mask, shift, width; + + /* If register and value are zero, there is nothing to configure. */ + if (reg == 0 && val == 0) + return; + + /* + * If the config value has 0xff in the high byte it is encoded: + * 31 23 15 7 0 + * | 0xff | shift | width | select | + * We need to mask out the old select value and OR in the new, using a + * mask of the given width and shifting the values up by shift. + */ + if ((val & 0xff000000) == 0xff000000) { + select = val & 0x000000ff; + width = (val & 0x0000ff00) >> 8; + shift = (val & 0x00ff0000) >> 16; + mask = ((1u << width) - 1) << shift; + val = (RD4(sc, reg) & ~mask) | (select << shift); + } + WR4(sc, reg, val); +} + static int iomux_configure_pins(device_t dev, phandle_t cfgxref) { - struct iomux_softc * sc; + struct iomux_softc *sc; struct pincfg *cfgtuples, *cfg; phandle_t cfgnode; int i, ntuples; @@ -137,8 +163,7 @@ iomux_configure_pins(device_t dev, phandle_t cfgxref) for (i = 0, cfg = cfgtuples; i < ntuples; i++, cfg++) { sion = (cfg->padconf_val & PADCONF_SION) ? PADMUX_SION : 0; WR4(sc, cfg->mux_reg, cfg->mux_val | sion); - if (cfg->input_reg != 0) - WR4(sc, cfg->input_reg, cfg->input_val); + iomux_configure_input(sc, cfg->input_reg, cfg->input_val); if ((cfg->padconf_val & PADCONF_NONE) == 0) WR4(sc, cfg->padconf_reg, cfg->padconf_val); if (bootverbose) { From 8f871060e6f2ddfcf4177c91739c3d7f14e15994 Mon Sep 17 00:00:00 2001 From: will Date: Fri, 23 Jan 2015 16:15:55 +0000 Subject: [PATCH 188/258] Make "vmstat -i" respect the -c and -i options together. Submitted by: asomers MFC after: 1 week Sponsored by: Spectra Logic MFSpectraBSD: 1066735 on 2014/06/04 --- usr.bin/vmstat/vmstat.c | 149 +++++++++++++++++++++++++++++----------- 1 file changed, 110 insertions(+), 39 deletions(-) diff --git a/usr.bin/vmstat/vmstat.c b/usr.bin/vmstat/vmstat.c index 760dce835932..a54a0dd45b20 100644 --- a/usr.bin/vmstat/vmstat.c +++ b/usr.bin/vmstat/vmstat.c @@ -148,7 +148,7 @@ static void cpustats(void); static void pcpustats(int, u_long, int); static void devstats(void); static void doforkst(void); -static void dointr(void); +static void dointr(unsigned int, int); static void dosum(void); static void dovmstat(unsigned int, int); static void domemstat_malloc(void); @@ -325,7 +325,7 @@ main(int argc, char *argv[]) dotimes(); #endif if (todo & INTRSTAT) - dointr(); + dointr(interval, reps); if (todo & VMSTAT) dovmstat(interval, reps); exit(0); @@ -1165,61 +1165,132 @@ pcpustats(int ncpus, u_long cpumask, int maxid) } } -static void -dointr(void) +static unsigned int +read_intrcnts(unsigned long **intrcnts) { - unsigned long *intrcnt, uptime; - uint64_t inttotal; - size_t clen, inamlen, intrcntlen, istrnamlen; - unsigned int i, nintr; - char *intrname, *tintrname; + size_t intrcntlen; - uptime = getuptime(); if (kd != NULL) { kread(X_SINTRCNT, &intrcntlen, sizeof(intrcntlen)); - kread(X_SINTRNAMES, &inamlen, sizeof(inamlen)); - if ((intrcnt = malloc(intrcntlen)) == NULL || - (intrname = malloc(inamlen)) == NULL) + if ((*intrcnts = malloc(intrcntlen)) == NULL) err(1, "malloc()"); - kread(X_INTRCNT, intrcnt, intrcntlen); - kread(X_INTRNAMES, intrname, inamlen); + kread(X_INTRCNT, *intrcnts, intrcntlen); } else { - for (intrcnt = NULL, intrcntlen = 1024; ; intrcntlen *= 2) { - if ((intrcnt = reallocf(intrcnt, intrcntlen)) == NULL) + for (*intrcnts = NULL, intrcntlen = 1024; ; intrcntlen *= 2) { + *intrcnts = reallocf(*intrcnts, intrcntlen); + if (*intrcnts == NULL) err(1, "reallocf()"); if (mysysctl("hw.intrcnt", - intrcnt, &intrcntlen, NULL, 0) == 0) - break; - } - for (intrname = NULL, inamlen = 1024; ; inamlen *= 2) { - if ((intrname = reallocf(intrname, inamlen)) == NULL) - err(1, "reallocf()"); - if (mysysctl("hw.intrnames", - intrname, &inamlen, NULL, 0) == 0) + *intrcnts, &intrcntlen, NULL, 0) == 0) break; } } - nintr = intrcntlen / sizeof(unsigned long); - tintrname = intrname; + + return (intrcntlen / sizeof(unsigned long)); +} + +static void +print_intrcnts(unsigned long *intrcnts, unsigned long *old_intrcnts, + char *intrnames, unsigned int nintr, + size_t istrnamlen, unsigned long long period) +{ + unsigned long *intrcnt, *old_intrcnt; + uint64_t inttotal, old_inttotal, total_count, total_rate; + char* intrname; + unsigned int i; + + inttotal = 0; + old_inttotal = 0; + intrname = intrnames; + for (i = 0, intrcnt=intrcnts, old_intrcnt=old_intrcnts; i < nintr; i++) { + if (intrname[0] != '\0' && (*intrcnt != 0 || aflag)) { + unsigned long count, rate; + + count = *intrcnt - *old_intrcnt; + rate = (count * 1000 + period/2) / period; + (void)printf("%-*s %20lu %10lu\n", (int)istrnamlen, + intrname, count, rate); + } + intrname += strlen(intrname) + 1; + inttotal += *intrcnt++; + old_inttotal += *old_intrcnt++; + } + total_count = inttotal - old_inttotal; + total_rate = (total_count * 1000 + period/2) / period; + (void)printf("%-*s %20" PRIu64 " %10" PRIu64 "\n", (int)istrnamlen, + "Total", total_count, total_rate); +} + +static void +dointr(unsigned int interval, int reps) +{ + unsigned long *intrcnts; + unsigned long long uptime, period; + unsigned long *old_intrcnts = NULL; + size_t clen, inamlen, istrnamlen; + unsigned int rep; + char *intrnames, *intrname; + + uptime = getuptime(); + + /* Get the names of each interrupt source */ + if (kd != NULL) { + kread(X_SINTRNAMES, &inamlen, sizeof(inamlen)); + if ((intrnames = malloc(inamlen)) == NULL) + err(1, "malloc()"); + kread(X_INTRNAMES, intrnames, inamlen); + } else { + for (intrnames = NULL, inamlen = 1024; ; inamlen *= 2) { + if ((intrnames = reallocf(intrnames, inamlen)) == NULL) + err(1, "reallocf()"); + if (mysysctl("hw.intrnames", + intrnames, &inamlen, NULL, 0) == 0) + break; + } + } + + /* Determine the length of the longest interrupt name */ + intrname = intrnames; istrnamlen = strlen("interrupt"); - for (i = 0; i < nintr; i++) { - clen = strlen(tintrname); + while(*intrname != '\0') { + clen = strlen(intrname); if (clen > istrnamlen) istrnamlen = clen; - tintrname += clen + 1; + intrname += strlen(intrname) + 1; } (void)printf("%-*s %20s %10s\n", (int)istrnamlen, "interrupt", "total", "rate"); - inttotal = 0; - for (i = 0; i < nintr; i++) { - if (intrname[0] != '\0' && (*intrcnt != 0 || aflag)) - (void)printf("%-*s %20lu %10lu\n", (int)istrnamlen, - intrname, *intrcnt, *intrcnt / uptime); - intrname += strlen(intrname) + 1; - inttotal += *intrcnt++; + + /* + * Loop reps times printing differential interrupt counts. If reps is + * zero, then run just once, printing total counts + */ + period = uptime * 1000; + while(1) { + char *intrname; + unsigned int nintr; + + nintr = read_intrcnts(&intrcnts); + /* + * Initialize old_intrcnts to 0 for the first pass, so + * print_intrcnts will print total interrupts since boot + */ + if (old_intrcnts == NULL) { + old_intrcnts = calloc(nintr, sizeof(unsigned long)); + if (old_intrcnts == NULL) + err(1, "calloc()"); + } + + print_intrcnts(intrcnts, old_intrcnts, intrnames, nintr, + istrnamlen, period); + + free(old_intrcnts); + old_intrcnts = intrcnts; + if (reps >= 0 && --reps <= 0) + break; + usleep(interval * 1000); + period = interval; } - (void)printf("%-*s %20" PRIu64 " %10" PRIu64 "\n", (int)istrnamlen, - "Total", inttotal, inttotal / uptime); } static void From 1c17feb7e9fac76c5231fe9b63cc0941e1a92acd Mon Sep 17 00:00:00 2001 From: will Date: Fri, 23 Jan 2015 16:18:39 +0000 Subject: [PATCH 189/258] Use CLOCK_UPTIME to get the uptime instead of CLOCK_MONOTONIC. Submitted by: asomers MFC after: 1 week Sponsored by: Spectra Logic MFSpectraBSD: 1066740 on 2014/06/04 --- usr.bin/vmstat/vmstat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr.bin/vmstat/vmstat.c b/usr.bin/vmstat/vmstat.c index a54a0dd45b20..925967c7f431 100644 --- a/usr.bin/vmstat/vmstat.c +++ b/usr.bin/vmstat/vmstat.c @@ -411,7 +411,7 @@ getuptime(void) { struct timespec sp; - (void)clock_gettime(CLOCK_MONOTONIC, &sp); + (void)clock_gettime(CLOCK_UPTIME, &sp); return(sp.tv_sec); } From 5cc1a7a015f5b17e67d926a9081d8825d89267aa Mon Sep 17 00:00:00 2001 From: will Date: Fri, 23 Jan 2015 16:21:31 +0000 Subject: [PATCH 190/258] Use clock_gettime to measure the time that we spent asleep during "vmstat -i" instead of assuming it's what we asked for. Submitted by: asomers MFC after: 1 week Sponsored by: Spectra Logic MFSpectraBSD: 1066751 on 2014/06/04 --- usr.bin/vmstat/vmstat.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/usr.bin/vmstat/vmstat.c b/usr.bin/vmstat/vmstat.c index 925967c7f431..9049e442227f 100644 --- a/usr.bin/vmstat/vmstat.c +++ b/usr.bin/vmstat/vmstat.c @@ -163,7 +163,7 @@ static void printhdr(int, u_long); static void usage(void); static long pct(long, long); -static long getuptime(void); +static long long getuptime(void); static char **getdrivedata(char **); @@ -406,14 +406,15 @@ getdrivedata(char **argv) return(argv); } -static long +/* Return system uptime in nanoseconds */ +static long long getuptime(void) { struct timespec sp; (void)clock_gettime(CLOCK_UPTIME, &sp); - return(sp.tv_sec); + return((long long)sp.tv_sec * 1000000000LL + sp.tv_nsec); } static void @@ -654,7 +655,7 @@ dovmstat(unsigned int interval, int reps) u_long cpumask; int rate_adj; - uptime = getuptime(); + uptime = getuptime() / 1000000000LL; halfuptime = uptime / 2; rate_adj = 1; ncpus = 1; @@ -1192,7 +1193,7 @@ read_intrcnts(unsigned long **intrcnts) static void print_intrcnts(unsigned long *intrcnts, unsigned long *old_intrcnts, char *intrnames, unsigned int nintr, - size_t istrnamlen, unsigned long long period) + size_t istrnamlen, long long period_ms) { unsigned long *intrcnt, *old_intrcnt; uint64_t inttotal, old_inttotal, total_count, total_rate; @@ -1207,7 +1208,7 @@ print_intrcnts(unsigned long *intrcnts, unsigned long *old_intrcnts, unsigned long count, rate; count = *intrcnt - *old_intrcnt; - rate = (count * 1000 + period/2) / period; + rate = (count * 1000 + period_ms / 2) / period_ms; (void)printf("%-*s %20lu %10lu\n", (int)istrnamlen, intrname, count, rate); } @@ -1216,7 +1217,7 @@ print_intrcnts(unsigned long *intrcnts, unsigned long *old_intrcnts, old_inttotal += *old_intrcnt++; } total_count = inttotal - old_inttotal; - total_rate = (total_count * 1000 + period/2) / period; + total_rate = (total_count * 1000 + period_ms / 2) / period_ms; (void)printf("%-*s %20" PRIu64 " %10" PRIu64 "\n", (int)istrnamlen, "Total", total_count, total_rate); } @@ -1225,10 +1226,9 @@ static void dointr(unsigned int interval, int reps) { unsigned long *intrcnts; - unsigned long long uptime, period; + long long uptime, period_ms; unsigned long *old_intrcnts = NULL; size_t clen, inamlen, istrnamlen; - unsigned int rep; char *intrnames, *intrname; uptime = getuptime(); @@ -1265,10 +1265,10 @@ dointr(unsigned int interval, int reps) * Loop reps times printing differential interrupt counts. If reps is * zero, then run just once, printing total counts */ - period = uptime * 1000; + period_ms = uptime / 1000000; while(1) { - char *intrname; unsigned int nintr; + long long old_uptime; nintr = read_intrcnts(&intrcnts); /* @@ -1282,14 +1282,16 @@ dointr(unsigned int interval, int reps) } print_intrcnts(intrcnts, old_intrcnts, intrnames, nintr, - istrnamlen, period); + istrnamlen, period_ms); free(old_intrcnts); old_intrcnts = intrcnts; if (reps >= 0 && --reps <= 0) break; usleep(interval * 1000); - period = interval; + old_uptime = uptime; + uptime = getuptime(); + period_ms = (uptime - old_uptime) / 1000000; } } From c3bbac9fac9d8936d81ba077575488fce0a70bdb Mon Sep 17 00:00:00 2001 From: jkim Date: Fri, 23 Jan 2015 18:12:44 +0000 Subject: [PATCH 191/258] Revert r216942. This commit was premature and caused too many complaints. PR: 162859 MFC after: 3 days --- sys/dev/acpica/acpi_ec.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/sys/dev/acpica/acpi_ec.c b/sys/dev/acpica/acpi_ec.c index 6537e4062b4d..2261b355d9f6 100644 --- a/sys/dev/acpica/acpi_ec.c +++ b/sys/dev/acpica/acpi_ec.c @@ -620,7 +620,7 @@ EcGpeQueryHandler(void *Context) struct acpi_ec_softc *sc = (struct acpi_ec_softc *)Context; UINT8 Data; ACPI_STATUS Status; - int retry, sci_enqueued; + int retry; char qxx[5]; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); @@ -641,7 +641,6 @@ EcGpeQueryHandler(void *Context) * that may arise from running the query from causing another query * to be queued, we clear the pending flag only after running it. */ - sci_enqueued = sc->ec_sci_pend; for (retry = 0; retry < 2; retry++) { Status = EcCommand(sc, EC_COMMAND_QUERY); if (ACPI_SUCCESS(Status)) @@ -681,14 +680,6 @@ EcGpeQueryHandler(void *Context) device_printf(sc->ec_dev, "evaluation of query method %s failed: %s\n", qxx, AcpiFormatException(Status)); } - - /* Reenable runtime GPE if its execution was deferred. */ - if (sci_enqueued) { - Status = AcpiFinishGpe(sc->ec_gpehandle, sc->ec_gpebit); - if (ACPI_FAILURE(Status)) - device_printf(sc->ec_dev, "reenabling runtime GPE failed: %s\n", - AcpiFormatException(Status)); - } } /* @@ -722,10 +713,9 @@ EcGpeHandler(ACPI_HANDLE GpeDevice, UINT32 GpeNumber, void *Context) if ((EcStatus & EC_EVENT_SCI) && !sc->ec_sci_pend) { CTR0(KTR_ACPI, "ec gpe queueing query handler"); Status = AcpiOsExecute(OSL_GPE_HANDLER, EcGpeQueryHandler, Context); - if (ACPI_SUCCESS(Status)) { + if (ACPI_SUCCESS(Status)) sc->ec_sci_pend = TRUE; - return (0); - } else + else printf("EcGpeHandler: queuing GPE query handler failed\n"); } return (ACPI_REENABLE_GPE); From 218f4108d5d6c2acc67126ce70b20e45c24835bf Mon Sep 17 00:00:00 2001 From: jkim Date: Fri, 23 Jan 2015 18:55:04 +0000 Subject: [PATCH 192/258] Simplify retry loops. No functional change. --- sys/dev/acpica/acpi_ec.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/sys/dev/acpica/acpi_ec.c b/sys/dev/acpica/acpi_ec.c index 2261b355d9f6..8a8cb6ea4f3a 100644 --- a/sys/dev/acpica/acpi_ec.c +++ b/sys/dev/acpica/acpi_ec.c @@ -645,10 +645,8 @@ EcGpeQueryHandler(void *Context) Status = EcCommand(sc, EC_COMMAND_QUERY); if (ACPI_SUCCESS(Status)) break; - if (ACPI_SUCCESS(EcCheckStatus(sc, "retr_check", + if (ACPI_FAILURE(EcCheckStatus(sc, "retr_check", EC_EVENT_INPUT_BUFFER_EMPTY))) - continue; - else break; } sc->ec_sci_pend = FALSE; @@ -963,15 +961,13 @@ EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data) gen_count = sc->ec_gencount; EC_SET_DATA(sc, Address); status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL, gen_count); - if (ACPI_FAILURE(status)) { - if (ACPI_SUCCESS(EcCheckStatus(sc, "retr_check", - EC_EVENT_INPUT_BUFFER_EMPTY))) - continue; - else - break; + if (ACPI_SUCCESS(status)) { + *Data = EC_GET_DATA(sc); + return (AE_OK); } - *Data = EC_GET_DATA(sc); - return (AE_OK); + if (ACPI_FAILURE(EcCheckStatus(sc, "retr_check", + EC_EVENT_INPUT_BUFFER_EMPTY))) + break; } device_printf(sc->ec_dev, "EcRead: failed waiting to get data\n"); return (status); From 782ca776824bb9864fd315906204bd3936ec0f9d Mon Sep 17 00:00:00 2001 From: gjb Date: Fri, 23 Jan 2015 19:33:03 +0000 Subject: [PATCH 193/258] Document r276881, libedit UTF-8 support. Sponsored by: The FreeBSD Foundation --- release/doc/en_US.ISO8859-1/relnotes/article.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/release/doc/en_US.ISO8859-1/relnotes/article.xml b/release/doc/en_US.ISO8859-1/relnotes/article.xml index 4a5b4d6d28d4..1522f61da1ba 100644 --- a/release/doc/en_US.ISO8859-1/relnotes/article.xml +++ b/release/doc/en_US.ISO8859-1/relnotes/article.xml @@ -791,6 +791,11 @@ strings were switched to the versions from the ELF Tool Chain project. + The libedit library + has been updated to include UTF-8 support, + adding UTF-8 support to the &man.sh.1; + shell. + OpenSSL has been updated to version 1.0.1l. From 70100a6eadaf60e0a5726f5ea8537659bdf149fe Mon Sep 17 00:00:00 2001 From: gjb Date: Fri, 23 Jan 2015 19:33:05 +0000 Subject: [PATCH 194/258] Document r277166, ptrace(2) Altivec register support. Sponsored by: The FreeBSD Foundation --- release/doc/en_US.ISO8859-1/relnotes/article.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/release/doc/en_US.ISO8859-1/relnotes/article.xml b/release/doc/en_US.ISO8859-1/relnotes/article.xml index 1522f61da1ba..ac30f3b00a06 100644 --- a/release/doc/en_US.ISO8859-1/relnotes/article.xml +++ b/release/doc/en_US.ISO8859-1/relnotes/article.xml @@ -691,6 +691,10 @@ has been updated to support UTF-8, which additionally provides unicode support to &man.sh.1;. + The &man.ptrace.2; system + call has been updated include support for Altivec registers on + &os;/&arch.powerpc;. + <acronym>ABI</acronym> Compatibility From 4a0b24c4668bbcbef3d98034f17e42207d6fe426 Mon Sep 17 00:00:00 2001 From: gjb Date: Fri, 23 Jan 2015 19:33:08 +0000 Subject: [PATCH 195/258] Document r277458, support for cloud hosting providers added to the Release Engineering build tools. Sponsored by: The FreeBSD Foundation --- release/doc/en_US.ISO8859-1/relnotes/article.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/release/doc/en_US.ISO8859-1/relnotes/article.xml b/release/doc/en_US.ISO8859-1/relnotes/article.xml index ac30f3b00a06..756e74a8081e 100644 --- a/release/doc/en_US.ISO8859-1/relnotes/article.xml +++ b/release/doc/en_US.ISO8859-1/relnotes/article.xml @@ -813,7 +813,10 @@ Release Engineering and Integration -   + The + Release Engineering build tools have been updated to include + support for producing virtual machine disk images for various + cloud hosting providers. From c5771a6a64b551019397622bf7cc18190c3430a5 Mon Sep 17 00:00:00 2001 From: gjb Date: Fri, 23 Jan 2015 19:33:46 +0000 Subject: [PATCH 196/258] Update the latest revision. Sponsored by: The FreeBSD Foundation --- release/doc/en_US.ISO8859-1/relnotes/article.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/doc/en_US.ISO8859-1/relnotes/article.xml b/release/doc/en_US.ISO8859-1/relnotes/article.xml index 756e74a8081e..e0625f302c6e 100644 --- a/release/doc/en_US.ISO8859-1/relnotes/article.xml +++ b/release/doc/en_US.ISO8859-1/relnotes/article.xml @@ -20,7 +20,7 @@ $FreeBSD$ - + 2015 From b45ededabbeff9c56081d187f9561e3891c2c1f5 Mon Sep 17 00:00:00 2001 From: cperciva Date: Fri, 23 Jan 2015 20:24:13 +0000 Subject: [PATCH 197/258] Provide a recipe of "true" for building the "release" target once its prerequisites are satisfied, in order to avoid having an implicit rule triggered by the presence of release.sh. Approved by: gjb --- release/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/release/Makefile b/release/Makefile index a601921b3303..9b80f8afa8f0 100644 --- a/release/Makefile +++ b/release/Makefile @@ -279,6 +279,7 @@ ftp: packagesystem cp *.txz MANIFEST ftp release: real-release vm-release cloudware-release + @true real-release: ${MAKE} -C ${.CURDIR} ${.MAKEFLAGS} obj From 7de9767772450e381a498ed15f8e22c42047bbc7 Mon Sep 17 00:00:00 2001 From: pfg Date: Fri, 23 Jan 2015 20:40:31 +0000 Subject: [PATCH 198/258] MFV r277607: GDB: Fix memset thinkos. 2005-03-25 Anthony Green * remote.c (remote_store_registers): Fix memset usage. * std-regs.c (value_of_builtin_frame_reg): Ditto. (value_of_builtin_frame_fp_reg): Ditto. (value_of_builtin_frame_reg): Ditto. Reported by: Dirk Engling CID: 604160, 604161, 604162, 604163 MFC after: 5 days --- contrib/gdb/gdb/remote.c | 2 +- contrib/gdb/gdb/std-regs.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/contrib/gdb/gdb/remote.c b/contrib/gdb/gdb/remote.c index 7ff2cb8087ea..33641ed491a3 100644 --- a/contrib/gdb/gdb/remote.c +++ b/contrib/gdb/gdb/remote.c @@ -3463,7 +3463,7 @@ remote_store_registers (int regnum) { int i; regs = alloca (rs->sizeof_g_packet); - memset (regs, rs->sizeof_g_packet, 0); + memset (regs, 0, rs->sizeof_g_packet); for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++) { struct packet_reg *r = &rs->regs[i]; diff --git a/contrib/gdb/gdb/std-regs.c b/contrib/gdb/gdb/std-regs.c index 368720dd95b0..bd134b515b38 100644 --- a/contrib/gdb/gdb/std-regs.c +++ b/contrib/gdb/gdb/std-regs.c @@ -61,7 +61,7 @@ value_of_builtin_frame_reg (struct frame_info *frame) val = allocate_value (builtin_type_frame_reg); VALUE_LVAL (val) = not_lval; buf = VALUE_CONTENTS_RAW (val); - memset (buf, TYPE_LENGTH (VALUE_TYPE (val)), 0); + memset (buf, 0, TYPE_LENGTH (VALUE_TYPE (val))); /* frame.base. */ if (frame != NULL) ADDRESS_TO_POINTER (builtin_type_void_data_ptr, buf, @@ -87,7 +87,7 @@ value_of_builtin_frame_fp_reg (struct frame_info *frame) struct value *val = allocate_value (builtin_type_void_data_ptr); char *buf = VALUE_CONTENTS_RAW (val); if (frame == NULL) - memset (buf, TYPE_LENGTH (VALUE_TYPE (val)), 0); + memset (buf, 0, TYPE_LENGTH (VALUE_TYPE (val))); else ADDRESS_TO_POINTER (builtin_type_void_data_ptr, buf, get_frame_base_address (frame)); @@ -105,7 +105,7 @@ value_of_builtin_frame_pc_reg (struct frame_info *frame) struct value *val = allocate_value (builtin_type_void_data_ptr); char *buf = VALUE_CONTENTS_RAW (val); if (frame == NULL) - memset (buf, TYPE_LENGTH (VALUE_TYPE (val)), 0); + memset (buf, 0, TYPE_LENGTH (VALUE_TYPE (val))); else ADDRESS_TO_POINTER (builtin_type_void_data_ptr, buf, get_frame_pc (frame)); From 4743c20fb6384559028572e519b637c0667e87ec Mon Sep 17 00:00:00 2001 From: gjb Date: Fri, 23 Jan 2015 21:04:59 +0000 Subject: [PATCH 199/258] When iterating through VMFORMATS, the VMBASE file is not removed or truncated to a zero-size file, which if used to create more than one disk image format, can result in accidental pollution of the target formatted disk image. Instead of using a single VMBASE image (vm.img, by default), use a single base file for each format, named as VMFORMAT.img, which produces VMBASE.VMFORMAT as the final formatted image. Reported by: cperciva MFC after: 1 month X-MFC-with: r277458, r277536 Sponsored by: The FreeBSD Foundation --- release/Makefile.vm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release/Makefile.vm b/release/Makefile.vm index 17229bfb2792..fe955d30d8c1 100644 --- a/release/Makefile.vm +++ b/release/Makefile.vm @@ -50,8 +50,8 @@ vm-${_CW:tl}: .if defined(WITH_VMIMAGES) && !empty(WITH_VMIMAGES) CLEANDIRS+= ${VMTARGETS} -CLEANFILES+= ${VMBASE}.img . for FORMAT in ${VMFORMATS} +CLEANFILES+= ${FORMAT}.img CLEANFILES+= ${VMBASE}.${FORMAT} . endfor .endif @@ -65,7 +65,7 @@ vm-image: env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ ${.CURDIR}/scripts/mk-vmimage.sh \ -C ${.CURDIR}/tools/vmimage.subr -d ${.OBJDIR}/${.TARGET} \ - -i ${.OBJDIR}/${VMBASE}.img -s ${VMSIZE} -f ${FORMAT} \ + -i ${.OBJDIR}/${FORMAT}.img -s ${VMSIZE} -f ${FORMAT} \ -S ${WORLDDIR} -o ${.OBJDIR}/${VMBASE}.${FORMAT} . endfor .endif From 67db24d0f2b81a222335fe5bb13977ef0c2258a9 Mon Sep 17 00:00:00 2001 From: jilles Date: Fri, 23 Jan 2015 21:07:08 +0000 Subject: [PATCH 200/258] Add futimens and utimensat system calls. The core kernel part is patch file utimes.2008.4.diff from pluknet@FreeBSD.org. I updated the code for API changes, added the manual page and added compatibility code for old kernels. There is also audit and Capsicum support. A new UTIME_* constant might allow setting birthtimes in future. Differential Revision: https://reviews.freebsd.org/D1426 Submitted by: pluknet (partially) Reviewed by: delphij, pluknet, rwatson Relnotes: yes --- bin/ln/symlink.7 | 7 +- lib/libc/include/libc_private.h | 4 + lib/libc/sys/Makefile.inc | 6 + lib/libc/sys/Symbol.map | 2 + lib/libc/sys/futimens.c | 97 +++++++++ lib/libc/sys/utimensat.2 | 292 ++++++++++++++++++++++++++ lib/libc/sys/utimensat.c | 109 ++++++++++ share/man/man4/rights.4 | 8 +- sys/compat/freebsd32/freebsd32_misc.c | 43 ++++ sys/compat/freebsd32/syscalls.master | 5 + sys/kern/capabilities.conf | 4 +- sys/kern/syscalls.master | 5 + sys/kern/vfs_syscalls.c | 126 ++++++++++- sys/sys/capsicum.h | 4 +- sys/sys/param.h | 2 +- sys/sys/stat.h | 8 + sys/sys/syscallsubr.h | 5 + usr.bin/kdump/kdump.c | 1 + 18 files changed, 717 insertions(+), 11 deletions(-) create mode 100644 lib/libc/sys/futimens.c create mode 100644 lib/libc/sys/utimensat.2 create mode 100644 lib/libc/sys/utimensat.c diff --git a/bin/ln/symlink.7 b/bin/ln/symlink.7 index 6aba773db7e5..821a3128c914 100644 --- a/bin/ln/symlink.7 +++ b/bin/ln/symlink.7 @@ -29,7 +29,7 @@ .\" @(#)symlink.7 8.3 (Berkeley) 3/31/94 .\" $FreeBSD$ .\" -.Dd December 29, 2014 +.Dd January 23, 2015 .Dt SYMLINK 7 .Os .Sh NAME @@ -147,9 +147,10 @@ unless given the .Dv AT_SYMLINK_NOFOLLOW flag: .Xr fchmodat 2 , -.Xr fchownat 2 +.Xr fchownat 2 , +.Xr fstatat 2 and -.Xr fstatat 2 . +.Xr utimensat 2 . .Pp The owner and group of an existing symbolic link can be changed by means of the diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h index 347b46305d4b..bfcd3d060e96 100644 --- a/lib/libc/include/libc_private.h +++ b/lib/libc/include/libc_private.h @@ -357,6 +357,10 @@ int __libc_system(const char *); int __libc_tcdrain(int); int __fcntl_compat(int fd, int cmd, ...); +int __sys_futimens(int fd, const struct timespec *times) __hidden; +int __sys_utimensat(int fd, const char *path, + const struct timespec *times, int flag) __hidden; + /* execve() with PATH processing to implement posix_spawnp() */ int _execvpe(const char *, char * const *, char * const *); diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc index 0a3c13f8e3b1..e8ec58e7a088 100644 --- a/lib/libc/sys/Makefile.inc +++ b/lib/libc/sys/Makefile.inc @@ -38,6 +38,10 @@ SRCS+= ${SYSCALL_COMPAT_SRCS} NOASM+= ${SYSCALL_COMPAT_SRCS:S/.c/.o/} .endif +SRCS+= futimens.c utimensat.c +NOASM+= futimens.o utimensat.o +PSEUDO+= _futimens.o _utimensat.o + INTERPOSED = \ accept \ accept4 \ @@ -310,6 +314,7 @@ MAN+= sctp_generic_recvmsg.2 \ umask.2 \ undelete.2 \ unlink.2 \ + utimensat.2 \ utimes.2 \ utrace.2 \ uuidgen.2 \ @@ -442,6 +447,7 @@ MLINKS+=timer_settime.2 timer_getoverrun.2 \ timer_settime.2 timer_gettime.2 MLINKS+=truncate.2 ftruncate.2 MLINKS+=unlink.2 unlinkat.2 +MLINKS+=utimensat.2 futimens.2 MLINKS+=utimes.2 futimes.2 \ utimes.2 futimesat.2 \ utimes.2 lutimes.2 diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map index f1f57ba9fb79..194aa5bf0999 100644 --- a/lib/libc/sys/Symbol.map +++ b/lib/libc/sys/Symbol.map @@ -397,7 +397,9 @@ FBSD_1.3 { }; FBSD_1.4 { + futimens; ppoll; + utimensat; }; FBSDprivate_1.0 { diff --git a/lib/libc/sys/futimens.c b/lib/libc/sys/futimens.c new file mode 100644 index 000000000000..2014cc5cecf3 --- /dev/null +++ b/lib/libc/sys/futimens.c @@ -0,0 +1,97 @@ +/*- + * Copyright (c) 2015 Jilles Tjoelker + * 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 "namespace.h" +#include + +#include +#include +#include +#include "un-namespace.h" + +#include "libc_private.h" + +int +futimens(int fd, const struct timespec times[2]) +{ + struct timeval now, tv[2], *tvp; + struct stat sb; + + if (__getosreldate() >= 1100056) + return (__sys_futimens(fd, times)); + + if (times == NULL || (times[0].tv_nsec == UTIME_NOW && + times[1].tv_nsec == UTIME_NOW)) + tvp = NULL; + else if (times[0].tv_nsec == UTIME_OMIT && + times[1].tv_nsec == UTIME_OMIT) + return (0); + else { + if ((times[0].tv_nsec < 0 || times[0].tv_nsec > 999999999) && + times[0].tv_nsec != UTIME_NOW && + times[0].tv_nsec != UTIME_OMIT) { + errno = EINVAL; + return (-1); + } + if ((times[1].tv_nsec < 0 || times[1].tv_nsec > 999999999) && + times[1].tv_nsec != UTIME_NOW && + times[1].tv_nsec != UTIME_OMIT) { + errno = EINVAL; + return (-1); + } + tv[0].tv_sec = times[0].tv_sec; + tv[0].tv_usec = times[0].tv_nsec / 1000; + tv[1].tv_sec = times[1].tv_sec; + tv[1].tv_usec = times[1].tv_nsec / 1000; + tvp = tv; + if (times[0].tv_nsec == UTIME_OMIT || + times[1].tv_nsec == UTIME_OMIT) { + if (_fstat(fd, &sb) == -1) + return (-1); + if (times[0].tv_nsec == UTIME_OMIT) { + tv[0].tv_sec = sb.st_atim.tv_sec; + tv[0].tv_usec = sb.st_atim.tv_nsec / 1000; + } + if (times[1].tv_nsec == UTIME_OMIT) { + tv[1].tv_sec = sb.st_mtim.tv_sec; + tv[1].tv_usec = sb.st_mtim.tv_nsec / 1000; + } + } + if (times[0].tv_nsec == UTIME_NOW || + times[1].tv_nsec == UTIME_NOW) { + if (gettimeofday(&now, NULL) == -1) + return (-1); + if (times[0].tv_nsec == UTIME_NOW) + tv[0] = now; + if (times[1].tv_nsec == UTIME_NOW) + tv[1] = now; + } + } + return (futimes(fd, tvp)); +} diff --git a/lib/libc/sys/utimensat.2 b/lib/libc/sys/utimensat.2 new file mode 100644 index 000000000000..0f397c6a99aa --- /dev/null +++ b/lib/libc/sys/utimensat.2 @@ -0,0 +1,292 @@ +.\" $NetBSD: utimes.2,v 1.13 1999/03/22 19:45:11 garbled Exp $ +.\" +.\" Copyright (c) 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" Copyright (c) 2012, Jilles Tjoelker +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)utimes.2 8.1 (Berkeley) 6/4/93 +.\" $FreeBSD$ +.\" +.Dd January 23, 2015 +.Dt UTIMENSAT 2 +.Os +.Sh NAME +.Nm futimens , +.Nm utimensat +.Nd set file access and modification times +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In sys/stat.h +.Ft int +.Fn futimens "int fd" "const struct timespec times[2]" +.Ft int +.Fo utimensat +.Fa "int fd" +.Fa "const char *path" +.Fa "const struct timespec times[2]" +.Fa "int flag" +.Fc +.Sh DESCRIPTION +The access and modification times of the file named by +.Fa path +or referenced by +.Fa fd +are changed as specified by the argument +.Fa times . +The inode-change-time of the file is set to the current time. +.Pp +If +.Fa path +specifies a relative path, +it is relative to the current working directory if +.Fa fd +is +.Dv AT_FDCWD +and otherwise relative to the directory associated with the file descriptor +.Fa fd . +.Pp +The +.Va tv_nsec +field of a +.Vt timespec +structure +can be set to the special value +.Dv UTIME_NOW +to set the current time, or to +.Dv UTIME_OMIT +to leave the time unchanged. +In either case, the +.Va tv_sec +field is ignored. +.Pp +If +.Fa times +is +.No non- Ns Dv NULL , +it is assumed to point to an array of two timespec structures. +The access time is set to the value of the first element, and the +modification time is set to the value of the second element. +For file systems that support file birth (creation) times (such as +.Dv UFS2 ) , +the birth time will be set to the value of the second element +if the second element is older than the currently set birth time. +To set both a birth time and a modification time, +two calls are required; the first to set the birth time +and the second to set the (presumably newer) modification time. +Ideally a new system call will be added that allows the setting +of all three times at once. +If +.Fa times +is +.Dv NULL , +this is equivalent to passing +a pointer to an array of two timespec structures +with both +.Va tv_nsec +fields set to +.Dv UTIME_NOW . +.Pp +If both +.Va tv_nsec +fields are +.Dv UTIME_OMIT , +the timestamps remain unchanged and +no permissions are needed for the file itself, +although search permissions may be required for the path prefix. +The call may or may not succeed if the named file does not exist. +.Pp +If both +.Va tv_nsec +fields are +.Dv UTIME_NOW , +the caller must be the owner of the file, have permission to +write the file, or be the super-user. +.Pp +For all other values of the timestamps, +the caller must be the owner of the file or be the super-user. +.Pp +The values for the +.Fa flag +argument of the +.Fn utimensat +system call +are constructed by a bitwise-inclusive OR of flags from the following list, +defined in +.In fcntl.h : +.Bl -tag -width indent +.It Dv AT_SYMLINK_NOFOLLOW +If +.Fa path +names a symbolic link, the symbolic link's times are changed. +By default, +.Fn utimensat +changes the times of the file referenced by the symbolic link. +.El +.Sh RETURN VALUES +.Rv -std +.Sh COMPATIBILITY +If the running kernel does not support this system call, +a wrapper emulates it using +.Xr fstatat 2 , +.Xr futimesat 2 +and +.Xr lutimes 2 . +As a result, timestamps will be rounded down to the nearest microsecond, +.Dv UTIME_OMIT +is not atomic and +.Dv AT_SYMLINK_NOFOLLOW +is not available with a path relative to a file descriptor. +.Sh ERRORS +These system calls will fail if: +.Bl -tag -width Er +.It Bq Er EACCES +The +.Fa times +argument is +.Dv NULL , +or both +.Va tv_nsec +values are +.Dv UTIME_NOW , +and the effective user ID of the process does not +match the owner of the file, and is not the super-user, and write +access is denied. +.It Bq Er EFAULT +The +.Fa times +argument +points outside the process's allocated address space. +.It Bq Er EINVAL +The +.Va tv_usec +component of at least one of the values specified by the +.Fa times +argument has a value less than 0 or greater than 999999. +.It Bq Er EIO +An I/O error occurred while reading or writing the affected inode. +.It Bq Er EPERM +The +.Fa times +argument is not +.Dv NULL +nor are both +.Va tv_nsec +values +.Dv UTIME_NOW , +nor are both +.Va tv_nsec +values +.Dv UTIME_OMIT +and the calling process's effective user ID +does not match the owner of the file and is not the super-user. +.It Bq Er EPERM +The named file has its immutable or append-only flag set, see the +.Xr chflags 2 +manual page for more information. +.It Bq Er EROFS +The file system containing the file is mounted read-only. +.El +.Pp +The +.Fn futimens +system call +will fail if: +.Bl -tag -width Er +.It Bq Er EBADF +The +.Fa fd +argument +does not refer to a valid descriptor. +.El +.Pp +The +.Fn utimensat +system call +will fail if: +.Bl -tag -width Er +.It Bq Er EACCES +Search permission is denied for a component of the path prefix. +.It Bq Er EBADF +The +.Fa path +argument does not specify an absolute path and the +.Fa fd +argument is neither +.Dv AT_FDCWD +nor a valid file descriptor. +.It Bq Er EFAULT +The +.Fa path +argument +points outside the process's allocated address space. +.It Bq Er ELOOP +Too many symbolic links were encountered in translating the pathname. +.It Bq Er ENAMETOOLONG +A component of a pathname exceeded +.Dv NAME_MAX +characters, or an entire path name exceeded +.Dv PATH_MAX +characters. +.It Bq Er ENOENT +The named file does not exist. +.It Bq Er ENOTDIR +A component of the path prefix is not a directory. +.It Bq Er ENOTDIR +The +.Fa path +argument is not an absolute path and +.Fa fd +is neither +.Dv AT_FDCWD +nor a file descriptor associated with a directory. +.It Bq Er ENOTSUP +The running kernel does not support this system call and +.Dv AT_SYMLINK_NOFOLLOW +is used with a path relative to a file descriptor. +.El +.Sh SEE ALSO +.Xr chflags 2 , +.Xr stat 2 , +.Xr symlink 2 , +.Xr utimes 2 , +.Xr utime 3 , +.Xr symlink 7 +.Sh STANDARDS +The +.Fn futimens +and +.Fn utimensat +system calls are expected to conform to +.St -p1003.1-2008 . +.Sh HISTORY +The +.Fn futimens +and +.Fn utimensat +system calls appeared in +.Fx 11.0 . diff --git a/lib/libc/sys/utimensat.c b/lib/libc/sys/utimensat.c new file mode 100644 index 000000000000..67d19cb2f9ba --- /dev/null +++ b/lib/libc/sys/utimensat.c @@ -0,0 +1,109 @@ +/*- + * Copyright (c) 2015 Jilles Tjoelker + * 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 "namespace.h" +#include + +#include +#include +#include +#include "un-namespace.h" + +#include "libc_private.h" + +int +utimensat(int fd, const char *path, const struct timespec times[2], int flag) +{ + struct timeval now, tv[2], *tvp; + struct stat sb; + + if (__getosreldate() >= 1100056) + return (__sys_utimensat(fd, path, times, flag)); + + if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0) { + errno = EINVAL; + return (-1); + } + if (times == NULL || (times[0].tv_nsec == UTIME_NOW && + times[1].tv_nsec == UTIME_NOW)) + tvp = NULL; + else if (times[0].tv_nsec == UTIME_OMIT && + times[1].tv_nsec == UTIME_OMIT) + return (0); + else { + if ((times[0].tv_nsec < 0 || times[0].tv_nsec > 999999999) && + times[0].tv_nsec != UTIME_NOW && + times[0].tv_nsec != UTIME_OMIT) { + errno = EINVAL; + return (-1); + } + if ((times[1].tv_nsec < 0 || times[1].tv_nsec > 999999999) && + times[1].tv_nsec != UTIME_NOW && + times[1].tv_nsec != UTIME_OMIT) { + errno = EINVAL; + return (-1); + } + tv[0].tv_sec = times[0].tv_sec; + tv[0].tv_usec = times[0].tv_nsec / 1000; + tv[1].tv_sec = times[1].tv_sec; + tv[1].tv_usec = times[1].tv_nsec / 1000; + tvp = tv; + if (times[0].tv_nsec == UTIME_OMIT || + times[1].tv_nsec == UTIME_OMIT) { + if (fstatat(fd, path, &sb, flag) == -1) + return (-1); + if (times[0].tv_nsec == UTIME_OMIT) { + tv[0].tv_sec = sb.st_atim.tv_sec; + tv[0].tv_usec = sb.st_atim.tv_nsec / 1000; + } + if (times[1].tv_nsec == UTIME_OMIT) { + tv[1].tv_sec = sb.st_mtim.tv_sec; + tv[1].tv_usec = sb.st_mtim.tv_nsec / 1000; + } + } + if (times[0].tv_nsec == UTIME_NOW || + times[1].tv_nsec == UTIME_NOW) { + if (gettimeofday(&now, NULL) == -1) + return (-1); + if (times[0].tv_nsec == UTIME_NOW) + tv[0] = now; + if (times[1].tv_nsec == UTIME_NOW) + tv[1] = now; + } + } + if ((flag & AT_SYMLINK_NOFOLLOW) == 0) + return (futimesat(fd, path, tvp)); + else if ((flag & AT_SYMLINK_NOFOLLOW) != 0 && + (fd == AT_FDCWD || path[0] == '/')) + return (lutimes(path, tvp)); + else { + errno = ENOTSUP; + return (-1); + } +} diff --git a/share/man/man4/rights.4 b/share/man/man4/rights.4 index 476b15bad1d4..16025c179e65 100644 --- a/share/man/man4/rights.4 +++ b/share/man/man4/rights.4 @@ -32,7 +32,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 23, 2013 +.Dd January 23, 2015 .Dt RIGHTS 4 .Os .Sh NAME @@ -272,9 +272,13 @@ with the flag. .It Dv CAP_FUTIMES Permit -.Xr futimes 2 +.Xr futimens 2 and +.Xr futimes 2 , +and permit .Xr futimesat 2 +and +.Xr utimensat 2 if the .Dv CAP_LOOKUP right is also present. diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c index ffea28371043..a72612b53c1c 100644 --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -1299,6 +1299,49 @@ freebsd32_futimesat(struct thread *td, struct freebsd32_futimesat_args *uap) sp, UIO_SYSSPACE)); } +int +freebsd32_futimens(struct thread *td, struct freebsd32_futimens_args *uap) +{ + struct timespec32 ts32[2]; + struct timespec ts[2], *tsp; + int error; + + if (uap->times != NULL) { + error = copyin(uap->times, ts32, sizeof(ts32)); + if (error) + return (error); + CP(ts32[0], ts[0], tv_sec); + CP(ts32[0], ts[0], tv_nsec); + CP(ts32[1], ts[1], tv_sec); + CP(ts32[1], ts[1], tv_nsec); + tsp = ts; + } else + tsp = NULL; + return (kern_futimens(td, uap->fd, tsp, UIO_SYSSPACE)); +} + +int +freebsd32_utimensat(struct thread *td, struct freebsd32_utimensat_args *uap) +{ + struct timespec32 ts32[2]; + struct timespec ts[2], *tsp; + int error; + + if (uap->times != NULL) { + error = copyin(uap->times, ts32, sizeof(ts32)); + if (error) + return (error); + CP(ts32[0], ts[0], tv_sec); + CP(ts32[0], ts[0], tv_nsec); + CP(ts32[1], ts[1], tv_sec); + CP(ts32[1], ts[1], tv_nsec); + tsp = ts; + } else + tsp = NULL; + return (kern_utimensat(td, uap->fd, uap->path, UIO_USERSPACE, + tsp, UIO_SYSSPACE, uap->flag)); +} + int freebsd32_adjtime(struct thread *td, struct freebsd32_adjtime_args *uap) { diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master index ce655bcfa581..91d1727a7f98 100644 --- a/sys/compat/freebsd32/syscalls.master +++ b/sys/compat/freebsd32/syscalls.master @@ -1069,3 +1069,8 @@ 545 AUE_POLL STD { int freebsd32_ppoll(struct pollfd *fds, \ u_int nfds, const struct timespec32 *ts, \ const sigset_t *set); } +546 AUE_FUTIMES STD { int freebsd32_futimens(int fd, \ + struct timespec *times); } +547 AUE_FUTIMESAT STD { int freebsd32_utimensat(int fd, \ + char *path, \ + struct timespec *times, int flag); } diff --git a/sys/kern/capabilities.conf b/sys/kern/capabilities.conf index f7a46aebce2c..d0ea97c4e831 100644 --- a/sys/kern/capabilities.conf +++ b/sys/kern/capabilities.conf @@ -220,8 +220,9 @@ fsync ftruncate ## -## Allow futimes(2), subject to capability rights. +## Allow futimens(2) and futimes(2), subject to capability rights. ## +futimens futimes ## @@ -453,6 +454,7 @@ readlinkat renameat symlinkat unlinkat +utimensat ## ## Allow entry into open(2). This system call will fail, since access to the diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 089896b73751..09d38d40101a 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -983,5 +983,10 @@ 545 AUE_POLL STD { int ppoll(struct pollfd *fds, u_int nfds, \ const struct timespec *ts, \ const sigset_t *set); } +546 AUE_FUTIMES STD { int futimens(int fd, \ + struct timespec *times); } +547 AUE_FUTIMESAT STD { int utimensat(int fd, \ + char *path, \ + struct timespec *times, int flag); } ; Please copy any additions and changes to the following compatability tables: ; sys/compat/freebsd32/syscalls.master diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 3105c2f4bcd5..0f248199d0d4 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -95,10 +95,12 @@ SDT_PROBE_DEFINE2(vfs, , stat, mode, "char *", "int"); SDT_PROBE_DEFINE2(vfs, , stat, reg, "char *", "int"); static int chroot_refuse_vdir_fds(struct filedesc *fdp); -static int getutimes(const struct timeval *, enum uio_seg, struct timespec *); static int kern_chflagsat(struct thread *td, int fd, const char *path, enum uio_seg pathseg, u_long flags, int atflag); static int setfflags(struct thread *td, struct vnode *, u_long); +static int getutimes(const struct timeval *, enum uio_seg, struct timespec *); +static int getutimens(const struct timespec *, enum uio_seg, + struct timespec *, int *); static int setutimes(struct thread *td, struct vnode *, const struct timespec *, int, int); static int vn_access(struct vnode *vp, int user_flags, struct ucred *cred, @@ -3007,7 +3009,53 @@ getutimes(usrtvp, tvpseg, tsp) } /* - * Common implementation code for utimes(), lutimes(), and futimes(). + * Common implementation code for futimens(), utimensat(). + */ +#define UTIMENS_NULL 0x1 +#define UTIMENS_EXIT 0x2 +static int +getutimens(const struct timespec *usrtsp, enum uio_seg tspseg, + struct timespec *tsp, int *retflags) +{ + struct timespec tsnow; + int error; + + vfs_timestamp(&tsnow); + *retflags = 0; + if (usrtsp == NULL) { + tsp[0] = tsnow; + tsp[1] = tsnow; + *retflags |= UTIMENS_NULL; + return (0); + } + if (tspseg == UIO_SYSSPACE) { + tsp[0] = usrtsp[0]; + tsp[1] = usrtsp[1]; + } else if ((error = copyin(usrtsp, tsp, sizeof(*tsp) * 2)) != 0) + return (error); + if (tsp[0].tv_nsec == UTIME_OMIT && tsp[1].tv_nsec == UTIME_OMIT) + *retflags |= UTIMENS_EXIT; + if (tsp[0].tv_nsec == UTIME_NOW && tsp[1].tv_nsec == UTIME_NOW) + *retflags |= UTIMENS_NULL; + if (tsp[0].tv_nsec == UTIME_OMIT) + tsp[0].tv_sec = VNOVAL; + else if (tsp[0].tv_nsec == UTIME_NOW) + tsp[0] = tsnow; + else if (tsp[0].tv_nsec < 0 || tsp[0].tv_nsec >= 1000000000L) + return (EINVAL); + if (tsp[1].tv_nsec == UTIME_OMIT) + tsp[1].tv_sec = VNOVAL; + else if (tsp[1].tv_nsec == UTIME_NOW) + tsp[1] = tsnow; + else if (tsp[1].tv_nsec < 0 || tsp[1].tv_nsec >= 1000000000L) + return (EINVAL); + + return (0); +} + +/* + * Common implementation code for utimes(), lutimes(), futimes(), futimens(), + * and utimensat(). */ static int setutimes(td, vp, ts, numtimes, nullflag) @@ -3196,6 +3244,80 @@ kern_futimes(struct thread *td, int fd, struct timeval *tptr, return (error); } +int +sys_futimens(struct thread *td, struct futimens_args *uap) +{ + + return (kern_futimens(td, uap->fd, uap->times, UIO_USERSPACE)); +} + +int +kern_futimens(struct thread *td, int fd, struct timespec *tptr, + enum uio_seg tptrseg) +{ + struct timespec ts[2]; + struct file *fp; + cap_rights_t rights; + int error, flags; + + AUDIT_ARG_FD(fd); + error = getutimens(tptr, tptrseg, ts, &flags); + if (error != 0) + return (error); + if (flags & UTIMENS_EXIT) + return (0); + error = getvnode(td->td_proc->p_fd, fd, + cap_rights_init(&rights, CAP_FUTIMES), &fp); + if (error != 0) + return (error); +#ifdef AUDIT + vn_lock(fp->f_vnode, LK_SHARED | LK_RETRY); + AUDIT_ARG_VNODE1(fp->f_vnode); + VOP_UNLOCK(fp->f_vnode, 0); +#endif + error = setutimes(td, fp->f_vnode, ts, 2, flags & UTIMENS_NULL); + fdrop(fp, td); + return (error); +} + +int +sys_utimensat(struct thread *td, struct utimensat_args *uap) +{ + + return (kern_utimensat(td, uap->fd, uap->path, UIO_USERSPACE, + uap->times, UIO_USERSPACE, uap->flag)); +} + +int +kern_utimensat(struct thread *td, int fd, char *path, enum uio_seg pathseg, + struct timespec *tptr, enum uio_seg tptrseg, int flag) +{ + struct nameidata nd; + struct timespec ts[2]; + int error, flags; + + if (flag & ~AT_SYMLINK_NOFOLLOW) + return (EINVAL); + + if ((error = getutimens(tptr, tptrseg, ts, &flags)) != 0) + return (error); + NDINIT_AT(&nd, LOOKUP, ((flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : + FOLLOW) | AUDITVNODE1, pathseg, path, fd, td); + if ((error = namei(&nd)) != 0) + return (error); + /* + * We are allowed to call namei() regardless of 2xUTIME_OMIT. + * POSIX states: + * "If both tv_nsec fields are UTIME_OMIT... EACCESS may be detected." + * "Search permission is denied by a component of the path prefix." + */ + NDFREE(&nd, NDF_ONLY_PNBUF); + if ((flags & UTIMENS_EXIT) == 0) + error = setutimes(td, nd.ni_vp, ts, 2, flags & UTIMENS_NULL); + vrele(nd.ni_vp); + return (error); +} + /* * Truncate a file given its path name. */ diff --git a/sys/sys/capsicum.h b/sys/sys/capsicum.h index de113c62fefc..8502a967498a 100644 --- a/sys/sys/capsicum.h +++ b/sys/sys/capsicum.h @@ -146,9 +146,9 @@ #define CAP_FSTATAT (CAP_FSTAT | CAP_LOOKUP) /* Allows for fstatfs(2). */ #define CAP_FSTATFS CAPRIGHT(0, 0x0000000000100000ULL) -/* Allows for futimes(2). */ +/* Allows for futimens(2) and futimes(2). */ #define CAP_FUTIMES CAPRIGHT(0, 0x0000000000200000ULL) -/* Allows for futimes(2) and futimesat(2). */ +/* Allows for futimens(2), futimes(2), futimesat(2) and utimensat(2). */ #define CAP_FUTIMESAT (CAP_FUTIMES | CAP_LOOKUP) /* Allows for linkat(2) and renameat(2) (destination directory descriptor). */ #define CAP_LINKAT (CAP_LOOKUP | 0x0000000000400000ULL) diff --git a/sys/sys/param.h b/sys/sys/param.h index bf59b0bf7226..eea93c957abd 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -58,7 +58,7 @@ * in the range 5 to 9. */ #undef __FreeBSD_version -#define __FreeBSD_version 1100055 /* Master, propagated to newvers */ +#define __FreeBSD_version 1100056 /* Master, propagated to newvers */ /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD, diff --git a/sys/sys/stat.h b/sys/sys/stat.h index 13dea2dc72b9..7a4370d64a27 100644 --- a/sys/sys/stat.h +++ b/sys/sys/stat.h @@ -307,6 +307,11 @@ struct nstat { #endif /* __BSD_VISIBLE */ +#if __POSIX_VISIBLE >= 200809 +#define UTIME_NOW -1 +#define UTIME_OMIT -2 +#endif + #ifndef _KERNEL __BEGIN_DECLS #if __BSD_VISIBLE @@ -322,6 +327,9 @@ int fchmod(int, mode_t); #endif #if __POSIX_VISIBLE >= 200809 int fchmodat(int, const char *, mode_t, int); +int futimens(int fd, const struct timespec times[2]); +int utimensat(int fd, const char *path, const struct timespec times[2], + int flag); #endif int fstat(int, struct stat *); #if __BSD_VISIBLE diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h index f4131a48032b..cb6d4e36cc90 100644 --- a/sys/sys/syscallsubr.h +++ b/sys/sys/syscallsubr.h @@ -99,6 +99,8 @@ int kern_fstatfs(struct thread *td, int fd, struct statfs *buf); int kern_ftruncate(struct thread *td, int fd, off_t length); int kern_futimes(struct thread *td, int fd, struct timeval *tptr, enum uio_seg tptrseg); +int kern_futimens(struct thread *td, int fd, struct timespec *tptr, + enum uio_seg tptrseg); int kern_getdirentries(struct thread *td, int fd, char *buf, u_int count, long *basep, ssize_t *residp, enum uio_seg bufseg); int kern_getfsstat(struct thread *td, struct statfs **buf, size_t bufsize, @@ -220,6 +222,9 @@ int kern_unlinkat(struct thread *td, int fd, char *path, enum uio_seg pathseg, ino_t oldinum); int kern_utimesat(struct thread *td, int fd, char *path, enum uio_seg pathseg, struct timeval *tptr, enum uio_seg tptrseg); +int kern_utimensat(struct thread *td, int fd, char *path, + enum uio_seg pathseg, struct timespec *tptr, enum uio_seg tptrseg, + int follow); int kern_wait(struct thread *td, pid_t pid, int *status, int options, struct rusage *rup); int kern_wait6(struct thread *td, enum idtype idtype, id_t id, int *status, diff --git a/usr.bin/kdump/kdump.c b/usr.bin/kdump/kdump.c index ad29bfde74c0..0daf7373cd19 100644 --- a/usr.bin/kdump/kdump.c +++ b/usr.bin/kdump/kdump.c @@ -714,6 +714,7 @@ ktrsyscall(struct ktr_syscall *ktr, u_int flags) case SYS_readlinkat: case SYS_renameat: case SYS_unlinkat: + case SYS_utimensat: putchar('('); atfdname(*ip, decimal); c = ','; From 6ad32c1c7937ea6cc035c8260bd9091cc2ea5626 Mon Sep 17 00:00:00 2001 From: jilles Date: Fri, 23 Jan 2015 21:08:24 +0000 Subject: [PATCH 201/258] Run make sysent. --- sys/compat/freebsd32/freebsd32_proto.h | 16 ++++- sys/compat/freebsd32/freebsd32_syscall.h | 6 +- sys/compat/freebsd32/freebsd32_syscalls.c | 4 +- sys/compat/freebsd32/freebsd32_sysent.c | 4 +- .../freebsd32/freebsd32_systrace_args.c | 60 +++++++++++++++++++ sys/kern/init_sysent.c | 4 +- sys/kern/syscalls.c | 4 +- sys/kern/systrace_args.c | 60 +++++++++++++++++++ sys/sys/syscall.h | 6 +- sys/sys/syscall.mk | 6 +- sys/sys/sysproto.h | 16 ++++- 11 files changed, 174 insertions(+), 12 deletions(-) diff --git a/sys/compat/freebsd32/freebsd32_proto.h b/sys/compat/freebsd32/freebsd32_proto.h index 305b76c2d735..bf9253dc3471 100644 --- a/sys/compat/freebsd32/freebsd32_proto.h +++ b/sys/compat/freebsd32/freebsd32_proto.h @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 276654 2015-01-04 10:34:02Z dchagin + * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 277610 2015-01-23 21:07:08Z jilles */ #ifndef _FREEBSD32_SYSPROTO_H_ @@ -693,6 +693,16 @@ struct freebsd32_ppoll_args { char ts_l_[PADL_(const struct timespec32 *)]; const struct timespec32 * ts; char ts_r_[PADR_(const struct timespec32 *)]; char set_l_[PADL_(const sigset_t *)]; const sigset_t * set; char set_r_[PADR_(const sigset_t *)]; }; +struct freebsd32_futimens_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char times_l_[PADL_(struct timespec *)]; struct timespec * times; char times_r_[PADR_(struct timespec *)]; +}; +struct freebsd32_utimensat_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char times_l_[PADL_(struct timespec *)]; struct timespec * times; char times_r_[PADR_(struct timespec *)]; + char flag_l_[PADL_(int)]; int flag; char flag_r_[PADR_(int)]; +}; #if !defined(PAD64_REQUIRED) && (defined(__powerpc__) || defined(__mips__)) #define PAD64_REQUIRED #endif @@ -825,6 +835,8 @@ int freebsd32_procctl(struct thread *, struct freebsd32_procctl_args *); int freebsd32_procctl(struct thread *, struct freebsd32_procctl_args *); #endif int freebsd32_ppoll(struct thread *, struct freebsd32_ppoll_args *); +int freebsd32_futimens(struct thread *, struct freebsd32_futimens_args *); +int freebsd32_utimensat(struct thread *, struct freebsd32_utimensat_args *); #ifdef COMPAT_43 @@ -1240,6 +1252,8 @@ int freebsd7_freebsd32_shmctl(struct thread *, struct freebsd7_freebsd32_shmctl_ #define FREEBSD32_SYS_AUE_freebsd32_procctl AUE_NULL #define FREEBSD32_SYS_AUE_freebsd32_procctl AUE_NULL #define FREEBSD32_SYS_AUE_freebsd32_ppoll AUE_POLL +#define FREEBSD32_SYS_AUE_freebsd32_futimens AUE_FUTIMES +#define FREEBSD32_SYS_AUE_freebsd32_utimensat AUE_FUTIMESAT #undef PAD_ #undef PADL_ diff --git a/sys/compat/freebsd32/freebsd32_syscall.h b/sys/compat/freebsd32/freebsd32_syscall.h index 370c0706fee8..5e5bb0ad6ed7 100644 --- a/sys/compat/freebsd32/freebsd32_syscall.h +++ b/sys/compat/freebsd32/freebsd32_syscall.h @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 276654 2015-01-04 10:34:02Z dchagin + * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 277610 2015-01-23 21:07:08Z jilles */ #define FREEBSD32_SYS_syscall 0 @@ -453,4 +453,6 @@ #define FREEBSD32_SYS_freebsd32_procctl 544 #define FREEBSD32_SYS_freebsd32_procctl 544 #define FREEBSD32_SYS_freebsd32_ppoll 545 -#define FREEBSD32_SYS_MAXSYSCALL 546 +#define FREEBSD32_SYS_freebsd32_futimens 546 +#define FREEBSD32_SYS_freebsd32_utimensat 547 +#define FREEBSD32_SYS_MAXSYSCALL 548 diff --git a/sys/compat/freebsd32/freebsd32_syscalls.c b/sys/compat/freebsd32/freebsd32_syscalls.c index 9cad2f135f2c..143ed72107e6 100644 --- a/sys/compat/freebsd32/freebsd32_syscalls.c +++ b/sys/compat/freebsd32/freebsd32_syscalls.c @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 276654 2015-01-04 10:34:02Z dchagin + * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 277610 2015-01-23 21:07:08Z jilles */ const char *freebsd32_syscallnames[] = { @@ -579,4 +579,6 @@ const char *freebsd32_syscallnames[] = { "freebsd32_procctl", /* 544 = freebsd32_procctl */ #endif "freebsd32_ppoll", /* 545 = freebsd32_ppoll */ + "freebsd32_futimens", /* 546 = freebsd32_futimens */ + "freebsd32_utimensat", /* 547 = freebsd32_utimensat */ }; diff --git a/sys/compat/freebsd32/freebsd32_sysent.c b/sys/compat/freebsd32/freebsd32_sysent.c index 195ee940010a..6d2a7d48bd3a 100644 --- a/sys/compat/freebsd32/freebsd32_sysent.c +++ b/sys/compat/freebsd32/freebsd32_sysent.c @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 276654 2015-01-04 10:34:02Z dchagin + * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 277610 2015-01-23 21:07:08Z jilles */ #include "opt_compat.h" @@ -616,4 +616,6 @@ struct sysent freebsd32_sysent[] = { { AS(freebsd32_procctl_args), (sy_call_t *)freebsd32_procctl, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 544 = freebsd32_procctl */ #endif { AS(freebsd32_ppoll_args), (sy_call_t *)freebsd32_ppoll, AUE_POLL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 545 = freebsd32_ppoll */ + { AS(freebsd32_futimens_args), (sy_call_t *)freebsd32_futimens, AUE_FUTIMES, NULL, 0, 0, 0, SY_THR_STATIC }, /* 546 = freebsd32_futimens */ + { AS(freebsd32_utimensat_args), (sy_call_t *)freebsd32_utimensat, AUE_FUTIMESAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 547 = freebsd32_utimensat */ }; diff --git a/sys/compat/freebsd32/freebsd32_systrace_args.c b/sys/compat/freebsd32/freebsd32_systrace_args.c index 6f6b0ac97c13..a2668aa7cb05 100644 --- a/sys/compat/freebsd32/freebsd32_systrace_args.c +++ b/sys/compat/freebsd32/freebsd32_systrace_args.c @@ -3309,6 +3309,24 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) *n_args = 4; break; } + /* freebsd32_futimens */ + case 546: { + struct freebsd32_futimens_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->times; /* struct timespec * */ + *n_args = 2; + break; + } + /* freebsd32_utimensat */ + case 547: { + struct freebsd32_utimensat_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->path; /* char * */ + uarg[2] = (intptr_t) p->times; /* struct timespec * */ + iarg[3] = p->flag; /* int */ + *n_args = 4; + break; + } default: *n_args = 0; break; @@ -8873,6 +8891,38 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; + /* freebsd32_futimens */ + case 546: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "struct timespec *"; + break; + default: + break; + }; + break; + /* freebsd32_utimensat */ + case 547: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "char *"; + break; + case 2: + p = "struct timespec *"; + break; + case 3: + p = "int"; + break; + default: + break; + }; + break; default: break; }; @@ -10751,6 +10801,16 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) if (ndx == 0 || ndx == 1) p = "int"; break; + /* freebsd32_futimens */ + case 546: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* freebsd32_utimensat */ + case 547: + if (ndx == 0 || ndx == 1) + p = "int"; + break; default: break; }; diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c index 9d044784863b..8aefa3f7be13 100644 --- a/sys/kern/init_sysent.c +++ b/sys/kern/init_sysent.c @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/kern/syscalls.master 276654 2015-01-04 10:34:02Z dchagin + * created from FreeBSD: head/sys/kern/syscalls.master 277610 2015-01-23 21:07:08Z jilles */ #include "opt_compat.h" @@ -580,4 +580,6 @@ struct sysent sysent[] = { { AS(aio_mlock_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 543 = aio_mlock */ { AS(procctl_args), (sy_call_t *)sys_procctl, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 544 = procctl */ { AS(ppoll_args), (sy_call_t *)sys_ppoll, AUE_POLL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 545 = ppoll */ + { AS(futimens_args), (sy_call_t *)sys_futimens, AUE_FUTIMES, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 546 = futimens */ + { AS(utimensat_args), (sy_call_t *)sys_utimensat, AUE_FUTIMESAT, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 547 = utimensat */ }; diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c index 41f5cce8f1bd..e99ae94a2e50 100644 --- a/sys/kern/syscalls.c +++ b/sys/kern/syscalls.c @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/kern/syscalls.master 276654 2015-01-04 10:34:02Z dchagin + * created from FreeBSD: head/sys/kern/syscalls.master 277610 2015-01-23 21:07:08Z jilles */ const char *syscallnames[] = { @@ -553,4 +553,6 @@ const char *syscallnames[] = { "aio_mlock", /* 543 = aio_mlock */ "procctl", /* 544 = procctl */ "ppoll", /* 545 = ppoll */ + "futimens", /* 546 = futimens */ + "utimensat", /* 547 = utimensat */ }; diff --git a/sys/kern/systrace_args.c b/sys/kern/systrace_args.c index d5c368df4d4f..c5d3b85fcd15 100644 --- a/sys/kern/systrace_args.c +++ b/sys/kern/systrace_args.c @@ -3382,6 +3382,24 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) *n_args = 4; break; } + /* futimens */ + case 546: { + struct futimens_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->times; /* struct timespec * */ + *n_args = 2; + break; + } + /* utimensat */ + case 547: { + struct utimensat_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->path; /* char * */ + uarg[2] = (intptr_t) p->times; /* struct timespec * */ + iarg[3] = p->flag; /* int */ + *n_args = 4; + break; + } default: *n_args = 0; break; @@ -9019,6 +9037,38 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; + /* futimens */ + case 546: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "struct timespec *"; + break; + default: + break; + }; + break; + /* utimensat */ + case 547: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "char *"; + break; + case 2: + p = "struct timespec *"; + break; + case 3: + p = "int"; + break; + default: + break; + }; + break; default: break; }; @@ -10962,6 +11012,16 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) if (ndx == 0 || ndx == 1) p = "int"; break; + /* futimens */ + case 546: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* utimensat */ + case 547: + if (ndx == 0 || ndx == 1) + p = "int"; + break; default: break; }; diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h index 42e52909fb52..54a450ff8c84 100644 --- a/sys/sys/syscall.h +++ b/sys/sys/syscall.h @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/kern/syscalls.master 276654 2015-01-04 10:34:02Z dchagin + * created from FreeBSD: head/sys/kern/syscalls.master 277610 2015-01-23 21:07:08Z jilles */ #define SYS_syscall 0 @@ -463,4 +463,6 @@ #define SYS_aio_mlock 543 #define SYS_procctl 544 #define SYS_ppoll 545 -#define SYS_MAXSYSCALL 546 +#define SYS_futimens 546 +#define SYS_utimensat 547 +#define SYS_MAXSYSCALL 548 diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk index 294a1140b927..4e8e891c0d57 100644 --- a/sys/sys/syscall.mk +++ b/sys/sys/syscall.mk @@ -1,7 +1,7 @@ # FreeBSD system call names. # DO NOT EDIT-- this file is automatically generated. # $FreeBSD$ -# created from FreeBSD: head/sys/kern/syscalls.master 276654 2015-01-04 10:34:02Z dchagin +# created from FreeBSD: head/sys/kern/syscalls.master 277610 2015-01-23 21:07:08Z jilles MIASM = \ syscall.o \ exit.o \ @@ -410,4 +410,6 @@ MIASM = \ pipe2.o \ aio_mlock.o \ procctl.o \ - ppoll.o + ppoll.o \ + futimens.o \ + utimensat.o diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h index ecaaa593cdf1..71dc979fd913 100644 --- a/sys/sys/sysproto.h +++ b/sys/sys/sysproto.h @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/kern/syscalls.master 276654 2015-01-04 10:34:02Z dchagin + * created from FreeBSD: head/sys/kern/syscalls.master 277610 2015-01-23 21:07:08Z jilles */ #ifndef _SYS_SYSPROTO_H_ @@ -1819,6 +1819,16 @@ struct ppoll_args { char ts_l_[PADL_(const struct timespec *)]; const struct timespec * ts; char ts_r_[PADR_(const struct timespec *)]; char set_l_[PADL_(const sigset_t *)]; const sigset_t * set; char set_r_[PADR_(const sigset_t *)]; }; +struct futimens_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char times_l_[PADL_(struct timespec *)]; struct timespec * times; char times_r_[PADR_(struct timespec *)]; +}; +struct utimensat_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char times_l_[PADL_(struct timespec *)]; struct timespec * times; char times_r_[PADR_(struct timespec *)]; + char flag_l_[PADL_(int)]; int flag; char flag_r_[PADR_(int)]; +}; int nosys(struct thread *, struct nosys_args *); void sys_sys_exit(struct thread *, struct sys_exit_args *); int sys_fork(struct thread *, struct fork_args *); @@ -2211,6 +2221,8 @@ int sys_pipe2(struct thread *, struct pipe2_args *); int sys_aio_mlock(struct thread *, struct aio_mlock_args *); int sys_procctl(struct thread *, struct procctl_args *); int sys_ppoll(struct thread *, struct ppoll_args *); +int sys_futimens(struct thread *, struct futimens_args *); +int sys_utimensat(struct thread *, struct utimensat_args *); #ifdef COMPAT_43 @@ -2917,6 +2929,8 @@ int freebsd7_shmctl(struct thread *, struct freebsd7_shmctl_args *); #define SYS_AUE_aio_mlock AUE_NULL #define SYS_AUE_procctl AUE_NULL #define SYS_AUE_ppoll AUE_POLL +#define SYS_AUE_futimens AUE_FUTIMES +#define SYS_AUE_utimensat AUE_FUTIMESAT #undef PAD_ #undef PADL_ From 8b186299aaa81eb7e86f5856a6ba143d37ef3fdd Mon Sep 17 00:00:00 2001 From: emaste Date: Fri, 23 Jan 2015 21:34:08 +0000 Subject: [PATCH 202/258] Restore addr2line to cross tools Addr2line is not required for the build, and a per-arch binary is no longer required with the switch to the ELF Tool Chain. However, building these tools during the cross tools stage can be useful for developers who cross build HEAD from stable/10, and adds very little to the build time. Reviewed by: ian, imp Differential Revision: https://reviews.freebsd.org/D1583 --- Makefile.inc1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile.inc1 b/Makefile.inc1 index afa49408e688..0d0aea476918 100644 --- a/Makefile.inc1 +++ b/Makefile.inc1 @@ -1437,6 +1437,9 @@ _elftctools= lib/libelftc \ 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 .endif From 481a456c5d4130dd0e11b6d65b65746c41aba684 Mon Sep 17 00:00:00 2001 From: will Date: Fri, 23 Jan 2015 23:53:56 +0000 Subject: [PATCH 203/258] Fix panic in firewire and creation of invalid config ROM. (This change was supposed to be included in r277508.) sys/boot/i386/libfirewire/firewire.c: Fix configuration ROM generation count wrapping logic so that the generation count is never outside of allowed limits (0x2 -> 0xF). Submitted by: gibbs MFC after: 1 week MFC with: 277508 Sponsored by: Spectra Logic MFSpectraBSD: 1110685 on 2015/01/05 --- sys/boot/i386/libfirewire/firewire.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/sys/boot/i386/libfirewire/firewire.c b/sys/boot/i386/libfirewire/firewire.c index 5edb67a4ecbe..8191a63d8b3d 100644 --- a/sys/boot/i386/libfirewire/firewire.c +++ b/sys/boot/i386/libfirewire/firewire.c @@ -233,7 +233,8 @@ fw_init_crom(struct fwohci_softc *sc) src->businfo.cyc_clk_acc = 100; src->businfo.max_rec = sc->maxrec; src->businfo.max_rom = MAXROM_4; - src->businfo.generation = 1; +#define FW_GENERATION_CHANGEABLE 2 + src->businfo.generation = FW_GENERATION_CHANGEABLE; src->businfo.link_spd = sc->speed; src->businfo.eui64.hi = sc->eui.hi; @@ -313,11 +314,14 @@ fw_crom(struct fwohci_softc *sc) src = &sc->crom_src_buf->src; crom_load(src, (uint32_t *)newrom, CROMSIZE); if (bcmp(newrom, sc->config_rom, CROMSIZE) != 0) { - /* bump generation and reload */ - src->businfo.generation ++; - /* generation must be between 0x2 and 0xF */ + /* Bump generation and reload. */ + src->businfo.generation++; + + /* Handle generation count wraps. */ if (src->businfo.generation < 2) - src->businfo.generation ++; + src->businfo.generation = 2; + + /* Recalculate CRC to account for generation change. */ crom_load(src, (uint32_t *)newrom, CROMSIZE); bcopy(newrom, (void *)sc->config_rom, CROMSIZE); } From 86478b20811b9f42a97c27fc684ba3101706721f Mon Sep 17 00:00:00 2001 From: will Date: Sat, 24 Jan 2015 00:04:34 +0000 Subject: [PATCH 204/258] Bump config(8) minor version for r277567. Config files built using this version that take advantage of the bugfix won't be buildable using older config(8). Submitted by: imp MFC after: 1 week MFC with: 277567 --- usr.sbin/config/configvers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr.sbin/config/configvers.h b/usr.sbin/config/configvers.h index 56ca85cd692a..5c2937311d70 100644 --- a/usr.sbin/config/configvers.h +++ b/usr.sbin/config/configvers.h @@ -49,5 +49,5 @@ * * $FreeBSD$ */ -#define CONFIGVERS 600013 +#define CONFIGVERS 600014 #define MAJOR_VERS(x) ((x) / 100000) From 5c373339e4fc1df859c4f8d45b13f1e868342aaf Mon Sep 17 00:00:00 2001 From: neel Date: Sat, 24 Jan 2015 00:35:49 +0000 Subject: [PATCH 205/258] Add macro to identify AVIC capability (advanced virtual interrupt controller) in AMD processors. Submitted by: Dmitry Luhtionov (dmitryluhtionov@gmail.com) --- sys/amd64/vmm/amd/svm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/amd64/vmm/amd/svm.c b/sys/amd64/vmm/amd/svm.c index 31164d7c58da..bcd9efc4b200 100644 --- a/sys/amd64/vmm/amd/svm.c +++ b/sys/amd64/vmm/amd/svm.c @@ -80,6 +80,7 @@ SYSCTL_NODE(_hw_vmm, OID_AUTO, svm, CTLFLAG_RW, NULL, NULL); #define AMD_CPUID_SVM_DECODE_ASSIST BIT(7) /* Decode assist */ #define AMD_CPUID_SVM_PAUSE_INC BIT(10) /* Pause intercept filter. */ #define AMD_CPUID_SVM_PAUSE_FTH BIT(12) /* Pause filter threshold */ +#define AMD_CPUID_SVM_AVIC BIT(13) /* AVIC present */ #define VMCB_CACHE_DEFAULT (VMCB_CACHE_ASID | \ VMCB_CACHE_IOPM | \ From 982d209a3d06d4da6d31dd3700839bbfeda9bc88 Mon Sep 17 00:00:00 2001 From: will Date: Sat, 24 Jan 2015 00:37:41 +0000 Subject: [PATCH 206/258] Add routing_test:static_ipv6_loopback_route_for_each_fib. It tests that all FIBs get a static IPv6 loopback route. Submitted by: asomers MFC after: 1 week Sponsored by: Spectra Logic MFSpectraBSD: 1048456 on 2014/03/13 1114523 on 2015/01/23 --- etc/tests/Makefile | 2 + etc/tests/rc.d/Makefile | 7 ++ etc/tests/rc.d/routing_test.sh | 138 +++++++++++++++++++++++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 etc/tests/rc.d/Makefile create mode 100755 etc/tests/rc.d/routing_test.sh diff --git a/etc/tests/Makefile b/etc/tests/Makefile index 5aacd5b19e57..fd9efdaa566c 100644 --- a/etc/tests/Makefile +++ b/etc/tests/Makefile @@ -7,4 +7,6 @@ TESTSDIR= ${TESTSBASE}/etc .PATH: ${.CURDIR:H:H}/tests KYUAFILE= yes +TESTS_SUBDIRS+= rc.d + .include diff --git a/etc/tests/rc.d/Makefile b/etc/tests/rc.d/Makefile new file mode 100644 index 000000000000..368e8f4fc875 --- /dev/null +++ b/etc/tests/rc.d/Makefile @@ -0,0 +1,7 @@ +# $FreeBSD$ + +TESTSDIR= ${TESTSBASE}/etc/rc.d + +ATF_TESTS_SH+= routing_test + +.include diff --git a/etc/tests/rc.d/routing_test.sh b/etc/tests/rc.d/routing_test.sh new file mode 100755 index 000000000000..693af232ea39 --- /dev/null +++ b/etc/tests/rc.d/routing_test.sh @@ -0,0 +1,138 @@ +# +# Copyright (c) 2014 Spectra Logic 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, +# without modification. +# 2. Redistributions in binary form must reproduce at minimum a disclaimer +# substantially similar to the "NO WARRANTY" disclaimer below +# ("Disclaimer") and any redistribution must be conditioned upon +# including a substantially similar Disclaimer requirement for further +# binary redistribution. +# +# NO WARRANTY +# 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 MERCHANTIBILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. +# +# Authors: Alan Somers (Spectra Logic Corporation) +# +# $FreeBSD$ + +atf_test_case static_ipv6_loopback_route_for_each_fib cleanup +static_ipv6_loopback_route_for_each_fib_head() +{ + atf_set "descr" "Every FIB should have a static IPv6 loopback route" + atf_set "require.user" "root" + atf_set "require.config" "fibs" + atf_set "require.progs" "sysrc" +} +static_ipv6_loopback_route_for_each_fib_body() +{ + # Configure the TAP interface to use an RFC5737 nonrouteable address + # and a non-default fib + ADDR="192.0.2.2" + SUBNET="192.0.2.0" + MASK="24" + + # Check system configuration + if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then + atf_skip "This test requires net.add_addr_allfibs=0" + fi + + get_fibs 1 + get_tap + + # Configure a TAP interface in /etc/rc.conf. Register the sysrc + # variable for cleanup. + echo "ifconfig_${TAP}" >> "sysrc_vars_to_cleanup" + sysrc ifconfig_${TAP}="${ADDR}/${MASK} fib ${FIB0}" + + # Start the interface + service netif start ${TAP} + # Check for an IPv6 loopback route + setfib ${FIB0} netstat -rn -f inet6 | grep -q "^::1.*lo0$" + if [ 0 -eq $? ]; then + atf_pass + else + setfib ${FIB0} netstat -rn -f inet6 + atf_fail "Did not find an IPv6 loopback route" + fi +} +static_ipv6_loopback_route_for_each_fib_cleanup() +{ + cleanup_sysrc + cleanup_tap +} + +atf_init_test_cases() +{ + atf_add_test_case static_ipv6_loopback_route_for_each_fib +} + +# Looks up one or more fibs from the configuration data and validates them. +# Returns the results in the env varilables FIB0, FIB1, etc. +# parameter numfibs The number of fibs to lookup +get_fibs() +{ + NUMFIBS=$1 + net_fibs=`sysctl -n net.fibs` + i=0 + while [ $i -lt "$NUMFIBS" ]; do + fib=`atf_config_get "fibs" | \ + awk -v i=$(( i + 1 )) '{print $i}'` + echo "fib is ${fib}" + eval FIB${i}=${fib} + if [ "$fib" -ge "$net_fibs" ]; then + msg="The ${i}th configured fib is ${fub}, which is " + msg="$msg not less than net.fibs (${net_fibs})" + atf_skip "$msg" + fi + i=$(( $i + 1 )) + done +} + + +# Creates a new tap(4) interface, registers it for cleanup, and returns the +# name via the environment variable TAP +get_tap() +{ + local TAPN=0 + while ! ifconfig tap${TAPN} create > /dev/null 2>&1; do + if [ "$TAPN" -ge 8 ]; then + atf_skip "Could not create a tap(4) interface" + else + TAPN=$(($TAPN + 1)) + fi + done + local TAPD=tap${TAPN} + # Record the TAP device so we can clean it up later + echo ${TAPD} >> "tap_devices_to_cleanup" + TAP=${TAPD} +} + +cleanup_sysrc() +{ + for var in `cat "sysrc_vars_to_cleanup"`; do + sysrc -x $var + done +} + +cleanup_tap() +{ + for TAPD in `cat "tap_devices_to_cleanup"`; do + ifconfig ${TAPD} destroy + done +} From 9f59ab68684dd8db650ca8276f9f3b44cc61b03d Mon Sep 17 00:00:00 2001 From: will Date: Sat, 24 Jan 2015 00:43:02 +0000 Subject: [PATCH 207/258] When creating or updating a node, use vfs_timestamp() for "now" instead of gethrestime(), to allow the administrator to decide the appropriate timestamp precision instead of always using nanosecond precision. --- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c index 44b782096b20..d92571293325 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c @@ -794,7 +794,7 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr, gen = vap->va_nblocks; /* ditto */ } else { obj = 0; - gethrestime(&now); + vfs_timestamp(&now); gen = dmu_tx_get_txg(tx); } @@ -1426,7 +1426,7 @@ zfs_tstamp_update_setup(znode_t *zp, uint_t flag, uint64_t mtime[2], { timestruc_t now; - gethrestime(&now); + vfs_timestamp(&now); if (have_tx) { /* will sa_bulk_update happen really soon? */ zp->z_atime_dirty = 0; From f4af1114dc88153fb314dabfebf6e41434b30998 Mon Sep 17 00:00:00 2001 From: gonzo Date: Sat, 24 Jan 2015 01:53:28 +0000 Subject: [PATCH 208/258] After interrupt read value from register to make sure it reached hardware. This should fix "Spurious inteerupt" message Suggested by ian@ --- sys/arm/ti/am335x/am335x_lcd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sys/arm/ti/am335x/am335x_lcd.c b/sys/arm/ti/am335x/am335x_lcd.c index ada08011b64c..4fd811cc2eac 100644 --- a/sys/arm/ti/am335x/am335x_lcd.c +++ b/sys/arm/ti/am335x/am335x_lcd.c @@ -356,6 +356,8 @@ am335x_lcd_intr(void *arg) reg = LCD_READ4(sc, LCD_IRQSTATUS); LCD_WRITE4(sc, LCD_IRQSTATUS, reg); + /* Read value back to make sure it reached the hardware */ + reg = LCD_READ4(sc, LCD_IRQSTATUS); if (reg & IRQ_SYNC_LOST) { reg = LCD_READ4(sc, LCD_RASTER_CTRL); @@ -401,6 +403,8 @@ am335x_lcd_intr(void *arg) done: LCD_WRITE4(sc, LCD_END_OF_INT_IND, 0); + /* Read value back to make sure it reached the hardware */ + reg = LCD_READ4(sc, LCD_END_OF_INT_IND); } static int From ee74081aba2c04cf9764b8c9eea5e71d616ef217 Mon Sep 17 00:00:00 2001 From: nwhitehorn Date: Sat, 24 Jan 2015 01:58:15 +0000 Subject: [PATCH 209/258] Fix typo in r277561. --- sys/powerpc/aim/machdep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c index a6d254b3f145..020c07ab48f1 100644 --- a/sys/powerpc/aim/machdep.c +++ b/sys/powerpc/aim/machdep.c @@ -535,7 +535,7 @@ powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp) #endif bcopy(&alitrap, (void *)(EXC_ALI + trap_offset), (size_t)&aliend - (size_t)&alitrap); - bcopy(&dsitrap, (void *)(EXC_DSI + trap_offset), (size_t)&dsitrap - + bcopy(&dsitrap, (void *)(EXC_DSI + trap_offset), (size_t)&dsiend - (size_t)&dsitrap); bcopy(generictrap, (void *)EXC_ISI, trapsize); #ifdef __powerpc64__ From 4c57d385c3520b32632df1eb34a82a6595c5ded2 Mon Sep 17 00:00:00 2001 From: np Date: Sat, 24 Jan 2015 04:41:14 +0000 Subject: [PATCH 210/258] Make sure the compiler flag to get cxgbe(4) to compile with gcc is used only when gcc is being used. This is what r277225 should have been. Suggested by: dim@ --- sys/conf/files | 2 +- sys/modules/cxgbe/if_cxgbe/Makefile | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/sys/conf/files b/sys/conf/files index 5895cce88ab7..ee8a5381be9c 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1141,7 +1141,7 @@ dev/cxgb/sys/uipc_mvec.c optional cxgb pci \ dev/cxgb/cxgb_t3fw.c optional cxgb cxgb_t3fw \ compile-with "${NORMAL_C} -I$S/dev/cxgb" dev/cxgbe/t4_mp_ring.c optional cxgbe pci \ - compile-with "${NORMAL_C} -I$S/dev/cxgbe -fms-extensions" + compile-with "${NORMAL_C} -I$S/dev/cxgbe ${GCC_MS_EXTENSIONS}" dev/cxgbe/t4_main.c optional cxgbe pci \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/t4_netmap.c optional cxgbe pci \ diff --git a/sys/modules/cxgbe/if_cxgbe/Makefile b/sys/modules/cxgbe/if_cxgbe/Makefile index 9c0c857a8e98..32347f468b1e 100644 --- a/sys/modules/cxgbe/if_cxgbe/Makefile +++ b/sys/modules/cxgbe/if_cxgbe/Makefile @@ -23,6 +23,7 @@ SRCS+= t4_tracer.c # Provide the timestamp of a packet in its header mbuf. #CFLAGS+= -DT4_PKT_TIMESTAMP -CFLAGS+= -I${CXGBE} -fms-extensions +CFLAGS+= -I${CXGBE} .include +CFLAGS+= ${GCC_MS_EXTENSIONS} From ca1fdb3c2cf128e07da63ee4336b805f60be6ee4 Mon Sep 17 00:00:00 2001 From: delphij Date: Sat, 24 Jan 2015 06:06:46 +0000 Subject: [PATCH 211/258] Don't include libcapsicum headers when requested. Reported by: luigi MFC after: 14 days X-MFC-with: r276788 --- contrib/tcpdump/tcpdump.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/tcpdump/tcpdump.c b/contrib/tcpdump/tcpdump.c index 9c9609b93257..b1630818f615 100644 --- a/contrib/tcpdump/tcpdump.c +++ b/contrib/tcpdump/tcpdump.c @@ -77,12 +77,12 @@ extern int SIZE_BUF; #ifdef __FreeBSD__ #include #include +#endif /* __FreeBSD__ */ +#ifdef HAVE_CAPSICUM #include #include #include #include -#endif /* __FreeBSD__ */ -#ifdef HAVE_CAPSICUM #include #include #include @@ -966,8 +966,8 @@ main(int argc, char **argv) FILE *VFile; #ifdef HAVE_CAPSICUM cap_rights_t rights; - int cansandbox; #endif /* HAVE_CAPSICUM */ + int cansandbox; #ifdef WIN32 if(wsockinit() != 0) return 1; From 70c9059ac63a17a0170e0407668bfd907bedf638 Mon Sep 17 00:00:00 2001 From: luigi Date: Sat, 24 Jan 2015 08:48:05 +0000 Subject: [PATCH 212/258] do not strip /stand This is a temporary workaround until the elftoolchain's version of strip is fixed: The previous (GNU) strip, when acting on a file with multiple links, would modify the one and only file in place (which means creating a new stripped copy, and then writing it back to the original). The new version from elftoolchain creates the new file and then unlinks the old one and renames the new. With multiple hard links, the original remains alive. In the /stand directory, this ends up creating 80+ copies of the same file. --- release/picobsd/build/picobsd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/release/picobsd/build/picobsd b/release/picobsd/build/picobsd index 19a983949277..728e9f4e3d68 100755 --- a/release/picobsd/build/picobsd +++ b/release/picobsd/build/picobsd @@ -734,8 +734,8 @@ populate_mfs_tree() { [ -n "${copy_files}" ] && do_copyfiles ${dst} copy_files do_copyfiles_user ${dst} || true [ -n "${links}" ] && do_links ${dst} links - strip ${dst}/libexec/* ${dst}/lib/* ${dst}/stand/* 2> /dev/null || true - + strip ${dst}/libexec/* ${dst}/lib/* 2> /dev/null || true + # strip ${dst}/stand/* 2> /dev/null || true # The 'import_files' mechanism is deprecated, as it requires # root permissions to follow the symlinks, and also does # not let you rename the entries. @@ -756,7 +756,7 @@ populate_mfs_tree() { # override the owner echo "/set uid=0 gid=0" > mtree.out mtree -ic -p ${dst} -k "" >> mtree.out - log "mtre.out at ${BUILDDIR}/mtree.out" + log "mtree.out at ${BUILDDIR}/mtree.out size ${MFS_SIZE}k" makefs -t ffs -o bsize=4096 -o fsize=512 \ -s ${MFS_SIZE}k -f 1000 -F mtree.out ${c_fs} ${dst} ls -l ${c_fs} ) From f3fd716384efab41262353c6ad81586b9c202822 Mon Sep 17 00:00:00 2001 From: kib Date: Sat, 24 Jan 2015 12:43:36 +0000 Subject: [PATCH 213/258] Provide individual prototype and generate macros for the red-black tree. This helps to reduce code size in statically linked applications. Submitted by: Sebastian Huber MFC after: 2 weeks --- share/man/man3/tree.3 | 71 ++++++++++++++++++++++++++++++++++- sys/sys/tree.h | 86 ++++++++++++++++++++++++++++++------------- 2 files changed, 131 insertions(+), 26 deletions(-) diff --git a/share/man/man3/tree.3 b/share/man/man3/tree.3 index 2e9c63cf751e..ea70506ea025 100644 --- a/share/man/man3/tree.3 +++ b/share/man/man3/tree.3 @@ -30,7 +30,7 @@ .\" .\" $FreeBSD$ .\" -.Dd November 10, 2013 +.Dd January 24, 2015 .Dt TREE 3 .Os .Sh NAME @@ -53,8 +53,26 @@ .Nm SPLAY_REMOVE , .Nm RB_PROTOTYPE , .Nm RB_PROTOTYPE_STATIC , +.Nm RB_PROTOTYPE_INSERT , +.Nm RB_PROTOTYPE_INSERT_COLOR , +.Nm RB_PROTOTYPE_REMOVE , +.Nm RB_PROTOTYPE_REMOVE_COLOR , +.Nm RB_PROTOTYPE_FIND , +.Nm RB_PROTOTYPE_NFIND , +.Nm RB_PROTOTYPE_NEXT , +.Nm RB_PROTOTYPE_PREV , +.Nm RB_PROTOTYPE_MINMAX , .Nm RB_GENERATE , .Nm RB_GENERATE_STATIC , +.Nm RB_GENERATE_INSERT , +.Nm RB_GENERATE_INSERT_COLOR , +.Nm RB_GENERATE_REMOVE , +.Nm RB_GENERATE_REMOVE_COLOR , +.Nm RB_GENERATE_FIND , +.Nm RB_GENERATE_NFIND , +.Nm RB_GENERATE_NEXT , +.Nm RB_GENERATE_PREV , +.Nm RB_GENERATE_MINMAX , .Nm RB_ENTRY , .Nm RB_HEAD , .Nm RB_INITIALIZER , @@ -111,8 +129,26 @@ .Fn SPLAY_REMOVE NAME "SPLAY_HEAD *head" "struct TYPE *elm" .Fn RB_PROTOTYPE NAME TYPE FIELD CMP .Fn RB_PROTOTYPE_STATIC NAME TYPE FIELD CMP +.Fn RB_PROTOTYPE_INSERT NAME TYPE ATTR +.Fn RB_PROTOTYPE_INSERT_COLOR NAME TYPE ATTR +.Fn RB_PROTOTYPE_REMOVE NAME TYPE ATTR +.Fn RB_PROTOTYPE_REMOVE_COLOR NAME TYPE ATTR +.Fn RB_PROTOTYPE_FIND NAME TYPE ATTR +.Fn RB_PROTOTYPE_NFIND NAME TYPE ATTR +.Fn RB_PROTOTYPE_NEXT NAME TYPE ATTR +.Fn RB_PROTOTYPE_PREV NAME TYPE ATTR +.Fn RB_PROTOTYPE_MINMAX NAME TYPE ATTR .Fn RB_GENERATE NAME TYPE FIELD CMP .Fn RB_GENERATE_STATIC NAME TYPE FIELD CMP +.Fn RB_GENERATE_INSERT NAME TYPE FIELD CMP ATTR +.Fn RB_GENERATE_INSERT_COLOR NAME TYPE FIELD ATTR +.Fn RB_GENERATE_REMOVE NAME TYPE FIELD ATTR +.Fn RB_GENERATE_REMOVE_COLOR NAME TYPE FIELD ATTR +.Fn RB_GENERATE_FIND NAME TYPE FIELD CMP ATTR +.Fn RB_GENERATE_NFIND NAME TYPE FIELD CMP ATTR +.Fn RB_GENERATE_NEXT NAME TYPE FIELD ATTR +.Fn RB_GENERATE_PREV NAME TYPE FIELD ATTR +.Fn RB_GENERATE_MINMAX NAME TYPE FIELD ATTR .Fn RB_ENTRY TYPE .Fn RB_HEAD HEADNAME TYPE .Fn RB_INITIALIZER "RB_HEAD *head" @@ -377,6 +413,27 @@ The .Fa FIELD argument is the name of the element defined by .Fn RB_ENTRY . +Individual prototypes can be declared with +.Fn RB_PROTOTYPE_INSERT , +.Fn RB_PROTOTYPE_INSERT_COLOR , +.Fn RB_PROTOTYPE_REMOVE , +.Fn RB_PROTOTYPE_REMOVE_COLOR , +.Fn RB_PROTOTYPE_FIND , +.Fn RB_PROTOTYPE_NFIND , +.Fn RB_PROTOTYPE_NEXT , +.Fn RB_PROTOTYPE_PREV , +and +.Fn RB_PROTOTYPE_MINMAX +in case not all functions are required. The individual prototype macros expect +.Fa NAME , +.Fa TYPE , +and +.Fa ATTR +arguments. The +.Fa ATTR +argument must be empty for global functions or +.Fa static +for static functions. .Pp The function bodies are generated with the .Fn RB_GENERATE @@ -388,6 +445,18 @@ These macros take the same arguments as the and .Fn RB_PROTOTYPE_STATIC macros, but should be used only once. +As an alternative individual function bodies are generated with the +.Fn RB_GENERATE_INSERT , +.Fn RB_GENERATE_INSERT_COLOR , +.Fn RB_GENERATE_REMOVE , +.Fn RB_GENERATE_REMOVE_COLOR , +.Fn RB_GENERATE_FIND , +.Fn RB_GENERATE_NFIND , +.Fn RB_GENERATE_NEXT , +.Fn RB_GENERATE_PREV , +and +.Fn RB_GENERATE_MINMAX +macros. .Pp Finally, the diff --git a/sys/sys/tree.h b/sys/sys/tree.h index 1cce727868ae..c9df686fbb13 100644 --- a/sys/sys/tree.h +++ b/sys/sys/tree.h @@ -383,16 +383,33 @@ struct { \ #define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static) #define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ -attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \ -attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ -attr struct type *name##_RB_REMOVE(struct name *, struct type *); \ -attr struct type *name##_RB_INSERT(struct name *, struct type *); \ -attr struct type *name##_RB_FIND(struct name *, struct type *); \ -attr struct type *name##_RB_NFIND(struct name *, struct type *); \ -attr struct type *name##_RB_NEXT(struct type *); \ -attr struct type *name##_RB_PREV(struct type *); \ -attr struct type *name##_RB_MINMAX(struct name *, int); \ - \ + RB_PROTOTYPE_INSERT_COLOR(name, type, attr); \ + RB_PROTOTYPE_REMOVE_COLOR(name, type, attr); \ + RB_PROTOTYPE_INSERT(name, type, attr); \ + RB_PROTOTYPE_REMOVE(name, type, attr); \ + RB_PROTOTYPE_FIND(name, type, attr); \ + RB_PROTOTYPE_NFIND(name, type, attr); \ + RB_PROTOTYPE_NEXT(name, type, attr); \ + RB_PROTOTYPE_PREV(name, type, attr); \ + RB_PROTOTYPE_MINMAX(name, type, attr); +#define RB_PROTOTYPE_INSERT_COLOR(name, type, attr) \ + attr void name##_RB_INSERT_COLOR(struct name *, struct type *) +#define RB_PROTOTYPE_REMOVE_COLOR(name, type, attr) \ + attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *) +#define RB_PROTOTYPE_REMOVE(name, type, attr) \ + attr struct type *name##_RB_REMOVE(struct name *, struct type *) +#define RB_PROTOTYPE_INSERT(name, type, attr) \ + attr struct type *name##_RB_INSERT(struct name *, struct type *) +#define RB_PROTOTYPE_FIND(name, type, attr) \ + attr struct type *name##_RB_FIND(struct name *, struct type *) +#define RB_PROTOTYPE_NFIND(name, type, attr) \ + attr struct type *name##_RB_NFIND(struct name *, struct type *) +#define RB_PROTOTYPE_NEXT(name, type, attr) \ + attr struct type *name##_RB_NEXT(struct type *) +#define RB_PROTOTYPE_PREV(name, type, attr) \ + attr struct type *name##_RB_PREV(struct type *) +#define RB_PROTOTYPE_MINMAX(name, type, attr) \ + attr struct type *name##_RB_MINMAX(struct name *, int) /* Main rb operation. * Moves node close to the key of elm to top @@ -402,6 +419,17 @@ attr struct type *name##_RB_MINMAX(struct name *, int); \ #define RB_GENERATE_STATIC(name, type, field, cmp) \ RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static) #define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ + RB_GENERATE_INSERT_COLOR(name, type, field, attr) \ + RB_GENERATE_REMOVE_COLOR(name, type, field, attr) \ + RB_GENERATE_INSERT(name, type, field, cmp, attr) \ + RB_GENERATE_REMOVE(name, type, field, attr) \ + RB_GENERATE_FIND(name, type, field, cmp, attr) \ + RB_GENERATE_NFIND(name, type, field, cmp, attr) \ + RB_GENERATE_NEXT(name, type, field, attr) \ + RB_GENERATE_PREV(name, type, field, attr) \ + RB_GENERATE_MINMAX(name, type, field, attr) + +#define RB_GENERATE_INSERT_COLOR(name, type, field, attr) \ attr void \ name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ { \ @@ -444,8 +472,9 @@ name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ } \ } \ RB_COLOR(head->rbh_root, field) = RB_BLACK; \ -} \ - \ +} + +#define RB_GENERATE_REMOVE_COLOR(name, type, field, attr) \ attr void \ name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ { \ @@ -522,8 +551,9 @@ name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) } \ if (elm) \ RB_COLOR(elm, field) = RB_BLACK; \ -} \ - \ +} + +#define RB_GENERATE_REMOVE(name, type, field, attr) \ attr struct type * \ name##_RB_REMOVE(struct name *head, struct type *elm) \ { \ @@ -590,7 +620,8 @@ color: \ name##_RB_REMOVE_COLOR(head, parent, child); \ return (old); \ } \ - \ + +#define RB_GENERATE_INSERT(name, type, field, cmp, attr) \ /* Inserts a node into the RB tree */ \ attr struct type * \ name##_RB_INSERT(struct name *head, struct type *elm) \ @@ -620,8 +651,9 @@ name##_RB_INSERT(struct name *head, struct type *elm) \ RB_ROOT(head) = elm; \ name##_RB_INSERT_COLOR(head, elm); \ return (NULL); \ -} \ - \ +} + +#define RB_GENERATE_FIND(name, type, field, cmp, attr) \ /* Finds the node with the same key as elm */ \ attr struct type * \ name##_RB_FIND(struct name *head, struct type *elm) \ @@ -638,8 +670,9 @@ name##_RB_FIND(struct name *head, struct type *elm) \ return (tmp); \ } \ return (NULL); \ -} \ - \ +} + +#define RB_GENERATE_NFIND(name, type, field, cmp, attr) \ /* Finds the first node greater than or equal to the search key */ \ attr struct type * \ name##_RB_NFIND(struct name *head, struct type *elm) \ @@ -659,8 +692,9 @@ name##_RB_NFIND(struct name *head, struct type *elm) \ return (tmp); \ } \ return (res); \ -} \ - \ +} + +#define RB_GENERATE_NEXT(name, type, field, attr) \ /* ARGSUSED */ \ attr struct type * \ name##_RB_NEXT(struct type *elm) \ @@ -681,8 +715,9 @@ name##_RB_NEXT(struct type *elm) \ } \ } \ return (elm); \ -} \ - \ +} + +#define RB_GENERATE_PREV(name, type, field, attr) \ /* ARGSUSED */ \ attr struct type * \ name##_RB_PREV(struct type *elm) \ @@ -703,8 +738,9 @@ name##_RB_PREV(struct type *elm) \ } \ } \ return (elm); \ -} \ - \ +} + +#define RB_GENERATE_MINMAX(name, type, field, attr) \ attr struct type * \ name##_RB_MINMAX(struct name *head, int val) \ { \ From b8f7b5ec8d512cfc097c9038c760c6ab3382a28b Mon Sep 17 00:00:00 2001 From: kib Date: Sat, 24 Jan 2015 12:51:15 +0000 Subject: [PATCH 214/258] Remove Giant from /dev/mem and /dev/kmem. It is definitely not needed for i386, and from the code inspection, nothing in the arm/mips/sparc64 implementations depends on it. Discussed with: imp, nwhitehorn Sponsored by: The FreeBSD Foundation MFC after: 3 weeks --- sys/arm/arm/mem.c | 2 -- sys/dev/mem/memdev.c | 2 +- sys/i386/i386/mem.c | 4 ---- sys/mips/mips/mem.c | 2 -- sys/sparc64/sparc64/mem.c | 2 -- 5 files changed, 1 insertion(+), 11 deletions(-) diff --git a/sys/arm/arm/mem.c b/sys/arm/arm/mem.c index 460a00495101..30d4b1d8ab00 100644 --- a/sys/arm/arm/mem.c +++ b/sys/arm/arm/mem.c @@ -82,8 +82,6 @@ memrw(struct cdev *dev, struct uio *uio, int flags) int error = 0; vm_offset_t addr, eaddr; - GIANT_REQUIRED; - while (uio->uio_resid > 0 && error == 0) { iov = uio->uio_iov; if (iov->iov_len == 0) { diff --git a/sys/dev/mem/memdev.c b/sys/dev/mem/memdev.c index 37bad1538f7f..c3d1af1ac3a2 100644 --- a/sys/dev/mem/memdev.c +++ b/sys/dev/mem/memdev.c @@ -52,7 +52,7 @@ static struct cdev *memdev, *kmemdev; static struct cdevsw mem_cdevsw = { .d_version = D_VERSION, - .d_flags = D_MEM|D_NEEDGIANT, + .d_flags = D_MEM, .d_open = memopen, .d_read = memrw, .d_write = memrw, diff --git a/sys/i386/i386/mem.c b/sys/i386/i386/mem.c index 9c83f47428f0..b036bd3ec3c7 100644 --- a/sys/i386/i386/mem.c +++ b/sys/i386/i386/mem.c @@ -86,10 +86,6 @@ memrw(struct cdev *dev, struct uio *uio, int flags) int error = 0; vm_offset_t addr; - /* XXX UPS Why ? */ - GIANT_REQUIRED; - - if (dev2unit(dev) != CDEV_MINOR_MEM && dev2unit(dev) != CDEV_MINOR_KMEM) return EIO; diff --git a/sys/mips/mips/mem.c b/sys/mips/mips/mem.c index d40c424888af..08bb6b094c4a 100644 --- a/sys/mips/mips/mem.c +++ b/sys/mips/mips/mem.c @@ -85,8 +85,6 @@ memrw(struct cdev *dev, struct uio *uio, int flags) cnt = 0; error = 0; - GIANT_REQUIRED; - pmap_page_init(&m); while (uio->uio_resid > 0 && !error) { iov = uio->uio_iov; diff --git a/sys/sparc64/sparc64/mem.c b/sys/sparc64/sparc64/mem.c index d09f6b86771e..6bd52253666c 100644 --- a/sys/sparc64/sparc64/mem.c +++ b/sys/sparc64/sparc64/mem.c @@ -99,8 +99,6 @@ memrw(struct cdev *dev, struct uio *uio, int flags) error = 0; ova = 0; - GIANT_REQUIRED; - while (uio->uio_resid > 0 && error == 0) { iov = uio->uio_iov; if (iov->iov_len == 0) { From b126e557b253b006789504806612c8f6dc907bbe Mon Sep 17 00:00:00 2001 From: br Date: Sat, 24 Jan 2015 13:07:07 +0000 Subject: [PATCH 215/258] Add support for audio transmitting, include drivers for: o Digital Audio Multiplexer (AUDMUX) o Smart Direct Memory Access Controller (SDMA) o Synchronous Serial Interface (SSI) Disable by default as it depends on SDMA firmware. Sponsored by: Machdep, Inc. --- sys/arm/freescale/imx/files.imx6 | 19 + sys/arm/freescale/imx/imx6_anatop.c | 21 + sys/arm/freescale/imx/imx6_anatopreg.h | 3 + sys/arm/freescale/imx/imx6_anatopvar.h | 2 + sys/arm/freescale/imx/imx6_audmux.c | 159 +++++ sys/arm/freescale/imx/imx6_ccm.c | 54 +- sys/arm/freescale/imx/imx6_ccmreg.h | 20 + sys/arm/freescale/imx/imx6_sdma.c | 518 +++++++++++++++ sys/arm/freescale/imx/imx6_sdma.h | 245 +++++++ sys/arm/freescale/imx/imx6_ssi.c | 855 +++++++++++++++++++++++++ sys/arm/freescale/imx/imx_ccmvar.h | 1 + sys/boot/fdt/dts/arm/apalis-imx6.dts | 20 +- sys/boot/fdt/dts/arm/imx6.dtsi | 8 +- 13 files changed, 1920 insertions(+), 5 deletions(-) create mode 100644 sys/arm/freescale/imx/imx6_audmux.c create mode 100644 sys/arm/freescale/imx/imx6_sdma.c create mode 100644 sys/arm/freescale/imx/imx6_sdma.h create mode 100644 sys/arm/freescale/imx/imx6_ssi.c diff --git a/sys/arm/freescale/imx/files.imx6 b/sys/arm/freescale/imx/files.imx6 index df86ef9d596a..de1fc41000b0 100644 --- a/sys/arm/freescale/imx/files.imx6 +++ b/sys/arm/freescale/imx/files.imx6 @@ -28,6 +28,9 @@ arm/freescale/imx/imx_machdep.c standard arm/freescale/imx/imx_gpt.c standard arm/freescale/imx/imx_gpio.c optional gpio arm/freescale/imx/imx_i2c.c optional fsliic +arm/freescale/imx/imx6_sdma.c optional sdma +arm/freescale/imx/imx6_audmux.c optional sound +arm/freescale/imx/imx6_ssi.c optional sound # # Optional devices. @@ -52,3 +55,19 @@ arm/freescale/imx/imx6_usbphy.c optional ehci # Not ready yet... # #arm/freescale/imx/imx51_ipuv3.c optional sc + +# SDMA firmware +sdma_fw.c optional sdma_fw \ + compile-with "${AWK} -f $S/tools/fw_stub.awk sdma-imx6q-to1.bin:sdma_fw -msdma -c${.TARGET}" \ + no-implicit-rule before-depend local \ + clean "sdma_fw.c" +sdma-imx6q-to1.fwo optional sdma_fw \ + dependency "sdma-imx6q-to1.bin" \ + compile-with "${LD} -b binary -d -warn-common -r -d -o ${.TARGET} sdma-imx6q-to1.bin" \ + no-implicit-rule \ + clean "sdma-imx6q-to1.fwo" +sdma-imx6q-to1.bin optional sdma_fw \ + dependency "$S/contrib/dev/imx/sdma-imx6q-to1.bin.uu" \ + compile-with "uudecode < $S/contrib/dev/imx/sdma-imx6q-to1.bin.uu" \ + no-obj no-implicit-rule \ + clean "sdma-imx6q-to1.bin" diff --git a/sys/arm/freescale/imx/imx6_anatop.c b/sys/arm/freescale/imx/imx6_anatop.c index fab28b3732bd..644ac7fa7770 100644 --- a/sys/arm/freescale/imx/imx6_anatop.c +++ b/sys/arm/freescale/imx/imx6_anatop.c @@ -710,6 +710,27 @@ imx6_anatop_attach(device_t dev) return (err); } +uint32_t +pll4_configure_output(uint32_t mfi, uint32_t mfn, uint32_t mfd) +{ + int reg; + + /* + * Audio PLL (PLL4). + * PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM) + */ + + reg = (IMX6_ANALOG_CCM_PLL_AUDIO_ENABLE); + reg &= ~(IMX6_ANALOG_CCM_PLL_AUDIO_DIV_SELECT_MASK << \ + IMX6_ANALOG_CCM_PLL_AUDIO_DIV_SELECT_SHIFT); + reg |= (mfi << IMX6_ANALOG_CCM_PLL_AUDIO_DIV_SELECT_SHIFT); + imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_AUDIO, reg); + imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_AUDIO_NUM, mfn); + imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_AUDIO_DENOM, mfd); + + return (0); +} + static int imx6_anatop_probe(device_t dev) { diff --git a/sys/arm/freescale/imx/imx6_anatopreg.h b/sys/arm/freescale/imx/imx6_anatopreg.h index bb75735c521b..a155249ec00d 100644 --- a/sys/arm/freescale/imx/imx6_anatopreg.h +++ b/sys/arm/freescale/imx/imx6_anatopreg.h @@ -58,6 +58,9 @@ #define IMX6_ANALOG_CCM_PLL_SYS_NUM 0x050 #define IMX6_ANALOG_CCM_PLL_SYS_DENOM 0x060 #define IMX6_ANALOG_CCM_PLL_AUDIO 0x070 +#define IMX6_ANALOG_CCM_PLL_AUDIO_ENABLE (1 << 13) +#define IMX6_ANALOG_CCM_PLL_AUDIO_DIV_SELECT_SHIFT 0 +#define IMX6_ANALOG_CCM_PLL_AUDIO_DIV_SELECT_MASK 0x7f #define IMX6_ANALOG_CCM_PLL_AUDIO_SET 0x074 #define IMX6_ANALOG_CCM_PLL_AUDIO_CLR 0x078 #define IMX6_ANALOG_CCM_PLL_AUDIO_TOG 0x07C diff --git a/sys/arm/freescale/imx/imx6_anatopvar.h b/sys/arm/freescale/imx/imx6_anatopvar.h index 5ede71187e6d..4ebe672dfdab 100644 --- a/sys/arm/freescale/imx/imx6_anatopvar.h +++ b/sys/arm/freescale/imx/imx6_anatopvar.h @@ -42,4 +42,6 @@ void imx6_anatop_write_4(bus_size_t _offset, uint32_t _value); uint32_t imx6_get_cpu_clock(void); +uint32_t pll4_configure_output(uint32_t mfi, uint32_t mfn, uint32_t mfd); + #endif diff --git a/sys/arm/freescale/imx/imx6_audmux.c b/sys/arm/freescale/imx/imx6_audmux.c new file mode 100644 index 000000000000..4ea21094784d --- /dev/null +++ b/sys/arm/freescale/imx/imx6_audmux.c @@ -0,0 +1,159 @@ +/*- + * Copyright (c) 2015 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. + */ + +/* + * i.MX6 Digital Audio Multiplexer (AUDMUX) + * Chapter 16, i.MX 6Dual/6Quad Applications Processor Reference Manual, + * Rev. 1, 04/2013 + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#define READ4(_sc, _reg) \ + bus_space_read_4(_sc->bst, _sc->bsh, _reg) +#define WRITE4(_sc, _reg, _val) \ + bus_space_write_4(_sc->bst, _sc->bsh, _reg, _val) + +#define AUDMUX_PTCR(n) (0x8 * (n - 1)) /* Port Timing Control Register */ +#define PTCR_TFS_DIR (1 << 31) /* Transmit Frame Sync Direction Control */ +#define PTCR_TFSEL_S 27 /* Transmit Frame Sync Select */ +#define PTCR_TFSEL_M 0xf +#define PTCR_TCLKDIR (1 << 26) /* Transmit Clock Direction Control */ +#define PTCR_TCSEL_S 22 /* Transmit Clock Select. */ +#define PTCR_TCSEL_M 0xf +#define PTCR_RFS_DIR (1 << 21) /* Receive Frame Sync Direction Control */ +#define PTCR_SYN (1 << 11) +#define AUDMUX_PDCR(n) (0x8 * (n - 1) + 0x4) /* Port Data Control Reg */ +#define PDCR_RXDSEL_S 13 /* Receive Data Select */ +#define PDCR_RXDSEL_M 0x3 +#define PDCR_RXDSEL_PORT(n) (n - 1) + +struct audmux_softc { + struct resource *res[1]; + bus_space_tag_t bst; + bus_space_handle_t bsh; + void *ih; +}; + +static struct resource_spec audmux_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { -1, 0 } +}; + +static int +audmux_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "fsl,imx6q-audmux")) + return (ENXIO); + + device_set_desc(dev, "i.MX6 Digital Audio Multiplexer"); + return (BUS_PROBE_DEFAULT); +} + +static int +audmux_configure(struct audmux_softc *sc, + int ssi_port, int audmux_port) +{ + uint32_t reg; + + /* Direction: output */ + reg = (PTCR_TFS_DIR | PTCR_TCLKDIR | PTCR_SYN); + WRITE4(sc, AUDMUX_PTCR(audmux_port), reg); + + /* Select source */ + reg = (PDCR_RXDSEL_PORT(ssi_port) << PDCR_RXDSEL_S); + WRITE4(sc, AUDMUX_PDCR(audmux_port), reg); + + return (0); +} + +static int +audmux_attach(device_t dev) +{ + struct audmux_softc *sc; + + sc = device_get_softc(dev); + + if (bus_alloc_resources(dev, audmux_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]); + + /* + * Direct SSI1 output to AUDMUX5 pins. + * TODO: dehardcore this. + */ + audmux_configure(sc, 1, 5); + + return (0); +}; + +static device_method_t audmux_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, audmux_probe), + DEVMETHOD(device_attach, audmux_attach), + { 0, 0 } +}; + +static driver_t audmux_driver = { + "audmux", + audmux_methods, + sizeof(struct audmux_softc), +}; + +static devclass_t audmux_devclass; + +DRIVER_MODULE(audmux, simplebus, audmux_driver, audmux_devclass, 0, 0); diff --git a/sys/arm/freescale/imx/imx6_ccm.c b/sys/arm/freescale/imx/imx6_ccm.c index 2c80bd9ee030..8d7f14f13076 100644 --- a/sys/arm/freescale/imx/imx6_ccm.c +++ b/sys/arm/freescale/imx/imx6_ccm.c @@ -94,7 +94,7 @@ ccm_init_gates(struct ccm_softc *sc) WR4(sc, CCM_CCGR2, 0x0fffffc0); /* ipmux & ipsync (bridges), iomux, i2c */ WR4(sc, CCM_CCGR3, 0x3ff00000); /* DDR memory controller */ WR4(sc, CCM_CCGR4, 0x0000f300); /* pl301 bus crossbar */ - WR4(sc, CCM_CCGR5, 0x0f000000); /* uarts */ + WR4(sc, CCM_CCGR5, 0x0ffc00c0); /* uarts, ssi, sdma */ WR4(sc, CCM_CCGR6, 0x000000ff); /* usdhc 1-4 */ } @@ -179,6 +179,58 @@ ccm_probe(device_t dev) return (BUS_PROBE_DEFAULT); } +void +imx_ccm_ssi_configure(device_t _ssidev) +{ + struct ccm_softc *sc; + uint32_t reg; + + sc = ccm_sc; + + /* + * Select PLL4 (Audio PLL) clock multiplexer as source. + * PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM). + */ + + reg = RD4(sc, CCM_CSCMR1); + reg &= ~(SSI_CLK_SEL_M << SSI1_CLK_SEL_S); + reg |= (SSI_CLK_SEL_PLL4 << SSI1_CLK_SEL_S); + reg &= ~(SSI_CLK_SEL_M << SSI2_CLK_SEL_S); + reg |= (SSI_CLK_SEL_PLL4 << SSI2_CLK_SEL_S); + reg &= ~(SSI_CLK_SEL_M << SSI3_CLK_SEL_S); + reg |= (SSI_CLK_SEL_PLL4 << SSI3_CLK_SEL_S); + WR4(sc, CCM_CSCMR1, reg); + + /* + * Ensure we have set hardware-default values + * for pre and post dividers. + */ + + /* SSI1 and SSI3 */ + reg = RD4(sc, CCM_CS1CDR); + /* Divide by 2 */ + reg &= ~(SSI_CLK_PODF_MASK << SSI1_CLK_PODF_SHIFT); + reg &= ~(SSI_CLK_PODF_MASK << SSI3_CLK_PODF_SHIFT); + reg |= (0x1 << SSI1_CLK_PODF_SHIFT); + reg |= (0x1 << SSI3_CLK_PODF_SHIFT); + /* Divide by 4 */ + reg &= ~(SSI_CLK_PRED_MASK << SSI1_CLK_PRED_SHIFT); + reg &= ~(SSI_CLK_PRED_MASK << SSI3_CLK_PRED_SHIFT); + reg |= (0x3 << SSI1_CLK_PRED_SHIFT); + reg |= (0x3 << SSI3_CLK_PRED_SHIFT); + WR4(sc, CCM_CS1CDR, reg); + + /* SSI2 */ + reg = RD4(sc, CCM_CS2CDR); + /* Divide by 2 */ + reg &= ~(SSI_CLK_PODF_MASK << SSI2_CLK_PODF_SHIFT); + reg |= (0x1 << SSI2_CLK_PODF_SHIFT); + /* Divide by 4 */ + reg &= ~(SSI_CLK_PRED_MASK << SSI2_CLK_PRED_SHIFT); + reg |= (0x3 << SSI2_CLK_PRED_SHIFT); + WR4(sc, CCM_CS2CDR, reg); +} + void imx_ccm_usb_enable(device_t _usbdev) { diff --git a/sys/arm/freescale/imx/imx6_ccmreg.h b/sys/arm/freescale/imx/imx6_ccmreg.h index d50c190c736f..31d92caa6d4a 100644 --- a/sys/arm/freescale/imx/imx6_ccmreg.h +++ b/sys/arm/freescale/imx/imx6_ccmreg.h @@ -29,6 +29,26 @@ #ifndef IMX6_CCMREG_H #define IMX6_CCMREG_H +#define CCM_CSCMR1 0x01C +#define SSI1_CLK_SEL_S 10 +#define SSI2_CLK_SEL_S 12 +#define SSI3_CLK_SEL_S 14 +#define SSI_CLK_SEL_M 0x3 +#define SSI_CLK_SEL_508_PFD 0 +#define SSI_CLK_SEL_454_PFD 1 +#define SSI_CLK_SEL_PLL4 2 +#define CCM_CSCMR2 0x020 +#define CCM_CS1CDR 0x028 +#define SSI1_CLK_PODF_SHIFT 0 +#define SSI1_CLK_PRED_SHIFT 6 +#define SSI3_CLK_PODF_SHIFT 16 +#define SSI3_CLK_PRED_SHIFT 22 +#define SSI_CLK_PODF_MASK 0x3f +#define SSI_CLK_PRED_MASK 0x7 +#define CCM_CS2CDR 0x02C +#define SSI2_CLK_PODF_SHIFT 0 +#define SSI2_CLK_PRED_SHIFT 6 +#define CCM_CSCDR2 0x038 #define CCM_CLPCR 0x054 #define CCM_CLPCR_LPM_MASK 0x03 #define CCM_CLPCR_LPM_RUN 0x00 diff --git a/sys/arm/freescale/imx/imx6_sdma.c b/sys/arm/freescale/imx/imx6_sdma.c new file mode 100644 index 000000000000..4a4c28725504 --- /dev/null +++ b/sys/arm/freescale/imx/imx6_sdma.c @@ -0,0 +1,518 @@ +/*- + * Copyright (c) 2015 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. + */ + +/* + * i.MX6 Smart Direct Memory Access Controller (sDMA) + * Chapter 41, i.MX 6Dual/6Quad Applications Processor Reference Manual, + * Rev. 1, 04/2013 + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#define MAX_BD (PAGE_SIZE / sizeof(struct sdma_buffer_descriptor)) + +#define READ4(_sc, _reg) \ + bus_space_read_4(_sc->bst, _sc->bsh, _reg) +#define WRITE4(_sc, _reg, _val) \ + bus_space_write_4(_sc->bst, _sc->bsh, _reg, _val) + +struct sdma_softc *sdma_sc; + +static struct resource_spec sdma_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { SYS_RES_IRQ, 0, RF_ACTIVE }, + { -1, 0 } +}; + +static void +sdma_intr(void *arg) +{ + struct sdma_buffer_descriptor *bd; + struct sdma_channel *channel; + struct sdma_conf *conf; + struct sdma_softc *sc; + int pending; + int i; + int j; + + sc = arg; + + pending = READ4(sc, SDMAARM_INTR); + + /* Ack intr */ + WRITE4(sc, SDMAARM_INTR, pending); + + for (i = 0; i < SDMA_N_CHANNELS; i++) { + if ((pending & (1 << i)) == 0) + continue; + channel = &sc->channel[i]; + conf = channel->conf; + if (!conf) + continue; + for (j = 0; j < conf->num_bd; j++) { + bd = &channel->bd[j]; + bd->mode.status |= BD_DONE; + if (bd->mode.status & BD_RROR) + printf("sDMA error\n"); + } + + conf->ih(conf->ih_user, 1); + + WRITE4(sc, SDMAARM_HSTART, (1 << i)); + } +} + +static int +sdma_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "fsl,imx6q-sdma")) + return (ENXIO); + + device_set_desc(dev, "i.MX6 Smart Direct Memory Access Controller"); + return (BUS_PROBE_DEFAULT); +} + +int +sdma_start(int chn) +{ + struct sdma_softc *sc; + + sc = sdma_sc; + + WRITE4(sc, SDMAARM_HSTART, (1 << chn)); + + return (0); +} + +int +sdma_stop(int chn) +{ + struct sdma_softc *sc; + + sc = sdma_sc; + + WRITE4(sc, SDMAARM_STOP_STAT, (1 << chn)); + + return (0); +} + +int +sdma_alloc(void) +{ + struct sdma_channel *channel; + struct sdma_softc *sc; + int found; + int chn; + int i; + + sc = sdma_sc; + found = 0; + + /* Channel 0 can't be used */ + for (i = 1; i < SDMA_N_CHANNELS; i++) { + channel = &sc->channel[i]; + if (channel->in_use == 0) { + channel->in_use = 1; + found = 1; + break; + } + } + + if (!found) + return (-1); + + chn = i; + + /* Allocate area for buffer descriptors */ + channel->bd = (void *)kmem_alloc_contig(kernel_arena, + PAGE_SIZE, M_ZERO, 0, ~0, PAGE_SIZE, 0, + VM_MEMATTR_UNCACHEABLE); + + return (chn); +} + +int +sdma_free(int chn) +{ + struct sdma_channel *channel; + struct sdma_softc *sc; + + sc = sdma_sc; + + channel = &sc->channel[chn]; + channel->in_use = 0; + + kmem_free(kernel_arena, (vm_offset_t)channel->bd, + PAGE_SIZE); + + return (0); +} + +static int +sdma_overrides(struct sdma_softc *sc, int chn, + int evt, int host, int dsp) +{ + int reg; + + /* Ignore sDMA requests */ + reg = READ4(sc, SDMAARM_EVTOVR); + if (evt) + reg |= (1 << chn); + else + reg &= ~(1 << chn); + WRITE4(sc, SDMAARM_EVTOVR, reg); + + /* Ignore enable bit (HE) */ + reg = READ4(sc, SDMAARM_HOSTOVR); + if (host) + reg |= (1 << chn); + else + reg &= ~(1 << chn); + WRITE4(sc, SDMAARM_HOSTOVR, reg); + + /* Prevent sDMA channel from starting */ + reg = READ4(sc, SDMAARM_DSPOVR); + if (!dsp) + reg |= (1 << chn); + else + reg &= ~(1 << chn); + WRITE4(sc, SDMAARM_DSPOVR, reg); + + return (0); +} + +int +sdma_configure(int chn, struct sdma_conf *conf) +{ + struct sdma_buffer_descriptor *bd0; + struct sdma_buffer_descriptor *bd; + struct sdma_context_data *context; + struct sdma_channel *channel; + struct sdma_softc *sc; +#if 0 + int timeout; + int ret; +#endif + int i; + + sc = sdma_sc; + + channel = &sc->channel[chn]; + channel->conf = conf; + + /* Ensure operation has stopped */ + sdma_stop(chn); + + /* Set priority and enable the channel */ + WRITE4(sc, SDMAARM_SDMA_CHNPRI(chn), 1); + WRITE4(sc, SDMAARM_CHNENBL(conf->event), (1 << chn)); + + sdma_overrides(sc, chn, 0, 0, 0); + + if (conf->num_bd > MAX_BD) { + device_printf(sc->dev, "Error: too much buffer" + " descriptors requested\n"); + return (-1); + } + + for (i = 0; i < conf->num_bd; i++) { + bd = &channel->bd[i]; + bd->mode.command = conf->command; + bd->mode.status = BD_DONE | BD_EXTD | BD_CONT | BD_INTR; + if (i == (conf->num_bd - 1)) + bd->mode.status |= BD_WRAP; + bd->mode.count = conf->period; + bd->buffer_addr = conf->saddr + (conf->period * i); + bd->ext_buffer_addr = 0; + } + + sc->ccb[chn].base_bd_ptr = vtophys(channel->bd); + sc->ccb[chn].current_bd_ptr = vtophys(channel->bd); + + /* + * Load context. + * + * i.MX6 Reference Manual: Appendix A SDMA Scripts + * A.3.1.7.1 (mcu_2_app) + */ + + /* + * TODO: allow using other scripts + */ + context = sc->context; + memset(context, 0, sizeof(*context)); + context->channel_state.pc = sc->fw_scripts->mcu_2_app_addr; + + /* + * Tx FIFO 0 address (r6) + * Event_mask (r1) + * Event2_mask (r0) + * Watermark level (r7) + */ + + if (conf->event > 32) { + context->gReg[0] = (1 << (conf->event % 32)); + context->gReg[1] = 0; + } else { + context->gReg[0] = 0; + context->gReg[1] = (1 << conf->event); + } + + context->gReg[6] = conf->daddr; + context->gReg[7] = conf->word_length; + + bd0 = sc->bd0; + bd0->mode.command = C0_SETDM; + bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD; + bd0->mode.count = sizeof(*context) / 4; + bd0->buffer_addr = sc->context_phys; + bd0->ext_buffer_addr = 2048 + (sizeof(*context) / 4) * chn; + + WRITE4(sc, SDMAARM_HSTART, 1); + +#if 0 + /* Debug purposes */ + + timeout = 1000; + while (!(ret = READ4(sc, SDMAARM_INTR) & 1)) { + if (timeout-- <= 0) + break; + DELAY(10); + }; + + if (!ret) { + device_printf(sc->dev, "Failed to load context.\n"); + return (-1); + } + + WRITE4(sc, SDMAARM_INTR, ret); + + device_printf(sc->dev, "Context loaded successfully.\n"); +#endif + + return (0); +} + +static int +load_firmware(struct sdma_softc *sc) +{ + struct sdma_firmware_header *header; + const struct firmware *fp; + + fp = firmware_get("sdma_fw"); + if (fp == NULL) { + device_printf(sc->dev, "Can't get firmware.\n"); + return (-1); + } + + header = (struct sdma_firmware_header *)fp->data; + if (header->magic != FW_HEADER_MAGIC) { + device_printf(sc->dev, "Can't use firmware.\n"); + return (-1); + } + + sc->fw_header = header; + sc->fw_scripts = (void *)((char *)header + + header->script_addrs_start); + + return (0); +} + +static int +boot_firmware(struct sdma_softc *sc) +{ + struct sdma_buffer_descriptor *bd0; + uint32_t *ram_code; + int timeout; + int ret; + int chn; + int sz; + int i; + + ram_code = (void *)((char *)sc->fw_header + + sc->fw_header->ram_code_start); + + /* Make sure SDMA has not started yet */ + WRITE4(sc, SDMAARM_MC0PTR, 0); + + sz = SDMA_N_CHANNELS * sizeof(struct sdma_channel_control) + \ + sizeof(struct sdma_context_data); + sc->ccb = (void *)kmem_alloc_contig(kernel_arena, + sz, M_ZERO, 0, ~0, PAGE_SIZE, 0, VM_MEMATTR_UNCACHEABLE); + sc->ccb_phys = vtophys(sc->ccb); + + sc->context = (void *)((char *)sc->ccb + \ + SDMA_N_CHANNELS * sizeof(struct sdma_channel_control)); + sc->context_phys = vtophys(sc->context); + + /* Disable all the channels */ + for (i = 0; i < SDMA_N_EVENTS; i++) + WRITE4(sc, SDMAARM_CHNENBL(i), 0); + + /* All channels have priority 0 */ + for (i = 0; i < SDMA_N_CHANNELS; i++) + WRITE4(sc, SDMAARM_SDMA_CHNPRI(i), 0); + + /* Channel 0 is used for booting firmware */ + chn = 0; + + sc->bd0 = (void *)kmem_alloc_contig(kernel_arena, + PAGE_SIZE, M_ZERO, 0, ~0, PAGE_SIZE, 0, + VM_MEMATTR_UNCACHEABLE); + bd0 = sc->bd0; + sc->ccb[chn].base_bd_ptr = vtophys(bd0); + sc->ccb[chn].current_bd_ptr = vtophys(bd0); + + WRITE4(sc, SDMAARM_SDMA_CHNPRI(chn), 1); + + sdma_overrides(sc, chn, 1, 0, 0); + + /* XXX: not sure what is that */ + WRITE4(sc, SDMAARM_CHN0ADDR, 0x4050); + + WRITE4(sc, SDMAARM_CONFIG, 0); + WRITE4(sc, SDMAARM_MC0PTR, sc->ccb_phys); + WRITE4(sc, SDMAARM_CONFIG, CONFIG_CSM); + WRITE4(sc, SDMAARM_SDMA_CHNPRI(chn), 1); + + bd0->mode.command = C0_SETPM; + bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD; + bd0->mode.count = sc->fw_header->ram_code_size / 2; + bd0->buffer_addr = vtophys(ram_code); + bd0->ext_buffer_addr = sc->fw_scripts->ram_code_start_addr; + + WRITE4(sc, SDMAARM_HSTART, 1); + + timeout = 100; + while (!(ret = READ4(sc, SDMAARM_INTR) & 1)) { + if (timeout-- <= 0) + break; + DELAY(10); + }; + + if (ret == 0) { + device_printf(sc->dev, "SDMA failed to boot\n"); + return (-1); + } + + WRITE4(sc, SDMAARM_INTR, ret); + +#if 0 + device_printf(sc->dev, "SDMA booted successfully.\n"); +#endif + + /* Debug is disabled */ + WRITE4(sc, SDMAARM_ONCE_ENB, 0); + + return (0); +} + +static int +sdma_attach(device_t dev) +{ + struct sdma_softc *sc; + int err; + + sc = device_get_softc(dev); + sc->dev = dev; + + if (bus_alloc_resources(dev, sdma_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]); + + sdma_sc = sc; + + /* Setup interrupt handler */ + err = bus_setup_intr(dev, sc->res[1], INTR_TYPE_MISC | INTR_MPSAFE, + NULL, sdma_intr, sc, &sc->ih); + if (err) { + device_printf(dev, "Unable to alloc interrupt resource.\n"); + return (ENXIO); + } + + if (load_firmware(sc) == -1) + return (ENXIO); + + if (boot_firmware(sc) == -1) + return (ENXIO); + + return (0); +}; + +static device_method_t sdma_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, sdma_probe), + DEVMETHOD(device_attach, sdma_attach), + { 0, 0 } +}; + +static driver_t sdma_driver = { + "sdma", + sdma_methods, + sizeof(struct sdma_softc), +}; + +static devclass_t sdma_devclass; + +DRIVER_MODULE(sdma, simplebus, sdma_driver, sdma_devclass, 0, 0); diff --git a/sys/arm/freescale/imx/imx6_sdma.h b/sys/arm/freescale/imx/imx6_sdma.h new file mode 100644 index 000000000000..0f970de4b022 --- /dev/null +++ b/sys/arm/freescale/imx/imx6_sdma.h @@ -0,0 +1,245 @@ +/*- + * Copyright (c) 2015 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. + * + * $FreeBSD$ + */ + +#define SDMAARM_MC0PTR 0x00 /* ARM platform Channel 0 Pointer */ +#define SDMAARM_INTR 0x04 /* Channel Interrupts */ +#define SDMAARM_STOP_STAT 0x08 /* Channel Stop/Channel Status */ +#define SDMAARM_HSTART 0x0C /* Channel Start */ +#define SDMAARM_EVTOVR 0x10 /* Channel Event Override */ +#define SDMAARM_DSPOVR 0x14 /* Channel BP Override */ +#define SDMAARM_HOSTOVR 0x18 /* Channel ARM platform Override */ +#define SDMAARM_EVTPEND 0x1C /* Channel Event Pending */ +#define SDMAARM_RESET 0x24 /* Reset Register */ +#define SDMAARM_EVTERR 0x28 /* DMA Request Error Register */ +#define SDMAARM_INTRMASK 0x2C /* Channel ARM platform Interrupt Mask */ +#define SDMAARM_PSW 0x30 /* Schedule Status */ +#define SDMAARM_EVTERRDBG 0x34 /* DMA Request Error Register */ +#define SDMAARM_CONFIG 0x38 /* Configuration Register */ +#define CONFIG_CSM 0x3 +#define SDMAARM_SDMA_LOCK 0x3C /* SDMA LOCK */ +#define SDMAARM_ONCE_ENB 0x40 /* OnCE Enable */ +#define SDMAARM_ONCE_DATA 0x44 /* OnCE Data Register */ +#define SDMAARM_ONCE_INSTR 0x48 /* OnCE Instruction Register */ +#define SDMAARM_ONCE_STAT 0x4C /* OnCE Status Register */ +#define SDMAARM_ONCE_CMD 0x50 /* OnCE Command Register */ +#define SDMAARM_ILLINSTADDR 0x58 /* Illegal Instruction Trap Address */ +#define SDMAARM_CHN0ADDR 0x5C /* Channel 0 Boot Address */ +#define SDMAARM_EVT_MIRROR 0x60 /* DMA Requests */ +#define SDMAARM_EVT_MIRROR2 0x64 /* DMA Requests 2 */ +#define SDMAARM_XTRIG_CONF1 0x70 /* Cross-Trigger Events Configuration Register 1 */ +#define SDMAARM_XTRIG_CONF2 0x74 /* Cross-Trigger Events Configuration Register 2 */ +#define SDMAARM_SDMA_CHNPRI(n) (0x100 + 0x4 * n) /* Channel Priority Registers */ +#define SDMAARM_CHNENBL(n) (0x200 + 0x4 * n) /* Channel Enable RAM */ + +/* SDMA Event Mappings */ +#define SSI1_RX_1 35 +#define SSI1_TX_1 36 +#define SSI1_RX_0 37 +#define SSI1_TX_0 38 +#define SSI2_RX_1 39 +#define SSI2_TX_1 40 +#define SSI2_RX_0 41 +#define SSI2_TX_0 42 +#define SSI3_RX_1 43 +#define SSI3_TX_1 44 +#define SSI3_RX_0 45 +#define SSI3_TX_0 46 + +#define C0_ADDR 0x01 +#define C0_LOAD 0x02 +#define C0_DUMP 0x03 +#define C0_SETCTX 0x07 +#define C0_GETCTX 0x03 +#define C0_SETDM 0x01 +#define C0_SETPM 0x04 +#define C0_GETDM 0x02 +#define C0_GETPM 0x08 + +#define BD_DONE 0x01 +#define BD_WRAP 0x02 +#define BD_CONT 0x04 +#define BD_INTR 0x08 +#define BD_RROR 0x10 +#define BD_LAST 0x20 +#define BD_EXTD 0x80 + +/* sDMA data transfer length */ +#define CMD_4BYTES 0 +#define CMD_3BYTES 3 +#define CMD_2BYTES 2 +#define CMD_1BYTES 1 + +struct sdma_firmware_header { + uint32_t magic; + uint32_t version_major; + uint32_t version_minor; + uint32_t script_addrs_start; + uint32_t num_script_addrs; + uint32_t ram_code_start; + uint32_t ram_code_size; +}; + +struct sdma_mode_count { + uint16_t count; + uint8_t status; + uint8_t command; +}; + +struct sdma_buffer_descriptor { + struct sdma_mode_count mode; + uint32_t buffer_addr; + uint32_t ext_buffer_addr; +} __packed; + +struct sdma_channel_control { + uint32_t current_bd_ptr; + uint32_t base_bd_ptr; + uint32_t unused[2]; +} __packed; + +struct sdma_state_registers { + uint32_t pc :14; + uint32_t unused1: 1; + uint32_t t : 1; + uint32_t rpc :14; + uint32_t unused0: 1; + uint32_t sf : 1; + uint32_t spc :14; + uint32_t unused2: 1; + uint32_t df : 1; + uint32_t epc :14; + uint32_t lm : 2; +} __packed; + +struct sdma_context_data { + struct sdma_state_registers channel_state; + uint32_t gReg[8]; + uint32_t mda; + uint32_t msa; + uint32_t ms; + uint32_t md; + uint32_t pda; + uint32_t psa; + uint32_t ps; + uint32_t pd; + uint32_t ca; + uint32_t cs; + uint32_t dda; + uint32_t dsa; + uint32_t ds; + uint32_t dd; + uint32_t unused[8]; +} __packed; + +/* SDMA firmware script pointers */ +struct sdma_script_start_addrs { + int32_t ap_2_ap_addr; + int32_t ap_2_bp_addr; + int32_t ap_2_ap_fixed_addr; + int32_t bp_2_ap_addr; + int32_t loopback_on_dsp_side_addr; + int32_t mcu_interrupt_only_addr; + int32_t firi_2_per_addr; + int32_t firi_2_mcu_addr; + int32_t per_2_firi_addr; + int32_t mcu_2_firi_addr; + int32_t uart_2_per_addr; + int32_t uart_2_mcu_addr; + int32_t per_2_app_addr; + int32_t mcu_2_app_addr; + int32_t per_2_per_addr; + int32_t uartsh_2_per_addr; + int32_t uartsh_2_mcu_addr; + int32_t per_2_shp_addr; + int32_t mcu_2_shp_addr; + int32_t ata_2_mcu_addr; + int32_t mcu_2_ata_addr; + int32_t app_2_per_addr; + int32_t app_2_mcu_addr; + int32_t shp_2_per_addr; + int32_t shp_2_mcu_addr; + int32_t mshc_2_mcu_addr; + int32_t mcu_2_mshc_addr; + int32_t spdif_2_mcu_addr; + int32_t mcu_2_spdif_addr; + int32_t asrc_2_mcu_addr; + int32_t ext_mem_2_ipu_addr; + int32_t descrambler_addr; + int32_t dptc_dvfs_addr; + int32_t utra_addr; + int32_t ram_code_start_addr; + int32_t mcu_2_ssish_addr; + int32_t ssish_2_mcu_addr; + int32_t hdmi_dma_addr; +}; + +#define SDMA_N_CHANNELS 32 +#define SDMA_N_EVENTS 48 +#define FW_HEADER_MAGIC 0x414d4453 + +struct sdma_channel { + struct sdma_conf *conf; + struct sdma_buffer_descriptor *bd; + uint8_t in_use; +}; + +struct sdma_softc { + struct resource *res[2]; + bus_space_tag_t bst; + bus_space_handle_t bsh; + device_t dev; + void *ih; + struct sdma_channel_control *ccb; + struct sdma_buffer_descriptor *bd0; + struct sdma_context_data *context; + struct sdma_channel channel[SDMA_N_CHANNELS]; + uint32_t num_bd; + uint32_t ccb_phys; + uint32_t context_phys; + struct sdma_firmware_header *fw_header; + struct sdma_script_start_addrs *fw_scripts; +}; + +struct sdma_conf { + bus_addr_t saddr; + bus_addr_t daddr; + uint32_t word_length; + uint32_t nbits; + uint32_t command; + uint32_t num_bd; + uint32_t event; + uint32_t period; + uint32_t (*ih)(void *, int); + void *ih_user; +}; + +int sdma_configure(int, struct sdma_conf *); +int sdma_start(int); +int sdma_stop(int); +int sdma_alloc(void); +int sdma_free(int); diff --git a/sys/arm/freescale/imx/imx6_ssi.c b/sys/arm/freescale/imx/imx6_ssi.c new file mode 100644 index 000000000000..af8a9e8f279a --- /dev/null +++ b/sys/arm/freescale/imx/imx6_ssi.c @@ -0,0 +1,855 @@ +/*- + * Copyright (c) 2015 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. + */ + +/* + * i.MX6 Synchronous Serial Interface (SSI) + * + * Chapter 61, i.MX 6Dual/6Quad Applications Processor Reference Manual, + * Rev. 1, 04/2013 + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#define READ4(_sc, _reg) \ + bus_space_read_4(_sc->bst, _sc->bsh, _reg) +#define WRITE4(_sc, _reg, _val) \ + bus_space_write_4(_sc->bst, _sc->bsh, _reg, _val) + +#define SSI_NCHANNELS 1 + +/* i.MX6 SSI registers */ + +#define SSI_STX0 0x00 /* Transmit Data Register n */ +#define SSI_STX1 0x04 /* Transmit Data Register n */ +#define SSI_SRX0 0x08 /* Receive Data Register n */ +#define SSI_SRX1 0x0C /* Receive Data Register n */ +#define SSI_SCR 0x10 /* Control Register */ +#define SCR_I2S_MODE_S 5 /* I2S Mode Select. */ +#define SCR_I2S_MODE_M 0x3 +#define SCR_SYN (1 << 4) +#define SCR_NET (1 << 3) /* Network mode */ +#define SCR_RE (1 << 2) /* Receive Enable. */ +#define SCR_TE (1 << 1) /* Transmit Enable. */ +#define SCR_SSIEN (1 << 0) /* SSI Enable */ +#define SSI_SISR 0x14 /* Interrupt Status Register */ +#define SSI_SIER 0x18 /* Interrupt Enable Register */ +#define SIER_RDMAE (1 << 22) /* Receive DMA Enable. */ +#define SIER_RIE (1 << 21) /* Receive Interrupt Enable. */ +#define SIER_TDMAE (1 << 20) /* Transmit DMA Enable. */ +#define SIER_TIE (1 << 19) /* Transmit Interrupt Enable. */ +#define SIER_TDE0IE (1 << 12) /* Transmit Data Register Empty 0. */ +#define SIER_TUE0IE (1 << 8) /* Transmitter Underrun Error 0. */ +#define SIER_TFE0IE (1 << 0) /* Transmit FIFO Empty 0 IE. */ +#define SSI_STCR 0x1C /* Transmit Configuration Register */ +#define STCR_TXBIT0 (1 << 9) /* Transmit Bit 0 shift MSB/LSB */ +#define STCR_TFEN1 (1 << 8) /* Transmit FIFO Enable 1. */ +#define STCR_TFEN0 (1 << 7) /* Transmit FIFO Enable 0. */ +#define STCR_TFDIR (1 << 6) /* Transmit Frame Direction. */ +#define STCR_TXDIR (1 << 5) /* Transmit Clock Direction. */ +#define STCR_TSHFD (1 << 4) /* Transmit Shift Direction. */ +#define STCR_TSCKP (1 << 3) /* Transmit Clock Polarity. */ +#define STCR_TFSI (1 << 2) /* Transmit Frame Sync Invert. */ +#define STCR_TFSL (1 << 1) /* Transmit Frame Sync Length. */ +#define STCR_TEFS (1 << 0) /* Transmit Early Frame Sync. */ +#define SSI_SRCR 0x20 /* Receive Configuration Register */ +#define SSI_STCCR 0x24 /* Transmit Clock Control Register */ +#define STCCR_DIV2 (1 << 18) /* Divide By 2. */ +#define STCCR_PSR (1 << 17) /* Divide clock by 8. */ +#define WL3_WL0_S 13 +#define WL3_WL0_M 0xf +#define DC4_DC0_S 8 +#define DC4_DC0_M 0x1f +#define PM7_PM0_S 0 +#define PM7_PM0_M 0xff +#define SSI_SRCCR 0x28 /* Receive Clock Control Register */ +#define SSI_SFCSR 0x2C /* FIFO Control/Status Register */ +#define SFCSR_RFWM1_S 20 /* Receive FIFO Empty WaterMark 1 */ +#define SFCSR_RFWM1_M 0xf +#define SFCSR_TFWM1_S 16 /* Transmit FIFO Empty WaterMark 1 */ +#define SFCSR_TFWM1_M 0xf +#define SFCSR_RFWM0_S 4 /* Receive FIFO Empty WaterMark 0 */ +#define SFCSR_RFWM0_M 0xf +#define SFCSR_TFWM0_S 0 /* Transmit FIFO Empty WaterMark 0 */ +#define SFCSR_TFWM0_M 0xf +#define SSI_SACNT 0x38 /* AC97 Control Register */ +#define SSI_SACADD 0x3C /* AC97 Command Address Register */ +#define SSI_SACDAT 0x40 /* AC97 Command Data Register */ +#define SSI_SATAG 0x44 /* AC97 Tag Register */ +#define SSI_STMSK 0x48 /* Transmit Time Slot Mask Register */ +#define SSI_SRMSK 0x4C /* Receive Time Slot Mask Register */ +#define SSI_SACCST 0x50 /* AC97 Channel Status Register */ +#define SSI_SACCEN 0x54 /* AC97 Channel Enable Register */ +#define SSI_SACCDIS 0x58 /* AC97 Channel Disable Register */ + +static MALLOC_DEFINE(M_SSI, "ssi", "ssi audio"); + +uint32_t ssi_dma_intr(void *arg, int chn); + +struct ssi_rate { + uint32_t speed; + uint32_t mfi; /* PLL4 Multiplication Factor Integer */ + uint32_t mfn; /* PLL4 Multiplication Factor Numerator */ + uint32_t mfd; /* PLL4 Multiplication Factor Denominator */ + /* More dividers to configure can be added here */ +}; + +static struct ssi_rate rate_map[] = { + { 192000, 49, 152, 1000 }, /* PLL4 49.152 Mhz */ + /* TODO: add more frequences */ + { 0, 0 }, +}; + +/* + * i.MX6 example bit clock formula + * + * BCLK = 2 channels * 192000 hz * 24 bit = 9216000 hz = + * (24000000 * (49 + 152/1000.0) / 4 / 4 / 2 / 2 / 2 / 1 / 1) + * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ + * | | | | | | | | | | | + * Fref ------/ | | | | | | | | | | + * PLL4 div select -/ | | | | | | | | | + * PLL4 num --------------/ | | | | | | | | + * PLL4 denom -------------------/ | | | | | | | + * PLL4 post div ---------------------/ | | | | | | + * CCM ssi pre div (CCM_CS1CDR) ----------/ | | | | | + * CCM ssi post div (CCM_CS1CDR) -------------/ | | | | + * SSI PM7_PM0_S ---------------------------------/ | | | + * SSI Fixed divider ---------------------------------/ | | + * SSI DIV2 ----------------------------------------------/ | + * SSI PSR (prescaler /1 or /8) ------------------------------/ + * + * MCLK (Master clock) depends on DAC, usually BCLK * 4 + */ + +struct sc_info { + struct resource *res[2]; + bus_space_tag_t bst; + bus_space_handle_t bsh; + device_t dev; + struct mtx *lock; + void *ih; + int pos; + int dma_size; + bus_dma_tag_t dma_tag; + bus_dmamap_t dma_map; + bus_addr_t buf_base_phys; + uint32_t *buf_base; + struct sdma_conf *conf; + struct ssi_rate *sr; + struct sdma_softc *sdma_sc; + int sdma_ev_rx; + int sdma_ev_tx; + int sdma_channel; +}; + +/* Channel registers */ +struct sc_chinfo { + struct snd_dbuf *buffer; + struct pcm_channel *channel; + struct sc_pcminfo *parent; + + /* Channel information */ + uint32_t dir; + uint32_t format; + + /* Flags */ + uint32_t run; +}; + +/* PCM device private data */ +struct sc_pcminfo { + device_t dev; + uint32_t (*ih)(struct sc_pcminfo *scp); + uint32_t chnum; + struct sc_chinfo chan[SSI_NCHANNELS]; + struct sc_info *sc; +}; + +static struct resource_spec ssi_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { SYS_RES_IRQ, 0, RF_ACTIVE }, + { -1, 0 } +}; + +static int setup_dma(struct sc_pcminfo *scp); +static void setup_ssi(struct sc_info *); +static void ssi_configure_clock(struct sc_info *); + +/* + * Mixer interface. + */ + +static int +ssimixer_init(struct snd_mixer *m) +{ + struct sc_pcminfo *scp; + struct sc_info *sc; + int mask; + + scp = mix_getdevinfo(m); + sc = scp->sc; + + if (sc == NULL) + return -1; + + mask = SOUND_MASK_PCM; + mask |= SOUND_MASK_VOLUME; + + snd_mtxlock(sc->lock); + pcm_setflags(scp->dev, pcm_getflags(scp->dev) | SD_F_SOFTPCMVOL); + mix_setdevs(m, mask); + snd_mtxunlock(sc->lock); + + return (0); +} + +static int +ssimixer_set(struct snd_mixer *m, unsigned dev, + unsigned left, unsigned right) +{ + struct sc_pcminfo *scp; + + scp = mix_getdevinfo(m); + + /* Here we can configure hardware volume on our DAC */ + +#if 1 + device_printf(scp->dev, "ssimixer_set() %d %d\n", + left, right); +#endif + + return (0); +} + +static kobj_method_t ssimixer_methods[] = { + KOBJMETHOD(mixer_init, ssimixer_init), + KOBJMETHOD(mixer_set, ssimixer_set), + KOBJMETHOD_END +}; +MIXER_DECLARE(ssimixer); + + +/* + * Channel interface. + */ + +static void * +ssichan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, + struct pcm_channel *c, int dir) +{ + struct sc_pcminfo *scp; + struct sc_chinfo *ch; + struct sc_info *sc; + + scp = (struct sc_pcminfo *)devinfo; + sc = scp->sc; + + snd_mtxlock(sc->lock); + ch = &scp->chan[0]; + ch->dir = dir; + ch->run = 0; + ch->buffer = b; + ch->channel = c; + ch->parent = scp; + snd_mtxunlock(sc->lock); + + if (sndbuf_setup(ch->buffer, sc->buf_base, sc->dma_size) != 0) { + device_printf(scp->dev, "Can't setup sndbuf.\n"); + return NULL; + } + + return ch; +} + +static int +ssichan_free(kobj_t obj, void *data) +{ + struct sc_chinfo *ch = data; + struct sc_pcminfo *scp = ch->parent; + struct sc_info *sc = scp->sc; + +#if 0 + device_printf(scp->dev, "ssichan_free()\n"); +#endif + + snd_mtxlock(sc->lock); + /* TODO: free channel buffer */ + snd_mtxunlock(sc->lock); + + return (0); +} + +static int +ssichan_setformat(kobj_t obj, void *data, uint32_t format) +{ + struct sc_chinfo *ch = data; + + ch->format = format; + + return (0); +} + +static uint32_t +ssichan_setspeed(kobj_t obj, void *data, uint32_t speed) +{ + struct sc_pcminfo *scp; + struct sc_chinfo *ch; + struct ssi_rate *sr; + struct sc_info *sc; + int threshold; + int i; + + ch = data; + scp = ch->parent; + sc = scp->sc; + + sr = NULL; + + /* First look for equal frequency. */ + for (i = 0; rate_map[i].speed != 0; i++) { + if (rate_map[i].speed == speed) + sr = &rate_map[i]; + } + + /* If no match, just find nearest. */ + if (sr == NULL) { + for (i = 0; rate_map[i].speed != 0; i++) { + sr = &rate_map[i]; + threshold = sr->speed + ((rate_map[i + 1].speed != 0) ? + ((rate_map[i + 1].speed - sr->speed) >> 1) : 0); + if (speed < threshold) + break; + } + } + + sc->sr = sr; + + ssi_configure_clock(sc); + + return (sr->speed); +} + +static void +ssi_configure_clock(struct sc_info *sc) +{ + struct ssi_rate *sr; + + sr = sc->sr; + + pll4_configure_output(sr->mfi, sr->mfn, sr->mfd); + + /* Configure other dividers here, if any */ +} + +static uint32_t +ssichan_setblocksize(kobj_t obj, void *data, uint32_t blocksize) +{ + struct sc_chinfo *ch = data; + struct sc_pcminfo *scp = ch->parent; + struct sc_info *sc = scp->sc; + + sndbuf_resize(ch->buffer, sc->dma_size / blocksize, blocksize); + + setup_dma(scp); + + return (sndbuf_getblksz(ch->buffer)); +} + +uint32_t +ssi_dma_intr(void *arg, int chn) +{ + struct sc_pcminfo *scp; + struct sdma_conf *conf; + struct sc_chinfo *ch; + struct sc_info *sc; + int bufsize; + + scp = arg; + ch = &scp->chan[0]; + sc = scp->sc; + conf = sc->conf; + + bufsize = sndbuf_getsize(ch->buffer); + + sc->pos += conf->period; + if (sc->pos >= bufsize) + sc->pos -= bufsize; + + if (ch->run) + chn_intr(ch->channel); + + return (0); +} + +static int +find_sdma_controller(struct sc_info *sc) +{ + struct sdma_softc *sdma_sc; + phandle_t node, sdma_node; + device_t sdma_dev; + int dts_value[8]; + int len; + + if ((node = ofw_bus_get_node(sc->dev)) == -1) + return (ENXIO); + + if ((len = OF_getproplen(node, "dmas")) <= 0) + return (ENXIO); + + OF_getprop(node, "dmas", &dts_value, len); + + sc->sdma_ev_rx = fdt32_to_cpu(dts_value[1]); + sc->sdma_ev_tx = fdt32_to_cpu(dts_value[5]); + + sdma_node = OF_node_from_xref(fdt32_to_cpu(dts_value[0])); + + sdma_sc = NULL; + + sdma_dev = devclass_get_device(devclass_find("sdma"), 0); + if (sdma_dev) + sdma_sc = device_get_softc(sdma_dev); + + if (sdma_sc == NULL) { + device_printf(sc->dev, "No sDMA found. Can't operate\n"); + return (ENXIO); + }; + + sc->sdma_sc = sdma_sc; + + return (0); +}; + +static int +setup_dma(struct sc_pcminfo *scp) +{ + struct sdma_conf *conf; + struct sc_chinfo *ch; + struct sc_info *sc; + int fmt; + + ch = &scp->chan[0]; + sc = scp->sc; + conf = sc->conf; + + conf->ih = ssi_dma_intr; + conf->ih_user = scp; + conf->saddr = sc->buf_base_phys; + conf->daddr = rman_get_start(sc->res[0]) + SSI_STX0; + conf->event = sc->sdma_ev_tx; /* SDMA TX event */ + conf->period = sndbuf_getblksz(ch->buffer); + conf->num_bd = sndbuf_getblkcnt(ch->buffer); + + /* + * Word Length + * Can be 32, 24, 16 or 8 for sDMA. + * + * SSI supports 24 at max. + */ + + fmt = sndbuf_getfmt(ch->buffer); + + if (fmt & AFMT_16BIT) { + conf->word_length = 16; + conf->command = CMD_2BYTES; + } else if (fmt & AFMT_24BIT) { + conf->word_length = 24; + conf->command = CMD_3BYTES; + } else { + device_printf(sc->dev, "Unknown format\n"); + return (-1); + } + + return (0); +} + +static int +ssi_start(struct sc_pcminfo *scp) +{ + struct sc_info *sc; + int reg; + + sc = scp->sc; + + if (sdma_configure(sc->sdma_channel, sc->conf) != 0) { + device_printf(sc->dev, "Can't configure sDMA\n"); + return (-1); + } + + /* Enable DMA interrupt */ + reg = (SIER_TDMAE); + WRITE4(sc, SSI_SIER, reg); + + sdma_start(sc->sdma_channel); + + return (0); +} + +static int +ssi_stop(struct sc_pcminfo *scp) +{ + struct sc_info *sc; + int reg; + + sc = scp->sc; + + reg = READ4(sc, SSI_SIER); + reg &= ~(SIER_TDMAE); + WRITE4(sc, SSI_SIER, reg); + + sdma_stop(sc->sdma_channel); + + bzero(sc->buf_base, sc->dma_size); + + return (0); +} + +static int +ssichan_trigger(kobj_t obj, void *data, int go) +{ + struct sc_pcminfo *scp; + struct sc_chinfo *ch; + struct sc_info *sc; + + ch = data; + scp = ch->parent; + sc = scp->sc; + + snd_mtxlock(sc->lock); + + switch (go) { + case PCMTRIG_START: +#if 0 + device_printf(scp->dev, "trigger start\n"); +#endif + ch->run = 1; + + ssi_start(scp); + + break; + + case PCMTRIG_STOP: + case PCMTRIG_ABORT: +#if 0 + device_printf(scp->dev, "trigger stop or abort\n"); +#endif + ch->run = 0; + + ssi_stop(scp); + + break; + } + + snd_mtxunlock(sc->lock); + + return (0); +} + +static uint32_t +ssichan_getptr(kobj_t obj, void *data) +{ + struct sc_pcminfo *scp; + struct sc_chinfo *ch; + struct sc_info *sc; + + ch = data; + scp = ch->parent; + sc = scp->sc; + + return (sc->pos); +} + +static uint32_t ssi_pfmt[] = { + SND_FORMAT(AFMT_S24_LE, 2, 0), + 0 +}; + +static struct pcmchan_caps ssi_pcaps = {44100, 192000, ssi_pfmt, 0}; + +static struct pcmchan_caps * +ssichan_getcaps(kobj_t obj, void *data) +{ + + return (&ssi_pcaps); +} + +static kobj_method_t ssichan_methods[] = { + KOBJMETHOD(channel_init, ssichan_init), + KOBJMETHOD(channel_free, ssichan_free), + KOBJMETHOD(channel_setformat, ssichan_setformat), + KOBJMETHOD(channel_setspeed, ssichan_setspeed), + KOBJMETHOD(channel_setblocksize, ssichan_setblocksize), + KOBJMETHOD(channel_trigger, ssichan_trigger), + KOBJMETHOD(channel_getptr, ssichan_getptr), + KOBJMETHOD(channel_getcaps, ssichan_getcaps), + KOBJMETHOD_END +}; +CHANNEL_DECLARE(ssichan); + +static int +ssi_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "fsl,imx6q-ssi")) + return (ENXIO); + + device_set_desc(dev, "i.MX6 Synchronous Serial Interface (SSI)"); + return (BUS_PROBE_DEFAULT); +} + +static void +ssi_intr(void *arg) +{ + struct sc_pcminfo *scp; + struct sc_chinfo *ch; + struct sc_info *sc; + + scp = arg; + sc = scp->sc; + ch = &scp->chan[0]; + + /* We don't use SSI interrupt */ +#if 0 + device_printf(sc->dev, "SSI Intr 0x%08x\n", + READ4(sc, SSI_SISR)); +#endif +} + +static void +setup_ssi(struct sc_info *sc) +{ + int reg; + + reg = READ4(sc, SSI_STCCR); + reg &= ~(WL3_WL0_M << WL3_WL0_S); + reg |= (0xb << WL3_WL0_S); /* 24 bit */ + reg &= ~(DC4_DC0_M << DC4_DC0_S); + reg |= (1 << DC4_DC0_S); /* 2 words per frame */ + reg &= ~(STCCR_DIV2); /* Divide by 1 */ + reg &= ~(STCCR_PSR); /* Divide by 1 */ + reg &= ~(PM7_PM0_M << PM7_PM0_S); + reg |= (1 << PM7_PM0_S); /* Divide by 2 */ + WRITE4(sc, SSI_STCCR, reg); + + reg = READ4(sc, SSI_SFCSR); + reg &= ~(SFCSR_TFWM0_M << SFCSR_TFWM0_S); + reg |= (8 << SFCSR_TFWM0_S); /* empty slots */ + WRITE4(sc, SSI_SFCSR, reg); + + reg = READ4(sc, SSI_STCR); + reg |= (STCR_TFEN0); + reg &= ~(STCR_TFEN1); + reg &= ~(STCR_TSHFD); /* MSB */ + reg |= (STCR_TXBIT0); + reg |= (STCR_TXDIR | STCR_TFDIR); + reg |= (STCR_TSCKP); /* falling edge */ + reg |= (STCR_TFSI); + reg &= ~(STCR_TFSI); /* active high frame sync */ + reg &= ~(STCR_TFSL); + reg |= STCR_TEFS; + WRITE4(sc, SSI_STCR, reg); + + reg = READ4(sc, SSI_SCR); + reg &= ~(SCR_I2S_MODE_M << SCR_I2S_MODE_S); /* Not master */ + reg |= (SCR_SSIEN | SCR_TE); + reg |= (SCR_NET); + reg |= (SCR_SYN); + WRITE4(sc, SSI_SCR, reg); +} + +static void +ssi_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err) +{ + bus_addr_t *addr; + + if (err) + return; + + addr = (bus_addr_t*)arg; + *addr = segs[0].ds_addr; +} + +static int +ssi_attach(device_t dev) +{ + char status[SND_STATUSLEN]; + struct sc_pcminfo *scp; + struct sc_info *sc; + int err; + + sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); + sc->dev = dev; + sc->sr = &rate_map[0]; + sc->pos = 0; + sc->conf = malloc(sizeof(struct sdma_conf), M_DEVBUF, M_WAITOK | M_ZERO); + + sc->lock = snd_mtxcreate(device_get_nameunit(dev), "ssi softc"); + if (sc->lock == NULL) { + device_printf(dev, "Cant create mtx\n"); + return (ENXIO); + } + + if (bus_alloc_resources(dev, ssi_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]); + + /* SDMA */ + if (find_sdma_controller(sc)) { + device_printf(dev, "could not find active SDMA\n"); + return (ENXIO); + } + + /* Setup PCM */ + scp = malloc(sizeof(struct sc_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO); + scp->sc = sc; + scp->dev = dev; + + /* + * Maximum possible DMA buffer. + * Will be used partialy to match 24 bit word. + */ + sc->dma_size = 131072; + + /* + * Must use dma_size boundary as modulo feature required. + * Modulo feature allows setup circular buffer. + */ + + err = bus_dma_tag_create( + bus_get_dma_tag(sc->dev), + 4, sc->dma_size, /* alignment, boundary */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + sc->dma_size, 1, /* maxsize, nsegments */ + sc->dma_size, 0, /* maxsegsize, flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->dma_tag); + + err = bus_dmamem_alloc(sc->dma_tag, (void **)&sc->buf_base, + BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &sc->dma_map); + if (err) { + device_printf(dev, "cannot allocate framebuffer\n"); + return (ENXIO); + } + + err = bus_dmamap_load(sc->dma_tag, sc->dma_map, sc->buf_base, + sc->dma_size, ssi_dmamap_cb, &sc->buf_base_phys, BUS_DMA_NOWAIT); + if (err) { + device_printf(dev, "cannot load DMA map\n"); + return (ENXIO); + } + + bzero(sc->buf_base, sc->dma_size); + + /* Setup interrupt handler */ + err = bus_setup_intr(dev, sc->res[1], INTR_MPSAFE | INTR_TYPE_AV, + NULL, ssi_intr, scp, &sc->ih); + if (err) { + device_printf(dev, "Unable to alloc interrupt resource.\n"); + return (ENXIO); + } + + pcm_setflags(dev, pcm_getflags(dev) | SD_F_MPSAFE); + + err = pcm_register(dev, scp, 1, 0); + if (err) { + device_printf(dev, "Can't register pcm.\n"); + return (ENXIO); + } + + scp->chnum = 0; + pcm_addchan(dev, PCMDIR_PLAY, &ssichan_class, scp); + scp->chnum++; + + snprintf(status, SND_STATUSLEN, "at simplebus"); + pcm_setstatus(dev, status); + + mixer_init(dev, &ssimixer_class, scp); + setup_ssi(sc); + + imx_ccm_ssi_configure(dev); + + sc->sdma_channel = sdma_alloc(); + if (sc->sdma_channel < 0) { + device_printf(sc->dev, "Can't get sDMA channel\n"); + return (1); + } + + return (0); +} + +static device_method_t ssi_pcm_methods[] = { + DEVMETHOD(device_probe, ssi_probe), + DEVMETHOD(device_attach, ssi_attach), + { 0, 0 } +}; + +static driver_t ssi_pcm_driver = { + "pcm", + ssi_pcm_methods, + PCM_SOFTC_SIZE, +}; + +DRIVER_MODULE(ssi, simplebus, ssi_pcm_driver, pcm_devclass, 0, 0); +MODULE_DEPEND(ssi, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); +MODULE_VERSION(ssi, 1); diff --git a/sys/arm/freescale/imx/imx_ccmvar.h b/sys/arm/freescale/imx/imx_ccmvar.h index 354e6163b45f..f15943791c68 100644 --- a/sys/arm/freescale/imx/imx_ccmvar.h +++ b/sys/arm/freescale/imx/imx_ccmvar.h @@ -51,5 +51,6 @@ uint32_t imx_ccm_ahb_hz(void); void imx_ccm_usb_enable(device_t _usbdev); void imx_ccm_usbphy_enable(device_t _phydev); +void imx_ccm_ssi_configure(device_t _ssidev); #endif diff --git a/sys/boot/fdt/dts/arm/apalis-imx6.dts b/sys/boot/fdt/dts/arm/apalis-imx6.dts index 0806f4e39815..b6440603c583 100644 --- a/sys/boot/fdt/dts/arm/apalis-imx6.dts +++ b/sys/boot/fdt/dts/arm/apalis-imx6.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Ruslan Bukin + * Copyright (c) 2014-2015 Ruslan Bukin * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,6 +26,8 @@ * $FreeBSD$ */ +#include "imx6q-pinfunc.h" + /dts-v1/; /include/ "imx6.dtsi" @@ -42,7 +44,20 @@ SOC: soc@00000000 { aips@02000000 { /* AIPS1 */ - iomux@020e0000 { status = "okay"; }; + iomux@020e0000 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pins_ssi>; + pins_ssi: ssi { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT16__AUD5_TXC 0x130b0 + MX6QDL_PAD_DISP0_DAT17__AUD5_TXD 0x110b0 + MX6QDL_PAD_DISP0_DAT18__AUD5_TXFS 0x130b0 + MX6QDL_PAD_DISP0_DAT19__AUD5_RXD 0x130b0 + MX6QDL_PAD_GPIO_19__CCM_CLKO1 0x130b0 + >; + }; + }; gpio@0209c000 { status = "okay"; }; gpio@020a0000 { status = "okay"; }; gpio@020a4000 { status = "okay"; }; @@ -76,6 +91,7 @@ usdhc@02198000 { status = "disabled"; }; usdhc@0219c000 { status = "disabled"; }; audmux@021d8000 { status = "okay"; }; + i2c@021a0000 { status = "okay"; }; }; }; diff --git a/sys/boot/fdt/dts/arm/imx6.dtsi b/sys/boot/fdt/dts/arm/imx6.dtsi index c24bb81a004e..db8b44e53b26 100644 --- a/sys/boot/fdt/dts/arm/imx6.dtsi +++ b/sys/boot/fdt/dts/arm/imx6.dtsi @@ -126,11 +126,12 @@ gpt: timer@02098000 { compatible = "fsl,imx6q-gpt", "fsl,imx51-gpt"; reg = <0x02098000 0x4000>; - interrupt-parent = <&gic>; interrupts = <87>; + interrupt-parent = <&gic>; + interrupts = <87>; }; iomux@020e0000 { - compatible = "fsl,imx6q-iomux"; + compatible = "fsl,imx6q-iomuxc"; reg = <0x020e0000 0x4000>; interrupt-parent = <&gic>; interrupts = <32>; @@ -311,6 +312,9 @@ compatible = "fsl,imx6q-ssi"; reg = <0x02028000 0x4000>; interrupts = < 78 >; + dmas = <&sdma 37 1 0>, + <&sdma 38 1 0>; + dma-names = "rx", "tx"; status = "disabled"; }; From 3a9e3cd8d9759079220ebe0f13a1d1a8a458734e Mon Sep 17 00:00:00 2001 From: jilles Date: Sat, 24 Jan 2015 13:50:13 +0000 Subject: [PATCH 216/258] cp,mv,touch: Set timestamps with nanosecond precision. This uses utimensat(). --- bin/cp/utils.c | 11 +++--- bin/mv/mv.c | 9 +++-- usr.bin/touch/touch.c | 79 +++++++++++++++++++++---------------------- 3 files changed, 48 insertions(+), 51 deletions(-) diff --git a/bin/cp/utils.c b/bin/cp/utils.c index ad9695c08a13..e77a6c13a370 100644 --- a/bin/cp/utils.c +++ b/bin/cp/utils.c @@ -330,7 +330,7 @@ copy_special(struct stat *from_stat, int exists) int setfile(struct stat *fs, int fd) { - static struct timeval tv[2]; + static struct timespec tspec[2]; struct stat ts; int rval, gotstat, islink, fdval; @@ -340,10 +340,11 @@ setfile(struct stat *fs, int fd) fs->st_mode &= S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO; - TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atim); - TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtim); - if (islink ? lutimes(to.p_path, tv) : utimes(to.p_path, tv)) { - warn("%sutimes: %s", islink ? "l" : "", to.p_path); + tspec[0] = fs->st_atim; + tspec[1] = fs->st_mtim; + if (utimensat(AT_FDCWD, to.p_path, tspec, + islink ? AT_SYMLINK_NOFOLLOW : 0)) { + warn("utimensat: %s", to.p_path); rval = 1; } if (fdval ? fstat(fd, &ts) : diff --git a/bin/mv/mv.c b/bin/mv/mv.c index 3e832acbfdf0..999c8fc8af4c 100644 --- a/bin/mv/mv.c +++ b/bin/mv/mv.c @@ -273,7 +273,7 @@ do_move(const char *from, const char *to) static int fastcopy(const char *from, const char *to, struct stat *sbp) { - struct timeval tval[2]; + struct timespec ts[2]; static u_int blen = MAXPHYS; static char *bp = NULL; mode_t oldmode; @@ -350,10 +350,9 @@ err: if (unlink(to)) } else warn("%s: cannot stat", to); - tval[0].tv_sec = sbp->st_atime; - tval[1].tv_sec = sbp->st_mtime; - tval[0].tv_usec = tval[1].tv_usec = 0; - if (utimes(to, tval)) + ts[0] = sbp->st_atim; + ts[1] = sbp->st_mtim; + if (utimensat(AT_FDCWD, to, ts, 0)) warn("%s: set times", to); if (close(to_fd)) { diff --git a/usr.bin/touch/touch.c b/usr.bin/touch/touch.c index 4439c07eb43d..c8bfd28d692d 100644 --- a/usr.bin/touch/touch.c +++ b/usr.bin/touch/touch.c @@ -56,10 +56,10 @@ static const char sccsid[] = "@(#)touch.c 8.1 (Berkeley) 6/6/93"; #include #include -static void stime_arg1(const char *, struct timeval *); -static void stime_arg2(const char *, int, struct timeval *); -static void stime_darg(const char *, struct timeval *); -static void stime_file(const char *, struct timeval *); +static void stime_arg1(const char *, struct timespec *); +static void stime_arg2(const char *, int, struct timespec *); +static void stime_darg(const char *, struct timespec *); +static void stime_file(const char *, struct timespec *); static int timeoffset(const char *); static void usage(const char *); @@ -67,19 +67,17 @@ int main(int argc, char *argv[]) { struct stat sb; - struct timeval tv[2]; - int (*stat_f)(const char *, struct stat *); - int (*utimes_f)(const char *, const struct timeval *); + struct timespec ts[2]; + int atflag; int Aflag, aflag, cflag, mflag, ch, fd, len, rval, timeset; char *p; char *myname; myname = basename(argv[0]); Aflag = aflag = cflag = mflag = timeset = 0; - stat_f = stat; - utimes_f = utimes; - if (gettimeofday(&tv[0], NULL) == -1) - err(1, "gettimeofday"); + atflag = 0; + if (clock_gettime(CLOCK_REALTIME, &ts[0]) == -1) + err(1, "clock_gettime(CLOCK_REALTIME)"); while ((ch = getopt(argc, argv, "A:acd:fhmr:t:")) != -1) switch(ch) { @@ -94,26 +92,25 @@ main(int argc, char *argv[]) break; case 'd': timeset = 1; - stime_darg(optarg, tv); + stime_darg(optarg, ts); break; case 'f': /* No-op for compatibility. */ break; case 'h': cflag = 1; - stat_f = lstat; - utimes_f = lutimes; + atflag = AT_SYMLINK_NOFOLLOW; break; case 'm': mflag = 1; break; case 'r': timeset = 1; - stime_file(optarg, tv); + stime_file(optarg, ts); break; case 't': timeset = 1; - stime_arg1(optarg, tv); + stime_arg1(optarg, ts); break; default: usage(myname); @@ -132,9 +129,9 @@ main(int argc, char *argv[]) * that time once and for all here. */ if (aflag) - tv[0].tv_sec += Aflag; + ts[0].tv_sec += Aflag; if (mflag) - tv[1].tv_sec += Aflag; + ts[1].tv_sec += Aflag; Aflag = 0; /* done our job */ } } else { @@ -148,11 +145,11 @@ main(int argc, char *argv[]) len = p - argv[0]; if (*p == '\0' && (len == 8 || len == 10)) { timeset = 1; - stime_arg2(*argv++, len == 10, tv); + stime_arg2(*argv++, len == 10, ts); } } /* Both times default to the same. */ - tv[1] = tv[0]; + ts[1] = ts[0]; } if (*argv == NULL) @@ -163,7 +160,7 @@ main(int argc, char *argv[]) for (rval = 0; *argv; ++argv) { /* See if the file exists. */ - if (stat_f(*argv, &sb) != 0) { + if (fstatat(AT_FDCWD, *argv, &sb, atflag) != 0) { if (errno != ENOENT) { rval = 1; warn("%s", *argv); @@ -187,9 +184,9 @@ main(int argc, char *argv[]) } if (!aflag) - TIMESPEC_TO_TIMEVAL(&tv[0], &sb.st_atim); + ts[0] = sb.st_atim; if (!mflag) - TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtim); + ts[1] = sb.st_mtim; /* * We're adjusting the times based on the file times, not a @@ -197,17 +194,17 @@ main(int argc, char *argv[]) */ if (Aflag) { if (aflag) { - TIMESPEC_TO_TIMEVAL(&tv[0], &sb.st_atim); - tv[0].tv_sec += Aflag; + ts[0] = sb.st_atim; + ts[0].tv_sec += Aflag; } if (mflag) { - TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtim); - tv[1].tv_sec += Aflag; + ts[1] = sb.st_mtim; + ts[1].tv_sec += Aflag; } } - /* Try utimes(2). */ - if (!utimes_f(*argv, tv)) + /* Try utimensat(2). */ + if (!utimensat(AT_FDCWD, *argv, ts, atflag)) continue; /* If the user specified a time, nothing else we can do. */ @@ -223,7 +220,7 @@ main(int argc, char *argv[]) * The permission checks are different, too, in that the * ability to write the file is sufficient. Take a shot. */ - if (!utimes_f(*argv, NULL)) + if (!utimensat(AT_FDCWD, *argv, NULL, atflag)) continue; rval = 1; @@ -235,7 +232,7 @@ main(int argc, char *argv[]) #define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2; static void -stime_arg1(const char *arg, struct timeval *tvp) +stime_arg1(const char *arg, struct timespec *tvp) { time_t now; struct tm *t; @@ -291,7 +288,7 @@ stime_arg1(const char *arg, struct timeval *tvp) if (tvp[0].tv_sec == -1) goto terr; - tvp[0].tv_usec = tvp[1].tv_usec = 0; + tvp[0].tv_nsec = tvp[1].tv_nsec = 0; return; terr: @@ -299,7 +296,7 @@ stime_arg1(const char *arg, struct timeval *tvp) } static void -stime_arg2(const char *arg, int year, struct timeval *tvp) +stime_arg2(const char *arg, int year, struct timespec *tvp) { time_t now; struct tm *t; @@ -325,18 +322,18 @@ stime_arg2(const char *arg, int year, struct timeval *tvp) errx(1, "out of range or illegal time specification: MMDDhhmm[yy]"); - tvp[0].tv_usec = tvp[1].tv_usec = 0; + tvp[0].tv_nsec = tvp[1].tv_nsec = 0; } static void -stime_darg(const char *arg, struct timeval *tvp) +stime_darg(const char *arg, struct timespec *tvp) { struct tm t = { .tm_sec = 0 }; const char *fmt, *colon; char *p; int val, isutc = 0; - tvp[0].tv_usec = 0; + tvp[0].tv_nsec = 0; t.tm_isdst = -1; colon = strchr(arg, ':'); if (colon == NULL || strchr(colon + 1, ':') == NULL) @@ -349,9 +346,9 @@ stime_darg(const char *arg, struct timeval *tvp) /* POSIX: must have at least one digit after dot */ if ((*p == '.' || *p == ',') && isdigit((unsigned char)p[1])) { p++; - val = 100000; + val = 100000000; while (isdigit((unsigned char)*p)) { - tvp[0].tv_usec += val * (*p - '0'); + tvp[0].tv_nsec += val * (*p - '0'); p++; val /= 10; } @@ -403,14 +400,14 @@ timeoffset(const char *arg) } static void -stime_file(const char *fname, struct timeval *tvp) +stime_file(const char *fname, struct timespec *tsp) { struct stat sb; if (stat(fname, &sb)) err(1, "%s", fname); - TIMESPEC_TO_TIMEVAL(tvp, &sb.st_atim); - TIMESPEC_TO_TIMEVAL(tvp + 1, &sb.st_mtim); + tsp[0] = sb.st_atim; + tsp[1] = sb.st_mtim; } static void From 7cbc6347a2d46248dcfc9c9448ec6facdbd857cb Mon Sep 17 00:00:00 2001 From: kib Date: Sat, 24 Jan 2015 15:33:42 +0000 Subject: [PATCH 217/258] Avoid calling vmspace_free() while owning the process lock. Freeing of an vm space may require obtaining sleepable locks. Hold the process to keep the pointer valid, and change trylock to lock, since there is no longer two process locks owned simultaneously in vm_pageout_oom(). Note that after the process lock is dropped, process might exec, and no longer qualify as the owner of biggest vm space. In collaboration with: rstone Sponsored by: The FreeBSD Foundation MFC after: 1 week --- sys/vm/vm_pageout.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/sys/vm/vm_pageout.c b/sys/vm/vm_pageout.c index ca9d7f9a3b5b..c81290ca097d 100644 --- a/sys/vm/vm_pageout.c +++ b/sys/vm/vm_pageout.c @@ -1516,15 +1516,15 @@ vm_pageout_oom(int shortage) FOREACH_PROC_IN_SYSTEM(p) { int breakout; - if (PROC_TRYLOCK(p) == 0) - continue; + PROC_LOCK(p); + /* * If this is a system, protected or killed process, skip it. */ - if (p->p_state != PRS_NORMAL || - (p->p_flag & (P_INEXEC | P_PROTECTED | P_SYSTEM)) || - (p->p_pid == 1) || P_KILLED(p) || - ((p->p_pid < 48) && (swap_pager_avail != 0))) { + if (p->p_state != PRS_NORMAL || (p->p_flag & (P_INEXEC | + P_PROTECTED | P_SYSTEM | P_WEXIT)) != 0 || + p->p_pid == 1 || P_KILLED(p) || + (p->p_pid < 48 && swap_pager_avail != 0)) { PROC_UNLOCK(p); continue; } @@ -1557,11 +1557,14 @@ vm_pageout_oom(int shortage) PROC_UNLOCK(p); continue; } + _PHOLD(p); if (!vm_map_trylock_read(&vm->vm_map)) { - vmspace_free(vm); + _PRELE(p); PROC_UNLOCK(p); + vmspace_free(vm); continue; } + PROC_UNLOCK(p); size = vmspace_swap_count(vm); vm_map_unlock_read(&vm->vm_map); if (shortage == VM_OOM_MEM) @@ -1573,16 +1576,19 @@ vm_pageout_oom(int shortage) */ if (size > bigsize) { if (bigproc != NULL) - PROC_UNLOCK(bigproc); + PRELE(bigproc); bigproc = p; bigsize = size; - } else - PROC_UNLOCK(p); + } else { + PRELE(p); + } } sx_sunlock(&allproc_lock); if (bigproc != NULL) { + PROC_LOCK(bigproc); killproc(bigproc, "out of swap space"); sched_nice(bigproc, PRIO_MIN); + _PRELE(bigproc); PROC_UNLOCK(bigproc); wakeup(&vm_cnt.v_free_count); } From 19d04ba8a14674ace732db65fc7c6a6367e94854 Mon Sep 17 00:00:00 2001 From: mav Date: Sat, 24 Jan 2015 15:40:52 +0000 Subject: [PATCH 218/258] Fix wrong LUN reference in XCOPY block-to-block operation. This could cause data corruption due to accessing wrong LUN in case of retries on write errors. Failed writes were retried to read LUN. MFC after: 3 days --- sys/cam/ctl/ctl_tpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/cam/ctl/ctl_tpc.c b/sys/cam/ctl/ctl_tpc.c index 4e67ce14d322..63aee278bb96 100644 --- a/sys/cam/ctl/ctl_tpc.c +++ b/sys/cam/ctl/ctl_tpc.c @@ -916,7 +916,7 @@ tpc_process_b2b(struct tpc_list *list) /*control*/ 0); tiow->io->io_hdr.retries = 3; tiow->lun = dl; - tiow->io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = tior; + tiow->io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = tiow; TAILQ_INSERT_TAIL(&tior->run, tiow, rlinks); TAILQ_INSERT_TAIL(prun, tior, rlinks); From 9dbba1ddabdba6f04969e6672a75762073b2babb Mon Sep 17 00:00:00 2001 From: jilles Date: Sat, 24 Jan 2015 15:49:40 +0000 Subject: [PATCH 219/258] Enable utimensat tests from NetBSD. As with other tests from c063, a required #include was missing. --- contrib/netbsd-tests/lib/libc/c063/t_utimensat.c | 3 +++ lib/libc/tests/c063/Makefile | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/contrib/netbsd-tests/lib/libc/c063/t_utimensat.c b/contrib/netbsd-tests/lib/libc/c063/t_utimensat.c index 9f21fd6f126a..bbfa28bd01df 100644 --- a/contrib/netbsd-tests/lib/libc/c063/t_utimensat.c +++ b/contrib/netbsd-tests/lib/libc/c063/t_utimensat.c @@ -40,6 +40,9 @@ __RCSID("$NetBSD: t_utimensat.c,v 1.5 2013/03/17 04:46:06 jmmv Exp $"); #include #include #include +#ifdef __FreeBSD__ +#include +#endif #include #define DIR "dir" diff --git a/lib/libc/tests/c063/Makefile b/lib/libc/tests/c063/Makefile index 0b8f3b0974fc..5f4e1ca9c31f 100644 --- a/lib/libc/tests/c063/Makefile +++ b/lib/libc/tests/c063/Makefile @@ -2,7 +2,7 @@ TESTSDIR= ${TESTSBASE}/lib/libc/c063 -#TODO: t_o_search, t_utimensat +#TODO: t_o_search NETBSD_ATF_TESTS_C= faccessat NETBSD_ATF_TESTS_C+= fchmodat @@ -18,6 +18,7 @@ NETBSD_ATF_TESTS_C+= readlinkat NETBSD_ATF_TESTS_C+= renameat NETBSD_ATF_TESTS_C+= symlinkat NETBSD_ATF_TESTS_C+= unlinkat +NETBSD_ATF_TESTS_C+= utimensat CFLAGS+= -D_INCOMPLETE_XOPEN_C063 From 520ad845550c500350a7667fb69591ae7ac395c5 Mon Sep 17 00:00:00 2001 From: rstone Date: Sat, 24 Jan 2015 16:59:38 +0000 Subject: [PATCH 220/258] vmspace_release() may sleep if the last reference is being released, so add a WITNESS_WARN() to catch cases where it is called with a non-sleepable lock held. MFC after: 1 month Sponsored by: Sandvine Inc. --- sys/vm/vm_map.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index b8d67bd30a3e..b7e668b928b0 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -344,6 +344,9 @@ void vmspace_free(struct vmspace *vm) { + WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, + "vmspace_free() called with non-sleepable lock held"); + if (vm->vm_refcnt == 0) panic("vmspace_free: attempt to free already freed vmspace"); From c16f446f6c0823691b1e8f7ab8cbb9084b5d5e7c Mon Sep 17 00:00:00 2001 From: will Date: Sat, 24 Jan 2015 17:11:11 +0000 Subject: [PATCH 221/258] Add tests/etc/rc.d to mtree. Submitted by: stefanf MFC after: 1 week MFC with: 277627 --- etc/mtree/BSD.tests.dist | 2 ++ 1 file changed, 2 insertions(+) diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist index c43f1aea48dc..7ea2155d3727 100644 --- a/etc/mtree/BSD.tests.dist +++ b/etc/mtree/BSD.tests.dist @@ -52,6 +52,8 @@ .. .. etc + rc.d + .. .. games .. From 2e062600fe2beb07bf5fe1884d91d576a21ce714 Mon Sep 17 00:00:00 2001 From: will Date: Sat, 24 Jan 2015 17:32:45 +0000 Subject: [PATCH 222/258] Add vm.panic_on_oom sysctl, which enables those who would rather panic than kill a process, when the system runs out of memory. Defaults to off. Usually, this is most useful when the OOM condition is due to mismanagement of memory, on a system where the applications in question don't respond well to being killed. In theory, if the system is properly managed, it shouldn't be possible to hit this condition. If it does, the panic can be more desirable for some users (since it can be a good means of finding the root cause) rather than killing the largest process and continuing on its merry way. As kib@ mentions in the differential, there is also protect(1), which uses procctl(PROC_SPROTECT) to ensure that some processes are immune. However, a panic approach is still useful in some environments. This is primarily intended as a development/debugging tool. Differential Revision: D1627 Reviewed by: kib MFC after: 1 week --- sys/vm/vm_pageout.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sys/vm/vm_pageout.c b/sys/vm/vm_pageout.c index c81290ca097d..ecc3dabfe70f 100644 --- a/sys/vm/vm_pageout.c +++ b/sys/vm/vm_pageout.c @@ -180,6 +180,12 @@ static int vm_swap_enabled = 1; static int vm_swap_idle_enabled = 0; #endif +static int vm_panic_on_oom = 0; + +SYSCTL_INT(_vm, OID_AUTO, panic_on_oom, + CTLFLAG_RWTUN, &vm_panic_on_oom, 0, + "panic on out of memory instead of killing the largest process"); + SYSCTL_INT(_vm, OID_AUTO, pageout_wakeup_thresh, CTLFLAG_RW, &vm_pageout_wakeup_thresh, 0, "free page threshold for waking up the pageout daemon"); @@ -1585,6 +1591,8 @@ vm_pageout_oom(int shortage) } sx_sunlock(&allproc_lock); if (bigproc != NULL) { + if (vm_panic_on_oom != 0) + panic("out of swap space"); PROC_LOCK(bigproc); killproc(bigproc, "out of swap space"); sched_nice(bigproc, PRIO_MIN); From d39bfa5fd5299b8181f53380bc339390ee74f1b4 Mon Sep 17 00:00:00 2001 From: bapt Date: Sat, 24 Jan 2015 19:13:03 +0000 Subject: [PATCH 223/258] Allow negative numbers in -u and -g options PR: 196514 MFC after: 1 week --- usr.sbin/pw/pw_group.c | 6 +++++- usr.sbin/pw/pw_user.c | 5 ++++- usr.sbin/pw/tests/Makefile | 4 +++- usr.sbin/pw/tests/pw_groupshow.sh | 19 +++++++++++++++++++ usr.sbin/pw/tests/pw_usershow.sh | 19 +++++++++++++++++++ 5 files changed, 50 insertions(+), 3 deletions(-) create mode 100755 usr.sbin/pw/tests/pw_groupshow.sh create mode 100755 usr.sbin/pw/tests/pw_usershow.sh diff --git a/usr.sbin/pw/pw_group.c b/usr.sbin/pw/pw_group.c index b20ce88fb301..51166cdebca5 100644 --- a/usr.sbin/pw/pw_group.c +++ b/usr.sbin/pw/pw_group.c @@ -68,7 +68,11 @@ pw_group(struct userconf * cnf, int mode, struct cargs * args) }; if (a_gid != NULL) { - if (strspn(a_gid->val, "0123456789") != strlen(a_gid->val)) + const char *teststr; + teststr = a_gid->val; + if (*teststr == '-') + teststr++; + if (strspn(teststr, "0123456789") != strlen(teststr)) errx(EX_USAGE, "-g expects a number"); } diff --git a/usr.sbin/pw/pw_user.c b/usr.sbin/pw/pw_user.c index 483148af4909..f146b464adb6 100644 --- a/usr.sbin/pw/pw_user.c +++ b/usr.sbin/pw/pw_user.c @@ -322,7 +322,10 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args) a_name = NULL; } } else { - if (strspn(a_uid->val, "0123456789") != strlen(a_uid->val)) + const char *teststr = a_uid->val; + if (*teststr == '-') + teststr++; + if (strspn(teststr, "0123456789") != strlen(teststr)) errx(EX_USAGE, "-u expects a number"); } diff --git a/usr.sbin/pw/tests/Makefile b/usr.sbin/pw/tests/Makefile index 1283ff2a7d27..c60988418222 100644 --- a/usr.sbin/pw/tests/Makefile +++ b/usr.sbin/pw/tests/Makefile @@ -9,9 +9,11 @@ ATF_TESTS_SH= pw_etcdir \ pw_lock \ pw_groupdel \ pw_groupmod \ + pw_groupshow \ pw_useradd \ pw_userdel \ - pw_usermod + pw_usermod \ + pw_usershow .for tp in ${ATF_TESTS_SH} TEST_METADATA.${tp}+= required_user="root" diff --git a/usr.sbin/pw/tests/pw_groupshow.sh b/usr.sbin/pw/tests/pw_groupshow.sh new file mode 100755 index 000000000000..2ba53d6ff19f --- /dev/null +++ b/usr.sbin/pw/tests/pw_groupshow.sh @@ -0,0 +1,19 @@ +# $FreeBSD$ + +# Import helper functions +. $(atf_get_srcdir)/helper_functions.shin + + +# Test negative uid are still valid +# PR: 196514 +atf_test_case show_group_with_negative_number +show_group_with_negative_number_body() { + populate_etc_skel + atf_check -s exit:0 \ + -o inline:"wheel:*:0:root\n" \ + ${PW} groupshow -n wheel -g -1 +} + +atf_init_test_cases() { + atf_add_test_case show_group_with_negative_number +} diff --git a/usr.sbin/pw/tests/pw_usershow.sh b/usr.sbin/pw/tests/pw_usershow.sh new file mode 100755 index 000000000000..4703644ca36c --- /dev/null +++ b/usr.sbin/pw/tests/pw_usershow.sh @@ -0,0 +1,19 @@ +# $FreeBSD$ + +# Import helper functions +. $(atf_get_srcdir)/helper_functions.shin + + +# Test negative uid are still valid +# PR: 196514 +atf_test_case show_user_with_negative_number +show_user_with_negative_number_body() { + populate_etc_skel + atf_check -s exit:0 \ + -o inline:"root:*:0:0::0:0:Charlie &:/root:/bin/csh\n" \ + ${PW} usershow -n root -u -1 +} + +atf_init_test_cases() { + atf_add_test_case show_user_with_negative_number +} From 6132573ef1a998e51342ddb35a6f7dcc2bd5f399 Mon Sep 17 00:00:00 2001 From: adrian Date: Sat, 24 Jan 2015 19:49:27 +0000 Subject: [PATCH 224/258] Change the permissions from 0660 to 0600. Otherwise people in wheel can do things with netmap, including but not limited to promisc transmit/receive. Approved by: luigi MFC after: 1 week --- sys/dev/netmap/netmap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c index 9369f6cf2a24..959b2703fc8f 100644 --- a/sys/dev/netmap/netmap.c +++ b/sys/dev/netmap/netmap.c @@ -3075,10 +3075,10 @@ netmap_init(void) #ifdef __FreeBSD__ /* support for the 'eternal' flag */ netmap_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, - &netmap_cdevsw, 0, NULL, UID_ROOT, GID_WHEEL, 0660, + &netmap_cdevsw, 0, NULL, UID_ROOT, GID_WHEEL, 0600, "netmap"); #else - netmap_dev = make_dev(&netmap_cdevsw, 0, UID_ROOT, GID_WHEEL, 0660, + netmap_dev = make_dev(&netmap_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "netmap"); #endif if (!netmap_dev) From b2d128e87b769bd326ea73352a7a68d9b7ca7256 Mon Sep 17 00:00:00 2001 From: ian Date: Sat, 24 Jan 2015 20:18:37 +0000 Subject: [PATCH 225/258] Reimplement fdt_clock_register_provider() correctly. It turns out you can't use OF_xref_from_device() to implement the function that registers the xref association with the device. Pointy hat: ian Submitted by: loos --- sys/dev/fdt/fdt_clock.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sys/dev/fdt/fdt_clock.c b/sys/dev/fdt/fdt_clock.c index e471523b8a2c..88c2ac4c63d8 100644 --- a/sys/dev/fdt/fdt_clock.c +++ b/sys/dev/fdt/fdt_clock.c @@ -149,7 +149,8 @@ void fdt_clock_register_provider(device_t provider) { - OF_device_register_xref(OF_xref_from_device(provider), provider); + OF_device_register_xref( + OF_xref_from_node(ofw_bus_get_node(provider)), provider); } void From 984840d5afc4461981c5bfc6a3ac5935278ee71a Mon Sep 17 00:00:00 2001 From: pfg Date: Sat, 24 Jan 2015 20:25:21 +0000 Subject: [PATCH 226/258] MFV: r277654 gdb: Add missing break statements 2004-05-21 Jim Blandy * dwarf2expr.c (execute_stack_op): Add 'break' statements after cases for DW_OP_div and DW_OP_shr. (Thanks to Reva Cuthbertson.) Sourceware commit 99c87dab95747d380392a3698740507a21ad3236 CID: 1008254 MFC after: 4 days --- contrib/gdb/gdb/dwarf2expr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contrib/gdb/gdb/dwarf2expr.c b/contrib/gdb/gdb/dwarf2expr.c index 50baced5f2e8..294afa06c63c 100644 --- a/contrib/gdb/gdb/dwarf2expr.c +++ b/contrib/gdb/gdb/dwarf2expr.c @@ -575,6 +575,7 @@ execute_stack_op (struct dwarf_expr_context *ctx, unsigned char *op_ptr, break; case DW_OP_div: binop = BINOP_DIV; + break; case DW_OP_minus: binop = BINOP_SUB; break; @@ -595,6 +596,7 @@ execute_stack_op (struct dwarf_expr_context *ctx, unsigned char *op_ptr, break; case DW_OP_shr: binop = BINOP_RSH; + break; case DW_OP_shra: binop = BINOP_RSH; val1 = value_from_longest (signed_address_type (), first); From 58730a3555d007a8209b6467769a9bf14886e32c Mon Sep 17 00:00:00 2001 From: pfg Date: Sat, 24 Jan 2015 21:05:18 +0000 Subject: [PATCH 227/258] MFV r277658: GDB: Replace use of sprintf. 2005-03-17 Mark Kettenis * corelow.c (get_core_register_section): Replace usage of sprintf and strcpy with xstrprintf and xstrdup. Sourceware commit: 3ecda4574edb38ad12fb491ccaf6d9b0caa3a07a CID: 1006819 MFC after: 4 days --- contrib/gdb/gdb/corelow.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/contrib/gdb/gdb/corelow.c b/contrib/gdb/gdb/corelow.c index 9e201cc548a0..5517e1d80dc0 100644 --- a/contrib/gdb/gdb/corelow.c +++ b/contrib/gdb/gdb/corelow.c @@ -432,15 +432,16 @@ get_core_register_section (char *name, char *human_name, int required) { - char section_name[100]; + static char *section_name = NULL; struct bfd_section *section; bfd_size_type size; char *contents; + xfree (section_name); if (PIDGET (inferior_ptid)) - sprintf (section_name, "%s/%d", name, PIDGET (inferior_ptid)); + section_name = xstrprintf ("%s/%d", name, PIDGET (inferior_ptid)); else - strcpy (section_name, name); + section_name = xstrdup (name); section = bfd_get_section_by_name (core_bfd, section_name); if (! section) From 20758e801e2b96a60ff0ac61ac87d47e9e935201 Mon Sep 17 00:00:00 2001 From: ngie Date: Sun, 25 Jan 2015 00:03:44 +0000 Subject: [PATCH 228/258] Add MK_EE knob to control installing edit, ee, etc MFC after: 2 weeks Sponsored by: EMC / Isilon Storage Division --- share/mk/src.opts.mk | 1 + tools/build/mk/OptionalObsoleteFiles.inc | 17 +++++++++++++++++ tools/build/options/WITHOUT_EE | 5 +++++ usr.bin/Makefile | 5 ++++- 4 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 tools/build/options/WITHOUT_EE diff --git a/share/mk/src.opts.mk b/share/mk/src.opts.mk index f8adc30c9634..b196e388059d 100644 --- a/share/mk/src.opts.mk +++ b/share/mk/src.opts.mk @@ -73,6 +73,7 @@ __DEFAULT_YES_OPTIONS = \ DMAGENT \ DYNAMICROOT \ ED_CRYPTO \ + EE \ ELFTOOLCHAIN_TOOLS \ EXAMPLES \ FDT \ diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc index 4f3b6e11d5ac..fe2897ef7219 100644 --- a/tools/build/mk/OptionalObsoleteFiles.inc +++ b/tools/build/mk/OptionalObsoleteFiles.inc @@ -1216,6 +1216,23 @@ OLD_FILES+=usr/share/dict/words OLD_DIRS+=usr/share/dict .endif +.if ${MK_EE} == no +OLD_FILES+=usr/bin/edit +OLD_FILES+=usr/bin/ee +OLD_FILES+=usr/bin/ree +OLD_FILES+=usr/share/man/man1/edit.1.gz +OLD_FILES+=usr/share/man/man1/ee.1.gz +OLD_FILES+=usr/share/man/man1/ree.1.gz +OLD_FILES+=usr/share/nls/C/ee.cat +OLD_FILES+=usr/share/nls/de_DE.ISO8859-1/ee.cat +OLD_FILES+=usr/share/nls/fr_FR.ISO8859-1/ee.cat +OLD_FILES+=usr/share/nls/hu_HU.ISO8859-2/ee.cat +OLD_FILES+=usr/share/nls/pl_PL.ISO8859-2/ee.cat +OLD_FILES+=usr/share/nls/pt_BR.ISO8859-1/ee.cat +OLD_FILES+=usr/share/nls/ru_RU.KOI8-R/ee.cat +OLD_FILES+=usr/share/nls/uk_UA.KOI8-U/ee.cat +.endif + .if ${MK_ELFTOOLCHAIN_TOOLS} == no OLD_FILES+=usr/bin/elfcopy OLD_FILES+=usr/share/man/man1/elfcopy.1.gz diff --git a/tools/build/options/WITHOUT_EE b/tools/build/options/WITHOUT_EE new file mode 100644 index 000000000000..721ddaab9df8 --- /dev/null +++ b/tools/build/options/WITHOUT_EE @@ -0,0 +1,5 @@ +.\" $FreeBSD$ +Set to not build and install +.Xr edit 1 , +.Xr ee 1 , +and related programs. diff --git a/usr.bin/Makefile b/usr.bin/Makefile index 2e54cdfaba09..7106db75e50a 100644 --- a/usr.bin/Makefile +++ b/usr.bin/Makefile @@ -40,7 +40,6 @@ SUBDIR= ${_addr2line} \ dirname \ dpv \ du \ - ee \ elf2aout \ ${_elfcopy} \ elfdump \ @@ -240,6 +239,10 @@ SUBDIR+= calendar _clang= clang .endif +.if ${MK_EE} != "no" +SUBDIR+= ee +.endif + .if ${MK_ELFTOOLCHAIN_TOOLS} != "no" _addr2line= addr2line _elfcopy= elfcopy From 51ac90809f77332c959522197ee46912e64cb52c Mon Sep 17 00:00:00 2001 From: ngie Date: Sun, 25 Jan 2015 00:30:22 +0000 Subject: [PATCH 229/258] Only build vi support into rescue if MK_VI != no Sponsored by: EMC / Isilon Storage Division --- rescue/rescue/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rescue/rescue/Makefile b/rescue/rescue/Makefile index e08ec2953f1f..cb4422d4528b 100644 --- a/rescue/rescue/Makefile +++ b/rescue/rescue/Makefile @@ -199,8 +199,10 @@ CRUNCH_LIBS+= -lcrypto .endif CRUNCH_LIBS+= -lmd +.if ${MK_VI} != "no" CRUNCH_PROGS_usr.bin+= vi CRUNCH_ALIAS_vi= ex +.endif CRUNCH_PROGS_usr.bin+= id CRUNCH_ALIAS_id= groups whoami From d14b227ab5d3ce2f8f4471702d14d0eca2c81683 Mon Sep 17 00:00:00 2001 From: ngie Date: Sun, 25 Jan 2015 00:32:17 +0000 Subject: [PATCH 230/258] Only build share/dtrace if MK_CDDL != no MFC after: 1 week Sponsored by: EMC / Isilon Storage Division --- share/Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/share/Makefile b/share/Makefile index 63c18bb6464a..97d1dac540ca 100644 --- a/share/Makefile +++ b/share/Makefile @@ -8,7 +8,7 @@ SUBDIR= ${_colldef} \ ${_dict} \ ${_doc} \ - dtrace \ + ${_dtrace} \ ${_examples} \ ${_i18n} \ keys \ @@ -37,6 +37,10 @@ SUBDIR= ${_colldef} \ _snmp= snmp .endif +.if ${MK_CDDL} != "no" +_dtrace= dtrace +.endif + .if ${MK_DICT} != "no" _dict= dict .endif From 054aba9acd5684d6e8eb1857c351530437afc0fe Mon Sep 17 00:00:00 2001 From: markj Date: Sun, 25 Jan 2015 00:34:43 +0000 Subject: [PATCH 231/258] Ensure that we don't try to demangle a symbol name if we failed to look up the symbol. Add a test to exercise this code path. Reviewed by: adrian --- lib/libproc/proc_sym.c | 4 ++-- lib/libproc/tests/proc_test.c | 40 ++++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/lib/libproc/proc_sym.c b/lib/libproc/proc_sym.c index e52f8ff563ec..90d40a899c33 100644 --- a/lib/libproc/proc_sym.c +++ b/lib/libproc/proc_sym.c @@ -335,8 +335,8 @@ proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name, goto out; error = lookup_addr(e, symtabscn, symtabstridx, off, addr, &s, symcopy); - if (error == 0) - goto out; + if (error != 0) + goto err2; out: demangle(s, name, namesz); diff --git a/lib/libproc/tests/proc_test.c b/lib/libproc/tests/proc_test.c index 0242b5b5ee96..dbaace84f5a8 100644 --- a/lib/libproc/tests/proc_test.c +++ b/lib/libproc/tests/proc_test.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2014 Mark Johnston + * Copyright (c) 2014, 2015 Mark Johnston * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -295,6 +295,43 @@ ATF_TC_BODY(symbol_lookup, tc) proc_free(phdl); } +ATF_TC(symbol_lookup_fail); +ATF_TC_HEAD(symbol_lookup_fail, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify that proc_addr2sym() returns an error when given an offset " + "that it cannot resolve."); +} +ATF_TC_BODY(symbol_lookup_fail, tc) +{ + char symname[32]; + GElf_Sym sym; + struct proc_handle *phdl; + prmap_t *map; + int error; + + phdl = start_prog(tc, false); + + /* Initialize the rtld_db handle. */ + (void)proc_rdagent(phdl); + + map = proc_obj2map(phdl, target_prog_file); + ATF_REQUIRE_MSG(map != NULL, "failed to look up map for '%s'", + target_prog_file); + + /* + * We shouldn't be able to find symbols at the beginning of a mapped + * file. + */ + error = proc_addr2sym(phdl, map->pr_vaddr, symname, sizeof(symname), + &sym); + ATF_REQUIRE_MSG(error != 0, "unexpectedly found a symbol"); + + ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution"); + + proc_free(phdl); +} + ATF_TC(signal_forward); ATF_TC_HEAD(signal_forward, tc) { @@ -343,6 +380,7 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, map_alias_name2map); ATF_TP_ADD_TC(tp, map_alias_name2sym); ATF_TP_ADD_TC(tp, symbol_lookup); + ATF_TP_ADD_TC(tp, symbol_lookup_fail); ATF_TP_ADD_TC(tp, signal_forward); return (atf_no_error()); From ff6d41472cb33ca8ba6156edf06009c5eeea42b4 Mon Sep 17 00:00:00 2001 From: markj Date: Sun, 25 Jan 2015 00:36:42 +0000 Subject: [PATCH 232/258] Document the fact that modules declared with SYSCALL_MODULE(9) have their names prefixed with "sys/". MFC after: 3 days --- share/man/man9/SYSCALL_MODULE.9 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/share/man/man9/SYSCALL_MODULE.9 b/share/man/man9/SYSCALL_MODULE.9 index b803bcec11e3..eb90aeb08326 100644 --- a/share/man/man9/SYSCALL_MODULE.9 +++ b/share/man/man9/SYSCALL_MODULE.9 @@ -28,7 +28,7 @@ .\" .\" $FreeBSD$ .\" -.Dd January 7, 2005 +.Dd January 24, 2015 .Dt SYSCALL_MODULE 9 .Os .Sh NAME @@ -46,8 +46,8 @@ The .Fn SYSCALL_MODULE macro declares a new syscall. .Fn SYSCALL_MODULE -expands into a kernel module declaration named as -.Fa name . +expands into a kernel module declaration with name +.Ql sys/ Ns Fa name . .Pp The rest of the arguments expected by this macro are: .Bl -tag -width ".Fa new_sysent" From 944cc17639fd03cbfc73af721b0c46b686d3f6c9 Mon Sep 17 00:00:00 2001 From: markj Date: Sun, 25 Jan 2015 00:47:06 +0000 Subject: [PATCH 233/258] gr_equal(): Fix a crash that could occur if the first group's member list was longer than the second's. There is no need to compute and compare the member list lengths in a separate pass, since we now just return false when comparing member names if the list lengths are not equal. MFC after: 2 weeks --- lib/libutil/gr_util.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/lib/libutil/gr_util.c b/lib/libutil/gr_util.c index 465efd982423..b0b0b36f0818 100644 --- a/lib/libutil/gr_util.c +++ b/lib/libutil/gr_util.c @@ -351,8 +351,6 @@ gr_fini(void) int gr_equal(const struct group *gr1, const struct group *gr2) { - int gr1_ndx; - int gr2_ndx; /* Check that the non-member information is the same. */ if (gr1->gr_name == NULL || gr2->gr_name == NULL) { @@ -368,7 +366,8 @@ gr_equal(const struct group *gr1, const struct group *gr2) if (gr1->gr_gid != gr2->gr_gid) return (false); - /* Check all members in both groups. + /* + * Check all members in both groups. * getgrnam can return gr_mem with a pointer to NULL. * gr_dup and gr_add strip out this superfluous NULL, setting * gr_mem to NULL for no members. @@ -376,22 +375,18 @@ gr_equal(const struct group *gr1, const struct group *gr2) if (gr1->gr_mem != NULL && gr2->gr_mem != NULL) { int i; - for (i = 0; gr1->gr_mem[i] != NULL; i++) { + for (i = 0; + gr1->gr_mem[i] != NULL && gr2->gr_mem[i] != NULL; i++) { if (strcmp(gr1->gr_mem[i], gr2->gr_mem[i]) != 0) return (false); } - } - /* Count number of members in both structs */ - gr2_ndx = 0; - if (gr2->gr_mem != NULL) - for(; gr2->gr_mem[gr2_ndx] != NULL; gr2_ndx++) - /* empty */; - gr1_ndx = 0; - if (gr1->gr_mem != NULL) - for(; gr1->gr_mem[gr1_ndx] != NULL; gr1_ndx++) - /* empty */; - if (gr1_ndx != gr2_ndx) + if (gr1->gr_mem[i] != NULL || gr2->gr_mem[i] != NULL) + return (false); + } else if (gr1->gr_mem != NULL && gr1->gr_mem[0] != NULL) { return (false); + } else if (gr2->gr_mem != NULL && gr2->gr_mem[0] != NULL) { + return (false); + } return (true); } From a0cd5317f225a81a46816691e7edf44ff8c29de5 Mon Sep 17 00:00:00 2001 From: ngie Date: Sun, 25 Jan 2015 03:08:21 +0000 Subject: [PATCH 234/258] Fix building rcorder with -DDEBUG by using libutil.h instead of util.h from usr.bin/make MFC after: 1 week Sponsored by: EMC / Isilon Storage Division --- sbin/rcorder/Makefile | 9 ++------- sbin/rcorder/rcorder.c | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/sbin/rcorder/Makefile b/sbin/rcorder/Makefile index 50e797f4cc43..2f1bbac1fa8f 100644 --- a/sbin/rcorder/Makefile +++ b/sbin/rcorder/Makefile @@ -7,13 +7,8 @@ MAN= rcorder.8 LIBADD= util -# XXX hack for make's hash.[ch] -CFLAGS+= -DORDER -I. +CFLAGS+= -DORDER -SRCS+= util.h -CLEANFILES+= util.h - -util.h: - ln -sf ${.CURDIR}/../../lib/libutil/libutil.h ${.TARGET} +#CFLAGS+= -DDEBUG .include diff --git a/sbin/rcorder/rcorder.c b/sbin/rcorder/rcorder.c index 83f6df839682..8c46b4fd1def 100644 --- a/sbin/rcorder/rcorder.c +++ b/sbin/rcorder/rcorder.c @@ -42,10 +42,10 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include -#include #include "ealloc.h" #include "sprite.h" From 29002c447a2be3066b7fa926c39a37caedd45c4f Mon Sep 17 00:00:00 2001 From: ngie Date: Sun, 25 Jan 2015 04:20:11 +0000 Subject: [PATCH 235/258] Add MK_ISCSI knob for building the iscsi initiator, iscsi daemon, kernel modules, etc MFC after: 2 weeks Sponsored by: EMC / Isilon Storage Division --- etc/rc.d/Makefile | 7 +++++-- sbin/Makefile | 5 ++++- share/man/man4/Makefile | 8 ++++++-- share/mk/src.opts.mk | 1 + sys/conf/kern.opts.mk | 1 + sys/modules/Makefile | 7 +++++-- tools/build/mk/OptionalObsoleteFiles.inc | 14 ++++++++++++++ tools/build/options/WITHOUT_ISCSI | 4 ++++ usr.bin/Makefile | 5 ++++- usr.sbin/Makefile | 5 ++++- 10 files changed, 48 insertions(+), 9 deletions(-) create mode 100644 tools/build/options/WITHOUT_ISCSI diff --git a/etc/rc.d/Makefile b/etc/rc.d/Makefile index 4994e9da8aa8..bb10868ad4fd 100644 --- a/etc/rc.d/Makefile +++ b/etc/rc.d/Makefile @@ -66,8 +66,6 @@ FILES= DAEMON \ ipropd_master \ ipropd_slave \ ipsec \ - iscsictl \ - iscsid \ jail \ ${_kadmind} \ ${_kdc} \ @@ -174,6 +172,11 @@ _ubthidhci= ubthidhci _casperd= casperd .endif +.if ${MK_ISCSI} != "no" +FILES+= iscsictl +FILES+= iscsid +.endif + .if ${MK_NS_CACHING} != "no" _nscd= nscd .endif diff --git a/sbin/Makefile b/sbin/Makefile index 3725270c4c3f..ae0db296e48e 100644 --- a/sbin/Makefile +++ b/sbin/Makefile @@ -35,7 +35,6 @@ SUBDIR=adjkerntz \ hastd \ ifconfig \ init \ - iscontrol \ kldconfig \ kldload \ kldstat \ @@ -109,6 +108,10 @@ SUBDIR+= pflogd SUBDIR+= ping6 SUBDIR+= rtsol .endif + +.if ${MK_ISCSI} != "no" +SUBDIR+= iscontrol +.endif .if ${MK_QUOTAS} != "no" SUBDIR+= quotacheck diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index ffedc0fca451..5c07303670ca 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -206,8 +206,6 @@ MAN= aac.4 \ ipw.4 \ ipwfw.4 \ isci.4 \ - iscsi.4 \ - iscsi_initiator.4 \ ismt.4 \ isp.4 \ ispfw.4 \ @@ -860,6 +858,12 @@ _nvram2env.4= nvram2env.4 SUBDIR= man4.${MACHINE_CPUARCH} .endif +.if ${MK_ISCSI} != "no" +MAN+= iscsi.4 +MAN+= iscsi_initiator.4 + +.endif + .if ${MK_TESTS} != "no" ATF= ${.CURDIR}/../../../contrib/atf .PATH: ${ATF}/doc diff --git a/share/mk/src.opts.mk b/share/mk/src.opts.mk index b196e388059d..fc29acee1711 100644 --- a/share/mk/src.opts.mk +++ b/share/mk/src.opts.mk @@ -97,6 +97,7 @@ __DEFAULT_YES_OPTIONS = \ INET6 \ IPFILTER \ IPFW \ + ISCSI \ JAIL \ KDUMP \ KVM \ diff --git a/sys/conf/kern.opts.mk b/sys/conf/kern.opts.mk index 16bb13447a71..63e8510e4fac 100644 --- a/sys/conf/kern.opts.mk +++ b/sys/conf/kern.opts.mk @@ -30,6 +30,7 @@ __DEFAULT_YES_OPTIONS = \ INET \ INET6 \ IPFILTER \ + ISCSI \ KERNEL_SYMBOLS \ NETGRAPH \ PF \ diff --git a/sys/modules/Makefile b/sys/modules/Makefile index 211c8e7508ca..aedb6d09404c 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -169,8 +169,6 @@ SUBDIR= \ ${_ipw} \ ${_ipwfw} \ ${_isci} \ - iscsi \ - iscsi_initiator \ isp \ ${_ispfw} \ ${_iwi} \ @@ -413,6 +411,11 @@ _ipfw= ipfw _ipfilter= ipfilter .endif +.if ${MK_ISCSI} != "no" || defined(ALL_MODULES) +SUBDIR+= iscsi +SUBDIR+= iscsi_initiator +.endif + .if ${MK_NAND} != "no" || defined(ALL_MODULES) _nandfs= nandfs _nandsim= nandsim diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc index fe2897ef7219..ceb81c9b34fc 100644 --- a/tools/build/mk/OptionalObsoleteFiles.inc +++ b/tools/build/mk/OptionalObsoleteFiles.inc @@ -2094,6 +2094,20 @@ OLD_FILES+=usr/share/man/man8/ipfwpcap.8.gz OLD_FILES+=usr/share/man/man8/natd.8.gz .endif +.if ${MK_ISCSI} == no +OLD_FILES+=etc/rc.d/iscsictl +OLD_FILES+=etc/rc.d/iscsid +OLD_FILES+=sbin/iscontrol +OLD_FILES+=usr/bin/iscsictl +OLD_FILES+=usr/sbin/iscsid +OLD_FILES+=usr/share/man/man4/iscsi.4.gz +OLD_FILES+=usr/share/man/man4/iscsi_initiator.4.gz +OLD_FILES+=usr/share/man/man5/iscsi.conf.5.gz +OLD_FILES+=usr/share/man/man8/iscontrol.8.gz +OLD_FILES+=usr/share/man/man8/iscsictl.8.gz +OLD_FILES+=usr/share/man/man8/iscsid.8.gz +.endif + .if ${MK_JAIL} == no OLD_FILES+=usr/sbin/jail OLD_FILES+=usr/sbin/jexec diff --git a/tools/build/options/WITHOUT_ISCSI b/tools/build/options/WITHOUT_ISCSI new file mode 100644 index 000000000000..83f3d7467ba6 --- /dev/null +++ b/tools/build/options/WITHOUT_ISCSI @@ -0,0 +1,4 @@ +.\" $FreeBSD$ +Set to not build +.Xr iscid 8 +and related utilities. diff --git a/usr.bin/Makefile b/usr.bin/Makefile index 7106db75e50a..fb12ef8f0dc2 100644 --- a/usr.bin/Makefile +++ b/usr.bin/Makefile @@ -69,7 +69,6 @@ SUBDIR= ${_addr2line} \ id \ ipcrm \ ipcs \ - iscsictl \ join \ jot \ ${_kdump} \ @@ -273,6 +272,10 @@ _mkcsmapper= mkcsmapper _mkesdb= mkesdb .endif +.if ${MK_ISCSI} != "no" +SUBDIR+= iscsictl +.endif + .if ${MK_KDUMP} != "no" SUBDIR+= kdump SUBDIR+= truss diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index 09e53adc9810..e1e20d44dc44 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -38,7 +38,6 @@ SUBDIR= adduser \ ifmcstat \ inetd \ iostat \ - iscsid \ kldxref \ mailwrapper \ makefs \ @@ -178,6 +177,10 @@ SUBDIR+= traceroute6 SUBDIR+= ipfwpcap .endif +.if ${MK_ISCSI} != "no" +SUBDIR+= iscsid +.endif + .if ${MK_JAIL} != "no" SUBDIR+= jail SUBDIR+= jexec From 21e793b32c614e38da078f83deaccb050e5875cb Mon Sep 17 00:00:00 2001 From: ngie Date: Sun, 25 Jan 2015 04:37:44 +0000 Subject: [PATCH 236/258] Add MK_TALK knob for building the talk and talkd MFC after: 2 weeks Sponsored by: EMC / Isilon Storage Division --- libexec/Makefile | 5 ++++- share/mk/src.opts.mk | 1 + tools/build/mk/OptionalObsoleteFiles.inc | 7 +++++++ tools/build/options/WITHOUT_TALK | 5 +++++ usr.bin/Makefile | 5 ++++- 5 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 tools/build/options/WITHOUT_TALK diff --git a/libexec/Makefile b/libexec/Makefile index 7d1c1f8ddae4..c8b5386678c4 100644 --- a/libexec/Makefile +++ b/libexec/Makefile @@ -28,7 +28,6 @@ SUBDIR= ${_atf} \ ${_rtld-elf} \ save-entropy \ ${_smrsh} \ - talkd \ tcpd \ ${_telnetd} \ ${_tests} \ @@ -81,6 +80,10 @@ _mail.local= mail.local _smrsh= smrsh .endif +.if ${MK_TALK} != "no" +SUBDIR+= talkd +.endif + .if ${MK_TELNET} != "no" _telnetd= telnetd .endif diff --git a/share/mk/src.opts.mk b/share/mk/src.opts.mk index fc29acee1711..126e7868c6fb 100644 --- a/share/mk/src.opts.mk +++ b/share/mk/src.opts.mk @@ -144,6 +144,7 @@ __DEFAULT_YES_OPTIONS = \ SYSCALL_COMPAT \ SYSCONS \ SYSINSTALL \ + TALK \ TCSH \ TELNET \ TESTS \ diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc index ceb81c9b34fc..1f326b4c829d 100644 --- a/tools/build/mk/OptionalObsoleteFiles.inc +++ b/tools/build/mk/OptionalObsoleteFiles.inc @@ -4073,6 +4073,13 @@ OLD_DIRS+=usr/share/doc/pjdfstest # to be filled in #.endif +.if ${MK_TALK} == no +OLD_FILES+=usr/bin/talk +OLD_FILES+=usr/libexec/ntalkd +OLD_FILES+=usr/share/man/man1/talk.1.gz +OLD_FILES+=usr/share/man/man8/talkd.8.gz +.endif + .if ${MK_TCSH} == no OLD_FILES+=bin/csh OLD_FILES+=bin/tcsh diff --git a/tools/build/options/WITHOUT_TALK b/tools/build/options/WITHOUT_TALK new file mode 100644 index 000000000000..33d41675000b --- /dev/null +++ b/tools/build/options/WITHOUT_TALK @@ -0,0 +1,5 @@ +.\" $FreeBSD$ +Set to not build or install +.Xr talk 1 +and +.Xr talkd 8 . diff --git a/usr.bin/Makefile b/usr.bin/Makefile index fb12ef8f0dc2..fbe87bd296d8 100644 --- a/usr.bin/Makefile +++ b/usr.bin/Makefile @@ -162,7 +162,6 @@ SUBDIR= ${_addr2line} \ systat \ tabs \ tail \ - talk \ tar \ tcopy \ tee \ @@ -348,6 +347,10 @@ SUBDIR+= rwho SUBDIR+= vacation .endif +.if ${MK_TALK} != "no" +SUBDIR+= talk +.endif + .if ${MK_TELNET} != "no" SUBDIR+= telnet .endif From b7d970adae001cb6bee81cfb7e348f39ed6c66d2 Mon Sep 17 00:00:00 2001 From: ngie Date: Sun, 25 Jan 2015 04:43:13 +0000 Subject: [PATCH 237/258] Add MK_BSDINSTALL knob for building and installing bsdinstall MFC after: 2 weeks Sponsored by: EMC / Isilon Storage Division --- share/mk/src.opts.mk | 1 + tools/build/mk/OptionalObsoleteFiles.inc | 33 ++++++++++++++++++++++++ tools/build/options/WITHOUT_BSDINSTALL | 5 ++++ usr.sbin/Makefile | 5 +++- 4 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 tools/build/options/WITHOUT_BSDINSTALL diff --git a/share/mk/src.opts.mk b/share/mk/src.opts.mk index 126e7868c6fb..0fcf0cc8a5b6 100644 --- a/share/mk/src.opts.mk +++ b/share/mk/src.opts.mk @@ -57,6 +57,7 @@ __DEFAULT_YES_OPTIONS = \ BLUETOOTH \ BOOT \ BSD_CPIO \ + BSDINSTALL \ BSNMP \ BZIP2 \ CALENDAR \ diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc index 1f326b4c829d..110275fd577a 100644 --- a/tools/build/mk/OptionalObsoleteFiles.inc +++ b/tools/build/mk/OptionalObsoleteFiles.inc @@ -274,6 +274,39 @@ OLD_FILES+=usr/share/man/man8/sdpd.8.gz # to be filled in #.endif +.if ${MK_BSDINSTALL} == no +OLD_FILES+=usr/libexec/bsdinstall/adduser +OLD_FILES+=usr/libexec/bsdinstall/auto +OLD_FILES+=usr/libexec/bsdinstall/autopart +OLD_FILES+=usr/libexec/bsdinstall/checksum +OLD_FILES+=usr/libexec/bsdinstall/config +OLD_FILES+=usr/libexec/bsdinstall/distextract +OLD_FILES+=usr/libexec/bsdinstall/distfetch +OLD_FILES+=usr/libexec/bsdinstall/docsinstall +OLD_FILES+=usr/libexec/bsdinstall/entropy +OLD_FILES+=usr/libexec/bsdinstall/hostname +OLD_FILES+=usr/libexec/bsdinstall/jail +OLD_FILES+=usr/libexec/bsdinstall/keymap +OLD_FILES+=usr/libexec/bsdinstall/mirrorselect +OLD_FILES+=usr/libexec/bsdinstall/mount +OLD_FILES+=usr/libexec/bsdinstall/netconfig +OLD_FILES+=usr/libexec/bsdinstall/netconfig_ipv4 +OLD_FILES+=usr/libexec/bsdinstall/netconfig_ipv6 +OLD_FILES+=usr/libexec/bsdinstall/partedit +OLD_FILES+=usr/libexec/bsdinstall/rootpass +OLD_FILES+=usr/libexec/bsdinstall/script +OLD_FILES+=usr/libexec/bsdinstall/scriptedpart +OLD_FILES+=usr/libexec/bsdinstall/services +OLD_FILES+=usr/libexec/bsdinstall/time +OLD_FILES+=usr/libexec/bsdinstall/umount +OLD_FILES+=usr/libexec/bsdinstall/wlanconfig +OLD_FILES+=usr/libexec/bsdinstall/zfsboot +OLD_FILES+=usr/sbin/bsdinstall +OLD_FILES+=usr/share/man/man8/bsdinstall.8.gz +OLD_FILES+=usr/share/man/man8/sade.8.gz +OLD_DIRS+=usr/libexec/bsdinstall +.endif + .if ${MK_CALENDAR} == no OLD_FILES+=etc/periodic/daily/300.calendar OLD_FILES+=usr/bin/calendar diff --git a/tools/build/options/WITHOUT_BSDINSTALL b/tools/build/options/WITHOUT_BSDINSTALL new file mode 100644 index 000000000000..8aaf2a6544ed --- /dev/null +++ b/tools/build/options/WITHOUT_BSDINSTALL @@ -0,0 +1,5 @@ +.\" $FreeBSD$ +Set to not build +.Xr bsdinstall 8 , +.Xr sade 8 , +and related programs. diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index e1e20d44dc44..1db40466657f 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -9,7 +9,6 @@ SUBDIR= adduser \ binmiscctl \ bootparamd \ bsdconfig \ - bsdinstall \ cdcontrol \ chkgrp \ chown \ @@ -129,6 +128,10 @@ SUBDIR+= authpf SUBDIR+= bluetooth .endif +.if ${MK_BSDINSTALL} != "no" +SUBDIR+= bsdinstall +.endif + .if ${MK_BSNMP} != "no" SUBDIR+= bsnmpd .endif From ed476849d331bd54d76f9e5652537bbb9fa233a4 Mon Sep 17 00:00:00 2001 From: ngie Date: Sun, 25 Jan 2015 04:52:48 +0000 Subject: [PATCH 238/258] Add MK_CCD knob for building and installing ccd(4), ccdconfig, etc MFC after: 2 weeks Sponsored by: EMC / Isilon Storage Division --- etc/rc.d/Makefile | 5 ++++- sbin/Makefile | 5 ++++- share/man/man4/Makefile | 6 +++++- share/mk/src.opts.mk | 1 + sys/conf/kern.opts.mk | 1 + sys/modules/geom/Makefile | 8 +++++++- tools/build/mk/OptionalObsoleteFiles.inc | 7 +++++++ tools/build/options/WITHOUT_CCD | 4 ++++ 8 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 tools/build/options/WITHOUT_CCD diff --git a/etc/rc.d/Makefile b/etc/rc.d/Makefile index bb10868ad4fd..465f3412d957 100644 --- a/etc/rc.d/Makefile +++ b/etc/rc.d/Makefile @@ -30,7 +30,6 @@ FILES= DAEMON \ bsnmpd \ ${_bthidd} \ ${_casperd} \ - ccd \ cleanvar \ cleartmp \ cron \ @@ -172,6 +171,10 @@ _ubthidhci= ubthidhci _casperd= casperd .endif +.if ${MK_CCD} != "no" +FILES+= ccd +.endif + .if ${MK_ISCSI} != "no" FILES+= iscsictl FILES+= iscsid diff --git a/sbin/Makefile b/sbin/Makefile index ae0db296e48e..1c34e0cc50f0 100644 --- a/sbin/Makefile +++ b/sbin/Makefile @@ -8,7 +8,6 @@ SUBDIR=adjkerntz \ badsect \ camcontrol \ - ccdconfig \ clri \ comcontrol \ conscontrol \ @@ -81,6 +80,10 @@ SUBDIR+= atm SUBDIR+= casperd .endif +.if ${MK_CCD} != "no" +SUBDIR+= ccdconfig +.endif + .if ${MK_CXX} != "no" SUBDIR+= devd .endif diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index 5c07303670ca..8bfd87572fec 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -91,7 +91,7 @@ MAN= aac.4 \ cc_htcp.4 \ cc_newreno.4 \ cc_vegas.4 \ - ccd.4 \ + ${_ccd.4} \ cd.4 \ cdce.4 \ ch.4 \ @@ -858,6 +858,10 @@ _nvram2env.4= nvram2env.4 SUBDIR= man4.${MACHINE_CPUARCH} .endif +.if ${MK_CCD} != "no" +_ccd.4= ccd.4 +.endif + .if ${MK_ISCSI} != "no" MAN+= iscsi.4 MAN+= iscsi_initiator.4 diff --git a/share/mk/src.opts.mk b/share/mk/src.opts.mk index 0fcf0cc8a5b6..8082b141527d 100644 --- a/share/mk/src.opts.mk +++ b/share/mk/src.opts.mk @@ -63,6 +63,7 @@ __DEFAULT_YES_OPTIONS = \ CALENDAR \ CAPSICUM \ CASPER \ + CCD \ CDDL \ CPP \ CROSS_COMPILER \ diff --git a/sys/conf/kern.opts.mk b/sys/conf/kern.opts.mk index 63e8510e4fac..8b3567928b8f 100644 --- a/sys/conf/kern.opts.mk +++ b/sys/conf/kern.opts.mk @@ -24,6 +24,7 @@ __DEFAULT_YES_OPTIONS = \ BLUETOOTH \ + CCD \ CDDL \ CRYPT \ FORMAT_EXTENSIONS \ diff --git a/sys/modules/geom/Makefile b/sys/modules/geom/Makefile index a94f7600505a..f54a3e83c8a1 100644 --- a/sys/modules/geom/Makefile +++ b/sys/modules/geom/Makefile @@ -1,8 +1,10 @@ # $FreeBSD$ +SYSDIR?=${.CURDIR}/../.. +.include "${SYSDIR}/conf/kern.opts.mk" + SUBDIR= geom_bde \ geom_cache \ - geom_ccd \ geom_concat \ geom_eli \ geom_gate \ @@ -25,4 +27,8 @@ SUBDIR= geom_bde \ geom_virstor \ geom_zero +.if ${MK_CCD} != "no" || defined(ALL_MODULES) +SUBDIR+= geom_ccd +.endif + .include diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc index 110275fd577a..66c331b21588 100644 --- a/tools/build/mk/OptionalObsoleteFiles.inc +++ b/tools/build/mk/OptionalObsoleteFiles.inc @@ -398,6 +398,13 @@ OLD_FILES+=sbin/casper OLD_FILES+=usr/lib/libcasper.a .endif +.if ${MK_CCD} == no +OLD_FILES+=etc/rc.d/ccd +OLD_FILES+=sbin/ccdconfig +OLD_FILES+=usr/share/man/man4/ccd.4.gz +OLD_FILES+=usr/share/man/man8/ccdconfig.8.gz +.endif + .if ${MK_CDDL} == no OLD_LIBS+=lib/libavl.so.2 OLD_LIBS+=lib/libctf.so.2 diff --git a/tools/build/options/WITHOUT_CCD b/tools/build/options/WITHOUT_CCD new file mode 100644 index 000000000000..b4d044ecaaa9 --- /dev/null +++ b/tools/build/options/WITHOUT_CCD @@ -0,0 +1,4 @@ +.\" $FreeBSD$ +Set to not build +.Xr geom_ccd 4 +and related utilities. From 41080ba6934763c33f32321415ad143a847598a6 Mon Sep 17 00:00:00 2001 From: ngie Date: Sun, 25 Jan 2015 04:56:43 +0000 Subject: [PATCH 239/258] Regen src.conf(5) --- share/man/man5/src.conf.5 | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/share/man/man5/src.conf.5 b/share/man/man5/src.conf.5 index f0910cb1de7a..ed806a403859 100644 --- a/share/man/man5/src.conf.5 +++ b/share/man/man5/src.conf.5 @@ -1,7 +1,7 @@ .\" DO NOT EDIT-- this file is automatically generated. .\" from FreeBSD: head/tools/build/options/makeman 255964 2013-10-01 07:22:04Z des .\" $FreeBSD$ -.Dd January 7, 2015 +.Dd January 24, 2015 .Dt SRC.CONF 5 .Os .Sh NAME @@ -142,6 +142,12 @@ Set to not build Bluetooth related kernel modules, programs and libraries. .It Va WITHOUT_BOOT .\" from FreeBSD: head/tools/build/options/WITHOUT_BOOT 156932 2006-03-21 07:50:50Z ru Set to not build the boot blocks and loader. +.It Va WITHOUT_BSDINSTALL +.\" from FreeBSD: head/tools/build/options/WITHOUT_BSDINSTALL 277677 2015-01-25 04:43:13Z ngie +Set to not build +.Xr bsdinstall 8 , +.Xr sade 8 , +and related programs. .It Va WITHOUT_BSD_CPIO .\" from FreeBSD: head/tools/build/options/WITHOUT_BSD_CPIO 179813 2008-06-16 05:48:15Z dougb Set to not build the BSD licensed version of cpio based on @@ -179,6 +185,11 @@ Set to not build Capsicum support into system programs. .It Va WITHOUT_CASPER .\" from FreeBSD: head/tools/build/options/WITHOUT_CASPER 258838 2013-12-02 08:21:28Z pjd Set to not build Casper program and related libraries. +.It Va WITHOUT_CCD +.\" from FreeBSD: head/tools/build/options/WITHOUT_CCD 277678 2015-01-25 04:52:48Z ngie +Set to not build +.Xr geom_ccd 4 +and related utilities. .It Va WITHOUT_CDDL .\" from FreeBSD: head/tools/build/options/WITHOUT_CDDL 163861 2006-11-01 09:02:11Z jb Set to not build code licensed under Sun's CDDL. @@ -218,13 +229,13 @@ unless an alternative compiler is provided via XCC. .Pp It is a default setting on -arm/armeb, mips/mipsel, mips/mips, mips/mips64el, mips/mips64, mips/mipsn32 and sparc64/sparc64. +arm/armeb, mips/mipsel, mips/mips, mips/mips64el, mips/mips64, mips/mipsn32, powerpc/powerpc, powerpc/powerpc64 and sparc64/sparc64. .It Va WITH_CLANG_BOOTSTRAP .\" from FreeBSD: head/tools/build/options/WITH_CLANG_BOOTSTRAP 264660 2014-04-18 17:03:58Z imp Set to build the Clang C/C++ compiler during the bootstrap phase of the build. .Pp It is a default setting on -amd64/amd64, arm/arm, arm/armv6, arm/armv6hf, i386/i386, pc98/i386, powerpc/powerpc and powerpc/powerpc64. +amd64/amd64, arm/arm, arm/armv6, arm/armv6hf, i386/i386 and pc98/i386. .It Va WITH_CLANG_EXTRAS .\" from FreeBSD: head/tools/build/options/WITH_CLANG_EXTRAS 231057 2012-02-05 23:56:22Z dim Set to build additional clang and llvm tools, such as bugpoint. @@ -380,6 +391,12 @@ dynamically. Set to build .Xr ed 1 without support for encryption/decryption. +.It Va WITHOUT_EE +.\" from FreeBSD: head/tools/build/options/WITHOUT_EE 277663 2015-01-25 00:03:44Z ngie +Set to not build and install +.Xr edit 1 , +.Xr ee 1 , +and related programs. .It Va WITH_EISA .\" from FreeBSD: head/tools/build/options/WITH_EISA 264654 2014-04-18 16:53:06Z imp Set to build EISA kernel modules. @@ -593,6 +610,11 @@ Set to not build IP Filter package. .It Va WITHOUT_IPFW .\" from FreeBSD: head/tools/build/options/WITHOUT_IPFW 183242 2008-09-21 22:02:26Z sam Set to not build IPFW tools. +.It Va WITHOUT_ISCSI +.\" from FreeBSD: head/tools/build/options/WITHOUT_ISCSI 277675 2015-01-25 04:20:11Z ngie +Set to not build +.Xr iscid 8 +and related utilities. .It Va WITHOUT_JAIL .\" from FreeBSD: head/tools/build/options/WITHOUT_JAIL 249966 2013-04-27 04:09:09Z eadler Set to not build tools for the support of jails; e.g., @@ -1035,6 +1057,12 @@ support files such as keyboard maps, fonts, and screen output maps. Set to not build .Xr sysinstall 8 and related programs. +.It Va WITHOUT_TALK +.\" from FreeBSD: head/tools/build/options/WITHOUT_TALK 277676 2015-01-25 04:37:44Z ngie +Set to not build or install +.Xr talk 1 +and +.Xr talkd 8 . .It Va WITHOUT_TCSH .\" from FreeBSD: head/tools/build/options/WITHOUT_TCSH 156932 2006-03-21 07:50:50Z ru Set to not build and install From eac68c5fc40633e827139fbe20ba05d0370361c6 Mon Sep 17 00:00:00 2001 From: imp Date: Sun, 25 Jan 2015 04:58:41 +0000 Subject: [PATCH 240/258] spl man page hasn't been relevant for a while, retire it. --- ObsoleteFiles.inc | 14 +++ share/man/man9/Makefile | 13 --- share/man/man9/spl.9 | 228 ---------------------------------------- 3 files changed, 14 insertions(+), 241 deletions(-) delete mode 100644 share/man/man9/spl.9 diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc index 271cbef2c53a..036e5d4cff24 100644 --- a/ObsoleteFiles.inc +++ b/ObsoleteFiles.inc @@ -38,6 +38,20 @@ # xargs -n1 | sort | uniq -d; # done +# 20150124: spl.9 and friends +OLD_FILES+=usr/share/man/man9/spl.9 +OLD_FILES+=usr/share/man/man9/spl0.9 +OLD_FILES+=usr/share/man/man9/splbio.9 +OLD_FILES+=usr/share/man/man9/splclock.9 +OLD_FILES+=usr/share/man/man9/splhigh.9 +OLD_FILES+=usr/share/man/man9/splimp.9 +OLD_FILES+=usr/share/man/man9/splnet.9 +OLD_FILES+=usr/share/man/man9/splsoftclock.9 +OLD_FILES+=usr/share/man/man9/splsofttty.9 +OLD_FILES+=usr/share/man/man9/splstatclock.9 +OLD_FILES+=usr/share/man/man9/spltty.9 +OLD_FILES+=usr/share/man/man9/splvm.9 +OLD_FILES+=usr/share/man/man9/splx.9 # 20150118: new clang import which bumps version from 3.5.0 to 3.5.1. OLD_FILES+=usr/include/clang/3.5.0/__wmmintrin_aes.h OLD_FILES+=usr/include/clang/3.5.0/__wmmintrin_pclmul.h diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile index cf64df7c811b..ddd46aaf3f13 100644 --- a/share/man/man9/Makefile +++ b/share/man/man9/Makefile @@ -252,7 +252,6 @@ MAN= accept_filter.9 \ sleep.9 \ sleepqueue.9 \ socket.9 \ - spl.9 \ stack.9 \ store.9 \ style.9 \ @@ -1447,18 +1446,6 @@ MLINKS+=socket.9 soabort.9 \ socket.9 soupcall_clear.9 \ socket.9 soupcall_set.9 \ socket.9 sowakeup.9 -MLINKS+=spl.9 spl0.9 \ - spl.9 splbio.9 \ - spl.9 splclock.9 \ - spl.9 splhigh.9 \ - spl.9 splimp.9 \ - spl.9 splnet.9 \ - spl.9 splsoftclock.9 \ - spl.9 splsofttty.9 \ - spl.9 splstatclock.9 \ - spl.9 spltty.9 \ - spl.9 splvm.9 \ - spl.9 splx.9 MLINKS+=stack.9 stack_copy.9 \ stack.9 stack_create.9 \ stack.9 stack_destroy.9 \ diff --git a/share/man/man9/spl.9 b/share/man/man9/spl.9 deleted file mode 100644 index 3bfa556d4b78..000000000000 --- a/share/man/man9/spl.9 +++ /dev/null @@ -1,228 +0,0 @@ -.\" -.\" Copyright (c) 1996 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 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 21, 1996 -.Dt SPL 9 -.Os -.Sh NAME -.Nm splbio , -.Nm splclock , -.Nm splhigh , -.Nm splimp , -.Nm splnet , -.Nm splsoftclock , -.Nm splsofttty , -.Nm splstatclock , -.Nm spltty , -.Nm splvm , -.Nm spl0 , -.Nm splx -.Nd manipulate interrupt priorities -.Sh SYNOPSIS -.In sys/types.h -.In sys/systm.h -.Ft intrmask_t -.Fn splbio "void" -.Ft intrmask_t -.Fn splclock "void" -.Ft intrmask_t -.Fn splhigh "void" -.Ft intrmask_t -.Fn splimp "void" -.Ft intrmask_t -.Fn splnet "void" -.Ft intrmask_t -.Fn splsoftclock "void" -.Ft intrmask_t -.Fn splsofttty "void" -.Ft intrmask_t -.Fn splstatclock "void" -.Ft intrmask_t -.Fn spltty "void" -.Ft void -.Fn spl0 "void" -.Ft void -.Fn splx "intrmask_t ipl" -.Sh DESCRIPTION -.Bf -symbolic -This API is deprecated. -Use mutexes to protect data structures instead. -See -.Xr mutex 9 -for more information. -The API is now a complete NOP. -This man page documents historical behavior so you can understand the -code locking that the spl did when converting code from versions of the -kernel prior to -.Fx 5.0 . -The examples in this man page are also obsolete and should not be viewed -as documenting -.Fx 5.0 -and newer. -.Ef -.Pp -The -.Fn spl -function family sets the interrupt priority -.Dq level -of the CPU. -This prevents interrupt handlers of the blocked priority level from -being run. -This is used in the -.Dq synchronous -part of a driver (the part that runs on behalf of the user process) to -examine or modify data areas that might be examined or modified by -interrupt handlers. -.Pp -Each driver that uses interrupts is normally assigned to an interrupt -priority group by a keyword in its config line. -For example: -.Bd -literal -offset indent -device foo0 at isa? port 0x0815 irq 12 tty -.Ed -.Pp -assigns interrupt 12 to the -.Dq tty -priority group. -The system automatically arranges for interrupts in -the -.Em xxx -group to be called at a priority >= -.Em spl Ns Fn xxx -.Pp -The function -.Fn splx -sets the interrupt priority to an absolute value. -The intent is that -the value returned by the other functions should be saved in a local -variable, and later passed to -.Fn splx -in order to restore the previous priority. -.Pp -The function -.Fn spl0 -lowers the priority to a value where all interrupt handlers are -unblocked, but ASTs (asynchronous system traps) remain blocked until -the system is about to return to user mode. -.Pp -The traditional assignment of the various device drivers to the -interrupt priority groups can be roughly classified as: -.Bl -tag -width Fn -.It Fn splnet -Software part of the network interface drivers. -.It Fn splimp -All network interface drivers. -.It Fn splbio -All -.Em buffered IO -(i.e., disk and the like) drivers. -.It Fn spltty -Basically, all non-network communications devices, but effectively -used for all drivers that are neither network nor disks. -.El -.Sh RETURN VALUES -All functions except -.Fn splx -and -.Fn spl0 -return the previous priority value. -.Sh EXAMPLES -This is a typical example demonstrating the usage: -.Bd -literal -struct foo_softc { - ... - int flags; -#define FOO_ASLEEP 1 -#define FOO_READY 2 - -} foo_softc[NFOO]; - -int -foowrite(...) -{ - struct foo_softc *sc; - int s, error; - - ... - s = spltty(); - if (!(sc->flags & FOO_READY)) { - /* Not ready, must sleep on resource. */ - sc->flags |= FOO_ASLEEP; - error = tsleep(sc, PZERO, "foordy", 0); - sc->flags &= ~FOO_ASLEEP; - } - sc->flags &= ~FOO_READY; - splx(s); - - ... -} - -void -foointr(...) -{ - struct foo_softc *sc; - - ... - sc->flags |= FOO_READY; - if (sc->flags & FOO_ASLEEP) - /* Somebody was waiting for us, awake him. */ - wakeup(sc); - ... -} - -.Ed -Note that the interrupt handler should -.Em never -reduce the priority level. -It is automatically called as it had -raised the interrupt priority to its own level, i.e., further interrupts -of the same group are being blocked. -.Sh HISTORY -The interrupt priority levels appeared in a very early version of -.Ux . -They have been traditionally known by number instead of by -names, and were inclusive up to higher priority levels (i.e., priority -5 has been blocking everything up to level 5). -This is no longer the case in -.Fx . -The traditional name -.Ql level -for them is still reflected in the letter -.Ql l -of the respective functions and variables, although they are not -really levels anymore, but rather different (partially inclusive) -sets of functions to be blocked during some periods of the life of -the system. -The historical number scheme can be considered as a -simple linearly ordered set of interrupt priority groups. -.Pp -.Fx 5.0 -eliminated spl entirely in favor of locking primitives which scale -to more than one processor. -.Sh AUTHORS -This manual page was written by -.An J\(:org Wunsch . From 4e2ad7cd0b4ab8b426d8b7d16395312b9befc2ee Mon Sep 17 00:00:00 2001 From: ngie Date: Sun, 25 Jan 2015 05:13:15 +0000 Subject: [PATCH 241/258] Build cuse(4) if MK_CUSE != no MFC after: 1 week Sponsored by: EMC / Isilon Storage Division --- sys/conf/kern.opts.mk | 1 + sys/modules/Makefile | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/sys/conf/kern.opts.mk b/sys/conf/kern.opts.mk index 8b3567928b8f..84e4e4f8b4e4 100644 --- a/sys/conf/kern.opts.mk +++ b/sys/conf/kern.opts.mk @@ -27,6 +27,7 @@ __DEFAULT_YES_OPTIONS = \ CCD \ CDDL \ CRYPT \ + CUSE \ FORMAT_EXTENSIONS \ INET \ INET6 \ diff --git a/sys/modules/Makefile b/sys/modules/Makefile index aedb6d09404c..5c7485684fda 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -86,7 +86,6 @@ SUBDIR= \ ${_ct} \ ${_ctau} \ ctl \ - cuse \ ${_cxgb} \ ${_cxgbe} \ dc \ @@ -393,6 +392,10 @@ _random= random .endif .endif +.if ${MK_CUSE} != "no" || defined(ALL_MODULES) +SUBDIR+= cuse +.endif + .if (${MK_INET_SUPPORT} != "no" || ${MK_INET6_SUPPORT} != "no") || \ defined(ALL_MODULES) _carp= carp From 6a0f226d1c3f817209bfbf69ab5ca82852977eac Mon Sep 17 00:00:00 2001 From: ngie Date: Sun, 25 Jan 2015 05:15:06 +0000 Subject: [PATCH 242/258] Make install cuse headers if MK_CUSE != no MFC after: 2 weeks Sponsored by: EMC / Isilon Storage Division --- include/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/Makefile b/include/Makefile index fa815272c2b8..e7da89bdd922 100644 --- a/include/Makefile +++ b/include/Makefile @@ -45,7 +45,6 @@ LSUBDIRS= cam/ata cam/scsi \ dev/ic dev/iicbus dev/io dev/lmc dev/mfi dev/nvme \ dev/ofw dev/pbio dev/pci ${_dev_powermac_nvram} dev/ppbus dev/smbus \ dev/speaker dev/usb dev/utopia dev/vkbd dev/wi \ - fs/cuse \ fs/devfs fs/fdescfs fs/msdosfs fs/nandfs fs/nfs fs/nullfs \ fs/procfs fs/smbfs fs/udf fs/unionfs \ geom/cache geom/concat geom/eli geom/gate geom/journal geom/label \ @@ -59,6 +58,10 @@ LSUBDIRS= cam/ata cam/scsi \ LSUBSUBDIRS= dev/mpt/mpilib +.if ${MK_CUSE} != "no" +LSUBDIRS+= fs/cuse +.endif + .if ${MACHINE_ARCH} == "powerpc" || ${MACHINE_ARCH} == "powerpc64" _dev_powermac_nvram= dev/powermac_nvram .endif From 52f67fd7d7e7b590294043d995f278b741599be4 Mon Sep 17 00:00:00 2001 From: ngie Date: Sun, 25 Jan 2015 05:15:45 +0000 Subject: [PATCH 243/258] Fill in entries for MK_CUSE == no MFC after: 1 week Sponsored by: EMC / Isilon Storage Division --- tools/build/mk/OptionalObsoleteFiles.inc | 37 ++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc index 66c331b21588..de4e87014803 100644 --- a/tools/build/mk/OptionalObsoleteFiles.inc +++ b/tools/build/mk/OptionalObsoleteFiles.inc @@ -649,6 +649,43 @@ OLD_FILES+=usr/share/man/man1/ctm_smail.1.gz OLD_FILES+=usr/share/man/man5/ctm.5.gz .endif +.if ${MK_CUSE} == no +OLD_FILES+=usr/include/fs/cuse/cuse_defs.h +OLD_FILES+=usr/include/fs/cuse/cuse_ioctl.h +OLD_FILES+=usr/include/cuse.h +OLD_FILES+=usr/lib/libcuse.a +OLD_LIBS+=usr/lib/libcuse.so.1 +OLD_FILES+=usr/lib/libcuse_p.a +OLD_FILES+=usr/share/man/man3/cuse.3.gz +OLD_FILES+=usr/share/man/man3/cuse_alloc_unit_number.3.gz +OLD_FILES+=usr/share/man/man3/cuse_alloc_unit_number_by_id.3.gz +OLD_FILES+=usr/share/man/man3/cuse_copy_in.3.gz +OLD_FILES+=usr/share/man/man3/cuse_copy_out.3.gz +OLD_FILES+=usr/share/man/man3/cuse_dev_create.3.gz +OLD_FILES+=usr/share/man/man3/cuse_dev_destroy.3.gz +OLD_FILES+=usr/share/man/man3/cuse_dev_get_current.3.gz +OLD_FILES+=usr/share/man/man3/cuse_dev_get_per_file_handle.3.gz +OLD_FILES+=usr/share/man/man3/cuse_dev_get_priv0.3.gz +OLD_FILES+=usr/share/man/man3/cuse_dev_get_priv1.3.gz +OLD_FILES+=usr/share/man/man3/cuse_dev_set_per_file_handle.3.gz +OLD_FILES+=usr/share/man/man3/cuse_dev_set_priv0.3.gz +OLD_FILES+=usr/share/man/man3/cuse_dev_set_priv1.3.gz +OLD_FILES+=usr/share/man/man3/cuse_free_unit_number.3.gz +OLD_FILES+=usr/share/man/man3/cuse_free_unit_number_by_id.3.gz +OLD_FILES+=usr/share/man/man3/cuse_get_local.3.gz +OLD_FILES+=usr/share/man/man3/cuse_got_peer_signal.3.gz +OLD_FILES+=usr/share/man/man3/cuse_init.3.gz +OLD_FILES+=usr/share/man/man3/cuse_is_vmalloc_addr.3.gz +OLD_FILES+=usr/share/man/man3/cuse_poll_wakeup.3.gz +OLD_FILES+=usr/share/man/man3/cuse_set_local.3.gz +OLD_FILES+=usr/share/man/man3/cuse_uninit.3.gz +OLD_FILES+=usr/share/man/man3/cuse_vmalloc.3.gz +OLD_FILES+=usr/share/man/man3/cuse_vmfree.3.gz +OLD_FILES+=usr/share/man/man3/cuse_vmoffset.3.gz +OLD_FILES+=usr/share/man/man3/cuse_wait_and_process.3.gz +OLD_DIRS+=usr/include/fs/cuse +.endif + # devd(8) not listed here on purpose .if ${MK_CXX} == no OLD_FILES+=usr/bin/CC From 6597c32b9b526c6733028b20a998b147823735f5 Mon Sep 17 00:00:00 2001 From: ngie Date: Sun, 25 Jan 2015 05:23:22 +0000 Subject: [PATCH 244/258] Fill in some dtrace entries when MK_CDDL == no MFC after: 1 week Sponsored by: EMC / Isilon Storage Division --- tools/build/mk/OptionalObsoleteFiles.inc | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc index de4e87014803..3c4b53a9024a 100644 --- a/tools/build/mk/OptionalObsoleteFiles.inc +++ b/tools/build/mk/OptionalObsoleteFiles.inc @@ -428,7 +428,6 @@ OLD_FILES+=usr/lib/dtrace/signal.d OLD_FILES+=usr/lib/dtrace/tcp.d OLD_FILES+=usr/lib/dtrace/udp.d OLD_FILES+=usr/lib/dtrace/unistd.d -OLD_DIRS+=usr/lib/dtrace OLD_FILES+=usr/lib/libavl.a OLD_FILES+=usr/lib/libavl.so OLD_FILES+=usr/lib/libavl_p.a @@ -449,7 +448,6 @@ OLD_FILES+=usr/lib/libuutil.so OLD_FILES+=usr/lib/libuutil_p.a .if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64" OLD_FILES+=usr/lib32/dtrace/drti.o -OLD_DIRS+=usr/lib32/dtrace OLD_FILES+=usr/lib32/libavl.a OLD_FILES+=usr/lib32/libavl.so OLD_LIBS+=usr/lib32/libavl.so.2 @@ -475,9 +473,24 @@ OLD_FILES+=usr/lib32/libuutil.so OLD_LIBS+=usr/lib32/libuutil.so.2 OLD_FILES+=usr/lib32/libuutil_p.a .endif +OLD_LIBS+=lib/libdtrace.so.2 OLD_FILES+=usr/sbin/dtrace OLD_FILES+=usr/sbin/lockstat OLD_FILES+=usr/share/man/man1/dtrace.1.gz +OLD_FILES+=usr/share/dtrace/disklatency +OLD_FILES+=usr/share/dtrace/disklatencycmd +OLD_FILES+=usr/share/dtrace/hotopen +OLD_FILES+=usr/share/dtrace/nfsclienttime +OLD_FILES+=usr/share/dtrace/toolkit/execsnoop +OLD_FILES+=usr/share/dtrace/toolkit/hotkernel +OLD_FILES+=usr/share/dtrace/toolkit/hotuser +OLD_FILES+=usr/share/dtrace/toolkit/opensnoop +OLD_FILES+=usr/share/dtrace/toolkit/procsystime +OLD_FILES+=usr/share/man/man1/dtrace.1.gz +OLD_DIRS+=usr/lib/dtrace +OLD_DIRS+=usr/lib32/dtrace +OLD_DIRS+=usr/share/dtrace/toolkit +OLD_DIRS+=usr/share/dtrace .endif .if ${MK_ZFS} == no From 03fee7baed93ff5c66f970b3b6d63b898e82145e Mon Sep 17 00:00:00 2001 From: ngie Date: Sun, 25 Jan 2015 05:30:03 +0000 Subject: [PATCH 245/258] Install bsnmp rc.d script if MK_BSNMP != no MFC after: 1 week Sponsored by: EMC / Isilon Storage Division --- etc/rc.d/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/etc/rc.d/Makefile b/etc/rc.d/Makefile index 465f3412d957..3cd07110323b 100644 --- a/etc/rc.d/Makefile +++ b/etc/rc.d/Makefile @@ -27,7 +27,6 @@ FILES= DAEMON \ ${_bluetooth} \ bootparams \ bridge \ - bsnmpd \ ${_bthidd} \ ${_casperd} \ cleanvar \ @@ -167,6 +166,10 @@ _hcsecd= hcsecd _ubthidhci= ubthidhci .endif +.if ${MK_BSNMP} != "no" +FILES+= bsnmpd +.endif + .if ${MK_CASPER} != "no" _casperd= casperd .endif From 28b578742c71e172021c6d46a141585e33da55da Mon Sep 17 00:00:00 2001 From: ngie Date: Sun, 25 Jan 2015 05:30:45 +0000 Subject: [PATCH 246/258] Fill in entries for MK_BSNMP == no MFC after: 1 week Sponsored by: EMC / Isilon Storage Division --- tools/build/mk/OptionalObsoleteFiles.inc | 93 ++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc index 3c4b53a9024a..77f4dd897ffc 100644 --- a/tools/build/mk/OptionalObsoleteFiles.inc +++ b/tools/build/mk/OptionalObsoleteFiles.inc @@ -307,6 +307,99 @@ OLD_FILES+=usr/share/man/man8/sade.8.gz OLD_DIRS+=usr/libexec/bsdinstall .endif +.if ${MK_BSNMP} == no +OLD_FILES+=etc/snmpd.config +OLD_FILES+=etc/rc.d/bsnmpd +OLD_FILES+=usr/bin/bsnmpget +OLD_FILES+=usr/bin/bsnmpset +OLD_FILES+=usr/bin/bsnmpwalk +OLD_FILES+=usr/include/bsnmp/asn1.h +OLD_FILES+=usr/include/bsnmp/bridge_snmp.h +OLD_FILES+=usr/include/bsnmp/snmp.h +OLD_FILES+=usr/include/bsnmp/snmp_atm.h +OLD_FILES+=usr/include/bsnmp/snmp_mibII.h +OLD_FILES+=usr/include/bsnmp/snmp_netgraph.h +OLD_FILES+=usr/include/bsnmp/snmpagent.h +OLD_FILES+=usr/include/bsnmp/snmpclient.h +OLD_FILES+=usr/include/bsnmp/snmpmod.h +OLD_FILES+=usr/lib/libbsnmp.a +OLD_LIBS+=usr/lib/libbsnmp.so.6 +OLD_FILES+=usr/lib/libbsnmp_p.a +OLD_FILES+=usr/lib/libbsnmptools.a +OLD_LIBS+=usr/lib/libbsnmptools.so.0 +OLD_FILES+=usr/lib/libbsnmptools_p.a +OLD_LIBS+=usr/lib/snmp_atm.so.6 +OLD_LIBS+=usr/lib/snmp_bridge.so.6 +OLD_LIBS+=usr/lib/snmp_hast.so.6 +OLD_LIBS+=usr/lib/snmp_hostres.so.6 +OLD_LIBS+=usr/lib/snmp_lm75.so.6 +OLD_LIBS+=usr/lib/snmp_mibII.so.6 +OLD_LIBS+=usr/lib/snmp_netgraph.so.6 +OLD_LIBS+=usr/lib/snmp_pf.so.6 +OLD_LIBS+=usr/lib/snmp_target.so.6 +OLD_LIBS+=usr/lib/snmp_usm.so.6 +OLD_LIBS+=usr/lib/snmp_vacm.so.6 +OLD_LIBS+=usr/lib/snmp_wlan.so.6 +OLD_FILES+=usr/sbin/bsnmpd +OLD_FILES+=usr/sbin/gensnmptree +OLD_FILES+=usr/share/man/man1/bsnmpd.1.gz +OLD_FILES+=usr/share/man/man1/bsnmpget.1.gz +OLD_FILES+=usr/share/man/man1/bsnmpset.1.gz +OLD_FILES+=usr/share/man/man1/bsnmpwalk.1.gz +OLD_FILES+=usr/share/man/man1/gensnmptree.1.gz +OLD_FILES+=usr/share/man/man3/asn1.3.gz +OLD_FILES+=usr/share/man/man3/bsnmpagent.3.gz +OLD_FILES+=usr/share/man/man3/bsnmpclient.3.gz +OLD_FILES+=usr/share/man/man3/bsnmplib.3.gz +OLD_FILES+=usr/share/man/man3/snmp_atm.3.gz +OLD_FILES+=usr/share/man/man3/snmp_bridge.3.gz +OLD_FILES+=usr/share/man/man3/snmp_hast.3.gz +OLD_FILES+=usr/share/man/man3/snmp_hostres.3.gz +OLD_FILES+=usr/share/man/man3/snmp_lm75.3.gz +OLD_FILES+=usr/share/man/man3/snmp_mibII.3.gz +OLD_FILES+=usr/share/man/man3/snmp_netgraph.3.gz +OLD_FILES+=usr/share/man/man3/snmp_target.3.gz +OLD_FILES+=usr/share/man/man3/snmp_usm.3.gz +OLD_FILES+=usr/share/man/man3/snmp_vacm.3.gz +OLD_FILES+=usr/share/man/man3/snmp_wlan.3.gz +OLD_FILES+=usr/share/man/man3/snmpmod.3.gz +OLD_FILES+=usr/share/snmp/defs/atm_freebsd.def +OLD_FILES+=usr/share/snmp/defs/atm_tree.def +OLD_FILES+=usr/share/snmp/defs/bridge_tree.def +OLD_FILES+=usr/share/snmp/defs/hast_tree.def +OLD_FILES+=usr/share/snmp/defs/hostres_tree.def +OLD_FILES+=usr/share/snmp/defs/lm75_tree.def +OLD_FILES+=usr/share/snmp/defs/mibII_tree.def +OLD_FILES+=usr/share/snmp/defs/netgraph_tree.def +OLD_FILES+=usr/share/snmp/defs/pf_tree.def +OLD_FILES+=usr/share/snmp/defs/target_tree.def +OLD_FILES+=usr/share/snmp/defs/tree.def +OLD_FILES+=usr/share/snmp/defs/usm_tree.def +OLD_FILES+=usr/share/snmp/defs/vacm_tree.def +OLD_FILES+=usr/share/snmp/defs/wlan_tree.def +OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-ATM-FREEBSD-MIB.txt +OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-ATM.txt +OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-BRIDGE-MIB.txt +OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-HAST-MIB.txt +OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-HOSTRES-MIB.txt +OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-IP-MIB.txt +OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-LM75-MIB.txt +OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-MIB.txt +OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-MIB2-MIB.txt +OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-NETGRAPH.txt +OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-PF-MIB.txt +OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-SNMPD.txt +OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-WIRELESS-MIB.txt +OLD_FILES+=usr/share/snmp/mibs/BRIDGE-MIB.txt +OLD_FILES+=usr/share/snmp/mibs/FOKUS-MIB.txt +OLD_FILES+=usr/share/snmp/mibs/FREEBSD-MIB.txt +OLD_FILES+=usr/share/snmp/mibs/RSTP-MIB.txt +OLD_DIRS+=usr/include/bsnmp +OLD_DIRS+=usr/share/snmp +OLD_DIRS+=usr/share/snmp/defs +OLD_DIRS+=usr/share/snmp/mibs +.endif + .if ${MK_CALENDAR} == no OLD_FILES+=etc/periodic/daily/300.calendar OLD_FILES+=usr/bin/calendar From 8210fdf7e3a63c7ad055eb2de16c2ece11c91675 Mon Sep 17 00:00:00 2001 From: ngie Date: Sun, 25 Jan 2015 05:37:06 +0000 Subject: [PATCH 247/258] Build lib/libgpio if MK_GPIO != no Fill in corresponding entries for MK_GPIO == no in OptionalObsoleteFiles.inc MFC after: 2 weeks Sponsored by: EMC / Isilon Storage Division --- lib/Makefile | 6 +++++- tools/build/mk/OptionalObsoleteFiles.inc | 25 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/lib/Makefile b/lib/Makefile index c51ae96b1c3d..83d9d636ee94 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -53,7 +53,7 @@ SUBDIR= ${SUBDIR_ORDERED} \ libfetch \ libfigpar \ libgeom \ - libgpio \ + ${_libgpio} \ ${_libgssapi} \ ${_librpcsec_gss} \ ${_libiconv_modules} \ @@ -195,6 +195,10 @@ _cuse= libcuse _libelftc= libelftc .endif +.if ${MK_GPIO} != "no" +_libgpio= libgpio +.endif + .if ${MK_GSSAPI} != "no" _libgssapi= libgssapi _librpcsec_gss= librpcsec_gss diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc index 77f4dd897ffc..ecd471199fdd 100644 --- a/tools/build/mk/OptionalObsoleteFiles.inc +++ b/tools/build/mk/OptionalObsoleteFiles.inc @@ -1550,7 +1550,32 @@ OLD_FILES+=usr/share/man/man1/kgdb.1.gz .endif .if ${MK_GPIO} == no +OLD_FILES+=usr/include/libgpio.h +OLD_FILES+=usr/lib/libgpio.a +OLD_LIBS+=usr/lib/libgpio.so.0 +OLD_FILES+=usr/lib/libgpio_p.a OLD_FILES+=usr/sbin/gpioctl +OLD_FILES+=usr/share/man/man3/gpio.3.gz +OLD_FILES+=usr/share/man/man3/gpio_close.3.gz +OLD_FILES+=usr/share/man/man3/gpio_open.3.gz +OLD_FILES+=usr/share/man/man3/gpio_open_device.3.gz +OLD_FILES+=usr/share/man/man3/gpio_pin_config.3.gz +OLD_FILES+=usr/share/man/man3/gpio_pin_get.3.gz +OLD_FILES+=usr/share/man/man3/gpio_pin_high.3.gz +OLD_FILES+=usr/share/man/man3/gpio_pin_input.3.gz +OLD_FILES+=usr/share/man/man3/gpio_pin_invin.3.gz +OLD_FILES+=usr/share/man/man3/gpio_pin_invout.3.gz +OLD_FILES+=usr/share/man/man3/gpio_pin_list.3.gz +OLD_FILES+=usr/share/man/man3/gpio_pin_low.3.gz +OLD_FILES+=usr/share/man/man3/gpio_pin_opendrain.3.gz +OLD_FILES+=usr/share/man/man3/gpio_pin_output.3.gz +OLD_FILES+=usr/share/man/man3/gpio_pin_pulldown.3.gz +OLD_FILES+=usr/share/man/man3/gpio_pin_pullup.3.gz +OLD_FILES+=usr/share/man/man3/gpio_pin_pulsate.3.gz +OLD_FILES+=usr/share/man/man3/gpio_pin_pushpull.3.gz +OLD_FILES+=usr/share/man/man3/gpio_pin_set.3.gz +OLD_FILES+=usr/share/man/man3/gpio_pin_set_flags.3.gz +OLD_FILES+=usr/share/man/man3/gpio_pin_tristate.3.gz OLD_FILES+=usr/share/man/man8/gpioctl.8.gz .endif From f968f0ce0e73b87f4111c1f78bc3521ec3bd9a01 Mon Sep 17 00:00:00 2001 From: des Date: Sun, 25 Jan 2015 11:57:18 +0000 Subject: [PATCH 248/258] Fix the font in the text version. This has bothered me for a long time... MFC after: 1 week --- sys/boot/forth/beastie.4th | 11 +++++------ sys/boot/forth/brand.4th | 3 +-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/sys/boot/forth/beastie.4th b/sys/boot/forth/beastie.4th index 8d2424408bbc..6512d739c271 100644 --- a/sys/boot/forth/beastie.4th +++ b/sys/boot/forth/beastie.4th @@ -89,7 +89,7 @@ variable logoY 0 25 at-xy ; -: fbsdbw-logo ( x y -- ) \ "FreeBSD" logo in B/W (13 rows x 21 columns) +: fbsdbw-logo ( x y -- ) \ "FreeBSD" logo in B/W (12 rows x 21 columns) \ We used to use the beastie himself as our default... until the \ eventual complaint derided his reign of the advanced boot-menu. @@ -106,17 +106,16 @@ variable logoY 5 + swap 6 + swap 2dup at-xy ." ______" 1+ - 2dup at-xy ." | ____| __ ___ ___ " 1+ - 2dup at-xy ." | |__ | '__/ _ \/ _ \" 1+ - 2dup at-xy ." | __|| | | __/ __/" 1+ - 2dup at-xy ." | | | | | | |" 1+ + 2dup at-xy ." | ____|" 1+ + 2dup at-xy ." | |__ _ __ ___ ___ " 1+ + 2dup at-xy ." | __|| '__/ _ \/ _ \" 1+ + 2dup at-xy ." | | | | | __/ __/" 1+ 2dup at-xy ." |_| |_| \___|\___|" 1+ 2dup at-xy ." ____ _____ _____" 1+ 2dup at-xy ." | _ \ / ____| __ \" 1+ 2dup at-xy ." | |_) | (___ | | | |" 1+ 2dup at-xy ." | _ < \___ \| | | |" 1+ 2dup at-xy ." | |_) |____) | |__| |" 1+ - 2dup at-xy ." | | | |" 1+ at-xy ." |____/|_____/|_____/" \ Put the cursor back at the bottom diff --git a/sys/boot/forth/brand.4th b/sys/boot/forth/brand.4th index 28d3c5c1d26f..3dda97cc3e2f 100644 --- a/sys/boot/forth/brand.4th +++ b/sys/boot/forth/brand.4th @@ -33,14 +33,13 @@ variable brandY 2 brandX ! 1 brandY ! -: fbsd-logo ( x y -- ) \ "FreeBSD" [wide] logo in B/W (7 rows x 42 columns) +: fbsd-logo ( x y -- ) \ "FreeBSD" [wide] logo in B/W (6 rows x 42 columns) 2dup at-xy ." ______ ____ _____ _____ " 1+ 2dup at-xy ." | ____| | _ \ / ____| __ \ " 1+ 2dup at-xy ." | |___ _ __ ___ ___ | |_) | (___ | | | |" 1+ 2dup at-xy ." | ___| '__/ _ \/ _ \| _ < \___ \| | | |" 1+ 2dup at-xy ." | | | | | __/ __/| |_) |____) | |__| |" 1+ - 2dup at-xy ." | | | | | | || | | |" 1+ at-xy ." |_| |_| \___|\___||____/|_____/|_____/ " \ Put the cursor back at the bottom From ffa2c78ca2854f13ee0f2bbd81d66a0541968b8c Mon Sep 17 00:00:00 2001 From: des Date: Sun, 25 Jan 2015 12:02:38 +0000 Subject: [PATCH 249/258] Remove ISA NICs. Anyone still using these on amd64 can build their own kernel. --- sys/amd64/conf/GENERIC | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC index 370ab10bba95..86891b7507f9 100644 --- a/sys/amd64/conf/GENERIC +++ b/sys/amd64/conf/GENERIC @@ -260,16 +260,6 @@ device vr # VIA Rhine, Rhine II device wb # Winbond W89C840F device xl # 3Com 3c90x (``Boomerang'', ``Cyclone'') -# ISA Ethernet NICs. pccard NICs included. -device cs # Crystal Semiconductor CS89x0 NIC -# 'device ed' requires 'device miibus' -device ed # NE[12]000, SMC Ultra, 3c503, DS8390 cards -device ex # Intel EtherExpress Pro/10 and Pro/10+ -device ep # Etherlink III based cards -device fe # Fujitsu MB8696x based cards -device sn # SMC's 9000 series of Ethernet chips -device xe # Xircom pccard Ethernet - # Wireless NIC cards device wlan # 802.11 support options IEEE80211_DEBUG # enable debug msgs From c3a22f55db5a43d2e7a21f3c9adfe17fd2b3f95f Mon Sep 17 00:00:00 2001 From: des Date: Sun, 25 Jan 2015 12:11:50 +0000 Subject: [PATCH 250/258] Allow tracing dlfunc() / dlsym() events. MFC after: 1 week --- libexec/rtld-elf/rtld.c | 17 +++++++++++++---- usr.bin/kdump/kdump.c | 9 +++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 5f449c138e11..7b19f5aa65c2 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -266,6 +266,8 @@ bool ld_library_path_rpath = false; #define UTRACE_PRELOAD_FINISHED 8 #define UTRACE_INIT_CALL 9 #define UTRACE_FINI_CALL 10 +#define UTRACE_DLSYM_START 11 +#define UTRACE_DLSYM_STOP 12 struct utrace_rtld { char sig[4]; /* 'RTLD' */ @@ -3099,6 +3101,7 @@ do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve, SymLook req; RtldLockState lockstate; tls_index ti; + void *sym; int res; def = NULL; @@ -3108,6 +3111,7 @@ do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve, req.flags = flags | SYMLOOK_IN_PLT; req.lockstate = &lockstate; + LD_UTRACE(UTRACE_DLSYM_START, handle, NULL, 0, 0, name); rlock_acquire(rtld_bind_lock, &lockstate); if (sigsetjmp(lockstate.env, 0) != 0) lock_upgrade(rtld_bind_lock, &lockstate); @@ -3117,6 +3121,7 @@ do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve, if ((obj = obj_from_addr(retaddr)) == NULL) { _rtld_error("Cannot determine caller's shared object"); lock_release(rtld_bind_lock, &lockstate); + LD_UTRACE(UTRACE_DLSYM_STOP, handle, NULL, 0, 0, name); return NULL; } if (handle == NULL) { /* Just the caller's shared object. */ @@ -3164,6 +3169,7 @@ do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve, } else { if ((obj = dlcheck(handle)) == NULL) { lock_release(rtld_bind_lock, &lockstate); + LD_UTRACE(UTRACE_DLSYM_STOP, handle, NULL, 0, 0, name); return NULL; } @@ -3207,19 +3213,22 @@ do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve, * symbol. */ if (ELF_ST_TYPE(def->st_info) == STT_FUNC) - return (make_function_pointer(def, defobj)); + sym = make_function_pointer(def, defobj); else if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) - return (rtld_resolve_ifunc(defobj, def)); + sym = rtld_resolve_ifunc(defobj, def); else if (ELF_ST_TYPE(def->st_info) == STT_TLS) { ti.ti_module = defobj->tlsindex; ti.ti_offset = def->st_value; - return (__tls_get_addr(&ti)); + sym = __tls_get_addr(&ti); } else - return (defobj->relocbase + def->st_value); + sym = defobj->relocbase + def->st_value; + LD_UTRACE(UTRACE_DLSYM_STOP, handle, sym, 0, 0, name); + return (sym); } _rtld_error("Undefined symbol \"%s\"", name); lock_release(rtld_bind_lock, &lockstate); + LD_UTRACE(UTRACE_DLSYM_STOP, handle, NULL, 0, 0, name); return NULL; } diff --git a/usr.bin/kdump/kdump.c b/usr.bin/kdump/kdump.c index 0daf7373cd19..b8e5903a0c8a 100644 --- a/usr.bin/kdump/kdump.c +++ b/usr.bin/kdump/kdump.c @@ -1531,6 +1531,8 @@ ktrcsw(struct ktr_csw *cs) #define UTRACE_PRELOAD_FINISHED 8 #define UTRACE_INIT_CALL 9 #define UTRACE_FINI_CALL 10 +#define UTRACE_DLSYM_START 11 +#define UTRACE_DLSYM_STOP 12 struct utrace_rtld { char sig[4]; /* 'RTLD' */ @@ -1610,6 +1612,13 @@ ktruser_rtld(int len, void *p) printf("RTLD: fini %p for %p (%s)\n", ut->mapbase, ut->handle, ut->name); break; + case UTRACE_DLSYM_START: + printf("RTLD: dlsym(%p, %s)\n", ut->handle, ut->name); + break; + case UTRACE_DLSYM_STOP: + printf("RTLD: %p = dlsym(%p, %s)\n", ut->mapbase, ut->handle, + ut->name); + break; default: cp = p; cp += 4; From 3fef9601c6ee3dca76a74c534be9f7ec338bbf2c Mon Sep 17 00:00:00 2001 From: des Date: Sun, 25 Jan 2015 15:44:46 +0000 Subject: [PATCH 251/258] Allow the user to specify the location of control.conf. --- etc/rc.d/local_unbound | 2 ++ 1 file changed, 2 insertions(+) diff --git a/etc/rc.d/local_unbound b/etc/rc.d/local_unbound index ed69c193d886..d8eef7dcba52 100755 --- a/etc/rc.d/local_unbound +++ b/etc/rc.d/local_unbound @@ -26,6 +26,7 @@ pidfile="/var/run/${name}.pid" : ${local_unbound_config:=${local_unbound_workdir}/unbound.conf} : ${local_unbound_flags:=-c${local_unbound_config}} : ${local_unbound_forwardconf:=${local_unbound_workdir}/forward.conf} +: ${local_unbound_controlconf:=${local_unbound_workdir}/control.conf} : ${local_unbound_anchor:=${local_unbound_workdir}/root.key} : ${local_unbound_forwarders:=} @@ -66,6 +67,7 @@ local_unbound_setup() -w ${local_unbound_workdir} \ -c ${local_unbound_config} \ -f ${local_unbound_forwardconf} \ + -o ${local_unbound_controlconf} \ -a ${local_unbound_anchor} \ ${local_unbound_forwarders} } From 35e00e3ca8ddb6e9696568f1ffa473f6817f650c Mon Sep 17 00:00:00 2001 From: jhb Date: Sun, 25 Jan 2015 19:45:44 +0000 Subject: [PATCH 252/258] Use an sbuf to generate the output of the net.inet.tcp.hostcache.list sysctl to avoid a possible buffer overflow if the cache grows while the text is being generated. PR: 172675 MFC after: 2 weeks --- sys/netinet/tcp_hostcache.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/sys/netinet/tcp_hostcache.c b/sys/netinet/tcp_hostcache.c index cbe24985a701..b03556ff67e0 100644 --- a/sys/netinet/tcp_hostcache.c +++ b/sys/netinet/tcp_hostcache.c @@ -73,6 +73,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -595,30 +596,27 @@ tcp_hc_update(struct in_conninfo *inc, struct hc_metrics_lite *hcml) static int sysctl_tcp_hc_list(SYSCTL_HANDLER_ARGS) { - int bufsize; int linesize = 128; - char *p, *buf; - int len, i, error; + struct sbuf sb; + int i, error; struct hc_metrics *hc_entry; #ifdef INET6 char ip6buf[INET6_ADDRSTRLEN]; #endif - bufsize = linesize * (V_tcp_hostcache.cache_count + 1); + sbuf_new(&sb, NULL, linesize * (V_tcp_hostcache.cache_count + 1), + SBUF_FIXEDLEN); - p = buf = (char *)malloc(bufsize, M_TEMP, M_WAITOK|M_ZERO); - - len = snprintf(p, linesize, - "\nIP address MTU SSTRESH RTT RTTVAR BANDWIDTH " + sbuf_printf(&sb, + "\nIP address MTU SSTRESH RTT RTTVAR BANDWIDTH " " CWND SENDPIPE RECVPIPE HITS UPD EXP\n"); - p += len; #define msec(u) (((u) + 500) / 1000) for (i = 0; i < V_tcp_hostcache.hashsize; i++) { THC_LOCK(&V_tcp_hostcache.hashbase[i].hch_mtx); TAILQ_FOREACH(hc_entry, &V_tcp_hostcache.hashbase[i].hch_bucket, rmx_q) { - len = snprintf(p, linesize, + sbuf_printf(&sb, "%-15s %5lu %8lu %6lums %6lums %9lu %8lu %8lu %8lu " "%4lu %4lu %4i\n", hc_entry->ip4.s_addr ? inet_ntoa(hc_entry->ip4) : @@ -640,13 +638,13 @@ sysctl_tcp_hc_list(SYSCTL_HANDLER_ARGS) hc_entry->rmx_hits, hc_entry->rmx_updates, hc_entry->rmx_expire); - p += len; } THC_UNLOCK(&V_tcp_hostcache.hashbase[i].hch_mtx); } #undef msec - error = SYSCTL_OUT(req, buf, p - buf); - free(buf, M_TEMP); + sbuf_finish(&sb); + error = SYSCTL_OUT(req, sbuf_data(&sb), sbuf_len(&sb)); + sbuf_delete(&sb); return(error); } From a19f39141436a7d08e52c63534b5ee2b2740546e Mon Sep 17 00:00:00 2001 From: jhb Date: Sun, 25 Jan 2015 19:53:09 +0000 Subject: [PATCH 253/258] Pass a valid Dx state variable to PCIB_POWER_FOR_SLEEP() in pcib_resume() instead of NULL. Submitted by: dchagin MFC after: 2 weeks --- sys/dev/pci/pci_pci.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sys/dev/pci/pci_pci.c b/sys/dev/pci/pci_pci.c index f35b481a1ab6..c7029f28f0f0 100644 --- a/sys/dev/pci/pci_pci.c +++ b/sys/dev/pci/pci_pci.c @@ -1114,11 +1114,13 @@ int pcib_resume(device_t dev) { device_t pcib; + int dstate; if (pci_do_power_resume) { pcib = device_get_parent(device_get_parent(dev)); - if (PCIB_POWER_FOR_SLEEP(pcib, dev, NULL) == 0) - pci_set_powerstate(dev, PCI_POWERSTATE_D0); + dstate = PCI_POWERSTATE_D0; + if (PCIB_POWER_FOR_SLEEP(pcib, dev, &dstate) == 0) + pci_set_powerstate(dev, dstate); } pcib_cfg_restore(device_get_softc(dev)); return (bus_generic_resume(dev)); From 71715e274d4165b5e34b83a6a25c3f769083671f Mon Sep 17 00:00:00 2001 From: jhb Date: Sun, 25 Jan 2015 19:56:45 +0000 Subject: [PATCH 254/258] Change the default VFS timestamp precision from seconds to microseconds. Discussed on: arch@ MFC after: 2 weeks --- sys/kern/vfs_subr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 292052368521..912863e6ddf9 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -632,7 +632,7 @@ vfs_getnewfsid(struct mount *mp) */ enum { TSP_SEC, TSP_HZ, TSP_USEC, TSP_NSEC }; -static int timestamp_precision = TSP_SEC; +static int timestamp_precision = TSP_USEC; SYSCTL_INT(_vfs, OID_AUTO, timestamp_precision, CTLFLAG_RW, ×tamp_precision, 0, "File timestamp precision (0: seconds, " "1: sec + ns accurate to 1/HZ, 2: sec + ns truncated to ms, " From 03984c1e9c74ce91042ef333ec96564424269039 Mon Sep 17 00:00:00 2001 From: jhb Date: Sun, 25 Jan 2015 20:16:45 +0000 Subject: [PATCH 255/258] If the boot-time memory test is enabled, output a dot ('.') for each GB of RAM tested so people watching the console can see that the machine is making progress and not hung. PR: 196650 Submitted by: Ravi Pokala Suggestions from: Eric van Gyzen MFC after: 2 weeks --- sys/amd64/amd64/machdep.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index bcfdac143b4e..07378fddce3b 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -1557,6 +1557,8 @@ native_parse_memmap(caddr_t kmdp, vm_paddr_t *physmap, int *physmap_idx) } } +#define PAGES_PER_GB (1024 * 1024 * 1024 / PAGE_SIZE) + /* * Populate the (physmap) array with base/bound pairs describing the * available physical memory in the system, then test this memory and @@ -1575,6 +1577,7 @@ getmemsize(caddr_t kmdp, u_int64_t first) u_long physmem_start, physmem_tunable, memtest; pt_entry_t *pte; quad_t dcons_addr, dcons_size; + int page_counter; bzero(physmap, sizeof(physmap)); basemem = 0; @@ -1678,6 +1681,9 @@ getmemsize(caddr_t kmdp, u_int64_t first) * physmap is in bytes, so when converting to page boundaries, * round up the start address and round down the end address. */ + page_counter = 0; + if (memtest != 0) + printf("Testing system memory"); for (i = 0; i <= physmap_idx; i += 2) { vm_paddr_t end; @@ -1707,6 +1713,14 @@ getmemsize(caddr_t kmdp, u_int64_t first) if (memtest == 0) goto skip_memtest; + /* + * Print a "." every GB to show we're making + * progress. + */ + page_counter++; + if ((page_counter % PAGES_PER_GB) == 0) + printf("."); + /* * map page into kernel: valid, read/write,non-cacheable */ @@ -1794,6 +1808,8 @@ getmemsize(caddr_t kmdp, u_int64_t first) } *pte = 0; invltlb(); + if (memtest != 0) + printf("\n"); /* * XXX From 71eba92ca59be0af74c0d1ed3e68559add33521c Mon Sep 17 00:00:00 2001 From: jhb Date: Sun, 25 Jan 2015 20:37:32 +0000 Subject: [PATCH 256/258] natd(8) will work with an unconfigured interface and effectively not do anything until the interface is assigned an address. This fixes ipfw_nat to do the same by using an IP of INADDR_ANY instead of aborting the nat setup if the requested interface is not yet configured. Differential Revision: https://reviews.freebsd.org/D1539 Reviewed by: melifaro, glebius, gnn MFC after: 1 week --- sbin/ipfw/nat.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sbin/ipfw/nat.c b/sbin/ipfw/nat.c index 3bd0259ad5ad..439177875e22 100644 --- a/sbin/ipfw/nat.c +++ b/sbin/ipfw/nat.c @@ -163,9 +163,9 @@ set_addr_dynamic(const char *ifn, struct nat44_cfg_nat *n) } } if (sin == NULL) - errx(1, "%s: cannot get interface address", ifn); - - n->ip = sin->sin_addr; + n->ip.s_addr = htonl(INADDR_ANY); + else + n->ip = sin->sin_addr; strncpy(n->if_name, ifn, IF_NAMESIZE); free(buf); From fad3fbbf45006174f321fd2ba796cece12a8b6f3 Mon Sep 17 00:00:00 2001 From: gonzo Date: Sun, 25 Jan 2015 22:08:36 +0000 Subject: [PATCH 257/258] Add vt(4) support to AM335x LCDC driver --- sys/arm/ti/am335x/am335x_lcd.c | 51 ++++++++++++++++++++++++++++++++-- sys/arm/ti/am335x/files.am335x | 2 +- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/sys/arm/ti/am335x/am335x_lcd.c b/sys/arm/ti/am335x/am335x_lcd.c index 4fd811cc2eac..053567ec3086 100644 --- a/sys/arm/ti/am335x/am335x_lcd.c +++ b/sys/arm/ti/am335x/am335x_lcd.c @@ -27,6 +27,7 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_syscons.h" #include #include #include @@ -41,8 +42,6 @@ __FBSDID("$FreeBSD$"); #include #include #include - -/* syscons bits */ #include #include @@ -54,7 +53,11 @@ __FBSDID("$FreeBSD$"); #include #include +#ifdef DEV_SC #include +#else /* VT */ +#include +#endif #include #include @@ -62,6 +65,8 @@ __FBSDID("$FreeBSD$"); #include "am335x_lcd.h" #include "am335x_pwm.h" +#include "fb_if.h" + #define LCD_PID 0x00 #define LCD_CTRL 0x04 #define CTRL_DIV_MASK 0xff @@ -178,6 +183,7 @@ __FBSDID("$FreeBSD$"); struct am335x_lcd_softc { device_t sc_dev; + struct fb_info sc_fb_info; struct resource *sc_mem_res; struct resource *sc_irq_res; void *sc_intr_hl; @@ -410,7 +416,9 @@ am335x_lcd_intr(void *arg) static int am335x_lcd_probe(device_t dev) { +#ifdef DEV_SC int err; +#endif if (!ofw_bus_status_okay(dev)) return (ENXIO); @@ -420,10 +428,12 @@ am335x_lcd_probe(device_t dev) device_set_desc(dev, "AM335x LCD controller"); +#ifdef DEV_SC err = sc_probe_unit(device_get_unit(dev), device_get_flags(dev) | SC_AUTODETECT_KBD); if (err != 0) return (err); +#endif return (BUS_PROBE_DEFAULT); } @@ -670,6 +680,16 @@ am335x_lcd_attach(device_t dev) PWM_PERIOD, PWM_PERIOD) == 0) sc->sc_backlight = 100; + sc->sc_fb_info.fb_name = device_get_nameunit(sc->sc_dev); + sc->sc_fb_info.fb_vbase = (intptr_t)sc->sc_fb_base; + sc->sc_fb_info.fb_pbase = sc->sc_fb_phys; + sc->sc_fb_info.fb_size = sc->sc_fb_size; + sc->sc_fb_info.fb_bpp = sc->sc_fb_info.fb_depth = panel.bpp; + sc->sc_fb_info.fb_stride = panel.panel_width*panel.bpp / 8; + sc->sc_fb_info.fb_width = panel.panel_width; + sc->sc_fb_info.fb_height = panel.panel_height; + +#ifdef DEV_SC err = (sc_attach_unit(device_get_unit(dev), device_get_flags(dev) | SC_AUTODETECT_KBD)); @@ -679,6 +699,18 @@ am335x_lcd_attach(device_t dev) } am335x_lcd_syscons_setup((vm_offset_t)sc->sc_fb_base, sc->sc_fb_phys, &panel); +#else /* VT */ + device_t fbd = device_add_child(dev, "fbd", + device_get_unit(dev)); + if (fbd == NULL) { + device_printf(dev, "Failed to add fbd child\n"); + goto fail; + } + if (device_probe_and_attach(fbd) != 0) { + device_printf(dev, "Failed to attach fbd device\n"); + goto fail; + } +#endif return (0); @@ -693,16 +725,29 @@ am335x_lcd_detach(device_t dev) return (EBUSY); } +static struct fb_info * +am335x_lcd_fb_getinfo(device_t dev) +{ + struct am335x_lcd_softc *sc; + + sc = device_get_softc(dev); + + return (&sc->sc_fb_info); +} + static device_method_t am335x_lcd_methods[] = { DEVMETHOD(device_probe, am335x_lcd_probe), DEVMETHOD(device_attach, am335x_lcd_attach), DEVMETHOD(device_detach, am335x_lcd_detach), + /* Framebuffer service methods */ + DEVMETHOD(fb_getinfo, am335x_lcd_fb_getinfo), + DEVMETHOD_END }; static driver_t am335x_lcd_driver = { - "am335x_lcd", + "fb", am335x_lcd_methods, sizeof(struct am335x_lcd_softc), }; diff --git a/sys/arm/ti/am335x/files.am335x b/sys/arm/ti/am335x/files.am335x index 465a7fc9deac..aee414fc7b8d 100644 --- a/sys/arm/ti/am335x/files.am335x +++ b/sys/arm/ti/am335x/files.am335x @@ -4,7 +4,7 @@ arm/ti/aintc.c standard arm/ti/am335x/am335x_dmtimer.c standard arm/ti/am335x/am335x_gpio.c optional gpio -arm/ti/am335x/am335x_lcd.c optional sc +arm/ti/am335x/am335x_lcd.c optional sc | vt arm/ti/am335x/am335x_lcd_syscons.c optional sc arm/ti/am335x/am335x_pmic.c optional am335x_pmic arm/ti/am335x/am335x_prcm.c standard From 588a6eb29f37c0081497dc155776215a84099f02 Mon Sep 17 00:00:00 2001 From: scottl Date: Sun, 25 Jan 2015 22:29:23 +0000 Subject: [PATCH 258/258] Fix the ioctl interface to properly support fetching the header of regular and extended config pages. Obtained from: Netflix, Inc. MFC after: 3 days --- sys/dev/mps/mps.c | 14 ++++++++++---- sys/dev/mps/mps_user.c | 4 ++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/sys/dev/mps/mps.c b/sys/dev/mps/mps.c index 20c7f75308d2..0957602ccc19 100644 --- a/sys/dev/mps/mps.c +++ b/sys/dev/mps/mps.c @@ -2621,9 +2621,12 @@ mps_read_config_page(struct mps_softc *sc, struct mps_config_params *params) cm->cm_data = params->buffer; cm->cm_length = params->length; - cm->cm_sge = &req->PageBufferSGE; - cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); - cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN; + if (cm->cm_data != NULL) { + cm->cm_sge = &req->PageBufferSGE; + cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); + cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN; + } else + cm->cm_sge = NULL; cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; cm->cm_complete_data = params; @@ -2680,9 +2683,12 @@ mps_config_complete(struct mps_softc *sc, struct mps_command *cm) goto done; } params->status = reply->IOCStatus; - if (params->hdr.Ext.ExtPageType != 0) { + if (params->hdr.Struct.PageType == MPI2_CONFIG_PAGETYPE_EXTENDED) { params->hdr.Ext.ExtPageType = reply->ExtPageType; params->hdr.Ext.ExtPageLength = reply->ExtPageLength; + params->hdr.Ext.PageType = reply->Header.PageType; + params->hdr.Ext.PageNumber = reply->Header.PageNumber; + params->hdr.Ext.PageVersion = reply->Header.PageVersion; } else { params->hdr.Struct.PageType = reply->Header.PageType; params->hdr.Struct.PageNumber = reply->Header.PageNumber; diff --git a/sys/dev/mps/mps_user.c b/sys/dev/mps/mps_user.c index 16ec4e4e623a..63f78b6ccd46 100644 --- a/sys/dev/mps/mps_user.c +++ b/sys/dev/mps/mps_user.c @@ -309,6 +309,10 @@ mps_user_read_extcfg_header(struct mps_softc *sc, hdr->PageNumber = ext_page_req->header.PageNumber; hdr->ExtPageType = ext_page_req->header.ExtPageType; params.page_address = le32toh(ext_page_req->page_address); + params.buffer = NULL; + params.length = 0; + params.callback = NULL; + if ((error = mps_read_config_page(sc, ¶ms)) != 0) { /* * Leave the request. Without resetting the chip, it's